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