The Lenovo Ideacentre Stick 300 I recently acquired has a Realtek
RTL8723BS wireless chip which uses an SDIO interface. This made me
look at our SDIO support code again. I noticed that reading the
per-function CIS wasn't implemented, so I wrote the missing code.
The diff below fixes a couple of issues with the code. The most
important thing as the we need to read from function 0 to gather all
the information. I also noticed that the current code mistakenly
identified the SDIO card function code as "wireless network". Last but
not least, the bus width was being set to a reserved value. I removed
that setting, as it is obviously wrong and bus width 1 is supposed to
be the default anyway.
As far as I know we don't actually have any SDIO device drivers in our
tree anymore, so this should all be very low risk.
ok?
Index: sdmmc_cis.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_cis.c,v
retrieving revision 1.6
diff -u -p -r1.6 sdmmc_cis.c
--- sdmmc_cis.c 11 Jan 2016 07:32:38 -0000 1.6
+++ sdmmc_cis.c 19 Apr 2016 21:20:47 -0000
@@ -37,18 +37,16 @@ u_int32_t sdmmc_cisptr(struct sdmmc_func
u_int32_t
sdmmc_cisptr(struct sdmmc_function *sf)
{
+ struct sdmmc_function *sf0 = sf->sc->sc_fn0;
u_int32_t cisptr = 0;
+ int reg;
rw_assert_wrlock(&sf->sc->sc_lock);
- /* 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;
+ reg = SD_IO_CCCR_CISPTR + (sf->number * SD_IO_CCCR_SIZE);
+ cisptr |= sdmmc_io_read_1(sf0, reg + 0) << 0;
+ cisptr |= sdmmc_io_read_1(sf0, reg + 1) << 8;
+ cisptr |= sdmmc_io_read_1(sf0, reg + 2) << 16;
return cisptr;
}
@@ -56,18 +54,13 @@ sdmmc_cisptr(struct sdmmc_function *sf)
int
sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis)
{
+ struct sdmmc_function *sf0 = sf->sc->sc_fn0;
int reg;
u_int8_t tplcode;
u_int8_t tpllen;
rw_assert_wrlock(&sf->sc->sc_lock);
- bzero(cis, sizeof *cis);
-
- /* XXX read per-function CIS */
- if (sf->number != 0)
- return 1;
-
reg = (int)sdmmc_cisptr(sf);
if (reg < SD_IO_CIS_START ||
reg >= (SD_IO_CIS_START+SD_IO_CIS_SIZE-16)) {
@@ -76,13 +69,13 @@ sdmmc_read_cis(struct sdmmc_function *sf
}
for (;;) {
- tplcode = sdmmc_io_read_1(sf, reg++);
+ tplcode = sdmmc_io_read_1(sf0, reg++);
if (tplcode == SD_IO_CISTPL_END)
break;
if (tplcode == SD_IO_CISTPL_NULL)
continue;
- tpllen = sdmmc_io_read_1(sf, reg++);
+ tpllen = sdmmc_io_read_1(sf0, reg++);
if (tpllen == 0) {
printf("%s: CIS parse error at %d, "
"tuple code %#x, length %d\n",
@@ -98,7 +91,7 @@ sdmmc_read_cis(struct sdmmc_function *sf
reg += tpllen;
break;
}
- cis->function = sdmmc_io_read_1(sf, reg);
+ cis->function = sdmmc_io_read_1(sf0, reg);
reg += tpllen;
break;
case SD_IO_CISTPL_MANFID:
@@ -108,10 +101,10 @@ sdmmc_read_cis(struct sdmmc_function *sf
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;
break;
case SD_IO_CISTPL_VERS_1:
if (tpllen < 2) {
@@ -123,12 +116,12 @@ sdmmc_read_cis(struct sdmmc_function *sf
{
int start, i, ch, count;
- cis->cis1_major = sdmmc_io_read_1(sf, reg++);
- cis->cis1_minor = sdmmc_io_read_1(sf, reg++);
+ 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(sf, reg + i);
+ ch = sdmmc_io_read_1(sf0, reg + i);
if (ch == 0xff)
break;
cis->cis1_info_buf[i] = ch;
@@ -178,8 +171,8 @@ sdmmc_print_cis(struct sdmmc_function *s
printf("%s: function %d: ", DEVNAME(sf->sc), sf->number);
switch (sf->cis.function) {
- case SDMMC_FUNCTION_WLAN:
- printf("wireless network adapter");
+ case TPLFID_FUNCTION_SDIO:
+ printf("SDIO");
break;
default:
printf("unknown (%d)", sf->cis.function);
Index: sdmmc_io.c
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_io.c,v
retrieving revision 1.22
diff -u -p -r1.22 sdmmc_io.c
--- sdmmc_io.c 14 Mar 2015 03:38:49 -0000 1.22
+++ sdmmc_io.c 19 Apr 2016 21:20:47 -0000
@@ -171,21 +171,17 @@ sdmmc_io_init(struct sdmmc_softc *sc, st
{
rw_assert_wrlock(&sc->sc_lock);
- if (sf->number == 0) {
- sdmmc_io_write_1(sf, SD_IO_CCCR_BUS_WIDTH,
- CCCR_BUS_WIDTH_1);
+ if (sdmmc_read_cis(sf, &sf->cis) != 0) {
+ printf("%s: can't read CIS\n", DEVNAME(sc));
+ SET(sf->flags, SFF_ERROR);
+ return 1;
+ }
- if (sdmmc_read_cis(sf, &sf->cis) != 0) {
- printf("%s: can't read CIS\n", DEVNAME(sc));
- SET(sf->flags, SFF_ERROR);
- return 1;
- }
+ sdmmc_check_cis_quirks(sf);
- sdmmc_check_cis_quirks(sf);
+ if (sdmmc_verbose)
+ sdmmc_print_cis(sf);
- if (sdmmc_verbose)
- sdmmc_print_cis(sf);
- }
return 0;
}
Index: sdmmc_ioreg.h
===================================================================
RCS file: /cvs/src/sys/dev/sdmmc/sdmmc_ioreg.h,v
retrieving revision 1.5
diff -u -p -r1.5 sdmmc_ioreg.h
--- sdmmc_ioreg.h 11 Jan 2016 07:32:38 -0000 1.5
+++ sdmmc_ioreg.h 19 Apr 2016 21:20:47 -0000
@@ -69,8 +69,9 @@
#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_1 (0<<0)
+#define CCCR_BUS_WIDTH_4 (2<<0)
+#define CCCR_BUS_WIDTH_8 (3<<0)
#define SD_IO_CCCR_CISPTR 0x09 /* XXX 9-10, 10-11, or 9-12 */
/* Function Basic Registers (FBR) */
@@ -90,6 +91,6 @@
#define SD_IO_CISTPL_END 0xff
/* CISTPL_FUNCID codes */
-#define SDMMC_FUNCTION_WLAN 0x0c
+#define TPLFID_FUNCTION_SDIO 0x0c
#endif