xref: /optee_os/core/drivers/nvmem/atmel_sfc.c (revision 209c34dc03563af70f1e406f304008495dae7a5e)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2021, Microchip
4  */
5 
6 #include <drivers/nvmem.h>
7 #include <io.h>
8 #include <kernel/dt_driver.h>
9 #include <malloc.h>
10 #include <matrix.h>
11 #include <platform_config.h>
12 #include <string.h>
13 #include <tee_api_defines.h>
14 #include <tee_api_types.h>
15 #include <types_ext.h>
16 
17 #define ATMEL_SFC_KR		0x0
18 #define ATMEL_SFC_SR		0x1C
19 #define ATMEL_SFC_SR_PGMC	BIT(0)
20 #define ATMEL_SFC_SR_PGMF	BIT(1)
21 #define ATMEL_SFC_DR		0x20
22 
23 #define ATMEL_SFC_CELLS_32	17
24 #define ATMEL_SFC_CELLS_8	(ATMEL_SFC_CELLS_32 * sizeof(uint32_t))
25 
26 struct atmel_sfc {
27 	vaddr_t base;
28 	uint8_t fuses[ATMEL_SFC_CELLS_8];
29 };
30 
31 static TEE_Result atmel_sfc_read_cell(struct nvmem_cell *cell, uint8_t *data)
32 {
33 	struct atmel_sfc *atmel_sfc = cell->drv_data;
34 
35 	memcpy(data, &atmel_sfc->fuses[cell->offset], cell->len);
36 
37 	return TEE_SUCCESS;
38 }
39 
40 static void atmel_sfc_put_cell(struct nvmem_cell *cell)
41 {
42 	free(cell);
43 }
44 
45 static const struct nvmem_ops atmel_sfc_nvmem_ops = {
46 	.read_cell = atmel_sfc_read_cell,
47 	.put_cell = atmel_sfc_put_cell,
48 };
49 
50 static TEE_Result atmel_sfc_dt_get(struct dt_pargs *args,
51 				   void *data, struct nvmem_cell **out_cell)
52 {
53 	TEE_Result res = TEE_ERROR_GENERIC;
54 	struct nvmem_cell *cell = NULL;
55 
56 	/* Freed from atmel_sfc_put_cell() */
57 	cell = calloc(1, sizeof(*cell));
58 	if (!cell)
59 		return TEE_ERROR_OUT_OF_MEMORY;
60 
61 	res = nvmem_cell_parse_dt(args->fdt, args->phandle_node, cell);
62 	if (res)
63 		goto out_free;
64 
65 	if (cell->offset + cell->len > ATMEL_SFC_CELLS_8) {
66 		res = TEE_ERROR_GENERIC;
67 		goto out_free;
68 	}
69 
70 	cell->ops = &atmel_sfc_nvmem_ops;
71 	cell->drv_data = data;
72 	*out_cell = cell;
73 
74 	return TEE_SUCCESS;
75 
76 out_free:
77 	free(cell);
78 
79 	return res;
80 }
81 
82 static void atmel_sfc_read_fuse(struct atmel_sfc *atmel_sfc)
83 {
84 	size_t i = 0;
85 	uint32_t val = 0;
86 
87 	for (i = 0; i < ATMEL_SFC_CELLS_32; i++) {
88 		val = io_read32(atmel_sfc->base + ATMEL_SFC_DR + i * 4);
89 		memcpy(&atmel_sfc->fuses[i * 4], &val, sizeof(val));
90 	}
91 }
92 
93 static TEE_Result atmel_sfc_probe(const void *fdt, int node,
94 				  const void *compat_data __unused)
95 {
96 	vaddr_t base = 0;
97 	size_t size = 0;
98 	struct atmel_sfc *atmel_sfc = NULL;
99 
100 	if (fdt_get_status(fdt, node) != DT_STATUS_OK_SEC)
101 		return TEE_ERROR_NODE_DISABLED;
102 
103 	matrix_configure_periph_secure(AT91C_ID_SFC);
104 
105 	if (dt_map_dev(fdt, node, &base, &size, DT_MAP_AUTO) < 0)
106 		return TEE_ERROR_GENERIC;
107 
108 	atmel_sfc = calloc(1, sizeof(*atmel_sfc));
109 	if (!atmel_sfc)
110 		return TEE_ERROR_OUT_OF_MEMORY;
111 
112 	atmel_sfc->base = base;
113 
114 	atmel_sfc_read_fuse(atmel_sfc);
115 
116 	return nvmem_register_provider(fdt, node, atmel_sfc_dt_get, atmel_sfc);
117 }
118 
119 static const struct dt_device_match atmel_sfc_match_table[] = {
120 	{ .compatible = "atmel,sama5d2-sfc" },
121 	{ }
122 };
123 
124 DEFINE_DT_DRIVER(atmel_sfc_dt_driver) = {
125 	.name = "atmel_sfc",
126 	.type = DT_DRIVER_NVMEM,
127 	.match_table = atmel_sfc_match_table,
128 	.probe = atmel_sfc_probe,
129 };
130