1 /*- 2 * Copyright (c) 2017 Ilya Bakulin 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 #include "cam_sdio.h" 29 30 /* Use CMD52 to read or write a single byte */ 31 int 32 sdio_rw_direct(struct cam_device *dev, 33 uint8_t func_number, 34 uint32_t addr, 35 uint8_t is_write, 36 uint8_t *data, uint8_t *resp) { 37 union ccb *ccb; 38 uint32_t flags; 39 uint32_t arg; 40 int retval = 0; 41 42 ccb = cam_getccb(dev); 43 if (ccb == NULL) { 44 warnx("%s: error allocating CCB", __func__); 45 return (-1); 46 } 47 bzero(&(&ccb->ccb_h)[1], 48 sizeof(union ccb) - sizeof(struct ccb_hdr)); 49 50 flags = MMC_RSP_R5 | MMC_CMD_AC; 51 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr); 52 if (is_write) 53 arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data); 54 55 cam_fill_mmcio(&ccb->mmcio, 56 /*retries*/ 0, 57 /*cbfcnp*/ NULL, 58 /*flags*/ CAM_DIR_NONE, 59 /*mmc_opcode*/ SD_IO_RW_DIRECT, 60 /*mmc_arg*/ arg, 61 /*mmc_flags*/ flags, 62 /*mmc_data*/ 0, 63 /*timeout*/ 5000); 64 65 if (((retval = cam_send_ccb(dev, ccb)) < 0) 66 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 67 const char warnstr[] = "error sending command"; 68 69 if (retval < 0) 70 warn(warnstr); 71 else 72 warnx(warnstr); 73 return (-1); 74 } 75 76 *resp = ccb->mmcio.cmd.resp[0] & 0xFF; 77 cam_freeccb(ccb); 78 return (retval); 79 } 80 81 /* 82 * CMD53 -- IO_RW_EXTENDED 83 * Use to read or write memory blocks 84 * 85 * is_increment=1: FIFO mode 86 * blk_count > 0: block mode 87 */ 88 int 89 sdio_rw_extended(struct cam_device *dev, 90 uint8_t func_number, 91 uint32_t addr, 92 uint8_t is_write, 93 caddr_t data, size_t datalen, 94 uint8_t is_increment, 95 uint16_t blk_count) { 96 union ccb *ccb; 97 uint32_t flags; 98 uint32_t arg; 99 uint32_t cam_flags; 100 uint8_t resp; 101 struct mmc_data mmcd; 102 int retval = 0; 103 104 if (blk_count != 0) { 105 warnx("%s: block mode is not supported yet", __func__); 106 return (-1); 107 } 108 109 ccb = cam_getccb(dev); 110 if (ccb == NULL) { 111 warnx("%s: error allocating CCB", __func__); 112 return (-1); 113 } 114 bzero(&(&ccb->ccb_h)[1], 115 sizeof(union ccb) - sizeof(struct ccb_hdr)); 116 117 flags = MMC_RSP_R5 | MMC_CMD_ADTC; 118 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr) | 119 SD_IOE_RW_LEN(datalen); 120 121 if (is_increment) 122 arg |= SD_IO_RW_INCR; 123 124 mmcd.data = data; 125 mmcd.len = datalen; 126 mmcd.xfer_len = 0; /* not used by MMCCAM */ 127 mmcd.mrq = NULL; /* not used by MMCCAM */ 128 129 if (is_write) { 130 arg |= SD_IO_RW_WR; 131 cam_flags = CAM_DIR_OUT; 132 mmcd.flags = MMC_DATA_WRITE; 133 } else { 134 cam_flags = CAM_DIR_IN; 135 mmcd.flags = MMC_DATA_READ; 136 } 137 cam_fill_mmcio(&ccb->mmcio, 138 /*retries*/ 0, 139 /*cbfcnp*/ NULL, 140 /*flags*/ cam_flags, 141 /*mmc_opcode*/ SD_IO_RW_EXTENDED, 142 /*mmc_arg*/ arg, 143 /*mmc_flags*/ flags, 144 /*mmc_data*/ &mmcd, 145 /*timeout*/ 5000); 146 147 if (((retval = cam_send_ccb(dev, ccb)) < 0) 148 || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) { 149 const char warnstr[] = "error sending command"; 150 151 if (retval < 0) 152 warn(warnstr); 153 else 154 warnx(warnstr); 155 return (-1); 156 } 157 158 resp = ccb->mmcio.cmd.resp[0] & 0xFF; 159 if (resp != 0) 160 warn("Response from CMD53 is not 0?!"); 161 cam_freeccb(ccb); 162 return (retval); 163 } 164 165 166 int 167 sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) { 168 uint8_t resp; 169 int ret; 170 171 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp); 172 if (ret < 0) 173 return ret; 174 175 *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0; 176 177 return (0); 178 } 179 180 int 181 sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) { 182 uint8_t resp; 183 int ret; 184 uint8_t is_enabled; 185 186 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp); 187 if (ret != 0) 188 return ret; 189 190 is_enabled = resp & (1 << func_number); 191 if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0)) 192 return 0; 193 194 if (enable) 195 resp |= 1 << func_number; 196 else 197 resp &= ~ (1 << func_number); 198 199 ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp); 200 201 return ret; 202 } 203 204 /* Conventional I/O functions */ 205 uint8_t 206 sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) { 207 uint8_t val; 208 *ret = sdio_rw_direct(dev, func_number, addr, 0, NULL, &val); 209 return val; 210 } 211 212 int 213 sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) { 214 uint8_t _val; 215 return sdio_rw_direct(dev, func_number, addr, 0, &val, &_val); 216 } 217 218 uint16_t 219 sdio_read_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) { 220 uint16_t val; 221 *ret = sdio_rw_extended(dev, func_number, addr, 222 /* is_write */ 0, 223 /* data */ (caddr_t) &val, 224 /* datalen */ sizeof(val), 225 /* is_increment */ 1, 226 /* blk_count */ 0 227 ); 228 return val; 229 } 230 231 232 int 233 sdio_write_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint16_t val) { 234 return sdio_rw_extended(dev, func_number, addr, 235 /* is_write */ 1, 236 /* data */ (caddr_t) &val, 237 /* datalen */ sizeof(val), 238 /* is_increment */ 1, 239 /* blk_count */ 0 240 ); 241 } 242 243 uint32_t 244 sdio_read_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) { 245 uint32_t val; 246 *ret = sdio_rw_extended(dev, func_number, addr, 247 /* is_write */ 0, 248 /* data */ (caddr_t) &val, 249 /* datalen */ sizeof(val), 250 /* is_increment */ 1, 251 /* blk_count */ 0 252 ); 253 return val; 254 } 255 256 257 int 258 sdio_write_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint32_t val) { 259 return sdio_rw_extended(dev, func_number, addr, 260 /* is_write */ 1, 261 /* data */ (caddr_t) &val, 262 /* datalen */ sizeof(val), 263 /* is_increment */ 1, 264 /* blk_count */ 0 265 ); 266 } 267 268 /* Higher-level wrappers for certain management operations */ 269 int 270 sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) { 271 return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_READY, func_number, is_enab); 272 } 273 274 int 275 sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) { 276 return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, is_enab); 277 } 278 279 int 280 sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable) { 281 return sdio_set_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, enable); 282 } 283 284 int 285 sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) { 286 return sdio_read_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, is_enab); 287 } 288 289 int 290 sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable) { 291 return sdio_set_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, enable); 292 } 293 294 int 295 sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) { 296 int ret; 297 uint8_t ctl_val; 298 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val); 299 if (ret < 0) { 300 warn("Error getting CCCR_BUS_WIDTH value"); 301 return ret; 302 } 303 ctl_val &= ~0x3; 304 switch (bw) { 305 case bus_width_1: 306 /* Already set to 1-bit */ 307 break; 308 case bus_width_4: 309 ctl_val |= CCCR_BUS_WIDTH_4; 310 break; 311 case bus_width_8: 312 warn("Cannot do 8-bit on SDIO yet"); 313 return -1; 314 break; 315 } 316 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val); 317 if (ret < 0) { 318 warn("Error setting CCCR_BUS_WIDTH value"); 319 return ret; 320 } 321 return ret; 322 } 323 324 int 325 sdio_func_read_cis(struct cam_device *dev, uint8_t func_number, 326 uint32_t cis_addr, struct cis_info *info) { 327 uint8_t tuple_id, tuple_len, tuple_count; 328 uint32_t addr; 329 330 char *cis1_info[4]; 331 int start, i, ch, count, ret; 332 char cis1_info_buf[256]; 333 334 tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */ 335 memset(cis1_info_buf, 0, 256); 336 do { 337 addr = cis_addr; 338 tuple_id = sdio_read_1(dev, 0, addr++, &ret); 339 if (tuple_id == SD_IO_CISTPL_END) 340 break; 341 if (tuple_id == 0) { 342 cis_addr++; 343 continue; 344 } 345 tuple_len = sdio_read_1(dev, 0, addr++, &ret); 346 if (tuple_len == 0 && tuple_id != 0x00) { 347 warn("Parse error: 0-length tuple %02X\n", tuple_id); 348 return -1; 349 } 350 351 switch (tuple_id) { 352 case SD_IO_CISTPL_VERS_1: 353 addr += 2; 354 for (count = 0, start = 0, i = 0; 355 (count < 4) && ((i + 4) < 256); i++) { 356 ch = sdio_read_1(dev, 0, addr + i, &ret); 357 printf("count=%d, start=%d, i=%d, Got %c (0x%02x)\n", count, start, i, ch, ch); 358 if (ch == 0xff) 359 break; 360 cis1_info_buf[i] = ch; 361 if (ch == 0) { 362 cis1_info[count] = 363 cis1_info_buf + start; 364 start = i + 1; 365 count++; 366 } 367 } 368 printf("Card info:"); 369 for (i=0; i<4; i++) 370 if (cis1_info[i]) 371 printf(" %s", cis1_info[i]); 372 printf("\n"); 373 break; 374 case SD_IO_CISTPL_MANFID: 375 info->man_id = sdio_read_1(dev, 0, addr++, &ret); 376 info->man_id |= sdio_read_1(dev, 0, addr++, &ret) << 8; 377 378 info->prod_id = sdio_read_1(dev, 0, addr++, &ret); 379 info->prod_id |= sdio_read_1(dev, 0, addr++, &ret) << 8; 380 break; 381 case SD_IO_CISTPL_FUNCID: 382 /* not sure if we need to parse it? */ 383 break; 384 case SD_IO_CISTPL_FUNCE: 385 if (tuple_len < 4) { 386 printf("FUNCE is too short: %d\n", tuple_len); 387 break; 388 } 389 if (func_number == 0) { 390 /* skip extended_data */ 391 addr++; 392 info->max_block_size = sdio_read_1(dev, 0, addr++, &ret); 393 info->max_block_size |= sdio_read_1(dev, 0, addr++, &ret) << 8; 394 } else { 395 info->max_block_size = sdio_read_1(dev, 0, addr + 0xC, &ret); 396 info->max_block_size |= sdio_read_1(dev, 0, addr + 0xD, &ret) << 8; 397 } 398 break; 399 default: 400 warnx("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len); 401 } 402 cis_addr += tuple_len + 2; 403 tuple_count++; 404 } while (tuple_count < 20); 405 406 return 0; 407 } 408 409 uint32_t 410 sdio_get_common_cis_addr(struct cam_device *dev) { 411 uint32_t addr; 412 int ret; 413 414 addr = sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR, &ret); 415 addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 1, &ret) << 8; 416 addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 2, &ret) << 16; 417 418 if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) { 419 warn("Bad CIS address: %04X\n", addr); 420 addr = 0; 421 } 422 423 return addr; 424 } 425 426 void sdio_card_reset(struct cam_device *dev) { 427 int ret; 428 uint8_t ctl_val; 429 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val); 430 if (ret < 0) 431 errx(1, "Error getting CCCR_CTL value"); 432 ctl_val |= CCCR_CTL_RES; 433 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 1, &ctl_val, &ctl_val); 434 if (ret < 0) 435 errx(1, "Error setting CCCR_CTL value"); 436 } 437