| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- /**************************************************************************//**
- *
- * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-10-5 Wayne First version
- *
- ******************************************************************************/
- #include <rtconfig.h>
- #if defined(BSP_USING_HWSEM)
- #include <rthw.h>
- #include "drv_hwsem.h"
- #include "drv_sys.h"
- #include "drv_common.h"
- #include "nu_bitutil.h"
- /* Private define ---------------------------------------------------------------*/
- enum
- {
- HWSEM_START = -1,
- #if defined(BSP_USING_HWSEM0)
- HWSEM0_IDX,
- #endif
- HWSEM_END
- };
- /* Private typedef --------------------------------------------------------------*/
- struct nu_mutex_priv
- {
- struct nu_mutex parent;
- rt_thread_t owner;
- uint8_t key;
- uint8_t hold;
- struct rt_completion completion;
- void *user_data;
- };
- typedef struct nu_mutex_priv *nu_mutex_priv_t;
- struct nu_hwsem
- {
- struct rt_device dev;
- char *name;
- HWSEM_T *base;
- IRQn_Type irqn;
- uint32_t rstidx;
- struct nu_mutex_priv mutex[evHWSEM_CNT];
- };
- typedef struct nu_hwsem *nu_hwsem_t;
- static struct nu_hwsem nu_hwsem_arr [] =
- {
- #if defined(BSP_USING_HWSEM0)
- {
- .name = "hwsem0",
- .base = HWSEM0,
- .irqn = HWSEM0_IRQn,
- .rstidx = HWSEM0_RST,
- },
- #endif
- }; /* nu_hwsem */
- /**
- * All HWSEM interrupt service routine
- */
- static void nu_hwsem_isr(int vector, void *param)
- {
- nu_hwsem_t psNuHwSem = (nu_hwsem_t)param;
- rt_int32_t irqidx;
- volatile uint32_t vu32Intsts = psNuHwSem->base->INTSTS_CORE;
- while ((irqidx = nu_ctz(vu32Intsts)) < evHWSEM_CNT)
- {
- nu_mutex_priv_t priv = (nu_mutex_priv_t)&psNuHwSem->mutex[irqidx];
- uint32_t u32IsrBitMask = 1 << irqidx ;
- HWSEM_CLR_INT_FLAG(psNuHwSem->base, irqidx);
- /* Unlocked, Signal waiter. */
- rt_completion_done(&priv->completion);
- /* Clear sent bit */
- vu32Intsts &= ~(u32IsrBitMask);
- }
- }
- nu_mutex_t nu_mutex_init(struct rt_device *device, E_HWSEM_ID id)
- {
- if (id < evHWSEM_CNT)
- {
- nu_hwsem_t psNuHwSem = (nu_hwsem_t)device->user_data;
- nu_mutex_t mutex = (nu_mutex_t)&psNuHwSem->mutex[id];
- nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
- if (!priv->owner)
- {
- priv->owner = rt_thread_self();
- }
- else
- {
- goto exit_nu_mutex_init;
- }
- return mutex;
- }
- exit_nu_mutex_init:
- return RT_NULL;
- }
- void nu_mutex_deinit(struct rt_device *device, E_HWSEM_ID id)
- {
- if (id < evHWSEM_CNT)
- {
- nu_hwsem_t psNuHwSem = (nu_hwsem_t)device->user_data;
- nu_mutex_t mutex = (nu_mutex_t)&psNuHwSem->mutex[id];
- nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
- if (priv->owner == rt_thread_self())
- {
- priv->owner = RT_NULL;
- }
- }
- }
- rt_err_t nu_mutex_take(nu_mutex_t mutex, rt_int32_t timeout)
- {
- rt_err_t ret = RT_EOK;
- nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
- nu_hwsem_t dev = (nu_hwsem_t)priv->user_data;
- uint8_t u8PrivKey = priv->key;
- #ifdef RT_USING_SMP
- u8PrivKey |= (rt_hw_cpu_id() << 6);
- #endif /* RT_USING_SMP */
- if (priv->owner != rt_thread_self())
- {
- return -RT_ERROR;
- }
- rt_completion_init(&priv->completion);
- while (1)
- {
- if (HWSEM_IS_LOCKED(dev->base, mutex->id) != HWSEM_NOLOCK)
- {
- /* LOCKED */
- if (HWSEM_GET_KEY(dev->base, mutex->id) != u8PrivKey)
- {
- /* Enable interrupt */
- HWSEM_ENABLE_INT(dev->base, mutex->id);
- /* owner is NOT me. */
- if (rt_completion_wait(&priv->completion, timeout) != RT_EOK)
- {
- ret = -RT_EBUSY;
- break;
- }
- else
- {
- /* Got notification, do lock. */
- }
- }
- else
- {
- /* owner is me. */
- priv->hold++;
- break;
- }
- }
- else
- {
- /* NOLOCK, To lock */
- HWSEM_LOCK(dev->base, mutex->id, u8PrivKey);
- if (HWSEM_GET_KEY(dev->base, mutex->id) == u8PrivKey)
- {
- /* owner is me. */
- priv->hold = 1;
- /* Disable interrupt */
- HWSEM_DISABLE_INT(dev->base, mutex->id);
- break;
- }
- else
- {
- /* Failed to lock, owner is not me. wait notification. */
- }
- }
- } //while(1)
- return ret;
- }
- RTM_EXPORT(nu_mutex_take);
- rt_err_t nu_mutex_release(nu_mutex_t mutex)
- {
- rt_err_t ret = RT_EOK;
- nu_mutex_priv_t priv = (nu_mutex_priv_t)mutex;
- nu_hwsem_t dev = (nu_hwsem_t)priv->user_data;
- uint8_t u8PrivKey = priv->key;
- if (priv->owner != rt_thread_self())
- {
- return -RT_ERROR;
- }
- #ifdef RT_USING_SMP
- u8PrivKey |= (rt_hw_cpu_id() << 6);
- #endif /* RT_USING_SMP */
- if (HWSEM_IS_LOCKED(dev->base, mutex->id) != 0 &&
- HWSEM_GET_KEY(dev->base, mutex->id) == u8PrivKey)
- {
- priv->hold--;
- if (priv->hold == 0)
- {
- /* Unlocked */
- HWSEM_UNLOCK(dev->base, mutex->id, u8PrivKey);
- }
- }
- else
- {
- ret = -RT_ERROR;
- }
- return ret;
- }
- RTM_EXPORT(nu_mutex_release);
- static rt_err_t hwsem_register(struct rt_device *device, const char *name, void *user_data)
- {
- RT_ASSERT(device);
- device->type = RT_Device_Class_Miscellaneous;
- device->rx_indicate = RT_NULL;
- device->tx_complete = RT_NULL;
- #ifdef RT_USING_DEVICE_OPS
- device->ops = RT_NULL;
- #else
- device->init = RT_NULL;
- device->open = RT_NULL;
- device->close = RT_NULL;
- device->read = RT_NULL;
- device->write = RT_NULL;
- device->control = RT_NULL;
- #endif
- device->user_data = user_data;
- return rt_device_register(device, name, RT_DEVICE_FLAG_RDONLY | RT_DEVICE_FLAG_STANDALONE);
- }
- /**
- * Hardware Sem Initialization
- */
- int rt_hw_hwsem_init(void)
- {
- int i, j;
- rt_err_t ret = RT_EOK;
- for (i = (HWSEM_START + 1); i < HWSEM_END; i++)
- {
- #if !defined(USE_MA35D1_SUBM)
- /* Reset this module */
- nu_sys_ip_reset(nu_hwsem_arr[i].rstidx);
- #endif
- for (j = 0; j < evHWSEM_CNT; j++)
- {
- nu_hwsem_arr[i].mutex[j].parent.id = (E_HWSEM_ID)j;
- nu_hwsem_arr[i].mutex[j].user_data = (void *)&nu_hwsem_arr[i];
- nu_hwsem_arr[i].mutex[j].key = (HWSEM_LOCK_BY_OWNER << 4) | j; // CoreID + SemID
- nu_hwsem_arr[i].mutex[j].hold = 0;
- nu_hwsem_arr[i].mutex[j].owner = RT_NULL;
- if (HWSEM_IS_LOCKED(nu_hwsem_arr[i].base, j) == HWSEM_LOCK_BY_OWNER)
- HWSEM_UNLOCK(nu_hwsem_arr[i].base, j, nu_hwsem_arr[i].mutex[j].key);
- /* Disable interrupt */
- HWSEM_DISABLE_INT(nu_hwsem_arr[i].base, j);
- }
- rt_hw_interrupt_install(nu_hwsem_arr[i].irqn, nu_hwsem_isr, &nu_hwsem_arr[i], nu_hwsem_arr[i].name);
- rt_hw_interrupt_umask(nu_hwsem_arr[i].irqn);
- ret = hwsem_register(&nu_hwsem_arr[i].dev, (const char *)nu_hwsem_arr[i].name, (void *)&nu_hwsem_arr[i]);
- RT_ASSERT(ret == RT_EOK);
- }
- return 0;
- }
- INIT_BOARD_EXPORT(rt_hw_hwsem_init);
- #endif //#if defined(BSP_USING_UART)
|