xref: /openbsd-src/sys/dev/sdmmc/sdmmc_cis.c (revision 4372d0df8945018256d1f237db36d452225718e1)
1*4372d0dfSpatrick /*	$OpenBSD: sdmmc_cis.c,v 1.8 2020/04/29 09:44:49 patrick Exp $	*/
2cfd1c195Suwe 
3cfd1c195Suwe /*
4cfd1c195Suwe  * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
5cfd1c195Suwe  *
6cfd1c195Suwe  * Permission to use, copy, modify, and distribute this software for any
7cfd1c195Suwe  * purpose with or without fee is hereby granted, provided that the above
8cfd1c195Suwe  * copyright notice and this permission notice appear in all copies.
9cfd1c195Suwe  *
10cfd1c195Suwe  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11cfd1c195Suwe  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12cfd1c195Suwe  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13cfd1c195Suwe  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14cfd1c195Suwe  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15cfd1c195Suwe  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16cfd1c195Suwe  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17cfd1c195Suwe  */
18cfd1c195Suwe 
19cfd1c195Suwe /* Routines to decode the Card Information Structure of SD I/O cards */
20cfd1c195Suwe 
21cfd1c195Suwe #include <sys/param.h>
2296813442Skettenis #include <sys/device.h>
23cfd1c195Suwe #include <sys/systm.h>
24cfd1c195Suwe 
25cfd1c195Suwe #include <dev/sdmmc/sdmmc_ioreg.h>
26cfd1c195Suwe #include <dev/sdmmc/sdmmcdevs.h>
27cfd1c195Suwe #include <dev/sdmmc/sdmmcvar.h>
28cfd1c195Suwe 
29cfd1c195Suwe u_int32_t sdmmc_cisptr(struct sdmmc_function *);
30cfd1c195Suwe 
31cfd1c195Suwe #ifdef SDMMC_DEBUG
32cfd1c195Suwe #define DPRINTF(s)	printf s
33cfd1c195Suwe #else
34cfd1c195Suwe #define DPRINTF(s)	/**/
35cfd1c195Suwe #endif
36cfd1c195Suwe 
37cfd1c195Suwe u_int32_t
sdmmc_cisptr(struct sdmmc_function * sf)38cfd1c195Suwe sdmmc_cisptr(struct sdmmc_function *sf)
39cfd1c195Suwe {
402d832f63Skettenis 	struct sdmmc_function *sf0 = sf->sc->sc_fn0;
41cfd1c195Suwe 	u_int32_t cisptr = 0;
422d832f63Skettenis 	int reg;
43cfd1c195Suwe 
449de6240fSblambert 	rw_assert_wrlock(&sf->sc->sc_lock);
45d86927c1Sjasper 
462d832f63Skettenis 	reg = SD_IO_CCCR_CISPTR + (sf->number * SD_IO_CCCR_SIZE);
472d832f63Skettenis 	cisptr |= sdmmc_io_read_1(sf0, reg + 0) << 0;
482d832f63Skettenis 	cisptr |= sdmmc_io_read_1(sf0, reg + 1) << 8;
492d832f63Skettenis 	cisptr |= sdmmc_io_read_1(sf0, reg + 2) << 16;
50d86927c1Sjasper 
51cfd1c195Suwe 	return cisptr;
52cfd1c195Suwe }
53cfd1c195Suwe 
54cfd1c195Suwe int
sdmmc_read_cis(struct sdmmc_function * sf,struct sdmmc_cis * cis)55cfd1c195Suwe sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis)
56cfd1c195Suwe {
572d832f63Skettenis 	struct sdmmc_function *sf0 = sf->sc->sc_fn0;
58cfd1c195Suwe 	int reg;
59cfd1c195Suwe 	u_int8_t tplcode;
60cfd1c195Suwe 	u_int8_t tpllen;
61cfd1c195Suwe 
629de6240fSblambert 	rw_assert_wrlock(&sf->sc->sc_lock);
63d86927c1Sjasper 
64cfd1c195Suwe 	reg = (int)sdmmc_cisptr(sf);
65cfd1c195Suwe 	if (reg < SD_IO_CIS_START ||
66cfd1c195Suwe 	    reg >= (SD_IO_CIS_START+SD_IO_CIS_SIZE-16)) {
67a93f47f6Sjasper 		printf("%s: bad CIS ptr %#x\n", DEVNAME(sf->sc), reg);
68cfd1c195Suwe 		return 1;
69cfd1c195Suwe 	}
70cfd1c195Suwe 
71cfd1c195Suwe 	for (;;) {
722d832f63Skettenis 		tplcode = sdmmc_io_read_1(sf0, reg++);
73b961a0f8Skettenis 		if (tplcode == SD_IO_CISTPL_END)
74b961a0f8Skettenis 			break;
75b961a0f8Skettenis 		if (tplcode == SD_IO_CISTPL_NULL)
76b961a0f8Skettenis 			continue;
77cfd1c195Suwe 
782d832f63Skettenis 		tpllen = sdmmc_io_read_1(sf0, reg++);
79cfd1c195Suwe 
80cfd1c195Suwe 		switch (tplcode) {
81cfd1c195Suwe 		case SD_IO_CISTPL_FUNCID:
82cfd1c195Suwe 			if (tpllen < 2) {
83cfd1c195Suwe 				printf("%s: bad CISTPL_FUNCID length\n",
84a93f47f6Sjasper 				    DEVNAME(sf->sc));
85cfd1c195Suwe 				reg += tpllen;
86cfd1c195Suwe 				break;
87cfd1c195Suwe 			}
882d832f63Skettenis 			cis->function = sdmmc_io_read_1(sf0, reg);
89cfd1c195Suwe 			reg += tpllen;
90cfd1c195Suwe 			break;
91cfd1c195Suwe 		case SD_IO_CISTPL_MANFID:
92cfd1c195Suwe 			if (tpllen < 4) {
93cfd1c195Suwe 				printf("%s: bad CISTPL_MANFID length\n",
94a93f47f6Sjasper 				    DEVNAME(sf->sc));
95cfd1c195Suwe 				reg += tpllen;
96cfd1c195Suwe 				break;
97cfd1c195Suwe 			}
982d832f63Skettenis 			cis->manufacturer = sdmmc_io_read_1(sf0, reg++);
992d832f63Skettenis 			cis->manufacturer |= sdmmc_io_read_1(sf0, reg++) << 8;
1002d832f63Skettenis 			cis->product = sdmmc_io_read_1(sf0, reg++);
1012d832f63Skettenis 			cis->product |= sdmmc_io_read_1(sf0, reg++) << 8;
102cfd1c195Suwe 			break;
103cfd1c195Suwe 		case SD_IO_CISTPL_VERS_1:
104cfd1c195Suwe 			if (tpllen < 2) {
105cfd1c195Suwe 				printf("%s: CISTPL_VERS_1 too short\n",
106a93f47f6Sjasper 				    DEVNAME(sf->sc));
107cfd1c195Suwe 				reg += tpllen;
108cfd1c195Suwe 				break;
109cfd1c195Suwe 			}
110cfd1c195Suwe 			{
111cfd1c195Suwe 				int start, i, ch, count;
112cfd1c195Suwe 
1132d832f63Skettenis 				cis->cis1_major = sdmmc_io_read_1(sf0, reg++);
1142d832f63Skettenis 				cis->cis1_minor = sdmmc_io_read_1(sf0, reg++);
115cfd1c195Suwe 
116cfd1c195Suwe 				for (count = 0, start = 0, i = 0;
117cfd1c195Suwe 				     (count < 4) && ((i + 4) < 256); i++) {
1182d832f63Skettenis 					ch = sdmmc_io_read_1(sf0, reg + i);
119cfd1c195Suwe 					if (ch == 0xff)
120cfd1c195Suwe 						break;
121cfd1c195Suwe 					cis->cis1_info_buf[i] = ch;
122cfd1c195Suwe 					if (ch == 0) {
123cfd1c195Suwe 						cis->cis1_info[count] =
124cfd1c195Suwe 						    cis->cis1_info_buf + start;
125cfd1c195Suwe 						start = i + 1;
126cfd1c195Suwe 						count++;
127cfd1c195Suwe 					}
128cfd1c195Suwe 				}
129cfd1c195Suwe 
130cfd1c195Suwe 				reg += tpllen - 2;
131cfd1c195Suwe 			}
132cfd1c195Suwe 			break;
133cfd1c195Suwe 		default:
134cfd1c195Suwe 			DPRINTF(("%s: unknown tuple code %#x, length %d\n",
135a93f47f6Sjasper 			    DEVNAME(sf->sc), tplcode, tpllen));
136cfd1c195Suwe 			reg += tpllen;
137cfd1c195Suwe 			break;
138cfd1c195Suwe 		}
139cfd1c195Suwe 	}
140d86927c1Sjasper 
141cfd1c195Suwe 	return 0;
142cfd1c195Suwe }
143cfd1c195Suwe 
144cfd1c195Suwe void
sdmmc_print_cis(struct sdmmc_function * sf)145cfd1c195Suwe sdmmc_print_cis(struct sdmmc_function *sf)
146cfd1c195Suwe {
147cfd1c195Suwe 	struct sdmmc_cis *cis = &sf->cis;
148cfd1c195Suwe 	int i;
149cfd1c195Suwe 
150a93f47f6Sjasper 	printf("%s: CIS version %d.%d\n", DEVNAME(sf->sc),
151cfd1c195Suwe 	    cis->cis1_major, cis->cis1_minor);
152cfd1c195Suwe 
153a93f47f6Sjasper 	printf("%s: CIS info: ", DEVNAME(sf->sc));
154cfd1c195Suwe 	for (i = 0; i < 4; i++) {
155cfd1c195Suwe 		if (cis->cis1_info[i] == NULL)
156cfd1c195Suwe 			break;
157cfd1c195Suwe 		if (i)
158cfd1c195Suwe 			printf(", ");
159cfd1c195Suwe 		printf("%s", cis->cis1_info[i]);
160cfd1c195Suwe 	}
161cfd1c195Suwe 	printf("\n");
162cfd1c195Suwe 
163cfd1c195Suwe 	printf("%s: Manufacturer code 0x%x, product 0x%x\n",
164a93f47f6Sjasper 	    DEVNAME(sf->sc), cis->manufacturer, cis->product);
165cfd1c195Suwe 
166a93f47f6Sjasper 	printf("%s: function %d: ", DEVNAME(sf->sc), sf->number);
167cfd1c195Suwe 	switch (sf->cis.function) {
1682d832f63Skettenis 	case TPLFID_FUNCTION_SDIO:
1692d832f63Skettenis 		printf("SDIO");
170cfd1c195Suwe 		break;
171cfd1c195Suwe 	default:
172cfd1c195Suwe 		printf("unknown (%d)", sf->cis.function);
173cfd1c195Suwe 		break;
174cfd1c195Suwe 	}
175cfd1c195Suwe 	printf("\n");
176cfd1c195Suwe }
177cfd1c195Suwe 
178cfd1c195Suwe void
sdmmc_check_cis_quirks(struct sdmmc_function * sf)179cfd1c195Suwe sdmmc_check_cis_quirks(struct sdmmc_function *sf)
180cfd1c195Suwe {
181cfd1c195Suwe 	if (sf->cis.manufacturer == SDMMC_VENDOR_SPECTEC &&
182cfd1c195Suwe 	    sf->cis.product == SDMMC_PRODUCT_SPECTEC_SDW820) {
183cfd1c195Suwe 		/* This card lacks the VERS_1 tuple. */
184cfd1c195Suwe 		sf->cis.cis1_major = 0x01;
185cfd1c195Suwe 		sf->cis.cis1_minor = 0x00;
186cfd1c195Suwe 		sf->cis.cis1_info[0] = "Spectec";
187cfd1c195Suwe 		sf->cis.cis1_info[1] = "SDIO WLAN Card";
188cfd1c195Suwe 		sf->cis.cis1_info[2] = "SDW-820";
189cfd1c195Suwe 		sf->cis.cis1_info[3] = "";
190cfd1c195Suwe 	}
191cfd1c195Suwe }
192