1*98e9fa9cSpatrick /* $OpenBSD: dwmmc.c,v 1.31 2024/12/19 18:02:47 patrick Exp $ */ 224225f53Skettenis /* 324225f53Skettenis * Copyright (c) 2017 Mark Kettenis 424225f53Skettenis * 524225f53Skettenis * Permission to use, copy, modify, and distribute this software for any 624225f53Skettenis * purpose with or without fee is hereby granted, provided that the above 724225f53Skettenis * copyright notice and this permission notice appear in all copies. 824225f53Skettenis * 924225f53Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1024225f53Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1124225f53Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1224225f53Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1324225f53Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1424225f53Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1524225f53Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1624225f53Skettenis */ 1724225f53Skettenis 1824225f53Skettenis #include <sys/param.h> 19b9e8b644Skettenis #include <sys/kernel.h> 2024225f53Skettenis #include <sys/malloc.h> 2124225f53Skettenis #include <sys/systm.h> 2224225f53Skettenis 2324225f53Skettenis #include <machine/bus.h> 2424225f53Skettenis #include <machine/fdt.h> 2524225f53Skettenis #include <machine/intr.h> 2624225f53Skettenis 2724225f53Skettenis #include <dev/ofw/openfirm.h> 2824225f53Skettenis #include <dev/ofw/ofw_clock.h> 29f8fb77f5Skettenis #include <dev/ofw/ofw_gpio.h> 3024225f53Skettenis #include <dev/ofw/ofw_pinctrl.h> 31*98e9fa9cSpatrick #include <dev/ofw/ofw_regulator.h> 3224225f53Skettenis #include <dev/ofw/fdt.h> 3324225f53Skettenis 3424225f53Skettenis #include <dev/sdmmc/sdmmcvar.h> 353704a61cSkettenis #include <dev/sdmmc/sdmmc_ioreg.h> 3624225f53Skettenis 3724225f53Skettenis #define SDMMC_CTRL 0x0000 3824225f53Skettenis #define SDMMC_CTRL_USE_INTERNAL_DMAC (1 << 25) 39b9e8b644Skettenis #define SDMMC_CTRL_DMA_ENABLE (1 << 5) 40d5957df7Skettenis #define SDMMC_CTRL_INT_ENABLE (1 << 4) 4168c9da83Skettenis #define SDMMC_CTRL_DMA_RESET (1 << 2) 4268c9da83Skettenis #define SDMMC_CTRL_FIFO_RESET (1 << 1) 4368c9da83Skettenis #define SDMMC_CTRL_CONTROLLER_RESET (1 << 0) 4424225f53Skettenis #define SDMMC_CTRL_ALL_RESET (SDMMC_CTRL_CONTROLLER_RESET | \ 4524225f53Skettenis SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) 4624225f53Skettenis #define SDMMC_PWREN 0x0004 4724225f53Skettenis #define SDMMC_CLKDIV 0x0008 4824225f53Skettenis #define SDMMC_CLKSRC 0x000c 4924225f53Skettenis #define SDMMC_CLKENA 0x0010 5024225f53Skettenis #define SDMMC_CLKENA_CCLK_LOW_POWER (1 << 16) 5124225f53Skettenis #define SDMMC_CLKENA_CCLK_ENABLE (1 << 0) 5224225f53Skettenis #define SDMMC_TMOUT 0x0014 5324225f53Skettenis #define SDMMC_CTYPE 0x0018 5424225f53Skettenis #define SDMMC_CTYPE_8BIT (1 << 16) 5524225f53Skettenis #define SDMMC_CTYPE_4BIT (1 << 0) 5624225f53Skettenis #define SDMMC_BLKSIZ 0x001c 5724225f53Skettenis #define SDMMC_BYTCNT 0x0020 5824225f53Skettenis #define SDMMC_INTMASK 0x0024 5924225f53Skettenis #define SDMMC_CMDARG 0x0028 6024225f53Skettenis #define SDMMC_CMD 0x002c 6124225f53Skettenis #define SDMMC_CMD_START_CMD (1U << 31) 6224225f53Skettenis #define SDMMC_CMD_USE_HOLD_REG (1 << 29) 6324225f53Skettenis #define SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY (1 << 21) 6424225f53Skettenis #define SDMMC_CMD_SEND_INITIALIZATION (1 << 15) 6524225f53Skettenis #define SDMMC_CMD_STOP_ABORT_CMD (1 << 14) 6624225f53Skettenis #define SDMMC_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) 6724225f53Skettenis #define SDMMC_CMD_SEND_AUTO_STOP (1 << 12) 6824225f53Skettenis #define SDMMC_CMD_WR (1 << 10) 6924225f53Skettenis #define SDMMC_CMD_DATA_EXPECTED (1 << 9) 7024225f53Skettenis #define SDMMC_CMD_CHECK_REPONSE_CRC (1 << 8) 7124225f53Skettenis #define SDMMC_CMD_RESPONSE_LENGTH (1 << 7) 7224225f53Skettenis #define SDMMC_CMD_RESPONSE_EXPECT (1 << 6) 7324225f53Skettenis #define SDMMC_RESP0 0x0030 7424225f53Skettenis #define SDMMC_RESP1 0x0034 7524225f53Skettenis #define SDMMC_RESP2 0x0038 7624225f53Skettenis #define SDMMC_RESP3 0x003c 7724225f53Skettenis #define SDMMC_MINTSTS 0x0040 7824225f53Skettenis #define SDMMC_RINTSTS 0x0044 79d5957df7Skettenis #define SDMMC_RINTSTS_SDIO (1 << 24) 8024225f53Skettenis #define SDMMC_RINTSTS_EBE (1 << 15) 8124225f53Skettenis #define SDMMC_RINTSTS_ACD (1 << 14) 8224225f53Skettenis #define SDMMC_RINTSTS_SBE (1 << 13) 8324225f53Skettenis #define SDMMC_RINTSTS_HLE (1 << 12) 8424225f53Skettenis #define SDMMC_RINTSTS_FRUN (1 << 11) 8524225f53Skettenis #define SDMMC_RINTSTS_HTO (1 << 10) 8624225f53Skettenis #define SDMMC_RINTSTS_DRTO (1 << 9) 8724225f53Skettenis #define SDMMC_RINTSTS_RTO (1 << 8) 8824225f53Skettenis #define SDMMC_RINTSTS_DCRC (1 << 7) 8924225f53Skettenis #define SDMMC_RINTSTS_RCRC (1 << 6) 9024225f53Skettenis #define SDMMC_RINTSTS_RXDR (1 << 5) 9124225f53Skettenis #define SDMMC_RINTSTS_TXDR (1 << 4) 9224225f53Skettenis #define SDMMC_RINTSTS_DTO (1 << 3) 9324225f53Skettenis #define SDMMC_RINTSTS_CD (1 << 2) 9424225f53Skettenis #define SDMMC_RINTSTS_RE (1 << 1) 9524225f53Skettenis #define SDMMC_RINTSTS_CDT (1 << 0) 9624225f53Skettenis #define SDMMC_RINTSTS_DATA_ERR (SDMMC_RINTSTS_EBE | SDMMC_RINTSTS_SBE | \ 9724225f53Skettenis SDMMC_RINTSTS_HLE | SDMMC_RINTSTS_FRUN | SDMMC_RINTSTS_DCRC) 9824225f53Skettenis #define SDMMC_RINTSTS_DATA_TO (SDMMC_RINTSTS_HTO | SDMMC_RINTSTS_DRTO) 9924225f53Skettenis #define SDMMC_STATUS 0x0048 10024225f53Skettenis #define SDMMC_STATUS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff) 10124225f53Skettenis #define SDMMC_STATUS_DATA_BUSY (1 << 9) 10224225f53Skettenis #define SDMMC_FIFOTH 0x004c 10325f77276Skettenis #define SDMMC_FIFOTH_MSIZE_SHIFT 28 10425f77276Skettenis #define SDMMC_FIFOTH_RXWM_SHIFT 16 1050299d551Skettenis #define SDMMC_FIFOTH_RXWM(x) (((x) >> 16) & 0xfff) 10625f77276Skettenis #define SDMMC_FIFOTH_TXWM_SHIFT 0 10724225f53Skettenis #define SDMMC_CDETECT 0x0050 10824225f53Skettenis #define SDMMC_CDETECT_CARD_DETECT_0 (1 << 0) 10924225f53Skettenis #define SDMMC_WRTPRT 0x0054 11024225f53Skettenis #define SDMMC_TCBCNT 0x005c 11124225f53Skettenis #define SDMMC_TBBCNT 0x0060 11224225f53Skettenis #define SDMMC_DEBNCE 0x0064 11324225f53Skettenis #define SDMMC_USRID 0x0068 11424225f53Skettenis #define SDMMC_VERID 0x006c 11524225f53Skettenis #define SDMMC_HCON 0x0070 11670864666Skettenis #define SDMMC_HCON_DATA_WIDTH(x) (((x) >> 7) & 0x7) 1174df26cf2Skettenis #define SDMMC_HCON_DMA64 (1 << 27) 11824225f53Skettenis #define SDMMC_UHS_REG 0x0074 11924225f53Skettenis #define SDMMC_RST_n 0x0078 12024225f53Skettenis #define SDMMC_BMOD 0x0080 121b9e8b644Skettenis #define SDMMC_BMOD_DE (1 << 7) 122b9e8b644Skettenis #define SDMMC_BMOD_FB (1 << 1) 123b9e8b644Skettenis #define SDMMC_BMOD_SWR (1 << 0) 12424225f53Skettenis #define SDMMC_PLDMND 0x0084 12524225f53Skettenis #define SDMMC_DBADDR 0x0088 1264df26cf2Skettenis #define SDMMC_IDSTS32 0x008c 127b9e8b644Skettenis #define SDMMC_IDSTS_NIS (1 << 8) 128b9e8b644Skettenis #define SDMMC_IDSTS_RI (1 << 1) 129b9e8b644Skettenis #define SDMMC_IDSTS_TI (1 << 0) 1304df26cf2Skettenis #define SDMMC_IDINTEN32 0x0090 131b9e8b644Skettenis #define SDMMC_IDINTEN_NI (1 << 8) 132b9e8b644Skettenis #define SDMMC_IDINTEN_RI (1 << 1) 133b9e8b644Skettenis #define SDMMC_IDINTEN_TI (1 << 0) 13424225f53Skettenis #define SDMMC_DSCADDR 0x0094 13524225f53Skettenis #define SDMMC_BUFADDR 0x0098 13670864666Skettenis #define SDMMC_CLKSEL 0x009c 13724225f53Skettenis #define SDMMC_CARDTHRCTL 0x0100 13824225f53Skettenis #define SDMMC_CARDTHRCTL_RDTHR_SHIFT 16 13924225f53Skettenis #define SDMMC_CARDTHRCTL_RDTHREN (1 << 0) 14024225f53Skettenis #define SDMMC_BACK_END_POWER 0x0104 14124225f53Skettenis #define SDMMC_EMMC_DDR_REG 0x0108 14224225f53Skettenis #define SDMMC_FIFO_BASE 0x0200 14324225f53Skettenis 1444df26cf2Skettenis #define SDMMC_DBADDRL 0x0088 1454df26cf2Skettenis #define SDMMC_DBADDRH 0x008c 1464df26cf2Skettenis #define SDMMC_IDSTS64 0x0090 1474df26cf2Skettenis #define SDMMC_IDINTEN64 0x0094 1484df26cf2Skettenis #define SDMMC_DSCADDRL 0x0098 1494df26cf2Skettenis #define SDMMC_DSCADDRH 0x009c 1504df26cf2Skettenis #define SDMMC_BUFADDRL 0x00a0 1514df26cf2Skettenis #define SDMMC_BUFADDRH 0x00a4 1524df26cf2Skettenis 1534df26cf2Skettenis #define SDMMC_IDSTS(sc) \ 1544df26cf2Skettenis ((sc)->sc_dma64 ? SDMMC_IDSTS64 : SDMMC_IDSTS32) 1554df26cf2Skettenis 15624225f53Skettenis #define HREAD4(sc, reg) \ 15724225f53Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 15824225f53Skettenis #define HWRITE4(sc, reg, val) \ 15924225f53Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 16024225f53Skettenis #define HSET4(sc, reg, bits) \ 16124225f53Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 16224225f53Skettenis #define HCLR4(sc, reg, bits) \ 16324225f53Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 16424225f53Skettenis 1654df26cf2Skettenis struct dwmmc_desc32 { 166b9e8b644Skettenis uint32_t des[4]; 167b9e8b644Skettenis }; 168b9e8b644Skettenis 1694df26cf2Skettenis struct dwmmc_desc64 { 1704df26cf2Skettenis uint32_t des[8]; 1714df26cf2Skettenis }; 1724df26cf2Skettenis 1734df26cf2Skettenis #define DWMMC_NDESC (PAGE_SIZE / sizeof(struct dwmmc_desc64)) 174b9e8b644Skettenis #define DWMMC_MAXSEGSZ 0x1000 175b9e8b644Skettenis 176b9e8b644Skettenis #define DES0_OWN (1U << 31) 177b9e8b644Skettenis #define DES0_CES (1 << 30) 178b9e8b644Skettenis #define DES0_ER (1 << 5) 179b9e8b644Skettenis #define DES0_CH (1 << 4) 180b9e8b644Skettenis #define DES0_FS (1 << 3) 181b9e8b644Skettenis #define DES0_LD (1 << 2) 182b9e8b644Skettenis #define DES0_DIC (1 << 1) 183b9e8b644Skettenis 184b9e8b644Skettenis #define DES1_BS2(sz) (((sz) & 0x1fff) << 13) 185b9e8b644Skettenis #define DES1_BS1(sz) (((sz) & 0x1fff) << 0) 1864df26cf2Skettenis #define DES2_BS2(sz) DES1_BS2(sz) 1874df26cf2Skettenis #define DES2_BS1(sz) DES1_BS1(sz) 188b9e8b644Skettenis 18924225f53Skettenis struct dwmmc_softc { 19024225f53Skettenis struct device sc_dev; 19124225f53Skettenis bus_space_tag_t sc_iot; 19224225f53Skettenis bus_space_handle_t sc_ioh; 19324225f53Skettenis bus_size_t sc_size; 194b9e8b644Skettenis bus_dma_tag_t sc_dmat; 195b9e8b644Skettenis bus_dmamap_t sc_dmap; 196f8fb77f5Skettenis int sc_node; 197f8fb77f5Skettenis 19824225f53Skettenis void *sc_ih; 19924225f53Skettenis 20024225f53Skettenis uint32_t sc_clkbase; 20124225f53Skettenis uint32_t sc_fifo_depth; 20270864666Skettenis uint32_t sc_fifo_width; 20370864666Skettenis void (*sc_read_data)(struct dwmmc_softc *, u_char *, int); 20470864666Skettenis void (*sc_write_data)(struct dwmmc_softc *, u_char *, int); 2053704a61cSkettenis int sc_blklen; 20624225f53Skettenis 207b9e8b644Skettenis bus_dmamap_t sc_desc_map; 208b9e8b644Skettenis bus_dma_segment_t sc_desc_segs[1]; 209b9e8b644Skettenis caddr_t sc_desc; 2104df26cf2Skettenis int sc_dma64; 211b9e8b644Skettenis int sc_dmamode; 212b9e8b644Skettenis uint32_t sc_idsts; 213b9e8b644Skettenis 214f8fb77f5Skettenis uint32_t sc_gpio[4]; 215d5957df7Skettenis int sc_sdio_irq; 216*98e9fa9cSpatrick uint32_t sc_vqmmc; 217d5957df7Skettenis uint32_t sc_pwrseq; 218d5957df7Skettenis uint32_t sc_vdd; 219f8fb77f5Skettenis 22024225f53Skettenis struct device *sc_sdmmc; 22124225f53Skettenis }; 22224225f53Skettenis 22324225f53Skettenis int dwmmc_match(struct device *, void *, void *); 22424225f53Skettenis void dwmmc_attach(struct device *, struct device *, void *); 22524225f53Skettenis 2269fdf0c62Smpi const struct cfattach dwmmc_ca = { 22724225f53Skettenis sizeof(struct dwmmc_softc), dwmmc_match, dwmmc_attach 22824225f53Skettenis }; 22924225f53Skettenis 23024225f53Skettenis struct cfdriver dwmmc_cd = { 23124225f53Skettenis NULL, "dwmmc", DV_DULL 23224225f53Skettenis }; 23324225f53Skettenis 23424225f53Skettenis int dwmmc_intr(void *); 23524225f53Skettenis 23624225f53Skettenis int dwmmc_host_reset(sdmmc_chipset_handle_t); 23724225f53Skettenis uint32_t dwmmc_host_ocr(sdmmc_chipset_handle_t); 23824225f53Skettenis int dwmmc_host_maxblklen(sdmmc_chipset_handle_t); 23924225f53Skettenis int dwmmc_card_detect(sdmmc_chipset_handle_t); 24024225f53Skettenis int dwmmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 24124225f53Skettenis int dwmmc_bus_clock(sdmmc_chipset_handle_t, int, int); 24224225f53Skettenis int dwmmc_bus_width(sdmmc_chipset_handle_t, int); 24324225f53Skettenis void dwmmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); 244d5957df7Skettenis void dwmmc_card_intr_mask(sdmmc_chipset_handle_t, int); 245d5957df7Skettenis void dwmmc_card_intr_ack(sdmmc_chipset_handle_t); 246*98e9fa9cSpatrick int dwmmc_signal_voltage(sdmmc_chipset_handle_t, int); 24724225f53Skettenis 24824225f53Skettenis struct sdmmc_chip_functions dwmmc_chip_functions = { 24924225f53Skettenis .host_reset = dwmmc_host_reset, 25024225f53Skettenis .host_ocr = dwmmc_host_ocr, 25124225f53Skettenis .host_maxblklen = dwmmc_host_maxblklen, 25224225f53Skettenis .card_detect = dwmmc_card_detect, 25324225f53Skettenis .bus_power = dwmmc_bus_power, 25424225f53Skettenis .bus_clock = dwmmc_bus_clock, 25524225f53Skettenis .bus_width = dwmmc_bus_width, 25624225f53Skettenis .exec_command = dwmmc_exec_command, 257d5957df7Skettenis .card_intr_mask = dwmmc_card_intr_mask, 258d5957df7Skettenis .card_intr_ack = dwmmc_card_intr_ack, 259*98e9fa9cSpatrick .signal_voltage = dwmmc_signal_voltage, 26024225f53Skettenis }; 26124225f53Skettenis 2623704a61cSkettenis void dwmmc_pio_mode(struct dwmmc_softc *); 263b9e8b644Skettenis int dwmmc_alloc_descriptors(struct dwmmc_softc *); 264b9e8b644Skettenis void dwmmc_init_descriptors(struct dwmmc_softc *); 26524225f53Skettenis void dwmmc_transfer_data(struct dwmmc_softc *, struct sdmmc_command *); 26670864666Skettenis void dwmmc_read_data32(struct dwmmc_softc *, u_char *, int); 26770864666Skettenis void dwmmc_write_data32(struct dwmmc_softc *, u_char *, int); 26870864666Skettenis void dwmmc_read_data64(struct dwmmc_softc *, u_char *, int); 26970864666Skettenis void dwmmc_write_data64(struct dwmmc_softc *, u_char *, int); 270d5957df7Skettenis void dwmmc_pwrseq_pre(uint32_t); 271d5957df7Skettenis void dwmmc_pwrseq_post(uint32_t); 27224225f53Skettenis 27324225f53Skettenis int 27424225f53Skettenis dwmmc_match(struct device *parent, void *match, void *aux) 27524225f53Skettenis { 27624225f53Skettenis struct fdt_attach_args *faa = aux; 27724225f53Skettenis 2780299d551Skettenis return (OF_is_compatible(faa->fa_node, "hisilicon,hi3660-dw-mshc") || 2790299d551Skettenis OF_is_compatible(faa->fa_node, "hisilicon,hi3670-dw-mshc") || 2800299d551Skettenis OF_is_compatible(faa->fa_node, "rockchip,rk3288-dw-mshc") || 281619f63beSjsg OF_is_compatible(faa->fa_node, "samsung,exynos5420-dw-mshc") || 28264cee0edSjsing OF_is_compatible(faa->fa_node, "snps,dw-mshc") || 28364cee0edSjsing OF_is_compatible(faa->fa_node, "starfive,jh7110-mmc")); 28424225f53Skettenis } 28524225f53Skettenis 28624225f53Skettenis void 28724225f53Skettenis dwmmc_attach(struct device *parent, struct device *self, void *aux) 28824225f53Skettenis { 28924225f53Skettenis struct dwmmc_softc *sc = (struct dwmmc_softc *)self; 29024225f53Skettenis struct fdt_attach_args *faa = aux; 29124225f53Skettenis struct sdmmcbus_attach_args saa; 29228eeafaaSkettenis uint32_t freq = 0, div = 0; 293a78d0ad4Skettenis uint32_t hcon, width; 2940299d551Skettenis uint32_t fifoth; 295b9e8b644Skettenis int error, timeout; 29624225f53Skettenis 29724225f53Skettenis if (faa->fa_nreg < 1) { 29824225f53Skettenis printf(": no registers\n"); 29924225f53Skettenis return; 30024225f53Skettenis } 30124225f53Skettenis 302f8fb77f5Skettenis sc->sc_node = faa->fa_node; 30324225f53Skettenis sc->sc_iot = faa->fa_iot; 30424225f53Skettenis sc->sc_size = faa->fa_reg[0].size; 30524225f53Skettenis 30624225f53Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 30724225f53Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 30824225f53Skettenis printf(": can't map registers\n"); 30924225f53Skettenis return; 31024225f53Skettenis } 31124225f53Skettenis 31224225f53Skettenis pinctrl_byname(faa->fa_node, "default"); 31324225f53Skettenis 31424225f53Skettenis clock_enable_all(faa->fa_node); 31524225f53Skettenis reset_deassert_all(faa->fa_node); 31624225f53Skettenis 31770864666Skettenis /* 31870864666Skettenis * Determine FIFO width from hardware configuration register. 31970864666Skettenis * We only support 32-bit and 64-bit FIFOs. 32070864666Skettenis */ 32170864666Skettenis hcon = HREAD4(sc, SDMMC_HCON); 32270864666Skettenis switch (SDMMC_HCON_DATA_WIDTH(hcon)) { 32370864666Skettenis case 1: 32470864666Skettenis sc->sc_fifo_width = 4; 32570864666Skettenis sc->sc_read_data = dwmmc_read_data32; 32670864666Skettenis sc->sc_write_data = dwmmc_write_data32; 32770864666Skettenis break; 32870864666Skettenis case 2: 32970864666Skettenis sc->sc_fifo_width = 8; 33070864666Skettenis sc->sc_read_data = dwmmc_read_data64; 33170864666Skettenis sc->sc_write_data = dwmmc_write_data64; 33270864666Skettenis break; 33370864666Skettenis default: 33470864666Skettenis printf(": unsupported FIFO width\n"); 33570864666Skettenis return; 33670864666Skettenis } 33770864666Skettenis 33870864666Skettenis sc->sc_fifo_depth = OF_getpropint(faa->fa_node, "fifo-depth", 0); 33970864666Skettenis if (sc->sc_fifo_depth == 0) { 3400299d551Skettenis fifoth = HREAD4(sc, SDMMC_FIFOTH); 3410299d551Skettenis sc->sc_fifo_depth = SDMMC_FIFOTH_RXWM(fifoth) + 1; 34270864666Skettenis } 34370864666Skettenis 3444df26cf2Skettenis if (hcon & SDMMC_HCON_DMA64) 3454df26cf2Skettenis sc->sc_dma64 = 1; 3464df26cf2Skettenis 34732408765Skettenis /* Some SoCs pre-divide the clock. */ 348a78d0ad4Skettenis if (OF_is_compatible(faa->fa_node, "rockchip,rk3288-dw-mshc")) 349a78d0ad4Skettenis div = 1; 35032408765Skettenis if (OF_is_compatible(faa->fa_node, "hisilicon,hi3660-dw-mshc") || 35132408765Skettenis OF_is_compatible(faa->fa_node, "hisilicon,hi3670-dw-mshc")) 35232408765Skettenis div = 7; 353a78d0ad4Skettenis 35428eeafaaSkettenis /* Force the base clock to 50MHz on Rockchip SoCs. */ 35528eeafaaSkettenis if (OF_is_compatible(faa->fa_node, "rockchip,rk3288-dw-mshc")) 35628eeafaaSkettenis freq = 50000000; 35728eeafaaSkettenis 35828eeafaaSkettenis freq = OF_getpropint(faa->fa_node, "clock-frequency", freq); 359a78d0ad4Skettenis if (freq > 0) 360a78d0ad4Skettenis clock_set_frequency(faa->fa_node, "ciu", (div + 1) * freq); 361a78d0ad4Skettenis 36224225f53Skettenis sc->sc_clkbase = clock_get_frequency(faa->fa_node, "ciu"); 363619f63beSjsg /* if ciu clock is missing the rate is clock-frequency */ 364619f63beSjsg if (sc->sc_clkbase == 0) 365619f63beSjsg sc->sc_clkbase = freq; 3662b571f7fSjsing if (sc->sc_clkbase == 0) { 3672b571f7fSjsing printf(": no clock base\n"); 3682b571f7fSjsing return; 3692b571f7fSjsing } 370a78d0ad4Skettenis div = OF_getpropint(faa->fa_node, "samsung,dw-mshc-ciu-div", div); 371a78d0ad4Skettenis sc->sc_clkbase /= (div + 1); 37224225f53Skettenis 37370e69ae2Spatrick sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO, 37424225f53Skettenis dwmmc_intr, sc, sc->sc_dev.dv_xname); 37524225f53Skettenis if (sc->sc_ih == NULL) { 37624225f53Skettenis printf(": can't establish interrupt\n"); 37724225f53Skettenis goto unmap; 37824225f53Skettenis } 37924225f53Skettenis 380f8fb77f5Skettenis OF_getpropintarray(faa->fa_node, "cd-gpios", sc->sc_gpio, 381f8fb77f5Skettenis sizeof(sc->sc_gpio)); 382f8fb77f5Skettenis if (sc->sc_gpio[0]) 383f8fb77f5Skettenis gpio_controller_config_pin(sc->sc_gpio, GPIO_CONFIG_INPUT); 384f8fb77f5Skettenis 385d5957df7Skettenis sc->sc_sdio_irq = (OF_getproplen(sc->sc_node, "cap-sdio-irq") == 0); 386*98e9fa9cSpatrick sc->sc_vqmmc = OF_getpropint(sc->sc_node, "vqmmc-supply", 0); 387d5957df7Skettenis sc->sc_pwrseq = OF_getpropint(sc->sc_node, "mmc-pwrseq", 0); 388d5957df7Skettenis 38970864666Skettenis printf(": %d MHz base clock\n", sc->sc_clkbase / 1000000); 39024225f53Skettenis 39124225f53Skettenis HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_ALL_RESET); 392e036655fSkettenis for (timeout = 5000; timeout > 0; timeout--) { 39324225f53Skettenis if ((HREAD4(sc, SDMMC_CTRL) & SDMMC_CTRL_ALL_RESET) == 0) 39424225f53Skettenis break; 395e036655fSkettenis delay(100); 39624225f53Skettenis } 39724225f53Skettenis if (timeout == 0) 39824225f53Skettenis printf("%s: reset failed\n", sc->sc_dev.dv_xname); 39924225f53Skettenis 400d5957df7Skettenis /* Enable interrupts, but mask them all. */ 401d5957df7Skettenis HWRITE4(sc, SDMMC_INTMASK, 0); 402d5957df7Skettenis HWRITE4(sc, SDMMC_RINTSTS, 0xffffffff); 403d5957df7Skettenis HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE); 40424225f53Skettenis 40524225f53Skettenis dwmmc_bus_width(sc, 1); 40624225f53Skettenis 4073704a61cSkettenis /* Start out in non-DMA mode. */ 4083704a61cSkettenis dwmmc_pio_mode(sc); 4093704a61cSkettenis 410b9e8b644Skettenis sc->sc_dmat = faa->fa_dmat; 411b9e8b644Skettenis dwmmc_alloc_descriptors(sc); 412b9e8b644Skettenis dwmmc_init_descriptors(sc); 413b9e8b644Skettenis 414b9e8b644Skettenis error = bus_dmamap_create(sc->sc_dmat, MAXPHYS, DWMMC_NDESC, 415b9e8b644Skettenis DWMMC_MAXSEGSZ, 0, BUS_DMA_WAITOK|BUS_DMA_ALLOCNOW, &sc->sc_dmap); 416b9e8b644Skettenis if (error) { 417b9e8b644Skettenis printf(": can't create DMA map\n"); 418b9e8b644Skettenis goto unmap; 419b9e8b644Skettenis } 420b9e8b644Skettenis 42124225f53Skettenis memset(&saa, 0, sizeof(saa)); 42224225f53Skettenis saa.saa_busname = "sdmmc"; 42324225f53Skettenis saa.sct = &dwmmc_chip_functions; 42424225f53Skettenis saa.sch = sc; 425b9e8b644Skettenis saa.dmat = sc->sc_dmat; 426b9e8b644Skettenis saa.dmap = sc->sc_dmap; 4274481f01cSkettenis saa.caps |= SMC_CAPS_DMA; 42824225f53Skettenis 429c61301d7Skettenis if (OF_getproplen(sc->sc_node, "cap-mmc-highspeed") == 0) 430c61301d7Skettenis saa.caps |= SMC_CAPS_MMC_HIGHSPEED; 431c61301d7Skettenis if (OF_getproplen(sc->sc_node, "cap-sd-highspeed") == 0) 432c61301d7Skettenis saa.caps |= SMC_CAPS_SD_HIGHSPEED; 433c61301d7Skettenis 43424225f53Skettenis width = OF_getpropint(faa->fa_node, "bus-width", 1); 43524225f53Skettenis if (width >= 8) 43624225f53Skettenis saa.caps |= SMC_CAPS_8BIT_MODE; 43724225f53Skettenis if (width >= 4) 43824225f53Skettenis saa.caps |= SMC_CAPS_4BIT_MODE; 43924225f53Skettenis 44024225f53Skettenis sc->sc_sdmmc = config_found(self, &saa, NULL); 44124225f53Skettenis return; 44224225f53Skettenis 44324225f53Skettenis unmap: 44424225f53Skettenis bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); 44524225f53Skettenis } 44624225f53Skettenis 44724225f53Skettenis int 448b9e8b644Skettenis dwmmc_alloc_descriptors(struct dwmmc_softc *sc) 449b9e8b644Skettenis { 450b9e8b644Skettenis int error, rseg; 451b9e8b644Skettenis 452b9e8b644Skettenis /* Allocate descriptor memory */ 453b9e8b644Skettenis error = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 454b9e8b644Skettenis PAGE_SIZE, sc->sc_desc_segs, 1, &rseg, 455b9e8b644Skettenis BUS_DMA_WAITOK | BUS_DMA_ZERO); 456b9e8b644Skettenis if (error) 457b9e8b644Skettenis return error; 458b9e8b644Skettenis error = bus_dmamem_map(sc->sc_dmat, sc->sc_desc_segs, rseg, 459b9e8b644Skettenis PAGE_SIZE, &sc->sc_desc, BUS_DMA_WAITOK | BUS_DMA_COHERENT); 460b9e8b644Skettenis if (error) { 461b9e8b644Skettenis bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, rseg); 462b9e8b644Skettenis return error; 463b9e8b644Skettenis } 464b9e8b644Skettenis error = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 465b9e8b644Skettenis 0, BUS_DMA_WAITOK, &sc->sc_desc_map); 466b9e8b644Skettenis if (error) { 467b9e8b644Skettenis bus_dmamem_unmap(sc->sc_dmat, sc->sc_desc, PAGE_SIZE); 468b9e8b644Skettenis bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, rseg); 469b9e8b644Skettenis return error; 470b9e8b644Skettenis } 471b9e8b644Skettenis error = bus_dmamap_load(sc->sc_dmat, sc->sc_desc_map, 472b9e8b644Skettenis sc->sc_desc, PAGE_SIZE, NULL, BUS_DMA_WAITOK | BUS_DMA_WRITE); 473b9e8b644Skettenis if (error) { 474b9e8b644Skettenis bus_dmamap_destroy(sc->sc_dmat, sc->sc_desc_map); 475b9e8b644Skettenis bus_dmamem_unmap(sc->sc_dmat, sc->sc_desc, PAGE_SIZE); 476b9e8b644Skettenis bus_dmamem_free(sc->sc_dmat, sc->sc_desc_segs, rseg); 477b9e8b644Skettenis return error; 478b9e8b644Skettenis } 479b9e8b644Skettenis 480b9e8b644Skettenis return 0; 481b9e8b644Skettenis } 482b9e8b644Skettenis 483b9e8b644Skettenis void 4844df26cf2Skettenis dwmmc_init_descriptors32(struct dwmmc_softc *sc) 485b9e8b644Skettenis { 4864df26cf2Skettenis struct dwmmc_desc32 *desc; 487b9e8b644Skettenis bus_addr_t addr; 488b9e8b644Skettenis int i; 489b9e8b644Skettenis 490b9e8b644Skettenis desc = (void *)sc->sc_desc; 491b9e8b644Skettenis addr = sc->sc_desc_map->dm_segs[0].ds_addr; 492b9e8b644Skettenis for (i = 0; i < DWMMC_NDESC; i++) { 4934df26cf2Skettenis addr += sizeof(struct dwmmc_desc32); 494b9e8b644Skettenis desc[i].des[3] = addr; 495b9e8b644Skettenis } 496b9e8b644Skettenis desc[DWMMC_NDESC - 1].des[3] = sc->sc_desc_map->dm_segs[0].ds_addr; 497b9e8b644Skettenis desc[DWMMC_NDESC - 1].des[0] = DES0_ER; 498b9e8b644Skettenis bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0, 499b9e8b644Skettenis PAGE_SIZE, BUS_DMASYNC_PREWRITE); 500b9e8b644Skettenis 5014df26cf2Skettenis HWRITE4(sc, SDMMC_IDSTS32, 0xffffffff); 5024df26cf2Skettenis HWRITE4(sc, SDMMC_IDINTEN32, 503b9e8b644Skettenis SDMMC_IDINTEN_NI | SDMMC_IDINTEN_RI | SDMMC_IDINTEN_TI); 504b9e8b644Skettenis HWRITE4(sc, SDMMC_DBADDR, sc->sc_desc_map->dm_segs[0].ds_addr); 505b9e8b644Skettenis } 506b9e8b644Skettenis 5074df26cf2Skettenis void 5084df26cf2Skettenis dwmmc_init_descriptors64(struct dwmmc_softc *sc) 5094df26cf2Skettenis { 5104df26cf2Skettenis struct dwmmc_desc64 *desc; 5114df26cf2Skettenis bus_addr_t addr; 5124df26cf2Skettenis int i; 5134df26cf2Skettenis 5144df26cf2Skettenis desc = (void *)sc->sc_desc; 5154df26cf2Skettenis addr = sc->sc_desc_map->dm_segs[0].ds_addr; 5164df26cf2Skettenis for (i = 0; i < DWMMC_NDESC; i++) { 5174df26cf2Skettenis addr += sizeof(struct dwmmc_desc64); 5184df26cf2Skettenis desc[i].des[6] = addr; 5194df26cf2Skettenis desc[i].des[7] = (uint64_t)addr >> 32; 5204df26cf2Skettenis } 5214df26cf2Skettenis desc[DWMMC_NDESC - 1].des[6] = sc->sc_desc_map->dm_segs[0].ds_addr; 5224df26cf2Skettenis desc[DWMMC_NDESC - 1].des[7] = 5234df26cf2Skettenis (uint64_t)sc->sc_desc_map->dm_segs[0].ds_addr >> 32; 5244df26cf2Skettenis desc[DWMMC_NDESC - 1].des[0] = DES0_ER; 5254df26cf2Skettenis bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0, 5264df26cf2Skettenis PAGE_SIZE, BUS_DMASYNC_PREWRITE); 5274df26cf2Skettenis 5284df26cf2Skettenis HWRITE4(sc, SDMMC_IDSTS64, 0xffffffff); 5294df26cf2Skettenis HWRITE4(sc, SDMMC_IDINTEN64, 5304df26cf2Skettenis SDMMC_IDINTEN_NI | SDMMC_IDINTEN_RI | SDMMC_IDINTEN_TI); 5314df26cf2Skettenis HWRITE4(sc, SDMMC_DBADDRL, sc->sc_desc_map->dm_segs[0].ds_addr); 5324df26cf2Skettenis HWRITE4(sc, SDMMC_DBADDRH, 5334df26cf2Skettenis (uint64_t)sc->sc_desc_map->dm_segs[0].ds_addr >> 32); 5344df26cf2Skettenis } 5354df26cf2Skettenis 5364df26cf2Skettenis void 5374df26cf2Skettenis dwmmc_init_descriptors(struct dwmmc_softc *sc) 5384df26cf2Skettenis { 5394df26cf2Skettenis if (sc->sc_dma64) 5404df26cf2Skettenis dwmmc_init_descriptors64(sc); 5414df26cf2Skettenis else 5424df26cf2Skettenis dwmmc_init_descriptors32(sc); 5434df26cf2Skettenis } 5444df26cf2Skettenis 545b9e8b644Skettenis int 54624225f53Skettenis dwmmc_intr(void *arg) 54724225f53Skettenis { 548d5957df7Skettenis struct dwmmc_softc *sc = arg; 549d5957df7Skettenis uint32_t stat; 550d5957df7Skettenis int handled = 0; 551d5957df7Skettenis 5524df26cf2Skettenis stat = HREAD4(sc, SDMMC_IDSTS(sc)); 553b9e8b644Skettenis if (stat) { 5544df26cf2Skettenis HWRITE4(sc, SDMMC_IDSTS(sc), stat); 555b9e8b644Skettenis sc->sc_idsts |= stat; 556b9e8b644Skettenis wakeup(&sc->sc_idsts); 557b9e8b644Skettenis handled = 1; 558b9e8b644Skettenis } 559b9e8b644Skettenis 560d5957df7Skettenis stat = HREAD4(sc, SDMMC_MINTSTS); 561d5957df7Skettenis if (stat & SDMMC_RINTSTS_SDIO) { 5628fc6eeeeSpatrick HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_SDIO); 563d5957df7Skettenis HCLR4(sc, SDMMC_INTMASK, SDMMC_RINTSTS_SDIO); 564d5957df7Skettenis sdmmc_card_intr(sc->sc_sdmmc); 565d5957df7Skettenis handled = 1; 566d5957df7Skettenis } 567d5957df7Skettenis 568d5957df7Skettenis return handled; 569d5957df7Skettenis } 570d5957df7Skettenis 571d5957df7Skettenis void 572d5957df7Skettenis dwmmc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable) 573d5957df7Skettenis { 574d5957df7Skettenis struct dwmmc_softc *sc = sch; 575d5957df7Skettenis 576d5957df7Skettenis if (enable) 577d5957df7Skettenis HSET4(sc, SDMMC_INTMASK, SDMMC_RINTSTS_SDIO); 578d5957df7Skettenis else 579d5957df7Skettenis HCLR4(sc, SDMMC_INTMASK, SDMMC_RINTSTS_SDIO); 580d5957df7Skettenis } 581d5957df7Skettenis 582d5957df7Skettenis void 583d5957df7Skettenis dwmmc_card_intr_ack(sdmmc_chipset_handle_t sch) 584d5957df7Skettenis { 585d5957df7Skettenis struct dwmmc_softc *sc = sch; 586d5957df7Skettenis 587d5957df7Skettenis HSET4(sc, SDMMC_INTMASK, SDMMC_RINTSTS_SDIO); 58824225f53Skettenis } 58924225f53Skettenis 59024225f53Skettenis int 59124225f53Skettenis dwmmc_host_reset(sdmmc_chipset_handle_t sch) 59224225f53Skettenis { 59324225f53Skettenis printf("%s\n", __func__); 59424225f53Skettenis return 0; 59524225f53Skettenis } 59624225f53Skettenis 59724225f53Skettenis uint32_t 59824225f53Skettenis dwmmc_host_ocr(sdmmc_chipset_handle_t sch) 59924225f53Skettenis { 60024225f53Skettenis return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 60124225f53Skettenis } 60224225f53Skettenis 60324225f53Skettenis int 60424225f53Skettenis dwmmc_host_maxblklen(sdmmc_chipset_handle_t sch) 60524225f53Skettenis { 60624225f53Skettenis return 512; 60724225f53Skettenis } 60824225f53Skettenis 60924225f53Skettenis int 61024225f53Skettenis dwmmc_card_detect(sdmmc_chipset_handle_t sch) 61124225f53Skettenis { 61224225f53Skettenis struct dwmmc_softc *sc = sch; 61324225f53Skettenis uint32_t cdetect; 61424225f53Skettenis 615721f294eSkettenis /* XXX treat broken-cd as non-removable */ 616721f294eSkettenis if (OF_getproplen(sc->sc_node, "non-removable") == 0 || 617721f294eSkettenis OF_getproplen(sc->sc_node, "broken-cd") == 0) 618f8fb77f5Skettenis return 1; 619f8fb77f5Skettenis 620f8fb77f5Skettenis if (sc->sc_gpio[0]) { 621f8fb77f5Skettenis int inverted, val; 622f8fb77f5Skettenis 623f8fb77f5Skettenis val = gpio_controller_get_pin(sc->sc_gpio); 624f8fb77f5Skettenis 625f8fb77f5Skettenis inverted = (OF_getproplen(sc->sc_node, "cd-inverted") == 0); 626f8fb77f5Skettenis return inverted ? !val : val; 627f8fb77f5Skettenis } 628f8fb77f5Skettenis 62924225f53Skettenis cdetect = HREAD4(sc, SDMMC_CDETECT); 63024225f53Skettenis return !(cdetect & SDMMC_CDETECT_CARD_DETECT_0); 63124225f53Skettenis } 63224225f53Skettenis 63324225f53Skettenis int 63424225f53Skettenis dwmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 63524225f53Skettenis { 63624225f53Skettenis struct dwmmc_softc *sc = sch; 637d5957df7Skettenis uint32_t vdd = 0; 638d5957df7Skettenis 639d5957df7Skettenis if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) 640d5957df7Skettenis vdd = 3300000; 641d5957df7Skettenis 642d5957df7Skettenis if (sc->sc_vdd == 0 && vdd > 0) 643d5957df7Skettenis dwmmc_pwrseq_pre(sc->sc_pwrseq); 64424225f53Skettenis 64524225f53Skettenis if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) 64624225f53Skettenis HSET4(sc, SDMMC_PWREN, 1); 64724225f53Skettenis else 64824225f53Skettenis HCLR4(sc, SDMMC_PWREN, 0); 64924225f53Skettenis 650d5957df7Skettenis if (sc->sc_vdd == 0 && vdd > 0) 651d5957df7Skettenis dwmmc_pwrseq_post(sc->sc_pwrseq); 652d5957df7Skettenis 653d5957df7Skettenis sc->sc_vdd = vdd; 65424225f53Skettenis return 0; 65524225f53Skettenis } 65624225f53Skettenis 65724225f53Skettenis int 65824225f53Skettenis dwmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) 65924225f53Skettenis { 66024225f53Skettenis struct dwmmc_softc *sc = sch; 66124225f53Skettenis int div = 0, timeout; 662d5957df7Skettenis uint32_t clkena; 66324225f53Skettenis 66424225f53Skettenis HWRITE4(sc, SDMMC_CLKENA, 0); 66524225f53Skettenis HWRITE4(sc, SDMMC_CLKSRC, 0); 66624225f53Skettenis 66724225f53Skettenis if (freq == 0) 66824225f53Skettenis return 0; 66924225f53Skettenis 67024225f53Skettenis if (sc->sc_clkbase / 1000 > freq) { 67124225f53Skettenis for (div = 1; div < 256; div++) 67224225f53Skettenis if (sc->sc_clkbase / (2 * 1000 * div) <= freq) 67324225f53Skettenis break; 67424225f53Skettenis } 67524225f53Skettenis HWRITE4(sc, SDMMC_CLKDIV, div); 67624225f53Skettenis 67724225f53Skettenis /* Update clock. */ 67824225f53Skettenis HWRITE4(sc, SDMMC_CMD, SDMMC_CMD_START_CMD | 67924225f53Skettenis SDMMC_CMD_WAIT_PRVDATA_COMPLETE | 68024225f53Skettenis SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY); 68124225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 68224225f53Skettenis if ((HREAD4(sc, SDMMC_CMD) & SDMMC_CMD_START_CMD) == 0) 68324225f53Skettenis break; 68424225f53Skettenis } 68524225f53Skettenis if (timeout == 0) { 68624225f53Skettenis printf("%s: timeout\n", __func__); 68724225f53Skettenis return ETIMEDOUT; 68824225f53Skettenis } 68924225f53Skettenis 690d5957df7Skettenis /* Enable clock; low power mode only for memory mode. */ 691d5957df7Skettenis clkena = SDMMC_CLKENA_CCLK_ENABLE; 692d5957df7Skettenis if (!sc->sc_sdio_irq) 693d5957df7Skettenis clkena |= SDMMC_CLKENA_CCLK_LOW_POWER; 694d5957df7Skettenis HWRITE4(sc, SDMMC_CLKENA, clkena); 69524225f53Skettenis 69624225f53Skettenis /* Update clock again. */ 69724225f53Skettenis HWRITE4(sc, SDMMC_CMD, SDMMC_CMD_START_CMD | 69824225f53Skettenis SDMMC_CMD_WAIT_PRVDATA_COMPLETE | 69924225f53Skettenis SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY); 70024225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 70124225f53Skettenis if ((HREAD4(sc, SDMMC_CMD) & SDMMC_CMD_START_CMD) == 0) 70224225f53Skettenis break; 70324225f53Skettenis } 70424225f53Skettenis if (timeout == 0) { 70524225f53Skettenis printf("%s: timeout\n", __func__); 70624225f53Skettenis return ETIMEDOUT; 70724225f53Skettenis } 70824225f53Skettenis 70924225f53Skettenis delay(1000000); 71024225f53Skettenis 71124225f53Skettenis return 0; 71224225f53Skettenis } 71324225f53Skettenis 71424225f53Skettenis int 71524225f53Skettenis dwmmc_bus_width(sdmmc_chipset_handle_t sch, int width) 71624225f53Skettenis { 71724225f53Skettenis struct dwmmc_softc *sc = sch; 71824225f53Skettenis 71924225f53Skettenis switch (width) { 72024225f53Skettenis case 1: 72124225f53Skettenis HCLR4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT|SDMMC_CTYPE_4BIT); 72224225f53Skettenis break; 72324225f53Skettenis case 4: 72424225f53Skettenis HSET4(sc, SDMMC_CTYPE, SDMMC_CTYPE_4BIT); 72524225f53Skettenis HCLR4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT); 72624225f53Skettenis break; 72724225f53Skettenis case 8: 72824225f53Skettenis HSET4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT); 72924225f53Skettenis break; 73024225f53Skettenis default: 73124225f53Skettenis return EINVAL; 73224225f53Skettenis } 73324225f53Skettenis 73424225f53Skettenis return 0; 73524225f53Skettenis } 73624225f53Skettenis 7373704a61cSkettenis void 7383704a61cSkettenis dwmmc_pio_mode(struct dwmmc_softc *sc) 7393704a61cSkettenis { 7403704a61cSkettenis /* Disable DMA. */ 7413704a61cSkettenis HCLR4(sc, SDMMC_CTRL, SDMMC_CTRL_USE_INTERNAL_DMAC | 7423704a61cSkettenis SDMMC_CTRL_DMA_ENABLE); 7433704a61cSkettenis 7443704a61cSkettenis /* Set FIFO thresholds. */ 7453704a61cSkettenis HWRITE4(sc, SDMMC_FIFOTH, 2 << SDMMC_FIFOTH_MSIZE_SHIFT | 7463704a61cSkettenis (sc->sc_fifo_depth / 2 - 1) << SDMMC_FIFOTH_RXWM_SHIFT | 7473704a61cSkettenis (sc->sc_fifo_depth / 2) << SDMMC_FIFOTH_TXWM_SHIFT); 7483704a61cSkettenis 7493704a61cSkettenis sc->sc_dmamode = 0; 7503704a61cSkettenis sc->sc_blklen = 0; 7513704a61cSkettenis } 7523704a61cSkettenis 7533704a61cSkettenis void 7543704a61cSkettenis dwmmc_dma_mode(struct dwmmc_softc *sc) 7553704a61cSkettenis { 7563704a61cSkettenis int timeout; 7573704a61cSkettenis 7583704a61cSkettenis /* Reset DMA. */ 7593704a61cSkettenis HSET4(sc, SDMMC_BMOD, SDMMC_BMOD_SWR); 7603704a61cSkettenis for (timeout = 1000; timeout > 0; timeout--) { 7613704a61cSkettenis if ((HREAD4(sc, SDMMC_BMOD) & SDMMC_BMOD_SWR) == 0) 7623704a61cSkettenis break; 7633704a61cSkettenis delay(100); 7643704a61cSkettenis } 7653704a61cSkettenis if (timeout == 0) 7663704a61cSkettenis printf("%s: DMA reset failed\n", sc->sc_dev.dv_xname); 7673704a61cSkettenis 7683704a61cSkettenis /* Enable DMA. */ 7693704a61cSkettenis HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_USE_INTERNAL_DMAC | 7703704a61cSkettenis SDMMC_CTRL_DMA_ENABLE); 7713704a61cSkettenis HSET4(sc, SDMMC_BMOD, SDMMC_BMOD_FB | SDMMC_BMOD_DE); 7723704a61cSkettenis 7733704a61cSkettenis sc->sc_dmamode = 1; 7743704a61cSkettenis } 7753704a61cSkettenis 7763704a61cSkettenis void 7774df26cf2Skettenis dwmmc_dma_setup32(struct dwmmc_softc *sc, struct sdmmc_command *cmd) 778b9e8b644Skettenis { 7794df26cf2Skettenis struct dwmmc_desc32 *desc = (void *)sc->sc_desc; 780b9e8b644Skettenis uint32_t flags; 781b9e8b644Skettenis int seg; 782b9e8b644Skettenis 783b9e8b644Skettenis flags = DES0_OWN | DES0_FS | DES0_CH | DES0_DIC; 784b9e8b644Skettenis for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { 785b9e8b644Skettenis bus_addr_t addr = cmd->c_dmamap->dm_segs[seg].ds_addr; 786b9e8b644Skettenis bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len; 787b9e8b644Skettenis 788b9e8b644Skettenis if (seg == cmd->c_dmamap->dm_nsegs - 1) { 789b9e8b644Skettenis flags |= DES0_LD; 790b9e8b644Skettenis flags &= ~DES0_DIC; 791b9e8b644Skettenis } 792b9e8b644Skettenis 793b9e8b644Skettenis KASSERT((desc[seg].des[0] & DES0_OWN) == 0); 794b9e8b644Skettenis desc[seg].des[0] = flags; 795b9e8b644Skettenis desc[seg].des[1] = DES1_BS1(len); 796b9e8b644Skettenis desc[seg].des[2] = addr; 797b9e8b644Skettenis flags &= ~DES0_FS; 798b9e8b644Skettenis } 7994df26cf2Skettenis } 8004df26cf2Skettenis 8014df26cf2Skettenis void 8024df26cf2Skettenis dwmmc_dma_setup64(struct dwmmc_softc *sc, struct sdmmc_command *cmd) 8034df26cf2Skettenis { 8044df26cf2Skettenis struct dwmmc_desc64 *desc = (void *)sc->sc_desc; 8054df26cf2Skettenis uint32_t flags; 8064df26cf2Skettenis int seg; 8074df26cf2Skettenis 8084df26cf2Skettenis flags = DES0_OWN | DES0_FS | DES0_CH | DES0_DIC; 8094df26cf2Skettenis for (seg = 0; seg < cmd->c_dmamap->dm_nsegs; seg++) { 8104df26cf2Skettenis bus_addr_t addr = cmd->c_dmamap->dm_segs[seg].ds_addr; 8114df26cf2Skettenis bus_size_t len = cmd->c_dmamap->dm_segs[seg].ds_len; 8124df26cf2Skettenis 8134df26cf2Skettenis if (seg == cmd->c_dmamap->dm_nsegs - 1) { 8144df26cf2Skettenis flags |= DES0_LD; 8154df26cf2Skettenis flags &= ~DES0_DIC; 8164df26cf2Skettenis } 8174df26cf2Skettenis 8184df26cf2Skettenis KASSERT((desc[seg].des[0] & DES0_OWN) == 0); 8194df26cf2Skettenis desc[seg].des[0] = flags; 8204df26cf2Skettenis desc[seg].des[2] = DES2_BS1(len); 8214df26cf2Skettenis desc[seg].des[4] = addr; 8224df26cf2Skettenis desc[seg].des[5] = (uint64_t)addr >> 32; 8234df26cf2Skettenis flags &= ~DES0_FS; 8244df26cf2Skettenis } 8254df26cf2Skettenis } 8264df26cf2Skettenis 8274df26cf2Skettenis void 8284df26cf2Skettenis dwmmc_dma_setup(struct dwmmc_softc *sc, struct sdmmc_command *cmd) 8294df26cf2Skettenis { 8304df26cf2Skettenis if (sc->sc_dma64) 8314df26cf2Skettenis dwmmc_dma_setup64(sc, cmd); 8324df26cf2Skettenis else 8334df26cf2Skettenis dwmmc_dma_setup32(sc, cmd); 834b9e8b644Skettenis 835b9e8b644Skettenis bus_dmamap_sync(sc->sc_dmat, sc->sc_desc_map, 0, PAGE_SIZE, 836b9e8b644Skettenis BUS_DMASYNC_PREWRITE); 837b9e8b644Skettenis 838b9e8b644Skettenis sc->sc_idsts = 0; 8393704a61cSkettenis } 8403704a61cSkettenis 8413704a61cSkettenis void 8423704a61cSkettenis dwmmc_dma_reset(struct dwmmc_softc *sc, struct sdmmc_command *cmd) 8433704a61cSkettenis { 8443704a61cSkettenis int timeout; 8453704a61cSkettenis 8463704a61cSkettenis /* Reset DMA unit. */ 8473704a61cSkettenis HSET4(sc, SDMMC_BMOD, SDMMC_BMOD_SWR); 8483704a61cSkettenis for (timeout = 1000; timeout > 0; timeout--) { 8493704a61cSkettenis if ((HREAD4(sc, SDMMC_BMOD) & 8503704a61cSkettenis SDMMC_BMOD_SWR) == 0) 8513704a61cSkettenis break; 8523704a61cSkettenis delay(100); 8533704a61cSkettenis } 8543704a61cSkettenis 8553704a61cSkettenis dwmmc_pio_mode(sc); 8563704a61cSkettenis 8573704a61cSkettenis /* Clear descriptors that were in use, */ 8583704a61cSkettenis memset(sc->sc_desc, 0, PAGE_SIZE); 8593704a61cSkettenis dwmmc_init_descriptors(sc); 8603704a61cSkettenis } 8613704a61cSkettenis 8623704a61cSkettenis void 8633704a61cSkettenis dwmmc_fifo_setup(struct dwmmc_softc *sc, int blklen) 8643704a61cSkettenis { 8653704a61cSkettenis int blkdepth = blklen / sc->sc_fifo_width; 8663704a61cSkettenis int txwm = sc->sc_fifo_depth / 2; 8673704a61cSkettenis int rxwm, msize = 0; 8683704a61cSkettenis 8693704a61cSkettenis /* 8703704a61cSkettenis * Bursting is only possible of the block size is a multiple of 8713704a61cSkettenis * the FIFO width. 8723704a61cSkettenis */ 8733704a61cSkettenis if (blklen % sc->sc_fifo_width == 0) 8743704a61cSkettenis msize = 7; 8753704a61cSkettenis 8763704a61cSkettenis /* Magic to calculate the maximum burst size. */ 8773704a61cSkettenis while (msize > 0) { 8783704a61cSkettenis if (blkdepth % (2 << msize) == 0 && 8793704a61cSkettenis (sc->sc_fifo_depth - txwm) % (2 << msize) == 0) 8803704a61cSkettenis break; 8813704a61cSkettenis msize--; 8823704a61cSkettenis } 8833704a61cSkettenis rxwm = (2 << msize) - 1; 8843704a61cSkettenis 8853704a61cSkettenis HWRITE4(sc, SDMMC_FIFOTH, 8863704a61cSkettenis msize << SDMMC_FIFOTH_MSIZE_SHIFT | 8873704a61cSkettenis rxwm << SDMMC_FIFOTH_RXWM_SHIFT | 8883704a61cSkettenis txwm << SDMMC_FIFOTH_TXWM_SHIFT); 8893704a61cSkettenis 8903704a61cSkettenis sc->sc_blklen = blklen; 891b9e8b644Skettenis } 892b9e8b644Skettenis 89324225f53Skettenis void 89424225f53Skettenis dwmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 89524225f53Skettenis { 89624225f53Skettenis struct dwmmc_softc *sc = sch; 89724225f53Skettenis uint32_t cmdval = SDMMC_CMD_START_CMD | SDMMC_CMD_USE_HOLD_REG; 89824225f53Skettenis uint32_t status; 899b9e8b644Skettenis int error, timeout; 90024225f53Skettenis int s; 90124225f53Skettenis 90224225f53Skettenis #if 0 90324225f53Skettenis printf("%s: cmd %d arg 0x%x flags 0x%x data %p datalen %d blklen %d\n", 90424225f53Skettenis sc->sc_dev.dv_xname, cmd->c_opcode, cmd->c_arg, cmd->c_flags, 90524225f53Skettenis cmd->c_data, cmd->c_datalen, cmd->c_blklen); 90624225f53Skettenis #endif 90724225f53Skettenis 90824225f53Skettenis s = splbio(); 90924225f53Skettenis 910e036655fSkettenis for (timeout = 10000; timeout > 0; timeout--) { 91124225f53Skettenis status = HREAD4(sc, SDMMC_STATUS); 91224225f53Skettenis if ((status & SDMMC_STATUS_DATA_BUSY) == 0) 91324225f53Skettenis break; 91424225f53Skettenis delay(100); 91524225f53Skettenis } 91624225f53Skettenis if (timeout == 0) { 91724225f53Skettenis printf("%s: timeout on data busy\n", sc->sc_dev.dv_xname); 91824225f53Skettenis goto done; 91924225f53Skettenis } 92024225f53Skettenis 92124225f53Skettenis if (cmd->c_opcode == MMC_STOP_TRANSMISSION) 92224225f53Skettenis cmdval |= SDMMC_CMD_STOP_ABORT_CMD; 92324225f53Skettenis else if (cmd->c_opcode != MMC_SEND_STATUS) 92424225f53Skettenis cmdval |= SDMMC_CMD_WAIT_PRVDATA_COMPLETE; 92524225f53Skettenis 92624225f53Skettenis if (cmd->c_opcode == 0) 92724225f53Skettenis cmdval |= SDMMC_CMD_SEND_INITIALIZATION; 92824225f53Skettenis if (cmd->c_flags & SCF_RSP_PRESENT) 92924225f53Skettenis cmdval |= SDMMC_CMD_RESPONSE_EXPECT; 93024225f53Skettenis if (cmd->c_flags & SCF_RSP_136) 93124225f53Skettenis cmdval |= SDMMC_CMD_RESPONSE_LENGTH; 93224225f53Skettenis if (cmd->c_flags & SCF_RSP_CRC) 93324225f53Skettenis cmdval |= SDMMC_CMD_CHECK_REPONSE_CRC; 93424225f53Skettenis 93524225f53Skettenis if (cmd->c_datalen > 0) { 93624225f53Skettenis HWRITE4(sc, SDMMC_TMOUT, 0xffffffff); 93724225f53Skettenis HWRITE4(sc, SDMMC_BYTCNT, cmd->c_datalen); 93824225f53Skettenis HWRITE4(sc, SDMMC_BLKSIZ, cmd->c_blklen); 93924225f53Skettenis 940d5957df7Skettenis if (ISSET(cmd->c_flags, SCF_CMD_READ)) { 941d5957df7Skettenis /* Set card read threshold to the size of a block. */ 942d5957df7Skettenis HWRITE4(sc, SDMMC_CARDTHRCTL, 943d5957df7Skettenis cmd->c_blklen << SDMMC_CARDTHRCTL_RDTHR_SHIFT | 944d5957df7Skettenis SDMMC_CARDTHRCTL_RDTHREN); 945d5957df7Skettenis } 946d5957df7Skettenis 94724225f53Skettenis cmdval |= SDMMC_CMD_DATA_EXPECTED; 94824225f53Skettenis if (!ISSET(cmd->c_flags, SCF_CMD_READ)) 94924225f53Skettenis cmdval |= SDMMC_CMD_WR; 9503704a61cSkettenis if (cmd->c_datalen > cmd->c_blklen && 9513704a61cSkettenis cmd->c_opcode != SD_IO_RW_EXTENDED) 9523704a61cSkettenis cmdval |= SDMMC_CMD_SEND_AUTO_STOP; 95324225f53Skettenis } 95424225f53Skettenis 955b9e8b644Skettenis if (cmd->c_datalen > 0 && !cmd->c_dmamap) { 956b9e8b644Skettenis HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET); 957b9e8b644Skettenis for (timeout = 1000; timeout > 0; timeout--) { 958b9e8b644Skettenis if ((HREAD4(sc, SDMMC_CTRL) & 959b9e8b644Skettenis SDMMC_CTRL_FIFO_RESET) == 0) 960b9e8b644Skettenis break; 961b9e8b644Skettenis delay(100); 962b9e8b644Skettenis } 963b9e8b644Skettenis if (timeout == 0) 964b9e8b644Skettenis printf("%s: FIFO reset failed\n", sc->sc_dev.dv_xname); 965b9e8b644Skettenis 9663704a61cSkettenis /* Disable DMA if we are switching back to PIO. */ 9673704a61cSkettenis if (sc->sc_dmamode) 9683704a61cSkettenis dwmmc_pio_mode(sc); 969b9e8b644Skettenis } 970b9e8b644Skettenis 971b9e8b644Skettenis if (cmd->c_datalen > 0 && cmd->c_dmamap) { 972b9e8b644Skettenis dwmmc_dma_setup(sc, cmd); 9733704a61cSkettenis HWRITE4(sc, SDMMC_PLDMND, 1); 974b9e8b644Skettenis 9754b1a56afSjsg /* Enable DMA if we did PIO before. */ 9763704a61cSkettenis if (!sc->sc_dmamode) 9773704a61cSkettenis dwmmc_dma_mode(sc); 978b9e8b644Skettenis 9793704a61cSkettenis /* Reconfigure FIFO thresholds if block size changed. */ 9803704a61cSkettenis if (cmd->c_blklen != sc->sc_blklen) 9813704a61cSkettenis dwmmc_fifo_setup(sc, cmd->c_blklen); 982b9e8b644Skettenis } 983b9e8b644Skettenis 984d5957df7Skettenis HWRITE4(sc, SDMMC_RINTSTS, ~SDMMC_RINTSTS_SDIO); 98524225f53Skettenis 98624225f53Skettenis HWRITE4(sc, SDMMC_CMDARG, cmd->c_arg); 98724225f53Skettenis HWRITE4(sc, SDMMC_CMD, cmdval | cmd->c_opcode); 98824225f53Skettenis 98924225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 99024225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 99124225f53Skettenis if (status & SDMMC_RINTSTS_CD) 99224225f53Skettenis break; 99324225f53Skettenis delay(100); 99424225f53Skettenis } 99524225f53Skettenis if (timeout == 0 || status & SDMMC_RINTSTS_RTO) { 99624225f53Skettenis cmd->c_error = ETIMEDOUT; 9973704a61cSkettenis dwmmc_dma_reset(sc, cmd); 99824225f53Skettenis goto done; 99924225f53Skettenis } 100024225f53Skettenis 100124225f53Skettenis if (cmd->c_flags & SCF_RSP_PRESENT) { 100224225f53Skettenis if (cmd->c_flags & SCF_RSP_136) { 100324225f53Skettenis cmd->c_resp[0] = HREAD4(sc, SDMMC_RESP0); 100424225f53Skettenis cmd->c_resp[1] = HREAD4(sc, SDMMC_RESP1); 100524225f53Skettenis cmd->c_resp[2] = HREAD4(sc, SDMMC_RESP2); 100624225f53Skettenis cmd->c_resp[3] = HREAD4(sc, SDMMC_RESP3); 100724225f53Skettenis if (cmd->c_flags & SCF_RSP_CRC) { 100824225f53Skettenis cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 100924225f53Skettenis (cmd->c_resp[1] << 24); 101024225f53Skettenis cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 101124225f53Skettenis (cmd->c_resp[2] << 24); 101224225f53Skettenis cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 101324225f53Skettenis (cmd->c_resp[3] << 24); 101424225f53Skettenis cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 101524225f53Skettenis } 101624225f53Skettenis } else { 101724225f53Skettenis cmd->c_resp[0] = HREAD4(sc, SDMMC_RESP0); 101824225f53Skettenis } 101924225f53Skettenis } 102024225f53Skettenis 1021b9e8b644Skettenis if (cmd->c_datalen > 0 && !cmd->c_dmamap) 102224225f53Skettenis dwmmc_transfer_data(sc, cmd); 102324225f53Skettenis 1024b9e8b644Skettenis if (cmd->c_datalen > 0 && cmd->c_dmamap) { 1025b9e8b644Skettenis while (sc->sc_idsts == 0) { 10268544fed6Smpi error = tsleep_nsec(&sc->sc_idsts, PWAIT, "idsts", 10278544fed6Smpi SEC_TO_NSEC(1)); 1028b9e8b644Skettenis if (error) { 1029b9e8b644Skettenis cmd->c_error = error; 10303704a61cSkettenis dwmmc_dma_reset(sc, cmd); 1031b9e8b644Skettenis goto done; 1032b9e8b644Skettenis } 1033b9e8b644Skettenis } 1034b9e8b644Skettenis 1035b9e8b644Skettenis for (timeout = 10000; timeout > 0; timeout--) { 1036b9e8b644Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 1037b9e8b644Skettenis if (status & SDMMC_RINTSTS_DTO) 1038b9e8b644Skettenis break; 1039b9e8b644Skettenis delay(100); 1040b9e8b644Skettenis } 1041b9e8b644Skettenis if (timeout == 0) { 1042b9e8b644Skettenis cmd->c_error = ETIMEDOUT; 10433704a61cSkettenis dwmmc_dma_reset(sc, cmd); 1044b9e8b644Skettenis goto done; 1045b9e8b644Skettenis } 1046b9e8b644Skettenis } 1047b9e8b644Skettenis 104824225f53Skettenis if (cmdval & SDMMC_CMD_SEND_AUTO_STOP) { 104924225f53Skettenis for (timeout = 10000; timeout > 0; timeout--) { 105024225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 10511f08c36fSkettenis if (status & SDMMC_RINTSTS_ACD) 105224225f53Skettenis break; 105324225f53Skettenis delay(10); 105424225f53Skettenis } 105524225f53Skettenis if (timeout == 0) { 105624225f53Skettenis cmd->c_error = ETIMEDOUT; 10573704a61cSkettenis dwmmc_dma_reset(sc, cmd); 105824225f53Skettenis goto done; 105924225f53Skettenis } 106024225f53Skettenis } 106124225f53Skettenis 106224225f53Skettenis done: 106324225f53Skettenis cmd->c_flags |= SCF_ITSDONE; 106424225f53Skettenis #if 0 106524225f53Skettenis printf("%s: err %d rintsts 0x%x\n", sc->sc_dev.dv_xname, cmd->c_error, 106624225f53Skettenis HREAD4(sc, SDMMC_RINTSTS)); 106724225f53Skettenis #endif 106824225f53Skettenis splx(s); 106924225f53Skettenis } 107024225f53Skettenis 107124225f53Skettenis void 107224225f53Skettenis dwmmc_transfer_data(struct dwmmc_softc *sc, struct sdmmc_command *cmd) 107324225f53Skettenis { 107424225f53Skettenis int datalen = cmd->c_datalen; 107524225f53Skettenis u_char *datap = cmd->c_data; 107624225f53Skettenis uint32_t status; 107724225f53Skettenis int count, timeout; 107870864666Skettenis int fifodr = SDMMC_RINTSTS_DTO | SDMMC_RINTSTS_HTO; 107924225f53Skettenis 108024225f53Skettenis if (ISSET(cmd->c_flags, SCF_CMD_READ)) 108124225f53Skettenis fifodr |= SDMMC_RINTSTS_RXDR; 108224225f53Skettenis else 108324225f53Skettenis fifodr |= SDMMC_RINTSTS_TXDR; 108424225f53Skettenis 108524225f53Skettenis while (datalen > 0) { 108624225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 108724225f53Skettenis if (status & SDMMC_RINTSTS_DATA_ERR) { 108824225f53Skettenis cmd->c_error = EIO; 108924225f53Skettenis return; 109024225f53Skettenis } 109170864666Skettenis if (status & SDMMC_RINTSTS_DRTO) { 109224225f53Skettenis cmd->c_error = ETIMEDOUT; 109324225f53Skettenis return; 109424225f53Skettenis } 109524225f53Skettenis 109624225f53Skettenis for (timeout = 10000; timeout > 0; timeout--) { 109724225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 109824225f53Skettenis if (status & fifodr) 109924225f53Skettenis break; 110024225f53Skettenis delay(100); 110124225f53Skettenis } 110224225f53Skettenis if (timeout == 0) { 110324225f53Skettenis cmd->c_error = ETIMEDOUT; 110424225f53Skettenis return; 110524225f53Skettenis } 110624225f53Skettenis 110724225f53Skettenis count = SDMMC_STATUS_FIFO_COUNT(HREAD4(sc, SDMMC_STATUS)); 110824225f53Skettenis if (!ISSET(cmd->c_flags, SCF_CMD_READ)) 110924225f53Skettenis count = sc->sc_fifo_depth - count; 111024225f53Skettenis 111170864666Skettenis count = MIN(datalen, count * sc->sc_fifo_width); 111224225f53Skettenis if (ISSET(cmd->c_flags, SCF_CMD_READ)) 111370864666Skettenis sc->sc_read_data(sc, datap, count); 111424225f53Skettenis else 111570864666Skettenis sc->sc_write_data(sc, datap, count); 111624225f53Skettenis 111724225f53Skettenis datap += count; 111824225f53Skettenis datalen -= count; 111924225f53Skettenis } 112024225f53Skettenis 1121e036655fSkettenis for (timeout = 10000; timeout > 0; timeout--) { 112224225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 112324225f53Skettenis if (status & SDMMC_RINTSTS_DTO) 112424225f53Skettenis break; 112524225f53Skettenis delay(100); 112624225f53Skettenis } 112724225f53Skettenis if (timeout == 0) 112824225f53Skettenis cmd->c_error = ETIMEDOUT; 112924225f53Skettenis } 113024225f53Skettenis 113124225f53Skettenis void 113270864666Skettenis dwmmc_read_data32(struct dwmmc_softc *sc, u_char *datap, int datalen) 113324225f53Skettenis { 113424225f53Skettenis while (datalen > 3) { 113524225f53Skettenis *(uint32_t *)datap = HREAD4(sc, SDMMC_FIFO_BASE); 113624225f53Skettenis datap += 4; 113724225f53Skettenis datalen -= 4; 113824225f53Skettenis } 113924225f53Skettenis if (datalen > 0) { 114024225f53Skettenis uint32_t rv = HREAD4(sc, SDMMC_FIFO_BASE); 114124225f53Skettenis do { 114224225f53Skettenis *datap++ = rv & 0xff; 114324225f53Skettenis rv = rv >> 8; 114424225f53Skettenis } while (--datalen > 0); 114524225f53Skettenis } 114624225f53Skettenis HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_RXDR); 114724225f53Skettenis } 114824225f53Skettenis 114924225f53Skettenis void 115070864666Skettenis dwmmc_write_data32(struct dwmmc_softc *sc, u_char *datap, int datalen) 115124225f53Skettenis { 115224225f53Skettenis while (datalen > 3) { 115324225f53Skettenis HWRITE4(sc, SDMMC_FIFO_BASE, *((uint32_t *)datap)); 115424225f53Skettenis datap += 4; 115524225f53Skettenis datalen -= 4; 115624225f53Skettenis } 115724225f53Skettenis if (datalen > 0) { 115824225f53Skettenis uint32_t rv = *datap++; 115924225f53Skettenis if (datalen > 1) 116024225f53Skettenis rv |= *datap++ << 8; 116124225f53Skettenis if (datalen > 2) 116224225f53Skettenis rv |= *datap++ << 16; 116324225f53Skettenis HWRITE4(sc, SDMMC_FIFO_BASE, rv); 116424225f53Skettenis } 116524225f53Skettenis HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_TXDR); 116624225f53Skettenis } 116770864666Skettenis 116870864666Skettenis void 116970864666Skettenis dwmmc_read_data64(struct dwmmc_softc *sc, u_char *datap, int datalen) 117070864666Skettenis { 117170864666Skettenis while (datalen > 7) { 117270864666Skettenis *(uint32_t *)datap = HREAD4(sc, SDMMC_FIFO_BASE); 117370864666Skettenis datap += 4; 117470864666Skettenis datalen -= 4; 117570864666Skettenis *(uint32_t *)datap = HREAD4(sc, SDMMC_FIFO_BASE + 4); 117670864666Skettenis datap += 4; 117770864666Skettenis datalen -= 4; 117870864666Skettenis } 117970864666Skettenis if (datalen > 0) { 118070864666Skettenis uint64_t rv = HREAD4(sc, SDMMC_FIFO_BASE) | 118170864666Skettenis ((uint64_t)HREAD4(sc, SDMMC_FIFO_BASE + 4) << 32); 118270864666Skettenis do { 118370864666Skettenis *datap++ = rv & 0xff; 118470864666Skettenis rv = rv >> 8; 118570864666Skettenis } while (--datalen > 0); 118670864666Skettenis } 118770864666Skettenis HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_RXDR); 118870864666Skettenis } 118970864666Skettenis 119070864666Skettenis void 119170864666Skettenis dwmmc_write_data64(struct dwmmc_softc *sc, u_char *datap, int datalen) 119270864666Skettenis { 119370864666Skettenis while (datalen > 7) { 119470864666Skettenis HWRITE4(sc, SDMMC_FIFO_BASE, *((uint32_t *)datap)); 119570864666Skettenis datap += 4; 119670864666Skettenis datalen -= 4; 119770864666Skettenis HWRITE4(sc, SDMMC_FIFO_BASE + 4, *((uint32_t *)datap)); 119870864666Skettenis datap += 4; 119970864666Skettenis datalen -= 4; 120070864666Skettenis } 120170864666Skettenis if (datalen > 0) { 120270864666Skettenis uint32_t rv = *datap++; 120370864666Skettenis if (datalen > 1) 120470864666Skettenis rv |= *datap++ << 8; 120570864666Skettenis if (datalen > 2) 120670864666Skettenis rv |= *datap++ << 16; 120770864666Skettenis if (datalen > 3) 120870864666Skettenis rv |= *datap++ << 24; 120970864666Skettenis HWRITE4(sc, SDMMC_FIFO_BASE, rv); 121070864666Skettenis if (datalen > 4) 121170864666Skettenis rv = *datap++; 121270864666Skettenis if (datalen > 5) 121370864666Skettenis rv |= *datap++ << 8; 121470864666Skettenis if (datalen > 6) 121570864666Skettenis rv |= *datap++ << 16; 121670864666Skettenis HWRITE4(sc, SDMMC_FIFO_BASE + 4, rv); 121770864666Skettenis } 121870864666Skettenis HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_TXDR); 121970864666Skettenis } 1220d5957df7Skettenis 1221d5957df7Skettenis void 1222d5957df7Skettenis dwmmc_pwrseq_pre(uint32_t phandle) 1223d5957df7Skettenis { 1224d5957df7Skettenis uint32_t *gpios, *gpio; 1225d5957df7Skettenis int node; 1226d5957df7Skettenis int len; 1227d5957df7Skettenis 1228d5957df7Skettenis node = OF_getnodebyphandle(phandle); 1229d5957df7Skettenis if (node == 0) 1230d5957df7Skettenis return; 1231d5957df7Skettenis 1232d5957df7Skettenis if (!OF_is_compatible(node, "mmc-pwrseq-simple")) 1233d5957df7Skettenis return; 1234d5957df7Skettenis 1235d5957df7Skettenis pinctrl_byname(node, "default"); 1236d5957df7Skettenis 1237d5957df7Skettenis clock_enable(node, "ext_clock"); 1238d5957df7Skettenis 1239d5957df7Skettenis len = OF_getproplen(node, "reset-gpios"); 1240d5957df7Skettenis if (len <= 0) 1241d5957df7Skettenis return; 1242d5957df7Skettenis 1243d5957df7Skettenis gpios = malloc(len, M_TEMP, M_WAITOK); 1244d5957df7Skettenis OF_getpropintarray(node, "reset-gpios", gpios, len); 1245d5957df7Skettenis 1246d5957df7Skettenis gpio = gpios; 1247d5957df7Skettenis while (gpio && gpio < gpios + (len / sizeof(uint32_t))) { 1248d5957df7Skettenis gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); 1249d5957df7Skettenis gpio_controller_set_pin(gpio, 1); 1250d5957df7Skettenis gpio = gpio_controller_next_pin(gpio); 1251d5957df7Skettenis } 1252d5957df7Skettenis 1253d5957df7Skettenis free(gpios, M_TEMP, len); 1254d5957df7Skettenis } 1255d5957df7Skettenis 1256d5957df7Skettenis void 1257d5957df7Skettenis dwmmc_pwrseq_post(uint32_t phandle) 1258d5957df7Skettenis { 1259d5957df7Skettenis uint32_t *gpios, *gpio; 12604c69420eSkettenis int post_delay; 1261d5957df7Skettenis int node; 1262d5957df7Skettenis int len; 1263d5957df7Skettenis 1264d5957df7Skettenis node = OF_getnodebyphandle(phandle); 1265d5957df7Skettenis if (node == 0) 1266d5957df7Skettenis return; 1267d5957df7Skettenis 1268d5957df7Skettenis if (!OF_is_compatible(node, "mmc-pwrseq-simple")) 1269d5957df7Skettenis return; 1270d5957df7Skettenis 1271d5957df7Skettenis len = OF_getproplen(node, "reset-gpios"); 1272d5957df7Skettenis if (len <= 0) 1273d5957df7Skettenis return; 1274d5957df7Skettenis 1275d5957df7Skettenis gpios = malloc(len, M_TEMP, M_WAITOK); 1276d5957df7Skettenis OF_getpropintarray(node, "reset-gpios", gpios, len); 1277d5957df7Skettenis 1278d5957df7Skettenis gpio = gpios; 1279d5957df7Skettenis while (gpio && gpio < gpios + (len / sizeof(uint32_t))) { 1280d5957df7Skettenis gpio_controller_set_pin(gpio, 0); 1281d5957df7Skettenis gpio = gpio_controller_next_pin(gpio); 1282d5957df7Skettenis } 1283d5957df7Skettenis 12844c69420eSkettenis post_delay = OF_getpropint(node, "post-power-on-delay-ms", 0); 12854c69420eSkettenis if (post_delay) 12864c69420eSkettenis delay(post_delay * 1000); 12874c69420eSkettenis 1288d5957df7Skettenis free(gpios, M_TEMP, len); 1289d5957df7Skettenis } 1290*98e9fa9cSpatrick 1291*98e9fa9cSpatrick int 1292*98e9fa9cSpatrick dwmmc_signal_voltage(sdmmc_chipset_handle_t sch, int signal_voltage) 1293*98e9fa9cSpatrick { 1294*98e9fa9cSpatrick struct dwmmc_softc *sc = sch; 1295*98e9fa9cSpatrick uint32_t vccq; 1296*98e9fa9cSpatrick 1297*98e9fa9cSpatrick if (sc->sc_vqmmc == 0) 1298*98e9fa9cSpatrick return ENODEV; 1299*98e9fa9cSpatrick 1300*98e9fa9cSpatrick switch (signal_voltage) { 1301*98e9fa9cSpatrick case SDMMC_SIGNAL_VOLTAGE_180: 1302*98e9fa9cSpatrick vccq = 1800000; 1303*98e9fa9cSpatrick break; 1304*98e9fa9cSpatrick case SDMMC_SIGNAL_VOLTAGE_330: 1305*98e9fa9cSpatrick vccq = 3300000; 1306*98e9fa9cSpatrick break; 1307*98e9fa9cSpatrick default: 1308*98e9fa9cSpatrick return EINVAL; 1309*98e9fa9cSpatrick } 1310*98e9fa9cSpatrick 1311*98e9fa9cSpatrick if (regulator_get_voltage(sc->sc_vqmmc) == vccq) 1312*98e9fa9cSpatrick return 0; 1313*98e9fa9cSpatrick 1314*98e9fa9cSpatrick return regulator_set_voltage(sc->sc_vqmmc, vccq); 1315*98e9fa9cSpatrick } 1316