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 struct aw_sid_conf { 173 struct aw_sid_efuse *efuses; 174 size_t nfuses; 175 }; 176 177 static const struct aw_sid_conf a10_conf = { 178 .efuses = a10_efuses, 179 .nfuses = nitems(a10_efuses), 180 }; 181 182 static const struct aw_sid_conf a20_conf = { 183 .efuses = a10_efuses, 184 .nfuses = nitems(a10_efuses), 185 }; 186 187 static const struct aw_sid_conf a64_conf = { 188 .efuses = a64_efuses, 189 .nfuses = nitems(a64_efuses), 190 }; 191 192 static const struct aw_sid_conf a83t_conf = { 193 .efuses = a83t_efuses, 194 .nfuses = nitems(a83t_efuses), 195 }; 196 197 static const struct aw_sid_conf h3_conf = { 198 .efuses = h3_efuses, 199 .nfuses = nitems(h3_efuses), 200 }; 201 202 static const struct aw_sid_conf h5_conf = { 203 .efuses = h5_efuses, 204 .nfuses = nitems(h5_efuses), 205 }; 206 207 static struct ofw_compat_data compat_data[] = { 208 { "allwinner,sun4i-a10-sid", (uintptr_t)&a10_conf}, 209 { "allwinner,sun7i-a20-sid", (uintptr_t)&a20_conf}, 210 { "allwinner,sun50i-a64-sid", (uintptr_t)&a64_conf}, 211 { "allwinner,sun8i-a83t-sid", (uintptr_t)&a83t_conf}, 212 { "allwinner,sun8i-h3-sid", (uintptr_t)&h3_conf}, 213 { "allwinner,sun50i-h5-sid", (uintptr_t)&h5_conf}, 214 { NULL, 0 } 215 }; 216 217 struct aw_sid_softc { 218 device_t sid_dev; 219 struct resource *res; 220 struct aw_sid_conf *sid_conf; 221 struct mtx prctl_mtx; 222 }; 223 224 static struct aw_sid_softc *aw_sid_sc; 225 226 static struct resource_spec aw_sid_spec[] = { 227 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 228 { -1, 0 } 229 }; 230 231 #define RD1(sc, reg) bus_read_1((sc)->res, (reg)) 232 #define RD4(sc, reg) bus_read_4((sc)->res, (reg)) 233 #define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val)) 234 235 static int aw_sid_sysctl(SYSCTL_HANDLER_ARGS); 236 237 static int 238 aw_sid_probe(device_t dev) 239 { 240 if (!ofw_bus_status_okay(dev)) 241 return (ENXIO); 242 243 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 244 return (ENXIO); 245 246 device_set_desc(dev, "Allwinner Secure ID Controller"); 247 return (BUS_PROBE_DEFAULT); 248 } 249 250 static int 251 aw_sid_attach(device_t dev) 252 { 253 struct aw_sid_softc *sc; 254 phandle_t node; 255 int i; 256 257 node = ofw_bus_get_node(dev); 258 sc = device_get_softc(dev); 259 sc->sid_dev = dev; 260 261 if (bus_alloc_resources(dev, aw_sid_spec, &sc->res) != 0) { 262 device_printf(dev, "cannot allocate resources for device\n"); 263 return (ENXIO); 264 } 265 266 mtx_init(&sc->prctl_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 267 sc->sid_conf = (struct aw_sid_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data; 268 aw_sid_sc = sc; 269 270 /* Register ourself so device can resolve who we are */ 271 OF_device_register_xref(OF_xref_from_node(node), dev); 272 273 for (i = 0; i < sc->sid_conf->nfuses ;i++) {\ 274 SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 275 SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 276 OID_AUTO, sc->sid_conf->efuses[i].name, 277 CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT, 278 dev, sc->sid_conf->efuses[i].id, aw_sid_sysctl, 279 "A", sc->sid_conf->efuses[i].desc); 280 } 281 return (0); 282 } 283 284 int 285 aw_sid_get_fuse(enum aw_sid_fuse_id id, uint8_t *out, uint32_t *size) 286 { 287 struct aw_sid_softc *sc; 288 uint32_t val; 289 int i, j; 290 291 sc = aw_sid_sc; 292 if (sc == NULL) 293 return (ENXIO); 294 295 for (i = 0; i < sc->sid_conf->nfuses; i++) 296 if (id == sc->sid_conf->efuses[i].id) 297 break; 298 299 if (i == sc->sid_conf->nfuses) 300 return (ENOENT); 301 302 if (*size != sc->sid_conf->efuses[i].size) { 303 *size = sc->sid_conf->efuses[i].size; 304 return (ENOMEM); 305 } 306 307 if (out == NULL) 308 return (ENOMEM); 309 310 if (sc->sid_conf->efuses[i].public == false) 311 mtx_lock(&sc->prctl_mtx); 312 for (j = 0; j < sc->sid_conf->efuses[i].size; j += 4) { 313 if (sc->sid_conf->efuses[i].public == false) { 314 val = SID_PRCTL_OFFSET(sc->sid_conf->efuses[i].offset + j) | 315 SID_PRCTL_LOCK | 316 SID_PRCTL_READ; 317 WR4(sc, SID_PRCTL, val); 318 /* Read bit will be cleared once read has concluded */ 319 while (RD4(sc, SID_PRCTL) & SID_PRCTL_READ) 320 continue; 321 val = RD4(sc, SID_RDKEY); 322 } else 323 val = RD4(sc, sc->sid_conf->efuses[i].base + 324 sc->sid_conf->efuses[i].offset + j); 325 out[j] = val & 0xFF; 326 if (j + 1 < *size) 327 out[j + 1] = (val & 0xFF00) >> 8; 328 if (j + 2 < *size) 329 out[j + 2] = (val & 0xFF0000) >> 16; 330 if (j + 3 < *size) 331 out[j + 3] = (val & 0xFF000000) >> 24; 332 } 333 if (sc->sid_conf->efuses[i].public == false) 334 mtx_unlock(&sc->prctl_mtx); 335 336 return (0); 337 } 338 339 static int 340 aw_sid_read(device_t dev, uint32_t offset, uint32_t size, uint8_t *buffer) 341 { 342 struct aw_sid_softc *sc; 343 enum aw_sid_fuse_id fuse_id = 0; 344 int i; 345 346 sc = device_get_softc(dev); 347 348 for (i = 0; i < sc->sid_conf->nfuses; i++) 349 if (offset == sc->sid_conf->efuses[i].offset) { 350 fuse_id = sc->sid_conf->efuses[i].id; 351 break; 352 } 353 354 if (fuse_id == 0) 355 return (ENOENT); 356 357 return (aw_sid_get_fuse(fuse_id, buffer, &size)); 358 } 359 360 static int 361 aw_sid_sysctl(SYSCTL_HANDLER_ARGS) 362 { 363 device_t dev = arg1; 364 enum aw_sid_fuse_id fuse = arg2; 365 uint8_t data[32]; 366 char out[128]; 367 uint32_t size; 368 int ret, i; 369 370 /* Get the size of the efuse data */ 371 size = 0; 372 aw_sid_get_fuse(fuse, NULL, &size); 373 /* We now have the real size */ 374 ret = aw_sid_get_fuse(fuse, data, &size); 375 if (ret != 0) { 376 device_printf(dev, "Cannot get fuse id %d: %d\n", fuse, ret); 377 return (ENOENT); 378 } 379 380 for (i = 0; i < size; i++) 381 snprintf(out + (i * 2), sizeof(out) - (i * 2), 382 "%.2x", data[i]); 383 384 return sysctl_handle_string(oidp, out, sizeof(out), req); 385 } 386 387 static device_method_t aw_sid_methods[] = { 388 /* Device interface */ 389 DEVMETHOD(device_probe, aw_sid_probe), 390 DEVMETHOD(device_attach, aw_sid_attach), 391 392 /* NVMEM interface */ 393 DEVMETHOD(nvmem_read, aw_sid_read), 394 DEVMETHOD_END 395 }; 396 397 static driver_t aw_sid_driver = { 398 "aw_sid", 399 aw_sid_methods, 400 sizeof(struct aw_sid_softc), 401 }; 402 403 EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, 0, 0, 404 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST); 405 MODULE_VERSION(aw_sid, 1); 406 SIMPLEBUS_PNP_INFO(compat_data); 407