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 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 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 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 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 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 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 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 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 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 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 475*723da5d9SJohn Baldwin bus_identify_children(dev); 4769e28e985SOleksandr Tymoshenko bus_generic_attach(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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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