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>