xref: /netbsd-src/sys/dev/marvell/mvsdio.c (revision c7fb772b85b2b5d4cfb282f868f454b4701534fd)
1*c7fb772bSthorpej /*	$NetBSD: mvsdio.c,v 1.8 2021/08/07 16:19:13 thorpej Exp $	*/
2c9cd5538Skiyohara /*
3c9cd5538Skiyohara  * Copyright (c) 2010 KIYOHARA Takashi
4c9cd5538Skiyohara  * All rights reserved.
5c9cd5538Skiyohara  *
6c9cd5538Skiyohara  * Redistribution and use in source and binary forms, with or without
7c9cd5538Skiyohara  * modification, are permitted provided that the following conditions
8c9cd5538Skiyohara  * are met:
9c9cd5538Skiyohara  * 1. Redistributions of source code must retain the above copyright
10c9cd5538Skiyohara  *    notice, this list of conditions and the following disclaimer.
11c9cd5538Skiyohara  * 2. Redistributions in binary form must reproduce the above copyright
12c9cd5538Skiyohara  *    notice, this list of conditions and the following disclaimer in the
13c9cd5538Skiyohara  *    documentation and/or other materials provided with the distribution.
14c9cd5538Skiyohara  *
15c9cd5538Skiyohara  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16c9cd5538Skiyohara  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17c9cd5538Skiyohara  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18c9cd5538Skiyohara  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
19c9cd5538Skiyohara  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20c9cd5538Skiyohara  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21c9cd5538Skiyohara  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c9cd5538Skiyohara  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23c9cd5538Skiyohara  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
24c9cd5538Skiyohara  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25c9cd5538Skiyohara  * POSSIBILITY OF SUCH DAMAGE.
26c9cd5538Skiyohara  */
27c9cd5538Skiyohara #include <sys/cdefs.h>
28*c7fb772bSthorpej __KERNEL_RCSID(0, "$NetBSD: mvsdio.c,v 1.8 2021/08/07 16:19:13 thorpej Exp $");
29c9cd5538Skiyohara 
30c9cd5538Skiyohara #include "opt_mvsdio.h"
31c9cd5538Skiyohara 
32c9cd5538Skiyohara #include <sys/param.h>
33c9cd5538Skiyohara #include <sys/bus.h>
34c9cd5538Skiyohara #include <sys/condvar.h>
35c9cd5538Skiyohara #include <sys/device.h>
36c9cd5538Skiyohara #include <sys/errno.h>
37c9cd5538Skiyohara #include <sys/mutex.h>
38c9cd5538Skiyohara 
39c9cd5538Skiyohara #include <dev/marvell/marvellreg.h>
40c9cd5538Skiyohara #include <dev/marvell/marvellvar.h>
41c9cd5538Skiyohara #include <dev/marvell/mvsdioreg.h>
42c9cd5538Skiyohara 
43c9cd5538Skiyohara #include <dev/sdmmc/sdmmcvar.h>
44c9cd5538Skiyohara #include <dev/sdmmc/sdmmcchip.h>
45c9cd5538Skiyohara 
46c9cd5538Skiyohara //#define MVSDIO_DEBUG 1
47c9cd5538Skiyohara #ifdef MVSDIO_DEBUG
48c9cd5538Skiyohara #define DPRINTF(n, x)	if (mvsdio_debug >= (n)) printf x
49c9cd5538Skiyohara int mvsdio_debug = MVSDIO_DEBUG;
50c9cd5538Skiyohara #else
51c9cd5538Skiyohara #define DPRINTF(n, x)
52c9cd5538Skiyohara #endif
53c9cd5538Skiyohara 
54c9cd5538Skiyohara struct mvsdio_softc {
55c9cd5538Skiyohara 	device_t sc_dev;
56c9cd5538Skiyohara 	device_t sc_sdmmc;
57c9cd5538Skiyohara 
58c9cd5538Skiyohara 	bus_space_tag_t sc_iot;
59c9cd5538Skiyohara 	bus_space_handle_t sc_ioh;
60c9cd5538Skiyohara 	bus_dma_tag_t sc_dmat;
61c9cd5538Skiyohara 
62c9cd5538Skiyohara 	struct kmutex sc_mtx;
63c9cd5538Skiyohara 	kcondvar_t sc_cv;
64c9cd5538Skiyohara 
65c9cd5538Skiyohara 	struct sdmmc_command *sc_exec_cmd;
66c9cd5538Skiyohara 	uint32_t sc_waitintr;
67c9cd5538Skiyohara };
68c9cd5538Skiyohara 
69c9cd5538Skiyohara static int mvsdio_match(device_t, struct cfdata *, void *);
70c9cd5538Skiyohara static void mvsdio_attach(device_t, device_t, void *);
71c9cd5538Skiyohara 
72c9cd5538Skiyohara static int mvsdio_intr(void *);
73c9cd5538Skiyohara 
74c9cd5538Skiyohara static int mvsdio_host_reset(sdmmc_chipset_handle_t);
75c9cd5538Skiyohara static uint32_t mvsdio_host_ocr(sdmmc_chipset_handle_t);
76c9cd5538Skiyohara static int mvsdio_host_maxblklen(sdmmc_chipset_handle_t);
77c9cd5538Skiyohara #ifdef MVSDIO_CARD_DETECT
78c9cd5538Skiyohara int MVSDIO_CARD_DETECT(sdmmc_chipset_handle_t);
79c9cd5538Skiyohara #else
80c9cd5538Skiyohara static int mvsdio_card_detect(sdmmc_chipset_handle_t);
81c9cd5538Skiyohara #endif
82c9cd5538Skiyohara #ifdef MVSDIO_WRITE_PROTECT
83c9cd5538Skiyohara int MVSDIO_WRITE_PROTECT(sdmmc_chipset_handle_t);
84c9cd5538Skiyohara #else
85c9cd5538Skiyohara static int mvsdio_write_protect(sdmmc_chipset_handle_t);
86c9cd5538Skiyohara #endif
87c9cd5538Skiyohara static int mvsdio_bus_power(sdmmc_chipset_handle_t, uint32_t);
88c9cd5538Skiyohara static int mvsdio_bus_clock(sdmmc_chipset_handle_t, int);
89c9cd5538Skiyohara static int mvsdio_bus_width(sdmmc_chipset_handle_t, int);
90c9cd5538Skiyohara static int mvsdio_bus_rod(sdmmc_chipset_handle_t, int);
91c9cd5538Skiyohara static void mvsdio_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
92c9cd5538Skiyohara static void mvsdio_card_enable_intr(sdmmc_chipset_handle_t, int);
93c9cd5538Skiyohara static void mvsdio_card_intr_ack(sdmmc_chipset_handle_t);
94c9cd5538Skiyohara 
95c51a6569Skiyohara static void mvsdio_wininit(struct mvsdio_softc *, enum marvell_tags *);
96c9cd5538Skiyohara 
97c9cd5538Skiyohara static struct sdmmc_chip_functions mvsdio_chip_functions = {
98c9cd5538Skiyohara 	/* host controller reset */
99c9cd5538Skiyohara 	.host_reset		= mvsdio_host_reset,
100c9cd5538Skiyohara 
101c9cd5538Skiyohara 	/* host controller capabilities */
102c9cd5538Skiyohara 	.host_ocr		= mvsdio_host_ocr,
103c9cd5538Skiyohara 	.host_maxblklen		= mvsdio_host_maxblklen,
104c9cd5538Skiyohara 
105c9cd5538Skiyohara 	/* card detection */
106c9cd5538Skiyohara #ifdef MVSDIO_CARD_DETECT
107c9cd5538Skiyohara 	.card_detect		= MVSDIO_CARD_DETECT,
108c9cd5538Skiyohara #else
109c9cd5538Skiyohara 	.card_detect		= mvsdio_card_detect,
110c9cd5538Skiyohara #endif
111c9cd5538Skiyohara 
112c9cd5538Skiyohara 	/* write protect */
113c9cd5538Skiyohara #ifdef MVSDIO_WRITE_PROTECT
114c9cd5538Skiyohara 	.write_protect		= MVSDIO_WRITE_PROTECT,
115c9cd5538Skiyohara #else
116c9cd5538Skiyohara 	.write_protect		= mvsdio_write_protect,
117c9cd5538Skiyohara #endif
118c9cd5538Skiyohara 
119c9cd5538Skiyohara 	/* bus power, clock frequency, width, rod */
120c9cd5538Skiyohara 	.bus_power		= mvsdio_bus_power,
121c9cd5538Skiyohara 	.bus_clock		= mvsdio_bus_clock,
122c9cd5538Skiyohara 	.bus_width		= mvsdio_bus_width,
123c9cd5538Skiyohara 	.bus_rod		= mvsdio_bus_rod,
124c9cd5538Skiyohara 
125c9cd5538Skiyohara 	/* command execution */
126c9cd5538Skiyohara 	.exec_command		= mvsdio_exec_command,
127c9cd5538Skiyohara 
128c9cd5538Skiyohara 	/* card interrupt */
129c9cd5538Skiyohara 	.card_enable_intr	= mvsdio_card_enable_intr,
130c9cd5538Skiyohara 	.card_intr_ack		= mvsdio_card_intr_ack,
131c9cd5538Skiyohara };
132c9cd5538Skiyohara 
133c9cd5538Skiyohara CFATTACH_DECL_NEW(mvsdio_mbus, sizeof(struct mvsdio_softc),
134c9cd5538Skiyohara     mvsdio_match, mvsdio_attach, NULL, NULL);
135c9cd5538Skiyohara 
136c9cd5538Skiyohara 
137c9cd5538Skiyohara /* ARGSUSED */
138c9cd5538Skiyohara static int
mvsdio_match(device_t parent,struct cfdata * match,void * aux)139c9cd5538Skiyohara mvsdio_match(device_t parent, struct cfdata *match, void *aux)
140c9cd5538Skiyohara {
141c9cd5538Skiyohara 	struct marvell_attach_args *mva = aux;
142c9cd5538Skiyohara 
143c9cd5538Skiyohara 	if (strcmp(mva->mva_name, match->cf_name) != 0)
144c9cd5538Skiyohara 		return 0;
145c9cd5538Skiyohara 	if (mva->mva_offset == MVA_OFFSET_DEFAULT)
146c9cd5538Skiyohara 		return 0;
147c9cd5538Skiyohara 
148c9cd5538Skiyohara 	mva->mva_size = MVSDIO_SIZE;
149c9cd5538Skiyohara 	return 1;
150c9cd5538Skiyohara }
151c9cd5538Skiyohara 
152c9cd5538Skiyohara /* ARGSUSED */
153c9cd5538Skiyohara static void
mvsdio_attach(device_t parent,device_t self,void * aux)154c9cd5538Skiyohara mvsdio_attach(device_t parent, device_t self, void *aux)
155c9cd5538Skiyohara {
156c9cd5538Skiyohara 	struct mvsdio_softc *sc = device_private(self);
157c9cd5538Skiyohara 	struct marvell_attach_args *mva = aux;
158c9cd5538Skiyohara 	struct sdmmcbus_attach_args saa;
159c9cd5538Skiyohara 	uint32_t nis, eis;
160c6347068Sjakllsch 	uint32_t hps;
161c9cd5538Skiyohara 
162c9cd5538Skiyohara 	aprint_naive("\n");
163c9cd5538Skiyohara 	aprint_normal(": Marvell Secure Digital Input/Output Interface\n");
164c9cd5538Skiyohara 
165c9cd5538Skiyohara 	sc->sc_dev = self;
166c9cd5538Skiyohara 	sc->sc_iot = mva->mva_iot;
167c9cd5538Skiyohara 	if (bus_space_subregion(mva->mva_iot, mva->mva_ioh, mva->mva_offset,
168c9cd5538Skiyohara 	    mva->mva_size, &sc->sc_ioh)) {
169c9cd5538Skiyohara 		aprint_error_dev(self, "Cannot map registers\n");
170c9cd5538Skiyohara 		return;
171c9cd5538Skiyohara 	}
172c9cd5538Skiyohara 	sc->sc_dmat = mva->mva_dmat;
173c9cd5538Skiyohara 
174c9cd5538Skiyohara 	mutex_init(&sc->sc_mtx, MUTEX_DEFAULT, IPL_SDMMC);
175c9cd5538Skiyohara 	cv_init(&sc->sc_cv, "mvsdio_intr");
176c9cd5538Skiyohara 
177c9cd5538Skiyohara 	sc->sc_exec_cmd = NULL;
178c9cd5538Skiyohara 	sc->sc_waitintr = 0;
179c9cd5538Skiyohara 
180c9cd5538Skiyohara 	marvell_intr_establish(mva->mva_irq, IPL_SDMMC, mvsdio_intr, sc);
181c9cd5538Skiyohara 
182c51a6569Skiyohara 	mvsdio_wininit(sc, mva->mva_tags);
183c9cd5538Skiyohara 
184c9cd5538Skiyohara #if BYTE_ORDER == LITTLE_ENDIAN
185c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, HC_BIGENDIAN);
186c9cd5538Skiyohara #else
187c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, HC_LSBFIRST);
188c9cd5538Skiyohara #endif
189c9cd5538Skiyohara 	nis =
190c9cd5538Skiyohara 	    NIS_CMDCOMPLETE	/* Command Complete */		|
191c9cd5538Skiyohara 	    NIS_XFERCOMPLETE	/* Transfer Complete */		|
192c9cd5538Skiyohara 	    NIS_BLOCKGAPEV	/* Block gap event */		|
193c9cd5538Skiyohara 	    NIS_DMAINT		/* DMA interrupt */		|
194c9cd5538Skiyohara 	    NIS_CARDINT		/* Card interrupt */		|
195c9cd5538Skiyohara 	    NIS_READWAITON	/* Read Wait state is on */	|
196c9cd5538Skiyohara 	    NIS_SUSPENSEON					|
197c9cd5538Skiyohara 	    NIS_AUTOCMD12COMPLETE	/* Auto_cmd12 is comp */|
198c9cd5538Skiyohara 	    NIS_UNEXPECTEDRESPDET				|
199c9cd5538Skiyohara 	    NIS_ERRINT;			/* Error interrupt */
200c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NIS, nis);
201c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISE, nis);
202c9cd5538Skiyohara 
203c9cd5538Skiyohara #define NIC_DYNAMIC_CONFIG_INTRS	(NIS_CMDCOMPLETE	| \
204c9cd5538Skiyohara 					 NIS_XFERCOMPLETE	| \
205c9cd5538Skiyohara 					 NIS_DMAINT		| \
206c9cd5538Skiyohara 					 NIS_CARDINT		| \
207c9cd5538Skiyohara 					 NIS_AUTOCMD12COMPLETE)
208c9cd5538Skiyohara 
209c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE,
210c9cd5538Skiyohara 	    nis & ~NIC_DYNAMIC_CONFIG_INTRS);
211c9cd5538Skiyohara 
212c9cd5538Skiyohara 	eis =
213c9cd5538Skiyohara 	    EIS_CMDTIMEOUTERR	/*Command timeout err*/		|
214c9cd5538Skiyohara 	    EIS_CMDCRCERR	/* Command CRC Error */		|
215c9cd5538Skiyohara 	    EIS_CMDENDBITERR	/*Command end bit err*/		|
216c9cd5538Skiyohara 	    EIS_CMDINDEXERR	/*Command Index Error*/		|
217c9cd5538Skiyohara 	    EIS_DATATIMEOUTERR	/* Data timeout error */	|
218c9cd5538Skiyohara 	    EIS_RDDATACRCERR	/* Read data CRC err */		|
219c9cd5538Skiyohara 	    EIS_RDDATAENDBITERR	/*Rd data end bit err*/		|
220c9cd5538Skiyohara 	    EIS_AUTOCMD12ERR	/* Auto CMD12 error */		|
221c9cd5538Skiyohara 	    EIS_CMDSTARTBITERR	/*Cmd start bit error*/		|
222c9cd5538Skiyohara 	    EIS_XFERSIZEERR	/*Tx size mismatched err*/	|
223c9cd5538Skiyohara 	    EIS_RESPTBITERR	/* Response T bit err */	|
224c9cd5538Skiyohara 	    EIS_CRCENDBITERR	/* CRC end bit error */		|
225c9cd5538Skiyohara 	    EIS_CRCSTARTBITERR	/* CRC start bit err */		|
226c9cd5538Skiyohara 	    EIS_CRCSTATERR;	/* CRC status error */
227c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EIS, eis);
228c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISE, eis);
229c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISIE, eis);
230c9cd5538Skiyohara 
231c6347068Sjakllsch 	hps = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HPS16LSB);
232c6347068Sjakllsch 	if ((hps & HPS16LSB_CMDLEVEL) == 0) {
233c6347068Sjakllsch 		aprint_error_dev(sc->sc_dev,
234c6347068Sjakllsch 		    "CMD line not idle, HPS 0x%x (bad MPP config?)\n", hps);
235c6347068Sjakllsch 		return;
236c6347068Sjakllsch 	}
237c6347068Sjakllsch 
238c9cd5538Skiyohara         /*
239c9cd5538Skiyohara 	 * Attach the generic SD/MMC bus driver.  (The bus driver must
240c9cd5538Skiyohara 	 * not invoke any chipset functions before it is attached.)
241c9cd5538Skiyohara 	 */
242c9cd5538Skiyohara 	memset(&saa, 0, sizeof(saa));
243c9cd5538Skiyohara 	saa.saa_busname = "sdmmc";
244c9cd5538Skiyohara 	saa.saa_sct = &mvsdio_chip_functions;
245c9cd5538Skiyohara 	saa.saa_sch = sc;
246c9cd5538Skiyohara 	saa.saa_dmat = sc->sc_dmat;
247171c49e4Skiyohara 	saa.saa_clkmin = 100;		/* XXXX: 100 kHz from SheevaPlug LSP */
248c9cd5538Skiyohara 	saa.saa_clkmax = MVSDIO_MAX_CLOCK;
2492431d55eSnonaka 	saa.saa_caps = SMC_CAPS_AUTO_STOP | SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA |
250833f4534Snonaka 	    SMC_CAPS_SD_HIGHSPEED | SMC_CAPS_MMC_HIGHSPEED;
251c9cd5538Skiyohara #ifndef MVSDIO_CARD_DETECT
252c9cd5538Skiyohara 	saa.saa_caps |= SMC_CAPS_POLL_CARD_DET;
253c9cd5538Skiyohara #endif
254*c7fb772bSthorpej 	sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL, CFARGS_NONE);
255c9cd5538Skiyohara }
256c9cd5538Skiyohara 
257c9cd5538Skiyohara static int
mvsdio_intr(void * arg)258c9cd5538Skiyohara mvsdio_intr(void *arg)
259c9cd5538Skiyohara {
260c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)arg;
261c9cd5538Skiyohara 	struct sdmmc_command *cmd = sc->sc_exec_cmd;
262c9cd5538Skiyohara 	uint32_t nis, eis;
263c9cd5538Skiyohara 	int handled = 0, error;
264c9cd5538Skiyohara 
265c9cd5538Skiyohara 	nis = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NIS);
266c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NIS, nis);
267c9cd5538Skiyohara 
268c9cd5538Skiyohara 	DPRINTF(3, ("%s: intr: NIS=0x%x, NISE=0x%x, NISIE=0x%x\n",
269c9cd5538Skiyohara 	    __func__, nis,
270c9cd5538Skiyohara 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISE),
271c9cd5538Skiyohara 	    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE)));
272c9cd5538Skiyohara 
273c9cd5538Skiyohara 	if (__predict_false(nis & NIS_ERRINT)) {
274c9cd5538Skiyohara 		sc->sc_exec_cmd = NULL;
275c9cd5538Skiyohara 		eis = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EIS);
276c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EIS, eis);
277c9cd5538Skiyohara 
278c9cd5538Skiyohara 		DPRINTF(3, ("    EIS=0x%x, EISE=0x%x, EISIE=0x%x\n",
279c9cd5538Skiyohara 		    eis,
280c9cd5538Skiyohara 		    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISE),
281c9cd5538Skiyohara 		    bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_EISIE)));
282c9cd5538Skiyohara 
283c9cd5538Skiyohara 		if (eis & (EIS_CMDTIMEOUTERR | EIS_DATATIMEOUTERR)) {
284c9cd5538Skiyohara 			error = ETIMEDOUT;	/* Timeouts */
285c9cd5538Skiyohara 			DPRINTF(2, ("    Command/Data Timeout (0x%x)\n",
286c9cd5538Skiyohara 			    eis & (EIS_CMDTIMEOUTERR | EIS_DATATIMEOUTERR)));
287c9cd5538Skiyohara 		} else {
288c9cd5538Skiyohara 
289c9cd5538Skiyohara #define CRC_ERROR	(EIS_CMDCRCERR		| \
290c9cd5538Skiyohara 			 EIS_RDDATACRCERR	| \
291c9cd5538Skiyohara 			 EIS_CRCENDBITERR	| \
292c9cd5538Skiyohara 			 EIS_CRCSTARTBITERR	| \
293c9cd5538Skiyohara 			 EIS_CRCSTATERR)
294c9cd5538Skiyohara 			if (eis & CRC_ERROR) {
295c9cd5538Skiyohara 				error = EIO;		/* CRC errors */
296c9cd5538Skiyohara 				aprint_error_dev(sc->sc_dev,
297c9cd5538Skiyohara 				    "CRC Error (0x%x)\n", eis & CRC_ERROR);
298c9cd5538Skiyohara 			}
299c9cd5538Skiyohara 
300c9cd5538Skiyohara #define COMMAND_ERROR	(EIS_CMDENDBITERR	| \
301c9cd5538Skiyohara 			 EIS_CMDINDEXERR	| \
302c9cd5538Skiyohara 			 EIS_CMDSTARTBITERR)
303c9cd5538Skiyohara 			if (eis & COMMAND_ERROR) {
304c9cd5538Skiyohara 				error = EIO;		/*Other command errors*/
305c9cd5538Skiyohara 				aprint_error_dev(sc->sc_dev,
306c9cd5538Skiyohara 				    "Command Error (0x%x)\n",
307c9cd5538Skiyohara 				    eis & COMMAND_ERROR);
308c9cd5538Skiyohara 			}
309c9cd5538Skiyohara 
310c9cd5538Skiyohara #define MISC_ERROR	(EIS_RDDATAENDBITERR	| \
311c9cd5538Skiyohara 			 EIS_AUTOCMD12ERR	| \
312c9cd5538Skiyohara 			 EIS_XFERSIZEERR	| \
313c9cd5538Skiyohara 			 EIS_RESPTBITERR)
314c9cd5538Skiyohara 			if (eis & MISC_ERROR) {
315c9cd5538Skiyohara 				error = EIO;		/* Misc error */
316c9cd5538Skiyohara 				aprint_error_dev(sc->sc_dev,
317c9cd5538Skiyohara 				    "Misc Error (0x%x)\n", eis & MISC_ERROR);
318c9cd5538Skiyohara 			}
319c9cd5538Skiyohara 		}
320c9cd5538Skiyohara 
321c9cd5538Skiyohara 		if (cmd != NULL) {
322c9cd5538Skiyohara 			cmd->c_error = error;
323c9cd5538Skiyohara 			cv_signal(&sc->sc_cv);
324c9cd5538Skiyohara 		}
325c9cd5538Skiyohara 		handled = 1;
326c9cd5538Skiyohara 	} else if (cmd != NULL &&
327c9cd5538Skiyohara 	    ((nis & sc->sc_waitintr) || (nis & NIS_UNEXPECTEDRESPDET))) {
328c9cd5538Skiyohara 		sc->sc_exec_cmd = NULL;
329c9cd5538Skiyohara 		sc->sc_waitintr = 0;
330c9cd5538Skiyohara 		if (cmd->c_flags & SCF_RSP_PRESENT) {
331c9cd5538Skiyohara 			uint16_t rh[MVSDIO_NRH + 1];
332c9cd5538Skiyohara 			int i, j;
333c9cd5538Skiyohara 
334c9cd5538Skiyohara 			if (cmd->c_flags & SCF_RSP_136) {
335c9cd5538Skiyohara 				for (i = 0; i < MVSDIO_NRH; i++)
336c9cd5538Skiyohara 					rh[i + 1] = bus_space_read_4(sc->sc_iot,
337c9cd5538Skiyohara 					    sc->sc_ioh, MVSDIO_RH(i));
338c9cd5538Skiyohara 				rh[0] = 0;
339c9cd5538Skiyohara 				for (j = 3, i = 1; j >= 0; j--, i += 2) {
340c9cd5538Skiyohara 					cmd->c_resp[j] =
341c9cd5538Skiyohara 					    rh[i - 1] << 30 |
342c9cd5538Skiyohara 					    rh[i + 0] << 14 |
343c9cd5538Skiyohara 					    rh[i + 1] >> 2;
344c9cd5538Skiyohara 				}
345c9cd5538Skiyohara 				cmd->c_resp[3] &= 0x00ffffff;
346c9cd5538Skiyohara 			} else {
347c9cd5538Skiyohara 				for (i = 0; i < 3; i++)
348c9cd5538Skiyohara 					rh[i] = bus_space_read_4(sc->sc_iot,
349c9cd5538Skiyohara 					    sc->sc_ioh, MVSDIO_RH(i));
350c9cd5538Skiyohara 				cmd->c_resp[0] =
351c9cd5538Skiyohara 				    ((rh[0] & 0x03ff) << 22) |
352c9cd5538Skiyohara 				    ((rh[1]         ) <<  6) |
353c9cd5538Skiyohara 				    ((rh[2] & 0x003f) <<  0);
354c9cd5538Skiyohara 				cmd->c_resp[1] = (rh[0] & 0xfc00) >> 10;
355c9cd5538Skiyohara 				cmd->c_resp[2] = 0;
356c9cd5538Skiyohara 				cmd->c_resp[3] = 0;
357c9cd5538Skiyohara 			}
358c9cd5538Skiyohara 		}
359c9cd5538Skiyohara 		if (nis & NIS_UNEXPECTEDRESPDET)
360c9cd5538Skiyohara 			cmd->c_error = EIO;
361c9cd5538Skiyohara 		cv_signal(&sc->sc_cv);
362c9cd5538Skiyohara 	}
363c9cd5538Skiyohara 
364c9cd5538Skiyohara 	if (nis & NIS_CARDINT)
365c9cd5538Skiyohara 		if (bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE) &
366c9cd5538Skiyohara 		    NIS_CARDINT) {
367c9cd5538Skiyohara 			sdmmc_card_intr(sc->sc_sdmmc);
368c9cd5538Skiyohara 			handled = 1;
369c9cd5538Skiyohara 		}
370c9cd5538Skiyohara 
371c9cd5538Skiyohara 	return handled;
372c9cd5538Skiyohara }
373c9cd5538Skiyohara 
374c9cd5538Skiyohara static int
mvsdio_host_reset(sdmmc_chipset_handle_t sch)375c9cd5538Skiyohara mvsdio_host_reset(sdmmc_chipset_handle_t sch)
376c9cd5538Skiyohara {
377c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
378c9cd5538Skiyohara 
379c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_SR, SR_SWRESET);
380c9cd5538Skiyohara 	return 0;
381c9cd5538Skiyohara }
382c9cd5538Skiyohara 
383c9cd5538Skiyohara static uint32_t
mvsdio_host_ocr(sdmmc_chipset_handle_t sch)384c9cd5538Skiyohara mvsdio_host_ocr(sdmmc_chipset_handle_t sch)
385c9cd5538Skiyohara {
386c9cd5538Skiyohara 
387c9cd5538Skiyohara 	return MMC_OCR_3_3V_3_4V | MMC_OCR_3_2V_3_3V;
388c9cd5538Skiyohara }
389c9cd5538Skiyohara 
390c9cd5538Skiyohara static int
mvsdio_host_maxblklen(sdmmc_chipset_handle_t sch)391c9cd5538Skiyohara mvsdio_host_maxblklen(sdmmc_chipset_handle_t sch)
392c9cd5538Skiyohara {
393c9cd5538Skiyohara 
394c9cd5538Skiyohara 	return DBS_BLOCKSIZE_MAX;
395c9cd5538Skiyohara }
396c9cd5538Skiyohara 
397c9cd5538Skiyohara #ifndef MVSDIO_CARD_DETECT
398c9cd5538Skiyohara static int
mvsdio_card_detect(sdmmc_chipset_handle_t sch)399c9cd5538Skiyohara mvsdio_card_detect(sdmmc_chipset_handle_t sch)
400c9cd5538Skiyohara {
401c9cd5538Skiyohara 	struct mvsdio_softc *sc __unused = (struct mvsdio_softc *)sch;
402c9cd5538Skiyohara 
403c9cd5538Skiyohara 	DPRINTF(2, ("%s: driver lacks card_detect() function.\n",
404c9cd5538Skiyohara 	    device_xname(sc->sc_dev)));
405c9cd5538Skiyohara 	return 1;	/* always detect */
406c9cd5538Skiyohara }
407c9cd5538Skiyohara #endif
408c9cd5538Skiyohara 
409c9cd5538Skiyohara #ifndef MVSDIO_WRITE_PROTECT
410c9cd5538Skiyohara static int
mvsdio_write_protect(sdmmc_chipset_handle_t sch)411c9cd5538Skiyohara mvsdio_write_protect(sdmmc_chipset_handle_t sch)
412c9cd5538Skiyohara {
413c9cd5538Skiyohara 
414c9cd5538Skiyohara 	/* Nothing */
415c9cd5538Skiyohara 
416c9cd5538Skiyohara 	return 0;
417c9cd5538Skiyohara }
418c9cd5538Skiyohara #endif
419c9cd5538Skiyohara 
420c9cd5538Skiyohara static int
mvsdio_bus_power(sdmmc_chipset_handle_t sch,uint32_t ocr)421c9cd5538Skiyohara mvsdio_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
422c9cd5538Skiyohara {
423c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
424c9cd5538Skiyohara 	uint32_t reg;
425c9cd5538Skiyohara 
426c9cd5538Skiyohara 	/* Initial state is Open Drain on CMD line. */
427c9cd5538Skiyohara 	mutex_enter(&sc->sc_mtx);
428c9cd5538Skiyohara 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC);
429c9cd5538Skiyohara 	reg &= ~HC_PUSHPULLEN;
430c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg);
431c9cd5538Skiyohara 	mutex_exit(&sc->sc_mtx);
432c9cd5538Skiyohara 
433c9cd5538Skiyohara 	return 0;
434c9cd5538Skiyohara }
435c9cd5538Skiyohara 
436c9cd5538Skiyohara static int
mvsdio_bus_clock(sdmmc_chipset_handle_t sch,int freq)437c9cd5538Skiyohara mvsdio_bus_clock(sdmmc_chipset_handle_t sch, int freq)
438c9cd5538Skiyohara {
439c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
440c9cd5538Skiyohara 	uint32_t reg;
441c9cd5538Skiyohara 	int m;
442c9cd5538Skiyohara 
443c9cd5538Skiyohara 	mutex_enter(&sc->sc_mtx);
444c9cd5538Skiyohara 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM);
445c9cd5538Skiyohara 
446c9cd5538Skiyohara 	/* Just stop the clock. */
447c9cd5538Skiyohara 	if (freq == 0) {
448c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM,
449c9cd5538Skiyohara 		    reg | TM_STOPCLKEN);
450c9cd5538Skiyohara 		goto out;
451c9cd5538Skiyohara 	}
452c9cd5538Skiyohara 
453c9cd5538Skiyohara #define FREQ_TO_M(f)	(100000 / (f) - 1)
454c9cd5538Skiyohara 
455c9cd5538Skiyohara 	m = FREQ_TO_M(freq);
456c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_CDV,
457c9cd5538Skiyohara 	    m & CDV_CLKDVDRMVALUE_MASK);
458c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM,
459c9cd5538Skiyohara 	    reg & ~TM_STOPCLKEN);
460c9cd5538Skiyohara 
461c9cd5538Skiyohara 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC);
462c9cd5538Skiyohara 	if (freq > 25000)
463c9cd5538Skiyohara 		reg |= HC_HISPEEDEN;
464c9cd5538Skiyohara 	else
465c9cd5538Skiyohara 		reg &= ~HC_HISPEEDEN;	/* up to 25 MHz */
466c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg);
467c9cd5538Skiyohara 
468c9cd5538Skiyohara out:
469c9cd5538Skiyohara 	mutex_exit(&sc->sc_mtx);
470c9cd5538Skiyohara 
471c9cd5538Skiyohara 	return 0;
472c9cd5538Skiyohara }
473c9cd5538Skiyohara 
474c9cd5538Skiyohara static int
mvsdio_bus_width(sdmmc_chipset_handle_t sch,int width)475c9cd5538Skiyohara mvsdio_bus_width(sdmmc_chipset_handle_t sch, int width)
476c9cd5538Skiyohara {
477c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
478c9cd5538Skiyohara 	uint32_t reg, v;
479c9cd5538Skiyohara 
480c9cd5538Skiyohara 	switch (width) {
481c9cd5538Skiyohara 	case 1:
482c9cd5538Skiyohara 		v = 0;
483c9cd5538Skiyohara 		break;
484c9cd5538Skiyohara 
485c9cd5538Skiyohara 	case 4:
486c9cd5538Skiyohara 		v = HC_DATAWIDTH;
487c9cd5538Skiyohara 		break;
488c9cd5538Skiyohara 
489c9cd5538Skiyohara 	default:
490c9cd5538Skiyohara 		DPRINTF(0, ("%s: unsupported bus width (%d)\n",
491c9cd5538Skiyohara 		    device_xname(sc->sc_dev), width));
492c9cd5538Skiyohara 		return EINVAL;
493c9cd5538Skiyohara 	}
494c9cd5538Skiyohara 
495c9cd5538Skiyohara 	mutex_enter(&sc->sc_mtx);
496c9cd5538Skiyohara 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC);
497c9cd5538Skiyohara 	reg &= ~HC_DATAWIDTH;
498c9cd5538Skiyohara 	reg |= v;
499c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg);
500c9cd5538Skiyohara 	mutex_exit(&sc->sc_mtx);
501c9cd5538Skiyohara 
502c9cd5538Skiyohara 	return 0;
503c9cd5538Skiyohara }
504c9cd5538Skiyohara 
505c9cd5538Skiyohara static int
mvsdio_bus_rod(sdmmc_chipset_handle_t sch,int on)506c9cd5538Skiyohara mvsdio_bus_rod(sdmmc_chipset_handle_t sch, int on)
507c9cd5538Skiyohara {
508c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
509c9cd5538Skiyohara 	uint32_t reg;
510c9cd5538Skiyohara 
511c9cd5538Skiyohara 	/* Change Open-drain/Push-pull. */
512c9cd5538Skiyohara 	mutex_enter(&sc->sc_mtx);
513c9cd5538Skiyohara 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC);
514c9cd5538Skiyohara 	if (on)
515c9cd5538Skiyohara 		reg &= ~HC_PUSHPULLEN;
516c9cd5538Skiyohara 	else
517c9cd5538Skiyohara 		reg |= HC_PUSHPULLEN;
518c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, reg);
519c9cd5538Skiyohara 	mutex_exit(&sc->sc_mtx);
520c9cd5538Skiyohara 
521c9cd5538Skiyohara 	return 0;
522c9cd5538Skiyohara }
523c9cd5538Skiyohara 
524c9cd5538Skiyohara static void
mvsdio_exec_command(sdmmc_chipset_handle_t sch,struct sdmmc_command * cmd)525c9cd5538Skiyohara mvsdio_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
526c9cd5538Skiyohara {
527c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
528c9cd5538Skiyohara 	uint32_t tm, c, hc, aacc, nisie, wait;
529c9cd5538Skiyohara 	int blklen;
530c9cd5538Skiyohara 
531c9cd5538Skiyohara 	DPRINTF(1, ("%s: start cmd %d arg=%#x data=%p dlen=%d flags=%#x\n",
532c9cd5538Skiyohara 	    device_xname(sc->sc_dev), cmd->c_opcode, cmd->c_arg, cmd->c_data,
533c9cd5538Skiyohara 	    cmd->c_datalen, cmd->c_flags));
534c9cd5538Skiyohara 
535c9cd5538Skiyohara 	mutex_enter(&sc->sc_mtx);
536c9cd5538Skiyohara 
537c9cd5538Skiyohara 	tm = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM);
538c9cd5538Skiyohara 
539c9cd5538Skiyohara 	if (cmd->c_datalen > 0) {
540c9cd5538Skiyohara 		bus_dma_segment_t *dm_seg =
541c9cd5538Skiyohara 		    &cmd->c_dmamap->dm_segs[cmd->c_dmaseg];
542c9cd5538Skiyohara 		bus_addr_t ds_addr = dm_seg->ds_addr + cmd->c_dmaoff;
543c9cd5538Skiyohara 
544c9cd5538Skiyohara 		blklen = MIN(cmd->c_datalen, cmd->c_blklen);
545c9cd5538Skiyohara 
546c9cd5538Skiyohara 		if (cmd->c_datalen % blklen > 0) {
547c9cd5538Skiyohara 			aprint_error_dev(sc->sc_dev,
548c9cd5538Skiyohara 			    "data not a multiple of %u bytes\n", blklen);
549c9cd5538Skiyohara 			cmd->c_error = EINVAL;
550c9cd5538Skiyohara 			goto out;
551c9cd5538Skiyohara 		}
552c9cd5538Skiyohara 		if ((uint32_t)cmd->c_data & 0x3) {
553c9cd5538Skiyohara 			aprint_error_dev(sc->sc_dev,
554c9cd5538Skiyohara 			    "data not 4byte aligned\n");
555c9cd5538Skiyohara 			cmd->c_error = EINVAL;
556c9cd5538Skiyohara 			goto out;
557c9cd5538Skiyohara 		}
558c9cd5538Skiyohara 
559c9cd5538Skiyohara 		/* Set DMA Buffer Address */
560c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DMABA16LSB,
561c9cd5538Skiyohara 		    ds_addr & 0xffff);
562c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DMABA16MSB,
563c9cd5538Skiyohara 		    (ds_addr >> 16) & 0xffff);
564c9cd5538Skiyohara 
565c9cd5538Skiyohara 		/* Set Data Block Size and Count */
566c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DBS,
567c9cd5538Skiyohara 		    DBS_BLOCKSIZE(blklen));
568c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_DBC,
569c9cd5538Skiyohara 		    DBC_BLOCKCOUNT(cmd->c_datalen / blklen));
570c9cd5538Skiyohara 
571c9cd5538Skiyohara 		tm &= ~TM_HOSTXFERMODE;			/* Always DMA */
572c9cd5538Skiyohara 		if (cmd->c_flags & SCF_CMD_READ)
573c9cd5538Skiyohara 			tm |= TM_DATAXFERTOWARDHOST;
574c9cd5538Skiyohara 		else
575c9cd5538Skiyohara 			tm &= ~TM_DATAXFERTOWARDHOST;
576c9cd5538Skiyohara 		tm |= TM_HWWRDATAEN;
577c9cd5538Skiyohara 		wait = NIS_XFERCOMPLETE;
578c9cd5538Skiyohara 	} else {
579c9cd5538Skiyohara 		tm &= ~TM_HWWRDATAEN;
580c9cd5538Skiyohara 		wait = NIS_CMDCOMPLETE;
581c9cd5538Skiyohara 	}
582c9cd5538Skiyohara 
583c9cd5538Skiyohara 	/* Set Argument in Command */
584c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AC16LSB,
585c9cd5538Skiyohara 	    cmd->c_arg & 0xffff);
586c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AC16MSB,
587c9cd5538Skiyohara 	    (cmd->c_arg >> 16) & 0xffff);
588c9cd5538Skiyohara 
589c9cd5538Skiyohara 	/* Set Host Control, exclude PushPullEn, DataWidth, HiSpeedEn. */
590c9cd5538Skiyohara 	hc = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC);
591c9cd5538Skiyohara 	hc |= (HC_TIMEOUTVALUE_MAX | HC_TIMEOUTEN);
592c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_HC, hc);
593c9cd5538Skiyohara 
594c9cd5538Skiyohara 	/* Data Block Gap Control: Resume */
595c9cd5538Skiyohara 
596c9cd5538Skiyohara 	/* Clock Control: SclkMasterEn */
597c9cd5538Skiyohara 
598c9cd5538Skiyohara 	if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE ||
599c9cd5538Skiyohara 	    cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE) {
600c9cd5538Skiyohara 		aacc = 0;
601c9cd5538Skiyohara #if 1	/* XXXX: need? */
602c9cd5538Skiyohara 		if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE) {
603c9cd5538Skiyohara 			struct sdmmc_softc *sdmmc =
604c9cd5538Skiyohara 			    device_private(sc->sc_sdmmc);
605c9cd5538Skiyohara 			struct sdmmc_function *sf = sdmmc->sc_card;
606c9cd5538Skiyohara 
607c9cd5538Skiyohara 			aacc = MMC_ARG_RCA(sf->rca);
608c9cd5538Skiyohara 		}
609c9cd5538Skiyohara #endif
610c9cd5538Skiyohara 
611c9cd5538Skiyohara 		/* Set Argument in Auto Cmd12 Command */
612c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AACC16LSBT,
613c9cd5538Skiyohara 		    aacc & 0xffff);
614c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_AACC16MSBT,
615c9cd5538Skiyohara 		    (aacc >> 16) & 0xffff);
616c9cd5538Skiyohara 
617c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_IACCT,
618c9cd5538Skiyohara 		    IACCT_AUTOCMD12BUSYCHKEN	|
619c9cd5538Skiyohara 		    IACCT_AUTOCMD12INDEXCHKEN	|
620c9cd5538Skiyohara 		    IACCT_AUTOCMD12INDEX);
621c9cd5538Skiyohara 
622c9cd5538Skiyohara 		tm |= TM_AUTOCMD12EN;
623c9cd5538Skiyohara 		wait = NIS_AUTOCMD12COMPLETE;
624c9cd5538Skiyohara 	} else
625c9cd5538Skiyohara 		tm &= ~TM_AUTOCMD12EN;
626c9cd5538Skiyohara 
627c9cd5538Skiyohara 	tm |= TM_INTCHKEN;
628c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_TM, tm);
629c9cd5538Skiyohara 
630c9cd5538Skiyohara 	c = C_CMDINDEX(cmd->c_opcode);
631c9cd5538Skiyohara 	if (cmd->c_flags & SCF_RSP_PRESENT) {
632c9cd5538Skiyohara 		if (cmd->c_flags & SCF_RSP_136)
633c9cd5538Skiyohara 			c |= C_RESPTYPE_136BR;
634c9cd5538Skiyohara 		else if (!(cmd->c_flags & SCF_RSP_BSY))
635c9cd5538Skiyohara 			c |= C_RESPTYPE_48BR;
636c9cd5538Skiyohara 		else
637c9cd5538Skiyohara 			c |= C_RESPTYPE_48BRCB;
638c9cd5538Skiyohara 		c |= C_UNEXPECTEDRESPEN;
639c9cd5538Skiyohara 	} else
640c9cd5538Skiyohara 		c |= C_RESPTYPE_NR;
641c9cd5538Skiyohara 	if (cmd->c_flags & SCF_RSP_CRC)
642c9cd5538Skiyohara 		c |= C_CMDCRCCHKEN;
643c9cd5538Skiyohara 	if (cmd->c_flags & SCF_RSP_IDX)
644c9cd5538Skiyohara 		c |= C_CMDINDEXCHKEN;
645c9cd5538Skiyohara 	if (cmd->c_datalen > 0)
646c9cd5538Skiyohara 		c |= (C_DATAPRESENT | C_DATACRC16CHKEN);
647c9cd5538Skiyohara 
648c9cd5538Skiyohara 	DPRINTF(2, ("%s: TM=0x%x, C=0x%x, HC=0x%x\n", __func__, tm, c, hc));
649c9cd5538Skiyohara 
650c9cd5538Skiyohara 	nisie = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE);
651c9cd5538Skiyohara 	nisie &= ~(NIS_CMDCOMPLETE | NIS_XFERCOMPLETE | NIS_AUTOCMD12COMPLETE);
652c9cd5538Skiyohara 	nisie |= wait;
653c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE, nisie);
654c9cd5538Skiyohara 
655c9cd5538Skiyohara 	/* Execute command */
656c9cd5538Skiyohara 	sc->sc_exec_cmd = cmd;
657c9cd5538Skiyohara 	sc->sc_waitintr = wait;
658c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_C, c);
659c9cd5538Skiyohara 
660c9cd5538Skiyohara 	/* Wait interrupt for complete or error or timeout */
661c9cd5538Skiyohara 	while (sc->sc_exec_cmd == cmd)
662c9cd5538Skiyohara 		cv_wait(&sc->sc_cv, &sc->sc_mtx);
663c9cd5538Skiyohara 
664c9cd5538Skiyohara out:
665c9cd5538Skiyohara 	mutex_exit(&sc->sc_mtx);
666c9cd5538Skiyohara 
667c9cd5538Skiyohara 	DPRINTF(1, ("%s: cmd %d done (flags=%08x error=%d)\n",
668c9cd5538Skiyohara 	    device_xname(sc->sc_dev),
669c9cd5538Skiyohara 	    cmd->c_opcode, cmd->c_flags, cmd->c_error));
670c9cd5538Skiyohara }
671c9cd5538Skiyohara 
672c9cd5538Skiyohara static void
mvsdio_card_enable_intr(sdmmc_chipset_handle_t sch,int enable)673c9cd5538Skiyohara mvsdio_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
674c9cd5538Skiyohara {
675c9cd5538Skiyohara 	struct mvsdio_softc *sc = (struct mvsdio_softc *)sch;
676c9cd5538Skiyohara 	uint32_t reg;
677c9cd5538Skiyohara 
678c9cd5538Skiyohara 	mutex_enter(&sc->sc_mtx);
679c9cd5538Skiyohara 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE);
680c9cd5538Skiyohara 	reg |= NIS_CARDINT;
681c9cd5538Skiyohara 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_NISIE, reg);
682c9cd5538Skiyohara 	mutex_exit(&sc->sc_mtx);
683c9cd5538Skiyohara }
684c9cd5538Skiyohara 
685c9cd5538Skiyohara static void
mvsdio_card_intr_ack(sdmmc_chipset_handle_t sch)686c9cd5538Skiyohara mvsdio_card_intr_ack(sdmmc_chipset_handle_t sch)
687c9cd5538Skiyohara {
688c9cd5538Skiyohara 
689c9cd5538Skiyohara 	/* Nothing */
690c9cd5538Skiyohara }
691c9cd5538Skiyohara 
692c9cd5538Skiyohara 
693c9cd5538Skiyohara static void
mvsdio_wininit(struct mvsdio_softc * sc,enum marvell_tags * tags)694c51a6569Skiyohara mvsdio_wininit(struct mvsdio_softc *sc, enum marvell_tags *tags)
695c9cd5538Skiyohara {
696c9cd5538Skiyohara 	uint64_t base;
697c9cd5538Skiyohara 	uint32_t size;
698c9cd5538Skiyohara 	int window, target, attr, rv, i;
699c9cd5538Skiyohara 
700c9cd5538Skiyohara 	for (window = 0, i = 0;
701c9cd5538Skiyohara 	    tags[i] != MARVELL_TAG_UNDEFINED && window < MVSDIO_NWINDOW; i++) {
702c9cd5538Skiyohara 		rv = marvell_winparams_by_tag(sc->sc_dev, tags[i],
703c9cd5538Skiyohara 		    &target, &attr, &base, &size);
704c9cd5538Skiyohara 		if (rv != 0 || size == 0)
705c9cd5538Skiyohara 			continue;
706c9cd5538Skiyohara 
707c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_WC(window),
708c9cd5538Skiyohara 		    WC_WINEN		|
709c9cd5538Skiyohara 		    WC_TARGET(target)	|
710c9cd5538Skiyohara 		    WC_ATTR(attr)	|
711c9cd5538Skiyohara 		    WC_SIZE(size));
712c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_WB(window),
713c9cd5538Skiyohara 		    WB_BASE(base));
714c9cd5538Skiyohara 		window++;
715c9cd5538Skiyohara 	}
716c9cd5538Skiyohara 	for (; window < MVSDIO_NWINDOW; window++)
717c9cd5538Skiyohara 		bus_space_write_4(sc->sc_iot, sc->sc_ioh, MVSDIO_WC(window), 0);
718c9cd5538Skiyohara }
719