xref: /freebsd/usr.bin/sdiotool/cam_sdio.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
1*029c02a3SIlya Bakulin /*-
2*029c02a3SIlya Bakulin  * Copyright (c) 2017 Ilya Bakulin
3*029c02a3SIlya Bakulin  * All rights reserved.
4*029c02a3SIlya Bakulin  *
5*029c02a3SIlya Bakulin  * Redistribution and use in source and binary forms, with or without
6*029c02a3SIlya Bakulin  * modification, are permitted provided that the following conditions
7*029c02a3SIlya Bakulin  * are met:
8*029c02a3SIlya Bakulin  * 1. Redistributions of source code must retain the above copyright
9*029c02a3SIlya Bakulin  *    notice, this list of conditions and the following disclaimer.
10*029c02a3SIlya Bakulin  * 2. Redistributions in binary form must reproduce the above copyright
11*029c02a3SIlya Bakulin  *    notice, this list of conditions and the following disclaimer in the
12*029c02a3SIlya Bakulin  *    documentation and/or other materials provided with the distribution.
13*029c02a3SIlya Bakulin  *
14*029c02a3SIlya Bakulin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*029c02a3SIlya Bakulin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*029c02a3SIlya Bakulin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*029c02a3SIlya Bakulin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*029c02a3SIlya Bakulin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*029c02a3SIlya Bakulin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*029c02a3SIlya Bakulin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*029c02a3SIlya Bakulin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*029c02a3SIlya Bakulin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*029c02a3SIlya Bakulin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*029c02a3SIlya Bakulin  * SUCH DAMAGE.
25*029c02a3SIlya Bakulin  */
26*029c02a3SIlya Bakulin 
27*029c02a3SIlya Bakulin #include <sys/cdefs.h>
28*029c02a3SIlya Bakulin #include "cam_sdio.h"
29*029c02a3SIlya Bakulin 
30*029c02a3SIlya Bakulin /* Use CMD52 to read or write a single byte */
31*029c02a3SIlya Bakulin 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*029c02a3SIlya Bakulin sdio_rw_direct(struct cam_device *dev,
33*029c02a3SIlya Bakulin 	       uint8_t func_number,
34*029c02a3SIlya Bakulin 	       uint32_t addr,
35*029c02a3SIlya Bakulin 	       uint8_t is_write,
36*029c02a3SIlya Bakulin 	       uint8_t *data, uint8_t *resp) {
37*029c02a3SIlya Bakulin 	union ccb *ccb;
38*029c02a3SIlya Bakulin 	uint32_t flags;
39*029c02a3SIlya Bakulin 	uint32_t arg;
40*029c02a3SIlya Bakulin 	int retval = 0;
41*029c02a3SIlya Bakulin 
42*029c02a3SIlya Bakulin 	ccb = cam_getccb(dev);
43*029c02a3SIlya Bakulin 	if (ccb == NULL) {
44*029c02a3SIlya Bakulin 		warnx("%s: error allocating CCB", __func__);
45*029c02a3SIlya Bakulin 		return (-1);
46*029c02a3SIlya Bakulin 	}
47*029c02a3SIlya Bakulin 	bzero(&(&ccb->ccb_h)[1],
48*029c02a3SIlya Bakulin 	      sizeof(union ccb) - sizeof(struct ccb_hdr));
49*029c02a3SIlya Bakulin 
50*029c02a3SIlya Bakulin 	flags = MMC_RSP_R5 | MMC_CMD_AC;
51*029c02a3SIlya Bakulin 	arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr);
52*029c02a3SIlya Bakulin 	if (is_write)
53*029c02a3SIlya Bakulin 		arg |= SD_IO_RW_WR | SD_IO_RW_RAW | SD_IO_RW_DAT(*data);
54*029c02a3SIlya Bakulin 
55*029c02a3SIlya Bakulin 	cam_fill_mmcio(&ccb->mmcio,
56*029c02a3SIlya Bakulin 		       /*retries*/ 0,
57*029c02a3SIlya Bakulin 		       /*cbfcnp*/ NULL,
58*029c02a3SIlya Bakulin 		       /*flags*/ CAM_DIR_NONE,
59*029c02a3SIlya Bakulin 		       /*mmc_opcode*/ SD_IO_RW_DIRECT,
60*029c02a3SIlya Bakulin 		       /*mmc_arg*/ arg,
61*029c02a3SIlya Bakulin 		       /*mmc_flags*/ flags,
62*029c02a3SIlya Bakulin 		       /*mmc_data*/ 0,
63*029c02a3SIlya Bakulin 		       /*timeout*/ 5000);
64*029c02a3SIlya Bakulin 
65*029c02a3SIlya Bakulin 	if (((retval = cam_send_ccb(dev, ccb)) < 0)
66*029c02a3SIlya Bakulin 	    || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
67*029c02a3SIlya Bakulin 		const char warnstr[] = "error sending command";
68*029c02a3SIlya Bakulin 
69*029c02a3SIlya Bakulin 		if (retval < 0)
70*029c02a3SIlya Bakulin 			warn(warnstr);
71*029c02a3SIlya Bakulin 		else
72*029c02a3SIlya Bakulin 			warnx(warnstr);
73*029c02a3SIlya Bakulin 		return (-1);
74*029c02a3SIlya Bakulin 	}
75*029c02a3SIlya Bakulin 
76*029c02a3SIlya Bakulin 	*resp = ccb->mmcio.cmd.resp[0] & 0xFF;
77*029c02a3SIlya Bakulin 	cam_freeccb(ccb);
78*029c02a3SIlya Bakulin 	return (retval);
79*029c02a3SIlya Bakulin }
80*029c02a3SIlya Bakulin 
81*029c02a3SIlya Bakulin /*
82*029c02a3SIlya Bakulin  * CMD53 -- IO_RW_EXTENDED
83*029c02a3SIlya Bakulin  * Use to read or write memory blocks
84*029c02a3SIlya Bakulin  *
85*029c02a3SIlya Bakulin  * is_increment=1: FIFO mode
86*029c02a3SIlya Bakulin  * blk_count > 0: block mode
87*029c02a3SIlya Bakulin  */
88*029c02a3SIlya Bakulin 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*029c02a3SIlya Bakulin sdio_rw_extended(struct cam_device *dev,
90*029c02a3SIlya Bakulin 		 uint8_t func_number,
91*029c02a3SIlya Bakulin 		 uint32_t addr,
92*029c02a3SIlya Bakulin 		 uint8_t is_write,
93*029c02a3SIlya Bakulin 		 caddr_t data, size_t datalen,
94*029c02a3SIlya Bakulin 		 uint8_t is_increment,
95*029c02a3SIlya Bakulin 		 uint16_t blk_count) {
96*029c02a3SIlya Bakulin 	union ccb *ccb;
97*029c02a3SIlya Bakulin 	uint32_t flags;
98*029c02a3SIlya Bakulin 	uint32_t arg;
99*029c02a3SIlya Bakulin 	uint32_t cam_flags;
100*029c02a3SIlya Bakulin 	uint8_t resp;
101*029c02a3SIlya Bakulin 	struct mmc_data mmcd;
102*029c02a3SIlya Bakulin 	int retval = 0;
103*029c02a3SIlya Bakulin 
104*029c02a3SIlya Bakulin 	if (blk_count != 0) {
105*029c02a3SIlya Bakulin 		warnx("%s: block mode is not supported yet", __func__);
106*029c02a3SIlya Bakulin 		return (-1);
107*029c02a3SIlya Bakulin 	}
108*029c02a3SIlya Bakulin 
109*029c02a3SIlya Bakulin 	ccb = cam_getccb(dev);
110*029c02a3SIlya Bakulin 	if (ccb == NULL) {
111*029c02a3SIlya Bakulin 		warnx("%s: error allocating CCB", __func__);
112*029c02a3SIlya Bakulin 		return (-1);
113*029c02a3SIlya Bakulin 	}
114*029c02a3SIlya Bakulin 	bzero(&(&ccb->ccb_h)[1],
115*029c02a3SIlya Bakulin 	      sizeof(union ccb) - sizeof(struct ccb_hdr));
116*029c02a3SIlya Bakulin 
117*029c02a3SIlya Bakulin 	flags = MMC_RSP_R5 | MMC_CMD_ADTC;
118*029c02a3SIlya Bakulin 	arg = SD_IO_RW_FUNC(func_number) | SD_IO_RW_ADR(addr) |
119*029c02a3SIlya Bakulin 		SD_IOE_RW_LEN(datalen);
120*029c02a3SIlya Bakulin 
121*029c02a3SIlya Bakulin 	if (is_increment)
122*029c02a3SIlya Bakulin 		arg |= SD_IO_RW_INCR;
123*029c02a3SIlya Bakulin 
124*029c02a3SIlya Bakulin 	mmcd.data = data;
125*029c02a3SIlya Bakulin 	mmcd.len = datalen;
126*029c02a3SIlya Bakulin 	mmcd.xfer_len = 0; /* not used by MMCCAM */
127*029c02a3SIlya Bakulin 	mmcd.mrq = NULL; /* not used by MMCCAM */
128*029c02a3SIlya Bakulin 
129*029c02a3SIlya Bakulin 	if (is_write) {
130*029c02a3SIlya Bakulin 		arg |= SD_IO_RW_WR;
131*029c02a3SIlya Bakulin 		cam_flags = CAM_DIR_OUT;
132*029c02a3SIlya Bakulin 		mmcd.flags = MMC_DATA_WRITE;
133*029c02a3SIlya Bakulin 	} else {
134*029c02a3SIlya Bakulin 		cam_flags = CAM_DIR_IN;
135*029c02a3SIlya Bakulin 		mmcd.flags = MMC_DATA_READ;
136*029c02a3SIlya Bakulin 	}
137*029c02a3SIlya Bakulin 	cam_fill_mmcio(&ccb->mmcio,
138*029c02a3SIlya Bakulin 		       /*retries*/ 0,
139*029c02a3SIlya Bakulin 		       /*cbfcnp*/ NULL,
140*029c02a3SIlya Bakulin 		       /*flags*/ cam_flags,
141*029c02a3SIlya Bakulin 		       /*mmc_opcode*/ SD_IO_RW_EXTENDED,
142*029c02a3SIlya Bakulin 		       /*mmc_arg*/ arg,
143*029c02a3SIlya Bakulin 		       /*mmc_flags*/ flags,
144*029c02a3SIlya Bakulin 		       /*mmc_data*/ &mmcd,
145*029c02a3SIlya Bakulin 		       /*timeout*/ 5000);
146*029c02a3SIlya Bakulin 
147*029c02a3SIlya Bakulin 	if (((retval = cam_send_ccb(dev, ccb)) < 0)
148*029c02a3SIlya Bakulin 	    || ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP)) {
149*029c02a3SIlya Bakulin 		const char warnstr[] = "error sending command";
150*029c02a3SIlya Bakulin 
151*029c02a3SIlya Bakulin 		if (retval < 0)
152*029c02a3SIlya Bakulin 			warn(warnstr);
153*029c02a3SIlya Bakulin 		else
154*029c02a3SIlya Bakulin 			warnx(warnstr);
155*029c02a3SIlya Bakulin 		return (-1);
156*029c02a3SIlya Bakulin 	}
157*029c02a3SIlya Bakulin 
158*029c02a3SIlya Bakulin 	resp = ccb->mmcio.cmd.resp[0] & 0xFF;
159*029c02a3SIlya Bakulin 	if (resp != 0)
160*029c02a3SIlya Bakulin 		warn("Response from CMD53 is not 0?!");
161*029c02a3SIlya Bakulin 	cam_freeccb(ccb);
162*029c02a3SIlya Bakulin 	return (retval);
163*029c02a3SIlya Bakulin }
164*029c02a3SIlya Bakulin 
165*029c02a3SIlya Bakulin 
166*029c02a3SIlya Bakulin int
sdio_read_bool_for_func(struct cam_device * dev,uint32_t addr,uint8_t func_number,uint8_t * is_enab)167*029c02a3SIlya Bakulin sdio_read_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, uint8_t *is_enab) {
168*029c02a3SIlya Bakulin 	uint8_t resp;
169*029c02a3SIlya Bakulin 	int ret;
170*029c02a3SIlya Bakulin 
171*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
172*029c02a3SIlya Bakulin 	if (ret < 0)
173*029c02a3SIlya Bakulin 		return ret;
174*029c02a3SIlya Bakulin 
175*029c02a3SIlya Bakulin 	*is_enab = (resp & (1 << func_number)) > 0 ? 1 : 0;
176*029c02a3SIlya Bakulin 
177*029c02a3SIlya Bakulin 	return (0);
178*029c02a3SIlya Bakulin }
179*029c02a3SIlya Bakulin 
180*029c02a3SIlya Bakulin int
sdio_set_bool_for_func(struct cam_device * dev,uint32_t addr,uint8_t func_number,int enable)181*029c02a3SIlya Bakulin sdio_set_bool_for_func(struct cam_device *dev, uint32_t addr, uint8_t func_number, int enable) {
182*029c02a3SIlya Bakulin 	uint8_t resp;
183*029c02a3SIlya Bakulin 	int ret;
184*029c02a3SIlya Bakulin 	uint8_t is_enabled;
185*029c02a3SIlya Bakulin 
186*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, addr, 0, NULL, &resp);
187*029c02a3SIlya Bakulin 	if (ret != 0)
188*029c02a3SIlya Bakulin 		return ret;
189*029c02a3SIlya Bakulin 
190*029c02a3SIlya Bakulin 	is_enabled = resp & (1 << func_number);
191*029c02a3SIlya Bakulin 	if ((is_enabled !=0 && enable == 1) || (is_enabled == 0 && enable == 0))
192*029c02a3SIlya Bakulin 		return 0;
193*029c02a3SIlya Bakulin 
194*029c02a3SIlya Bakulin 	if (enable)
195*029c02a3SIlya Bakulin 		resp |= 1 << func_number;
196*029c02a3SIlya Bakulin 	else
197*029c02a3SIlya Bakulin 		resp &= ~ (1 << func_number);
198*029c02a3SIlya Bakulin 
199*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, addr, 1, &resp, &resp);
200*029c02a3SIlya Bakulin 
201*029c02a3SIlya Bakulin 	return ret;
202*029c02a3SIlya Bakulin }
203*029c02a3SIlya Bakulin 
204*029c02a3SIlya Bakulin /* Conventional I/O functions */
205*029c02a3SIlya Bakulin uint8_t
sdio_read_1(struct cam_device * dev,uint8_t func_number,uint32_t addr,int * ret)206*029c02a3SIlya Bakulin sdio_read_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
207*029c02a3SIlya Bakulin 	uint8_t val;
208*029c02a3SIlya Bakulin 	*ret = sdio_rw_direct(dev, func_number, addr, 0, NULL, &val);
209*029c02a3SIlya Bakulin 	return val;
210*029c02a3SIlya Bakulin }
211*029c02a3SIlya Bakulin 
212*029c02a3SIlya Bakulin int
sdio_write_1(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint8_t val)213*029c02a3SIlya Bakulin sdio_write_1(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint8_t val) {
214*029c02a3SIlya Bakulin 	uint8_t _val;
215*029c02a3SIlya Bakulin 	return sdio_rw_direct(dev, func_number, addr, 0, &val, &_val);
216*029c02a3SIlya Bakulin }
217*029c02a3SIlya Bakulin 
218*029c02a3SIlya Bakulin uint16_t
sdio_read_2(struct cam_device * dev,uint8_t func_number,uint32_t addr,int * ret)219*029c02a3SIlya Bakulin sdio_read_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
220*029c02a3SIlya Bakulin 	uint16_t val;
221*029c02a3SIlya Bakulin 	*ret = sdio_rw_extended(dev, func_number, addr,
222*029c02a3SIlya Bakulin 				/* is_write */ 0,
223*029c02a3SIlya Bakulin 				/* data */ (caddr_t) &val,
224*029c02a3SIlya Bakulin 				/* datalen */ sizeof(val),
225*029c02a3SIlya Bakulin 				/* is_increment */ 1,
226*029c02a3SIlya Bakulin 				/* blk_count */ 0
227*029c02a3SIlya Bakulin 		);
228*029c02a3SIlya Bakulin 	return val;
229*029c02a3SIlya Bakulin }
230*029c02a3SIlya Bakulin 
231*029c02a3SIlya Bakulin 
232*029c02a3SIlya Bakulin int
sdio_write_2(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint16_t val)233*029c02a3SIlya Bakulin sdio_write_2(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint16_t val) {
234*029c02a3SIlya Bakulin 	return sdio_rw_extended(dev, func_number, addr,
235*029c02a3SIlya Bakulin 				/* is_write */ 1,
236*029c02a3SIlya Bakulin 				/* data */ (caddr_t) &val,
237*029c02a3SIlya Bakulin 				/* datalen */ sizeof(val),
238*029c02a3SIlya Bakulin 				/* is_increment */ 1,
239*029c02a3SIlya Bakulin 				/* blk_count */ 0
240*029c02a3SIlya Bakulin 		);
241*029c02a3SIlya Bakulin }
242*029c02a3SIlya Bakulin 
243*029c02a3SIlya Bakulin uint32_t
sdio_read_4(struct cam_device * dev,uint8_t func_number,uint32_t addr,int * ret)244*029c02a3SIlya Bakulin sdio_read_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, int *ret) {
245*029c02a3SIlya Bakulin 	uint32_t val;
246*029c02a3SIlya Bakulin 	*ret = sdio_rw_extended(dev, func_number, addr,
247*029c02a3SIlya Bakulin 				/* is_write */ 0,
248*029c02a3SIlya Bakulin 				/* data */ (caddr_t) &val,
249*029c02a3SIlya Bakulin 				/* datalen */ sizeof(val),
250*029c02a3SIlya Bakulin 				/* is_increment */ 1,
251*029c02a3SIlya Bakulin 				/* blk_count */ 0
252*029c02a3SIlya Bakulin 		);
253*029c02a3SIlya Bakulin 	return val;
254*029c02a3SIlya Bakulin }
255*029c02a3SIlya Bakulin 
256*029c02a3SIlya Bakulin 
257*029c02a3SIlya Bakulin int
sdio_write_4(struct cam_device * dev,uint8_t func_number,uint32_t addr,uint32_t val)258*029c02a3SIlya Bakulin sdio_write_4(struct cam_device *dev, uint8_t func_number, uint32_t addr, uint32_t val) {
259*029c02a3SIlya Bakulin 	return sdio_rw_extended(dev, func_number, addr,
260*029c02a3SIlya Bakulin 				/* is_write */ 1,
261*029c02a3SIlya Bakulin 				/* data */ (caddr_t) &val,
262*029c02a3SIlya Bakulin 				/* datalen */ sizeof(val),
263*029c02a3SIlya Bakulin 				/* is_increment */ 1,
264*029c02a3SIlya Bakulin 				/* blk_count */ 0
265*029c02a3SIlya Bakulin 		);
266*029c02a3SIlya Bakulin }
267*029c02a3SIlya Bakulin 
268*029c02a3SIlya Bakulin /* Higher-level wrappers for certain management operations */
269*029c02a3SIlya Bakulin int
sdio_is_func_ready(struct cam_device * dev,uint8_t func_number,uint8_t * is_enab)270*029c02a3SIlya Bakulin sdio_is_func_ready(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
271*029c02a3SIlya Bakulin 	return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_READY, func_number, is_enab);
272*029c02a3SIlya Bakulin }
273*029c02a3SIlya Bakulin 
274*029c02a3SIlya Bakulin int
sdio_is_func_enabled(struct cam_device * dev,uint8_t func_number,uint8_t * is_enab)275*029c02a3SIlya Bakulin sdio_is_func_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
276*029c02a3SIlya Bakulin 	return sdio_read_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, is_enab);
277*029c02a3SIlya Bakulin }
278*029c02a3SIlya Bakulin 
279*029c02a3SIlya Bakulin int
sdio_func_enable(struct cam_device * dev,uint8_t func_number,int enable)280*029c02a3SIlya Bakulin sdio_func_enable(struct cam_device *dev, uint8_t func_number, int enable) {
281*029c02a3SIlya Bakulin 	return sdio_set_bool_for_func(dev, SD_IO_CCCR_FN_ENABLE, func_number, enable);
282*029c02a3SIlya Bakulin }
283*029c02a3SIlya Bakulin 
284*029c02a3SIlya Bakulin int
sdio_is_func_intr_enabled(struct cam_device * dev,uint8_t func_number,uint8_t * is_enab)285*029c02a3SIlya Bakulin sdio_is_func_intr_enabled(struct cam_device *dev, uint8_t func_number, uint8_t *is_enab) {
286*029c02a3SIlya Bakulin 	return sdio_read_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, is_enab);
287*029c02a3SIlya Bakulin }
288*029c02a3SIlya Bakulin 
289*029c02a3SIlya Bakulin int
sdio_func_intr_enable(struct cam_device * dev,uint8_t func_number,int enable)290*029c02a3SIlya Bakulin sdio_func_intr_enable(struct cam_device *dev, uint8_t func_number, int enable) {
291*029c02a3SIlya Bakulin 	return sdio_set_bool_for_func(dev, SD_IO_CCCR_INT_ENABLE, func_number, enable);
292*029c02a3SIlya Bakulin }
293*029c02a3SIlya Bakulin 
294*029c02a3SIlya Bakulin int
sdio_card_set_bus_width(struct cam_device * dev,enum mmc_bus_width bw)295*029c02a3SIlya Bakulin sdio_card_set_bus_width(struct cam_device *dev, enum mmc_bus_width bw) {
296*029c02a3SIlya Bakulin 	int ret;
297*029c02a3SIlya Bakulin 	uint8_t ctl_val;
298*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 0, NULL, &ctl_val);
299*029c02a3SIlya Bakulin 	if (ret < 0) {
300*029c02a3SIlya Bakulin 		warn("Error getting CCCR_BUS_WIDTH value");
301*029c02a3SIlya Bakulin 		return ret;
302*029c02a3SIlya Bakulin 	}
303*029c02a3SIlya Bakulin 	ctl_val &= ~0x3;
304*029c02a3SIlya Bakulin 	switch (bw) {
305*029c02a3SIlya Bakulin 	case bus_width_1:
306*029c02a3SIlya Bakulin 		/* Already set to 1-bit */
307*029c02a3SIlya Bakulin 		break;
308*029c02a3SIlya Bakulin 	case bus_width_4:
309*029c02a3SIlya Bakulin 		ctl_val |= CCCR_BUS_WIDTH_4;
310*029c02a3SIlya Bakulin 		break;
311*029c02a3SIlya Bakulin 	case bus_width_8:
312*029c02a3SIlya Bakulin 		warn("Cannot do 8-bit on SDIO yet");
313*029c02a3SIlya Bakulin 		return -1;
314*029c02a3SIlya Bakulin 		break;
315*029c02a3SIlya Bakulin 	}
316*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_BUS_WIDTH, 1, &ctl_val, &ctl_val);
317*029c02a3SIlya Bakulin 	if (ret < 0) {
318*029c02a3SIlya Bakulin 		warn("Error setting CCCR_BUS_WIDTH value");
319*029c02a3SIlya Bakulin 		return ret;
320*029c02a3SIlya Bakulin 	}
321*029c02a3SIlya Bakulin 	return ret;
322*029c02a3SIlya Bakulin }
323*029c02a3SIlya Bakulin 
324*029c02a3SIlya Bakulin int
sdio_func_read_cis(struct cam_device * dev,uint8_t func_number,uint32_t cis_addr,struct cis_info * info)325*029c02a3SIlya Bakulin sdio_func_read_cis(struct cam_device *dev, uint8_t func_number,
326*029c02a3SIlya Bakulin 		   uint32_t cis_addr, struct cis_info *info) {
327*029c02a3SIlya Bakulin 	uint8_t tuple_id, tuple_len, tuple_count;
328*029c02a3SIlya Bakulin 	uint32_t addr;
329*029c02a3SIlya Bakulin 
330*029c02a3SIlya Bakulin 	char *cis1_info[4];
331*029c02a3SIlya Bakulin 	int start, i, ch, count, ret;
332*029c02a3SIlya Bakulin 	char cis1_info_buf[256];
333*029c02a3SIlya Bakulin 
334*029c02a3SIlya Bakulin 	tuple_count = 0; /* Use to prevent infinite loop in case of parse errors */
335*029c02a3SIlya Bakulin 	memset(cis1_info_buf, 0, 256);
336*029c02a3SIlya Bakulin 	do {
337*029c02a3SIlya Bakulin 		addr = cis_addr;
338*029c02a3SIlya Bakulin 		tuple_id = sdio_read_1(dev, 0, addr++, &ret);
339*029c02a3SIlya Bakulin 		if (tuple_id == SD_IO_CISTPL_END)
340*029c02a3SIlya Bakulin 			break;
341*029c02a3SIlya Bakulin 		if (tuple_id == 0) {
342*029c02a3SIlya Bakulin 			cis_addr++;
343*029c02a3SIlya Bakulin 			continue;
344*029c02a3SIlya Bakulin 		}
345*029c02a3SIlya Bakulin 		tuple_len = sdio_read_1(dev, 0, addr++, &ret);
346*029c02a3SIlya Bakulin 		if (tuple_len == 0 && tuple_id != 0x00) {
347*029c02a3SIlya Bakulin 			warn("Parse error: 0-length tuple %02X\n", tuple_id);
348*029c02a3SIlya Bakulin 			return -1;
349*029c02a3SIlya Bakulin 		}
350*029c02a3SIlya Bakulin 
351*029c02a3SIlya Bakulin 		switch (tuple_id) {
352*029c02a3SIlya Bakulin 		case SD_IO_CISTPL_VERS_1:
353*029c02a3SIlya Bakulin 			addr += 2;
354*029c02a3SIlya Bakulin 			for (count = 0, start = 0, i = 0;
355*029c02a3SIlya Bakulin 			     (count < 4) && ((i + 4) < 256); i++) {
356*029c02a3SIlya Bakulin 				ch = sdio_read_1(dev, 0, addr + i, &ret);
357*029c02a3SIlya Bakulin 				printf("count=%d, start=%d, i=%d, Got %c (0x%02x)\n", count, start, i, ch, ch);
358*029c02a3SIlya Bakulin 				if (ch == 0xff)
359*029c02a3SIlya Bakulin 					break;
360*029c02a3SIlya Bakulin 				cis1_info_buf[i] = ch;
361*029c02a3SIlya Bakulin 				if (ch == 0) {
362*029c02a3SIlya Bakulin 					cis1_info[count] =
363*029c02a3SIlya Bakulin 						cis1_info_buf + start;
364*029c02a3SIlya Bakulin 					start = i + 1;
365*029c02a3SIlya Bakulin 					count++;
366*029c02a3SIlya Bakulin 				}
367*029c02a3SIlya Bakulin 			}
368*029c02a3SIlya Bakulin 			printf("Card info:");
369*029c02a3SIlya Bakulin 			for (i=0; i<4; i++)
370*029c02a3SIlya Bakulin 				if (cis1_info[i])
371*029c02a3SIlya Bakulin 					printf(" %s", cis1_info[i]);
372*029c02a3SIlya Bakulin 			printf("\n");
373*029c02a3SIlya Bakulin 			break;
374*029c02a3SIlya Bakulin 		case SD_IO_CISTPL_MANFID:
375*029c02a3SIlya Bakulin 			info->man_id =  sdio_read_1(dev, 0, addr++, &ret);
376*029c02a3SIlya Bakulin 			info->man_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
377*029c02a3SIlya Bakulin 
378*029c02a3SIlya Bakulin 			info->prod_id =  sdio_read_1(dev, 0, addr++, &ret);
379*029c02a3SIlya Bakulin 			info->prod_id |= sdio_read_1(dev, 0, addr++, &ret) << 8;
380*029c02a3SIlya Bakulin 			break;
381*029c02a3SIlya Bakulin 		case SD_IO_CISTPL_FUNCID:
382*029c02a3SIlya Bakulin 			/* not sure if we need to parse it? */
383*029c02a3SIlya Bakulin 			break;
384*029c02a3SIlya Bakulin 		case SD_IO_CISTPL_FUNCE:
385*029c02a3SIlya Bakulin 			if (tuple_len < 4) {
386*029c02a3SIlya Bakulin 				printf("FUNCE is too short: %d\n", tuple_len);
387*029c02a3SIlya Bakulin 				break;
388*029c02a3SIlya Bakulin 			}
389*029c02a3SIlya Bakulin 			if (func_number == 0) {
390*029c02a3SIlya Bakulin 				/* skip extended_data */
391*029c02a3SIlya Bakulin 				addr++;
392*029c02a3SIlya Bakulin 				info->max_block_size  = sdio_read_1(dev, 0, addr++, &ret);
393*029c02a3SIlya Bakulin 				info->max_block_size |= sdio_read_1(dev, 0, addr++, &ret) << 8;
394*029c02a3SIlya Bakulin 			} else {
395*029c02a3SIlya Bakulin 				info->max_block_size  = sdio_read_1(dev, 0, addr + 0xC, &ret);
396*029c02a3SIlya Bakulin 				info->max_block_size |= sdio_read_1(dev, 0, addr + 0xD, &ret) << 8;
397*029c02a3SIlya Bakulin 			}
398*029c02a3SIlya Bakulin 			break;
399*029c02a3SIlya Bakulin 		default:
400*029c02a3SIlya Bakulin 			warnx("Skipping tuple ID %02X len %02X\n", tuple_id, tuple_len);
401*029c02a3SIlya Bakulin 		}
402*029c02a3SIlya Bakulin 		cis_addr += tuple_len + 2;
403*029c02a3SIlya Bakulin 		tuple_count++;
404*029c02a3SIlya Bakulin 	} while (tuple_count < 20);
405*029c02a3SIlya Bakulin 
406*029c02a3SIlya Bakulin 	return 0;
407*029c02a3SIlya Bakulin }
408*029c02a3SIlya Bakulin 
409*029c02a3SIlya Bakulin uint32_t
sdio_get_common_cis_addr(struct cam_device * dev)410*029c02a3SIlya Bakulin sdio_get_common_cis_addr(struct cam_device *dev) {
411*029c02a3SIlya Bakulin 	uint32_t addr;
412*029c02a3SIlya Bakulin 	int ret;
413*029c02a3SIlya Bakulin 
414*029c02a3SIlya Bakulin 	addr =  sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR, &ret);
415*029c02a3SIlya Bakulin 	addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 1, &ret) << 8;
416*029c02a3SIlya Bakulin 	addr |= sdio_read_1(dev, 0, SD_IO_CCCR_CISPTR + 2, &ret) << 16;
417*029c02a3SIlya Bakulin 
418*029c02a3SIlya Bakulin 	if (addr < SD_IO_CIS_START || addr > SD_IO_CIS_START + SD_IO_CIS_SIZE) {
419*029c02a3SIlya Bakulin 		warn("Bad CIS address: %04X\n", addr);
420*029c02a3SIlya Bakulin 		addr = 0;
421*029c02a3SIlya Bakulin 	}
422*029c02a3SIlya Bakulin 
423*029c02a3SIlya Bakulin 	return addr;
424*029c02a3SIlya Bakulin }
425*029c02a3SIlya Bakulin 
sdio_card_reset(struct cam_device * dev)426*029c02a3SIlya Bakulin void sdio_card_reset(struct cam_device *dev) {
427*029c02a3SIlya Bakulin 	int ret;
428*029c02a3SIlya Bakulin 	uint8_t ctl_val;
429*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 0, NULL, &ctl_val);
430*029c02a3SIlya Bakulin 	if (ret < 0)
431*029c02a3SIlya Bakulin 		errx(1, "Error getting CCCR_CTL value");
432*029c02a3SIlya Bakulin 	ctl_val |= CCCR_CTL_RES;
433*029c02a3SIlya Bakulin 	ret = sdio_rw_direct(dev, 0, SD_IO_CCCR_CTL, 1, &ctl_val, &ctl_val);
434*029c02a3SIlya Bakulin 	if (ret < 0)
435*029c02a3SIlya Bakulin 		errx(1, "Error setting CCCR_CTL value");
436*029c02a3SIlya Bakulin }
437