1 /* $NetBSD: sdmmc_cis.c,v 1.10 2025/01/17 11:54:50 jmcneill Exp $ */ 2 /* $OpenBSD: sdmmc_cis.c,v 1.1 2006/06/01 21:53:41 uwe Exp $ */ 3 4 /* 5 * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 /* Routines to decode the Card Information Structure of SD I/O cards */ 21 22 #include <sys/cdefs.h> 23 __KERNEL_RCSID(0, "$NetBSD: sdmmc_cis.c,v 1.10 2025/01/17 11:54:50 jmcneill Exp $"); 24 25 #ifdef _KERNEL_OPT 26 #include "opt_sdmmc.h" 27 #endif 28 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 32 #include <dev/sdmmc/sdmmc_ioreg.h> 33 #include <dev/sdmmc/sdmmcdevs.h> 34 #include <dev/sdmmc/sdmmcvar.h> 35 36 #include <dev/pcmcia/pcmciareg.h> 37 38 #ifdef SDMMCCISDEBUG 39 #define DPRINTF(s) printf s 40 #else 41 #define DPRINTF(s) /**/ 42 #endif 43 44 static void decode_funce_common(struct sdmmc_function *, struct sdmmc_cis *, 45 int, uint32_t); 46 static void decode_funce_function(struct sdmmc_function *, struct sdmmc_cis *, 47 int, uint32_t); 48 static void decode_vers_1(struct sdmmc_function *, struct sdmmc_cis *, int, 49 uint32_t); 50 51 uint32_t 52 sdmmc_cisptr(struct sdmmc_function *sf) 53 { 54 uint32_t cisptr = 0; 55 56 /* CIS pointer stored in little-endian format. */ 57 if (sf->number == 0) { 58 cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 0) << 0; 59 cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 1) << 8; 60 cisptr |= sdmmc_io_read_1(sf, SD_IO_CCCR_CISPTR + 2) << 16; 61 } else { 62 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 63 int num = sf->number; 64 65 cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 9) << 0; 66 cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 10) << 8; 67 cisptr |= sdmmc_io_read_1(sf0, SD_IO_FBR(num) + 11) << 16; 68 } 69 return cisptr; 70 } 71 72 static void 73 decode_funce_common(struct sdmmc_function *sf, struct sdmmc_cis *cis, 74 int tpllen, uint32_t reg) 75 { 76 static const int speed_val[] = 77 { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; 78 static const int speed_unit[] = { 10, 100, 1000, 10000, }; 79 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 80 device_t dev = sf->sc->sc_dev; 81 int fn0_blk_size, max_tran_speed; 82 83 if (sf->number != 0) { 84 aprint_error_dev(dev, 85 "CISTPL_FUNCE(common) found in function\n"); 86 return; 87 } 88 if (tpllen < 4) { 89 aprint_error_dev(dev, "CISTPL_FUNCE(common) too short\n"); 90 return; 91 } 92 93 fn0_blk_size = sdmmc_io_read_1(sf0, reg++); 94 fn0_blk_size |= sdmmc_io_read_1(sf0, reg++) << 8; 95 max_tran_speed = sdmmc_io_read_1(sf0, reg++); 96 sf->csd.tran_speed = 97 speed_val[max_tran_speed >> 3] * speed_unit[max_tran_speed & 7]; 98 99 DPRINTF( 100 ("CISTPL_FUNCE: FN0_BLK_SIZE=0x%x, MAX_TRAN_SPEED=0x%x(%dkHz)\n", 101 fn0_blk_size, max_tran_speed, sf->csd.tran_speed)); 102 } 103 104 static void 105 decode_funce_lan_nid(struct sdmmc_function *sf, struct sdmmc_cis *cis, 106 int tpllen, uint32_t reg) 107 { 108 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 109 device_t dev = sf->sc->sc_dev; 110 int i; 111 112 if (tpllen != 8) { 113 aprint_error_dev(dev, 114 "CISTPL_FUNCE(lan_nid) too short\n"); 115 return; 116 } 117 118 if (sdmmc_io_read_1(sf0, reg++) != 6) { 119 aprint_error_dev(dev, 120 "CISTPL_FUNCE(lan_nid) invalid\n"); 121 } 122 123 for (i = 0; i < 6; i++) { 124 cis->lan_nid[i] = sdmmc_io_read_1(sf0, reg++); 125 } 126 127 DPRINTF( 128 ("CISTPL_FUNCE: LAN_NID=%02x:%02x:%02x:%02x:%02x:%02x\n", 129 cis->lan_nid[0], cis->lan_nid[1], cis->lan_nid[2], 130 cis->lan_nid[3], cis->lan_nid[4], cis->lan_nid[5])); 131 } 132 133 static void 134 decode_funce_function(struct sdmmc_function *sf, struct sdmmc_cis *cis, 135 int tpllen, uint32_t reg) 136 { 137 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 138 device_t dev = sf->sc->sc_dev; 139 int sdiox_cccrx, sdiox, max_blk_size; 140 141 sdiox_cccrx = sdmmc_io_read_1(sf0, SD_IO_CCCR_CCCR_SDIO_REV); 142 sdiox = SD_IO_CCCR_SDIO_REV(sdiox_cccrx); 143 144 if (sf->number == 0) { 145 aprint_error_dev(dev, 146 "CISTPL_FUNCE(function) found in common\n"); 147 return; 148 } 149 if (sdiox == CCCR_SDIO_REV_1_00 && tpllen < 0x1c) { 150 aprint_error_dev(dev, 151 "CISTPL_FUNCE(function) too short (v1.00)\n"); 152 return; 153 } else if (sdiox != CCCR_SDIO_REV_1_00 && tpllen < 0x2a) { 154 aprint_error_dev(dev, "CISTPL_FUNCE(function) too short\n"); 155 return; 156 } 157 158 max_blk_size = sdmmc_io_read_1(sf0, reg + 11); 159 max_blk_size |= sdmmc_io_read_1(sf0, reg + 12) << 8; 160 161 DPRINTF(("CISTPL_FUNCE: MAX_BLK_SIZE=0x%x\n", max_blk_size)); 162 } 163 164 static void 165 decode_vers_1(struct sdmmc_function *sf, struct sdmmc_cis *cis, int tpllen, 166 uint32_t reg) 167 { 168 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 169 device_t dev = sf->sc->sc_dev; 170 int start, ch, count, i; 171 172 if (tpllen < 2) { 173 aprint_error_dev(dev, "CISTPL_VERS_1 too short\n"); 174 return; 175 } 176 177 cis->cis1_major = sdmmc_io_read_1(sf0, reg++); 178 cis->cis1_minor = sdmmc_io_read_1(sf0, reg++); 179 180 for (count = 0, start = 0, i = 0; (count < 4) && ((i + 4) < 256); i++) { 181 ch = sdmmc_io_read_1(sf0, reg + i); 182 if (ch == 0xff) 183 break; 184 cis->cis1_info_buf[i] = ch; 185 if (ch == 0) { 186 cis->cis1_info[count] = cis->cis1_info_buf + start; 187 start = i + 1; 188 count++; 189 } 190 } 191 192 DPRINTF(("CISTPL_VERS_1\n")); 193 } 194 195 int 196 sdmmc_read_cis(struct sdmmc_function *sf, struct sdmmc_cis *cis) 197 { 198 struct sdmmc_function *sf0 = sf->sc->sc_fn0; 199 device_t dev = sf->sc->sc_dev; 200 uint32_t reg; 201 uint8_t tplcode, tpllen; 202 203 memset(cis, 0, sizeof *cis); 204 205 reg = sdmmc_cisptr(sf); 206 if (reg < SD_IO_CIS_START || 207 reg >= (SD_IO_CIS_START + SD_IO_CIS_SIZE - 16)) { 208 aprint_error_dev(dev, "bad CIS ptr %#x\n", reg); 209 return 1; 210 } 211 212 for (;;) { 213 tplcode = sdmmc_io_read_1(sf0, reg++); 214 215 if (tplcode == PCMCIA_CISTPL_NULL) { 216 DPRINTF((" 00\nCISTPL_NONE\n")); 217 continue; 218 } 219 220 tpllen = sdmmc_io_read_1(sf0, reg++); 221 if (tplcode == PCMCIA_CISTPL_END || tpllen == 0) { 222 if (tplcode != 0xff) 223 aprint_error_dev(dev, "CIS parse error at %d, " 224 "tuple code %#x, length %d\n", 225 reg, tplcode, tpllen); 226 else { 227 DPRINTF((" ff\nCISTPL_END\n")); 228 } 229 break; 230 } 231 232 #ifdef SDMMCCISDEBUG 233 { 234 int i; 235 236 /* print the tuple */ 237 DPRINTF((" %02x %02x", tplcode, tpllen)); 238 239 for (i = 0; i < tpllen; i++) { 240 DPRINTF((" %02x", 241 sdmmc_io_read_1(sf0, reg + i))); 242 if ((i % 16) == 13) 243 DPRINTF(("\n")); 244 } 245 if ((i % 16) != 14) 246 DPRINTF(("\n")); 247 } 248 #endif 249 250 switch (tplcode) { 251 case PCMCIA_CISTPL_FUNCE: 252 switch (sdmmc_io_read_1(sf0, reg++)) { 253 case 0: 254 decode_funce_common(sf, cis, tpllen, reg); 255 break; 256 case PCMCIA_TPLFE_TYPE_LAN_NID: 257 decode_funce_lan_nid(sf, cis, tpllen, reg); 258 break; 259 default: 260 decode_funce_function(sf, cis, tpllen, reg); 261 } 262 reg += (tpllen - 1); 263 break; 264 265 case PCMCIA_CISTPL_FUNCID: 266 if (tpllen < 2) { 267 aprint_error_dev(dev, 268 "bad CISTPL_FUNCID length\n"); 269 reg += tpllen; 270 break; 271 } 272 cis->function = sdmmc_io_read_1(sf0, reg); 273 DPRINTF(("CISTPL_FUNCID\n")); 274 reg += tpllen; 275 break; 276 277 case PCMCIA_CISTPL_MANFID: 278 if (tpllen < 4) { 279 aprint_error_dev(dev, 280 "bad CISTPL_MANFID length\n"); 281 reg += tpllen; 282 break; 283 } 284 cis->manufacturer = sdmmc_io_read_1(sf0, reg++); 285 cis->manufacturer |= sdmmc_io_read_1(sf0, reg++) << 8; 286 cis->product = sdmmc_io_read_1(sf0, reg++); 287 cis->product |= sdmmc_io_read_1(sf0, reg++) << 8; 288 DPRINTF(("CISTPL_MANFID\n")); 289 break; 290 291 case PCMCIA_CISTPL_VERS_1: 292 decode_vers_1(sf, cis, tpllen, reg); 293 reg += tpllen; 294 break; 295 296 case PCMCIA_CISTPL_SDIO: 297 aprint_normal_dev(dev, "SDIO function\n"); 298 reg += tpllen; 299 break; 300 301 default: 302 /* 303 * Tuple codes between 80h-8Fh are vendor unique. 304 * Print a warning about all other codes. 305 */ 306 if ((tplcode & 0xf0) != 0x80) 307 aprint_error_dev(dev, 308 "unknown tuple code %#x, length %d\n", 309 tplcode, tpllen); 310 reg += tpllen; 311 break; 312 } 313 } 314 315 return 0; 316 } 317 318 void 319 sdmmc_print_cis(struct sdmmc_function *sf) 320 { 321 device_t dev = sf->sc->sc_dev; 322 struct sdmmc_cis *cis = &sf->cis; 323 int i; 324 325 printf("%s: CIS version %u.%u\n", device_xname(dev), cis->cis1_major, 326 cis->cis1_minor); 327 328 printf("%s: CIS info: ", device_xname(dev)); 329 for (i = 0; i < 4; i++) { 330 if (cis->cis1_info[i] == NULL) 331 break; 332 if (i != 0) 333 aprint_verbose(", "); 334 printf("%s", cis->cis1_info[i]); 335 } 336 printf("\n"); 337 338 printf("%s: Manufacturer code 0x%x, product 0x%x\n", device_xname(dev), 339 cis->manufacturer, cis->product); 340 341 printf("%s: function %d: ", device_xname(dev), sf->number); 342 printf("\n"); 343 } 344 345 void 346 sdmmc_check_cis_quirks(struct sdmmc_function *sf) 347 { 348 char *p; 349 int i; 350 351 if (sf->cis.manufacturer == SDMMC_VENDOR_SPECTEC && 352 sf->cis.product == SDMMC_PRODUCT_SPECTEC_SDW820) { 353 /* This card lacks the VERS_1 tuple. */ 354 static const char cis1_info[] = 355 "Spectec\0SDIO WLAN Card\0SDW-820\0\0"; 356 357 sf->cis.cis1_major = 0x01; 358 sf->cis.cis1_minor = 0x00; 359 360 p = sf->cis.cis1_info_buf; 361 strlcpy(p, cis1_info, sizeof(sf->cis.cis1_info_buf)); 362 for (i = 0; i < 4; i++) { 363 sf->cis.cis1_info[i] = p; 364 p += strlen(p) + 1; 365 } 366 } 367 } 368