1184138Smav/*-
2184138Smav * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
3184138Smav * All rights reserved.
4184138Smav *
5184138Smav * Redistribution and use in source and binary forms, with or without
6184138Smav * modification, are permitted provided that the following conditions
7184138Smav * are met:
8184138Smav * 1. Redistributions of source code must retain the above copyright
9184138Smav *    notice, this list of conditions and the following disclaimer.
10184138Smav * 2. Redistributions in binary form must reproduce the above copyright
11184138Smav *    notice, this list of conditions and the following disclaimer in the
12184138Smav *    documentation and/or other materials provided with the distribution.
13184138Smav *
14184138Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15184138Smav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16184138Smav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17184138Smav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18184138Smav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19184138Smav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20184138Smav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21184138Smav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22184138Smav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23184138Smav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24184138Smav */
25184138Smav
26184138Smav#include <sys/cdefs.h>
27184138Smav__FBSDID("$FreeBSD: releng/10.3/sys/dev/sdhci/sdhci.c 283318 2015-05-23 17:43:02Z ian $");
28184138Smav
29184138Smav#include <sys/param.h>
30184138Smav#include <sys/systm.h>
31184138Smav#include <sys/bus.h>
32266200Sian#include <sys/callout.h>
33184138Smav#include <sys/conf.h>
34184138Smav#include <sys/kernel.h>
35184138Smav#include <sys/lock.h>
36184138Smav#include <sys/module.h>
37184138Smav#include <sys/mutex.h>
38184138Smav#include <sys/resource.h>
39184138Smav#include <sys/rman.h>
40187876Smav#include <sys/sysctl.h>
41184138Smav#include <sys/taskqueue.h>
42184138Smav
43184138Smav#include <machine/bus.h>
44184138Smav#include <machine/resource.h>
45184138Smav#include <machine/stdarg.h>
46184138Smav
47184138Smav#include <dev/mmc/bridge.h>
48184138Smav#include <dev/mmc/mmcreg.h>
49184138Smav#include <dev/mmc/mmcbrvar.h>
50184138Smav
51184138Smav#include "mmcbr_if.h"
52184138Smav#include "sdhci.h"
53241600Sgonzo#include "sdhci_if.h"
54184138Smav
55271051SmariusSYSCTL_NODE(_hw, OID_AUTO, sdhci, CTLFLAG_RD, 0, "sdhci driver");
56184138Smav
57271051Smariusstatic int sdhci_debug;
58187876SmavTUNABLE_INT("hw.sdhci.debug", &sdhci_debug);
59271051SmariusSYSCTL_INT(_hw_sdhci, OID_AUTO, debug, CTLFLAG_RWTUN, &sdhci_debug, 0, "Debug level");
60187876Smav
61241600Sgonzo#define RD1(slot, off)	SDHCI_READ_1((slot)->bus, (slot), (off))
62241600Sgonzo#define RD2(slot, off)	SDHCI_READ_2((slot)->bus, (slot), (off))
63241600Sgonzo#define RD4(slot, off)	SDHCI_READ_4((slot)->bus, (slot), (off))
64241600Sgonzo#define RD_MULTI_4(slot, off, ptr, count)	\
65241600Sgonzo    SDHCI_READ_MULTI_4((slot)->bus, (slot), (off), (ptr), (count))
66184138Smav
67241600Sgonzo#define WR1(slot, off, val)	SDHCI_WRITE_1((slot)->bus, (slot), (off), (val))
68241600Sgonzo#define WR2(slot, off, val)	SDHCI_WRITE_2((slot)->bus, (slot), (off), (val))
69241600Sgonzo#define WR4(slot, off, val)	SDHCI_WRITE_4((slot)->bus, (slot), (off), (val))
70241600Sgonzo#define WR_MULTI_4(slot, off, ptr, count)	\
71241600Sgonzo    SDHCI_WRITE_MULTI_4((slot)->bus, (slot), (off), (ptr), (count))
72184138Smav
73184138Smavstatic void sdhci_set_clock(struct sdhci_slot *slot, uint32_t clock);
74184138Smavstatic void sdhci_start(struct sdhci_slot *slot);
75184138Smavstatic void sdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data);
76184138Smav
77184138Smavstatic void sdhci_card_task(void *, int);
78184138Smav
79184138Smav/* helper routines */
80184138Smav#define SDHCI_LOCK(_slot)		mtx_lock(&(_slot)->mtx)
81184138Smav#define	SDHCI_UNLOCK(_slot)		mtx_unlock(&(_slot)->mtx)
82184138Smav#define SDHCI_LOCK_INIT(_slot) \
83184138Smav	mtx_init(&_slot->mtx, "SD slot mtx", "sdhci", MTX_DEF)
84184138Smav#define SDHCI_LOCK_DESTROY(_slot)	mtx_destroy(&_slot->mtx);
85184138Smav#define SDHCI_ASSERT_LOCKED(_slot)	mtx_assert(&_slot->mtx, MA_OWNED);
86184138Smav#define SDHCI_ASSERT_UNLOCKED(_slot)	mtx_assert(&_slot->mtx, MA_NOTOWNED);
87184138Smav
88243689Sgonzo#define	SDHCI_DEFAULT_MAX_FREQ	50
89243689Sgonzo
90246886Sgonzo#define	SDHCI_200_MAX_DIVIDER	256
91246886Sgonzo#define	SDHCI_300_MAX_DIVIDER	2046
92246886Sgonzo
93241600Sgonzostatic void
94241600Sgonzosdhci_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
95241600Sgonzo{
96241600Sgonzo	if (error != 0) {
97241600Sgonzo		printf("getaddr: error %d\n", error);
98241600Sgonzo		return;
99241600Sgonzo	}
100241600Sgonzo	*(bus_addr_t *)arg = segs[0].ds_addr;
101241600Sgonzo}
102241600Sgonzo
103184138Smavstatic int
104184138Smavslot_printf(struct sdhci_slot *slot, const char * fmt, ...)
105184138Smav{
106184138Smav	va_list ap;
107184138Smav	int retval;
108184138Smav
109184138Smav    	retval = printf("%s-slot%d: ",
110241600Sgonzo	    device_get_nameunit(slot->bus), slot->num);
111184138Smav
112184138Smav	va_start(ap, fmt);
113184138Smav	retval += vprintf(fmt, ap);
114184138Smav	va_end(ap);
115184138Smav	return (retval);
116184138Smav}
117184138Smav
118184138Smavstatic void
119184138Smavsdhci_dumpregs(struct sdhci_slot *slot)
120184138Smav{
121184138Smav	slot_printf(slot,
122184138Smav	    "============== REGISTER DUMP ==============\n");
123184138Smav
124184138Smav	slot_printf(slot, "Sys addr: 0x%08x | Version:  0x%08x\n",
125184138Smav	    RD4(slot, SDHCI_DMA_ADDRESS), RD2(slot, SDHCI_HOST_VERSION));
126184138Smav	slot_printf(slot, "Blk size: 0x%08x | Blk cnt:  0x%08x\n",
127184138Smav	    RD2(slot, SDHCI_BLOCK_SIZE), RD2(slot, SDHCI_BLOCK_COUNT));
128184138Smav	slot_printf(slot, "Argument: 0x%08x | Trn mode: 0x%08x\n",
129184138Smav	    RD4(slot, SDHCI_ARGUMENT), RD2(slot, SDHCI_TRANSFER_MODE));
130184138Smav	slot_printf(slot, "Present:  0x%08x | Host ctl: 0x%08x\n",
131184138Smav	    RD4(slot, SDHCI_PRESENT_STATE), RD1(slot, SDHCI_HOST_CONTROL));
132184138Smav	slot_printf(slot, "Power:    0x%08x | Blk gap:  0x%08x\n",
133184138Smav	    RD1(slot, SDHCI_POWER_CONTROL), RD1(slot, SDHCI_BLOCK_GAP_CONTROL));
134184138Smav	slot_printf(slot, "Wake-up:  0x%08x | Clock:    0x%08x\n",
135184138Smav	    RD1(slot, SDHCI_WAKE_UP_CONTROL), RD2(slot, SDHCI_CLOCK_CONTROL));
136184138Smav	slot_printf(slot, "Timeout:  0x%08x | Int stat: 0x%08x\n",
137184138Smav	    RD1(slot, SDHCI_TIMEOUT_CONTROL), RD4(slot, SDHCI_INT_STATUS));
138184138Smav	slot_printf(slot, "Int enab: 0x%08x | Sig enab: 0x%08x\n",
139184138Smav	    RD4(slot, SDHCI_INT_ENABLE), RD4(slot, SDHCI_SIGNAL_ENABLE));
140184138Smav	slot_printf(slot, "AC12 err: 0x%08x | Slot int: 0x%08x\n",
141184138Smav	    RD2(slot, SDHCI_ACMD12_ERR), RD2(slot, SDHCI_SLOT_INT_STATUS));
142184138Smav	slot_printf(slot, "Caps:     0x%08x | Max curr: 0x%08x\n",
143184138Smav	    RD4(slot, SDHCI_CAPABILITIES), RD4(slot, SDHCI_MAX_CURRENT));
144184138Smav
145184138Smav	slot_printf(slot,
146184138Smav	    "===========================================\n");
147184138Smav}
148184138Smav
149184138Smavstatic void
150184138Smavsdhci_reset(struct sdhci_slot *slot, uint8_t mask)
151184138Smav{
152184138Smav	int timeout;
153184138Smav
154241600Sgonzo	if (slot->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
155184138Smav		if (!(RD4(slot, SDHCI_PRESENT_STATE) &
156184138Smav			SDHCI_CARD_PRESENT))
157184138Smav			return;
158184138Smav	}
159184138Smav
160184138Smav	/* Some controllers need this kick or reset won't work. */
161184138Smav	if ((mask & SDHCI_RESET_ALL) == 0 &&
162241600Sgonzo	    (slot->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)) {
163184138Smav		uint32_t clock;
164184138Smav
165184138Smav		/* This is to force an update */
166184138Smav		clock = slot->clock;
167184138Smav		slot->clock = 0;
168184138Smav		sdhci_set_clock(slot, clock);
169184138Smav	}
170184138Smav
171185661Smav	if (mask & SDHCI_RESET_ALL) {
172184138Smav		slot->clock = 0;
173185661Smav		slot->power = 0;
174185661Smav	}
175184138Smav
176276287Sian	WR1(slot, SDHCI_SOFTWARE_RESET, mask);
177276287Sian
178276287Sian	if (slot->quirks & SDHCI_QUIRK_WAITFOR_RESET_ASSERTED) {
179276287Sian		/*
180276287Sian		 * Resets on TI OMAPs and AM335x are incompatible with SDHCI
181276287Sian		 * specification.  The reset bit has internal propagation delay,
182276287Sian		 * so a fast read after write returns 0 even if reset process is
183276287Sian		 * in progress. The workaround is to poll for 1 before polling
184276287Sian		 * for 0.  In the worst case, if we miss seeing it asserted the
185276287Sian		 * time we spent waiting is enough to ensure the reset finishes.
186276287Sian		 */
187276287Sian		timeout = 10000;
188276287Sian		while ((RD1(slot, SDHCI_SOFTWARE_RESET) & mask) != mask) {
189276287Sian			if (timeout <= 0)
190276287Sian				break;
191276287Sian			timeout--;
192276287Sian			DELAY(1);
193276287Sian		}
194276287Sian	}
195276287Sian
196184138Smav	/* Wait max 100 ms */
197276287Sian	timeout = 10000;
198184138Smav	/* Controller clears the bits when it's done */
199276287Sian	while (RD1(slot, SDHCI_SOFTWARE_RESET) & mask) {
200276287Sian		if (timeout <= 0) {
201276287Sian			slot_printf(slot, "Reset 0x%x never completed.\n",
202276287Sian			    mask);
203184138Smav			sdhci_dumpregs(slot);
204184138Smav			return;
205184138Smav		}
206184138Smav		timeout--;
207276287Sian		DELAY(10);
208184138Smav	}
209184138Smav}
210184138Smav
211184138Smavstatic void
212184138Smavsdhci_init(struct sdhci_slot *slot)
213184138Smav{
214184138Smav
215184138Smav	sdhci_reset(slot, SDHCI_RESET_ALL);
216184138Smav
217184138Smav	/* Enable interrupts. */
218184138Smav	slot->intmask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT |
219184138Smav	    SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX |
220184138Smav	    SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
221184138Smav	    SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
222184138Smav	    SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
223184138Smav	    SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
224184138Smav	    SDHCI_INT_ACMD12ERR;
225184138Smav	WR4(slot, SDHCI_INT_ENABLE, slot->intmask);
226184138Smav	WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
227184138Smav}
228184138Smav
229184138Smavstatic void
230184138Smavsdhci_set_clock(struct sdhci_slot *slot, uint32_t clock)
231184138Smav{
232184138Smav	uint32_t res;
233184138Smav	uint16_t clk;
234242320Sgonzo	uint16_t div;
235184138Smav	int timeout;
236184138Smav
237184138Smav	if (clock == slot->clock)
238184138Smav		return;
239184138Smav	slot->clock = clock;
240184138Smav
241184138Smav	/* Turn off the clock. */
242266751Sian	clk = RD2(slot, SDHCI_CLOCK_CONTROL);
243266751Sian	WR2(slot, SDHCI_CLOCK_CONTROL, clk & ~SDHCI_CLOCK_CARD_EN);
244184138Smav	/* If no clock requested - left it so. */
245184138Smav	if (clock == 0)
246184138Smav		return;
247254423Sian
248254423Sian	/* Recalculate timeout clock frequency based on the new sd clock. */
249254423Sian	if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
250254423Sian		slot->timeout_clk = slot->clock / 1000;
251254423Sian
252242320Sgonzo	if (slot->version < SDHCI_SPEC_300) {
253242320Sgonzo		/* Looking for highest freq <= clock. */
254242320Sgonzo		res = slot->max_clk;
255246886Sgonzo		for (div = 1; div < SDHCI_200_MAX_DIVIDER; div <<= 1) {
256242320Sgonzo			if (res <= clock)
257242320Sgonzo				break;
258242320Sgonzo			res >>= 1;
259242320Sgonzo		}
260242320Sgonzo		/* Divider 1:1 is 0x00, 2:1 is 0x01, 256:1 is 0x80 ... */
261242320Sgonzo		div >>= 1;
262184138Smav	}
263242320Sgonzo	else {
264242320Sgonzo		/* Version 3.0 divisors are multiples of two up to 1023*2 */
265246886Sgonzo		if (clock >= slot->max_clk)
266246886Sgonzo			div = 0;
267242320Sgonzo		else {
268246886Sgonzo			for (div = 2; div < SDHCI_300_MAX_DIVIDER; div += 2) {
269242320Sgonzo				if ((slot->max_clk / div) <= clock)
270242320Sgonzo					break;
271242320Sgonzo			}
272242320Sgonzo		}
273242320Sgonzo		div >>= 1;
274242320Sgonzo	}
275242320Sgonzo
276242320Sgonzo	if (bootverbose || sdhci_debug)
277242320Sgonzo		slot_printf(slot, "Divider %d for freq %d (max %d)\n",
278242320Sgonzo			div, clock, slot->max_clk);
279242320Sgonzo
280184138Smav	/* Now we have got divider, set it. */
281242320Sgonzo	clk = (div & SDHCI_DIVIDER_MASK) << SDHCI_DIVIDER_SHIFT;
282242320Sgonzo	clk |= ((div >> SDHCI_DIVIDER_MASK_LEN) & SDHCI_DIVIDER_HI_MASK)
283242320Sgonzo		<< SDHCI_DIVIDER_HI_SHIFT;
284242320Sgonzo
285184138Smav	WR2(slot, SDHCI_CLOCK_CONTROL, clk);
286184138Smav	/* Enable clock. */
287184138Smav	clk |= SDHCI_CLOCK_INT_EN;
288184138Smav	WR2(slot, SDHCI_CLOCK_CONTROL, clk);
289184138Smav	/* Wait up to 10 ms until it stabilize. */
290184138Smav	timeout = 10;
291184138Smav	while (!((clk = RD2(slot, SDHCI_CLOCK_CONTROL))
292184138Smav		& SDHCI_CLOCK_INT_STABLE)) {
293184138Smav		if (timeout == 0) {
294184138Smav			slot_printf(slot,
295184138Smav			    "Internal clock never stabilised.\n");
296184138Smav			sdhci_dumpregs(slot);
297184138Smav			return;
298184138Smav		}
299184138Smav		timeout--;
300184138Smav		DELAY(1000);
301184138Smav	}
302184138Smav	/* Pass clock signal to the bus. */
303184138Smav	clk |= SDHCI_CLOCK_CARD_EN;
304184138Smav	WR2(slot, SDHCI_CLOCK_CONTROL, clk);
305184138Smav}
306184138Smav
307184138Smavstatic void
308184138Smavsdhci_set_power(struct sdhci_slot *slot, u_char power)
309184138Smav{
310184138Smav	uint8_t pwr;
311184138Smav
312184138Smav	if (slot->power == power)
313184138Smav		return;
314241600Sgonzo
315184138Smav	slot->power = power;
316184138Smav
317184138Smav	/* Turn off the power. */
318184138Smav	pwr = 0;
319184138Smav	WR1(slot, SDHCI_POWER_CONTROL, pwr);
320184138Smav	/* If power down requested - left it so. */
321184138Smav	if (power == 0)
322184138Smav		return;
323184138Smav	/* Set voltage. */
324184138Smav	switch (1 << power) {
325184138Smav	case MMC_OCR_LOW_VOLTAGE:
326184138Smav		pwr |= SDHCI_POWER_180;
327184138Smav		break;
328184138Smav	case MMC_OCR_290_300:
329184138Smav	case MMC_OCR_300_310:
330184138Smav		pwr |= SDHCI_POWER_300;
331184138Smav		break;
332184138Smav	case MMC_OCR_320_330:
333184138Smav	case MMC_OCR_330_340:
334184138Smav		pwr |= SDHCI_POWER_330;
335184138Smav		break;
336184138Smav	}
337184138Smav	WR1(slot, SDHCI_POWER_CONTROL, pwr);
338184138Smav	/* Turn on the power. */
339184138Smav	pwr |= SDHCI_POWER_ON;
340184138Smav	WR1(slot, SDHCI_POWER_CONTROL, pwr);
341184138Smav}
342184138Smav
343184138Smavstatic void
344184138Smavsdhci_read_block_pio(struct sdhci_slot *slot)
345184138Smav{
346184138Smav	uint32_t data;
347184138Smav	char *buffer;
348184138Smav	size_t left;
349184138Smav
350184138Smav	buffer = slot->curcmd->data->data;
351184138Smav	buffer += slot->offset;
352184138Smav	/* Transfer one block at a time. */
353184138Smav	left = min(512, slot->curcmd->data->len - slot->offset);
354184138Smav	slot->offset += left;
355184138Smav
356184138Smav	/* If we are too fast, broken controllers return zeroes. */
357241600Sgonzo	if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS)
358184138Smav		DELAY(10);
359254512Srpaulo	/* Handle unaligned and aligned buffer cases. */
360184138Smav	if ((intptr_t)buffer & 3) {
361184138Smav		while (left > 3) {
362184138Smav			data = RD4(slot, SDHCI_BUFFER);
363184138Smav			buffer[0] = data;
364184138Smav			buffer[1] = (data >> 8);
365184138Smav			buffer[2] = (data >> 16);
366184138Smav			buffer[3] = (data >> 24);
367184138Smav			buffer += 4;
368184138Smav			left -= 4;
369184138Smav		}
370184138Smav	} else {
371241600Sgonzo		RD_MULTI_4(slot, SDHCI_BUFFER,
372184138Smav		    (uint32_t *)buffer, left >> 2);
373184138Smav		left &= 3;
374184138Smav	}
375184138Smav	/* Handle uneven size case. */
376184138Smav	if (left > 0) {
377184138Smav		data = RD4(slot, SDHCI_BUFFER);
378184138Smav		while (left > 0) {
379184138Smav			*(buffer++) = data;
380184138Smav			data >>= 8;
381184138Smav			left--;
382184138Smav		}
383184138Smav	}
384184138Smav}
385184138Smav
386184138Smavstatic void
387184138Smavsdhci_write_block_pio(struct sdhci_slot *slot)
388184138Smav{
389184138Smav	uint32_t data = 0;
390184138Smav	char *buffer;
391184138Smav	size_t left;
392184138Smav
393184138Smav	buffer = slot->curcmd->data->data;
394184138Smav	buffer += slot->offset;
395184138Smav	/* Transfer one block at a time. */
396184138Smav	left = min(512, slot->curcmd->data->len - slot->offset);
397184138Smav	slot->offset += left;
398184138Smav
399254512Srpaulo	/* Handle unaligned and aligned buffer cases. */
400184138Smav	if ((intptr_t)buffer & 3) {
401184138Smav		while (left > 3) {
402184138Smav			data = buffer[0] +
403184138Smav			    (buffer[1] << 8) +
404184138Smav			    (buffer[2] << 16) +
405184138Smav			    (buffer[3] << 24);
406184138Smav			left -= 4;
407184138Smav			buffer += 4;
408184138Smav			WR4(slot, SDHCI_BUFFER, data);
409184138Smav		}
410184138Smav	} else {
411241600Sgonzo		WR_MULTI_4(slot, SDHCI_BUFFER,
412184138Smav		    (uint32_t *)buffer, left >> 2);
413184138Smav		left &= 3;
414184138Smav	}
415184138Smav	/* Handle uneven size case. */
416184138Smav	if (left > 0) {
417184138Smav		while (left > 0) {
418184138Smav			data <<= 8;
419184138Smav			data += *(buffer++);
420184138Smav			left--;
421184138Smav		}
422184138Smav		WR4(slot, SDHCI_BUFFER, data);
423184138Smav	}
424184138Smav}
425184138Smav
426184138Smavstatic void
427184138Smavsdhci_transfer_pio(struct sdhci_slot *slot)
428184138Smav{
429184138Smav
430184138Smav	/* Read as many blocks as possible. */
431184138Smav	if (slot->curcmd->data->flags & MMC_DATA_READ) {
432184138Smav		while (RD4(slot, SDHCI_PRESENT_STATE) &
433184138Smav		    SDHCI_DATA_AVAILABLE) {
434184138Smav			sdhci_read_block_pio(slot);
435184138Smav			if (slot->offset >= slot->curcmd->data->len)
436184138Smav				break;
437184138Smav		}
438184138Smav	} else {
439184138Smav		while (RD4(slot, SDHCI_PRESENT_STATE) &
440184138Smav		    SDHCI_SPACE_AVAILABLE) {
441184138Smav			sdhci_write_block_pio(slot);
442184138Smav			if (slot->offset >= slot->curcmd->data->len)
443184138Smav				break;
444184138Smav		}
445184138Smav	}
446184138Smav}
447184138Smav
448184138Smavstatic void
449184138Smavsdhci_card_delay(void *arg)
450184138Smav{
451184138Smav	struct sdhci_slot *slot = arg;
452184138Smav
453184138Smav	taskqueue_enqueue(taskqueue_swi_giant, &slot->card_task);
454184138Smav}
455184138Smav
456184138Smavstatic void
457184138Smavsdhci_card_task(void *arg, int pending)
458184138Smav{
459184138Smav	struct sdhci_slot *slot = arg;
460184138Smav
461184138Smav	SDHCI_LOCK(slot);
462184138Smav	if (RD4(slot, SDHCI_PRESENT_STATE) & SDHCI_CARD_PRESENT) {
463184138Smav		if (slot->dev == NULL) {
464184138Smav			/* If card is present - attach mmc bus. */
465241600Sgonzo			slot->dev = device_add_child(slot->bus, "mmc", -1);
466184138Smav			device_set_ivars(slot->dev, slot);
467184138Smav			SDHCI_UNLOCK(slot);
468184138Smav			device_probe_and_attach(slot->dev);
469184138Smav		} else
470184138Smav			SDHCI_UNLOCK(slot);
471184138Smav	} else {
472184138Smav		if (slot->dev != NULL) {
473184138Smav			/* If no card present - detach mmc bus. */
474184138Smav			device_t d = slot->dev;
475184138Smav			slot->dev = NULL;
476184138Smav			SDHCI_UNLOCK(slot);
477241600Sgonzo			device_delete_child(slot->bus, d);
478184138Smav		} else
479184138Smav			SDHCI_UNLOCK(slot);
480184138Smav	}
481184138Smav}
482184138Smav
483241600Sgonzoint
484241600Sgonzosdhci_init_slot(device_t dev, struct sdhci_slot *slot, int num)
485184138Smav{
486254507Sian	uint32_t caps, freq;
487241600Sgonzo	int err;
488184138Smav
489241600Sgonzo	SDHCI_LOCK_INIT(slot);
490241600Sgonzo	slot->num = num;
491241600Sgonzo	slot->bus = dev;
492184138Smav
493241600Sgonzo	/* Allocate DMA tag. */
494241600Sgonzo	err = bus_dma_tag_create(bus_get_dma_tag(dev),
495241600Sgonzo	    DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
496241600Sgonzo	    BUS_SPACE_MAXADDR, NULL, NULL,
497241600Sgonzo	    DMA_BLOCK_SIZE, 1, DMA_BLOCK_SIZE,
498241600Sgonzo	    BUS_DMA_ALLOCNOW, NULL, NULL,
499241600Sgonzo	    &slot->dmatag);
500241600Sgonzo	if (err != 0) {
501241600Sgonzo		device_printf(dev, "Can't create DMA tag\n");
502241600Sgonzo		SDHCI_LOCK_DESTROY(slot);
503241600Sgonzo		return (err);
504184138Smav	}
505241600Sgonzo	/* Allocate DMA memory. */
506241600Sgonzo	err = bus_dmamem_alloc(slot->dmatag, (void **)&slot->dmamem,
507241600Sgonzo	    BUS_DMA_NOWAIT, &slot->dmamap);
508241600Sgonzo	if (err != 0) {
509241600Sgonzo		device_printf(dev, "Can't alloc DMA memory\n");
510241600Sgonzo		SDHCI_LOCK_DESTROY(slot);
511241600Sgonzo		return (err);
512184138Smav	}
513241600Sgonzo	/* Map the memory. */
514241600Sgonzo	err = bus_dmamap_load(slot->dmatag, slot->dmamap,
515241600Sgonzo	    (void *)slot->dmamem, DMA_BLOCK_SIZE,
516241600Sgonzo	    sdhci_getaddr, &slot->paddr, 0);
517241600Sgonzo	if (err != 0 || slot->paddr == 0) {
518241600Sgonzo		device_printf(dev, "Can't load DMA memory\n");
519241600Sgonzo		SDHCI_LOCK_DESTROY(slot);
520241600Sgonzo		if(err)
521241600Sgonzo			return (err);
522241600Sgonzo		else
523241600Sgonzo			return (EFAULT);
524184138Smav	}
525184138Smav
526241600Sgonzo	/* Initialize slot. */
527241600Sgonzo	sdhci_init(slot);
528241600Sgonzo	slot->version = (RD2(slot, SDHCI_HOST_VERSION)
529241600Sgonzo		>> SDHCI_SPEC_VER_SHIFT) & SDHCI_SPEC_VER_MASK;
530242320Sgonzo	if (slot->quirks & SDHCI_QUIRK_MISSING_CAPS)
531242320Sgonzo		caps = slot->caps;
532242320Sgonzo	else
533242320Sgonzo		caps = RD4(slot, SDHCI_CAPABILITIES);
534241600Sgonzo	/* Calculate base clock frequency. */
535243689Sgonzo	if (slot->version >= SDHCI_SPEC_300)
536254507Sian		freq = (caps & SDHCI_CLOCK_V3_BASE_MASK) >>
537254507Sian		    SDHCI_CLOCK_BASE_SHIFT;
538243689Sgonzo	else
539254507Sian		freq = (caps & SDHCI_CLOCK_BASE_MASK) >>
540254507Sian		    SDHCI_CLOCK_BASE_SHIFT;
541254507Sian	if (freq != 0)
542254507Sian		slot->max_clk = freq * 1000000;
543254507Sian	/*
544254507Sian	 * If the frequency wasn't in the capabilities and the hardware driver
545254507Sian	 * hasn't already set max_clk we're probably not going to work right
546254507Sian	 * with an assumption, so complain about it.
547254507Sian	 */
548241600Sgonzo	if (slot->max_clk == 0) {
549254507Sian		slot->max_clk = SDHCI_DEFAULT_MAX_FREQ * 1000000;
550241600Sgonzo		device_printf(dev, "Hardware doesn't specify base clock "
551243689Sgonzo		    "frequency, using %dMHz as default.\n", SDHCI_DEFAULT_MAX_FREQ);
552241600Sgonzo	}
553241600Sgonzo	/* Calculate timeout clock frequency. */
554242320Sgonzo	if (slot->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK) {
555242320Sgonzo		slot->timeout_clk = slot->max_clk / 1000;
556242320Sgonzo	} else {
557242320Sgonzo		slot->timeout_clk =
558242320Sgonzo			(caps & SDHCI_TIMEOUT_CLK_MASK) >> SDHCI_TIMEOUT_CLK_SHIFT;
559242320Sgonzo		if (caps & SDHCI_TIMEOUT_CLK_UNIT)
560242320Sgonzo			slot->timeout_clk *= 1000;
561242320Sgonzo	}
562254507Sian	/*
563254507Sian	 * If the frequency wasn't in the capabilities and the hardware driver
564254507Sian	 * hasn't already set timeout_clk we'll probably work okay using the
565254507Sian	 * max timeout, but still mention it.
566254507Sian	 */
567241600Sgonzo	if (slot->timeout_clk == 0) {
568241600Sgonzo		device_printf(dev, "Hardware doesn't specify timeout clock "
569254423Sian		    "frequency, setting BROKEN_TIMEOUT quirk.\n");
570254423Sian		slot->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
571241600Sgonzo	}
572184138Smav
573246886Sgonzo	slot->host.f_min = SDHCI_MIN_FREQ(slot->bus, slot);
574241600Sgonzo	slot->host.f_max = slot->max_clk;
575241600Sgonzo	slot->host.host_ocr = 0;
576241600Sgonzo	if (caps & SDHCI_CAN_VDD_330)
577241600Sgonzo	    slot->host.host_ocr |= MMC_OCR_320_330 | MMC_OCR_330_340;
578241600Sgonzo	if (caps & SDHCI_CAN_VDD_300)
579241600Sgonzo	    slot->host.host_ocr |= MMC_OCR_290_300 | MMC_OCR_300_310;
580241600Sgonzo	if (caps & SDHCI_CAN_VDD_180)
581241600Sgonzo	    slot->host.host_ocr |= MMC_OCR_LOW_VOLTAGE;
582241600Sgonzo	if (slot->host.host_ocr == 0) {
583241600Sgonzo		device_printf(dev, "Hardware doesn't report any "
584241600Sgonzo		    "support voltages.\n");
585184138Smav	}
586241600Sgonzo	slot->host.caps = MMC_CAP_4_BIT_DATA;
587283318Sian	if (caps & SDHCI_CAN_DO_8BITBUS)
588283318Sian		slot->host.caps |= MMC_CAP_8_BIT_DATA;
589241600Sgonzo	if (caps & SDHCI_CAN_DO_HISPD)
590241600Sgonzo		slot->host.caps |= MMC_CAP_HSPEED;
591241600Sgonzo	/* Decide if we have usable DMA. */
592241600Sgonzo	if (caps & SDHCI_CAN_DO_DMA)
593241600Sgonzo		slot->opt |= SDHCI_HAVE_DMA;
594184138Smav
595241600Sgonzo	if (slot->quirks & SDHCI_QUIRK_BROKEN_DMA)
596241600Sgonzo		slot->opt &= ~SDHCI_HAVE_DMA;
597241600Sgonzo	if (slot->quirks & SDHCI_QUIRK_FORCE_DMA)
598241600Sgonzo		slot->opt |= SDHCI_HAVE_DMA;
599241600Sgonzo
600247495Sgonzo	/*
601247495Sgonzo	 * Use platform-provided transfer backend
602247495Sgonzo	 * with PIO as a fallback mechanism
603247495Sgonzo	 */
604247495Sgonzo	if (slot->opt & SDHCI_PLATFORM_TRANSFER)
605247495Sgonzo		slot->opt &= ~SDHCI_HAVE_DMA;
606247495Sgonzo
607241600Sgonzo	if (bootverbose || sdhci_debug) {
608283318Sian		slot_printf(slot, "%uMHz%s %s%s%s%s %s\n",
609241600Sgonzo		    slot->max_clk / 1000000,
610241600Sgonzo		    (caps & SDHCI_CAN_DO_HISPD) ? " HS" : "",
611283318Sian		    (caps & MMC_CAP_8_BIT_DATA) ? "8bits" :
612283318Sian			((caps & MMC_CAP_4_BIT_DATA) ? "4bits" : "1bit"),
613241600Sgonzo		    (caps & SDHCI_CAN_VDD_330) ? " 3.3V" : "",
614241600Sgonzo		    (caps & SDHCI_CAN_VDD_300) ? " 3.0V" : "",
615241600Sgonzo		    (caps & SDHCI_CAN_VDD_180) ? " 1.8V" : "",
616241600Sgonzo		    (slot->opt & SDHCI_HAVE_DMA) ? "DMA" : "PIO");
617241600Sgonzo		sdhci_dumpregs(slot);
618184138Smav	}
619241600Sgonzo
620241600Sgonzo	TASK_INIT(&slot->card_task, 0, sdhci_card_task, slot);
621241600Sgonzo	callout_init(&slot->card_callout, 1);
622266200Sian	callout_init_mtx(&slot->timeout_callout, &slot->mtx, 0);
623184138Smav	return (0);
624184138Smav}
625184138Smav
626241600Sgonzovoid
627241600Sgonzosdhci_start_slot(struct sdhci_slot *slot)
628184138Smav{
629241600Sgonzo	sdhci_card_task(slot, 0);
630241600Sgonzo}
631184138Smav
632241600Sgonzoint
633241600Sgonzosdhci_cleanup_slot(struct sdhci_slot *slot)
634241600Sgonzo{
635241600Sgonzo	device_t d;
636184138Smav
637266200Sian	callout_drain(&slot->timeout_callout);
638241600Sgonzo	callout_drain(&slot->card_callout);
639241600Sgonzo	taskqueue_drain(taskqueue_swi_giant, &slot->card_task);
640184138Smav
641241600Sgonzo	SDHCI_LOCK(slot);
642241600Sgonzo	d = slot->dev;
643241600Sgonzo	slot->dev = NULL;
644241600Sgonzo	SDHCI_UNLOCK(slot);
645241600Sgonzo	if (d != NULL)
646241600Sgonzo		device_delete_child(slot->bus, d);
647184138Smav
648241600Sgonzo	SDHCI_LOCK(slot);
649241600Sgonzo	sdhci_reset(slot, SDHCI_RESET_ALL);
650241600Sgonzo	SDHCI_UNLOCK(slot);
651241600Sgonzo	bus_dmamap_unload(slot->dmatag, slot->dmamap);
652241600Sgonzo	bus_dmamem_free(slot->dmatag, slot->dmamem, slot->dmamap);
653241600Sgonzo	bus_dma_tag_destroy(slot->dmatag);
654184138Smav
655241600Sgonzo	SDHCI_LOCK_DESTROY(slot);
656241600Sgonzo
657184138Smav	return (0);
658184138Smav}
659184138Smav
660241600Sgonzoint
661241600Sgonzosdhci_generic_suspend(struct sdhci_slot *slot)
662185527Smav{
663241600Sgonzo	sdhci_reset(slot, SDHCI_RESET_ALL);
664185527Smav
665185527Smav	return (0);
666185527Smav}
667185527Smav
668241600Sgonzoint
669241600Sgonzosdhci_generic_resume(struct sdhci_slot *slot)
670185527Smav{
671241600Sgonzo	sdhci_init(slot);
672185527Smav
673241600Sgonzo	return (0);
674185527Smav}
675185527Smav
676246886Sgonzouint32_t
677246886Sgonzosdhci_generic_min_freq(device_t brdev, struct sdhci_slot *slot)
678246886Sgonzo{
679246886Sgonzo	if (slot->version >= SDHCI_SPEC_300)
680246886Sgonzo		return (slot->max_clk / SDHCI_300_MAX_DIVIDER);
681246886Sgonzo	else
682246886Sgonzo		return (slot->max_clk / SDHCI_200_MAX_DIVIDER);
683246886Sgonzo}
684246886Sgonzo
685241600Sgonzoint
686241600Sgonzosdhci_generic_update_ios(device_t brdev, device_t reqdev)
687184138Smav{
688184138Smav	struct sdhci_slot *slot = device_get_ivars(reqdev);
689184138Smav	struct mmc_ios *ios = &slot->host.ios;
690184138Smav
691184138Smav	SDHCI_LOCK(slot);
692184138Smav	/* Do full reset on bus power down to clear from any state. */
693184138Smav	if (ios->power_mode == power_off) {
694184138Smav		WR4(slot, SDHCI_SIGNAL_ENABLE, 0);
695184138Smav		sdhci_init(slot);
696184138Smav	}
697184138Smav	/* Configure the bus. */
698184138Smav	sdhci_set_clock(slot, ios->clock);
699283318Sian	sdhci_set_power(slot, (ios->power_mode == power_off) ? 0 : ios->vdd);
700283318Sian	if (ios->bus_width == bus_width_8) {
701283318Sian		slot->hostctrl |= SDHCI_CTRL_8BITBUS;
702283318Sian		slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
703283318Sian	} else if (ios->bus_width == bus_width_4) {
704283318Sian		slot->hostctrl &= ~SDHCI_CTRL_8BITBUS;
705184138Smav		slot->hostctrl |= SDHCI_CTRL_4BITBUS;
706283318Sian	} else if (ios->bus_width == bus_width_1) {
707283318Sian		slot->hostctrl &= ~SDHCI_CTRL_8BITBUS;
708184138Smav		slot->hostctrl &= ~SDHCI_CTRL_4BITBUS;
709283318Sian	} else {
710283318Sian		panic("Invalid bus width: %d", ios->bus_width);
711283318Sian	}
712278703Sian	if (ios->timing == bus_timing_hs &&
713278703Sian	    !(slot->quirks & SDHCI_QUIRK_DONT_SET_HISPD_BIT))
714184138Smav		slot->hostctrl |= SDHCI_CTRL_HISPD;
715184138Smav	else
716184138Smav		slot->hostctrl &= ~SDHCI_CTRL_HISPD;
717184138Smav	WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl);
718184138Smav	/* Some controllers like reset after bus changes. */
719241600Sgonzo	if(slot->quirks & SDHCI_QUIRK_RESET_ON_IOS)
720184138Smav		sdhci_reset(slot, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
721184138Smav
722184138Smav	SDHCI_UNLOCK(slot);
723184138Smav	return (0);
724184138Smav}
725184138Smav
726266200Sianstatic void
727266200Siansdhci_req_done(struct sdhci_slot *slot)
728266200Sian{
729266200Sian	struct mmc_request *req;
730266200Sian
731266200Sian	if (slot->req != NULL && slot->curcmd != NULL) {
732266200Sian		callout_stop(&slot->timeout_callout);
733266200Sian		req = slot->req;
734266200Sian		slot->req = NULL;
735266200Sian		slot->curcmd = NULL;
736266200Sian		req->done(req);
737266200Sian	}
738266200Sian}
739266200Sian
740266200Sianstatic void
741266200Siansdhci_timeout(void *arg)
742266200Sian{
743266200Sian	struct sdhci_slot *slot = arg;
744266200Sian
745266200Sian	if (slot->curcmd != NULL) {
746276287Sian		slot_printf(slot, " Controller timeout\n");
747276287Sian		sdhci_dumpregs(slot);
748266200Sian		sdhci_reset(slot, SDHCI_RESET_CMD|SDHCI_RESET_DATA);
749266200Sian		slot->curcmd->error = MMC_ERR_TIMEOUT;
750266200Sian		sdhci_req_done(slot);
751276287Sian	} else {
752276287Sian		slot_printf(slot, " Spurious timeout - no active command\n");
753266200Sian	}
754266200Sian}
755266200Sian
756184138Smavstatic void
757184138Smavsdhci_set_transfer_mode(struct sdhci_slot *slot,
758184138Smav	struct mmc_data *data)
759184138Smav{
760184138Smav	uint16_t mode;
761184138Smav
762184138Smav	if (data == NULL)
763184138Smav		return;
764184138Smav
765184138Smav	mode = SDHCI_TRNS_BLK_CNT_EN;
766184138Smav	if (data->len > 512)
767184138Smav		mode |= SDHCI_TRNS_MULTI;
768184138Smav	if (data->flags & MMC_DATA_READ)
769184138Smav		mode |= SDHCI_TRNS_READ;
770184138Smav	if (slot->req->stop)
771184138Smav		mode |= SDHCI_TRNS_ACMD12;
772184138Smav	if (slot->flags & SDHCI_USE_DMA)
773184138Smav		mode |= SDHCI_TRNS_DMA;
774184138Smav
775184138Smav	WR2(slot, SDHCI_TRANSFER_MODE, mode);
776184138Smav}
777184138Smav
778184138Smavstatic void
779184138Smavsdhci_start_command(struct sdhci_slot *slot, struct mmc_command *cmd)
780184138Smav{
781184138Smav	int flags, timeout;
782184138Smav	uint32_t mask, state;
783184138Smav
784184138Smav	slot->curcmd = cmd;
785184138Smav	slot->cmd_done = 0;
786184138Smav
787184138Smav	cmd->error = MMC_ERR_NONE;
788184138Smav
789184138Smav	/* This flags combination is not supported by controller. */
790184138Smav	if ((cmd->flags & MMC_RSP_136) && (cmd->flags & MMC_RSP_BUSY)) {
791184138Smav		slot_printf(slot, "Unsupported response type!\n");
792184138Smav		cmd->error = MMC_ERR_FAILED;
793266200Sian		sdhci_req_done(slot);
794184138Smav		return;
795184138Smav	}
796184138Smav
797184138Smav	/* Read controller present state. */
798184138Smav	state = RD4(slot, SDHCI_PRESENT_STATE);
799185661Smav	/* Do not issue command if there is no card, clock or power.
800185661Smav	 * Controller will not detect timeout without clock active. */
801185661Smav	if ((state & SDHCI_CARD_PRESENT) == 0 ||
802185661Smav	    slot->power == 0 ||
803185661Smav	    slot->clock == 0) {
804184138Smav		cmd->error = MMC_ERR_FAILED;
805266200Sian		sdhci_req_done(slot);
806184138Smav		return;
807184138Smav	}
808184138Smav	/* Always wait for free CMD bus. */
809184138Smav	mask = SDHCI_CMD_INHIBIT;
810184138Smav	/* Wait for free DAT if we have data or busy signal. */
811184138Smav	if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
812184138Smav		mask |= SDHCI_DAT_INHIBIT;
813184138Smav	/* We shouldn't wait for DAT for stop commands. */
814184138Smav	if (cmd == slot->req->stop)
815184138Smav		mask &= ~SDHCI_DAT_INHIBIT;
816266200Sian	/*
817266200Sian	 *  Wait for bus no more then 250 ms.  Typically there will be no wait
818266200Sian	 *  here at all, but when writing a crash dump we may be bypassing the
819266200Sian	 *  host platform's interrupt handler, and in some cases that handler
820266200Sian	 *  may be working around hardware quirks such as not respecting r1b
821266200Sian	 *  busy indications.  In those cases, this wait-loop serves the purpose
822266200Sian	 *  of waiting for the prior command and data transfers to be done, and
823266200Sian	 *  SD cards are allowed to take up to 250ms for write and erase ops.
824266200Sian	 *  (It's usually more like 20-30ms in the real world.)
825266200Sian	 */
826266200Sian	timeout = 250;
827184138Smav	while (state & mask) {
828184138Smav		if (timeout == 0) {
829184138Smav			slot_printf(slot, "Controller never released "
830184138Smav			    "inhibit bit(s).\n");
831184138Smav			sdhci_dumpregs(slot);
832184138Smav			cmd->error = MMC_ERR_FAILED;
833266200Sian			sdhci_req_done(slot);
834184138Smav			return;
835184138Smav		}
836184138Smav		timeout--;
837184138Smav		DELAY(1000);
838184138Smav		state = RD4(slot, SDHCI_PRESENT_STATE);
839184138Smav	}
840184138Smav
841184138Smav	/* Prepare command flags. */
842184138Smav	if (!(cmd->flags & MMC_RSP_PRESENT))
843184138Smav		flags = SDHCI_CMD_RESP_NONE;
844184138Smav	else if (cmd->flags & MMC_RSP_136)
845184138Smav		flags = SDHCI_CMD_RESP_LONG;
846184138Smav	else if (cmd->flags & MMC_RSP_BUSY)
847184138Smav		flags = SDHCI_CMD_RESP_SHORT_BUSY;
848184138Smav	else
849184138Smav		flags = SDHCI_CMD_RESP_SHORT;
850184138Smav	if (cmd->flags & MMC_RSP_CRC)
851184138Smav		flags |= SDHCI_CMD_CRC;
852184138Smav	if (cmd->flags & MMC_RSP_OPCODE)
853184138Smav		flags |= SDHCI_CMD_INDEX;
854184138Smav	if (cmd->data)
855184138Smav		flags |= SDHCI_CMD_DATA;
856184138Smav	if (cmd->opcode == MMC_STOP_TRANSMISSION)
857184138Smav		flags |= SDHCI_CMD_TYPE_ABORT;
858184138Smav	/* Prepare data. */
859184138Smav	sdhci_start_data(slot, cmd->data);
860184138Smav	/*
861184138Smav	 * Interrupt aggregation: To reduce total number of interrupts
862184138Smav	 * group response interrupt with data interrupt when possible.
863184138Smav	 * If there going to be data interrupt, mask response one.
864184138Smav	 */
865184138Smav	if (slot->data_done == 0) {
866184138Smav		WR4(slot, SDHCI_SIGNAL_ENABLE,
867184138Smav		    slot->intmask &= ~SDHCI_INT_RESPONSE);
868184138Smav	}
869184138Smav	/* Set command argument. */
870184138Smav	WR4(slot, SDHCI_ARGUMENT, cmd->arg);
871184138Smav	/* Set data transfer mode. */
872184138Smav	sdhci_set_transfer_mode(slot, cmd->data);
873184138Smav	/* Start command. */
874241600Sgonzo	WR2(slot, SDHCI_COMMAND_FLAGS, (cmd->opcode << 8) | (flags & 0xff));
875266200Sian	/* Start timeout callout. */
876266200Sian	callout_reset(&slot->timeout_callout, 2*hz, sdhci_timeout, slot);
877184138Smav}
878184138Smav
879184138Smavstatic void
880184138Smavsdhci_finish_command(struct sdhci_slot *slot)
881184138Smav{
882184138Smav	int i;
883184138Smav
884184138Smav	slot->cmd_done = 1;
885184138Smav	/* Interrupt aggregation: Restore command interrupt.
886184138Smav	 * Main restore point for the case when command interrupt
887184138Smav	 * happened first. */
888184138Smav	WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask |= SDHCI_INT_RESPONSE);
889184138Smav	/* In case of error - reset host and return. */
890184138Smav	if (slot->curcmd->error) {
891184138Smav		sdhci_reset(slot, SDHCI_RESET_CMD);
892184138Smav		sdhci_reset(slot, SDHCI_RESET_DATA);
893184138Smav		sdhci_start(slot);
894184138Smav		return;
895184138Smav	}
896184138Smav	/* If command has response - fetch it. */
897184138Smav	if (slot->curcmd->flags & MMC_RSP_PRESENT) {
898184138Smav		if (slot->curcmd->flags & MMC_RSP_136) {
899184138Smav			/* CRC is stripped so we need one byte shift. */
900184138Smav			uint8_t extra = 0;
901184138Smav			for (i = 0; i < 4; i++) {
902184138Smav				uint32_t val = RD4(slot, SDHCI_RESPONSE + i * 4);
903254496Sian				if (slot->quirks & SDHCI_QUIRK_DONT_SHIFT_RESPONSE)
904254496Sian					slot->curcmd->resp[3 - i] = val;
905254496Sian				else {
906254496Sian					slot->curcmd->resp[3 - i] =
907254496Sian					    (val << 8) | extra;
908254496Sian					extra = val >> 24;
909254496Sian				}
910184138Smav			}
911184138Smav		} else
912184138Smav			slot->curcmd->resp[0] = RD4(slot, SDHCI_RESPONSE);
913184138Smav	}
914184138Smav	/* If data ready - finish. */
915184138Smav	if (slot->data_done)
916184138Smav		sdhci_start(slot);
917184138Smav}
918184138Smav
919184138Smavstatic void
920184138Smavsdhci_start_data(struct sdhci_slot *slot, struct mmc_data *data)
921184138Smav{
922184138Smav	uint32_t target_timeout, current_timeout;
923184138Smav	uint8_t div;
924184138Smav
925184138Smav	if (data == NULL && (slot->curcmd->flags & MMC_RSP_BUSY) == 0) {
926184138Smav		slot->data_done = 1;
927184138Smav		return;
928184138Smav	}
929184138Smav
930184138Smav	slot->data_done = 0;
931184138Smav
932184138Smav	/* Calculate and set data timeout.*/
933184138Smav	/* XXX: We should have this from mmc layer, now assume 1 sec. */
934254423Sian	if (slot->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL) {
935184138Smav		div = 0xE;
936254423Sian	} else {
937254423Sian		target_timeout = 1000000;
938254423Sian		div = 0;
939254423Sian		current_timeout = (1 << 13) * 1000 / slot->timeout_clk;
940254423Sian		while (current_timeout < target_timeout && div < 0xE) {
941254423Sian			++div;
942254423Sian			current_timeout <<= 1;
943254423Sian		}
944254423Sian		/* Compensate for an off-by-one error in the CaFe chip.*/
945254423Sian		if (div < 0xE &&
946254423Sian		    (slot->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL)) {
947254423Sian			++div;
948254423Sian		}
949184138Smav	}
950184138Smav	WR1(slot, SDHCI_TIMEOUT_CONTROL, div);
951184138Smav
952184138Smav	if (data == NULL)
953184138Smav		return;
954184138Smav
955184138Smav	/* Use DMA if possible. */
956184138Smav	if ((slot->opt & SDHCI_HAVE_DMA))
957184138Smav		slot->flags |= SDHCI_USE_DMA;
958184138Smav	/* If data is small, broken DMA may return zeroes instead of data, */
959241600Sgonzo	if ((slot->quirks & SDHCI_QUIRK_BROKEN_TIMINGS) &&
960184138Smav	    (data->len <= 512))
961184138Smav		slot->flags &= ~SDHCI_USE_DMA;
962184138Smav	/* Some controllers require even block sizes. */
963241600Sgonzo	if ((slot->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
964184138Smav	    ((data->len) & 0x3))
965184138Smav		slot->flags &= ~SDHCI_USE_DMA;
966184138Smav	/* Load DMA buffer. */
967184138Smav	if (slot->flags & SDHCI_USE_DMA) {
968184138Smav		if (data->flags & MMC_DATA_READ)
969254512Srpaulo			bus_dmamap_sync(slot->dmatag, slot->dmamap,
970254512Srpaulo			    BUS_DMASYNC_PREREAD);
971184138Smav		else {
972184138Smav			memcpy(slot->dmamem, data->data,
973254512Srpaulo			    (data->len < DMA_BLOCK_SIZE) ?
974254512Srpaulo			    data->len : DMA_BLOCK_SIZE);
975254512Srpaulo			bus_dmamap_sync(slot->dmatag, slot->dmamap,
976254512Srpaulo			    BUS_DMASYNC_PREWRITE);
977184138Smav		}
978184138Smav		WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr);
979184138Smav		/* Interrupt aggregation: Mask border interrupt
980184138Smav		 * for the last page and unmask else. */
981184138Smav		if (data->len == DMA_BLOCK_SIZE)
982184138Smav			slot->intmask &= ~SDHCI_INT_DMA_END;
983184138Smav		else
984184138Smav			slot->intmask |= SDHCI_INT_DMA_END;
985184138Smav		WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
986184138Smav	}
987184138Smav	/* Current data offset for both PIO and DMA. */
988184138Smav	slot->offset = 0;
989184138Smav	/* Set block size and request IRQ on 4K border. */
990184138Smav	WR2(slot, SDHCI_BLOCK_SIZE,
991184138Smav	    SDHCI_MAKE_BLKSZ(DMA_BOUNDARY, (data->len < 512)?data->len:512));
992184138Smav	/* Set block count. */
993184138Smav	WR2(slot, SDHCI_BLOCK_COUNT, (data->len + 511) / 512);
994184138Smav}
995184138Smav
996247495Sgonzovoid
997184138Smavsdhci_finish_data(struct sdhci_slot *slot)
998184138Smav{
999184138Smav	struct mmc_data *data = slot->curcmd->data;
1000184138Smav
1001184138Smav	/* Interrupt aggregation: Restore command interrupt.
1002254512Srpaulo	 * Auxiliary restore point for the case when data interrupt
1003184138Smav	 * happened first. */
1004184138Smav	if (!slot->cmd_done) {
1005184138Smav		WR4(slot, SDHCI_SIGNAL_ENABLE,
1006184138Smav		    slot->intmask |= SDHCI_INT_RESPONSE);
1007184138Smav	}
1008184138Smav	/* Unload rest of data from DMA buffer. */
1009278688Sian	if (!slot->data_done && (slot->flags & SDHCI_USE_DMA)) {
1010184138Smav		if (data->flags & MMC_DATA_READ) {
1011184138Smav			size_t left = data->len - slot->offset;
1012254512Srpaulo			bus_dmamap_sync(slot->dmatag, slot->dmamap,
1013254512Srpaulo			    BUS_DMASYNC_POSTREAD);
1014184138Smav			memcpy((u_char*)data->data + slot->offset, slot->dmamem,
1015184138Smav			    (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE);
1016184138Smav		} else
1017254512Srpaulo			bus_dmamap_sync(slot->dmatag, slot->dmamap,
1018254512Srpaulo			    BUS_DMASYNC_POSTWRITE);
1019184138Smav	}
1020278688Sian	slot->data_done = 1;
1021184138Smav	/* If there was error - reset the host. */
1022184138Smav	if (slot->curcmd->error) {
1023184138Smav		sdhci_reset(slot, SDHCI_RESET_CMD);
1024184138Smav		sdhci_reset(slot, SDHCI_RESET_DATA);
1025184138Smav		sdhci_start(slot);
1026184138Smav		return;
1027184138Smav	}
1028184138Smav	/* If we already have command response - finish. */
1029184138Smav	if (slot->cmd_done)
1030184138Smav		sdhci_start(slot);
1031184138Smav}
1032184138Smav
1033184138Smavstatic void
1034184138Smavsdhci_start(struct sdhci_slot *slot)
1035184138Smav{
1036184138Smav	struct mmc_request *req;
1037184138Smav
1038184138Smav	req = slot->req;
1039184138Smav	if (req == NULL)
1040184138Smav		return;
1041184138Smav
1042184138Smav	if (!(slot->flags & CMD_STARTED)) {
1043184138Smav		slot->flags |= CMD_STARTED;
1044184138Smav		sdhci_start_command(slot, req->cmd);
1045184138Smav		return;
1046184138Smav	}
1047184138Smav/* 	We don't need this until using Auto-CMD12 feature
1048184138Smav	if (!(slot->flags & STOP_STARTED) && req->stop) {
1049184138Smav		slot->flags |= STOP_STARTED;
1050184138Smav		sdhci_start_command(slot, req->stop);
1051184138Smav		return;
1052184138Smav	}
1053184138Smav*/
1054187876Smav	if (sdhci_debug > 1)
1055187876Smav		slot_printf(slot, "result: %d\n", req->cmd->error);
1056187876Smav	if (!req->cmd->error &&
1057241600Sgonzo	    (slot->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) {
1058184138Smav		sdhci_reset(slot, SDHCI_RESET_CMD);
1059184138Smav		sdhci_reset(slot, SDHCI_RESET_DATA);
1060184138Smav	}
1061184138Smav
1062266200Sian	sdhci_req_done(slot);
1063184138Smav}
1064184138Smav
1065241600Sgonzoint
1066241600Sgonzosdhci_generic_request(device_t brdev, device_t reqdev, struct mmc_request *req)
1067184138Smav{
1068184138Smav	struct sdhci_slot *slot = device_get_ivars(reqdev);
1069184138Smav
1070184138Smav	SDHCI_LOCK(slot);
1071184138Smav	if (slot->req != NULL) {
1072184138Smav		SDHCI_UNLOCK(slot);
1073184138Smav		return (EBUSY);
1074184138Smav	}
1075187876Smav	if (sdhci_debug > 1) {
1076187876Smav		slot_printf(slot, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n",
1077187876Smav    		    req->cmd->opcode, req->cmd->arg, req->cmd->flags,
1078187876Smav    		    (req->cmd->data)?(u_int)req->cmd->data->len:0,
1079187876Smav		    (req->cmd->data)?req->cmd->data->flags:0);
1080187876Smav	}
1081184138Smav	slot->req = req;
1082184138Smav	slot->flags = 0;
1083184138Smav	sdhci_start(slot);
1084184138Smav	SDHCI_UNLOCK(slot);
1085188724Smav	if (dumping) {
1086188724Smav		while (slot->req != NULL) {
1087241600Sgonzo			sdhci_generic_intr(slot);
1088188724Smav			DELAY(10);
1089188724Smav		}
1090188724Smav	}
1091184138Smav	return (0);
1092184138Smav}
1093184138Smav
1094241600Sgonzoint
1095241600Sgonzosdhci_generic_get_ro(device_t brdev, device_t reqdev)
1096184138Smav{
1097184138Smav	struct sdhci_slot *slot = device_get_ivars(reqdev);
1098184138Smav	uint32_t val;
1099184138Smav
1100184138Smav	SDHCI_LOCK(slot);
1101184138Smav	val = RD4(slot, SDHCI_PRESENT_STATE);
1102184138Smav	SDHCI_UNLOCK(slot);
1103184138Smav	return (!(val & SDHCI_WRITE_PROTECT));
1104184138Smav}
1105184138Smav
1106241600Sgonzoint
1107241600Sgonzosdhci_generic_acquire_host(device_t brdev, device_t reqdev)
1108184138Smav{
1109184138Smav	struct sdhci_slot *slot = device_get_ivars(reqdev);
1110184138Smav	int err = 0;
1111184138Smav
1112184138Smav	SDHCI_LOCK(slot);
1113184138Smav	while (slot->bus_busy)
1114185722Smav		msleep(slot, &slot->mtx, 0, "sdhciah", 0);
1115184138Smav	slot->bus_busy++;
1116184138Smav	/* Activate led. */
1117184138Smav	WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl |= SDHCI_CTRL_LED);
1118184138Smav	SDHCI_UNLOCK(slot);
1119184138Smav	return (err);
1120184138Smav}
1121184138Smav
1122241600Sgonzoint
1123241600Sgonzosdhci_generic_release_host(device_t brdev, device_t reqdev)
1124184138Smav{
1125184138Smav	struct sdhci_slot *slot = device_get_ivars(reqdev);
1126184138Smav
1127184138Smav	SDHCI_LOCK(slot);
1128184138Smav	/* Deactivate led. */
1129184138Smav	WR1(slot, SDHCI_HOST_CONTROL, slot->hostctrl &= ~SDHCI_CTRL_LED);
1130184138Smav	slot->bus_busy--;
1131185722Smav	SDHCI_UNLOCK(slot);
1132184138Smav	wakeup(slot);
1133184138Smav	return (0);
1134184138Smav}
1135184138Smav
1136184138Smavstatic void
1137184138Smavsdhci_cmd_irq(struct sdhci_slot *slot, uint32_t intmask)
1138184138Smav{
1139184138Smav
1140184138Smav	if (!slot->curcmd) {
1141184138Smav		slot_printf(slot, "Got command interrupt 0x%08x, but "
1142184138Smav		    "there is no active command.\n", intmask);
1143184138Smav		sdhci_dumpregs(slot);
1144184138Smav		return;
1145184138Smav	}
1146184138Smav	if (intmask & SDHCI_INT_TIMEOUT)
1147184138Smav		slot->curcmd->error = MMC_ERR_TIMEOUT;
1148184138Smav	else if (intmask & SDHCI_INT_CRC)
1149184138Smav		slot->curcmd->error = MMC_ERR_BADCRC;
1150184138Smav	else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
1151184138Smav		slot->curcmd->error = MMC_ERR_FIFO;
1152184138Smav
1153184138Smav	sdhci_finish_command(slot);
1154184138Smav}
1155184138Smav
1156184138Smavstatic void
1157184138Smavsdhci_data_irq(struct sdhci_slot *slot, uint32_t intmask)
1158184138Smav{
1159184138Smav
1160184138Smav	if (!slot->curcmd) {
1161184138Smav		slot_printf(slot, "Got data interrupt 0x%08x, but "
1162184138Smav		    "there is no active command.\n", intmask);
1163184138Smav		sdhci_dumpregs(slot);
1164184138Smav		return;
1165184138Smav	}
1166184138Smav	if (slot->curcmd->data == NULL &&
1167184138Smav	    (slot->curcmd->flags & MMC_RSP_BUSY) == 0) {
1168184138Smav		slot_printf(slot, "Got data interrupt 0x%08x, but "
1169184138Smav		    "there is no active data operation.\n",
1170184138Smav		    intmask);
1171184138Smav		sdhci_dumpregs(slot);
1172184138Smav		return;
1173184138Smav	}
1174184138Smav	if (intmask & SDHCI_INT_DATA_TIMEOUT)
1175184138Smav		slot->curcmd->error = MMC_ERR_TIMEOUT;
1176246891Sgonzo	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
1177184138Smav		slot->curcmd->error = MMC_ERR_BADCRC;
1178184138Smav	if (slot->curcmd->data == NULL &&
1179184138Smav	    (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
1180184138Smav	    SDHCI_INT_DMA_END))) {
1181184138Smav		slot_printf(slot, "Got data interrupt 0x%08x, but "
1182184138Smav		    "there is busy-only command.\n", intmask);
1183184138Smav		sdhci_dumpregs(slot);
1184184138Smav		slot->curcmd->error = MMC_ERR_INVALID;
1185184138Smav	}
1186184138Smav	if (slot->curcmd->error) {
1187184138Smav		/* No need to continue after any error. */
1188278688Sian		goto done;
1189184138Smav	}
1190184138Smav
1191184138Smav	/* Handle PIO interrupt. */
1192247495Sgonzo	if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL)) {
1193247495Sgonzo		if ((slot->opt & SDHCI_PLATFORM_TRANSFER) &&
1194247495Sgonzo		    SDHCI_PLATFORM_WILL_HANDLE(slot->bus, slot)) {
1195247495Sgonzo			SDHCI_PLATFORM_START_TRANSFER(slot->bus, slot, &intmask);
1196247495Sgonzo			slot->flags |= PLATFORM_DATA_STARTED;
1197247495Sgonzo		} else
1198247495Sgonzo			sdhci_transfer_pio(slot);
1199247495Sgonzo	}
1200184138Smav	/* Handle DMA border. */
1201184138Smav	if (intmask & SDHCI_INT_DMA_END) {
1202184138Smav		struct mmc_data *data = slot->curcmd->data;
1203184138Smav		size_t left;
1204184138Smav
1205184138Smav		/* Unload DMA buffer... */
1206184138Smav		left = data->len - slot->offset;
1207184138Smav		if (data->flags & MMC_DATA_READ) {
1208184138Smav			bus_dmamap_sync(slot->dmatag, slot->dmamap,
1209184138Smav			    BUS_DMASYNC_POSTREAD);
1210184138Smav			memcpy((u_char*)data->data + slot->offset, slot->dmamem,
1211184138Smav			    (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE);
1212184138Smav		} else {
1213184138Smav			bus_dmamap_sync(slot->dmatag, slot->dmamap,
1214184138Smav			    BUS_DMASYNC_POSTWRITE);
1215184138Smav		}
1216184138Smav		/* ... and reload it again. */
1217184138Smav		slot->offset += DMA_BLOCK_SIZE;
1218184138Smav		left = data->len - slot->offset;
1219184138Smav		if (data->flags & MMC_DATA_READ) {
1220184138Smav			bus_dmamap_sync(slot->dmatag, slot->dmamap,
1221184138Smav			    BUS_DMASYNC_PREREAD);
1222184138Smav		} else {
1223184138Smav			memcpy(slot->dmamem, (u_char*)data->data + slot->offset,
1224184138Smav			    (left < DMA_BLOCK_SIZE)?left:DMA_BLOCK_SIZE);
1225184138Smav			bus_dmamap_sync(slot->dmatag, slot->dmamap,
1226184138Smav			    BUS_DMASYNC_PREWRITE);
1227184138Smav		}
1228184138Smav		/* Interrupt aggregation: Mask border interrupt
1229184138Smav		 * for the last page. */
1230184138Smav		if (left == DMA_BLOCK_SIZE) {
1231184138Smav			slot->intmask &= ~SDHCI_INT_DMA_END;
1232184138Smav			WR4(slot, SDHCI_SIGNAL_ENABLE, slot->intmask);
1233184138Smav		}
1234184138Smav		/* Restart DMA. */
1235184138Smav		WR4(slot, SDHCI_DMA_ADDRESS, slot->paddr);
1236184138Smav	}
1237184138Smav	/* We have got all data. */
1238247495Sgonzo	if (intmask & SDHCI_INT_DATA_END) {
1239247495Sgonzo		if (slot->flags & PLATFORM_DATA_STARTED) {
1240247495Sgonzo			slot->flags &= ~PLATFORM_DATA_STARTED;
1241247495Sgonzo			SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot);
1242247495Sgonzo		} else
1243247495Sgonzo			sdhci_finish_data(slot);
1244247495Sgonzo	}
1245278688Siandone:
1246278688Sian	if (slot->curcmd != NULL && slot->curcmd->error != 0) {
1247278688Sian		if (slot->flags & PLATFORM_DATA_STARTED) {
1248278688Sian			slot->flags &= ~PLATFORM_DATA_STARTED;
1249278688Sian			SDHCI_PLATFORM_FINISH_TRANSFER(slot->bus, slot);
1250278688Sian		} else
1251278688Sian			sdhci_finish_data(slot);
1252278688Sian		return;
1253278688Sian	}
1254184138Smav}
1255184138Smav
1256184138Smavstatic void
1257184138Smavsdhci_acmd_irq(struct sdhci_slot *slot)
1258184138Smav{
1259184138Smav	uint16_t err;
1260184138Smav
1261184138Smav	err = RD4(slot, SDHCI_ACMD12_ERR);
1262184138Smav	if (!slot->curcmd) {
1263184138Smav		slot_printf(slot, "Got AutoCMD12 error 0x%04x, but "
1264184138Smav		    "there is no active command.\n", err);
1265184138Smav		sdhci_dumpregs(slot);
1266184138Smav		return;
1267184138Smav	}
1268184138Smav	slot_printf(slot, "Got AutoCMD12 error 0x%04x\n", err);
1269184138Smav	sdhci_reset(slot, SDHCI_RESET_CMD);
1270184138Smav}
1271184138Smav
1272241600Sgonzovoid
1273241600Sgonzosdhci_generic_intr(struct sdhci_slot *slot)
1274184138Smav{
1275241600Sgonzo	uint32_t intmask;
1276241600Sgonzo
1277241600Sgonzo	SDHCI_LOCK(slot);
1278241600Sgonzo	/* Read slot interrupt status. */
1279241600Sgonzo	intmask = RD4(slot, SDHCI_INT_STATUS);
1280241600Sgonzo	if (intmask == 0 || intmask == 0xffffffff) {
1281241600Sgonzo		SDHCI_UNLOCK(slot);
1282241600Sgonzo		return;
1283241600Sgonzo	}
1284241600Sgonzo	if (sdhci_debug > 2)
1285241600Sgonzo		slot_printf(slot, "Interrupt %#x\n", intmask);
1286184138Smav
1287241600Sgonzo	/* Handle card presence interrupts. */
1288241600Sgonzo	if (intmask & (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE)) {
1289241600Sgonzo		WR4(slot, SDHCI_INT_STATUS, intmask &
1290241600Sgonzo		    (SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE));
1291187876Smav
1292241600Sgonzo		if (intmask & SDHCI_INT_CARD_REMOVE) {
1293241600Sgonzo			if (bootverbose || sdhci_debug)
1294241600Sgonzo				slot_printf(slot, "Card removed\n");
1295241600Sgonzo			callout_stop(&slot->card_callout);
1296241600Sgonzo			taskqueue_enqueue(taskqueue_swi_giant,
1297241600Sgonzo			    &slot->card_task);
1298184138Smav		}
1299241600Sgonzo		if (intmask & SDHCI_INT_CARD_INSERT) {
1300241600Sgonzo			if (bootverbose || sdhci_debug)
1301241600Sgonzo				slot_printf(slot, "Card inserted\n");
1302241600Sgonzo			callout_reset(&slot->card_callout, hz / 2,
1303241600Sgonzo			    sdhci_card_delay, slot);
1304184138Smav		}
1305241600Sgonzo		intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE);
1306184138Smav	}
1307241600Sgonzo	/* Handle command interrupts. */
1308241600Sgonzo	if (intmask & SDHCI_INT_CMD_MASK) {
1309241600Sgonzo		WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_CMD_MASK);
1310241600Sgonzo		sdhci_cmd_irq(slot, intmask & SDHCI_INT_CMD_MASK);
1311241600Sgonzo	}
1312241600Sgonzo	/* Handle data interrupts. */
1313241600Sgonzo	if (intmask & SDHCI_INT_DATA_MASK) {
1314241600Sgonzo		WR4(slot, SDHCI_INT_STATUS, intmask & SDHCI_INT_DATA_MASK);
1315276287Sian		/* Dont call data_irq in case of errored command */
1316276287Sian		if ((intmask & SDHCI_INT_CMD_ERROR_MASK) == 0)
1317276287Sian			sdhci_data_irq(slot, intmask & SDHCI_INT_DATA_MASK);
1318241600Sgonzo	}
1319241600Sgonzo	/* Handle AutoCMD12 error interrupt. */
1320241600Sgonzo	if (intmask & SDHCI_INT_ACMD12ERR) {
1321241600Sgonzo		WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_ACMD12ERR);
1322241600Sgonzo		sdhci_acmd_irq(slot);
1323241600Sgonzo	}
1324241600Sgonzo	intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
1325241600Sgonzo	intmask &= ~SDHCI_INT_ACMD12ERR;
1326241600Sgonzo	intmask &= ~SDHCI_INT_ERROR;
1327241600Sgonzo	/* Handle bus power interrupt. */
1328241600Sgonzo	if (intmask & SDHCI_INT_BUS_POWER) {
1329241600Sgonzo		WR4(slot, SDHCI_INT_STATUS, SDHCI_INT_BUS_POWER);
1330241600Sgonzo		slot_printf(slot,
1331241600Sgonzo		    "Card is consuming too much power!\n");
1332241600Sgonzo		intmask &= ~SDHCI_INT_BUS_POWER;
1333241600Sgonzo	}
1334241600Sgonzo	/* The rest is unknown. */
1335241600Sgonzo	if (intmask) {
1336241600Sgonzo		WR4(slot, SDHCI_INT_STATUS, intmask);
1337241600Sgonzo		slot_printf(slot, "Unexpected interrupt 0x%08x.\n",
1338241600Sgonzo		    intmask);
1339241600Sgonzo		sdhci_dumpregs(slot);
1340241600Sgonzo	}
1341241600Sgonzo
1342241600Sgonzo	SDHCI_UNLOCK(slot);
1343184138Smav}
1344184138Smav
1345241600Sgonzoint
1346241600Sgonzosdhci_generic_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
1347184138Smav{
1348184138Smav	struct sdhci_slot *slot = device_get_ivars(child);
1349184138Smav
1350184138Smav	switch (which) {
1351184138Smav	default:
1352184138Smav		return (EINVAL);
1353184138Smav	case MMCBR_IVAR_BUS_MODE:
1354222475Sjchandra		*result = slot->host.ios.bus_mode;
1355184138Smav		break;
1356184138Smav	case MMCBR_IVAR_BUS_WIDTH:
1357222475Sjchandra		*result = slot->host.ios.bus_width;
1358184138Smav		break;
1359184138Smav	case MMCBR_IVAR_CHIP_SELECT:
1360222475Sjchandra		*result = slot->host.ios.chip_select;
1361184138Smav		break;
1362184138Smav	case MMCBR_IVAR_CLOCK:
1363222475Sjchandra		*result = slot->host.ios.clock;
1364184138Smav		break;
1365184138Smav	case MMCBR_IVAR_F_MIN:
1366222475Sjchandra		*result = slot->host.f_min;
1367184138Smav		break;
1368184138Smav	case MMCBR_IVAR_F_MAX:
1369222475Sjchandra		*result = slot->host.f_max;
1370184138Smav		break;
1371184138Smav	case MMCBR_IVAR_HOST_OCR:
1372222475Sjchandra		*result = slot->host.host_ocr;
1373184138Smav		break;
1374184138Smav	case MMCBR_IVAR_MODE:
1375222475Sjchandra		*result = slot->host.mode;
1376184138Smav		break;
1377184138Smav	case MMCBR_IVAR_OCR:
1378222475Sjchandra		*result = slot->host.ocr;
1379184138Smav		break;
1380184138Smav	case MMCBR_IVAR_POWER_MODE:
1381222475Sjchandra		*result = slot->host.ios.power_mode;
1382184138Smav		break;
1383184138Smav	case MMCBR_IVAR_VDD:
1384222475Sjchandra		*result = slot->host.ios.vdd;
1385184138Smav		break;
1386184138Smav	case MMCBR_IVAR_CAPS:
1387222475Sjchandra		*result = slot->host.caps;
1388184138Smav		break;
1389184138Smav	case MMCBR_IVAR_TIMING:
1390222475Sjchandra		*result = slot->host.ios.timing;
1391184138Smav		break;
1392184452Smav	case MMCBR_IVAR_MAX_DATA:
1393222475Sjchandra		*result = 65535;
1394184452Smav		break;
1395184138Smav	}
1396184138Smav	return (0);
1397184138Smav}
1398184138Smav
1399241600Sgonzoint
1400241600Sgonzosdhci_generic_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
1401184138Smav{
1402184138Smav	struct sdhci_slot *slot = device_get_ivars(child);
1403184138Smav
1404184138Smav	switch (which) {
1405184138Smav	default:
1406184138Smav		return (EINVAL);
1407184138Smav	case MMCBR_IVAR_BUS_MODE:
1408184138Smav		slot->host.ios.bus_mode = value;
1409184138Smav		break;
1410184138Smav	case MMCBR_IVAR_BUS_WIDTH:
1411184138Smav		slot->host.ios.bus_width = value;
1412184138Smav		break;
1413184138Smav	case MMCBR_IVAR_CHIP_SELECT:
1414184138Smav		slot->host.ios.chip_select = value;
1415184138Smav		break;
1416184138Smav	case MMCBR_IVAR_CLOCK:
1417184138Smav		if (value > 0) {
1418246886Sgonzo			uint32_t max_clock;
1419246886Sgonzo			uint32_t clock;
1420184138Smav			int i;
1421184138Smav
1422246886Sgonzo			max_clock = slot->max_clk;
1423246886Sgonzo			clock = max_clock;
1424246886Sgonzo
1425246886Sgonzo			if (slot->version < SDHCI_SPEC_300) {
1426246886Sgonzo				for (i = 0; i < SDHCI_200_MAX_DIVIDER;
1427246886Sgonzo				    i <<= 1) {
1428246886Sgonzo					if (clock <= value)
1429246886Sgonzo						break;
1430246886Sgonzo					clock >>= 1;
1431246886Sgonzo				}
1432184138Smav			}
1433246886Sgonzo			else {
1434246886Sgonzo				for (i = 0; i < SDHCI_300_MAX_DIVIDER;
1435246886Sgonzo				    i += 2) {
1436246886Sgonzo					if (clock <= value)
1437246886Sgonzo						break;
1438246886Sgonzo					clock = max_clock / (i + 2);
1439246886Sgonzo				}
1440246886Sgonzo			}
1441246886Sgonzo
1442184138Smav			slot->host.ios.clock = clock;
1443184138Smav		} else
1444184138Smav			slot->host.ios.clock = 0;
1445184138Smav		break;
1446184138Smav	case MMCBR_IVAR_MODE:
1447184138Smav		slot->host.mode = value;
1448184138Smav		break;
1449184138Smav	case MMCBR_IVAR_OCR:
1450184138Smav		slot->host.ocr = value;
1451184138Smav		break;
1452184138Smav	case MMCBR_IVAR_POWER_MODE:
1453184138Smav		slot->host.ios.power_mode = value;
1454184138Smav		break;
1455184138Smav	case MMCBR_IVAR_VDD:
1456184138Smav		slot->host.ios.vdd = value;
1457184138Smav		break;
1458184138Smav	case MMCBR_IVAR_TIMING:
1459184138Smav		slot->host.ios.timing = value;
1460184138Smav		break;
1461184138Smav	case MMCBR_IVAR_CAPS:
1462184138Smav	case MMCBR_IVAR_HOST_OCR:
1463184138Smav	case MMCBR_IVAR_F_MIN:
1464184138Smav	case MMCBR_IVAR_F_MAX:
1465184452Smav	case MMCBR_IVAR_MAX_DATA:
1466184138Smav		return (EINVAL);
1467184138Smav	}
1468184138Smav	return (0);
1469184138Smav}
1470184138Smav
1471241600SgonzoMODULE_VERSION(sdhci, 1);
1472