The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/powerpc/mpc85xx/fsl_sdhc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2011-2012 Semihalf
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * Driver for Freescale integrated eSDHC controller.
   29  * Limitations:
   30  *      - No support for multi-block transfers.
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD: releng/11.0/sys/powerpc/mpc85xx/fsl_sdhc.c 298642 2016-04-26 14:44:49Z pfg $");
   35 
   36 #include <sys/param.h>
   37 #include <sys/bus.h>
   38 #include <sys/kernel.h>
   39 #include <sys/lock.h>
   40 #include <sys/module.h>
   41 #include <sys/mutex.h>
   42 #include <sys/rman.h>
   43 #include <sys/sysctl.h>
   44 #include <sys/systm.h>
   45 #include <sys/taskqueue.h>
   46 
   47 #include <machine/bus.h>
   48 #include <machine/vmparam.h>
   49 
   50 #include <dev/fdt/fdt_common.h>
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <dev/ofw/ofw_bus_subr.h>
   53 
   54 #include <dev/mmc/bridge.h>
   55 #include <dev/mmc/mmcreg.h>
   56 #include <dev/mmc/mmcvar.h>
   57 #include <dev/mmc/mmcbrvar.h>
   58 
   59 #include <powerpc/mpc85xx/mpc85xx.h>
   60 
   61 #include "opt_platform.h"
   62 
   63 #include "mmcbr_if.h"
   64 
   65 #include "fsl_sdhc.h"
   66 
   67 #ifdef DEBUG
   68 #define DPRINTF(fmt, arg...)    printf("DEBUG %s(): " fmt, __FUNCTION__, ##arg)
   69 #else
   70 #define DPRINTF(fmt, arg...)
   71 #endif
   72 
   73 
   74 /*****************************************************************************
   75  * Register the driver
   76  *****************************************************************************/
   77 /* Forward declarations */
   78 static int      fsl_sdhc_probe(device_t);
   79 static int      fsl_sdhc_attach(device_t);
   80 static int      fsl_sdhc_detach(device_t);
   81 
   82 static int      fsl_sdhc_read_ivar(device_t, device_t, int, uintptr_t *);
   83 static int      fsl_sdhc_write_ivar(device_t, device_t, int, uintptr_t);
   84 
   85 static int      fsl_sdhc_update_ios(device_t, device_t);
   86 static int      fsl_sdhc_request(device_t, device_t, struct mmc_request *);
   87 static int      fsl_sdhc_get_ro(device_t, device_t);
   88 static int      fsl_sdhc_acquire_host(device_t, device_t);
   89 static int      fsl_sdhc_release_host(device_t, device_t);
   90 
   91 static device_method_t fsl_sdhc_methods[] = {
   92         /* device_if */
   93         DEVMETHOD(device_probe, fsl_sdhc_probe),
   94         DEVMETHOD(device_attach, fsl_sdhc_attach),
   95         DEVMETHOD(device_detach, fsl_sdhc_detach),
   96 
   97         /* Bus interface */
   98         DEVMETHOD(bus_read_ivar, fsl_sdhc_read_ivar),
   99         DEVMETHOD(bus_write_ivar, fsl_sdhc_write_ivar),
  100 
  101         /* OFW bus interface */
  102         DEVMETHOD(ofw_bus_get_compat,   ofw_bus_gen_get_compat),
  103         DEVMETHOD(ofw_bus_get_model,    ofw_bus_gen_get_model),
  104         DEVMETHOD(ofw_bus_get_name,     ofw_bus_gen_get_name),
  105         DEVMETHOD(ofw_bus_get_node,     ofw_bus_gen_get_node),
  106         DEVMETHOD(ofw_bus_get_type,     ofw_bus_gen_get_type),
  107 
  108         /* mmcbr_if */
  109         DEVMETHOD(mmcbr_update_ios, fsl_sdhc_update_ios),
  110         DEVMETHOD(mmcbr_request, fsl_sdhc_request),
  111         DEVMETHOD(mmcbr_get_ro, fsl_sdhc_get_ro),
  112         DEVMETHOD(mmcbr_acquire_host, fsl_sdhc_acquire_host),
  113         DEVMETHOD(mmcbr_release_host, fsl_sdhc_release_host),
  114 
  115         {0, 0},
  116 };
  117 
  118 /* kobj_class definition */
  119 static driver_t fsl_sdhc_driver = {
  120         "sdhci_fsl",
  121         fsl_sdhc_methods,
  122         sizeof(struct fsl_sdhc_softc)
  123 };
  124 
  125 static devclass_t fsl_sdhc_devclass;
  126 
  127 DRIVER_MODULE(sdhci_fsl, simplebus, fsl_sdhc_driver, fsl_sdhc_devclass, 0, 0);
  128 DRIVER_MODULE(mmc, sdhci_fsl, mmc_driver, mmc_devclass, NULL, NULL);
  129 MODULE_DEPEND(sdhci_fsl, mmc, 1, 1, 1);
  130 
  131 /*****************************************************************************
  132  * Private methods
  133  *****************************************************************************/
  134 static inline int
  135 read4(struct fsl_sdhc_softc *sc, unsigned int offset)
  136 {
  137 
  138         return bus_space_read_4(sc->bst, sc->bsh, offset);
  139 }
  140 
  141 static inline void
  142 write4(struct fsl_sdhc_softc *sc, unsigned int offset, int value)
  143 {
  144 
  145         bus_space_write_4(sc->bst, sc->bsh, offset, value);
  146 }
  147 
  148 static inline void
  149 set_bit(struct fsl_sdhc_softc *sc, uint32_t offset, uint32_t mask)
  150 {
  151         uint32_t x = read4(sc, offset);
  152 
  153         write4(sc, offset, x | mask);
  154 }
  155 
  156 static inline void
  157 clear_bit(struct fsl_sdhc_softc *sc, uint32_t offset, uint32_t mask)
  158 {
  159         uint32_t x = read4(sc, offset);
  160 
  161         write4(sc, offset, x & ~mask);
  162 }
  163 
  164 static int
  165 wait_for_bit_clear(struct fsl_sdhc_softc *sc, enum sdhc_reg_off reg,
  166     uint32_t bit)
  167 {
  168         uint32_t timeout = 10;
  169         uint32_t stat;
  170 
  171         stat = read4(sc, reg);
  172         while (stat & bit) {
  173                 if (timeout == 0) {
  174                         return (-1);
  175                 }
  176                 --timeout;
  177                 DELAY(1000);
  178                 stat = read4(sc, reg);
  179         }
  180 
  181         return (0);
  182 }
  183 
  184 static int
  185 wait_for_free_line(struct fsl_sdhc_softc *sc, enum sdhc_line line)
  186 {
  187         uint32_t timeout = 100;
  188         uint32_t stat;
  189 
  190         stat = read4(sc, SDHC_PRSSTAT);
  191         while (stat & line) {
  192                 if (timeout == 0) {
  193                         return (-1);
  194                 }
  195                 --timeout;
  196                 DELAY(1000);
  197                 stat = read4(sc, SDHC_PRSSTAT);
  198         }
  199 
  200         return (0);
  201 }
  202 
  203 static uint32_t
  204 get_platform_clock(struct fsl_sdhc_softc *sc)
  205 {
  206         device_t self, parent;
  207         phandle_t node;
  208         uint32_t clock;
  209 
  210         self = sc->self;
  211         node = ofw_bus_get_node(self);
  212 
  213         /* Get sdhci node properties */
  214         if((OF_getprop(node, "clock-frequency", (void *)&clock,
  215             sizeof(clock)) <= 0) || (clock == 0)) {
  216 
  217                 /*
  218                  * Trying to get clock from parent device (soc) if correct
  219                  * clock cannot be acquired from sdhci node.
  220                  */
  221                 parent = device_get_parent(self);
  222                 node = ofw_bus_get_node(parent);
  223 
  224                 /* Get soc properties */
  225                 if ((OF_getprop(node, "bus-frequency", (void *)&clock,
  226                     sizeof(clock)) <= 0) || (clock == 0)) {
  227                         device_printf(self,"Cannot acquire correct sdhci "
  228                             "frequency from DTS.\n");
  229 
  230                         return (0);
  231                 }
  232         }
  233 
  234         DPRINTF("Acquired clock: %d from DTS\n", clock);
  235 
  236         return (clock);
  237 }
  238 
  239 /**
  240  * Set clock driving card.
  241  * @param sc
  242  * @param clock Desired clock frequency in Hz
  243  */
  244 static void
  245 set_clock(struct fsl_sdhc_softc *sc, uint32_t clock)
  246 {
  247         uint32_t base_clock;
  248         uint32_t divisor, prescaler = 1;
  249         uint32_t round = 0;
  250 
  251         if (clock == sc->slot.clock)
  252                 return;
  253 
  254         if (clock == 0) {
  255                 clear_bit(sc, SDHC_SYSCTL, MASK_CLOCK_CONTROL | SYSCTL_PEREN |
  256                     SYSCTL_HCKEN | SYSCTL_IPGEN);
  257                 return;
  258         }
  259 
  260         base_clock = sc->platform_clock;
  261         round = base_clock & 0x2;
  262         base_clock >>= 2;
  263         base_clock += round;
  264         round = 0;
  265 
  266         /* SD specification 1.1 doesn't allow frequences above 50 MHz */
  267         if (clock > FSL_SDHC_MAX_CLOCK)
  268                 clock = FSL_SDHC_MAX_CLOCK;
  269 
  270         /*
  271          * divisor = ceil(base_clock / clock)
  272          * TODO: Reconsider symmetric rounding here instead of ceiling.
  273          */
  274         divisor = howmany(base_clock, clock);
  275 
  276         while (divisor > 16) {
  277                 round = divisor & 0x1;
  278                 divisor >>= 1;
  279 
  280                 prescaler <<= 1;
  281         }
  282         divisor += round - 1;
  283 
  284         /* Turn off the clock. */
  285         clear_bit(sc, SDHC_SYSCTL, MASK_CLOCK_CONTROL);
  286 
  287         /* Write clock settings. */
  288         set_bit(sc, SDHC_SYSCTL, (prescaler << SHIFT_SDCLKFS) |
  289             (divisor << SHIFT_DVS));
  290 
  291         /*
  292          * Turn on clocks.
  293          * TODO: This actually disables clock automatic gating off feature of
  294          * the controller which eventually should be enabled but as for now
  295          * it prevents controller from generating card insertion/removal
  296          * interrupts correctly.
  297          */
  298         set_bit(sc, SDHC_SYSCTL, SYSCTL_PEREN | SYSCTL_HCKEN | SYSCTL_IPGEN);
  299 
  300         sc->slot.clock = clock;
  301 
  302         DPRINTF("given clock = %d, computed clock = %d\n", clock,
  303             (base_clock / prescaler) / (divisor + 1));
  304 }
  305 
  306 static inline void
  307 send_80_clock_ticks(struct fsl_sdhc_softc *sc)
  308 {
  309         int err;
  310 
  311         err = wait_for_free_line(sc, SDHC_CMD_LINE | SDHC_DAT_LINE);
  312         if (err != 0) {
  313                 device_printf(sc->self, "Can't acquire data/cmd lines\n");
  314                 return;
  315         }
  316 
  317         set_bit(sc, SDHC_SYSCTL, SYSCTL_INITA);
  318         err = wait_for_bit_clear(sc, SDHC_SYSCTL, SYSCTL_INITA);
  319         if (err != 0) {
  320                 device_printf(sc->self, "Can't send 80 clocks to the card.\n");
  321         }
  322 }
  323 
  324 static void
  325 set_bus_width(struct fsl_sdhc_softc *sc, enum mmc_bus_width width)
  326 {
  327 
  328         DPRINTF("setting bus width to %d\n", width);
  329         switch (width) {
  330         case bus_width_1:
  331                 set_bit(sc, SDHC_PROCTL, DTW_1);
  332                 break;
  333         case bus_width_4:
  334                 set_bit(sc, SDHC_PROCTL, DTW_4);
  335                 break;
  336         case bus_width_8:
  337                 set_bit(sc, SDHC_PROCTL, DTW_8);
  338                 break;
  339         default:
  340                 device_printf(sc->self, "Unsupported bus width\n");
  341         }
  342 }
  343 
  344 static void
  345 reset_controller_all(struct fsl_sdhc_softc *sc)
  346 {
  347         uint32_t count = 5;
  348 
  349         set_bit(sc, SDHC_SYSCTL, SYSCTL_RSTA);
  350         while (read4(sc, SDHC_SYSCTL) & SYSCTL_RSTA) {
  351                 DELAY(FSL_SDHC_RESET_DELAY);
  352                 --count;
  353                 if (count == 0) {
  354                         device_printf(sc->self,
  355                             "Can't reset the controller\n");
  356                         return;
  357                 }
  358         }
  359 }
  360 
  361 static void
  362 reset_controller_dat_cmd(struct fsl_sdhc_softc *sc)
  363 {
  364         int err;
  365 
  366         set_bit(sc, SDHC_SYSCTL, SYSCTL_RSTD | SYSCTL_RSTC);
  367         err = wait_for_bit_clear(sc, SDHC_SYSCTL, SYSCTL_RSTD | SYSCTL_RSTC);
  368         if (err != 0) {
  369                 device_printf(sc->self, "Can't reset data & command part!\n");
  370                 return;
  371         }
  372 }
  373 
  374 static void
  375 init_controller(struct fsl_sdhc_softc *sc)
  376 {
  377 
  378         /* Enable interrupts. */
  379 #ifdef FSL_SDHC_NO_DMA
  380         write4(sc, SDHC_IRQSTATEN, MASK_IRQ_ALL & ~IRQ_DINT & ~IRQ_DMAE);
  381         write4(sc, SDHC_IRQSIGEN, MASK_IRQ_ALL & ~IRQ_DINT & ~IRQ_DMAE);
  382 #else
  383         write4(sc, SDHC_IRQSTATEN, MASK_IRQ_ALL & ~IRQ_BRR & ~IRQ_BWR);
  384         write4(sc, SDHC_IRQSIGEN, MASK_IRQ_ALL & ~IRQ_BRR & ~IRQ_BWR);
  385 
  386         /* Write DMA address */
  387         write4(sc, SDHC_DSADDR, sc->dma_phys);
  388 
  389         /* Enable snooping and fix for AHB2MAG bypass. */
  390         write4(sc, SDHC_DCR, DCR_SNOOP | DCR_AHB2MAG_BYPASS);
  391 #endif
  392         /* Set data timeout. */
  393         set_bit(sc, SDHC_SYSCTL, 0xe << SHIFT_DTOCV);
  394 
  395         /* Set water-mark levels (FIFO buffer size). */
  396         write4(sc, SDHC_WML, (FSL_SDHC_FIFO_BUF_WORDS << 16) |
  397             FSL_SDHC_FIFO_BUF_WORDS);
  398 }
  399 
  400 static void
  401 init_mmc_host_struct(struct fsl_sdhc_softc *sc)
  402 {
  403         struct mmc_host *host = &sc->mmc_host;
  404 
  405         /* Clear host structure. */
  406         bzero(host, sizeof(struct mmc_host));
  407 
  408         /* Calculate minimum and maximum operating frequencies. */
  409         host->f_min = sc->platform_clock / FSL_SDHC_MAX_DIV;
  410         host->f_max = FSL_SDHC_MAX_CLOCK;
  411 
  412         /* Set operation conditions (voltage). */
  413         host->host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340;
  414 
  415         /* Set additional host controller capabilities. */
  416         host->caps = MMC_CAP_4_BIT_DATA;
  417 
  418         /* Set mode. */
  419         host->mode = mode_sd;
  420 }
  421 
  422 static void
  423 card_detect_task(void *arg, int pending)
  424 {
  425         struct fsl_sdhc_softc *sc = (struct fsl_sdhc_softc *)arg;
  426         int err;
  427         int insert;
  428 
  429         insert = read4(sc, SDHC_PRSSTAT) & PRSSTAT_CINS;
  430 
  431         mtx_lock(&sc->mtx);
  432 
  433         if (insert) {
  434                 if (sc->child != NULL) {
  435                         mtx_unlock(&sc->mtx);
  436                         return;
  437                 }
  438 
  439                 sc->child = device_add_child(sc->self, "mmc", -1);
  440                 if (sc->child == NULL) {
  441                         device_printf(sc->self, "Couldn't add MMC bus!\n");
  442                         mtx_unlock(&sc->mtx);
  443                         return;
  444                 }
  445 
  446                 /* Initialize MMC bus host structure. */
  447                 init_mmc_host_struct(sc);
  448                 device_set_ivars(sc->child, &sc->mmc_host);
  449 
  450         } else {
  451                 if (sc->child == NULL) {
  452                         mtx_unlock(&sc->mtx);
  453                         return;
  454                 }
  455         }
  456 
  457         mtx_unlock(&sc->mtx);
  458 
  459         if (insert) {
  460                 if ((err = device_probe_and_attach(sc->child)) != 0) {
  461                         device_printf(sc->self, "MMC bus failed on probe "
  462                             "and attach! error %d\n", err);
  463                         device_delete_child(sc->self, sc->child);
  464                         sc->child = NULL;
  465                 }
  466         } else {
  467                 if (device_delete_child(sc->self, sc->child) != 0)
  468                         device_printf(sc->self, "Could not delete MMC bus!\n");
  469                 sc->child = NULL;
  470         }
  471 }
  472 
  473 static void
  474 card_detect_delay(void *arg)
  475 {
  476         struct fsl_sdhc_softc *sc = arg;
  477 
  478         taskqueue_enqueue(taskqueue_swi_giant, &sc->card_detect_task);
  479 }
  480 
  481 static void
  482 finalize_request(struct fsl_sdhc_softc *sc)
  483 {
  484 
  485         DPRINTF("finishing request %p\n", sc->request);
  486 
  487         sc->request->done(sc->request);
  488         sc->request = NULL;
  489 }
  490 
  491 /**
  492  * Read response from card.
  493  * @todo Implement Auto-CMD responses being held in R3 for multi-block xfers.
  494  * @param sc
  495  */
  496 static void
  497 get_response(struct fsl_sdhc_softc *sc)
  498 {
  499         struct mmc_command *cmd = sc->request->cmd;
  500         int i;
  501         uint32_t val;
  502         uint8_t ext = 0;
  503 
  504         if (cmd->flags & MMC_RSP_136) {
  505                 /* CRC is stripped, need to shift one byte left. */
  506                 for (i = 0; i < 4; i++) {
  507                         val = read4(sc, SDHC_CMDRSP0 + i * 4);
  508                         cmd->resp[3 - i] = (val << 8) + ext;
  509                         ext = val >> 24;
  510                 }
  511         } else {
  512                 cmd->resp[0] = read4(sc, SDHC_CMDRSP0);
  513         }
  514 }
  515 
  516 #ifdef FSL_SDHC_NO_DMA
  517 /**
  518  * Read all content of a fifo buffer.
  519  * @warning Assumes data buffer is 32-bit aligned.
  520  * @param sc
  521  */
  522 static void
  523 read_block_pio(struct fsl_sdhc_softc *sc)
  524 {
  525         struct mmc_data *data = sc->request->cmd->data;
  526         size_t left = min(FSL_SDHC_FIFO_BUF_SIZE, data->len);
  527         uint8_t *buf = data->data;
  528         uint32_t word;
  529 
  530         buf += sc->data_offset;
  531         bus_space_read_multi_4(sc->bst, sc->bsh, SDHC_DATPORT, (uint32_t *)buf,
  532             left >> 2);
  533 
  534         sc->data_offset += left;
  535 
  536         /* Handle 32-bit unaligned size case. */
  537         left &= 0x3;
  538         if (left > 0) {
  539                 buf = (uint8_t *)data->data + (sc->data_offset & ~0x3);
  540                 word = read4(sc, SDHC_DATPORT);
  541                 while (left > 0) {
  542                         *(buf++) = word;
  543                         word >>= 8;
  544                         --left;
  545                 }
  546         }
  547 }
  548 
  549 /**
  550  * Write a fifo buffer.
  551  * @warning Assumes data buffer size is 32-bit aligned.
  552  * @param sc
  553  */
  554 static void
  555 write_block_pio(struct fsl_sdhc_softc *sc)
  556 {
  557         struct mmc_data *data = sc->request->cmd->data;
  558         size_t left = min(FSL_SDHC_FIFO_BUF_SIZE, data->len);
  559         uint8_t *buf = data->data;
  560         uint32_t word = 0;
  561 
  562         DPRINTF("sc->data_offset %d\n", sc->data_offset);
  563 
  564         buf += sc->data_offset;
  565         bus_space_write_multi_4(sc->bst, sc->bsh, SDHC_DATPORT, (uint32_t *)buf,
  566             left >> 2);
  567 
  568         sc->data_offset += left;
  569 
  570         /* Handle 32-bit unaligned size case. */
  571         left &= 0x3;
  572         if (left > 0) {
  573                 buf = (uint8_t *)data->data + (sc->data_offset & ~0x3);
  574                 while (left > 0) {
  575                         word += *(buf++);
  576                         word <<= 8;
  577                         --left;
  578                 }
  579                 write4(sc, SDHC_DATPORT, word);
  580         }
  581 }
  582 
  583 static void
  584 pio_read_transfer(struct fsl_sdhc_softc *sc)
  585 {
  586 
  587         while (read4(sc, SDHC_PRSSTAT) & PRSSTAT_BREN) {
  588                 read_block_pio(sc);
  589 
  590                 /*
  591                  * TODO: should we check here whether data_offset >= data->len?
  592                  */
  593         }
  594 }
  595 
  596 static void
  597 pio_write_transfer(struct fsl_sdhc_softc *sc)
  598 {
  599 
  600         while (read4(sc, SDHC_PRSSTAT) & PRSSTAT_BWEN) {
  601                 write_block_pio(sc);
  602 
  603                 /*
  604                  * TODO: should we check here whether data_offset >= data->len?
  605                  */
  606         }
  607 }
  608 #endif /* FSL_SDHC_USE_DMA */
  609 
  610 static inline void
  611 handle_command_intr(struct fsl_sdhc_softc *sc, uint32_t irq_stat)
  612 {
  613         struct mmc_command *cmd = sc->request->cmd;
  614 
  615         /* Handle errors. */
  616         if (irq_stat & IRQ_CTOE) {
  617                 cmd->error = MMC_ERR_TIMEOUT;
  618         } else if (irq_stat & IRQ_CCE) {
  619                 cmd->error = MMC_ERR_BADCRC;
  620         } else if (irq_stat & (IRQ_CEBE | IRQ_CIE)) {
  621                 cmd->error = MMC_ERR_FIFO;
  622         }
  623 
  624         if (cmd->error) {
  625                 device_printf(sc->self, "Error interrupt occured\n");
  626                 reset_controller_dat_cmd(sc);
  627                 return;
  628         }
  629 
  630         if (sc->command_done)
  631                 return;
  632 
  633         if (irq_stat & IRQ_CC) {
  634                 sc->command_done = 1;
  635 
  636                 if (cmd->flags & MMC_RSP_PRESENT)
  637                         get_response(sc);
  638         }
  639 }
  640 
  641 static inline void
  642 handle_data_intr(struct fsl_sdhc_softc *sc, uint32_t irq_stat)
  643 {
  644         struct mmc_command *cmd = sc->request->cmd;
  645 
  646         /* Handle errors. */
  647         if (irq_stat & IRQ_DTOE) {
  648                 cmd->error = MMC_ERR_TIMEOUT;
  649         } else if (irq_stat & (IRQ_DCE | IRQ_DEBE)) {
  650                 cmd->error = MMC_ERR_BADCRC;
  651         } else if (irq_stat & IRQ_ERROR_DATA_MASK) {
  652                 cmd->error = MMC_ERR_FAILED;
  653         }
  654 
  655         if (cmd->error) {
  656                 device_printf(sc->self, "Error interrupt occured\n");
  657                 sc->data_done = 1;
  658                 reset_controller_dat_cmd(sc);
  659                 return;
  660         }
  661 
  662         if (sc->data_done)
  663                 return;
  664 
  665 #ifdef FSL_SDHC_NO_DMA
  666         if (irq_stat & IRQ_BRR) {
  667                 pio_read_transfer(sc);
  668         }
  669 
  670         if (irq_stat & IRQ_BWR) {
  671                 pio_write_transfer(sc);
  672         }
  673 #else
  674         if (irq_stat & IRQ_DINT) {
  675                 struct mmc_data *data = sc->request->cmd->data;
  676 
  677                 /* Synchronize DMA. */
  678                 if (data->flags & MMC_DATA_READ) {
  679                         bus_dmamap_sync(sc->dma_tag, sc->dma_map,
  680                             BUS_DMASYNC_POSTREAD);
  681                         memcpy(data->data, sc->dma_mem, data->len);
  682                 } else {
  683                         bus_dmamap_sync(sc->dma_tag, sc->dma_map,
  684                             BUS_DMASYNC_POSTWRITE);
  685                 }
  686 
  687                 /*
  688                  * TODO: For multiple block transfers, address of dma memory
  689                  * in DSADDR register should be set to the beginning of the
  690                  * segment here. Also offset to data pointer should be handled.
  691                  */
  692         }
  693 #endif
  694 
  695         if (irq_stat & IRQ_TC)
  696                 sc->data_done = 1;
  697 }
  698 
  699 static void
  700 interrupt_handler(void *arg)
  701 {
  702         struct fsl_sdhc_softc *sc = (struct fsl_sdhc_softc *)arg;
  703         uint32_t irq_stat;
  704 
  705         mtx_lock(&sc->mtx);
  706 
  707         irq_stat = read4(sc, SDHC_IRQSTAT);
  708 
  709         /* Card interrupt. */
  710         if (irq_stat & IRQ_CINT) {
  711                 DPRINTF("Card interrupt recievied\n");
  712 
  713         }
  714 
  715         /* Card insertion interrupt. */
  716         if (irq_stat & IRQ_CINS) {
  717                 clear_bit(sc, SDHC_IRQSIGEN, IRQ_CINS);
  718                 clear_bit(sc, SDHC_IRQSTATEN, IRQ_CINS);
  719                 set_bit(sc, SDHC_IRQSIGEN, IRQ_CRM);
  720                 set_bit(sc, SDHC_IRQSTATEN, IRQ_CRM);
  721 
  722                 callout_reset(&sc->card_detect_callout, hz / 2,
  723                     card_detect_delay, sc);
  724         }
  725 
  726         /* Card removal interrupt. */
  727         if (irq_stat & IRQ_CRM) {
  728                 clear_bit(sc, SDHC_IRQSIGEN, IRQ_CRM);
  729                 clear_bit(sc, SDHC_IRQSTATEN, IRQ_CRM);
  730                 set_bit(sc, SDHC_IRQSIGEN, IRQ_CINS);
  731                 set_bit(sc, SDHC_IRQSTATEN, IRQ_CINS);
  732 
  733                 callout_stop(&sc->card_detect_callout);
  734                 taskqueue_enqueue(taskqueue_swi_giant, &sc->card_detect_task);
  735         }
  736 
  737         /* Handle request interrupts. */
  738         if (sc->request) {
  739                 handle_command_intr(sc, irq_stat);
  740                 handle_data_intr(sc, irq_stat);
  741 
  742                 /*
  743                  * Finalize request when transfer is done successfully
  744                  * or was interrupted due to error.
  745                  */  
  746                 if ((sc->data_done && sc->command_done) ||
  747                     (sc->request->cmd->error))
  748                         finalize_request(sc);
  749         }
  750 
  751         /* Clear status register. */
  752         write4(sc, SDHC_IRQSTAT, irq_stat);
  753 
  754         mtx_unlock(&sc->mtx);
  755 }
  756 
  757 #ifndef FSL_SDHC_NO_DMA
  758 static void
  759 dma_get_phys_addr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
  760 {
  761 
  762         if (error != 0)
  763                 return;
  764 
  765         /* Get first segment's physical address. */
  766         *(bus_addr_t *)arg = segs->ds_addr;
  767 }
  768 
  769 static int
  770 init_dma(struct fsl_sdhc_softc *sc)
  771 {
  772         device_t self = sc->self;
  773         int err;
  774 
  775         err = bus_dma_tag_create(bus_get_dma_tag(self),
  776             FSL_SDHC_DMA_BLOCK_SIZE, 0, BUS_SPACE_MAXADDR_32BIT,
  777             BUS_SPACE_MAXADDR, NULL, NULL, FSL_SDHC_DMA_BLOCK_SIZE, 1,
  778             FSL_SDHC_DMA_BLOCK_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL,
  779             &sc->dma_tag);
  780 
  781         if (err) {
  782                 device_printf(self, "Could not create DMA tag!\n");
  783                 return (-1);
  784         }
  785 
  786         err = bus_dmamem_alloc(sc->dma_tag, (void **)&(sc->dma_mem),
  787             BUS_DMA_NOWAIT | BUS_DMA_NOCACHE, &sc->dma_map);
  788         if (err) {
  789                 device_printf(self, "Could not allocate DMA memory!\n");
  790                 goto fail1;
  791         }
  792 
  793         err = bus_dmamap_load(sc->dma_tag, sc->dma_map, (void *)sc->dma_mem,
  794             FSL_SDHC_DMA_BLOCK_SIZE, dma_get_phys_addr, &sc->dma_phys, 0);
  795         if (err) {
  796                 device_printf(self, "Could not load DMA map!\n");
  797                 goto fail2;
  798         }
  799 
  800         return (0);
  801 
  802 fail2:
  803         bus_dmamem_free(sc->dma_tag, sc->dma_mem, sc->dma_map);
  804 fail1:
  805         bus_dma_tag_destroy(sc->dma_tag);
  806 
  807         return (-1);
  808 }
  809 #endif /* FSL_SDHC_NO_DMA */
  810 
  811 static uint32_t
  812 set_xfertyp_register(const struct mmc_command *cmd)
  813 {
  814         uint32_t xfertyp = 0;
  815 
  816         /* Set command index. */
  817         xfertyp |= cmd->opcode << CMDINX_SHIFT;
  818 
  819         /* Set command type. */
  820         if (cmd->opcode == MMC_STOP_TRANSMISSION)
  821                 xfertyp |= CMDTYP_ABORT;
  822 
  823         /* Set data preset select. */
  824         if (cmd->data) {
  825                 xfertyp |= XFERTYP_DPSEL;
  826 
  827                 /* Set transfer direction. */
  828                 if (cmd->data->flags & MMC_DATA_READ)
  829                         xfertyp |= XFERTYP_DTDSEL;
  830         }
  831 
  832         /* Set command index check. */
  833         if (cmd->flags & MMC_RSP_OPCODE)
  834                 xfertyp |= XFERTYP_CICEN;
  835 
  836         /* Set command CRC check. */
  837         if (cmd->flags & MMC_RSP_CRC)
  838                 xfertyp |= XFERTYP_CCCEN;
  839 
  840         /* Set response type */
  841         if (!(cmd->flags & MMC_RSP_PRESENT))
  842                 xfertyp |= RSPTYP_NONE;
  843         else if (cmd->flags & MMC_RSP_136)
  844                 xfertyp |= RSPTYP_136;
  845         else if (cmd->flags & MMC_RSP_BUSY)
  846                 xfertyp |= RSPTYP_48_BUSY;
  847         else
  848                 xfertyp |= RSPTYP_48;
  849 
  850 #ifndef FSL_SDHC_NO_DMA
  851         /* Enable DMA */
  852         xfertyp |= XFERTYP_DMAEN;
  853 #endif
  854 
  855         return (xfertyp);
  856 }
  857 
  858 static uint32_t
  859 set_blkattr_register(const struct mmc_data *data)
  860 {
  861 
  862         if (data->len <= FSL_SDHC_MAX_BLOCK_SIZE) {
  863                 /* One block transfer. */
  864                 return (BLKATTR_BLOCK_COUNT(1) | ((data->len) &
  865                     BLKATTR_BLKSZE));
  866         }
  867 
  868         /* TODO: Write code here for multi-block transfers. */
  869         return (0);
  870 }
  871 
  872 /**
  873  * Initiate data transfer. Interrupt handler will finalize it.
  874  * @todo Implement multi-block transfers.
  875  * @param sc
  876  * @param cmd
  877  */
  878 static int
  879 start_data(struct fsl_sdhc_softc *sc, struct mmc_data *data)
  880 {
  881         uint32_t reg;
  882 
  883         if ((uint32_t)data->data & 0x3) {
  884                 device_printf(sc->self, "32-bit unaligned data pointer in "
  885                     "request\n");
  886                 return (-1);
  887         }
  888 
  889         sc->data_done = 0;
  890 
  891 #ifdef FSL_SDHC_NO_DMA
  892         sc->data_ptr = data->data;
  893         sc->data_offset = 0;
  894 #else
  895         /* Write DMA address register. */
  896         write4(sc, SDHC_DSADDR, sc->dma_phys);
  897 
  898         /* Synchronize DMA. */
  899         if (data->flags & MMC_DATA_READ) {
  900                 bus_dmamap_sync(sc->dma_tag, sc->dma_map,
  901                     BUS_DMASYNC_PREREAD);
  902         } else {
  903                 memcpy(sc->dma_mem, data->data, data->len);
  904                 bus_dmamap_sync(sc->dma_tag, sc->dma_map,
  905                     BUS_DMASYNC_PREWRITE);
  906         }
  907 #endif
  908         /* Set block size and count. */
  909         reg = set_blkattr_register(data);
  910         if (reg == 0) {
  911                 device_printf(sc->self, "Requested unsupported multi-block "
  912                     "transfer.\n");
  913                 return (-1);
  914         }
  915         write4(sc, SDHC_BLKATTR, reg);
  916 
  917         return (0);
  918 }
  919 
  920 static int
  921 start_command(struct fsl_sdhc_softc *sc, struct mmc_command *cmd)
  922 {
  923         struct mmc_request *req = sc->request;
  924         uint32_t mask;
  925         uint32_t xfertyp;
  926         int err;
  927 
  928         DPRINTF("opcode %d, flags 0x%08x\n", cmd->opcode, cmd->flags);
  929         DPRINTF("PRSSTAT = 0x%08x\n", read4(sc, SDHC_PRSSTAT));
  930 
  931         sc->command_done = 0;
  932 
  933         cmd->error = MMC_ERR_NONE;
  934 
  935         /* TODO: should we check here for card presence and clock settings? */
  936 
  937         /* Always wait for free CMD line. */
  938         mask = SDHC_CMD_LINE;
  939         /* Wait for free DAT if we have data or busy signal. */
  940         if (cmd->data || (cmd->flags & MMC_RSP_BUSY))
  941                 mask |= SDHC_DAT_LINE;
  942         /* We shouldn't wait for DAT for stop commands. */
  943         if (cmd == req->stop)
  944                 mask &= ~SDHC_DAT_LINE;
  945         err = wait_for_free_line(sc, mask);
  946         if (err != 0) {
  947                 device_printf(sc->self, "Controller never released inhibit "
  948                     "bit(s).\n");
  949                 reset_controller_dat_cmd(sc);
  950                 cmd->error = MMC_ERR_FAILED;
  951                 sc->request = NULL;
  952                 req->done(req);
  953                 return (-1);
  954         }
  955 
  956         xfertyp = set_xfertyp_register(cmd);
  957 
  958         if (cmd->data != NULL) {
  959                 err = start_data(sc, cmd->data);
  960                 if (err != 0) {
  961                         device_printf(sc->self,
  962                             "Data transfer request failed\n");
  963                         reset_controller_dat_cmd(sc);
  964                         cmd->error = MMC_ERR_FAILED;
  965                         sc->request = NULL;
  966                         req->done(req);
  967                         return (-1);
  968                 }
  969         }
  970 
  971         write4(sc, SDHC_CMDARG, cmd->arg);
  972         write4(sc, SDHC_XFERTYP, xfertyp);
  973 
  974         DPRINTF("XFERTYP = 0x%08x\n", xfertyp);
  975         DPRINTF("CMDARG = 0x%08x\n", cmd->arg);
  976 
  977         return (0);
  978 }
  979 
  980 #ifdef DEBUG
  981 static void
  982 dump_registers(struct fsl_sdhc_softc *sc)
  983 {
  984         printf("PRSSTAT = 0x%08x\n", read4(sc, SDHC_PRSSTAT));
  985         printf("PROCTL = 0x%08x\n", read4(sc, SDHC_PROCTL));
  986         printf("HOSTCAPBLT = 0x%08x\n", read4(sc, SDHC_HOSTCAPBLT));
  987         printf("IRQSTAT = 0x%08x\n", read4(sc, SDHC_IRQSTAT));
  988         printf("IRQSTATEN = 0x%08x\n", read4(sc, SDHC_IRQSTATEN));
  989         printf("IRQSIGEN = 0x%08x\n", read4(sc, SDHC_IRQSIGEN));
  990         printf("WML = 0x%08x\n", read4(sc, SDHC_WML));
  991         printf("DSADDR = 0x%08x\n", read4(sc, SDHC_DSADDR));
  992         printf("XFERTYP = 0x%08x\n", read4(sc, SDHC_XFERTYP));
  993         printf("DCR = 0x%08x\n", read4(sc, SDHC_DCR));
  994 }
  995 #endif
  996 
  997 /*****************************************************************************
  998  * Public methods
  999  *****************************************************************************/
 1000 /*
 1001  * Device interface methods.
 1002  */
 1003 static int
 1004 fsl_sdhc_probe(device_t self)
 1005 {
 1006         static const char *desc =
 1007             "Freescale Enhanced Secure Digital Host Controller";
 1008 
 1009         if (!ofw_bus_is_compatible(self, "fsl,p2020-esdhc") &&
 1010             !ofw_bus_is_compatible(self, "fsl,esdhc"))
 1011                 return (ENXIO);
 1012 
 1013         device_set_desc(self, desc);
 1014 
 1015         return (BUS_PROBE_VENDOR);
 1016 }
 1017 
 1018 static int
 1019 fsl_sdhc_attach(device_t self)
 1020 {
 1021         struct fsl_sdhc_softc *sc;
 1022 
 1023         sc = device_get_softc(self);
 1024 
 1025         sc->self = self;
 1026 
 1027         mtx_init(&sc->mtx, device_get_nameunit(self), NULL, MTX_DEF);
 1028 
 1029         /* Setup memory resource */
 1030         sc->mem_rid = 0;
 1031         sc->mem_resource = bus_alloc_resource_any(self, SYS_RES_MEMORY,
 1032             &sc->mem_rid, RF_ACTIVE);
 1033         if (sc->mem_resource == NULL) {
 1034                 device_printf(self, "Could not allocate memory.\n");
 1035                 goto fail;
 1036         }
 1037         sc->bst = rman_get_bustag(sc->mem_resource);
 1038         sc->bsh = rman_get_bushandle(sc->mem_resource);
 1039 
 1040         /* Setup interrupt resource. */
 1041         sc->irq_rid = 0;
 1042         sc->irq_resource = bus_alloc_resource_any(self, SYS_RES_IRQ,
 1043             &sc->irq_rid, RF_ACTIVE);
 1044         if (sc->irq_resource == NULL) {
 1045                 device_printf(self, "Could not allocate interrupt.\n");
 1046                 goto fail;
 1047         }
 1048         if (bus_setup_intr(self, sc->irq_resource, INTR_TYPE_MISC |
 1049             INTR_MPSAFE, NULL, interrupt_handler, sc, &sc->ihl) != 0) {
 1050                 device_printf(self, "Could not setup interrupt.\n");
 1051                 goto fail;
 1052         }
 1053 
 1054         /* Setup DMA. */
 1055 #ifndef FSL_SDHC_NO_DMA
 1056         if (init_dma(sc) != 0) {
 1057                 device_printf(self, "Could not setup DMA\n");
 1058         }
 1059 #endif
 1060         sc->bus_busy = 0;
 1061         sc->platform_clock = get_platform_clock(sc);
 1062         if (sc->platform_clock == 0) {
 1063                 device_printf(self, "Could not get platform clock.\n");
 1064                 goto fail;
 1065         }
 1066         sc->command_done = 1;
 1067         sc->data_done = 1;
 1068 
 1069         /* Init card detection task. */
 1070         TASK_INIT(&sc->card_detect_task, 0, card_detect_task, sc);
 1071         callout_init(&sc->card_detect_callout, 1);
 1072 
 1073         reset_controller_all(sc);
 1074         init_controller(sc);
 1075         set_clock(sc, 400000);
 1076         send_80_clock_ticks(sc);
 1077 
 1078 #ifdef DEBUG
 1079         dump_registers(sc);
 1080 #endif
 1081 
 1082         return (0);
 1083 
 1084 fail:
 1085         fsl_sdhc_detach(self);
 1086         return (ENXIO);
 1087 }
 1088 
 1089 static int
 1090 fsl_sdhc_detach(device_t self)
 1091 {
 1092         struct fsl_sdhc_softc *sc = device_get_softc(self);
 1093         int err;
 1094 
 1095         if (sc->child)
 1096                 device_delete_child(self, sc->child);
 1097 
 1098         taskqueue_drain(taskqueue_swi_giant, &sc->card_detect_task);
 1099 
 1100 #ifndef FSL_SDHC_NO_DMA
 1101         bus_dmamap_unload(sc->dma_tag, sc->dma_map);
 1102         bus_dmamem_free(sc->dma_tag, sc->dma_mem, sc->dma_map);
 1103         bus_dma_tag_destroy(sc->dma_tag);
 1104 #endif
 1105 
 1106         if (sc->ihl != NULL) {
 1107                 err = bus_teardown_intr(self, sc->irq_resource, sc->ihl);
 1108                 if (err)
 1109                         return (err);
 1110         }
 1111         if (sc->irq_resource != NULL) {
 1112                 err = bus_release_resource(self, SYS_RES_IRQ, sc->irq_rid,
 1113                     sc->irq_resource);
 1114                 if (err)
 1115                         return (err);
 1116 
 1117         }
 1118         if (sc->mem_resource != NULL) {
 1119                 err = bus_release_resource(self, SYS_RES_MEMORY, sc->mem_rid,
 1120                     sc->mem_resource);
 1121                 if (err)
 1122                         return (err);
 1123         }
 1124 
 1125         mtx_destroy(&sc->mtx);
 1126 
 1127         return (0);
 1128 }
 1129 
 1130 
 1131 /*
 1132  * Bus interface methods.
 1133  */
 1134 static int
 1135 fsl_sdhc_read_ivar(device_t self, device_t child, int index,
 1136     uintptr_t *result)
 1137 {
 1138         struct mmc_host *host = device_get_ivars(child);
 1139 
 1140         switch (index) {
 1141         case MMCBR_IVAR_BUS_MODE:
 1142                 *(int *)result = host->ios.bus_mode;
 1143                 break;
 1144         case MMCBR_IVAR_BUS_WIDTH:
 1145                 *(int *)result = host->ios.bus_width;
 1146                 break;
 1147         case MMCBR_IVAR_CHIP_SELECT:
 1148                 *(int *)result = host->ios.chip_select;
 1149                 break;
 1150         case MMCBR_IVAR_CLOCK:
 1151                 *(int *)result = host->ios.clock;
 1152                 break;
 1153         case MMCBR_IVAR_F_MIN:
 1154                 *(int *)result = host->f_min;
 1155                 break;
 1156         case MMCBR_IVAR_F_MAX:
 1157                 *(int *)result = host->f_max;
 1158                 break;
 1159         case MMCBR_IVAR_HOST_OCR:
 1160                 *(int *)result = host->host_ocr;
 1161                 break;
 1162         case MMCBR_IVAR_MODE:
 1163                 *(int *)result = host->mode;
 1164                 break;
 1165         case MMCBR_IVAR_OCR:
 1166                 *(int *)result = host->ocr;
 1167                 break;
 1168         case MMCBR_IVAR_POWER_MODE:
 1169                 *(int *)result = host->ios.power_mode;
 1170                 break;
 1171         case MMCBR_IVAR_VDD:
 1172                 *(int *)result = host->ios.vdd;
 1173                 break;
 1174         default:
 1175                 return (EINVAL);
 1176         }
 1177 
 1178         return (0);
 1179 }
 1180 
 1181 static int
 1182 fsl_sdhc_write_ivar(device_t self, device_t child, int index,
 1183     uintptr_t value)
 1184 {
 1185         struct mmc_host *host = device_get_ivars(child);
 1186 
 1187         switch (index) {
 1188         case MMCBR_IVAR_BUS_MODE:
 1189                 host->ios.bus_mode = value;
 1190                 break;
 1191         case MMCBR_IVAR_BUS_WIDTH:
 1192                 host->ios.bus_width = value;
 1193                 break;
 1194         case MMCBR_IVAR_CHIP_SELECT:
 1195                 host->ios.chip_select = value;
 1196                 break;
 1197         case MMCBR_IVAR_CLOCK:
 1198                 host->ios.clock = value;
 1199                 break;
 1200         case MMCBR_IVAR_MODE:
 1201                 host->mode = value;
 1202                 break;
 1203         case MMCBR_IVAR_OCR:
 1204                 host->ocr = value;
 1205                 break;
 1206         case MMCBR_IVAR_POWER_MODE:
 1207                 host->ios.power_mode = value;
 1208                 break;
 1209         case MMCBR_IVAR_VDD:
 1210                 host->ios.vdd = value;
 1211                 break;
 1212         case MMCBR_IVAR_HOST_OCR:
 1213         case MMCBR_IVAR_F_MIN:
 1214         case MMCBR_IVAR_F_MAX:
 1215         default:
 1216                 /* Instance variable not writable. */
 1217                 return (EINVAL);
 1218         }
 1219 
 1220         return (0);
 1221 }
 1222 
 1223 
 1224 /*
 1225  * MMC bridge methods.
 1226  */
 1227 static int
 1228 fsl_sdhc_update_ios(device_t self, device_t reqdev)
 1229 {
 1230         struct fsl_sdhc_softc *sc = device_get_softc(self);
 1231         struct mmc_host *host = device_get_ivars(reqdev);
 1232         struct mmc_ios *ios = &host->ios;
 1233 
 1234         mtx_lock(&sc->mtx);
 1235 
 1236         /* Full reset on bus power down to clear from any state. */
 1237         if (ios->power_mode == power_off) {
 1238                 reset_controller_all(sc);
 1239                 init_controller(sc);
 1240         }
 1241 
 1242         set_clock(sc, ios->clock);
 1243         set_bus_width(sc, ios->bus_width);
 1244 
 1245         mtx_unlock(&sc->mtx);
 1246 
 1247         return (0);
 1248 }
 1249 
 1250 static int
 1251 fsl_sdhc_request(device_t self, device_t reqdev, struct mmc_request *req)
 1252 {
 1253         struct fsl_sdhc_softc *sc = device_get_softc(self);
 1254         int err;
 1255 
 1256         mtx_lock(&sc->mtx);
 1257 
 1258         sc->request = req;
 1259         err = start_command(sc, req->cmd);
 1260 
 1261         mtx_unlock(&sc->mtx);
 1262 
 1263         return (err);
 1264 }
 1265 
 1266 static int
 1267 fsl_sdhc_get_ro(device_t self, device_t reqdev)
 1268 {
 1269         struct fsl_sdhc_softc *sc = device_get_softc(self);
 1270 
 1271         /* Wouldn't it be faster using branching (if {}) ?? */
 1272         return (((read4(sc, SDHC_PRSSTAT) & PRSSTAT_WPSPL) >> 19) ^ 0x1);
 1273 }
 1274 
 1275 static int
 1276 fsl_sdhc_acquire_host(device_t self, device_t reqdev)
 1277 {
 1278         struct fsl_sdhc_softc *sc = device_get_softc(self);
 1279         int retval = 0;
 1280 
 1281         mtx_lock(&sc->mtx);
 1282 
 1283         while (sc->bus_busy)
 1284                 retval = mtx_sleep(sc, &sc->mtx, PZERO, "sdhcah", 0);
 1285         ++(sc->bus_busy);
 1286 
 1287         mtx_unlock(&sc->mtx);
 1288 
 1289         return (retval);
 1290 }
 1291 
 1292 static int
 1293 fsl_sdhc_release_host(device_t self, device_t reqdev)
 1294 {
 1295         struct fsl_sdhc_softc *sc = device_get_softc(self);
 1296 
 1297         mtx_lock(&sc->mtx);
 1298         --(sc->bus_busy);
 1299         mtx_unlock(&sc->mtx);
 1300         wakeup(sc);
 1301 
 1302         return (0);
 1303 }

Cache object: 10b00c3db130112d2ec9cc50a4cb242a


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.