You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by an...@apache.org on 2019/10/18 18:09:48 UTC

[mynewt-core] 01/02: hw/mcu/da1469x: Add support to use trim values from OTP

This is an automated email from the ASF dual-hosted git repository.

andk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 08e102c0eacb8c66a5a17bf4cc987f08e79aaa2c
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Thu Sep 12 18:15:22 2019 +0200

    hw/mcu/da1469x: Add support to use trim values from OTP
---
 hw/mcu/dialog/da14699/include/mcu/mcu.h           |   3 +
 hw/mcu/dialog/da1469x/include/mcu/da1469x_trimv.h |  40 ++++++
 hw/mcu/dialog/da1469x/src/da1469x_trimv.c         | 147 ++++++++++++++++++++++
 3 files changed, 190 insertions(+)

diff --git a/hw/mcu/dialog/da14699/include/mcu/mcu.h b/hw/mcu/dialog/da14699/include/mcu/mcu.h
index 3114bfb..6a1fdea 100644
--- a/hw/mcu/dialog/da14699/include/mcu/mcu.h
+++ b/hw/mcu/dialog/da14699/include/mcu/mcu.h
@@ -153,6 +153,9 @@ void mcu_gpio_exit_sleep(void);
 #define MCU_OTPM_BASE 0x10080000UL
 #define MCU_OTPM_SIZE 4096
 
+/* Largest group id seen on a DA14699 was 18 so far */
+#define MCU_TRIMV_GROUP_ID_MAX          (18)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/hw/mcu/dialog/da1469x/include/mcu/da1469x_trimv.h b/hw/mcu/dialog/da1469x/include/mcu/da1469x_trimv.h
new file mode 100644
index 0000000..b65d84b
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/include/mcu/da1469x_trimv.h
@@ -0,0 +1,40 @@
+/*
+ * 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_TRIMV_H_
+#define __MCU_DA1469X_TRIMV_H_
+
+#include <stdint.h>
+#include "mcu/mcu.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void da1469x_trimv_init_from_otp(void);
+
+uint8_t da1469x_trimv_group_num_words_get(uint8_t group);
+
+uint8_t da1469x_trimv_group_read(uint8_t group, uint32_t *buf, uint8_t length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MCU_DA1469X_TRIMV_H_ */
diff --git a/hw/mcu/dialog/da1469x/src/da1469x_trimv.c b/hw/mcu/dialog/da1469x/src/da1469x_trimv.c
new file mode 100644
index 0000000..b676784
--- /dev/null
+++ b/hw/mcu/dialog/da1469x/src/da1469x_trimv.c
@@ -0,0 +1,147 @@
+/*
+ * 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 <string.h>
+#include "mcu/da1469x_otp.h"
+#include "mcu/da1469x_trimv.h"
+#include "mcu/mcu.h"
+#include "os/os.h"
+
+#if MCU_TRIMV_GROUP_ID_MAX
+#define GROUP_ID_MAX            (MCU_TRIMV_GROUP_ID_MAX)
+#else
+#define GROUP_ID_MAX            (0)
+#endif
+
+#ifndef MCU_OTPM_CS_OFFSET
+#define MCU_OTPM_CS_OFFSET      (0x0c00)
+#endif
+#ifndef MCU_OTPM_CS_LENGTH
+#define MCU_OTPM_CS_LENGTH      (0x0400)
+#endif
+
+#define CS_ADDRESS              ((MCU_OTPM_BASE) + (MCU_OTPM_CS_OFFSET))
+#define CS_LENGTH               (MCU_OTPM_CS_LENGTH)
+
+#define CS_WORD_START           0xa5a5a5a5
+#define CS_WORD_END             0x00000000
+#define CS_WORD_INVALID         0xffffffff
+#define CS_WORD_TYPE_MASK       0xf0000000
+#define CS_WORD_TYPE_BOOTER     0x60000000
+#define CS_WORD_TYPE_TRIM       0x90000000
+
+struct da1469x_trimv_group {
+    uint8_t index;
+    uint8_t num_words;
+};
+
+static struct da1469x_trimv_group g_mcu_trimv_groups[GROUP_ID_MAX + 1];
+
+void
+da1469x_trimv_init_from_otp(void)
+{
+    uint32_t oaddr_start;
+    uint32_t oaddr_end;
+    uint32_t oaddr;
+    uint32_t ow;
+    uint8_t trimv_group;
+    uint8_t trimv_num_words;
+
+    /* Clear groups if anything was previously loaded */
+    memset(&g_mcu_trimv_groups, 0, sizeof(g_mcu_trimv_groups));
+
+    /* Start of configuration script */
+    oaddr_start = CS_ADDRESS;
+    oaddr_end = CS_ADDRESS + CS_LENGTH;
+    oaddr = oaddr_start;
+
+    da1469x_otp_read(oaddr, &ow, sizeof(ow));
+    if (ow != CS_WORD_START) {
+        return;
+    }
+
+    oaddr += 4;
+
+    while (oaddr < oaddr_end) {
+        da1469x_otp_read(oaddr, &ow, sizeof(ow));
+
+        oaddr += 4;
+
+        if ((ow == CS_WORD_END) || (ow == CS_WORD_INVALID)) {
+            /* End of CS or empty word */
+            break;
+        } else if ((ow & CS_WORD_TYPE_MASK) < CS_WORD_TYPE_BOOTER) {
+            /* This is a register+value configuration, skip one more word */
+            oaddr += 4;
+        } else if ((ow & CS_WORD_TYPE_MASK) == CS_WORD_TYPE_TRIM) {
+            trimv_num_words = (ow & 0x0000ff00) >> 8;
+            trimv_group = ow & 0x000000ff;
+
+            if (trimv_group <= GROUP_ID_MAX) {
+                /*
+                 * XXX not sure if each group can be present only once in OTP,
+                 *     but our implementation requires it for now and it works
+                 */
+                assert(g_mcu_trimv_groups[trimv_group].num_words == 0);
+
+                g_mcu_trimv_groups[trimv_group].index = (oaddr - oaddr_start) / 4;
+                g_mcu_trimv_groups[trimv_group].num_words = trimv_num_words;
+            }
+
+            oaddr += trimv_num_words * 4;
+        }
+    }
+}
+
+uint8_t
+da1469x_trimv_group_num_words_get(uint8_t group)
+{
+    struct da1469x_trimv_group *grp = &g_mcu_trimv_groups[group];
+
+    if (group > GROUP_ID_MAX) {
+        return 0;
+    }
+
+    return grp->num_words;
+}
+
+uint8_t
+da1469x_trimv_group_read(uint8_t group, uint32_t *buf, uint8_t num_words)
+{
+    struct da1469x_trimv_group *grp = &g_mcu_trimv_groups[group];
+    uint32_t oaddr;
+    int rc;
+
+    /* Silence warning if built without asserts */
+    (void)rc;
+
+    num_words = min(num_words, da1469x_trimv_group_num_words_get(group));
+
+    if (!num_words) {
+        return 0;
+    }
+
+    oaddr = CS_ADDRESS + grp->index * 4;
+
+    rc = da1469x_otp_read(oaddr, buf, num_words * 4);
+    assert(rc == 0);
+
+    return num_words;
+}