diff --git a/drivers/Kconfig b/drivers/Kconfig index 57c8961b6b..3e2ad26a18 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 d58a78b8ff..ad8ea5e6b5 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 0000000000..da2b1ee312 --- /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 0000000000..9f99f73865 --- /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 0000000000..d200fc47c4 --- /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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#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 0000000000..96b15e283a --- /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 +#include + +#include +#include + +#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 07481a57e9..12a3539fc3 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 */