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 }
Cache object: 7ccf461f160b58401372698febab16b5
|