141709d23SRuslan Bukin /*- 23ee93b74SRuslan Bukin * Copyright (c) 2014-2019 Ruslan Bukin <br@bsdpad.com> 341709d23SRuslan Bukin * All rights reserved. 441709d23SRuslan Bukin * 541709d23SRuslan Bukin * This software was developed by SRI International and the University of 641709d23SRuslan Bukin * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 741709d23SRuslan Bukin * ("CTSRD"), as part of the DARPA CRASH research programme. 841709d23SRuslan Bukin * 941709d23SRuslan Bukin * Redistribution and use in source and binary forms, with or without 1041709d23SRuslan Bukin * modification, are permitted provided that the following conditions 1141709d23SRuslan Bukin * are met: 1241709d23SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 1341709d23SRuslan Bukin * notice, this list of conditions and the following disclaimer. 1441709d23SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 1541709d23SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 1641709d23SRuslan Bukin * documentation and/or other materials provided with the distribution. 1741709d23SRuslan Bukin * 1841709d23SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1941709d23SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2041709d23SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2141709d23SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2241709d23SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2341709d23SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2441709d23SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2541709d23SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2641709d23SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2741709d23SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2841709d23SRuslan Bukin * SUCH DAMAGE. 2941709d23SRuslan Bukin */ 3041709d23SRuslan Bukin 3141709d23SRuslan Bukin /* 3241709d23SRuslan Bukin * Synopsys DesignWare Mobile Storage Host Controller 3341709d23SRuslan Bukin * Chapter 14, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22) 3441709d23SRuslan Bukin */ 3541709d23SRuslan Bukin 3641709d23SRuslan Bukin #include <sys/param.h> 3741709d23SRuslan Bukin #include <sys/systm.h> 3844682688SAndriy Gapon #include <sys/conf.h> 3941709d23SRuslan Bukin #include <sys/bus.h> 4041709d23SRuslan Bukin #include <sys/kernel.h> 41e2e050c8SConrad Meyer #include <sys/lock.h> 4241709d23SRuslan Bukin #include <sys/module.h> 4341709d23SRuslan Bukin #include <sys/malloc.h> 44e2e050c8SConrad Meyer #include <sys/mutex.h> 4544682688SAndriy Gapon #include <sys/proc.h> 4641709d23SRuslan Bukin #include <sys/rman.h> 4787d4212bSEmmanuel Vadot #include <sys/queue.h> 4887d4212bSEmmanuel Vadot #include <sys/taskqueue.h> 4941709d23SRuslan Bukin 5041709d23SRuslan Bukin #include <dev/mmc/bridge.h> 5141709d23SRuslan Bukin #include <dev/mmc/mmcbrvar.h> 52a1af70e5SEmmanuel Vadot #include <dev/mmc/mmc_fdt_helpers.h> 5341709d23SRuslan Bukin 5441709d23SRuslan Bukin #include <dev/fdt/fdt_common.h> 5541709d23SRuslan Bukin #include <dev/ofw/openfirm.h> 5641709d23SRuslan Bukin #include <dev/ofw/ofw_bus.h> 5741709d23SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 5841709d23SRuslan Bukin 5941709d23SRuslan Bukin #include <machine/bus.h> 6041709d23SRuslan Bukin #include <machine/cpu.h> 6141709d23SRuslan Bukin #include <machine/intr.h> 6241709d23SRuslan Bukin 63be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h> 64dd198e86SEmmanuel Vadot 65755eb18fSAndrew Turner #include <dev/mmc/host/dwmmc_reg.h> 66fa6ea996SAndrew Turner #include <dev/mmc/host/dwmmc_var.h> 6741709d23SRuslan Bukin 6841c653beSEmmanuel Vadot #include "opt_mmccam.h" 6941c653beSEmmanuel Vadot 7041c653beSEmmanuel Vadot #ifdef MMCCAM 7141c653beSEmmanuel Vadot #include <cam/cam.h> 7241c653beSEmmanuel Vadot #include <cam/cam_ccb.h> 7341c653beSEmmanuel Vadot #include <cam/cam_debug.h> 7441c653beSEmmanuel Vadot #include <cam/cam_sim.h> 7541c653beSEmmanuel Vadot #include <cam/cam_xpt_sim.h> 76f1cc48e5SEmmanuel Vadot 77f1cc48e5SEmmanuel Vadot #include "mmc_sim_if.h" 7841c653beSEmmanuel Vadot #endif 7941c653beSEmmanuel Vadot 8041709d23SRuslan Bukin #include "mmcbr_if.h" 8141709d23SRuslan Bukin 8241c653beSEmmanuel Vadot #ifdef DEBUG 8341c653beSEmmanuel Vadot #define dprintf(fmt, args...) printf(fmt, ##args) 8441c653beSEmmanuel Vadot #else 8541709d23SRuslan Bukin #define dprintf(x, arg...) 8641c653beSEmmanuel Vadot #endif 8741709d23SRuslan Bukin 8841709d23SRuslan Bukin #define READ4(_sc, _reg) \ 8941709d23SRuslan Bukin bus_read_4((_sc)->res[0], _reg) 9041709d23SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 9141709d23SRuslan Bukin bus_write_4((_sc)->res[0], _reg, _val) 9241709d23SRuslan Bukin 93057b4402SPedro F. Giffuni #define DIV_ROUND_UP(n, d) howmany(n, d) 9441709d23SRuslan Bukin 9541709d23SRuslan Bukin #define DWMMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 9641709d23SRuslan Bukin #define DWMMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 9741709d23SRuslan Bukin #define DWMMC_LOCK_INIT(_sc) \ 9841709d23SRuslan Bukin mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->dev), \ 9941709d23SRuslan Bukin "dwmmc", MTX_DEF) 10041709d23SRuslan Bukin #define DWMMC_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 10141709d23SRuslan Bukin #define DWMMC_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 10241709d23SRuslan Bukin #define DWMMC_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 10341709d23SRuslan Bukin 10441709d23SRuslan Bukin #define PENDING_CMD 0x01 10541709d23SRuslan Bukin #define PENDING_STOP 0x02 10641709d23SRuslan Bukin #define CARD_INIT_DONE 0x04 10741709d23SRuslan Bukin 10841709d23SRuslan Bukin #define DWMMC_DATA_ERR_FLAGS (SDMMC_INTMASK_DRT | SDMMC_INTMASK_DCRC \ 1098727c174SMichal Meloun |SDMMC_INTMASK_SBE | SDMMC_INTMASK_EBE) 11041709d23SRuslan Bukin #define DWMMC_CMD_ERR_FLAGS (SDMMC_INTMASK_RTO | SDMMC_INTMASK_RCRC \ 11141709d23SRuslan Bukin |SDMMC_INTMASK_RE) 11241709d23SRuslan Bukin #define DWMMC_ERR_FLAGS (DWMMC_DATA_ERR_FLAGS | DWMMC_CMD_ERR_FLAGS \ 11341709d23SRuslan Bukin |SDMMC_INTMASK_HLE) 11441709d23SRuslan Bukin 115c30e9bebSEmmanuel Vadot #define DES0_DIC (1 << 1) /* Disable Interrupt on Completion */ 116c30e9bebSEmmanuel Vadot #define DES0_LD (1 << 2) /* Last Descriptor */ 117c30e9bebSEmmanuel Vadot #define DES0_FS (1 << 3) /* First Descriptor */ 118c30e9bebSEmmanuel Vadot #define DES0_CH (1 << 4) /* second address CHained */ 119c30e9bebSEmmanuel Vadot #define DES0_ER (1 << 5) /* End of Ring */ 120c30e9bebSEmmanuel Vadot #define DES0_CES (1 << 30) /* Card Error Summary */ 121c30e9bebSEmmanuel Vadot #define DES0_OWN (1 << 31) /* OWN */ 12241709d23SRuslan Bukin 123c30e9bebSEmmanuel Vadot #define DES1_BS1_MASK 0x1fff 12441709d23SRuslan Bukin 12541709d23SRuslan Bukin struct idmac_desc { 12641709d23SRuslan Bukin uint32_t des0; /* control */ 12741709d23SRuslan Bukin uint32_t des1; /* bufsize */ 12841709d23SRuslan Bukin uint32_t des2; /* buf1 phys addr */ 12941709d23SRuslan Bukin uint32_t des3; /* buf2 phys addr or next descr */ 13041709d23SRuslan Bukin }; 13141709d23SRuslan Bukin 132c30e9bebSEmmanuel Vadot #define IDMAC_DESC_SEGS (PAGE_SIZE / (sizeof(struct idmac_desc))) 133c30e9bebSEmmanuel Vadot #define IDMAC_DESC_SIZE (sizeof(struct idmac_desc) * IDMAC_DESC_SEGS) 13441709d23SRuslan Bukin #define DEF_MSIZE 0x2 /* Burst size of multiple transaction */ 1358727c174SMichal Meloun /* 1368727c174SMichal Meloun * Size field in DMA descriptor is 13 bits long (up to 4095 bytes), 1378727c174SMichal Meloun * but must be a multiple of the data bus size.Additionally, we must ensure 1388727c174SMichal Meloun * that bus_dmamap_load() doesn't additionally fragments buffer (because it 1398727c174SMichal Meloun * is processed with page size granularity). Thus limit fragment size to half 1408727c174SMichal Meloun * of page. 1418727c174SMichal Meloun * XXX switch descriptor format to array and use second buffer pointer for 1428727c174SMichal Meloun * second half of page 1438727c174SMichal Meloun */ 1448727c174SMichal Meloun #define IDMAC_MAX_SIZE 2048 145dfb73602SMichal Meloun /* 146dfb73602SMichal Meloun * Busdma may bounce buffers, so we must reserve 2 descriptors 147dfb73602SMichal Meloun * (on start and on end) for bounced fragments. 148dfb73602SMichal Meloun */ 149dfb73602SMichal Meloun #define DWMMC_MAX_DATA (IDMAC_MAX_SIZE * (IDMAC_DESC_SEGS - 2)) / MMC_SECTOR_SIZE 15041709d23SRuslan Bukin 15141709d23SRuslan Bukin static void dwmmc_next_operation(struct dwmmc_softc *); 15241709d23SRuslan Bukin static int dwmmc_setup_bus(struct dwmmc_softc *, int); 15341709d23SRuslan Bukin static int dma_done(struct dwmmc_softc *, struct mmc_command *); 15441709d23SRuslan Bukin static int dma_stop(struct dwmmc_softc *); 155e2763dcaSGanbold Tsagaankhuu static void pio_read(struct dwmmc_softc *, struct mmc_command *); 156e2763dcaSGanbold Tsagaankhuu static void pio_write(struct dwmmc_softc *, struct mmc_command *); 15787d4212bSEmmanuel Vadot static void dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present); 15841709d23SRuslan Bukin 15941709d23SRuslan Bukin static struct resource_spec dwmmc_spec[] = { 16041709d23SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 16141709d23SRuslan Bukin { SYS_RES_IRQ, 0, RF_ACTIVE }, 16241709d23SRuslan Bukin { -1, 0 } 16341709d23SRuslan Bukin }; 16441709d23SRuslan Bukin 16541709d23SRuslan Bukin #define HWTYPE_MASK (0x0000ffff) 16641709d23SRuslan Bukin #define HWFLAG_MASK (0xffff << 16) 16741709d23SRuslan Bukin 16841709d23SRuslan Bukin static void 16941709d23SRuslan Bukin dwmmc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 17041709d23SRuslan Bukin { 17141709d23SRuslan Bukin 1728727c174SMichal Meloun if (nsegs != 1) 1738727c174SMichal Meloun panic("%s: nsegs != 1 (%d)\n", __func__, nsegs); 17441709d23SRuslan Bukin if (error != 0) 1758727c174SMichal Meloun panic("%s: error != 0 (%d)\n", __func__, error); 1768727c174SMichal Meloun 17741709d23SRuslan Bukin *(bus_addr_t *)arg = segs[0].ds_addr; 17841709d23SRuslan Bukin } 17941709d23SRuslan Bukin 18041709d23SRuslan Bukin static void 18141709d23SRuslan Bukin dwmmc_ring_setup(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 18241709d23SRuslan Bukin { 18341709d23SRuslan Bukin struct dwmmc_softc *sc; 18441709d23SRuslan Bukin int idx; 18541709d23SRuslan Bukin 18641709d23SRuslan Bukin sc = arg; 18741709d23SRuslan Bukin dprintf("nsegs %d seg0len %lu\n", nsegs, segs[0].ds_len); 1888727c174SMichal Meloun if (error != 0) 1898727c174SMichal Meloun panic("%s: error != 0 (%d)\n", __func__, error); 19041709d23SRuslan Bukin 19141709d23SRuslan Bukin for (idx = 0; idx < nsegs; idx++) { 1928727c174SMichal Meloun sc->desc_ring[idx].des0 = DES0_DIC | DES0_CH; 193c30e9bebSEmmanuel Vadot sc->desc_ring[idx].des1 = segs[idx].ds_len & DES1_BS1_MASK; 19441709d23SRuslan Bukin sc->desc_ring[idx].des2 = segs[idx].ds_addr; 19541709d23SRuslan Bukin 19641709d23SRuslan Bukin if (idx == 0) 19741709d23SRuslan Bukin sc->desc_ring[idx].des0 |= DES0_FS; 19841709d23SRuslan Bukin 19941709d23SRuslan Bukin if (idx == (nsegs - 1)) { 20041709d23SRuslan Bukin sc->desc_ring[idx].des0 &= ~(DES0_DIC | DES0_CH); 20141709d23SRuslan Bukin sc->desc_ring[idx].des0 |= DES0_LD; 20241709d23SRuslan Bukin } 2038727c174SMichal Meloun wmb(); 2048727c174SMichal Meloun sc->desc_ring[idx].des0 |= DES0_OWN; 20541709d23SRuslan Bukin } 20641709d23SRuslan Bukin } 20741709d23SRuslan Bukin 20841709d23SRuslan Bukin static int 20941709d23SRuslan Bukin dwmmc_ctrl_reset(struct dwmmc_softc *sc, int reset_bits) 21041709d23SRuslan Bukin { 21141709d23SRuslan Bukin int reg; 21241709d23SRuslan Bukin int i; 21341709d23SRuslan Bukin 21441709d23SRuslan Bukin reg = READ4(sc, SDMMC_CTRL); 21541709d23SRuslan Bukin reg |= (reset_bits); 21641709d23SRuslan Bukin WRITE4(sc, SDMMC_CTRL, reg); 21741709d23SRuslan Bukin 21841709d23SRuslan Bukin /* Wait reset done */ 21941709d23SRuslan Bukin for (i = 0; i < 100; i++) { 22041709d23SRuslan Bukin if (!(READ4(sc, SDMMC_CTRL) & reset_bits)) 22141709d23SRuslan Bukin return (0); 22241709d23SRuslan Bukin DELAY(10); 22374b8d63dSPedro F. Giffuni } 22441709d23SRuslan Bukin 22541709d23SRuslan Bukin device_printf(sc->dev, "Reset failed\n"); 22641709d23SRuslan Bukin 22741709d23SRuslan Bukin return (1); 22841709d23SRuslan Bukin } 22941709d23SRuslan Bukin 23041709d23SRuslan Bukin static int 23141709d23SRuslan Bukin dma_setup(struct dwmmc_softc *sc) 23241709d23SRuslan Bukin { 23341709d23SRuslan Bukin int error; 23441709d23SRuslan Bukin int nidx; 23541709d23SRuslan Bukin int idx; 23641709d23SRuslan Bukin 23741709d23SRuslan Bukin /* 23841709d23SRuslan Bukin * Set up TX descriptor ring, descriptors, and dma maps. 23941709d23SRuslan Bukin */ 24041709d23SRuslan Bukin error = bus_dma_tag_create( 24141709d23SRuslan Bukin bus_get_dma_tag(sc->dev), /* Parent tag. */ 24241709d23SRuslan Bukin 4096, 0, /* alignment, boundary */ 24341709d23SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 24441709d23SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 24541709d23SRuslan Bukin NULL, NULL, /* filter, filterarg */ 246c30e9bebSEmmanuel Vadot IDMAC_DESC_SIZE, 1, /* maxsize, nsegments */ 247c30e9bebSEmmanuel Vadot IDMAC_DESC_SIZE, /* maxsegsize */ 24841709d23SRuslan Bukin 0, /* flags */ 24941709d23SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 25041709d23SRuslan Bukin &sc->desc_tag); 25141709d23SRuslan Bukin if (error != 0) { 25241709d23SRuslan Bukin device_printf(sc->dev, 25341709d23SRuslan Bukin "could not create ring DMA tag.\n"); 25441709d23SRuslan Bukin return (1); 25541709d23SRuslan Bukin } 25641709d23SRuslan Bukin 25741709d23SRuslan Bukin error = bus_dmamem_alloc(sc->desc_tag, (void**)&sc->desc_ring, 25841709d23SRuslan Bukin BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO, 25941709d23SRuslan Bukin &sc->desc_map); 26041709d23SRuslan Bukin if (error != 0) { 26141709d23SRuslan Bukin device_printf(sc->dev, 26241709d23SRuslan Bukin "could not allocate descriptor ring.\n"); 26341709d23SRuslan Bukin return (1); 26441709d23SRuslan Bukin } 26541709d23SRuslan Bukin 26641709d23SRuslan Bukin error = bus_dmamap_load(sc->desc_tag, sc->desc_map, 267c30e9bebSEmmanuel Vadot sc->desc_ring, IDMAC_DESC_SIZE, dwmmc_get1paddr, 26841709d23SRuslan Bukin &sc->desc_ring_paddr, 0); 26941709d23SRuslan Bukin if (error != 0) { 27041709d23SRuslan Bukin device_printf(sc->dev, 27141709d23SRuslan Bukin "could not load descriptor ring map.\n"); 27241709d23SRuslan Bukin return (1); 27341709d23SRuslan Bukin } 27441709d23SRuslan Bukin 275c30e9bebSEmmanuel Vadot for (idx = 0; idx < IDMAC_DESC_SEGS; idx++) { 27641709d23SRuslan Bukin sc->desc_ring[idx].des0 = DES0_CH; 27741709d23SRuslan Bukin sc->desc_ring[idx].des1 = 0; 278c30e9bebSEmmanuel Vadot nidx = (idx + 1) % IDMAC_DESC_SEGS; 27941709d23SRuslan Bukin sc->desc_ring[idx].des3 = sc->desc_ring_paddr + \ 28041709d23SRuslan Bukin (nidx * sizeof(struct idmac_desc)); 28141709d23SRuslan Bukin } 282c30e9bebSEmmanuel Vadot sc->desc_ring[idx - 1].des3 = sc->desc_ring_paddr; 283c30e9bebSEmmanuel Vadot sc->desc_ring[idx - 1].des0 |= DES0_ER; 28441709d23SRuslan Bukin 28541709d23SRuslan Bukin error = bus_dma_tag_create( 28641709d23SRuslan Bukin bus_get_dma_tag(sc->dev), /* Parent tag. */ 2878727c174SMichal Meloun 8, 0, /* alignment, boundary */ 28841709d23SRuslan Bukin BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 28941709d23SRuslan Bukin BUS_SPACE_MAXADDR, /* highaddr */ 29041709d23SRuslan Bukin NULL, NULL, /* filter, filterarg */ 291c30e9bebSEmmanuel Vadot IDMAC_MAX_SIZE * IDMAC_DESC_SEGS, /* maxsize */ 292c30e9bebSEmmanuel Vadot IDMAC_DESC_SEGS, /* nsegments */ 293c30e9bebSEmmanuel Vadot IDMAC_MAX_SIZE, /* maxsegsize */ 29441709d23SRuslan Bukin 0, /* flags */ 29541709d23SRuslan Bukin NULL, NULL, /* lockfunc, lockarg */ 29641709d23SRuslan Bukin &sc->buf_tag); 29741709d23SRuslan Bukin if (error != 0) { 29841709d23SRuslan Bukin device_printf(sc->dev, 29941709d23SRuslan Bukin "could not create ring DMA tag.\n"); 30041709d23SRuslan Bukin return (1); 30141709d23SRuslan Bukin } 30241709d23SRuslan Bukin 30341709d23SRuslan Bukin error = bus_dmamap_create(sc->buf_tag, 0, 30441709d23SRuslan Bukin &sc->buf_map); 30541709d23SRuslan Bukin if (error != 0) { 30641709d23SRuslan Bukin device_printf(sc->dev, 30741709d23SRuslan Bukin "could not create TX buffer DMA map.\n"); 30841709d23SRuslan Bukin return (1); 30941709d23SRuslan Bukin } 31041709d23SRuslan Bukin 31141709d23SRuslan Bukin return (0); 31241709d23SRuslan Bukin } 31341709d23SRuslan Bukin 31441709d23SRuslan Bukin static void 31541709d23SRuslan Bukin dwmmc_cmd_done(struct dwmmc_softc *sc) 31641709d23SRuslan Bukin { 31741709d23SRuslan Bukin struct mmc_command *cmd; 31841c653beSEmmanuel Vadot #ifdef MMCCAM 31941c653beSEmmanuel Vadot union ccb *ccb; 32041c653beSEmmanuel Vadot #endif 32141709d23SRuslan Bukin 32241c653beSEmmanuel Vadot #ifdef MMCCAM 32341c653beSEmmanuel Vadot ccb = sc->ccb; 32441c653beSEmmanuel Vadot if (ccb == NULL) 32541c653beSEmmanuel Vadot return; 32641c653beSEmmanuel Vadot cmd = &ccb->mmcio.cmd; 32741c653beSEmmanuel Vadot #else 32841709d23SRuslan Bukin cmd = sc->curcmd; 32941c653beSEmmanuel Vadot #endif 33041709d23SRuslan Bukin if (cmd == NULL) 33141709d23SRuslan Bukin return; 33241709d23SRuslan Bukin 33341709d23SRuslan Bukin if (cmd->flags & MMC_RSP_PRESENT) { 33441709d23SRuslan Bukin if (cmd->flags & MMC_RSP_136) { 33541709d23SRuslan Bukin cmd->resp[3] = READ4(sc, SDMMC_RESP0); 33641709d23SRuslan Bukin cmd->resp[2] = READ4(sc, SDMMC_RESP1); 33741709d23SRuslan Bukin cmd->resp[1] = READ4(sc, SDMMC_RESP2); 33841709d23SRuslan Bukin cmd->resp[0] = READ4(sc, SDMMC_RESP3); 33941709d23SRuslan Bukin } else { 34041709d23SRuslan Bukin cmd->resp[3] = 0; 34141709d23SRuslan Bukin cmd->resp[2] = 0; 34241709d23SRuslan Bukin cmd->resp[1] = 0; 34341709d23SRuslan Bukin cmd->resp[0] = READ4(sc, SDMMC_RESP0); 34441709d23SRuslan Bukin } 34541709d23SRuslan Bukin } 34641709d23SRuslan Bukin } 34741709d23SRuslan Bukin 34841709d23SRuslan Bukin static void 34941709d23SRuslan Bukin dwmmc_tasklet(struct dwmmc_softc *sc) 35041709d23SRuslan Bukin { 35141709d23SRuslan Bukin struct mmc_command *cmd; 35241709d23SRuslan Bukin 35341709d23SRuslan Bukin cmd = sc->curcmd; 35441709d23SRuslan Bukin if (cmd == NULL) 35541709d23SRuslan Bukin return; 35641709d23SRuslan Bukin 357fdbf76c3SRuslan Bukin if (!sc->cmd_done) 358fdbf76c3SRuslan Bukin return; 359fdbf76c3SRuslan Bukin 360fdbf76c3SRuslan Bukin if (cmd->error != MMC_ERR_NONE || !cmd->data) { 36141709d23SRuslan Bukin dwmmc_next_operation(sc); 36241709d23SRuslan Bukin } else if (cmd->data && sc->dto_rcvd) { 36341709d23SRuslan Bukin if ((cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || 36441709d23SRuslan Bukin cmd->opcode == MMC_READ_MULTIPLE_BLOCK) && 36541709d23SRuslan Bukin sc->use_auto_stop) { 36641709d23SRuslan Bukin if (sc->acd_rcvd) 36741709d23SRuslan Bukin dwmmc_next_operation(sc); 36841709d23SRuslan Bukin } else { 36941709d23SRuslan Bukin dwmmc_next_operation(sc); 37041709d23SRuslan Bukin } 37141709d23SRuslan Bukin } 37241709d23SRuslan Bukin } 37341709d23SRuslan Bukin 37441709d23SRuslan Bukin static void 37541709d23SRuslan Bukin dwmmc_intr(void *arg) 37641709d23SRuslan Bukin { 37741709d23SRuslan Bukin struct mmc_command *cmd; 37841709d23SRuslan Bukin struct dwmmc_softc *sc; 37941709d23SRuslan Bukin uint32_t reg; 38041709d23SRuslan Bukin 38141709d23SRuslan Bukin sc = arg; 38241709d23SRuslan Bukin 38341709d23SRuslan Bukin DWMMC_LOCK(sc); 38441709d23SRuslan Bukin 38541709d23SRuslan Bukin cmd = sc->curcmd; 38641709d23SRuslan Bukin 38741709d23SRuslan Bukin /* First handle SDMMC controller interrupts */ 38841709d23SRuslan Bukin reg = READ4(sc, SDMMC_MINTSTS); 38941709d23SRuslan Bukin if (reg) { 39041709d23SRuslan Bukin dprintf("%s 0x%08x\n", __func__, reg); 39141709d23SRuslan Bukin 39241709d23SRuslan Bukin if (reg & DWMMC_CMD_ERR_FLAGS) { 39341709d23SRuslan Bukin dprintf("cmd err 0x%08x cmd 0x%08x\n", 39441709d23SRuslan Bukin reg, cmd->opcode); 39541709d23SRuslan Bukin cmd->error = MMC_ERR_TIMEOUT; 39641709d23SRuslan Bukin } 39741709d23SRuslan Bukin 39841709d23SRuslan Bukin if (reg & DWMMC_DATA_ERR_FLAGS) { 39941709d23SRuslan Bukin dprintf("data err 0x%08x cmd 0x%08x\n", 40041709d23SRuslan Bukin reg, cmd->opcode); 40141709d23SRuslan Bukin cmd->error = MMC_ERR_FAILED; 402e2763dcaSGanbold Tsagaankhuu if (!sc->use_pio) { 40341709d23SRuslan Bukin dma_done(sc, cmd); 40441709d23SRuslan Bukin dma_stop(sc); 40541709d23SRuslan Bukin } 406e2763dcaSGanbold Tsagaankhuu } 40741709d23SRuslan Bukin 40841709d23SRuslan Bukin if (reg & SDMMC_INTMASK_CMD_DONE) { 40941709d23SRuslan Bukin dwmmc_cmd_done(sc); 41041709d23SRuslan Bukin sc->cmd_done = 1; 41141709d23SRuslan Bukin } 41241709d23SRuslan Bukin 413dd198e86SEmmanuel Vadot if (reg & SDMMC_INTMASK_ACD) 41441709d23SRuslan Bukin sc->acd_rcvd = 1; 41541709d23SRuslan Bukin 416dd198e86SEmmanuel Vadot if (reg & SDMMC_INTMASK_DTO) 41741709d23SRuslan Bukin sc->dto_rcvd = 1; 41841709d23SRuslan Bukin 41941709d23SRuslan Bukin if (reg & SDMMC_INTMASK_CD) { 42087d4212bSEmmanuel Vadot dwmmc_handle_card_present(sc, 42187d4212bSEmmanuel Vadot READ4(sc, SDMMC_CDETECT) == 0 ? true : false); 42241709d23SRuslan Bukin } 42341709d23SRuslan Bukin } 42441709d23SRuslan Bukin 425dd198e86SEmmanuel Vadot /* Ack interrupts */ 426dd198e86SEmmanuel Vadot WRITE4(sc, SDMMC_RINTSTS, reg); 427dd198e86SEmmanuel Vadot 428e2763dcaSGanbold Tsagaankhuu if (sc->use_pio) { 429e2763dcaSGanbold Tsagaankhuu if (reg & (SDMMC_INTMASK_RXDR|SDMMC_INTMASK_DTO)) { 430e2763dcaSGanbold Tsagaankhuu pio_read(sc, cmd); 431e2763dcaSGanbold Tsagaankhuu } 432e2763dcaSGanbold Tsagaankhuu if (reg & (SDMMC_INTMASK_TXDR|SDMMC_INTMASK_DTO)) { 433e2763dcaSGanbold Tsagaankhuu pio_write(sc, cmd); 434e2763dcaSGanbold Tsagaankhuu } 435e2763dcaSGanbold Tsagaankhuu } else { 43641709d23SRuslan Bukin /* Now handle DMA interrupts */ 43741709d23SRuslan Bukin reg = READ4(sc, SDMMC_IDSTS); 43841709d23SRuslan Bukin if (reg) { 43941709d23SRuslan Bukin dprintf("dma intr 0x%08x\n", reg); 44041709d23SRuslan Bukin if (reg & (SDMMC_IDINTEN_TI | SDMMC_IDINTEN_RI)) { 44141709d23SRuslan Bukin WRITE4(sc, SDMMC_IDSTS, (SDMMC_IDINTEN_TI | 44241709d23SRuslan Bukin SDMMC_IDINTEN_RI)); 44341709d23SRuslan Bukin WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_NI); 44441709d23SRuslan Bukin dma_done(sc, cmd); 44541709d23SRuslan Bukin } 44641709d23SRuslan Bukin } 447e2763dcaSGanbold Tsagaankhuu } 44841709d23SRuslan Bukin 44941709d23SRuslan Bukin dwmmc_tasklet(sc); 45041709d23SRuslan Bukin 45141709d23SRuslan Bukin DWMMC_UNLOCK(sc); 45241709d23SRuslan Bukin } 45341709d23SRuslan Bukin 45487d4212bSEmmanuel Vadot static void 45587d4212bSEmmanuel Vadot dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present) 45687d4212bSEmmanuel Vadot { 45787d4212bSEmmanuel Vadot bool was_present; 45887d4212bSEmmanuel Vadot 45944682688SAndriy Gapon if (dumping || SCHEDULER_STOPPED()) 46044682688SAndriy Gapon return; 46144682688SAndriy Gapon 46287d4212bSEmmanuel Vadot was_present = sc->child != NULL; 46387d4212bSEmmanuel Vadot 46487d4212bSEmmanuel Vadot if (!was_present && is_present) { 46587d4212bSEmmanuel Vadot taskqueue_enqueue_timeout(taskqueue_swi_giant, 46687d4212bSEmmanuel Vadot &sc->card_delayed_task, -(hz / 2)); 46787d4212bSEmmanuel Vadot } else if (was_present && !is_present) { 46887d4212bSEmmanuel Vadot taskqueue_enqueue(taskqueue_swi_giant, &sc->card_task); 46987d4212bSEmmanuel Vadot } 47087d4212bSEmmanuel Vadot } 47187d4212bSEmmanuel Vadot 47287d4212bSEmmanuel Vadot static void 47387d4212bSEmmanuel Vadot dwmmc_card_task(void *arg, int pending __unused) 47487d4212bSEmmanuel Vadot { 47587d4212bSEmmanuel Vadot struct dwmmc_softc *sc = arg; 47687d4212bSEmmanuel Vadot 47741c653beSEmmanuel Vadot #ifdef MMCCAM 478f1cc48e5SEmmanuel Vadot mmc_cam_sim_discover(&sc->mmc_sim); 47941c653beSEmmanuel Vadot #else 48087d4212bSEmmanuel Vadot DWMMC_LOCK(sc); 48187d4212bSEmmanuel Vadot 4824c1ecf55SRuslan Bukin if (READ4(sc, SDMMC_CDETECT) == 0 || 4834c1ecf55SRuslan Bukin (sc->mmc_helper.props & MMC_PROP_BROKEN_CD)) { 48487d4212bSEmmanuel Vadot if (sc->child == NULL) { 48587d4212bSEmmanuel Vadot if (bootverbose) 48687d4212bSEmmanuel Vadot device_printf(sc->dev, "Card inserted\n"); 48787d4212bSEmmanuel Vadot 4885b56413dSWarner Losh sc->child = device_add_child(sc->dev, "mmc", DEVICE_UNIT_ANY); 48987d4212bSEmmanuel Vadot DWMMC_UNLOCK(sc); 49087d4212bSEmmanuel Vadot if (sc->child) { 49187d4212bSEmmanuel Vadot device_set_ivars(sc->child, sc); 49287d4212bSEmmanuel Vadot (void)device_probe_and_attach(sc->child); 49387d4212bSEmmanuel Vadot } 49487d4212bSEmmanuel Vadot } else 49587d4212bSEmmanuel Vadot DWMMC_UNLOCK(sc); 49687d4212bSEmmanuel Vadot } else { 49787d4212bSEmmanuel Vadot /* Card isn't present, detach if necessary */ 49887d4212bSEmmanuel Vadot if (sc->child != NULL) { 49987d4212bSEmmanuel Vadot if (bootverbose) 50087d4212bSEmmanuel Vadot device_printf(sc->dev, "Card removed\n"); 50187d4212bSEmmanuel Vadot 50287d4212bSEmmanuel Vadot DWMMC_UNLOCK(sc); 50387d4212bSEmmanuel Vadot device_delete_child(sc->dev, sc->child); 50487d4212bSEmmanuel Vadot sc->child = NULL; 50587d4212bSEmmanuel Vadot } else 50687d4212bSEmmanuel Vadot DWMMC_UNLOCK(sc); 50787d4212bSEmmanuel Vadot } 50841c653beSEmmanuel Vadot #endif /* MMCCAM */ 50987d4212bSEmmanuel Vadot } 51087d4212bSEmmanuel Vadot 51141709d23SRuslan Bukin static int 51241709d23SRuslan Bukin parse_fdt(struct dwmmc_softc *sc) 51341709d23SRuslan Bukin { 51441709d23SRuslan Bukin pcell_t dts_value[3]; 51541709d23SRuslan Bukin phandle_t node; 516a1af70e5SEmmanuel Vadot uint32_t bus_hz = 0; 51741709d23SRuslan Bukin int len; 518dd198e86SEmmanuel Vadot int error; 51941709d23SRuslan Bukin 52041709d23SRuslan Bukin if ((node = ofw_bus_get_node(sc->dev)) == -1) 52141709d23SRuslan Bukin return (ENXIO); 52241709d23SRuslan Bukin 523a1af70e5SEmmanuel Vadot /* Set some defaults for freq and supported mode */ 524a1af70e5SEmmanuel Vadot sc->host.f_min = 400000; 525e82ba2c5SEmmanuel Vadot sc->host.f_max = 200000000; 526a1af70e5SEmmanuel Vadot sc->host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; 527a1af70e5SEmmanuel Vadot sc->host.caps = MMC_CAP_HSPEED | MMC_CAP_SIGNALING_330; 528a1af70e5SEmmanuel Vadot mmc_fdt_parse(sc->dev, node, &sc->mmc_helper, &sc->host); 529dd198e86SEmmanuel Vadot 53041709d23SRuslan Bukin /* fifo-depth */ 531488d593aSAndrew Turner if ((len = OF_getproplen(node, "fifo-depth")) > 0) { 53241709d23SRuslan Bukin OF_getencprop(node, "fifo-depth", dts_value, len); 53341709d23SRuslan Bukin sc->fifo_depth = dts_value[0]; 534488d593aSAndrew Turner } 53541709d23SRuslan Bukin 536dd198e86SEmmanuel Vadot /* num-slots (Deprecated) */ 537488d593aSAndrew Turner sc->num_slots = 1; 538488d593aSAndrew Turner if ((len = OF_getproplen(node, "num-slots")) > 0) { 539dd198e86SEmmanuel Vadot device_printf(sc->dev, "num-slots property is deprecated\n"); 54041709d23SRuslan Bukin OF_getencprop(node, "num-slots", dts_value, len); 54141709d23SRuslan Bukin sc->num_slots = dts_value[0]; 542488d593aSAndrew Turner } 54341709d23SRuslan Bukin 544dd198e86SEmmanuel Vadot /* clock-frequency */ 545dd198e86SEmmanuel Vadot if ((len = OF_getproplen(node, "clock-frequency")) > 0) { 546dd198e86SEmmanuel Vadot OF_getencprop(node, "clock-frequency", dts_value, len); 547dd198e86SEmmanuel Vadot bus_hz = dts_value[0]; 548dd198e86SEmmanuel Vadot } 549dd198e86SEmmanuel Vadot 550e088e853SMichal Meloun /* IP block reset is optional */ 551e088e853SMichal Meloun error = hwreset_get_by_ofw_name(sc->dev, 0, "reset", &sc->hwreset); 552a53a43d9SRuslan Bukin if (error != 0 && 553a53a43d9SRuslan Bukin error != ENOENT && 554a53a43d9SRuslan Bukin error != ENODEV) { 555e088e853SMichal Meloun device_printf(sc->dev, "Cannot get reset\n"); 556a53a43d9SRuslan Bukin goto fail; 557a53a43d9SRuslan Bukin } 558e088e853SMichal Meloun 559e088e853SMichal Meloun /* vmmc regulator is optional */ 560e088e853SMichal Meloun error = regulator_get_by_ofw_property(sc->dev, 0, "vmmc-supply", 561e088e853SMichal Meloun &sc->vmmc); 562a53a43d9SRuslan Bukin if (error != 0 && 563a53a43d9SRuslan Bukin error != ENOENT && 564a53a43d9SRuslan Bukin error != ENODEV) { 565e088e853SMichal Meloun device_printf(sc->dev, "Cannot get regulator 'vmmc-supply'\n"); 566a53a43d9SRuslan Bukin goto fail; 567a53a43d9SRuslan Bukin } 568e088e853SMichal Meloun 569e088e853SMichal Meloun /* vqmmc regulator is optional */ 570e088e853SMichal Meloun error = regulator_get_by_ofw_property(sc->dev, 0, "vqmmc-supply", 571e088e853SMichal Meloun &sc->vqmmc); 572a53a43d9SRuslan Bukin if (error != 0 && 573a53a43d9SRuslan Bukin error != ENOENT && 574a53a43d9SRuslan Bukin error != ENODEV) { 575e088e853SMichal Meloun device_printf(sc->dev, "Cannot get regulator 'vqmmc-supply'\n"); 576a53a43d9SRuslan Bukin goto fail; 577a53a43d9SRuslan Bukin } 578e088e853SMichal Meloun 579e088e853SMichal Meloun /* Assert reset first */ 580e088e853SMichal Meloun if (sc->hwreset != NULL) { 581e088e853SMichal Meloun error = hwreset_assert(sc->hwreset); 582e088e853SMichal Meloun if (error != 0) { 583e088e853SMichal Meloun device_printf(sc->dev, "Cannot assert reset\n"); 584e088e853SMichal Meloun goto fail; 585e088e853SMichal Meloun } 586e088e853SMichal Meloun } 587e088e853SMichal Meloun 588dd198e86SEmmanuel Vadot /* BIU (Bus Interface Unit clock) is optional */ 589dd198e86SEmmanuel Vadot error = clk_get_by_ofw_name(sc->dev, 0, "biu", &sc->biu); 590a53a43d9SRuslan Bukin if (error != 0 && 591a53a43d9SRuslan Bukin error != ENOENT && 592a53a43d9SRuslan Bukin error != ENODEV) { 593e088e853SMichal Meloun device_printf(sc->dev, "Cannot get 'biu' clock\n"); 594a53a43d9SRuslan Bukin goto fail; 595a53a43d9SRuslan Bukin } 5963ee93b74SRuslan Bukin 597dd198e86SEmmanuel Vadot if (sc->biu) { 598dd198e86SEmmanuel Vadot error = clk_enable(sc->biu); 599dd198e86SEmmanuel Vadot if (error != 0) { 600dd198e86SEmmanuel Vadot device_printf(sc->dev, "cannot enable biu clock\n"); 601dd198e86SEmmanuel Vadot goto fail; 602dd198e86SEmmanuel Vadot } 603dd198e86SEmmanuel Vadot } 604dd198e86SEmmanuel Vadot 60541709d23SRuslan Bukin /* 606dd198e86SEmmanuel Vadot * CIU (Controller Interface Unit clock) is mandatory 607dd198e86SEmmanuel Vadot * if no clock-frequency property is given 60841709d23SRuslan Bukin */ 609dd198e86SEmmanuel Vadot error = clk_get_by_ofw_name(sc->dev, 0, "ciu", &sc->ciu); 610a53a43d9SRuslan Bukin if (error != 0 && 611a53a43d9SRuslan Bukin error != ENOENT && 612a53a43d9SRuslan Bukin error != ENODEV) { 613e088e853SMichal Meloun device_printf(sc->dev, "Cannot get 'ciu' clock\n"); 614a53a43d9SRuslan Bukin goto fail; 615a53a43d9SRuslan Bukin } 6163ee93b74SRuslan Bukin 617e088e853SMichal Meloun if (sc->ciu) { 618dd198e86SEmmanuel Vadot if (bus_hz != 0) { 619dd198e86SEmmanuel Vadot error = clk_set_freq(sc->ciu, bus_hz, 0); 620dd198e86SEmmanuel Vadot if (error != 0) 621dd198e86SEmmanuel Vadot device_printf(sc->dev, 622dd198e86SEmmanuel Vadot "cannot set ciu clock to %u\n", bus_hz); 623dd198e86SEmmanuel Vadot } 624e088e853SMichal Meloun error = clk_enable(sc->ciu); 625e088e853SMichal Meloun if (error != 0) { 626e088e853SMichal Meloun device_printf(sc->dev, "cannot enable ciu clock\n"); 627e088e853SMichal Meloun goto fail; 628e088e853SMichal Meloun } 629dd198e86SEmmanuel Vadot clk_get_freq(sc->ciu, &sc->bus_hz); 630dd198e86SEmmanuel Vadot } 631e088e853SMichal Meloun 63287dc015dSEmmanuel Vadot /* Enable regulators */ 63387dc015dSEmmanuel Vadot if (sc->vmmc != NULL) { 63487dc015dSEmmanuel Vadot error = regulator_enable(sc->vmmc); 63587dc015dSEmmanuel Vadot if (error != 0) { 63687dc015dSEmmanuel Vadot device_printf(sc->dev, "Cannot enable vmmc regulator\n"); 63787dc015dSEmmanuel Vadot goto fail; 63887dc015dSEmmanuel Vadot } 63987dc015dSEmmanuel Vadot } 64087dc015dSEmmanuel Vadot if (sc->vqmmc != NULL) { 64187dc015dSEmmanuel Vadot error = regulator_enable(sc->vqmmc); 64287dc015dSEmmanuel Vadot if (error != 0) { 64387dc015dSEmmanuel Vadot device_printf(sc->dev, "Cannot enable vqmmc regulator\n"); 64487dc015dSEmmanuel Vadot goto fail; 64587dc015dSEmmanuel Vadot } 64687dc015dSEmmanuel Vadot } 64787dc015dSEmmanuel Vadot 648e088e853SMichal Meloun /* Take dwmmc out of reset */ 649e088e853SMichal Meloun if (sc->hwreset != NULL) { 650e088e853SMichal Meloun error = hwreset_deassert(sc->hwreset); 651e088e853SMichal Meloun if (error != 0) { 652e088e853SMichal Meloun device_printf(sc->dev, "Cannot deassert reset\n"); 653e088e853SMichal Meloun goto fail; 654e088e853SMichal Meloun } 655e088e853SMichal Meloun } 656dd198e86SEmmanuel Vadot 657725b72d5SAndrew Turner if (sc->bus_hz == 0) { 658dd198e86SEmmanuel Vadot device_printf(sc->dev, "No bus speed provided\n"); 659dd198e86SEmmanuel Vadot goto fail; 660725b72d5SAndrew Turner } 66141709d23SRuslan Bukin 66241709d23SRuslan Bukin return (0); 663dd198e86SEmmanuel Vadot 664dd198e86SEmmanuel Vadot fail: 665dd198e86SEmmanuel Vadot return (ENXIO); 66641709d23SRuslan Bukin } 66741709d23SRuslan Bukin 668fa6ea996SAndrew Turner int 66941709d23SRuslan Bukin dwmmc_attach(device_t dev) 67041709d23SRuslan Bukin { 67141709d23SRuslan Bukin struct dwmmc_softc *sc; 67241709d23SRuslan Bukin int error; 67341709d23SRuslan Bukin 67441709d23SRuslan Bukin sc = device_get_softc(dev); 67541709d23SRuslan Bukin 67641709d23SRuslan Bukin sc->dev = dev; 67741709d23SRuslan Bukin 67841709d23SRuslan Bukin /* Why not to use Auto Stop? It save a hundred of irq per second */ 67941709d23SRuslan Bukin sc->use_auto_stop = 1; 68041709d23SRuslan Bukin 68141709d23SRuslan Bukin error = parse_fdt(sc); 68241709d23SRuslan Bukin if (error != 0) { 68341709d23SRuslan Bukin device_printf(dev, "Can't get FDT property.\n"); 68441709d23SRuslan Bukin return (ENXIO); 68541709d23SRuslan Bukin } 68641709d23SRuslan Bukin 68741709d23SRuslan Bukin DWMMC_LOCK_INIT(sc); 68841709d23SRuslan Bukin 68941709d23SRuslan Bukin if (bus_alloc_resources(dev, dwmmc_spec, sc->res)) { 69041709d23SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 69141709d23SRuslan Bukin return (ENXIO); 69241709d23SRuslan Bukin } 69341709d23SRuslan Bukin 69441709d23SRuslan Bukin /* Setup interrupt handler. */ 69541709d23SRuslan Bukin error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE, 69641709d23SRuslan Bukin NULL, dwmmc_intr, sc, &sc->intr_cookie); 69741709d23SRuslan Bukin if (error != 0) { 69841709d23SRuslan Bukin device_printf(dev, "could not setup interrupt handler.\n"); 69941709d23SRuslan Bukin return (ENXIO); 70041709d23SRuslan Bukin } 70141709d23SRuslan Bukin 70241709d23SRuslan Bukin device_printf(dev, "Hardware version ID is %04x\n", 70341709d23SRuslan Bukin READ4(sc, SDMMC_VERID) & 0xffff); 70441709d23SRuslan Bukin 70541709d23SRuslan Bukin /* Reset all */ 70641709d23SRuslan Bukin if (dwmmc_ctrl_reset(sc, (SDMMC_CTRL_RESET | 70741709d23SRuslan Bukin SDMMC_CTRL_FIFO_RESET | 70841709d23SRuslan Bukin SDMMC_CTRL_DMA_RESET))) 70941709d23SRuslan Bukin return (ENXIO); 71041709d23SRuslan Bukin 71141709d23SRuslan Bukin dwmmc_setup_bus(sc, sc->host.f_min); 71241709d23SRuslan Bukin 713488d593aSAndrew Turner if (sc->fifo_depth == 0) { 714488d593aSAndrew Turner sc->fifo_depth = 1 + 715488d593aSAndrew Turner ((READ4(sc, SDMMC_FIFOTH) >> SDMMC_FIFOTH_RXWMARK_S) & 0xfff); 716488d593aSAndrew Turner device_printf(dev, "No fifo-depth, using FIFOTH %x\n", 717488d593aSAndrew Turner sc->fifo_depth); 718488d593aSAndrew Turner } 719488d593aSAndrew Turner 720e2763dcaSGanbold Tsagaankhuu if (!sc->use_pio) { 721e3014a57SEmmanuel Vadot dma_stop(sc); 72241709d23SRuslan Bukin if (dma_setup(sc)) 72341709d23SRuslan Bukin return (ENXIO); 72441709d23SRuslan Bukin 72541709d23SRuslan Bukin /* Install desc base */ 72641709d23SRuslan Bukin WRITE4(sc, SDMMC_DBADDR, sc->desc_ring_paddr); 72741709d23SRuslan Bukin 72841709d23SRuslan Bukin /* Enable DMA interrupts */ 72941709d23SRuslan Bukin WRITE4(sc, SDMMC_IDSTS, SDMMC_IDINTEN_MASK); 73041709d23SRuslan Bukin WRITE4(sc, SDMMC_IDINTEN, (SDMMC_IDINTEN_NI | 73141709d23SRuslan Bukin SDMMC_IDINTEN_RI | 73241709d23SRuslan Bukin SDMMC_IDINTEN_TI)); 733e2763dcaSGanbold Tsagaankhuu } 73441709d23SRuslan Bukin 73541709d23SRuslan Bukin /* Clear and disable interrups for a while */ 73641709d23SRuslan Bukin WRITE4(sc, SDMMC_RINTSTS, 0xffffffff); 73741709d23SRuslan Bukin WRITE4(sc, SDMMC_INTMASK, 0); 73841709d23SRuslan Bukin 73941709d23SRuslan Bukin /* Maximum timeout */ 74041709d23SRuslan Bukin WRITE4(sc, SDMMC_TMOUT, 0xffffffff); 74141709d23SRuslan Bukin 74241709d23SRuslan Bukin /* Enable interrupts */ 74341709d23SRuslan Bukin WRITE4(sc, SDMMC_RINTSTS, 0xffffffff); 74441709d23SRuslan Bukin WRITE4(sc, SDMMC_INTMASK, (SDMMC_INTMASK_CMD_DONE | 74541709d23SRuslan Bukin SDMMC_INTMASK_DTO | 74641709d23SRuslan Bukin SDMMC_INTMASK_ACD | 74741709d23SRuslan Bukin SDMMC_INTMASK_TXDR | 74841709d23SRuslan Bukin SDMMC_INTMASK_RXDR | 74941709d23SRuslan Bukin DWMMC_ERR_FLAGS | 75041709d23SRuslan Bukin SDMMC_INTMASK_CD)); 75141709d23SRuslan Bukin WRITE4(sc, SDMMC_CTRL, SDMMC_CTRL_INT_ENABLE); 75241709d23SRuslan Bukin 75387d4212bSEmmanuel Vadot TASK_INIT(&sc->card_task, 0, dwmmc_card_task, sc); 75487d4212bSEmmanuel Vadot TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->card_delayed_task, 0, 75587d4212bSEmmanuel Vadot dwmmc_card_task, sc); 75687d4212bSEmmanuel Vadot 75741c653beSEmmanuel Vadot #ifdef MMCCAM 75841c653beSEmmanuel Vadot sc->ccb = NULL; 759f1cc48e5SEmmanuel Vadot if (mmc_cam_sim_alloc(dev, "dw_mmc", &sc->mmc_sim) != 0) { 760f1cc48e5SEmmanuel Vadot device_printf(dev, "cannot alloc cam sim\n"); 761f1cc48e5SEmmanuel Vadot dwmmc_detach(dev); 762f1cc48e5SEmmanuel Vadot return (ENXIO); 76341c653beSEmmanuel Vadot } 76441c653beSEmmanuel Vadot #endif 76587d4212bSEmmanuel Vadot /* 76687d4212bSEmmanuel Vadot * Schedule a card detection as we won't get an interrupt 76787d4212bSEmmanuel Vadot * if the card is inserted when we attach 76887d4212bSEmmanuel Vadot */ 76987d4212bSEmmanuel Vadot dwmmc_card_task(sc, 0); 77087d4212bSEmmanuel Vadot return (0); 77141709d23SRuslan Bukin } 77241709d23SRuslan Bukin 77387dc015dSEmmanuel Vadot int 77487dc015dSEmmanuel Vadot dwmmc_detach(device_t dev) 77587dc015dSEmmanuel Vadot { 77687dc015dSEmmanuel Vadot struct dwmmc_softc *sc; 77787dc015dSEmmanuel Vadot int ret; 77887dc015dSEmmanuel Vadot 77987dc015dSEmmanuel Vadot sc = device_get_softc(dev); 78087dc015dSEmmanuel Vadot 781*3ddaf820SJohn Baldwin ret = bus_generic_detach(dev); 78287dc015dSEmmanuel Vadot if (ret != 0) 78387dc015dSEmmanuel Vadot return (ret); 78487dc015dSEmmanuel Vadot 78587d4212bSEmmanuel Vadot taskqueue_drain(taskqueue_swi_giant, &sc->card_task); 78687d4212bSEmmanuel Vadot taskqueue_drain_timeout(taskqueue_swi_giant, &sc->card_delayed_task); 78787d4212bSEmmanuel Vadot 78887dc015dSEmmanuel Vadot if (sc->intr_cookie != NULL) { 78987dc015dSEmmanuel Vadot ret = bus_teardown_intr(dev, sc->res[1], sc->intr_cookie); 79087dc015dSEmmanuel Vadot if (ret != 0) 79187dc015dSEmmanuel Vadot return (ret); 79287dc015dSEmmanuel Vadot } 79387dc015dSEmmanuel Vadot bus_release_resources(dev, dwmmc_spec, sc->res); 79487dc015dSEmmanuel Vadot 79587d4212bSEmmanuel Vadot DWMMC_LOCK_DESTROY(sc); 79687d4212bSEmmanuel Vadot 79787dc015dSEmmanuel Vadot if (sc->hwreset != NULL && hwreset_deassert(sc->hwreset) != 0) 79887dc015dSEmmanuel Vadot device_printf(sc->dev, "cannot deassert reset\n"); 79987dc015dSEmmanuel Vadot if (sc->biu != NULL && clk_disable(sc->biu) != 0) 80087dc015dSEmmanuel Vadot device_printf(sc->dev, "cannot disable biu clock\n"); 80187dc015dSEmmanuel Vadot if (sc->ciu != NULL && clk_disable(sc->ciu) != 0) 80287dc015dSEmmanuel Vadot device_printf(sc->dev, "cannot disable ciu clock\n"); 80387dc015dSEmmanuel Vadot 80487dc015dSEmmanuel Vadot if (sc->vmmc && regulator_disable(sc->vmmc) != 0) 80587dc015dSEmmanuel Vadot device_printf(sc->dev, "Cannot disable vmmc regulator\n"); 80687dc015dSEmmanuel Vadot if (sc->vqmmc && regulator_disable(sc->vqmmc) != 0) 80787dc015dSEmmanuel Vadot device_printf(sc->dev, "Cannot disable vqmmc regulator\n"); 80887dc015dSEmmanuel Vadot 809f1cc48e5SEmmanuel Vadot #ifdef MMCCAM 810f1cc48e5SEmmanuel Vadot mmc_cam_sim_free(&sc->mmc_sim); 811f1cc48e5SEmmanuel Vadot #endif 812f1cc48e5SEmmanuel Vadot 81387dc015dSEmmanuel Vadot return (0); 81487dc015dSEmmanuel Vadot } 81587dc015dSEmmanuel Vadot 81641709d23SRuslan Bukin static int 81741709d23SRuslan Bukin dwmmc_setup_bus(struct dwmmc_softc *sc, int freq) 81841709d23SRuslan Bukin { 81941709d23SRuslan Bukin int tout; 82041709d23SRuslan Bukin int div; 82141709d23SRuslan Bukin 82241709d23SRuslan Bukin if (freq == 0) { 82341709d23SRuslan Bukin WRITE4(sc, SDMMC_CLKENA, 0); 82441709d23SRuslan Bukin WRITE4(sc, SDMMC_CMD, (SDMMC_CMD_WAIT_PRVDATA | 82541709d23SRuslan Bukin SDMMC_CMD_UPD_CLK_ONLY | SDMMC_CMD_START)); 82641709d23SRuslan Bukin 82741709d23SRuslan Bukin tout = 1000; 82841709d23SRuslan Bukin do { 82941709d23SRuslan Bukin if (tout-- < 0) { 83041709d23SRuslan Bukin device_printf(sc->dev, "Failed update clk\n"); 83141709d23SRuslan Bukin return (1); 83241709d23SRuslan Bukin } 83341709d23SRuslan Bukin } while (READ4(sc, SDMMC_CMD) & SDMMC_CMD_START); 83441709d23SRuslan Bukin 83541709d23SRuslan Bukin return (0); 83641709d23SRuslan Bukin } 83741709d23SRuslan Bukin 83841709d23SRuslan Bukin WRITE4(sc, SDMMC_CLKENA, 0); 83941709d23SRuslan Bukin WRITE4(sc, SDMMC_CLKSRC, 0); 84041709d23SRuslan Bukin 84141709d23SRuslan Bukin div = (sc->bus_hz != freq) ? DIV_ROUND_UP(sc->bus_hz, 2 * freq) : 0; 84241709d23SRuslan Bukin 84341709d23SRuslan Bukin WRITE4(sc, SDMMC_CLKDIV, div); 84441709d23SRuslan Bukin WRITE4(sc, SDMMC_CMD, (SDMMC_CMD_WAIT_PRVDATA | 84541709d23SRuslan Bukin SDMMC_CMD_UPD_CLK_ONLY | SDMMC_CMD_START)); 84641709d23SRuslan Bukin 84741709d23SRuslan Bukin tout = 1000; 84841709d23SRuslan Bukin do { 84941709d23SRuslan Bukin if (tout-- < 0) { 8507cbdf8a0SEmmanuel Vadot device_printf(sc->dev, "Failed to update clk\n"); 85141709d23SRuslan Bukin return (1); 85241709d23SRuslan Bukin } 85341709d23SRuslan Bukin } while (READ4(sc, SDMMC_CMD) & SDMMC_CMD_START); 85441709d23SRuslan Bukin 85541709d23SRuslan Bukin WRITE4(sc, SDMMC_CLKENA, (SDMMC_CLKENA_CCLK_EN | SDMMC_CLKENA_LP)); 85641709d23SRuslan Bukin WRITE4(sc, SDMMC_CMD, SDMMC_CMD_WAIT_PRVDATA | 85741709d23SRuslan Bukin SDMMC_CMD_UPD_CLK_ONLY | SDMMC_CMD_START); 85841709d23SRuslan Bukin 85941709d23SRuslan Bukin tout = 1000; 86041709d23SRuslan Bukin do { 86141709d23SRuslan Bukin if (tout-- < 0) { 86241709d23SRuslan Bukin device_printf(sc->dev, "Failed to enable clk\n"); 86341709d23SRuslan Bukin return (1); 86441709d23SRuslan Bukin } 86541709d23SRuslan Bukin } while (READ4(sc, SDMMC_CMD) & SDMMC_CMD_START); 86641709d23SRuslan Bukin 86741709d23SRuslan Bukin return (0); 86841709d23SRuslan Bukin } 86941709d23SRuslan Bukin 87041709d23SRuslan Bukin static int 87141709d23SRuslan Bukin dwmmc_update_ios(device_t brdev, device_t reqdev) 87241709d23SRuslan Bukin { 87341709d23SRuslan Bukin struct dwmmc_softc *sc; 87441709d23SRuslan Bukin struct mmc_ios *ios; 875dd198e86SEmmanuel Vadot uint32_t reg; 876dd198e86SEmmanuel Vadot int ret = 0; 87741709d23SRuslan Bukin 87841709d23SRuslan Bukin sc = device_get_softc(brdev); 87941709d23SRuslan Bukin ios = &sc->host.ios; 88041709d23SRuslan Bukin 881ea7f45d3SAndriy Gapon dprintf("Setting up clk %u bus_width %d, timing: %d\n", 8828727c174SMichal Meloun ios->clock, ios->bus_width, ios->timing); 88341709d23SRuslan Bukin 884af32e2ccSEmmanuel Vadot switch (ios->power_mode) { 885af32e2ccSEmmanuel Vadot case power_on: 886af32e2ccSEmmanuel Vadot break; 887af32e2ccSEmmanuel Vadot case power_off: 888af32e2ccSEmmanuel Vadot WRITE4(sc, SDMMC_PWREN, 0); 889af32e2ccSEmmanuel Vadot break; 890af32e2ccSEmmanuel Vadot case power_up: 891af32e2ccSEmmanuel Vadot WRITE4(sc, SDMMC_PWREN, 1); 892af32e2ccSEmmanuel Vadot break; 893af32e2ccSEmmanuel Vadot } 894af32e2ccSEmmanuel Vadot 895ce41765cSEmmanuel Vadot mmc_fdt_set_power(&sc->mmc_helper, ios->power_mode); 896ce41765cSEmmanuel Vadot 89741709d23SRuslan Bukin if (ios->bus_width == bus_width_8) 89841709d23SRuslan Bukin WRITE4(sc, SDMMC_CTYPE, SDMMC_CTYPE_8BIT); 89941709d23SRuslan Bukin else if (ios->bus_width == bus_width_4) 90041709d23SRuslan Bukin WRITE4(sc, SDMMC_CTYPE, SDMMC_CTYPE_4BIT); 90141709d23SRuslan Bukin else 90241709d23SRuslan Bukin WRITE4(sc, SDMMC_CTYPE, 0); 90341709d23SRuslan Bukin 90441709d23SRuslan Bukin if ((sc->hwtype & HWTYPE_MASK) == HWTYPE_EXYNOS) { 90541709d23SRuslan Bukin /* XXX: take care about DDR or SDR use here */ 90641709d23SRuslan Bukin WRITE4(sc, SDMMC_CLKSEL, sc->sdr_timing); 90741709d23SRuslan Bukin } 90841709d23SRuslan Bukin 909dd198e86SEmmanuel Vadot /* Set DDR mode */ 910dd198e86SEmmanuel Vadot reg = READ4(sc, SDMMC_UHS_REG); 911dd198e86SEmmanuel Vadot if (ios->timing == bus_timing_uhs_ddr50 || 912dd198e86SEmmanuel Vadot ios->timing == bus_timing_mmc_ddr52 || 913dd198e86SEmmanuel Vadot ios->timing == bus_timing_mmc_hs400) 914dd198e86SEmmanuel Vadot reg |= (SDMMC_UHS_REG_DDR); 915dd198e86SEmmanuel Vadot else 916dd198e86SEmmanuel Vadot reg &= ~(SDMMC_UHS_REG_DDR); 917dd198e86SEmmanuel Vadot WRITE4(sc, SDMMC_UHS_REG, reg); 91841709d23SRuslan Bukin 919dd198e86SEmmanuel Vadot if (sc->update_ios) 920dd198e86SEmmanuel Vadot ret = sc->update_ios(sc, ios); 921dd198e86SEmmanuel Vadot 922dd198e86SEmmanuel Vadot dwmmc_setup_bus(sc, ios->clock); 923dd198e86SEmmanuel Vadot 924dd198e86SEmmanuel Vadot return (ret); 92541709d23SRuslan Bukin } 92641709d23SRuslan Bukin 92741709d23SRuslan Bukin static int 92841709d23SRuslan Bukin dma_done(struct dwmmc_softc *sc, struct mmc_command *cmd) 92941709d23SRuslan Bukin { 93041709d23SRuslan Bukin struct mmc_data *data; 93141709d23SRuslan Bukin 93241709d23SRuslan Bukin data = cmd->data; 93341709d23SRuslan Bukin 93441709d23SRuslan Bukin if (data->flags & MMC_DATA_WRITE) 93541709d23SRuslan Bukin bus_dmamap_sync(sc->buf_tag, sc->buf_map, 93641709d23SRuslan Bukin BUS_DMASYNC_POSTWRITE); 93741709d23SRuslan Bukin else 93841709d23SRuslan Bukin bus_dmamap_sync(sc->buf_tag, sc->buf_map, 93941709d23SRuslan Bukin BUS_DMASYNC_POSTREAD); 94041709d23SRuslan Bukin 941f3ad8ea0SAndrew Turner bus_dmamap_sync(sc->desc_tag, sc->desc_map, 942f3ad8ea0SAndrew Turner BUS_DMASYNC_POSTWRITE); 943f3ad8ea0SAndrew Turner 94441709d23SRuslan Bukin bus_dmamap_unload(sc->buf_tag, sc->buf_map); 94541709d23SRuslan Bukin 94641709d23SRuslan Bukin return (0); 94741709d23SRuslan Bukin } 94841709d23SRuslan Bukin 94941709d23SRuslan Bukin static int 95041709d23SRuslan Bukin dma_stop(struct dwmmc_softc *sc) 95141709d23SRuslan Bukin { 95241709d23SRuslan Bukin int reg; 95341709d23SRuslan Bukin 95441709d23SRuslan Bukin reg = READ4(sc, SDMMC_CTRL); 95541709d23SRuslan Bukin reg &= ~(SDMMC_CTRL_USE_IDMAC); 95641709d23SRuslan Bukin reg |= (SDMMC_CTRL_DMA_RESET); 95741709d23SRuslan Bukin WRITE4(sc, SDMMC_CTRL, reg); 95841709d23SRuslan Bukin 95941709d23SRuslan Bukin reg = READ4(sc, SDMMC_BMOD); 96041709d23SRuslan Bukin reg &= ~(SDMMC_BMOD_DE | SDMMC_BMOD_FB); 96141709d23SRuslan Bukin reg |= (SDMMC_BMOD_SWR); 96241709d23SRuslan Bukin WRITE4(sc, SDMMC_BMOD, reg); 96341709d23SRuslan Bukin 96441709d23SRuslan Bukin return (0); 96541709d23SRuslan Bukin } 96641709d23SRuslan Bukin 96741709d23SRuslan Bukin static int 96841709d23SRuslan Bukin dma_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd) 96941709d23SRuslan Bukin { 97041709d23SRuslan Bukin struct mmc_data *data; 97141709d23SRuslan Bukin int err; 97241709d23SRuslan Bukin int reg; 97341709d23SRuslan Bukin 97441709d23SRuslan Bukin data = cmd->data; 97541709d23SRuslan Bukin 97641709d23SRuslan Bukin reg = READ4(sc, SDMMC_INTMASK); 97741709d23SRuslan Bukin reg &= ~(SDMMC_INTMASK_TXDR | SDMMC_INTMASK_RXDR); 97841709d23SRuslan Bukin WRITE4(sc, SDMMC_INTMASK, reg); 9798727c174SMichal Meloun dprintf("%s: bus_dmamap_load size: %zu\n", __func__, data->len); 98041709d23SRuslan Bukin err = bus_dmamap_load(sc->buf_tag, sc->buf_map, 98141709d23SRuslan Bukin data->data, data->len, dwmmc_ring_setup, 98241709d23SRuslan Bukin sc, BUS_DMA_NOWAIT); 98341709d23SRuslan Bukin if (err != 0) 98441709d23SRuslan Bukin panic("dmamap_load failed\n"); 98541709d23SRuslan Bukin 986f3ad8ea0SAndrew Turner /* Ensure the device can see the desc */ 987f3ad8ea0SAndrew Turner bus_dmamap_sync(sc->desc_tag, sc->desc_map, 988f3ad8ea0SAndrew Turner BUS_DMASYNC_PREWRITE); 989f3ad8ea0SAndrew Turner 99041709d23SRuslan Bukin if (data->flags & MMC_DATA_WRITE) 99141709d23SRuslan Bukin bus_dmamap_sync(sc->buf_tag, sc->buf_map, 99241709d23SRuslan Bukin BUS_DMASYNC_PREWRITE); 99341709d23SRuslan Bukin else 99441709d23SRuslan Bukin bus_dmamap_sync(sc->buf_tag, sc->buf_map, 99541709d23SRuslan Bukin BUS_DMASYNC_PREREAD); 99641709d23SRuslan Bukin 99741709d23SRuslan Bukin reg = (DEF_MSIZE << SDMMC_FIFOTH_MSIZE_S); 99841709d23SRuslan Bukin reg |= ((sc->fifo_depth / 2) - 1) << SDMMC_FIFOTH_RXWMARK_S; 99941709d23SRuslan Bukin reg |= (sc->fifo_depth / 2) << SDMMC_FIFOTH_TXWMARK_S; 100041709d23SRuslan Bukin 100141709d23SRuslan Bukin WRITE4(sc, SDMMC_FIFOTH, reg); 100241709d23SRuslan Bukin wmb(); 100341709d23SRuslan Bukin 100441709d23SRuslan Bukin reg = READ4(sc, SDMMC_CTRL); 100541709d23SRuslan Bukin reg |= (SDMMC_CTRL_USE_IDMAC | SDMMC_CTRL_DMA_ENABLE); 100641709d23SRuslan Bukin WRITE4(sc, SDMMC_CTRL, reg); 100741709d23SRuslan Bukin wmb(); 100841709d23SRuslan Bukin 100941709d23SRuslan Bukin reg = READ4(sc, SDMMC_BMOD); 101041709d23SRuslan Bukin reg |= (SDMMC_BMOD_DE | SDMMC_BMOD_FB); 101141709d23SRuslan Bukin WRITE4(sc, SDMMC_BMOD, reg); 101241709d23SRuslan Bukin 101341709d23SRuslan Bukin /* Start */ 101441709d23SRuslan Bukin WRITE4(sc, SDMMC_PLDMND, 1); 101541709d23SRuslan Bukin 101641709d23SRuslan Bukin return (0); 101741709d23SRuslan Bukin } 101841709d23SRuslan Bukin 1019e2763dcaSGanbold Tsagaankhuu static int 1020e2763dcaSGanbold Tsagaankhuu pio_prepare(struct dwmmc_softc *sc, struct mmc_command *cmd) 1021e2763dcaSGanbold Tsagaankhuu { 1022e2763dcaSGanbold Tsagaankhuu struct mmc_data *data; 1023e2763dcaSGanbold Tsagaankhuu int reg; 1024e2763dcaSGanbold Tsagaankhuu 1025e2763dcaSGanbold Tsagaankhuu data = cmd->data; 1026e2763dcaSGanbold Tsagaankhuu data->xfer_len = 0; 1027e2763dcaSGanbold Tsagaankhuu 1028e2763dcaSGanbold Tsagaankhuu reg = (DEF_MSIZE << SDMMC_FIFOTH_MSIZE_S); 1029e2763dcaSGanbold Tsagaankhuu reg |= ((sc->fifo_depth / 2) - 1) << SDMMC_FIFOTH_RXWMARK_S; 1030e2763dcaSGanbold Tsagaankhuu reg |= (sc->fifo_depth / 2) << SDMMC_FIFOTH_TXWMARK_S; 1031e2763dcaSGanbold Tsagaankhuu 1032e2763dcaSGanbold Tsagaankhuu WRITE4(sc, SDMMC_FIFOTH, reg); 1033e2763dcaSGanbold Tsagaankhuu wmb(); 1034e2763dcaSGanbold Tsagaankhuu 1035e2763dcaSGanbold Tsagaankhuu return (0); 1036e2763dcaSGanbold Tsagaankhuu } 1037e2763dcaSGanbold Tsagaankhuu 1038e2763dcaSGanbold Tsagaankhuu static void 1039e2763dcaSGanbold Tsagaankhuu pio_read(struct dwmmc_softc *sc, struct mmc_command *cmd) 1040e2763dcaSGanbold Tsagaankhuu { 1041e2763dcaSGanbold Tsagaankhuu struct mmc_data *data; 1042e2763dcaSGanbold Tsagaankhuu uint32_t *p, status; 1043e2763dcaSGanbold Tsagaankhuu 1044e2763dcaSGanbold Tsagaankhuu if (cmd == NULL || cmd->data == NULL) 1045e2763dcaSGanbold Tsagaankhuu return; 1046e2763dcaSGanbold Tsagaankhuu 1047e2763dcaSGanbold Tsagaankhuu data = cmd->data; 1048e2763dcaSGanbold Tsagaankhuu if ((data->flags & MMC_DATA_READ) == 0) 1049e2763dcaSGanbold Tsagaankhuu return; 1050e2763dcaSGanbold Tsagaankhuu 1051e2763dcaSGanbold Tsagaankhuu KASSERT((data->xfer_len & 3) == 0, ("xfer_len not aligned")); 1052e2763dcaSGanbold Tsagaankhuu p = (uint32_t *)data->data + (data->xfer_len >> 2); 1053e2763dcaSGanbold Tsagaankhuu 1054e2763dcaSGanbold Tsagaankhuu while (data->xfer_len < data->len) { 1055e2763dcaSGanbold Tsagaankhuu status = READ4(sc, SDMMC_STATUS); 1056e2763dcaSGanbold Tsagaankhuu if (status & SDMMC_STATUS_FIFO_EMPTY) 1057e2763dcaSGanbold Tsagaankhuu break; 1058e2763dcaSGanbold Tsagaankhuu *p++ = READ4(sc, SDMMC_DATA); 1059e2763dcaSGanbold Tsagaankhuu data->xfer_len += 4; 1060e2763dcaSGanbold Tsagaankhuu } 1061e2763dcaSGanbold Tsagaankhuu 1062e2763dcaSGanbold Tsagaankhuu WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_RXDR); 1063e2763dcaSGanbold Tsagaankhuu } 1064e2763dcaSGanbold Tsagaankhuu 1065e2763dcaSGanbold Tsagaankhuu static void 1066e2763dcaSGanbold Tsagaankhuu pio_write(struct dwmmc_softc *sc, struct mmc_command *cmd) 1067e2763dcaSGanbold Tsagaankhuu { 1068e2763dcaSGanbold Tsagaankhuu struct mmc_data *data; 1069e2763dcaSGanbold Tsagaankhuu uint32_t *p, status; 1070e2763dcaSGanbold Tsagaankhuu 1071e2763dcaSGanbold Tsagaankhuu if (cmd == NULL || cmd->data == NULL) 1072e2763dcaSGanbold Tsagaankhuu return; 1073e2763dcaSGanbold Tsagaankhuu 1074e2763dcaSGanbold Tsagaankhuu data = cmd->data; 1075e2763dcaSGanbold Tsagaankhuu if ((data->flags & MMC_DATA_WRITE) == 0) 1076e2763dcaSGanbold Tsagaankhuu return; 1077e2763dcaSGanbold Tsagaankhuu 1078e2763dcaSGanbold Tsagaankhuu KASSERT((data->xfer_len & 3) == 0, ("xfer_len not aligned")); 1079e2763dcaSGanbold Tsagaankhuu p = (uint32_t *)data->data + (data->xfer_len >> 2); 1080e2763dcaSGanbold Tsagaankhuu 1081e2763dcaSGanbold Tsagaankhuu while (data->xfer_len < data->len) { 1082e2763dcaSGanbold Tsagaankhuu status = READ4(sc, SDMMC_STATUS); 1083e2763dcaSGanbold Tsagaankhuu if (status & SDMMC_STATUS_FIFO_FULL) 1084e2763dcaSGanbold Tsagaankhuu break; 1085e2763dcaSGanbold Tsagaankhuu WRITE4(sc, SDMMC_DATA, *p++); 1086e2763dcaSGanbold Tsagaankhuu data->xfer_len += 4; 1087e2763dcaSGanbold Tsagaankhuu } 1088e2763dcaSGanbold Tsagaankhuu 1089e2763dcaSGanbold Tsagaankhuu WRITE4(sc, SDMMC_RINTSTS, SDMMC_INTMASK_TXDR); 1090e2763dcaSGanbold Tsagaankhuu } 1091e2763dcaSGanbold Tsagaankhuu 109241709d23SRuslan Bukin static void 109341709d23SRuslan Bukin dwmmc_start_cmd(struct dwmmc_softc *sc, struct mmc_command *cmd) 109441709d23SRuslan Bukin { 109541709d23SRuslan Bukin struct mmc_data *data; 109641709d23SRuslan Bukin uint32_t blksz; 109741709d23SRuslan Bukin uint32_t cmdr; 109841709d23SRuslan Bukin 109941c653beSEmmanuel Vadot dprintf("%s\n", __func__); 110041709d23SRuslan Bukin sc->curcmd = cmd; 110141709d23SRuslan Bukin data = cmd->data; 110241709d23SRuslan Bukin 110341c653beSEmmanuel Vadot #ifndef MMCCAM 110441709d23SRuslan Bukin /* XXX Upper layers don't always set this */ 110541709d23SRuslan Bukin cmd->mrq = sc->req; 110641c653beSEmmanuel Vadot #endif 110741709d23SRuslan Bukin /* Begin setting up command register. */ 110841709d23SRuslan Bukin 110941709d23SRuslan Bukin cmdr = cmd->opcode; 111041709d23SRuslan Bukin 111141709d23SRuslan Bukin dprintf("cmd->opcode 0x%08x\n", cmd->opcode); 111241709d23SRuslan Bukin 111341709d23SRuslan Bukin if (cmd->opcode == MMC_STOP_TRANSMISSION || 111441709d23SRuslan Bukin cmd->opcode == MMC_GO_IDLE_STATE || 111541709d23SRuslan Bukin cmd->opcode == MMC_GO_INACTIVE_STATE) 111641709d23SRuslan Bukin cmdr |= SDMMC_CMD_STOP_ABORT; 111741709d23SRuslan Bukin else if (cmd->opcode != MMC_SEND_STATUS && data) 111841709d23SRuslan Bukin cmdr |= SDMMC_CMD_WAIT_PRVDATA; 111941709d23SRuslan Bukin 112041709d23SRuslan Bukin /* Set up response handling. */ 112141709d23SRuslan Bukin if (MMC_RSP(cmd->flags) != MMC_RSP_NONE) { 112241709d23SRuslan Bukin cmdr |= SDMMC_CMD_RESP_EXP; 112341709d23SRuslan Bukin if (cmd->flags & MMC_RSP_136) 112441709d23SRuslan Bukin cmdr |= SDMMC_CMD_RESP_LONG; 112541709d23SRuslan Bukin } 112641709d23SRuslan Bukin 112741709d23SRuslan Bukin if (cmd->flags & MMC_RSP_CRC) 112841709d23SRuslan Bukin cmdr |= SDMMC_CMD_RESP_CRC; 112941709d23SRuslan Bukin 113041709d23SRuslan Bukin /* 113141709d23SRuslan Bukin * XXX: Not all platforms want this. 113241709d23SRuslan Bukin */ 113341709d23SRuslan Bukin cmdr |= SDMMC_CMD_USE_HOLD_REG; 113441709d23SRuslan Bukin 113541709d23SRuslan Bukin if ((sc->flags & CARD_INIT_DONE) == 0) { 113641709d23SRuslan Bukin sc->flags |= (CARD_INIT_DONE); 113741709d23SRuslan Bukin cmdr |= SDMMC_CMD_SEND_INIT; 113841709d23SRuslan Bukin } 113941709d23SRuslan Bukin 114041709d23SRuslan Bukin if (data) { 114141709d23SRuslan Bukin if ((cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK || 114241709d23SRuslan Bukin cmd->opcode == MMC_READ_MULTIPLE_BLOCK) && 114341709d23SRuslan Bukin sc->use_auto_stop) 114441709d23SRuslan Bukin cmdr |= SDMMC_CMD_SEND_ASTOP; 114541709d23SRuslan Bukin 114641709d23SRuslan Bukin cmdr |= SDMMC_CMD_DATA_EXP; 114741709d23SRuslan Bukin if (data->flags & MMC_DATA_STREAM) 114841709d23SRuslan Bukin cmdr |= SDMMC_CMD_MODE_STREAM; 114941709d23SRuslan Bukin if (data->flags & MMC_DATA_WRITE) 115041709d23SRuslan Bukin cmdr |= SDMMC_CMD_DATA_WRITE; 115141709d23SRuslan Bukin 115241709d23SRuslan Bukin WRITE4(sc, SDMMC_TMOUT, 0xffffffff); 1153990a1dbfSEmmanuel Vadot #ifdef MMCCAM 1154990a1dbfSEmmanuel Vadot if (cmd->data->flags & MMC_DATA_BLOCK_SIZE) { 1155990a1dbfSEmmanuel Vadot WRITE4(sc, SDMMC_BLKSIZ, cmd->data->block_size); 1156990a1dbfSEmmanuel Vadot WRITE4(sc, SDMMC_BYTCNT, cmd->data->len); 1157990a1dbfSEmmanuel Vadot } else 1158990a1dbfSEmmanuel Vadot #endif 1159990a1dbfSEmmanuel Vadot { 116041709d23SRuslan Bukin WRITE4(sc, SDMMC_BYTCNT, data->len); 116141709d23SRuslan Bukin blksz = (data->len < MMC_SECTOR_SIZE) ? \ 116241709d23SRuslan Bukin data->len : MMC_SECTOR_SIZE; 116341709d23SRuslan Bukin WRITE4(sc, SDMMC_BLKSIZ, blksz); 1164990a1dbfSEmmanuel Vadot } 116541709d23SRuslan Bukin 1166e2763dcaSGanbold Tsagaankhuu if (sc->use_pio) { 1167e2763dcaSGanbold Tsagaankhuu pio_prepare(sc, cmd); 1168e2763dcaSGanbold Tsagaankhuu } else { 116941709d23SRuslan Bukin dma_prepare(sc, cmd); 1170e2763dcaSGanbold Tsagaankhuu } 117141709d23SRuslan Bukin wmb(); 117241709d23SRuslan Bukin } 117341709d23SRuslan Bukin 117441709d23SRuslan Bukin dprintf("cmdr 0x%08x\n", cmdr); 117541709d23SRuslan Bukin 117641709d23SRuslan Bukin WRITE4(sc, SDMMC_CMDARG, cmd->arg); 117741709d23SRuslan Bukin wmb(); 117841709d23SRuslan Bukin WRITE4(sc, SDMMC_CMD, cmdr | SDMMC_CMD_START); 117941709d23SRuslan Bukin }; 118041709d23SRuslan Bukin 118141709d23SRuslan Bukin static void 118241709d23SRuslan Bukin dwmmc_next_operation(struct dwmmc_softc *sc) 118341709d23SRuslan Bukin { 118441c653beSEmmanuel Vadot struct mmc_command *cmd; 118541c653beSEmmanuel Vadot dprintf("%s\n", __func__); 118641c653beSEmmanuel Vadot #ifdef MMCCAM 118741c653beSEmmanuel Vadot union ccb *ccb; 118841c653beSEmmanuel Vadot 118941c653beSEmmanuel Vadot ccb = sc->ccb; 119041c653beSEmmanuel Vadot if (ccb == NULL) 119141c653beSEmmanuel Vadot return; 119241c653beSEmmanuel Vadot cmd = &ccb->mmcio.cmd; 119341c653beSEmmanuel Vadot #else 119441709d23SRuslan Bukin struct mmc_request *req; 119541709d23SRuslan Bukin 119641709d23SRuslan Bukin req = sc->req; 119741709d23SRuslan Bukin if (req == NULL) 119841709d23SRuslan Bukin return; 119941c653beSEmmanuel Vadot cmd = req->cmd; 120041c653beSEmmanuel Vadot #endif 120141709d23SRuslan Bukin 120241709d23SRuslan Bukin sc->acd_rcvd = 0; 120341709d23SRuslan Bukin sc->dto_rcvd = 0; 120441709d23SRuslan Bukin sc->cmd_done = 0; 120541709d23SRuslan Bukin 120641709d23SRuslan Bukin /* 120741709d23SRuslan Bukin * XXX: Wait until card is still busy. 120841709d23SRuslan Bukin * We do need this to prevent data timeouts, 120941709d23SRuslan Bukin * mostly caused by multi-block write command 121041709d23SRuslan Bukin * followed by single-read. 121141709d23SRuslan Bukin */ 121241709d23SRuslan Bukin while(READ4(sc, SDMMC_STATUS) & (SDMMC_STATUS_DATA_BUSY)) 121341709d23SRuslan Bukin continue; 121441709d23SRuslan Bukin 121541709d23SRuslan Bukin if (sc->flags & PENDING_CMD) { 121641709d23SRuslan Bukin sc->flags &= ~PENDING_CMD; 121741c653beSEmmanuel Vadot dwmmc_start_cmd(sc, cmd); 121841709d23SRuslan Bukin return; 121941709d23SRuslan Bukin } else if (sc->flags & PENDING_STOP && !sc->use_auto_stop) { 122041709d23SRuslan Bukin sc->flags &= ~PENDING_STOP; 122141c653beSEmmanuel Vadot /// XXX: What to do with this? 122241c653beSEmmanuel Vadot //dwmmc_start_cmd(sc, req->stop); 122341709d23SRuslan Bukin return; 122441709d23SRuslan Bukin } 122541709d23SRuslan Bukin 122641c653beSEmmanuel Vadot #ifdef MMCCAM 122741c653beSEmmanuel Vadot sc->ccb = NULL; 122841c653beSEmmanuel Vadot sc->curcmd = NULL; 122941c653beSEmmanuel Vadot ccb->ccb_h.status = 123041c653beSEmmanuel Vadot (ccb->mmcio.cmd.error == 0 ? CAM_REQ_CMP : CAM_REQ_CMP_ERR); 123141c653beSEmmanuel Vadot xpt_done(ccb); 123241c653beSEmmanuel Vadot #else 123341709d23SRuslan Bukin sc->req = NULL; 123441709d23SRuslan Bukin sc->curcmd = NULL; 123541709d23SRuslan Bukin req->done(req); 123641c653beSEmmanuel Vadot #endif 123741709d23SRuslan Bukin } 123841709d23SRuslan Bukin 123941709d23SRuslan Bukin static int 124041709d23SRuslan Bukin dwmmc_request(device_t brdev, device_t reqdev, struct mmc_request *req) 124141709d23SRuslan Bukin { 124241709d23SRuslan Bukin struct dwmmc_softc *sc; 124341709d23SRuslan Bukin 124441709d23SRuslan Bukin sc = device_get_softc(brdev); 124541709d23SRuslan Bukin 124641709d23SRuslan Bukin dprintf("%s\n", __func__); 124741709d23SRuslan Bukin 124841709d23SRuslan Bukin DWMMC_LOCK(sc); 124941709d23SRuslan Bukin 125041c653beSEmmanuel Vadot #ifdef MMCCAM 125141c653beSEmmanuel Vadot sc->flags |= PENDING_CMD; 125241c653beSEmmanuel Vadot #else 125341709d23SRuslan Bukin if (sc->req != NULL) { 125441709d23SRuslan Bukin DWMMC_UNLOCK(sc); 125541709d23SRuslan Bukin return (EBUSY); 125641709d23SRuslan Bukin } 125741709d23SRuslan Bukin 125841709d23SRuslan Bukin sc->req = req; 125941709d23SRuslan Bukin sc->flags |= PENDING_CMD; 126041709d23SRuslan Bukin if (sc->req->stop) 126141709d23SRuslan Bukin sc->flags |= PENDING_STOP; 126241c653beSEmmanuel Vadot #endif 126341709d23SRuslan Bukin dwmmc_next_operation(sc); 126441709d23SRuslan Bukin 126541709d23SRuslan Bukin DWMMC_UNLOCK(sc); 126641709d23SRuslan Bukin return (0); 126741709d23SRuslan Bukin } 126841709d23SRuslan Bukin 1269f1cc48e5SEmmanuel Vadot #ifndef MMCCAM 127041709d23SRuslan Bukin static int 127141709d23SRuslan Bukin dwmmc_get_ro(device_t brdev, device_t reqdev) 127241709d23SRuslan Bukin { 127341709d23SRuslan Bukin 127441709d23SRuslan Bukin dprintf("%s\n", __func__); 127541709d23SRuslan Bukin 127641709d23SRuslan Bukin return (0); 127741709d23SRuslan Bukin } 127841709d23SRuslan Bukin 127941709d23SRuslan Bukin static int 128041709d23SRuslan Bukin dwmmc_acquire_host(device_t brdev, device_t reqdev) 128141709d23SRuslan Bukin { 128241709d23SRuslan Bukin struct dwmmc_softc *sc; 128341709d23SRuslan Bukin 128441709d23SRuslan Bukin sc = device_get_softc(brdev); 128541709d23SRuslan Bukin 128641709d23SRuslan Bukin DWMMC_LOCK(sc); 128741709d23SRuslan Bukin while (sc->bus_busy) 128841709d23SRuslan Bukin msleep(sc, &sc->sc_mtx, PZERO, "dwmmcah", hz / 5); 128941709d23SRuslan Bukin sc->bus_busy++; 129041709d23SRuslan Bukin DWMMC_UNLOCK(sc); 129141709d23SRuslan Bukin return (0); 129241709d23SRuslan Bukin } 129341709d23SRuslan Bukin 129441709d23SRuslan Bukin static int 129541709d23SRuslan Bukin dwmmc_release_host(device_t brdev, device_t reqdev) 129641709d23SRuslan Bukin { 129741709d23SRuslan Bukin struct dwmmc_softc *sc; 129841709d23SRuslan Bukin 129941709d23SRuslan Bukin sc = device_get_softc(brdev); 130041709d23SRuslan Bukin 130141709d23SRuslan Bukin DWMMC_LOCK(sc); 130241709d23SRuslan Bukin sc->bus_busy--; 130341709d23SRuslan Bukin wakeup(sc); 130441709d23SRuslan Bukin DWMMC_UNLOCK(sc); 130541709d23SRuslan Bukin return (0); 130641709d23SRuslan Bukin } 1307f1cc48e5SEmmanuel Vadot #endif /* !MMCCAM */ 130841709d23SRuslan Bukin 130941709d23SRuslan Bukin static int 131041709d23SRuslan Bukin dwmmc_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 131141709d23SRuslan Bukin { 131241709d23SRuslan Bukin struct dwmmc_softc *sc; 131341709d23SRuslan Bukin 131441709d23SRuslan Bukin sc = device_get_softc(bus); 131541709d23SRuslan Bukin 131641709d23SRuslan Bukin switch (which) { 131741709d23SRuslan Bukin default: 131841709d23SRuslan Bukin return (EINVAL); 131941709d23SRuslan Bukin case MMCBR_IVAR_BUS_MODE: 132041709d23SRuslan Bukin *(int *)result = sc->host.ios.bus_mode; 132141709d23SRuslan Bukin break; 132241709d23SRuslan Bukin case MMCBR_IVAR_BUS_WIDTH: 132341709d23SRuslan Bukin *(int *)result = sc->host.ios.bus_width; 132441709d23SRuslan Bukin break; 132541709d23SRuslan Bukin case MMCBR_IVAR_CHIP_SELECT: 132641709d23SRuslan Bukin *(int *)result = sc->host.ios.chip_select; 132741709d23SRuslan Bukin break; 132841709d23SRuslan Bukin case MMCBR_IVAR_CLOCK: 132941709d23SRuslan Bukin *(int *)result = sc->host.ios.clock; 133041709d23SRuslan Bukin break; 133141709d23SRuslan Bukin case MMCBR_IVAR_F_MIN: 133241709d23SRuslan Bukin *(int *)result = sc->host.f_min; 133341709d23SRuslan Bukin break; 133441709d23SRuslan Bukin case MMCBR_IVAR_F_MAX: 133541709d23SRuslan Bukin *(int *)result = sc->host.f_max; 133641709d23SRuslan Bukin break; 133741709d23SRuslan Bukin case MMCBR_IVAR_HOST_OCR: 133841709d23SRuslan Bukin *(int *)result = sc->host.host_ocr; 133941709d23SRuslan Bukin break; 134041709d23SRuslan Bukin case MMCBR_IVAR_MODE: 134141709d23SRuslan Bukin *(int *)result = sc->host.mode; 134241709d23SRuslan Bukin break; 134341709d23SRuslan Bukin case MMCBR_IVAR_OCR: 134441709d23SRuslan Bukin *(int *)result = sc->host.ocr; 134541709d23SRuslan Bukin break; 134641709d23SRuslan Bukin case MMCBR_IVAR_POWER_MODE: 134741709d23SRuslan Bukin *(int *)result = sc->host.ios.power_mode; 134841709d23SRuslan Bukin break; 134941709d23SRuslan Bukin case MMCBR_IVAR_VDD: 135041709d23SRuslan Bukin *(int *)result = sc->host.ios.vdd; 135141709d23SRuslan Bukin break; 13524924bcd3SWarner Losh case MMCBR_IVAR_VCCQ: 13534924bcd3SWarner Losh *(int *)result = sc->host.ios.vccq; 13544924bcd3SWarner Losh break; 135541709d23SRuslan Bukin case MMCBR_IVAR_CAPS: 135641709d23SRuslan Bukin *(int *)result = sc->host.caps; 135741709d23SRuslan Bukin break; 135841709d23SRuslan Bukin case MMCBR_IVAR_MAX_DATA: 1359dfb73602SMichal Meloun *(int *)result = DWMMC_MAX_DATA; 1360a4e0b5a4SEmmanuel Vadot break; 1361a4e0b5a4SEmmanuel Vadot case MMCBR_IVAR_TIMING: 1362a4e0b5a4SEmmanuel Vadot *(int *)result = sc->host.ios.timing; 1363a4e0b5a4SEmmanuel Vadot break; 136441709d23SRuslan Bukin } 136541709d23SRuslan Bukin return (0); 136641709d23SRuslan Bukin } 136741709d23SRuslan Bukin 136841709d23SRuslan Bukin static int 136941709d23SRuslan Bukin dwmmc_write_ivar(device_t bus, device_t child, int which, uintptr_t value) 137041709d23SRuslan Bukin { 137141709d23SRuslan Bukin struct dwmmc_softc *sc; 137241709d23SRuslan Bukin 137341709d23SRuslan Bukin sc = device_get_softc(bus); 137441709d23SRuslan Bukin 137541709d23SRuslan Bukin switch (which) { 137641709d23SRuslan Bukin default: 137741709d23SRuslan Bukin return (EINVAL); 137841709d23SRuslan Bukin case MMCBR_IVAR_BUS_MODE: 137941709d23SRuslan Bukin sc->host.ios.bus_mode = value; 138041709d23SRuslan Bukin break; 138141709d23SRuslan Bukin case MMCBR_IVAR_BUS_WIDTH: 138241709d23SRuslan Bukin sc->host.ios.bus_width = value; 138341709d23SRuslan Bukin break; 138441709d23SRuslan Bukin case MMCBR_IVAR_CHIP_SELECT: 138541709d23SRuslan Bukin sc->host.ios.chip_select = value; 138641709d23SRuslan Bukin break; 138741709d23SRuslan Bukin case MMCBR_IVAR_CLOCK: 138841709d23SRuslan Bukin sc->host.ios.clock = value; 138941709d23SRuslan Bukin break; 139041709d23SRuslan Bukin case MMCBR_IVAR_MODE: 139141709d23SRuslan Bukin sc->host.mode = value; 139241709d23SRuslan Bukin break; 139341709d23SRuslan Bukin case MMCBR_IVAR_OCR: 139441709d23SRuslan Bukin sc->host.ocr = value; 139541709d23SRuslan Bukin break; 139641709d23SRuslan Bukin case MMCBR_IVAR_POWER_MODE: 139741709d23SRuslan Bukin sc->host.ios.power_mode = value; 139841709d23SRuslan Bukin break; 139941709d23SRuslan Bukin case MMCBR_IVAR_VDD: 140041709d23SRuslan Bukin sc->host.ios.vdd = value; 140141709d23SRuslan Bukin break; 1402a4e0b5a4SEmmanuel Vadot case MMCBR_IVAR_TIMING: 1403a4e0b5a4SEmmanuel Vadot sc->host.ios.timing = value; 1404a4e0b5a4SEmmanuel Vadot break; 1405a4e0b5a4SEmmanuel Vadot case MMCBR_IVAR_VCCQ: 1406fbcd7187SWarner Losh sc->host.ios.vccq = value; 1407a4e0b5a4SEmmanuel Vadot break; 140841709d23SRuslan Bukin /* These are read-only */ 140941709d23SRuslan Bukin case MMCBR_IVAR_CAPS: 141041709d23SRuslan Bukin case MMCBR_IVAR_HOST_OCR: 141141709d23SRuslan Bukin case MMCBR_IVAR_F_MIN: 141241709d23SRuslan Bukin case MMCBR_IVAR_F_MAX: 141341709d23SRuslan Bukin case MMCBR_IVAR_MAX_DATA: 141441709d23SRuslan Bukin return (EINVAL); 141541709d23SRuslan Bukin } 141641709d23SRuslan Bukin return (0); 141741709d23SRuslan Bukin } 141841709d23SRuslan Bukin 1419f4e5e045SEmmanuel Vadot #ifdef MMCCAM 142041c653beSEmmanuel Vadot /* Note: this function likely belongs to the specific driver impl */ 142141c653beSEmmanuel Vadot static int 142241c653beSEmmanuel Vadot dwmmc_switch_vccq(device_t dev, device_t child) 142341c653beSEmmanuel Vadot { 142441c653beSEmmanuel Vadot device_printf(dev, "This is a default impl of switch_vccq() that always fails\n"); 142541c653beSEmmanuel Vadot return EINVAL; 142641c653beSEmmanuel Vadot } 142741c653beSEmmanuel Vadot 1428f1cc48e5SEmmanuel Vadot static int 1429f1cc48e5SEmmanuel Vadot dwmmc_get_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts) 143041c653beSEmmanuel Vadot { 143141c653beSEmmanuel Vadot struct dwmmc_softc *sc; 143241c653beSEmmanuel Vadot 1433f1cc48e5SEmmanuel Vadot sc = device_get_softc(dev); 143441c653beSEmmanuel Vadot 1435f1cc48e5SEmmanuel Vadot cts->host_ocr = sc->host.host_ocr; 1436f1cc48e5SEmmanuel Vadot cts->host_f_min = sc->host.f_min; 1437f1cc48e5SEmmanuel Vadot cts->host_f_max = sc->host.f_max; 1438f1cc48e5SEmmanuel Vadot cts->host_caps = sc->host.caps; 1439dfb73602SMichal Meloun cts->host_max_data = DWMMC_MAX_DATA; 1440f1cc48e5SEmmanuel Vadot memcpy(&cts->ios, &sc->host.ios, sizeof(struct mmc_ios)); 144141c653beSEmmanuel Vadot 1442f1cc48e5SEmmanuel Vadot return (0); 144341c653beSEmmanuel Vadot } 144441c653beSEmmanuel Vadot 144541c653beSEmmanuel Vadot static int 1446f1cc48e5SEmmanuel Vadot dwmmc_set_tran_settings(device_t dev, struct ccb_trans_settings_mmc *cts) 144741c653beSEmmanuel Vadot { 1448f1cc48e5SEmmanuel Vadot struct dwmmc_softc *sc; 144941c653beSEmmanuel Vadot struct mmc_ios *ios; 145041c653beSEmmanuel Vadot struct mmc_ios *new_ios; 145141c653beSEmmanuel Vadot int res; 145241c653beSEmmanuel Vadot 1453f1cc48e5SEmmanuel Vadot sc = device_get_softc(dev); 145441c653beSEmmanuel Vadot ios = &sc->host.ios; 145541c653beSEmmanuel Vadot 145641c653beSEmmanuel Vadot new_ios = &cts->ios; 145741c653beSEmmanuel Vadot 145841c653beSEmmanuel Vadot /* Update only requested fields */ 145941c653beSEmmanuel Vadot if (cts->ios_valid & MMC_CLK) { 146041c653beSEmmanuel Vadot ios->clock = new_ios->clock; 146141c653beSEmmanuel Vadot if (bootverbose) 146241c653beSEmmanuel Vadot device_printf(sc->dev, "Clock => %d\n", ios->clock); 146341c653beSEmmanuel Vadot } 146441c653beSEmmanuel Vadot if (cts->ios_valid & MMC_VDD) { 146541c653beSEmmanuel Vadot ios->vdd = new_ios->vdd; 146641c653beSEmmanuel Vadot if (bootverbose) 146741c653beSEmmanuel Vadot device_printf(sc->dev, "VDD => %d\n", ios->vdd); 146841c653beSEmmanuel Vadot } 146941c653beSEmmanuel Vadot if (cts->ios_valid & MMC_CS) { 147041c653beSEmmanuel Vadot ios->chip_select = new_ios->chip_select; 147141c653beSEmmanuel Vadot if (bootverbose) 147241c653beSEmmanuel Vadot device_printf(sc->dev, "CS => %d\n", ios->chip_select); 147341c653beSEmmanuel Vadot } 147441c653beSEmmanuel Vadot if (cts->ios_valid & MMC_BW) { 147541c653beSEmmanuel Vadot ios->bus_width = new_ios->bus_width; 147641c653beSEmmanuel Vadot if (bootverbose) 147741c653beSEmmanuel Vadot device_printf(sc->dev, "Bus width => %d\n", ios->bus_width); 147841c653beSEmmanuel Vadot } 147941c653beSEmmanuel Vadot if (cts->ios_valid & MMC_PM) { 148041c653beSEmmanuel Vadot ios->power_mode = new_ios->power_mode; 148141c653beSEmmanuel Vadot if (bootverbose) 148241c653beSEmmanuel Vadot device_printf(sc->dev, "Power mode => %d\n", ios->power_mode); 148341c653beSEmmanuel Vadot } 148441c653beSEmmanuel Vadot if (cts->ios_valid & MMC_BT) { 148541c653beSEmmanuel Vadot ios->timing = new_ios->timing; 148641c653beSEmmanuel Vadot if (bootverbose) 148741c653beSEmmanuel Vadot device_printf(sc->dev, "Timing => %d\n", ios->timing); 148841c653beSEmmanuel Vadot } 148941c653beSEmmanuel Vadot if (cts->ios_valid & MMC_BM) { 149041c653beSEmmanuel Vadot ios->bus_mode = new_ios->bus_mode; 149141c653beSEmmanuel Vadot if (bootverbose) 149241c653beSEmmanuel Vadot device_printf(sc->dev, "Bus mode => %d\n", ios->bus_mode); 149341c653beSEmmanuel Vadot } 149441c653beSEmmanuel Vadot if (cts->ios_valid & MMC_VCCQ) { 149541c653beSEmmanuel Vadot ios->vccq = new_ios->vccq; 149641c653beSEmmanuel Vadot if (bootverbose) 149741c653beSEmmanuel Vadot device_printf(sc->dev, "VCCQ => %d\n", ios->vccq); 149841c653beSEmmanuel Vadot res = dwmmc_switch_vccq(sc->dev, NULL); 149941c653beSEmmanuel Vadot device_printf(sc->dev, "VCCQ switch result: %d\n", res); 150041c653beSEmmanuel Vadot } 150141c653beSEmmanuel Vadot 150241c653beSEmmanuel Vadot return (dwmmc_update_ios(sc->dev, NULL)); 150341c653beSEmmanuel Vadot } 150441c653beSEmmanuel Vadot 150541c653beSEmmanuel Vadot static int 1506f1cc48e5SEmmanuel Vadot dwmmc_cam_request(device_t dev, union ccb *ccb) 150741c653beSEmmanuel Vadot { 1508f1cc48e5SEmmanuel Vadot struct dwmmc_softc *sc; 150941c653beSEmmanuel Vadot struct ccb_mmcio *mmcio; 151041c653beSEmmanuel Vadot 1511f1cc48e5SEmmanuel Vadot sc = device_get_softc(dev); 151241c653beSEmmanuel Vadot mmcio = &ccb->mmcio; 151341c653beSEmmanuel Vadot 151441c653beSEmmanuel Vadot DWMMC_LOCK(sc); 151541c653beSEmmanuel Vadot 151641c653beSEmmanuel Vadot #ifdef DEBUG 151741c653beSEmmanuel Vadot if (__predict_false(bootverbose)) { 151841c653beSEmmanuel Vadot device_printf(sc->dev, "CMD%u arg %#x flags %#x dlen %u dflags %#x\n", 151941c653beSEmmanuel Vadot mmcio->cmd.opcode, mmcio->cmd.arg, mmcio->cmd.flags, 152041c653beSEmmanuel Vadot mmcio->cmd.data != NULL ? (unsigned int) mmcio->cmd.data->len : 0, 152141c653beSEmmanuel Vadot mmcio->cmd.data != NULL ? mmcio->cmd.data->flags: 0); 152241c653beSEmmanuel Vadot } 152341c653beSEmmanuel Vadot #endif 152441c653beSEmmanuel Vadot if (mmcio->cmd.data != NULL) { 152541c653beSEmmanuel Vadot if (mmcio->cmd.data->len == 0 || mmcio->cmd.data->flags == 0) 152641c653beSEmmanuel Vadot panic("data->len = %d, data->flags = %d -- something is b0rked", 152741c653beSEmmanuel Vadot (int)mmcio->cmd.data->len, mmcio->cmd.data->flags); 152841c653beSEmmanuel Vadot } 152941c653beSEmmanuel Vadot if (sc->ccb != NULL) { 153041c653beSEmmanuel Vadot device_printf(sc->dev, "Controller still has an active command\n"); 153141c653beSEmmanuel Vadot return (EBUSY); 153241c653beSEmmanuel Vadot } 153341c653beSEmmanuel Vadot sc->ccb = ccb; 153441c653beSEmmanuel Vadot DWMMC_UNLOCK(sc); 153541c653beSEmmanuel Vadot dwmmc_request(sc->dev, NULL, NULL); 153641c653beSEmmanuel Vadot 153741c653beSEmmanuel Vadot return (0); 153841c653beSEmmanuel Vadot } 153944682688SAndriy Gapon 154044682688SAndriy Gapon static void 154144682688SAndriy Gapon dwmmc_cam_poll(device_t dev) 154244682688SAndriy Gapon { 154344682688SAndriy Gapon struct dwmmc_softc *sc; 154444682688SAndriy Gapon 154544682688SAndriy Gapon sc = device_get_softc(dev); 154644682688SAndriy Gapon dwmmc_intr(sc); 154744682688SAndriy Gapon } 1548f1cc48e5SEmmanuel Vadot #endif /* MMCCAM */ 154941c653beSEmmanuel Vadot 155041709d23SRuslan Bukin static device_method_t dwmmc_methods[] = { 155141709d23SRuslan Bukin /* Bus interface */ 155241709d23SRuslan Bukin DEVMETHOD(bus_read_ivar, dwmmc_read_ivar), 155341709d23SRuslan Bukin DEVMETHOD(bus_write_ivar, dwmmc_write_ivar), 155441709d23SRuslan Bukin 1555f1cc48e5SEmmanuel Vadot #ifndef MMCCAM 155641709d23SRuslan Bukin /* mmcbr_if */ 155741709d23SRuslan Bukin DEVMETHOD(mmcbr_update_ios, dwmmc_update_ios), 155841709d23SRuslan Bukin DEVMETHOD(mmcbr_request, dwmmc_request), 155941709d23SRuslan Bukin DEVMETHOD(mmcbr_get_ro, dwmmc_get_ro), 156041709d23SRuslan Bukin DEVMETHOD(mmcbr_acquire_host, dwmmc_acquire_host), 156141709d23SRuslan Bukin DEVMETHOD(mmcbr_release_host, dwmmc_release_host), 1562f1cc48e5SEmmanuel Vadot #endif 1563f1cc48e5SEmmanuel Vadot 1564f1cc48e5SEmmanuel Vadot #ifdef MMCCAM 1565f1cc48e5SEmmanuel Vadot /* MMCCAM interface */ 1566f1cc48e5SEmmanuel Vadot DEVMETHOD(mmc_sim_get_tran_settings, dwmmc_get_tran_settings), 1567f1cc48e5SEmmanuel Vadot DEVMETHOD(mmc_sim_set_tran_settings, dwmmc_set_tran_settings), 1568f1cc48e5SEmmanuel Vadot DEVMETHOD(mmc_sim_cam_request, dwmmc_cam_request), 156944682688SAndriy Gapon DEVMETHOD(mmc_sim_cam_poll, dwmmc_cam_poll), 1570c99d887cSEmmanuel Vadot 1571c99d887cSEmmanuel Vadot DEVMETHOD(bus_add_child, bus_generic_add_child), 1572f1cc48e5SEmmanuel Vadot #endif 157341709d23SRuslan Bukin 157441709d23SRuslan Bukin DEVMETHOD_END 157541709d23SRuslan Bukin }; 157641709d23SRuslan Bukin 157774e0613eSEmmanuel Vadot DEFINE_CLASS_0(dwmmc, dwmmc_driver, dwmmc_methods, 157874e0613eSEmmanuel Vadot sizeof(struct dwmmc_softc)); 1579