You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by we...@apache.org on 2019/06/19 23:55:44 UTC
[mynewt-core] branch master updated: hw/mcu/dialog: SNC (#1868)
This is an automated email from the ASF dual-hosted git repository.
wes3 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git
The following commit(s) were added to refs/heads/master by this push:
new af296c0 hw/mcu/dialog: SNC (#1868)
af296c0 is described below
commit af296c05b67a2fe77d8a8b0651dcfa6757c11185
Author: wes3 <wi...@runtime.io>
AuthorDate: Wed Jun 19 16:55:39 2019 -0700
hw/mcu/dialog: SNC (#1868)
* hw/mcu/dialog: SNC
Sensor node controller API. This commit allows users to create
SNC programs using the macros in da1469x_snc.h and run them
either under software control or use the PDC to start them. Note
that PDC control of the SNC is not contained here; the PDC api
already contain all that is needed to have the PDC start the
SNC.
Added in this commit is a test program (hosted) that illustrates
how a program can be created and run under software control. The
code for the test program is in hw/mcu/dialong/da1469x/hosttest.
This directory is also intended for other host tests and not
just the SNC test.
* hw/mcu/dialog: SNC
This commit adds interrupt registering and handling code for the SNC. Adds additional test cases to test the interrupt handling API. Addressed PR review comments as well.
* hw/mcu/dialog/da1469x/hosttest: Add license file to syscfg.yml
---
.../hosttest/include/da1469x_test/da1469x_test.h | 43 ++
hw/mcu/dialog/da1469x/hosttest/pkg.yml | 30 ++
hw/mcu/dialog/da1469x/hosttest/src/da1469x_test.c | 42 ++
.../src/testcases/da1469x_snc_test_cases.c | 467 +++++++++++++++++++
hw/mcu/dialog/da1469x/hosttest/syscfg.yml | 26 ++
hw/mcu/dialog/da1469x/include/mcu/da1469x_snc.h | 514 +++++++++++++++++++++
hw/mcu/dialog/da1469x/src/da1469x_snc.c | 212 +++++++++
7 files changed, 1334 insertions(+)
diff --git a/hw/mcu/dialog/da1469x/hosttest/include/da1469x_test/da1469x_test.h b/hw/mcu/dialog/da1469x/hosttest/include/da1469x_test/da1469x_test.h
new file mode 100644
index 0000000..a040641
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/hosttest/include/da1469x_test/da1469x_test.h
@@ -0,0 +1,43 @@
+/*
+ * 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 _DA1469X_TEST_H
+#define _DA1469X_TEST_H
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stddef.h>
+#include "os/mynewt.h"
+#include "testutil/testutil.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+TEST_CASE_DECL(da1469x_snc_test_case_1);
+TEST_CASE_DECL(da1469x_snc_test_case_2);
+TEST_CASE_DECL(da1469x_snc_test_case_3);
+TEST_SUITE_DECL(da1469x_test_suite);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DA1469X_TEST_H */
diff --git a/hw/mcu/dialog/da1469x/hosttest/pkg.yml b/hw/mcu/dialog/da1469x/hosttest/pkg.yml
new file mode 100644
index 0000000..c10f645
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/hosttest/pkg.yml
@@ -0,0 +1,30 @@
+# 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.
+#
+
+pkg.name: hw/mcu/dialog/da1469x/hosttest
+pkg.type: lib
+pkg.description: "Hosted da1469x unit tests."
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+ - "@apache-mynewt-core/test/testutil"
+ - "@apache-mynewt-core/hw/mcu/dialog"
+
+pkg.init:
+ da1469x_hosttest_init: 'MYNEWT_VAL(DA1469x_HOSTTEST_SYSINIT_STAGE)'
diff --git a/hw/mcu/dialog/da1469x/hosttest/src/da1469x_test.c b/hw/mcu/dialog/da1469x/hosttest/src/da1469x_test.c
new file mode 100644
index 0000000..49fdcad
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/hosttest/src/da1469x_test.c
@@ -0,0 +1,42 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stddef.h>
+#include "os/mynewt.h"
+#include "syscfg/syscfg.h"
+#include "testutil/testutil.h"
+#include "da1469x_test/da1469x_test.h"
+
+TEST_SUITE(da1469x_test_suite)
+{
+#if MYNEWT_VAL(TESTBENCH_DA1469X_SNC == 1)
+ da1469x_snc_test_case_1();
+ da1469x_snc_test_case_2();
+ da1469x_snc_test_case_3();
+#endif
+}
+
+void
+da1469x_hosttest_init(void)
+{
+ TEST_SUITE_REGISTER(da1469x_test_suite);
+}
diff --git a/hw/mcu/dialog/da1469x/hosttest/src/testcases/da1469x_snc_test_cases.c b/hw/mcu/dialog/da1469x/hosttest/src/testcases/da1469x_snc_test_cases.c
new file mode 100644
index 0000000..f35c3ec
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/hosttest/src/testcases/da1469x_snc_test_cases.c
@@ -0,0 +1,467 @@
+/*
+ * 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 "syscfg/syscfg.h"
+#include "da1469x_test/da1469x_test.h"
+
+/* XXX: not tested
+ - WADAD register addresses for op1 and op2
+ - WADVA using registers.
+ - RDCGR reigster for addr1 and addr2
+*/
+
+#if MYNEWT_VAL(TESTBENCH_DA1469X_SNC == 1)
+#include <modlog/modlog.h>
+#include "mcu/da1469x_snc.h"
+
+#define SNC_TEST_XOR_MASK (0x003C00F0)
+
+/*
+ * This is an ugly hack, but to use the 64-bit macros it requires hard-coded
+ * addresses. These are defined at the bottom of the stack so highly unlikely
+ * they will get used as the stack is extremely large.
+ */
+uint32_t da1469x_test_var0;
+uint32_t da1469x_test_var1;
+uint32_t da1469x_test_var2;
+uint32_t da1469x_test_var3;
+uint32_t da1469x_test_var4;
+uint32_t da1469x_test_var5;
+uint32_t da1469x_test_var6;
+uint32_t da1469x_test_var7;
+uint32_t da1469x_test_var8;
+uint32_t da1469x_test_var9;
+uint32_t da1469x_test_var10;
+uint32_t da1469x_test_var11;
+uint32_t da1469x_test_var12;
+uint32_t da1469x_test_var13;
+uint32_t da1469x_test_var14;
+uint32_t da1469x_test_var15;
+uint32_t da1469x_test_var16;
+
+/*
+ * The test program. Note that the X: in the comment refers to the "line"
+ * number of the program (the offset into the program array). Some instructions
+ * are 64-bits which is why one initializer occupies two "lines".
+ */
+uint32_t snc_program[] =
+{
+ /* 0: No operation */
+ SNC_CMD_NOOP(),
+
+ /* 1: Delay 10 ticks */
+ SNC_CMD_DEL(10),
+
+ /* 2: Increment test var 1 by 1 */
+ SNC_CMD_INC_BY_1(&da1469x_test_var1),
+
+ /* 3: Increment test var 2 by 4 */
+ SNC_CMD_INC_BY_4(&da1469x_test_var2),
+
+ /* 4:
+ * This compares bit position 2 of test var 2 with 1. Sets the EQUALHIGH
+ * flag if set (which it is in this case).
+ */
+ SNC_CMD_RDCBI_RAM(&da1469x_test_var2, 2),
+
+ /* 5:
+ * Branch if EQUALHIGH flag is true. This branch should move past the
+ * next two instructions.
+ */
+ SNC_CMD_COBR_EQ_DIR(&snc_program[8]),
+
+ /* 6, 7: These two instructions should get skipped*/
+ SNC_CMD_INC_BY_4(&da1469x_test_var3),
+ SNC_CMD_INC_BY_4(&da1469x_test_var3),
+
+ /* 8: Just cause I feel like it */
+ SNC_CMD_NOOP(),
+
+ /* 9, 10: These two instructions should cause a loop here 10 times */
+ SNC_CMD_INC_BY_1(&da1469x_test_var4),
+ SNC_CMD_COBR_LOOP(&snc_program[9], 10),
+
+ /* 11, 12:
+ * These two instructions should cause a loop here 20 times.
+ * Purpose here is to see if the loop counter is a decrementing counter
+ * and after it gets exhausted it restarts.
+ */
+ SNC_CMD_INC_BY_1(&da1469x_test_var5),
+ SNC_CMD_COBR_LOOP(&snc_program[11], 20),
+
+ /* 13, 14: Move the contents of test var 7 to test var 8 */
+ SNC_CMD_WADAD_RAM2RAM(&da1469x_test_var8, SNC_WADAD_AM1_DIRECT,
+ SNC_WADAD_AM2_DIRECT, &da1469x_test_var7),
+
+ /* 15, 16:
+ * var 9 is pointer; move contents of what var 9 points to, to what var
+ * 10 points to (var 10 is a pointer).
+ */
+ SNC_CMD_WADAD_RAM2RAM(&da1469x_test_var10, SNC_WADAD_AM1_INDIRECT,
+ SNC_WADAD_AM2_INDIRECT, &da1469x_test_var9),
+
+ /* 17, 18: XOR */
+ SNC_CMD_TOBRE_RAM(&da1469x_test_var12, SNC_TEST_XOR_MASK),
+
+ /* 19, 20: XOR register (SNC_CTRL_REG). Should toggle both IRQ config bits */
+ SNC_CMD_TOBRE_REG(0x50020C00, 0xC0),
+
+ /* 21, 22: Moves immediate (the address of var 12) into var 13 */
+ SNC_CMD_WADVA_DIR_RAM(&da1469x_test_var13, &da1469x_test_var12),
+
+ /* 23, 24: Moves immediate into address pointed to by var14 */
+ SNC_CMD_WADVA_IND_RAM(&da1469x_test_var14, 0x33333333),
+
+ /* 25, 26:
+ * Compare the contents of test var 9 and 7. This instruction basically
+ * does this: if (var9 > var7) set GREATERVAL_FLAG. In this case, var9
+ * should be greater than var 7
+ */
+ SNC_CMD_RDCGR_RAMRAM(&da1469x_test_var9, &da1469x_test_var7),
+
+ /* 27:
+ * Branch if EQUALHIGH flag is true. This branch should move past the
+ * next instruction
+ */
+ SNC_CMD_COBR_GT_DIR(&snc_program[30]),
+
+ /* 28, 29: These two instructions should get skipped*/
+ SNC_CMD_INC_BY_4(&da1469x_test_var0),
+ SNC_CMD_INC_BY_4(&da1469x_test_var0),
+
+ /* 30: Increment test var 0 by 1 */
+ SNC_CMD_INC_BY_1(&da1469x_test_var0),
+
+ /* 31: Check if SW contrl bit is set in SNC control register. It should! */
+ SNC_CMD_RDCBI_REG(0x50020C00, SNC_SNC_CTRL_REG_SNC_SW_CTRL_Pos),
+
+ /* 32: Branch past next instruction if EQUALHIGH_FLAG is set (should be!) */
+ SNC_CMD_COBR_EQ_DIR(&snc_program[34]),
+ SNC_CMD_INC_BY_4(&da1469x_test_var16),
+
+ /* 34: Sleep (program ends) */
+ SNC_CMD_SLEEP()
+};
+
+/* Number of words (32-bits) in the static program */
+#define SNC_STATIC_PROGRAM_NUM_WORDS (sizeof(snc_static_program) / 4)
+
+TEST_CASE(da1469x_snc_test_case_1)
+{
+ int rc;
+
+ MODLOG_INFO(LOG_MODULE_TEST, "DA1469x snc test 1");
+
+ /*
+ * Initialize to some non-zero number. The test program should increment
+ * var1 by 1 and var2 by 4 using the increment instruction.
+ */
+ da1469x_test_var1 = 10;
+ da1469x_test_var2 = 10;
+
+ /* Initialize test var 7 with a value */
+ da1469x_test_var7 = 0x12345678;
+
+ /* Make test var 9 a pointer that points to test var 7 */
+ da1469x_test_var9 = (uint32_t)&da1469x_test_var7;
+
+ /* Make test var 10 a pointer that points to test var 11 */
+ da1469x_test_var10 = (uint32_t)&da1469x_test_var11;
+
+ /* test var 12 will test xor */
+ da1469x_test_var12 = 0xC3A78F;
+
+ /* Test var 14 is a pointer to var 15 */
+ da1469x_test_var14 = (uint32_t)&da1469x_test_var15;
+
+ /* Configure the SNC (base address and divider) */
+ rc = da1469x_snc_config(&snc_program, SNC_CLK_DIV_1);
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc config failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Initialize the SNC */
+ rc = da1469x_snc_sw_init();
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc init failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /*
+ * Make sure IRQ config bits are 0. The init function clears these but
+ * we do it here as well.
+ */
+ da1469x_snc_irq_config(SNC_IRQ_MASK_NONE, NULL, NULL);
+ if ((SNC->SNC_CTRL_REG & SNC_SNC_CTRL_REG_SNC_IRQ_CONFIG_Msk) != 0) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc irq config failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Start the program */
+ da1469x_snc_sw_start();
+
+ /* Wait 1 second for program to finish. */
+ os_time_delay(OS_TICKS_PER_SEC);
+ if (!da1469x_snc_program_is_done()) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed (not done)");
+ da1469x_snc_sw_stop();
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Check test var 1 and test var 2 have correct values */
+ if (da1469x_test_var1 != 11) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: inc by 1");
+ TEST_ASSERT_FATAL(0);
+ }
+ if (da1469x_test_var2 != 14) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: inc by 4");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 3 should be 0 */
+ if (da1469x_test_var3 != 0) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: RDCBI and/or COBR_EQ");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 4 should be 10 */
+ if (da1469x_test_var4 != 11) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: COBR loop. tv4=%lu",
+ da1469x_test_var4);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 5 should be 20 */
+ if (da1469x_test_var5 != 21) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: COBR loop 2. tv5=%lu",
+ da1469x_test_var5);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 8 should be equal to test var 7 */
+ if (da1469x_test_var8 != da1469x_test_var7) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: WADAD direct. tv7=%lx"
+ " tv8=%lx",
+ da1469x_test_var7, da1469x_test_var8);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 11 should have value in test var 7 */
+ if (da1469x_test_var11 != da1469x_test_var7) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: WADAD indirect. tv7=%lx"
+ " tv11=%lx",
+ da1469x_test_var7, da1469x_test_var11);
+ TEST_ASSERT_FATAL(0);
+ }
+
+
+ /* Test var 12 should be those two values xor'd (should equal 0xFFA77F) */
+ if (da1469x_test_var12 != (SNC_TEST_XOR_MASK ^ 0xC3A78F)) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: TOBRE. tv12=%lx",
+ da1469x_test_var12);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* SNC control registers should have both IRQ bits set */
+ if ((SNC->SNC_CTRL_REG & SNC_SNC_CTRL_REG_SNC_IRQ_CONFIG_Msk) !=
+ SNC_SNC_CTRL_REG_SNC_IRQ_CONFIG_Msk) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: TOBRE register %lx",
+ SNC->SNC_CTRL_REG);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Contents of test var 13 should equal address of test var 12 */
+ if (da1469x_test_var13 != (uint32_t)&da1469x_test_var12) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: WADVA direct. &tv12=%lx"
+ " tv13=%lx",
+ &da1469x_test_var12,
+ da1469x_test_var13);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 15 should be equal 0x33333333 */
+ if (da1469x_test_var15 != 0x33333333) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: WADVA indirect tv15=%lx",
+ da1469x_test_var15);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 0 should be equal to 1 */
+ if (da1469x_test_var0 != 1) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: RDCGR RAMRAM tv0=%lx",
+ da1469x_test_var0);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Test var 16 should be equal to 0 */
+ if (da1469x_test_var16 != 0) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: RDCBI reg tv16=%lx",
+ da1469x_test_var16);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Check for hard fault or bus status errors */
+ if (SNC->SNC_STATUS_REG & (SNC_SNC_STATUS_REG_HARD_FAULT_STATUS_Msk |
+ SNC_SNC_STATUS_REG_BUS_ERROR_STATUS_Msk)) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed: ERR snc status %lx",
+ SNC->SNC_STATUS_REG);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ da1469x_snc_sw_stop();
+ rc = da1469x_snc_sw_deinit();
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc s/w deinit failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test 1 success");
+}
+
+/*====================== TEST CASE 2 =====================================
+The intent of this test case is to test the interrupt API.
+========================================================================*/
+uint32_t g_snc_tc2_cntr;
+uint32_t snc_prog_test_case2[] =
+{
+ /* This should toggle the IRQ_EN bit, thus generating an interrupt */
+ SNC_CMD_TOBRE_REG(0x50020C00, SNC_SNC_CTRL_REG_SNC_IRQ_EN_Msk),
+ SNC_CMD_SLEEP()
+};
+
+void snc_tc2_irq_cb(void *arg)
+{
+ uint32_t *tmp;
+
+ tmp = (uint32_t *)arg;
+ if (tmp) {
+ *tmp += 1;
+ }
+}
+
+TEST_CASE(da1469x_snc_test_case_2)
+{
+ int rc;
+
+ MODLOG_INFO(LOG_MODULE_TEST, "DA1469x snc test 2");
+
+ /* Configure the SNC (base address and divider) */
+ rc = da1469x_snc_config(&snc_prog_test_case2, SNC_CLK_DIV_1);
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc config failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Initialize the SNC */
+ rc = da1469x_snc_sw_init();
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc init failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /*
+ * Register an interrupt routine. Pass it an argument as well. This
+ * argument points to a global counter that should get incremented once
+ */
+ da1469x_snc_irq_config(SNC_IRQ_MASK_HOST, snc_tc2_irq_cb, &g_snc_tc2_cntr);
+
+ /* Start the program */
+ da1469x_snc_sw_start();
+
+ /* This program should finish very quickly */
+ os_time_delay(OS_TICKS_PER_SEC / 10);
+ if (!da1469x_snc_program_is_done()) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test 2 failed (not done)");
+ da1469x_snc_sw_stop();
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Check that the counter got incremented */
+ if (g_snc_tc2_cntr != 1) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed tc2=%u", g_snc_tc2_cntr);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ da1469x_snc_sw_stop();
+ rc = da1469x_snc_sw_deinit();
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc s/w deinit failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test 2 success");
+}
+
+/*
+ * This test case enables only the PDC interrupt. Should not get a SNC
+ * interrupt to the M33 in this case
+ */
+TEST_CASE(da1469x_snc_test_case_3)
+{
+ int rc;
+
+ MODLOG_INFO(LOG_MODULE_TEST, "DA1469x snc test 3");
+
+ /* Configure the SNC (base address and divider) */
+ rc = da1469x_snc_config(&snc_prog_test_case2, SNC_CLK_DIV_1);
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc config failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Initialize the SNC */
+ rc = da1469x_snc_sw_init();
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc init failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /*
+ * Register an interrupt routine. Pass it an argument as well. This
+ * argument points to a global counter that should get incremented once
+ */
+ da1469x_snc_irq_config(SNC_IRQ_MASK_PDC, snc_tc2_irq_cb, &g_snc_tc2_cntr);
+
+ /* Start the program */
+ da1469x_snc_sw_start();
+
+ /* This program should finish very quickly */
+ os_time_delay(OS_TICKS_PER_SEC / 10);
+ if (!da1469x_snc_program_is_done()) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test 3 failed (not done)");
+ da1469x_snc_sw_stop();
+ TEST_ASSERT_FATAL(0);
+ }
+
+ /* Check that the counter got incremented */
+ if (g_snc_tc2_cntr != 1) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test failed tc2=%u", g_snc_tc2_cntr);
+ TEST_ASSERT_FATAL(0);
+ }
+
+ da1469x_snc_sw_stop();
+ rc = da1469x_snc_sw_deinit();
+ if (rc) {
+ MODLOG_INFO(LOG_MODULE_TEST, "snc s/w deinit failed");
+ TEST_ASSERT_FATAL(0);
+ }
+
+ MODLOG_INFO(LOG_MODULE_TEST, "snc test 3 success");
+}
+#endif
diff --git a/hw/mcu/dialog/da1469x/hosttest/syscfg.yml b/hw/mcu/dialog/da1469x/hosttest/syscfg.yml
new file mode 100644
index 0000000..d203e01
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/hosttest/syscfg.yml
@@ -0,0 +1,26 @@
+# 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.
+#
+
+syscfg.defs:
+ DA1469x_HOSTTEST_SYSINIT_STAGE:
+ description: The sysinit stage number for the da1469x hosttest package
+ value: 800
+
+ TESTBENCH_DA1469X_SNC:
+ description: Enables dialog SNC support in the testbench.
+ value: 0
diff --git a/hw/mcu/dialog/da1469x/include/mcu/da1469x_snc.h b/hw/mcu/dialog/da1469x/include/mcu/da1469x_snc.h
new file mode 100644
index 0000000..0ee27e5
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/include/mcu/da1469x_snc.h
@@ -0,0 +1,514 @@
+/*
+ * 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 __MCU_DA1469X_SNC_H_
+#define __MCU_DA1469X_SNC_H_
+
+#include <stdint.h>
+#include "mcu/mcu.h"
+#include "DA1469xAB.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The following two defintions are used by some instructions to determine if
+ * the address used in the instruction refers to a peripheral register location
+ * or is an address in system RAM.
+ */
+#define SNC_PERIPH_ADDR (0x50000000)
+#define SNC_SYSRAM_ADDR (MCU_MEM_SYSRAM_START_ADDRESS)
+#define SNC_REG_MASK (1 << 19)
+#define SNC_OP_IS_REG(op) ((((uint32_t)op) & SNC_PERIPH_ADDR) ? SNC_REG_MASK : 0)
+#define SNC_ADDR(addr) (((uint32_t)addr) - SNC_SYSRAM_ADDR)
+#define SNC_REG(addr) (((uint32_t)addr) - SNC_PERIPH_ADDR)
+
+/* Proto for isr callback function (for M33) */
+typedef void (*snc_isr_cb_t)(void *arg);
+
+/*
+ * For certain commands which use direct or indirect addresses. A direct address
+ * specifies a memory location. An indirect address (a pointer) means that the
+ * address contains the address of the desired memory location.
+ *
+ * Please refer to the specific command to see if these definitions should be
+ * used for that command!
+ */
+#define SNC_ADDR_MODE_DIRECT (0)
+#define SNC_ADDR_MODE_INDIRECT (1)
+
+/*
+ * No operation instruction.
+ *
+ * There are no operands for this instruction.
+ *
+ * -----------------------
+ * | opcode (0) | N/C |
+ * -----------------------
+ * | 31 - 28 | 27 - 0 |
+ * -----------------------
+ */
+#define SNC_OPCODE_NOP (0) /* No operands */
+#define SNC_CMD_NOOP() (uint32_t)(SNC_OPCODE_NOP << 28)
+
+/*
+ * Store Contents
+ *
+ * Stores the contents of addr2 in addr1. Addr1 and/or Addr2 can be addresses
+ * or pointers and can reference either system RAM or a register
+ *
+ * am1: Addressing mode for addr1
+ * SNC_WADAD_AM1_INDIRECT: Indirect addressing mode.
+ * SNC_WADAD_AM1_DIRECT: Direct addressing mode
+ *
+ * am2: Addressing mode for addr2
+ * SNC_WADAD_AM2_INDIRECT: Indirect addressing mode.
+ * SNC_WADAD_AM2_DIRECT: Direct addressing mode
+ * ----------------------------------------------
+ * | opcode (1) | am1 | am2 | N/C | addr1 |
+ * ----------------------------------------------
+ * | 31 - 28 | 27 | 26 | 25 - 20 | 19 - 0 |
+ * ----------------------------------------------
+ *
+ * ----------
+ * | addr2 |
+ * ----------
+ * | 31 - 0 |
+ * ----------
+ *
+ * NOTE: The nomenclature used is addr2 first then addr1.
+ *
+ * Ex. RAM2RAM: addr2 and addr1 are both in system RAM.
+ * RAM2REG: addr2 is in system RAM and addr1 is in register space
+ * REG2RAM: addr2 is a register and addr1 is in system RAM.
+ */
+#define SNC_OPCODE_WADAD (1)
+#define SNC_CMD_WADAD_RAM2RAM(addr1, am1, am2, addr2) \
+ (uint32_t)((SNC_OPCODE_WADAD << 28) + (am1 << 27) + (am2 << 26) + \
+ SNC_ADDR(addr1)), \
+ (uint32_t)(SNC_ADDR(addr2))
+#define SNC_CMD_WADAD_RAM2REG(addr1, am1, am2, addr2) \
+ (uint32_t)((SNC_OPCODE_WADAD << 28) + (am1 << 27) + (am2 << 26) + \
+ SNC_REG_MASK + SNC_REG(addr1)), \
+ (uint32_t)(SNC_ADDR(addr2))
+#define SNC_CMD_WADAD_REG2RAM(addr1, am1, am2, addr2) \
+ (uint32_t)((SNC_OPCODE_WADAD << 28) + (am1 << 27) + (am2 << 26) + \
+ SNC_ADDR(addr1)), \
+ (uint32_t)(SNC_REG_MASK + SNC_REG(addr2))
+#define SNC_CMD_WADAD_REG2REG(addr1, am1, am2, addr2) \
+ (uint32_t)((SNC_OPCODE_WADAD << 28) + (am1 << 27) + (am2 << 26) + \
+ SNC_REG_MASK + SNC_REG(addr1)), \
+ (uint32_t)(SNC_REG_MASK + SNC_REG(addr2))
+
+#define SNC_WADAD_AM1_INDIRECT (0)
+#define SNC_WADAD_AM1_DIRECT (1)
+#define SNC_WADAD_AM2_DIRECT (0)
+#define SNC_WADAD_AM2_INDIRECT (1)
+
+/*
+ * Store Value
+ *
+ * Stores immediate value (32-bits) in either addr (direct) or the address
+ * pointed to by addr (indirect)
+ *
+ * addr_mode:
+ * SNC_WADVA_AM_IND: Indirect address Ex. *addr = value
+ * SNC_WADVA_AM_DIR: Direct address mode Ex. addr = value
+ *
+ * ----------------------------------------------
+ * | opcode (2) | addr_mode | N/C | addr |
+ * ----------------------------------------------
+ * | 31 - 28 | 27 | 26 - 20 | 19 - 0 |
+ * ----------------------------------------------
+ *
+ * ----------
+ * | value |
+ * ----------
+ * | 31 - 0 |
+ * ----------
+ */
+#define SNC_OPCODE_WADVA (2)
+#define SNC_CMD_WADVA_REG(addr, addr_mode, value) \
+ (uint32_t)((SNC_OPCODE_WADVA << 28) + (addr_mode << 27) + \
+ SNC_REG_MASK + SNC_REG(addr)), \
+ (uint32_t)(value)
+
+#define SNC_CMD_WADVA_RAM(addr, addr_mode, value) \
+ (uint32_t)((SNC_OPCODE_WADVA << 28) + (addr_mode << 27) + \
+ SNC_ADDR(addr)), \
+ (uint32_t)(value)
+
+#define SNC_WADVA_AM_IND (0)
+#define SNC_WADVA_AM_DIR (1)
+
+#define SNC_CMD_WADVA_IND_RAM(addr, val) \
+ SNC_CMD_WADVA_RAM(addr, SNC_WADVA_AM_IND, val)
+#define SNC_CMD_WADVA_IND_REG(addr, val) \
+ SNC_CMD_WADVA_REG(addr, SNC_WADVA_AM_IND, val)
+#define SNC_CMD_WADVA_DIR_RAM(addr, val) \
+ SNC_CMD_WADVA_RAM(addr, SNC_WADVA_AM_DIR, val)
+#define SNC_CMD_WADVA_DIR_REG(addr, val) \
+ SNC_CMD_WADVA_REG(addr, SNC_WADVA_AM_DIR, val)
+
+/*
+ * XOR
+ *
+ * Performs an XOR operation with the contents of addr and mask; stores contents
+ * in addr. Note that addr can be a register or RAM address,
+ *
+ * Ex: x = x ^ mask
+ *
+ * -------------------------
+ * | opcode (3) | addr |
+ * -------------------------
+ * | 31 - 28 | 19 - 0 |
+ * -------------------------
+ *
+ * ----------
+ * | mask |
+ * ----------
+ * | 31 - 0 |
+ * ----------
+ */
+#define SNC_OPCODE_TOBRE (3)
+#define SNC_CMD_TOBRE_RAM(addr, mask) \
+ (uint32_t)((SNC_OPCODE_TOBRE << 28) + SNC_ADDR(addr)), \
+ (uint32_t)(mask)
+#define SNC_CMD_TOBRE_REG(addr, mask) \
+ (uint32_t)((SNC_OPCODE_TOBRE << 28) + SNC_REG_MASK + SNC_REG(addr)), \
+ (uint32_t)(mask)
+
+/*
+ * Compare Bit in Address
+ *
+ * Compares the contents of addr and sets the EQUALHIGH_FLAG if the bit at
+ * position 'bitpos' is set to 1. NOTE: addr can be either RAM address
+ * or a register. Note that bitpos is a bit position (0 to 31).
+ *
+ * Ex: if (addr & (1 << bitpos)) {
+ * EQUALHIGH_FLAG = 1;
+ * } else {
+ * EQUALHIGH_FLAG = 0;
+ * }
+ *
+ * --------------------------------------------
+ * | opcode (4) | bitpos | N/C | addr |
+ * --------------------------------------------
+ * | 31 - 28 | 27 - 23 | 22 - 20 | 19 - 0 |
+ * --------------------------------------------
+ */
+#define SNC_OPCODE_RDCBI (4)
+#define SNC_CMD_RDCBI_REG(addr, bitpos) \
+ (uint32_t)((SNC_OPCODE_RDCBI << 28) + ((bitpos & 0x1F) << 23) + \
+ SNC_REG_MASK + SNC_REG(addr))
+#define SNC_CMD_RDCBI_RAM(addr, bitpos) \
+ (uint32_t)((SNC_OPCODE_RDCBI << 28) + ((bitpos & 0x1F) << 23) + \
+ SNC_ADDR(addr))
+
+/*
+ * Compare Address Contents
+ *
+ * Compares the contents of addr1 and addr2 and sets the GREATERVAL_FLAG if the
+ * contents of addr1 are greater than the contents of addr2. Note that addr1
+ * and addr2 can be either RAM addresses or a register.
+ *
+ * ---------------------------------
+ * | opcode (5) | N/C | addr1 |
+ * ---------------------------------
+ * | 31 - 28 | 27 - 20 | 19 - 0 |
+ * ---------------------------------
+ *
+ * --------------------
+ * | N/C | addr2 |
+ * --------------------
+ * | 31 - 20 | 19 - 0 |
+ * --------------------
+ *
+ * NOTE: the nomenclature here is addr1 first, then addr2
+ * EX: RAMRAM: both addr1 and addr2 are in system RAM
+ * RAMREG: addr1 is in system RAM, addr2 is a register
+ * REGRAM: addr1 is a register, addr2 is in system RAM
+ * REGREG: both addr1 and addr2 are registers
+ */
+#define SNC_OPCODE_RDCGR (5)
+#define SNC_CMD_RDCGR_RAMRAM(addr1, addr2) \
+ (uint32_t)((SNC_OPCODE_RDCGR << 28) + SNC_ADDR(addr1)), \
+ (uint32_t)(SNC_ADDR(addr2))
+#define SNC_CMD_RDCGR_RAMREG(addr1, addr2) \
+ (uint32_t)((SNC_OPCODE_RDCGR << 28) + SNC_ADDR(addr1)), \
+ (uint32_t)(SNC_REG_MASK + SNC_REG(addr2))
+#define SNC_CMD_RDCGR_REGRAM(addr1, addr2) \
+ (uint32_t)((SNC_OPCODE_RDCGR << 28) + SNC_REG_MASK + SNC_REG(addr1)), \
+ (uint32_t)(SNC_ADDR(addr2))
+#define SNC_CMD_RDCGR_REGREG(addr1, addr2) \
+ (uint32_t)((SNC_OPCODE_RDCGR << 28) + SNC_REG_MASK + SNC_REG(addr1)), \
+ (uint32_t)(SNC_REG_MASK + SNC_REG(addr2))
+
+/*
+ * Conditional branch instruction
+ *
+ * Perform a conditional branch to a direct or indirect memory
+ * address (RAM). There are three types of branches:
+ *
+ * EQUALHIGH_FLAG: branch if flag is true. (direct or indirect)
+ * 0x0A => branch to direct address
+ * 0x1A => branch to indirect address
+ * GREATERVAL_FLAG: branch if flag is true. (direct or indirect)
+ * 0x05 => branch to direct address
+ * 0x15 => branch to indirect address
+ * LOOP: perform branch up to 128 times. (direct only)
+ * 0b1yyyyyyy where yyyyyyy is loop count.
+ *
+ * ----------------------------------------
+ * | opcode (6) | flags | N/C | ADDR |
+ * ----------------------------------------
+ * | 31 - 28 | 27 - 20 | 19 | 18 - 0 |
+ * ----------------------------------------
+ *
+ * addr: Either a direct address (specifies an address in RAM) or an indirect
+ * memory address (addr contains the RAM address to branch to).
+ * loops: Number of times to loop (max 127).
+ */
+#define SNC_OPCODE_COBR (6)
+#define SNC_CMD_COBR_EQ_DIR(addr) \
+ (uint32_t)((SNC_OPCODE_COBR << 28) + (0x0A << 20) + SNC_ADDR(addr))
+#define SNC_CMD_COBR_EQ_IND(addr) \
+ (uint32_t)((SNC_OPCODE_COBR << 28) + (0x1A << 20) + SNC_ADDR(addr))
+#define SNC_CMD_COBR_GT_DIR(addr) \
+ (uint32_t)((SNC_OPCODE_COBR << 28) + (0x05 << 20) + SNC_ADDR(addr))
+#define SNC_CMD_COBR_GT_IND(addr) \
+ (uint32_t)((SNC_OPCODE_COBR << 28) + (0x15 << 20) + SNC_ADDR(addr))
+#define SNC_CMD_COBR_LOOP(addr, loops) \
+ (uint32_t)((SNC_OPCODE_COBR << 28) + ((0x80 + (loops & 0x7f)) << 20) + \
+ SNC_ADDR(addr))
+
+/*
+ * Increment instruction
+ *
+ * Increments the contents of a memory address (RAM address) by
+ * either 1 or 4.
+ *
+ * INC bit value of 0: increment by 1
+ * INC bit value of 1: increment by 4
+ *
+ * -----------------------------------
+ * | opcode (7) | N/C | INC | ADDR |
+ * -----------------------------------
+ * | 31 - 28 | 27-20 | 19 | 18-0 |
+ * -----------------------------------
+ */
+#define SNC_OPCODE_INC (7)
+#define SNC_CMD_INC(addr, inc_by_4) \
+ (uint32_t)((SNC_OPCODE_INC << 28) + (inc_by_4 << 19) + SNC_ADDR(addr))
+#define SNC_CMD_INC_BY_1(addr) SNC_CMD_INC(addr, 0)
+#define SNC_CMD_INC_BY_4(addr) SNC_CMD_INC(addr, 1)
+
+/*
+ * Delay Instruction
+ *
+ * Delay for up to 255 LP clock ticks.
+ *
+ * -------------------------------
+ * | opcode (8) | N/C | Delay |
+ * -------------------------------
+ * | 31 - 28 | 27 - 8 | 7 - 0 |
+ * -------------------------------
+ */
+#define SNC_OPCODE_DEL (8)
+#define SNC_CMD_DEL(ticks) (uint32_t)((SNC_OPCODE_DEL << 28) | (ticks & 0xff))
+
+/*
+ * Sleep instruction
+ *
+ * This instruction is used to halt program execution. Will
+ * generate a signal pulse to PDC and power down the
+ * sensor node controller.
+ *
+ * There are no operands for this instruction.
+ *
+ * -----------------------
+ * | opcode (9) | N/C |
+ * -----------------------
+ * | 31 - 28 | 27 - 0 |
+ * -----------------------
+ */
+#define SNC_OPCODE_SLP (9) /* No operands */
+#define SNC_CMD_SLEEP() (uint32_t)(SNC_OPCODE_SLP << 28)
+
+/*
+ * API NOTES:
+ *
+ * 1) The SNC API are not protected by critical sections. If any of these
+ * API are called by more than one task or inside an ISR they need to be
+ * protected.
+ *
+ * 2) API with _sw_ are intended to be used when the host processor has control
+ * of the SNC (as opposed to the PDC). Typically these API are for debugging as
+ * the PDC usually controls the SNC.
+ */
+
+/**
+ * da1469x snc sw init
+ *
+ * initialize the SNC for software control
+ *
+ * Called when the host processor wants control of the SNC (PDC
+ * no longer controls SNC). The SNC must be stopped or this function will return
+ * an error.
+ *
+ * NOTE: this function will acquire the COM power domain.
+ *
+ * @return int 0: success, -1: error (SNC not currently stopped).
+ */
+int da1469x_snc_sw_init(void);
+
+/**
+ * da1469x snc sw deinit
+ *
+ * Takes the SNC out of software control. The SNC must be
+ * stopped and in software control or an error will be returned
+ *
+ * NOTE: this function releases the COM power domain when
+ * called.
+ *
+ * @return int 0: success, -1: error
+ */
+int da1469x_snc_sw_deinit(void);
+
+/**
+ * da1469x snc sw start
+ *
+ * Starts the SNC. Note that the user should have called
+ * snc_sw_load prior to starting the SNC via software control.
+ *
+ * @return int 0: success -1: error
+ */
+int da1469x_snc_sw_start(void);
+
+/**
+ * da1469x snc sw stop
+ *
+ * Stops the SNC from running a program. This should only be
+ * called when the SNC is under software control.
+ *
+ * @return int 0: success -1: error
+ */
+int da1469x_snc_sw_stop(void);
+
+/**
+ * da1469x snc program is done
+ *
+ * Checks if the SNC program has finished
+ *
+ * @return int 0: not finished 1: finished
+ */
+int da1469x_snc_program_is_done(void);
+
+/**
+ * da1469x snc irq config
+ *
+ * Configures the SNC to interrupt the host processor and/or PDC
+ * when SNC generates an interrupt.
+ *
+ * @param mask One or more of the following:
+ * SNC_IRQ_MASK_NONE: Do not interrupt host or PDC
+ * SNC_IRQ_MASK_HOST: Interrupt host processor (CM33)
+ * SNC_IRQ_MASK_PDC: Interrupt PDC
+ * @param isr_cb Callback function for M33 irq handler. Can
+ * be NULL.
+ * @param isr_arg Argument to isr callback function.
+ *
+ * @return int 0: success -1: invalid mask parameter
+ *
+ * NOTES:
+ *
+ * 1) The IRQ configuration cannot be changed if there is a
+ * pending IRQ. The IRQ must be cleared in that case. This
+ * function will automatically clear the IRQ if that is the case
+ * and will not report an error.
+ */
+int da1469x_snc_irq_config(uint8_t mask, snc_isr_cb_t isr_cb, void *arg);
+
+#define SNC_IRQ_MASK_NONE (0x00) /* Do not interrupt host or PDC */
+#define SNC_IRQ_MASK_HOST (0x01) /* Interrupt host processor (CM33) */
+#define SNC_IRQ_MASK_PDC (0x02) /* Interrupt PDC */
+
+/**
+ * da1469x snc irq clear
+ *
+ * Clears the IRQ from the SNC to the PDC and/or Host processor.
+ */
+static inline void
+da1469x_snc_irq_clear(void)
+{
+ SNC->SNC_CTRL_REG |= SNC_SNC_CTRL_REG_SNC_IRQ_ACK_Msk;
+}
+
+/**
+ * da1469x snc error status
+ *
+ * Returns error status for the SNC
+ *
+ * @return uint8_t Error status.
+ * Returns one or more of the following errors:
+ * SNC_BUS_ERROR: Bus Fault error (invalid memory access)
+ * SNC_HARD_FAULT_ERROR: Hard Fault error (invalid
+ * instruction)
+ */
+uint8_t da1469x_snc_error_status(void);
+
+#define SNC_BUS_ERROR (0x01)
+#define SNC_HARD_FAULT_ERROR (0x02)
+
+static inline void
+da1469x_snc_enable_bus_err_detect(void)
+{
+ SNC->SNC_CTRL_REG |= SNC_SNC_CTRL_REG_BUS_ERROR_DETECT_EN_Msk;
+}
+
+/**
+ * da1469x snc config
+ *
+ * Configures the starting program address of the SNC in the
+ * memory controller and sets SNC clock divider.
+ *
+ * @param prog_addr This is the starting address in system RAM
+ * of program
+ *
+ * @param clk_div Clock divider. One of the following:
+ * SNC_CLK_DIV_1: Divide low power clock by 1
+ * SNC_CLK_DIV_2: Divide low power clock by 2
+ * SNC_CLK_DIV_4: Divide low power clock by 4
+ * SNC_CLK_DIV_8: Divide low power clock by 8
+ *
+ * @return int 0: success, -1 otherwise.
+ */
+int da1469x_snc_config(void *prog_addr, int clk_div);
+
+#define SNC_CLK_DIV_1 (0)
+#define SNC_CLK_DIV_2 (1)
+#define SNC_CLK_DIV_4 (2)
+#define SNC_CLK_DIV_8 (3)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MCU_DA1469X_SNC_H_ */
diff --git a/hw/mcu/dialog/da1469x/src/da1469x_snc.c b/hw/mcu/dialog/da1469x/src/da1469x_snc.c
new file mode 100644
index 0000000..01b8c34
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/src/da1469x_snc.c
@@ -0,0 +1,212 @@
+/*
+ * 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 <assert.h>
+#include "os/os_trace_api.h"
+#include "mcu/da1469x_snc.h"
+#include "mcu/da1469x_pd.h"
+
+/* IRQ callback for M33 and argument */
+snc_isr_cb_t g_snc_isr_cb_func;
+void *g_snc_isr_arg;
+
+static void
+da1469x_snc_irq_handler(void)
+{
+ os_trace_isr_enter();
+ da1469x_snc_irq_clear();
+ if (g_snc_isr_cb_func) {
+ g_snc_isr_cb_func(g_snc_isr_arg);
+ }
+ os_trace_isr_exit();
+}
+
+int
+da1469x_snc_sw_init(void)
+{
+ /* SNC better be stopped! */
+ if ((SNC->SNC_STATUS_REG & SNC_SNC_STATUS_REG_SNC_IS_STOPPED_Msk) == 0) {
+ return -1;
+ }
+
+ /* First, just put it S/W control. */
+ SNC->SNC_CTRL_REG = SNC_SNC_CTRL_REG_SNC_SW_CTRL_Msk;
+
+
+ /* We will be using the COM power domain so acquire it here */
+ da1469x_pd_acquire(MCU_PD_DOMAIN_COM);
+
+ /* Reset the SNC (keep in SW ctrl as well) */
+ SNC->SNC_CTRL_REG = SNC_SNC_CTRL_REG_SNC_SW_CTRL_Msk |
+ SNC_SNC_CTRL_REG_SNC_RESET_Msk;
+
+ /*
+ * Program the following in control register
+ * SNC_SW_CTRL: Puts SNC in software control (PDC does not use SNC).
+ * IRQ_ACK: set just in case to clear any interrupts.
+ * BRANCH_LOOP_INIT: set to clear loop counter.
+ * BUS_ERROR_DETECT: set to enable bus error detection.
+ */
+ SNC->SNC_CTRL_REG = SNC_SNC_CTRL_REG_SNC_SW_CTRL_Msk |
+ SNC_SNC_CTRL_REG_SNC_BRANCH_LOOP_INIT_Msk |
+ SNC_SNC_CTRL_REG_BUS_ERROR_DETECT_EN_Msk |
+ SNC_SNC_CTRL_REG_SNC_IRQ_ACK_Msk;
+ return 0;
+}
+
+int
+da1469x_snc_sw_deinit(void)
+{
+ /* SNC better be in SW control! */
+ if ((SNC->SNC_CTRL_REG & SNC_SNC_CTRL_REG_SNC_SW_CTRL_Msk) == 0) {
+ return -1;
+ }
+
+ /* SNC better be stopped! */
+ if ((SNC->SNC_STATUS_REG & SNC_SNC_STATUS_REG_SNC_IS_STOPPED_Msk) == 0) {
+ return -1;
+ }
+
+ /* Take out of SW control */
+ SNC->SNC_CTRL_REG &= ~SNC_SNC_CTRL_REG_SNC_SW_CTRL_Msk;
+
+ /* Release COM power domain */
+ da1469x_pd_release(MCU_PD_DOMAIN_COM);
+
+ return 0;
+}
+
+int
+da1469x_snc_sw_start(void)
+{
+ /* XXX: Should we check if already running and return error if not? */
+ SNC->SNC_CTRL_REG |= SNC_SNC_CTRL_REG_SNC_EN_Msk;
+ return 0;
+}
+
+int
+da1469x_snc_sw_stop(void)
+{
+ /* XXX: Should we check if in S/W control and return error if not? */
+ SNC->SNC_CTRL_REG &= ~SNC_SNC_CTRL_REG_SNC_EN_Msk;
+ return 0;
+}
+
+int
+da1469x_snc_program_is_done(void)
+{
+ int rc;
+ uint32_t status;
+
+ status = SNC->SNC_STATUS_REG & SNC_SNC_STATUS_REG_SNC_DONE_STATUS_Msk;
+ if (status) {
+ rc = 1;
+ } else {
+ rc = 0;
+ }
+ return rc;
+}
+
+uint8_t
+da1469x_snc_error_status(void)
+{
+ uint8_t err;
+ uint32_t status;
+
+ err = 0;
+ status = SNC->SNC_STATUS_REG;
+ if (status & SNC_SNC_STATUS_REG_BUS_ERROR_STATUS_Msk) {
+ err |= SNC_BUS_ERROR;
+ }
+ if (status & SNC_SNC_STATUS_REG_HARD_FAULT_STATUS_Msk) {
+ err |= SNC_HARD_FAULT_ERROR;
+ }
+
+ return err;
+}
+
+int
+da1469x_snc_irq_config(uint8_t mask, snc_isr_cb_t isr_cb, void *arg)
+{
+ int rc;
+ uint32_t irqs;
+
+ NVIC_DisableIRQ(SNC_IRQn);
+ NVIC_SetVector(SNC_IRQn, (uint32_t)da1469x_snc_irq_handler);
+
+ /* Clear the bits first... */
+ SNC->SNC_CTRL_REG &= ~SNC_SNC_CTRL_REG_SNC_IRQ_CONFIG_Msk;
+
+ rc = 0;
+ if (SNC->SNC_STATUS_REG & SNC_SNC_CTRL_REG_SNC_IRQ_EN_Msk) {
+ da1469x_snc_irq_clear();
+ }
+
+ if (mask != SNC_IRQ_MASK_NONE) {
+ if (mask > (SNC_IRQ_MASK_HOST | SNC_IRQ_MASK_PDC)) {
+ rc = -1;
+ } else {
+ irqs = 0;
+ if (mask & SNC_IRQ_MASK_HOST) {
+ irqs |= (1 << 6);
+ g_snc_isr_arg = arg;
+ g_snc_isr_cb_func = isr_cb;
+ NVIC_EnableIRQ(SNC_IRQn);
+ }
+ if (mask & SNC_IRQ_MASK_PDC) {
+ irqs |= (1 << 7);
+ }
+ SNC->SNC_CTRL_REG |= irqs;
+ }
+ }
+
+ return rc;
+}
+
+int
+da1469x_snc_config(void *prog_addr, int clk_div)
+{
+ uint32_t offset;
+
+ /* Do some basic checks to make sure it is OK */
+ offset = (uint32_t)prog_addr;
+ if ((offset & 0x3) || (offset < MCU_MEM_SYSRAM_START_ADDRESS)) {
+ return -1;
+ }
+
+ /*
+ * Program the SNC base address register. This is where the device
+ * will execute code.
+ *
+ * XXX: can probably just write the entire address without mask
+ * but just in case mask it.
+ */
+ MEMCTRL->SNC_BASE_REG = offset &
+ MEMCTRL_SNC_BASE_REG_SNC_BASE_ADDRESS_Msk;
+
+ /* Only two bits for clock divider */
+ if (clk_div > 3) {
+ return -1;
+ }
+
+ CRG_COM->CLK_COM_REG &= ~(clk_div << CRG_COM_CLK_COM_REG_SNC_DIV_Pos);
+ CRG_COM->CLK_COM_REG |= (clk_div << CRG_COM_CLK_COM_REG_SNC_DIV_Pos);
+
+ return 0;
+}