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