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/allwinner/aw_sid.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 Jared McNeill <jmcneill@invisible.ca>
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   18  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   20  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   21  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  * $FreeBSD$
   26  */
   27 
   28 /*
   29  * Allwinner secure ID controller
   30  */
   31 
   32 #include <sys/cdefs.h>
   33 __FBSDID("$FreeBSD$");
   34 
   35 #include <sys/endian.h>
   36 #include <sys/param.h>
   37 #include <sys/systm.h>
   38 #include <sys/bus.h>
   39 #include <sys/rman.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/mutex.h>
   43 #include <sys/module.h>
   44 #include <sys/sysctl.h>
   45 #include <machine/bus.h>
   46 
   47 #include <dev/ofw/ofw_bus.h>
   48 #include <dev/ofw/ofw_bus_subr.h>
   49 
   50 #include <arm/allwinner/aw_sid.h>
   51 
   52 #include "nvmem_if.h"
   53 
   54 /* 
   55  * Starting at least from sun8iw6 (A83T) EFUSE starts at 0x200 
   56  * There is 3 registers in the low area to read/write protected EFUSE.
   57  */
   58 #define SID_PRCTL               0x40
   59 #define  SID_PRCTL_OFFSET_MASK  0xff
   60 #define  SID_PRCTL_OFFSET(n)    (((n) & SID_PRCTL_OFFSET_MASK) << 16)
   61 #define  SID_PRCTL_LOCK         (0xac << 8)
   62 #define  SID_PRCTL_READ         (0x01 << 1)
   63 #define  SID_PRCTL_WRITE        (0x01 << 0)
   64 #define SID_PRKEY               0x50
   65 #define SID_RDKEY               0x60
   66 
   67 #define EFUSE_OFFSET            0x200
   68 #define EFUSE_NAME_SIZE         32
   69 #define EFUSE_DESC_SIZE         64
   70 
   71 struct aw_sid_efuse {
   72         char                    name[EFUSE_NAME_SIZE];
   73         char                    desc[EFUSE_DESC_SIZE];
   74         bus_size_t              base;
   75         bus_size_t              offset;
   76         uint32_t                size;
   77         enum aw_sid_fuse_id     id;
   78         bool                    public;
   79 };
   80 
   81 static struct aw_sid_efuse a10_efuses[] = {
   82         {
   83                 .name = "rootkey",
   84                 .desc = "Root Key or ChipID",
   85                 .offset = 0x0,
   86                 .size = 16,
   87                 .id = AW_SID_FUSE_ROOTKEY,
   88                 .public = true,
   89         },
   90 };
   91 
   92 static struct aw_sid_efuse a64_efuses[] = {
   93         {
   94                 .name = "rootkey",
   95                 .desc = "Root Key or ChipID",
   96                 .base = EFUSE_OFFSET,
   97                 .offset = 0x00,
   98                 .size = 16,
   99                 .id = AW_SID_FUSE_ROOTKEY,
  100                 .public = true,
  101         },
  102         {
  103                 .name = "calibration",
  104                 .desc = "Thermal Sensor Calibration Data",
  105                 .base = EFUSE_OFFSET,
  106                 .offset = 0x34,
  107                 .size = 8,
  108                 .id = AW_SID_FUSE_THSSENSOR,
  109                 .public = true,
  110         },
  111 };
  112 
  113 static struct aw_sid_efuse a83t_efuses[] = {
  114         {
  115                 .name = "rootkey",
  116                 .desc = "Root Key or ChipID",
  117                 .base = EFUSE_OFFSET,
  118                 .offset = 0x00,
  119                 .size = 16,
  120                 .id = AW_SID_FUSE_ROOTKEY,
  121                 .public = true,
  122         },
  123         {
  124                 .name = "calibration",
  125                 .desc = "Thermal Sensor Calibration Data",
  126                 .base = EFUSE_OFFSET,
  127                 .offset = 0x34,
  128                 .size = 8,
  129                 .id = AW_SID_FUSE_THSSENSOR,
  130                 .public = true,
  131         },
  132 };
  133 
  134 static struct aw_sid_efuse h3_efuses[] = {
  135         {
  136                 .name = "rootkey",
  137                 .desc = "Root Key or ChipID",
  138                 .base = EFUSE_OFFSET,
  139                 .offset = 0x00,
  140                 .size = 16,
  141                 .id = AW_SID_FUSE_ROOTKEY,
  142                 .public = true,
  143         },
  144         {
  145                 .name = "calibration",
  146                 .desc = "Thermal Sensor Calibration Data",
  147                 .base = EFUSE_OFFSET,
  148                 .offset = 0x34,
  149                 .size = 4,
  150                 .id = AW_SID_FUSE_THSSENSOR,
  151                 .public = false,
  152         },
  153 };
  154 
  155 static struct aw_sid_efuse h5_efuses[] = {
  156         {
  157                 .name = "rootkey",
  158                 .desc = "Root Key or ChipID",
  159                 .base = EFUSE_OFFSET,
  160                 .offset = 0x00,
  161                 .size = 16,
  162                 .id = AW_SID_FUSE_ROOTKEY,
  163                 .public = true,
  164         },
  165         {
  166                 .name = "calibration",
  167                 .desc = "Thermal Sensor Calibration Data",
  168                 .base = EFUSE_OFFSET,
  169                 .offset = 0x34,
  170                 .size = 4,
  171                 .id = AW_SID_FUSE_THSSENSOR,
  172                 .public = true,
  173         },
  174 };
  175 
  176 struct aw_sid_conf {
  177         struct aw_sid_efuse     *efuses;
  178         size_t                  nfuses;
  179 };
  180 
  181 static const struct aw_sid_conf a10_conf = {
  182         .efuses = a10_efuses,
  183         .nfuses = nitems(a10_efuses),
  184 };
  185 
  186 static const struct aw_sid_conf a20_conf = {
  187         .efuses = a10_efuses,
  188         .nfuses = nitems(a10_efuses),
  189 };
  190 
  191 static const struct aw_sid_conf a64_conf = {
  192         .efuses = a64_efuses,
  193         .nfuses = nitems(a64_efuses),
  194 };
  195 
  196 static const struct aw_sid_conf a83t_conf = {
  197         .efuses = a83t_efuses,
  198         .nfuses = nitems(a83t_efuses),
  199 };
  200 
  201 static const struct aw_sid_conf h3_conf = {
  202         .efuses = h3_efuses,
  203         .nfuses = nitems(h3_efuses),
  204 };
  205 
  206 static const struct aw_sid_conf h5_conf = {
  207         .efuses = h5_efuses,
  208         .nfuses = nitems(h5_efuses),
  209 };
  210 
  211 static struct ofw_compat_data compat_data[] = {
  212         { "allwinner,sun4i-a10-sid",            (uintptr_t)&a10_conf},
  213         { "allwinner,sun7i-a20-sid",            (uintptr_t)&a20_conf},
  214         { "allwinner,sun50i-a64-sid",           (uintptr_t)&a64_conf},
  215         { "allwinner,sun8i-a83t-sid",           (uintptr_t)&a83t_conf},
  216         { "allwinner,sun8i-h3-sid",             (uintptr_t)&h3_conf},
  217         { "allwinner,sun50i-h5-sid",            (uintptr_t)&h5_conf},
  218         { NULL,                                 0 }
  219 };
  220 
  221 struct aw_sid_softc {
  222         device_t                sid_dev;
  223         struct resource         *res;
  224         struct aw_sid_conf      *sid_conf;
  225         struct mtx              prctl_mtx;
  226 };
  227 
  228 static struct aw_sid_softc *aw_sid_sc;
  229 
  230 static struct resource_spec aw_sid_spec[] = {
  231         { SYS_RES_MEMORY,       0,      RF_ACTIVE },
  232         { -1, 0 }
  233 };
  234 
  235 #define RD1(sc, reg)            bus_read_1((sc)->res, (reg))
  236 #define RD4(sc, reg)            bus_read_4((sc)->res, (reg))
  237 #define WR4(sc, reg, val)       bus_write_4((sc)->res, (reg), (val))
  238 
  239 static int aw_sid_sysctl(SYSCTL_HANDLER_ARGS);
  240 
  241 static int
  242 aw_sid_probe(device_t dev)
  243 {
  244         if (!ofw_bus_status_okay(dev))
  245                 return (ENXIO);
  246 
  247         if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
  248                 return (ENXIO);
  249 
  250         device_set_desc(dev, "Allwinner Secure ID Controller");
  251         return (BUS_PROBE_DEFAULT);
  252 }
  253 
  254 static int
  255 aw_sid_attach(device_t dev)
  256 {
  257         struct aw_sid_softc *sc;
  258         phandle_t node;
  259         int i;
  260 
  261         node = ofw_bus_get_node(dev);
  262         sc = device_get_softc(dev);
  263         sc->sid_dev = dev;
  264 
  265         if (bus_alloc_resources(dev, aw_sid_spec, &sc->res) != 0) {
  266                 device_printf(dev, "cannot allocate resources for device\n");
  267                 return (ENXIO);
  268         }
  269 
  270         mtx_init(&sc->prctl_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
  271         sc->sid_conf = (struct aw_sid_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
  272         aw_sid_sc = sc;
  273 
  274         /* Register ourself so device can resolve who we are */
  275         OF_device_register_xref(OF_xref_from_node(node), dev);
  276 
  277         for (i = 0; i < sc->sid_conf->nfuses ;i++) {\
  278                 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  279                     SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
  280                     OID_AUTO, sc->sid_conf->efuses[i].name,
  281                     CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
  282                     dev, sc->sid_conf->efuses[i].id, aw_sid_sysctl,
  283                     "A", sc->sid_conf->efuses[i].desc);
  284         }
  285         return (0);
  286 }
  287 
  288 int
  289 aw_sid_get_fuse(enum aw_sid_fuse_id id, uint8_t *out, uint32_t *size)
  290 {
  291         struct aw_sid_softc *sc;
  292         uint32_t val;
  293         int i, j;
  294 
  295         sc = aw_sid_sc;
  296         if (sc == NULL)
  297                 return (ENXIO);
  298 
  299         for (i = 0; i < sc->sid_conf->nfuses; i++)
  300                 if (id == sc->sid_conf->efuses[i].id)
  301                         break;
  302 
  303         if (i == sc->sid_conf->nfuses)
  304                 return (ENOENT);
  305 
  306         if (*size != sc->sid_conf->efuses[i].size) {
  307                 *size = sc->sid_conf->efuses[i].size;
  308                 return (ENOMEM);
  309         }
  310 
  311         if (out == NULL)
  312                 return (ENOMEM);
  313 
  314         if (sc->sid_conf->efuses[i].public == false)
  315                 mtx_lock(&sc->prctl_mtx);
  316         for (j = 0; j < sc->sid_conf->efuses[i].size; j += 4) {
  317                 if (sc->sid_conf->efuses[i].public == false) {
  318                         val = SID_PRCTL_OFFSET(sc->sid_conf->efuses[i].offset + j) |
  319                                 SID_PRCTL_LOCK |
  320                                 SID_PRCTL_READ;
  321                         WR4(sc, SID_PRCTL, val);
  322                         /* Read bit will be cleared once read has concluded */
  323                         while (RD4(sc, SID_PRCTL) & SID_PRCTL_READ)
  324                                 continue;
  325                         val = RD4(sc, SID_RDKEY);
  326                 } else
  327                         val = RD4(sc, sc->sid_conf->efuses[i].base +
  328                             sc->sid_conf->efuses[i].offset + j);
  329                 out[j] = val & 0xFF;
  330                 if (j + 1 < *size)
  331                         out[j + 1] = (val & 0xFF00) >> 8;
  332                 if (j + 2 < *size)
  333                         out[j + 2] = (val & 0xFF0000) >> 16;
  334                 if (j + 3 < *size)
  335                         out[j + 3] = (val & 0xFF000000) >> 24;
  336         }
  337         if (sc->sid_conf->efuses[i].public == false)
  338                 mtx_unlock(&sc->prctl_mtx);
  339 
  340         return (0);
  341 }
  342 
  343 static int
  344 aw_sid_read(device_t dev, uint32_t offset, uint32_t size, uint8_t *buffer)
  345 {
  346         struct aw_sid_softc *sc;
  347         enum aw_sid_fuse_id fuse_id = 0;
  348         int i;
  349 
  350         sc = device_get_softc(dev);
  351 
  352         for (i = 0; i < sc->sid_conf->nfuses; i++)
  353                 if (offset == sc->sid_conf->efuses[i].offset) {
  354                         fuse_id = sc->sid_conf->efuses[i].id;
  355                         break;
  356                 }
  357 
  358         if (fuse_id == 0)
  359                 return (ENOENT);
  360 
  361         return (aw_sid_get_fuse(fuse_id, buffer, &size));
  362 }
  363 
  364 static int
  365 aw_sid_sysctl(SYSCTL_HANDLER_ARGS)
  366 {
  367         device_t dev = arg1;
  368         enum aw_sid_fuse_id fuse = arg2;
  369         uint8_t data[32];
  370         char out[128];
  371         uint32_t size;
  372         int ret, i;
  373 
  374         /* Get the size of the efuse data */
  375         size = 0;
  376         aw_sid_get_fuse(fuse, NULL, &size);
  377         /* We now have the real size */
  378         ret = aw_sid_get_fuse(fuse, data, &size);
  379         if (ret != 0) {
  380                 device_printf(dev, "Cannot get fuse id %d: %d\n", fuse, ret);
  381                 return (ENOENT);
  382         }
  383 
  384         for (i = 0; i < size; i++)
  385                 snprintf(out + (i * 2), sizeof(out) - (i * 2),
  386                   "%.2x", data[i]);
  387 
  388         return sysctl_handle_string(oidp, out, sizeof(out), req);
  389 }
  390 
  391 static device_method_t aw_sid_methods[] = {
  392         /* Device interface */
  393         DEVMETHOD(device_probe,         aw_sid_probe),
  394         DEVMETHOD(device_attach,        aw_sid_attach),
  395 
  396         /* NVMEM interface */
  397         DEVMETHOD(nvmem_read,           aw_sid_read),
  398         DEVMETHOD_END
  399 };
  400 
  401 static driver_t aw_sid_driver = {
  402         "aw_sid",
  403         aw_sid_methods,
  404         sizeof(struct aw_sid_softc),
  405 };
  406 
  407 static devclass_t aw_sid_devclass;
  408 
  409 EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, aw_sid_devclass, 0, 0,
  410     BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST);
  411 MODULE_VERSION(aw_sid, 1);
  412 SIMPLEBUS_PNP_INFO(compat_data);

Cache object: 518d97010af7f159ac1dbf94c6ae5fe7


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