]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/extres/nvmem/nvmem.c
Update to Zstandard 1.4.4
[FreeBSD/FreeBSD.git] / sys / dev / extres / nvmem / nvmem.c
1 /*-
2  * Copyright 2018 Emmanuel Vadot <manu@FreeBSD.org>
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 AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, 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 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28
29 #include <sys/param.h>
30 #include <sys/bus.h>
31 #include <sys/kernel.h>
32 #include <sys/malloc.h>
33 #include <sys/mutex.h>
34
35 #include <dev/fdt/fdt_common.h>
36 #include <dev/ofw/ofw_bus.h>
37 #include <dev/ofw/ofw_bus_subr.h>
38
39 #include "nvmem.h"
40 #include "nvmem_if.h"
41
42 static int
43 nvmem_get_cell_node(phandle_t node, int idx, phandle_t *cell)
44 {
45         phandle_t *p_cell;
46         phandle_t cell_node;
47         int ncell;
48
49         if (!OF_hasprop(node, "nvmem-cells") ||
50             !OF_hasprop(node, "nvmem-cell-names"))
51                 return (ENOENT);
52
53         ncell = OF_getencprop_alloc_multi(node, "nvmem-cells", sizeof(*p_cell), (void **)&p_cell);
54         if (ncell <= 0)
55                 return (ENOENT);
56
57         cell_node = OF_node_from_xref(p_cell[idx]);
58         if (cell_node == p_cell[idx]) {
59                 if (bootverbose)
60                         printf("nvmem_get_node: Cannot resolve phandle %x\n",
61                             p_cell[idx]);
62                 OF_prop_free(p_cell);
63                 return (ENOENT);
64         }
65
66         OF_prop_free(p_cell);
67         *cell = cell_node;
68
69         return (0);
70 }
71
72 int
73 nvmem_get_cell_len(phandle_t node, const char *name)
74 {
75         phandle_t cell_node;
76         uint32_t reg[2];
77         int rv, idx;
78
79         rv = ofw_bus_find_string_index(node, "nvmem-cell-names", name, &idx);
80         if (rv != 0)
81                 return (rv);
82
83         rv = nvmem_get_cell_node(node, idx, &cell_node);
84         if (rv != 0)
85                 return (rv);
86
87         if (OF_getencprop(cell_node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
88                 if (bootverbose)
89                         printf("nvmem_get_cell_len: Cannot parse reg property of cell %s\n",
90                             name);
91                 return (ENOENT);
92         }
93
94         return (reg[1]);
95 }
96
97 int
98 nvmem_read_cell_by_idx(phandle_t node, int idx, void *cell, size_t buflen)
99 {
100         phandle_t cell_node;
101         device_t provider;
102         uint32_t reg[2];
103         int rv;
104
105         rv = nvmem_get_cell_node(node, idx, &cell_node);
106         if (rv != 0)
107                 return (rv);
108
109         /* Validate the reg property */
110         if (OF_getencprop(cell_node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
111                 if (bootverbose)
112                         printf("nvmem_get_cell_by_name: Cannot parse reg property of cell %d\n",
113                             idx);
114                 return (ENOENT);
115         }
116
117         if (buflen != reg[1])
118                 return (EINVAL);
119
120         provider = OF_device_from_xref(OF_xref_from_node(OF_parent(cell_node)));
121         if (provider == NULL) {
122                 if (bootverbose)
123                         printf("nvmem_get_cell_by_idx: Cannot find the nvmem device\n");
124                 return (ENXIO);
125         }
126
127         rv = NVMEM_READ(provider, reg[0], reg[1], cell);
128         if (rv != 0) {
129                 return (rv);
130         }
131
132         return (0);
133 }
134
135 int
136 nvmem_read_cell_by_name(phandle_t node, const char *name, void *cell, size_t buflen)
137 {
138         int rv, idx;
139
140         rv = ofw_bus_find_string_index(node, "nvmem-cell-names", name, &idx);
141         if (rv != 0)
142                 return (rv);
143
144         return (nvmem_read_cell_by_idx(node, idx, cell, buflen));
145 }
146
147 int
148 nvmem_write_cell_by_idx(phandle_t node, int idx, void *cell, size_t buflen)
149 {
150         phandle_t cell_node, prov_node;
151         device_t provider;
152         uint32_t reg[2];
153         int rv;
154
155         rv = nvmem_get_cell_node(node, idx, &cell_node);
156         if (rv != 0)
157                 return (rv);
158
159         prov_node = OF_parent(cell_node);
160         if (OF_hasprop(prov_node, "read-only"))
161                 return (ENXIO);
162
163         /* Validate the reg property */
164         if (OF_getencprop(cell_node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
165                 if (bootverbose)
166                         printf("nvmem_get_cell_by_idx: Cannot parse reg property of cell %d\n",
167                             idx);
168                 return (ENXIO);
169         }
170
171         if (buflen != reg[1])
172                 return (EINVAL);
173
174         provider = OF_device_from_xref(OF_xref_from_node(prov_node));
175         if (provider == NULL) {
176                 if (bootverbose)
177                         printf("nvmem_get_cell_by_idx: Cannot find the nvmem device\n");
178                 return (ENXIO);
179         }
180
181         rv = NVMEM_WRITE(provider, reg[0], reg[1], cell);
182         if (rv != 0) {
183                 return (rv);
184         }
185
186         return (0);
187 }
188
189 int
190 nvmem_write_cell_by_name(phandle_t node, const char *name, void *cell, size_t buflen)
191 {
192         int rv, idx;
193
194         rv = ofw_bus_find_string_index(node, "nvmem-cell-names", name, &idx);
195         if (rv != 0)
196                 return (rv);
197
198         return (nvmem_write_cell_by_idx(node, idx, cell, buflen));
199 }