xref: /freebsd/sys/dev/nvmem/nvmem.c (revision e51b3d8e)
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