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