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