Module Name: src Committed By: kiyohara Date: Thu Oct 7 12:40:34 UTC 2010
Modified Files: src/sys/dev/sdmmc: sdmmc.c sdmmc_cis.c sdmmc_io.c sdmmc_ioreg.h Log Message: Fix read CIS. And pass to attach args the standard function interface code. To generate a diff of this commit: cvs rdiff -u -r1.5 -r1.6 src/sys/dev/sdmmc/sdmmc.c cvs rdiff -u -r1.1 -r1.2 src/sys/dev/sdmmc/sdmmc_cis.c \ src/sys/dev/sdmmc/sdmmc_ioreg.h cvs rdiff -u -r1.4 -r1.5 src/sys/dev/sdmmc/sdmmc_io.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/sdmmc/sdmmc.c diff -u src/sys/dev/sdmmc/sdmmc.c:1.5 src/sys/dev/sdmmc/sdmmc.c:1.6 --- src/sys/dev/sdmmc/sdmmc.c:1.5 Thu Oct 7 12:24:23 2010 +++ src/sys/dev/sdmmc/sdmmc.c Thu Oct 7 12:40:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $ */ +/* $NetBSD: sdmmc.c,v 1.6 2010/10/07 12:40:34 kiyohara Exp $ */ /* $OpenBSD: sdmmc.c,v 1.18 2009/01/09 10:58:38 jsg Exp $ */ /* @@ -50,7 +50,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.5 2010/10/07 12:24:23 kiyohara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc.c,v 1.6 2010/10/07 12:40:34 kiyohara Exp $"); #include <sys/param.h> #include <sys/device.h> @@ -376,6 +376,7 @@ memset(&saa, 0, sizeof saa); saa.manufacturer = sf->cis.manufacturer; saa.product = sf->cis.product; + saa.interface = sf->interface; saa.sf = sf; sf->child = Index: src/sys/dev/sdmmc/sdmmc_cis.c diff -u src/sys/dev/sdmmc/sdmmc_cis.c:1.1 src/sys/dev/sdmmc/sdmmc_cis.c:1.2 --- src/sys/dev/sdmmc/sdmmc_cis.c:1.1 Tue Apr 21 03:00:30 2009 +++ src/sys/dev/sdmmc/sdmmc_cis.c Thu Oct 7 12:40:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_cis.c,v 1.1 2009/04/21 03:00:30 nonaka Exp $ */ +/* $NetBSD: sdmmc_cis.c,v 1.2 2010/10/07 12:40:34 kiyohara Exp $ */ /* $OpenBSD: sdmmc_cis.c,v 1.1 2006/06/01 21:53:41 uwe Exp $ */ /* @@ -20,7 +20,7 @@ /* Routines to decode the Card Information Structure of SD I/O cards */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.1 2009/04/21 03:00:30 nonaka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.2 2010/10/07 12:40:34 kiyohara Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -29,45 +29,147 @@ #include <dev/sdmmc/sdmmcdevs.h> #include <dev/sdmmc/sdmmcvar.h> -#ifdef SDMMC_DEBUG +#include <dev/pcmcia/pcmciareg.h> + +#ifdef SDMMCCISDEBUG #define DPRINTF(s) printf s #else #define DPRINTF(s) /**/ #endif static uint32_t sdmmc_cisptr(struct sdmmc_function *); +static void decode_funce_common(struct sdmmc_function *, struct sdmmc_cis *, + int, uint32_t); +static void decode_funce_function(struct sdmmc_function *, struct sdmmc_cis *, + int, uint32_t); +static void decode_vers_1(struct sdmmc_function *, struct sdmmc_cis *, int, + uint32_t); + static uint32_t sdmmc_cisptr(struct sdmmc_function *sf) { uint32_t cisptr = 0; - /* XXX where is the per-function CIS pointer register? */ - if (sf->number != 0) - return SD_IO_CIS_START; - - /* XXX is the CIS pointer stored in little-endian format? */ - cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 0) << 0; - cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 1) << 8; - cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 2) << 16; + /* CIS pointer stored in little-endian format. */ + if (sf->number == 0) { + cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 0) << 0; + cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 1) << 8; + cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 2) << 16; + } else { + struct sdmmc_function *sf0 = sf->sc->sc_fn0; + int num = sf->number; + + cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 9) << 0; + cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 10) << 8; + cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 11) << 16; + } return cisptr; } +static void +decode_funce_common(struct sdmmc_function *sf, struct sdmmc_cis *cis, + int tpllen, uint32_t reg) +{ + const static int speed_val[] = + { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; + const static int speed_unit[] = { 10, 100, 1000, 10000, }; + struct sdmmc_function *sf0 = sf->sc->sc_fn0; + device_t dev = sf->sc->sc_dev; + int fn0_blk_size, max_tran_speed; + + if (sf->number != 0) { + aprint_error_dev(dev, + "CISTPL_FUNCE(common) found in function\n"); + return; + } + if (tpllen < 4) { + aprint_error_dev(dev, "CISTPL_FUNCE(common) too short\n"); + return; + } + + fn0_blk_size = sdmmc_io_read_1(sf0, reg++); + fn0_blk_size |= sdmmc_io_read_1(sf0, reg++) << 8; + max_tran_speed = sdmmc_io_read_1(sf0, reg++); + sf->csd.tran_speed = + speed_val[max_tran_speed >> 3] * speed_unit[max_tran_speed & 7]; + + DPRINTF( + ("CISTPL_FUNCE: FN0_BLK_SIZE=0x%x, MAX_TRAN_SPEED=0x%x(%dkHz)\n", + fn0_blk_size, max_tran_speed, sf->csd.tran_speed)); +} + +static void +decode_funce_function(struct sdmmc_function *sf, struct sdmmc_cis *cis, + int tpllen, uint32_t reg) +{ + struct sdmmc_function *sf0 = sf->sc->sc_fn0; + device_t dev = sf->sc->sc_dev; + int sdiox_cccrx, sdiox, max_blk_size; + + sdiox_cccrx = sdmmc_io_read_1(sf0, SD_IO_CCCR_CCCR_SDIO_REV); + sdiox = SD_IO_CCCR_SDIO_REV(sdiox_cccrx); + + if (sf->number == 0) { + aprint_error_dev(dev, + "CISTPL_FUNCE(function) found in common\n"); + return; + } + if (sdiox == CCCR_SDIO_REV_1_00 && tpllen < 0x1c) { + aprint_error_dev(dev, + "CISTPL_FUNCE(function) too short (v1.00)\n"); + return; + } else if (sdiox != CCCR_SDIO_REV_1_00 && tpllen < 0x2a) { + aprint_error_dev(dev, "CISTPL_FUNCE(function) too short\n"); + return; + } + + max_blk_size = sdmmc_io_read_1(sf0, reg + 11); + max_blk_size |= sdmmc_io_read_1(sf0, reg + 12) << 8; + + DPRINTF(("CISTPL_FUNCE: MAX_BLK_SIZE=0x%x\n", max_blk_size)); +} + +static void +decode_vers_1(struct sdmmc_function *sf, struct sdmmc_cis *cis, int tpllen, + uint32_t reg) +{ + struct sdmmc_function *sf0 = sf->sc->sc_fn0; + device_t dev = sf->sc->sc_dev; + int start, ch, count, i; + + if (tpllen < 2) { + aprint_error_dev(dev, "CISTPL_VERS_1 too short\n"); + return; + } + + cis->cis1_major = sdmmc_io_read_1(sf0, reg++); + cis->cis1_minor = sdmmc_io_read_1(sf0, reg++); + + for (count = 0, start = 0, i = 0; (count < 4) && ((i + 4) < 256); i++) { + ch = sdmmc_io_read_1(sf0, reg + i); + if (ch == 0xff) + break; + cis->cis1_info_buf[i] = ch; + if (ch == 0) { + cis->cis1_info[count] = cis->cis1_info_buf + start; + start = i + 1; + count++; + } + } + + DPRINTF(("CISTPL_VERS_1\n")); +} + int sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis) { + struct sdmmc_function *sf0 = sf->sc->sc_fn0; device_t dev = sf->sc->sc_dev; uint32_t reg; - uint8_t tplcode; - uint8_t tpllen; - int start, ch, count; - int i; + uint8_t tplcode, tpllen; memset(cis, 0, sizeof *cis); - /* XXX read per-function CIS */ - if (sf->number != 0) - return 1; - reg = sdmmc_cisptr(sf); if (reg < SD_IO_CIS_START || reg >= (SD_IO_CIS_START + SD_IO_CIS_SIZE - 16)) { @@ -76,68 +178,81 @@ } for (;;) { - tplcode = sdmmc_io_read_1(sf, reg++); - tpllen = sdmmc_io_read_1(sf, reg++); + tplcode = sdmmc_io_read_1(sf0, reg++); + + if (tplcode == PCMCIA_CISTPL_NULL) { + DPRINTF((" 00\nCISTPL_NONE\n")); + continue; + } - if (tplcode == 0xff || tpllen == 0) { + tpllen = sdmmc_io_read_1(sf0, reg++); + if (tplcode == PCMCIA_CISTPL_END || tpllen == 0) { if (tplcode != 0xff) aprint_error_dev(dev, "CIS parse error at %d, " "tuple code %#x, length %d\n", reg, tplcode, tpllen); + else { + DPRINTF((" ff\nCISTPL_END\n")); + } break; } +#ifdef SDMMCCISDEBUG + { + int i; + + /* print the tuple */ + DPRINTF((" %02x %02x", tplcode, tpllen)); + + for (i = 0; i < tpllen; i++) { + DPRINTF((" %02x", + sdmmc_io_read_1(sf0, reg + i))); + if ((i % 16) == 13) + DPRINTF(("\n")); + } + if ((i % 16) != 14) + DPRINTF(("\n")); + } +#endif + switch (tplcode) { - case SD_IO_CISTPL_FUNCID: + case PCMCIA_CISTPL_FUNCE: + if (sdmmc_io_read_1(sf0, reg++) == 0) + decode_funce_common(sf, cis, tpllen, reg); + else + decode_funce_function(sf, cis, tpllen, reg); + reg += (tpllen - 1); + break; + + case PCMCIA_CISTPL_FUNCID: if (tpllen < 2) { aprint_error_dev(dev, "bad CISTPL_FUNCID length\n"); reg += tpllen; break; } - cis->function = sdmmc_io_read_1(sf, reg); + cis->function = sdmmc_io_read_1(sf0, reg); + DPRINTF(("CISTPL_FUNCID\n")); reg += tpllen; break; - case SD_IO_CISTPL_MANFID: + case PCMCIA_CISTPL_MANFID: if (tpllen < 4) { aprint_error_dev(dev, "bad CISTPL_MANFID length\n"); reg += tpllen; break; } - cis->manufacturer = sdmmc_io_read_1(sf, reg++); - cis->manufacturer |= sdmmc_io_read_1(sf, reg++) << 8; - cis->product = sdmmc_io_read_1(sf, reg++); - cis->product |= sdmmc_io_read_1(sf, reg++) << 8; + cis->manufacturer = sdmmc_io_read_1(sf0, reg++); + cis->manufacturer |= sdmmc_io_read_1(sf0, reg++) << 8; + cis->product = sdmmc_io_read_1(sf0, reg++); + cis->product |= sdmmc_io_read_1(sf0, reg++) << 8; + DPRINTF(("CISTPL_MANFID\n")); break; - case SD_IO_CISTPL_VERS_1: - if (tpllen < 2) { - aprint_error_dev(dev, - "CISTPL_VERS_1 too short\n"); - reg += tpllen; - break; - } - - cis->cis1_major = sdmmc_io_read_1(sf, reg++); - cis->cis1_minor = sdmmc_io_read_1(sf, reg++); - - for (count = 0, start = 0, i = 0; - (count < 4) && ((i + 4) < 256); i++) { - ch = sdmmc_io_read_1(sf, reg + i); - if (ch == 0xff) - break; - cis->cis1_info_buf[i] = ch; - if (ch == 0) { - cis->cis1_info[count] = - cis->cis1_info_buf + start; - start = i + 1; - count++; - } - } - - reg += tpllen - 2; + case PCMCIA_CISTPL_VERS_1: + decode_vers_1(sf, cis, tpllen, reg); + reg += tpllen; break; default: @@ -176,15 +291,6 @@ cis->manufacturer, cis->product); printf("%s: function %d: ", device_xname(dev), sf->number); - switch (sf->cis.function) { - case SDMMC_FUNCTION_WLAN: - printf("wireless network adapter"); - break; - - default: - printf("unknown function (%d)", sf->cis.function); - break; - } printf("\n"); } Index: src/sys/dev/sdmmc/sdmmc_ioreg.h diff -u src/sys/dev/sdmmc/sdmmc_ioreg.h:1.1 src/sys/dev/sdmmc/sdmmc_ioreg.h:1.2 --- src/sys/dev/sdmmc/sdmmc_ioreg.h:1.1 Tue Apr 21 03:00:30 2009 +++ src/sys/dev/sdmmc/sdmmc_ioreg.h Thu Oct 7 12:40:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_ioreg.h,v 1.1 2009/04/21 03:00:30 nonaka Exp $ */ +/* $NetBSD: sdmmc_ioreg.h,v 1.2 2010/10/07 12:40:34 kiyohara Exp $ */ /* $OpenBSD: sdmmc_ioreg.h,v 1.4 2007/06/02 01:48:37 uwe Exp $ */ /* @@ -56,9 +56,8 @@ /* SD R4 response (IO OCR) */ #define SD_IO_OCR_MEM_READY (1<<31) -#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x3) -/* XXX big fat memory present "flag" because we don't know better */ -#define SD_IO_OCR_MEM_PRESENT (0xf<<24) +#define SD_IO_OCR_NUM_FUNCTIONS(ocr) (((ocr) >> 28) & 0x7) +#define SD_IO_OCR_MEM_PRESENT (1<<27) #define SD_IO_OCR_MASK 0x00fffff0 /* Card Common Control Registers (CCCR) */ @@ -68,13 +67,17 @@ #define SD_IO_CCCR_CCCR_REV(r) ((r) & 0xf) #define CCCR_CCCR_REV_1_00 0 #define CCCR_CCCR_REV_1_10 1 +#define CCCR_CCCR_REV_1_20 2 #define SD_IO_CCCR_SDIO_REV(r) (((r) >> 4) & 0xf) #define CCCR_SDIO_REV_1_00 0 #define CCCR_SDIO_REV_1_10 1 +#define CCCR_SDIO_REV_1_20 2 /* (unreleased) */ +#define CCCR_SDIO_REV_2_00 3 #define SD_IO_CCCR_SPEC_REV 0x01 #define SD_IO_CCCR_SD_PHYS_SPEC_VER(r) ((r) & 0xf) #define CCCR_SD_PHYS_SPEC_VER_1_01 0 #define CCCR_SD_PHYS_SPEC_VER_1_10 1 +#define CCCR_SD_PHYS_SPEC_VER_2_00 2 #define SD_IO_CCCR_FN_ENABLE 0x02 #define SD_IO_CCCR_FN_IOREADY 0x03 #define SD_IO_CCCR_FN_INTEN 0x04 @@ -83,8 +86,8 @@ #define SD_IO_CCCR_CTL 0x06 #define CCCR_CTL_RES (1<<3) #define SD_IO_CCCR_BUS_WIDTH 0x07 -#define CCCR_BUS_WIDTH_4 (1<<1) -#define CCCR_BUS_WIDTH_1 (1<<0) +#define CCCR_BUS_WIDTH_4 (2<<0) +#define CCCR_BUS_WIDTH_1 (0<<0) #define SD_IO_CCCR_CAPABILITY 0x08 #define CCCR_CAPS_SDC (1<<0) #define CCCR_CAPS_SMB (1<<1) /* Multi-Block support */ @@ -104,22 +107,29 @@ #define SD_IO_CCCR_FN_READY_FLG 0x0f #define SD_IO_CCCR_FN0_BLKSIZ 0x10 /* 0x10-0x11 */ #define SD_IO_CCCR_POWER_CTL 0x12 +#define SD_IO_CCCR_HIGH_SPEED 0x13 +#define CCCR_HIGH_SPEED_SHS (1<<0) /* Support High-Speed */ +#define CCCR_HIGH_SPEED_EHS (1<<1) /* Enable High-Speed */ /* Function Basic Registers (FBR) */ #define SD_IO_FBR_START 0x00100 -#define SD_IO_FBR_SIZE 0x00700 +#define SD_IO_FBR_SIZE 0x100 +#define SD_IO_FBR(func) ((((func) - 1) * SD_IO_FBR_SIZE) + SD_IO_FBR_START) +#define FBR_STD_FUNC_IF_CODE(v) ((v) & 0x0f) /* Card Information Structure (CIS) */ #define SD_IO_CIS_START 0x01000 #define SD_IO_CIS_SIZE 0x17000 -/* CIS tuple codes (based on PC Card 16) */ -#define SD_IO_CISTPL_VERS_1 0x15 -#define SD_IO_CISTPL_MANFID 0x20 -#define SD_IO_CISTPL_FUNCID 0x21 -#define SD_IO_CISTPL_FUNCE 0x22 - -/* CISTPL_FUNCID codes */ -#define SDMMC_FUNCTION_WLAN 0x0c +/* SDIO Standard Function Interface code */ +#define SD_IO_SFIC_NO_STANDARD 0x0 +#define SD_IO_SFIC_UART 0x1 +#define SD_IO_SFIC_TYPEA_BLUETOOTH 0x2 /* Type-A Bluetooth */ +#define SD_IO_SFIC_TYPEB_BLUETOOTH 0x3 /* Type-B Bluetooth */ +#define SD_IO_SFIC_GPS 0x4 +#define SD_IO_SFIC_CAMERA 0x5 +#define SD_IO_SFIC_PHS 0x6 +#define SD_IO_SFIC_WLAN 0x7 +#define SD_IO_SFIC_ATA 0x8 /* Embedded SDIO-ATA */ #endif /* _SDMMC_IOREG_H_ */ Index: src/sys/dev/sdmmc/sdmmc_io.c diff -u src/sys/dev/sdmmc/sdmmc_io.c:1.4 src/sys/dev/sdmmc/sdmmc_io.c:1.5 --- src/sys/dev/sdmmc/sdmmc_io.c:1.4 Thu Oct 7 12:28:34 2010 +++ src/sys/dev/sdmmc/sdmmc_io.c Thu Oct 7 12:40:34 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sdmmc_io.c,v 1.4 2010/10/07 12:28:34 kiyohara Exp $ */ +/* $NetBSD: sdmmc_io.c,v 1.5 2010/10/07 12:40:34 kiyohara Exp $ */ /* $OpenBSD: sdmmc_io.c,v 1.10 2007/09/17 01:33:33 krw Exp $ */ /* @@ -20,7 +20,7 @@ /* Routines for SD I/O cards. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.4 2010/10/07 12:28:34 kiyohara Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sdmmc_io.c,v 1.5 2010/10/07 12:40:34 kiyohara Exp $"); #include <sys/param.h> #include <sys/kernel.h> @@ -187,12 +187,20 @@ int sdmmc_io_init(struct sdmmc_softc *sc, struct sdmmc_function *sf) { + struct sdmmc_function *sf0 = sc->sc_fn0; int error = 0; + uint8_t reg; SDMMC_LOCK(sc); if (sf->number == 0) { - sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH, CCCR_BUS_WIDTH_1); + sf->width = 1; + reg = sdmmc_io_read_1(sf, SD_IO_CCCR_CAPABILITY); + if (!(reg & CCCR_CAPS_LSC) || (reg & CCCR_CAPS_4BLS)) { + sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH, + CCCR_BUS_WIDTH_4); + sf->width = 4; + } error = sdmmc_read_cis(sf, &sf->cis); if (error) { @@ -208,6 +216,15 @@ sdmmc_print_cis(sf); #endif + reg = sdmmc_io_read_1(sf, SD_IO_CCCR_HIGH_SPEED); + if (reg & CCCR_HIGH_SPEED_SHS) { + reg |= CCCR_HIGH_SPEED_EHS; + sdmmc_io_write_1(sf, SD_IO_CCCR_HIGH_SPEED, reg); + sf->csd.tran_speed = 50000; /* 50MHz */ + + /* Wait 400KHz x 8 clock */ + delay(1); + } if (sc->sc_busclk > sf->csd.tran_speed) sc->sc_busclk = sf->csd.tran_speed; error = @@ -215,6 +232,25 @@ if (error) aprint_error_dev(sc->sc_dev, "can't change bus clock\n"); + } else { + reg = sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x000); + sf->interface = FBR_STD_FUNC_IF_CODE(reg); + if (sf->interface == 0x0f) + sf->interface = + sdmmc_io_read_1(sf0, SD_IO_FBR(sf->number) + 0x001); + error = sdmmc_read_cis(sf, &sf->cis); + if (error) { + aprint_error_dev(sc->sc_dev, "couldn't read CIS\n"); + SET(sf->flags, SFF_ERROR); + goto out; + } + + sdmmc_check_cis_quirks(sf); + +#ifdef SDMMC_DEBUG + if (sdmmcdebug) + sdmmc_print_cis(sf); +#endif } out: