Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/allwinner/aw_sid.c
105687 views
1
/*-
2
* Copyright (c) 2016 Jared McNeill <[email protected]>
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 h616_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
static struct aw_sid_efuse d1_efuses[] = {
194
{
195
.name = "rootkey",
196
.desc = "Root Key or ChipID",
197
.base = EFUSE_OFFSET,
198
.offset = 0x00,
199
.size = 16,
200
.id = AW_SID_FUSE_ROOTKEY,
201
.public = true,
202
},
203
{
204
.name = "calibration",
205
.desc = "Thermal Sensor Calibration Data",
206
.base = EFUSE_OFFSET,
207
.offset = 0x34,
208
.size = 4,
209
.id = AW_SID_FUSE_THSSENSOR,
210
.public = true,
211
},
212
};
213
214
struct aw_sid_conf {
215
struct aw_sid_efuse *efuses;
216
size_t nfuses;
217
};
218
219
static const struct aw_sid_conf a10_conf = {
220
.efuses = a10_efuses,
221
.nfuses = nitems(a10_efuses),
222
};
223
224
static const struct aw_sid_conf a20_conf = {
225
.efuses = a10_efuses,
226
.nfuses = nitems(a10_efuses),
227
};
228
229
static const struct aw_sid_conf a64_conf = {
230
.efuses = a64_efuses,
231
.nfuses = nitems(a64_efuses),
232
};
233
234
static const struct aw_sid_conf a83t_conf = {
235
.efuses = a83t_efuses,
236
.nfuses = nitems(a83t_efuses),
237
};
238
239
static const struct aw_sid_conf h3_conf = {
240
.efuses = h3_efuses,
241
.nfuses = nitems(h3_efuses),
242
};
243
244
static const struct aw_sid_conf h5_conf = {
245
.efuses = h5_efuses,
246
.nfuses = nitems(h5_efuses),
247
};
248
249
static const struct aw_sid_conf h616_conf = {
250
.efuses = h616_efuses,
251
.nfuses = nitems(h616_efuses),
252
};
253
254
static const struct aw_sid_conf d1_conf = {
255
.efuses = d1_efuses,
256
.nfuses = nitems(d1_efuses),
257
};
258
259
static struct ofw_compat_data compat_data[] = {
260
{ "allwinner,sun4i-a10-sid", (uintptr_t)&a10_conf},
261
{ "allwinner,sun7i-a20-sid", (uintptr_t)&a20_conf},
262
{ "allwinner,sun50i-a64-sid", (uintptr_t)&a64_conf},
263
{ "allwinner,sun8i-a83t-sid", (uintptr_t)&a83t_conf},
264
{ "allwinner,sun8i-h3-sid", (uintptr_t)&h3_conf},
265
{ "allwinner,sun50i-h5-sid", (uintptr_t)&h5_conf},
266
{ "allwinner,sun50i-h616-sid", (uintptr_t)&h616_conf},
267
{ "allwinner,sun20i-d1-sid", (uintptr_t)&d1_conf},
268
{ NULL, 0 }
269
};
270
271
struct aw_sid_softc {
272
device_t sid_dev;
273
struct resource *res;
274
struct aw_sid_conf *sid_conf;
275
struct mtx prctl_mtx;
276
};
277
278
static struct aw_sid_softc *aw_sid_sc;
279
280
static struct resource_spec aw_sid_spec[] = {
281
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
282
{ -1, 0 }
283
};
284
285
#define RD1(sc, reg) bus_read_1((sc)->res, (reg))
286
#define RD4(sc, reg) bus_read_4((sc)->res, (reg))
287
#define WR4(sc, reg, val) bus_write_4((sc)->res, (reg), (val))
288
289
static int aw_sid_sysctl(SYSCTL_HANDLER_ARGS);
290
291
static int
292
aw_sid_probe(device_t dev)
293
{
294
if (!ofw_bus_status_okay(dev))
295
return (ENXIO);
296
297
if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
298
return (ENXIO);
299
300
device_set_desc(dev, "Allwinner Secure ID Controller");
301
return (BUS_PROBE_DEFAULT);
302
}
303
304
static int
305
aw_sid_attach(device_t dev)
306
{
307
struct aw_sid_softc *sc;
308
phandle_t node;
309
int i;
310
311
node = ofw_bus_get_node(dev);
312
sc = device_get_softc(dev);
313
sc->sid_dev = dev;
314
315
if (bus_alloc_resources(dev, aw_sid_spec, &sc->res) != 0) {
316
device_printf(dev, "cannot allocate resources for device\n");
317
return (ENXIO);
318
}
319
320
mtx_init(&sc->prctl_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
321
sc->sid_conf = (struct aw_sid_conf *)ofw_bus_search_compatible(dev, compat_data)->ocd_data;
322
aw_sid_sc = sc;
323
324
/* Register ourself so device can resolve who we are */
325
OF_device_register_xref(OF_xref_from_node(node), dev);
326
327
for (i = 0; i < sc->sid_conf->nfuses; i++) {
328
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
329
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
330
OID_AUTO, sc->sid_conf->efuses[i].name,
331
CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
332
dev, sc->sid_conf->efuses[i].id, aw_sid_sysctl,
333
"A", sc->sid_conf->efuses[i].desc);
334
}
335
return (0);
336
}
337
338
int
339
aw_sid_get_fuse(enum aw_sid_fuse_id id, uint8_t *out, uint32_t *size)
340
{
341
struct aw_sid_softc *sc;
342
uint32_t val;
343
int i, j;
344
345
sc = aw_sid_sc;
346
if (sc == NULL)
347
return (ENXIO);
348
349
for (i = 0; i < sc->sid_conf->nfuses; i++)
350
if (id == sc->sid_conf->efuses[i].id)
351
break;
352
353
if (i == sc->sid_conf->nfuses)
354
return (ENOENT);
355
356
if (*size != sc->sid_conf->efuses[i].size) {
357
*size = sc->sid_conf->efuses[i].size;
358
return (ENOMEM);
359
}
360
361
if (out == NULL)
362
return (ENOMEM);
363
364
if (sc->sid_conf->efuses[i].public == false)
365
mtx_lock(&sc->prctl_mtx);
366
for (j = 0; j < sc->sid_conf->efuses[i].size; j += 4) {
367
if (sc->sid_conf->efuses[i].public == false) {
368
val = SID_PRCTL_OFFSET(sc->sid_conf->efuses[i].offset + j) |
369
SID_PRCTL_LOCK |
370
SID_PRCTL_READ;
371
WR4(sc, SID_PRCTL, val);
372
/* Read bit will be cleared once read has concluded */
373
while (RD4(sc, SID_PRCTL) & SID_PRCTL_READ)
374
continue;
375
val = RD4(sc, SID_RDKEY);
376
} else
377
val = RD4(sc, sc->sid_conf->efuses[i].base +
378
sc->sid_conf->efuses[i].offset + j);
379
out[j] = val & 0xFF;
380
if (j + 1 < *size)
381
out[j + 1] = (val & 0xFF00) >> 8;
382
if (j + 2 < *size)
383
out[j + 2] = (val & 0xFF0000) >> 16;
384
if (j + 3 < *size)
385
out[j + 3] = (val & 0xFF000000) >> 24;
386
}
387
if (sc->sid_conf->efuses[i].public == false)
388
mtx_unlock(&sc->prctl_mtx);
389
390
return (0);
391
}
392
393
static int
394
aw_sid_read(device_t dev, uint32_t offset, uint32_t size, uint8_t *buffer)
395
{
396
struct aw_sid_softc *sc;
397
enum aw_sid_fuse_id fuse_id = 0;
398
int i;
399
400
sc = device_get_softc(dev);
401
402
for (i = 0; i < sc->sid_conf->nfuses; i++)
403
if (offset == sc->sid_conf->efuses[i].offset) {
404
fuse_id = sc->sid_conf->efuses[i].id;
405
break;
406
}
407
408
if (fuse_id == 0)
409
return (ENOENT);
410
411
return (aw_sid_get_fuse(fuse_id, buffer, &size));
412
}
413
414
static int
415
aw_sid_sysctl(SYSCTL_HANDLER_ARGS)
416
{
417
device_t dev = arg1;
418
enum aw_sid_fuse_id fuse = arg2;
419
uint8_t data[32];
420
char out[128];
421
uint32_t size;
422
int ret, i;
423
424
/* Get the size of the efuse data */
425
size = 0;
426
aw_sid_get_fuse(fuse, NULL, &size);
427
/* We now have the real size */
428
ret = aw_sid_get_fuse(fuse, data, &size);
429
if (ret != 0) {
430
device_printf(dev, "Cannot get fuse id %d: %d\n", fuse, ret);
431
return (ENOENT);
432
}
433
434
for (i = 0; i < size; i++)
435
snprintf(out + (i * 2), sizeof(out) - (i * 2),
436
"%.2x", data[i]);
437
438
return sysctl_handle_string(oidp, out, sizeof(out), req);
439
}
440
441
static device_method_t aw_sid_methods[] = {
442
/* Device interface */
443
DEVMETHOD(device_probe, aw_sid_probe),
444
DEVMETHOD(device_attach, aw_sid_attach),
445
446
/* NVMEM interface */
447
DEVMETHOD(nvmem_read, aw_sid_read),
448
DEVMETHOD_END
449
};
450
451
static driver_t aw_sid_driver = {
452
"aw_sid",
453
aw_sid_methods,
454
sizeof(struct aw_sid_softc),
455
};
456
457
EARLY_DRIVER_MODULE(aw_sid, simplebus, aw_sid_driver, 0, 0,
458
BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_FIRST);
459
MODULE_VERSION(aw_sid, 1);
460
SIMPLEBUS_PNP_INFO(compat_data);
461
462