Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Apr 2012 14:52:39 GMT
From:      Robert Watson <rwatson@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 208918 for review
Message-ID:  <201204011452.q31Eqd2L038646@skunkworks.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@208918?ac=10

Change 208918 by rwatson@rwatson_svr_ctsrd_mipsbuild on 2012/04/01 14:51:53

	Implement first cut at reading the SD Card CSD register in the
	FreeBSD device driver for the Altera Univesity Program SD Card
	IP Core.  Currently, support only v1 CSD structures; we'll see
	what turns up in the actual SD Cards shipped by Altera.  Add
	support for "bad" cards whose insertion event is suppressed
	when we encounter unexpected configuration data.  Work under
	the assumption that CSD data is immediately available via
	memory-mapped registers -- if this proves not to be true, we
	will need to add additional states in order to allow blocking
	reads of CSD/CID/etc from the card prior to starting I/O.

Affected files ...

.. //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard.c#2 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard.h#4 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard_disk.c#2 edit
.. //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard_io.c#3 edit

Differences ...

==== //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard.c#2 (text+ko) ====

@@ -174,12 +174,27 @@
 	}
 
 	/*
-	 * Handle card insertion.
+	 * If there is no card insertion, remain in NOCARD.
+	 */
+	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT))
+		return;
+
+	/*
+	 * Read the CSD -- it may contain values that force the setting of
+	 * ALTERA_SDCARD_FLAG_BADCARD, in which case we suppress detection of
+	 * the card.  For example, if there is an unrecognised CSD structure
+	 * version, or if the IP Core doesn't support the returned sector
+	 * size.
+	 */
+	altera_sdcard_read_csd(sc);
+	if (sc->as_flags & ALTERA_SDCARD_FLAG_BADCARD)
+		return;
+
+	/*
+	 * Process card insertion and upgrade to the IDLE state.
 	 */
-	if (altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT) {
-		altera_sdcard_disk_insert(sc);
-		sc->as_state = ALTERA_SDCARD_STATE_IDLE;
-	}
+	altera_sdcard_disk_insert(sc);
+	sc->as_state = ALTERA_SDCARD_STATE_IDLE;
 }
 
 static void
@@ -198,6 +213,9 @@
 
 	/*
 	 * Handle safe card removal.
+	 *
+	 * XXXRW: In the future, we may want to handle the run-time setting of
+	 * ALTERA_SDCARD_FLAG_BADCARD.
 	 */
 	if (!(altera_sdcard_read_asr(sc) & ALTERA_SDCARD_ASR_CARDPRESENT)) {
 		altera_sdcard_disk_remove(sc);
@@ -217,6 +235,9 @@
 
 	/*
 	 * Check for unexpected card removal during an I/O.
+	 *
+	 * XXXRW: In the future, we may want to handle the run-time setting of
+	 * ALTERA_SDCARD_FLAG_BADCARD.
 	 */
 	if (!(asr & ALTERA_SDCARD_ASR_CARDPRESENT)) {
 		altera_sdcard_disk_remove(sc);

==== //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard.h#4 (text+ko) ====

@@ -31,6 +31,11 @@
 #ifndef _DEV_ALTERA_SDCARD_H_
 #define	_DEV_ALTERA_SDCARD_H_
 
+#define	ALTERA_SDCARD_CSD_SIZE	16
+struct altera_sdcard_csd {
+	uint8_t		 csd_data[ALTERA_SDCARD_CSD_SIZE];
+};
+
 struct altera_sdcard_softc {
 	device_t		 as_dev;
 	int			 as_unit;
@@ -45,6 +50,12 @@
 	struct bio		*as_currentbio;
 	struct taskqueue	*as_taskqueue;
 	struct timeout_task	 as_task;
+
+	/*
+	 * Infrequently changing fields cached from the SD Card IP Core.
+	 */
+	struct altera_sdcard_csd	 as_csd;
+	uint64_t		 as_mediasize;
 };
 
 #define	ALTERA_SDCARD_LOCK(sc)		mtx_lock(&(sc)->as_lock)
@@ -81,6 +92,7 @@
  * Driver status flags.
  */
 #define	ALTERA_SDCARD_FLAG_DETACHREQ	0x00000001	/* Detach requested. */
+#define	ALTERA_SDCARD_FLAG_BADCARD	0x00000002	/* Unsupported card. */
 
 /*
  * Functions for performing low-level register and memory I/O to/from the SD
@@ -88,7 +100,7 @@
  * hardware interface.
  */
 uint16_t	altera_sdcard_read_asr(struct altera_sdcard_softc *sc);
-uint64_t	altera_sdcard_read_csd_size(struct altera_sdcard_softc *sc);
+void		altera_sdcard_read_csd(struct altera_sdcard_softc *sc);
 
 void	altera_sdcard_io_complete(struct altera_sdcard_softc *sc,
 	    uint16_t asr);
@@ -96,6 +108,40 @@
 	    struct bio *bp);
 
 /*
+ * Constants for interpreting the SD Card Card Specific Data (CSD) register.
+ */
+#define	ALTERA_SDCARD_CSD_STRUCTURE_BYTE	15
+#define	ALTERA_SDCARD_CSD_STRUCTURE_MASK	0xc0	/* 2 bits */
+#define	ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT	6
+
+#define	ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE	10
+#define	ALTERA_SDCARD_CSD_READ_BL_LEN_MASK	0x0f	/* 4 bits */
+
+/*
+ * C_SIZE is a 12-bit field helpfully split over three differe bytes of CSD
+ * data.  Software ease of use was not a design consideration.
+ */
+#define	ALTERA_SDCARD_CSD_C_SIZE_BYTE0		7
+#define	ALTERA_SDCARD_CSD_C_SIZE_MASK0		0xc	/* top 2 bits */
+#define	ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0	6
+
+#define	ALTERA_SDCARD_CSD_C_SIZE_BYTE1		8
+#define	ALTERA_SDCARD_CSD_C_SIZE_MASK1		0xff	/* 8 bits */
+#define	ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1	2
+
+#define	ALTERA_SDCARD_CSD_C_SIZE_BYTE2		9
+#define	ALTERA_SDCARD_CSD_C_SIZE_MASK2		0x03	/* bottom 2 bits */
+#define	ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2	10
+
+#define	ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0	5
+#define	ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0	0x80	/* top 1 bit */
+#define	ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0	7
+
+#define	ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1	6
+#define	ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1	0x03	/* bottom 2 bits */
+#define	ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1	1
+
+/*
  * I/O register/buffer offsets, from Table 4.1.1 in the Altera University
  * Program SD Card IP Core specification.
  */

==== //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard_disk.c#2 (text+ko) ====

@@ -131,7 +131,7 @@
 	disk->d_dump = altera_sdcard_disk_dump;
 	disk->d_ioctl = altera_sdcard_disk_ioctl;
 	disk->d_sectorsize = ALTERA_SDCARD_SECTORSIZE;
-	disk->d_mediasize = altera_sdcard_read_csd_size(sc);
+	disk->d_mediasize = sc->as_mediasize;
 	disk->d_maxsize = ALTERA_SDCARD_SECTORSIZE;
 	sc->as_disk = disk;
 	disk_create(disk, DISK_VERSION);

==== //depot/projects/ctsrd/beribsd/src/sys/dev/altera/sdcard/altera_sdcard_io.c#3 (text+ko) ====

@@ -55,6 +55,11 @@
 
 /*
  * Low-level I/O routines for the Altera SD Card University IP Core driver.
+ *
+ * XXXRW: Throughout, it is assumed that the IP Core handles multibyte
+ * registers as little endian, as is the case for other Altera IP cores.
+ * However, the specification makes no reference to endianness, so this
+ * assumption might not always be correct.
  */
 uint16_t
 altera_sdcard_read_asr(struct altera_sdcard_softc *sc)
@@ -63,14 +68,96 @@
 	return (le16toh(bus_read_2(sc->as_res, ALTERA_SDCARD_OFF_ASR)));
 }
 
-uint64_t
-altera_sdcard_read_csd_size(struct altera_sdcard_softc *sc)
+void
+altera_sdcard_read_csd(struct altera_sdcard_softc *sc)
 {
+	uint64_t c_size, c_size_mult, read_bl_len;
+	uint8_t csd_structure, byte0, byte1, byte2;
+
+	ALTERA_SDCARD_LOCK_ASSERT(sc);
 
-	panic("%s: not yet", __func__);
+	/*
+	 * XXXRW: Assume for now that when the SD Card IP Core negotiates
+	 * voltage/speed/etc, it must use the CSD register, and therefore
+	 * populates the SD Card IP Core's cache of the register value.  This
+	 * means that we can read it without issuing further SD Card commands.
+	 * If this assumption proves false, we will (a) get back garbage and
+	 * (b) need to add additional states in the driver state machine in
+	 * order to query card properties before I/O can start.
+	 *
+	 * XXXRW: Treating this as an array of bytes, so no byte swapping --
+	 * is that a safe assumption?
+	 */
+	bus_read_region_1(sc->as_res, ALTERA_SDCARD_OFF_CSD,
+	    sc->as_csd.csd_data, sizeof(sc->as_csd));
+
+	/*
+	 * Interpret the loaded CSD, extracting certain fields and copying
+	 * them into the softc for easy software access.
+	 *
+	 * Currently, we support only CSD Version 1.0.  If we detect a newer
+	 * version, suppress card detection.
+	 */
+	csd_structure = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_STRUCTURE_BYTE];
+	csd_structure &= ALTERA_SDCARD_CSD_STRUCTURE_MASK;
+	csd_structure >>= ALTERA_SDCARD_CSD_STRUCTURE_RSHIFT;
+	if (csd_structure != 0) {
+		sc->as_flags |= ALTERA_SDCARD_FLAG_BADCARD;
+		return;
+	}
+
+	/*-
+	 * Compute card capacity per SD Card interface description as follows:
+	 *
+	 *   Memory capacity = BLOCKNR * BLOCK_LEN
+	 *
+	 * Where:
+	 *
+	 *   BLOCKNR = (C_SIZE + 1) * MULT
+	 *   MULT = C_SIZE_MULT << 8
+	 *   BLOCK_LEN = READ_BL_LEN << 12
+	 */
+	read_bl_len = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_READ_BL_LEN_BYTE];
+	read_bl_len &= ALTERA_SDCARD_CSD_READ_BL_LEN_MASK;
+
+	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
+	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
+	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
+	byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
+	c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
+	    (byte0 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
+
+	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE0];
+	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MASK0;
+	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE1];
+	byte2 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_BYTE2];
+	byte2 &= ALTERA_SDCARD_CSD_C_SIZE_MASK2;
+	c_size = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_RSHIFT0) |
+	    (byte1 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT1) |
+	    (byte2 << ALTERA_SDCARD_CSD_C_SIZE_LSHIFT2);
+
+	byte0 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE0];
+	byte0 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK0;
+	byte1 = sc->as_csd.csd_data[ALTERA_SDCARD_CSD_C_SIZE_MULT_BYTE1];
+	byte1 &= ALTERA_SDCARD_CSD_C_SIZE_MULT_MASK1;
+	c_size_mult = (byte0 >> ALTERA_SDCARD_CSD_C_SIZE_MULT_RSHIFT0) |
+	    (byte1 << ALTERA_SDCARD_CSD_C_SIZE_MULT_LSHIFT1);
+
+	/*
+	 * If we're just getting back zero's, mark the card as bad.
+	 */
+	sc->as_mediasize = (c_size + 1) * (c_size_mult << 8) *
+	    (read_bl_len << 12);
+	if (sc->as_mediasize == 0)
+		sc->as_flags |= ALTERA_SDCARD_FLAG_BADCARD;
 }
 
 #if 0
+/*
+ * XXXRW: The Altera IP Core specification indicates that RR1 is a 16-bit
+ * register, but all bits it identifies are >16 bit.  Most likely, RR1 is a
+ * 32-bit register?
+ */
 uint16_t
 altera_sdcard_read_rr1(struct altera_sdcard_softc *sc)
 {



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