1*4bb7efa7SGarrett D'Amore /*
2*4bb7efa7SGarrett D'Amore  * CDDL HEADER START
3*4bb7efa7SGarrett D'Amore  *
4*4bb7efa7SGarrett D'Amore  * The contents of this file are subject to the terms of the
5*4bb7efa7SGarrett D'Amore  * Common Development and Distribution License (the "License").
6*4bb7efa7SGarrett D'Amore  * You may not use this file except in compliance with the License.
7*4bb7efa7SGarrett D'Amore  *
8*4bb7efa7SGarrett D'Amore  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4bb7efa7SGarrett D'Amore  * or http://www.opensolaris.org/os/licensing.
10*4bb7efa7SGarrett D'Amore  * See the License for the specific language governing permissions
11*4bb7efa7SGarrett D'Amore  * and limitations under the License.
12*4bb7efa7SGarrett D'Amore  *
13*4bb7efa7SGarrett D'Amore  * When distributing Covered Code, include this CDDL HEADER in each
14*4bb7efa7SGarrett D'Amore  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4bb7efa7SGarrett D'Amore  * If applicable, add the following below this CDDL HEADER, with the
16*4bb7efa7SGarrett D'Amore  * fields enclosed by brackets "[]" replaced with your own identifying
17*4bb7efa7SGarrett D'Amore  * information: Portions Copyright [yyyy] [name of copyright owner]
18*4bb7efa7SGarrett D'Amore  *
19*4bb7efa7SGarrett D'Amore  * CDDL HEADER END
20*4bb7efa7SGarrett D'Amore  */
21*4bb7efa7SGarrett D'Amore /*
22*4bb7efa7SGarrett D'Amore  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*4bb7efa7SGarrett D'Amore  * Use is subject to license terms.
24*4bb7efa7SGarrett D'Amore  */
25*4bb7efa7SGarrett D'Amore 
26*4bb7efa7SGarrett D'Amore /*
27*4bb7efa7SGarrett D'Amore  * SD card initialization support.
28*4bb7efa7SGarrett D'Amore  */
29*4bb7efa7SGarrett D'Amore 
30*4bb7efa7SGarrett D'Amore #include <sys/types.h>
31*4bb7efa7SGarrett D'Amore #include <sys/ddi.h>
32*4bb7efa7SGarrett D'Amore #include <sys/sunddi.h>
33*4bb7efa7SGarrett D'Amore #include <sys/sdcard/sda.h>
34*4bb7efa7SGarrett D'Amore #include <sys/sdcard/sda_impl.h>
35*4bb7efa7SGarrett D'Amore 
36*4bb7efa7SGarrett D'Amore 
37*4bb7efa7SGarrett D'Amore /*
38*4bb7efa7SGarrett D'Amore  * Local Prototypes.
39*4bb7efa7SGarrett D'Amore  */
40*4bb7efa7SGarrett D'Amore 
41*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_mmc(sda_slot_t *);
42*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_sdio(sda_slot_t *);
43*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_sdmem(sda_slot_t *);
44*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_cmd(sda_slot_t *, sda_index_t, uint32_t,
45*4bb7efa7SGarrett D'Amore     sda_rtype_t, uint32_t *);
46*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_acmd(sda_slot_t *, sda_index_t, uint32_t,
47*4bb7efa7SGarrett D'Amore     sda_rtype_t, uint32_t *);
48*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_blocklen(sda_slot_t *);
49*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_width(sda_slot_t *);
50*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_rca(sda_slot_t *);
51*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_ifcond(sda_slot_t *);
52*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_highspeed(sda_slot_t *);
53*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_switch(sda_slot_t *, uint8_t, uint8_t, uint8_t,
54*4bb7efa7SGarrett D'Amore     uint8_t *);
55*4bb7efa7SGarrett D'Amore static void sda_init_clock(sda_slot_t *, uint32_t);
56*4bb7efa7SGarrett D'Amore 
57*4bb7efa7SGarrett D'Amore /*
58*4bb7efa7SGarrett D'Amore  * Implementation.
59*4bb7efa7SGarrett D'Amore  */
60*4bb7efa7SGarrett D'Amore sda_err_t
61*4bb7efa7SGarrett D'Amore sda_init_cmd(sda_slot_t *slot, sda_index_t cmd, uint32_t arg,
62*4bb7efa7SGarrett D'Amore     sda_rtype_t rtype, uint32_t *resp)
63*4bb7efa7SGarrett D'Amore {
64*4bb7efa7SGarrett D'Amore 	sda_cmd_t	*cmdp;
65*4bb7efa7SGarrett D'Amore 	sda_err_t	errno;
66*4bb7efa7SGarrett D'Amore 
67*4bb7efa7SGarrett D'Amore 	cmdp = sda_cmd_alloc(slot, cmd, arg, rtype, NULL, KM_SLEEP);
68*4bb7efa7SGarrett D'Amore 
69*4bb7efa7SGarrett D'Amore 	cmdp->sc_flags |= SDA_CMDF_INIT;
70*4bb7efa7SGarrett D'Amore 
71*4bb7efa7SGarrett D'Amore 	errno = sda_cmd_exec(slot, cmdp, resp);
72*4bb7efa7SGarrett D'Amore 
73*4bb7efa7SGarrett D'Amore 	sda_cmd_free(cmdp);
74*4bb7efa7SGarrett D'Amore 
75*4bb7efa7SGarrett D'Amore 	return (errno);
76*4bb7efa7SGarrett D'Amore }
77*4bb7efa7SGarrett D'Amore 
78*4bb7efa7SGarrett D'Amore sda_err_t
79*4bb7efa7SGarrett D'Amore sda_init_acmd(sda_slot_t *slot, sda_index_t cmd, uint32_t arg,
80*4bb7efa7SGarrett D'Amore     sda_rtype_t rtype, uint32_t *resp)
81*4bb7efa7SGarrett D'Amore {
82*4bb7efa7SGarrett D'Amore 	sda_cmd_t	*cmdp;
83*4bb7efa7SGarrett D'Amore 	sda_err_t	errno;
84*4bb7efa7SGarrett D'Amore 
85*4bb7efa7SGarrett D'Amore 	cmdp = sda_cmd_alloc_acmd(slot, cmd, arg, rtype, NULL, KM_SLEEP);
86*4bb7efa7SGarrett D'Amore 
87*4bb7efa7SGarrett D'Amore 	cmdp->sc_flags |= SDA_CMDF_INIT;
88*4bb7efa7SGarrett D'Amore 
89*4bb7efa7SGarrett D'Amore 	errno = sda_cmd_exec(slot, cmdp, resp);
90*4bb7efa7SGarrett D'Amore 
91*4bb7efa7SGarrett D'Amore 	sda_cmd_free(cmdp);
92*4bb7efa7SGarrett D'Amore 
93*4bb7efa7SGarrett D'Amore 	return (errno);
94*4bb7efa7SGarrett D'Amore }
95*4bb7efa7SGarrett D'Amore 
96*4bb7efa7SGarrett D'Amore sda_err_t
97*4bb7efa7SGarrett D'Amore sda_init_sdio(sda_slot_t *slot)
98*4bb7efa7SGarrett D'Amore {
99*4bb7efa7SGarrett D'Amore 	slot->s_num_io = 0;
100*4bb7efa7SGarrett D'Amore 
101*4bb7efa7SGarrett D'Amore 	/*
102*4bb7efa7SGarrett D'Amore 	 * TODO: SDIO: We need to initialize the SDIO OCR register using
103*4bb7efa7SGarrett D'Amore 	 * the special CMD_IO_SEND_OCR (CMD5) command.
104*4bb7efa7SGarrett D'Amore 	 */
105*4bb7efa7SGarrett D'Amore 	return (SDA_EOK);
106*4bb7efa7SGarrett D'Amore }
107*4bb7efa7SGarrett D'Amore 
108*4bb7efa7SGarrett D'Amore sda_err_t
109*4bb7efa7SGarrett D'Amore sda_init_sdmem(sda_slot_t *slot)
110*4bb7efa7SGarrett D'Amore {
111*4bb7efa7SGarrett D'Amore 	uint32_t	ocr;
112*4bb7efa7SGarrett D'Amore 	int		count;
113*4bb7efa7SGarrett D'Amore 
114*4bb7efa7SGarrett D'Amore 	slot->s_flags &= ~SLOTF_SDMEM;
115*4bb7efa7SGarrett D'Amore 
116*4bb7efa7SGarrett D'Amore 	/*
117*4bb7efa7SGarrett D'Amore 	 * Try sending the ACMD41 to query the OCR (Op Cond Register).
118*4bb7efa7SGarrett D'Amore 	 */
119*4bb7efa7SGarrett D'Amore 	if (sda_init_acmd(slot, ACMD_SD_SEND_OCR, 0, R3, &ocr) != SDA_EOK) {
120*4bb7efa7SGarrett D'Amore 		/*
121*4bb7efa7SGarrett D'Amore 		 * Card failed to respond to query, not an SD card?
122*4bb7efa7SGarrett D'Amore 		 * We send GO_IDLE to clear any error status on the
123*4bb7efa7SGarrett D'Amore 		 * card.
124*4bb7efa7SGarrett D'Amore 		 */
125*4bb7efa7SGarrett D'Amore 		(void) sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL);
126*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
127*4bb7efa7SGarrett D'Amore 	}
128*4bb7efa7SGarrett D'Amore 
129*4bb7efa7SGarrett D'Amore 	/*
130*4bb7efa7SGarrett D'Amore 	 * Now we have to send our OCR value, along with the HCS (High
131*4bb7efa7SGarrett D'Amore 	 * Capacity Support) bit.  The HCS bit is required, to
132*4bb7efa7SGarrett D'Amore 	 * activate high capacity cards.  We only set the HCS bit if
133*4bb7efa7SGarrett D'Amore 	 * the card responded to CMD8 (SEND_IFCOND), indicating that
134*4bb7efa7SGarrett D'Amore 	 * it supports the new protocol.
135*4bb7efa7SGarrett D'Amore 	 *
136*4bb7efa7SGarrett D'Amore 	 * Note that the HCS bit occupies the same location as the CCS bit
137*4bb7efa7SGarrett D'Amore 	 * in the response.
138*4bb7efa7SGarrett D'Amore 	 */
139*4bb7efa7SGarrett D'Amore 	if ((ocr & slot->s_cur_ocr) == 0) {
140*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "SD card not compatible with host");
141*4bb7efa7SGarrett D'Amore 		return (SDA_ENOTSUP);
142*4bb7efa7SGarrett D'Amore 	}
143*4bb7efa7SGarrett D'Amore 	/* set the HCS bit if its a ver 2.00 card */
144*4bb7efa7SGarrett D'Amore 	if (slot->s_flags & SLOTF_IFCOND) {
145*4bb7efa7SGarrett D'Amore 		ocr |= OCR_CCS;
146*4bb7efa7SGarrett D'Amore 	}
147*4bb7efa7SGarrett D'Amore 
148*4bb7efa7SGarrett D'Amore 	/* make sure card is powered up */
149*4bb7efa7SGarrett D'Amore 	for (count = 1000000; count != 0; count -= 10000) {
150*4bb7efa7SGarrett D'Amore 		uint32_t	r3;
151*4bb7efa7SGarrett D'Amore 
152*4bb7efa7SGarrett D'Amore 		if (sda_init_acmd(slot, ACMD_SD_SEND_OCR, ocr, R3, &r3) != 0) {
153*4bb7efa7SGarrett D'Amore 			sda_slot_err(slot, "SD card failed to power up");
154*4bb7efa7SGarrett D'Amore 			return (SDA_ENOTSUP);
155*4bb7efa7SGarrett D'Amore 		}
156*4bb7efa7SGarrett D'Amore 
157*4bb7efa7SGarrett D'Amore 		/* Now check the busy bit */
158*4bb7efa7SGarrett D'Amore 		if (r3 & OCR_POWER_UP) {
159*4bb7efa7SGarrett D'Amore 			slot->s_flags |= SLOTF_SDMEM;
160*4bb7efa7SGarrett D'Amore 			if ((slot->s_flags & SLOTF_IFCOND) &&
161*4bb7efa7SGarrett D'Amore 			    (r3 & OCR_CCS)) {
162*4bb7efa7SGarrett D'Amore 				slot->s_flags |= SLOTF_SDHC;
163*4bb7efa7SGarrett D'Amore 			} else {
164*4bb7efa7SGarrett D'Amore 				slot->s_flags &= ~SLOTF_SDHC;
165*4bb7efa7SGarrett D'Amore 			}
166*4bb7efa7SGarrett D'Amore 			return (0);
167*4bb7efa7SGarrett D'Amore 		}
168*4bb7efa7SGarrett D'Amore 
169*4bb7efa7SGarrett D'Amore 		drv_usecwait(10000);
170*4bb7efa7SGarrett D'Amore 	}
171*4bb7efa7SGarrett D'Amore 
172*4bb7efa7SGarrett D'Amore 	sda_slot_err(slot, "SD card timed out during power up");
173*4bb7efa7SGarrett D'Amore 	return (SDA_ETIME);
174*4bb7efa7SGarrett D'Amore }
175*4bb7efa7SGarrett D'Amore 
176*4bb7efa7SGarrett D'Amore sda_err_t
177*4bb7efa7SGarrett D'Amore sda_init_mmc(sda_slot_t *slot)
178*4bb7efa7SGarrett D'Amore {
179*4bb7efa7SGarrett D'Amore 	uint32_t	ocr;
180*4bb7efa7SGarrett D'Amore 	int		count;
181*4bb7efa7SGarrett D'Amore 
182*4bb7efa7SGarrett D'Amore 	slot->s_flags &= ~SLOTF_MMC;
183*4bb7efa7SGarrett D'Amore 
184*4bb7efa7SGarrett D'Amore 	/*
185*4bb7efa7SGarrett D'Amore 	 * If the card has already been identified as an SD card, then
186*4bb7efa7SGarrett D'Amore 	 * cannot also be an MMC card, so don't probe it as such.
187*4bb7efa7SGarrett D'Amore 	 */
188*4bb7efa7SGarrett D'Amore 	if (slot->s_flags & SLOTF_SD) {
189*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
190*4bb7efa7SGarrett D'Amore 	}
191*4bb7efa7SGarrett D'Amore 
192*4bb7efa7SGarrett D'Amore 	/*
193*4bb7efa7SGarrett D'Amore 	 * Try sending the CMD1 to query the OCR.
194*4bb7efa7SGarrett D'Amore 	 */
195*4bb7efa7SGarrett D'Amore 	if (sda_init_cmd(slot, CMD_SEND_OCR, 0, R3, &ocr) != 0) {
196*4bb7efa7SGarrett D'Amore 		/*
197*4bb7efa7SGarrett D'Amore 		 * Card failed to respond to query, not an MMC card?
198*4bb7efa7SGarrett D'Amore 		 * We send GO_IDLE to clear any error status on the
199*4bb7efa7SGarrett D'Amore 		 * card.
200*4bb7efa7SGarrett D'Amore 		 */
201*4bb7efa7SGarrett D'Amore 		(void) sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL);
202*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
203*4bb7efa7SGarrett D'Amore 	}
204*4bb7efa7SGarrett D'Amore 
205*4bb7efa7SGarrett D'Amore 	if ((ocr & slot->s_cur_ocr) == 0) {
206*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "MMC card not compatible with host");
207*4bb7efa7SGarrett D'Amore 		return (SDA_ENOTSUP);
208*4bb7efa7SGarrett D'Amore 	}
209*4bb7efa7SGarrett D'Amore 
210*4bb7efa7SGarrett D'Amore 	/* make sure card is powered up */
211*4bb7efa7SGarrett D'Amore 	for (count = 1000000; count != 0; count -= 10000) {
212*4bb7efa7SGarrett D'Amore 		uint32_t	r3;
213*4bb7efa7SGarrett D'Amore 
214*4bb7efa7SGarrett D'Amore 		if (sda_init_cmd(slot, CMD_SEND_OCR, ocr, R3, &r3) != 0) {
215*4bb7efa7SGarrett D'Amore 			sda_slot_err(slot, "MMC card failed to power up");
216*4bb7efa7SGarrett D'Amore 			return (SDA_ENOTSUP);
217*4bb7efa7SGarrett D'Amore 		}
218*4bb7efa7SGarrett D'Amore 
219*4bb7efa7SGarrett D'Amore 		/* Now check the busy bit */
220*4bb7efa7SGarrett D'Amore 		if (r3 & OCR_POWER_UP) {
221*4bb7efa7SGarrett D'Amore 			slot->s_flags |= SLOTF_MMC;
222*4bb7efa7SGarrett D'Amore 			return (SDA_EOK);
223*4bb7efa7SGarrett D'Amore 		}
224*4bb7efa7SGarrett D'Amore 
225*4bb7efa7SGarrett D'Amore 		drv_usecwait(10000);
226*4bb7efa7SGarrett D'Amore 	}
227*4bb7efa7SGarrett D'Amore 
228*4bb7efa7SGarrett D'Amore 	sda_slot_err(slot, "MMC card timed out during power up");
229*4bb7efa7SGarrett D'Amore 	return (SDA_ETIME);
230*4bb7efa7SGarrett D'Amore }
231*4bb7efa7SGarrett D'Amore 
232*4bb7efa7SGarrett D'Amore sda_err_t
233*4bb7efa7SGarrett D'Amore sda_init_card(sda_slot_t *slot)
234*4bb7efa7SGarrett D'Amore {
235*4bb7efa7SGarrett D'Amore 	int		rv;
236*4bb7efa7SGarrett D'Amore 	uint32_t	resp;
237*4bb7efa7SGarrett D'Amore 	uint32_t	val;
238*4bb7efa7SGarrett D'Amore 
239*4bb7efa7SGarrett D'Amore 	/*
240*4bb7efa7SGarrett D'Amore 	 * Power off slot/card initially.
241*4bb7efa7SGarrett D'Amore 	 */
242*4bb7efa7SGarrett D'Amore 	sda_slot_power_off(slot);
243*4bb7efa7SGarrett D'Amore 
244*4bb7efa7SGarrett D'Amore 	/*
245*4bb7efa7SGarrett D'Amore 	 * Apply initial power to the slot.
246*4bb7efa7SGarrett D'Amore 	 */
247*4bb7efa7SGarrett D'Amore 	if ((rv = sda_slot_power_on(slot)) != 0) {
248*4bb7efa7SGarrett D'Amore 		return (rv);
249*4bb7efa7SGarrett D'Amore 	}
250*4bb7efa7SGarrett D'Amore 
251*4bb7efa7SGarrett D'Amore 	/*
252*4bb7efa7SGarrett D'Amore 	 * First enable the clock, but only at 400 kHz.  All cards are
253*4bb7efa7SGarrett D'Amore 	 * supposed to be able to operate between this speed and 100
254*4bb7efa7SGarrett D'Amore 	 * kHz, and all hosts must be able to pick a speed between 100
255*4bb7efa7SGarrett D'Amore 	 * kHz and 400 kHz.
256*4bb7efa7SGarrett D'Amore 	 *
257*4bb7efa7SGarrett D'Amore 	 * Once we know what the device can support, then we speed up.
258*4bb7efa7SGarrett D'Amore 	 */
259*4bb7efa7SGarrett D'Amore 	sda_init_clock(slot, 400000);
260*4bb7efa7SGarrett D'Amore 
261*4bb7efa7SGarrett D'Amore 	if ((rv = sda_init_ifcond(slot)) != SDA_EOK) {
262*4bb7efa7SGarrett D'Amore 		goto done;
263*4bb7efa7SGarrett D'Amore 	}
264*4bb7efa7SGarrett D'Amore 
265*4bb7efa7SGarrett D'Amore 	if (((rv = sda_init_sdio(slot)) != SDA_EOK) ||
266*4bb7efa7SGarrett D'Amore 	    ((rv = sda_init_sdmem(slot)) != SDA_EOK) ||
267*4bb7efa7SGarrett D'Amore 	    ((rv = sda_init_mmc(slot)) != SDA_EOK)) {
268*4bb7efa7SGarrett D'Amore 
269*4bb7efa7SGarrett D'Amore 		/* message will already have been logged */
270*4bb7efa7SGarrett D'Amore 		goto done;
271*4bb7efa7SGarrett D'Amore 	}
272*4bb7efa7SGarrett D'Amore 
273*4bb7efa7SGarrett D'Amore 	if ((slot->s_flags & (SLOTF_MEMORY | SLOTF_SDIO)) == 0) {
274*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Unidentified card type");
275*4bb7efa7SGarrett D'Amore 		rv = SDA_ENOTSUP;
276*4bb7efa7SGarrett D'Amore 		goto done;
277*4bb7efa7SGarrett D'Amore 	}
278*4bb7efa7SGarrett D'Amore 
279*4bb7efa7SGarrett D'Amore 	/*
280*4bb7efa7SGarrett D'Amore 	 * Memory cards need to obtain their CID before getting their RCA.
281*4bb7efa7SGarrett D'Amore 	 * This is a requirement for the state transitions... they go thru
282*4bb7efa7SGarrett D'Amore 	 * the ident state, unlike SDIO cards.
283*4bb7efa7SGarrett D'Amore 	 */
284*4bb7efa7SGarrett D'Amore 	if (slot->s_flags & SLOTF_MEMORY) {
285*4bb7efa7SGarrett D'Amore 		rv = sda_init_cmd(slot, CMD_BCAST_CID, 0, R2, slot->s_rcid);
286*4bb7efa7SGarrett D'Amore 		if (rv != SDA_EOK) {
287*4bb7efa7SGarrett D'Amore 			sda_slot_err(slot, "Failed getting card CID (%d)", rv);
288*4bb7efa7SGarrett D'Amore 			goto done;
289*4bb7efa7SGarrett D'Amore 		}
290*4bb7efa7SGarrett D'Amore 	}
291*4bb7efa7SGarrett D'Amore 
292*4bb7efa7SGarrett D'Amore 	if ((rv = sda_init_rca(slot)) != SDA_EOK) {
293*4bb7efa7SGarrett D'Amore 		goto done;
294*4bb7efa7SGarrett D'Amore 	}
295*4bb7efa7SGarrett D'Amore 
296*4bb7efa7SGarrett D'Amore 	slot->s_maxclk = 0xffffffffU;	/* special sentinel */
297*4bb7efa7SGarrett D'Amore 
298*4bb7efa7SGarrett D'Amore 	/*
299*4bb7efa7SGarrett D'Amore 	 * Figure out card supported bus width and speed.
300*4bb7efa7SGarrett D'Amore 	 *
301*4bb7efa7SGarrett D'Amore 	 * TODO: SDIO: For IO cards, we have to check what speed the card
302*4bb7efa7SGarrett D'Amore 	 * supports by looking in the CCCR_CAPAB register.  (SDIO cards
303*4bb7efa7SGarrett D'Amore 	 * can go low-speed only, full-speed, or high-speed.)
304*4bb7efa7SGarrett D'Amore 	 */
305*4bb7efa7SGarrett D'Amore 	if (slot->s_flags & SLOTF_MEMORY) {
306*4bb7efa7SGarrett D'Amore 
307*4bb7efa7SGarrett D'Amore 		/*
308*4bb7efa7SGarrett D'Amore 		 * We need to obtain the CSD.
309*4bb7efa7SGarrett D'Amore 		 */
310*4bb7efa7SGarrett D'Amore 		rv = sda_init_cmd(slot, CMD_SEND_CSD, slot->s_rca << 16, R2,
311*4bb7efa7SGarrett D'Amore 		    slot->s_rcsd);
312*4bb7efa7SGarrett D'Amore 		if (rv != 0) {
313*4bb7efa7SGarrett D'Amore 			sda_slot_err(slot, "Failed getting card CSD (%d)", rv);
314*4bb7efa7SGarrett D'Amore 			goto done;
315*4bb7efa7SGarrett D'Amore 		}
316*4bb7efa7SGarrett D'Amore 
317*4bb7efa7SGarrett D'Amore 		/*
318*4bb7efa7SGarrett D'Amore 		 * Calculate the maxclock.
319*4bb7efa7SGarrett D'Amore 		 */
320*4bb7efa7SGarrett D'Amore 		slot->s_maxclk = sda_mem_maxclk(slot);
321*4bb7efa7SGarrett D'Amore 	}
322*4bb7efa7SGarrett D'Amore 	if (((slot->s_flags & SLOTF_SDMEM) != 0) &&
323*4bb7efa7SGarrett D'Amore 	    ((slot->s_caps & SLOT_CAP_4BITS) != 0)) {
324*4bb7efa7SGarrett D'Amore 		slot->s_flags |= SLOTF_4BITS;
325*4bb7efa7SGarrett D'Amore 	}
326*4bb7efa7SGarrett D'Amore 	if (slot->s_flags & SLOTF_SDIO) {
327*4bb7efa7SGarrett D'Amore 		sda_slot_debug(slot, "Wide SDIO bus not yet supported");
328*4bb7efa7SGarrett D'Amore 		slot->s_flags &= ~SLOTF_4BITS;
329*4bb7efa7SGarrett D'Amore 	}
330*4bb7efa7SGarrett D'Amore 
331*4bb7efa7SGarrett D'Amore 	/*
332*4bb7efa7SGarrett D'Amore 	 * Now select the card.
333*4bb7efa7SGarrett D'Amore 	 */
334*4bb7efa7SGarrett D'Amore 	if ((rv = sda_init_cmd(slot, CMD_SELECT_CARD, slot->s_rca << 16,
335*4bb7efa7SGarrett D'Amore 	    R1b, &resp)) != SDA_EOK) {
336*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Failed selecting card (%d, %x)", rv, resp);
337*4bb7efa7SGarrett D'Amore 		goto done;
338*4bb7efa7SGarrett D'Amore 	}
339*4bb7efa7SGarrett D'Amore 
340*4bb7efa7SGarrett D'Amore 	if ((rv = sda_init_highspeed(slot)) != SDA_EOK) {
341*4bb7efa7SGarrett D'Amore 		goto done;
342*4bb7efa7SGarrett D'Amore 	}
343*4bb7efa7SGarrett D'Amore 
344*4bb7efa7SGarrett D'Amore 	sda_init_clock(slot, slot->s_maxclk);
345*4bb7efa7SGarrett D'Amore 
346*4bb7efa7SGarrett D'Amore 	/*
347*4bb7efa7SGarrett D'Amore 	 * Lets go to 4-bit bus mode, if possible.
348*4bb7efa7SGarrett D'Amore 	 */
349*4bb7efa7SGarrett D'Amore 	if ((rv = sda_init_width(slot)) != SDA_EOK) {
350*4bb7efa7SGarrett D'Amore 		goto done;
351*4bb7efa7SGarrett D'Amore 	}
352*4bb7efa7SGarrett D'Amore 
353*4bb7efa7SGarrett D'Amore 	if ((rv = sda_init_blocklen(slot)) != SDA_EOK) {
354*4bb7efa7SGarrett D'Amore 		goto done;
355*4bb7efa7SGarrett D'Amore 	}
356*4bb7efa7SGarrett D'Amore 
357*4bb7efa7SGarrett D'Amore 	/* note if a card is writable */
358*4bb7efa7SGarrett D'Amore 	if ((sda_getprop(slot, SDA_PROP_WPROTECT, &val) == SDA_EOK) &&
359*4bb7efa7SGarrett D'Amore 	    (val == 0)) {
360*4bb7efa7SGarrett D'Amore 		slot->s_flags |= SLOTF_WRITABLE;
361*4bb7efa7SGarrett D'Amore 	}
362*4bb7efa7SGarrett D'Amore 
363*4bb7efa7SGarrett D'Amore 	rv = SDA_EOK;
364*4bb7efa7SGarrett D'Amore 
365*4bb7efa7SGarrett D'Amore done:
366*4bb7efa7SGarrett D'Amore 
367*4bb7efa7SGarrett D'Amore 	sda_slot_enter(slot);
368*4bb7efa7SGarrett D'Amore 	slot->s_init = B_FALSE;
369*4bb7efa7SGarrett D'Amore 	sda_slot_exit(slot);
370*4bb7efa7SGarrett D'Amore 
371*4bb7efa7SGarrett D'Amore 	sda_slot_wakeup(slot);
372*4bb7efa7SGarrett D'Amore 
373*4bb7efa7SGarrett D'Amore 	return (rv);
374*4bb7efa7SGarrett D'Amore }
375*4bb7efa7SGarrett D'Amore 
376*4bb7efa7SGarrett D'Amore sda_err_t
377*4bb7efa7SGarrett D'Amore sda_init_blocklen(sda_slot_t *slot)
378*4bb7efa7SGarrett D'Amore {
379*4bb7efa7SGarrett D'Amore 	int		rv;
380*4bb7efa7SGarrett D'Amore 	uint32_t	resp;
381*4bb7efa7SGarrett D'Amore 
382*4bb7efa7SGarrett D'Amore 	if ((slot->s_flags & SLOTF_MEMORY) == 0)  {
383*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
384*4bb7efa7SGarrett D'Amore 	}
385*4bb7efa7SGarrett D'Amore 
386*4bb7efa7SGarrett D'Amore 	/*
387*4bb7efa7SGarrett D'Amore 	 * All memory cards support block sizes of 512.  Full stop.
388*4bb7efa7SGarrett D'Amore 	 */
389*4bb7efa7SGarrett D'Amore 	rv = sda_init_cmd(slot, CMD_SET_BLOCKLEN, 512, R1, &resp);
390*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
391*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Unable to set block length (%d, %x)",
392*4bb7efa7SGarrett D'Amore 		    rv, resp);
393*4bb7efa7SGarrett D'Amore 	}
394*4bb7efa7SGarrett D'Amore 	return (rv);
395*4bb7efa7SGarrett D'Amore }
396*4bb7efa7SGarrett D'Amore 
397*4bb7efa7SGarrett D'Amore void
398*4bb7efa7SGarrett D'Amore sda_init_clock(sda_slot_t *slot, uint32_t hz)
399*4bb7efa7SGarrett D'Amore {
400*4bb7efa7SGarrett D'Amore 	int		rv;
401*4bb7efa7SGarrett D'Amore 	uint32_t	act;
402*4bb7efa7SGarrett D'Amore 
403*4bb7efa7SGarrett D'Amore 	/*
404*4bb7efa7SGarrett D'Amore 	 * Note that at no time is a failure programming the clock
405*4bb7efa7SGarrett D'Amore 	 * itself necessarily a fatal error.  Although if the clock
406*4bb7efa7SGarrett D'Amore 	 * wasn't programmed, other things will probably not work during
407*4bb7efa7SGarrett D'Amore 	 * initialization.
408*4bb7efa7SGarrett D'Amore 	 */
409*4bb7efa7SGarrett D'Amore 
410*4bb7efa7SGarrett D'Amore 	if ((rv = sda_setprop(slot, SDA_PROP_CLOCK, hz)) != SDA_EOK) {
411*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Failed setting clock to %u Hz (%d)",
412*4bb7efa7SGarrett D'Amore 		    hz, rv);
413*4bb7efa7SGarrett D'Amore 		/* XXX: FMA fail the slot */
414*4bb7efa7SGarrett D'Amore 		return;
415*4bb7efa7SGarrett D'Amore 	}
416*4bb7efa7SGarrett D'Amore 
417*4bb7efa7SGarrett D'Amore 	if ((rv = sda_getprop(slot, SDA_PROP_CLOCK, &act)) == SDA_EOK) {
418*4bb7efa7SGarrett D'Amore 		sda_slot_debug(slot, "Clock set to %u Hz (requested %u Hz)",
419*4bb7efa7SGarrett D'Amore 		    act, hz);
420*4bb7efa7SGarrett D'Amore 	} else {
421*4bb7efa7SGarrett D'Amore 		sda_slot_debug(slot, "Clock frequency unknown (good luck).");
422*4bb7efa7SGarrett D'Amore 	}
423*4bb7efa7SGarrett D'Amore 
424*4bb7efa7SGarrett D'Amore 	/*
425*4bb7efa7SGarrett D'Amore 	 * For now, just wait 10msec for clocks to stabilize to the
426*4bb7efa7SGarrett D'Amore 	 * card.  (Is this really necessary?)
427*4bb7efa7SGarrett D'Amore 	 */
428*4bb7efa7SGarrett D'Amore 	delay(drv_usectohz(10000));
429*4bb7efa7SGarrett D'Amore }
430*4bb7efa7SGarrett D'Amore 
431*4bb7efa7SGarrett D'Amore sda_err_t
432*4bb7efa7SGarrett D'Amore sda_init_width(sda_slot_t *slot)
433*4bb7efa7SGarrett D'Amore {
434*4bb7efa7SGarrett D'Amore 	int		rv;
435*4bb7efa7SGarrett D'Amore 	uint32_t	resp;
436*4bb7efa7SGarrett D'Amore 
437*4bb7efa7SGarrett D'Amore 	/*
438*4bb7efa7SGarrett D'Amore 	 * Spec says we should command the card first.
439*4bb7efa7SGarrett D'Amore 	 */
440*4bb7efa7SGarrett D'Amore 
441*4bb7efa7SGarrett D'Amore 	rv = sda_setprop(slot, SDA_PROP_BUSWIDTH, 1);
442*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
443*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Unable to set slot 1-bit mode (%d)", rv);
444*4bb7efa7SGarrett D'Amore 		return (rv);
445*4bb7efa7SGarrett D'Amore 	}
446*4bb7efa7SGarrett D'Amore 
447*4bb7efa7SGarrett D'Amore 	if ((slot->s_flags & SLOTF_4BITS) == 0) {
448*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
449*4bb7efa7SGarrett D'Amore 	}
450*4bb7efa7SGarrett D'Amore 
451*4bb7efa7SGarrett D'Amore 	/*
452*4bb7efa7SGarrett D'Amore 	 * TODO: SDIO: SDIO cards set the CCCR_BUS_WIDTH
453*4bb7efa7SGarrett D'Amore 	 * and CCCR_CD_DISABLE bits here.
454*4bb7efa7SGarrett D'Amore 	 */
455*4bb7efa7SGarrett D'Amore 
456*4bb7efa7SGarrett D'Amore 	/*
457*4bb7efa7SGarrett D'Amore 	 * If we're going to use all 4 pins, we really need to disconnect
458*4bb7efa7SGarrett D'Amore 	 * the card pullup resistor.   A consquence of this, is that hosts
459*4bb7efa7SGarrett D'Amore 	 * which use that resistor for detection must not claim to support
460*4bb7efa7SGarrett D'Amore 	 * 4-bit bus mode.  This is a limitation of our implementation.
461*4bb7efa7SGarrett D'Amore 	 */
462*4bb7efa7SGarrett D'Amore 	rv = sda_init_acmd(slot, ACMD_SET_CLR_CARD_DETECT, 1, R1, &resp);
463*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
464*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot,
465*4bb7efa7SGarrett D'Amore 		    "Unable disconnect DAT3 resistor on card (%d, %x)",
466*4bb7efa7SGarrett D'Amore 		    rv, resp);
467*4bb7efa7SGarrett D'Amore 		/* non-fatal error, muddle on */
468*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
469*4bb7efa7SGarrett D'Amore 	}
470*4bb7efa7SGarrett D'Amore 
471*4bb7efa7SGarrett D'Amore 	rv = sda_init_acmd(slot, ACMD_SET_BUS_WIDTH, 2, R1, &resp);
472*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
473*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Unable to set card 4-bit mode (%d, %x)",
474*4bb7efa7SGarrett D'Amore 		    rv, resp);
475*4bb7efa7SGarrett D'Amore 		/* non-fatal error, muddle on */
476*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
477*4bb7efa7SGarrett D'Amore 	}
478*4bb7efa7SGarrett D'Amore 
479*4bb7efa7SGarrett D'Amore 	rv = sda_setprop(slot, SDA_PROP_BUSWIDTH, 4);
480*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
481*4bb7efa7SGarrett D'Amore 		/*
482*4bb7efa7SGarrett D'Amore 		 * This is bad news.  We've already asked for the card to
483*4bb7efa7SGarrett D'Amore 		 * to use 4-bit mode, but the host is not complying.  It
484*4bb7efa7SGarrett D'Amore 		 * shouldn't ever happen, so we just error out.
485*4bb7efa7SGarrett D'Amore 		 */
486*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Unable to set slot 4-bit mode (%d)", rv);
487*4bb7efa7SGarrett D'Amore 	}
488*4bb7efa7SGarrett D'Amore 
489*4bb7efa7SGarrett D'Amore 	return (rv);
490*4bb7efa7SGarrett D'Amore }
491*4bb7efa7SGarrett D'Amore 
492*4bb7efa7SGarrett D'Amore sda_err_t
493*4bb7efa7SGarrett D'Amore sda_init_ifcond(sda_slot_t *slot)
494*4bb7efa7SGarrett D'Amore {
495*4bb7efa7SGarrett D'Amore 	int		rv;
496*4bb7efa7SGarrett D'Amore 	int		tries;
497*4bb7efa7SGarrett D'Amore 	uint32_t	vchk;
498*4bb7efa7SGarrett D'Amore 	uint32_t	resp;
499*4bb7efa7SGarrett D'Amore 
500*4bb7efa7SGarrett D'Amore 	/*
501*4bb7efa7SGarrett D'Amore 	 * Try SEND_IF_COND.  Note that this assumes that the host is
502*4bb7efa7SGarrett D'Amore 	 * supplying 2.7 - 3.6 voltage range.  The standard is not
503*4bb7efa7SGarrett D'Amore 	 * defined for any other ranges.
504*4bb7efa7SGarrett D'Amore 	 */
505*4bb7efa7SGarrett D'Amore 	vchk = R7_VHS_27_36V | R7_PATTERN;
506*4bb7efa7SGarrett D'Amore 
507*4bb7efa7SGarrett D'Amore 	/* we try this a few times, just to be sure */
508*4bb7efa7SGarrett D'Amore 	for (tries = 0; tries < 5; tries++) {
509*4bb7efa7SGarrett D'Amore 		rv = sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL);
510*4bb7efa7SGarrett D'Amore 		if (rv != SDA_EOK) {
511*4bb7efa7SGarrett D'Amore 			sda_slot_err(slot, "Failed to IDLE card");
512*4bb7efa7SGarrett D'Amore 			return (rv);
513*4bb7efa7SGarrett D'Amore 		}
514*4bb7efa7SGarrett D'Amore 
515*4bb7efa7SGarrett D'Amore 		rv = sda_init_cmd(slot, CMD_SEND_IF_COND, vchk, R7, &resp);
516*4bb7efa7SGarrett D'Amore 		if (rv == SDA_EOK) {
517*4bb7efa7SGarrett D'Amore 			break;
518*4bb7efa7SGarrett D'Amore 		}
519*4bb7efa7SGarrett D'Amore 		delay(drv_usectohz(10000));
520*4bb7efa7SGarrett D'Amore 	}
521*4bb7efa7SGarrett D'Amore 
522*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
523*4bb7efa7SGarrett D'Amore 		(void) sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL);
524*4bb7efa7SGarrett D'Amore 		slot->s_flags &= ~SLOTF_IFCOND;
525*4bb7efa7SGarrett D'Amore 
526*4bb7efa7SGarrett D'Amore 	} else if (resp != vchk) {
527*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Card voltages incompatible! (%x)", resp);
528*4bb7efa7SGarrett D'Amore 		return (SDA_ENOTSUP);
529*4bb7efa7SGarrett D'Amore 
530*4bb7efa7SGarrett D'Amore 	} else {
531*4bb7efa7SGarrett D'Amore 		/* SDHC compliant */
532*4bb7efa7SGarrett D'Amore 		slot->s_flags |= SLOTF_IFCOND;
533*4bb7efa7SGarrett D'Amore 	}
534*4bb7efa7SGarrett D'Amore 
535*4bb7efa7SGarrett D'Amore 	return (SDA_EOK);
536*4bb7efa7SGarrett D'Amore }
537*4bb7efa7SGarrett D'Amore 
538*4bb7efa7SGarrett D'Amore sda_err_t
539*4bb7efa7SGarrett D'Amore sda_init_rca(sda_slot_t *slot)
540*4bb7efa7SGarrett D'Amore {
541*4bb7efa7SGarrett D'Amore 	int		rv;
542*4bb7efa7SGarrett D'Amore 	int		tries;
543*4bb7efa7SGarrett D'Amore 	uint32_t	resp;
544*4bb7efa7SGarrett D'Amore 
545*4bb7efa7SGarrett D'Amore 	/*
546*4bb7efa7SGarrett D'Amore 	 * Program the RCA.  Note that MMC has a different mechanism
547*4bb7efa7SGarrett D'Amore 	 * for this.
548*4bb7efa7SGarrett D'Amore 	 */
549*4bb7efa7SGarrett D'Amore 	for (tries = 0; tries < 10; tries++) {
550*4bb7efa7SGarrett D'Amore 
551*4bb7efa7SGarrett D'Amore 		if (slot->s_flags & SLOTF_MMC) {
552*4bb7efa7SGarrett D'Amore 			/*
553*4bb7efa7SGarrett D'Amore 			 * For MMC, we push the RCA to the MMC.  We
554*4bb7efa7SGarrett D'Amore 			 * arbitrarily start at 0x100, and add from
555*4bb7efa7SGarrett D'Amore 			 * there.
556*4bb7efa7SGarrett D'Amore 			 */
557*4bb7efa7SGarrett D'Amore 			rv = sda_init_cmd(slot, CMD_SEND_RCA,
558*4bb7efa7SGarrett D'Amore 			    (0x100 + tries) << 16, R1, NULL);
559*4bb7efa7SGarrett D'Amore 			if (rv == SDA_EOK)
560*4bb7efa7SGarrett D'Amore 				slot->s_rca = 0x100 + tries;
561*4bb7efa7SGarrett D'Amore 		} else {
562*4bb7efa7SGarrett D'Amore 			/*
563*4bb7efa7SGarrett D'Amore 			 * For SDcard, we are basically asking the
564*4bb7efa7SGarrett D'Amore 			 * card to propose a value.  It *may* propose
565*4bb7efa7SGarrett D'Amore 			 * a value of zero, in which case we will have
566*4bb7efa7SGarrett D'Amore 			 * to ask again.
567*4bb7efa7SGarrett D'Amore 			 */
568*4bb7efa7SGarrett D'Amore 			rv = sda_init_cmd(slot, CMD_SEND_RCA, 0, R6, &resp);
569*4bb7efa7SGarrett D'Amore 			if (rv == SDA_EOK)
570*4bb7efa7SGarrett D'Amore 				slot->s_rca = resp >> 16;
571*4bb7efa7SGarrett D'Amore 		}
572*4bb7efa7SGarrett D'Amore 		if ((rv == SDA_EOK) && (slot->s_rca != 0)) {
573*4bb7efa7SGarrett D'Amore 			sda_slot_debug(slot, "Relative address (RCA) = %d",
574*4bb7efa7SGarrett D'Amore 			    slot->s_rca);
575*4bb7efa7SGarrett D'Amore 			return (SDA_EOK);
576*4bb7efa7SGarrett D'Amore 		}
577*4bb7efa7SGarrett D'Amore 	}
578*4bb7efa7SGarrett D'Amore 
579*4bb7efa7SGarrett D'Amore 	sda_slot_err(slot, "Unable to negotiate a suitable RCA (%d)", rv);
580*4bb7efa7SGarrett D'Amore 	return ((rv != SDA_EOK) ? rv : SDA_EINVAL);
581*4bb7efa7SGarrett D'Amore }
582*4bb7efa7SGarrett D'Amore 
583*4bb7efa7SGarrett D'Amore sda_err_t
584*4bb7efa7SGarrett D'Amore sda_init_switch(sda_slot_t *slot, uint8_t mode, uint8_t grp, uint8_t val,
585*4bb7efa7SGarrett D'Amore     uint8_t *data)
586*4bb7efa7SGarrett D'Amore {
587*4bb7efa7SGarrett D'Amore 	sda_cmd_t	*cmdp;
588*4bb7efa7SGarrett D'Amore 	sda_err_t	errno;
589*4bb7efa7SGarrett D'Amore 	uint32_t	arg;
590*4bb7efa7SGarrett D'Amore 
591*4bb7efa7SGarrett D'Amore 	/*
592*4bb7efa7SGarrett D'Amore 	 * The spec says we should leave unselected groups set to 0xf,
593*4bb7efa7SGarrett D'Amore 	 * to prevent inadvertent changes.
594*4bb7efa7SGarrett D'Amore 	 */
595*4bb7efa7SGarrett D'Amore 	arg = (mode << 31) | 0xffffff;
596*4bb7efa7SGarrett D'Amore 	arg &= ~(0xf << (grp << 2));
597*4bb7efa7SGarrett D'Amore 	arg |= (val << (grp << 2));
598*4bb7efa7SGarrett D'Amore 
599*4bb7efa7SGarrett D'Amore 	cmdp = sda_cmd_alloc(slot, CMD_SWITCH_FUNC, arg, R1, NULL, KM_SLEEP);
600*4bb7efa7SGarrett D'Amore 
601*4bb7efa7SGarrett D'Amore 	cmdp->sc_flags |= SDA_CMDF_INIT | SDA_CMDF_DAT | SDA_CMDF_READ;
602*4bb7efa7SGarrett D'Amore 	cmdp->sc_blksz = 64;
603*4bb7efa7SGarrett D'Amore 	cmdp->sc_nblks = 1;
604*4bb7efa7SGarrett D'Amore 	cmdp->sc_kvaddr = (void *)data;
605*4bb7efa7SGarrett D'Amore 
606*4bb7efa7SGarrett D'Amore 	errno = sda_cmd_exec(slot, cmdp, NULL);
607*4bb7efa7SGarrett D'Amore 
608*4bb7efa7SGarrett D'Amore 	sda_cmd_free(cmdp);
609*4bb7efa7SGarrett D'Amore 
610*4bb7efa7SGarrett D'Amore 	return (errno);
611*4bb7efa7SGarrett D'Amore 
612*4bb7efa7SGarrett D'Amore }
613*4bb7efa7SGarrett D'Amore 
614*4bb7efa7SGarrett D'Amore sda_err_t
615*4bb7efa7SGarrett D'Amore sda_init_highspeed(sda_slot_t *slot)
616*4bb7efa7SGarrett D'Amore {
617*4bb7efa7SGarrett D'Amore 	uint32_t	ccc;
618*4bb7efa7SGarrett D'Amore 	uint8_t		data[64];
619*4bb7efa7SGarrett D'Amore 	sda_err_t	rv;
620*4bb7efa7SGarrett D'Amore 
621*4bb7efa7SGarrett D'Amore 	if ((slot->s_caps & SLOT_CAP_HISPEED) == 0) {
622*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
623*4bb7efa7SGarrett D'Amore 	}
624*4bb7efa7SGarrett D'Amore 	if ((slot->s_flags & SLOTF_SDMEM) == 0) {
625*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
626*4bb7efa7SGarrett D'Amore 	}
627*4bb7efa7SGarrett D'Amore 	ccc = sda_mem_getbits(slot->s_rcsd, 95, 12);
628*4bb7efa7SGarrett D'Amore 	if ((ccc & (1 << 10)) == 0) {
629*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
630*4bb7efa7SGarrett D'Amore 	}
631*4bb7efa7SGarrett D'Amore 
632*4bb7efa7SGarrett D'Amore 	rv = sda_init_switch(slot, 0, 0, 1, data);
633*4bb7efa7SGarrett D'Amore 
634*4bb7efa7SGarrett D'Amore 	/* these are big-endian bits, bit 401 */
635*4bb7efa7SGarrett D'Amore 	if ((rv != SDA_EOK) || ((data[13] & (1 << 1)) == 0)) {
636*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
637*4bb7efa7SGarrett D'Amore 	}
638*4bb7efa7SGarrett D'Amore 
639*4bb7efa7SGarrett D'Amore 	rv = sda_init_switch(slot, 1, 0, 1, data);
640*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
641*4bb7efa7SGarrett D'Amore 		return (SDA_EOK);
642*4bb7efa7SGarrett D'Amore 	}
643*4bb7efa7SGarrett D'Amore 
644*4bb7efa7SGarrett D'Amore 	/* now program the card */
645*4bb7efa7SGarrett D'Amore 	rv = sda_setprop(slot, SDA_PROP_HISPEED, 1);
646*4bb7efa7SGarrett D'Amore 	if (rv != SDA_EOK) {
647*4bb7efa7SGarrett D'Amore 		sda_slot_err(slot, "Failed setting slot to high speed mode");
648*4bb7efa7SGarrett D'Amore 	} else {
649*4bb7efa7SGarrett D'Amore 		/* the card should now support 50 MHz */
650*4bb7efa7SGarrett D'Amore 		slot->s_maxclk = 50000000;
651*4bb7efa7SGarrett D'Amore 	}
652*4bb7efa7SGarrett D'Amore 
653*4bb7efa7SGarrett D'Amore 	return (rv);
654*4bb7efa7SGarrett D'Amore }
655