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 */
31int
32sdio_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 */
88int
89sdio_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
166int
167sdio_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
180int
181sdio_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 */
205uint8_t
206sdio_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
212int
213sdio_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
218uint16_t
219sdio_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
232int
233sdio_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
243uint32_t
244sdio_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
257int
258sdio_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 */
269int
270sdio_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
274int
275sdio_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
279int
280sdio_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
284int
285sdio_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
289int
290sdio_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
294int
295sdio_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
324int
325sdio_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
409uint32_t
410sdio_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
426void 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