xref: /freebsd/usr.bin/sdiotool/cam_sdio.c (revision 84b3c4547afa496b37e86c5e649e99237c8afc6e)
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