1239281Sgonzo/*-
2239281Sgonzo * Copyright (c) 2011
3239281Sgonzo *	Ben Gray <ben.r.gray@gmail.com>.
4239281Sgonzo * All rights reserved.
5239281Sgonzo *
6239281Sgonzo * Redistribution and use in source and binary forms, with or without
7239281Sgonzo * modification, are permitted provided that the following conditions
8239281Sgonzo * are met:
9239281Sgonzo * 1. Redistributions of source code must retain the above copyright
10239281Sgonzo *    notice, this list of conditions and the following disclaimer.
11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
12239281Sgonzo *    notice, this list of conditions and the following disclaimer in the
13239281Sgonzo *    documentation and/or other materials provided with the distribution.
14239281Sgonzo *
15239281Sgonzo * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16239281Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17239281Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18239281Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19239281Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20239281Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21239281Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22239281Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23239281Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24239281Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25239281Sgonzo * SUCH DAMAGE.
26239281Sgonzo */
27239281Sgonzo
28239281Sgonzo/**
29239281Sgonzo * Driver for the MMC/SD/SDIO module on the TI OMAP series of SoCs.
30239281Sgonzo *
31239281Sgonzo * This driver is heavily based on the SD/MMC driver for the AT91 (at91_mci.c).
32239281Sgonzo *
33239281Sgonzo * It's important to realise that the MMC state machine is already in the kernel
34239281Sgonzo * and this driver only exposes the specific interfaces of the controller.
35239281Sgonzo *
36239281Sgonzo * This driver is still very much a work in progress, I've verified that basic
37239281Sgonzo * sector reading can be performed. But I've yet to test it with a file system
38239281Sgonzo * or even writing.  In addition I've only tested the driver with an SD card,
39239281Sgonzo * I've no idea if MMC cards work.
40239281Sgonzo *
41239281Sgonzo */
42239281Sgonzo#include <sys/cdefs.h>
43239281Sgonzo__FBSDID("$FreeBSD: releng/10.3/sys/arm/ti/ti_mmchs.c 266159 2014-05-15 16:59:47Z ian $");
44239281Sgonzo
45239281Sgonzo#include <sys/param.h>
46239281Sgonzo#include <sys/systm.h>
47239281Sgonzo#include <sys/bio.h>
48239281Sgonzo#include <sys/bus.h>
49239281Sgonzo#include <sys/conf.h>
50239281Sgonzo#include <sys/endian.h>
51239281Sgonzo#include <sys/kernel.h>
52239281Sgonzo#include <sys/kthread.h>
53239281Sgonzo#include <sys/lock.h>
54239281Sgonzo#include <sys/malloc.h>
55239281Sgonzo#include <sys/module.h>
56239281Sgonzo#include <sys/mutex.h>
57239281Sgonzo#include <sys/queue.h>
58239281Sgonzo#include <sys/resource.h>
59239281Sgonzo#include <sys/rman.h>
60239281Sgonzo#include <sys/time.h>
61239281Sgonzo#include <sys/timetc.h>
62239281Sgonzo#include <sys/gpio.h>
63239281Sgonzo
64239281Sgonzo#include <machine/bus.h>
65239281Sgonzo#include <machine/cpu.h>
66239281Sgonzo#include <machine/cpufunc.h>
67239281Sgonzo#include <machine/resource.h>
68239281Sgonzo#include <machine/intr.h>
69239281Sgonzo
70239281Sgonzo#include <dev/mmc/bridge.h>
71239281Sgonzo#include <dev/mmc/mmcreg.h>
72239281Sgonzo#include <dev/mmc/mmcbrvar.h>
73239281Sgonzo
74239281Sgonzo#include <dev/fdt/fdt_common.h>
75239281Sgonzo#include <dev/ofw/openfirm.h>
76239281Sgonzo#include <dev/ofw/ofw_bus.h>
77239281Sgonzo#include <dev/ofw/ofw_bus_subr.h>
78239281Sgonzo
79239281Sgonzo#include "gpio_if.h"
80239281Sgonzo
81239281Sgonzo#include "mmcbr_if.h"
82239281Sgonzo#include "mmcbus_if.h"
83239281Sgonzo
84239281Sgonzo#include <arm/ti/ti_sdma.h>
85239281Sgonzo#include <arm/ti/ti_edma3.h>
86239281Sgonzo#include <arm/ti/ti_mmchs.h>
87239281Sgonzo#include <arm/ti/ti_cpuid.h>
88239281Sgonzo#include <arm/ti/ti_prcm.h>
89239281Sgonzo
90239281Sgonzo#include <arm/ti/twl/twl.h>
91239281Sgonzo#include <arm/ti/twl/twl_vreg.h>
92239281Sgonzo
93239281Sgonzo#ifdef DEBUG
94239281Sgonzo#define ti_mmchs_dbg(sc, fmt, args...) \
95239281Sgonzo	device_printf((sc)->sc_dev, fmt, ## args);
96239281Sgonzo#else
97239281Sgonzo#define ti_mmchs_dbg(sc, fmt, args...)
98239281Sgonzo#endif
99239281Sgonzo
100239281Sgonzo/**
101239281Sgonzo *	Structure that stores the driver context
102239281Sgonzo */
103239281Sgonzostruct ti_mmchs_softc {
104239281Sgonzo	device_t		sc_dev;
105239281Sgonzo	uint32_t		device_id;
106239281Sgonzo	struct resource*	sc_irq_res;
107239281Sgonzo	struct resource*	sc_mem_res;
108239281Sgonzo
109239281Sgonzo	void*			sc_irq_h;
110239281Sgonzo
111239281Sgonzo	bus_dma_tag_t		sc_dmatag;
112239281Sgonzo	bus_dmamap_t		sc_dmamap;
113239281Sgonzo	int			sc_dmamapped;
114239281Sgonzo
115239281Sgonzo	unsigned int		sc_dmach_rd;
116239281Sgonzo	unsigned int		sc_dmach_wr;
117239281Sgonzo	int			dma_rx_trig;
118239281Sgonzo	int			dma_tx_trig;
119239281Sgonzo
120239281Sgonzo	device_t		sc_gpio_dev;
121239281Sgonzo	int			sc_wp_gpio_pin;  /* GPIO pin for MMC write protect */
122239281Sgonzo
123239281Sgonzo	device_t		sc_vreg_dev;
124239281Sgonzo	const char*		sc_vreg_name;
125239281Sgonzo
126239281Sgonzo	struct mtx		sc_mtx;
127239281Sgonzo
128239281Sgonzo	struct mmc_host		host;
129239281Sgonzo	struct mmc_request*	req;
130239281Sgonzo	struct mmc_command*	curcmd;
131239281Sgonzo
132239281Sgonzo	int			flags;
133239281Sgonzo#define CMD_STARTED     1
134239281Sgonzo#define STOP_STARTED    2
135239281Sgonzo
136239281Sgonzo	int			bus_busy;  /* TODO: Needed ? */
137239281Sgonzo
138239281Sgonzo	void*			sc_cmd_data_vaddr;
139239281Sgonzo	int			sc_cmd_data_len;
140239281Sgonzo
141239281Sgonzo	/* The offset applied to each of the register base addresses, OMAP4
142239281Sgonzo	 * register sets are offset 0x100 from the OMAP3 series.
143239281Sgonzo	 */
144239281Sgonzo	unsigned long		sc_reg_off;
145239281Sgonzo
146239281Sgonzo	/* The physical address of the MMCHS_DATA register, used for the DMA xfers */
147239281Sgonzo	unsigned long		sc_data_reg_paddr;
148239281Sgonzo
149239281Sgonzo	/* The reference clock frequency */
150239281Sgonzo	unsigned int		sc_ref_freq;
151239281Sgonzo
152239281Sgonzo	enum mmc_power_mode	sc_cur_power_mode;
153239281Sgonzo};
154239281Sgonzo
155239281Sgonzo/**
156239281Sgonzo *	Macros for driver mutex locking
157239281Sgonzo */
158239281Sgonzo#define TI_MMCHS_LOCK(_sc)              mtx_lock(&(_sc)->sc_mtx)
159239281Sgonzo#define	TI_MMCHS_UNLOCK(_sc)            mtx_unlock(&(_sc)->sc_mtx)
160239281Sgonzo#define TI_MMCHS_LOCK_INIT(_sc) \
161239281Sgonzo	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
162239281Sgonzo	         "ti_mmchs", MTX_DEF)
163239281Sgonzo#define TI_MMCHS_LOCK_DESTROY(_sc)      mtx_destroy(&_sc->sc_mtx);
164239281Sgonzo#define TI_MMCHS_ASSERT_LOCKED(_sc)     mtx_assert(&_sc->sc_mtx, MA_OWNED);
165239281Sgonzo#define TI_MMCHS_ASSERT_UNLOCKED(_sc)   mtx_assert(&_sc->sc_mtx, MA_NOTOWNED);
166239281Sgonzo
167239281Sgonzostatic void ti_mmchs_start(struct ti_mmchs_softc *sc);
168239281Sgonzo
169239281Sgonzo/**
170239281Sgonzo *	ti_mmchs_read_4 - reads a 32-bit value from a register
171239281Sgonzo *	ti_mmchs_write_4 - writes a 32-bit value to a register
172239281Sgonzo *	@sc: pointer to the driver context
173239281Sgonzo *	@off: register offset to read from
174239281Sgonzo *	@val: the value to write into the register
175239281Sgonzo *
176239281Sgonzo *	LOCKING:
177239281Sgonzo *	None
178239281Sgonzo *
179239281Sgonzo *	RETURNS:
180239281Sgonzo *	The 32-bit value read from the register
181239281Sgonzo */
182239281Sgonzostatic inline uint32_t
183239281Sgonzoti_mmchs_read_4(struct ti_mmchs_softc *sc, bus_size_t off)
184239281Sgonzo{
185239281Sgonzo	return bus_read_4(sc->sc_mem_res, (sc->sc_reg_off + off));
186239281Sgonzo}
187239281Sgonzo
188239281Sgonzostatic inline void
189239281Sgonzoti_mmchs_write_4(struct ti_mmchs_softc *sc, bus_size_t off, uint32_t val)
190239281Sgonzo{
191239281Sgonzo	bus_write_4(sc->sc_mem_res, (sc->sc_reg_off + off), val);
192239281Sgonzo}
193239281Sgonzo
194239281Sgonzo/**
195239281Sgonzo *	ti_mmchs_reset_controller -
196239281Sgonzo *	@arg: caller supplied arg
197239281Sgonzo *	@segs: array of segments (although in our case should only be one)
198239281Sgonzo *	@nsegs: number of segments (in our case should be 1)
199239281Sgonzo *	@error:
200239281Sgonzo *
201239281Sgonzo *
202239281Sgonzo *
203239281Sgonzo */
204239281Sgonzostatic void
205239281Sgonzoti_mmchs_reset_controller(struct ti_mmchs_softc *sc, uint32_t bit)
206239281Sgonzo{
207239281Sgonzo	unsigned long attempts;
208239281Sgonzo	uint32_t sysctl;
209239281Sgonzo
210239281Sgonzo	ti_mmchs_dbg(sc, "reseting controller - bit 0x%08x\n", bit);
211239281Sgonzo
212239281Sgonzo	sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
213239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | bit);
214253023Sgonzo	/*
215253053Srpaulo	 * AM335x and OMAP4 >= ES2 have an updated reset logic.
216253053Srpaulo	 * Monitor a 0->1 transition first.
217253023Sgonzo	 */
218253023Sgonzo	if ((ti_chip() == CHIP_AM335X) ||
219253023Sgonzo	    ((ti_chip() == CHIP_OMAP_4) && (ti_revision() > OMAP4430_REV_ES1_0))) {
220239281Sgonzo		attempts = 10000;
221239281Sgonzo		while (!(ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0))
222239281Sgonzo			continue;
223239281Sgonzo	}
224239281Sgonzo
225239281Sgonzo	attempts = 10000;
226239281Sgonzo	while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0))
227239281Sgonzo		continue;
228239281Sgonzo
229239281Sgonzo	if (ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit)
230239281Sgonzo		device_printf(sc->sc_dev, "Error - Timeout waiting on controller reset\n");
231239281Sgonzo}
232239281Sgonzo
233239281Sgonzo/**
234239281Sgonzo *	ti_mmchs_getaddr - called by the DMA function to simply return the phys addr
235239281Sgonzo *	@arg: caller supplied arg
236239281Sgonzo *	@segs: array of segments (although in our case should only be one)
237239281Sgonzo *	@nsegs: number of segments (in our case should be 1)
238239281Sgonzo *	@error:
239239281Sgonzo *
240239281Sgonzo *	This function is called by bus_dmamap_load() after it has compiled an array
241239281Sgonzo *	of segments, each segment is a phsyical chunk of memory. However in our case
242239281Sgonzo *	we should only have one segment, because we don't (yet?) support DMA scatter
243239281Sgonzo *	gather. To ensure we only have one segment, the DMA tag was created by
244239281Sgonzo *	bus_dma_tag_create() (called from ti_mmchs_attach) with nsegments set to 1.
245239281Sgonzo *
246239281Sgonzo */
247239281Sgonzostatic void
248239281Sgonzoti_mmchs_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
249239281Sgonzo{
250239281Sgonzo	if (error != 0)
251239281Sgonzo		return;
252239281Sgonzo
253239281Sgonzo	*(bus_addr_t *)arg = segs[0].ds_addr;
254239281Sgonzo}
255239281Sgonzo
256239281Sgonzo#ifndef SOC_TI_AM335X
257239281Sgonzo/**
258239281Sgonzo *	ti_mmchs_dma_intr - interrupt handler for DMA events triggered by the controller
259239281Sgonzo *	@ch: the dma channel number
260239281Sgonzo *	@status: bit field of the status bytes
261239281Sgonzo *	@data: callback data, in this case a pointer to the controller struct
262239281Sgonzo *
263239281Sgonzo *
264239281Sgonzo *	LOCKING:
265239281Sgonzo *	Called from interrupt context
266239281Sgonzo *
267239281Sgonzo */
268239281Sgonzostatic void
269239281Sgonzoti_mmchs_dma_intr(unsigned int ch, uint32_t status, void *data)
270239281Sgonzo{
271239281Sgonzo	/* Ignore for now ... we don't need this interrupt as we already have the
272239281Sgonzo	 * interrupt from the MMC controller.
273239281Sgonzo	 */
274239281Sgonzo}
275239281Sgonzo#endif
276239281Sgonzo
277239281Sgonzo/**
278239281Sgonzo *	ti_mmchs_intr_xfer_compl - called if a 'transfer complete' IRQ was received
279239281Sgonzo *	@sc: pointer to the driver context
280239281Sgonzo *	@cmd: the command that was sent previously
281239281Sgonzo *
282239281Sgonzo *	This function is simply responsible for syncing up the DMA buffer.
283239281Sgonzo *
284239281Sgonzo *	LOCKING:
285239281Sgonzo *	Called from interrupt context
286239281Sgonzo *
287239281Sgonzo *	RETURNS:
288239281Sgonzo *	Return value indicates if the transaction is complete, not done = 0, done != 0
289239281Sgonzo */
290239281Sgonzostatic int
291239281Sgonzoti_mmchs_intr_xfer_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
292239281Sgonzo{
293239281Sgonzo	uint32_t cmd_reg;
294239281Sgonzo
295239281Sgonzo	/* Read command register to test whether this command was a read or write. */
296239281Sgonzo	cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD);
297239281Sgonzo
298239281Sgonzo	/* Sync-up the DMA buffer so the caller can access the new memory */
299239281Sgonzo	if (cmd_reg & MMCHS_CMD_DDIR) {
300239281Sgonzo		bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTREAD);
301239281Sgonzo		bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
302239281Sgonzo	}
303239281Sgonzo	else {
304239281Sgonzo		bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTWRITE);
305239281Sgonzo		bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
306239281Sgonzo	}
307239281Sgonzo	sc->sc_dmamapped--;
308239281Sgonzo
309239281Sgonzo	/* Debugging dump of the data received */
310239281Sgonzo#if 0
311239281Sgonzo	{
312239281Sgonzo		int i;
313239281Sgonzo		uint8_t *p = (uint8_t*) sc->sc_cmd_data_vaddr;
314239281Sgonzo		for (i=0; i<sc->sc_cmd_data_len; i++) {
315239281Sgonzo			if ((i % 16) == 0)
316239281Sgonzo				printf("\n0x%04x : ", i);
317239281Sgonzo			printf("%02X ", *p++);
318239281Sgonzo		}
319239281Sgonzo		printf("\n");
320239281Sgonzo	}
321239281Sgonzo#endif
322239281Sgonzo
323239281Sgonzo	/* We are done, transfer complete */
324239281Sgonzo	return 1;
325239281Sgonzo}
326239281Sgonzo
327239281Sgonzo/**
328239281Sgonzo *	ti_mmchs_intr_cmd_compl - called if a 'command complete' IRQ was received
329239281Sgonzo *	@sc: pointer to the driver context
330239281Sgonzo *	@cmd: the command that was sent previously
331239281Sgonzo *
332239281Sgonzo *
333239281Sgonzo *	LOCKING:
334239281Sgonzo *	Called from interrupt context
335239281Sgonzo *
336239281Sgonzo *	RETURNS:
337239281Sgonzo *	Return value indicates if the transaction is complete, not done = 0, done != 0
338239281Sgonzo */
339239281Sgonzostatic int
340239281Sgonzoti_mmchs_intr_cmd_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
341239281Sgonzo{
342239281Sgonzo	uint32_t cmd_reg;
343239281Sgonzo
344239281Sgonzo	/* Copy the response into the request struct ... if a response was
345239281Sgonzo	 * expected */
346239281Sgonzo	if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) {
347239281Sgonzo		if (cmd->flags & MMC_RSP_136) {
348239281Sgonzo			cmd->resp[3] = ti_mmchs_read_4(sc, MMCHS_RSP10);
349239281Sgonzo			cmd->resp[2] = ti_mmchs_read_4(sc, MMCHS_RSP32);
350239281Sgonzo			cmd->resp[1] = ti_mmchs_read_4(sc, MMCHS_RSP54);
351239281Sgonzo			cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP76);
352239281Sgonzo		} else {
353239281Sgonzo			cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP10);
354239281Sgonzo		}
355239281Sgonzo	}
356239281Sgonzo
357239281Sgonzo	/* Check if the command was expecting some data transfer, if not
358239281Sgonzo	 * we are done. */
359239281Sgonzo	cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD);
360239281Sgonzo	return ((cmd_reg & MMCHS_CMD_DP) == 0);
361239281Sgonzo}
362239281Sgonzo
363239281Sgonzo/**
364239281Sgonzo *	ti_mmchs_intr_error - handles error interrupts
365239281Sgonzo *	@sc: pointer to the driver context
366239281Sgonzo *	@cmd: the command that was sent previously
367239281Sgonzo *	@stat_reg: the value that was in the status register
368239281Sgonzo *
369239281Sgonzo *
370239281Sgonzo *	LOCKING:
371239281Sgonzo *	Called from interrupt context
372239281Sgonzo *
373239281Sgonzo *	RETURNS:
374239281Sgonzo *	Return value indicates if the transaction is complete, not done = 0, done != 0
375239281Sgonzo */
376239281Sgonzostatic int
377239281Sgonzoti_mmchs_intr_error(struct ti_mmchs_softc *sc, struct mmc_command *cmd,
378239281Sgonzo					 uint32_t stat_reg)
379239281Sgonzo{
380239281Sgonzo	ti_mmchs_dbg(sc, "error in xfer - stat 0x%08x\n", stat_reg);
381239281Sgonzo
382239281Sgonzo	/* Ignore CRC errors on CMD2 and ACMD47, per relevant standards */
383239281Sgonzo	if ((stat_reg & MMCHS_STAT_CCRC) && (cmd->opcode == MMC_SEND_OP_COND ||
384239281Sgonzo	    cmd->opcode == ACMD_SD_SEND_OP_COND))
385239281Sgonzo		cmd->error = MMC_ERR_NONE;
386239281Sgonzo	else if (stat_reg & (MMCHS_STAT_CTO | MMCHS_STAT_DTO))
387239281Sgonzo		cmd->error = MMC_ERR_TIMEOUT;
388239281Sgonzo	else if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_DCRC))
389239281Sgonzo		cmd->error = MMC_ERR_BADCRC;
390239281Sgonzo	else
391239281Sgonzo		cmd->error = MMC_ERR_FAILED;
392239281Sgonzo
393239281Sgonzo	/* If a dma transaction we should also stop the dma transfer */
394239281Sgonzo	if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DE) {
395239281Sgonzo
396239281Sgonzo		/* Abort the DMA transfer (DDIR bit tells direction) */
397239281Sgonzo		if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DDIR)
398239281Sgonzo#ifdef SOC_TI_AM335X
399239281Sgonzo			printf("%s: DMA unimplemented\n", __func__);
400239281Sgonzo#else
401239281Sgonzo			ti_sdma_stop_xfer(sc->sc_dmach_rd);
402239281Sgonzo#endif
403239281Sgonzo		else
404239281Sgonzo#ifdef SOC_TI_AM335X
405239281Sgonzo			printf("%s: DMA unimplemented\n", __func__);
406239281Sgonzo#else
407239281Sgonzo			ti_sdma_stop_xfer(sc->sc_dmach_wr);
408239281Sgonzo#endif
409239281Sgonzo
410239281Sgonzo		/* If an error occure abort the DMA operation and free the dma map */
411239281Sgonzo		if ((sc->sc_dmamapped > 0) && (cmd->error != MMC_ERR_NONE)) {
412239281Sgonzo			bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap);
413239281Sgonzo			sc->sc_dmamapped--;
414239281Sgonzo		}
415239281Sgonzo	}
416239281Sgonzo
417239281Sgonzo	/* Command error occured? ... if so issue a soft reset for the cmd fsm */
418239281Sgonzo	if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_CTO)) {
419239281Sgonzo		ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRC);
420239281Sgonzo	}
421239281Sgonzo
422239281Sgonzo	/* Data error occured? ... if so issue a soft reset for the data line */
423239281Sgonzo	if (stat_reg & (MMCHS_STAT_DEB | MMCHS_STAT_DCRC | MMCHS_STAT_DTO)) {
424239281Sgonzo		ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRD);
425239281Sgonzo	}
426239281Sgonzo
427239281Sgonzo	/* On any error the command is cancelled ... so we are done */
428239281Sgonzo	return 1;
429239281Sgonzo}
430239281Sgonzo
431239281Sgonzo/**
432239281Sgonzo *	ti_mmchs_intr - interrupt handler for MMC/SD/SDIO controller
433239281Sgonzo *	@arg: pointer to the driver context
434239281Sgonzo *
435239281Sgonzo *	Interrupt handler for the MMC/SD/SDIO controller, responsible for handling
436239281Sgonzo *	the IRQ and clearing the status flags.
437239281Sgonzo *
438239281Sgonzo *	LOCKING:
439239281Sgonzo *	Called from interrupt context
440239281Sgonzo *
441239281Sgonzo *	RETURNS:
442239281Sgonzo *	nothing
443239281Sgonzo */
444239281Sgonzostatic void
445239281Sgonzoti_mmchs_intr(void *arg)
446239281Sgonzo{
447239281Sgonzo	struct ti_mmchs_softc *sc = (struct ti_mmchs_softc *) arg;
448239281Sgonzo	uint32_t stat_reg;
449239281Sgonzo	int done = 0;
450239281Sgonzo
451239281Sgonzo	TI_MMCHS_LOCK(sc);
452239281Sgonzo
453239281Sgonzo	stat_reg = ti_mmchs_read_4(sc, MMCHS_STAT) & (ti_mmchs_read_4(sc,
454239281Sgonzo	    MMCHS_IE) | MMCHS_STAT_ERRI);
455239281Sgonzo
456239281Sgonzo	if (sc->curcmd == NULL) {
457239281Sgonzo		device_printf(sc->sc_dev, "Error: current cmd NULL, already done?\n");
458239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg);
459239281Sgonzo		TI_MMCHS_UNLOCK(sc);
460239281Sgonzo		return;
461239281Sgonzo	}
462239281Sgonzo
463239281Sgonzo	if (stat_reg & MMCHS_STAT_ERRI) {
464239281Sgonzo		/* An error has been tripped in the status register */
465239281Sgonzo		done = ti_mmchs_intr_error(sc, sc->curcmd, stat_reg);
466239281Sgonzo
467239281Sgonzo	} else {
468239281Sgonzo
469239281Sgonzo		/* NOTE: This implementation could be a bit inefficent, I don't think
470239281Sgonzo		 * it is necessary to handle both the 'command complete' and 'transfer
471239281Sgonzo		 * complete' for data transfers ... presumably just transfer complete
472239281Sgonzo		 * is enough.
473239281Sgonzo		 */
474239281Sgonzo
475239281Sgonzo		/* No error */
476239281Sgonzo		sc->curcmd->error = MMC_ERR_NONE;
477239281Sgonzo
478239281Sgonzo		/* Check if the command completed */
479239281Sgonzo		if (stat_reg & MMCHS_STAT_CC) {
480239281Sgonzo			done = ti_mmchs_intr_cmd_compl(sc, sc->curcmd);
481239281Sgonzo		}
482239281Sgonzo
483239281Sgonzo		/* Check if the transfer has completed */
484239281Sgonzo		if (stat_reg & MMCHS_STAT_TC) {
485239281Sgonzo			done = ti_mmchs_intr_xfer_compl(sc, sc->curcmd);
486239281Sgonzo		}
487239281Sgonzo
488239281Sgonzo	}
489239281Sgonzo
490239281Sgonzo	/* Clear all the interrupt status bits by writing the value back */
491239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg);
492239281Sgonzo
493239281Sgonzo	/* This may mark the command as done if there is no stop request */
494239281Sgonzo	/* TODO: This is a bit ugly, needs fix-up */
495239281Sgonzo	if (done) {
496239281Sgonzo		ti_mmchs_start(sc);
497239281Sgonzo	}
498239281Sgonzo
499239281Sgonzo	TI_MMCHS_UNLOCK(sc);
500239281Sgonzo}
501239281Sgonzo
502239281Sgonzo#ifdef SOC_TI_AM335X
503239281Sgonzostatic void
504239281Sgonzoti_mmchs_edma3_rx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr,
505239281Sgonzo    uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks)
506239281Sgonzo{
507239281Sgonzo	struct ti_edma3cc_param_set ps;
508239281Sgonzo
509239281Sgonzo	bzero(&ps, sizeof(struct ti_edma3cc_param_set));
510239281Sgonzo	ps.src		= src_paddr;
511239281Sgonzo	ps.dst		= dst_paddr;
512239281Sgonzo	ps.dstbidx	= 4;
513239281Sgonzo	ps.dstcidx	= blk_size;
514239281Sgonzo	ps.acnt		= 4;
515239281Sgonzo	ps.bcnt		= blk_size/4;
516239281Sgonzo	ps.ccnt		= num_blks;
517239281Sgonzo	ps.link		= 0xffff;
518239281Sgonzo	ps.opt.tcc	= sc->dma_rx_trig;
519239281Sgonzo	ps.opt.tcinten	= 1;
520239281Sgonzo	ps.opt.fwid	= 2; /* fifo width is 32 */
521239281Sgonzo	ps.opt.sam	= 1;
522239281Sgonzo	ps.opt.syncdim	= 1;
523239281Sgonzo
524239281Sgonzo	ti_edma3_param_write(sc->dma_rx_trig, &ps);
525239281Sgonzo	ti_edma3_enable_transfer_event(sc->dma_rx_trig);
526239281Sgonzo}
527239281Sgonzo
528239281Sgonzostatic void
529239281Sgonzoti_mmchs_edma3_tx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr,
530239281Sgonzo    uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks)
531239281Sgonzo{
532239281Sgonzo	struct ti_edma3cc_param_set ps;
533239281Sgonzo
534239281Sgonzo	bzero(&ps, sizeof(struct ti_edma3cc_param_set));
535239281Sgonzo	ps.src		= src_paddr;
536239281Sgonzo	ps.dst		= dst_paddr;
537239281Sgonzo	ps.srccidx	= blk_size;
538239281Sgonzo	ps.bcnt		= blk_size/4;
539239281Sgonzo	ps.ccnt		= num_blks;
540239281Sgonzo	ps.srcbidx	= 4;
541239281Sgonzo	ps.acnt		= 0x4;
542239281Sgonzo	ps.link		= 0xffff;
543239281Sgonzo	ps.opt.tcc	= sc->dma_tx_trig;
544239281Sgonzo	ps.opt.tcinten	= 1;
545239281Sgonzo	ps.opt.fwid	= 2; /* fifo width is 32 */
546239281Sgonzo	ps.opt.dam	= 1;
547239281Sgonzo	ps.opt.syncdim	= 1;
548239281Sgonzo
549239281Sgonzo	ti_edma3_param_write(sc->dma_tx_trig, &ps);
550239281Sgonzo	ti_edma3_enable_transfer_event(sc->dma_tx_trig);
551239281Sgonzo}
552239281Sgonzo#endif
553239281Sgonzo
554239281Sgonzo/**
555239281Sgonzo *	ti_mmchs_start_cmd - starts the given command
556239281Sgonzo *	@sc: pointer to the driver context
557239281Sgonzo *	@cmd: the command to start
558239281Sgonzo *
559239281Sgonzo *	The call tree for this function is
560239281Sgonzo *		- ti_mmchs_start_cmd
561239281Sgonzo *			- ti_mmchs_start
562239281Sgonzo *				- ti_mmchs_request
563239281Sgonzo *
564239281Sgonzo *	LOCKING:
565239281Sgonzo *	Caller should be holding the OMAP_MMC lock.
566239281Sgonzo *
567239281Sgonzo *	RETURNS:
568239281Sgonzo *	nothing
569239281Sgonzo */
570239281Sgonzostatic void
571239281Sgonzoti_mmchs_start_cmd(struct ti_mmchs_softc *sc, struct mmc_command *cmd)
572239281Sgonzo{
573239281Sgonzo	uint32_t cmd_reg, con_reg, ise_reg;
574239281Sgonzo	struct mmc_data *data;
575239281Sgonzo	struct mmc_request *req;
576239281Sgonzo	void *vaddr;
577239281Sgonzo	bus_addr_t paddr;
578239281Sgonzo#ifndef SOC_TI_AM335X
579239281Sgonzo	uint32_t pktsize;
580239281Sgonzo#endif
581239281Sgonzo	sc->curcmd = cmd;
582239281Sgonzo	data = cmd->data;
583239281Sgonzo	req = cmd->mrq;
584239281Sgonzo
585239281Sgonzo	/* Ensure the STR and MIT bits are cleared, these are only used for special
586239281Sgonzo	 * command types.
587239281Sgonzo	 */
588239281Sgonzo	con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
589239281Sgonzo	con_reg &= ~(MMCHS_CON_STR | MMCHS_CON_MIT);
590239281Sgonzo
591239281Sgonzo	/* Load the command into bits 29:24 of the CMD register */
592239281Sgonzo	cmd_reg = (uint32_t)(cmd->opcode & 0x3F) << 24;
593239281Sgonzo
594239281Sgonzo	/* Set the default set of interrupts */
595239281Sgonzo	ise_reg = (MMCHS_STAT_CERR | MMCHS_STAT_CTO | MMCHS_STAT_CC | MMCHS_STAT_CEB);
596239281Sgonzo
597239281Sgonzo	/* Enable CRC checking if requested */
598239281Sgonzo	if (cmd->flags & MMC_RSP_CRC)
599239281Sgonzo		ise_reg |= MMCHS_STAT_CCRC;
600239281Sgonzo
601239281Sgonzo	/* Enable reply index checking if the response supports it */
602239281Sgonzo	if (cmd->flags & MMC_RSP_OPCODE)
603239281Sgonzo		ise_reg |= MMCHS_STAT_CIE;
604239281Sgonzo
605239281Sgonzo	/* Set the expected response length */
606239281Sgonzo	if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) {
607239281Sgonzo		cmd_reg |= MMCHS_CMD_RSP_TYPE_NO;
608239281Sgonzo	} else {
609239281Sgonzo		if (cmd->flags & MMC_RSP_136)
610239281Sgonzo			cmd_reg |= MMCHS_CMD_RSP_TYPE_136;
611239281Sgonzo		else if (cmd->flags & MMC_RSP_BUSY)
612239281Sgonzo			cmd_reg |= MMCHS_CMD_RSP_TYPE_48_BSY;
613239281Sgonzo		else
614239281Sgonzo			cmd_reg |= MMCHS_CMD_RSP_TYPE_48;
615239281Sgonzo
616239281Sgonzo		/* Enable command index/crc checks if necessary expected */
617239281Sgonzo		if (cmd->flags & MMC_RSP_CRC)
618239281Sgonzo			cmd_reg |= MMCHS_CMD_CCCE;
619239281Sgonzo		if (cmd->flags & MMC_RSP_OPCODE)
620239281Sgonzo			cmd_reg |= MMCHS_CMD_CICE;
621239281Sgonzo	}
622239281Sgonzo
623239281Sgonzo	/* Set the bits for the special commands CMD12 (MMC_STOP_TRANSMISSION) and
624239281Sgonzo	 * CMD52 (SD_IO_RW_DIRECT) */
625239281Sgonzo	if (cmd->opcode == MMC_STOP_TRANSMISSION)
626239281Sgonzo		cmd_reg |= MMCHS_CMD_CMD_TYPE_IO_ABORT;
627239281Sgonzo
628239281Sgonzo	/* Check if there is any data to write */
629239281Sgonzo	if (data == NULL) {
630239281Sgonzo		/* Clear the block count */
631239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_BLK, 0);
632239281Sgonzo
633239281Sgonzo		/* The no data case is fairly simple */
634239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
635239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_IE, ise_reg);
636239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg);
637239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg);
638239281Sgonzo		ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg);
639239281Sgonzo		return;
640239281Sgonzo	}
641239281Sgonzo
642239281Sgonzo	/* Indicate that data is present */
643239281Sgonzo	cmd_reg |= MMCHS_CMD_DP | MMCHS_CMD_MSBS | MMCHS_CMD_BCE;
644239281Sgonzo
645239281Sgonzo	/* Indicate a read operation */
646239281Sgonzo	if (data->flags & MMC_DATA_READ)
647239281Sgonzo		cmd_reg |= MMCHS_CMD_DDIR;
648239281Sgonzo
649239281Sgonzo	/* Streaming mode */
650239281Sgonzo	if (data->flags & MMC_DATA_STREAM) {
651239281Sgonzo		con_reg |= MMCHS_CON_STR;
652239281Sgonzo	}
653239281Sgonzo
654239281Sgonzo	/* Multi-block mode */
655239281Sgonzo	if (data->flags & MMC_DATA_MULTI) {
656239281Sgonzo		cmd_reg |= MMCHS_CMD_MSBS;
657239281Sgonzo	}
658239281Sgonzo
659239281Sgonzo	/* Enable extra interrupt sources for the transfer */
660239281Sgonzo	ise_reg |= (MMCHS_STAT_TC | MMCHS_STAT_DTO | MMCHS_STAT_DEB | MMCHS_STAT_CEB);
661239281Sgonzo	if (cmd->flags & MMC_RSP_CRC)
662239281Sgonzo		ise_reg |= MMCHS_STAT_DCRC;
663239281Sgonzo
664239281Sgonzo	/* Enable the DMA transfer bit */
665239281Sgonzo	cmd_reg |= MMCHS_CMD_DE;
666239281Sgonzo
667239281Sgonzo	/* Set the block size and block count */
668239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_BLK, (1 << 16) | data->len);
669239281Sgonzo
670239281Sgonzo	/* Setup the DMA stuff */
671239281Sgonzo	if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) {
672239281Sgonzo
673239281Sgonzo		vaddr = data->data;
674239281Sgonzo		data->xfer_len = 0;
675239281Sgonzo
676239281Sgonzo		/* Map the buffer buf into bus space using the dmamap map. */
677239281Sgonzo		if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, vaddr, data->len,
678239281Sgonzo		    ti_mmchs_getaddr, &paddr, 0) != 0) {
679239281Sgonzo
680239281Sgonzo			if (req->cmd->flags & STOP_STARTED)
681239281Sgonzo				req->stop->error = MMC_ERR_NO_MEMORY;
682239281Sgonzo			else
683239281Sgonzo				req->cmd->error = MMC_ERR_NO_MEMORY;
684239281Sgonzo			sc->req = NULL;
685239281Sgonzo			sc->curcmd = NULL;
686239281Sgonzo			req->done(req);
687239281Sgonzo			return;
688239281Sgonzo		}
689239281Sgonzo
690239281Sgonzo#ifndef SOC_TI_AM335X
691239281Sgonzo		/* Calculate the packet size, the max packet size is 512 bytes
692239281Sgonzo		 * (or 128 32-bit elements).
693239281Sgonzo		 */
694239281Sgonzo		pktsize = min((data->len / 4), (512 / 4));
695239281Sgonzo#endif
696239281Sgonzo		/* Sync the DMA buffer and setup the DMA controller */
697239281Sgonzo		if (data->flags & MMC_DATA_READ) {
698239281Sgonzo			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREREAD);
699239281Sgonzo#ifdef SOC_TI_AM335X
700239281Sgonzo			ti_mmchs_edma3_rx_xfer_setup(sc, sc->sc_data_reg_paddr,
701239281Sgonzo			    paddr, data->len, 1);
702239281Sgonzo#else
703239281Sgonzo			ti_sdma_start_xfer_packet(sc->sc_dmach_rd, sc->sc_data_reg_paddr,
704239281Sgonzo			    paddr, 1, (data->len / 4), pktsize);
705239281Sgonzo#endif
706239281Sgonzo		} else {
707239281Sgonzo			bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREWRITE);
708239281Sgonzo#ifdef SOC_TI_AM335X
709239281Sgonzo			ti_mmchs_edma3_tx_xfer_setup(sc, paddr,
710239281Sgonzo			    sc->sc_data_reg_paddr, data->len, 1);
711239281Sgonzo#else
712239281Sgonzo			ti_sdma_start_xfer_packet(sc->sc_dmach_wr, paddr,
713239281Sgonzo			    sc->sc_data_reg_paddr, 1, (data->len / 4), pktsize);
714239281Sgonzo#endif
715239281Sgonzo		}
716239281Sgonzo
717239281Sgonzo		/* Increase the mapped count */
718239281Sgonzo		sc->sc_dmamapped++;
719239281Sgonzo
720239281Sgonzo		sc->sc_cmd_data_vaddr = vaddr;
721239281Sgonzo		sc->sc_cmd_data_len = data->len;
722239281Sgonzo	}
723239281Sgonzo
724239281Sgonzo	/* Finally kick off the command */
725239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
726239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_IE, ise_reg);
727239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg);
728239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg);
729239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg);
730239281Sgonzo
731239281Sgonzo	/* and we're done */
732239281Sgonzo}
733239281Sgonzo
734239281Sgonzo/**
735239281Sgonzo *	ti_mmchs_start - starts a request stored in the driver context
736239281Sgonzo *	@sc: pointer to the driver context
737239281Sgonzo *
738239281Sgonzo *	This function is called by ti_mmchs_request() in response to a read/write
739239281Sgonzo *	request from the MMC core module.
740239281Sgonzo *
741239281Sgonzo *	LOCKING:
742239281Sgonzo *	Caller should be holding the OMAP_MMC lock.
743239281Sgonzo *
744239281Sgonzo *	RETURNS:
745239281Sgonzo *	nothing
746239281Sgonzo */
747239281Sgonzostatic void
748239281Sgonzoti_mmchs_start(struct ti_mmchs_softc *sc)
749239281Sgonzo{
750239281Sgonzo	struct mmc_request *req;
751239281Sgonzo
752239281Sgonzo	/* Sanity check we have a request */
753239281Sgonzo	req = sc->req;
754239281Sgonzo	if (req == NULL)
755239281Sgonzo		return;
756239281Sgonzo
757239281Sgonzo	/* assert locked */
758239281Sgonzo	if (!(sc->flags & CMD_STARTED)) {
759239281Sgonzo		sc->flags |= CMD_STARTED;
760239281Sgonzo		ti_mmchs_start_cmd(sc, req->cmd);
761239281Sgonzo		return;
762239281Sgonzo	}
763239281Sgonzo
764239281Sgonzo	if (!(sc->flags & STOP_STARTED) && req->stop) {
765239281Sgonzo		sc->flags |= STOP_STARTED;
766239281Sgonzo		ti_mmchs_start_cmd(sc, req->stop);
767239281Sgonzo		return;
768239281Sgonzo	}
769239281Sgonzo
770239281Sgonzo	/* We must be done -- bad idea to do this while locked? */
771239281Sgonzo	sc->req = NULL;
772239281Sgonzo	sc->curcmd = NULL;
773239281Sgonzo	req->done(req);
774239281Sgonzo}
775239281Sgonzo
776239281Sgonzo/**
777239281Sgonzo *	ti_mmchs_request - entry point for all read/write/cmd requests
778239281Sgonzo *	@brdev: mmc bridge device handle
779239281Sgonzo *	@reqdev: the device doing the requesting ?
780239281Sgonzo *	@req: the action requested
781239281Sgonzo *
782239281Sgonzo *	LOCKING:
783239281Sgonzo *	None, internally takes the OMAP_MMC lock.
784239281Sgonzo *
785239281Sgonzo *	RETURNS:
786239281Sgonzo *	0 on success
787239281Sgonzo *	EBUSY if the driver is already performing a request
788239281Sgonzo */
789239281Sgonzostatic int
790239281Sgonzoti_mmchs_request(device_t brdev, device_t reqdev, struct mmc_request *req)
791239281Sgonzo{
792239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(brdev);
793239281Sgonzo
794239281Sgonzo	TI_MMCHS_LOCK(sc);
795239281Sgonzo
796239281Sgonzo	/*
797239281Sgonzo	 * XXX do we want to be able to queue up multiple commands?
798239281Sgonzo	 * XXX sounds like a good idea, but all protocols are sync, so
799239281Sgonzo	 * XXX maybe the idea is naive...
800239281Sgonzo	 */
801239281Sgonzo	if (sc->req != NULL) {
802239281Sgonzo		TI_MMCHS_UNLOCK(sc);
803239281Sgonzo		return (EBUSY);
804239281Sgonzo	}
805239281Sgonzo
806239281Sgonzo	/* Store the request and start the command */
807239281Sgonzo	sc->req = req;
808239281Sgonzo	sc->flags = 0;
809239281Sgonzo	ti_mmchs_start(sc);
810239281Sgonzo
811239281Sgonzo	TI_MMCHS_UNLOCK(sc);
812239281Sgonzo
813239281Sgonzo	return (0);
814239281Sgonzo}
815239281Sgonzo
816239281Sgonzo/**
817239281Sgonzo *	ti_mmchs_get_ro - returns the status of the read-only setting
818239281Sgonzo *	@brdev: mmc bridge device handle
819239281Sgonzo *	@reqdev: device doing the request
820239281Sgonzo *
821239281Sgonzo *	This function is relies on hint'ed values to determine which GPIO is used
822239281Sgonzo *	to determine if the write protect is enabled. On the BeagleBoard the pin
823239281Sgonzo *	is GPIO_23.
824239281Sgonzo *
825239281Sgonzo *	LOCKING:
826239281Sgonzo *	-
827239281Sgonzo *
828239281Sgonzo *	RETURNS:
829239281Sgonzo *	0 if not read-only
830239281Sgonzo *	1 if read only
831239281Sgonzo */
832239281Sgonzostatic int
833239281Sgonzoti_mmchs_get_ro(device_t brdev, device_t reqdev)
834239281Sgonzo{
835239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(brdev);
836239281Sgonzo	unsigned int readonly = 0;
837239281Sgonzo
838239281Sgonzo	TI_MMCHS_LOCK(sc);
839239281Sgonzo
840239281Sgonzo	if ((sc->sc_wp_gpio_pin != -1) && (sc->sc_gpio_dev != NULL)) {
841239281Sgonzo		if (GPIO_PIN_GET(sc->sc_gpio_dev, sc->sc_wp_gpio_pin, &readonly) != 0)
842239281Sgonzo			readonly = 0;
843239281Sgonzo		else
844239281Sgonzo			readonly = (readonly == 0) ? 0 : 1;
845239281Sgonzo	}
846239281Sgonzo
847239281Sgonzo	TI_MMCHS_UNLOCK(sc);
848239281Sgonzo
849239281Sgonzo	return (readonly);
850239281Sgonzo}
851239281Sgonzo
852239281Sgonzo/**
853239281Sgonzo *	ti_mmchs_send_init_stream - sets bus/controller settings
854239281Sgonzo *	@brdev: mmc bridge device handle
855239281Sgonzo *	@reqdev: device doing the request
856239281Sgonzo *
857239281Sgonzo *	Send init stream sequence to card before sending IDLE command
858239281Sgonzo *
859239281Sgonzo *	LOCKING:
860239281Sgonzo *
861239281Sgonzo *
862239281Sgonzo *	RETURNS:
863239281Sgonzo *	0 if function succeeded
864239281Sgonzo */
865239281Sgonzostatic void
866239281Sgonzoti_mmchs_send_init_stream(struct ti_mmchs_softc *sc)
867239281Sgonzo{
868239281Sgonzo	unsigned long timeout;
869239281Sgonzo	uint32_t ie, ise, con;
870239281Sgonzo
871239281Sgonzo	ti_mmchs_dbg(sc, "Performing init sequence\n");
872239281Sgonzo
873239281Sgonzo	/* Prior to issuing any command, the MMCHS controller has to execute a
874239281Sgonzo	 * special INIT procedure. The MMCHS controller has to generate a clock
875239281Sgonzo	 * during 1ms. During the INIT procedure, the MMCHS controller generates 80
876239281Sgonzo	 * clock periods. In order to keep the 1ms gap, the MMCHS controller should
877239281Sgonzo	 * be configured to generate a clock whose frequency is smaller or equal to
878239281Sgonzo	 * 80 KHz. If the MMCHS controller divider bitfield width doesn't allow to
879239281Sgonzo	 * choose big values, the MMCHS controller driver should perform the INIT
880239281Sgonzo	 * procedure twice or three times. Twice is generally enough.
881239281Sgonzo	 *
882239281Sgonzo	 * The INIt procedure is executed by setting MMCHS1.MMCHS_CON[1] INIT
883239281Sgonzo	 * bitfield to 1 and by sending a dummy command, writing 0x00000000 in
884239281Sgonzo	 * MMCHS1.MMCHS_CMD register.
885239281Sgonzo	 */
886239281Sgonzo
887239281Sgonzo	/* Disable interrupt status events but enable interrupt generation.
888239281Sgonzo	 * This doesn't seem right to me, but if the interrupt generation is not
889239281Sgonzo	 * enabled the CC bit doesn't seem to be set in the STAT register.
890239281Sgonzo	 */
891239281Sgonzo
892239281Sgonzo	/* Enable interrupt generation */
893239281Sgonzo	ie = ti_mmchs_read_4(sc, MMCHS_IE);
894239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_IE, 0x307F0033);
895239281Sgonzo
896239281Sgonzo	/* Disable generation of status events (stops interrupt triggering) */
897239281Sgonzo	ise = ti_mmchs_read_4(sc, MMCHS_ISE);
898239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_ISE, 0);
899239281Sgonzo
900239281Sgonzo	/* Set the initialise stream bit */
901239281Sgonzo	con = ti_mmchs_read_4(sc, MMCHS_CON);
902239281Sgonzo	con |= MMCHS_CON_INIT;
903239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CON, con);
904239281Sgonzo
905239281Sgonzo	/* Write a dummy command 0x00 */
906239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000);
907239281Sgonzo
908239281Sgonzo	/* Loop waiting for the command to finish */
909239281Sgonzo	timeout = hz;
910239281Sgonzo	do {
911239281Sgonzo		pause("MMCINIT", 1);
912239281Sgonzo		if (timeout-- == 0) {
913239281Sgonzo			device_printf(sc->sc_dev, "Error: first stream init timed out\n");
914239281Sgonzo			break;
915239281Sgonzo		}
916239281Sgonzo	} while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC));
917239281Sgonzo
918239281Sgonzo	/* Clear the command complete status bit */
919239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_STAT, MMCHS_STAT_CC);
920239281Sgonzo
921239281Sgonzo	/* Write another dummy command 0x00 */
922239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000);
923239281Sgonzo
924239281Sgonzo	/* Loop waiting for the second command to finish */
925239281Sgonzo	timeout = hz;
926239281Sgonzo	do {
927239281Sgonzo		pause("MMCINIT", 1);
928239281Sgonzo		if (timeout-- == 0) {
929239281Sgonzo			device_printf(sc->sc_dev, "Error: second stream init timed out\n");
930239281Sgonzo			break;
931239281Sgonzo		}
932239281Sgonzo	} while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC));
933239281Sgonzo
934239281Sgonzo	/* Clear the stream init bit */
935239281Sgonzo	con &= ~MMCHS_CON_INIT;
936239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CON, con);
937239281Sgonzo
938239281Sgonzo	/* Clear the status register, then restore the IE and ISE registers */
939239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_STAT, 0xffffffff);
940239281Sgonzo	ti_mmchs_read_4(sc, MMCHS_STAT);
941239281Sgonzo
942239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_ISE, ise);
943239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_IE, ie);
944239281Sgonzo}
945239281Sgonzo
946239281Sgonzo/**
947239281Sgonzo *	ti_mmchs_update_ios - sets bus/controller settings
948239281Sgonzo *	@brdev: mmc bridge device handle
949239281Sgonzo *	@reqdev: device doing the request
950239281Sgonzo *
951239281Sgonzo *	Called to set the bus and controller settings that need to be applied to
952239281Sgonzo *	the actual HW.  Currently this function just sets the bus width and the
953239281Sgonzo *	clock speed.
954239281Sgonzo *
955239281Sgonzo *	LOCKING:
956239281Sgonzo *
957239281Sgonzo *
958239281Sgonzo *	RETURNS:
959239281Sgonzo *	0 if function succeeded
960239281Sgonzo */
961239281Sgonzostatic int
962239281Sgonzoti_mmchs_update_ios(device_t brdev, device_t reqdev)
963239281Sgonzo{
964239281Sgonzo	struct ti_mmchs_softc *sc;
965239281Sgonzo	struct mmc_host *host;
966239281Sgonzo	struct mmc_ios *ios;
967239281Sgonzo	uint32_t clkdiv;
968239281Sgonzo	uint32_t hctl_reg;
969239281Sgonzo	uint32_t con_reg;
970239281Sgonzo	uint32_t sysctl_reg;
971239281Sgonzo#ifndef SOC_TI_AM335X
972239281Sgonzo	uint16_t mv;
973239281Sgonzo#endif
974239281Sgonzo	unsigned long timeout;
975239281Sgonzo	int do_card_init = 0;
976239281Sgonzo
977239281Sgonzo	sc = device_get_softc(brdev);
978239281Sgonzo	host = &sc->host;
979239281Sgonzo	ios = &host->ios;
980239281Sgonzo
981239281Sgonzo	/* Read the initial values of the registers */
982239281Sgonzo	hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
983239281Sgonzo	con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
984239281Sgonzo
985239281Sgonzo	/* Set the bus width */
986239281Sgonzo	switch (ios->bus_width) {
987239281Sgonzo		case bus_width_1:
988239281Sgonzo			hctl_reg &= ~MMCHS_HCTL_DTW;
989239281Sgonzo			con_reg &= ~MMCHS_CON_DW8;
990239281Sgonzo			break;
991239281Sgonzo		case bus_width_4:
992239281Sgonzo			hctl_reg |= MMCHS_HCTL_DTW;
993239281Sgonzo			con_reg &= ~MMCHS_CON_DW8;
994239281Sgonzo			break;
995239281Sgonzo		case bus_width_8:
996239281Sgonzo			con_reg |= MMCHS_CON_DW8;
997239281Sgonzo			break;
998239281Sgonzo	}
999239281Sgonzo
1000239281Sgonzo	/* Finally write all these settings back to the registers */
1001239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg);
1002239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
1003239281Sgonzo
1004239281Sgonzo	/* Check if we need to change the external voltage regulator */
1005239281Sgonzo	if (sc->sc_cur_power_mode != ios->power_mode) {
1006239281Sgonzo
1007239281Sgonzo		if (ios->power_mode == power_up) {
1008239281Sgonzo
1009239281Sgonzo			/* Set the power level */
1010239281Sgonzo			hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
1011239281Sgonzo			hctl_reg &= ~(MMCHS_HCTL_SDVS_MASK | MMCHS_HCTL_SDBP);
1012239281Sgonzo
1013239281Sgonzo			if ((ios->vdd == -1) || (ios->vdd >= vdd_240)) {
1014239281Sgonzo#ifndef SOC_TI_AM335X
1015239281Sgonzo				mv = 3000;
1016239281Sgonzo#endif
1017239281Sgonzo				hctl_reg |= MMCHS_HCTL_SDVS_V30;
1018239281Sgonzo			} else {
1019239281Sgonzo#ifndef SOC_TI_AM335X
1020239281Sgonzo				mv = 1800;
1021239281Sgonzo#endif
1022239281Sgonzo				hctl_reg |= MMCHS_HCTL_SDVS_V18;
1023239281Sgonzo			}
1024239281Sgonzo
1025239281Sgonzo			ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg);
1026239281Sgonzo
1027239281Sgonzo#ifdef SOC_TI_AM335X
1028239281Sgonzo			printf("%s: TWL unimplemented\n", __func__);
1029239281Sgonzo#else
1030239281Sgonzo			/* Set the desired voltage on the regulator */
1031239281Sgonzo			if (sc->sc_vreg_dev && sc->sc_vreg_name)
1032239281Sgonzo				twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, mv);
1033239281Sgonzo#endif
1034239281Sgonzo			/* Enable the bus power */
1035239281Sgonzo			ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg | MMCHS_HCTL_SDBP));
1036239281Sgonzo			timeout = hz;
1037239281Sgonzo			while (!(ti_mmchs_read_4(sc, MMCHS_HCTL) & MMCHS_HCTL_SDBP)) {
1038239281Sgonzo				if (timeout-- == 0)
1039239281Sgonzo					break;
1040239281Sgonzo				pause("MMC_PWRON", 1);
1041239281Sgonzo			}
1042239281Sgonzo
1043239281Sgonzo		} else if (ios->power_mode == power_off) {
1044239281Sgonzo			/* Disable the bus power */
1045239281Sgonzo			hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL);
1046239281Sgonzo			ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg & ~MMCHS_HCTL_SDBP));
1047239281Sgonzo
1048239281Sgonzo#ifdef SOC_TI_AM335X
1049239281Sgonzo			printf("%s: TWL unimplemented\n", __func__);
1050239281Sgonzo#else
1051239281Sgonzo			/* Turn the power off on the voltage regulator */
1052239281Sgonzo			if (sc->sc_vreg_dev && sc->sc_vreg_name)
1053239281Sgonzo				twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, 0);
1054239281Sgonzo#endif
1055239281Sgonzo		} else if (ios->power_mode == power_on) {
1056239281Sgonzo			/* Force a card re-initialisation sequence */
1057239281Sgonzo			do_card_init = 1;
1058239281Sgonzo		}
1059239281Sgonzo
1060239281Sgonzo		/* Save the new power state */
1061239281Sgonzo		sc->sc_cur_power_mode = ios->power_mode;
1062239281Sgonzo	}
1063239281Sgonzo
1064239281Sgonzo	/* need the MMCHS_SYSCTL register */
1065239281Sgonzo	sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
1066239281Sgonzo
1067239281Sgonzo	/* Just in case this hasn't been setup before, set the timeout to the default */
1068239281Sgonzo	sysctl_reg &= ~MMCHS_SYSCTL_DTO_MASK;
1069239281Sgonzo	sysctl_reg |= MMCHS_SYSCTL_DTO(0xe);
1070239281Sgonzo
1071239281Sgonzo	/* Disable the clock output while configuring the new clock */
1072239281Sgonzo	sysctl_reg &= ~(MMCHS_SYSCTL_ICE | MMCHS_SYSCTL_CEN);
1073239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
1074239281Sgonzo
1075239281Sgonzo	/* bus mode? */
1076239281Sgonzo	if (ios->clock == 0) {
1077239281Sgonzo		clkdiv = 0;
1078239281Sgonzo	} else {
1079239281Sgonzo		clkdiv = sc->sc_ref_freq / ios->clock;
1080239281Sgonzo		if (clkdiv < 1)
1081239281Sgonzo			clkdiv = 1;
1082239281Sgonzo		if ((sc->sc_ref_freq / clkdiv) > ios->clock)
1083239281Sgonzo			clkdiv += 1;
1084239281Sgonzo		if (clkdiv > 250)
1085239281Sgonzo			clkdiv = 250;
1086239281Sgonzo	}
1087239281Sgonzo
1088239281Sgonzo	/* Set the new clock divider */
1089239281Sgonzo	sysctl_reg &= ~MMCHS_SYSCTL_CLKD_MASK;
1090239281Sgonzo	sysctl_reg |= MMCHS_SYSCTL_CLKD(clkdiv);
1091239281Sgonzo
1092239281Sgonzo	/* Write the new settings ... */
1093239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
1094239281Sgonzo	/* ... write the internal clock enable bit ... */
1095239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg | MMCHS_SYSCTL_ICE);
1096239281Sgonzo	/* ... wait for the clock to stablise ... */
1097239281Sgonzo	while (((sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL)) &
1098239281Sgonzo	    MMCHS_SYSCTL_ICS) == 0) {
1099239281Sgonzo		continue;
1100239281Sgonzo	}
1101239281Sgonzo	/* ... then enable */
1102239281Sgonzo	sysctl_reg |= MMCHS_SYSCTL_CEN;
1103239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg);
1104239281Sgonzo
1105239281Sgonzo	/* If the power state has changed to 'power_on' then run the init sequence*/
1106239281Sgonzo	if (do_card_init) {
1107239281Sgonzo		ti_mmchs_send_init_stream(sc);
1108239281Sgonzo	}
1109239281Sgonzo
1110239281Sgonzo	/* Set the bus mode (opendrain or normal) */
1111239281Sgonzo	con_reg = ti_mmchs_read_4(sc, MMCHS_CON);
1112239281Sgonzo	if (ios->bus_mode == opendrain)
1113239281Sgonzo		con_reg |= MMCHS_CON_OD;
1114239281Sgonzo	else
1115239281Sgonzo		con_reg &= ~MMCHS_CON_OD;
1116239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CON, con_reg);
1117239281Sgonzo
1118239281Sgonzo	return (0);
1119239281Sgonzo}
1120239281Sgonzo
1121239281Sgonzo/**
1122239281Sgonzo *	ti_mmchs_acquire_host -
1123239281Sgonzo *	@brdev: mmc bridge device handle
1124239281Sgonzo *	@reqdev: device doing the request
1125239281Sgonzo *
1126239281Sgonzo *	TODO: Is this function needed ?
1127239281Sgonzo *
1128239281Sgonzo *	LOCKING:
1129239281Sgonzo *	none
1130239281Sgonzo *
1131239281Sgonzo *	RETURNS:
1132239281Sgonzo *	0 function succeeded
1133239281Sgonzo *
1134239281Sgonzo */
1135239281Sgonzostatic int
1136239281Sgonzoti_mmchs_acquire_host(device_t brdev, device_t reqdev)
1137239281Sgonzo{
1138239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(brdev);
1139239281Sgonzo	int err = 0;
1140239281Sgonzo
1141239281Sgonzo	TI_MMCHS_LOCK(sc);
1142239281Sgonzo
1143239281Sgonzo	while (sc->bus_busy) {
1144239281Sgonzo		msleep(sc, &sc->sc_mtx, PZERO, "mmc", hz / 5);
1145239281Sgonzo	}
1146239281Sgonzo
1147239281Sgonzo	sc->bus_busy++;
1148239281Sgonzo
1149239281Sgonzo	TI_MMCHS_UNLOCK(sc);
1150239281Sgonzo
1151239281Sgonzo	return (err);
1152239281Sgonzo}
1153239281Sgonzo
1154239281Sgonzo/**
1155239281Sgonzo *	ti_mmchs_release_host -
1156239281Sgonzo *	@brdev: mmc bridge device handle
1157239281Sgonzo *	@reqdev: device doing the request
1158239281Sgonzo *
1159239281Sgonzo *	TODO: Is this function needed ?
1160239281Sgonzo *
1161239281Sgonzo *	LOCKING:
1162239281Sgonzo *	none
1163239281Sgonzo *
1164239281Sgonzo *	RETURNS:
1165239281Sgonzo *	0 function succeeded
1166239281Sgonzo *
1167239281Sgonzo */
1168239281Sgonzostatic int
1169239281Sgonzoti_mmchs_release_host(device_t brdev, device_t reqdev)
1170239281Sgonzo{
1171239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(brdev);
1172239281Sgonzo
1173239281Sgonzo	TI_MMCHS_LOCK(sc);
1174239281Sgonzo
1175239281Sgonzo	sc->bus_busy--;
1176239281Sgonzo	wakeup(sc);
1177239281Sgonzo
1178239281Sgonzo	TI_MMCHS_UNLOCK(sc);
1179239281Sgonzo
1180239281Sgonzo	return (0);
1181239281Sgonzo}
1182239281Sgonzo
1183239281Sgonzo/**
1184239281Sgonzo *	ti_mmchs_read_ivar - returns driver conf variables
1185239281Sgonzo *	@bus:
1186239281Sgonzo *	@child:
1187239281Sgonzo *	@which: The variable to get the result for
1188239281Sgonzo *	@result: Upon return will store the variable value
1189239281Sgonzo *
1190239281Sgonzo *
1191239281Sgonzo *
1192239281Sgonzo *	LOCKING:
1193239281Sgonzo *	None, caller must hold locks
1194239281Sgonzo *
1195239281Sgonzo *	RETURNS:
1196239281Sgonzo *	0 on success
1197239281Sgonzo *	EINVAL if the variable requested is invalid
1198239281Sgonzo */
1199239281Sgonzostatic int
1200239281Sgonzoti_mmchs_read_ivar(device_t bus, device_t child, int which, uintptr_t *result)
1201239281Sgonzo{
1202239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(bus);
1203239281Sgonzo
1204239281Sgonzo	switch (which) {
1205239281Sgonzo		case MMCBR_IVAR_BUS_MODE:
1206239281Sgonzo			*(int *)result = sc->host.ios.bus_mode;
1207239281Sgonzo			break;
1208239281Sgonzo		case MMCBR_IVAR_BUS_WIDTH:
1209239281Sgonzo			*(int *)result = sc->host.ios.bus_width;
1210239281Sgonzo			break;
1211239281Sgonzo		case MMCBR_IVAR_CHIP_SELECT:
1212239281Sgonzo			*(int *)result = sc->host.ios.chip_select;
1213239281Sgonzo			break;
1214239281Sgonzo		case MMCBR_IVAR_CLOCK:
1215239281Sgonzo			*(int *)result = sc->host.ios.clock;
1216239281Sgonzo			break;
1217239281Sgonzo		case MMCBR_IVAR_F_MIN:
1218239281Sgonzo			*(int *)result = sc->host.f_min;
1219239281Sgonzo			break;
1220239281Sgonzo		case MMCBR_IVAR_F_MAX:
1221239281Sgonzo			*(int *)result = sc->host.f_max;
1222239281Sgonzo			break;
1223239281Sgonzo		case MMCBR_IVAR_HOST_OCR:
1224239281Sgonzo			*(int *)result = sc->host.host_ocr;
1225239281Sgonzo			break;
1226239281Sgonzo		case MMCBR_IVAR_MODE:
1227239281Sgonzo			*(int *)result = sc->host.mode;
1228239281Sgonzo			break;
1229239281Sgonzo		case MMCBR_IVAR_OCR:
1230239281Sgonzo			*(int *)result = sc->host.ocr;
1231239281Sgonzo			break;
1232239281Sgonzo		case MMCBR_IVAR_POWER_MODE:
1233239281Sgonzo			*(int *)result = sc->host.ios.power_mode;
1234239281Sgonzo			break;
1235239281Sgonzo		case MMCBR_IVAR_VDD:
1236239281Sgonzo			*(int *)result = sc->host.ios.vdd;
1237239281Sgonzo			break;
1238239281Sgonzo		case MMCBR_IVAR_CAPS:
1239239281Sgonzo			*(int *)result = sc->host.caps;
1240239281Sgonzo			break;
1241239281Sgonzo		case MMCBR_IVAR_MAX_DATA:
1242239281Sgonzo			*(int *)result = 1;
1243239281Sgonzo			break;
1244239281Sgonzo		default:
1245239281Sgonzo			return (EINVAL);
1246239281Sgonzo	}
1247239281Sgonzo	return (0);
1248239281Sgonzo}
1249239281Sgonzo
1250239281Sgonzo/**
1251239281Sgonzo *	ti_mmchs_write_ivar - writes a driver conf variables
1252239281Sgonzo *	@bus:
1253239281Sgonzo *	@child:
1254239281Sgonzo *	@which: The variable to set
1255239281Sgonzo *	@value: The value to write into the variable
1256239281Sgonzo *
1257239281Sgonzo *
1258239281Sgonzo *
1259239281Sgonzo *	LOCKING:
1260239281Sgonzo *	None, caller must hold locks
1261239281Sgonzo *
1262239281Sgonzo *	RETURNS:
1263239281Sgonzo *	0 on success
1264239281Sgonzo *	EINVAL if the variable requested is invalid
1265239281Sgonzo */
1266239281Sgonzostatic int
1267239281Sgonzoti_mmchs_write_ivar(device_t bus, device_t child, int which, uintptr_t value)
1268239281Sgonzo{
1269239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(bus);
1270239281Sgonzo
1271239281Sgonzo	switch (which) {
1272239281Sgonzo		case MMCBR_IVAR_BUS_MODE:
1273239281Sgonzo			sc->host.ios.bus_mode = value;
1274239281Sgonzo			break;
1275239281Sgonzo		case MMCBR_IVAR_BUS_WIDTH:
1276239281Sgonzo			sc->host.ios.bus_width = value;
1277239281Sgonzo			break;
1278239281Sgonzo		case MMCBR_IVAR_CHIP_SELECT:
1279239281Sgonzo			sc->host.ios.chip_select = value;
1280239281Sgonzo			break;
1281239281Sgonzo		case MMCBR_IVAR_CLOCK:
1282239281Sgonzo			sc->host.ios.clock = value;
1283239281Sgonzo			break;
1284239281Sgonzo		case MMCBR_IVAR_MODE:
1285239281Sgonzo			sc->host.mode = value;
1286239281Sgonzo			break;
1287239281Sgonzo		case MMCBR_IVAR_OCR:
1288239281Sgonzo			sc->host.ocr = value;
1289239281Sgonzo			break;
1290239281Sgonzo		case MMCBR_IVAR_POWER_MODE:
1291239281Sgonzo			sc->host.ios.power_mode = value;
1292239281Sgonzo			break;
1293239281Sgonzo		case MMCBR_IVAR_VDD:
1294239281Sgonzo			sc->host.ios.vdd = value;
1295239281Sgonzo			break;
1296239281Sgonzo			/* These are read-only */
1297239281Sgonzo		case MMCBR_IVAR_CAPS:
1298239281Sgonzo		case MMCBR_IVAR_HOST_OCR:
1299239281Sgonzo		case MMCBR_IVAR_F_MIN:
1300239281Sgonzo		case MMCBR_IVAR_F_MAX:
1301239281Sgonzo		case MMCBR_IVAR_MAX_DATA:
1302239281Sgonzo			return (EINVAL);
1303239281Sgonzo		default:
1304239281Sgonzo			return (EINVAL);
1305239281Sgonzo	}
1306239281Sgonzo	return (0);
1307239281Sgonzo}
1308239281Sgonzo
1309239281Sgonzo/**
1310239281Sgonzo *	ti_mmchs_hw_init - initialises the MMC/SD/SIO controller
1311239281Sgonzo *	@dev: mmc device handle
1312239281Sgonzo *
1313239281Sgonzo *	Called by the driver attach function during driver initialisation. This
1314239281Sgonzo *	function is responsibly to setup the controller ready for transactions.
1315239281Sgonzo *
1316239281Sgonzo *	LOCKING:
1317239281Sgonzo *	No locking, assumed to only be called during initialisation.
1318239281Sgonzo *
1319239281Sgonzo *	RETURNS:
1320239281Sgonzo *	nothing
1321239281Sgonzo */
1322239281Sgonzostatic void
1323239281Sgonzoti_mmchs_hw_init(device_t dev)
1324239281Sgonzo{
1325239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(dev);
1326239281Sgonzo	clk_ident_t clk;
1327239281Sgonzo	unsigned long timeout;
1328239281Sgonzo	uint32_t sysctl;
1329239281Sgonzo	uint32_t capa;
1330252863Srpaulo	uint32_t con, sysconfig;
1331239281Sgonzo
1332239281Sgonzo	/* 1: Enable the controller and interface/functional clocks */
1333239281Sgonzo	clk = MMC0_CLK + sc->device_id;
1334239281Sgonzo
1335239281Sgonzo	if (ti_prcm_clk_enable(clk) != 0) {
1336239281Sgonzo		device_printf(dev, "Error: failed to enable MMC clock\n");
1337239281Sgonzo		return;
1338239281Sgonzo	}
1339239281Sgonzo
1340239281Sgonzo	/* 1a: Get the frequency of the source clock */
1341239281Sgonzo	if (ti_prcm_clk_get_source_freq(clk, &sc->sc_ref_freq) != 0) {
1342239281Sgonzo		device_printf(dev, "Error: failed to get source clock freq\n");
1343239281Sgonzo		return;
1344239281Sgonzo	}
1345239281Sgonzo
1346239281Sgonzo	/* 2: Issue a softreset to the controller */
1347252863Srpaulo	sysconfig = ti_mmchs_read_4(sc, MMCHS_SYSCONFIG);
1348252863Srpaulo	sysconfig |= MMCHS_SYSCONFIG_SRST;
1349252863Srpaulo	ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, sysconfig);
1350239281Sgonzo	timeout = 100;
1351239281Sgonzo	while ((ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & 0x01) == 0x0) {
1352239281Sgonzo		DELAY(1000);
1353239281Sgonzo		if (timeout-- == 0) {
1354239281Sgonzo			device_printf(dev, "Error: reset operation timed out\n");
1355239281Sgonzo			return;
1356239281Sgonzo		}
1357239281Sgonzo	}
1358239281Sgonzo
1359239281Sgonzo	/* 3: Reset both the command and data state machines */
1360239281Sgonzo	sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL);
1361239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | MMCHS_SYSCTL_SRA);
1362239281Sgonzo	timeout = 100;
1363239281Sgonzo	while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & MMCHS_SYSCTL_SRA) != 0x0) {
1364239281Sgonzo		DELAY(1000);
1365239281Sgonzo		if (timeout-- == 0) {
1366239281Sgonzo			device_printf(dev, "Error: reset operation timed out\n");
1367239281Sgonzo			return;
1368239281Sgonzo		}
1369239281Sgonzo	}
1370239281Sgonzo
1371239281Sgonzo	/* 4: Set initial host configuration (1-bit mode, pwroff) and capabilities */
1372239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_HCTL, MMCHS_HCTL_SDVS_V30);
1373239281Sgonzo
1374239281Sgonzo	capa = ti_mmchs_read_4(sc, MMCHS_CAPA);
1375239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CAPA, capa | MMCHS_CAPA_VS30 | MMCHS_CAPA_VS18);
1376239281Sgonzo
1377239281Sgonzo	/* 5: Set the initial bus configuration
1378239281Sgonzo	 *       0  CTPL_MMC_SD      : Control Power for DAT1 line
1379239281Sgonzo	 *       0  WPP_ACTIVE_HIGH  : Write protect polarity
1380239281Sgonzo	 *       0  CDP_ACTIVE_HIGH  : Card detect polarity
1381239281Sgonzo	 *       0  CTO_ENABLED      : MMC interrupt command
1382239281Sgonzo	 *       0  DW8_DISABLED     : 8-bit mode MMC select
1383239281Sgonzo	 *       0  MODE_FUNC        : Mode select
1384239281Sgonzo	 *       0  STREAM_DISABLED  : Stream command
1385239281Sgonzo	 *       0  HR_DISABLED      : Broadcast host response
1386239281Sgonzo	 *       0  INIT_DISABLED    : Send initialization stream
1387239281Sgonzo	 *       0  OD_DISABLED      : No Open Drain
1388239281Sgonzo	 */
1389239281Sgonzo	con = ti_mmchs_read_4(sc, MMCHS_CON) & MMCHS_CON_DVAL_MASK;
1390239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_CON, con);
1391239281Sgonzo
1392239281Sgonzo}
1393239281Sgonzo
1394239281Sgonzo/**
1395239281Sgonzo *	ti_mmchs_fini - shutdown the MMC/SD/SIO controller
1396239281Sgonzo *	@dev: mmc device handle
1397239281Sgonzo *
1398239281Sgonzo *	Responsible for shutting done the MMC controller, this function may be
1399239281Sgonzo *	called as part of a reset sequence.
1400239281Sgonzo *
1401239281Sgonzo *	LOCKING:
1402239281Sgonzo *	No locking, assumed to be called during tear-down/reset.
1403239281Sgonzo *
1404239281Sgonzo *	RETURNS:
1405239281Sgonzo *	nothing
1406239281Sgonzo */
1407239281Sgonzostatic void
1408239281Sgonzoti_mmchs_hw_fini(device_t dev)
1409239281Sgonzo{
1410239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(dev);
1411239281Sgonzo
1412239281Sgonzo	/* Disable all interrupts */
1413239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_ISE, 0x00000000);
1414239281Sgonzo	ti_mmchs_write_4(sc, MMCHS_IE, 0x00000000);
1415239281Sgonzo
1416239281Sgonzo	/* Disable the functional and interface clocks */
1417239281Sgonzo	ti_prcm_clk_disable(MMC0_CLK + sc->device_id);
1418239281Sgonzo}
1419239281Sgonzo
1420239281Sgonzo/**
1421239281Sgonzo *	ti_mmchs_init_dma_channels - initalise the DMA channels
1422239281Sgonzo *	@sc: driver soft context
1423239281Sgonzo *
1424239281Sgonzo *	Attempts to activate an RX and TX DMA channel for the MMC device.
1425239281Sgonzo *
1426239281Sgonzo *	LOCKING:
1427239281Sgonzo *	No locking, assumed to be called during tear-down/reset.
1428239281Sgonzo *
1429239281Sgonzo *	RETURNS:
1430239281Sgonzo *	0 on success, a negative error code on failure.
1431239281Sgonzo */
1432239281Sgonzostatic int
1433239281Sgonzoti_mmchs_init_dma_channels(struct ti_mmchs_softc *sc)
1434239281Sgonzo{
1435239281Sgonzo#ifdef SOC_TI_AM335X
1436239281Sgonzo	switch (sc->device_id) {
1437239281Sgonzo		case 0:
1438239281Sgonzo			sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT0;
1439239281Sgonzo			sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT0;
1440239281Sgonzo			break;
1441239281Sgonzo		case 1:
1442239281Sgonzo			sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT1;
1443239281Sgonzo			sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT1;
1444239281Sgonzo			break;
1445239281Sgonzo		default:
1446239281Sgonzo			return(EINVAL);
1447239281Sgonzo	}
1448239281Sgonzo
1449239281Sgonzo#define EVTQNUM		0
1450239281Sgonzo	/* TODO EDMA3 have 3 queues, so we need some queue allocation call */
1451239281Sgonzo	ti_edma3_init(EVTQNUM);
1452239281Sgonzo	ti_edma3_request_dma_ch(sc->dma_tx_trig, sc->dma_tx_trig, EVTQNUM);
1453239281Sgonzo	ti_edma3_request_dma_ch(sc->dma_rx_trig, sc->dma_rx_trig, EVTQNUM);
1454239281Sgonzo#else
1455239281Sgonzo	int err;
1456239281Sgonzo	uint32_t rev;
1457239281Sgonzo
1458239281Sgonzo	/* Get the current chip revision */
1459239281Sgonzo	rev = ti_revision();
1460239281Sgonzo	if ((OMAP_REV_DEVICE(rev) != OMAP4430_DEV) && (sc->device_id > 3))
1461239281Sgonzo		return(EINVAL);
1462239281Sgonzo
1463239281Sgonzo	/* Get the DMA MMC triggers */
1464239281Sgonzo	switch (sc->device_id) {
1465239281Sgonzo		case 1:
1466239281Sgonzo			sc->dma_tx_trig = 60;
1467239281Sgonzo			sc->dma_rx_trig = 61;
1468239281Sgonzo			break;
1469239281Sgonzo		case 2:
1470239281Sgonzo			sc->dma_tx_trig = 46;
1471239281Sgonzo			sc->dma_rx_trig = 47;
1472239281Sgonzo			break;
1473239281Sgonzo		case 3:
1474239281Sgonzo			sc->dma_tx_trig = 76;
1475239281Sgonzo			sc->dma_rx_trig = 77;
1476239281Sgonzo			break;
1477239281Sgonzo		/* The following are OMAP4 only */
1478239281Sgonzo		case 4:
1479239281Sgonzo			sc->dma_tx_trig = 56;
1480239281Sgonzo			sc->dma_rx_trig = 57;
1481239281Sgonzo			break;
1482239281Sgonzo		case 5:
1483239281Sgonzo			sc->dma_tx_trig = 58;
1484239281Sgonzo			sc->dma_rx_trig = 59;
1485239281Sgonzo			break;
1486239281Sgonzo		default:
1487239281Sgonzo			return(EINVAL);
1488239281Sgonzo	}
1489239281Sgonzo
1490239281Sgonzo	/* Activate a RX channel from the OMAP DMA driver */
1491239281Sgonzo	err = ti_sdma_activate_channel(&sc->sc_dmach_rd, ti_mmchs_dma_intr, sc);
1492239281Sgonzo	if (err != 0)
1493239281Sgonzo		return(err);
1494239281Sgonzo
1495239281Sgonzo	/* Setup the RX channel for MMC data transfers */
1496239281Sgonzo	ti_sdma_set_xfer_burst(sc->sc_dmach_rd, TI_SDMA_BURST_NONE,
1497239281Sgonzo	    TI_SDMA_BURST_64);
1498239281Sgonzo	ti_sdma_set_xfer_data_type(sc->sc_dmach_rd, TI_SDMA_DATA_32BITS_SCALAR);
1499239281Sgonzo	ti_sdma_sync_params(sc->sc_dmach_rd, sc->dma_rx_trig,
1500239281Sgonzo	    TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_SRC);
1501239281Sgonzo	ti_sdma_set_addr_mode(sc->sc_dmach_rd, TI_SDMA_ADDR_CONSTANT,
1502239281Sgonzo	    TI_SDMA_ADDR_POST_INCREMENT);
1503239281Sgonzo
1504239281Sgonzo	/* Activate and configure the TX DMA channel */
1505239281Sgonzo	err = ti_sdma_activate_channel(&sc->sc_dmach_wr, ti_mmchs_dma_intr, sc);
1506239281Sgonzo	if (err != 0)
1507239281Sgonzo		return(err);
1508239281Sgonzo
1509239281Sgonzo	/* Setup the TX channel for MMC data transfers */
1510239281Sgonzo	ti_sdma_set_xfer_burst(sc->sc_dmach_wr, TI_SDMA_BURST_64,
1511239281Sgonzo	    TI_SDMA_BURST_NONE);
1512239281Sgonzo	ti_sdma_set_xfer_data_type(sc->sc_dmach_wr, TI_SDMA_DATA_32BITS_SCALAR);
1513239281Sgonzo	ti_sdma_sync_params(sc->sc_dmach_wr, sc->dma_tx_trig,
1514239281Sgonzo	    TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_DST);
1515239281Sgonzo	ti_sdma_set_addr_mode(sc->sc_dmach_wr, TI_SDMA_ADDR_POST_INCREMENT,
1516239281Sgonzo	    TI_SDMA_ADDR_CONSTANT);
1517239281Sgonzo#endif
1518239281Sgonzo	return(0);
1519239281Sgonzo}
1520239281Sgonzo
1521239281Sgonzo/**
1522239281Sgonzo *	ti_mmchs_deactivate - deactivates the driver
1523239281Sgonzo *	@dev: mmc device handle
1524239281Sgonzo *
1525239281Sgonzo *	Unmaps the register set and releases the IRQ resource.
1526239281Sgonzo *
1527239281Sgonzo *	LOCKING:
1528239281Sgonzo *	None required
1529239281Sgonzo *
1530239281Sgonzo *	RETURNS:
1531239281Sgonzo *	nothing
1532239281Sgonzo */
1533239281Sgonzostatic void
1534239281Sgonzoti_mmchs_deactivate(device_t dev)
1535239281Sgonzo{
1536239281Sgonzo	struct ti_mmchs_softc *sc= device_get_softc(dev);
1537239281Sgonzo
1538239281Sgonzo	/* Remove the IRQ handler */
1539239281Sgonzo	if (sc->sc_irq_h != NULL) {
1540239281Sgonzo		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h);
1541239281Sgonzo		sc->sc_irq_h = NULL;
1542239281Sgonzo	}
1543239281Sgonzo
1544239281Sgonzo	/* Do the generic detach */
1545239281Sgonzo	bus_generic_detach(sc->sc_dev);
1546239281Sgonzo
1547239281Sgonzo#ifdef SOC_TI_AM335X
1548239281Sgonzo	printf("%s: DMA unimplemented\n", __func__);
1549239281Sgonzo#else
1550239281Sgonzo	/* Deactivate the DMA channels */
1551239281Sgonzo	ti_sdma_deactivate_channel(sc->sc_dmach_rd);
1552239281Sgonzo	ti_sdma_deactivate_channel(sc->sc_dmach_wr);
1553239281Sgonzo#endif
1554239281Sgonzo
1555239281Sgonzo	/* Unmap the MMC controller registers */
1556239281Sgonzo	if (sc->sc_mem_res != 0) {
1557239281Sgonzo		bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_irq_res),
1558239281Sgonzo		    sc->sc_mem_res);
1559239281Sgonzo		sc->sc_mem_res = NULL;
1560239281Sgonzo	}
1561239281Sgonzo
1562239281Sgonzo	/* Release the IRQ resource */
1563239281Sgonzo	if (sc->sc_irq_res != NULL) {
1564239281Sgonzo		bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res),
1565239281Sgonzo		    sc->sc_irq_res);
1566239281Sgonzo		sc->sc_irq_res = NULL;
1567239281Sgonzo	}
1568239281Sgonzo
1569239281Sgonzo	return;
1570239281Sgonzo}
1571239281Sgonzo
1572239281Sgonzo/**
1573239281Sgonzo *	ti_mmchs_activate - activates the driver
1574239281Sgonzo *	@dev: mmc device handle
1575239281Sgonzo *
1576239281Sgonzo *	Maps in the register set and requests an IRQ handler for the MMC controller.
1577239281Sgonzo *
1578239281Sgonzo *	LOCKING:
1579239281Sgonzo *	None required
1580239281Sgonzo *
1581239281Sgonzo *	RETURNS:
1582239281Sgonzo *	0 on sucess
1583239281Sgonzo *	ENOMEM if failed to map register set
1584239281Sgonzo */
1585239281Sgonzostatic int
1586239281Sgonzoti_mmchs_activate(device_t dev)
1587239281Sgonzo{
1588239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(dev);
1589239281Sgonzo	int rid;
1590239281Sgonzo	int err;
1591239281Sgonzo
1592239281Sgonzo	/* Get the memory resource for the register mapping */
1593239281Sgonzo	rid = 0;
1594239281Sgonzo	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
1595239281Sgonzo	    RF_ACTIVE);
1596239281Sgonzo	if (sc->sc_mem_res == NULL)
1597239281Sgonzo		panic("%s: Cannot map registers", device_get_name(dev));
1598239281Sgonzo
1599239281Sgonzo	/* Allocate an IRQ resource for the MMC controller */
1600239281Sgonzo	rid = 0;
1601239281Sgonzo	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
1602239281Sgonzo	    RF_ACTIVE | RF_SHAREABLE);
1603239281Sgonzo	if (sc->sc_irq_res == NULL)
1604239281Sgonzo		goto errout;
1605239281Sgonzo
1606239281Sgonzo	/* Allocate DMA tags and maps */
1607239281Sgonzo	err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
1608239281Sgonzo	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL,
1609239281Sgonzo	    NULL, MAXPHYS, 1, MAXPHYS, BUS_DMA_ALLOCNOW, NULL,
1610239281Sgonzo	    NULL, &sc->sc_dmatag);
1611239281Sgonzo	if (err != 0)
1612239281Sgonzo		goto errout;
1613239281Sgonzo
1614239281Sgonzo	err = bus_dmamap_create(sc->sc_dmatag, 0,  &sc->sc_dmamap);
1615239281Sgonzo	if (err != 0)
1616239281Sgonzo		goto errout;
1617239281Sgonzo
1618239281Sgonzo	/* Initialise the DMA channels to be used by the controller */
1619239281Sgonzo	err = ti_mmchs_init_dma_channels(sc);
1620239281Sgonzo	if (err != 0)
1621239281Sgonzo		goto errout;
1622239281Sgonzo
1623239281Sgonzo	/* Set the register offset */
1624239281Sgonzo	if (ti_chip() == CHIP_OMAP_3)
1625239281Sgonzo		sc->sc_reg_off = OMAP3_MMCHS_REG_OFFSET;
1626239281Sgonzo	else if (ti_chip() == CHIP_OMAP_4)
1627239281Sgonzo		sc->sc_reg_off = OMAP4_MMCHS_REG_OFFSET;
1628239281Sgonzo	else if (ti_chip() == CHIP_AM335X)
1629239281Sgonzo		sc->sc_reg_off = AM335X_MMCHS_REG_OFFSET;
1630239281Sgonzo	else
1631239281Sgonzo		panic("Unknown OMAP device\n");
1632239281Sgonzo
1633239281Sgonzo	/* Get the physical address of the MMC data register, needed for DMA */
1634248407Sian	sc->sc_data_reg_paddr = BUS_SPACE_PHYSADDR(sc->sc_mem_res,
1635248407Sian	    sc->sc_reg_off + MMCHS_DATA);
1636239281Sgonzo
1637239281Sgonzo	/* Set the initial power state to off */
1638239281Sgonzo	sc->sc_cur_power_mode = power_off;
1639239281Sgonzo
1640239281Sgonzo	return (0);
1641239281Sgonzo
1642239281Sgonzoerrout:
1643239281Sgonzo	ti_mmchs_deactivate(dev);
1644239281Sgonzo	return (ENOMEM);
1645239281Sgonzo}
1646239281Sgonzo
1647239281Sgonzo/**
1648239281Sgonzo *	ti_mmchs_probe - probe function for the driver
1649239281Sgonzo *	@dev: mmc device handle
1650239281Sgonzo *
1651239281Sgonzo *
1652239281Sgonzo *
1653239281Sgonzo *	RETURNS:
1654239281Sgonzo *	always returns 0
1655239281Sgonzo */
1656239281Sgonzostatic int
1657239281Sgonzoti_mmchs_probe(device_t dev)
1658239281Sgonzo{
1659266152Sian
1660266152Sian	if (!ofw_bus_status_okay(dev))
1661266152Sian		return (ENXIO);
1662266152Sian
1663239281Sgonzo	if (!ofw_bus_is_compatible(dev, "ti,mmchs"))
1664239281Sgonzo		return (ENXIO);
1665239281Sgonzo
1666239281Sgonzo	device_set_desc(dev, "TI MMC/SD/SDIO High Speed Interface");
1667239281Sgonzo	return (0);
1668239281Sgonzo}
1669239281Sgonzo
1670239281Sgonzo/**
1671239281Sgonzo *	ti_mmchs_attach - attach function for the driver
1672239281Sgonzo *	@dev: mmc device handle
1673239281Sgonzo *
1674239281Sgonzo *	Driver initialisation, sets-up the bus mappings, DMA mapping/channels and
1675239281Sgonzo *	the actual controller by calling ti_mmchs_init().
1676239281Sgonzo *
1677239281Sgonzo *	RETURNS:
1678239281Sgonzo *	Returns 0 on success or a negative error code.
1679239281Sgonzo */
1680239281Sgonzostatic int
1681239281Sgonzoti_mmchs_attach(device_t dev)
1682239281Sgonzo{
1683239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(dev);
1684239281Sgonzo	int unit = device_get_unit(dev);
1685239281Sgonzo	phandle_t node;
1686239281Sgonzo	pcell_t did;
1687239281Sgonzo	int err;
1688239281Sgonzo
1689239281Sgonzo	/* Save the device and bus tag */
1690239281Sgonzo	sc->sc_dev = dev;
1691239281Sgonzo
1692239281Sgonzo	/* Get the mmchs device id from FDT */
1693239281Sgonzo	node = ofw_bus_get_node(dev);
1694239281Sgonzo	if ((OF_getprop(node, "mmchs-device-id", &did, sizeof(did))) <= 0) {
1695239281Sgonzo	    device_printf(dev, "missing mmchs-device-id attribute in FDT\n");
1696239281Sgonzo		return (ENXIO);
1697239281Sgonzo	}
1698239281Sgonzo	sc->device_id = fdt32_to_cpu(did);
1699239281Sgonzo
1700239281Sgonzo	/* Initiate the mtex lock */
1701239281Sgonzo	TI_MMCHS_LOCK_INIT(sc);
1702239281Sgonzo
1703239281Sgonzo	/* Indicate the DMA channels haven't yet been allocated */
1704239281Sgonzo	sc->sc_dmach_rd = (unsigned int)-1;
1705239281Sgonzo	sc->sc_dmach_wr = (unsigned int)-1;
1706239281Sgonzo
1707239281Sgonzo	/* Get the hint'ed write detect pin */
1708239281Sgonzo	/* TODO: take this from FDT */
1709239281Sgonzo	if (resource_int_value("ti_mmchs", unit, "wp_gpio", &sc->sc_wp_gpio_pin) != 0){
1710239281Sgonzo		sc->sc_wp_gpio_pin = -1;
1711239281Sgonzo	} else {
1712239281Sgonzo		/* Get the GPIO device, we need this for the write protect pin */
1713239281Sgonzo		sc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
1714239281Sgonzo		if (sc->sc_gpio_dev == NULL)
1715239281Sgonzo			device_printf(dev, "Error: failed to get the GPIO device\n");
1716239281Sgonzo		else
1717239281Sgonzo			GPIO_PIN_SETFLAGS(sc->sc_gpio_dev, sc->sc_wp_gpio_pin,
1718239281Sgonzo			                  GPIO_PIN_INPUT);
1719239281Sgonzo	}
1720239281Sgonzo
1721239281Sgonzo	/* Get the TWL voltage regulator device, we need this to for setting the
1722239281Sgonzo	 * voltage of the bus on certain OMAP platforms.
1723239281Sgonzo	 */
1724239281Sgonzo	sc->sc_vreg_name = NULL;
1725239281Sgonzo
1726239281Sgonzo	/* TODO: add voltage regulator knob to FDT */
1727239281Sgonzo#ifdef notyet
1728239281Sgonzo	sc->sc_vreg_dev = devclass_get_device(devclass_find("twl_vreg"), 0);
1729239281Sgonzo	if (sc->sc_vreg_dev == NULL) {
1730239281Sgonzo		device_printf(dev, "Error: failed to get the votlage regulator"
1731239281Sgonzo		    " device\n");
1732239281Sgonzo		sc->sc_vreg_name = NULL;
1733239281Sgonzo	}
1734239281Sgonzo#endif
1735239281Sgonzo
1736239281Sgonzo	/* Activate the device */
1737239281Sgonzo	err = ti_mmchs_activate(dev);
1738239281Sgonzo	if (err)
1739239281Sgonzo		goto out;
1740239281Sgonzo
1741239281Sgonzo	/* Initialise the controller */
1742239281Sgonzo	ti_mmchs_hw_init(dev);
1743239281Sgonzo
1744239281Sgonzo	/* Activate the interrupt and attach a handler */
1745239281Sgonzo	err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
1746239281Sgonzo	    NULL, ti_mmchs_intr, sc, &sc->sc_irq_h);
1747239281Sgonzo	if (err != 0)
1748239281Sgonzo		goto out;
1749239281Sgonzo
1750239281Sgonzo	/* Add host details */
1751239281Sgonzo	sc->host.f_min = sc->sc_ref_freq / 1023;
1752239281Sgonzo	sc->host.f_max = sc->sc_ref_freq;
1753239281Sgonzo	sc->host.host_ocr = MMC_OCR_290_300 | MMC_OCR_300_310;
1754239281Sgonzo	sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA;
1755239281Sgonzo
1756250791Skientzle	device_add_child(dev, "mmc", 0);
1757239281Sgonzo
1758239281Sgonzo	err = bus_generic_attach(dev);
1759239281Sgonzo
1760239281Sgonzoout:
1761239281Sgonzo	if (err) {
1762239281Sgonzo		TI_MMCHS_LOCK_DESTROY(sc);
1763239281Sgonzo		ti_mmchs_deactivate(dev);
1764239281Sgonzo
1765239281Sgonzo#ifdef SOC_TI_AM335X
1766239281Sgonzo		printf("%s: DMA unimplemented\n", __func__);
1767239281Sgonzo#else
1768239281Sgonzo		if (sc->sc_dmach_rd != (unsigned int)-1)
1769239281Sgonzo			ti_sdma_deactivate_channel(sc->sc_dmach_rd);
1770239281Sgonzo		if (sc->sc_dmach_wr != (unsigned int)-1)
1771239281Sgonzo			ti_sdma_deactivate_channel(sc->sc_dmach_wr);
1772239281Sgonzo#endif
1773239281Sgonzo	}
1774239281Sgonzo
1775239281Sgonzo	return (err);
1776239281Sgonzo}
1777239281Sgonzo
1778239281Sgonzo/**
1779239281Sgonzo *	ti_mmchs_detach - dettach function for the driver
1780239281Sgonzo *	@dev: mmc device handle
1781239281Sgonzo *
1782239281Sgonzo *	Shutdowns the controll and release resources allocated by the driver.
1783239281Sgonzo *
1784239281Sgonzo *	RETURNS:
1785239281Sgonzo *	Always returns 0.
1786239281Sgonzo */
1787239281Sgonzostatic int
1788239281Sgonzoti_mmchs_detach(device_t dev)
1789239281Sgonzo{
1790239281Sgonzo#ifndef SOC_TI_AM335X
1791239281Sgonzo	struct ti_mmchs_softc *sc = device_get_softc(dev);
1792239281Sgonzo#endif
1793239281Sgonzo
1794239281Sgonzo	ti_mmchs_hw_fini(dev);
1795239281Sgonzo	ti_mmchs_deactivate(dev);
1796239281Sgonzo
1797239281Sgonzo#ifdef SOC_TI_AM335X
1798239281Sgonzo		printf("%s: DMA unimplemented\n", __func__);
1799239281Sgonzo#else
1800239281Sgonzo	ti_sdma_deactivate_channel(sc->sc_dmach_wr);
1801239281Sgonzo	ti_sdma_deactivate_channel(sc->sc_dmach_rd);
1802239281Sgonzo#endif
1803239281Sgonzo
1804239281Sgonzo	return (0);
1805239281Sgonzo}
1806239281Sgonzo
1807239281Sgonzostatic device_method_t ti_mmchs_methods[] = {
1808239281Sgonzo	/* device_if */
1809239281Sgonzo	DEVMETHOD(device_probe, ti_mmchs_probe),
1810239281Sgonzo	DEVMETHOD(device_attach, ti_mmchs_attach),
1811239281Sgonzo	DEVMETHOD(device_detach, ti_mmchs_detach),
1812239281Sgonzo
1813239281Sgonzo	/* Bus interface */
1814239281Sgonzo	DEVMETHOD(bus_read_ivar,	ti_mmchs_read_ivar),
1815239281Sgonzo	DEVMETHOD(bus_write_ivar,	ti_mmchs_write_ivar),
1816239281Sgonzo
1817239281Sgonzo	/* mmcbr_if - MMC state machine callbacks */
1818239281Sgonzo	DEVMETHOD(mmcbr_update_ios, ti_mmchs_update_ios),
1819239281Sgonzo	DEVMETHOD(mmcbr_request, ti_mmchs_request),
1820239281Sgonzo	DEVMETHOD(mmcbr_get_ro, ti_mmchs_get_ro),
1821239281Sgonzo	DEVMETHOD(mmcbr_acquire_host, ti_mmchs_acquire_host),
1822239281Sgonzo	DEVMETHOD(mmcbr_release_host, ti_mmchs_release_host),
1823239281Sgonzo
1824239281Sgonzo	{0, 0},
1825239281Sgonzo};
1826239281Sgonzo
1827239281Sgonzostatic driver_t ti_mmchs_driver = {
1828239281Sgonzo	"ti_mmchs",
1829239281Sgonzo	ti_mmchs_methods,
1830239281Sgonzo	sizeof(struct ti_mmchs_softc),
1831239281Sgonzo};
1832239281Sgonzostatic devclass_t ti_mmchs_devclass;
1833239281Sgonzo
1834239281SgonzoDRIVER_MODULE(ti_mmchs, simplebus, ti_mmchs_driver, ti_mmchs_devclass, 0, 0);
1835239281SgonzoMODULE_DEPEND(ti_mmchs, ti_prcm, 1, 1, 1);
1836239281Sgonzo#ifdef SOC_TI_AM335X
1837239281SgonzoMODULE_DEPEND(ti_mmchs, ti_edma, 1, 1, 1);
1838239281Sgonzo#else
1839239281SgonzoMODULE_DEPEND(ti_mmchs, ti_sdma, 1, 1, 1);
1840239281Sgonzo#endif
1841239281SgonzoMODULE_DEPEND(ti_mmchs, ti_gpio, 1, 1, 1);
1842239281Sgonzo
1843239281Sgonzo/* FIXME: MODULE_DEPEND(ti_mmchs, twl_vreg, 1, 1, 1); */
1844