[COMMON] chub: add board clock control
authorBoojin Kim <boojin.kim@samsung.com>
Wed, 11 Jul 2018 07:06:40 +0000 (16:06 +0900)
committerCosmin Tanislav <demonsingur@gmail.com>
Mon, 22 Apr 2024 17:22:55 +0000 (20:22 +0300)
Change-Id: I45f36d0b88a0969e50fe2f1254b21cbe927257b6
Signed-off-by: Boojin Kim <boojin.kim@samsung.com>
Signed-off-by: Sukwon Ryoo <sw.ryoo@samsung.com>
drivers/staging/nanohub/chub.c
drivers/staging/nanohub/chub.h
drivers/staging/nanohub/chub_dbg.c
drivers/staging/nanohub/chub_ipc.c
drivers/staging/nanohub/chub_ipc.h

index b43b1b5471ee7f71b30f4da924e3e19d843fec76..70f3bae8bc58bb370daecdd878c626730120d5ea 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/random.h>
 #include <linux/rtc.h>
 #include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/timekeeping.h>
 #ifdef CONFIG_EXYNOS_ITMON
 #include <soc/samsung/exynos-itmon.h>
@@ -44,6 +45,7 @@
 #include "../../soc/samsung/cal-if/pmucal_shub.h"
 #define WAIT_TRY_CNT (3)
 #define WAIT_TIMEOUT_MS (1000)
+#define WAIT_RESET_MS (100)
 enum { CHUB_ON, CHUB_OFF };
 enum { C2A_ON, C2A_OFF };
 
@@ -60,6 +62,19 @@ int contexthub_is_run(struct contexthub_ipc_info *ipc)
 #endif
 }
 
+static inline int contexthub_is_active(struct contexthub_ipc_info *ipc)
+{
+       int status = atomic_read(&ipc->chub_status);
+
+       if (status == CHUB_ST_RUN)
+               return 0;
+       else {
+               dev_warn(ipc->dev, "%s: isn't active: status:%d\n",
+                       __func__, status);
+               return -EINVAL;
+       }
+}
+
 /* request contexthub to host driver */
 int contexthub_request(struct contexthub_ipc_info *ipc)
 {
@@ -162,6 +177,7 @@ static int contexthub_ipc_drv_init(struct contexthub_ipc_info *chub)
 {
        struct device *chub_dev = chub->dev;
        int ret = 0;
+       int i;
 
        chub->ipc_map = ipc_get_chub_map();
        if (!chub->ipc_map)
@@ -177,6 +193,13 @@ static int contexthub_ipc_drv_init(struct contexthub_ipc_info *chub)
        if (!chub->fw_log)
                return -EINVAL;
 
+       for (i = 0; i < chub->irq_pin_len; i++) {
+               disable_irq_nosync(chub->irq_pins[i]);
+               dev_info(chub_dev,
+                       "%s: %d is for chub. disable it\n",
+                       __func__, chub->irq_pins[i]);
+       }
+
 #ifdef LOWLEVEL_DEBUG
        chub->dd_log_buffer = vmalloc(SZ_256K + sizeof(struct LOG_BUFFER *));
        chub->dd_log_buffer->index_reader = 0;
@@ -249,6 +272,7 @@ static void enable_debug_workqueue(struct contexthub_ipc_info *ipc, enum chub_er
                        __func__, err, ipc->err_cnt[err], ipc->active_err);
        }
 
+       dev_info(ipc->dev, "%s: dbg:%d\n", __func__, err);
        if (err == CHUB_ERR_ITMON) {
                chub_dbg_dump_gpr(ipc);
                chub_dbg_dump_ram(ipc, err);
@@ -264,7 +288,13 @@ int contexthub_ipc_read(struct contexthub_ipc_info *ipc, uint8_t *rx, int max_le
 #ifdef USE_IPC_BUF
        int size = 0;
        int ret;
+       int lock;
+       struct ipc_buf *ipc_buf;
 
+       if (contexthub_is_active(ipc))
+               return 0;
+
+       ipc_buf = ipc_get_base(IPC_REG_IPC_C2A);
        if (!ipc->read_lock.flag) {
                spin_lock_irqsave(&ipc->read_lock.event.lock, flag);
                read_get_locked(ipc);
@@ -291,6 +321,9 @@ int contexthub_ipc_read(struct contexthub_ipc_info *ipc, uint8_t *rx, int max_le
        struct ipc_content *content;
        int ch = INVAL_CHANNEL;
 
+       if (contexthub_is_active(ipc))
+               return 0;
+
        if (ipc->read_lock.flag) {
 search_channel:
                ch = get_recv_channel(&ipc->recv_order);
@@ -337,6 +370,9 @@ int contexthub_ipc_write(struct contexthub_ipc_info *ipc,
 #ifdef USE_IPC_BUF
        int ret;
 
+       if (contexthub_is_active(ipc))
+               return 0;
+
        ret = ipc_write_data(IPC_DATA_A2C, tx, (u16)length);
        if (ret) {
                pr_err("%s: fails to write data: ret:%d, len:%d errcnt:%d\n",
@@ -346,7 +382,12 @@ int contexthub_ipc_write(struct contexthub_ipc_info *ipc,
        }
        return length;
 #else
-       struct ipc_content *content =
+       struct ipc_content *content;
+
+       if (contexthub_is_active(ipc))
+               return 0;
+
+       content =
            ipc_get_channel(IPC_REG_IPC_A2C, CS_IDLE, CS_AP_WRITE);
 
        if (!content) {
@@ -388,13 +429,12 @@ static void check_rtc_time(void)
        ap_t = rtc_tm_to_time64(&ap_tm);
 }
 
-/* simple alive check function */
+/* simple alive check function : don't use ipc map */
 static bool contexthub_lowlevel_alive(struct contexthub_ipc_info *ipc)
 {
        int val;
 
        ipc->chub_alive_lock.flag = 0;
-       ipc_write_val(AP, sched_clock());
        ipc_hw_gen_interrupt(AP, IRQ_EVT_CHUB_ALIVE);
        val = wait_event_timeout(ipc->chub_alive_lock.event,
                                 ipc->chub_alive_lock.flag,
@@ -521,6 +561,7 @@ static int contexthub_hw_reset(struct contexthub_ipc_info *ipc,
                break;
        }
 
+       msleep(WAIT_RESET_MS);
        if (ret)
                return ret;
        else
@@ -765,6 +806,12 @@ int contexthub_reset(struct contexthub_ipc_info *ipc)
                dev_info(ipc->dev, "%s: chub reseted! (cnt:%d)\n",
                        __func__, atomic_read(&ipc->in_reset));
 
+       if (!ret)
+               ipc->err_cnt[CHUB_ERR_RESET_CNT]++;
+
+       if (!ret)
+               ret = ipc_check_reset_valid();
+
        atomic_dec(&ipc->in_reset);
        return ret;
 }
@@ -874,6 +921,7 @@ static void handle_debug_work_func(struct work_struct *work)
                                 "Contexthub notified that logbuf is full\n");
                        break;
                case IPC_DEBUG_CHUB_PRINT_LOG:
+                       log_flush(ipc->fw_log);
                        break;
                case IPC_DEBUG_CHUB_FAULT:
                        dev_warn(ipc->dev, "Contexthub notified fault\n");
@@ -892,15 +940,18 @@ static void handle_debug_work_func(struct work_struct *work)
                }
 
                /* clear dbg event */
+               dev_info(ipc->dev, "%s: dbg from chub:%d, err:%d\n",
+                       __func__, event, err);
                ipc_write_debug_event(AP, 0);
                if (err)
                        ipc->err_cnt[err]++;
-               return;
+               else
+                       return;
        }
 
 do_err_handle:
-       dev_info(ipc->dev, "%s: active_err:0x%x, alive:%d\n",
-               __func__, ipc->active_err, alive);
+       dev_info(ipc->dev, "%s: active_err:0x%x, alive:%d, dbg:%d\n",
+               __func__, ipc->active_err, alive, event);
 
        /* print error status */
        for (i = 0; i < CHUB_ERR_CHUB_MAX; i++) {
@@ -1060,7 +1111,8 @@ static irqreturn_t contexthub_irq_handler(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-#ifdef CHUB_RESET_ENABLE
+#define CONFIG_WDT_ENABLE
+#if defined(CHUB_RESET_ENABLE) && defined(CONFIG_WDT_ENABLE)
 static irqreturn_t contexthub_irq_wdt_handler(int irq, void *data)
 {
        struct contexthub_ipc_info *ipc = data;
@@ -1073,67 +1125,32 @@ static irqreturn_t contexthub_irq_wdt_handler(int irq, void *data)
 }
 #endif
 
-static int contexthub_get_cmgp_clocks(struct device *dev)
+static struct clk *devm_clk_get_and_prepare(struct device *dev,
+       const char *name)
 {
-#if defined(CONFIG_SOC_EXYNOS9610)
-       struct clk *clk;
-       int ret = 0;
+       struct clk *clk = NULL;
+       int ret;
 
-       /* RPR0521, LIS3MDL */
-       clk = devm_clk_get(dev, "cmgp_usi01");
+       clk = devm_clk_get(dev, name);
        if (IS_ERR(clk)) {
-               dev_err(dev, "[nanohub] cannot get cmgp_usi01\n");
-               return -ENOENT;
-       }
-       ret = clk_prepare(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot prepare cmgp_usi01\n");
-               return ret;
+               dev_err(dev, "Failed to get clock %s\n", name);
+               goto error;
        }
-       ret = clk_enable(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot enable cmgp_usi01\n");
-               return ret;
-       }
-       dev_info(dev, "cmgp_usi01(%lu) is enabled\n", clk_get_rate(clk));
 
-       /* BMP280 */
-       clk = devm_clk_get(dev, "cmgp_usi03");
-       if (IS_ERR(clk)) {
-               dev_err(dev, "[nanohub] cannot get cmgp_usi03\n");
-               return -ENOENT;
-       }
        ret = clk_prepare(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot prepare cmgp_usi03\n");
-               return ret;
-       }
-       ret = clk_enable(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot enable cmgp_usi03\n");
-               return ret;
+       if (ret < 0) {
+               dev_err(dev, "Failed to prepare clock %s\n", name);
+               goto error;
        }
-       dev_info(dev, "cmgp_usi03(%lu) is enabled\n", clk_get_rate(clk));
 
-       clk = devm_clk_get(dev, "cmgp_i2c");
-       if (IS_ERR(clk)) {
-               dev_err(dev, "[nanohub] cannot get cmgp_i2c\n");
-               return -ENOENT;
-       }
-       ret = clk_prepare(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot prepare cmgp_i2c\n");
-               return ret;
-       }
        ret = clk_enable(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot enable cmgp_i2c\n");
-               return ret;
+       if (ret < 0) {
+               dev_err(dev, "Failed to enable clock %s\n", name);
+               goto error;
        }
-       dev_info(dev, "cmgp_i2c(%lu) is enabled\n", clk_get_rate(clk));
-#endif
 
-       return 0;
+error:
+       return clk;
 }
 
 #if defined(CONFIG_SOC_EXYNOS9610)
@@ -1150,7 +1167,10 @@ static __init int contexthub_ipc_hw_init(struct platform_device *pdev,
        const char *resetmode;
        struct device *dev = &pdev->dev;
        struct device_node *node = dev->of_node;
+       const char *string_array[10];
+       int chub_clk_len;
        struct clk *clk;
+       int i;
 
        if (!node) {
                dev_err(dev, "driver doesn't support non-dt\n");
@@ -1191,7 +1211,7 @@ static __init int contexthub_ipc_hw_init(struct platform_device *pdev,
                return ret;
        }
 
-#ifdef CHUB_RESET_ENABLE
+#if defined(CHUB_RESET_ENABLE) && defined(CONFIG_WDT_ENABLE)
        /* get wdt interrupt optionally */
        chub->irq_wdt = irq_of_parse_and_map(node, 1);
        if (chub->irq_wdt > 0) {
@@ -1284,33 +1304,40 @@ static __init int contexthub_ipc_hw_init(struct platform_device *pdev,
                return -ENODEV;
        }
 
+       /* disable chub irq list (for sensor irq) */
+       chub->irq_pin_len = of_property_count_u32_elems(node, "chub-irq-pin");
+       if (chub->irq_pin_len) {
+               if (chub->irq_pin_len > sizeof(chub->irq_pins)) {
+                       dev_err(&pdev->dev,
+                       "failed to get irq pin length %d, %d\n",
+                       chub->irq_pin_len, sizeof(chub->irq_pins));
+                       chub->irq_pin_len = 0;
+                       return -ENODEV;
+               }
+
+               if(of_property_read_u32_array(node, "chub-irq-pin",
+                               chub->irq_pins, chub->irq_pin_len)) {
+                       dev_err(&pdev->dev,
+                               "failed to get irq-pin\n");
+                       return -ENODEV;
+               }
+       }
 #if defined(CONFIG_SOC_EXYNOS9610)
        cal_dll_apm_enable();
 #endif
-       clk = devm_clk_get(dev, "chub_bus");
-       if (IS_ERR(clk)) {
-               dev_err(dev, "[nanohub] cannot get clock\n");
-               return -ENOENT;
-       }
-#if defined(CONFIG_SOC_EXYNOS9610)
-       ret = clk_prepare(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot prepare clock\n");
-               return ret;
-       }
 
-       ret = clk_enable(clk);
-       if (ret) {
-               dev_err(dev, "[nanohub] cannot enable clock\n");
-               return ret;
-       }
-#endif
+       clk = devm_clk_get_and_prepare(dev, "chub_bus");
+       if (!clk)
+               return -ENODEV;
        chub->clkrate = clk_get_rate(clk);
 
-       ret = contexthub_get_cmgp_clocks(&pdev->dev);
-       if (ret) {
-               dev_err(&pdev->dev, "[nanohub] contexthub_get_cmgp_clocks failed\n");
-               return ret;
+       chub_clk_len = of_property_count_strings(node, "clock-names");
+       of_property_read_string_array(node, "clock-names", string_array, chub_clk_len);
+       for (i = 0 ; i < chub_clk_len; i++){
+               clk = devm_clk_get_and_prepare(dev, string_array[i]);
+               if (!clk)
+                       return -ENODEV;
+               dev_info(&pdev->dev, "clk_name: %s enable\n", __clk_get_name(clk));
        }
 
        return 0;
@@ -1324,7 +1351,7 @@ static ssize_t chub_poweron(struct device *dev,
        int ret = contexthub_poweron(ipc);
 
        if (!ret)
-               ret = ipc_check_reset_valid(ipc->ipc_map);
+               ret = ipc_check_reset_valid();
 
        return ret < 0 ? ret : count;
 }
@@ -1342,9 +1369,6 @@ static ssize_t chub_reset(struct device *dev,
        if (!ret)
                ret = contexthub_reset(ipc);
 
-       if (!ret)
-               ret = ipc_check_reset_valid(ipc->ipc_map);
-
        return ret < 0 ? ret : count;
 }
 
index 89925fd7d89ae243b7655f423c03be1fd53611b4..c885fcca88d4085078f72728229810b2dfcd0886 100644 (file)
@@ -111,7 +111,11 @@ struct chub_alive {
        wait_queue_head_t event;
 };
 
+#ifdef USE_EXYNOS_LOG
 #define CHUB_DBG_DIR "/data/exynos/log/chub"
+#else
+#define CHUB_DBG_DIR "/data"
+#endif
 
 enum chub_err_type {
        CHUB_ERR_NONE,
@@ -122,11 +126,12 @@ enum chub_err_type {
        CHUB_ERR_CHUB_NO_RESPONSE,
        CHUB_ERR_ITMON,
        CHUB_ERR_NANOHUB,
+       CHUB_ERR_RESET_CNT,
        CHUB_ERR_CHUB_MAX,
        CHUB_ERR_NANOHUB_FAULT, /* chub error */
        CHUB_ERR_NANOHUB_ASSERT,
        CHUB_ERR_NANOHUB_ERROR,
-       CHUB_ERR_NANOHUB_WDT,
+       CHUB_ERR_NANOHUB_WDT, /* 13 */
        CHUB_ERR_COMMS_NACK,
        CHUB_ERR_COMMS_BUSY,
        CHUB_ERR_COMMS_UNKNOWN,
@@ -141,6 +146,7 @@ struct contexthub_baaw_info {
        unsigned int baaw_p_apm_chub_remap;
 };
 
+#define CHUB_IRQ_PIN_MAX (5)
 struct contexthub_ipc_info {
        struct device *dev;
        struct nanohub_data *data;
@@ -181,6 +187,8 @@ struct contexthub_ipc_info {
        bool os_load;
        char os_name[MAX_FILE_LEN];
        struct notifier_block itmon_nb;
+       u32 irq_pin_len;
+       u32 irq_pins[CHUB_IRQ_PIN_MAX];
 #ifdef CONFIG_CONTEXTHUB_DEBUG
        struct work_struct utc_work;
 #endif
index 614abdb853312a97680309376c5228648b4add2c..e5801b928c7f8d0feae9a21ce5e25c76b34f925b 100644 (file)
@@ -92,11 +92,12 @@ static void chub_dbg_write_file(struct device *dev, char *name, void *buf, int s
                CHUB_DBG_DIR, p_dump->reason, sec, name);
 
        old_fs = get_fs();
-       set_fs(KERNEL_DS);
+       set_fs(get_ds());
 
-       filp = filp_open(file_name, O_RDWR | O_TRUNC | O_CREAT, S_IRWUG);
+       filp = filp_open(file_name, O_RDWR|O_CREAT|O_APPEND, 0666);
        if (IS_ERR(filp)) {
-               dev_warn(dev, "%s: open file fail\n", __func__);
+               dev_warn(dev, "%s: open '%s' file fail: filp:%p\n",
+                       __func__, file_name, filp);
                goto out;
        }
 
@@ -202,6 +203,12 @@ void chub_dbg_check_and_download_image(struct contexthub_ipc_info *ipc)
 void chub_dbg_dump_status(struct contexthub_ipc_info *ipc)
 {
        int val;
+       char *dbg_name[CHUB_ERR_MAX] = {"none", "evtq_empty",
+               "read_fail", "write_fail", "evtq_no_hw_trigger",
+               "chub_no_resp", "itmon", "nanohub_dbg", "reset_cnt",
+               "chub_err_max", "fw_fault", "fw_assert", "fw_error",
+               "fw_wdt", "comms_nack", "comms_busy",
+               "comms_unknown", "comms", "comms_max"};
 
 #ifdef CONFIG_CHRE_SENSORHUB_HAL
        struct nanohub_data *data = ipc->data;
@@ -231,8 +238,8 @@ void chub_dbg_dump_status(struct contexthub_ipc_info *ipc)
 #endif
        for (val = 0; val < CHUB_ERR_MAX; val++)
                if (ipc->err_cnt[val])
-                       CSP_PRINTF_INFO("error %d occurs %d times\n",
-                                       val, ipc->err_cnt[val]);
+                       CSP_PRINTF_INFO("error %d(%s) occurs %d times\n",
+                                       val, dbg_name[val], ipc->err_cnt[val]);
        ipc_dump();
        /* dump nanohub kernel status */
        CSP_PRINTF_INFO("CHUB DUMP: Request to dump nanohub kernel status\n");
@@ -299,7 +306,6 @@ char chub_utc_name[][SIZE_UTC_NAME] = {
        [IPC_DEBUG_UTC_HANG] = "hang",
 };
 
-
 static ssize_t chub_alive_show(struct device *dev,
                             struct device_attribute *attr, char *buf)
 {
@@ -339,6 +345,8 @@ static ssize_t chub_utc_store(struct device *dev,
        int err;
 
        err = kstrtol(&buf[0], 10, &event);
+       dev_info(ipc->dev, "%s: event:%d\n", __func__, event);
+
        if (!err) {
                err = contexthub_request(ipc);
                if (err)
index 37675f33f1b4e21baa292fdc6b9aab8fde33d280..bdc077c00701d4a9784e3e93a2ae7aeeabe6c126 100644 (file)
@@ -211,7 +211,7 @@ void *ipc_get_chub_map(void)
 #endif
 
        CSP_PRINTF_INFO
-           ("contexthub map information(v%u)\nbl(%p %d)\nos(%p %d)\nipc(%p %d)\nram(%p %d)\nshared(%p %d)\ndump(%p %d)\n",
+           ("contexthub map information(v%u)\n bl(%p %d)\n os(%p %d)\n ipc(%p %d)\n ram(%p %d)\n shared(%p %d)\n dump(%p %d)\n",
             map->ipc_version,
             ipc_addr[IPC_REG_BL].base, ipc_addr[IPC_REG_BL].offset,
             ipc_addr[IPC_REG_OS].base, ipc_addr[IPC_REG_OS].offset,
@@ -556,10 +556,11 @@ void ipc_print_channel(void)
 }
 #endif
 
-int ipc_check_reset_valid(struct ipc_map_area *map)
+int ipc_check_reset_valid()
 {
        int i;
        int ret = 0;
+       struct ipc_map_area *map = ipc_get_base(IPC_REG_IPC);
 
        for (i = 0; i < IPC_DATA_MAX; i++)
                if (map->data[i].dq || map->data[i].eq ||
index ee79e7c82f37d4a9bd3c8cda17aef07a9dd6d1d0..d0bcbf504949cce47cdb4f0ea770476cc85595ed 100644 (file)
@@ -177,7 +177,7 @@ enum ipc_debug_event {
        IPC_DEBUG_UTC_SPI,
        IPC_DEBUG_UTC_CMU,
        IPC_DEBUG_UTC_TIME_SYNC,
-       IPC_DEBUG_UTC_ASSERT,
+       IPC_DEBUG_UTC_ASSERT, /* 10 */
        IPC_DEBUG_UTC_FAULT,
        IPC_DEBUG_UTC_CHECK_STATUS,
        IPC_DEBUG_UTC_CHECK_CPU_UTIL,
@@ -187,7 +187,7 @@ enum ipc_debug_event {
        IPC_DEBUG_UTC_IPC_TEST_END,
        IPC_DEBUG_UTC_MAX,
        IPC_DEBUG_NANOHUB_MAX,
-       IPC_DEBUG_DUMP_STATUS,
+       IPC_DEBUG_DUMP_STATUS,  /* 20 */
        IPC_DEBUG_CHUB_PRINT_LOG,
        IPC_DEBUG_CHUB_FULL_LOG,
        IPC_DEBUG_CHUB_FAULT,
@@ -347,6 +347,7 @@ struct ipc_buf {
 };
 
 struct ipc_map_area {
+       u8 persist_padding[128]; /* persisten base shoud be ipc base */
 #ifdef USE_IPC_BUF
        struct ipc_buf data[IPC_DATA_MAX];
 #else
@@ -410,12 +411,13 @@ struct ipc_map_area {
 
 /* channel ctrl functions */
 void ipc_print_channel(void);
+int ipc_check_valid(void);
 char *ipc_get_cs_name(enum channel_status cs);
 void ipc_set_base(void *addr);
 void *ipc_get_base(enum ipc_region area);
 u32 ipc_get_offset(enum ipc_region area);
 void *ipc_get_addr(enum ipc_region area, int buf_num);
-int ipc_check_reset_valid(struct ipc_map_area *ipc_map);
+int ipc_check_reset_valid(void);
 void ipc_init(void);
 int ipc_hw_read_int_start_index(enum ipc_owner owner);
 void ipc_update_channel_status(struct ipc_content *content,