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