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 */