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