You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2021/01/15 16:34:19 UTC
[incubator-nuttx] branch master updated: Add generic efuse driver
for NuttX
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 1549494 Add generic efuse driver for NuttX
1549494 is described below
commit 154949403c3867ea596617e47953ec83171576a4
Author: Alan C. Assis <ac...@gmail.com>
AuthorDate: Fri Jan 15 10:52:43 2021 -0300
Add generic efuse driver for NuttX
Squashed commits:
Fix small typos on efuse driver
Fix nxstyle issues
Fix aligment and missing FAR
Improvements to efuse driver
Fix: don't free 'lower' on efuse_unregister
Describe the efuse_param
Remove upper pointer from lowerhalt
Fix blank line at end of function
Co-authored-by: saramonteiro <sa...@gmail.com>
Co-authored-by: Xiang Xiao <xi...@xiaomi.com>
---
drivers/Kconfig | 1 +
drivers/Makefile | 1 +
drivers/efuse/Kconfig | 11 ++
drivers/efuse/Make.defs | 31 ++++
drivers/efuse/efuse.c | 394 ++++++++++++++++++++++++++++++++++++++++++++
include/nuttx/efuse/efuse.h | 174 +++++++++++++++++++
include/nuttx/fs/ioctl.h | 6 +
7 files changed, 618 insertions(+)
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 57c8961..3e2ad26 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -95,6 +95,7 @@ source drivers/mmcsd/Kconfig
source drivers/modem/Kconfig
source drivers/mtd/Kconfig
source drivers/eeprom/Kconfig
+source drivers/efuse/Kconfig
source drivers/net/Kconfig
source drivers/note/Kconfig
source drivers/pipes/Kconfig
diff --git a/drivers/Makefile b/drivers/Makefile
index d58a78b..ad8ea5e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -55,6 +55,7 @@ include mmcsd/Make.defs
include modem/Make.defs
include mtd/Make.defs
include eeprom/Make.defs
+include efuse/Make.defs
include net/Make.defs
include note/Make.defs
include pipes/Make.defs
diff --git a/drivers/efuse/Kconfig b/drivers/efuse/Kconfig
new file mode 100644
index 0000000..da2b1ee
--- /dev/null
+++ b/drivers/efuse/Kconfig
@@ -0,0 +1,11 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+menuconfig EFUSE
+ bool "EFUSE support"
+ default n
+ ---help---
+ This directory holds implementations of EFUSE subsystem.
+
diff --git a/drivers/efuse/Make.defs b/drivers/efuse/Make.defs
new file mode 100644
index 0000000..9f99f73
--- /dev/null
+++ b/drivers/efuse/Make.defs
@@ -0,0 +1,31 @@
+############################################################################
+# drivers/efuse/Make.defs
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+############################################################################
+
+# Include EFUSE support
+
+ifeq ($(CONFIG_EFUSE),y)
+
+CSRCS += efuse.c
+
+# Include build support
+
+DEPPATH += --dep-path efuse
+VPATH += :efuse
+endif
diff --git a/drivers/efuse/efuse.c b/drivers/efuse/efuse.c
new file mode 100644
index 0000000..d200fc4
--- /dev/null
+++ b/drivers/efuse/efuse.c
@@ -0,0 +1,394 @@
+/****************************************************************************
+ * drivers/efuse/efuse.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/power/pm.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/efuse/efuse.h>
+
+#ifdef CONFIG_EFUSE
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Definitions
+ ****************************************************************************/
+
+/* This structure describes the state of the upper half driver */
+
+struct efuse_upperhalf_s
+{
+ sem_t exclsem; /* Supports mutual exclusion */
+ FAR char *path; /* Registration path */
+
+ /* The contained lower-half driver */
+
+ FAR struct efuse_lowerhalf_s *lower;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int efuse_open(FAR struct file *filep);
+static int efuse_close(FAR struct file *filep);
+static ssize_t efuse_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen);
+static ssize_t efuse_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen);
+static int efuse_ioctl(FAR struct file *filep, int cmd,
+ unsigned long arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_efuseops =
+{
+ efuse_open, /* open */
+ efuse_close, /* close */
+ efuse_read, /* read */
+ efuse_write, /* write */
+ NULL, /* seek */
+ efuse_ioctl, /* ioctl */
+ NULL /* poll */
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: efuse_open
+ *
+ * Description:
+ * This function is called whenever the efuse timer device is opened.
+ *
+ ****************************************************************************/
+
+static int efuse_open(FAR struct file *filep)
+{
+ return OK;
+}
+
+/****************************************************************************
+ * Name: efuse_close
+ *
+ * Description:
+ * This function is called when the efuse timer device is closed.
+ *
+ ****************************************************************************/
+
+static int efuse_close(FAR struct file *filep)
+{
+ return OK;
+}
+
+/****************************************************************************
+ * Name: efuse_read
+ *
+ * Description:
+ * A dummy read method. This is provided only to satisfy the VFS layer.
+ *
+ ****************************************************************************/
+
+static ssize_t efuse_read(FAR struct file *filep, FAR char *buffer,
+ size_t buflen)
+{
+ /* Return zero -- usually meaning end-of-file */
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: efuse_write
+ *
+ * Description:
+ * A dummy write method. This is provided only to satisfy the VFS layer.
+ *
+ ****************************************************************************/
+
+static ssize_t efuse_write(FAR struct file *filep, FAR const char *buffer,
+ size_t buflen)
+{
+ return 0;
+}
+
+/****************************************************************************
+ * Name: efuse_ioctl
+ *
+ * Description:
+ * The standard ioctl method. This is where ALL of the efuse timer
+ * work is done.
+ *
+ ****************************************************************************/
+
+static int efuse_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
+{
+ FAR struct inode *inode = filep->f_inode;
+ FAR struct efuse_upperhalf_s *upper;
+ FAR struct efuse_lowerhalf_s *lower;
+ int ret;
+
+ minfo("cmd: %d arg: %lu\n", cmd, arg);
+ upper = inode->i_private;
+ DEBUGASSERT(upper != NULL);
+ lower = upper->lower;
+ DEBUGASSERT(lower != NULL);
+
+ /* Get exclusive access to the device structures */
+
+ ret = nxsem_wait(&upper->exclsem);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Handle built-in ioctl commands */
+
+ switch (cmd)
+ {
+ /* cmd: EFUSEIOC_READ_FIELD
+ * Description: Read a field
+ * Argument: A pointer to a struct efuse_param.
+ * Where the field is an array.
+ * Each item in the array is a pointer to an efuse_desc_t
+ * variable.
+ * An efuse_desc_t variable contains an offset to a field
+ * or subfield and its size in bits.
+ * The size param is a redundancy, and it is the sum
+ * of all subfields sizes from efuse_desc_t in bits.
+ * The data is a pointer to a pre-allocated space
+ * where the driver will load the data read from efuse.
+ */
+
+ case EFUSEIOC_READ_FIELD:
+ {
+ FAR struct efuse_param *param =
+ (FAR struct efuse_param *)((uintptr_t)arg);
+
+ /* Read the efuse */
+
+ DEBUGASSERT(lower->ops->read_field); /* Required */
+ ret = lower->ops->read_field(lower,
+ param->field,
+ param->data,
+ param->size);
+ }
+ break;
+
+ /* cmd: EFUSEIOC_WRITE_FIELD
+ * Description: Write a field
+ * Argument: A pointer to a struct efuse_param.
+ * Where the field is an array.
+ * Each item in the array is a pointer to an efuse_desc_t
+ * variable.
+ * An efuse_desc_t variable contains an offset to a field
+ * or subfield and its size in bits.
+ * The size param is a redundancy, and it is the sum
+ * of all subfields sizes from efuse_desc_t in bits.
+ * The data is a pointer to a pre-allocated space
+ * where the user wrote the value that he wants
+ * to write in a field or subfield.
+ */
+
+ case EFUSEIOC_WRITE_FIELD:
+ {
+ FAR struct efuse_param *param =
+ (FAR struct efuse_param *)((uintptr_t)arg);
+
+ /* Write the efuse */
+
+ DEBUGASSERT(lower->ops->write_field); /* Required */
+ ret = lower->ops->write_field(lower,
+ param->field,
+ param->data,
+ param->size);
+ }
+ break;
+
+ default:
+ {
+ minfo("Forwarding unrecognized cmd: %d arg: %lu\n", cmd, arg);
+
+ /* Ioctls commands that are not recognized by the "upper-half"
+ * driver are forwarded to the lower half driver through this
+ * method.
+ */
+
+ if (lower->ops->ioctl) /* Optional */
+ {
+ ret = lower->ops->ioctl(lower, cmd, arg);
+ }
+ else
+ {
+ ret = -ENOTTY;
+ }
+ }
+ break;
+ }
+
+ nxsem_post(&upper->exclsem);
+ return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: efuse_register
+ *
+ * Description:
+ * This function binds an instance of a "lower half" efuse driver with
+ * the "upper half" efuse device and registers that device so that can
+ * be used by application code.
+ *
+ * Input Parameters:
+ * dev path - The full path to the driver to be registered in the NuttX
+ * pseudo-filesystem. The recommended convention is to name all
+ * efuse drivers as "/dev/efuse".
+ * lower - A pointer to an instance of lower half efuse driver. This
+ * instance is bound to the efuse driver and must persists as long as
+ * the driver persists.
+ *
+ * Returned Value:
+ * On success, a non-NULL handle is returned to the caller. In the event
+ * of any failure, a NULL value is returned.
+ *
+ ****************************************************************************/
+
+FAR void *efuse_register(FAR const char *path,
+ FAR struct efuse_lowerhalf_s *lower)
+{
+ FAR struct efuse_upperhalf_s *upper;
+ int ret;
+
+ DEBUGASSERT(path && lower);
+ minfo("Entry: path=%s\n", path);
+
+ /* Allocate the upper-half data structure */
+
+ upper = (FAR struct efuse_upperhalf_s *)
+ kmm_zalloc(sizeof(struct efuse_upperhalf_s));
+ if (!upper)
+ {
+ merr("Upper half allocation failed\n");
+ goto errout;
+ }
+
+ /* Initialize the efuse timer device structure (it was already zeroed
+ * by kmm_zalloc()).
+ */
+
+ nxsem_init(&upper->exclsem, 0, 1);
+ upper->lower = lower;
+
+ /* Copy the registration path */
+
+ upper->path = strdup(path);
+ if (!upper->path)
+ {
+ merr("Path allocation failed\n");
+ goto errout_with_upper;
+ }
+
+ /* Register the efuse timer device */
+
+ ret = register_driver(path, &g_efuseops, 0666, upper);
+ if (ret < 0)
+ {
+ merr("register_driver failed: %d\n", ret);
+ goto errout_with_path;
+ }
+
+ return (FAR void *)upper;
+
+errout_with_path:
+ kmm_free(upper->path);
+
+errout_with_upper:
+ nxsem_destroy(&upper->exclsem);
+ kmm_free(upper);
+
+errout:
+ return NULL;
+}
+
+/****************************************************************************
+ * Name: efuse_unregister
+ *
+ * Description:
+ * This function can be called to disable and unregister the efuse
+ * device driver.
+ *
+ * Input Parameters:
+ * handle - This is the handle that was returned by efuse_register()
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void efuse_unregister(FAR void *handle)
+{
+ FAR struct efuse_upperhalf_s *upper;
+ FAR struct efuse_lowerhalf_s *lower;
+
+ /* Recover the pointer to the upper-half driver state */
+
+ upper = (FAR struct efuse_upperhalf_s *)handle;
+ DEBUGASSERT(upper != NULL);
+ lower = upper->lower;
+ DEBUGASSERT(lower != NULL);
+
+ minfo("Unregistering: %s\n", upper->path);
+
+ /* Unregister the efuse timer device */
+
+ unregister_driver(upper->path);
+
+ /* Then free all of the driver resources */
+
+ kmm_free(upper->path);
+ nxsem_destroy(&upper->exclsem);
+ kmm_free(upper);
+}
+
+#endif /* CONFIG_EFUSE */
diff --git a/include/nuttx/efuse/efuse.h b/include/nuttx/efuse/efuse.h
new file mode 100644
index 0000000..96b15e2
--- /dev/null
+++ b/include/nuttx/efuse/efuse.h
@@ -0,0 +1,174 @@
+/****************************************************************************
+ * include/nuttx/efuse/efuse.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_EFUSE_EFUSE_H
+#define __INCLUDE_NUTTX_EFUSE_EFUSE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/fs/ioctl.h>
+
+#include <signal.h>
+#include <stdint.h>
+
+#ifdef CONFIG_EFUSE
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Command: EFUSEIOC_READ_FIELD
+ * Description: Read a blob of bits from an efuse field.
+ * Arguments: A structure containing the field[], a dst pointer, and size
+ * of bits to be read from efuses.
+ * Return: Zero (OK) on success. Minus one will be returned on failure
+ * with the errno value set appropriately.
+ */
+
+#define EFUSEIOC_READ_FIELD _EFUSEIOC(0x0001)
+
+/* Command: EFUSEIOC_WRITE_FIELD
+ * Description: Write a blob of bits to an efuse's field
+ * Arguments: A structure containing the field[], the src memory and the
+ * amount of bits to write.
+ * Return: Zero (OK) on success. Minus one will be returned on failure
+ * with the errno value set appropriately.
+ */
+
+#define EFUSEIOC_WRITE_FIELD _EFUSEIOC(0x0002)
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* Structure eFuse field */
+
+struct efuse_desc_s
+{
+ uint16_t bit_offset; /* Bit offset related to beginning of efuse */
+ uint16_t bit_count; /* Length of bit field */
+};
+
+/* Type definition for an eFuse field */
+
+typedef struct efuse_desc_s efuse_desc_t;
+
+/* Structs with the parameters passed to the IOCTLs */
+
+/* The efuse_param is used by the application to inform which field(s)
+ * will be passed to the ioctl() operation.
+ * - 'efuse_desc_t *field[]': contains one or more field and it
+ * it termined by a NULL to indicate there is no more fields.
+ * NOTE: normally the application don't need to create these fields
+ * they are mapped inside an arch efuse table and referenced
+ * in a header file inside include/nuttx/efuse/ directory.
+ * - size: how many bits the field(s) use
+ * - data: an application side allocated buffer where the read operation
+ * will store the efuse bits, so the number of allocated bytes
+ * need to be enough to store all bits. For write operaton, this
+ * pointer contains the bits to be written.
+ *
+ * FINAL NOTE: The bit order is architecture dependent (tested only on
+ * little endian arch, because I don't have a big endian arch
+ * supported by NuttX. So, the first efuse bit starting at
+ * 'bit_offset' will be store at bit 0 of the data[0] and so
+ * on.
+ */
+
+struct efuse_param
+{
+ FAR const efuse_desc_t **field;
+ size_t size;
+ FAR uint8_t *data;
+};
+
+/* This structure provides the "lower-half" driver operations available to
+ * the "upper-half" driver.
+ */
+
+struct efuse_lowerhalf_s;
+struct efuse_ops_s
+{
+ /* Required methods *******************************************************/
+
+ /* Read an EFUSE bit */
+
+ CODE int (*read_field)(FAR struct efuse_lowerhalf_s *lower,
+ FAR const efuse_desc_t *field[],
+ FAR uint8_t *data, size_t bit_size);
+
+ /* Write an EFUSE bit */
+
+ CODE int (*write_field)(FAR struct efuse_lowerhalf_s *lower,
+ FAR const efuse_desc_t *field[],
+ FAR const uint8_t *data, size_t bit_size);
+
+ /* Any ioctl commands that are not recognized by the "upper-half" driver
+ * are forwarded to the lower half driver through this method.
+ */
+
+ CODE int (*ioctl)(FAR struct efuse_lowerhalf_s *lower, int cmd,
+ unsigned long arg);
+};
+
+/* This structure provides the publicly visible representation of the
+ * "lower-half" driver state structure. "lower half" drivers will have an
+ * internal structure definition that will be cast-compatible with this
+ * structure definitions.
+ */
+
+struct efuse_lowerhalf_s
+{
+ /* Publicly visible portion of the "lower-half" driver state structure. */
+
+ FAR const struct efuse_ops_s *ops; /* Lower half operations */
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+FAR void *efuse_register(FAR const char *path,
+ FAR struct efuse_lowerhalf_s *lower);
+
+void efuse_unregister(FAR void *handle);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CONFIG_EFUSE */
+#endif /* __INCLUDE_NUTTX_EFUSE_EFUSE_H */
diff --git a/include/nuttx/fs/ioctl.h b/include/nuttx/fs/ioctl.h
index 07481a5..12a3539 100644
--- a/include/nuttx/fs/ioctl.h
+++ b/include/nuttx/fs/ioctl.h
@@ -101,6 +101,7 @@
#define _NOTERAMBASE (0x2d00) /* Noteram device ioctl commands*/
#define _RCIOCBASE (0x2e00) /* Remote Control device ioctl commands */
#define _HIMEMBASE (0x2f00) /* Himem device ioctl commands*/
+#define _EFUSEBASE (0x3000) /* Efuse device ioctl commands*/
#define _WLIOCBASE (0x8b00) /* Wireless modules ioctl network commands */
/* boardctl() commands share the same number space */
@@ -551,6 +552,11 @@
#define _HIMEMIOCVALID(c) (_IOC_TYPE(c) == _HIMEMBASE)
#define _HIMEMIOC(nr) _IOC(_HIMEMBASE, nr)
+/* Efuse drivers ************************************************************/
+
+#define _EFUSEIOCVALID(c) (_IOC_TYPE(c) == _EFUSEBASE)
+#define _EFUSEIOC(nr) _IOC(_EFUSEBASE, nr)
+
/* Wireless driver network ioctl definitions ********************************/
/* (see nuttx/include/wireless/wireless.h */