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
sdio_rw_direct(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint8_t is_write,uint8_t * data,uint8_t * resp)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
sdio_rw_extended(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint8_t is_write,caddr_t data,size_t datalen,uint8_t is_increment,uint16_t blk_count)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
sdio_read_bool_for_func(struct cam_device * dev,uint32_t addr,uint8_t func_number,uint8_t * is_enab)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
sdio_set_bool_for_func(struct cam_device * dev,uint32_t addr,uint8_t func_number,int enable)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
sdio_read_1(struct cam_device * dev,uint8_t func_number,uint32_t addr,int * ret)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
sdio_write_1(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint8_t val)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
sdio_read_2(struct cam_device * dev,uint8_t func_number,uint32_t addr,int * ret)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
sdio_write_2(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint16_t val)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
sdio_read_4(struct cam_device * dev,uint8_t func_number,uint32_t addr,int * ret)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
sdio_write_4(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint32_t val)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
sdio_is_func_ready(struct cam_device * dev,uint8_t func_number,uint8_t * is_enab)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
sdio_is_func_enabled(struct cam_device * dev,uint8_t func_number,uint8_t * is_enab)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
sdio_func_enable(struct cam_device * dev,uint8_t func_number,int enable)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
sdio_is_func_intr_enabled(struct cam_device * dev,uint8_t func_number,uint8_t * is_enab)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
sdio_func_intr_enable(struct cam_device * dev,uint8_t func_number,int enable)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
sdio_card_set_bus_width(struct cam_device * dev,enum mmc_bus_width bw)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
sdio_func_read_cis(struct cam_device * dev,uint8_t func_number,uint32_t cis_addr,struct cis_info * info)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
sdio_get_common_cis_addr(struct cam_device * dev)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
sdio_card_reset(struct cam_device * dev)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