diff --git a/Kconfig b/Kconfig index e4adb6295d..abd0d4e512 100644 --- a/Kconfig +++ b/Kconfig @@ -2010,6 +2010,31 @@ config DEBUG_VIRTIO_INFO endif # DEBUG_VIDEO +config DEBUG_RESET + bool "RESET Debug Features" + default n + depends on RESET + ---help--- + Enable RESET debug features. + +if DEBUG_RESET + +config DEBUG_RESET_ERROR + bool "RESET Error Output" + default n + depends on DEBUG_ERROR + ---help--- + Enable RESET driver error output to SYSLOG. + +config DEBUG_RESET_INFO + bool "RESET Informational Output" + default n + depends on DEBUG_INFO + ---help--- + Enable RESET driver informational output to SYSLOG. + +endif # DEBUG_RESET + endif # DEBUG_FEATURES config ARCH_HAVE_STACKCHECK diff --git a/drivers/Kconfig b/drivers/Kconfig index 2a90acbb02..e0b75180f0 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -55,3 +55,4 @@ source "drivers/segger/Kconfig" source "drivers/usrsock/Kconfig" source "drivers/dma/Kconfig" source "drivers/devicetree/Kconfig" +source "drivers/reset/Kconfig" diff --git a/drivers/Makefile b/drivers/Makefile index 0bb262423f..18add19beb 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -73,6 +73,7 @@ include rf/Make.defs include rc/Make.defs include segger/Make.defs include usrsock/Make.defs +include reset/Make.defs ifeq ($(CONFIG_SPECIFIC_DRIVERS),y) -include platform/Make.defs diff --git a/drivers/reset/CMakeLists.txt b/drivers/reset/CMakeLists.txt new file mode 100644 index 0000000000..ced6a54616 --- /dev/null +++ b/drivers/reset/CMakeLists.txt @@ -0,0 +1,25 @@ +# ############################################################################## +# drivers/reset/CMakeLists.txt +# +# 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. +# +# ############################################################################## + +if(CONFIG_RESET) + set(SRCS core.c) + + target_sources(drivers PRIVATE ${SRCS}) +endif() diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig new file mode 100644 index 0000000000..01e1617614 --- /dev/null +++ b/drivers/reset/Kconfig @@ -0,0 +1,10 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +menuconfig RESET + bool "reset driver Support" + default n + ---help--- + This selection enables building of the "upper-half" reset driver. diff --git a/drivers/reset/Make.defs b/drivers/reset/Make.defs new file mode 100644 index 0000000000..7aeea7704a --- /dev/null +++ b/drivers/reset/Make.defs @@ -0,0 +1,31 @@ +############################################################################ +# drivers/reset/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 reset driver build surrport + +ifeq ($(CONFIG_RESET),y) + +CSRCS += core.c + +DEPPATH += --dep-path reset +VPATH += :reset +CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)drivers$(DELIM)reset + +endif # CONFIG_RESET diff --git a/drivers/reset/core.c b/drivers/reset/core.c new file mode 100644 index 0000000000..12550882b2 --- /dev/null +++ b/drivers/reset/core.c @@ -0,0 +1,989 @@ +/**************************************************************************** + * drivers/reset/core.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 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static struct list_node +g_reset_controller_list = LIST_INITIAL_VALUE(g_reset_controller_list); +static mutex_t g_reset_list_mutex = NXMUTEX_INITIALIZER; + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* struct reset_control_array - an array of reset controls + * @base: reset control for compatibility with reset control API functions + * @num_rstcs: number of reset controls + * @rstc: array of reset controls + */ + +struct reset_control_array +{ + struct reset_control base; + unsigned int num_rstcs; + FAR struct reset_control *rstc[]; +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static inline FAR struct reset_control_array * +rstc_to_array(FAR struct reset_control *rstc) +{ + return container_of(rstc, struct reset_control_array, base); +} + +/**************************************************************************** + * Name: reset_control_array_reset + * + * Description: + * This function is used to perform reset operation of a reset control + * array. + * + * Input Parameters: + * resets - An instance of a reset_control_array. + * + * Returned Value: + * A 0 in case of success, otherwise error. + ****************************************************************************/ + +static int reset_control_array_reset(FAR struct reset_control_array *resets) +{ + int ret = 0; + unsigned int i; + + for (i = 0; i < resets->num_rstcs; i++) + { + ret = reset_control_reset(resets->rstc[i]); + if (ret < 0) + { + return ret; + } + } + + return ret; +} + +/**************************************************************************** + * Name: reset_control_array_assert + * + * Description: + * This function is used to perform assert operation of a reset control + * array. + * + * Input Parameters: + * resets - An instance of a reset_control_array. + * + * Returned Value: + * A 0 in case of success, otherwise error. + ****************************************************************************/ + +static int reset_control_array_assert(FAR struct reset_control_array *resets) +{ + int ret = 0; + unsigned int i; + + for (i = 0; i < resets->num_rstcs; i++) + { + ret = reset_control_assert(resets->rstc[i]); + if (ret < 0) + { + while (i--) + { + reset_control_deassert(resets->rstc[i]); + } + + break; + } + } + + return ret; +} + +/**************************************************************************** + * Name: reset_control_array_deassert + * + * Description: + * This function is used to perform deassert operation of a reset control + * array. + * + * Input Parameters: + * resets - An instance of a reset_control_array. + * + * Returned Value: + * A 0 in case of success, an negative error code otherwise. + ****************************************************************************/ + +static int +reset_control_array_deassert(FAR struct reset_control_array *resets) +{ + int ret = 0; + unsigned int i; + + for (i = 0; i < resets->num_rstcs; i++) + { + ret = reset_control_deassert(resets->rstc[i]); + if (ret < 0) + { + while (i--) + { + reset_control_assert(resets->rstc[i]); + } + + break; + } + } + + return ret; +} + +/**************************************************************************** + * Name: reset_control_array_acquire + * + * Description: + * This function is used to perform acquire operation of a reset control + * array. + * + * Input Parameters: + * resets - An instance of a reset_control_array. + * + * Returned Value: + * A 0 in case of success, an negative error code otherwise. + ****************************************************************************/ + +static int +reset_control_array_acquire(FAR struct reset_control_array *resets) +{ + unsigned int i; + unsigned int ret = 0; + + for (i = 0; i < resets->num_rstcs; i++) + { + ret = reset_control_acquire(resets->rstc[i]); + if (ret < 0) + { + while (i--) + { + reset_control_release(resets->rstc[i]); + } + + break; + } + } + + return ret; +} + +/**************************************************************************** + * Name: reset_control_array_release + * + * Description: + * This function is used to perform release operation of a reset control + * array. + * + * Input Parameters: + * resets - An instance of a reset_control_array. + ****************************************************************************/ + +static void +reset_control_array_release(FAR struct reset_control_array *resets) +{ + unsigned int i; + + for (i = 0; i < resets->num_rstcs; i++) + { + reset_control_release(resets->rstc[i]); + } +} + +/**************************************************************************** + * Name: reset_control_get_internal + * + * Description: + * This function is used to return a reset_control by rcdev,index,shared, + * acquired parameters. + * + * Input Parameters: + * rcdev - An instance of reset_controller_dev type. + * index - ID of the reset controller in the reset controller device. + * shared - Is this a shared (1), or an exclusive (0) reset_control. + * acquired - Only one reset_control may be acquired for a given rcdev and + * index. + * + * Returned Value: + * Return reset_control if success, others NULL. + ****************************************************************************/ + +static FAR struct reset_control * +reset_control_get_internal(FAR struct reset_controller_dev *rcdev, + unsigned int index, bool shared, bool acquired) +{ + FAR struct reset_control *rstc; + + DEBUGASSERT(nxmutex_is_locked(&g_reset_list_mutex)); + + list_for_every_entry(&rcdev->reset_control_head, rstc, + struct reset_control, list) + { + if (rstc->id == index) + { + /* Allow creating a secondary exclusive reset_control + * that is initially not acquired for an already + * controlled reset line. + */ + + if (!rstc->shared && !shared && !acquired) + { + break; + } + + /* shared reset controller */ + + if (!rstc->shared || !shared) + { + rsterr("not shared reset control\n"); + return NULL; + } + + atomic_fetch_add(&rstc->refcnt, 1); + return rstc; + } + } + + rstc = kmm_zalloc(sizeof(*rstc)); + if (!rstc) + { + return NULL; + } + + rstc->rcdev = rcdev; + list_add_after(&rcdev->reset_control_head, &rstc->list); + rstc->id = index; + atomic_init(&rstc->refcnt, 1); + rstc->acquired = acquired; + rstc->shared = shared; + + return rstc; +} + +/**************************************************************************** + * Name: reset_control_put_internal + * + * Description: + * This is used to free a reset_control getted by reset_control_get. + * + * Input Parameters: + * rstc - An reset control + * + ****************************************************************************/ + +static void reset_control_put_internal(FAR struct reset_control *rstc) +{ + DEBUGASSERT(nxmutex_is_locked(&g_reset_list_mutex)); + + if (atomic_fetch_sub(&rstc->refcnt, 1) == 1) + { + DEBUGASSERT(nxmutex_is_locked(&g_reset_list_mutex)); + list_delete(&rstc->list); + kmm_free(rstc); + } +} + +/**************************************************************************** + * Name: reset_control_array_put + * + * Description: + * This function is used to perform a free operation of reset + * control array. + * + * Input Parameters: + * resets - An instance of reset_control_array. + * + ****************************************************************************/ + +static void reset_control_array_put(FAR struct reset_control_array *resets) +{ + unsigned int i; + + nxmutex_lock(&g_reset_list_mutex); + for (i = 0; i < resets->num_rstcs; i++) + { + reset_control_put_internal(resets->rstc[i]); + } + + nxmutex_unlock(&g_reset_list_mutex); + kmm_free(resets); +} + +/**************************************************************************** + * Name: reset_controller_get_by_name + * + * Description: + * This function is used to get a reset_controller_dev instance register + * by name. + * + * Input Parameters: + * name - An name of reset_controller_dev var register. + * + * Returned Value: + * Return reset_controller_dev if success, others failed. + ****************************************************************************/ + +static FAR struct reset_controller_dev * +reset_controller_get_by_name(FAR const char *name) +{ + FAR struct reset_controller_dev *rcdev; + + list_for_every_entry(&g_reset_controller_list, rcdev, + struct reset_controller_dev, list) + { + if (!strcmp(name, rcdev->name)) + { + return rcdev; + } + } + + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: reset_control_get + * + * Description: + * This function is used to get a reset control by reset controller name. + * + * Firstly, get a reset controller device from list, and then call + * reset_control_get_internal function by index, shared or acquired + * parameters retrun a reset control. + * + * Input Parameters: + * name - The reset controller name + * index - The reset controller in reset controller device + * shared - Is this a shared (1), or an exclusive (0) reset_control + * acquired - Flags that used to get a exculsive reset control + * + * Returned Value: + * Return reset_control if success, others return NULL if failed + ****************************************************************************/ + +FAR struct reset_control * +reset_control_get(FAR const char *name, int index, bool shared, + bool acquired) +{ + FAR struct reset_control *rstc; + FAR struct reset_controller_dev *rcdev; + + if (name == NULL) + { + return NULL; + } + + /* ID of the reset controller in the reset controller device */ + + if (index < 0) + { + rsterr("ID of the reset controller is invalid\n"); + return NULL; + } + + if (shared && acquired) + { + rsterr("shared && acquired exist meanwhile\n"); + return NULL; + } + + rcdev = reset_controller_get_by_name(name); + if (!rcdev) + { + return NULL; + } + + nxmutex_lock(&g_reset_list_mutex); + + /* g_reset_list_mutex also protects the rcdev's reset_control list */ + + rstc = reset_control_get_internal(rcdev, index, shared, acquired); + nxmutex_unlock(&g_reset_list_mutex); + + return rstc; +} + +/**************************************************************************** + * Name: reset_control_reset + * + * Description: + * On a shared reset line the actual reset pulse is only triggered once for + * the lifetime of the reset_control instance: for all but the first caller + * this is a no-op. + * Consumers must not use reset_control_(de)assert on shared reset lines + * when reset_control_reset has been used. + * + * Input Parameters: + * rstc - Reset controller + * + * Returned Value: + * Returns a negative errno if not supported, a positive value if the + * reset line is asserted. + ****************************************************************************/ + +int reset_control_reset(FAR struct reset_control *rstc) +{ + int ret; + + rstinfo("Enter: reset_control_reset\n"); + + if (rstc == NULL) + { + rsterr("rstc is null\n"); + return -EINVAL; + } + + if (rstc->array) + { + return reset_control_array_reset(rstc_to_array(rstc)); + } + + if (!rstc->rcdev->ops->reset) + { + rsterr("rstc callback is null\n"); + return -ENOTSUP; + } + + if (rstc->shared) + { + if (atomic_load(&rstc->deassert_count) != 0) + { + return -EINVAL; + } + + if (atomic_fetch_add(&rstc->triggered_count, 1) != 0) + { + return 0; + } + } + else + { + if (!rstc->acquired) + { + return -EPERM; + } + } + + ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); + + /* shared:1 and reset failed, triggered_count subtract 1 */ + + if (rstc->shared && ret < 0) + { + atomic_fetch_sub(&rstc->triggered_count, 1); + } + + return ret; +} + +/**************************************************************************** + * Name: reset_control_assert + * + * Description: + * Asserts the reset line. + * + * Calling this on an exclusive reset controller guarantees that the reset + * will be asserted. When called on a shared reset controller the line may + * still be deasserted, as long as other users keep it so. + * + * For shared reset controls a driver cannot expect the hw's registers and + * internal state to be reset, but must be prepared for this to happen. + * Consumers must not use reset_control_reset on shared reset lines when + * reset_control_(de)assert has been used. + * return -EBUSY. + * + * Input Parameters: + * rstc - Reset controller + * + * Returned Value: + * Returns a negative errno if not supported, a positive value if the + * reset line is asserted. + ****************************************************************************/ + +int reset_control_assert(FAR struct reset_control *rstc) +{ + rstinfo("Enter: reset_control_assert\n"); + if (rstc == NULL) + { + rsterr("rstc is null\n"); + return -EINVAL; + } + + if (rstc->array) + { + return reset_control_array_assert(rstc_to_array(rstc)); + } + + if (rstc->shared) + { + if (atomic_load(&rstc->triggered_count) != 0) + { + return -EINVAL; + } + + if (atomic_load(&rstc->deassert_count) == 0) + { + rsterr("deassert_count = 0, invalid value\n"); + return -EINVAL; + } + + if (atomic_fetch_sub(&rstc->deassert_count, 1) != 1) + { + return 0; + } + + /* Shared reset controls allow the reset line to be in any state + * after this call, so doing nothing is a valid option. + */ + + if (!rstc->rcdev->ops->assert) + { + return -EBUSY; + } + } + else + { + /* If the reset controller does not implement .assert(), there + * is no way to guarantee that the reset line is asserted after + * this call. + */ + + if (!rstc->rcdev->ops->assert) + { + return -ENOTSUP; + } + + if (!rstc->acquired) + { + rsterr("reset %s (ID: %u) is not acquired\n", + rstc->rcdev->name, rstc->id); + return -EPERM; + } + } + +#undef assert + return rstc->rcdev->ops->assert(rstc->rcdev, rstc->id); +} + +/**************************************************************************** + * Name: reset_control_deassert + * + * Description: + * Deasserts the reset line. + * After calling this function, the reset is guaranteed to be deasserted. + * Consumers must not use reset_control_reset on shared reset lines when + * reset_control_(de)assert has been used. + * return -EBUSY. + * + * Input Parameters: + * rstc - Reset controller + * + * Returned Value: + * Returns a negative errno if not supported, a positive value if the + * reset line is asserted. + * + ****************************************************************************/ + +int reset_control_deassert(FAR struct reset_control *rstc) +{ + rstinfo("Enter: reset_control_deassert\n"); + if (!rstc) + { + rsterr("rstc is null\n"); + return -EINVAL; + } + + if (rstc->array) + { + return reset_control_array_deassert(rstc_to_array(rstc)); + } + + if (rstc->shared) + { + if (atomic_load(&rstc->triggered_count) != 0) + { + rsterr("triggered_count != 0, invalid value\n"); + return -EINVAL; + } + + if (atomic_fetch_add(&rstc->deassert_count, 1) != 0) + { + return 0; + } + } + else + { + if (!rstc->acquired) + { + rsterr("reset %s (ID: %u) is not acquired\n", + rstc->rcdev->name, rstc->id); + return -EPERM; + } + } + + /* If the reset controller does not implement .deassert(), we assume + * that it handles self-deasserting reset lines via .reset(). In that + * case, the reset lines are deasserted by default. If that is not the + * case, the reset controller driver should implement .deassert() and + * return -ENOTSUPP. + */ + + if (!rstc->rcdev->ops->deassert) + { + return -ESRCH ; + } + + return rstc->rcdev->ops->deassert(rstc->rcdev, rstc->id); +} + +/**************************************************************************** + * Name: reset_control_status + * + * Description: + * Get the reset line status. + * + * Input Parameters: + * rstc - Reset controller + * + * Returned Value: + * Returns a negative errno if not supported, a positive value if the + * reset line is asserted. + ****************************************************************************/ + +int reset_control_status(FAR struct reset_control *rstc) +{ + if (rstc == NULL) + { + return -EINVAL; + } + + if (rstc->array) + { + return -EINVAL; + } + + if (rstc->rcdev->ops->status) + { + return rstc->rcdev->ops->status(rstc->rcdev, rstc->id); + } + + return -ENOTSUP; +} + +/**************************************************************************** + * Name: reset_control_acquire() + * + * Description: + * Acquires a reset control for exclusive use. + * This is used to explicitly acquire a reset control for exclusive use. + * Note that exclusive resets are requested as acquired by default. + * In order for a second consumer to be able to control the reset, the + * first consumer has to release it first. + * Typically the easiest way to achieve this is to call the + * reset_control_get_exclusive_released() to obtain an instance of the + * reset control. Such reset controls are not acquired by default. + * + * Consumers implementing shared access to an exclusive reset need to + * follow a specific protocol in order to work together. Before consumers + * can change a reset they must acquire exclusive access using + * reset_control_acquire(). + * After they are done operating the reset, they must release exclusive + * access with a call to reset_control_release(). Consumers are not + * granted exclusive access to the reset as long as another consumer + * hasn't released a reset. + * See also: reset_control_release() + * + * Input Parameters: + * rstc - Reset control + * + * Returned Value: + * Returns a negative errno if not supported, a positive value if the + * reset line is asserted. + ****************************************************************************/ + +int reset_control_acquire(FAR struct reset_control *rstc) +{ + FAR struct reset_control *rc; + + if (rstc == NULL) + { + return 0; + } + + if (rstc->array) + { + return reset_control_array_acquire(rstc_to_array(rstc)); + } + + nxmutex_lock(&g_reset_list_mutex); + + if (rstc->acquired) + { + nxmutex_unlock(&g_reset_list_mutex); + return 0; + } + + list_for_every_entry(&rstc->rcdev->reset_control_head, rc, + struct reset_control, list) + { + if (rstc != rc && rstc->id == rc->id) + { + if (rc->acquired) + { + nxmutex_unlock(&g_reset_list_mutex); + return -EBUSY; + } + } + } + + rstc->acquired = true; + + nxmutex_unlock(&g_reset_list_mutex); + return 0; +} + +/**************************************************************************** + * Name: reset_control_release() + * + * Discription: + * Releases exclusive access to a reset control. + * + * Releases exclusive access right to a reset control previously obtained + * by a call to reset_control_acquire(). Until a consumer calls this + * function, no other consumers will be granted exclusive access. + * + * See also: reset_control_acquire() + * + * Input Parameters: + * rstc - Reset control + ****************************************************************************/ + +void reset_control_release(FAR struct reset_control *rstc) +{ + if (rstc == NULL) + { + return; + } + + if (rstc->array) + { + reset_control_array_release(rstc_to_array(rstc)); + } + else + { + rstc->acquired = false; + } +} + +/**************************************************************************** + * Name: reset_control_put + * + * Description: + * Free the reset control. + * + * Input Parameters: + * rstc - Reset controller + ****************************************************************************/ + +void reset_control_put(FAR struct reset_control *rstc) +{ + if (!rstc) + { + return; + } + + if (rstc->array) + { + reset_control_array_put(rstc_to_array(rstc)); + return; + } + + nxmutex_lock(&g_reset_list_mutex); + reset_control_put_internal(rstc); + nxmutex_unlock(&g_reset_list_mutex); +} + +/**************************************************************************** + * Name: reset_control_array_get + * + * Description: + * Get a list of reset controls using device node. + * + * Input Parameters: + * name - The reset controller name + * shared - Whether reset controls are shared or not + * acquired - Only one reset control may be acquired for a given controller + * and ID + * + * Returned Value: + * Returns pointer to allocated reset_control on success or error on + * failure + ****************************************************************************/ + +FAR struct reset_control * +reset_control_array_get(FAR const char *name, const int id[], + const unsigned int num, bool shared, bool acquired) +{ + FAR struct reset_control_array *resets; + FAR struct reset_control *rstc; + unsigned int i; + + resets = kmm_zalloc(sizeof(struct reset_control_array) + + sizeof(struct reset_control) * num); + if (!resets) + { + return NULL; + } + + for (i = 0; i < num; i++) + { + rstc = reset_control_get(name, id[i], shared, acquired); + if (rstc == NULL) + { + goto err_rst; + } + + resets->rstc[i] = rstc; + } + + resets->num_rstcs = num; + resets->base.array = true; + + return &resets->base; + +err_rst: + nxmutex_lock(&g_reset_list_mutex); + while (i--) + { + reset_control_put_internal(resets->rstc[i]); + } + + nxmutex_unlock(&g_reset_list_mutex); + kmm_free(resets); + + return rstc; +} + +/**************************************************************************** + * Name: reset_control_device_reset + * + * Description: + * Find reset controller associated with the device and perform reset, + * finally free the reset control. + * Convenience wrapper for reset_control_get() and reset_control_reset(). + * This is useful for the common case of devices with single, dedicated + * reset lines. + * + * Input Parameters: + * name - The controller name + * + * Returned Value: + * Returns a negative errno if failed, otherwise success. + ****************************************************************************/ + +int reset_control_device_reset(FAR const char *name) +{ + FAR struct reset_control *rstc; + int ret; + + rstc = reset_control_get(name, 0, false, true); + if (!rstc) + { + rsterr("get rstc failed.\n"); + return -EINVAL; + } + + ret = reset_control_reset(rstc); + reset_control_put(rstc); + + return ret; +} + +/**************************************************************************** + * Nmae: reset_controller_register + * + * Description: + * Register a reset controller device + * + * Input Parameters: + * rcdev - A pointer to the initialized reset controller device + * + * Returned Value: + * Returns 0 if success, otherwise failed. + ****************************************************************************/ + +int reset_controller_register(FAR struct reset_controller_dev *rcdev) +{ + if (rcdev == NULL || rcdev->name == NULL || rcdev->ops == NULL) + { + rsterr("rcdev is null\n"); + return -EINVAL; + } + + list_initialize(&rcdev->reset_control_head); + + nxmutex_lock(&g_reset_list_mutex); + list_add_after(&g_reset_controller_list, &rcdev->list); + nxmutex_unlock(&g_reset_list_mutex); + + return 0; +} + +/**************************************************************************** + * Name: reset_controller_unregister + * + * Description: + * Unregister a reset controller device + * + * Input Parameters: + * rcdev - A pointer to the reset controller device + ****************************************************************************/ + +void reset_controller_unregister(FAR struct reset_controller_dev *rcdev) +{ + nxmutex_lock(&g_reset_list_mutex); + list_delete(&rcdev->list); + nxmutex_unlock(&g_reset_list_mutex); +} + diff --git a/include/debug.h b/include/debug.h index d1411af6cb..170d8b00c7 100644 --- a/include/debug.h +++ b/include/debug.h @@ -827,6 +827,24 @@ # define vrtinfo _none #endif +#ifdef CONFIG_DEBUG_RESET_ERROR +# define rsterr _err +#else +# define rsterr _none +#endif + +#ifdef CONFIG_DEBUG_RESET_WARN +# define rstwarn _warn +#else +# define rstwarn _none +#endif + +#ifdef CONFIG_DEBUG_RESET_INFO +# define rstinfo _info +#else +# define rstinfo _none +#endif + /* Buffer dumping macros do not depend on varargs */ #ifdef CONFIG_DEBUG_ERROR @@ -1099,6 +1117,14 @@ # define mtrinfodumpbuffer(m,b,n) #endif +#ifdef CONFIG_DEBUG_RESET +# define reseterrdumpbuffer(m,b,n) errdumpbuffer(m,b,n) +# define resetinfodumpbuffer(m,b,n) infodumpbuffer(m,b,n) +#else +# define reseterrdumpbuffer(m,b,n) +# define resetinfodumpbuffer(m,b,n) +#endif + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ diff --git a/include/nuttx/reset/reset-controller.h b/include/nuttx/reset/reset-controller.h new file mode 100644 index 0000000000..604e975753 --- /dev/null +++ b/include/nuttx/reset/reset-controller.h @@ -0,0 +1,106 @@ +/**************************************************************************** + * include/nuttx/reset/reset-controller.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_RESET_CONTROLLER_H +#define __INCLUDE_NUTTX_RESET_CONTROLLER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct reset_controller_dev; + +/* struct reset_control_ops - reset controller driver operations + * reset: for self-deasserting resets, does all necessary + * things to reset the device + * assert: manually assert the reset line, if supported + * deassert: manually deassert the reset line, if supported + * status: return the status of the reset line, if supported + */ + +struct reset_control_ops +{ + CODE int (*reset)(FAR struct reset_controller_dev *rcdev, unsigned int id); + CODE int (*assert)(FAR struct reset_controller_dev *rcdev, + unsigned int id); + CODE int (*deassert)(FAR struct reset_controller_dev *rcdev, + unsigned int id); + CODE int (*status)(FAR struct reset_controller_dev *rcdev, + unsigned long id); +}; + +/* struct reset_controller_dev - reset controller entity that might + * provide multiple reset controls + * name a reset controller device name + * ops: a pointer to device specific struct reset_control_ops + * list: internal list of reset controller devices + * reset_control_head: head of internal list of requested reset controls + */ + +struct reset_controller_dev +{ + FAR const char *name; + FAR const struct reset_control_ops *ops; + struct list_node list; + struct list_node reset_control_head; +}; + +/**************************************************************************** + * Public Functions Definitions + ****************************************************************************/ + +/**************************************************************************** + * Name: reset_controller_register() + * + * Description: + * this function is used to register a reset_controller_dev to list. + * + * Input Parameters: + * rcdev - a instance of reset_controller_dev. + * + * Return value: + * return 0 if success, others failed. + ****************************************************************************/ + +int reset_controller_register(FAR struct reset_controller_dev *rcdev); + +/**************************************************************************** + * Name: reset_controller_unregister() + * + * Description: + * this function is used to unregister a reset_controller_dev to list. + * + * Input Parameters: + * rcdev - a instance of reset_controller_dev. + * + * Return value: + * return 0 if success, others failed. + ****************************************************************************/ + +void reset_controller_unregister(FAR struct reset_controller_dev *rcdev); + +#endif /* __INCLUDE_NUTTX_RESET_CONTROLLER_H */ diff --git a/include/nuttx/reset/reset.h b/include/nuttx/reset/reset.h new file mode 100644 index 0000000000..c1a1629643 --- /dev/null +++ b/include/nuttx/reset/reset.h @@ -0,0 +1,359 @@ +/**************************************************************************** + * include/nuttx/reset/reset.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_RESET_H +#define __INCLUDE_NUTTX_RESET_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include + +#include + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +struct reset_controller_dev; + +/* struct reset_control - a reset control + * @rcdev: A pointer to the reset controller device + * this reset control belongs to + * @list: List entry for the rcdev's reset controller list + * @id: ID of the reset controller in the reset + * controller device + * @refcnt: Number of gets of this reset_control + * @acquired: Only one reset_control may be acquired for a given rcdev and + * id. + * @shared: Is this a shared (1), or an exclusive (0) reset_control? + * @deassert_cnt: Number of times this reset line has been deasserted + * @triggered_count: Number of times this reset line has been reset. + * Currently only used for shared resets, which means that the value will + * be either 0 or 1. + */ + +struct reset_control +{ + FAR struct reset_controller_dev *rcdev; + struct list_node list; + unsigned int id; + atomic_int refcnt; + bool acquired; + bool shared; + bool array; + atomic_int deassert_count; + atomic_int triggered_count; +}; + +/**************************************************************************** + * Public Functions Definitions + ****************************************************************************/ + +struct reset_control; + +/**************************************************************************** + * Name: reset_control_reset() + * + * Description: + * this function is used to execute reset ops. + * + * Input Parameters: + * rstc - a instance of reset control. + * + ****************************************************************************/ + +int reset_control_reset(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_assert() + * + * Description: + * This function is used to execute assert ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + ****************************************************************************/ + +int reset_control_assert(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_deassert() + * + * Description: + * This function is used to execute deassert ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + ****************************************************************************/ + +int reset_control_deassert(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_status() + * + * Description: + * This function is used to get reset_control ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + * Returned Value: + * Return a reset_control if success, NULL others. + * + ****************************************************************************/ + +int reset_control_status(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_get + * + * Description: + * This function is used to get a reset control by reset controller name. + * + * Firstly, get a reset controller device from list, and then call + * reset_control_get_internal function by index, shared or acquired + * parameters retrun a reset control. + * + * Input Parameters: + * name - The reset controller name + * index - The reset controller in reset controller device + * shared - Is this a shared (1), or an exclusive (0) reset_control + * acquired - flags that used to get a exculsive reset control + * + * Returned Value: + * Return reset_control if success, others return NULL if failed + ****************************************************************************/ + +FAR struct reset_control * +reset_control_get(FAR const char *name, int index, bool shared, + bool acquired); + +/**************************************************************************** + * Name: reset_control_acquire() + * + * Description: + * This function is used to acquire reset_control access ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + ****************************************************************************/ + +int reset_control_acquire(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_release() + * + * Description: + * This function is used to release reset_control access ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + ****************************************************************************/ + +void reset_control_release(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_put() + * + * Description: + * This function is used to free reset_control ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + ****************************************************************************/ + +void reset_control_put(FAR struct reset_control *rstc); + +/**************************************************************************** + * Name: reset_control_device_reset() + * + * Description: + * This function is used to get and free reset_control ops. + * + * Input Parameters: + * rstc - An instance of reset control. + * + ****************************************************************************/ + +int reset_control_device_reset(FAR const char *name); + +/**************************************************************************** + * Name: reset_control_array_get + * + * Description: + * Get a list of reset controls using device node. + * + * Input Parameters: + * name - The reset controller name + * shared - Whether reset controls are shared or not + * acquired - Only one reset control may be acquired for a given controller + * and ID + * + * Returned Value: + * Returns pointer to allocated reset_control on success or error on + * failure + ****************************************************************************/ + +FAR struct reset_control * +reset_control_array_get(FAR const char *name, const int id[], + const unsigned int num, bool shared, bool acquired); + +/**************************************************************************** + * Name: reset_control_get_exclusive() + * + * Description: + * Lookup and obtain an exclusive reference to a reset controller. + * If this function is called more than once for the same reset_control + * it will return NULL. + * + * Input Parameters: + * name - Reset line name. + * + * Returned Value: + * Return a reset_control if success, NULL others. + * + ****************************************************************************/ + +static FAR inline struct reset_control * +reset_control_get_exclusive(FAR const char *name) +{ + return reset_control_get(name, 0, false, true); +} + +/**************************************************************************** + * Name: reset_control_get_exclusive_released() + * + * Description: + * Lookup and obtain a temoprarily exclusive reference to a reset + * controller. + * Reset-controls returned by this function must be acquired via + * reset_control_acquire() before they can be used and should be released + * via reset_control_release() afterwards + * + * Input Parameters: + * name - Reset line name. + * + * Returned Value: + * Return a reset_control if success, NULL others. + * + ****************************************************************************/ + +static inline FAR struct reset_control * +reset_control_get_exclusive_released(FAR const char *name) +{ + return reset_control_get(name, 0, false, false); +} + +/**************************************************************************** + * Name: reset_control_get_shared() + * + * Description: + * Lookup and obtain a shared reference to a reset controller. + * + * This function is intended for use with reset-controls which are shared + * between hardware blocks. + * + * When a reset-control is shared, the behavior of reset_control_assert + * deassert is changed, the reset-core will keep track of a deassert_count + * and only (re-)assert the reset after reset_control_assert has been + * called as many times as reset_control_deassert was called. Also see the + * remark about shared reset-controls in the reset_control_assert docs. + * + * Input Parameters: + * name - Reset line name. + * + * Returned Value: + * Return a reset_control if success, NULL others. + * + ****************************************************************************/ + +static inline FAR struct reset_control * +reset_control_get_shared(FAR const char *name) +{ + return reset_control_get(name, 0, true, false); +} + +/**************************************************************************** + * Name: reset_control_get_exclusive_by_index + * + * Description: + * Lookup and obtain an exclusive reference to a reset controller by index. + * + * This is to be used to perform a list of resets for a device or power + * domain in whatever order. Returns a struct reset_control or NULL errno. + * Input Parameters: + * name - The controller name symble + * index - Index of the reset controller + * + * Returned Value: + * Return a reset_control if success, others failed. + ****************************************************************************/ + +static inline FAR struct reset_control * +reset_control_get_exclusive_by_index(FAR const char *name, int index) +{ + return reset_control_get(name, index, false, true); +} + +/**************************************************************************** + * Name: reset_control_get_shared_by_index + * + * Description: + * Lookup and obtain a shared reference to a reset controller by index. + * + * When a reset-control is shared, the behavior of reset_control_assert + * deassert is changed, the reset-core will keep track of a deassert_count + * and only (re-)assert the reset after reset_control_assert has been + * called as many times as reset_control_deassert was called. Also see the + * remark about shared reset-controls in the reset_control_assert docs. + * + * Calling reset_control_assert without first calling + * reset_control_deassert is not allowed on a shared reset control. Calling + * reset_control_reset is also not allowed on a shared reset control. + * Returns a struct reset_control or NULL errno. + * + * This is to be used to perform a list of resets for a device or power + * domain in whatever order. Returns a struct reset_control or NULL errno. + * + * Input Parameters: + * node - Device to be reset by the controller + * index - Index of the reset controller + * + * Returned Value: + * Return a reset_control if success, others failed. + * + ****************************************************************************/ + +static inline FAR struct reset_control * +reset_control_get_shared_by_index(FAR const char *name, int index) +{ + return reset_control_get(name, index, true, false); +} + +#endif /* __INCLUDE_NUTTX_RESET_H */