1*24225f53Skettenis /* $OpenBSD: dwmmc.c,v 1.1 2017/05/21 08:59:45 kettenis Exp $ */ 2*24225f53Skettenis /* 3*24225f53Skettenis * Copyright (c) 2017 Mark Kettenis 4*24225f53Skettenis * 5*24225f53Skettenis * Permission to use, copy, modify, and distribute this software for any 6*24225f53Skettenis * purpose with or without fee is hereby granted, provided that the above 7*24225f53Skettenis * copyright notice and this permission notice appear in all copies. 8*24225f53Skettenis * 9*24225f53Skettenis * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10*24225f53Skettenis * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11*24225f53Skettenis * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12*24225f53Skettenis * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13*24225f53Skettenis * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14*24225f53Skettenis * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15*24225f53Skettenis * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16*24225f53Skettenis */ 17*24225f53Skettenis 18*24225f53Skettenis #include <sys/param.h> 19*24225f53Skettenis #include <sys/malloc.h> 20*24225f53Skettenis #include <sys/systm.h> 21*24225f53Skettenis 22*24225f53Skettenis #include <machine/bus.h> 23*24225f53Skettenis #include <machine/fdt.h> 24*24225f53Skettenis #include <machine/intr.h> 25*24225f53Skettenis 26*24225f53Skettenis #include <dev/ofw/openfirm.h> 27*24225f53Skettenis #include <dev/ofw/ofw_clock.h> 28*24225f53Skettenis #include <dev/ofw/ofw_pinctrl.h> 29*24225f53Skettenis #include <dev/ofw/fdt.h> 30*24225f53Skettenis 31*24225f53Skettenis #include <dev/sdmmc/sdmmcvar.h> 32*24225f53Skettenis 33*24225f53Skettenis #define SDMMC_CTRL 0x0000 34*24225f53Skettenis #define SDMMC_CTRL_USE_INTERNAL_DMAC (1 << 25) 35*24225f53Skettenis #define SDMMC_CTRL_DMA_RESET (1 << 3) 36*24225f53Skettenis #define SDMMC_CTRL_FIFO_RESET (1 << 2) 37*24225f53Skettenis #define SDMMC_CTRL_CONTROLLER_RESET (1 << 3) 38*24225f53Skettenis #define SDMMC_CTRL_ALL_RESET (SDMMC_CTRL_CONTROLLER_RESET | \ 39*24225f53Skettenis SDMMC_CTRL_FIFO_RESET | SDMMC_CTRL_DMA_RESET) 40*24225f53Skettenis #define SDMMC_PWREN 0x0004 41*24225f53Skettenis #define SDMMC_CLKDIV 0x0008 42*24225f53Skettenis #define SDMMC_CLKSRC 0x000c 43*24225f53Skettenis #define SDMMC_CLKENA 0x0010 44*24225f53Skettenis #define SDMMC_CLKENA_CCLK_LOW_POWER (1 << 16) 45*24225f53Skettenis #define SDMMC_CLKENA_CCLK_ENABLE (1 << 0) 46*24225f53Skettenis #define SDMMC_TMOUT 0x0014 47*24225f53Skettenis #define SDMMC_CTYPE 0x0018 48*24225f53Skettenis #define SDMMC_CTYPE_8BIT (1 << 16) 49*24225f53Skettenis #define SDMMC_CTYPE_4BIT (1 << 0) 50*24225f53Skettenis #define SDMMC_BLKSIZ 0x001c 51*24225f53Skettenis #define SDMMC_BYTCNT 0x0020 52*24225f53Skettenis #define SDMMC_INTMASK 0x0024 53*24225f53Skettenis #define SDMMC_CMDARG 0x0028 54*24225f53Skettenis #define SDMMC_CMD 0x002c 55*24225f53Skettenis #define SDMMC_CMD_START_CMD (1U << 31) 56*24225f53Skettenis #define SDMMC_CMD_USE_HOLD_REG (1 << 29) 57*24225f53Skettenis #define SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY (1 << 21) 58*24225f53Skettenis #define SDMMC_CMD_SEND_INITIALIZATION (1 << 15) 59*24225f53Skettenis #define SDMMC_CMD_STOP_ABORT_CMD (1 << 14) 60*24225f53Skettenis #define SDMMC_CMD_WAIT_PRVDATA_COMPLETE (1 << 13) 61*24225f53Skettenis #define SDMMC_CMD_SEND_AUTO_STOP (1 << 12) 62*24225f53Skettenis #define SDMMC_CMD_WR (1 << 10) 63*24225f53Skettenis #define SDMMC_CMD_DATA_EXPECTED (1 << 9) 64*24225f53Skettenis #define SDMMC_CMD_CHECK_REPONSE_CRC (1 << 8) 65*24225f53Skettenis #define SDMMC_CMD_RESPONSE_LENGTH (1 << 7) 66*24225f53Skettenis #define SDMMC_CMD_RESPONSE_EXPECT (1 << 6) 67*24225f53Skettenis #define SDMMC_RESP0 0x0030 68*24225f53Skettenis #define SDMMC_RESP1 0x0034 69*24225f53Skettenis #define SDMMC_RESP2 0x0038 70*24225f53Skettenis #define SDMMC_RESP3 0x003c 71*24225f53Skettenis #define SDMMC_MINTSTS 0x0040 72*24225f53Skettenis #define SDMMC_RINTSTS 0x0044 73*24225f53Skettenis #define SDMMC_RINTSTS_EBE (1 << 15) 74*24225f53Skettenis #define SDMMC_RINTSTS_ACD (1 << 14) 75*24225f53Skettenis #define SDMMC_RINTSTS_SBE (1 << 13) 76*24225f53Skettenis #define SDMMC_RINTSTS_HLE (1 << 12) 77*24225f53Skettenis #define SDMMC_RINTSTS_FRUN (1 << 11) 78*24225f53Skettenis #define SDMMC_RINTSTS_HTO (1 << 10) 79*24225f53Skettenis #define SDMMC_RINTSTS_DRTO (1 << 9) 80*24225f53Skettenis #define SDMMC_RINTSTS_RTO (1 << 8) 81*24225f53Skettenis #define SDMMC_RINTSTS_DCRC (1 << 7) 82*24225f53Skettenis #define SDMMC_RINTSTS_RCRC (1 << 6) 83*24225f53Skettenis #define SDMMC_RINTSTS_RXDR (1 << 5) 84*24225f53Skettenis #define SDMMC_RINTSTS_TXDR (1 << 4) 85*24225f53Skettenis #define SDMMC_RINTSTS_DTO (1 << 3) 86*24225f53Skettenis #define SDMMC_RINTSTS_CD (1 << 2) 87*24225f53Skettenis #define SDMMC_RINTSTS_RE (1 << 1) 88*24225f53Skettenis #define SDMMC_RINTSTS_CDT (1 << 0) 89*24225f53Skettenis #define SDMMC_RINTSTS_DATA_ERR (SDMMC_RINTSTS_EBE | SDMMC_RINTSTS_SBE | \ 90*24225f53Skettenis SDMMC_RINTSTS_HLE | SDMMC_RINTSTS_FRUN | SDMMC_RINTSTS_DCRC) 91*24225f53Skettenis #define SDMMC_RINTSTS_DATA_TO (SDMMC_RINTSTS_HTO | SDMMC_RINTSTS_DRTO) 92*24225f53Skettenis #define SDMMC_STATUS 0x0048 93*24225f53Skettenis #define SDMMC_STATUS_FIFO_COUNT(x) (((x) >> 17) & 0x1fff) 94*24225f53Skettenis #define SDMMC_STATUS_DATA_BUSY (1 << 9) 95*24225f53Skettenis #define SDMMC_FIFOTH 0x004c 96*24225f53Skettenis #define SDMMC_CDETECT 0x0050 97*24225f53Skettenis #define SDMMC_CDETECT_CARD_DETECT_0 (1 << 0) 98*24225f53Skettenis #define SDMMC_WRTPRT 0x0054 99*24225f53Skettenis #define SDMMC_TCBCNT 0x005c 100*24225f53Skettenis #define SDMMC_TBBCNT 0x0060 101*24225f53Skettenis #define SDMMC_DEBNCE 0x0064 102*24225f53Skettenis #define SDMMC_USRID 0x0068 103*24225f53Skettenis #define SDMMC_VERID 0x006c 104*24225f53Skettenis #define SDMMC_HCON 0x0070 105*24225f53Skettenis #define SDMMC_UHS_REG 0x0074 106*24225f53Skettenis #define SDMMC_RST_n 0x0078 107*24225f53Skettenis #define SDMMC_BMOD 0x0080 108*24225f53Skettenis #define SDMMC_PLDMND 0x0084 109*24225f53Skettenis #define SDMMC_DBADDR 0x0088 110*24225f53Skettenis #define SDMMC_IDSTS 0x008c 111*24225f53Skettenis #define SDMMC_IDINTEN 0x0090 112*24225f53Skettenis #define SDMMC_DSCADDR 0x0094 113*24225f53Skettenis #define SDMMC_BUFADDR 0x0098 114*24225f53Skettenis #define SDMMC_CARDTHRCTL 0x0100 115*24225f53Skettenis #define SDMMC_CARDTHRCTL_RDTHR_SHIFT 16 116*24225f53Skettenis #define SDMMC_CARDTHRCTL_RDTHREN (1 << 0) 117*24225f53Skettenis #define SDMMC_BACK_END_POWER 0x0104 118*24225f53Skettenis #define SDMMC_EMMC_DDR_REG 0x0108 119*24225f53Skettenis #define SDMMC_FIFO_BASE 0x0200 120*24225f53Skettenis 121*24225f53Skettenis #define HREAD4(sc, reg) \ 122*24225f53Skettenis (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 123*24225f53Skettenis #define HWRITE4(sc, reg, val) \ 124*24225f53Skettenis bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 125*24225f53Skettenis #define HSET4(sc, reg, bits) \ 126*24225f53Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) 127*24225f53Skettenis #define HCLR4(sc, reg, bits) \ 128*24225f53Skettenis HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) 129*24225f53Skettenis 130*24225f53Skettenis struct dwmmc_softc { 131*24225f53Skettenis struct device sc_dev; 132*24225f53Skettenis bus_space_tag_t sc_iot; 133*24225f53Skettenis bus_space_handle_t sc_ioh; 134*24225f53Skettenis bus_size_t sc_size; 135*24225f53Skettenis void *sc_ih; 136*24225f53Skettenis 137*24225f53Skettenis uint32_t sc_clkbase; 138*24225f53Skettenis uint32_t sc_fifo_depth; 139*24225f53Skettenis 140*24225f53Skettenis struct device *sc_sdmmc; 141*24225f53Skettenis }; 142*24225f53Skettenis 143*24225f53Skettenis int dwmmc_match(struct device *, void *, void *); 144*24225f53Skettenis void dwmmc_attach(struct device *, struct device *, void *); 145*24225f53Skettenis 146*24225f53Skettenis struct cfattach dwmmc_ca = { 147*24225f53Skettenis sizeof(struct dwmmc_softc), dwmmc_match, dwmmc_attach 148*24225f53Skettenis }; 149*24225f53Skettenis 150*24225f53Skettenis struct cfdriver dwmmc_cd = { 151*24225f53Skettenis NULL, "dwmmc", DV_DULL 152*24225f53Skettenis }; 153*24225f53Skettenis 154*24225f53Skettenis int dwmmc_intr(void *); 155*24225f53Skettenis 156*24225f53Skettenis int dwmmc_host_reset(sdmmc_chipset_handle_t); 157*24225f53Skettenis uint32_t dwmmc_host_ocr(sdmmc_chipset_handle_t); 158*24225f53Skettenis int dwmmc_host_maxblklen(sdmmc_chipset_handle_t); 159*24225f53Skettenis int dwmmc_card_detect(sdmmc_chipset_handle_t); 160*24225f53Skettenis int dwmmc_bus_power(sdmmc_chipset_handle_t, uint32_t); 161*24225f53Skettenis int dwmmc_bus_clock(sdmmc_chipset_handle_t, int, int); 162*24225f53Skettenis int dwmmc_bus_width(sdmmc_chipset_handle_t, int); 163*24225f53Skettenis void dwmmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); 164*24225f53Skettenis 165*24225f53Skettenis struct sdmmc_chip_functions dwmmc_chip_functions = { 166*24225f53Skettenis .host_reset = dwmmc_host_reset, 167*24225f53Skettenis .host_ocr = dwmmc_host_ocr, 168*24225f53Skettenis .host_maxblklen = dwmmc_host_maxblklen, 169*24225f53Skettenis .card_detect = dwmmc_card_detect, 170*24225f53Skettenis .bus_power = dwmmc_bus_power, 171*24225f53Skettenis .bus_clock = dwmmc_bus_clock, 172*24225f53Skettenis .bus_width = dwmmc_bus_width, 173*24225f53Skettenis .exec_command = dwmmc_exec_command, 174*24225f53Skettenis }; 175*24225f53Skettenis 176*24225f53Skettenis void dwmmc_transfer_data(struct dwmmc_softc *, struct sdmmc_command *); 177*24225f53Skettenis void dwmmc_read_data(struct dwmmc_softc *, u_char *, int); 178*24225f53Skettenis void dwmmc_write_data(struct dwmmc_softc *, u_char *, int); 179*24225f53Skettenis 180*24225f53Skettenis int 181*24225f53Skettenis dwmmc_match(struct device *parent, void *match, void *aux) 182*24225f53Skettenis { 183*24225f53Skettenis struct fdt_attach_args *faa = aux; 184*24225f53Skettenis 185*24225f53Skettenis return OF_is_compatible(faa->fa_node, "rockchip,rk3288-dw-mshc"); 186*24225f53Skettenis } 187*24225f53Skettenis 188*24225f53Skettenis void 189*24225f53Skettenis dwmmc_attach(struct device *parent, struct device *self, void *aux) 190*24225f53Skettenis { 191*24225f53Skettenis struct dwmmc_softc *sc = (struct dwmmc_softc *)self; 192*24225f53Skettenis struct fdt_attach_args *faa = aux; 193*24225f53Skettenis struct sdmmcbus_attach_args saa; 194*24225f53Skettenis int timeout; 195*24225f53Skettenis int width; 196*24225f53Skettenis 197*24225f53Skettenis if (faa->fa_nreg < 1) { 198*24225f53Skettenis printf(": no registers\n"); 199*24225f53Skettenis return; 200*24225f53Skettenis } 201*24225f53Skettenis 202*24225f53Skettenis sc->sc_iot = faa->fa_iot; 203*24225f53Skettenis sc->sc_size = faa->fa_reg[0].size; 204*24225f53Skettenis 205*24225f53Skettenis if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 206*24225f53Skettenis faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 207*24225f53Skettenis printf(": can't map registers\n"); 208*24225f53Skettenis return; 209*24225f53Skettenis } 210*24225f53Skettenis 211*24225f53Skettenis pinctrl_byname(faa->fa_node, "default"); 212*24225f53Skettenis 213*24225f53Skettenis clock_enable_all(faa->fa_node); 214*24225f53Skettenis reset_deassert_all(faa->fa_node); 215*24225f53Skettenis 216*24225f53Skettenis sc->sc_clkbase = clock_get_frequency(faa->fa_node, "ciu"); 217*24225f53Skettenis sc->sc_fifo_depth = OF_getpropint(faa->fa_node, "fifo-depth", 64); 218*24225f53Skettenis 219*24225f53Skettenis sc->sc_ih = arm_intr_establish_fdt(faa->fa_node, IPL_BIO, 220*24225f53Skettenis dwmmc_intr, sc, sc->sc_dev.dv_xname); 221*24225f53Skettenis if (sc->sc_ih == NULL) { 222*24225f53Skettenis printf(": can't establish interrupt\n"); 223*24225f53Skettenis goto unmap; 224*24225f53Skettenis } 225*24225f53Skettenis 226*24225f53Skettenis printf("\n"); 227*24225f53Skettenis 228*24225f53Skettenis HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_ALL_RESET); 229*24225f53Skettenis for (timeout = 10000; timeout > 0; timeout--) { 230*24225f53Skettenis if ((HREAD4(sc, SDMMC_CTRL) & SDMMC_CTRL_ALL_RESET) == 0) 231*24225f53Skettenis break; 232*24225f53Skettenis delay(10); 233*24225f53Skettenis } 234*24225f53Skettenis if (timeout == 0) 235*24225f53Skettenis printf("%s: reset failed\n", sc->sc_dev.dv_xname); 236*24225f53Skettenis 237*24225f53Skettenis /* We don't do DMA yet. */ 238*24225f53Skettenis HCLR4(sc, SDMMC_CTRL, SDMMC_CTRL_USE_INTERNAL_DMAC); 239*24225f53Skettenis 240*24225f53Skettenis /* Set card read threshold to the size of a block. */ 241*24225f53Skettenis HWRITE4(sc, SDMMC_CARDTHRCTL, 242*24225f53Skettenis 512 << SDMMC_CARDTHRCTL_RDTHR_SHIFT | SDMMC_CARDTHRCTL_RDTHREN); 243*24225f53Skettenis 244*24225f53Skettenis dwmmc_bus_width(sc, 1); 245*24225f53Skettenis 246*24225f53Skettenis memset(&saa, 0, sizeof(saa)); 247*24225f53Skettenis saa.saa_busname = "sdmmc"; 248*24225f53Skettenis saa.sct = &dwmmc_chip_functions; 249*24225f53Skettenis saa.sch = sc; 250*24225f53Skettenis 251*24225f53Skettenis width = OF_getpropint(faa->fa_node, "bus-width", 1); 252*24225f53Skettenis if (width >= 8) 253*24225f53Skettenis saa.caps |= SMC_CAPS_8BIT_MODE; 254*24225f53Skettenis if (width >= 4) 255*24225f53Skettenis saa.caps |= SMC_CAPS_4BIT_MODE; 256*24225f53Skettenis 257*24225f53Skettenis sc->sc_sdmmc = config_found(self, &saa, NULL); 258*24225f53Skettenis return; 259*24225f53Skettenis 260*24225f53Skettenis unmap: 261*24225f53Skettenis bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size); 262*24225f53Skettenis } 263*24225f53Skettenis 264*24225f53Skettenis int 265*24225f53Skettenis dwmmc_intr(void *arg) 266*24225f53Skettenis { 267*24225f53Skettenis return 1; 268*24225f53Skettenis } 269*24225f53Skettenis 270*24225f53Skettenis int 271*24225f53Skettenis dwmmc_host_reset(sdmmc_chipset_handle_t sch) 272*24225f53Skettenis { 273*24225f53Skettenis printf("%s\n", __func__); 274*24225f53Skettenis return 0; 275*24225f53Skettenis } 276*24225f53Skettenis 277*24225f53Skettenis uint32_t 278*24225f53Skettenis dwmmc_host_ocr(sdmmc_chipset_handle_t sch) 279*24225f53Skettenis { 280*24225f53Skettenis return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V; 281*24225f53Skettenis } 282*24225f53Skettenis 283*24225f53Skettenis int 284*24225f53Skettenis dwmmc_host_maxblklen(sdmmc_chipset_handle_t sch) 285*24225f53Skettenis { 286*24225f53Skettenis return 512; 287*24225f53Skettenis } 288*24225f53Skettenis 289*24225f53Skettenis int 290*24225f53Skettenis dwmmc_card_detect(sdmmc_chipset_handle_t sch) 291*24225f53Skettenis { 292*24225f53Skettenis struct dwmmc_softc *sc = sch; 293*24225f53Skettenis uint32_t cdetect; 294*24225f53Skettenis 295*24225f53Skettenis cdetect = HREAD4(sc, SDMMC_CDETECT); 296*24225f53Skettenis return !(cdetect & SDMMC_CDETECT_CARD_DETECT_0); 297*24225f53Skettenis } 298*24225f53Skettenis 299*24225f53Skettenis int 300*24225f53Skettenis dwmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) 301*24225f53Skettenis { 302*24225f53Skettenis struct dwmmc_softc *sc = sch; 303*24225f53Skettenis 304*24225f53Skettenis printf("%s: ocr 0x%08x\n", sc->sc_dev.dv_xname, ocr); 305*24225f53Skettenis 306*24225f53Skettenis if (ISSET(ocr, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) 307*24225f53Skettenis HSET4(sc, SDMMC_PWREN, 1); 308*24225f53Skettenis else 309*24225f53Skettenis HCLR4(sc, SDMMC_PWREN, 0); 310*24225f53Skettenis 311*24225f53Skettenis return 0; 312*24225f53Skettenis } 313*24225f53Skettenis 314*24225f53Skettenis int 315*24225f53Skettenis dwmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq, int timing) 316*24225f53Skettenis { 317*24225f53Skettenis struct dwmmc_softc *sc = sch; 318*24225f53Skettenis int div = 0, timeout; 319*24225f53Skettenis 320*24225f53Skettenis printf("%s: freq %d timing %d\n", sc->sc_dev.dv_xname, freq, timing); 321*24225f53Skettenis 322*24225f53Skettenis HWRITE4(sc, SDMMC_CLKENA, 0); 323*24225f53Skettenis HWRITE4(sc, SDMMC_CLKSRC, 0); 324*24225f53Skettenis 325*24225f53Skettenis if (freq == 0) 326*24225f53Skettenis return 0; 327*24225f53Skettenis 328*24225f53Skettenis if (sc->sc_clkbase / 1000 > freq) { 329*24225f53Skettenis for (div = 1; div < 256; div++) 330*24225f53Skettenis if (sc->sc_clkbase / (2 * 1000 * div) <= freq) 331*24225f53Skettenis break; 332*24225f53Skettenis } 333*24225f53Skettenis printf("%s: div %d\n", sc->sc_dev.dv_xname, div); 334*24225f53Skettenis HWRITE4(sc, SDMMC_CLKDIV, div); 335*24225f53Skettenis 336*24225f53Skettenis /* Update clock. */ 337*24225f53Skettenis HWRITE4(sc, SDMMC_CMD, SDMMC_CMD_START_CMD | 338*24225f53Skettenis SDMMC_CMD_WAIT_PRVDATA_COMPLETE | 339*24225f53Skettenis SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY); 340*24225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 341*24225f53Skettenis if ((HREAD4(sc, SDMMC_CMD) & SDMMC_CMD_START_CMD) == 0) 342*24225f53Skettenis break; 343*24225f53Skettenis } 344*24225f53Skettenis if (timeout == 0) { 345*24225f53Skettenis printf("%s: timeout\n", __func__); 346*24225f53Skettenis return ETIMEDOUT; 347*24225f53Skettenis } 348*24225f53Skettenis 349*24225f53Skettenis /* Enable clock in low power mode. */ 350*24225f53Skettenis HWRITE4(sc, SDMMC_CLKENA, 351*24225f53Skettenis SDMMC_CLKENA_CCLK_ENABLE | SDMMC_CLKENA_CCLK_LOW_POWER); 352*24225f53Skettenis 353*24225f53Skettenis /* Update clock again. */ 354*24225f53Skettenis HWRITE4(sc, SDMMC_CMD, SDMMC_CMD_START_CMD | 355*24225f53Skettenis SDMMC_CMD_WAIT_PRVDATA_COMPLETE | 356*24225f53Skettenis SDMMC_CMD_UPDATE_CLOCK_REGISTERS_ONLY); 357*24225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 358*24225f53Skettenis if ((HREAD4(sc, SDMMC_CMD) & SDMMC_CMD_START_CMD) == 0) 359*24225f53Skettenis break; 360*24225f53Skettenis } 361*24225f53Skettenis if (timeout == 0) { 362*24225f53Skettenis printf("%s: timeout\n", __func__); 363*24225f53Skettenis return ETIMEDOUT; 364*24225f53Skettenis } 365*24225f53Skettenis 366*24225f53Skettenis delay(1000000); 367*24225f53Skettenis 368*24225f53Skettenis return 0; 369*24225f53Skettenis } 370*24225f53Skettenis 371*24225f53Skettenis int 372*24225f53Skettenis dwmmc_bus_width(sdmmc_chipset_handle_t sch, int width) 373*24225f53Skettenis { 374*24225f53Skettenis struct dwmmc_softc *sc = sch; 375*24225f53Skettenis 376*24225f53Skettenis printf("%s: width %d\n", sc->sc_dev.dv_xname, width); 377*24225f53Skettenis 378*24225f53Skettenis switch (width) { 379*24225f53Skettenis case 1: 380*24225f53Skettenis HCLR4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT|SDMMC_CTYPE_4BIT); 381*24225f53Skettenis break; 382*24225f53Skettenis case 4: 383*24225f53Skettenis HSET4(sc, SDMMC_CTYPE, SDMMC_CTYPE_4BIT); 384*24225f53Skettenis HCLR4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT); 385*24225f53Skettenis break; 386*24225f53Skettenis case 8: 387*24225f53Skettenis HSET4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT); 388*24225f53Skettenis break; 389*24225f53Skettenis default: 390*24225f53Skettenis return EINVAL; 391*24225f53Skettenis } 392*24225f53Skettenis 393*24225f53Skettenis return 0; 394*24225f53Skettenis } 395*24225f53Skettenis 396*24225f53Skettenis void 397*24225f53Skettenis dwmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) 398*24225f53Skettenis { 399*24225f53Skettenis struct dwmmc_softc *sc = sch; 400*24225f53Skettenis uint32_t cmdval = SDMMC_CMD_START_CMD | SDMMC_CMD_USE_HOLD_REG; 401*24225f53Skettenis uint32_t status; 402*24225f53Skettenis int timeout; 403*24225f53Skettenis int s; 404*24225f53Skettenis 405*24225f53Skettenis #if 0 406*24225f53Skettenis printf("%s: cmd %d arg 0x%x flags 0x%x data %p datalen %d blklen %d\n", 407*24225f53Skettenis sc->sc_dev.dv_xname, cmd->c_opcode, cmd->c_arg, cmd->c_flags, 408*24225f53Skettenis cmd->c_data, cmd->c_datalen, cmd->c_blklen); 409*24225f53Skettenis #endif 410*24225f53Skettenis 411*24225f53Skettenis s = splbio(); 412*24225f53Skettenis 413*24225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 414*24225f53Skettenis status = HREAD4(sc, SDMMC_STATUS); 415*24225f53Skettenis if ((status & SDMMC_STATUS_DATA_BUSY) == 0) 416*24225f53Skettenis break; 417*24225f53Skettenis delay(100); 418*24225f53Skettenis } 419*24225f53Skettenis if (timeout == 0) { 420*24225f53Skettenis printf("%s: timeout on data busy\n", sc->sc_dev.dv_xname); 421*24225f53Skettenis goto done; 422*24225f53Skettenis } 423*24225f53Skettenis 424*24225f53Skettenis if (cmd->c_opcode == MMC_STOP_TRANSMISSION) 425*24225f53Skettenis cmdval |= SDMMC_CMD_STOP_ABORT_CMD; 426*24225f53Skettenis else if (cmd->c_opcode != MMC_SEND_STATUS) 427*24225f53Skettenis cmdval |= SDMMC_CMD_WAIT_PRVDATA_COMPLETE; 428*24225f53Skettenis 429*24225f53Skettenis if (cmd->c_opcode == MMC_READ_BLOCK_MULTIPLE || 430*24225f53Skettenis cmd->c_opcode == MMC_WRITE_BLOCK_MULTIPLE) 431*24225f53Skettenis cmdval |= SDMMC_CMD_SEND_AUTO_STOP; 432*24225f53Skettenis 433*24225f53Skettenis if (cmd->c_opcode == 0) 434*24225f53Skettenis cmdval |= SDMMC_CMD_SEND_INITIALIZATION; 435*24225f53Skettenis if (cmd->c_flags & SCF_RSP_PRESENT) 436*24225f53Skettenis cmdval |= SDMMC_CMD_RESPONSE_EXPECT; 437*24225f53Skettenis if (cmd->c_flags & SCF_RSP_136) 438*24225f53Skettenis cmdval |= SDMMC_CMD_RESPONSE_LENGTH; 439*24225f53Skettenis if (cmd->c_flags & SCF_RSP_CRC) 440*24225f53Skettenis cmdval |= SDMMC_CMD_CHECK_REPONSE_CRC; 441*24225f53Skettenis 442*24225f53Skettenis if (cmd->c_datalen > 0) { 443*24225f53Skettenis HWRITE4(sc, SDMMC_TMOUT, 0xffffffff); 444*24225f53Skettenis HWRITE4(sc, SDMMC_BYTCNT, cmd->c_datalen); 445*24225f53Skettenis HWRITE4(sc, SDMMC_BLKSIZ, cmd->c_blklen); 446*24225f53Skettenis 447*24225f53Skettenis HSET4(sc, SDMMC_CTRL, SDMMC_CTRL_FIFO_RESET); 448*24225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 449*24225f53Skettenis if ((HREAD4(sc, SDMMC_CTRL) & 450*24225f53Skettenis SDMMC_CTRL_FIFO_RESET) == 0) 451*24225f53Skettenis break; 452*24225f53Skettenis delay(100); 453*24225f53Skettenis } 454*24225f53Skettenis if (timeout == 0) 455*24225f53Skettenis printf("%s: FIFO reset failed\n", sc->sc_dev.dv_xname); 456*24225f53Skettenis 457*24225f53Skettenis cmdval |= SDMMC_CMD_DATA_EXPECTED; 458*24225f53Skettenis if (!ISSET(cmd->c_flags, SCF_CMD_READ)) 459*24225f53Skettenis cmdval |= SDMMC_CMD_WR; 460*24225f53Skettenis } 461*24225f53Skettenis 462*24225f53Skettenis HWRITE4(sc, SDMMC_RINTSTS, 0xffffffff); 463*24225f53Skettenis 464*24225f53Skettenis HWRITE4(sc, SDMMC_CMDARG, cmd->c_arg); 465*24225f53Skettenis HWRITE4(sc, SDMMC_CMD, cmdval | cmd->c_opcode); 466*24225f53Skettenis 467*24225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 468*24225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 469*24225f53Skettenis if (status & SDMMC_RINTSTS_CD) 470*24225f53Skettenis break; 471*24225f53Skettenis delay(100); 472*24225f53Skettenis } 473*24225f53Skettenis if (timeout == 0 || status & SDMMC_RINTSTS_RTO) { 474*24225f53Skettenis cmd->c_error = ETIMEDOUT; 475*24225f53Skettenis goto done; 476*24225f53Skettenis } 477*24225f53Skettenis 478*24225f53Skettenis if (cmd->c_flags & SCF_RSP_PRESENT) { 479*24225f53Skettenis if (cmd->c_flags & SCF_RSP_136) { 480*24225f53Skettenis cmd->c_resp[0] = HREAD4(sc, SDMMC_RESP0); 481*24225f53Skettenis cmd->c_resp[1] = HREAD4(sc, SDMMC_RESP1); 482*24225f53Skettenis cmd->c_resp[2] = HREAD4(sc, SDMMC_RESP2); 483*24225f53Skettenis cmd->c_resp[3] = HREAD4(sc, SDMMC_RESP3); 484*24225f53Skettenis if (cmd->c_flags & SCF_RSP_CRC) { 485*24225f53Skettenis cmd->c_resp[0] = (cmd->c_resp[0] >> 8) | 486*24225f53Skettenis (cmd->c_resp[1] << 24); 487*24225f53Skettenis cmd->c_resp[1] = (cmd->c_resp[1] >> 8) | 488*24225f53Skettenis (cmd->c_resp[2] << 24); 489*24225f53Skettenis cmd->c_resp[2] = (cmd->c_resp[2] >> 8) | 490*24225f53Skettenis (cmd->c_resp[3] << 24); 491*24225f53Skettenis cmd->c_resp[3] = (cmd->c_resp[3] >> 8); 492*24225f53Skettenis } 493*24225f53Skettenis } else { 494*24225f53Skettenis cmd->c_resp[0] = HREAD4(sc, SDMMC_RESP0); 495*24225f53Skettenis } 496*24225f53Skettenis } 497*24225f53Skettenis 498*24225f53Skettenis if (cmd->c_datalen > 0) 499*24225f53Skettenis dwmmc_transfer_data(sc, cmd); 500*24225f53Skettenis 501*24225f53Skettenis if (cmdval & SDMMC_CMD_SEND_AUTO_STOP) { 502*24225f53Skettenis for (timeout = 10000; timeout > 0; timeout--) { 503*24225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 504*24225f53Skettenis if (status & SDMMC_RINTSTS_CD) 505*24225f53Skettenis break; 506*24225f53Skettenis delay(10); 507*24225f53Skettenis } 508*24225f53Skettenis if (timeout == 0) { 509*24225f53Skettenis cmd->c_error = ETIMEDOUT; 510*24225f53Skettenis goto done; 511*24225f53Skettenis } 512*24225f53Skettenis } 513*24225f53Skettenis 514*24225f53Skettenis done: 515*24225f53Skettenis cmd->c_flags |= SCF_ITSDONE; 516*24225f53Skettenis #if 0 517*24225f53Skettenis printf("%s: err %d rintsts 0x%x\n", sc->sc_dev.dv_xname, cmd->c_error, 518*24225f53Skettenis HREAD4(sc, SDMMC_RINTSTS)); 519*24225f53Skettenis #endif 520*24225f53Skettenis splx(s); 521*24225f53Skettenis } 522*24225f53Skettenis 523*24225f53Skettenis void 524*24225f53Skettenis dwmmc_transfer_data(struct dwmmc_softc *sc, struct sdmmc_command *cmd) 525*24225f53Skettenis { 526*24225f53Skettenis int datalen = cmd->c_datalen; 527*24225f53Skettenis u_char *datap = cmd->c_data; 528*24225f53Skettenis uint32_t status; 529*24225f53Skettenis int count, timeout; 530*24225f53Skettenis int fifodr = SDMMC_RINTSTS_DTO; 531*24225f53Skettenis 532*24225f53Skettenis if (ISSET(cmd->c_flags, SCF_CMD_READ)) 533*24225f53Skettenis fifodr |= SDMMC_RINTSTS_RXDR; 534*24225f53Skettenis else 535*24225f53Skettenis fifodr |= SDMMC_RINTSTS_TXDR; 536*24225f53Skettenis 537*24225f53Skettenis while (datalen > 0) { 538*24225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 539*24225f53Skettenis if (status & SDMMC_RINTSTS_DATA_ERR) { 540*24225f53Skettenis cmd->c_error = EIO; 541*24225f53Skettenis return; 542*24225f53Skettenis } 543*24225f53Skettenis if (status & SDMMC_RINTSTS_DATA_TO) { 544*24225f53Skettenis cmd->c_error = ETIMEDOUT; 545*24225f53Skettenis return; 546*24225f53Skettenis } 547*24225f53Skettenis 548*24225f53Skettenis for (timeout = 10000; timeout > 0; timeout--) { 549*24225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 550*24225f53Skettenis if (status & fifodr) 551*24225f53Skettenis break; 552*24225f53Skettenis delay(100); 553*24225f53Skettenis } 554*24225f53Skettenis if (timeout == 0) { 555*24225f53Skettenis cmd->c_error = ETIMEDOUT; 556*24225f53Skettenis return; 557*24225f53Skettenis } 558*24225f53Skettenis 559*24225f53Skettenis count = SDMMC_STATUS_FIFO_COUNT(HREAD4(sc, SDMMC_STATUS)); 560*24225f53Skettenis if (!ISSET(cmd->c_flags, SCF_CMD_READ)) 561*24225f53Skettenis count = sc->sc_fifo_depth - count; 562*24225f53Skettenis 563*24225f53Skettenis count = MIN(datalen, count * 4); 564*24225f53Skettenis if (ISSET(cmd->c_flags, SCF_CMD_READ)) 565*24225f53Skettenis dwmmc_read_data(sc, datap, count); 566*24225f53Skettenis else 567*24225f53Skettenis dwmmc_write_data(sc, datap, count); 568*24225f53Skettenis 569*24225f53Skettenis datap += count; 570*24225f53Skettenis datalen -= count; 571*24225f53Skettenis } 572*24225f53Skettenis 573*24225f53Skettenis for (timeout = 1000; timeout > 0; timeout--) { 574*24225f53Skettenis status = HREAD4(sc, SDMMC_RINTSTS); 575*24225f53Skettenis if (status & SDMMC_RINTSTS_DTO) 576*24225f53Skettenis break; 577*24225f53Skettenis delay(100); 578*24225f53Skettenis } 579*24225f53Skettenis if (timeout == 0) 580*24225f53Skettenis cmd->c_error = ETIMEDOUT; 581*24225f53Skettenis } 582*24225f53Skettenis 583*24225f53Skettenis void 584*24225f53Skettenis dwmmc_read_data(struct dwmmc_softc *sc, u_char *datap, int datalen) 585*24225f53Skettenis { 586*24225f53Skettenis while (datalen > 3) { 587*24225f53Skettenis *(uint32_t *)datap = HREAD4(sc, SDMMC_FIFO_BASE); 588*24225f53Skettenis datap += 4; 589*24225f53Skettenis datalen -= 4; 590*24225f53Skettenis } 591*24225f53Skettenis if (datalen > 0) { 592*24225f53Skettenis uint32_t rv = HREAD4(sc, SDMMC_FIFO_BASE); 593*24225f53Skettenis do { 594*24225f53Skettenis *datap++ = rv & 0xff; 595*24225f53Skettenis rv = rv >> 8; 596*24225f53Skettenis } while (--datalen > 0); 597*24225f53Skettenis } 598*24225f53Skettenis HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_RXDR); 599*24225f53Skettenis } 600*24225f53Skettenis 601*24225f53Skettenis void 602*24225f53Skettenis dwmmc_write_data(struct dwmmc_softc *sc, u_char *datap, int datalen) 603*24225f53Skettenis { 604*24225f53Skettenis while (datalen > 3) { 605*24225f53Skettenis HWRITE4(sc, SDMMC_FIFO_BASE, *((uint32_t *)datap)); 606*24225f53Skettenis datap += 4; 607*24225f53Skettenis datalen -= 4; 608*24225f53Skettenis } 609*24225f53Skettenis if (datalen > 0) { 610*24225f53Skettenis uint32_t rv = *datap++; 611*24225f53Skettenis if (datalen > 1) 612*24225f53Skettenis rv |= *datap++ << 8; 613*24225f53Skettenis if (datalen > 2) 614*24225f53Skettenis rv |= *datap++ << 16; 615*24225f53Skettenis HWRITE4(sc, SDMMC_FIFO_BASE, rv); 616*24225f53Skettenis } 617*24225f53Skettenis HWRITE4(sc, SDMMC_RINTSTS, SDMMC_RINTSTS_TXDR); 618*24225f53Skettenis } 619