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/dev/ic/w83l518d_sdmmc.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 /* $NetBSD: w83l518d_sdmmc.c,v 1.6 2021/08/07 16:19:12 thorpej Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   20  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   22  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __KERNEL_RCSID(0, "$NetBSD: w83l518d_sdmmc.c,v 1.6 2021/08/07 16:19:12 thorpej Exp $");
   30 
   31 #include <sys/param.h>
   32 #include <sys/kernel.h>
   33 #include <sys/systm.h>
   34 #include <sys/errno.h>
   35 #include <sys/ioctl.h>
   36 #include <sys/syslog.h>
   37 #include <sys/device.h>
   38 #include <sys/proc.h>
   39 
   40 #include <sys/bus.h>
   41 
   42 #include <dev/sdmmc/sdmmcvar.h>
   43 #include <dev/sdmmc/sdmmcchip.h>
   44 #include <dev/sdmmc/sdmmc_ioreg.h>
   45 
   46 #include <dev/ic/w83l518dreg.h>
   47 #include <dev/ic/w83l518dvar.h>
   48 #include <dev/ic/w83l518d_sdmmc.h>
   49 
   50 /* #define WB_SDMMC_DEBUG */
   51 
   52 #ifdef WB_SDMMC_DEBUG
   53 static int wb_sdmmc_debug = 1;
   54 #else
   55 static int wb_sdmmc_debug = 0;
   56 #endif
   57 
   58 #if defined(__NetBSD__) && __NetBSD_Version__ < 599000600
   59 #define snprintb(b, l, f, v) bitmask_snprintf((v), (f), (b), (l))
   60 #endif
   61 
   62 #define REPORT(_wb, ...)                                        \
   63         if (wb_sdmmc_debug > 0)                                 \
   64                 aprint_normal_dev(((struct wb_softc *)(_wb))->wb_dev, \
   65                                   __VA_ARGS__)
   66 
   67 static int      wb_sdmmc_host_reset(sdmmc_chipset_handle_t);
   68 static uint32_t wb_sdmmc_host_ocr(sdmmc_chipset_handle_t);
   69 static int      wb_sdmmc_host_maxblklen(sdmmc_chipset_handle_t);
   70 static int      wb_sdmmc_card_detect(sdmmc_chipset_handle_t);
   71 static int      wb_sdmmc_write_protect(sdmmc_chipset_handle_t);
   72 static int      wb_sdmmc_bus_power(sdmmc_chipset_handle_t, uint32_t);
   73 static int      wb_sdmmc_bus_clock(sdmmc_chipset_handle_t, int);
   74 static int      wb_sdmmc_bus_width(sdmmc_chipset_handle_t, int);
   75 static int      wb_sdmmc_bus_rod(sdmmc_chipset_handle_t, int);
   76 static void     wb_sdmmc_exec_command(sdmmc_chipset_handle_t,
   77                                       struct sdmmc_command *);
   78 static void     wb_sdmmc_card_enable_intr(sdmmc_chipset_handle_t, int);
   79 static void     wb_sdmmc_card_intr_ack(sdmmc_chipset_handle_t);
   80 
   81 static struct sdmmc_chip_functions wb_sdmmc_chip_functions = {
   82         .host_reset = wb_sdmmc_host_reset,
   83         .host_ocr = wb_sdmmc_host_ocr,
   84         .host_maxblklen = wb_sdmmc_host_maxblklen,
   85         .card_detect = wb_sdmmc_card_detect,
   86         .write_protect = wb_sdmmc_write_protect,
   87         .bus_power = wb_sdmmc_bus_power,
   88         .bus_clock = wb_sdmmc_bus_clock,
   89         .bus_width = wb_sdmmc_bus_width,
   90         .bus_rod = wb_sdmmc_bus_rod,
   91         .exec_command = wb_sdmmc_exec_command,
   92         .card_enable_intr = wb_sdmmc_card_enable_intr,
   93         .card_intr_ack = wb_sdmmc_card_intr_ack,
   94 };
   95 
   96 static void
   97 wb_sdmmc_read_data(struct wb_softc *wb, uint8_t *data, int len)
   98 {
   99         bus_space_read_multi_1(wb->wb_iot, wb->wb_ioh, WB_SD_FIFO, data, len);
  100 }
  101 
  102 static void
  103 wb_sdmmc_write_data(struct wb_softc *wb, uint8_t *data, int len)
  104 {
  105         bus_space_write_multi_1(wb->wb_iot, wb->wb_ioh, WB_SD_FIFO, data, len);
  106 }
  107 
  108 static void
  109 wb_sdmmc_discover(void *opaque)
  110 {
  111         struct wb_softc *wb = opaque;
  112 
  113         REPORT(wb, "TRACE: discover(wb)\n");
  114 
  115         sdmmc_needs_discover(wb->wb_sdmmc_dev);
  116 }
  117 
  118 static bool
  119 wb_sdmmc_enable(struct wb_softc *wb)
  120 {
  121         int i = 5000;
  122 
  123         REPORT(wb, "TRACE: enable(wb)\n");
  124 
  125         /* put the device in a known state */
  126         wb_idx_write(wb, WB_INDEX_SETUP, WB_SETUP_SOFT_RST);
  127         while (--i > 0 && wb_idx_read(wb, WB_INDEX_SETUP) & WB_SETUP_SOFT_RST)
  128                 delay(100);
  129         if (i == 0) {
  130                 aprint_error_dev(wb->wb_dev, "timeout resetting device\n");
  131                 return false;
  132         }
  133         wb_idx_write(wb, WB_INDEX_CLK, wb->wb_sdmmc_clk);
  134         wb_idx_write(wb, WB_INDEX_FIFOEN, 0);
  135         wb_idx_write(wb, WB_INDEX_DMA, 0);
  136         wb_idx_write(wb, WB_INDEX_PBSMSB, 0);
  137         wb_idx_write(wb, WB_INDEX_PBSLSB, 0);
  138         /* drain FIFO */
  139         while ((wb_read(wb, WB_SD_FIFOSTS) & WB_FIFO_EMPTY) == 0)
  140                 wb_read(wb, WB_SD_FIFO);
  141 
  142         wb_write(wb, WB_SD_CSR, 0);
  143 
  144         wb_write(wb, WB_SD_INTCTL, WB_INT_DEFAULT);
  145 
  146         wb_sdmmc_card_detect(wb);
  147 
  148         return true;
  149 }
  150 
  151 static bool
  152 wb_sdmmc_disable(struct wb_softc *wb)
  153 {
  154         uint8_t val;
  155 
  156         REPORT(wb, "TRACE: disable(wb)\n");
  157 
  158         val = wb_read(wb, WB_SD_CSR);
  159         val |= WB_CSR_POWER_N;
  160         wb_write(wb, WB_SD_CSR, val);
  161 
  162         return true;
  163 }
  164 
  165 void
  166 wb_sdmmc_attach(struct wb_softc *wb)
  167 {
  168         struct sdmmcbus_attach_args saa;
  169 
  170         callout_init(&wb->wb_sdmmc_callout, 0);
  171         callout_setfunc(&wb->wb_sdmmc_callout, wb_sdmmc_discover, wb);
  172 
  173         wb->wb_sdmmc_width = 1;
  174         wb->wb_sdmmc_clk = WB_CLK_375K;
  175 
  176         if (wb_sdmmc_enable(wb) == false)
  177                 return;
  178 
  179         memset(&saa, 0, sizeof(saa));
  180         saa.saa_busname = "sdmmc";
  181         saa.saa_sct = &wb_sdmmc_chip_functions;
  182         saa.saa_sch = wb;
  183         saa.saa_clkmin = 375;
  184         saa.saa_clkmax = 24000;
  185         if (!ISSET(wb->wb_quirks, WB_QUIRK_1BIT))
  186                 saa.saa_caps = SMC_CAPS_4BIT_MODE;
  187 
  188         wb->wb_sdmmc_dev = config_found(wb->wb_dev, &saa, NULL, CFARGS_NONE);
  189 }
  190 
  191 int
  192 wb_sdmmc_detach(struct wb_softc *wb, int flags)
  193 {
  194         int rv;
  195 
  196         if (wb->wb_sdmmc_dev) {
  197                 rv = config_detach(wb->wb_sdmmc_dev, flags);
  198                 if (rv)
  199                         return rv;
  200         }
  201         wb_sdmmc_disable(wb);
  202 
  203         callout_halt(&wb->wb_sdmmc_callout, NULL);
  204         callout_destroy(&wb->wb_sdmmc_callout);
  205 
  206         return 0;
  207 }
  208 
  209 /*
  210  * SD/MMC interface
  211  */
  212 static int
  213 wb_sdmmc_host_reset(sdmmc_chipset_handle_t sch)
  214 {
  215         REPORT(sch, "TRACE: sdmmc/host_reset(wb)\n");
  216 
  217         return 0;
  218 }
  219 
  220 static uint32_t
  221 wb_sdmmc_host_ocr(sdmmc_chipset_handle_t sch)
  222 {
  223         REPORT(sch, "TRACE: sdmmc/host_ocr(wb)\n");
  224 
  225         return MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V;
  226 }
  227 
  228 static int
  229 wb_sdmmc_host_maxblklen(sdmmc_chipset_handle_t sch)
  230 {
  231         REPORT(sch, "TRACE: sdmmc/host_maxblklen(wb)\n");
  232 
  233         return 512;     /* XXX */
  234 }
  235 
  236 static int
  237 wb_sdmmc_card_detect(sdmmc_chipset_handle_t sch)
  238 {
  239         struct wb_softc *wb = sch;
  240         int rv;
  241 
  242         wb_led(wb, true);
  243         rv = (wb_read(wb, WB_SD_CSR) & WB_CSR_CARD_PRESENT) ? 1 : 0;
  244         wb_led(wb, false);
  245 
  246         REPORT(wb, "TRACE: sdmmc/card_detect(wb) -> %d\n", rv);
  247 
  248         return rv;
  249 }
  250 
  251 static int
  252 wb_sdmmc_write_protect(sdmmc_chipset_handle_t sch)
  253 {
  254         struct wb_softc *wb = sch;
  255         int rv;
  256 
  257         wb_led(wb, true);
  258         rv = (wb_read(wb, WB_SD_CSR) & WB_CSR_WRITE_PROTECT) ? 1 : 0;
  259         wb_led(wb, false);
  260 
  261         REPORT(wb, "TRACE: sdmmc/write_protect(wb) -> %d\n", rv);
  262 
  263         return rv;
  264 }
  265 
  266 static int
  267 wb_sdmmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
  268 {
  269         REPORT(sch, "TRACE: sdmmc/bus_power(wb, ocr=%x)\n", ocr);
  270 
  271         return 0;
  272 }
  273 
  274 static int
  275 wb_sdmmc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
  276 {
  277         struct wb_softc *wb = sch;
  278         uint8_t clk;
  279 
  280         REPORT(wb, "TRACE: sdmmc/bus_clock(wb, freq=%d)\n", freq);
  281 
  282         if (freq >= 24000)
  283                 clk = WB_CLK_24M;
  284         else if (freq >= 16000)
  285                 clk = WB_CLK_16M;
  286         else if (freq >= 12000)
  287                 clk = WB_CLK_12M;
  288         else
  289                 clk = WB_CLK_375K;
  290 
  291         wb->wb_sdmmc_clk = clk;
  292 
  293         if (wb_idx_read(wb, WB_INDEX_CLK) != clk)
  294                 wb_idx_write(wb, WB_INDEX_CLK, clk);
  295 
  296         return 0;
  297 }
  298 
  299 static int
  300 wb_sdmmc_bus_width(sdmmc_chipset_handle_t sch, int width)
  301 {
  302         struct wb_softc *wb = sch;
  303 
  304         REPORT(wb, "TRACE: sdmmc/bus_width(wb, width=%d)\n", width);
  305 
  306         if (width != 1 && width != 4)
  307                 return 1;
  308 
  309         wb->wb_sdmmc_width = width;
  310 
  311         return 0;
  312 }
  313 
  314 static int
  315 wb_sdmmc_bus_rod(sdmmc_chipset_handle_t sch, int on)
  316 {
  317 
  318         /* Not support */
  319         return -1;
  320 }
  321 
  322 
  323 static void
  324 wb_sdmmc_rsp_read_long(struct wb_softc *wb, struct sdmmc_command *cmd)
  325 {
  326         uint8_t *p = (uint8_t *)cmd->c_resp;
  327         int i;
  328 
  329         if (wb_idx_read(wb, WB_INDEX_RESPLEN) != 1) {
  330                 cmd->c_error = ENXIO;
  331                 return;
  332         }
  333 
  334         for (i = 12; i >= 0; i -= 4) {
  335 #if BYTE_ORDER == LITTLE_ENDIAN
  336                 p[3] = wb_idx_read(wb, WB_INDEX_RESP(i + 0));
  337                 p[2] = wb_idx_read(wb, WB_INDEX_RESP(i + 1));
  338                 p[1] = wb_idx_read(wb, WB_INDEX_RESP(i + 2));
  339                 p[0] = wb_idx_read(wb, WB_INDEX_RESP(i + 3));
  340 #else
  341                 p[0] = wb_idx_read(wb, WB_INDEX_RESP(i + 0));
  342                 p[1] = wb_idx_read(wb, WB_INDEX_RESP(i + 1));
  343                 p[2] = wb_idx_read(wb, WB_INDEX_RESP(i + 2));
  344                 p[3] = wb_idx_read(wb, WB_INDEX_RESP(i + 3));
  345 #endif
  346                 REPORT(wb, "TRACE: sdmmc/read_long (%d) 0x%08x\n",
  347                     (12 - i) / 4, cmd->c_resp[(12 - i) / 4]);
  348                 p += 4;
  349         }
  350 }
  351 
  352 static void
  353 wb_sdmmc_rsp_read_short(struct wb_softc *wb, struct sdmmc_command *cmd)
  354 {
  355         uint8_t *p = (uint8_t *)cmd->c_resp;
  356 
  357         if (wb_idx_read(wb, WB_INDEX_RESPLEN) != 0) {
  358                 cmd->c_error = ENXIO;
  359                 return;
  360         }
  361 
  362 #if BYTE_ORDER == LITTLE_ENDIAN
  363         p[3] = wb_idx_read(wb, WB_INDEX_RESP(12));
  364         p[2] = wb_idx_read(wb, WB_INDEX_RESP(13));
  365         p[1] = wb_idx_read(wb, WB_INDEX_RESP(14));
  366         p[0] = wb_idx_read(wb, WB_INDEX_RESP(15));
  367 #else
  368         p[0] = wb_idx_read(wb, WB_INDEX_RESP(12));
  369         p[1] = wb_idx_read(wb, WB_INDEX_RESP(13));
  370         p[2] = wb_idx_read(wb, WB_INDEX_RESP(14));
  371         p[3] = wb_idx_read(wb, WB_INDEX_RESP(15));
  372 #endif
  373         REPORT(wb, "TRACE: sdmmc/read_short 0x%08x\n",
  374             cmd->c_resp[0]);
  375 }
  376 
  377 static int
  378 wb_sdmmc_transfer_data(struct wb_softc *wb, struct sdmmc_command *cmd)
  379 {
  380         uint8_t fifosts;
  381         int datalen, retry = 5000;
  382 
  383         if (wb->wb_sdmmc_intsts & WB_INT_CARD)
  384                 return EIO;
  385 
  386         fifosts = wb_read(wb, WB_SD_FIFOSTS);
  387         if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
  388                 if (fifosts & WB_FIFO_EMPTY) {
  389                         while (--retry > 0) {
  390                                 fifosts = wb_read(wb, WB_SD_FIFOSTS);
  391                                 if ((fifosts & WB_FIFO_EMPTY) == 0)
  392                                         break;
  393                                 delay(100);
  394                         }
  395                         if (retry == 0)
  396                                 return EBUSY;
  397                 }
  398 
  399                 if (fifosts & WB_FIFO_FULL)
  400                         datalen = 16;
  401                 else
  402                         datalen = fifosts & WB_FIFO_DEPTH_MASK;
  403         } else {
  404                 if (fifosts & WB_FIFO_FULL) {
  405                         while (--retry > 0) {
  406                                 fifosts = wb_read(wb, WB_SD_FIFOSTS);
  407                                 if ((fifosts & WB_FIFO_FULL) == 0)
  408                                         break;
  409                                 delay(100);
  410                         }
  411                         if (retry == 0)
  412                                 return EBUSY;
  413                 }
  414 
  415                 if (fifosts & WB_FIFO_EMPTY)
  416                         datalen = 16;
  417                 else
  418                         datalen = 16 - (fifosts & WB_FIFO_DEPTH_MASK);
  419         }
  420 
  421         datalen = MIN(datalen, cmd->c_resid);
  422         if (datalen > 0) {
  423                 if (ISSET(cmd->c_flags, SCF_CMD_READ))
  424                         wb_sdmmc_read_data(wb, cmd->c_buf, datalen);
  425                 else
  426                         wb_sdmmc_write_data(wb, cmd->c_buf, datalen);
  427 
  428                 cmd->c_buf += datalen;
  429                 cmd->c_resid -= datalen;
  430         }
  431 
  432         return 0;
  433 }
  434 
  435 static void
  436 wb_sdmmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
  437 {
  438         static const int opcodes[] = {
  439                 11, 17, 18, 20, 24, 25, 26, 27, 30, 42, 51, 56
  440         };
  441         struct wb_softc *wb = sch;
  442         uint8_t val;
  443         int blklen;
  444         int error;
  445         int i, retry;
  446         int s;
  447 
  448         REPORT(wb, "TRACE: sdmmc/exec_command(wb, cmd) "
  449             "opcode %d flags 0x%x data %p datalen %d arg 0x%08x\n",
  450             cmd->c_opcode, cmd->c_flags, cmd->c_data, cmd->c_datalen,
  451             cmd->c_arg);
  452 
  453         if (cmd->c_datalen > 0) {
  454                 /* controller only supports a select number of data opcodes */
  455                 for (i = 0; i < __arraycount(opcodes); i++)
  456                         if (opcodes[i] == cmd->c_opcode)
  457                                 break;
  458                 if (i == __arraycount(opcodes)) {
  459                         cmd->c_error = ENOTSUP;
  460                         aprint_debug_dev(wb->wb_dev,
  461                             "unsupported opcode %d\n", cmd->c_opcode);
  462                         goto done;
  463                 }
  464 
  465                 /* Fragment the data into proper blocks */
  466                 blklen = MIN(cmd->c_datalen, cmd->c_blklen);
  467 
  468                 if (cmd->c_datalen % blklen > 0) {
  469                         aprint_error_dev(wb->wb_dev,
  470                             "data is not a multiple of %u bytes\n", blklen);
  471                         cmd->c_error = EINVAL;
  472                         goto done;
  473                 }
  474 
  475                 /* setup block size registers */
  476                 blklen = blklen + 2 * wb->wb_sdmmc_width;
  477                 wb_idx_write(wb, WB_INDEX_PBSMSB,
  478                     ((blklen >> 4) & 0xf0) | (wb->wb_sdmmc_width / 4));
  479                 wb_idx_write(wb, WB_INDEX_PBSLSB, blklen & 0xff);
  480 
  481                 /* clear FIFO */
  482                 val = wb_idx_read(wb, WB_INDEX_SETUP);
  483                 val |= WB_SETUP_FIFO_RST;
  484                 wb_idx_write(wb, WB_INDEX_SETUP, val);
  485                 while (wb_idx_read(wb, WB_INDEX_SETUP) & WB_SETUP_FIFO_RST)
  486                         ;
  487 
  488                 cmd->c_resid = cmd->c_datalen;
  489                 cmd->c_buf = cmd->c_data;
  490 
  491                 /* setup FIFO thresholds */
  492                 if (ISSET(cmd->c_flags, SCF_CMD_READ))
  493                         wb_idx_write(wb, WB_INDEX_FIFOEN, WB_FIFOEN_FULL | 8);
  494                 else {
  495                         wb_idx_write(wb, WB_INDEX_FIFOEN, WB_FIFOEN_EMPTY | 8);
  496 
  497                         /* pre-fill the FIFO on write */
  498                         error = wb_sdmmc_transfer_data(wb, cmd);
  499                         if (error) {
  500                                 cmd->c_error = error;
  501                                 goto done;
  502                         }
  503                 }
  504         }
  505 
  506         s = splsdmmc();
  507         wb->wb_sdmmc_intsts = 0;
  508         wb_write(wb, WB_SD_COMMAND, cmd->c_opcode);
  509         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 24) & 0xff);
  510         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 16) & 0xff);
  511         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 8) & 0xff);
  512         wb_write(wb, WB_SD_COMMAND, (cmd->c_arg >> 0) & 0xff);
  513         splx(s);
  514 
  515         retry = 100000;
  516         while (wb_idx_read(wb, WB_INDEX_STATUS) & WB_STATUS_CARD_TRAFFIC) {
  517                 if (--retry == 0)
  518                         break;
  519                 delay(1);
  520         }
  521         if (wb_idx_read(wb, WB_INDEX_STATUS) & WB_STATUS_CARD_TRAFFIC) {
  522                 REPORT(wb,
  523                     "command timed out, WB_INDEX_STATUS = 0x%02x\n",
  524                     wb_idx_read(wb, WB_INDEX_STATUS));
  525                 cmd->c_error = ETIMEDOUT;
  526                 goto done;
  527         }
  528 
  529         if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
  530                 if (wb->wb_sdmmc_intsts & WB_INT_TIMEOUT) {
  531                         cmd->c_error = ETIMEDOUT;
  532                         goto done;
  533                 }
  534 
  535                 if (ISSET(cmd->c_flags, SCF_RSP_136))
  536                         wb_sdmmc_rsp_read_long(wb, cmd);
  537                 else
  538                         wb_sdmmc_rsp_read_short(wb, cmd);
  539         }
  540 
  541         if (cmd->c_error == 0 && cmd->c_datalen > 0) {
  542                 wb_led(wb, true);
  543                 while (cmd->c_resid > 0) {
  544                         error = wb_sdmmc_transfer_data(wb, cmd);
  545                         if (error) {
  546                                 cmd->c_error = error;
  547                                 break;
  548                         }
  549                 }
  550                 wb_led(wb, false);
  551         }
  552 
  553 done:
  554         SET(cmd->c_flags, SCF_ITSDONE);
  555 
  556         if (cmd->c_error) {
  557                 REPORT(wb,
  558                     "cmd error = %d, op = %d [%s] "
  559                     "blklen %d datalen %d resid %d\n",
  560                     cmd->c_error, cmd->c_opcode,
  561                     ISSET(cmd->c_flags, SCF_CMD_READ) ? "rd" : "wr",
  562                     cmd->c_blklen, cmd->c_datalen, cmd->c_resid);
  563         }
  564 }
  565                                       
  566 static void
  567 wb_sdmmc_card_enable_intr(sdmmc_chipset_handle_t sch, int enable)
  568 {
  569         REPORT(sch, "TRACE: sdmmc/card_enable_intr(wb, enable=%d)\n", enable);
  570 }
  571 
  572 static void
  573 wb_sdmmc_card_intr_ack(sdmmc_chipset_handle_t sch)
  574 {
  575         REPORT(sch, "TRACE: sdmmc/card_intr_ack(wb)\n");
  576 }
  577 
  578 /*
  579  * intr handler 
  580  */
  581 int
  582 wb_sdmmc_intr(struct wb_softc *wb)
  583 {
  584         uint8_t val;
  585 
  586         val = wb_read(wb, WB_SD_INTSTS);
  587         if (val == 0xff || val == 0x00)
  588                 return 0;
  589 
  590         if (wb->wb_sdmmc_dev == NULL)
  591                 return 1;
  592 
  593         wb->wb_sdmmc_intsts |= val;
  594 
  595         if (wb_sdmmc_debug) {
  596                 char buf[64];
  597                 snprintb(buf, sizeof(buf),
  598                     "\2\1TC\2BUSYEND\3PROGEND\4TIMEOUT"
  599                     "\5CRC\6FIFO\7CARD\010PENDING",
  600                     val);
  601                 REPORT(wb, "WB_SD_INTSTS = %s\n", buf);
  602         }
  603 
  604         if (val & WB_INT_CARD)
  605                 callout_schedule(&wb->wb_sdmmc_callout, hz / 4);
  606 
  607         return 1;
  608 }
  609 
  610 /*
  611  * pmf
  612  */
  613 bool
  614 wb_sdmmc_suspend(struct wb_softc *wb)
  615 {
  616         return wb_sdmmc_disable(wb);
  617 }
  618 
  619 bool
  620 wb_sdmmc_resume(struct wb_softc *wb)
  621 {
  622         uint8_t val;
  623 
  624         val = wb_read(wb, WB_SD_CSR);
  625         val &= ~WB_CSR_POWER_N;
  626         wb_write(wb, WB_SD_CSR, val);
  627 
  628         if (wb_sdmmc_enable(wb) == false)
  629                 return false;
  630 
  631         if (wb_idx_read(wb, WB_INDEX_CLK) != wb->wb_sdmmc_clk)
  632                 wb_idx_write(wb, WB_INDEX_CLK, wb->wb_sdmmc_clk);
  633 
  634         return true;
  635 }

Cache object: bcdd20bc5c51f52db258ec4783b8611a


[ 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.