1239278Sgonzo/*- 2239278Sgonzo * Copyright (c) 2011 Jakub Wojciech Klama <jceel@FreeBSD.org> 3239278Sgonzo * All rights reserved. 4239278Sgonzo * 5239278Sgonzo * Redistribution and use in source and binary forms, with or without 6239278Sgonzo * modification, are permitted provided that the following conditions 7239278Sgonzo * are met: 8239278Sgonzo * 1. Redistributions of source code must retain the above copyright 9239278Sgonzo * notice, this list of conditions and the following disclaimer. 10239278Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 11239278Sgonzo * notice, this list of conditions and the following disclaimer in the 12239278Sgonzo * documentation and/or other materials provided with the distribution. 13239278Sgonzo * 14239278Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15239278Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16239278Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17239278Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18239278Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19239278Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20239278Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21239278Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22239278Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23239278Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24239278Sgonzo * SUCH DAMAGE. 25239278Sgonzo * 26239278Sgonzo */ 27239278Sgonzo#include <sys/cdefs.h> 28239278Sgonzo__FBSDID("$FreeBSD: stable/11/sys/arm/lpc/lpc_mmc.c 318197 2017-05-11 20:55:11Z marius $"); 29239278Sgonzo 30239278Sgonzo#include <sys/param.h> 31239278Sgonzo#include <sys/systm.h> 32239278Sgonzo#include <sys/bus.h> 33239278Sgonzo#include <sys/kernel.h> 34239278Sgonzo#include <sys/lock.h> 35239278Sgonzo#include <sys/malloc.h> 36239278Sgonzo#include <sys/module.h> 37239278Sgonzo#include <sys/mutex.h> 38239278Sgonzo#include <sys/resource.h> 39239278Sgonzo#include <sys/rman.h> 40239278Sgonzo 41239278Sgonzo#include <machine/bus.h> 42239278Sgonzo#include <machine/resource.h> 43239278Sgonzo#include <machine/intr.h> 44239278Sgonzo 45239278Sgonzo#include <dev/ofw/ofw_bus.h> 46239278Sgonzo#include <dev/ofw/ofw_bus_subr.h> 47239278Sgonzo 48239278Sgonzo#include <dev/mmc/bridge.h> 49239278Sgonzo#include <dev/mmc/mmcbrvar.h> 50239278Sgonzo 51239278Sgonzo#include <arm/lpc/lpcreg.h> 52239278Sgonzo#include <arm/lpc/lpcvar.h> 53239278Sgonzo 54239278Sgonzo#ifdef DEBUG 55239278Sgonzo#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 56239278Sgonzo printf(fmt,##args); } while (0) 57239278Sgonzo#else 58239278Sgonzo#define debugf(fmt, args...) 59239278Sgonzo#endif 60239278Sgonzo 61239278Sgonzostruct lpc_mmc_dmamap_arg { 62239278Sgonzo bus_addr_t lm_dma_busaddr; 63239278Sgonzo}; 64239278Sgonzo 65239278Sgonzostruct lpc_mmc_softc { 66239278Sgonzo device_t lm_dev; 67239278Sgonzo struct mtx lm_mtx; 68239278Sgonzo struct resource * lm_mem_res; 69239278Sgonzo struct resource * lm_irq_res; 70239278Sgonzo bus_space_tag_t lm_bst; 71239278Sgonzo bus_space_handle_t lm_bsh; 72239278Sgonzo void * lm_intrhand; 73239278Sgonzo struct mmc_host lm_host; 74239278Sgonzo struct mmc_request * lm_req; 75239278Sgonzo struct mmc_data * lm_data; 76239278Sgonzo uint32_t lm_flags; 77239278Sgonzo#define LPC_SD_FLAGS_IGNORECRC (1 << 0) 78239278Sgonzo int lm_xfer_direction; 79239278Sgonzo#define DIRECTION_READ 0 80239278Sgonzo#define DIRECTION_WRITE 1 81239278Sgonzo int lm_xfer_done; 82239278Sgonzo int lm_bus_busy; 83239278Sgonzo bus_dma_tag_t lm_dma_tag; 84239278Sgonzo bus_dmamap_t lm_dma_map; 85239278Sgonzo bus_addr_t lm_buffer_phys; 86239278Sgonzo void * lm_buffer; 87239278Sgonzo}; 88239278Sgonzo 89239278Sgonzo#define LPC_SD_MAX_BLOCKSIZE 1024 90239278Sgonzo/* XXX */ 91239278Sgonzo#define LPC_MMC_DMACH_READ 1 92239278Sgonzo#define LPC_MMC_DMACH_WRITE 0 93239278Sgonzo 94239278Sgonzo 95239278Sgonzostatic int lpc_mmc_probe(device_t); 96239278Sgonzostatic int lpc_mmc_attach(device_t); 97239278Sgonzostatic int lpc_mmc_detach(device_t); 98239278Sgonzostatic void lpc_mmc_intr(void *); 99239278Sgonzo 100239278Sgonzostatic void lpc_mmc_cmd(struct lpc_mmc_softc *, struct mmc_command *); 101239278Sgonzostatic void lpc_mmc_setup_xfer(struct lpc_mmc_softc *, struct mmc_data *); 102239278Sgonzo 103239278Sgonzostatic int lpc_mmc_update_ios(device_t, device_t); 104239278Sgonzostatic int lpc_mmc_request(device_t, device_t, struct mmc_request *); 105239278Sgonzostatic int lpc_mmc_get_ro(device_t, device_t); 106239278Sgonzostatic int lpc_mmc_acquire_host(device_t, device_t); 107239278Sgonzostatic int lpc_mmc_release_host(device_t, device_t); 108239278Sgonzo 109239278Sgonzostatic void lpc_mmc_dma_rxfinish(void *); 110239278Sgonzostatic void lpc_mmc_dma_rxerror(void *); 111239278Sgonzostatic void lpc_mmc_dma_txfinish(void *); 112239278Sgonzostatic void lpc_mmc_dma_txerror(void *); 113239278Sgonzo 114239278Sgonzostatic void lpc_mmc_dmamap_cb(void *, bus_dma_segment_t *, int, int); 115239278Sgonzo 116239278Sgonzo#define lpc_mmc_lock(_sc) \ 117239278Sgonzo mtx_lock(&_sc->lm_mtx); 118239278Sgonzo#define lpc_mmc_unlock(_sc) \ 119239278Sgonzo mtx_unlock(&_sc->lm_mtx); 120239278Sgonzo#define lpc_mmc_read_4(_sc, _reg) \ 121239278Sgonzo bus_space_read_4(_sc->lm_bst, _sc->lm_bsh, _reg) 122239278Sgonzo#define lpc_mmc_write_4(_sc, _reg, _value) \ 123239278Sgonzo bus_space_write_4(_sc->lm_bst, _sc->lm_bsh, _reg, _value) 124239278Sgonzo 125239278Sgonzostatic struct lpc_dmac_channel_config lpc_mmc_dma_rxconf = { 126239278Sgonzo .ldc_fcntl = LPC_DMAC_FLOW_D_P2M, 127239278Sgonzo .ldc_src_periph = LPC_DMAC_SD_ID, 128239278Sgonzo .ldc_src_width = LPC_DMAC_CH_CONTROL_WIDTH_4, 129239278Sgonzo .ldc_src_incr = 0, 130239278Sgonzo .ldc_src_burst = LPC_DMAC_CH_CONTROL_BURST_8, 131239278Sgonzo .ldc_dst_periph = LPC_DMAC_SD_ID, 132239278Sgonzo .ldc_dst_width = LPC_DMAC_CH_CONTROL_WIDTH_4, 133239278Sgonzo .ldc_dst_incr = 1, 134239278Sgonzo .ldc_dst_burst = LPC_DMAC_CH_CONTROL_BURST_8, 135239278Sgonzo .ldc_success_handler = lpc_mmc_dma_rxfinish, 136239278Sgonzo .ldc_error_handler = lpc_mmc_dma_rxerror, 137239278Sgonzo}; 138239278Sgonzo 139239278Sgonzostatic struct lpc_dmac_channel_config lpc_mmc_dma_txconf = { 140239278Sgonzo .ldc_fcntl = LPC_DMAC_FLOW_P_M2P, 141239278Sgonzo .ldc_src_periph = LPC_DMAC_SD_ID, 142239278Sgonzo .ldc_src_width = LPC_DMAC_CH_CONTROL_WIDTH_4, 143239278Sgonzo .ldc_src_incr = 1, 144239278Sgonzo .ldc_src_burst = LPC_DMAC_CH_CONTROL_BURST_8, 145239278Sgonzo .ldc_dst_periph = LPC_DMAC_SD_ID, 146239278Sgonzo .ldc_dst_width = LPC_DMAC_CH_CONTROL_WIDTH_4, 147239278Sgonzo .ldc_dst_incr = 0, 148239278Sgonzo .ldc_dst_burst = LPC_DMAC_CH_CONTROL_BURST_8, 149239278Sgonzo .ldc_success_handler = lpc_mmc_dma_txfinish, 150239278Sgonzo .ldc_error_handler = lpc_mmc_dma_txerror, 151239278Sgonzo}; 152239278Sgonzo 153239278Sgonzostatic int 154239278Sgonzolpc_mmc_probe(device_t dev) 155239278Sgonzo{ 156261410Sian 157261410Sian if (!ofw_bus_status_okay(dev)) 158261410Sian return (ENXIO); 159261410Sian 160239278Sgonzo if (!ofw_bus_is_compatible(dev, "lpc,mmc")) 161239278Sgonzo return (ENXIO); 162239278Sgonzo 163239278Sgonzo device_set_desc(dev, "LPC32x0 MMC/SD controller"); 164239278Sgonzo return (BUS_PROBE_DEFAULT); 165239278Sgonzo} 166239278Sgonzo 167239278Sgonzostatic int 168239278Sgonzolpc_mmc_attach(device_t dev) 169239278Sgonzo{ 170239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(dev); 171239278Sgonzo struct lpc_mmc_dmamap_arg ctx; 172239278Sgonzo device_t child; 173239278Sgonzo int rid, err; 174239278Sgonzo 175239278Sgonzo sc->lm_dev = dev; 176239278Sgonzo sc->lm_req = NULL; 177239278Sgonzo 178239278Sgonzo mtx_init(&sc->lm_mtx, "lpcmmc", "mmc", MTX_DEF); 179239278Sgonzo 180239278Sgonzo rid = 0; 181239278Sgonzo sc->lm_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 182239278Sgonzo RF_ACTIVE); 183239278Sgonzo if (!sc->lm_mem_res) { 184239278Sgonzo device_printf(dev, "cannot allocate memory window\n"); 185239278Sgonzo return (ENXIO); 186239278Sgonzo } 187239278Sgonzo 188239278Sgonzo sc->lm_bst = rman_get_bustag(sc->lm_mem_res); 189239278Sgonzo sc->lm_bsh = rman_get_bushandle(sc->lm_mem_res); 190239278Sgonzo 191239278Sgonzo debugf("virtual register space: 0x%08lx\n", sc->lm_bsh); 192239278Sgonzo 193239278Sgonzo rid = 0; 194239278Sgonzo sc->lm_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 195239278Sgonzo RF_ACTIVE); 196239278Sgonzo if (!sc->lm_irq_res) { 197239278Sgonzo device_printf(dev, "cannot allocate interrupt\n"); 198239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res); 199239278Sgonzo return (ENXIO); 200239278Sgonzo } 201239278Sgonzo 202239278Sgonzo if (bus_setup_intr(dev, sc->lm_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 203239278Sgonzo NULL, lpc_mmc_intr, sc, &sc->lm_intrhand)) 204239278Sgonzo { 205239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res); 206239278Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res); 207239278Sgonzo device_printf(dev, "cannot setup interrupt handler\n"); 208239278Sgonzo return (ENXIO); 209239278Sgonzo } 210239278Sgonzo 211239278Sgonzo sc->lm_host.f_min = 312500; 212239278Sgonzo sc->lm_host.f_max = 2500000; 213239278Sgonzo sc->lm_host.host_ocr = MMC_OCR_300_310 | MMC_OCR_310_320 | 214239278Sgonzo MMC_OCR_320_330 | MMC_OCR_330_340; 215239278Sgonzo#if 0 216239278Sgonzo sc->lm_host.caps = MMC_CAP_4_BIT_DATA; 217239278Sgonzo#endif 218239278Sgonzo 219239278Sgonzo lpc_pwr_write(dev, LPC_CLKPWR_MS_CTRL, 220239278Sgonzo LPC_CLKPWR_MS_CTRL_CLOCK_EN | LPC_CLKPWR_MS_CTRL_SD_CLOCK | 1); 221239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_POWER, LPC_SD_POWER_CTRL_ON); 222239278Sgonzo 223239278Sgonzo device_set_ivars(dev, &sc->lm_host); 224239278Sgonzo 225239278Sgonzo child = device_add_child(dev, "mmc", -1); 226239278Sgonzo if (!child) { 227239278Sgonzo device_printf(dev, "attaching MMC bus failed!\n"); 228239278Sgonzo bus_teardown_intr(dev, sc->lm_irq_res, sc->lm_intrhand); 229239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res); 230239278Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res); 231239278Sgonzo return (ENXIO); 232239278Sgonzo } 233239278Sgonzo 234239278Sgonzo /* Alloc DMA memory */ 235239278Sgonzo err = bus_dma_tag_create( 236239278Sgonzo bus_get_dma_tag(sc->lm_dev), 237239278Sgonzo 4, 0, /* alignment, boundary */ 238239278Sgonzo BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ 239239278Sgonzo BUS_SPACE_MAXADDR, /* highaddr */ 240239278Sgonzo NULL, NULL, /* filter, filterarg */ 241239278Sgonzo LPC_SD_MAX_BLOCKSIZE, 1, /* maxsize, nsegments */ 242239278Sgonzo LPC_SD_MAX_BLOCKSIZE, 0, /* maxsegsize, flags */ 243239278Sgonzo NULL, NULL, /* lockfunc, lockarg */ 244239278Sgonzo &sc->lm_dma_tag); 245239278Sgonzo 246239278Sgonzo err = bus_dmamem_alloc(sc->lm_dma_tag, (void **)&sc->lm_buffer, 247239278Sgonzo 0, &sc->lm_dma_map); 248239278Sgonzo if (err) { 249239278Sgonzo device_printf(dev, "cannot allocate framebuffer\n"); 250239278Sgonzo goto fail; 251239278Sgonzo } 252239278Sgonzo 253239278Sgonzo err = bus_dmamap_load(sc->lm_dma_tag, sc->lm_dma_map, sc->lm_buffer, 254239278Sgonzo LPC_SD_MAX_BLOCKSIZE, lpc_mmc_dmamap_cb, &ctx, BUS_DMA_NOWAIT); 255239278Sgonzo if (err) { 256239278Sgonzo device_printf(dev, "cannot load DMA map\n"); 257239278Sgonzo goto fail; 258239278Sgonzo } 259239278Sgonzo 260239278Sgonzo sc->lm_buffer_phys = ctx.lm_dma_busaddr; 261239278Sgonzo 262239278Sgonzo lpc_mmc_dma_rxconf.ldc_handler_arg = (void *)sc; 263239278Sgonzo err = lpc_dmac_config_channel(dev, LPC_MMC_DMACH_READ, &lpc_mmc_dma_rxconf); 264239278Sgonzo if (err) { 265239278Sgonzo device_printf(dev, "cannot allocate RX DMA channel\n"); 266239278Sgonzo goto fail; 267239278Sgonzo } 268239278Sgonzo 269239278Sgonzo 270239278Sgonzo lpc_mmc_dma_txconf.ldc_handler_arg = (void *)sc; 271239278Sgonzo err = lpc_dmac_config_channel(dev, LPC_MMC_DMACH_WRITE, &lpc_mmc_dma_txconf); 272239278Sgonzo if (err) { 273239278Sgonzo device_printf(dev, "cannot allocate TX DMA channel\n"); 274239278Sgonzo goto fail; 275239278Sgonzo } 276239278Sgonzo 277239278Sgonzo bus_generic_probe(dev); 278239278Sgonzo bus_generic_attach(dev); 279239278Sgonzo 280239278Sgonzo return (0); 281239278Sgonzo 282239278Sgonzofail: 283239278Sgonzo if (sc->lm_intrhand) 284239278Sgonzo bus_teardown_intr(dev, sc->lm_irq_res, sc->lm_intrhand); 285239278Sgonzo if (sc->lm_irq_res) 286239278Sgonzo bus_release_resource(dev, SYS_RES_IRQ, 0, sc->lm_irq_res); 287239278Sgonzo if (sc->lm_mem_res) 288239278Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->lm_mem_res); 289239278Sgonzo return (err); 290239278Sgonzo} 291239278Sgonzo 292239278Sgonzostatic int 293239278Sgonzolpc_mmc_detach(device_t dev) 294239278Sgonzo{ 295239278Sgonzo return (EBUSY); 296239278Sgonzo} 297239278Sgonzo 298239278Sgonzostatic void 299239278Sgonzolpc_mmc_intr(void *arg) 300239278Sgonzo{ 301239278Sgonzo struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg; 302239278Sgonzo struct mmc_command *cmd; 303239278Sgonzo uint32_t status; 304239278Sgonzo 305239278Sgonzo status = lpc_mmc_read_4(sc, LPC_SD_STATUS); 306239278Sgonzo 307239278Sgonzo debugf("interrupt: 0x%08x\n", status); 308239278Sgonzo 309239278Sgonzo if (status & LPC_SD_STATUS_CMDCRCFAIL) { 310239278Sgonzo cmd = sc->lm_req->cmd; 311239278Sgonzo cmd->error = sc->lm_flags & LPC_SD_FLAGS_IGNORECRC 312239278Sgonzo ? MMC_ERR_NONE : MMC_ERR_BADCRC; 313239278Sgonzo cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0); 314239278Sgonzo sc->lm_req->done(sc->lm_req); 315239278Sgonzo sc->lm_req = NULL; 316239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDCRCFAIL); 317239278Sgonzo } 318239278Sgonzo 319239278Sgonzo if (status & LPC_SD_STATUS_CMDACTIVE) 320239278Sgonzo { 321239278Sgonzo debugf("command active\n"); 322239278Sgonzo cmd = sc->lm_req->cmd; 323239278Sgonzo cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0); 324239278Sgonzo sc->lm_req->done(sc->lm_req); 325239278Sgonzo sc->lm_req = NULL; 326239278Sgonzo } 327239278Sgonzo 328239278Sgonzo if (status & LPC_SD_STATUS_DATATIMEOUT) { 329239278Sgonzo device_printf(sc->lm_dev, "data timeout\n"); 330239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATATIMEOUT); 331239278Sgonzo } 332239278Sgonzo 333239278Sgonzo if (status & LPC_SD_STATUS_TXUNDERRUN) { 334239278Sgonzo device_printf(sc->lm_dev, "TX underrun\n"); 335239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_TXUNDERRUN); 336239278Sgonzo } 337239278Sgonzo 338239278Sgonzo if (status & LPC_SD_STATUS_CMDRESPEND) { 339239278Sgonzo debugf("command response\n"); 340239278Sgonzo cmd = sc->lm_req->cmd; 341239278Sgonzo 342239278Sgonzo if (cmd->flags & MMC_RSP_136) { 343239278Sgonzo cmd->resp[3] = lpc_mmc_read_4(sc, LPC_SD_RESP3); 344239278Sgonzo cmd->resp[2] = lpc_mmc_read_4(sc, LPC_SD_RESP2); 345239278Sgonzo cmd->resp[1] = lpc_mmc_read_4(sc, LPC_SD_RESP1); 346239278Sgonzo } 347239278Sgonzo 348239278Sgonzo cmd->resp[0] = lpc_mmc_read_4(sc, LPC_SD_RESP0); 349239278Sgonzo cmd->error = MMC_ERR_NONE; 350239278Sgonzo 351239278Sgonzo if (cmd->data && (cmd->data->flags & MMC_DATA_WRITE)) 352239278Sgonzo lpc_mmc_setup_xfer(sc, sc->lm_req->cmd->data); 353239278Sgonzo 354239278Sgonzo if (!cmd->data) { 355239278Sgonzo sc->lm_req->done(sc->lm_req); 356239278Sgonzo sc->lm_req = NULL; 357239278Sgonzo } 358239278Sgonzo 359239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDRESPEND); 360239278Sgonzo } 361239278Sgonzo 362239278Sgonzo if (status & LPC_SD_STATUS_CMDSENT) { 363239278Sgonzo debugf("command sent\n"); 364239278Sgonzo cmd = sc->lm_req->cmd; 365239278Sgonzo cmd->error = MMC_ERR_NONE; 366239278Sgonzo sc->lm_req->done(sc->lm_req); 367239278Sgonzo sc->lm_req = NULL; 368239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDSENT); 369239278Sgonzo } 370239278Sgonzo 371239278Sgonzo if (status & LPC_SD_STATUS_DATAEND) { 372239278Sgonzo if (sc->lm_xfer_direction == DIRECTION_READ) 373239278Sgonzo lpc_dmac_start_burst(sc->lm_dev, LPC_DMAC_SD_ID); 374239278Sgonzo 375239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATAEND); 376239278Sgonzo } 377239278Sgonzo 378239278Sgonzo if (status & LPC_SD_STATUS_CMDTIMEOUT) { 379239278Sgonzo device_printf(sc->lm_dev, "command response timeout\n"); 380239278Sgonzo cmd = sc->lm_req->cmd; 381239278Sgonzo cmd->error = MMC_ERR_TIMEOUT; 382239278Sgonzo sc->lm_req->done(sc->lm_req); 383239278Sgonzo sc->lm_req = NULL; 384239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_CMDTIMEOUT); 385239278Sgonzo return; 386239278Sgonzo } 387239278Sgonzo 388239278Sgonzo if (status & LPC_SD_STATUS_STARTBITERR) { 389239278Sgonzo device_printf(sc->lm_dev, "start bit error\n"); 390239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_STARTBITERR); 391239278Sgonzo } 392239278Sgonzo 393239278Sgonzo if (status & LPC_SD_STATUS_DATACRCFAIL) { 394239278Sgonzo device_printf(sc->lm_dev, "data CRC error\n"); 395239278Sgonzo debugf("data buffer: %p\n", sc->lm_buffer); 396239278Sgonzo cmd = sc->lm_req->cmd; 397239278Sgonzo cmd->error = MMC_ERR_BADCRC; 398239278Sgonzo sc->lm_req->done(sc->lm_req); 399239278Sgonzo sc->lm_req = NULL; 400239278Sgonzo 401239278Sgonzo if (sc->lm_xfer_direction == DIRECTION_READ) 402239278Sgonzo lpc_dmac_start_burst(sc->lm_dev, LPC_DMAC_SD_ID); 403239278Sgonzo 404239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATACRCFAIL); 405239278Sgonzo } 406239278Sgonzo 407239278Sgonzo if (status & LPC_SD_STATUS_DATABLOCKEND) { 408239278Sgonzo debugf("data block end\n"); 409239278Sgonzo if (sc->lm_xfer_direction == DIRECTION_READ) 410239278Sgonzo memcpy(sc->lm_data->data, sc->lm_buffer, sc->lm_data->len); 411239278Sgonzo 412239278Sgonzo if (sc->lm_xfer_direction == DIRECTION_WRITE) { 413239278Sgonzo lpc_dmac_disable_channel(sc->lm_dev, LPC_MMC_DMACH_WRITE); 414239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_DATACTRL, 0); 415239278Sgonzo } 416239278Sgonzo 417239278Sgonzo sc->lm_req->done(sc->lm_req); 418239278Sgonzo sc->lm_req = NULL; 419239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLEAR, LPC_SD_STATUS_DATABLOCKEND); 420239278Sgonzo } 421239278Sgonzo 422239278Sgonzo debugf("done\n"); 423239278Sgonzo} 424239278Sgonzo 425239278Sgonzostatic int 426239278Sgonzolpc_mmc_request(device_t bus, device_t child, struct mmc_request *req) 427239278Sgonzo{ 428239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(bus); 429239278Sgonzo 430239278Sgonzo debugf("request: %p\n", req); 431239278Sgonzo 432239278Sgonzo lpc_mmc_lock(sc); 433239278Sgonzo if (sc->lm_req) 434239278Sgonzo return (EBUSY); 435239278Sgonzo 436239278Sgonzo sc->lm_req = req; 437239278Sgonzo 438239278Sgonzo if (req->cmd->data && req->cmd->data->flags & MMC_DATA_WRITE) { 439239278Sgonzo memcpy(sc->lm_buffer, req->cmd->data->data, req->cmd->data->len); 440239278Sgonzo lpc_mmc_cmd(sc, req->cmd); 441239278Sgonzo lpc_mmc_unlock(sc); 442239278Sgonzo return (0); 443239278Sgonzo } 444239278Sgonzo 445239278Sgonzo if (req->cmd->data) 446239278Sgonzo lpc_mmc_setup_xfer(sc, req->cmd->data); 447239278Sgonzo 448239278Sgonzo lpc_mmc_cmd(sc, req->cmd); 449239278Sgonzo lpc_mmc_unlock(sc); 450239278Sgonzo 451239278Sgonzo return (0); 452239278Sgonzo} 453239278Sgonzo 454239278Sgonzostatic void 455239278Sgonzolpc_mmc_cmd(struct lpc_mmc_softc *sc, struct mmc_command *cmd) 456239278Sgonzo{ 457239278Sgonzo uint32_t cmdreg = 0; 458239278Sgonzo 459239278Sgonzo debugf("cmd: %d arg: 0x%08x\n", cmd->opcode, cmd->arg); 460239278Sgonzo 461239278Sgonzo if (lpc_mmc_read_4(sc, LPC_SD_COMMAND) & LPC_SD_COMMAND_ENABLE) { 462239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_COMMAND, 0); 463239278Sgonzo DELAY(1000); 464239278Sgonzo } 465239278Sgonzo 466239278Sgonzo sc->lm_flags &= ~LPC_SD_FLAGS_IGNORECRC; 467239278Sgonzo 468239278Sgonzo if (cmd->flags & MMC_RSP_PRESENT) 469239278Sgonzo cmdreg |= LPC_SD_COMMAND_RESPONSE; 470239278Sgonzo 471239278Sgonzo if (MMC_RSP(cmd->flags) == MMC_RSP_R2) 472239278Sgonzo cmdreg |= LPC_SD_COMMAND_LONGRSP; 473239278Sgonzo 474239278Sgonzo if (MMC_RSP(cmd->flags) == MMC_RSP_R3) 475239278Sgonzo sc->lm_flags |= LPC_SD_FLAGS_IGNORECRC; 476239278Sgonzo 477239278Sgonzo cmdreg |= LPC_SD_COMMAND_ENABLE; 478239278Sgonzo cmdreg |= (cmd->opcode & LPC_SD_COMMAND_CMDINDEXMASK); 479239278Sgonzo 480239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_MASK0, 0xffffffff); 481239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_MASK1, 0xffffffff); 482239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_ARGUMENT, cmd->arg); 483239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_COMMAND, cmdreg); 484239278Sgonzo} 485239278Sgonzo 486239278Sgonzostatic void 487239278Sgonzolpc_mmc_setup_xfer(struct lpc_mmc_softc *sc, struct mmc_data *data) 488239278Sgonzo{ 489239278Sgonzo uint32_t datactrl = 0; 490239278Sgonzo int data_words = data->len / 4; 491239278Sgonzo 492239278Sgonzo sc->lm_data = data; 493239278Sgonzo sc->lm_xfer_done = 0; 494239278Sgonzo 495239278Sgonzo debugf("data: %p, len: %d, %s\n", data, 496239278Sgonzo data->len, (data->flags & MMC_DATA_READ) ? "read" : "write"); 497239278Sgonzo 498239278Sgonzo if (data->flags & MMC_DATA_READ) { 499239278Sgonzo sc->lm_xfer_direction = DIRECTION_READ; 500239278Sgonzo lpc_dmac_setup_transfer(sc->lm_dev, LPC_MMC_DMACH_READ, 501260326Sian LPC_SD_PHYS_BASE + LPC_SD_FIFO, sc->lm_buffer_phys, 502239278Sgonzo data_words, 0); 503239278Sgonzo } 504239278Sgonzo 505239278Sgonzo if (data->flags & MMC_DATA_WRITE) { 506239278Sgonzo sc->lm_xfer_direction = DIRECTION_WRITE; 507239278Sgonzo lpc_dmac_setup_transfer(sc->lm_dev, LPC_MMC_DMACH_WRITE, 508260326Sian sc->lm_buffer_phys, LPC_SD_PHYS_BASE + LPC_SD_FIFO, 509239278Sgonzo data_words, 0); 510239278Sgonzo } 511239278Sgonzo 512239278Sgonzo datactrl |= (sc->lm_xfer_direction 513239278Sgonzo ? LPC_SD_DATACTRL_WRITE 514239278Sgonzo : LPC_SD_DATACTRL_READ); 515239278Sgonzo 516239278Sgonzo datactrl |= LPC_SD_DATACTRL_DMAENABLE | LPC_SD_DATACTRL_ENABLE; 517239278Sgonzo datactrl |= (ffs(data->len) - 1) << 4; 518239278Sgonzo 519239278Sgonzo debugf("datactrl: 0x%08x\n", datactrl); 520239278Sgonzo 521239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_DATATIMER, 0xFFFF0000); 522239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_DATALENGTH, data->len); 523239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_DATACTRL, datactrl); 524239278Sgonzo} 525239278Sgonzo 526239278Sgonzostatic int 527239278Sgonzolpc_mmc_read_ivar(device_t bus, device_t child, int which, 528239278Sgonzo uintptr_t *result) 529239278Sgonzo{ 530239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(bus); 531239278Sgonzo 532239278Sgonzo switch (which) { 533239278Sgonzo default: 534239278Sgonzo return (EINVAL); 535239278Sgonzo case MMCBR_IVAR_BUS_MODE: 536239278Sgonzo *(int *)result = sc->lm_host.ios.bus_mode; 537239278Sgonzo break; 538239278Sgonzo case MMCBR_IVAR_BUS_WIDTH: 539239278Sgonzo *(int *)result = sc->lm_host.ios.bus_width; 540239278Sgonzo break; 541239278Sgonzo case MMCBR_IVAR_CHIP_SELECT: 542239278Sgonzo *(int *)result = sc->lm_host.ios.chip_select; 543239278Sgonzo break; 544239278Sgonzo case MMCBR_IVAR_CLOCK: 545239278Sgonzo *(int *)result = sc->lm_host.ios.clock; 546239278Sgonzo break; 547239278Sgonzo case MMCBR_IVAR_F_MIN: 548239278Sgonzo *(int *)result = sc->lm_host.f_min; 549239278Sgonzo break; 550239278Sgonzo case MMCBR_IVAR_F_MAX: 551239278Sgonzo *(int *)result = sc->lm_host.f_max; 552239278Sgonzo break; 553239278Sgonzo case MMCBR_IVAR_HOST_OCR: 554239278Sgonzo *(int *)result = sc->lm_host.host_ocr; 555239278Sgonzo break; 556239278Sgonzo case MMCBR_IVAR_MODE: 557239278Sgonzo *(int *)result = sc->lm_host.mode; 558239278Sgonzo break; 559239278Sgonzo case MMCBR_IVAR_OCR: 560239278Sgonzo *(int *)result = sc->lm_host.ocr; 561239278Sgonzo break; 562239278Sgonzo case MMCBR_IVAR_POWER_MODE: 563239278Sgonzo *(int *)result = sc->lm_host.ios.power_mode; 564239278Sgonzo break; 565239278Sgonzo case MMCBR_IVAR_VDD: 566239278Sgonzo *(int *)result = sc->lm_host.ios.vdd; 567239278Sgonzo break; 568239278Sgonzo case MMCBR_IVAR_CAPS: 569239278Sgonzo *(int *)result = sc->lm_host.caps; 570239278Sgonzo break; 571239278Sgonzo case MMCBR_IVAR_MAX_DATA: 572239278Sgonzo *(int *)result = 1; 573239278Sgonzo break; 574239278Sgonzo } 575239278Sgonzo 576239278Sgonzo return (0); 577239278Sgonzo} 578239278Sgonzo 579239278Sgonzostatic int 580239278Sgonzolpc_mmc_write_ivar(device_t bus, device_t child, int which, 581239278Sgonzo uintptr_t value) 582239278Sgonzo{ 583239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(bus); 584239278Sgonzo 585239278Sgonzo switch (which) { 586239278Sgonzo default: 587239278Sgonzo return (EINVAL); 588239278Sgonzo case MMCBR_IVAR_BUS_MODE: 589239278Sgonzo sc->lm_host.ios.bus_mode = value; 590239278Sgonzo break; 591239278Sgonzo case MMCBR_IVAR_BUS_WIDTH: 592239278Sgonzo sc->lm_host.ios.bus_width = value; 593239278Sgonzo break; 594239278Sgonzo case MMCBR_IVAR_CHIP_SELECT: 595239278Sgonzo sc->lm_host.ios.chip_select = value; 596239278Sgonzo break; 597239278Sgonzo case MMCBR_IVAR_CLOCK: 598239278Sgonzo sc->lm_host.ios.clock = value; 599239278Sgonzo break; 600239278Sgonzo case MMCBR_IVAR_MODE: 601239278Sgonzo sc->lm_host.mode = value; 602239278Sgonzo break; 603239278Sgonzo case MMCBR_IVAR_OCR: 604239278Sgonzo sc->lm_host.ocr = value; 605239278Sgonzo break; 606239278Sgonzo case MMCBR_IVAR_POWER_MODE: 607239278Sgonzo sc->lm_host.ios.power_mode = value; 608239278Sgonzo break; 609239278Sgonzo case MMCBR_IVAR_VDD: 610239278Sgonzo sc->lm_host.ios.vdd = value; 611239278Sgonzo break; 612239278Sgonzo /* These are read-only */ 613239278Sgonzo case MMCBR_IVAR_CAPS: 614239278Sgonzo case MMCBR_IVAR_HOST_OCR: 615239278Sgonzo case MMCBR_IVAR_F_MIN: 616239278Sgonzo case MMCBR_IVAR_F_MAX: 617239278Sgonzo case MMCBR_IVAR_MAX_DATA: 618239278Sgonzo return (EINVAL); 619239278Sgonzo } 620239278Sgonzo return (0); 621239278Sgonzo} 622239278Sgonzo 623239278Sgonzostatic int 624239278Sgonzolpc_mmc_update_ios(device_t bus, device_t child) 625239278Sgonzo{ 626239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(bus); 627239278Sgonzo struct mmc_ios *ios = &sc->lm_host.ios; 628239278Sgonzo uint32_t clkdiv = 0, pwr = 0; 629239278Sgonzo 630239278Sgonzo if (ios->bus_width == bus_width_4) 631239278Sgonzo clkdiv |= LPC_SD_CLOCK_WIDEBUS; 632239278Sgonzo 633239278Sgonzo /* Calculate clock divider */ 634239278Sgonzo clkdiv = (LPC_SD_CLK / (2 * ios->clock)) - 1; 635239278Sgonzo 636239278Sgonzo /* Clock rate should not exceed rate requested in ios */ 637239278Sgonzo if ((LPC_SD_CLK / (2 * (clkdiv + 1))) > ios->clock) 638239278Sgonzo clkdiv++; 639239278Sgonzo 640239278Sgonzo debugf("clock: %dHz, clkdiv: %d\n", ios->clock, clkdiv); 641239278Sgonzo 642239278Sgonzo if (ios->bus_width == bus_width_4) { 643239278Sgonzo debugf("using wide bus mode\n"); 644239278Sgonzo clkdiv |= LPC_SD_CLOCK_WIDEBUS; 645239278Sgonzo } 646239278Sgonzo 647239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_CLOCK, clkdiv | LPC_SD_CLOCK_ENABLE); 648239278Sgonzo 649239278Sgonzo switch (ios->power_mode) { 650239278Sgonzo case power_off: 651239278Sgonzo pwr |= LPC_SD_POWER_CTRL_OFF; 652239278Sgonzo break; 653239278Sgonzo case power_up: 654239278Sgonzo pwr |= LPC_SD_POWER_CTRL_UP; 655239278Sgonzo break; 656239278Sgonzo case power_on: 657239278Sgonzo pwr |= LPC_SD_POWER_CTRL_ON; 658239278Sgonzo break; 659239278Sgonzo } 660239278Sgonzo 661239278Sgonzo if (ios->bus_mode == opendrain) 662239278Sgonzo pwr |= LPC_SD_POWER_OPENDRAIN; 663239278Sgonzo 664239278Sgonzo lpc_mmc_write_4(sc, LPC_SD_POWER, pwr); 665239278Sgonzo 666239278Sgonzo return (0); 667239278Sgonzo} 668239278Sgonzo 669239278Sgonzostatic int 670239278Sgonzolpc_mmc_get_ro(device_t bus, device_t child) 671239278Sgonzo{ 672239278Sgonzo 673239278Sgonzo return (0); 674239278Sgonzo} 675239278Sgonzo 676239278Sgonzostatic int 677239278Sgonzolpc_mmc_acquire_host(device_t bus, device_t child) 678239278Sgonzo{ 679239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(bus); 680239278Sgonzo int error = 0; 681239278Sgonzo 682239278Sgonzo lpc_mmc_lock(sc); 683239278Sgonzo while (sc->lm_bus_busy) 684239278Sgonzo error = mtx_sleep(sc, &sc->lm_mtx, PZERO, "mmcah", 0); 685239278Sgonzo 686239278Sgonzo sc->lm_bus_busy++; 687239278Sgonzo lpc_mmc_unlock(sc); 688239278Sgonzo return (error); 689239278Sgonzo} 690239278Sgonzo 691239278Sgonzostatic int 692239278Sgonzolpc_mmc_release_host(device_t bus, device_t child) 693239278Sgonzo{ 694239278Sgonzo struct lpc_mmc_softc *sc = device_get_softc(bus); 695239278Sgonzo 696239278Sgonzo lpc_mmc_lock(sc); 697239278Sgonzo sc->lm_bus_busy--; 698239278Sgonzo wakeup(sc); 699239278Sgonzo lpc_mmc_unlock(sc); 700239278Sgonzo return (0); 701239278Sgonzo} 702239278Sgonzo 703239278Sgonzostatic void lpc_mmc_dma_rxfinish(void *arg) 704239278Sgonzo{ 705239278Sgonzo} 706239278Sgonzo 707239278Sgonzostatic void lpc_mmc_dma_rxerror(void *arg) 708239278Sgonzo{ 709239278Sgonzo struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg; 710239278Sgonzo device_printf(sc->lm_dev, "DMA RX error\n"); 711239278Sgonzo} 712239278Sgonzo 713239278Sgonzostatic void lpc_mmc_dma_txfinish(void *arg) 714239278Sgonzo{ 715239278Sgonzo} 716239278Sgonzo 717239278Sgonzostatic void lpc_mmc_dma_txerror(void *arg) 718239278Sgonzo{ 719239278Sgonzo struct lpc_mmc_softc *sc = (struct lpc_mmc_softc *)arg; 720239278Sgonzo device_printf(sc->lm_dev, "DMA TX error\n"); 721239278Sgonzo} 722239278Sgonzo 723239278Sgonzostatic void 724239278Sgonzolpc_mmc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int err) 725239278Sgonzo{ 726239278Sgonzo struct lpc_mmc_dmamap_arg *ctx; 727239278Sgonzo 728239278Sgonzo if (err) 729239278Sgonzo return; 730239278Sgonzo 731239278Sgonzo ctx = (struct lpc_mmc_dmamap_arg *)arg; 732239278Sgonzo ctx->lm_dma_busaddr = segs[0].ds_addr; 733239278Sgonzo} 734239278Sgonzo 735239278Sgonzostatic device_method_t lpc_mmc_methods[] = { 736239278Sgonzo /* Device interface */ 737239278Sgonzo DEVMETHOD(device_probe, lpc_mmc_probe), 738239278Sgonzo DEVMETHOD(device_attach, lpc_mmc_attach), 739239278Sgonzo DEVMETHOD(device_detach, lpc_mmc_detach), 740239278Sgonzo 741239278Sgonzo /* Bus interface */ 742239278Sgonzo DEVMETHOD(bus_read_ivar, lpc_mmc_read_ivar), 743239278Sgonzo DEVMETHOD(bus_write_ivar, lpc_mmc_write_ivar), 744239278Sgonzo 745239278Sgonzo /* MMC bridge interface */ 746239278Sgonzo DEVMETHOD(mmcbr_update_ios, lpc_mmc_update_ios), 747239278Sgonzo DEVMETHOD(mmcbr_request, lpc_mmc_request), 748239278Sgonzo DEVMETHOD(mmcbr_get_ro, lpc_mmc_get_ro), 749239278Sgonzo DEVMETHOD(mmcbr_acquire_host, lpc_mmc_acquire_host), 750239278Sgonzo DEVMETHOD(mmcbr_release_host, lpc_mmc_release_host), 751239278Sgonzo 752318197Smarius DEVMETHOD_END 753239278Sgonzo}; 754239278Sgonzo 755239278Sgonzostatic devclass_t lpc_mmc_devclass; 756239278Sgonzo 757239278Sgonzostatic driver_t lpc_mmc_driver = { 758239278Sgonzo "lpcmmc", 759239278Sgonzo lpc_mmc_methods, 760239278Sgonzo sizeof(struct lpc_mmc_softc), 761239278Sgonzo}; 762239278Sgonzo 763318197SmariusDRIVER_MODULE(lpcmmc, simplebus, lpc_mmc_driver, lpc_mmc_devclass, NULL, NULL); 764318197SmariusMMC_DECLARE_BRIDGE(lpcmmc); 765