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/arm/nvidia/tegra_mc.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) 2016 Michal Meloun <mmel@FreeBSD.org>
    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 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 /*
   31  * Memory controller driver for Tegra SoCs.
   32  */
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/kernel.h>
   37 #include <sys/limits.h>
   38 #include <sys/lock.h>
   39 #include <sys/mutex.h>
   40 #include <sys/module.h>
   41 #include <sys/resource.h>
   42 
   43 #include <machine/bus.h>
   44 #include <machine/resource.h>
   45 #include <sys/rman.h>
   46 
   47 #include <dev/extres/clk/clk.h>
   48 #include <dev/ofw/ofw_bus.h>
   49 #include <dev/ofw/ofw_bus_subr.h>
   50 
   51 #include "clock_if.h"
   52 
   53 #define MC_INTSTATUS                    0x000
   54 #define MC_INTMASK                      0x004
   55 #define  MC_INT_DECERR_MTS                      (1 << 16)
   56 #define  MC_INT_SECERR_SEC                      (1 << 13)
   57 #define  MC_INT_DECERR_VPR                      (1 << 12)
   58 #define  MC_INT_INVALID_APB_ASID_UPDATE         (1 << 11)
   59 #define  MC_INT_INVALID_SMMU_PAGE               (1 << 10)
   60 #define  MC_INT_ARBITRATION_EMEM                (1 << 9)
   61 #define  MC_INT_SECURITY_VIOLATION              (1 << 8)
   62 #define  MC_INT_DECERR_EMEM                     (1 << 6)
   63 #define  MC_INT_INT_MASK        (MC_INT_DECERR_MTS |                    \
   64                                  MC_INT_SECERR_SEC |                    \
   65                                  MC_INT_DECERR_VPR |                    \
   66                                  MC_INT_INVALID_APB_ASID_UPDATE |       \
   67                                  MC_INT_INVALID_SMMU_PAGE |             \
   68                                  MC_INT_ARBITRATION_EMEM |              \
   69                                  MC_INT_SECURITY_VIOLATION |            \
   70                                  MC_INT_DECERR_EMEM)
   71 
   72 #define MC_ERR_STATUS                   0x008
   73 #define  MC_ERR_TYPE(x)                         (((x) >> 28) & 0x7)
   74 #define  MC_ERR_TYPE_DECERR_EMEM                2
   75 #define  MC_ERR_TYPE_SECURITY_TRUSTZONE         3
   76 #define  MC_ERR_TYPE_SECURITY_CARVEOUT          4
   77 #define  MC_ERR_TYPE_INVALID_SMMU_PAGE          6
   78 #define  MC_ERR_INVALID_SMMU_PAGE_READABLE      (1 << 27)
   79 #define  MC_ERR_INVALID_SMMU_PAGE_WRITABLE      (1 << 26)
   80 #define  MC_ERR_INVALID_SMMU_PAGE_NONSECURE     (1 << 25)
   81 #define  MC_ERR_ADR_HI(x)                       (((x) >> 20) & 0x3)
   82 #define  MC_ERR_SWAP                            (1 << 18)
   83 #define  MC_ERR_SECURITY                        (1 << 17)
   84 #define  MC_ERR_RW                              (1 << 16)
   85 #define  MC_ERR_ADR1(x)                         (((x) >> 12) & 0x7)
   86 #define  MC_ERR_ID(x)                           (((x) >> 0) & 07F)
   87 
   88 #define MC_ERR_ADDR                     0x00C
   89 #define MC_EMEM_CFG                     0x050
   90 #define MC_EMEM_ADR_CFG                 0x054
   91 #define  MC_EMEM_NUMDEV(x)                      (((x) >> 0 ) & 0x1)
   92 
   93 #define MC_EMEM_ADR_CFG_DEV0            0x058
   94 #define MC_EMEM_ADR_CFG_DEV1            0x05C
   95 #define  EMEM_DEV_DEVSIZE(x)                    (((x) >> 16) & 0xF)
   96 #define  EMEM_DEV_BANKWIDTH(x)                  (((x) >>  8) & 0x3)
   97 #define  EMEM_DEV_COLWIDTH(x)                   (((x) >>  8) & 0x3)
   98 
   99 #define WR4(_sc, _r, _v)        bus_write_4((_sc)->mem_res, (_r), (_v))
  100 #define RD4(_sc, _r)            bus_read_4((_sc)->mem_res, (_r))
  101 
  102 #define LOCK(_sc)               mtx_lock(&(_sc)->mtx)
  103 #define UNLOCK(_sc)             mtx_unlock(&(_sc)->mtx)
  104 #define SLEEP(_sc, timeout)     mtx_sleep(sc, &sc->mtx, 0, "tegra_mc", timeout);
  105 #define LOCK_INIT(_sc)                                                  \
  106         mtx_init(&_sc->mtx, device_get_nameunit(_sc->dev), "tegra_mc", MTX_DEF)
  107 #define LOCK_DESTROY(_sc)       mtx_destroy(&_sc->mtx)
  108 #define ASSERT_LOCKED(_sc)      mtx_assert(&_sc->mtx, MA_OWNED)
  109 #define ASSERT_UNLOCKED(_sc)    mtx_assert(&_sc->mtx, MA_NOTOWNED)
  110 
  111 static struct ofw_compat_data compat_data[] = {
  112         {"nvidia,tegra124-mc",  1},
  113         {"nvidia,tegra210-mc",  1},
  114         {NULL,                  0}
  115 };
  116 
  117 struct tegra_mc_softc {
  118         device_t                dev;
  119         struct mtx              mtx;
  120 
  121         struct resource         *mem_res;
  122         struct resource         *irq_res;
  123         void                    *irq_h;
  124 
  125         clk_t                   clk;
  126 };
  127 
  128 static char *smmu_err_tbl[16] = {
  129         "reserved",             /*  0 */
  130         "reserved",             /*  1 */
  131         "DRAM decode",          /*  2 */
  132         "Trustzome Security",   /*  3 */
  133         "Security carveout",    /*  4 */
  134         "reserved",             /*  5 */
  135         "Invalid SMMU page",    /*  6 */
  136         "reserved",             /*  7 */
  137 };
  138 
  139 static void
  140 tegra_mc_intr(void *arg)
  141 {
  142         struct tegra_mc_softc *sc;
  143         uint32_t stat, err;
  144         uint64_t addr;
  145 
  146         sc = (struct tegra_mc_softc *)arg;
  147 
  148         stat = RD4(sc, MC_INTSTATUS);
  149         if ((stat & MC_INT_INT_MASK) == 0) {
  150                 WR4(sc, MC_INTSTATUS, stat);
  151                 return;
  152         }
  153 
  154         device_printf(sc->dev, "Memory Controller Interrupt:\n");
  155         if (stat & MC_INT_DECERR_MTS)
  156                 printf(" - MTS carveout violation\n");
  157         if (stat & MC_INT_SECERR_SEC)
  158                 printf(" - SEC carveout violation\n");
  159         if (stat & MC_INT_DECERR_VPR)
  160                 printf(" - VPR requirements violated\n");
  161         if (stat & MC_INT_INVALID_APB_ASID_UPDATE)
  162                 printf(" - ivalid APB ASID update\n");
  163         if (stat & MC_INT_INVALID_SMMU_PAGE)
  164                 printf(" - SMMU address translation error\n");
  165         if (stat & MC_INT_ARBITRATION_EMEM)
  166                 printf(" - arbitration deadlock-prevention threshold hit\n");
  167         if (stat & MC_INT_SECURITY_VIOLATION)
  168                 printf(" - SMMU address translation security error\n");
  169         if (stat & MC_INT_DECERR_EMEM)
  170                 printf(" - SMMU address decode error\n");
  171 
  172         if ((stat & (MC_INT_INVALID_SMMU_PAGE | MC_INT_SECURITY_VIOLATION |
  173            MC_INT_DECERR_EMEM)) != 0) {
  174                 err = RD4(sc, MC_ERR_STATUS);
  175                 addr = RD4(sc, MC_ERR_STATUS);
  176                 addr |= (uint64_t)(MC_ERR_ADR_HI(err)) << 32;
  177                 printf(" at 0x%012jX [%s %s %s]  - %s error.\n",
  178                     (uintmax_t)addr,
  179                     stat & MC_ERR_SWAP ? "Swap, " : "",
  180                     stat & MC_ERR_SECURITY ? "Sec, " : "",
  181                     stat & MC_ERR_RW ? "Write" : "Read",
  182                     smmu_err_tbl[MC_ERR_TYPE(err)]);
  183         }
  184         WR4(sc, MC_INTSTATUS, stat);
  185 }
  186 
  187 static void
  188 tegra_mc_init_hw(struct tegra_mc_softc *sc)
  189 {
  190 
  191         /* Disable and acknowledge all interrupts */
  192         WR4(sc, MC_INTMASK, 0);
  193         WR4(sc, MC_INTSTATUS, MC_INT_INT_MASK);
  194 }
  195 
  196 static int
  197 tegra_mc_probe(device_t dev)
  198 {
  199         if (!ofw_bus_status_okay(dev))
  200                 return (ENXIO);
  201 
  202         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  203                 return (ENXIO);
  204         device_set_desc(dev, "Tegra Memory Controller");
  205         return (BUS_PROBE_DEFAULT);
  206 }
  207 
  208 static int
  209 tegra_mc_attach(device_t dev)
  210 {
  211         int rv, rid;
  212         struct tegra_mc_softc *sc;
  213 
  214         sc = device_get_softc(dev);
  215         sc->dev = dev;
  216 
  217         LOCK_INIT(sc);
  218 
  219         /* Get the memory resource for the register mapping. */
  220         rid = 0;
  221         sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  222             RF_ACTIVE);
  223         if (sc->mem_res == NULL) {
  224                 device_printf(dev, "Cannot map registers.\n");
  225                 rv = ENXIO;
  226                 goto fail;
  227         }
  228 
  229         /* Allocate our IRQ resource. */
  230         rid = 0;
  231         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  232             RF_ACTIVE);
  233         if (sc->irq_res == NULL) {
  234                 device_printf(dev, "Cannot allocate interrupt.\n");
  235                 rv = ENXIO;
  236                 goto fail;
  237         }
  238 
  239         /* OFW resources. */
  240         rv = clk_get_by_ofw_name(dev, 0, "mc", &sc->clk);
  241         if (rv != 0) {
  242                 device_printf(dev, "Cannot get mc clock: %d\n", rv);
  243                 goto fail;
  244         }
  245         rv = clk_enable(sc->clk);
  246         if (rv != 0) {
  247                 device_printf(dev, "Cannot enable clock: %d\n", rv);
  248                 goto fail;
  249         }
  250 
  251         /* Init hardware. */
  252         tegra_mc_init_hw(sc);
  253 
  254         /* Setup  interrupt */
  255         rv = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  256             NULL, tegra_mc_intr, sc, &sc->irq_h);
  257         if (rv) {
  258                 device_printf(dev, "Cannot setup interrupt.\n");
  259                 goto fail;
  260         }
  261 
  262         /* Enable Interrupts */
  263         WR4(sc, MC_INTMASK, MC_INT_INT_MASK);
  264 
  265         return (bus_generic_attach(dev));
  266 
  267 fail:
  268         if (sc->clk != NULL)
  269                 clk_release(sc->clk);
  270         if (sc->irq_h != NULL)
  271                 bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
  272         if (sc->irq_res != NULL)
  273                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  274         if (sc->mem_res != NULL)
  275                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  276         LOCK_DESTROY(sc);
  277 
  278         return (rv);
  279 }
  280 
  281 static int
  282 tegra_mc_detach(device_t dev)
  283 {
  284         struct tegra_mc_softc *sc;
  285 
  286         sc = device_get_softc(dev);
  287         if (sc->irq_h != NULL)
  288                 bus_teardown_intr(dev, sc->irq_res, sc->irq_h);
  289         if (sc->irq_res != NULL)
  290                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  291         if (sc->mem_res != NULL)
  292                 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res);
  293 
  294         LOCK_DESTROY(sc);
  295         return (bus_generic_detach(dev));
  296 }
  297 
  298 static device_method_t tegra_mc_methods[] = {
  299         /* Device interface */
  300         DEVMETHOD(device_probe,         tegra_mc_probe),
  301         DEVMETHOD(device_attach,        tegra_mc_attach),
  302         DEVMETHOD(device_detach,        tegra_mc_detach),
  303 
  304         DEVMETHOD_END
  305 };
  306 
  307 static devclass_t tegra_mc_devclass;
  308 static DEFINE_CLASS_0(mc, tegra_mc_driver, tegra_mc_methods,
  309     sizeof(struct tegra_mc_softc));
  310 DRIVER_MODULE(tegra_mc, simplebus, tegra_mc_driver, tegra_mc_devclass,
  311     NULL, NULL);

Cache object: 623f48443b74ec8149ad44c4b186701b


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