svn commit: r336996 - in head: share/man/man9 sys/arm/conf sys/arm64/conf sys/conf sys/dev/extres/nvmem

Emmanuel Vadot manu at FreeBSD.org
Tue Jul 31 19:08:27 UTC 2018


Author: manu
Date: Tue Jul 31 19:08:24 2018
New Revision: 336996
URL: https://svnweb.freebsd.org/changeset/base/336996

Log:
  nvmem: Add nvmem interface and helpers
  
  The nvmem interface helps provider of nvmem data to expose themselves to consumer.
  NVMEM is generally present on some embedded board in a form of eeprom or fuses.
  The nvmem api are helpers for consumer to read/write the cell data from a provider.
  
  Differential Revision:	https://reviews.freebsd.org/D16419

Added:
  head/share/man/man9/nvmem.9   (contents, props changed)
  head/sys/dev/extres/nvmem/
  head/sys/dev/extres/nvmem/nvmem.c   (contents, props changed)
  head/sys/dev/extres/nvmem/nvmem.h   (contents, props changed)
  head/sys/dev/extres/nvmem/nvmem_if.m   (contents, props changed)
Modified:
  head/sys/arm/conf/GENERIC
  head/sys/arm64/conf/GENERIC
  head/sys/conf/files

Added: head/share/man/man9/nvmem.9
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/share/man/man9/nvmem.9	Tue Jul 31 19:08:24 2018	(r336996)
@@ -0,0 +1,157 @@
+.\" Copyright (c) 2018 Emmanuel Vadot <manu at freebsd.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+.\" IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd July 24, 2018
+.Dt nvmem 9
+.Os
+.Sh NAME
+.Nm nvmem
+.Nm nvmem_get_cell_len ,
+.Nm nvmem_read_cell_by_name ,
+.Nm nvmem_read_cell_by_idx ,
+.Nm nvmem_write_cell_by_name ,
+.Nm nvmem_write_cell_by_idx ,
+.Sh SYNOPSIS
+.Cd "options EXT_RESOURCES"
+.Cd "options FDT"
+.Cd "device nvmem"
+.In sys/extres/nvmem/nvmem.h
+.Ft int
+.Fn nvmem_get_cell_len "phandle_t node" "const char *name"
+.Ft int
+.Fn nvmem_read_cell_by_name "phandle_t node" "const char *name" "void *cell" "size_t buflen"
+.Ft int
+.Fn nvmem_read_cell_by_idx "phandle_t node" "int idx" "void *cell" "size_t buflen"
+.Ft int
+.Fn nvmem_write_cell_by_name "phandle_t node" "const char *name" "void *cell" "size_t buflen"
+.Ft int
+.Fn nvmem_write_cell_by_idx "phandle_t node" "int idx" "void *cell" "size_t buflen"
+.Sh DESCRIPTION
+On some embedded boards, the manufacturer stored some data on a NVMEM
+(Non-Volatile Memory), this is generally stored in some eeprom or fuses.
+.Pp
+The
+.Nm
+API consist of helpers functions for consumer and device methods for
+providers.
+.Sh FUNCTIONS
+.Bl -tag -width indent
+.It Fn nvmem_get_cell_len  "phandle_t node" "const char *name"
+Get the size of the cell base on the reg property on the node.
+Return the size or ENOENT if the cell name wasn't found
+.It Fn nvmem_read_cell_by_name "phandle_t node" "const char *name" "void *cell" "size_t buflen"
+Get the cell content based on the name.
+Return 0 on sucess or ENOENT if the cell doesn't exists, ENXIO if no provider device was found,
+EINVAL if the size isn't correct.
+.It Fn nvmem_read_cell_by_idx "phandle_t node" "int idx" "void *cell" "size_t buflen"
+Get the cell content based on the id.
+Return 0 on sucess or ENOENT if the cell doesn't exists, ENXIO if no provider device was found,
+EINVAL if the size isn't correct.
+.It Fn nvmem_write_cell_by_name "phandle_t node" "const char *name" "void *cell" "size_t buflen"
+Write the cell content based on the name.
+Return 0 on sucess or ENOENT if the cell doesn't exists, ENXIO if no provider device was found,
+EINVAL if the size isn't correct.
+.It Fn nvmem_write_cell_by_idx "phandle_t node" "int idx" "void *cell" "size_t buflen"
+Write the cell content based on the id.
+Return 0 on sucess or ENOENT if the cell doesn't exists, ENXIO if no provider device was found,
+EINVAL if the size isn't correct.
+.El
+.Sh DEVICE METHODS
+.Bl -tag -width indent
+.It Fn nvmem_read "device_t dev" "uint32_t offset" "uint32_t size" "uint8_t *buffer"
+Provider device method to read a cell content.
+.It Fn nvmem_write "device_t dev" "uint32_t offset" "uint32_t size" "uint8_t *buffer"
+Provider device method to write a cell content.
+.El
+.Sh EXAMPLES
+Consider this DTS
+.Bd -literal
+/* Provider */
+eeprom: eeprom at 20000 {
+	board_id: id at 0 {
+		reg = <0x0 0x4>;
+	};
+};
+/* Consumer */
+device at 30000 {
+	...
+
+	nvmem-cells = <&board_id>
+	nvmem-cell-names = "boardid";
+};
+.Ed
+.Pp
+The device driver for eeprom at 20000 needs to expose itself as a provider
+.Bd -literal
+#include "nvmem_if.h"
+
+int
+foo_nvmem_read(device_t dev, uint32_t offset, uint32_t size, uint8_t *buffer)
+{
+	/* Read the data */
+}
+
+int
+foo_attach(device_t dev)
+{
+	phandle_t node;
+
+	node = ofw_bus_get_node(dev);
+	...
+	/* Registering the device so the consumers can find us */
+	OF_device_register_xref(OF_xref_from_node(node), dev);
+
+	...
+}
+
+static device_method_t foo_methods[] = {
+	...
+
+	/* nvmem interface */
+	DEVMETHOD(nvmem_read, foo_nvmem_read),
+
+	/* Terminate method list */
+	DEVMETHOD_END
+};
+.Ed
+.Pp
+The consumer device driver for device at 30000 can now read the nvmem data
+.Bd -literal
+int
+bar_attach(device_t dev)
+{
+	phandle_t node;
+	uint32_t boardid;
+
+	...
+	node = ofw_bus_get_node(dev);
+	nvmem_read_cell_by_name(node, "boardid", (void *)&boardid, sizeof(boardid));
+	...
+}
+.Ed
+.Sh HISTORY
+The nvmem related function first appear in
+.Fx 12.0 .
+The nvmem interface and manual page was written by
+.An Emmanuel Vadot Aq Mt manu at FreeBSD.org .

Modified: head/sys/arm/conf/GENERIC
==============================================================================
--- head/sys/arm/conf/GENERIC	Tue Jul 31 18:57:11 2018	(r336995)
+++ head/sys/arm/conf/GENERIC	Tue Jul 31 19:08:24 2018	(r336996)
@@ -72,6 +72,7 @@ options 	EXT_RESOURCES
 device		clk
 device		phy
 device		hwreset
+device		nvmem
 device		regulator
 device		syscon
 

Modified: head/sys/arm64/conf/GENERIC
==============================================================================
--- head/sys/arm64/conf/GENERIC	Tue Jul 31 18:57:11 2018	(r336995)
+++ head/sys/arm64/conf/GENERIC	Tue Jul 31 19:08:24 2018	(r336996)
@@ -251,6 +251,7 @@ options 	EXT_RESOURCES
 device		clk
 device		phy
 device		hwreset
+device		nvmem
 device		regulator
 device		syscon
 

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Tue Jul 31 18:57:11 2018	(r336995)
+++ head/sys/conf/files	Tue Jul 31 19:08:24 2018	(r336996)
@@ -1750,6 +1750,8 @@ dev/extres/phy/phydev_if.m	optional ext_resources phy 
 dev/extres/phy/phynode_if.m	optional ext_resources phy fdt
 dev/extres/hwreset/hwreset.c	optional ext_resources hwreset fdt
 dev/extres/hwreset/hwreset_if.m	optional ext_resources hwreset fdt
+dev/extres/nvmem/nvmem.c	optional ext_resources nvmem fdt
+dev/extres/nvmem/nvmem_if.m	optional ext_resources nvmem fdt
 dev/extres/regulator/regdev_if.m	optional ext_resources regulator fdt
 dev/extres/regulator/regnode_if.m	optional ext_resources regulator fdt
 dev/extres/regulator/regulator.c	optional ext_resources regulator fdt

Added: head/sys/dev/extres/nvmem/nvmem.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/extres/nvmem/nvmem.c	Tue Jul 31 19:08:24 2018	(r336996)
@@ -0,0 +1,199 @@
+/*-
+ * Copyright 2018 Emmanuel Vadot <manu at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "nvmem.h"
+#include "nvmem_if.h"
+
+static int
+nvmem_get_cell_node(phandle_t node, int idx, phandle_t *cell)
+{
+	phandle_t *p_cell;
+	phandle_t cell_node;
+	int ncell;
+
+	if (!OF_hasprop(node, "nvmem-cells") ||
+	    !OF_hasprop(node, "nvmem-cell-names"))
+		return (ENOENT);
+
+	ncell = OF_getencprop_alloc_multi(node, "nvmem-cells", sizeof(*p_cell), (void **)&p_cell);
+	if (ncell <= 0)
+		return (ENOENT);
+
+	cell_node = OF_node_from_xref(p_cell[idx]);
+	if (cell_node == p_cell[idx]) {
+		if (bootverbose)
+			printf("nvmem_get_node: Cannot resolve phandle %x\n",
+			    p_cell[idx]);
+		OF_prop_free(p_cell);
+		return (ENOENT);
+	}
+
+	OF_prop_free(p_cell);
+	*cell = cell_node;
+
+	return (0);
+}
+
+int
+nvmem_get_cell_len(phandle_t node, const char *name)
+{
+	phandle_t cell_node;
+	uint32_t reg[2];
+	int rv, idx;
+
+	rv = ofw_bus_find_string_index(node, "nvmem-cell-names", name, &idx);
+	if (rv != 0)
+		return (rv);
+
+	rv = nvmem_get_cell_node(node, idx, &cell_node);
+	if (rv != 0)
+		return (rv);
+
+	if (OF_getencprop(cell_node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
+		if (bootverbose)
+			printf("nvmem_get_cell_len: Cannot parse reg property of cell %s\n",
+			    name);
+		return (ENOENT);
+	}
+
+	return (reg[1]);
+}
+
+int
+nvmem_read_cell_by_idx(phandle_t node, int idx, void *cell, size_t buflen)
+{
+	phandle_t cell_node;
+	device_t provider;
+	uint32_t reg[2];
+	int rv;
+
+	rv = nvmem_get_cell_node(node, idx, &cell_node);
+	if (rv != 0)
+		return (rv);
+
+	/* Validate the reg property */
+	if (OF_getencprop(cell_node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
+		if (bootverbose)
+			printf("nvmem_get_cell_by_name: Cannot parse reg property of cell %d\n",
+			    idx);
+		return (ENOENT);
+	}
+
+	if (buflen != reg[1])
+		return (EINVAL);
+
+	provider = OF_device_from_xref(OF_xref_from_node(OF_parent(cell_node)));
+	if (provider == NULL) {
+		if (bootverbose)
+			printf("nvmem_get_cell_by_idx: Cannot find the nvmem device\n");
+		return (ENXIO);
+	}
+
+	rv = NVMEM_READ(provider, reg[0], reg[1], cell);
+	if (rv != 0) {
+		return (rv);
+	}
+
+	return (0);
+}
+
+int
+nvmem_read_cell_by_name(phandle_t node, const char *name, void *cell, size_t buflen)
+{
+	int rv, idx;
+
+	rv = ofw_bus_find_string_index(node, "nvmem-cell-names", name, &idx);
+	if (rv != 0)
+		return (rv);
+
+	return (nvmem_read_cell_by_idx(node, idx, cell, buflen));
+}
+
+int
+nvmem_write_cell_by_idx(phandle_t node, int idx, void *cell, size_t buflen)
+{
+	phandle_t cell_node, prov_node;
+	device_t provider;
+	uint32_t reg[2];
+	int rv;
+
+	rv = nvmem_get_cell_node(node, idx, &cell_node);
+	if (rv != 0)
+		return (rv);
+
+	prov_node = OF_parent(cell_node);
+	if (OF_hasprop(prov_node, "read-only"))
+		return (ENXIO);
+
+	/* Validate the reg property */
+	if (OF_getencprop(cell_node, "reg", reg, sizeof(reg)) != sizeof(reg)) {
+		if (bootverbose)
+			printf("nvmem_get_cell_by_idx: Cannot parse reg property of cell %d\n",
+			    idx);
+		return (ENXIO);
+	}
+
+	if (buflen != reg[1])
+		return (EINVAL);
+
+	provider = OF_device_from_xref(OF_xref_from_node(prov_node));
+	if (provider == NULL) {
+		if (bootverbose)
+			printf("nvmem_get_cell_by_idx: Cannot find the nvmem device\n");
+		return (ENXIO);
+	}
+
+	rv = NVMEM_WRITE(provider, reg[0], reg[1], cell);
+	if (rv != 0) {
+		return (rv);
+	}
+
+	return (0);
+}
+
+int
+nvmem_write_cell_by_name(phandle_t node, const char *name, void *cell, size_t buflen)
+{
+	int rv, idx;
+
+	rv = ofw_bus_find_string_index(node, "nvmem-cell-names", name, &idx);
+	if (rv != 0)
+		return (rv);
+
+	return (nvmem_write_cell_by_idx(node, idx, cell, buflen));
+}

Added: head/sys/dev/extres/nvmem/nvmem.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/extres/nvmem/nvmem.h	Tue Jul 31 19:08:24 2018	(r336996)
@@ -0,0 +1,37 @@
+/*-
+ * Copyright 2018 Emmanuel Vadot <manu at FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DEV_EXTRES_NVMEM_H_
+#define _DEV_EXTRES_NVMEM_H_
+
+int nvmem_get_cell_len(phandle_t node, const char *name);
+int nvmem_read_cell_by_name(phandle_t node, const char *name, void *cell, size_t buflen);
+int nvmem_read_cell_by_idx(phandle_t node, int idx, void *cell, size_t buflen);
+int nvmem_write_cell_by_name(phandle_t node, const char *name, void *cell, size_t buflen);
+int nvmem_write_cell_by_idx(phandle_t node, int idx, void *cell, size_t buflen);
+
+#endif /* _DEV_EXTRES_NVMEM_H_ */

Added: head/sys/dev/extres/nvmem/nvmem_if.m
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/dev/extres/nvmem/nvmem_if.m	Tue Jul 31 19:08:24 2018	(r336996)
@@ -0,0 +1,67 @@
+#-
+# Copyright (c) 2018 Emmanuel Vadot <manu at FreeBSD.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+INTERFACE nvmem;
+
+#
+# Default implementations of some methods.
+#
+CODE {
+	static int
+	null_nvmem_read(device_t dev __unused, uint32_t offset __unused, uint32_t size __unused, uint8_t *buffer __unused)
+	{
+
+		return (ENXIO);
+	}
+
+	static int
+	null_nvmem_write(device_t dev __unused, uint32_t offset __unused, uint32_t size __unused, uint8_t *buffer __unused)
+	{
+
+		return (ENXIO);
+	}
+};
+
+#
+# Read
+#
+METHOD int read {
+	device_t dev;
+	uint32_t offset;
+	uint32_t size;
+	uint8_t *buffer;
+} DEFAULT null_nvmem_read;
+
+#
+# Write
+#
+METHOD int write {
+	device_t dev;
+	uint32_t offset;
+	uint32_t size;
+	uint8_t *buffer;
+} DEFAULT null_nvmem_write;


More information about the svn-src-all mailing list