xref: /freebsd/sys/arm/broadcom/bcm2835/bcm2835_sdhost.c (revision 18250ec6c089c0c50cbd9fd87d78e03ff89916df)
19e28e985SOleksandr Tymoshenko /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
39e28e985SOleksandr Tymoshenko  *
49e28e985SOleksandr Tymoshenko  * Copyright (c) 2018 Klaus P. Ohrhallinger <k@7he.at>
59e28e985SOleksandr Tymoshenko  * All rights reserved.
69e28e985SOleksandr Tymoshenko  *
79e28e985SOleksandr Tymoshenko  * Based on bcm2835_sdhci.c:
89e28e985SOleksandr Tymoshenko  * Copyright (c) 2012 Oleksandr Tymoshenko <gonzo@freebsd.org>
99e28e985SOleksandr Tymoshenko  * All rights reserved.
109e28e985SOleksandr Tymoshenko  *
119e28e985SOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
129e28e985SOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
139e28e985SOleksandr Tymoshenko  * are met:
149e28e985SOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
159e28e985SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
169e28e985SOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
179e28e985SOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
189e28e985SOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
199e28e985SOleksandr Tymoshenko  *
209e28e985SOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
219e28e985SOleksandr Tymoshenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229e28e985SOleksandr Tymoshenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239e28e985SOleksandr Tymoshenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
249e28e985SOleksandr Tymoshenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259e28e985SOleksandr Tymoshenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269e28e985SOleksandr Tymoshenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279e28e985SOleksandr Tymoshenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289e28e985SOleksandr Tymoshenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299e28e985SOleksandr Tymoshenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309e28e985SOleksandr Tymoshenko  * SUCH DAMAGE.
319e28e985SOleksandr Tymoshenko  *
329e28e985SOleksandr Tymoshenko  */
339e28e985SOleksandr Tymoshenko #include <sys/cdefs.h>
349e28e985SOleksandr Tymoshenko /*
359e28e985SOleksandr Tymoshenko  * pin 48-53 - card slot
369e28e985SOleksandr Tymoshenko  * pin 34-39 - radio module
379e28e985SOleksandr Tymoshenko  *
389e28e985SOleksandr Tymoshenko  * alt-0 - rubbish SDHCI  (0x7e202000) aka sdhost
399e28e985SOleksandr Tymoshenko  * alt-3 - advanced SDHCI (0x7e300000) aka sdhci/mmc/sdio
409e28e985SOleksandr Tymoshenko  *
419e28e985SOleksandr Tymoshenko  * driving card slot with mmc:
429e28e985SOleksandr Tymoshenko  *
439e28e985SOleksandr Tymoshenko  * sdhost_pins {
449e28e985SOleksandr Tymoshenko  *         brcm,pins = <0x30 0x31 0x32 0x33 0x34 0x35>;
459e28e985SOleksandr Tymoshenko  *         brcm,function = <0x7>;
469e28e985SOleksandr Tymoshenko  *         brcm,pull = <0x0 0x2 0x2 0x2 0x2 0x2>;
479e28e985SOleksandr Tymoshenko  *         phandle = <0x17>;
489e28e985SOleksandr Tymoshenko  * };
499e28e985SOleksandr Tymoshenko  * sdio_pins {
509e28e985SOleksandr Tymoshenko  *         brcm,pins = <0x22 0x23 0x24 0x25 0x26 0x27>;
519e28e985SOleksandr Tymoshenko  *         brcm,function = <0x4>;
529e28e985SOleksandr Tymoshenko  *         brcm,pull = <0x0 0x2 0x2 0x2 0x2 0x2>;
539e28e985SOleksandr Tymoshenko  *         phandle = <0x18>;
549e28e985SOleksandr Tymoshenko  * };
559e28e985SOleksandr Tymoshenko  *
569e28e985SOleksandr Tymoshenko  * driving card slot with sdhost:
579e28e985SOleksandr Tymoshenko  *
589e28e985SOleksandr Tymoshenko  * sdhost_pins {
599e28e985SOleksandr Tymoshenko  *         brcm,pins = <0x30 0x31 0x32 0x33 0x34 0x35>;
609e28e985SOleksandr Tymoshenko  *         brcm,function = <0x4>;
619e28e985SOleksandr Tymoshenko  *         brcm,pull = <0x0 0x2 0x2 0x2 0x2 0x2>;
629e28e985SOleksandr Tymoshenko  *         phandle = <0x17>;
639e28e985SOleksandr Tymoshenko  * };
649e28e985SOleksandr Tymoshenko  * sdio_pins {
659e28e985SOleksandr Tymoshenko  *         brcm,pins = <0x22 0x23 0x24 0x25 0x26 0x27>;
669e28e985SOleksandr Tymoshenko  *         brcm,function = <0x7>;
679e28e985SOleksandr Tymoshenko  *         brcm,pull = <0x0 0x2 0x2 0x2 0x2 0x2>;
689e28e985SOleksandr Tymoshenko  *         phandle = <0x18>;
699e28e985SOleksandr Tymoshenko  * };
709e28e985SOleksandr Tymoshenko  *
719e28e985SOleksandr Tymoshenko  */
729e28e985SOleksandr Tymoshenko 
739e28e985SOleksandr Tymoshenko #include <sys/param.h>
749e28e985SOleksandr Tymoshenko #include <sys/systm.h>
759e28e985SOleksandr Tymoshenko #include <sys/kobj.h>
769e28e985SOleksandr Tymoshenko #include <sys/bus.h>
779e28e985SOleksandr Tymoshenko #include <sys/kernel.h>
789e28e985SOleksandr Tymoshenko #include <sys/lock.h>
799e28e985SOleksandr Tymoshenko #include <sys/malloc.h>
809e28e985SOleksandr Tymoshenko #include <sys/module.h>
819e28e985SOleksandr Tymoshenko #include <sys/mutex.h>
829e28e985SOleksandr Tymoshenko #include <sys/rman.h>
839e28e985SOleksandr Tymoshenko #include <sys/sysctl.h>
849e28e985SOleksandr Tymoshenko #include <sys/taskqueue.h>
859e28e985SOleksandr Tymoshenko #include <sys/gpio.h>
869e28e985SOleksandr Tymoshenko 
879e28e985SOleksandr Tymoshenko #include <machine/bus.h>
889e28e985SOleksandr Tymoshenko 
899e28e985SOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h>
909e28e985SOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h>
919e28e985SOleksandr Tymoshenko 
929e28e985SOleksandr Tymoshenko #include <dev/mmc/bridge.h>
939e28e985SOleksandr Tymoshenko #include <dev/mmc/mmcreg.h>
949e28e985SOleksandr Tymoshenko 
959e28e985SOleksandr Tymoshenko #include <dev/sdhci/sdhci.h>
969e28e985SOleksandr Tymoshenko 
979e28e985SOleksandr Tymoshenko #include "mmcbr_if.h"
989e28e985SOleksandr Tymoshenko #include "sdhci_if.h"
999e28e985SOleksandr Tymoshenko 
1009e28e985SOleksandr Tymoshenko #include "opt_mmccam.h"
1019e28e985SOleksandr Tymoshenko 
1029e28e985SOleksandr Tymoshenko #include "bcm2835_dma.h"
1039e28e985SOleksandr Tymoshenko #include <arm/broadcom/bcm2835/bcm2835_mbox_prop.h>
1049e28e985SOleksandr Tymoshenko #include "bcm2835_vcbus.h"
1059e28e985SOleksandr Tymoshenko 
1069e28e985SOleksandr Tymoshenko /* #define SDHOST_DEBUG */
1079e28e985SOleksandr Tymoshenko 
1089e28e985SOleksandr Tymoshenko /* Registers */
1099e28e985SOleksandr Tymoshenko #define HC_COMMAND		0x00	/* Command and flags */
1109e28e985SOleksandr Tymoshenko #define HC_ARGUMENT		0x04
1119e28e985SOleksandr Tymoshenko #define HC_TIMEOUTCOUNTER	0x08
1129e28e985SOleksandr Tymoshenko #define HC_CLOCKDIVISOR		0x0c
1139e28e985SOleksandr Tymoshenko #define HC_RESPONSE_0		0x10
1149e28e985SOleksandr Tymoshenko #define HC_RESPONSE_1		0x14
1159e28e985SOleksandr Tymoshenko #define HC_RESPONSE_2		0x18
1169e28e985SOleksandr Tymoshenko #define HC_RESPONSE_3		0x1c
1179e28e985SOleksandr Tymoshenko #define HC_HOSTSTATUS		0x20
1189e28e985SOleksandr Tymoshenko #define HC_POWER		0x30
1199e28e985SOleksandr Tymoshenko #define HC_DEBUG		0x34
1209e28e985SOleksandr Tymoshenko #define HC_HOSTCONFIG		0x38
1219e28e985SOleksandr Tymoshenko #define HC_BLOCKSIZE		0x3c
1229e28e985SOleksandr Tymoshenko #define HC_DATAPORT		0x40
1239e28e985SOleksandr Tymoshenko #define HC_BLOCKCOUNT		0x50
1249e28e985SOleksandr Tymoshenko 
1259e28e985SOleksandr Tymoshenko /* Flags for HC_COMMAND register */
1269e28e985SOleksandr Tymoshenko #define HC_CMD_ENABLE			0x8000
1279e28e985SOleksandr Tymoshenko #define HC_CMD_FAILED			0x4000
1289e28e985SOleksandr Tymoshenko #define HC_CMD_BUSY			0x0800
1299e28e985SOleksandr Tymoshenko #define HC_CMD_RESPONSE_NONE		0x0400
1309e28e985SOleksandr Tymoshenko #define HC_CMD_RESPONSE_LONG		0x0200
1319e28e985SOleksandr Tymoshenko #define HC_CMD_WRITE			0x0080
1329e28e985SOleksandr Tymoshenko #define HC_CMD_READ			0x0040
1339e28e985SOleksandr Tymoshenko #define HC_CMD_COMMAND_MASK		0x003f
1349e28e985SOleksandr Tymoshenko 
1359e28e985SOleksandr Tymoshenko #define HC_CLOCKDIVISOR_MAXVAL		0x07ff
1369e28e985SOleksandr Tymoshenko 
1379e28e985SOleksandr Tymoshenko /* Flags for HC_HOSTSTATUS register */
1389e28e985SOleksandr Tymoshenko #define HC_HSTST_HAVEDATA		0x0001
1399e28e985SOleksandr Tymoshenko #define HC_HSTST_ERROR_FIFO		0x0008
1409e28e985SOleksandr Tymoshenko #define HC_HSTST_ERROR_CRC7		0x0010
1419e28e985SOleksandr Tymoshenko #define HC_HSTST_ERROR_CRC16		0x0020
1429e28e985SOleksandr Tymoshenko #define HC_HSTST_TIMEOUT_CMD		0x0040
1439e28e985SOleksandr Tymoshenko #define HC_HSTST_TIMEOUT_DATA		0x0080
1449e28e985SOleksandr Tymoshenko #define HC_HSTST_INT_BLOCK		0x0200
1459e28e985SOleksandr Tymoshenko #define HC_HSTST_INT_BUSY		0x0400
1469e28e985SOleksandr Tymoshenko 
1479e28e985SOleksandr Tymoshenko #define HC_HSTST_RESET			0xffff
1489e28e985SOleksandr Tymoshenko 
1499e28e985SOleksandr Tymoshenko #define HC_HSTST_MASK_ERROR_DATA	(HC_HSTST_ERROR_FIFO | \
1509e28e985SOleksandr Tymoshenko     HC_HSTST_ERROR_CRC7 | HC_HSTST_ERROR_CRC16 | HC_HSTST_TIMEOUT_DATA)
1519e28e985SOleksandr Tymoshenko 
1529e28e985SOleksandr Tymoshenko #define HC_HSTST_MASK_ERROR_ALL		(HC_HSTST_MASK_ERROR_DATA | \
1539e28e985SOleksandr Tymoshenko     HC_HSTST_TIMEOUT_CMD)
1549e28e985SOleksandr Tymoshenko 
1559e28e985SOleksandr Tymoshenko /* Flags for HC_HOSTCONFIG register */
1569e28e985SOleksandr Tymoshenko #define HC_HSTCF_INTBUS_WIDE		0x0002
1579e28e985SOleksandr Tymoshenko #define HC_HSTCF_EXTBUS_4BIT		0x0004
1589e28e985SOleksandr Tymoshenko #define HC_HSTCF_SLOW_CARD		0x0008
1599e28e985SOleksandr Tymoshenko #define HC_HSTCF_INT_DATA		0x0010
1609e28e985SOleksandr Tymoshenko #define HC_HSTCF_INT_BLOCK		0x0100
1619e28e985SOleksandr Tymoshenko #define HC_HSTCF_INT_BUSY		0x0400
1629e28e985SOleksandr Tymoshenko 
1639e28e985SOleksandr Tymoshenko /* Flags for HC_DEBUG register */
1649e28e985SOleksandr Tymoshenko #define HC_DBG_FIFO_THRESH_WRITE_SHIFT	9
1659e28e985SOleksandr Tymoshenko #define HC_DBG_FIFO_THRESH_READ_SHIFT	14
1669e28e985SOleksandr Tymoshenko #define HC_DBG_FIFO_THRESH_MASK		0x001f
1679e28e985SOleksandr Tymoshenko 
1689e28e985SOleksandr Tymoshenko /* Settings */
1699e28e985SOleksandr Tymoshenko #define HC_FIFO_SIZE		16
1709e28e985SOleksandr Tymoshenko #define HC_FIFO_THRESH_READ	4
1719e28e985SOleksandr Tymoshenko #define HC_FIFO_THRESH_WRITE	4
1729e28e985SOleksandr Tymoshenko 
1739e28e985SOleksandr Tymoshenko #define HC_TIMEOUT_DEFAULT	0x00f00000
1749e28e985SOleksandr Tymoshenko 
1759e28e985SOleksandr Tymoshenko #define	BCM2835_DEFAULT_SDHCI_FREQ	50
1769e28e985SOleksandr Tymoshenko 
1779e28e985SOleksandr Tymoshenko static int bcm2835_sdhost_debug = 0;
1789e28e985SOleksandr Tymoshenko 
1799e28e985SOleksandr Tymoshenko #ifdef SDHOST_DEBUG
1809e28e985SOleksandr Tymoshenko 
1819e28e985SOleksandr Tymoshenko TUNABLE_INT("hw.bcm2835.sdhost.debug", &bcm2835_sdhost_debug);
1829e28e985SOleksandr Tymoshenko SYSCTL_INT(_hw_sdhci, OID_AUTO, bcm2835_sdhost_debug, CTLFLAG_RWTUN,
1839e28e985SOleksandr Tymoshenko     &bcm2835_sdhost_debug, 0, "bcm2835-sdhost Debug level");
1849e28e985SOleksandr Tymoshenko 
1859e28e985SOleksandr Tymoshenko #define dprintf(fmt, args...) \
1869e28e985SOleksandr Tymoshenko 	do { \
1879e28e985SOleksandr Tymoshenko 		if (bcm2835_sdhost_debug > 0) \
1889e28e985SOleksandr Tymoshenko 			printf(fmt,##args); \
1899e28e985SOleksandr Tymoshenko 	} while (0)
1909e28e985SOleksandr Tymoshenko #else
1919e28e985SOleksandr Tymoshenko 
1929e28e985SOleksandr Tymoshenko #define dprintf(fmt, args...)
1939e28e985SOleksandr Tymoshenko 
1949e28e985SOleksandr Tymoshenko #endif /* ! SDHOST_DEBUG */
1959e28e985SOleksandr Tymoshenko 
1969e28e985SOleksandr Tymoshenko static struct ofw_compat_data compat_data[] = {
1979e28e985SOleksandr Tymoshenko 	{"brcm,bcm2835-sdhost",		1},
1989e28e985SOleksandr Tymoshenko 	{NULL,				0}
1999e28e985SOleksandr Tymoshenko };
2009e28e985SOleksandr Tymoshenko 
2019e28e985SOleksandr Tymoshenko struct bcm_sdhost_softc {
2029e28e985SOleksandr Tymoshenko 	device_t		sc_dev;
2039e28e985SOleksandr Tymoshenko 	struct resource *	sc_mem_res;
2049e28e985SOleksandr Tymoshenko 	struct resource *	sc_irq_res;
2059e28e985SOleksandr Tymoshenko 	bus_space_tag_t		sc_bst;
2069e28e985SOleksandr Tymoshenko 	bus_space_handle_t	sc_bsh;
2079e28e985SOleksandr Tymoshenko 	void *			sc_intrhand;
2089e28e985SOleksandr Tymoshenko 	struct mmc_request *	sc_req;
2099e28e985SOleksandr Tymoshenko 	struct sdhci_slot	sc_slot;
2109e28e985SOleksandr Tymoshenko 
2119e28e985SOleksandr Tymoshenko 	struct mtx		mtx;
2129e28e985SOleksandr Tymoshenko 
2139e28e985SOleksandr Tymoshenko 	char			cmdbusy;
2149e28e985SOleksandr Tymoshenko 	char			mmc_app_cmd;
2159e28e985SOleksandr Tymoshenko 
2169e28e985SOleksandr Tymoshenko 	u_int32_t		sdhci_int_status;
2179e28e985SOleksandr Tymoshenko 	u_int32_t		sdhci_signal_enable;
2189e28e985SOleksandr Tymoshenko 	u_int32_t		sdhci_present_state;
2199e28e985SOleksandr Tymoshenko 	u_int32_t		sdhci_blocksize;
2209e28e985SOleksandr Tymoshenko 	u_int32_t		sdhci_blockcount;
2219e28e985SOleksandr Tymoshenko 
2229e28e985SOleksandr Tymoshenko 	u_int32_t		sdcard_rca;
2239e28e985SOleksandr Tymoshenko };
2249e28e985SOleksandr Tymoshenko 
2259e28e985SOleksandr Tymoshenko static int bcm_sdhost_probe(device_t);
2269e28e985SOleksandr Tymoshenko static int bcm_sdhost_attach(device_t);
2279e28e985SOleksandr Tymoshenko static int bcm_sdhost_detach(device_t);
2289e28e985SOleksandr Tymoshenko static void bcm_sdhost_intr(void *);
2299e28e985SOleksandr Tymoshenko 
2309e28e985SOleksandr Tymoshenko static int bcm_sdhost_get_ro(device_t, device_t);
2319e28e985SOleksandr Tymoshenko 
2329e28e985SOleksandr Tymoshenko static inline uint32_t
RD4(struct bcm_sdhost_softc * sc,bus_size_t off)2339e28e985SOleksandr Tymoshenko RD4(struct bcm_sdhost_softc *sc, bus_size_t off)
2349e28e985SOleksandr Tymoshenko {
2359e28e985SOleksandr Tymoshenko 	uint32_t val;
2369e28e985SOleksandr Tymoshenko 
2379e28e985SOleksandr Tymoshenko 	val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
2389e28e985SOleksandr Tymoshenko 
2399e28e985SOleksandr Tymoshenko 	return (val);
2409e28e985SOleksandr Tymoshenko }
2419e28e985SOleksandr Tymoshenko 
2429e28e985SOleksandr Tymoshenko static inline void
WR4(struct bcm_sdhost_softc * sc,bus_size_t off,uint32_t val)2439e28e985SOleksandr Tymoshenko WR4(struct bcm_sdhost_softc *sc, bus_size_t off, uint32_t val)
2449e28e985SOleksandr Tymoshenko {
2459e28e985SOleksandr Tymoshenko 
2469e28e985SOleksandr Tymoshenko 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
2479e28e985SOleksandr Tymoshenko }
2489e28e985SOleksandr Tymoshenko 
2498c9ca28bSBjoern A. Zeeb #ifdef notyet
2509e28e985SOleksandr Tymoshenko static inline uint16_t
RD2(struct bcm_sdhost_softc * sc,bus_size_t off)2519e28e985SOleksandr Tymoshenko RD2(struct bcm_sdhost_softc *sc, bus_size_t off)
2529e28e985SOleksandr Tymoshenko {
2539e28e985SOleksandr Tymoshenko 	uint32_t val;
2549e28e985SOleksandr Tymoshenko 
2559e28e985SOleksandr Tymoshenko 	val = RD4(sc, off & ~3);
2569e28e985SOleksandr Tymoshenko 
2579e28e985SOleksandr Tymoshenko 	return ((val >> (off & 3)*8) & 0xffff);
2589e28e985SOleksandr Tymoshenko }
2598c9ca28bSBjoern A. Zeeb #endif
2609e28e985SOleksandr Tymoshenko 
2619e28e985SOleksandr Tymoshenko static inline uint8_t
RD1(struct bcm_sdhost_softc * sc,bus_size_t off)2629e28e985SOleksandr Tymoshenko RD1(struct bcm_sdhost_softc *sc, bus_size_t off)
2639e28e985SOleksandr Tymoshenko {
2649e28e985SOleksandr Tymoshenko 	uint32_t val;
2659e28e985SOleksandr Tymoshenko 
2669e28e985SOleksandr Tymoshenko 	val = RD4(sc, off & ~3);
2679e28e985SOleksandr Tymoshenko 
2689e28e985SOleksandr Tymoshenko 	return ((val >> (off & 3)*8) & 0xff);
2699e28e985SOleksandr Tymoshenko }
2709e28e985SOleksandr Tymoshenko 
2719e28e985SOleksandr Tymoshenko static inline void
WR2(struct bcm_sdhost_softc * sc,bus_size_t off,uint16_t val)2729e28e985SOleksandr Tymoshenko WR2(struct bcm_sdhost_softc *sc, bus_size_t off, uint16_t val)
2739e28e985SOleksandr Tymoshenko {
2749e28e985SOleksandr Tymoshenko 	uint32_t val32;
2759e28e985SOleksandr Tymoshenko 
2769e28e985SOleksandr Tymoshenko 	val32 = RD4(sc, off & ~3);
2779e28e985SOleksandr Tymoshenko 	val32 &= ~(0xffff << (off & 3)*8);
2789e28e985SOleksandr Tymoshenko 	val32 |= (val << (off & 3)*8);
2799e28e985SOleksandr Tymoshenko 	WR4(sc, off & ~3, val32);
2809e28e985SOleksandr Tymoshenko }
2819e28e985SOleksandr Tymoshenko 
2829e28e985SOleksandr Tymoshenko static inline void
WR1(struct bcm_sdhost_softc * sc,bus_size_t off,uint8_t val)2839e28e985SOleksandr Tymoshenko WR1(struct bcm_sdhost_softc *sc, bus_size_t off, uint8_t val)
2849e28e985SOleksandr Tymoshenko {
2859e28e985SOleksandr Tymoshenko 	uint32_t val32;
2869e28e985SOleksandr Tymoshenko 
2879e28e985SOleksandr Tymoshenko 	val32 = RD4(sc, off & ~3);
2889e28e985SOleksandr Tymoshenko 	val32 &= ~(0xff << (off & 3)*8);
2899e28e985SOleksandr Tymoshenko 	val32 |= (val << (off & 3)*8);
2909e28e985SOleksandr Tymoshenko 	WR4(sc, off & ~3, val32);
2919e28e985SOleksandr Tymoshenko }
2929e28e985SOleksandr Tymoshenko 
2939e28e985SOleksandr Tymoshenko static void
bcm_sdhost_print_regs(struct bcm_sdhost_softc * sc,struct sdhci_slot * slot,int line,int error)2949e28e985SOleksandr Tymoshenko bcm_sdhost_print_regs(struct bcm_sdhost_softc *sc, struct sdhci_slot *slot,
2959e28e985SOleksandr Tymoshenko     int line, int error)
2969e28e985SOleksandr Tymoshenko {
2979e28e985SOleksandr Tymoshenko 
2989e28e985SOleksandr Tymoshenko 	if (bcm2835_sdhost_debug > 0 || error > 0) {
2999e28e985SOleksandr Tymoshenko 		printf("%s: sc=%p slot=%p\n",
3009e28e985SOleksandr Tymoshenko 		    __func__, sc, slot);
3019e28e985SOleksandr Tymoshenko 		printf("HC_COMMAND:        0x%08x\n",
3029e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_COMMAND));
3039e28e985SOleksandr Tymoshenko 		printf("HC_ARGUMENT:       0x%08x\n",
3049e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_ARGUMENT));
3059e28e985SOleksandr Tymoshenko 		printf("HC_TIMEOUTCOUNTER: 0x%08x\n",
3069e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_TIMEOUTCOUNTER));
3079e28e985SOleksandr Tymoshenko 		printf("HC_CLOCKDIVISOR:   0x%08x\n",
3089e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_CLOCKDIVISOR));
3099e28e985SOleksandr Tymoshenko 		printf("HC_RESPONSE_0:     0x%08x\n",
3109e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_RESPONSE_0));
3119e28e985SOleksandr Tymoshenko 		printf("HC_RESPONSE_1:     0x%08x\n",
3129e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_RESPONSE_1));
3139e28e985SOleksandr Tymoshenko 		printf("HC_RESPONSE_2:     0x%08x\n",
3149e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_RESPONSE_2));
3159e28e985SOleksandr Tymoshenko 		printf("HC_RESPONSE_3:     0x%08x\n",
3169e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_RESPONSE_3));
3179e28e985SOleksandr Tymoshenko 		printf("HC_HOSTSTATUS:     0x%08x\n",
3189e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_HOSTSTATUS));
3199e28e985SOleksandr Tymoshenko 		printf("HC_POWER:          0x%08x\n",
3209e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_POWER));
3219e28e985SOleksandr Tymoshenko 		printf("HC_DEBUG:          0x%08x\n",
3229e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_DEBUG));
3239e28e985SOleksandr Tymoshenko 		printf("HC_HOSTCONFIG:     0x%08x\n",
3249e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_HOSTCONFIG));
3259e28e985SOleksandr Tymoshenko 		printf("HC_BLOCKSIZE:      0x%08x\n",
3269e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_BLOCKSIZE));
3279e28e985SOleksandr Tymoshenko 		printf("HC_BLOCKCOUNT:     0x%08x\n",
3289e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_BLOCKCOUNT));
3299e28e985SOleksandr Tymoshenko 
3309e28e985SOleksandr Tymoshenko 	} else {
3319e28e985SOleksandr Tymoshenko 		/*
3329e28e985SOleksandr Tymoshenko 		printf("%04d | HC_COMMAND: 0x%08x HC_ARGUMENT: 0x%08x "
3339e28e985SOleksandr Tymoshenko 		    "HC_HOSTSTATUS: 0x%08x HC_HOSTCONFIG: 0x%08x\n",
3349e28e985SOleksandr Tymoshenko 		    line, RD4(sc, HC_COMMAND), RD4(sc, HC_ARGUMENT),
3359e28e985SOleksandr Tymoshenko 		    RD4(sc, HC_HOSTSTATUS), RD4(sc, HC_HOSTCONFIG));
3369e28e985SOleksandr Tymoshenko 		*/
3379e28e985SOleksandr Tymoshenko 	}
3389e28e985SOleksandr Tymoshenko }
3399e28e985SOleksandr Tymoshenko 
3409e28e985SOleksandr Tymoshenko static void
bcm_sdhost_reset(device_t dev,struct sdhci_slot * slot)3419e28e985SOleksandr Tymoshenko bcm_sdhost_reset(device_t dev, struct sdhci_slot *slot)
3429e28e985SOleksandr Tymoshenko {
3439e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
3449e28e985SOleksandr Tymoshenko 	u_int32_t dbg;
3459e28e985SOleksandr Tymoshenko 
3469e28e985SOleksandr Tymoshenko 	WR4(sc, HC_POWER, 0);
3479e28e985SOleksandr Tymoshenko 
3489e28e985SOleksandr Tymoshenko 	WR4(sc, HC_COMMAND, 0);
3499e28e985SOleksandr Tymoshenko 	WR4(sc, HC_ARGUMENT, 0);
3509e28e985SOleksandr Tymoshenko 	WR4(sc, HC_TIMEOUTCOUNTER, HC_TIMEOUT_DEFAULT);
3519e28e985SOleksandr Tymoshenko 	WR4(sc, HC_CLOCKDIVISOR, 0);
3529e28e985SOleksandr Tymoshenko 	WR4(sc, HC_HOSTSTATUS, HC_HSTST_RESET);
3539e28e985SOleksandr Tymoshenko 	WR4(sc, HC_HOSTCONFIG, 0);
3549e28e985SOleksandr Tymoshenko 	WR4(sc, HC_BLOCKSIZE, 0);
3559e28e985SOleksandr Tymoshenko 	WR4(sc, HC_BLOCKCOUNT, 0);
3569e28e985SOleksandr Tymoshenko 
3579e28e985SOleksandr Tymoshenko 	dbg = RD4(sc, HC_DEBUG);
3589e28e985SOleksandr Tymoshenko 	dbg &= ~( (HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_READ_SHIFT) |
3599e28e985SOleksandr Tymoshenko 	          (HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_WRITE_SHIFT) );
3609e28e985SOleksandr Tymoshenko 	dbg |= (HC_FIFO_THRESH_READ << HC_DBG_FIFO_THRESH_READ_SHIFT) |
3619e28e985SOleksandr Tymoshenko 	       (HC_FIFO_THRESH_WRITE << HC_DBG_FIFO_THRESH_WRITE_SHIFT);
3629e28e985SOleksandr Tymoshenko 	WR4(sc, HC_DEBUG, dbg);
3639e28e985SOleksandr Tymoshenko 
3649e28e985SOleksandr Tymoshenko 	DELAY(250000);
3659e28e985SOleksandr Tymoshenko 
3669e28e985SOleksandr Tymoshenko 	WR4(sc, HC_POWER, 1);
3679e28e985SOleksandr Tymoshenko 
3689e28e985SOleksandr Tymoshenko 	DELAY(250000);
3699e28e985SOleksandr Tymoshenko 
3709e28e985SOleksandr Tymoshenko 	sc->sdhci_present_state = SDHCI_CARD_PRESENT | SDHCI_CARD_STABLE |
3719e28e985SOleksandr Tymoshenko 		SDHCI_WRITE_PROTECT;
3729e28e985SOleksandr Tymoshenko 
3739e28e985SOleksandr Tymoshenko 	WR4(sc, HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_MAXVAL);
3749e28e985SOleksandr Tymoshenko 	WR4(sc, HC_HOSTCONFIG, HC_HSTCF_INT_BUSY);
3759e28e985SOleksandr Tymoshenko }
3769e28e985SOleksandr Tymoshenko 
3779e28e985SOleksandr Tymoshenko static int
bcm_sdhost_probe(device_t dev)3789e28e985SOleksandr Tymoshenko bcm_sdhost_probe(device_t dev)
3799e28e985SOleksandr Tymoshenko {
3809e28e985SOleksandr Tymoshenko 
3819e28e985SOleksandr Tymoshenko 	dprintf("%s:\n", __func__);
3829e28e985SOleksandr Tymoshenko 
3839e28e985SOleksandr Tymoshenko 	if (!ofw_bus_status_okay(dev))
3849e28e985SOleksandr Tymoshenko 		return (ENXIO);
3859e28e985SOleksandr Tymoshenko 
3869e28e985SOleksandr Tymoshenko 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
3879e28e985SOleksandr Tymoshenko 		return (ENXIO);
3889e28e985SOleksandr Tymoshenko 
3899e28e985SOleksandr Tymoshenko 	device_set_desc(dev, "Broadcom 2708 SDHOST controller");
3909e28e985SOleksandr Tymoshenko 
3919e28e985SOleksandr Tymoshenko 	return (BUS_PROBE_DEFAULT);
3929e28e985SOleksandr Tymoshenko }
3939e28e985SOleksandr Tymoshenko 
3949e28e985SOleksandr Tymoshenko static int
bcm_sdhost_attach(device_t dev)3959e28e985SOleksandr Tymoshenko bcm_sdhost_attach(device_t dev)
3969e28e985SOleksandr Tymoshenko {
3979e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
3989e28e985SOleksandr Tymoshenko 	int rid, err;
3999e28e985SOleksandr Tymoshenko 	u_int default_freq;
4009e28e985SOleksandr Tymoshenko 
4019e28e985SOleksandr Tymoshenko 	dprintf("%s: dev=%p sc=%p unit=%d\n",
4029e28e985SOleksandr Tymoshenko 	    __func__, dev, sc, device_get_unit(dev));
4039e28e985SOleksandr Tymoshenko 
4049e28e985SOleksandr Tymoshenko 	mtx_init(&sc->mtx, "BCM SDHOST mtx", "bcm_sdhost",
4059e28e985SOleksandr Tymoshenko 	    MTX_DEF | MTX_RECURSE);
4069e28e985SOleksandr Tymoshenko 
4079e28e985SOleksandr Tymoshenko 	sc->sc_dev = dev;
4089e28e985SOleksandr Tymoshenko 	sc->sc_req = NULL;
4099e28e985SOleksandr Tymoshenko 
4109e28e985SOleksandr Tymoshenko 	sc->cmdbusy = 0;
4119e28e985SOleksandr Tymoshenko 	sc->mmc_app_cmd = 0;
4129e28e985SOleksandr Tymoshenko 	sc->sdhci_int_status = 0;
4139e28e985SOleksandr Tymoshenko 	sc->sdhci_signal_enable = 0;
4149e28e985SOleksandr Tymoshenko 	sc->sdhci_present_state = 0;
4159e28e985SOleksandr Tymoshenko 	sc->sdhci_blocksize = 0;
4169e28e985SOleksandr Tymoshenko 	sc->sdhci_blockcount = 0;
4179e28e985SOleksandr Tymoshenko 
4189e28e985SOleksandr Tymoshenko 	sc->sdcard_rca = 0;
4199e28e985SOleksandr Tymoshenko 
4209e28e985SOleksandr Tymoshenko 	default_freq = 50;
4219e28e985SOleksandr Tymoshenko 	err = 0;
4229e28e985SOleksandr Tymoshenko 
4239e28e985SOleksandr Tymoshenko 	if (bootverbose)
4249e28e985SOleksandr Tymoshenko 		device_printf(dev, "SDHCI frequency: %dMHz\n", default_freq);
4259e28e985SOleksandr Tymoshenko 
4269e28e985SOleksandr Tymoshenko 	rid = 0;
4279e28e985SOleksandr Tymoshenko 	sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
4289e28e985SOleksandr Tymoshenko 	    RF_ACTIVE);
4299e28e985SOleksandr Tymoshenko 	if (!sc->sc_mem_res) {
4309e28e985SOleksandr Tymoshenko 		device_printf(dev, "cannot allocate memory window\n");
4319e28e985SOleksandr Tymoshenko 		err = ENXIO;
4329e28e985SOleksandr Tymoshenko 		goto fail;
4339e28e985SOleksandr Tymoshenko 	}
4349e28e985SOleksandr Tymoshenko 
4359e28e985SOleksandr Tymoshenko 	sc->sc_bst = rman_get_bustag(sc->sc_mem_res);
4369e28e985SOleksandr Tymoshenko 	sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res);
4379e28e985SOleksandr Tymoshenko 
4389e28e985SOleksandr Tymoshenko 	bcm_sdhost_reset(dev, &sc->sc_slot);
4399e28e985SOleksandr Tymoshenko 
4409e28e985SOleksandr Tymoshenko 	bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 0);
4419e28e985SOleksandr Tymoshenko 
4429e28e985SOleksandr Tymoshenko 	rid = 0;
4439e28e985SOleksandr Tymoshenko 	sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
4449e28e985SOleksandr Tymoshenko 	    RF_ACTIVE);
4459e28e985SOleksandr Tymoshenko 	if (!sc->sc_irq_res) {
4469e28e985SOleksandr Tymoshenko 		device_printf(dev, "cannot allocate interrupt\n");
4479e28e985SOleksandr Tymoshenko 		err = ENXIO;
4489e28e985SOleksandr Tymoshenko 		goto fail;
4499e28e985SOleksandr Tymoshenko 	}
4509e28e985SOleksandr Tymoshenko 
4519e28e985SOleksandr Tymoshenko 	if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
4529e28e985SOleksandr Tymoshenko 	    NULL, bcm_sdhost_intr, sc, &sc->sc_intrhand)) {
4539e28e985SOleksandr Tymoshenko 		device_printf(dev, "cannot setup interrupt handler\n");
4549e28e985SOleksandr Tymoshenko 		err = ENXIO;
4559e28e985SOleksandr Tymoshenko 		goto fail;
4569e28e985SOleksandr Tymoshenko 	}
4579e28e985SOleksandr Tymoshenko 
4589e28e985SOleksandr Tymoshenko 	sc->sc_slot.caps = 0;
4599e28e985SOleksandr Tymoshenko 	sc->sc_slot.caps |= SDHCI_CAN_VDD_330;
4609e28e985SOleksandr Tymoshenko 	sc->sc_slot.caps |= SDHCI_CAN_DO_HISPD;
4619e28e985SOleksandr Tymoshenko 	sc->sc_slot.caps |= (default_freq << SDHCI_CLOCK_BASE_SHIFT);
4629e28e985SOleksandr Tymoshenko 
4639e28e985SOleksandr Tymoshenko 	sc->sc_slot.quirks = 0;
4649e28e985SOleksandr Tymoshenko 	sc->sc_slot.quirks |= SDHCI_QUIRK_MISSING_CAPS;
4659e28e985SOleksandr Tymoshenko 	sc->sc_slot.quirks |= SDHCI_QUIRK_DONT_SHIFT_RESPONSE;
4669e28e985SOleksandr Tymoshenko 
4679e28e985SOleksandr Tymoshenko 	sc->sc_slot.opt = 0;
4689e28e985SOleksandr Tymoshenko 
4699e28e985SOleksandr Tymoshenko 	/* XXX ?
4709e28e985SOleksandr Tymoshenko 	sc->slot->timeout_clk = ...;
4719e28e985SOleksandr Tymoshenko 	*/
4729e28e985SOleksandr Tymoshenko 
4739e28e985SOleksandr Tymoshenko 	sdhci_init_slot(dev, &sc->sc_slot, 0);
4749e28e985SOleksandr Tymoshenko 
475723da5d9SJohn Baldwin 	bus_identify_children(dev);
476*18250ec6SJohn Baldwin 	bus_attach_children(dev);
4779e28e985SOleksandr Tymoshenko 
4789e28e985SOleksandr Tymoshenko 	sdhci_start_slot(&sc->sc_slot);
4799e28e985SOleksandr Tymoshenko 
4809e28e985SOleksandr Tymoshenko 	return (0);
4819e28e985SOleksandr Tymoshenko 
4829e28e985SOleksandr Tymoshenko     fail:
4839e28e985SOleksandr Tymoshenko 	if (sc->sc_intrhand)
4849e28e985SOleksandr Tymoshenko 		bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand);
4859e28e985SOleksandr Tymoshenko 	if (sc->sc_irq_res)
4869e28e985SOleksandr Tymoshenko 		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res);
4879e28e985SOleksandr Tymoshenko 	if (sc->sc_mem_res)
4889e28e985SOleksandr Tymoshenko 		bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res);
4899e28e985SOleksandr Tymoshenko 
4909e28e985SOleksandr Tymoshenko 	return (err);
4919e28e985SOleksandr Tymoshenko }
4929e28e985SOleksandr Tymoshenko 
4939e28e985SOleksandr Tymoshenko static int
bcm_sdhost_detach(device_t dev)4949e28e985SOleksandr Tymoshenko bcm_sdhost_detach(device_t dev)
4959e28e985SOleksandr Tymoshenko {
4969e28e985SOleksandr Tymoshenko 
4979e28e985SOleksandr Tymoshenko 	dprintf("%s:\n", __func__);
4989e28e985SOleksandr Tymoshenko 
4999e28e985SOleksandr Tymoshenko 	return (EBUSY);
5009e28e985SOleksandr Tymoshenko }
5019e28e985SOleksandr Tymoshenko 
5029e28e985SOleksandr Tymoshenko /*
5039e28e985SOleksandr Tymoshenko  * rv 0 --> command finished
5049e28e985SOleksandr Tymoshenko  * rv 1 --> command timed out
5059e28e985SOleksandr Tymoshenko  */
5069e28e985SOleksandr Tymoshenko static inline int
bcm_sdhost_waitcommand(struct bcm_sdhost_softc * sc)5079e28e985SOleksandr Tymoshenko bcm_sdhost_waitcommand(struct bcm_sdhost_softc *sc)
5089e28e985SOleksandr Tymoshenko {
5099e28e985SOleksandr Tymoshenko 	int timeout = 1000;
5109e28e985SOleksandr Tymoshenko 
5119e28e985SOleksandr Tymoshenko 	mtx_assert(&sc->mtx, MA_OWNED);
5129e28e985SOleksandr Tymoshenko 
5139e28e985SOleksandr Tymoshenko 	while ((RD4(sc, HC_COMMAND) & HC_CMD_ENABLE) && --timeout > 0) {
5149e28e985SOleksandr Tymoshenko 		DELAY(100);
5159e28e985SOleksandr Tymoshenko 	}
5169e28e985SOleksandr Tymoshenko 
5179e28e985SOleksandr Tymoshenko 	return ((timeout > 0) ? 0 : 1);
5189e28e985SOleksandr Tymoshenko }
5199e28e985SOleksandr Tymoshenko 
5209e28e985SOleksandr Tymoshenko static int
bcm_sdhost_waitcommand_status(struct bcm_sdhost_softc * sc)5219e28e985SOleksandr Tymoshenko bcm_sdhost_waitcommand_status(struct bcm_sdhost_softc *sc)
5229e28e985SOleksandr Tymoshenko {
5239e28e985SOleksandr Tymoshenko 	u_int32_t cdst;
5249e28e985SOleksandr Tymoshenko 	int i;
5259e28e985SOleksandr Tymoshenko 
5269e28e985SOleksandr Tymoshenko 	/* wait for card to change status from
5279e28e985SOleksandr Tymoshenko 	 * ''prg'' to ''trn''
5289e28e985SOleksandr Tymoshenko 	 * card status: sd specs p. 103
5299e28e985SOleksandr Tymoshenko 	 */
5309e28e985SOleksandr Tymoshenko 	i = 0;
5319e28e985SOleksandr Tymoshenko 	do {
5329e28e985SOleksandr Tymoshenko 		DELAY(1000);
5339e28e985SOleksandr Tymoshenko 		WR4(sc, HC_ARGUMENT, sc->sdcard_rca << 16);
5349e28e985SOleksandr Tymoshenko 		WR4(sc, HC_COMMAND,
5359e28e985SOleksandr Tymoshenko 		    MMC_SEND_STATUS | HC_CMD_ENABLE);
5369e28e985SOleksandr Tymoshenko 		bcm_sdhost_waitcommand(sc);
5379e28e985SOleksandr Tymoshenko 		cdst = RD4(sc, HC_RESPONSE_0);
5389e28e985SOleksandr Tymoshenko 		dprintf("%s: card status %08x (cs %d)\n",
5399e28e985SOleksandr Tymoshenko 		    __func__, cdst, (cdst & 0x0e00) >> 9);
5409e28e985SOleksandr Tymoshenko 		if (i++ > 100) {
5419e28e985SOleksandr Tymoshenko 			printf("%s: giving up, "
5429e28e985SOleksandr Tymoshenko 			    "card status %08x (cs %d)\n",
5439e28e985SOleksandr Tymoshenko 			    __func__, cdst,
5449e28e985SOleksandr Tymoshenko 			    (cdst & 0x0e00) >> 9);
5459e28e985SOleksandr Tymoshenko 			return (1);
5469e28e985SOleksandr Tymoshenko 			break;
5479e28e985SOleksandr Tymoshenko 		}
5489e28e985SOleksandr Tymoshenko 	} while (((cdst & 0x0e00) >> 9) != 4);
5499e28e985SOleksandr Tymoshenko 
5509e28e985SOleksandr Tymoshenko 	return (0);
5519e28e985SOleksandr Tymoshenko }
5529e28e985SOleksandr Tymoshenko 
5539e28e985SOleksandr Tymoshenko static void
bcm_sdhost_intr(void * arg)5549e28e985SOleksandr Tymoshenko bcm_sdhost_intr(void *arg)
5559e28e985SOleksandr Tymoshenko {
5569e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = arg;
5579e28e985SOleksandr Tymoshenko 	struct sdhci_slot *slot = &sc->sc_slot;
5589e28e985SOleksandr Tymoshenko 	uint32_t hstst;
5599e28e985SOleksandr Tymoshenko 	uint32_t cmd;
5609e28e985SOleksandr Tymoshenko 
5619e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
5629e28e985SOleksandr Tymoshenko 
5639e28e985SOleksandr Tymoshenko 	hstst = RD4(sc, HC_HOSTSTATUS);
5649e28e985SOleksandr Tymoshenko 	cmd = RD4(sc, HC_COMMAND);
5659e28e985SOleksandr Tymoshenko 	if (hstst & HC_HSTST_HAVEDATA) {
5669e28e985SOleksandr Tymoshenko 		if (cmd & HC_CMD_READ) {
5679e28e985SOleksandr Tymoshenko 			sc->sdhci_present_state |= SDHCI_DATA_AVAILABLE;
5689e28e985SOleksandr Tymoshenko 			sc->sdhci_int_status |= SDHCI_INT_DATA_AVAIL;
5699e28e985SOleksandr Tymoshenko 		} else if (cmd & HC_CMD_WRITE) {
5709e28e985SOleksandr Tymoshenko 			sc->sdhci_present_state |= SDHCI_SPACE_AVAILABLE;
5719e28e985SOleksandr Tymoshenko 			sc->sdhci_int_status |= SDHCI_INT_SPACE_AVAIL;
5729e28e985SOleksandr Tymoshenko 		} else {
5739e28e985SOleksandr Tymoshenko 			panic("%s: hstst & HC_HSTST_HAVEDATA but no "
5749e28e985SOleksandr Tymoshenko 			    "HC_CMD_READ or HC_CMD_WRITE: cmd=%0x8 "
5759e28e985SOleksandr Tymoshenko 			    "hstst=%08x\n", __func__, cmd, hstst);
5769e28e985SOleksandr Tymoshenko 		}
5779e28e985SOleksandr Tymoshenko 	} else {
5789e28e985SOleksandr Tymoshenko 		sc->sdhci_present_state &=
5799e28e985SOleksandr Tymoshenko 		    ~(SDHCI_DATA_AVAILABLE|SDHCI_SPACE_AVAILABLE);
5809e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status &=
5819e28e985SOleksandr Tymoshenko 		    ~(SDHCI_INT_DATA_AVAIL|SDHCI_INT_SPACE_AVAIL);
5829e28e985SOleksandr Tymoshenko 	}
5839e28e985SOleksandr Tymoshenko 
5849e28e985SOleksandr Tymoshenko 	if (hstst & HC_HSTST_MASK_ERROR_ALL) {
5859e28e985SOleksandr Tymoshenko 		printf("%s: ERROR: HC_HOSTSTATUS: %08x\n", __func__, hstst);
5869e28e985SOleksandr Tymoshenko 		bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 1);
5879e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status |= SDHCI_INT_ERROR;
5889e28e985SOleksandr Tymoshenko 	} else {
5899e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status &= ~SDHCI_INT_ERROR;
5909e28e985SOleksandr Tymoshenko 	}
5919e28e985SOleksandr Tymoshenko 
5929e28e985SOleksandr Tymoshenko 	dprintf("%s: hstst=%08x offset=%08lx sdhci_present_state=%08x "
5939e28e985SOleksandr Tymoshenko 	    "sdhci_int_status=%08x\n", __func__, hstst, slot->offset,
5949e28e985SOleksandr Tymoshenko 	    sc->sdhci_present_state, sc->sdhci_int_status);
5959e28e985SOleksandr Tymoshenko 
5969e28e985SOleksandr Tymoshenko 	sdhci_generic_intr(&sc->sc_slot);
5979e28e985SOleksandr Tymoshenko 
5989e28e985SOleksandr Tymoshenko 	sc->sdhci_int_status &=
5999e28e985SOleksandr Tymoshenko 	    ~(SDHCI_INT_ERROR|SDHCI_INT_DATA_AVAIL|SDHCI_INT_DATA_END);
6009e28e985SOleksandr Tymoshenko 	sc->sdhci_present_state &= ~SDHCI_DATA_AVAILABLE;
6019e28e985SOleksandr Tymoshenko 
6029e28e985SOleksandr Tymoshenko 	if ((hstst & HC_HSTST_HAVEDATA) &&
6039e28e985SOleksandr Tymoshenko 	    (sc->sdhci_blocksize * sc->sdhci_blockcount == slot->offset)) {
6049e28e985SOleksandr Tymoshenko 		dprintf("%s: offset=%08lx sdhci_blocksize=%08x "
6059e28e985SOleksandr Tymoshenko 		    "sdhci_blockcount=%08x\n", __func__, slot->offset,
6069e28e985SOleksandr Tymoshenko 		    sc->sdhci_blocksize, sc->sdhci_blockcount);
6079e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status &=
6089e28e985SOleksandr Tymoshenko 		    ~(SDHCI_INT_DATA_AVAIL|SDHCI_INT_SPACE_AVAIL);
6099e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status |= SDHCI_INT_DATA_END;
6109e28e985SOleksandr Tymoshenko 		sdhci_generic_intr(&sc->sc_slot);
6119e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status &= ~SDHCI_INT_DATA_END;
6129e28e985SOleksandr Tymoshenko 
6139e28e985SOleksandr Tymoshenko 		if ((cmd & HC_CMD_COMMAND_MASK) == MMC_READ_MULTIPLE_BLOCK ||
6149e28e985SOleksandr Tymoshenko 		    (cmd & HC_CMD_COMMAND_MASK) == MMC_WRITE_MULTIPLE_BLOCK) {
6159e28e985SOleksandr Tymoshenko 			WR4(sc, HC_ARGUMENT, 0x00000000);
6169e28e985SOleksandr Tymoshenko 			WR4(sc, HC_COMMAND,
6179e28e985SOleksandr Tymoshenko 			    MMC_STOP_TRANSMISSION | HC_CMD_ENABLE);
6189e28e985SOleksandr Tymoshenko 
6199e28e985SOleksandr Tymoshenko 			if (bcm_sdhost_waitcommand(sc)) {
6209e28e985SOleksandr Tymoshenko 				printf("%s: timeout #1\n", __func__);
6219e28e985SOleksandr Tymoshenko 				bcm_sdhost_print_regs(sc, &sc->sc_slot,
6229e28e985SOleksandr Tymoshenko 				    __LINE__, 1);
6239e28e985SOleksandr Tymoshenko 			}
6249e28e985SOleksandr Tymoshenko 		}
6259e28e985SOleksandr Tymoshenko 
6269e28e985SOleksandr Tymoshenko 		if (cmd & HC_CMD_WRITE) {
6279e28e985SOleksandr Tymoshenko 			if (bcm_sdhost_waitcommand_status(sc) != 0)
6289e28e985SOleksandr Tymoshenko 				sc->sdhci_int_status |= SDHCI_INT_ERROR;
6299e28e985SOleksandr Tymoshenko 		}
6309e28e985SOleksandr Tymoshenko 
6319e28e985SOleksandr Tymoshenko 		slot->data_done = 1;
6329e28e985SOleksandr Tymoshenko 
6339e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status |= SDHCI_INT_RESPONSE;
6349e28e985SOleksandr Tymoshenko 		sdhci_generic_intr(&sc->sc_slot);
6359e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status &= ~(SDHCI_INT_RESPONSE|SDHCI_INT_ERROR);
6369e28e985SOleksandr Tymoshenko 	}
6379e28e985SOleksandr Tymoshenko 
6389e28e985SOleksandr Tymoshenko 	/* this resets the interrupt */
6399e28e985SOleksandr Tymoshenko 	WR4(sc, HC_HOSTSTATUS,
6409e28e985SOleksandr Tymoshenko 	    (HC_HSTST_INT_BUSY|HC_HSTST_INT_BLOCK|HC_HSTST_HAVEDATA));
6419e28e985SOleksandr Tymoshenko 
6429e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
6439e28e985SOleksandr Tymoshenko }
6449e28e985SOleksandr Tymoshenko 
6459e28e985SOleksandr Tymoshenko static int
bcm_sdhost_get_ro(device_t bus,device_t child)6469e28e985SOleksandr Tymoshenko bcm_sdhost_get_ro(device_t bus, device_t child)
6479e28e985SOleksandr Tymoshenko {
6489e28e985SOleksandr Tymoshenko 
6499e28e985SOleksandr Tymoshenko 	dprintf("%s:\n", __func__);
6509e28e985SOleksandr Tymoshenko 
6519e28e985SOleksandr Tymoshenko 	return (0);
6529e28e985SOleksandr Tymoshenko }
6539e28e985SOleksandr Tymoshenko 
6549e28e985SOleksandr Tymoshenko static bool
bcm_sdhost_get_card_present(device_t dev,struct sdhci_slot * slot)6559e28e985SOleksandr Tymoshenko bcm_sdhost_get_card_present(device_t dev, struct sdhci_slot *slot)
6569e28e985SOleksandr Tymoshenko {
6579e28e985SOleksandr Tymoshenko 
6589e28e985SOleksandr Tymoshenko 	dprintf("%s:\n", __func__);
6599e28e985SOleksandr Tymoshenko 
6609e28e985SOleksandr Tymoshenko 	return (1);
6619e28e985SOleksandr Tymoshenko }
6629e28e985SOleksandr Tymoshenko 
6639e28e985SOleksandr Tymoshenko static void
bcm_sdhost_command(device_t dev,struct sdhci_slot * slot,uint16_t val)6649e28e985SOleksandr Tymoshenko bcm_sdhost_command(device_t dev, struct sdhci_slot *slot, uint16_t val)
6659e28e985SOleksandr Tymoshenko {
6669e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
6679e28e985SOleksandr Tymoshenko 	struct mmc_data *data = slot->curcmd->data;
6689e28e985SOleksandr Tymoshenko 	uint16_t val2;
6699e28e985SOleksandr Tymoshenko 	uint8_t opcode;
6709e28e985SOleksandr Tymoshenko 	uint8_t flags;
6719e28e985SOleksandr Tymoshenko 
6729e28e985SOleksandr Tymoshenko 	mtx_assert(&sc->mtx, MA_OWNED);
6739e28e985SOleksandr Tymoshenko 
6749e28e985SOleksandr Tymoshenko 	if (RD4(sc, HC_COMMAND) & HC_CMD_ENABLE) {
6759e28e985SOleksandr Tymoshenko 		panic("%s: HC_CMD_ENABLE on entry\n", __func__);
6769e28e985SOleksandr Tymoshenko 	}
6779e28e985SOleksandr Tymoshenko 
6789e28e985SOleksandr Tymoshenko 	if (sc->cmdbusy == 1)
6799e28e985SOleksandr Tymoshenko 		panic("%s: cmdbusy\n", __func__);
6809e28e985SOleksandr Tymoshenko 
6819e28e985SOleksandr Tymoshenko 	sc->cmdbusy = 1;
6829e28e985SOleksandr Tymoshenko 
6839e28e985SOleksandr Tymoshenko 	val2 = ((val >> 8) & HC_CMD_COMMAND_MASK) | HC_CMD_ENABLE;
6849e28e985SOleksandr Tymoshenko 
6859e28e985SOleksandr Tymoshenko 	opcode = val >> 8;
6869e28e985SOleksandr Tymoshenko 	flags = val & 0xff;
6879e28e985SOleksandr Tymoshenko 
6889e28e985SOleksandr Tymoshenko 	if (opcode == MMC_APP_CMD)
6899e28e985SOleksandr Tymoshenko 		sc->mmc_app_cmd = 1;
6909e28e985SOleksandr Tymoshenko 
6919e28e985SOleksandr Tymoshenko 	if ((flags & SDHCI_CMD_RESP_MASK) == SDHCI_CMD_RESP_LONG)
6929e28e985SOleksandr Tymoshenko 		val2 |= HC_CMD_RESPONSE_LONG;
6939e28e985SOleksandr Tymoshenko 	else if ((flags & SDHCI_CMD_RESP_MASK) == SDHCI_CMD_RESP_SHORT_BUSY)
6949e28e985SOleksandr Tymoshenko 		/* XXX XXX when enabled, cmd 7 (select card) blocks forever */
6959e28e985SOleksandr Tymoshenko 		;/*val2 |= HC_CMD_BUSY; */
6969e28e985SOleksandr Tymoshenko 	else if ((flags & SDHCI_CMD_RESP_MASK) == SDHCI_CMD_RESP_SHORT)
6979e28e985SOleksandr Tymoshenko 		;
6989e28e985SOleksandr Tymoshenko 	else
6999e28e985SOleksandr Tymoshenko 		val2 |= HC_CMD_RESPONSE_NONE;
7009e28e985SOleksandr Tymoshenko 
7019e28e985SOleksandr Tymoshenko 	if (val2 & HC_CMD_BUSY)
7029e28e985SOleksandr Tymoshenko 		sc->sdhci_present_state |=
7039e28e985SOleksandr Tymoshenko 		    SDHCI_CMD_INHIBIT | SDHCI_DAT_INHIBIT;
7049e28e985SOleksandr Tymoshenko 
7059e28e985SOleksandr Tymoshenko 	if (data != NULL && data->flags & MMC_DATA_READ)
7069e28e985SOleksandr Tymoshenko 		val2 |= HC_CMD_READ;
7079e28e985SOleksandr Tymoshenko 	else if (data != NULL && data->flags & MMC_DATA_WRITE)
7089e28e985SOleksandr Tymoshenko 		val2 |= HC_CMD_WRITE;
7099e28e985SOleksandr Tymoshenko 
7109e28e985SOleksandr Tymoshenko 	dprintf("%s: SDHCI_COMMAND_FLAGS --> HC_COMMAND   %04x --> %04x\n",
7119e28e985SOleksandr Tymoshenko 	    __func__, val, val2);
7129e28e985SOleksandr Tymoshenko 
7139e28e985SOleksandr Tymoshenko 	if (opcode == MMC_READ_MULTIPLE_BLOCK ||
7149e28e985SOleksandr Tymoshenko 	    opcode == MMC_WRITE_MULTIPLE_BLOCK) {
7159e28e985SOleksandr Tymoshenko 		u_int32_t save_sdarg;
7169e28e985SOleksandr Tymoshenko 
7179e28e985SOleksandr Tymoshenko 		dprintf("%s: issuing MMC_SET_BLOCK_COUNT: CMD %08x ARG %08x\n",
7189e28e985SOleksandr Tymoshenko 		    __func__, MMC_SET_BLOCK_COUNT | HC_CMD_ENABLE,
7199e28e985SOleksandr Tymoshenko 		    sc->sdhci_blockcount);
7209e28e985SOleksandr Tymoshenko 
7219e28e985SOleksandr Tymoshenko 		save_sdarg = RD4(sc, HC_ARGUMENT);
7229e28e985SOleksandr Tymoshenko 		WR4(sc, HC_ARGUMENT, sc->sdhci_blockcount);
7239e28e985SOleksandr Tymoshenko 		WR4(sc, HC_COMMAND, MMC_SET_BLOCK_COUNT | HC_CMD_ENABLE);
7249e28e985SOleksandr Tymoshenko 
7259e28e985SOleksandr Tymoshenko 		/* Seems to always return timeout */
7269e28e985SOleksandr Tymoshenko 
7279e28e985SOleksandr Tymoshenko 		if (bcm_sdhost_waitcommand(sc)) {
7289e28e985SOleksandr Tymoshenko 			printf("%s: timeout #2\n", __func__);
7299e28e985SOleksandr Tymoshenko 			bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 1);
7309e28e985SOleksandr Tymoshenko 		} else {
7319e28e985SOleksandr Tymoshenko 			bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 0);
7329e28e985SOleksandr Tymoshenko 		}
7339e28e985SOleksandr Tymoshenko 		WR4(sc, HC_ARGUMENT, save_sdarg);
7349e28e985SOleksandr Tymoshenko 
7359e28e985SOleksandr Tymoshenko 	} else if (opcode == MMC_SELECT_CARD) {
7369e28e985SOleksandr Tymoshenko 		sc->sdcard_rca = (RD4(sc, HC_ARGUMENT) >> 16);
7379e28e985SOleksandr Tymoshenko 	}
7389e28e985SOleksandr Tymoshenko 
7399e28e985SOleksandr Tymoshenko 	/* actually issuing the command */
7409e28e985SOleksandr Tymoshenko 	WR4(sc, HC_COMMAND, val2);
7419e28e985SOleksandr Tymoshenko 
7429e28e985SOleksandr Tymoshenko 	if (val2 & HC_CMD_READ || val2 & HC_CMD_WRITE) {
7439e28e985SOleksandr Tymoshenko 		u_int8_t hstcfg;
7449e28e985SOleksandr Tymoshenko 
7459e28e985SOleksandr Tymoshenko 		hstcfg = RD4(sc, HC_HOSTCONFIG);
7469e28e985SOleksandr Tymoshenko 		hstcfg |= (HC_HSTCF_INT_BUSY | HC_HSTCF_INT_DATA);
7479e28e985SOleksandr Tymoshenko 		WR4(sc, HC_HOSTCONFIG, hstcfg);
7489e28e985SOleksandr Tymoshenko 		slot->data_done = 0;
7499e28e985SOleksandr Tymoshenko 
7509e28e985SOleksandr Tymoshenko 		if (bcm_sdhost_waitcommand(sc)) {
7519e28e985SOleksandr Tymoshenko 			printf("%s: timeout #3\n", __func__);
7529e28e985SOleksandr Tymoshenko 			bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 1);
7539e28e985SOleksandr Tymoshenko 		}
7549e28e985SOleksandr Tymoshenko 
7559e28e985SOleksandr Tymoshenko 	} else if (opcode == MMC_ERASE) {
7569e28e985SOleksandr Tymoshenko 		if (bcm_sdhost_waitcommand_status(sc) != 0) {
7579e28e985SOleksandr Tymoshenko 			printf("%s: timeout #4\n", __func__);
7589e28e985SOleksandr Tymoshenko 			bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 1);
7599e28e985SOleksandr Tymoshenko 		}
7609e28e985SOleksandr Tymoshenko 		slot->data_done = 1;
7619e28e985SOleksandr Tymoshenko 		sc->sdhci_present_state &=
7629e28e985SOleksandr Tymoshenko 		    ~(SDHCI_CMD_INHIBIT | SDHCI_DAT_INHIBIT);
7639e28e985SOleksandr Tymoshenko 
7649e28e985SOleksandr Tymoshenko 	} else {
7659e28e985SOleksandr Tymoshenko 		if (bcm_sdhost_waitcommand(sc)) {
7669e28e985SOleksandr Tymoshenko 			printf("%s: timeout #5\n", __func__);
7679e28e985SOleksandr Tymoshenko 			bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 1);
7689e28e985SOleksandr Tymoshenko 		}
7699e28e985SOleksandr Tymoshenko 		slot->data_done = 1;
7709e28e985SOleksandr Tymoshenko 		sc->sdhci_present_state &=
7719e28e985SOleksandr Tymoshenko 		    ~(SDHCI_CMD_INHIBIT | SDHCI_DAT_INHIBIT);
7729e28e985SOleksandr Tymoshenko 	}
7739e28e985SOleksandr Tymoshenko 
7749e28e985SOleksandr Tymoshenko 	bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 0);
7759e28e985SOleksandr Tymoshenko 
7769e28e985SOleksandr Tymoshenko 	if (RD4(sc, HC_HOSTSTATUS) & HC_HSTST_TIMEOUT_CMD)
7779e28e985SOleksandr Tymoshenko 		slot->curcmd->error = MMC_ERR_TIMEOUT;
7789e28e985SOleksandr Tymoshenko 	else if (RD4(sc, HC_COMMAND) & HC_CMD_FAILED)
7799e28e985SOleksandr Tymoshenko 		slot->curcmd->error = MMC_ERR_FAILED;
7809e28e985SOleksandr Tymoshenko 
7819e28e985SOleksandr Tymoshenko 	dprintf("%s: curcmd->flags=%d data_done=%d\n",
7829e28e985SOleksandr Tymoshenko 	    __func__, slot->curcmd->flags, slot->data_done);
7839e28e985SOleksandr Tymoshenko 
7849e28e985SOleksandr Tymoshenko 	if (val2 & HC_CMD_RESPONSE_NONE)
7859e28e985SOleksandr Tymoshenko 		slot->curcmd->error = 0;
7869e28e985SOleksandr Tymoshenko 
7879e28e985SOleksandr Tymoshenko 	if (sc->mmc_app_cmd == 1 && opcode != MMC_APP_CMD)
7889e28e985SOleksandr Tymoshenko 		sc->mmc_app_cmd = 0;
7899e28e985SOleksandr Tymoshenko 
7909e28e985SOleksandr Tymoshenko 	if (RD4(sc, HC_COMMAND) & HC_CMD_ENABLE) {
7919e28e985SOleksandr Tymoshenko 		bcm_sdhost_print_regs(sc, &sc->sc_slot, __LINE__, 1);
7929e28e985SOleksandr Tymoshenko 		panic("%s: still HC_CMD_ENABLE on exit\n", __func__);
7939e28e985SOleksandr Tymoshenko 	}
7949e28e985SOleksandr Tymoshenko 
7959e28e985SOleksandr Tymoshenko 	sc->cmdbusy = 0;
7969e28e985SOleksandr Tymoshenko 
7979e28e985SOleksandr Tymoshenko 	if (!(val2 & HC_CMD_READ || val2 & HC_CMD_WRITE))
7989e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status |= SDHCI_INT_RESPONSE;
7999e28e985SOleksandr Tymoshenko 
8009e28e985SOleksandr Tymoshenko 	/* HACK, so sdhci_finish_command() does not
8019e28e985SOleksandr Tymoshenko 	 * have to be exported
8029e28e985SOleksandr Tymoshenko 	 */
8039e28e985SOleksandr Tymoshenko 	mtx_unlock(&slot->mtx);
8049e28e985SOleksandr Tymoshenko 	sdhci_generic_intr(slot);
8059e28e985SOleksandr Tymoshenko 	mtx_lock(&slot->mtx);
8069e28e985SOleksandr Tymoshenko 	sc->sdhci_int_status &= ~SDHCI_INT_RESPONSE;
8079e28e985SOleksandr Tymoshenko }
8089e28e985SOleksandr Tymoshenko 
8099e28e985SOleksandr Tymoshenko static uint8_t
bcm_sdhost_read_1(device_t dev,struct sdhci_slot * slot,bus_size_t off)8109e28e985SOleksandr Tymoshenko bcm_sdhost_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
8119e28e985SOleksandr Tymoshenko {
8129e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
8139e28e985SOleksandr Tymoshenko 	uint32_t val1, val2;
8149e28e985SOleksandr Tymoshenko 
8159e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
8169e28e985SOleksandr Tymoshenko 
8179e28e985SOleksandr Tymoshenko 	switch (off) {
8189e28e985SOleksandr Tymoshenko 	case SDHCI_HOST_CONTROL:
8199e28e985SOleksandr Tymoshenko 		val1 = RD4(sc, HC_HOSTCONFIG);
8209e28e985SOleksandr Tymoshenko 		val2 = 0;
8219e28e985SOleksandr Tymoshenko 		if (val1 & HC_HSTCF_EXTBUS_4BIT)
8229e28e985SOleksandr Tymoshenko 			val2 |= SDHCI_CTRL_4BITBUS;
8239e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_HOST_CONTROL --> HC_HOSTCONFIG val2 %02x\n",
8249e28e985SOleksandr Tymoshenko 		    __func__, val2);
8259e28e985SOleksandr Tymoshenko 		break;
8269e28e985SOleksandr Tymoshenko 	case SDHCI_POWER_CONTROL:
8279e28e985SOleksandr Tymoshenko 		val1 = RD1(sc, HC_POWER);
8289e28e985SOleksandr Tymoshenko 		val2 = (val1 == 1) ? 0x0f : 0;
8299e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_POWER_CONTROL --> HC_POWER     val2 %02x\n",
8309e28e985SOleksandr Tymoshenko 		    __func__, val2);
8319e28e985SOleksandr Tymoshenko 		break;
8329e28e985SOleksandr Tymoshenko 	case SDHCI_BLOCK_GAP_CONTROL:
8339e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BLOCK_GAP_CONTROL\n", __func__);
8349e28e985SOleksandr Tymoshenko 		val2 = 0;
8359e28e985SOleksandr Tymoshenko 		break;
8369e28e985SOleksandr Tymoshenko 	case SDHCI_WAKE_UP_CONTROL:
8379e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_WAKE_UP_CONTROL\n", __func__);
8389e28e985SOleksandr Tymoshenko 		val2 = 0;
8399e28e985SOleksandr Tymoshenko 		break;
8409e28e985SOleksandr Tymoshenko 	case SDHCI_TIMEOUT_CONTROL:
8419e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_TIMEOUT_CONTROL\n", __func__);
8429e28e985SOleksandr Tymoshenko 		val2 = 0;
8439e28e985SOleksandr Tymoshenko 		break;
8449e28e985SOleksandr Tymoshenko 	case SDHCI_SOFTWARE_RESET:
8459e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_SOFTWARE_RESET\n", __func__);
8469e28e985SOleksandr Tymoshenko 		val2 = 0;
8479e28e985SOleksandr Tymoshenko 		break;
8489e28e985SOleksandr Tymoshenko 	case SDHCI_ADMA_ERR:
8499e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ADMA_ERR\n", __func__);
8509e28e985SOleksandr Tymoshenko 		val2 = 0;
8519e28e985SOleksandr Tymoshenko 		break;
8529e28e985SOleksandr Tymoshenko 	default:
8539e28e985SOleksandr Tymoshenko 		dprintf("%s: UNKNOWN off=%08lx\n", __func__, off);
8549e28e985SOleksandr Tymoshenko 		val2 = 0;
8559e28e985SOleksandr Tymoshenko 		break;
8569e28e985SOleksandr Tymoshenko 	}
8579e28e985SOleksandr Tymoshenko 
8589e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
8599e28e985SOleksandr Tymoshenko 
8609e28e985SOleksandr Tymoshenko 	return (val2);
8619e28e985SOleksandr Tymoshenko }
8629e28e985SOleksandr Tymoshenko 
8639e28e985SOleksandr Tymoshenko static uint16_t
bcm_sdhost_read_2(device_t dev,struct sdhci_slot * slot,bus_size_t off)8649e28e985SOleksandr Tymoshenko bcm_sdhost_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
8659e28e985SOleksandr Tymoshenko {
8669e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
8679e28e985SOleksandr Tymoshenko 	uint32_t val2, val; /* = RD4(sc, off & ~3); */
8689e28e985SOleksandr Tymoshenko 
8699e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
8709e28e985SOleksandr Tymoshenko 
8719e28e985SOleksandr Tymoshenko 	switch (off) {
8729e28e985SOleksandr Tymoshenko 	case SDHCI_BLOCK_SIZE:
8739e28e985SOleksandr Tymoshenko 		val2 = sc->sdhci_blocksize;
8749e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BLOCK_SIZE      --> HC_BLOCKSIZE   %08x\n",
8759e28e985SOleksandr Tymoshenko 		    __func__, val2);
8769e28e985SOleksandr Tymoshenko 		break;
8779e28e985SOleksandr Tymoshenko 	case SDHCI_BLOCK_COUNT:
8789e28e985SOleksandr Tymoshenko 		val2 = sc->sdhci_blockcount;
8799e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BLOCK_COUNT     --> HC_BLOCKCOUNT  %08x\n",
8809e28e985SOleksandr Tymoshenko 		    __func__, val2);
8819e28e985SOleksandr Tymoshenko 		break;
8829e28e985SOleksandr Tymoshenko 	case SDHCI_TRANSFER_MODE:
8839e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_TRANSFER_MODE\n", __func__);
8849e28e985SOleksandr Tymoshenko 		val2 = 0;
8859e28e985SOleksandr Tymoshenko 		break;
8869e28e985SOleksandr Tymoshenko 	case SDHCI_CLOCK_CONTROL:
8879e28e985SOleksandr Tymoshenko 		val = RD4(sc, HC_CLOCKDIVISOR);
8889e28e985SOleksandr Tymoshenko 		val2 = (val << SDHCI_DIVIDER_SHIFT) |
8899e28e985SOleksandr Tymoshenko 		    SDHCI_CLOCK_CARD_EN | SDHCI_CLOCK_INT_EN |
8909e28e985SOleksandr Tymoshenko 		    SDHCI_CLOCK_INT_STABLE;
8919e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_CLOCK_CONTROL     %04x --> %04x\n",
8929e28e985SOleksandr Tymoshenko 		    __func__, val, val2);
8939e28e985SOleksandr Tymoshenko 		break;
8949e28e985SOleksandr Tymoshenko 	case SDHCI_ACMD12_ERR:
8959e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ACMD12_ERR\n", __func__);
8969e28e985SOleksandr Tymoshenko 		val2 = 0;
8979e28e985SOleksandr Tymoshenko 		break;
8989e28e985SOleksandr Tymoshenko 	case SDHCI_HOST_CONTROL2:
8999e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_HOST_CONTROL2\n", __func__);
9009e28e985SOleksandr Tymoshenko 		val2 = 0;
9019e28e985SOleksandr Tymoshenko 		break;
9029e28e985SOleksandr Tymoshenko 	case SDHCI_SLOT_INT_STATUS:
9039e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_SLOT_INT_STATUS\n", __func__);
9049e28e985SOleksandr Tymoshenko 		val2 = 0;
9059e28e985SOleksandr Tymoshenko 		break;
9069e28e985SOleksandr Tymoshenko 	case SDHCI_HOST_VERSION:
9079e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_HOST_VERSION\n", __func__);
9089e28e985SOleksandr Tymoshenko 		val2 = 0;
9099e28e985SOleksandr Tymoshenko 		break;
9109e28e985SOleksandr Tymoshenko 	default:
9119e28e985SOleksandr Tymoshenko 		dprintf("%s: UNKNOWN off=%08lx\n", __func__, off);
9129e28e985SOleksandr Tymoshenko 		val2 = 0;
9139e28e985SOleksandr Tymoshenko 		break;
9149e28e985SOleksandr Tymoshenko 	}
9159e28e985SOleksandr Tymoshenko 
9169e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
9179e28e985SOleksandr Tymoshenko 
9189e28e985SOleksandr Tymoshenko 	return (val2);
9199e28e985SOleksandr Tymoshenko }
9209e28e985SOleksandr Tymoshenko 
9219e28e985SOleksandr Tymoshenko static uint32_t
bcm_sdhost_read_4(device_t dev,struct sdhci_slot * slot,bus_size_t off)9229e28e985SOleksandr Tymoshenko bcm_sdhost_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
9239e28e985SOleksandr Tymoshenko {
9249e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
9259e28e985SOleksandr Tymoshenko 	uint32_t val2;
9269e28e985SOleksandr Tymoshenko 
9279e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
9289e28e985SOleksandr Tymoshenko 
9299e28e985SOleksandr Tymoshenko 	switch (off) {
9309e28e985SOleksandr Tymoshenko 	case SDHCI_DMA_ADDRESS:
9319e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_DMA_ADDRESS\n", __func__);
9329e28e985SOleksandr Tymoshenko 		val2 = 0;
9339e28e985SOleksandr Tymoshenko 		break;
9349e28e985SOleksandr Tymoshenko 	case SDHCI_ARGUMENT:
9359e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ARGUMENT\n", __func__);
9369e28e985SOleksandr Tymoshenko 		val2 = (RD4(sc, HC_COMMAND) << 16) |
9379e28e985SOleksandr Tymoshenko 		    (RD4(sc, HC_ARGUMENT) & 0x0000ffff);
9389e28e985SOleksandr Tymoshenko 		break;
9399e28e985SOleksandr Tymoshenko 	case SDHCI_RESPONSE + 0:
9409e28e985SOleksandr Tymoshenko 		val2 = RD4(sc, HC_RESPONSE_0);
9419e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_RESPONSE+0       %08x\n", __func__, val2);
9429e28e985SOleksandr Tymoshenko 		break;
9439e28e985SOleksandr Tymoshenko 	case SDHCI_RESPONSE + 4:
9449e28e985SOleksandr Tymoshenko 		val2 = RD4(sc, HC_RESPONSE_1);
9459e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_RESPONSE+4       %08x\n", __func__, val2);
9469e28e985SOleksandr Tymoshenko 		break;
9479e28e985SOleksandr Tymoshenko 	case SDHCI_RESPONSE + 8:
9489e28e985SOleksandr Tymoshenko 		val2 = RD4(sc, HC_RESPONSE_2);
9499e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_RESPONSE+8       %08x\n", __func__, val2);
9509e28e985SOleksandr Tymoshenko 		break;
9519e28e985SOleksandr Tymoshenko 	case SDHCI_RESPONSE + 12:
9529e28e985SOleksandr Tymoshenko 		val2 = RD4(sc, HC_RESPONSE_3);
9539e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_RESPONSE+12      %08x\n", __func__, val2);
9549e28e985SOleksandr Tymoshenko 		break;
9559e28e985SOleksandr Tymoshenko 	case SDHCI_BUFFER:
9569e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BUFFER\n", __func__);
9579e28e985SOleksandr Tymoshenko 		val2 = 0;
9589e28e985SOleksandr Tymoshenko 		break;
9599e28e985SOleksandr Tymoshenko 	case SDHCI_PRESENT_STATE:
9609e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_PRESENT_STATE      %08x\n",
9619e28e985SOleksandr Tymoshenko 		    __func__, sc->sdhci_present_state);
9629e28e985SOleksandr Tymoshenko 		val2 = sc->sdhci_present_state;
9639e28e985SOleksandr Tymoshenko 		break;
9649e28e985SOleksandr Tymoshenko 	case SDHCI_INT_STATUS:
9659e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_INT_STATUS        %08x\n",
9669e28e985SOleksandr Tymoshenko 		    __func__, sc->sdhci_int_status);
9679e28e985SOleksandr Tymoshenko 		val2 = sc->sdhci_int_status;
9689e28e985SOleksandr Tymoshenko 		break;
9699e28e985SOleksandr Tymoshenko 	case SDHCI_INT_ENABLE:
9709e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_INT_ENABLE\n", __func__);
9719e28e985SOleksandr Tymoshenko 		val2 = 0;
9729e28e985SOleksandr Tymoshenko 		break;
9739e28e985SOleksandr Tymoshenko 	case SDHCI_SIGNAL_ENABLE:
9749e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_SIGNAL_ENABLE      %08x\n",
9759e28e985SOleksandr Tymoshenko 		    __func__, sc->sdhci_signal_enable);
9769e28e985SOleksandr Tymoshenko 		val2 = sc->sdhci_signal_enable;
9779e28e985SOleksandr Tymoshenko 		break;
9789e28e985SOleksandr Tymoshenko 	case SDHCI_CAPABILITIES:
9799e28e985SOleksandr Tymoshenko 		val2 = 0;
9809e28e985SOleksandr Tymoshenko 		break;
9819e28e985SOleksandr Tymoshenko 	case SDHCI_CAPABILITIES2:
9829e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_CAPABILITIES2\n", __func__);
9839e28e985SOleksandr Tymoshenko 		val2 = 0;
9849e28e985SOleksandr Tymoshenko 		break;
9859e28e985SOleksandr Tymoshenko 	case SDHCI_MAX_CURRENT:
9869e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_MAX_CURRENT\n", __func__);
9879e28e985SOleksandr Tymoshenko 		val2 = 0;
9889e28e985SOleksandr Tymoshenko 		break;
9899e28e985SOleksandr Tymoshenko 	case SDHCI_ADMA_ADDRESS_LO:
9909e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ADMA_ADDRESS_LO\n", __func__);
9919e28e985SOleksandr Tymoshenko 		val2 = 0;
9929e28e985SOleksandr Tymoshenko 		break;
9939e28e985SOleksandr Tymoshenko 	default:
9949e28e985SOleksandr Tymoshenko 		dprintf("%s: UNKNOWN off=%08lx\n", __func__, off);
9959e28e985SOleksandr Tymoshenko 		val2 = 0;
9969e28e985SOleksandr Tymoshenko 		break;
9979e28e985SOleksandr Tymoshenko 	}
9989e28e985SOleksandr Tymoshenko 
9999e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
10009e28e985SOleksandr Tymoshenko 
10019e28e985SOleksandr Tymoshenko 	return (val2);
10029e28e985SOleksandr Tymoshenko }
10039e28e985SOleksandr Tymoshenko 
10049e28e985SOleksandr Tymoshenko static void
bcm_sdhost_read_multi_4(device_t dev,struct sdhci_slot * slot,bus_size_t off,uint32_t * data,bus_size_t count)10059e28e985SOleksandr Tymoshenko bcm_sdhost_read_multi_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
10069e28e985SOleksandr Tymoshenko     uint32_t *data, bus_size_t count)
10079e28e985SOleksandr Tymoshenko {
10089e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
10099e28e985SOleksandr Tymoshenko 	bus_size_t i;
10109e28e985SOleksandr Tymoshenko 	bus_size_t avail;
10119e28e985SOleksandr Tymoshenko 	uint32_t edm;
10129e28e985SOleksandr Tymoshenko 
10139e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
10149e28e985SOleksandr Tymoshenko 
10159e28e985SOleksandr Tymoshenko 	dprintf("%s: off=%08lx count=%08lx\n", __func__, off, count);
10169e28e985SOleksandr Tymoshenko 
10179e28e985SOleksandr Tymoshenko 	for (i = 0; i < count;) {
10189e28e985SOleksandr Tymoshenko 		edm = RD4(sc, HC_DEBUG);
10199e28e985SOleksandr Tymoshenko 		avail = ((edm >> 4) & 0x1f);
1020e06262c1SOleksandr Tymoshenko 		if (i + avail > count)
10219e28e985SOleksandr Tymoshenko 			avail = count - i;
10229e28e985SOleksandr Tymoshenko 		if (avail > 0)
10239e28e985SOleksandr Tymoshenko 			bus_space_read_multi_4(sc->sc_bst, sc->sc_bsh,
10249e28e985SOleksandr Tymoshenko 			    HC_DATAPORT, data + i, avail);
10259e28e985SOleksandr Tymoshenko 		i += avail;
10269e28e985SOleksandr Tymoshenko 		DELAY(1);
10279e28e985SOleksandr Tymoshenko 	}
10289e28e985SOleksandr Tymoshenko 
10299e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
10309e28e985SOleksandr Tymoshenko }
10319e28e985SOleksandr Tymoshenko 
10329e28e985SOleksandr Tymoshenko static void
bcm_sdhost_write_1(device_t dev,struct sdhci_slot * slot,bus_size_t off,uint8_t val)10339e28e985SOleksandr Tymoshenko bcm_sdhost_write_1(device_t dev, struct sdhci_slot *slot,
10349e28e985SOleksandr Tymoshenko     bus_size_t off, uint8_t val)
10359e28e985SOleksandr Tymoshenko {
10369e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
10379e28e985SOleksandr Tymoshenko 	uint32_t val2;
10389e28e985SOleksandr Tymoshenko 
10399e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
10409e28e985SOleksandr Tymoshenko 
10419e28e985SOleksandr Tymoshenko 	switch (off) {
10429e28e985SOleksandr Tymoshenko 	case SDHCI_HOST_CONTROL:
10439e28e985SOleksandr Tymoshenko 		val2 = RD4(sc, HC_HOSTCONFIG);
10449e28e985SOleksandr Tymoshenko 		val2 |= HC_HSTCF_INT_BUSY;
10459e28e985SOleksandr Tymoshenko 		val2 |= HC_HSTCF_INTBUS_WIDE | HC_HSTCF_SLOW_CARD;
10469e28e985SOleksandr Tymoshenko 		if (val & SDHCI_CTRL_4BITBUS)
10479e28e985SOleksandr Tymoshenko 			val2 |= HC_HSTCF_EXTBUS_4BIT;
10489e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_HOST_CONTROL --> HC_HOSTC %04x --> %04x\n",
10499e28e985SOleksandr Tymoshenko 		    __func__, val, val2);
10509e28e985SOleksandr Tymoshenko 		WR4(sc, HC_HOSTCONFIG, val2);
10519e28e985SOleksandr Tymoshenko 		break;
10529e28e985SOleksandr Tymoshenko 	case SDHCI_POWER_CONTROL:
10539e28e985SOleksandr Tymoshenko 		val2 = (val != 0) ? 1 : 0;
10549e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_POWER_CONTROL --> HC_POWER %02x --> %02x\n",
10559e28e985SOleksandr Tymoshenko 		    __func__, val, val2);
10569e28e985SOleksandr Tymoshenko 		WR1(sc, HC_POWER, val2);
10579e28e985SOleksandr Tymoshenko 		break;
10589e28e985SOleksandr Tymoshenko 	case SDHCI_BLOCK_GAP_CONTROL:
10599e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BLOCK_GAP_CONTROL   val=%02x\n",
10609e28e985SOleksandr Tymoshenko 		    __func__, val);
10619e28e985SOleksandr Tymoshenko 		break;
10629e28e985SOleksandr Tymoshenko 	case SDHCI_TIMEOUT_CONTROL:
10639e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_TIMEOUT_CONTROL     val=%02x\n",
10649e28e985SOleksandr Tymoshenko 		    __func__, val);
10659e28e985SOleksandr Tymoshenko 		break;
10669e28e985SOleksandr Tymoshenko 	case SDHCI_SOFTWARE_RESET:
10679e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_SOFTWARE_RESET      val=%02x\n",
10689e28e985SOleksandr Tymoshenko 		    __func__, val);
10699e28e985SOleksandr Tymoshenko 		break;
10709e28e985SOleksandr Tymoshenko 	case SDHCI_ADMA_ERR:
10719e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ADMA_ERR            val=%02x\n",
10729e28e985SOleksandr Tymoshenko 		    __func__, val);
10739e28e985SOleksandr Tymoshenko 		break;
10749e28e985SOleksandr Tymoshenko 	default:
10759e28e985SOleksandr Tymoshenko 		dprintf("%s: UNKNOWN off=%08lx val=%08x\n",
10769e28e985SOleksandr Tymoshenko 		    __func__, off, val);
10779e28e985SOleksandr Tymoshenko 		break;
10789e28e985SOleksandr Tymoshenko 	}
10799e28e985SOleksandr Tymoshenko 
10809e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
10819e28e985SOleksandr Tymoshenko }
10829e28e985SOleksandr Tymoshenko 
10839e28e985SOleksandr Tymoshenko static void
bcm_sdhost_write_2(device_t dev,struct sdhci_slot * slot,bus_size_t off,uint16_t val)10849e28e985SOleksandr Tymoshenko bcm_sdhost_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint16_t val)
10859e28e985SOleksandr Tymoshenko {
10869e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
10879e28e985SOleksandr Tymoshenko 	uint16_t val2;
10889e28e985SOleksandr Tymoshenko 
10899e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
10909e28e985SOleksandr Tymoshenko 
10919e28e985SOleksandr Tymoshenko 	switch (off) {
10929e28e985SOleksandr Tymoshenko 	case SDHCI_BLOCK_SIZE:
10939e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BLOCK_SIZE          val=%04x\n" ,
10949e28e985SOleksandr Tymoshenko 		    __func__, val);
10959e28e985SOleksandr Tymoshenko 		sc->sdhci_blocksize = val;
10969e28e985SOleksandr Tymoshenko 		WR2(sc, HC_BLOCKSIZE, val);
10979e28e985SOleksandr Tymoshenko 		break;
10989e28e985SOleksandr Tymoshenko 
10999e28e985SOleksandr Tymoshenko 	case SDHCI_BLOCK_COUNT:
11009e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_BLOCK_COUNT         val=%04x\n" ,
11019e28e985SOleksandr Tymoshenko 		    __func__, val);
11029e28e985SOleksandr Tymoshenko 		sc->sdhci_blockcount = val;
11039e28e985SOleksandr Tymoshenko 		WR2(sc, HC_BLOCKCOUNT, val);
11049e28e985SOleksandr Tymoshenko 		break;
11059e28e985SOleksandr Tymoshenko 
11069e28e985SOleksandr Tymoshenko 	case SDHCI_TRANSFER_MODE:
11079e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_TRANSFER_MODE       val=%04x\n" ,
11089e28e985SOleksandr Tymoshenko 		    __func__, val);
11099e28e985SOleksandr Tymoshenko 		break;
11109e28e985SOleksandr Tymoshenko 
11119e28e985SOleksandr Tymoshenko 	case SDHCI_COMMAND_FLAGS:
11129e28e985SOleksandr Tymoshenko 		bcm_sdhost_command(dev, slot, val);
11139e28e985SOleksandr Tymoshenko 		break;
11149e28e985SOleksandr Tymoshenko 
11159e28e985SOleksandr Tymoshenko 	case SDHCI_CLOCK_CONTROL:
11169e28e985SOleksandr Tymoshenko 		val2 = (val & ~SDHCI_DIVIDER_MASK) >> SDHCI_DIVIDER_SHIFT;
11179e28e985SOleksandr Tymoshenko 		/* get crc16 errors with cdiv=0 */
11189e28e985SOleksandr Tymoshenko 		if (val2 == 0)
11199e28e985SOleksandr Tymoshenko 			val2 = 1;
11209e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_CLOCK_CONTROL       %04x --> SCDIV %04x\n",
11219e28e985SOleksandr Tymoshenko 		    __func__, val, val2);
11229e28e985SOleksandr Tymoshenko 		WR4(sc, HC_CLOCKDIVISOR, val2);
11239e28e985SOleksandr Tymoshenko 		break;
11249e28e985SOleksandr Tymoshenko 
11259e28e985SOleksandr Tymoshenko 	case SDHCI_ACMD12_ERR:
11269e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ACMD12_ERR          val=%04x\n" ,
11279e28e985SOleksandr Tymoshenko 		    __func__, val);
11289e28e985SOleksandr Tymoshenko 		break;
11299e28e985SOleksandr Tymoshenko 
11309e28e985SOleksandr Tymoshenko 	case SDHCI_HOST_CONTROL2:
11319e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_HOST_CONTROL2       val=%04x\n" ,
11329e28e985SOleksandr Tymoshenko 		    __func__, val);
11339e28e985SOleksandr Tymoshenko 		break;
11349e28e985SOleksandr Tymoshenko 
11359e28e985SOleksandr Tymoshenko 	case SDHCI_SLOT_INT_STATUS:
11369e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_SLOT_INT_STATUS     val=%04x\n" ,
11379e28e985SOleksandr Tymoshenko 		    __func__, val);
11389e28e985SOleksandr Tymoshenko 		break;
11399e28e985SOleksandr Tymoshenko 
11409e28e985SOleksandr Tymoshenko 	default:
11419e28e985SOleksandr Tymoshenko 		dprintf("%s: UNKNOWN off=%08lx val=%04x\n",
11429e28e985SOleksandr Tymoshenko 		    __func__, off, val);
11439e28e985SOleksandr Tymoshenko 		break;
11449e28e985SOleksandr Tymoshenko 	}
11459e28e985SOleksandr Tymoshenko 
11469e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
11479e28e985SOleksandr Tymoshenko }
11489e28e985SOleksandr Tymoshenko 
11499e28e985SOleksandr Tymoshenko static void
bcm_sdhost_write_4(device_t dev,struct sdhci_slot * slot,bus_size_t off,uint32_t val)11509e28e985SOleksandr Tymoshenko bcm_sdhost_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off, uint32_t val)
11519e28e985SOleksandr Tymoshenko {
11529e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
11539e28e985SOleksandr Tymoshenko 	uint32_t val2;
11549e28e985SOleksandr Tymoshenko 	uint32_t hstcfg;
11559e28e985SOleksandr Tymoshenko 
11569e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
11579e28e985SOleksandr Tymoshenko 
11589e28e985SOleksandr Tymoshenko 	switch (off) {
11599e28e985SOleksandr Tymoshenko 	case SDHCI_ARGUMENT:
11609e28e985SOleksandr Tymoshenko 		val2 = val;
11619e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ARGUMENT --> HC_ARGUMENT   val=%08x\n",
11629e28e985SOleksandr Tymoshenko 		    __func__, val);
11639e28e985SOleksandr Tymoshenko 		WR4(sc, HC_ARGUMENT, val2);
11649e28e985SOleksandr Tymoshenko 		break;
11659e28e985SOleksandr Tymoshenko 	case SDHCI_INT_STATUS:
11669e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_INT_STATUS           val=%08x\n",
11679e28e985SOleksandr Tymoshenko 		    __func__, val);
11689e28e985SOleksandr Tymoshenko 		sc->sdhci_int_status = val;
11699e28e985SOleksandr Tymoshenko 		break;
11709e28e985SOleksandr Tymoshenko 	case SDHCI_INT_ENABLE:
11719e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_INT_ENABLE          val=%08x\n" ,
11729e28e985SOleksandr Tymoshenko 		     __func__, val);
11739e28e985SOleksandr Tymoshenko 		break;
11749e28e985SOleksandr Tymoshenko 	case SDHCI_SIGNAL_ENABLE:
11759e28e985SOleksandr Tymoshenko 		sc->sdhci_signal_enable = val;
11769e28e985SOleksandr Tymoshenko 		hstcfg = RD4(sc, HC_HOSTCONFIG);
11779e28e985SOleksandr Tymoshenko 		if (val != 0)
11789e28e985SOleksandr Tymoshenko 			hstcfg &= ~(HC_HSTCF_INT_BLOCK | HC_HSTCF_INT_DATA);
11799e28e985SOleksandr Tymoshenko 		else
11809e28e985SOleksandr Tymoshenko 			hstcfg |= (HC_HSTCF_INT_BUSY|HC_HSTCF_INT_BLOCK|
11819e28e985SOleksandr Tymoshenko 			         HC_HSTCF_INT_DATA);
11829e28e985SOleksandr Tymoshenko 		hstcfg |= HC_HSTCF_INT_BUSY;
11839e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_SIGNAL_ENABLE --> HC_HOSTC %08x --> %08x\n" ,
11849e28e985SOleksandr Tymoshenko 		    __func__, val, hstcfg);
11859e28e985SOleksandr Tymoshenko 		WR4(sc, HC_HOSTCONFIG, hstcfg);
11869e28e985SOleksandr Tymoshenko 		break;
11879e28e985SOleksandr Tymoshenko 	case SDHCI_CAPABILITIES:
11889e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_CAPABILITIES        val=%08x\n",
11899e28e985SOleksandr Tymoshenko 		    __func__, val);
11909e28e985SOleksandr Tymoshenko 		break;
11919e28e985SOleksandr Tymoshenko 	case SDHCI_CAPABILITIES2:
11929e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_CAPABILITIES2       val=%08x\n",
11939e28e985SOleksandr Tymoshenko 		    __func__, val);
11949e28e985SOleksandr Tymoshenko 		break;
11959e28e985SOleksandr Tymoshenko 	case SDHCI_MAX_CURRENT:
11969e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_MAX_CURRENT         val=%08x\n",
11979e28e985SOleksandr Tymoshenko 		    __func__, val);
11989e28e985SOleksandr Tymoshenko 		break;
11999e28e985SOleksandr Tymoshenko 	case SDHCI_ADMA_ADDRESS_LO:
12009e28e985SOleksandr Tymoshenko 		dprintf("%s: SDHCI_ADMA_ADDRESS_LO     val=%08x\n",
12019e28e985SOleksandr Tymoshenko 		    __func__, val);
12029e28e985SOleksandr Tymoshenko 		break;
12039e28e985SOleksandr Tymoshenko 	default:
12049e28e985SOleksandr Tymoshenko 		dprintf("%s: UNKNOWN off=%08lx val=%08x\n",
12059e28e985SOleksandr Tymoshenko 		    __func__, off, val);
12069e28e985SOleksandr Tymoshenko 		break;
12079e28e985SOleksandr Tymoshenko 	}
12089e28e985SOleksandr Tymoshenko 
12099e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
12109e28e985SOleksandr Tymoshenko }
12119e28e985SOleksandr Tymoshenko 
12129e28e985SOleksandr Tymoshenko static void
bcm_sdhost_write_multi_4(device_t dev,struct sdhci_slot * slot,bus_size_t off,uint32_t * data,bus_size_t count)12139e28e985SOleksandr Tymoshenko bcm_sdhost_write_multi_4(device_t dev, struct sdhci_slot *slot,
12149e28e985SOleksandr Tymoshenko     bus_size_t off, uint32_t *data, bus_size_t count)
12159e28e985SOleksandr Tymoshenko {
12169e28e985SOleksandr Tymoshenko 	struct bcm_sdhost_softc *sc = device_get_softc(dev);
12179e28e985SOleksandr Tymoshenko 	bus_size_t i;
12189e28e985SOleksandr Tymoshenko 	bus_size_t space;
12199e28e985SOleksandr Tymoshenko 	uint32_t edm;
12209e28e985SOleksandr Tymoshenko 
12219e28e985SOleksandr Tymoshenko 	mtx_lock(&sc->mtx);
12229e28e985SOleksandr Tymoshenko 
12239e28e985SOleksandr Tymoshenko 	dprintf("%s: off=%08lx count=%02lx\n", __func__, off, count);
12249e28e985SOleksandr Tymoshenko 
12259e28e985SOleksandr Tymoshenko 	for (i = 0; i < count;) {
12269e28e985SOleksandr Tymoshenko 		edm = RD4(sc, HC_DEBUG);
12279e28e985SOleksandr Tymoshenko 		space = HC_FIFO_SIZE - ((edm >> 4) & 0x1f);
1228e06262c1SOleksandr Tymoshenko 		if (i + space > count)
12299e28e985SOleksandr Tymoshenko 			space = count - i;
12309e28e985SOleksandr Tymoshenko 		if (space > 0)
12319e28e985SOleksandr Tymoshenko 			bus_space_write_multi_4(sc->sc_bst, sc->sc_bsh,
12329e28e985SOleksandr Tymoshenko 			    HC_DATAPORT, data + i, space);
12339e28e985SOleksandr Tymoshenko 		i += space;
12349e28e985SOleksandr Tymoshenko 		DELAY(1);
12359e28e985SOleksandr Tymoshenko         }
12369e28e985SOleksandr Tymoshenko 
12379e28e985SOleksandr Tymoshenko 	/* wait until FIFO is really empty */
12389e28e985SOleksandr Tymoshenko 	while (((RD4(sc, HC_DEBUG) >> 4) & 0x1f) > 0)
12399e28e985SOleksandr Tymoshenko 		DELAY(1);
12409e28e985SOleksandr Tymoshenko 
12419e28e985SOleksandr Tymoshenko 	mtx_unlock(&sc->mtx);
12429e28e985SOleksandr Tymoshenko }
12439e28e985SOleksandr Tymoshenko 
12449e28e985SOleksandr Tymoshenko static device_method_t bcm_sdhost_methods[] = {
12459e28e985SOleksandr Tymoshenko 	/* Device interface */
12469e28e985SOleksandr Tymoshenko 	DEVMETHOD(device_probe,		bcm_sdhost_probe),
12479e28e985SOleksandr Tymoshenko 	DEVMETHOD(device_attach,	bcm_sdhost_attach),
12489e28e985SOleksandr Tymoshenko 	DEVMETHOD(device_detach,	bcm_sdhost_detach),
12499e28e985SOleksandr Tymoshenko 
12509e28e985SOleksandr Tymoshenko 	/* Bus interface */
12519e28e985SOleksandr Tymoshenko 	DEVMETHOD(bus_read_ivar,	sdhci_generic_read_ivar),
12529e28e985SOleksandr Tymoshenko 	DEVMETHOD(bus_write_ivar,	sdhci_generic_write_ivar),
12539e28e985SOleksandr Tymoshenko 
12549e28e985SOleksandr Tymoshenko 	/* MMC bridge interface */
12559e28e985SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_update_ios,	sdhci_generic_update_ios),
12569e28e985SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_request,	sdhci_generic_request),
12579e28e985SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_get_ro,		bcm_sdhost_get_ro),
12589e28e985SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_acquire_host,	sdhci_generic_acquire_host),
12599e28e985SOleksandr Tymoshenko 	DEVMETHOD(mmcbr_release_host,	sdhci_generic_release_host),
12609e28e985SOleksandr Tymoshenko 
12619e28e985SOleksandr Tymoshenko 	/* SDHCI registers accessors */
12629e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_1,		bcm_sdhost_read_1),
12639e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_2,		bcm_sdhost_read_2),
12649e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_4,		bcm_sdhost_read_4),
12659e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_read_multi_4,	bcm_sdhost_read_multi_4),
12669e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_1,	bcm_sdhost_write_1),
12679e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_2,	bcm_sdhost_write_2),
12689e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_4,	bcm_sdhost_write_4),
12699e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_write_multi_4,	bcm_sdhost_write_multi_4),
12709e28e985SOleksandr Tymoshenko 	DEVMETHOD(sdhci_get_card_present,bcm_sdhost_get_card_present),
12719e28e985SOleksandr Tymoshenko 
12729e28e985SOleksandr Tymoshenko 	DEVMETHOD_END
12739e28e985SOleksandr Tymoshenko };
12749e28e985SOleksandr Tymoshenko 
12759e28e985SOleksandr Tymoshenko static driver_t bcm_sdhost_driver = {
12769e28e985SOleksandr Tymoshenko 	"sdhost_bcm",
12779e28e985SOleksandr Tymoshenko 	bcm_sdhost_methods,
12789e28e985SOleksandr Tymoshenko 	sizeof(struct bcm_sdhost_softc),
12799e28e985SOleksandr Tymoshenko };
12809e28e985SOleksandr Tymoshenko 
128182d4dc06SJohn Baldwin DRIVER_MODULE(sdhost_bcm, simplebus, bcm_sdhost_driver, NULL, NULL);
1282ab00a509SMarius Strobl SDHCI_DEPEND(sdhost_bcm);
12839e28e985SOleksandr Tymoshenko #ifndef MMCCAM
12849e28e985SOleksandr Tymoshenko MMC_DECLARE_BRIDGE(sdhost_bcm);
12859e28e985SOleksandr Tymoshenko #endif
1286