Date: Tue, 31 Jul 2018 19:08:25 +0000 (UTC) From: Emmanuel Vadot <manu@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r336996 - in head: share/man/man9 sys/arm/conf sys/arm64/conf sys/conf sys/dev/extres/nvmem Message-ID: <201807311908.w6VJ8Pmv076244@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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@20000 { + board_id: id@0 { + reg = <0x0 0x4>; + }; +}; +/* Consumer */ +device@30000 { + ... + + nvmem-cells = <&board_id> + nvmem-cell-names = "boardid"; +}; +.Ed +.Pp +The device driver for eeprom@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@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@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@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@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@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;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201807311908.w6VJ8Pmv076244>