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 */
35int
36sdio_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 */
92int
93sdio_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
170int
171sdio_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
184int
185sdio_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 */
209uint8_t
210sdio_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
216int
217sdio_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
222uint16_t
223sdio_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
236int
237sdio_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
247uint32_t
248sdio_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
261int
262sdio_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 */
273int
274sdio_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
278int
279sdio_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
283int
284sdio_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
288int
289sdio_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
293int
294sdio_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
298int
299sdio_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
328int
329sdio_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
413uint32_t
414sdio_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
430void 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