1239281Sgonzo/*- 2239281Sgonzo * Copyright (c) 2011 3239281Sgonzo * Ben Gray <ben.r.gray@gmail.com>. 4239281Sgonzo * All rights reserved. 5239281Sgonzo * 6239281Sgonzo * Redistribution and use in source and binary forms, with or without 7239281Sgonzo * modification, are permitted provided that the following conditions 8239281Sgonzo * are met: 9239281Sgonzo * 1. Redistributions of source code must retain the above copyright 10239281Sgonzo * notice, this list of conditions and the following disclaimer. 11239281Sgonzo * 2. Redistributions in binary form must reproduce the above copyright 12239281Sgonzo * notice, this list of conditions and the following disclaimer in the 13239281Sgonzo * documentation and/or other materials provided with the distribution. 14239281Sgonzo * 15239281Sgonzo * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16239281Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17239281Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18239281Sgonzo * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19239281Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20239281Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21239281Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22239281Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23239281Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24239281Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25239281Sgonzo * SUCH DAMAGE. 26239281Sgonzo */ 27239281Sgonzo 28239281Sgonzo/** 29239281Sgonzo * Driver for the MMC/SD/SDIO module on the TI OMAP series of SoCs. 30239281Sgonzo * 31239281Sgonzo * This driver is heavily based on the SD/MMC driver for the AT91 (at91_mci.c). 32239281Sgonzo * 33239281Sgonzo * It's important to realise that the MMC state machine is already in the kernel 34239281Sgonzo * and this driver only exposes the specific interfaces of the controller. 35239281Sgonzo * 36239281Sgonzo * This driver is still very much a work in progress, I've verified that basic 37239281Sgonzo * sector reading can be performed. But I've yet to test it with a file system 38239281Sgonzo * or even writing. In addition I've only tested the driver with an SD card, 39239281Sgonzo * I've no idea if MMC cards work. 40239281Sgonzo * 41239281Sgonzo */ 42239281Sgonzo#include <sys/cdefs.h> 43239281Sgonzo__FBSDID("$FreeBSD$"); 44239281Sgonzo 45239281Sgonzo#include <sys/param.h> 46239281Sgonzo#include <sys/systm.h> 47239281Sgonzo#include <sys/bio.h> 48239281Sgonzo#include <sys/bus.h> 49239281Sgonzo#include <sys/conf.h> 50239281Sgonzo#include <sys/endian.h> 51239281Sgonzo#include <sys/kernel.h> 52239281Sgonzo#include <sys/kthread.h> 53239281Sgonzo#include <sys/lock.h> 54239281Sgonzo#include <sys/malloc.h> 55239281Sgonzo#include <sys/module.h> 56239281Sgonzo#include <sys/mutex.h> 57239281Sgonzo#include <sys/queue.h> 58239281Sgonzo#include <sys/resource.h> 59239281Sgonzo#include <sys/rman.h> 60239281Sgonzo#include <sys/time.h> 61239281Sgonzo#include <sys/timetc.h> 62239281Sgonzo#include <sys/gpio.h> 63239281Sgonzo 64239281Sgonzo#include <machine/bus.h> 65239281Sgonzo#include <machine/cpu.h> 66239281Sgonzo#include <machine/cpufunc.h> 67239281Sgonzo#include <machine/resource.h> 68239281Sgonzo#include <machine/frame.h> 69239281Sgonzo#include <machine/intr.h> 70239281Sgonzo 71239281Sgonzo#include <dev/mmc/bridge.h> 72239281Sgonzo#include <dev/mmc/mmcreg.h> 73239281Sgonzo#include <dev/mmc/mmcbrvar.h> 74239281Sgonzo 75239281Sgonzo#include <dev/fdt/fdt_common.h> 76239281Sgonzo#include <dev/ofw/openfirm.h> 77239281Sgonzo#include <dev/ofw/ofw_bus.h> 78239281Sgonzo#include <dev/ofw/ofw_bus_subr.h> 79239281Sgonzo 80239281Sgonzo#include "gpio_if.h" 81239281Sgonzo 82239281Sgonzo#include "mmcbr_if.h" 83239281Sgonzo#include "mmcbus_if.h" 84239281Sgonzo 85239281Sgonzo#include <arm/ti/ti_sdma.h> 86239281Sgonzo#include <arm/ti/ti_edma3.h> 87239281Sgonzo#include <arm/ti/ti_mmchs.h> 88239281Sgonzo#include <arm/ti/ti_cpuid.h> 89239281Sgonzo#include <arm/ti/ti_prcm.h> 90239281Sgonzo 91239281Sgonzo#include <arm/ti/twl/twl.h> 92239281Sgonzo#include <arm/ti/twl/twl_vreg.h> 93239281Sgonzo 94239281Sgonzo#ifdef DEBUG 95239281Sgonzo#define ti_mmchs_dbg(sc, fmt, args...) \ 96239281Sgonzo device_printf((sc)->sc_dev, fmt, ## args); 97239281Sgonzo#else 98239281Sgonzo#define ti_mmchs_dbg(sc, fmt, args...) 99239281Sgonzo#endif 100239281Sgonzo 101239281Sgonzo/** 102239281Sgonzo * Structure that stores the driver context 103239281Sgonzo */ 104239281Sgonzostruct ti_mmchs_softc { 105239281Sgonzo device_t sc_dev; 106239281Sgonzo uint32_t device_id; 107239281Sgonzo struct resource* sc_irq_res; 108239281Sgonzo struct resource* sc_mem_res; 109239281Sgonzo 110239281Sgonzo void* sc_irq_h; 111239281Sgonzo 112239281Sgonzo bus_dma_tag_t sc_dmatag; 113239281Sgonzo bus_dmamap_t sc_dmamap; 114239281Sgonzo int sc_dmamapped; 115239281Sgonzo 116239281Sgonzo unsigned int sc_dmach_rd; 117239281Sgonzo unsigned int sc_dmach_wr; 118239281Sgonzo int dma_rx_trig; 119239281Sgonzo int dma_tx_trig; 120239281Sgonzo 121239281Sgonzo device_t sc_gpio_dev; 122239281Sgonzo int sc_wp_gpio_pin; /* GPIO pin for MMC write protect */ 123239281Sgonzo 124239281Sgonzo device_t sc_vreg_dev; 125239281Sgonzo const char* sc_vreg_name; 126239281Sgonzo 127239281Sgonzo struct mtx sc_mtx; 128239281Sgonzo 129239281Sgonzo struct mmc_host host; 130239281Sgonzo struct mmc_request* req; 131239281Sgonzo struct mmc_command* curcmd; 132239281Sgonzo 133239281Sgonzo int flags; 134239281Sgonzo#define CMD_STARTED 1 135239281Sgonzo#define STOP_STARTED 2 136239281Sgonzo 137239281Sgonzo int bus_busy; /* TODO: Needed ? */ 138239281Sgonzo 139239281Sgonzo void* sc_cmd_data_vaddr; 140239281Sgonzo int sc_cmd_data_len; 141239281Sgonzo 142239281Sgonzo /* The offset applied to each of the register base addresses, OMAP4 143239281Sgonzo * register sets are offset 0x100 from the OMAP3 series. 144239281Sgonzo */ 145239281Sgonzo unsigned long sc_reg_off; 146239281Sgonzo 147239281Sgonzo /* The physical address of the MMCHS_DATA register, used for the DMA xfers */ 148239281Sgonzo unsigned long sc_data_reg_paddr; 149239281Sgonzo 150239281Sgonzo /* The reference clock frequency */ 151239281Sgonzo unsigned int sc_ref_freq; 152239281Sgonzo 153239281Sgonzo enum mmc_power_mode sc_cur_power_mode; 154239281Sgonzo}; 155239281Sgonzo 156239281Sgonzo/** 157239281Sgonzo * Macros for driver mutex locking 158239281Sgonzo */ 159239281Sgonzo#define TI_MMCHS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 160239281Sgonzo#define TI_MMCHS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 161239281Sgonzo#define TI_MMCHS_LOCK_INIT(_sc) \ 162239281Sgonzo mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ 163239281Sgonzo "ti_mmchs", MTX_DEF) 164239281Sgonzo#define TI_MMCHS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 165239281Sgonzo#define TI_MMCHS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED); 166239281Sgonzo#define TI_MMCHS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED); 167239281Sgonzo 168239281Sgonzostatic void ti_mmchs_start(struct ti_mmchs_softc *sc); 169239281Sgonzo 170239281Sgonzo/** 171239281Sgonzo * ti_mmchs_read_4 - reads a 32-bit value from a register 172239281Sgonzo * ti_mmchs_write_4 - writes a 32-bit value to a register 173239281Sgonzo * @sc: pointer to the driver context 174239281Sgonzo * @off: register offset to read from 175239281Sgonzo * @val: the value to write into the register 176239281Sgonzo * 177239281Sgonzo * LOCKING: 178239281Sgonzo * None 179239281Sgonzo * 180239281Sgonzo * RETURNS: 181239281Sgonzo * The 32-bit value read from the register 182239281Sgonzo */ 183239281Sgonzostatic inline uint32_t 184239281Sgonzoti_mmchs_read_4(struct ti_mmchs_softc *sc, bus_size_t off) 185239281Sgonzo{ 186239281Sgonzo return bus_read_4(sc->sc_mem_res, (sc->sc_reg_off + off)); 187239281Sgonzo} 188239281Sgonzo 189239281Sgonzostatic inline void 190239281Sgonzoti_mmchs_write_4(struct ti_mmchs_softc *sc, bus_size_t off, uint32_t val) 191239281Sgonzo{ 192239281Sgonzo bus_write_4(sc->sc_mem_res, (sc->sc_reg_off + off), val); 193239281Sgonzo} 194239281Sgonzo 195239281Sgonzo/** 196239281Sgonzo * ti_mmchs_reset_controller - 197239281Sgonzo * @arg: caller supplied arg 198239281Sgonzo * @segs: array of segments (although in our case should only be one) 199239281Sgonzo * @nsegs: number of segments (in our case should be 1) 200239281Sgonzo * @error: 201239281Sgonzo * 202239281Sgonzo * 203239281Sgonzo * 204239281Sgonzo */ 205239281Sgonzostatic void 206239281Sgonzoti_mmchs_reset_controller(struct ti_mmchs_softc *sc, uint32_t bit) 207239281Sgonzo{ 208239281Sgonzo unsigned long attempts; 209239281Sgonzo uint32_t sysctl; 210239281Sgonzo 211239281Sgonzo ti_mmchs_dbg(sc, "reseting controller - bit 0x%08x\n", bit); 212239281Sgonzo 213239281Sgonzo sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL); 214239281Sgonzo ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | bit); 215253023Sgonzo /* 216253053Srpaulo * AM335x and OMAP4 >= ES2 have an updated reset logic. 217253053Srpaulo * Monitor a 0->1 transition first. 218253023Sgonzo */ 219253023Sgonzo if ((ti_chip() == CHIP_AM335X) || 220253023Sgonzo ((ti_chip() == CHIP_OMAP_4) && (ti_revision() > OMAP4430_REV_ES1_0))) { 221239281Sgonzo attempts = 10000; 222239281Sgonzo while (!(ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0)) 223239281Sgonzo continue; 224239281Sgonzo } 225239281Sgonzo 226239281Sgonzo attempts = 10000; 227239281Sgonzo while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) && (attempts-- > 0)) 228239281Sgonzo continue; 229239281Sgonzo 230239281Sgonzo if (ti_mmchs_read_4(sc, MMCHS_SYSCTL) & bit) 231239281Sgonzo device_printf(sc->sc_dev, "Error - Timeout waiting on controller reset\n"); 232239281Sgonzo} 233239281Sgonzo 234239281Sgonzo/** 235239281Sgonzo * ti_mmchs_getaddr - called by the DMA function to simply return the phys addr 236239281Sgonzo * @arg: caller supplied arg 237239281Sgonzo * @segs: array of segments (although in our case should only be one) 238239281Sgonzo * @nsegs: number of segments (in our case should be 1) 239239281Sgonzo * @error: 240239281Sgonzo * 241239281Sgonzo * This function is called by bus_dmamap_load() after it has compiled an array 242239281Sgonzo * of segments, each segment is a phsyical chunk of memory. However in our case 243239281Sgonzo * we should only have one segment, because we don't (yet?) support DMA scatter 244239281Sgonzo * gather. To ensure we only have one segment, the DMA tag was created by 245239281Sgonzo * bus_dma_tag_create() (called from ti_mmchs_attach) with nsegments set to 1. 246239281Sgonzo * 247239281Sgonzo */ 248239281Sgonzostatic void 249239281Sgonzoti_mmchs_getaddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 250239281Sgonzo{ 251239281Sgonzo if (error != 0) 252239281Sgonzo return; 253239281Sgonzo 254239281Sgonzo *(bus_addr_t *)arg = segs[0].ds_addr; 255239281Sgonzo} 256239281Sgonzo 257239281Sgonzo#ifndef SOC_TI_AM335X 258239281Sgonzo/** 259239281Sgonzo * ti_mmchs_dma_intr - interrupt handler for DMA events triggered by the controller 260239281Sgonzo * @ch: the dma channel number 261239281Sgonzo * @status: bit field of the status bytes 262239281Sgonzo * @data: callback data, in this case a pointer to the controller struct 263239281Sgonzo * 264239281Sgonzo * 265239281Sgonzo * LOCKING: 266239281Sgonzo * Called from interrupt context 267239281Sgonzo * 268239281Sgonzo */ 269239281Sgonzostatic void 270239281Sgonzoti_mmchs_dma_intr(unsigned int ch, uint32_t status, void *data) 271239281Sgonzo{ 272239281Sgonzo /* Ignore for now ... we don't need this interrupt as we already have the 273239281Sgonzo * interrupt from the MMC controller. 274239281Sgonzo */ 275239281Sgonzo} 276239281Sgonzo#endif 277239281Sgonzo 278239281Sgonzo/** 279239281Sgonzo * ti_mmchs_intr_xfer_compl - called if a 'transfer complete' IRQ was received 280239281Sgonzo * @sc: pointer to the driver context 281239281Sgonzo * @cmd: the command that was sent previously 282239281Sgonzo * 283239281Sgonzo * This function is simply responsible for syncing up the DMA buffer. 284239281Sgonzo * 285239281Sgonzo * LOCKING: 286239281Sgonzo * Called from interrupt context 287239281Sgonzo * 288239281Sgonzo * RETURNS: 289239281Sgonzo * Return value indicates if the transaction is complete, not done = 0, done != 0 290239281Sgonzo */ 291239281Sgonzostatic int 292239281Sgonzoti_mmchs_intr_xfer_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd) 293239281Sgonzo{ 294239281Sgonzo uint32_t cmd_reg; 295239281Sgonzo 296239281Sgonzo /* Read command register to test whether this command was a read or write. */ 297239281Sgonzo cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD); 298239281Sgonzo 299239281Sgonzo /* Sync-up the DMA buffer so the caller can access the new memory */ 300239281Sgonzo if (cmd_reg & MMCHS_CMD_DDIR) { 301239281Sgonzo bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTREAD); 302239281Sgonzo bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); 303239281Sgonzo } 304239281Sgonzo else { 305239281Sgonzo bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_POSTWRITE); 306239281Sgonzo bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); 307239281Sgonzo } 308239281Sgonzo sc->sc_dmamapped--; 309239281Sgonzo 310239281Sgonzo /* Debugging dump of the data received */ 311239281Sgonzo#if 0 312239281Sgonzo { 313239281Sgonzo int i; 314239281Sgonzo uint8_t *p = (uint8_t*) sc->sc_cmd_data_vaddr; 315239281Sgonzo for (i=0; i<sc->sc_cmd_data_len; i++) { 316239281Sgonzo if ((i % 16) == 0) 317239281Sgonzo printf("\n0x%04x : ", i); 318239281Sgonzo printf("%02X ", *p++); 319239281Sgonzo } 320239281Sgonzo printf("\n"); 321239281Sgonzo } 322239281Sgonzo#endif 323239281Sgonzo 324239281Sgonzo /* We are done, transfer complete */ 325239281Sgonzo return 1; 326239281Sgonzo} 327239281Sgonzo 328239281Sgonzo/** 329239281Sgonzo * ti_mmchs_intr_cmd_compl - called if a 'command complete' IRQ was received 330239281Sgonzo * @sc: pointer to the driver context 331239281Sgonzo * @cmd: the command that was sent previously 332239281Sgonzo * 333239281Sgonzo * 334239281Sgonzo * LOCKING: 335239281Sgonzo * Called from interrupt context 336239281Sgonzo * 337239281Sgonzo * RETURNS: 338239281Sgonzo * Return value indicates if the transaction is complete, not done = 0, done != 0 339239281Sgonzo */ 340239281Sgonzostatic int 341239281Sgonzoti_mmchs_intr_cmd_compl(struct ti_mmchs_softc *sc, struct mmc_command *cmd) 342239281Sgonzo{ 343239281Sgonzo uint32_t cmd_reg; 344239281Sgonzo 345239281Sgonzo /* Copy the response into the request struct ... if a response was 346239281Sgonzo * expected */ 347239281Sgonzo if (cmd != NULL && (cmd->flags & MMC_RSP_PRESENT)) { 348239281Sgonzo if (cmd->flags & MMC_RSP_136) { 349239281Sgonzo cmd->resp[3] = ti_mmchs_read_4(sc, MMCHS_RSP10); 350239281Sgonzo cmd->resp[2] = ti_mmchs_read_4(sc, MMCHS_RSP32); 351239281Sgonzo cmd->resp[1] = ti_mmchs_read_4(sc, MMCHS_RSP54); 352239281Sgonzo cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP76); 353239281Sgonzo } else { 354239281Sgonzo cmd->resp[0] = ti_mmchs_read_4(sc, MMCHS_RSP10); 355239281Sgonzo } 356239281Sgonzo } 357239281Sgonzo 358239281Sgonzo /* Check if the command was expecting some data transfer, if not 359239281Sgonzo * we are done. */ 360239281Sgonzo cmd_reg = ti_mmchs_read_4(sc, MMCHS_CMD); 361239281Sgonzo return ((cmd_reg & MMCHS_CMD_DP) == 0); 362239281Sgonzo} 363239281Sgonzo 364239281Sgonzo/** 365239281Sgonzo * ti_mmchs_intr_error - handles error interrupts 366239281Sgonzo * @sc: pointer to the driver context 367239281Sgonzo * @cmd: the command that was sent previously 368239281Sgonzo * @stat_reg: the value that was in the status register 369239281Sgonzo * 370239281Sgonzo * 371239281Sgonzo * LOCKING: 372239281Sgonzo * Called from interrupt context 373239281Sgonzo * 374239281Sgonzo * RETURNS: 375239281Sgonzo * Return value indicates if the transaction is complete, not done = 0, done != 0 376239281Sgonzo */ 377239281Sgonzostatic int 378239281Sgonzoti_mmchs_intr_error(struct ti_mmchs_softc *sc, struct mmc_command *cmd, 379239281Sgonzo uint32_t stat_reg) 380239281Sgonzo{ 381239281Sgonzo ti_mmchs_dbg(sc, "error in xfer - stat 0x%08x\n", stat_reg); 382239281Sgonzo 383239281Sgonzo /* Ignore CRC errors on CMD2 and ACMD47, per relevant standards */ 384239281Sgonzo if ((stat_reg & MMCHS_STAT_CCRC) && (cmd->opcode == MMC_SEND_OP_COND || 385239281Sgonzo cmd->opcode == ACMD_SD_SEND_OP_COND)) 386239281Sgonzo cmd->error = MMC_ERR_NONE; 387239281Sgonzo else if (stat_reg & (MMCHS_STAT_CTO | MMCHS_STAT_DTO)) 388239281Sgonzo cmd->error = MMC_ERR_TIMEOUT; 389239281Sgonzo else if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_DCRC)) 390239281Sgonzo cmd->error = MMC_ERR_BADCRC; 391239281Sgonzo else 392239281Sgonzo cmd->error = MMC_ERR_FAILED; 393239281Sgonzo 394239281Sgonzo /* If a dma transaction we should also stop the dma transfer */ 395239281Sgonzo if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DE) { 396239281Sgonzo 397239281Sgonzo /* Abort the DMA transfer (DDIR bit tells direction) */ 398239281Sgonzo if (ti_mmchs_read_4(sc, MMCHS_CMD) & MMCHS_CMD_DDIR) 399239281Sgonzo#ifdef SOC_TI_AM335X 400239281Sgonzo printf("%s: DMA unimplemented\n", __func__); 401239281Sgonzo#else 402239281Sgonzo ti_sdma_stop_xfer(sc->sc_dmach_rd); 403239281Sgonzo#endif 404239281Sgonzo else 405239281Sgonzo#ifdef SOC_TI_AM335X 406239281Sgonzo printf("%s: DMA unimplemented\n", __func__); 407239281Sgonzo#else 408239281Sgonzo ti_sdma_stop_xfer(sc->sc_dmach_wr); 409239281Sgonzo#endif 410239281Sgonzo 411239281Sgonzo /* If an error occure abort the DMA operation and free the dma map */ 412239281Sgonzo if ((sc->sc_dmamapped > 0) && (cmd->error != MMC_ERR_NONE)) { 413239281Sgonzo bus_dmamap_unload(sc->sc_dmatag, sc->sc_dmamap); 414239281Sgonzo sc->sc_dmamapped--; 415239281Sgonzo } 416239281Sgonzo } 417239281Sgonzo 418239281Sgonzo /* Command error occured? ... if so issue a soft reset for the cmd fsm */ 419239281Sgonzo if (stat_reg & (MMCHS_STAT_CCRC | MMCHS_STAT_CTO)) { 420239281Sgonzo ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRC); 421239281Sgonzo } 422239281Sgonzo 423239281Sgonzo /* Data error occured? ... if so issue a soft reset for the data line */ 424239281Sgonzo if (stat_reg & (MMCHS_STAT_DEB | MMCHS_STAT_DCRC | MMCHS_STAT_DTO)) { 425239281Sgonzo ti_mmchs_reset_controller(sc, MMCHS_SYSCTL_SRD); 426239281Sgonzo } 427239281Sgonzo 428239281Sgonzo /* On any error the command is cancelled ... so we are done */ 429239281Sgonzo return 1; 430239281Sgonzo} 431239281Sgonzo 432239281Sgonzo/** 433239281Sgonzo * ti_mmchs_intr - interrupt handler for MMC/SD/SDIO controller 434239281Sgonzo * @arg: pointer to the driver context 435239281Sgonzo * 436239281Sgonzo * Interrupt handler for the MMC/SD/SDIO controller, responsible for handling 437239281Sgonzo * the IRQ and clearing the status flags. 438239281Sgonzo * 439239281Sgonzo * LOCKING: 440239281Sgonzo * Called from interrupt context 441239281Sgonzo * 442239281Sgonzo * RETURNS: 443239281Sgonzo * nothing 444239281Sgonzo */ 445239281Sgonzostatic void 446239281Sgonzoti_mmchs_intr(void *arg) 447239281Sgonzo{ 448239281Sgonzo struct ti_mmchs_softc *sc = (struct ti_mmchs_softc *) arg; 449239281Sgonzo uint32_t stat_reg; 450239281Sgonzo int done = 0; 451239281Sgonzo 452239281Sgonzo TI_MMCHS_LOCK(sc); 453239281Sgonzo 454239281Sgonzo stat_reg = ti_mmchs_read_4(sc, MMCHS_STAT) & (ti_mmchs_read_4(sc, 455239281Sgonzo MMCHS_IE) | MMCHS_STAT_ERRI); 456239281Sgonzo 457239281Sgonzo if (sc->curcmd == NULL) { 458239281Sgonzo device_printf(sc->sc_dev, "Error: current cmd NULL, already done?\n"); 459239281Sgonzo ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg); 460239281Sgonzo TI_MMCHS_UNLOCK(sc); 461239281Sgonzo return; 462239281Sgonzo } 463239281Sgonzo 464239281Sgonzo if (stat_reg & MMCHS_STAT_ERRI) { 465239281Sgonzo /* An error has been tripped in the status register */ 466239281Sgonzo done = ti_mmchs_intr_error(sc, sc->curcmd, stat_reg); 467239281Sgonzo 468239281Sgonzo } else { 469239281Sgonzo 470239281Sgonzo /* NOTE: This implementation could be a bit inefficent, I don't think 471239281Sgonzo * it is necessary to handle both the 'command complete' and 'transfer 472239281Sgonzo * complete' for data transfers ... presumably just transfer complete 473239281Sgonzo * is enough. 474239281Sgonzo */ 475239281Sgonzo 476239281Sgonzo /* No error */ 477239281Sgonzo sc->curcmd->error = MMC_ERR_NONE; 478239281Sgonzo 479239281Sgonzo /* Check if the command completed */ 480239281Sgonzo if (stat_reg & MMCHS_STAT_CC) { 481239281Sgonzo done = ti_mmchs_intr_cmd_compl(sc, sc->curcmd); 482239281Sgonzo } 483239281Sgonzo 484239281Sgonzo /* Check if the transfer has completed */ 485239281Sgonzo if (stat_reg & MMCHS_STAT_TC) { 486239281Sgonzo done = ti_mmchs_intr_xfer_compl(sc, sc->curcmd); 487239281Sgonzo } 488239281Sgonzo 489239281Sgonzo } 490239281Sgonzo 491239281Sgonzo /* Clear all the interrupt status bits by writing the value back */ 492239281Sgonzo ti_mmchs_write_4(sc, MMCHS_STAT, stat_reg); 493239281Sgonzo 494239281Sgonzo /* This may mark the command as done if there is no stop request */ 495239281Sgonzo /* TODO: This is a bit ugly, needs fix-up */ 496239281Sgonzo if (done) { 497239281Sgonzo ti_mmchs_start(sc); 498239281Sgonzo } 499239281Sgonzo 500239281Sgonzo TI_MMCHS_UNLOCK(sc); 501239281Sgonzo} 502239281Sgonzo 503239281Sgonzo#ifdef SOC_TI_AM335X 504239281Sgonzostatic void 505239281Sgonzoti_mmchs_edma3_rx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr, 506239281Sgonzo uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks) 507239281Sgonzo{ 508239281Sgonzo struct ti_edma3cc_param_set ps; 509239281Sgonzo 510239281Sgonzo bzero(&ps, sizeof(struct ti_edma3cc_param_set)); 511239281Sgonzo ps.src = src_paddr; 512239281Sgonzo ps.dst = dst_paddr; 513239281Sgonzo ps.dstbidx = 4; 514239281Sgonzo ps.dstcidx = blk_size; 515239281Sgonzo ps.acnt = 4; 516239281Sgonzo ps.bcnt = blk_size/4; 517239281Sgonzo ps.ccnt = num_blks; 518239281Sgonzo ps.link = 0xffff; 519239281Sgonzo ps.opt.tcc = sc->dma_rx_trig; 520239281Sgonzo ps.opt.tcinten = 1; 521239281Sgonzo ps.opt.fwid = 2; /* fifo width is 32 */ 522239281Sgonzo ps.opt.sam = 1; 523239281Sgonzo ps.opt.syncdim = 1; 524239281Sgonzo 525239281Sgonzo ti_edma3_param_write(sc->dma_rx_trig, &ps); 526239281Sgonzo ti_edma3_enable_transfer_event(sc->dma_rx_trig); 527239281Sgonzo} 528239281Sgonzo 529239281Sgonzostatic void 530239281Sgonzoti_mmchs_edma3_tx_xfer_setup(struct ti_mmchs_softc *sc, uint32_t src_paddr, 531239281Sgonzo uint32_t dst_paddr, uint16_t blk_size, uint16_t num_blks) 532239281Sgonzo{ 533239281Sgonzo struct ti_edma3cc_param_set ps; 534239281Sgonzo 535239281Sgonzo bzero(&ps, sizeof(struct ti_edma3cc_param_set)); 536239281Sgonzo ps.src = src_paddr; 537239281Sgonzo ps.dst = dst_paddr; 538239281Sgonzo ps.srccidx = blk_size; 539239281Sgonzo ps.bcnt = blk_size/4; 540239281Sgonzo ps.ccnt = num_blks; 541239281Sgonzo ps.srcbidx = 4; 542239281Sgonzo ps.acnt = 0x4; 543239281Sgonzo ps.link = 0xffff; 544239281Sgonzo ps.opt.tcc = sc->dma_tx_trig; 545239281Sgonzo ps.opt.tcinten = 1; 546239281Sgonzo ps.opt.fwid = 2; /* fifo width is 32 */ 547239281Sgonzo ps.opt.dam = 1; 548239281Sgonzo ps.opt.syncdim = 1; 549239281Sgonzo 550239281Sgonzo ti_edma3_param_write(sc->dma_tx_trig, &ps); 551239281Sgonzo ti_edma3_enable_transfer_event(sc->dma_tx_trig); 552239281Sgonzo} 553239281Sgonzo#endif 554239281Sgonzo 555239281Sgonzo/** 556239281Sgonzo * ti_mmchs_start_cmd - starts the given command 557239281Sgonzo * @sc: pointer to the driver context 558239281Sgonzo * @cmd: the command to start 559239281Sgonzo * 560239281Sgonzo * The call tree for this function is 561239281Sgonzo * - ti_mmchs_start_cmd 562239281Sgonzo * - ti_mmchs_start 563239281Sgonzo * - ti_mmchs_request 564239281Sgonzo * 565239281Sgonzo * LOCKING: 566239281Sgonzo * Caller should be holding the OMAP_MMC lock. 567239281Sgonzo * 568239281Sgonzo * RETURNS: 569239281Sgonzo * nothing 570239281Sgonzo */ 571239281Sgonzostatic void 572239281Sgonzoti_mmchs_start_cmd(struct ti_mmchs_softc *sc, struct mmc_command *cmd) 573239281Sgonzo{ 574239281Sgonzo uint32_t cmd_reg, con_reg, ise_reg; 575239281Sgonzo struct mmc_data *data; 576239281Sgonzo struct mmc_request *req; 577239281Sgonzo void *vaddr; 578239281Sgonzo bus_addr_t paddr; 579239281Sgonzo#ifndef SOC_TI_AM335X 580239281Sgonzo uint32_t pktsize; 581239281Sgonzo#endif 582239281Sgonzo sc->curcmd = cmd; 583239281Sgonzo data = cmd->data; 584239281Sgonzo req = cmd->mrq; 585239281Sgonzo 586239281Sgonzo /* Ensure the STR and MIT bits are cleared, these are only used for special 587239281Sgonzo * command types. 588239281Sgonzo */ 589239281Sgonzo con_reg = ti_mmchs_read_4(sc, MMCHS_CON); 590239281Sgonzo con_reg &= ~(MMCHS_CON_STR | MMCHS_CON_MIT); 591239281Sgonzo 592239281Sgonzo /* Load the command into bits 29:24 of the CMD register */ 593239281Sgonzo cmd_reg = (uint32_t)(cmd->opcode & 0x3F) << 24; 594239281Sgonzo 595239281Sgonzo /* Set the default set of interrupts */ 596239281Sgonzo ise_reg = (MMCHS_STAT_CERR | MMCHS_STAT_CTO | MMCHS_STAT_CC | MMCHS_STAT_CEB); 597239281Sgonzo 598239281Sgonzo /* Enable CRC checking if requested */ 599239281Sgonzo if (cmd->flags & MMC_RSP_CRC) 600239281Sgonzo ise_reg |= MMCHS_STAT_CCRC; 601239281Sgonzo 602239281Sgonzo /* Enable reply index checking if the response supports it */ 603239281Sgonzo if (cmd->flags & MMC_RSP_OPCODE) 604239281Sgonzo ise_reg |= MMCHS_STAT_CIE; 605239281Sgonzo 606239281Sgonzo /* Set the expected response length */ 607239281Sgonzo if (MMC_RSP(cmd->flags) == MMC_RSP_NONE) { 608239281Sgonzo cmd_reg |= MMCHS_CMD_RSP_TYPE_NO; 609239281Sgonzo } else { 610239281Sgonzo if (cmd->flags & MMC_RSP_136) 611239281Sgonzo cmd_reg |= MMCHS_CMD_RSP_TYPE_136; 612239281Sgonzo else if (cmd->flags & MMC_RSP_BUSY) 613239281Sgonzo cmd_reg |= MMCHS_CMD_RSP_TYPE_48_BSY; 614239281Sgonzo else 615239281Sgonzo cmd_reg |= MMCHS_CMD_RSP_TYPE_48; 616239281Sgonzo 617239281Sgonzo /* Enable command index/crc checks if necessary expected */ 618239281Sgonzo if (cmd->flags & MMC_RSP_CRC) 619239281Sgonzo cmd_reg |= MMCHS_CMD_CCCE; 620239281Sgonzo if (cmd->flags & MMC_RSP_OPCODE) 621239281Sgonzo cmd_reg |= MMCHS_CMD_CICE; 622239281Sgonzo } 623239281Sgonzo 624239281Sgonzo /* Set the bits for the special commands CMD12 (MMC_STOP_TRANSMISSION) and 625239281Sgonzo * CMD52 (SD_IO_RW_DIRECT) */ 626239281Sgonzo if (cmd->opcode == MMC_STOP_TRANSMISSION) 627239281Sgonzo cmd_reg |= MMCHS_CMD_CMD_TYPE_IO_ABORT; 628239281Sgonzo 629239281Sgonzo /* Check if there is any data to write */ 630239281Sgonzo if (data == NULL) { 631239281Sgonzo /* Clear the block count */ 632239281Sgonzo ti_mmchs_write_4(sc, MMCHS_BLK, 0); 633239281Sgonzo 634239281Sgonzo /* The no data case is fairly simple */ 635239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con_reg); 636239281Sgonzo ti_mmchs_write_4(sc, MMCHS_IE, ise_reg); 637239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg); 638239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg); 639239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg); 640239281Sgonzo return; 641239281Sgonzo } 642239281Sgonzo 643239281Sgonzo /* Indicate that data is present */ 644239281Sgonzo cmd_reg |= MMCHS_CMD_DP | MMCHS_CMD_MSBS | MMCHS_CMD_BCE; 645239281Sgonzo 646239281Sgonzo /* Indicate a read operation */ 647239281Sgonzo if (data->flags & MMC_DATA_READ) 648239281Sgonzo cmd_reg |= MMCHS_CMD_DDIR; 649239281Sgonzo 650239281Sgonzo /* Streaming mode */ 651239281Sgonzo if (data->flags & MMC_DATA_STREAM) { 652239281Sgonzo con_reg |= MMCHS_CON_STR; 653239281Sgonzo } 654239281Sgonzo 655239281Sgonzo /* Multi-block mode */ 656239281Sgonzo if (data->flags & MMC_DATA_MULTI) { 657239281Sgonzo cmd_reg |= MMCHS_CMD_MSBS; 658239281Sgonzo } 659239281Sgonzo 660239281Sgonzo /* Enable extra interrupt sources for the transfer */ 661239281Sgonzo ise_reg |= (MMCHS_STAT_TC | MMCHS_STAT_DTO | MMCHS_STAT_DEB | MMCHS_STAT_CEB); 662239281Sgonzo if (cmd->flags & MMC_RSP_CRC) 663239281Sgonzo ise_reg |= MMCHS_STAT_DCRC; 664239281Sgonzo 665239281Sgonzo /* Enable the DMA transfer bit */ 666239281Sgonzo cmd_reg |= MMCHS_CMD_DE; 667239281Sgonzo 668239281Sgonzo /* Set the block size and block count */ 669239281Sgonzo ti_mmchs_write_4(sc, MMCHS_BLK, (1 << 16) | data->len); 670239281Sgonzo 671239281Sgonzo /* Setup the DMA stuff */ 672239281Sgonzo if (data->flags & (MMC_DATA_READ | MMC_DATA_WRITE)) { 673239281Sgonzo 674239281Sgonzo vaddr = data->data; 675239281Sgonzo data->xfer_len = 0; 676239281Sgonzo 677239281Sgonzo /* Map the buffer buf into bus space using the dmamap map. */ 678239281Sgonzo if (bus_dmamap_load(sc->sc_dmatag, sc->sc_dmamap, vaddr, data->len, 679239281Sgonzo ti_mmchs_getaddr, &paddr, 0) != 0) { 680239281Sgonzo 681239281Sgonzo if (req->cmd->flags & STOP_STARTED) 682239281Sgonzo req->stop->error = MMC_ERR_NO_MEMORY; 683239281Sgonzo else 684239281Sgonzo req->cmd->error = MMC_ERR_NO_MEMORY; 685239281Sgonzo sc->req = NULL; 686239281Sgonzo sc->curcmd = NULL; 687239281Sgonzo req->done(req); 688239281Sgonzo return; 689239281Sgonzo } 690239281Sgonzo 691239281Sgonzo#ifndef SOC_TI_AM335X 692239281Sgonzo /* Calculate the packet size, the max packet size is 512 bytes 693239281Sgonzo * (or 128 32-bit elements). 694239281Sgonzo */ 695239281Sgonzo pktsize = min((data->len / 4), (512 / 4)); 696239281Sgonzo#endif 697239281Sgonzo /* Sync the DMA buffer and setup the DMA controller */ 698239281Sgonzo if (data->flags & MMC_DATA_READ) { 699239281Sgonzo bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREREAD); 700239281Sgonzo#ifdef SOC_TI_AM335X 701239281Sgonzo ti_mmchs_edma3_rx_xfer_setup(sc, sc->sc_data_reg_paddr, 702239281Sgonzo paddr, data->len, 1); 703239281Sgonzo#else 704239281Sgonzo ti_sdma_start_xfer_packet(sc->sc_dmach_rd, sc->sc_data_reg_paddr, 705239281Sgonzo paddr, 1, (data->len / 4), pktsize); 706239281Sgonzo#endif 707239281Sgonzo } else { 708239281Sgonzo bus_dmamap_sync(sc->sc_dmatag, sc->sc_dmamap, BUS_DMASYNC_PREWRITE); 709239281Sgonzo#ifdef SOC_TI_AM335X 710239281Sgonzo ti_mmchs_edma3_tx_xfer_setup(sc, paddr, 711239281Sgonzo sc->sc_data_reg_paddr, data->len, 1); 712239281Sgonzo#else 713239281Sgonzo ti_sdma_start_xfer_packet(sc->sc_dmach_wr, paddr, 714239281Sgonzo sc->sc_data_reg_paddr, 1, (data->len / 4), pktsize); 715239281Sgonzo#endif 716239281Sgonzo } 717239281Sgonzo 718239281Sgonzo /* Increase the mapped count */ 719239281Sgonzo sc->sc_dmamapped++; 720239281Sgonzo 721239281Sgonzo sc->sc_cmd_data_vaddr = vaddr; 722239281Sgonzo sc->sc_cmd_data_len = data->len; 723239281Sgonzo } 724239281Sgonzo 725239281Sgonzo /* Finally kick off the command */ 726239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con_reg); 727239281Sgonzo ti_mmchs_write_4(sc, MMCHS_IE, ise_reg); 728239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ISE, ise_reg); 729239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ARG, cmd->arg); 730239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CMD, cmd_reg); 731239281Sgonzo 732239281Sgonzo /* and we're done */ 733239281Sgonzo} 734239281Sgonzo 735239281Sgonzo/** 736239281Sgonzo * ti_mmchs_start - starts a request stored in the driver context 737239281Sgonzo * @sc: pointer to the driver context 738239281Sgonzo * 739239281Sgonzo * This function is called by ti_mmchs_request() in response to a read/write 740239281Sgonzo * request from the MMC core module. 741239281Sgonzo * 742239281Sgonzo * LOCKING: 743239281Sgonzo * Caller should be holding the OMAP_MMC lock. 744239281Sgonzo * 745239281Sgonzo * RETURNS: 746239281Sgonzo * nothing 747239281Sgonzo */ 748239281Sgonzostatic void 749239281Sgonzoti_mmchs_start(struct ti_mmchs_softc *sc) 750239281Sgonzo{ 751239281Sgonzo struct mmc_request *req; 752239281Sgonzo 753239281Sgonzo /* Sanity check we have a request */ 754239281Sgonzo req = sc->req; 755239281Sgonzo if (req == NULL) 756239281Sgonzo return; 757239281Sgonzo 758239281Sgonzo /* assert locked */ 759239281Sgonzo if (!(sc->flags & CMD_STARTED)) { 760239281Sgonzo sc->flags |= CMD_STARTED; 761239281Sgonzo ti_mmchs_start_cmd(sc, req->cmd); 762239281Sgonzo return; 763239281Sgonzo } 764239281Sgonzo 765239281Sgonzo if (!(sc->flags & STOP_STARTED) && req->stop) { 766239281Sgonzo sc->flags |= STOP_STARTED; 767239281Sgonzo ti_mmchs_start_cmd(sc, req->stop); 768239281Sgonzo return; 769239281Sgonzo } 770239281Sgonzo 771239281Sgonzo /* We must be done -- bad idea to do this while locked? */ 772239281Sgonzo sc->req = NULL; 773239281Sgonzo sc->curcmd = NULL; 774239281Sgonzo req->done(req); 775239281Sgonzo} 776239281Sgonzo 777239281Sgonzo/** 778239281Sgonzo * ti_mmchs_request - entry point for all read/write/cmd requests 779239281Sgonzo * @brdev: mmc bridge device handle 780239281Sgonzo * @reqdev: the device doing the requesting ? 781239281Sgonzo * @req: the action requested 782239281Sgonzo * 783239281Sgonzo * LOCKING: 784239281Sgonzo * None, internally takes the OMAP_MMC lock. 785239281Sgonzo * 786239281Sgonzo * RETURNS: 787239281Sgonzo * 0 on success 788239281Sgonzo * EBUSY if the driver is already performing a request 789239281Sgonzo */ 790239281Sgonzostatic int 791239281Sgonzoti_mmchs_request(device_t brdev, device_t reqdev, struct mmc_request *req) 792239281Sgonzo{ 793239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(brdev); 794239281Sgonzo 795239281Sgonzo TI_MMCHS_LOCK(sc); 796239281Sgonzo 797239281Sgonzo /* 798239281Sgonzo * XXX do we want to be able to queue up multiple commands? 799239281Sgonzo * XXX sounds like a good idea, but all protocols are sync, so 800239281Sgonzo * XXX maybe the idea is naive... 801239281Sgonzo */ 802239281Sgonzo if (sc->req != NULL) { 803239281Sgonzo TI_MMCHS_UNLOCK(sc); 804239281Sgonzo return (EBUSY); 805239281Sgonzo } 806239281Sgonzo 807239281Sgonzo /* Store the request and start the command */ 808239281Sgonzo sc->req = req; 809239281Sgonzo sc->flags = 0; 810239281Sgonzo ti_mmchs_start(sc); 811239281Sgonzo 812239281Sgonzo TI_MMCHS_UNLOCK(sc); 813239281Sgonzo 814239281Sgonzo return (0); 815239281Sgonzo} 816239281Sgonzo 817239281Sgonzo/** 818239281Sgonzo * ti_mmchs_get_ro - returns the status of the read-only setting 819239281Sgonzo * @brdev: mmc bridge device handle 820239281Sgonzo * @reqdev: device doing the request 821239281Sgonzo * 822239281Sgonzo * This function is relies on hint'ed values to determine which GPIO is used 823239281Sgonzo * to determine if the write protect is enabled. On the BeagleBoard the pin 824239281Sgonzo * is GPIO_23. 825239281Sgonzo * 826239281Sgonzo * LOCKING: 827239281Sgonzo * - 828239281Sgonzo * 829239281Sgonzo * RETURNS: 830239281Sgonzo * 0 if not read-only 831239281Sgonzo * 1 if read only 832239281Sgonzo */ 833239281Sgonzostatic int 834239281Sgonzoti_mmchs_get_ro(device_t brdev, device_t reqdev) 835239281Sgonzo{ 836239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(brdev); 837239281Sgonzo unsigned int readonly = 0; 838239281Sgonzo 839239281Sgonzo TI_MMCHS_LOCK(sc); 840239281Sgonzo 841239281Sgonzo if ((sc->sc_wp_gpio_pin != -1) && (sc->sc_gpio_dev != NULL)) { 842239281Sgonzo if (GPIO_PIN_GET(sc->sc_gpio_dev, sc->sc_wp_gpio_pin, &readonly) != 0) 843239281Sgonzo readonly = 0; 844239281Sgonzo else 845239281Sgonzo readonly = (readonly == 0) ? 0 : 1; 846239281Sgonzo } 847239281Sgonzo 848239281Sgonzo TI_MMCHS_UNLOCK(sc); 849239281Sgonzo 850239281Sgonzo return (readonly); 851239281Sgonzo} 852239281Sgonzo 853239281Sgonzo/** 854239281Sgonzo * ti_mmchs_send_init_stream - sets bus/controller settings 855239281Sgonzo * @brdev: mmc bridge device handle 856239281Sgonzo * @reqdev: device doing the request 857239281Sgonzo * 858239281Sgonzo * Send init stream sequence to card before sending IDLE command 859239281Sgonzo * 860239281Sgonzo * LOCKING: 861239281Sgonzo * 862239281Sgonzo * 863239281Sgonzo * RETURNS: 864239281Sgonzo * 0 if function succeeded 865239281Sgonzo */ 866239281Sgonzostatic void 867239281Sgonzoti_mmchs_send_init_stream(struct ti_mmchs_softc *sc) 868239281Sgonzo{ 869239281Sgonzo unsigned long timeout; 870239281Sgonzo uint32_t ie, ise, con; 871239281Sgonzo 872239281Sgonzo ti_mmchs_dbg(sc, "Performing init sequence\n"); 873239281Sgonzo 874239281Sgonzo /* Prior to issuing any command, the MMCHS controller has to execute a 875239281Sgonzo * special INIT procedure. The MMCHS controller has to generate a clock 876239281Sgonzo * during 1ms. During the INIT procedure, the MMCHS controller generates 80 877239281Sgonzo * clock periods. In order to keep the 1ms gap, the MMCHS controller should 878239281Sgonzo * be configured to generate a clock whose frequency is smaller or equal to 879239281Sgonzo * 80 KHz. If the MMCHS controller divider bitfield width doesn't allow to 880239281Sgonzo * choose big values, the MMCHS controller driver should perform the INIT 881239281Sgonzo * procedure twice or three times. Twice is generally enough. 882239281Sgonzo * 883239281Sgonzo * The INIt procedure is executed by setting MMCHS1.MMCHS_CON[1] INIT 884239281Sgonzo * bitfield to 1 and by sending a dummy command, writing 0x00000000 in 885239281Sgonzo * MMCHS1.MMCHS_CMD register. 886239281Sgonzo */ 887239281Sgonzo 888239281Sgonzo /* Disable interrupt status events but enable interrupt generation. 889239281Sgonzo * This doesn't seem right to me, but if the interrupt generation is not 890239281Sgonzo * enabled the CC bit doesn't seem to be set in the STAT register. 891239281Sgonzo */ 892239281Sgonzo 893239281Sgonzo /* Enable interrupt generation */ 894239281Sgonzo ie = ti_mmchs_read_4(sc, MMCHS_IE); 895239281Sgonzo ti_mmchs_write_4(sc, MMCHS_IE, 0x307F0033); 896239281Sgonzo 897239281Sgonzo /* Disable generation of status events (stops interrupt triggering) */ 898239281Sgonzo ise = ti_mmchs_read_4(sc, MMCHS_ISE); 899239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ISE, 0); 900239281Sgonzo 901239281Sgonzo /* Set the initialise stream bit */ 902239281Sgonzo con = ti_mmchs_read_4(sc, MMCHS_CON); 903239281Sgonzo con |= MMCHS_CON_INIT; 904239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con); 905239281Sgonzo 906239281Sgonzo /* Write a dummy command 0x00 */ 907239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000); 908239281Sgonzo 909239281Sgonzo /* Loop waiting for the command to finish */ 910239281Sgonzo timeout = hz; 911239281Sgonzo do { 912239281Sgonzo pause("MMCINIT", 1); 913239281Sgonzo if (timeout-- == 0) { 914239281Sgonzo device_printf(sc->sc_dev, "Error: first stream init timed out\n"); 915239281Sgonzo break; 916239281Sgonzo } 917239281Sgonzo } while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC)); 918239281Sgonzo 919239281Sgonzo /* Clear the command complete status bit */ 920239281Sgonzo ti_mmchs_write_4(sc, MMCHS_STAT, MMCHS_STAT_CC); 921239281Sgonzo 922239281Sgonzo /* Write another dummy command 0x00 */ 923239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CMD, 0x00000000); 924239281Sgonzo 925239281Sgonzo /* Loop waiting for the second command to finish */ 926239281Sgonzo timeout = hz; 927239281Sgonzo do { 928239281Sgonzo pause("MMCINIT", 1); 929239281Sgonzo if (timeout-- == 0) { 930239281Sgonzo device_printf(sc->sc_dev, "Error: second stream init timed out\n"); 931239281Sgonzo break; 932239281Sgonzo } 933239281Sgonzo } while (!(ti_mmchs_read_4(sc, MMCHS_STAT) & MMCHS_STAT_CC)); 934239281Sgonzo 935239281Sgonzo /* Clear the stream init bit */ 936239281Sgonzo con &= ~MMCHS_CON_INIT; 937239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con); 938239281Sgonzo 939239281Sgonzo /* Clear the status register, then restore the IE and ISE registers */ 940239281Sgonzo ti_mmchs_write_4(sc, MMCHS_STAT, 0xffffffff); 941239281Sgonzo ti_mmchs_read_4(sc, MMCHS_STAT); 942239281Sgonzo 943239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ISE, ise); 944239281Sgonzo ti_mmchs_write_4(sc, MMCHS_IE, ie); 945239281Sgonzo} 946239281Sgonzo 947239281Sgonzo/** 948239281Sgonzo * ti_mmchs_update_ios - sets bus/controller settings 949239281Sgonzo * @brdev: mmc bridge device handle 950239281Sgonzo * @reqdev: device doing the request 951239281Sgonzo * 952239281Sgonzo * Called to set the bus and controller settings that need to be applied to 953239281Sgonzo * the actual HW. Currently this function just sets the bus width and the 954239281Sgonzo * clock speed. 955239281Sgonzo * 956239281Sgonzo * LOCKING: 957239281Sgonzo * 958239281Sgonzo * 959239281Sgonzo * RETURNS: 960239281Sgonzo * 0 if function succeeded 961239281Sgonzo */ 962239281Sgonzostatic int 963239281Sgonzoti_mmchs_update_ios(device_t brdev, device_t reqdev) 964239281Sgonzo{ 965239281Sgonzo struct ti_mmchs_softc *sc; 966239281Sgonzo struct mmc_host *host; 967239281Sgonzo struct mmc_ios *ios; 968239281Sgonzo uint32_t clkdiv; 969239281Sgonzo uint32_t hctl_reg; 970239281Sgonzo uint32_t con_reg; 971239281Sgonzo uint32_t sysctl_reg; 972239281Sgonzo#ifndef SOC_TI_AM335X 973239281Sgonzo uint16_t mv; 974239281Sgonzo#endif 975239281Sgonzo unsigned long timeout; 976239281Sgonzo int do_card_init = 0; 977239281Sgonzo 978239281Sgonzo sc = device_get_softc(brdev); 979239281Sgonzo host = &sc->host; 980239281Sgonzo ios = &host->ios; 981239281Sgonzo 982239281Sgonzo /* Read the initial values of the registers */ 983239281Sgonzo hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL); 984239281Sgonzo con_reg = ti_mmchs_read_4(sc, MMCHS_CON); 985239281Sgonzo 986239281Sgonzo /* Set the bus width */ 987239281Sgonzo switch (ios->bus_width) { 988239281Sgonzo case bus_width_1: 989239281Sgonzo hctl_reg &= ~MMCHS_HCTL_DTW; 990239281Sgonzo con_reg &= ~MMCHS_CON_DW8; 991239281Sgonzo break; 992239281Sgonzo case bus_width_4: 993239281Sgonzo hctl_reg |= MMCHS_HCTL_DTW; 994239281Sgonzo con_reg &= ~MMCHS_CON_DW8; 995239281Sgonzo break; 996239281Sgonzo case bus_width_8: 997239281Sgonzo con_reg |= MMCHS_CON_DW8; 998239281Sgonzo break; 999239281Sgonzo } 1000239281Sgonzo 1001239281Sgonzo /* Finally write all these settings back to the registers */ 1002239281Sgonzo ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg); 1003239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con_reg); 1004239281Sgonzo 1005239281Sgonzo /* Check if we need to change the external voltage regulator */ 1006239281Sgonzo if (sc->sc_cur_power_mode != ios->power_mode) { 1007239281Sgonzo 1008239281Sgonzo if (ios->power_mode == power_up) { 1009239281Sgonzo 1010239281Sgonzo /* Set the power level */ 1011239281Sgonzo hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL); 1012239281Sgonzo hctl_reg &= ~(MMCHS_HCTL_SDVS_MASK | MMCHS_HCTL_SDBP); 1013239281Sgonzo 1014239281Sgonzo if ((ios->vdd == -1) || (ios->vdd >= vdd_240)) { 1015239281Sgonzo#ifndef SOC_TI_AM335X 1016239281Sgonzo mv = 3000; 1017239281Sgonzo#endif 1018239281Sgonzo hctl_reg |= MMCHS_HCTL_SDVS_V30; 1019239281Sgonzo } else { 1020239281Sgonzo#ifndef SOC_TI_AM335X 1021239281Sgonzo mv = 1800; 1022239281Sgonzo#endif 1023239281Sgonzo hctl_reg |= MMCHS_HCTL_SDVS_V18; 1024239281Sgonzo } 1025239281Sgonzo 1026239281Sgonzo ti_mmchs_write_4(sc, MMCHS_HCTL, hctl_reg); 1027239281Sgonzo 1028239281Sgonzo#ifdef SOC_TI_AM335X 1029239281Sgonzo printf("%s: TWL unimplemented\n", __func__); 1030239281Sgonzo#else 1031239281Sgonzo /* Set the desired voltage on the regulator */ 1032239281Sgonzo if (sc->sc_vreg_dev && sc->sc_vreg_name) 1033239281Sgonzo twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, mv); 1034239281Sgonzo#endif 1035239281Sgonzo /* Enable the bus power */ 1036239281Sgonzo ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg | MMCHS_HCTL_SDBP)); 1037239281Sgonzo timeout = hz; 1038239281Sgonzo while (!(ti_mmchs_read_4(sc, MMCHS_HCTL) & MMCHS_HCTL_SDBP)) { 1039239281Sgonzo if (timeout-- == 0) 1040239281Sgonzo break; 1041239281Sgonzo pause("MMC_PWRON", 1); 1042239281Sgonzo } 1043239281Sgonzo 1044239281Sgonzo } else if (ios->power_mode == power_off) { 1045239281Sgonzo /* Disable the bus power */ 1046239281Sgonzo hctl_reg = ti_mmchs_read_4(sc, MMCHS_HCTL); 1047239281Sgonzo ti_mmchs_write_4(sc, MMCHS_HCTL, (hctl_reg & ~MMCHS_HCTL_SDBP)); 1048239281Sgonzo 1049239281Sgonzo#ifdef SOC_TI_AM335X 1050239281Sgonzo printf("%s: TWL unimplemented\n", __func__); 1051239281Sgonzo#else 1052239281Sgonzo /* Turn the power off on the voltage regulator */ 1053239281Sgonzo if (sc->sc_vreg_dev && sc->sc_vreg_name) 1054239281Sgonzo twl_vreg_set_voltage(sc->sc_vreg_dev, sc->sc_vreg_name, 0); 1055239281Sgonzo#endif 1056239281Sgonzo } else if (ios->power_mode == power_on) { 1057239281Sgonzo /* Force a card re-initialisation sequence */ 1058239281Sgonzo do_card_init = 1; 1059239281Sgonzo } 1060239281Sgonzo 1061239281Sgonzo /* Save the new power state */ 1062239281Sgonzo sc->sc_cur_power_mode = ios->power_mode; 1063239281Sgonzo } 1064239281Sgonzo 1065239281Sgonzo /* need the MMCHS_SYSCTL register */ 1066239281Sgonzo sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL); 1067239281Sgonzo 1068239281Sgonzo /* Just in case this hasn't been setup before, set the timeout to the default */ 1069239281Sgonzo sysctl_reg &= ~MMCHS_SYSCTL_DTO_MASK; 1070239281Sgonzo sysctl_reg |= MMCHS_SYSCTL_DTO(0xe); 1071239281Sgonzo 1072239281Sgonzo /* Disable the clock output while configuring the new clock */ 1073239281Sgonzo sysctl_reg &= ~(MMCHS_SYSCTL_ICE | MMCHS_SYSCTL_CEN); 1074239281Sgonzo ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg); 1075239281Sgonzo 1076239281Sgonzo /* bus mode? */ 1077239281Sgonzo if (ios->clock == 0) { 1078239281Sgonzo clkdiv = 0; 1079239281Sgonzo } else { 1080239281Sgonzo clkdiv = sc->sc_ref_freq / ios->clock; 1081239281Sgonzo if (clkdiv < 1) 1082239281Sgonzo clkdiv = 1; 1083239281Sgonzo if ((sc->sc_ref_freq / clkdiv) > ios->clock) 1084239281Sgonzo clkdiv += 1; 1085239281Sgonzo if (clkdiv > 250) 1086239281Sgonzo clkdiv = 250; 1087239281Sgonzo } 1088239281Sgonzo 1089239281Sgonzo /* Set the new clock divider */ 1090239281Sgonzo sysctl_reg &= ~MMCHS_SYSCTL_CLKD_MASK; 1091239281Sgonzo sysctl_reg |= MMCHS_SYSCTL_CLKD(clkdiv); 1092239281Sgonzo 1093239281Sgonzo /* Write the new settings ... */ 1094239281Sgonzo ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg); 1095239281Sgonzo /* ... write the internal clock enable bit ... */ 1096239281Sgonzo ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg | MMCHS_SYSCTL_ICE); 1097239281Sgonzo /* ... wait for the clock to stablise ... */ 1098239281Sgonzo while (((sysctl_reg = ti_mmchs_read_4(sc, MMCHS_SYSCTL)) & 1099239281Sgonzo MMCHS_SYSCTL_ICS) == 0) { 1100239281Sgonzo continue; 1101239281Sgonzo } 1102239281Sgonzo /* ... then enable */ 1103239281Sgonzo sysctl_reg |= MMCHS_SYSCTL_CEN; 1104239281Sgonzo ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl_reg); 1105239281Sgonzo 1106239281Sgonzo /* If the power state has changed to 'power_on' then run the init sequence*/ 1107239281Sgonzo if (do_card_init) { 1108239281Sgonzo ti_mmchs_send_init_stream(sc); 1109239281Sgonzo } 1110239281Sgonzo 1111239281Sgonzo /* Set the bus mode (opendrain or normal) */ 1112239281Sgonzo con_reg = ti_mmchs_read_4(sc, MMCHS_CON); 1113239281Sgonzo if (ios->bus_mode == opendrain) 1114239281Sgonzo con_reg |= MMCHS_CON_OD; 1115239281Sgonzo else 1116239281Sgonzo con_reg &= ~MMCHS_CON_OD; 1117239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con_reg); 1118239281Sgonzo 1119239281Sgonzo return (0); 1120239281Sgonzo} 1121239281Sgonzo 1122239281Sgonzo/** 1123239281Sgonzo * ti_mmchs_acquire_host - 1124239281Sgonzo * @brdev: mmc bridge device handle 1125239281Sgonzo * @reqdev: device doing the request 1126239281Sgonzo * 1127239281Sgonzo * TODO: Is this function needed ? 1128239281Sgonzo * 1129239281Sgonzo * LOCKING: 1130239281Sgonzo * none 1131239281Sgonzo * 1132239281Sgonzo * RETURNS: 1133239281Sgonzo * 0 function succeeded 1134239281Sgonzo * 1135239281Sgonzo */ 1136239281Sgonzostatic int 1137239281Sgonzoti_mmchs_acquire_host(device_t brdev, device_t reqdev) 1138239281Sgonzo{ 1139239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(brdev); 1140239281Sgonzo int err = 0; 1141239281Sgonzo 1142239281Sgonzo TI_MMCHS_LOCK(sc); 1143239281Sgonzo 1144239281Sgonzo while (sc->bus_busy) { 1145239281Sgonzo msleep(sc, &sc->sc_mtx, PZERO, "mmc", hz / 5); 1146239281Sgonzo } 1147239281Sgonzo 1148239281Sgonzo sc->bus_busy++; 1149239281Sgonzo 1150239281Sgonzo TI_MMCHS_UNLOCK(sc); 1151239281Sgonzo 1152239281Sgonzo return (err); 1153239281Sgonzo} 1154239281Sgonzo 1155239281Sgonzo/** 1156239281Sgonzo * ti_mmchs_release_host - 1157239281Sgonzo * @brdev: mmc bridge device handle 1158239281Sgonzo * @reqdev: device doing the request 1159239281Sgonzo * 1160239281Sgonzo * TODO: Is this function needed ? 1161239281Sgonzo * 1162239281Sgonzo * LOCKING: 1163239281Sgonzo * none 1164239281Sgonzo * 1165239281Sgonzo * RETURNS: 1166239281Sgonzo * 0 function succeeded 1167239281Sgonzo * 1168239281Sgonzo */ 1169239281Sgonzostatic int 1170239281Sgonzoti_mmchs_release_host(device_t brdev, device_t reqdev) 1171239281Sgonzo{ 1172239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(brdev); 1173239281Sgonzo 1174239281Sgonzo TI_MMCHS_LOCK(sc); 1175239281Sgonzo 1176239281Sgonzo sc->bus_busy--; 1177239281Sgonzo wakeup(sc); 1178239281Sgonzo 1179239281Sgonzo TI_MMCHS_UNLOCK(sc); 1180239281Sgonzo 1181239281Sgonzo return (0); 1182239281Sgonzo} 1183239281Sgonzo 1184239281Sgonzo/** 1185239281Sgonzo * ti_mmchs_read_ivar - returns driver conf variables 1186239281Sgonzo * @bus: 1187239281Sgonzo * @child: 1188239281Sgonzo * @which: The variable to get the result for 1189239281Sgonzo * @result: Upon return will store the variable value 1190239281Sgonzo * 1191239281Sgonzo * 1192239281Sgonzo * 1193239281Sgonzo * LOCKING: 1194239281Sgonzo * None, caller must hold locks 1195239281Sgonzo * 1196239281Sgonzo * RETURNS: 1197239281Sgonzo * 0 on success 1198239281Sgonzo * EINVAL if the variable requested is invalid 1199239281Sgonzo */ 1200239281Sgonzostatic int 1201239281Sgonzoti_mmchs_read_ivar(device_t bus, device_t child, int which, uintptr_t *result) 1202239281Sgonzo{ 1203239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(bus); 1204239281Sgonzo 1205239281Sgonzo switch (which) { 1206239281Sgonzo case MMCBR_IVAR_BUS_MODE: 1207239281Sgonzo *(int *)result = sc->host.ios.bus_mode; 1208239281Sgonzo break; 1209239281Sgonzo case MMCBR_IVAR_BUS_WIDTH: 1210239281Sgonzo *(int *)result = sc->host.ios.bus_width; 1211239281Sgonzo break; 1212239281Sgonzo case MMCBR_IVAR_CHIP_SELECT: 1213239281Sgonzo *(int *)result = sc->host.ios.chip_select; 1214239281Sgonzo break; 1215239281Sgonzo case MMCBR_IVAR_CLOCK: 1216239281Sgonzo *(int *)result = sc->host.ios.clock; 1217239281Sgonzo break; 1218239281Sgonzo case MMCBR_IVAR_F_MIN: 1219239281Sgonzo *(int *)result = sc->host.f_min; 1220239281Sgonzo break; 1221239281Sgonzo case MMCBR_IVAR_F_MAX: 1222239281Sgonzo *(int *)result = sc->host.f_max; 1223239281Sgonzo break; 1224239281Sgonzo case MMCBR_IVAR_HOST_OCR: 1225239281Sgonzo *(int *)result = sc->host.host_ocr; 1226239281Sgonzo break; 1227239281Sgonzo case MMCBR_IVAR_MODE: 1228239281Sgonzo *(int *)result = sc->host.mode; 1229239281Sgonzo break; 1230239281Sgonzo case MMCBR_IVAR_OCR: 1231239281Sgonzo *(int *)result = sc->host.ocr; 1232239281Sgonzo break; 1233239281Sgonzo case MMCBR_IVAR_POWER_MODE: 1234239281Sgonzo *(int *)result = sc->host.ios.power_mode; 1235239281Sgonzo break; 1236239281Sgonzo case MMCBR_IVAR_VDD: 1237239281Sgonzo *(int *)result = sc->host.ios.vdd; 1238239281Sgonzo break; 1239239281Sgonzo case MMCBR_IVAR_CAPS: 1240239281Sgonzo *(int *)result = sc->host.caps; 1241239281Sgonzo break; 1242239281Sgonzo case MMCBR_IVAR_MAX_DATA: 1243239281Sgonzo *(int *)result = 1; 1244239281Sgonzo break; 1245239281Sgonzo default: 1246239281Sgonzo return (EINVAL); 1247239281Sgonzo } 1248239281Sgonzo return (0); 1249239281Sgonzo} 1250239281Sgonzo 1251239281Sgonzo/** 1252239281Sgonzo * ti_mmchs_write_ivar - writes a driver conf variables 1253239281Sgonzo * @bus: 1254239281Sgonzo * @child: 1255239281Sgonzo * @which: The variable to set 1256239281Sgonzo * @value: The value to write into the variable 1257239281Sgonzo * 1258239281Sgonzo * 1259239281Sgonzo * 1260239281Sgonzo * LOCKING: 1261239281Sgonzo * None, caller must hold locks 1262239281Sgonzo * 1263239281Sgonzo * RETURNS: 1264239281Sgonzo * 0 on success 1265239281Sgonzo * EINVAL if the variable requested is invalid 1266239281Sgonzo */ 1267239281Sgonzostatic int 1268239281Sgonzoti_mmchs_write_ivar(device_t bus, device_t child, int which, uintptr_t value) 1269239281Sgonzo{ 1270239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(bus); 1271239281Sgonzo 1272239281Sgonzo switch (which) { 1273239281Sgonzo case MMCBR_IVAR_BUS_MODE: 1274239281Sgonzo sc->host.ios.bus_mode = value; 1275239281Sgonzo break; 1276239281Sgonzo case MMCBR_IVAR_BUS_WIDTH: 1277239281Sgonzo sc->host.ios.bus_width = value; 1278239281Sgonzo break; 1279239281Sgonzo case MMCBR_IVAR_CHIP_SELECT: 1280239281Sgonzo sc->host.ios.chip_select = value; 1281239281Sgonzo break; 1282239281Sgonzo case MMCBR_IVAR_CLOCK: 1283239281Sgonzo sc->host.ios.clock = value; 1284239281Sgonzo break; 1285239281Sgonzo case MMCBR_IVAR_MODE: 1286239281Sgonzo sc->host.mode = value; 1287239281Sgonzo break; 1288239281Sgonzo case MMCBR_IVAR_OCR: 1289239281Sgonzo sc->host.ocr = value; 1290239281Sgonzo break; 1291239281Sgonzo case MMCBR_IVAR_POWER_MODE: 1292239281Sgonzo sc->host.ios.power_mode = value; 1293239281Sgonzo break; 1294239281Sgonzo case MMCBR_IVAR_VDD: 1295239281Sgonzo sc->host.ios.vdd = value; 1296239281Sgonzo break; 1297239281Sgonzo /* These are read-only */ 1298239281Sgonzo case MMCBR_IVAR_CAPS: 1299239281Sgonzo case MMCBR_IVAR_HOST_OCR: 1300239281Sgonzo case MMCBR_IVAR_F_MIN: 1301239281Sgonzo case MMCBR_IVAR_F_MAX: 1302239281Sgonzo case MMCBR_IVAR_MAX_DATA: 1303239281Sgonzo return (EINVAL); 1304239281Sgonzo default: 1305239281Sgonzo return (EINVAL); 1306239281Sgonzo } 1307239281Sgonzo return (0); 1308239281Sgonzo} 1309239281Sgonzo 1310239281Sgonzo/** 1311239281Sgonzo * ti_mmchs_hw_init - initialises the MMC/SD/SIO controller 1312239281Sgonzo * @dev: mmc device handle 1313239281Sgonzo * 1314239281Sgonzo * Called by the driver attach function during driver initialisation. This 1315239281Sgonzo * function is responsibly to setup the controller ready for transactions. 1316239281Sgonzo * 1317239281Sgonzo * LOCKING: 1318239281Sgonzo * No locking, assumed to only be called during initialisation. 1319239281Sgonzo * 1320239281Sgonzo * RETURNS: 1321239281Sgonzo * nothing 1322239281Sgonzo */ 1323239281Sgonzostatic void 1324239281Sgonzoti_mmchs_hw_init(device_t dev) 1325239281Sgonzo{ 1326239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(dev); 1327239281Sgonzo clk_ident_t clk; 1328239281Sgonzo unsigned long timeout; 1329239281Sgonzo uint32_t sysctl; 1330239281Sgonzo uint32_t capa; 1331252863Srpaulo uint32_t con, sysconfig; 1332239281Sgonzo 1333239281Sgonzo /* 1: Enable the controller and interface/functional clocks */ 1334239281Sgonzo clk = MMC0_CLK + sc->device_id; 1335239281Sgonzo 1336239281Sgonzo if (ti_prcm_clk_enable(clk) != 0) { 1337239281Sgonzo device_printf(dev, "Error: failed to enable MMC clock\n"); 1338239281Sgonzo return; 1339239281Sgonzo } 1340239281Sgonzo 1341239281Sgonzo /* 1a: Get the frequency of the source clock */ 1342239281Sgonzo if (ti_prcm_clk_get_source_freq(clk, &sc->sc_ref_freq) != 0) { 1343239281Sgonzo device_printf(dev, "Error: failed to get source clock freq\n"); 1344239281Sgonzo return; 1345239281Sgonzo } 1346239281Sgonzo 1347239281Sgonzo /* 2: Issue a softreset to the controller */ 1348252863Srpaulo sysconfig = ti_mmchs_read_4(sc, MMCHS_SYSCONFIG); 1349252863Srpaulo sysconfig |= MMCHS_SYSCONFIG_SRST; 1350252863Srpaulo ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, sysconfig); 1351239281Sgonzo timeout = 100; 1352239281Sgonzo while ((ti_mmchs_read_4(sc, MMCHS_SYSSTATUS) & 0x01) == 0x0) { 1353239281Sgonzo DELAY(1000); 1354239281Sgonzo if (timeout-- == 0) { 1355239281Sgonzo device_printf(dev, "Error: reset operation timed out\n"); 1356239281Sgonzo return; 1357239281Sgonzo } 1358239281Sgonzo } 1359239281Sgonzo 1360239281Sgonzo /* 3: Reset both the command and data state machines */ 1361239281Sgonzo sysctl = ti_mmchs_read_4(sc, MMCHS_SYSCTL); 1362239281Sgonzo ti_mmchs_write_4(sc, MMCHS_SYSCTL, sysctl | MMCHS_SYSCTL_SRA); 1363239281Sgonzo timeout = 100; 1364239281Sgonzo while ((ti_mmchs_read_4(sc, MMCHS_SYSCTL) & MMCHS_SYSCTL_SRA) != 0x0) { 1365239281Sgonzo DELAY(1000); 1366239281Sgonzo if (timeout-- == 0) { 1367239281Sgonzo device_printf(dev, "Error: reset operation timed out\n"); 1368239281Sgonzo return; 1369239281Sgonzo } 1370239281Sgonzo } 1371239281Sgonzo 1372239281Sgonzo /* 4: Set initial host configuration (1-bit mode, pwroff) and capabilities */ 1373239281Sgonzo ti_mmchs_write_4(sc, MMCHS_HCTL, MMCHS_HCTL_SDVS_V30); 1374239281Sgonzo 1375239281Sgonzo capa = ti_mmchs_read_4(sc, MMCHS_CAPA); 1376239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CAPA, capa | MMCHS_CAPA_VS30 | MMCHS_CAPA_VS18); 1377239281Sgonzo 1378239281Sgonzo /* 5: Set the initial bus configuration 1379239281Sgonzo * 0 CTPL_MMC_SD : Control Power for DAT1 line 1380239281Sgonzo * 0 WPP_ACTIVE_HIGH : Write protect polarity 1381239281Sgonzo * 0 CDP_ACTIVE_HIGH : Card detect polarity 1382239281Sgonzo * 0 CTO_ENABLED : MMC interrupt command 1383239281Sgonzo * 0 DW8_DISABLED : 8-bit mode MMC select 1384239281Sgonzo * 0 MODE_FUNC : Mode select 1385239281Sgonzo * 0 STREAM_DISABLED : Stream command 1386239281Sgonzo * 0 HR_DISABLED : Broadcast host response 1387239281Sgonzo * 0 INIT_DISABLED : Send initialization stream 1388239281Sgonzo * 0 OD_DISABLED : No Open Drain 1389239281Sgonzo */ 1390239281Sgonzo con = ti_mmchs_read_4(sc, MMCHS_CON) & MMCHS_CON_DVAL_MASK; 1391239281Sgonzo ti_mmchs_write_4(sc, MMCHS_CON, con); 1392239281Sgonzo 1393239281Sgonzo} 1394239281Sgonzo 1395239281Sgonzo/** 1396239281Sgonzo * ti_mmchs_fini - shutdown the MMC/SD/SIO controller 1397239281Sgonzo * @dev: mmc device handle 1398239281Sgonzo * 1399239281Sgonzo * Responsible for shutting done the MMC controller, this function may be 1400239281Sgonzo * called as part of a reset sequence. 1401239281Sgonzo * 1402239281Sgonzo * LOCKING: 1403239281Sgonzo * No locking, assumed to be called during tear-down/reset. 1404239281Sgonzo * 1405239281Sgonzo * RETURNS: 1406239281Sgonzo * nothing 1407239281Sgonzo */ 1408239281Sgonzostatic void 1409239281Sgonzoti_mmchs_hw_fini(device_t dev) 1410239281Sgonzo{ 1411239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(dev); 1412239281Sgonzo 1413239281Sgonzo /* Disable all interrupts */ 1414239281Sgonzo ti_mmchs_write_4(sc, MMCHS_ISE, 0x00000000); 1415239281Sgonzo ti_mmchs_write_4(sc, MMCHS_IE, 0x00000000); 1416239281Sgonzo 1417239281Sgonzo /* Disable the functional and interface clocks */ 1418239281Sgonzo ti_prcm_clk_disable(MMC0_CLK + sc->device_id); 1419239281Sgonzo} 1420239281Sgonzo 1421239281Sgonzo/** 1422239281Sgonzo * ti_mmchs_init_dma_channels - initalise the DMA channels 1423239281Sgonzo * @sc: driver soft context 1424239281Sgonzo * 1425239281Sgonzo * Attempts to activate an RX and TX DMA channel for the MMC device. 1426239281Sgonzo * 1427239281Sgonzo * LOCKING: 1428239281Sgonzo * No locking, assumed to be called during tear-down/reset. 1429239281Sgonzo * 1430239281Sgonzo * RETURNS: 1431239281Sgonzo * 0 on success, a negative error code on failure. 1432239281Sgonzo */ 1433239281Sgonzostatic int 1434239281Sgonzoti_mmchs_init_dma_channels(struct ti_mmchs_softc *sc) 1435239281Sgonzo{ 1436239281Sgonzo#ifdef SOC_TI_AM335X 1437239281Sgonzo switch (sc->device_id) { 1438239281Sgonzo case 0: 1439239281Sgonzo sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT0; 1440239281Sgonzo sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT0; 1441239281Sgonzo break; 1442239281Sgonzo case 1: 1443239281Sgonzo sc->dma_tx_trig = TI_EDMA3_EVENT_SDTXEVT1; 1444239281Sgonzo sc->dma_rx_trig = TI_EDMA3_EVENT_SDRXEVT1; 1445239281Sgonzo break; 1446239281Sgonzo default: 1447239281Sgonzo return(EINVAL); 1448239281Sgonzo } 1449239281Sgonzo 1450239281Sgonzo#define EVTQNUM 0 1451239281Sgonzo /* TODO EDMA3 have 3 queues, so we need some queue allocation call */ 1452239281Sgonzo ti_edma3_init(EVTQNUM); 1453239281Sgonzo ti_edma3_request_dma_ch(sc->dma_tx_trig, sc->dma_tx_trig, EVTQNUM); 1454239281Sgonzo ti_edma3_request_dma_ch(sc->dma_rx_trig, sc->dma_rx_trig, EVTQNUM); 1455239281Sgonzo#else 1456239281Sgonzo int err; 1457239281Sgonzo uint32_t rev; 1458239281Sgonzo 1459239281Sgonzo /* Get the current chip revision */ 1460239281Sgonzo rev = ti_revision(); 1461239281Sgonzo if ((OMAP_REV_DEVICE(rev) != OMAP4430_DEV) && (sc->device_id > 3)) 1462239281Sgonzo return(EINVAL); 1463239281Sgonzo 1464239281Sgonzo /* Get the DMA MMC triggers */ 1465239281Sgonzo switch (sc->device_id) { 1466239281Sgonzo case 1: 1467239281Sgonzo sc->dma_tx_trig = 60; 1468239281Sgonzo sc->dma_rx_trig = 61; 1469239281Sgonzo break; 1470239281Sgonzo case 2: 1471239281Sgonzo sc->dma_tx_trig = 46; 1472239281Sgonzo sc->dma_rx_trig = 47; 1473239281Sgonzo break; 1474239281Sgonzo case 3: 1475239281Sgonzo sc->dma_tx_trig = 76; 1476239281Sgonzo sc->dma_rx_trig = 77; 1477239281Sgonzo break; 1478239281Sgonzo /* The following are OMAP4 only */ 1479239281Sgonzo case 4: 1480239281Sgonzo sc->dma_tx_trig = 56; 1481239281Sgonzo sc->dma_rx_trig = 57; 1482239281Sgonzo break; 1483239281Sgonzo case 5: 1484239281Sgonzo sc->dma_tx_trig = 58; 1485239281Sgonzo sc->dma_rx_trig = 59; 1486239281Sgonzo break; 1487239281Sgonzo default: 1488239281Sgonzo return(EINVAL); 1489239281Sgonzo } 1490239281Sgonzo 1491239281Sgonzo /* Activate a RX channel from the OMAP DMA driver */ 1492239281Sgonzo err = ti_sdma_activate_channel(&sc->sc_dmach_rd, ti_mmchs_dma_intr, sc); 1493239281Sgonzo if (err != 0) 1494239281Sgonzo return(err); 1495239281Sgonzo 1496239281Sgonzo /* Setup the RX channel for MMC data transfers */ 1497239281Sgonzo ti_sdma_set_xfer_burst(sc->sc_dmach_rd, TI_SDMA_BURST_NONE, 1498239281Sgonzo TI_SDMA_BURST_64); 1499239281Sgonzo ti_sdma_set_xfer_data_type(sc->sc_dmach_rd, TI_SDMA_DATA_32BITS_SCALAR); 1500239281Sgonzo ti_sdma_sync_params(sc->sc_dmach_rd, sc->dma_rx_trig, 1501239281Sgonzo TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_SRC); 1502239281Sgonzo ti_sdma_set_addr_mode(sc->sc_dmach_rd, TI_SDMA_ADDR_CONSTANT, 1503239281Sgonzo TI_SDMA_ADDR_POST_INCREMENT); 1504239281Sgonzo 1505239281Sgonzo /* Activate and configure the TX DMA channel */ 1506239281Sgonzo err = ti_sdma_activate_channel(&sc->sc_dmach_wr, ti_mmchs_dma_intr, sc); 1507239281Sgonzo if (err != 0) 1508239281Sgonzo return(err); 1509239281Sgonzo 1510239281Sgonzo /* Setup the TX channel for MMC data transfers */ 1511239281Sgonzo ti_sdma_set_xfer_burst(sc->sc_dmach_wr, TI_SDMA_BURST_64, 1512239281Sgonzo TI_SDMA_BURST_NONE); 1513239281Sgonzo ti_sdma_set_xfer_data_type(sc->sc_dmach_wr, TI_SDMA_DATA_32BITS_SCALAR); 1514239281Sgonzo ti_sdma_sync_params(sc->sc_dmach_wr, sc->dma_tx_trig, 1515239281Sgonzo TI_SDMA_SYNC_PACKET | TI_SDMA_SYNC_TRIG_ON_DST); 1516239281Sgonzo ti_sdma_set_addr_mode(sc->sc_dmach_wr, TI_SDMA_ADDR_POST_INCREMENT, 1517239281Sgonzo TI_SDMA_ADDR_CONSTANT); 1518239281Sgonzo#endif 1519239281Sgonzo return(0); 1520239281Sgonzo} 1521239281Sgonzo 1522239281Sgonzo/** 1523239281Sgonzo * ti_mmchs_deactivate - deactivates the driver 1524239281Sgonzo * @dev: mmc device handle 1525239281Sgonzo * 1526239281Sgonzo * Unmaps the register set and releases the IRQ resource. 1527239281Sgonzo * 1528239281Sgonzo * LOCKING: 1529239281Sgonzo * None required 1530239281Sgonzo * 1531239281Sgonzo * RETURNS: 1532239281Sgonzo * nothing 1533239281Sgonzo */ 1534239281Sgonzostatic void 1535239281Sgonzoti_mmchs_deactivate(device_t dev) 1536239281Sgonzo{ 1537239281Sgonzo struct ti_mmchs_softc *sc= device_get_softc(dev); 1538239281Sgonzo 1539239281Sgonzo /* Remove the IRQ handler */ 1540239281Sgonzo if (sc->sc_irq_h != NULL) { 1541239281Sgonzo bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_irq_h); 1542239281Sgonzo sc->sc_irq_h = NULL; 1543239281Sgonzo } 1544239281Sgonzo 1545239281Sgonzo /* Do the generic detach */ 1546239281Sgonzo bus_generic_detach(sc->sc_dev); 1547239281Sgonzo 1548239281Sgonzo#ifdef SOC_TI_AM335X 1549239281Sgonzo printf("%s: DMA unimplemented\n", __func__); 1550239281Sgonzo#else 1551239281Sgonzo /* Deactivate the DMA channels */ 1552239281Sgonzo ti_sdma_deactivate_channel(sc->sc_dmach_rd); 1553239281Sgonzo ti_sdma_deactivate_channel(sc->sc_dmach_wr); 1554239281Sgonzo#endif 1555239281Sgonzo 1556239281Sgonzo /* Unmap the MMC controller registers */ 1557239281Sgonzo if (sc->sc_mem_res != 0) { 1558239281Sgonzo bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->sc_irq_res), 1559239281Sgonzo sc->sc_mem_res); 1560239281Sgonzo sc->sc_mem_res = NULL; 1561239281Sgonzo } 1562239281Sgonzo 1563239281Sgonzo /* Release the IRQ resource */ 1564239281Sgonzo if (sc->sc_irq_res != NULL) { 1565239281Sgonzo bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->sc_irq_res), 1566239281Sgonzo sc->sc_irq_res); 1567239281Sgonzo sc->sc_irq_res = NULL; 1568239281Sgonzo } 1569239281Sgonzo 1570239281Sgonzo return; 1571239281Sgonzo} 1572239281Sgonzo 1573239281Sgonzo/** 1574239281Sgonzo * ti_mmchs_activate - activates the driver 1575239281Sgonzo * @dev: mmc device handle 1576239281Sgonzo * 1577239281Sgonzo * Maps in the register set and requests an IRQ handler for the MMC controller. 1578239281Sgonzo * 1579239281Sgonzo * LOCKING: 1580239281Sgonzo * None required 1581239281Sgonzo * 1582239281Sgonzo * RETURNS: 1583239281Sgonzo * 0 on sucess 1584239281Sgonzo * ENOMEM if failed to map register set 1585239281Sgonzo */ 1586239281Sgonzostatic int 1587239281Sgonzoti_mmchs_activate(device_t dev) 1588239281Sgonzo{ 1589239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(dev); 1590239281Sgonzo int rid; 1591239281Sgonzo int err; 1592239281Sgonzo 1593239281Sgonzo /* Get the memory resource for the register mapping */ 1594239281Sgonzo rid = 0; 1595239281Sgonzo sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 1596239281Sgonzo RF_ACTIVE); 1597239281Sgonzo if (sc->sc_mem_res == NULL) 1598239281Sgonzo panic("%s: Cannot map registers", device_get_name(dev)); 1599239281Sgonzo 1600239281Sgonzo /* Allocate an IRQ resource for the MMC controller */ 1601239281Sgonzo rid = 0; 1602239281Sgonzo sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1603239281Sgonzo RF_ACTIVE | RF_SHAREABLE); 1604239281Sgonzo if (sc->sc_irq_res == NULL) 1605239281Sgonzo goto errout; 1606239281Sgonzo 1607239281Sgonzo /* Allocate DMA tags and maps */ 1608239281Sgonzo err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, 1609239281Sgonzo BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, 1610239281Sgonzo NULL, MAXPHYS, 1, MAXPHYS, BUS_DMA_ALLOCNOW, NULL, 1611239281Sgonzo NULL, &sc->sc_dmatag); 1612239281Sgonzo if (err != 0) 1613239281Sgonzo goto errout; 1614239281Sgonzo 1615239281Sgonzo err = bus_dmamap_create(sc->sc_dmatag, 0, &sc->sc_dmamap); 1616239281Sgonzo if (err != 0) 1617239281Sgonzo goto errout; 1618239281Sgonzo 1619239281Sgonzo /* Initialise the DMA channels to be used by the controller */ 1620239281Sgonzo err = ti_mmchs_init_dma_channels(sc); 1621239281Sgonzo if (err != 0) 1622239281Sgonzo goto errout; 1623239281Sgonzo 1624239281Sgonzo /* Set the register offset */ 1625239281Sgonzo if (ti_chip() == CHIP_OMAP_3) 1626239281Sgonzo sc->sc_reg_off = OMAP3_MMCHS_REG_OFFSET; 1627239281Sgonzo else if (ti_chip() == CHIP_OMAP_4) 1628239281Sgonzo sc->sc_reg_off = OMAP4_MMCHS_REG_OFFSET; 1629239281Sgonzo else if (ti_chip() == CHIP_AM335X) 1630239281Sgonzo sc->sc_reg_off = AM335X_MMCHS_REG_OFFSET; 1631239281Sgonzo else 1632239281Sgonzo panic("Unknown OMAP device\n"); 1633239281Sgonzo 1634239281Sgonzo /* Get the physical address of the MMC data register, needed for DMA */ 1635248407Sian sc->sc_data_reg_paddr = BUS_SPACE_PHYSADDR(sc->sc_mem_res, 1636248407Sian sc->sc_reg_off + MMCHS_DATA); 1637239281Sgonzo 1638239281Sgonzo /* Set the initial power state to off */ 1639239281Sgonzo sc->sc_cur_power_mode = power_off; 1640239281Sgonzo 1641239281Sgonzo return (0); 1642239281Sgonzo 1643239281Sgonzoerrout: 1644239281Sgonzo ti_mmchs_deactivate(dev); 1645239281Sgonzo return (ENOMEM); 1646239281Sgonzo} 1647239281Sgonzo 1648239281Sgonzo/** 1649239281Sgonzo * ti_mmchs_probe - probe function for the driver 1650239281Sgonzo * @dev: mmc device handle 1651239281Sgonzo * 1652239281Sgonzo * 1653239281Sgonzo * 1654239281Sgonzo * RETURNS: 1655239281Sgonzo * always returns 0 1656239281Sgonzo */ 1657239281Sgonzostatic int 1658239281Sgonzoti_mmchs_probe(device_t dev) 1659239281Sgonzo{ 1660239281Sgonzo if (!ofw_bus_is_compatible(dev, "ti,mmchs")) 1661239281Sgonzo return (ENXIO); 1662239281Sgonzo 1663239281Sgonzo device_set_desc(dev, "TI MMC/SD/SDIO High Speed Interface"); 1664239281Sgonzo return (0); 1665239281Sgonzo} 1666239281Sgonzo 1667239281Sgonzo/** 1668239281Sgonzo * ti_mmchs_attach - attach function for the driver 1669239281Sgonzo * @dev: mmc device handle 1670239281Sgonzo * 1671239281Sgonzo * Driver initialisation, sets-up the bus mappings, DMA mapping/channels and 1672239281Sgonzo * the actual controller by calling ti_mmchs_init(). 1673239281Sgonzo * 1674239281Sgonzo * RETURNS: 1675239281Sgonzo * Returns 0 on success or a negative error code. 1676239281Sgonzo */ 1677239281Sgonzostatic int 1678239281Sgonzoti_mmchs_attach(device_t dev) 1679239281Sgonzo{ 1680239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(dev); 1681239281Sgonzo int unit = device_get_unit(dev); 1682239281Sgonzo phandle_t node; 1683239281Sgonzo pcell_t did; 1684239281Sgonzo int err; 1685239281Sgonzo 1686239281Sgonzo /* Save the device and bus tag */ 1687239281Sgonzo sc->sc_dev = dev; 1688239281Sgonzo 1689239281Sgonzo /* Get the mmchs device id from FDT */ 1690239281Sgonzo node = ofw_bus_get_node(dev); 1691239281Sgonzo if ((OF_getprop(node, "mmchs-device-id", &did, sizeof(did))) <= 0) { 1692239281Sgonzo device_printf(dev, "missing mmchs-device-id attribute in FDT\n"); 1693239281Sgonzo return (ENXIO); 1694239281Sgonzo } 1695239281Sgonzo sc->device_id = fdt32_to_cpu(did); 1696239281Sgonzo 1697239281Sgonzo /* Initiate the mtex lock */ 1698239281Sgonzo TI_MMCHS_LOCK_INIT(sc); 1699239281Sgonzo 1700239281Sgonzo /* Indicate the DMA channels haven't yet been allocated */ 1701239281Sgonzo sc->sc_dmach_rd = (unsigned int)-1; 1702239281Sgonzo sc->sc_dmach_wr = (unsigned int)-1; 1703239281Sgonzo 1704239281Sgonzo /* Get the hint'ed write detect pin */ 1705239281Sgonzo /* TODO: take this from FDT */ 1706239281Sgonzo if (resource_int_value("ti_mmchs", unit, "wp_gpio", &sc->sc_wp_gpio_pin) != 0){ 1707239281Sgonzo sc->sc_wp_gpio_pin = -1; 1708239281Sgonzo } else { 1709239281Sgonzo /* Get the GPIO device, we need this for the write protect pin */ 1710239281Sgonzo sc->sc_gpio_dev = devclass_get_device(devclass_find("gpio"), 0); 1711239281Sgonzo if (sc->sc_gpio_dev == NULL) 1712239281Sgonzo device_printf(dev, "Error: failed to get the GPIO device\n"); 1713239281Sgonzo else 1714239281Sgonzo GPIO_PIN_SETFLAGS(sc->sc_gpio_dev, sc->sc_wp_gpio_pin, 1715239281Sgonzo GPIO_PIN_INPUT); 1716239281Sgonzo } 1717239281Sgonzo 1718239281Sgonzo /* Get the TWL voltage regulator device, we need this to for setting the 1719239281Sgonzo * voltage of the bus on certain OMAP platforms. 1720239281Sgonzo */ 1721239281Sgonzo sc->sc_vreg_name = NULL; 1722239281Sgonzo 1723239281Sgonzo /* TODO: add voltage regulator knob to FDT */ 1724239281Sgonzo#ifdef notyet 1725239281Sgonzo sc->sc_vreg_dev = devclass_get_device(devclass_find("twl_vreg"), 0); 1726239281Sgonzo if (sc->sc_vreg_dev == NULL) { 1727239281Sgonzo device_printf(dev, "Error: failed to get the votlage regulator" 1728239281Sgonzo " device\n"); 1729239281Sgonzo sc->sc_vreg_name = NULL; 1730239281Sgonzo } 1731239281Sgonzo#endif 1732239281Sgonzo 1733239281Sgonzo /* Activate the device */ 1734239281Sgonzo err = ti_mmchs_activate(dev); 1735239281Sgonzo if (err) 1736239281Sgonzo goto out; 1737239281Sgonzo 1738239281Sgonzo /* Initialise the controller */ 1739239281Sgonzo ti_mmchs_hw_init(dev); 1740239281Sgonzo 1741239281Sgonzo /* Activate the interrupt and attach a handler */ 1742239281Sgonzo err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 1743239281Sgonzo NULL, ti_mmchs_intr, sc, &sc->sc_irq_h); 1744239281Sgonzo if (err != 0) 1745239281Sgonzo goto out; 1746239281Sgonzo 1747239281Sgonzo /* Add host details */ 1748239281Sgonzo sc->host.f_min = sc->sc_ref_freq / 1023; 1749239281Sgonzo sc->host.f_max = sc->sc_ref_freq; 1750239281Sgonzo sc->host.host_ocr = MMC_OCR_290_300 | MMC_OCR_300_310; 1751239281Sgonzo sc->host.caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; 1752239281Sgonzo 1753250791Skientzle device_add_child(dev, "mmc", 0); 1754239281Sgonzo 1755239281Sgonzo device_set_ivars(dev, &sc->host); 1756239281Sgonzo err = bus_generic_attach(dev); 1757239281Sgonzo 1758239281Sgonzoout: 1759239281Sgonzo if (err) { 1760239281Sgonzo TI_MMCHS_LOCK_DESTROY(sc); 1761239281Sgonzo ti_mmchs_deactivate(dev); 1762239281Sgonzo 1763239281Sgonzo#ifdef SOC_TI_AM335X 1764239281Sgonzo printf("%s: DMA unimplemented\n", __func__); 1765239281Sgonzo#else 1766239281Sgonzo if (sc->sc_dmach_rd != (unsigned int)-1) 1767239281Sgonzo ti_sdma_deactivate_channel(sc->sc_dmach_rd); 1768239281Sgonzo if (sc->sc_dmach_wr != (unsigned int)-1) 1769239281Sgonzo ti_sdma_deactivate_channel(sc->sc_dmach_wr); 1770239281Sgonzo#endif 1771239281Sgonzo } 1772239281Sgonzo 1773239281Sgonzo return (err); 1774239281Sgonzo} 1775239281Sgonzo 1776239281Sgonzo/** 1777239281Sgonzo * ti_mmchs_detach - dettach function for the driver 1778239281Sgonzo * @dev: mmc device handle 1779239281Sgonzo * 1780239281Sgonzo * Shutdowns the controll and release resources allocated by the driver. 1781239281Sgonzo * 1782239281Sgonzo * RETURNS: 1783239281Sgonzo * Always returns 0. 1784239281Sgonzo */ 1785239281Sgonzostatic int 1786239281Sgonzoti_mmchs_detach(device_t dev) 1787239281Sgonzo{ 1788239281Sgonzo#ifndef SOC_TI_AM335X 1789239281Sgonzo struct ti_mmchs_softc *sc = device_get_softc(dev); 1790239281Sgonzo#endif 1791239281Sgonzo 1792239281Sgonzo ti_mmchs_hw_fini(dev); 1793239281Sgonzo ti_mmchs_deactivate(dev); 1794239281Sgonzo 1795239281Sgonzo#ifdef SOC_TI_AM335X 1796239281Sgonzo printf("%s: DMA unimplemented\n", __func__); 1797239281Sgonzo#else 1798239281Sgonzo ti_sdma_deactivate_channel(sc->sc_dmach_wr); 1799239281Sgonzo ti_sdma_deactivate_channel(sc->sc_dmach_rd); 1800239281Sgonzo#endif 1801239281Sgonzo 1802239281Sgonzo return (0); 1803239281Sgonzo} 1804239281Sgonzo 1805239281Sgonzostatic device_method_t ti_mmchs_methods[] = { 1806239281Sgonzo /* device_if */ 1807239281Sgonzo DEVMETHOD(device_probe, ti_mmchs_probe), 1808239281Sgonzo DEVMETHOD(device_attach, ti_mmchs_attach), 1809239281Sgonzo DEVMETHOD(device_detach, ti_mmchs_detach), 1810239281Sgonzo 1811239281Sgonzo /* Bus interface */ 1812239281Sgonzo DEVMETHOD(bus_read_ivar, ti_mmchs_read_ivar), 1813239281Sgonzo DEVMETHOD(bus_write_ivar, ti_mmchs_write_ivar), 1814239281Sgonzo 1815239281Sgonzo /* mmcbr_if - MMC state machine callbacks */ 1816239281Sgonzo DEVMETHOD(mmcbr_update_ios, ti_mmchs_update_ios), 1817239281Sgonzo DEVMETHOD(mmcbr_request, ti_mmchs_request), 1818239281Sgonzo DEVMETHOD(mmcbr_get_ro, ti_mmchs_get_ro), 1819239281Sgonzo DEVMETHOD(mmcbr_acquire_host, ti_mmchs_acquire_host), 1820239281Sgonzo DEVMETHOD(mmcbr_release_host, ti_mmchs_release_host), 1821239281Sgonzo 1822239281Sgonzo {0, 0}, 1823239281Sgonzo}; 1824239281Sgonzo 1825239281Sgonzostatic driver_t ti_mmchs_driver = { 1826239281Sgonzo "ti_mmchs", 1827239281Sgonzo ti_mmchs_methods, 1828239281Sgonzo sizeof(struct ti_mmchs_softc), 1829239281Sgonzo}; 1830239281Sgonzostatic devclass_t ti_mmchs_devclass; 1831239281Sgonzo 1832239281SgonzoDRIVER_MODULE(ti_mmchs, simplebus, ti_mmchs_driver, ti_mmchs_devclass, 0, 0); 1833239281SgonzoMODULE_DEPEND(ti_mmchs, ti_prcm, 1, 1, 1); 1834239281Sgonzo#ifdef SOC_TI_AM335X 1835239281SgonzoMODULE_DEPEND(ti_mmchs, ti_edma, 1, 1, 1); 1836239281Sgonzo#else 1837239281SgonzoMODULE_DEPEND(ti_mmchs, ti_sdma, 1, 1, 1); 1838239281Sgonzo#endif 1839239281SgonzoMODULE_DEPEND(ti_mmchs, ti_gpio, 1, 1, 1); 1840239281Sgonzo 1841239281Sgonzo/* FIXME: MODULE_DEPEND(ti_mmchs, twl_vreg, 1, 1, 1); */ 1842