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