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 EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, 0, 0, 408 BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST); 409 MODULE_VERSION(aw_sid, 1); 410 SIMPLEBUS_PNP_INFO(compat_data); 411