1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2023, Microchip
4 */
5
6 #ifndef __DRIVERS_NVMEM_H
7 #define __DRIVERS_NVMEM_H
8
9 #include <kernel/dt_driver.h>
10 #include <tee_api_defines.h>
11 #include <tee_api_types.h>
12 #include <types_ext.h>
13
14 struct nvmem_cell;
15
16 /*
17 * struct nvmem_ops - NVMEM device driver operations
18 * @read_cell: Allocate @data in the heap and load @len bytes to from an
19 * NVMEM cell
20 * @put_cell: Release resources allocated from nvmem_dt_get_func callback
21 * function
22 */
23 struct nvmem_ops {
24 /*
25 * Read data from an NVMEM cell.
26 * @cell: Cell to read data from
27 * @data: Output buffer of size greater or equal to @cell->size
28 */
29 TEE_Result (*read_cell)(struct nvmem_cell *cell, uint8_t *data);
30 void (*put_cell)(struct nvmem_cell *cell);
31 };
32
33 /*
34 * struct nvmem_cell - Description of an NVMEM cell
35 * @offset: Cell byte offset in the NVMEM device
36 * @len: Cell byte size
37 * @ops: NVMEM device driver operation handlers
38 * @drv_data: NVMEM device driver private data
39 */
40 struct nvmem_cell {
41 paddr_t offset;
42 size_t len;
43 const struct nvmem_ops *ops;
44 void *drv_data;
45 };
46
47 /*
48 * nvmem_dt_get_func - Typedef of handlers to get an NVMEM cell from a npode
49 * @args: Reference to phandle arguments
50 * @data: Pointer to data given at nvmem_dt_get_func() call
51 * @cell: Output reference to cell instance upon success
52 *
53 * Return TEE_SUCCESS in case of success.
54 * Return TEE_ERROR_DEFER_DRIVER_INIT if NVMEM driver is not initialized
55 * Return another TEE_Result compliant code otherwise.
56 */
57 typedef TEE_Result (*nvmem_dt_get_func)(struct dt_pargs *args,
58 void *data, struct nvmem_cell **cell);
59
60 #ifdef CFG_DRIVERS_NVMEM
61 /**
62 * nvmem_register_provider() - Register a NVMEM controller
63 *
64 * @fdt: Device tree to work on
65 * @nodeoffset: Node offset of NVMEM cell consumer
66 * @get_dt_nvmem: Callback to match the devicetree NVMEM reference with
67 * nvmem_cell
68 * @data: Data which will be passed to the get_dt_nvmem callback
69 * Return a TEE_Result compliant value
70 */
nvmem_register_provider(const void * fdt,int nodeoffset,nvmem_dt_get_func get_dt_nvmem,void * data)71 static inline TEE_Result nvmem_register_provider(const void *fdt,
72 int nodeoffset,
73 nvmem_dt_get_func get_dt_nvmem,
74 void *data)
75 {
76 return dt_driver_register_provider(fdt, nodeoffset,
77 (get_of_device_func)get_dt_nvmem,
78 data, DT_DRIVER_NVMEM);
79 }
80
81 /**
82 * nvmem_get_cell_by_name() - Obtain a NVMEM cell from its name in the DT node
83 *
84 * @fdt: Device tree to work on
85 * @nodeoffset: Node offset of NVMEM cell consumer
86 * @name: name of the NVMEM cell defined by property nvmem-cell-names to obtain
87 * from the device tree
88 * @cell: Pointer filled with the retrieved cell, must be freed after use
89 using nvmem_put_cell()
90 * Return a TEE_Result compliant value
91 */
92 TEE_Result nvmem_get_cell_by_name(const void *fdt, int nodeoffset,
93 const char *name, struct nvmem_cell **cell);
94
95 /**
96 * nvmem_get_cell_by_index() - Obtain a NVMEM cell from property nvmem-cells
97 *
98 * @fdt: Device tree to work on
99 * @nodeoffset: Node offset of NVMEM cell consumer
100 * @index: Index of the NVMEM cell to obtain from device-tree
101 * @out_cell: Pointer filled with the retrieved cell, must be freed after use
102 * using nvmem_put_cell()
103 * Return a TEE_Result compliant value
104 */
105 TEE_Result nvmem_get_cell_by_index(const void *fdt,
106 int nodeoffset,
107 unsigned int index,
108 struct nvmem_cell **out_cell);
109
110 /**
111 * nvmem_cell_parse_dt() - Parse device-tree information to fill a NVMEM cell
112 *
113 * @fdt: Device tree to work on
114 * @nodeoffset: Node offset of the NVMEM cell controller
115 * @cell: Pointer to cell that will be filled
116 */
117 TEE_Result nvmem_cell_parse_dt(const void *fdt, int nodeoffset,
118 struct nvmem_cell *cell);
119
120 /**
121 * nvmem_put_cell() - Free resource allocated from nvmem_get_cell_by_*()
122 *
123 * @cell: Cell to be freed
124 */
nvmem_put_cell(struct nvmem_cell * cell)125 static inline void nvmem_put_cell(struct nvmem_cell *cell)
126 {
127 if (cell->ops->put_cell)
128 cell->ops->put_cell(cell);
129 }
130
131 /*
132 * nvmem_cell_read() - Read data from a NVMEM cell
133 * @cell: Cell to read from NVMEM
134 * @data: Output data read from the cell upon success, byte size >= @cell->size
135 */
nvmem_cell_read(struct nvmem_cell * cell,uint8_t * data)136 static inline TEE_Result nvmem_cell_read(struct nvmem_cell *cell,
137 uint8_t *data)
138 {
139 if (!cell->ops->read_cell)
140 return TEE_ERROR_NOT_SUPPORTED;
141
142 return cell->ops->read_cell(cell, data);
143 }
144
145 /*
146 * nvmem_cell_malloc_and_read() - Allocate and read data from a NVMEM cell
147 * @cell: Cell to read from NVMEM
148 * @data: Output allocated buffer where NVMEM cell data are stored upon success
149 *
150 * Upon success, the output buffer is allocated with malloc(). Caller is
151 * responsible for freeing the buffer with free() if needed.
152 */
153 TEE_Result nvmem_cell_malloc_and_read(struct nvmem_cell *cell,
154 uint8_t **out_data);
155
156 #else /* CFG_DRIVERS_NVMEM */
nvmem_register_provider(const void * fdt __unused,int nodeoffset __unused,nvmem_dt_get_func fn __unused,void * data __unused)157 static inline TEE_Result nvmem_register_provider(const void *fdt __unused,
158 int nodeoffset __unused,
159 nvmem_dt_get_func fn __unused,
160 void *data __unused)
161 {
162 return TEE_ERROR_NOT_SUPPORTED;
163 }
164
nvmem_get_cell_by_name(const void * fdt __unused,int nodeoffset __unused,const char * name __unused,struct nvmem_cell ** c __unused)165 static inline TEE_Result nvmem_get_cell_by_name(const void *fdt __unused,
166 int nodeoffset __unused,
167 const char *name __unused,
168 struct nvmem_cell **c __unused)
169 {
170 return TEE_ERROR_NOT_SUPPORTED;
171 }
172
173 static inline
nvmem_get_cell_by_index(const void * fdt __unused,int nodeoffset __unused,unsigned int index __unused,struct nvmem_cell ** cell __unused)174 TEE_Result nvmem_get_cell_by_index(const void *fdt __unused,
175 int nodeoffset __unused,
176 unsigned int index __unused,
177 struct nvmem_cell **cell __unused)
178 {
179 return TEE_ERROR_NOT_SUPPORTED;
180 }
181
nvmem_cell_parse_dt(const void * fdt __unused,int nodeoffset __unused,struct nvmem_cell * cell __unused)182 static inline TEE_Result nvmem_cell_parse_dt(const void *fdt __unused,
183 int nodeoffset __unused,
184 struct nvmem_cell *cell __unused)
185 {
186 return TEE_ERROR_NOT_SUPPORTED;
187 }
188
nvmem_put_cell(struct nvmem_cell * cell __unused)189 static inline void nvmem_put_cell(struct nvmem_cell *cell __unused)
190 {
191 }
192 #endif /* CFG_DRIVERS_NVMEM */
193 #endif /* __DRIVERS_NVMEM_H */
194