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/sdhci/sdhci_fdt.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  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2012 Thomas Skibo
    5  * Copyright (c) 2008 Alexander Motin <mav@FreeBSD.org>
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 /* Generic driver to attach sdhci controllers on simplebus.
   30  * Derived mainly from sdhci_pci.c
   31  */
   32 
   33 #include <sys/cdefs.h>
   34 __FBSDID("$FreeBSD$");
   35 
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/kernel.h>
   40 #include <sys/lock.h>
   41 #include <sys/module.h>
   42 #include <sys/mutex.h>
   43 #include <sys/resource.h>
   44 #include <sys/rman.h>
   45 #include <sys/sysctl.h>
   46 #include <sys/taskqueue.h>
   47 
   48 #include <machine/bus.h>
   49 #include <machine/resource.h>
   50 
   51 #include <dev/fdt/fdt_common.h>
   52 #include <dev/ofw/ofw_bus.h>
   53 #include <dev/ofw/ofw_bus_subr.h>
   54 
   55 #include <dev/ofw/ofw_subr.h>
   56 #include <dev/extres/clk/clk.h>
   57 #include <dev/extres/clk/clk_fixed.h>
   58 #include <dev/extres/syscon/syscon.h>
   59 #include <dev/extres/phy/phy.h>
   60 
   61 #include <dev/mmc/bridge.h>
   62 
   63 #include <dev/sdhci/sdhci.h>
   64 
   65 #include "mmcbr_if.h"
   66 #include "sdhci_if.h"
   67 
   68 #include "opt_mmccam.h"
   69 
   70 #include "clkdev_if.h"
   71 #include "syscon_if.h"
   72 
   73 #define MAX_SLOTS               6
   74 #define SDHCI_FDT_ARMADA38X     1
   75 #define SDHCI_FDT_GENERIC       2
   76 #define SDHCI_FDT_XLNX_ZY7      3
   77 #define SDHCI_FDT_QUALCOMM      4
   78 #define SDHCI_FDT_RK3399        5
   79 #define SDHCI_FDT_RK3568        6
   80 
   81 #define RK3399_GRF_EMMCCORE_CON0                0xf000
   82 #define  RK3399_CORECFG_BASECLKFREQ             0xff00
   83 #define  RK3399_CORECFG_TIMEOUTCLKUNIT          (1 << 7)
   84 #define  RK3399_CORECFG_TUNINGCOUNT             0x3f
   85 #define RK3399_GRF_EMMCCORE_CON11               0xf02c
   86 #define  RK3399_CORECFG_CLOCKMULTIPLIER         0xff
   87 
   88 #define RK3568_EMMC_HOST_CTRL                   0x0508
   89 #define RK3568_EMMC_EMMC_CTRL                   0x052c
   90 #define RK3568_EMMC_ATCTRL                      0x0540
   91 #define RK3568_EMMC_DLL_CTRL                    0x0800
   92 #define  DLL_CTRL_SRST                          0x00000001
   93 #define  DLL_CTRL_START                         0x00000002
   94 #define  DLL_CTRL_START_POINT_DEFAULT           0x00050000
   95 #define  DLL_CTRL_INCREMENT_DEFAULT             0x00000200
   96 
   97 #define RK3568_EMMC_DLL_RXCLK                   0x0804
   98 #define  DLL_RXCLK_DELAY_ENABLE                 0x08000000
   99 #define  DLL_RXCLK_NO_INV                       0x20000000
  100 
  101 #define RK3568_EMMC_DLL_TXCLK                   0x0808
  102 #define  DLL_TXCLK_DELAY_ENABLE                 0x08000000
  103 #define  DLL_TXCLK_TAPNUM_DEFAULT               0x00000008
  104 #define  DLL_TXCLK_TAPNUM_FROM_SW               0x01000000
  105 
  106 #define RK3568_EMMC_DLL_STRBIN                  0x080c
  107 #define  DLL_STRBIN_DELAY_ENABLE                0x08000000
  108 #define  DLL_STRBIN_TAPNUM_DEFAULT              0x00000008
  109 #define DLL_STRBIN_TAPNUM_FROM_SW               0x01000000
  110 
  111 #define RK3568_EMMC_DLL_STATUS0                 0x0840
  112 #define  DLL_STATUS0_DLL_LOCK                   0x00000100
  113 #define  DLL_STATUS0_DLL_TIMEOUT                0x00000200
  114 
  115 #define LOWEST_SET_BIT(mask)    ((((mask) - 1) & (mask)) ^ (mask))
  116 #define SHIFTIN(x, mask)        ((x) * LOWEST_SET_BIT(mask))
  117 
  118 #define EMMCCARDCLK_ID          1000
  119 
  120 static struct ofw_compat_data compat_data[] = {
  121         { "marvell,armada-380-sdhci",   SDHCI_FDT_ARMADA38X },
  122         { "sdhci_generic",              SDHCI_FDT_GENERIC },
  123         { "qcom,sdhci-msm-v4",          SDHCI_FDT_QUALCOMM },
  124         { "rockchip,rk3399-sdhci-5.1",  SDHCI_FDT_RK3399 },
  125         { "xlnx,zy7_sdhci",             SDHCI_FDT_XLNX_ZY7 },
  126         { "rockchip,rk3568-dwcmshc",    SDHCI_FDT_RK3568 },
  127         { NULL, 0 }
  128 };
  129 
  130 struct sdhci_fdt_softc {
  131         device_t        dev;            /* Controller device */
  132         u_int           quirks;         /* Chip specific quirks */
  133         u_int           caps;           /* If we override SDHCI_CAPABILITIES */
  134         uint32_t        max_clk;        /* Max possible freq */
  135         uint8_t         sdma_boundary;  /* If we override the SDMA boundary */
  136         struct resource *irq_res;       /* IRQ resource */
  137         void            *intrhand;      /* Interrupt handle */
  138 
  139         int             num_slots;      /* Number of slots on this controller*/
  140         struct sdhci_slot slots[MAX_SLOTS];
  141         struct resource *mem_res[MAX_SLOTS];    /* Memory resource */
  142 
  143         bool            wp_inverted;    /* WP pin is inverted */
  144         bool            no_18v;         /* No 1.8V support */
  145 
  146         clk_t           clk_xin;        /* xin24m fixed clock */
  147         clk_t           clk_ahb;        /* ahb clock */
  148         clk_t           clk_core;       /* core clock */
  149         phy_t           phy;            /* phy to be used */
  150 };
  151 
  152 struct rk3399_emmccardclk_sc {
  153         device_t        clkdev;
  154         bus_addr_t      reg;
  155 };
  156 
  157 static int
  158 rk3399_emmccardclk_init(struct clknode *clk, device_t dev)
  159 {
  160 
  161         clknode_init_parent_idx(clk, 0);
  162         return (0);
  163 }
  164 
  165 static clknode_method_t rk3399_emmccardclk_clknode_methods[] = {
  166         /* Device interface */
  167         CLKNODEMETHOD(clknode_init,     rk3399_emmccardclk_init),
  168         CLKNODEMETHOD_END
  169 };
  170 DEFINE_CLASS_1(rk3399_emmccardclk_clknode, rk3399_emmccardclk_clknode_class,
  171     rk3399_emmccardclk_clknode_methods, sizeof(struct rk3399_emmccardclk_sc),
  172     clknode_class);
  173 
  174 static int
  175 rk3399_ofw_map(struct clkdom *clkdom, uint32_t ncells,
  176     phandle_t *cells, struct clknode **clk)
  177 {
  178 
  179         if (ncells == 0)
  180                 *clk = clknode_find_by_id(clkdom, EMMCCARDCLK_ID);
  181         else
  182                 return (ERANGE);
  183 
  184         if (*clk == NULL)
  185                 return (ENXIO);
  186         return (0);
  187 }
  188 
  189 static void
  190 sdhci_init_rk3399_emmccardclk(device_t dev)
  191 {
  192         struct clknode_init_def def;
  193         struct rk3399_emmccardclk_sc *sc;
  194         struct clkdom *clkdom;
  195         struct clknode *clk;
  196         clk_t clk_parent;
  197         bus_addr_t paddr;
  198         bus_size_t psize;
  199         const char **clknames;
  200         phandle_t node;
  201         int i, nclocks, ncells, error;
  202 
  203         node = ofw_bus_get_node(dev);
  204 
  205         if (ofw_reg_to_paddr(node, 0, &paddr, &psize, NULL) != 0) {
  206                 device_printf(dev, "cannot parse 'reg' property\n");
  207                 return;
  208         }
  209 
  210         error = ofw_bus_parse_xref_list_get_length(node, "clocks",
  211             "#clock-cells", &ncells);
  212         if (error != 0 || ncells != 2) {
  213                 device_printf(dev, "couldn't find parent clocks\n");
  214                 return;
  215         }
  216 
  217         nclocks = ofw_bus_string_list_to_array(node, "clock-output-names",
  218             &clknames);
  219         /* No clocks to export */
  220         if (nclocks <= 0)
  221                 return;
  222 
  223         if (nclocks != 1) {
  224                 device_printf(dev, "Having %d clock instead of 1, aborting\n",
  225                     nclocks);
  226                 return;
  227         }
  228 
  229         clkdom = clkdom_create(dev);
  230         clkdom_set_ofw_mapper(clkdom, rk3399_ofw_map);
  231 
  232         memset(&def, 0, sizeof(def));
  233         def.id = EMMCCARDCLK_ID;
  234         def.name = clknames[0];
  235         def.parent_names = malloc(sizeof(char *) * ncells, M_OFWPROP, M_WAITOK);
  236         for (i = 0; i < ncells; i++) {
  237                 error = clk_get_by_ofw_index(dev, 0, i, &clk_parent);
  238                 if (error != 0) {
  239                         device_printf(dev, "cannot get clock %d\n", error);
  240                         return;
  241                 }
  242                 def.parent_names[i] = clk_get_name(clk_parent);
  243                 if (bootverbose)
  244                         device_printf(dev, "clk parent: %s\n",
  245                             def.parent_names[i]);
  246                 clk_release(clk_parent);
  247         }
  248         def.parent_cnt = ncells;
  249 
  250         clk = clknode_create(clkdom, &rk3399_emmccardclk_clknode_class, &def);
  251         if (clk == NULL) {
  252                 device_printf(dev, "cannot create clknode\n");
  253                 return;
  254         }
  255 
  256         sc = clknode_get_softc(clk);
  257         sc->reg = paddr;
  258         sc->clkdev = device_get_parent(dev);
  259 
  260         clknode_register(clkdom, clk);
  261 
  262         if (clkdom_finit(clkdom) != 0) {
  263                 device_printf(dev, "cannot finalize clkdom initialization\n");
  264                 return;
  265         }
  266 
  267         if (bootverbose)
  268                 clkdom_dump(clkdom);
  269 }
  270 
  271 static int
  272 sdhci_init_rk3399(device_t dev)
  273 {
  274         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  275         struct syscon *grf = NULL;
  276         phandle_t node;
  277         uint64_t freq;
  278         uint32_t mask, val;
  279         int error;
  280 
  281         /* Get and activate clocks */
  282         error = clk_get_by_ofw_name(dev, 0, "clk_xin", &sc->clk_xin);
  283         if (error != 0) {
  284                 device_printf(dev, "cannot get xin clock\n");
  285                 return (ENXIO);
  286         }
  287         error = clk_enable(sc->clk_xin);
  288         if (error != 0) {
  289                 device_printf(dev, "cannot enable xin clock\n");
  290                 return (ENXIO);
  291         }
  292         error = clk_get_freq(sc->clk_xin, &freq);
  293         if (error != 0) {
  294                 device_printf(dev, "cannot get xin clock frequency\n");
  295                 return (ENXIO);
  296         }
  297         error = clk_get_by_ofw_name(dev, 0, "clk_ahb", &sc->clk_ahb);
  298         if (error != 0) {
  299                 device_printf(dev, "cannot get ahb clock\n");
  300                 return (ENXIO);
  301         }
  302         error = clk_enable(sc->clk_ahb);
  303         if (error != 0) {
  304                 device_printf(dev, "cannot enable ahb clock\n");
  305                 return (ENXIO);
  306         }
  307 
  308         /* Register clock */
  309         sdhci_init_rk3399_emmccardclk(dev);
  310 
  311         /* Enable PHY */
  312         error = phy_get_by_ofw_name(dev, 0, "phy_arasan", &sc->phy);
  313         if (error != 0) {
  314                 device_printf(dev, "Could not get phy\n");
  315                 return (ENXIO);
  316         }
  317         error = phy_enable(sc->phy);
  318         if (error != 0) {
  319                 device_printf(dev, "Could not enable phy\n");
  320                 return (ENXIO);
  321         }
  322         /* Get syscon */
  323         node = ofw_bus_get_node(dev);
  324         if (OF_hasprop(node, "arasan,soc-ctl-syscon") &&
  325             syscon_get_by_ofw_property(dev, node,
  326             "arasan,soc-ctl-syscon", &grf) != 0) {
  327                 device_printf(dev, "cannot get grf driver handle\n");
  328                 return (ENXIO);
  329         }
  330 
  331         /* Disable clock multiplier */
  332         mask = RK3399_CORECFG_CLOCKMULTIPLIER;
  333         val = 0;
  334         SYSCON_WRITE_4(grf, RK3399_GRF_EMMCCORE_CON11, (mask << 16) | val);
  335 
  336         /* Set base clock frequency */
  337         mask = RK3399_CORECFG_BASECLKFREQ;
  338         val = SHIFTIN((freq + (1000000 / 2)) / 1000000,
  339             RK3399_CORECFG_BASECLKFREQ);
  340         SYSCON_WRITE_4(grf, RK3399_GRF_EMMCCORE_CON0, (mask << 16) | val);
  341 
  342         return (0);
  343 }
  344 
  345 static uint8_t
  346 sdhci_fdt_read_1(device_t dev, struct sdhci_slot *slot, bus_size_t off)
  347 {
  348         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  349 
  350         return (bus_read_1(sc->mem_res[slot->num], off));
  351 }
  352 
  353 static void
  354 sdhci_fdt_write_1(device_t dev, struct sdhci_slot *slot, bus_size_t off,
  355     uint8_t val)
  356 {
  357         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  358 
  359         bus_write_1(sc->mem_res[slot->num], off, val);
  360 }
  361 
  362 static uint16_t
  363 sdhci_fdt_read_2(device_t dev, struct sdhci_slot *slot, bus_size_t off)
  364 {
  365         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  366 
  367         return (bus_read_2(sc->mem_res[slot->num], off));
  368 }
  369 
  370 static void
  371 sdhci_fdt_write_2(device_t dev, struct sdhci_slot *slot, bus_size_t off,
  372     uint16_t val)
  373 {
  374         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  375 
  376         bus_write_2(sc->mem_res[slot->num], off, val);
  377 }
  378 
  379 static uint32_t
  380 sdhci_fdt_read_4(device_t dev, struct sdhci_slot *slot, bus_size_t off)
  381 {
  382         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  383         uint32_t val32;
  384 
  385         val32 = bus_read_4(sc->mem_res[slot->num], off);
  386         if (off == SDHCI_CAPABILITIES && sc->no_18v)
  387                 val32 &= ~SDHCI_CAN_VDD_180;
  388 
  389         return (val32);
  390 }
  391 
  392 static void
  393 sdhci_fdt_write_4(device_t dev, struct sdhci_slot *slot, bus_size_t off,
  394     uint32_t val)
  395 {
  396         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  397 
  398         bus_write_4(sc->mem_res[slot->num], off, val);
  399 }
  400 
  401 static void
  402 sdhci_fdt_read_multi_4(device_t dev, struct sdhci_slot *slot,
  403     bus_size_t off, uint32_t *data, bus_size_t count)
  404 {
  405         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  406 
  407         bus_read_multi_4(sc->mem_res[slot->num], off, data, count);
  408 }
  409 
  410 static void
  411 sdhci_fdt_write_multi_4(device_t dev, struct sdhci_slot *slot,
  412     bus_size_t off, uint32_t *data, bus_size_t count)
  413 {
  414         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  415 
  416         bus_write_multi_4(sc->mem_res[slot->num], off, data, count);
  417 }
  418 
  419 static void
  420 sdhci_fdt_intr(void *arg)
  421 {
  422         struct sdhci_fdt_softc *sc = (struct sdhci_fdt_softc *)arg;
  423         int i;
  424 
  425         for (i = 0; i < sc->num_slots; i++)
  426                 sdhci_generic_intr(&sc->slots[i]);
  427 }
  428 
  429 static int
  430 sdhci_fdt_get_ro(device_t bus, device_t dev)
  431 {
  432         struct sdhci_fdt_softc *sc = device_get_softc(bus);
  433 
  434         return (sdhci_generic_get_ro(bus, dev) ^ sc->wp_inverted);
  435 }
  436 
  437 static int
  438 sdhci_fdt_set_clock(device_t dev, struct sdhci_slot *slot, int clock)
  439 {
  440         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  441         int32_t val;
  442         int i;
  443 
  444         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
  445             SDHCI_FDT_RK3568) {
  446                 if (clock == 400000)
  447                         clock = 375000;
  448 
  449                 if (clock) {
  450                         clk_set_freq(sc->clk_core, clock, 0);
  451 
  452                         if (clock <= 52000000) {
  453                                 bus_write_4(sc->mem_res[slot->num],
  454                                     RK3568_EMMC_DLL_CTRL, 0x0);
  455                                 bus_write_4(sc->mem_res[slot->num],
  456                                     RK3568_EMMC_DLL_RXCLK, DLL_RXCLK_NO_INV);
  457                                 bus_write_4(sc->mem_res[slot->num],
  458                                     RK3568_EMMC_DLL_TXCLK, 0x0);
  459                                 bus_write_4(sc->mem_res[slot->num],
  460                                     RK3568_EMMC_DLL_STRBIN, 0x0);
  461                                 return (clock);
  462                         }
  463 
  464                         bus_write_4(sc->mem_res[slot->num],
  465                             RK3568_EMMC_DLL_CTRL, DLL_CTRL_START);
  466                         DELAY(1000);
  467                         bus_write_4(sc->mem_res[slot->num],
  468                             RK3568_EMMC_DLL_CTRL, 0);
  469                         bus_write_4(sc->mem_res[slot->num],
  470                             RK3568_EMMC_DLL_CTRL, DLL_CTRL_START_POINT_DEFAULT |
  471                             DLL_CTRL_INCREMENT_DEFAULT | DLL_CTRL_START);
  472                         for (i = 0; i < 500; i++) {
  473                                 val = bus_read_4(sc->mem_res[slot->num],
  474                                     RK3568_EMMC_DLL_STATUS0);
  475                                 if (val & DLL_STATUS0_DLL_LOCK &&
  476                                     !(val & DLL_STATUS0_DLL_TIMEOUT))
  477                                         break;
  478                                 DELAY(1000);
  479                         }
  480                         bus_write_4(sc->mem_res[slot->num], RK3568_EMMC_ATCTRL,
  481                             (0x1 << 16 | 0x2 << 17 | 0x3 << 19));
  482                         bus_write_4(sc->mem_res[slot->num],
  483                             RK3568_EMMC_DLL_RXCLK,
  484                             DLL_RXCLK_DELAY_ENABLE | DLL_RXCLK_NO_INV);
  485                         bus_write_4(sc->mem_res[slot->num],
  486                             RK3568_EMMC_DLL_TXCLK, DLL_TXCLK_DELAY_ENABLE |
  487                             DLL_TXCLK_TAPNUM_DEFAULT|DLL_TXCLK_TAPNUM_FROM_SW);
  488                         bus_write_4(sc->mem_res[slot->num],
  489                             RK3568_EMMC_DLL_STRBIN, DLL_STRBIN_DELAY_ENABLE |
  490                             DLL_STRBIN_TAPNUM_DEFAULT |
  491                             DLL_STRBIN_TAPNUM_FROM_SW);
  492                 }
  493         }
  494         return (clock);
  495 }
  496 
  497 static int
  498 sdhci_fdt_probe(device_t dev)
  499 {
  500         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  501         phandle_t node;
  502         pcell_t cid;
  503 
  504         sc->quirks = 0;
  505         sc->num_slots = 1;
  506         sc->max_clk = 0;
  507 
  508         if (!ofw_bus_status_okay(dev))
  509                 return (ENXIO);
  510 
  511         switch (ofw_bus_search_compatible(dev, compat_data)->ocd_data) {
  512         case SDHCI_FDT_ARMADA38X:
  513                 sc->quirks = SDHCI_QUIRK_BROKEN_AUTO_STOP;
  514                 device_set_desc(dev, "ARMADA38X SDHCI controller");
  515                 break;
  516         case SDHCI_FDT_GENERIC:
  517                 device_set_desc(dev, "generic fdt SDHCI controller");
  518                 break;
  519         case SDHCI_FDT_QUALCOMM:
  520                 sc->quirks = SDHCI_QUIRK_ALL_SLOTS_NON_REMOVABLE |
  521                     SDHCI_QUIRK_BROKEN_SDMA_BOUNDARY;
  522                 sc->sdma_boundary = SDHCI_BLKSZ_SDMA_BNDRY_4K;
  523                 device_set_desc(dev, "Qualcomm FDT SDHCI controller");
  524                 break;
  525         case SDHCI_FDT_RK3399:
  526                 device_set_desc(dev, "Rockchip RK3399 fdt SDHCI controller");
  527                 break;
  528         case SDHCI_FDT_XLNX_ZY7:
  529                 sc->quirks = SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK;
  530                 device_set_desc(dev, "Zynq-7000 generic fdt SDHCI controller");
  531                 break;
  532         case SDHCI_FDT_RK3568:
  533                 device_set_desc(dev, "Rockchip RK3568 fdt SDHCI controller");
  534                 break;
  535         default:
  536                 return (ENXIO);
  537         }
  538 
  539         node = ofw_bus_get_node(dev);
  540 
  541         /* Allow dts to patch quirks, slots, and max-frequency. */
  542         if ((OF_getencprop(node, "quirks", &cid, sizeof(cid))) > 0)
  543                 sc->quirks = cid;
  544         if ((OF_getencprop(node, "num-slots", &cid, sizeof(cid))) > 0)
  545                 sc->num_slots = cid;
  546         if ((OF_getencprop(node, "max-frequency", &cid, sizeof(cid))) > 0)
  547                 sc->max_clk = cid;
  548         if (OF_hasprop(node, "no-1-8-v"))
  549                 sc->no_18v = true;
  550         if (OF_hasprop(node, "wp-inverted"))
  551                 sc->wp_inverted = true;
  552 
  553         return (0);
  554 }
  555 
  556 static int
  557 sdhci_fdt_attach(device_t dev)
  558 {
  559         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  560         struct sdhci_slot *slot;
  561         int err, slots, rid, i;
  562 
  563         sc->dev = dev;
  564 
  565         /* Allocate IRQ. */
  566         rid = 0;
  567         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  568             RF_ACTIVE);
  569         if (sc->irq_res == NULL) {
  570                 device_printf(dev, "Can't allocate IRQ\n");
  571                 return (ENOMEM);
  572         }
  573 
  574         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
  575             SDHCI_FDT_RK3399) {
  576                 /* Initialize SDHCI */
  577                 err = sdhci_init_rk3399(dev);
  578                 if (err != 0) {
  579                         device_printf(dev, "Cannot init RK3399 SDHCI\n");
  580                         return (err);
  581                 }
  582         }
  583 
  584         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data ==
  585             SDHCI_FDT_RK3568) {
  586                 /* setup & enable clocks */
  587                 if (clk_get_by_ofw_name(dev, 0, "core", &sc->clk_core)) {
  588                         device_printf(dev, "cannot get core clock\n");
  589                         return (ENXIO);
  590                 }
  591                 clk_enable(sc->clk_core);
  592         }
  593 
  594         /* Scan all slots. */
  595         slots = sc->num_slots;  /* number of slots determined in probe(). */
  596         sc->num_slots = 0;
  597         for (i = 0; i < slots; i++) {
  598                 slot = &sc->slots[sc->num_slots];
  599 
  600                 /* Allocate memory. */
  601                 rid = 0;
  602                 sc->mem_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  603                                                         &rid, RF_ACTIVE);
  604                 if (sc->mem_res[i] == NULL) {
  605                         device_printf(dev,
  606                             "Can't allocate memory for slot %d\n", i);
  607                         continue;
  608                 }
  609 
  610                 slot->quirks = sc->quirks;
  611                 slot->caps = sc->caps;
  612                 slot->max_clk = sc->max_clk;
  613                 slot->sdma_boundary = sc->sdma_boundary;
  614 
  615                 if (sdhci_init_slot(dev, slot, i) != 0)
  616                         continue;
  617 
  618                 sc->num_slots++;
  619         }
  620         device_printf(dev, "%d slot(s) allocated\n", sc->num_slots);
  621 
  622         /* Activate the interrupt */
  623         err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  624             NULL, sdhci_fdt_intr, sc, &sc->intrhand);
  625         if (err) {
  626                 device_printf(dev, "Cannot setup IRQ\n");
  627                 return (err);
  628         }
  629 
  630         /* Process cards detection. */
  631         for (i = 0; i < sc->num_slots; i++)
  632                 sdhci_start_slot(&sc->slots[i]);
  633 
  634         return (0);
  635 }
  636 
  637 static int
  638 sdhci_fdt_detach(device_t dev)
  639 {
  640         struct sdhci_fdt_softc *sc = device_get_softc(dev);
  641         int i;
  642 
  643         bus_generic_detach(dev);
  644         bus_teardown_intr(dev, sc->irq_res, sc->intrhand);
  645         bus_release_resource(dev, SYS_RES_IRQ, rman_get_rid(sc->irq_res),
  646             sc->irq_res);
  647 
  648         for (i = 0; i < sc->num_slots; i++) {
  649                 sdhci_cleanup_slot(&sc->slots[i]);
  650                 bus_release_resource(dev, SYS_RES_MEMORY,
  651                     rman_get_rid(sc->mem_res[i]), sc->mem_res[i]);
  652         }
  653 
  654         return (0);
  655 }
  656 
  657 static device_method_t sdhci_fdt_methods[] = {
  658         /* device_if */
  659         DEVMETHOD(device_probe,         sdhci_fdt_probe),
  660         DEVMETHOD(device_attach,        sdhci_fdt_attach),
  661         DEVMETHOD(device_detach,        sdhci_fdt_detach),
  662 
  663         /* Bus interface */
  664         DEVMETHOD(bus_read_ivar,        sdhci_generic_read_ivar),
  665         DEVMETHOD(bus_write_ivar,       sdhci_generic_write_ivar),
  666 
  667         /* mmcbr_if */
  668         DEVMETHOD(mmcbr_update_ios,     sdhci_generic_update_ios),
  669         DEVMETHOD(mmcbr_request,        sdhci_generic_request),
  670         DEVMETHOD(mmcbr_get_ro,         sdhci_fdt_get_ro),
  671         DEVMETHOD(mmcbr_acquire_host,   sdhci_generic_acquire_host),
  672         DEVMETHOD(mmcbr_release_host,   sdhci_generic_release_host),
  673 
  674         /* SDHCI registers accessors */
  675         DEVMETHOD(sdhci_read_1,         sdhci_fdt_read_1),
  676         DEVMETHOD(sdhci_read_2,         sdhci_fdt_read_2),
  677         DEVMETHOD(sdhci_read_4,         sdhci_fdt_read_4),
  678         DEVMETHOD(sdhci_read_multi_4,   sdhci_fdt_read_multi_4),
  679         DEVMETHOD(sdhci_write_1,        sdhci_fdt_write_1),
  680         DEVMETHOD(sdhci_write_2,        sdhci_fdt_write_2),
  681         DEVMETHOD(sdhci_write_4,        sdhci_fdt_write_4),
  682         DEVMETHOD(sdhci_write_multi_4,  sdhci_fdt_write_multi_4),
  683         DEVMETHOD(sdhci_set_clock,      sdhci_fdt_set_clock),
  684 
  685         DEVMETHOD_END
  686 };
  687 
  688 static driver_t sdhci_fdt_driver = {
  689         "sdhci_fdt",
  690         sdhci_fdt_methods,
  691         sizeof(struct sdhci_fdt_softc),
  692 };
  693 
  694 DRIVER_MODULE(sdhci_fdt, simplebus, sdhci_fdt_driver, NULL, NULL);
  695 SDHCI_DEPEND(sdhci_fdt);
  696 #ifndef MMCCAM
  697 MMC_DECLARE_BRIDGE(sdhci_fdt);
  698 #endif

Cache object: bb34cf326ebf38a8e6a8ad613c5be44d


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