2 * Copyright (c) 2017 Ilya Bakulin
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
34 /* Use CMD52 to read or write a single byte */
36 sdio_rw_direct(struct cam_device *dev,
40 uint8_t *data, uint8_t *resp) {
46 ccb = cam_getccb(dev);
48 warnx("%s: error allocating CCB", __func__);
51 bzero(&(&ccb->ccb_h)[1],
52 sizeof(union ccb) - sizeof(struct ccb_hdr));
54 flags = MMC_RSP_R5 | MMC_CMD_AC;
55 arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
57 arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
59 cam_fill_mmcio(&ccb->mmcio,
62 /*flags*/ CAM_DIR_NONE,
63 /*mmc_opcode*/ SD_IO_RW_DIRECT,
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";
80 *resp = ccb->mmcio.cmd.resp[0] & 0xFF;
86 * CMD53 -- IO_RW_EXTENDED
87 * Use to read or write memory blocks
89 * is_increment=1: FIFO mode
90 * blk_count > 0: block mode
93 sdio_rw_extended(struct cam_device *dev,
97 caddr_t data, size_t datalen,
105 struct mmc_data mmcd;
108 if (blk_count != 0) {
109 warnx("%s: block mode is not supported yet", __func__);
113 ccb = cam_getccb(dev);
115 warnx("%s: error allocating CCB", __func__);
118 bzero(&(&ccb->ccb_h)[1],
119 sizeof(union ccb) - sizeof(struct ccb_hdr));
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);
126 arg |= SD_IO_RW_INCR;
130 mmcd.xfer_len = 0; /* not used by MMCCAM */
131 mmcd.mrq = NULL; /* not used by MMCCAM */
135 cam_flags = CAM_DIR_OUT;
136 mmcd.flags = MMC_DATA_WRITE;
138 cam_flags = CAM_DIR_IN;
139 mmcd.flags = MMC_DATA_READ;
141 cam_fill_mmcio(&ccb->mmcio,
145 /*mmc_opcode*/ SD_IO_RW_EXTENDED,
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";
162 resp = ccb->mmcio.cmd.resp[0] & 0xFF;
164 warn("Response from CMD53 is not 0?!");
171 sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) {
175 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
179 *is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0;
185 sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) {
190 ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
194 is_enabled = resp & (1 << func_number);
195 if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0))
199 resp |= 1 << func_number;
201 resp &= ~ (1 << func_number);
203 ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp);
208 /* Conventional I/O functions */
210 sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
212 *ret = sdio_rw_direct(dev, func_number, addr, 0, NULL, &val);
217 sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) {
219 return sdio_rw_direct(dev, func_number, addr, 0, &val, &_val);
223 sdio_read_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
225 *ret = sdio_rw_extended(dev, func_number, addr,
227 /* data */ (caddr_t) &val,
228 /* datalen */ sizeof(val),
229 /* is_increment */ 1,
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,
240 /* data */ (caddr_t) &val,
241 /* datalen */ sizeof(val),
242 /* is_increment */ 1,
248 sdio_read_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
250 *ret = sdio_rw_extended(dev, func_number, addr,
252 /* data */ (caddr_t) &val,
253 /* datalen */ sizeof(val),
254 /* is_increment */ 1,
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,
265 /* data */ (caddr_t) &val,
266 /* datalen */ sizeof(val),
267 /* is_increment */ 1,
272 /* Higher-level wrappers for certain management operations */
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);
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);
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);
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);
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);
299 sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) {
302 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val);
304 warn("Error getting CCCR_BUS_WIDTH value");
310 /* Already set to 1-bit */
313 ctl_val |= CCCR_BUS_WIDTH_4;
316 warn("Cannot do 8-bit on SDIO yet");
320 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val);
322 warn("Error setting CCCR_BUS_WIDTH value");
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;
335 int start, i, ch, count, ret;
336 char cis1_info_buf[256];
338 tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */
339 memset(cis1_info_buf, 0, 256);
342 tuple_id = sdio_read_1(dev, 0, addr++, &ret);
343 if (tuple_id == SD_IO_CISTPL_END)
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);
356 case SD_IO_CISTPL_VERS_1:
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);
364 cis1_info_buf[i] = ch;
367 cis1_info_buf + start;
372 printf("Card info:");
375 printf(" %s", cis1_info[i]);
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;
382 info->prod_id = sdio_read_1(dev, 0, addr++, &ret);
383 info->prod_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
385 case SD_IO_CISTPL_FUNCID:
386 /* not sure if we need to parse it? */
388 case SD_IO_CISTPL_FUNCE:
390 printf("FUNCE is too short: %d\n", tuple_len);
393 if (func_number == 0) {
394 /* skip extended_data */
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;
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;
404 warnx("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len);
406 cis_addr += tuple_len + 2;
408 } while (tuple_count < 20);
414 sdio_get_common_cis_addr(struct cam_device *dev) {
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;
422 if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
423 warn("Bad CIS address: %04X\n", addr);
430 void sdio_card_reset(struct cam_device *dev) {
433 ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val);
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);
439 errx(1, "Error setting CCCR_CTL value");