Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/arm/allwinner/aw_sid.c
39507 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 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
435