Sfoglia il codice sorgente

[bsp][k230]:add gnne driver
Requirement: The BSP for the k230 platform in the RT-Thread repository does not yet have a gnne driver.
Solution: Provide gnne driver for the k230 platform in the RT-Thread repository.
- Implements mutex lock mechanism for AI2D and GNNE modules.
- Adds HARDLOCK_AI2D support in hardlock driver for mutual exclusion.
- Implements poll operation for device status monitoring.
- Updates documentation in bsp/README.md.
Signed-off-by: ChuanN-sudo <fjchuanil@gmail.com>

Chuan 1 mese fa
parent
commit
239f371fcb

+ 3 - 3
bsp/README.md

@@ -761,9 +761,9 @@ This document is based on the RT-Thread mainline repository and categorizes the
 
 #### 🟢 K230 (RT-Smart)
 
-| BSP Name | GPIO | UART | I2C | RTC | ADC | PWM | SDIO | HWTimer | WDT | SPI |
-|----------|------|------|-----|-----|-----|-----|------|---------|-----|-----|
-| [k230](k230) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
+| BSP Name | GPIO | UART | I2C | RTC | ADC | PWM | SDIO | HWTimer | WDT | SPI | GNNE |
+|----------|------|------|-----|-----|-----|-----|------|---------|-----|-----|------|
+| [k230](k230) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
 
 #### 🟢 Xuantie (RT-Smart)
 

+ 4 - 0
bsp/k230/.ci/attachconfig/ci.attachconfig.yml

@@ -1,6 +1,10 @@
 scons.args: &scons
     scons_arg:
       - '--strict'
+devices.gnee:
+    <<: *scons
+    kconfig:
+      - CONFIG_BSP_USING_GNNE=y
 devices.spi:
     <<: *scons
     kconfig:

+ 1 - 0
bsp/k230/.config

@@ -1617,6 +1617,7 @@ CONFIG_PKG_ZLIB_VER="latest"
 #
 # Drivers Configuration
 #
+# CONFIG_BSP_USING_GNNE is not set
 # CONFIG_BSP_USING_SPI is not set
 # CONFIG_BSP_USING_I2C is not set
 # CONFIG_BSP_USING_RTC is not set

+ 4 - 0
bsp/k230/board/Kconfig

@@ -1,4 +1,8 @@
 menu "Drivers Configuration"
+        
+    config BSP_USING_GNNE
+        bool "Enable KPU and AI2D"
+        default n
 
     menuconfig BSP_USING_SPI
         bool "Enable SPI"

+ 19 - 0
bsp/k230/drivers/interdrv/gnne/SConscript

@@ -0,0 +1,19 @@
+# RT-Thread building script for gnne component
+
+from building import *
+
+cwd     = GetCurrentDir()
+src     = Glob('*.c')
+CPPPATH = [cwd]
+
+group = DefineGroup('Gnne', src, depend = ['BSP_USING_GNNE'], CPPPATH = CPPPATH)
+
+objs = [group]
+
+list = os.listdir(cwd)
+
+for item in list:
+    if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
+        objs = objs + SConscript(os.path.join(item, 'SConscript'))
+
+Return('objs')

+ 227 - 0
bsp/k230/drivers/interdrv/gnne/ai2d_dev.c

@@ -0,0 +1,227 @@
+/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include "drv_hardlock.h"
+#include "board.h"
+
+#if defined(RT_USING_POSIX_DEVIO)
+    #include <dfs_posix.h>
+    #include <poll.h>
+    #include <termios.h>
+#endif
+
+#define AI2D_CMD_LOCK       0
+#define AI2D_CMD_TRYLOCK    1
+#define AI2D_CMD_UNLOCK     2
+static hardlock_type g_ai2d_lock = HARDLOCK_MAX;
+
+struct ai_2d_dev_handle
+{
+    rt_wqueue_t *wait;
+    rt_bool_t is_lock;
+};
+
+
+#define ai_2d_log(s...)    rt_kprintf(s)
+
+#define ai_2d_err(s...) do { \
+    ai_2d_log("<err>[%s:%d] ", __func__, __LINE__); \
+    ai_2d_log(s); \
+    ai_2d_log("\r\n"); \
+} while (0)
+
+static struct rt_device g_ai_2d_device = {0};
+static struct rt_event g_ai_2d_event = {0};
+extern void *gnne_base_addr;
+
+static int ai_2d_device_open(struct dfs_file *file)
+{
+    struct ai_2d_dev_handle *handle;
+    rt_device_t device;
+
+    handle = rt_malloc(sizeof(struct ai_2d_dev_handle));
+    if (handle == RT_NULL)
+    {
+        ai_2d_err("malloc failed\n");
+        return -1;
+    }
+    device = (rt_device_t)file->vnode->data;
+    handle->wait = &device->wait_queue;
+    handle->is_lock = RT_FALSE;
+    file->data = (void *)handle;
+    return RT_EOK;
+}
+
+static int ai_2d_device_close(struct dfs_file *file)
+{
+    struct ai_2d_dev_handle *handle;
+
+    handle = (struct ai_2d_dev_handle *)file->data;
+    if (handle == RT_NULL)
+    {
+        ai_2d_err("try to close a invalid handle");
+        return -RT_EINVAL;
+    }
+    if (handle->is_lock)
+    {
+        kd_hardlock_unlock(g_ai2d_lock);
+    }
+    rt_free(handle);
+    file->data = RT_NULL;
+    return RT_EOK;
+}
+
+static int ai_2d_device_ioctl(struct dfs_file *file, int cmd, void *args)
+{
+    struct ai_2d_dev_handle *handle;
+    int ret = -1;
+
+    handle = (struct ai_2d_dev_handle *)file->data;
+    if (g_ai2d_lock == HARDLOCK_MAX)
+        return ret;
+
+    if (cmd == AI2D_CMD_LOCK)
+    {
+        if (handle->is_lock == RT_TRUE)
+        {
+            return 0;
+        }
+        while (kd_hardlock_lock(g_ai2d_lock));
+        handle->is_lock = RT_TRUE;
+        ret = 0;
+    }
+    else if (cmd == AI2D_CMD_UNLOCK)
+    {
+        if (handle->is_lock == RT_FALSE)
+        {
+            return 0;
+        }
+        kd_hardlock_unlock(g_ai2d_lock);
+        handle->is_lock = RT_FALSE;
+        ret = 0;
+    }
+    else if (cmd == AI2D_CMD_TRYLOCK)
+    {
+        if (handle->is_lock == RT_TRUE)
+        {
+            return 0;
+        }
+        if (!kd_hardlock_lock(g_ai2d_lock))
+        {
+            handle->is_lock = RT_TRUE;
+            ret = 0;
+        }
+    }
+    return ret;
+}
+
+int ai_2d_device_poll(struct dfs_file *file, struct rt_pollreq *req)
+{
+    struct ai_2d_dev_handle *handle;
+    unsigned int flags;
+    handle = (struct ai_2d_dev_handle *)file->data;
+    if (!handle)
+    {
+        ai_2d_err("ai_2d_dev_handle NULL!");
+        return -EINVAL;
+    }
+    rt_event_recv(&g_ai_2d_event, 0x01, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, NULL);
+    rt_poll_add(handle->wait, req);
+    return POLLIN;
+}
+
+static const struct dfs_file_ops ai_2d_input_fops =
+{
+    .open = ai_2d_device_open,
+    .close = ai_2d_device_close,
+    .ioctl = ai_2d_device_ioctl,
+    .poll = ai_2d_device_poll,
+};
+
+static void irq_callback(int irq, void *data)
+{
+    rt_wqueue_t *wait = (rt_wqueue_t *)data;
+    volatile rt_uint32_t *write_addr = (rt_uint32_t *)((char *)gnne_base_addr + 0xca0);
+    if (gnne_base_addr == RT_NULL)
+    {
+        ai_2d_err("ai2d interrupts while the hardware is not yet initialized\n");
+    }
+    write_addr[0] = 1;
+    write_addr[1] = 0;
+    write_addr[2] = 0;
+    write_addr[3] = 0;
+    rt_wqueue_wakeup(wait, (void *)POLLIN);
+    rt_event_send(&g_ai_2d_event, 0x1);
+}
+
+int ai_2d_device_init(void)
+{
+    int ret = 0;
+    rt_isr_handler_t old_handler;
+    rt_device_t ai_2d_device = &g_ai_2d_device;
+
+    ret = rt_event_init(&g_ai_2d_event, "ai_2d_event", RT_IPC_FLAG_PRIO);
+    if (ret)
+    {
+        ai_2d_err("event init failed\n");
+        return -ENOMEM;
+    }
+
+    ret = rt_device_register(ai_2d_device, "ai_2d_device", RT_DEVICE_FLAG_RDWR);
+    if (ret)
+    {
+        ai_2d_err("ai_2d_device register fail\n");
+        return ret;
+    }
+
+    rt_wqueue_init(&ai_2d_device->wait_queue);
+    old_handler = rt_hw_interrupt_install(K230_IRQ_AI_2D, irq_callback, &ai_2d_device->wait_queue, "ai_2d_irq");
+    if (old_handler == RT_NULL)
+    {
+        ai_2d_err("ai_2d_device interrupt install fail\n");
+        return -RT_ERROR;
+    }
+    rt_hw_interrupt_umask(K230_IRQ_AI_2D);
+
+    ai_2d_device->fops = &ai_2d_input_fops;
+
+    if (kd_request_lock(HARDLOCK_AI2D))
+    {
+        ai_2d_err("fail to request hardlock-%d\n", HARDLOCK_AI2D);
+    }
+    else
+    {
+        g_ai2d_lock  = HARDLOCK_AI2D;
+    }
+    return RT_EOK;
+}

+ 49 - 0
bsp/k230/drivers/interdrv/gnne/ai_module.c

@@ -0,0 +1,49 @@
+/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * NOTE: Currently untested - nncase cannot run due to missing mmz library.
+ * The mmz library depends on MPP driver, which relies on deprecated RT-Thread
+ * kernel APIs (rt_proc_entry_create, rt_dma_chan_request, etc.) that are no
+ * longer available in the mainline kernel. Awaiting resolution.
+ */
+
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rtthread.h>
+
+extern int gnne_device_init(void);
+extern int ai_2d_device_init(void);
+
+int ai_module_init(void)
+{
+    gnne_device_init();
+    ai_2d_device_init();
+}
+INIT_COMPONENT_EXPORT(ai_module_init);

+ 237 - 0
bsp/k230/drivers/interdrv/gnne/gnne_dev.c

@@ -0,0 +1,237 @@
+/* Copyright (c) 2023, Canaan Bright Sight Co., Ltd
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 2006-2025 RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#include <rtthread.h>
+#include <rthw.h>
+#include "io.h"
+#include <ioremap.h>
+#include "board.h"
+#include "drv_hardlock.h"
+
+#if defined(RT_USING_POSIX_DEVIO)
+    #include <dfs_posix.h>
+    #include <poll.h>
+    #include <termios.h>
+#endif
+
+struct gnne_dev_handle
+{
+    rt_wqueue_t *wait;
+    rt_bool_t is_lock;
+};
+
+#define gnne_log(s...)    rt_kprintf(s)
+
+#define gnne_err(s...) do { \
+    gnne_log("<err>[%s:%d] ", __func__, __LINE__); \
+    gnne_log(s); \
+    gnne_log("\r\n"); \
+} while (0)
+
+#define GNNE_CMD_LOCK       0
+#define GNNE_CMD_TRYLOCK    1
+#define GNNE_CMD_UNLOCK     2
+
+static struct rt_device g_gnne_device = {0};
+static struct rt_event g_gnne_event = {0};
+void *gnne_base_addr = RT_NULL;
+static hardlock_type g_kpu_lock = HARDLOCK_MAX;
+
+static int gnne_device_open(struct dfs_file *file)
+{
+    struct gnne_dev_handle *handle;
+    rt_device_t device;
+
+    handle = rt_malloc(sizeof(struct gnne_dev_handle));
+    if (handle == RT_NULL)
+    {
+        gnne_err("malloc failed\n");
+        return -1;
+    }
+    device = (rt_device_t)file->vnode->data;
+    handle->wait = &device->wait_queue;
+    handle->is_lock = RT_FALSE;
+    file->data = (void *)handle;
+    return RT_EOK;
+}
+
+static int gnne_device_close(struct dfs_file *file)
+{
+    struct gnne_dev_handle *handle;
+
+    handle = (struct gnne_dev_handle *)file->data;
+    if (handle == RT_NULL)
+    {
+        gnne_err("try to close a invalid handle");
+        return -RT_EINVAL;
+    }
+    if (handle->is_lock)
+    {
+        kd_hardlock_unlock(g_kpu_lock);
+    }
+    rt_free(handle);
+    file->data = RT_NULL;
+    return RT_EOK;
+}
+
+static int gnne_device_ioctl(struct dfs_file *file, int cmd, void *args)
+{
+    struct gnne_dev_handle *handle;
+    int ret = -1;
+    handle = (struct gnne_dev_handle *)file->data;
+    if ((g_kpu_lock == HARDLOCK_MAX))
+    {
+        return ret;
+    }
+    if (cmd == GNNE_CMD_LOCK)
+    {
+        if (handle->is_lock == RT_TRUE)
+        {
+            return 0;
+        }
+        while (kd_hardlock_lock(g_kpu_lock));
+        handle->is_lock = RT_TRUE;
+        ret = 0;
+    }
+    else if (cmd == GNNE_CMD_UNLOCK)
+    {
+        if (handle->is_lock == RT_FALSE)
+        {
+            return 0;
+        }
+        kd_hardlock_unlock(g_kpu_lock);
+        handle->is_lock = RT_FALSE;
+        ret = 0;
+    }
+    else if (cmd == GNNE_CMD_TRYLOCK)
+    {
+        if (handle->is_lock == RT_TRUE)
+        {
+            return 0;
+        }
+        if (!kd_hardlock_lock(g_kpu_lock))
+        {
+            handle->is_lock = RT_TRUE;
+            ret = 0;
+        }
+    }
+    return ret;
+}
+
+int gnne_device_poll(struct dfs_file *file, struct rt_pollreq *req)
+{
+    struct gnne_dev_handle *handle;
+    unsigned int flags;
+    handle = (struct gnne_dev_handle *)file->data;
+    if (!handle)
+    {
+        gnne_err("gnne_dev_handle NULL!");
+        return -EINVAL;
+    }
+    rt_event_recv(&g_gnne_event, 0x01, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, NULL);
+    rt_poll_add(handle->wait, req);
+    return POLLIN;
+}
+
+static const struct dfs_file_ops gnne_input_fops =
+{
+    .open = gnne_device_open,
+    .close = gnne_device_close,
+    .ioctl = gnne_device_ioctl,
+    .poll = gnne_device_poll,
+};
+
+static void irq_callback(int irq, void *data)
+{
+    rt_wqueue_t *wait = (rt_wqueue_t *)data;
+    volatile void *write_addr = (void *)((char *)gnne_base_addr + 0x128);
+    if (gnne_base_addr == RT_NULL)
+    {
+        gnne_err("gnne interrupts while the hardware is not yet initialized\n");
+    }
+    /*clear kpu intr*/
+    __iowmb();
+    *(rt_uint64_t *)write_addr = 0x400000004;
+    rt_wqueue_wakeup(wait, (void *)POLLIN);
+    rt_event_send(&g_gnne_event, 0x1);
+}
+
+int gnne_device_init(void)
+{
+    int ret = 0;
+    rt_isr_handler_t old_handler;
+    rt_device_t gnne_device = &g_gnne_device;
+
+    ret = rt_event_init(&g_gnne_event, "gnne_event", RT_IPC_FLAG_PRIO);
+    if (ret)
+    {
+        gnne_err("event init failed\n");
+        return -ENOMEM;
+    }
+
+    ret = rt_device_register(gnne_device, "gnne_device", RT_DEVICE_FLAG_RDWR);
+    if (ret)
+    {
+        gnne_err("gnne_device register fail\n");
+        return ret;
+    }
+
+
+    /*rt_ioremap maps the size of at least one page*/
+    gnne_base_addr = rt_ioremap((void *)KPU_BASE_ADDR, (KPU_IO_SIZE + FFT_IO_SIZE + AI2D_IO_SIZE));
+    if (gnne_base_addr == RT_NULL)
+    {
+        gnne_err("gnne ioremap error\n");
+        return -1;
+    }
+
+    rt_wqueue_init(&gnne_device->wait_queue);
+    old_handler = rt_hw_interrupt_install(K230_IRQ_GNNE, irq_callback, &gnne_device->wait_queue, "gnne_irq");
+    if (old_handler == RT_NULL)
+    {
+        gnne_err("gnne_device interrupt install fail\n");
+        return -RT_ERROR;
+    }
+    rt_hw_interrupt_umask(K230_IRQ_GNNE);
+
+    gnne_device->fops = &gnne_input_fops;
+
+    if (kd_request_lock(HARDLOCK_KPU))
+    {
+        gnne_err("fail to request hardlock-%d\n", HARDLOCK_KPU);
+    }
+    else
+    {
+        g_kpu_lock  = HARDLOCK_KPU;
+    }
+
+    return RT_EOK;
+}

+ 1 - 0
bsp/k230/drivers/interdrv/hardlock/drv_hardlock.h

@@ -39,6 +39,7 @@ typedef enum k230_hardlock_type
     HARDLOCK_AES = 7,
     HARDLOCK_SM4 = 8,
     HARDLOCK_PDMA = 9,
+    HARDLOCK_AI2D = 10,
     HARDLOCK_MAX = 128
 } hardlock_type;