summaryrefslogtreecommitdiff
path: root/sys/dev/ofw/ofw_misc.c
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2020-01-23 02:57:11 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2020-01-23 02:57:11 +0000
commitd3dfaa810f99e6a0889b076e7f76eebda0283aa3 (patch)
treedc72d6b2564a6a4679bbaed637198869dc594a4e /sys/dev/ofw/ofw_misc.c
parent13b1e1430f44f5d7571a944e0657fbb47d07553d (diff)
Add an interface to read an nvmem "cell".
ok patrick@
Diffstat (limited to 'sys/dev/ofw/ofw_misc.c')
-rw-r--r--sys/dev/ofw/ofw_misc.c80
1 files changed, 76 insertions, 4 deletions
diff --git a/sys/dev/ofw/ofw_misc.c b/sys/dev/ofw/ofw_misc.c
index 7856088933f..e6672eb4fa9 100644
--- a/sys/dev/ofw/ofw_misc.c
+++ b/sys/dev/ofw/ofw_misc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ofw_misc.c,v 1.11 2020/01/21 00:21:55 kettenis Exp $ */
+/* $OpenBSD: ofw_misc.c,v 1.12 2020/01/23 02:57:10 kettenis Exp $ */
/*
* Copyright (c) 2017 Mark Kettenis
*
@@ -345,14 +345,51 @@ pwm_set_state(uint32_t *cells, struct pwm_state *ps)
LIST_HEAD(, nvmem_device) nvmem_devices =
LIST_HEAD_INITIALIZER(nvmem_devices);
+struct nvmem_cell {
+ uint32_t nc_phandle;
+ struct nvmem_device *nc_nd;
+ bus_addr_t nc_addr;
+ bus_size_t nc_size;
+
+ LIST_ENTRY(nvmem_cell) nc_list;
+};
+
+LIST_HEAD(, nvmem_cell) nvmem_cells =
+ LIST_HEAD_INITIALIZER(nvmem_cells);
+
+void
+nvmem_register_child(int node, struct nvmem_device *nd)
+{
+ struct nvmem_cell *nc;
+ uint32_t phandle;
+ uint32_t reg[2];
+
+ phandle = OF_getpropint(node, "phandle", 0);
+ if (phandle == 0)
+ return;
+
+ if (OF_getpropintarray(node, "reg", reg, sizeof(reg)) != sizeof(reg))
+ return;
+
+ nc = malloc(sizeof(struct nvmem_cell), M_DEVBUF, M_WAITOK);
+ nc->nc_phandle = phandle;
+ nc->nc_nd = nd;
+ nc->nc_addr = reg[0];
+ nc->nc_size = reg[1];
+ LIST_INSERT_HEAD(&nvmem_cells, nc, nc_list);
+}
+
void
nvmem_register(struct nvmem_device *nd)
{
+ int node;
+
nd->nd_phandle = OF_getpropint(nd->nd_node, "phandle", 0);
- if (nd->nd_phandle == 0)
- return;
+ if (nd->nd_phandle)
+ LIST_INSERT_HEAD(&nvmem_devices, nd, nd_list);
- LIST_INSERT_HEAD(&nvmem_devices, nd, nd_list);
+ for (node = OF_child(nd->nd_node); node; node = OF_peer(node))
+ nvmem_register_child(node, nd);
}
int
@@ -367,3 +404,38 @@ nvmem_read(uint32_t phandle, bus_addr_t addr, void *data, bus_size_t size)
return ENXIO;
}
+
+int
+nvmem_read_cell(int node, const char *name, void *data, bus_size_t size)
+{
+ struct nvmem_device *nd;
+ struct nvmem_cell *nc;
+ uint32_t phandle, *phandles;
+ int id, len;
+
+ id = OF_getindex(node, name, "nvmem-cell-names");
+ if (id < 0)
+ return ENXIO;
+
+ len = OF_getproplen(node, "nvmem-cells");
+ if (len <= 0)
+ return ENXIO;
+
+ phandles = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(node, "nvmem-cells", phandles, len);
+ phandle = phandles[id];
+ free(phandles, M_TEMP, len);
+
+ LIST_FOREACH(nc, &nvmem_cells, nc_list) {
+ if (nc->nc_phandle == phandle)
+ break;
+ }
+ if (nc == NULL)
+ return ENXIO;
+
+ if (size > nc->nc_size)
+ return EINVAL;
+
+ nd = nc->nc_nd;
+ return nd->nd_read(nd->nd_cookie, nc->nc_addr, data, size);
+}