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