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