summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/drivers/dialog_cmac')
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/README.md68
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/include/ble/xcvr.h39
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/pkg.yml33
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw.c340
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw_priv.h29
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_phy.c1798
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf.c747
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf_priv.h38
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/syscfg.yml29
9 files changed, 3121 insertions, 0 deletions
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/README.md b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/README.md
new file mode 100644
index 00000000..2e76e2c1
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/README.md
@@ -0,0 +1,68 @@
+<!--
+#
+# 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.
+#
+-->
+
+## How to run NimBLE controller on Dialog DA1469x
+
+Dialog DA1469x has separate Cortex-M0+ core inside CMAC hw block which can run
+NimBLE controller. This means DA1469x can run full NimBLE stack: host is running
+on M33 core while controller is running on M0+ core. Both communicate using
+standard HCI H4 protocol exchanged over mailboxes located in shared memory.
+
+### Basic setup
+
+In order to run full NimBLE stack on DA1469x you will need two newt targets: one
+for M33 (e.g. `dialog_da1469x-dk-pro` BSP) and one for M0+ (`dialog_cmac` BSP).
+
+Once everything is configured properly, you only need to build target for M33.
+Target configured for M0+ will be build automatically and image is linked with
+M33 image so everything can be flashed at once just as if there is only single
+target used.
+
+Target for M33 should be set and configured as any other BLE application. In
+order to use NimBLE controller on CMAC, set proper HCI transport via syscfg:
+
+ BLE_HCI_TRANSPORT: dialog_cmac
+
+This will include proper transport, driver and add M0+ target to build process.
+
+For M0+, there is sample target provided in `targets/dialog_cmac` and it's used
+by default unless overrided by syscfg in M33 target:
+
+ CMAC_IMAGE_TARGET_NAME: "@apache-mynewt-nimble/targets/dialog_cmac"
+
+If you wish to create own target for M0+, make sure your target is set the same
+way (`app`, `bsp` and `build_profile`) as sample. Also it is recommended to use
+syscfg settings from sample target in new target.
+
+### NimBLE configuration
+
+Since host and controller are running on different cores, they both use separate
+configuration: host configuration is in M33 target, controller configuration is
+in M0+ target. There is currently no way to automatically synchronize both, so
+care needs to be taken when enabling features in either of targets.
+
+A possible workaround is to use separate `.yml` file with all the NimBLE syscfg
+values settings and include it in both targets using `$import` directive which
+is supported by recent versions of `newt` tool.
+
+### Advanced settings
+
+(tbd)
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/include/ble/xcvr.h b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/include/ble/xcvr.h
new file mode 100644
index 00000000..e4e741c5
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/include/ble/xcvr.h
@@ -0,0 +1,39 @@
+/*
+ * 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 H_BLE_XCVR_
+#define H_BLE_XCVR_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XCVR_TX_SCHED_DELAY_USECS (250)
+
+/*
+ * Define HW whitelist size. This is the total possible whitelist size;
+ * not necessarily the size that will be used (may be smaller)
+ */
+#define BLE_HW_WHITE_LIST_SIZE (8)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* H_BLE_XCVR_ */
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/pkg.yml b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/pkg.yml
new file mode 100644
index 00000000..9cf63ffc
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/pkg.yml
@@ -0,0 +1,33 @@
+#
+# 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: nimble/drivers/dialog_cmac
+pkg.description: BLE driver for Dialog CMAC
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+pkg.deps:
+ - "@apache-mynewt-nimble/nimble/controller"
+ - "@apache-mynewt-core/crypto/tinycrypt"
+pkg.apis:
+ - ble_driver
+pkg.req_apis:
+ - ble_transport
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw.c b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw.c
new file mode 100644
index 00000000..98c8144b
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw.c
@@ -0,0 +1,340 @@
+/*
+ * 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 <stdint.h>
+#include "mcu/mcu.h"
+#include "nimble/ble.h"
+#include "controller/ble_hw.h"
+#include "CMAC.h"
+#include "cmac_driver/cmac_shared.h"
+#include "mcu/mcu.h"
+#include "tinycrypt/aes.h"
+
+static struct tc_aes_key_sched_struct g_ctx;
+
+int
+ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
+{
+ cmac_rand_set_isr_cb(cb);
+ return 0;
+}
+
+int
+ble_hw_rng_start(void)
+{
+ /* Chime the M33 in case we need random numbers generated */
+ cmac_rand_start();
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CMAC2SYS_IRQ_SET_Msk;
+ return 0;
+}
+
+int
+ble_hw_rng_stop(void)
+{
+ cmac_rand_stop();
+ return 0;
+}
+
+#define BLE_HW_RESOLV_LIST_SIZE (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
+
+struct ble_hw_resolv_irk {
+ uint32_t key[4];
+};
+
+struct ble_hw_resolv_list {
+ uint8_t count;
+ struct ble_hw_resolv_irk irk[BLE_HW_RESOLV_LIST_SIZE];
+};
+
+struct ble_hw_resolv_proc {
+ uint32_t hash;
+ uint8_t f_configured;
+ uint8_t f_active;
+ uint8_t f_match;
+ uint8_t f_done;
+ struct ble_hw_resolv_irk *irk;
+ struct ble_hw_resolv_irk *irk_end;
+ uint32_t crypto_prand_in[4];
+ uint32_t crypto_e_out[4];
+};
+
+static struct ble_hw_resolv_list g_ble_hw_resolv_list;
+static struct ble_hw_resolv_proc g_ble_hw_resolv_proc;
+
+int
+ble_hw_get_public_addr(ble_addr_t *addr)
+{
+ return -1;
+}
+
+int
+ble_hw_get_static_addr(ble_addr_t *addr)
+{
+ return -1;
+}
+
+void
+ble_hw_whitelist_clear(void)
+{
+}
+
+int
+ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
+{
+ return 0;
+}
+
+void
+ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
+{
+}
+
+uint8_t
+ble_hw_whitelist_size(void)
+{
+ return 0;
+}
+
+void
+ble_hw_whitelist_enable(void)
+{
+}
+
+
+void
+ble_hw_whitelist_disable(void)
+{
+}
+
+int
+ble_hw_whitelist_match(void)
+{
+ return 0;
+}
+
+int
+ble_hw_encrypt_block(struct ble_encryption_block *ecb)
+{
+ uint32_t in_addr;
+ uint32_t out_addr;
+
+ /*
+ * The following code bears some explanation. This function is called by
+ * the LL task to encrypt blocks and calculate session keys. Address
+ * resolution also calls this function. Furthermore, during connections,
+ * the M0 crypto accelerator is used but this function is not called when
+ * using it. During the entire connection event, the M0 crypto block cannot
+ * be used as the crypto state (some of it) needs to remain un-changed.
+ * Note that this is also true when address resolution is enabled: the
+ * HW crypto block is set up and cannot be modified.
+ *
+ * Rather than attempt to share the M0 crypto block between the various
+ * controller features which require it, we decided to use software to
+ * perform the encryption task for anything being done at the link-layer
+ * (outside of an ISR). If this function is called inside an ISR, and it
+ * is when resolving addresses, the crypto accelerator is not being used
+ * by a connection event. Thus, we check to see if we are inside of an ISR.
+ * If so, we use the M0 crypto block. If outside of an ISR, we use the M33
+ */
+ if (!os_arch_in_isr()) {
+ tc_aes128_set_encrypt_key(&g_ctx, ecb->key);
+ tc_aes_encrypt(ecb->cipher_text, ecb->plain_text, &g_ctx);
+ return 0;
+ }
+
+ /* Need to retain state of in/out pointers */
+ in_addr = CMAC->CM_CRYPTO_IN_ADR2_REG;
+ out_addr = CMAC->CM_CRYPTO_OUT_ADR_REG;
+
+ while (CMAC->CM_CRYPTO_STAT_REG & CMAC_CM_CRYPTO_STAT_REG_CM_CRYPTO_BUSY_Msk);
+
+ /* RECB, memory in/out, encryption */
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ECB_ENC_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
+
+ CMAC->CM_CRYPTO_KEY_31_0_REG = get_le32(&ecb->key[0]);
+ CMAC->CM_CRYPTO_KEY_63_32_REG = get_le32(&ecb->key[4]);
+ CMAC->CM_CRYPTO_KEY_95_64_REG = get_le32(&ecb->key[8]);
+ CMAC->CM_CRYPTO_KEY_127_96_REG = get_le32(&ecb->key[12]);
+ CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)ecb->plain_text;
+ CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)ecb->cipher_text;
+
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
+ while (!(CMAC->CM_EXC_STAT_REG & CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk));
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
+
+ CMAC->CM_CRYPTO_IN_ADR2_REG = in_addr;
+ CMAC->CM_CRYPTO_OUT_ADR_REG = out_addr;
+
+ return 0;
+}
+
+void
+ble_hw_resolv_list_clear(void)
+{
+ g_ble_hw_resolv_list.count = 0;
+}
+
+int
+ble_hw_resolv_list_add(uint8_t *irk)
+{
+ struct ble_hw_resolv_irk *e;
+
+ if (g_ble_hw_resolv_list.count == BLE_HW_RESOLV_LIST_SIZE) {
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ e = &g_ble_hw_resolv_list.irk[g_ble_hw_resolv_list.count];
+ /* Prepare key here so we do not need to do it during resolving */
+ e->key[0] = get_le32(&irk[0]);
+ e->key[1] = get_le32(&irk[4]);
+ e->key[2] = get_le32(&irk[8]);
+ e->key[3] = get_le32(&irk[12]);
+
+ g_ble_hw_resolv_list.count++;
+
+ return BLE_ERR_SUCCESS;
+}
+
+void
+ble_hw_resolv_list_rmv(int index)
+{
+ struct ble_hw_resolv_irk *e;
+
+ if (index < g_ble_hw_resolv_list.count) {
+ g_ble_hw_resolv_list.count--;
+
+ e = &g_ble_hw_resolv_list.irk[index];
+ memmove(e, e + 1, (g_ble_hw_resolv_list.count - index) * sizeof(e->key));
+ }
+}
+
+uint8_t
+ble_hw_resolv_list_size(void)
+{
+ return BLE_HW_RESOLV_LIST_SIZE;
+}
+
+int
+ble_hw_resolv_list_match(void)
+{
+ return g_ble_hw_resolv_proc.f_match ?
+ g_ble_hw_resolv_proc.irk - g_ble_hw_resolv_list.irk : -1;
+}
+
+static void
+ble_hw_resolv_proc_next(void)
+{
+ void *src = &g_ble_hw_resolv_proc.irk->key;
+
+ if (g_ble_hw_resolv_proc.irk == g_ble_hw_resolv_proc.irk_end) {
+ g_ble_hw_resolv_proc.f_done = 1;
+ g_ble_hw_resolv_proc.f_active = 0;
+ } else {
+ __asm__ volatile (".syntax unified \n"
+ " ldm %[ptr]!, {r1, r2, r3, r4} \n"
+ " ldr %[ptr], =%[reg] \n"
+ " stm %[ptr]!, {r1, r2, r3, r4} \n"
+ : [ptr] "+l" (src)
+ : [reg] "i" (&CMAC->CM_CRYPTO_KEY_31_0_REG)
+ : "r1", "r2", "r3", "r4", "memory");
+
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
+ }
+}
+
+void
+ble_hw_resolv_proc_enable(void)
+{
+ assert(!g_ble_hw_resolv_proc.f_active);
+
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_ABORT_Msk;
+
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ECB_ENC_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
+
+ CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)g_ble_hw_resolv_proc.crypto_prand_in;
+ CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)g_ble_hw_resolv_proc.crypto_e_out;
+
+ g_ble_hw_resolv_proc.irk = g_ble_hw_resolv_list.irk;
+ g_ble_hw_resolv_proc.irk_end = g_ble_hw_resolv_list.irk +
+ g_ble_hw_resolv_list.count;
+ g_ble_hw_resolv_proc.f_configured = 1;
+ g_ble_hw_resolv_proc.f_active = 0;
+
+ /*
+ * It would be better to enable IRQ in ble_hw_resolv_proc_start, but this
+ * would introduce a bit of latency when starting resolving procedure and
+ * we need to save every us possible there in order to be able to resolve
+ * RPA on time.
+ */
+ NVIC_ClearPendingIRQ(CRYPTO_IRQn);
+ NVIC_EnableIRQ(CRYPTO_IRQn);
+}
+
+void
+ble_hw_resolv_proc_disable(void)
+{
+ g_ble_hw_resolv_proc.f_configured = 0;
+ g_ble_hw_resolv_proc.f_active = 0;
+ g_ble_hw_resolv_proc.f_match = 0;
+ g_ble_hw_resolv_proc.f_done = 1;
+
+ NVIC_DisableIRQ(CRYPTO_IRQn);
+}
+
+void
+ble_hw_resolv_proc_start(const uint8_t *addr)
+{
+ assert(g_ble_hw_resolv_proc.f_configured);
+
+ /* crypto_prand_in is already zeroed so prand is properly padded */
+ g_ble_hw_resolv_proc.crypto_prand_in[3] = get_be24(&addr[3]) << 8;
+ g_ble_hw_resolv_proc.hash = get_be24(&addr[0]);
+
+ g_ble_hw_resolv_proc.f_match = 0;
+ g_ble_hw_resolv_proc.f_done = 0;
+ g_ble_hw_resolv_proc.f_active = 1;
+
+ ble_hw_resolv_proc_next();
+}
+
+void
+CRYPTO_IRQHandler(void)
+{
+ uint32_t hash;
+
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CRYPTO_Msk;
+
+ hash = g_ble_hw_resolv_proc.crypto_e_out[3] >> 8;
+ if (g_ble_hw_resolv_proc.hash == hash) {
+ g_ble_hw_resolv_proc.f_active = 0;
+ g_ble_hw_resolv_proc.f_match = 1;
+ g_ble_hw_resolv_proc.f_done = 1;
+ } else {
+ g_ble_hw_resolv_proc.irk++;
+ ble_hw_resolv_proc_next();
+ }
+}
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw_priv.h b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw_priv.h
new file mode 100644
index 00000000..627994ff
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_hw_priv.h
@@ -0,0 +1,29 @@
+/*
+ * 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 _BLE_HW_PRIV_H_
+#define _BLE_HW_PRIV_H_
+
+#include <stdint.h>
+
+void ble_hw_resolv_proc_enable(void);
+void ble_hw_resolv_proc_disable(void);
+void ble_hw_resolv_proc_start(const uint8_t *addr);
+
+#endif /* _BLE_HW_PRIV_H_ */
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_phy.c b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_phy.c
new file mode 100644
index 00000000..d5767c56
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_phy.c
@@ -0,0 +1,1798 @@
+/*
+ * 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"
+#if !MYNEWT_VAL(BLE_PHY_DEBUG_DSER)
+#define MCU_DIAG_SER_DISABLE
+#endif
+
+#include <assert.h>
+#include <stdint.h>
+#include <assert.h>
+#include "nimble/ble.h"
+#include "mcu/mcu.h"
+#include "mcu/cmac_timer.h"
+#include "cmac_driver/cmac_shared.h"
+#include "controller/ble_phy.h"
+#include "controller/ble_ll.h"
+#include "stats/stats.h"
+#include "CMAC.h"
+#include "ble_hw_priv.h"
+#include "ble_rf_priv.h"
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+#error LE Coded PHY cannot be enabled on DA1469x
+#endif
+
+/* Statistics */
+STATS_SECT_START(ble_phy_stats)
+ STATS_SECT_ENTRY(phy_isrs)
+ STATS_SECT_ENTRY(tx_good)
+ STATS_SECT_ENTRY(tx_fail)
+ STATS_SECT_ENTRY(tx_late)
+ STATS_SECT_ENTRY(tx_bytes)
+ STATS_SECT_ENTRY(rx_starts)
+ STATS_SECT_ENTRY(rx_aborts)
+ STATS_SECT_ENTRY(rx_valid)
+ STATS_SECT_ENTRY(rx_crc_err)
+ STATS_SECT_ENTRY(rx_late)
+ STATS_SECT_ENTRY(radio_state_errs)
+ STATS_SECT_ENTRY(rx_hw_err)
+ STATS_SECT_ENTRY(tx_hw_err)
+STATS_SECT_END
+STATS_SECT_DECL(ble_phy_stats) ble_phy_stats;
+
+STATS_NAME_START(ble_phy_stats)
+ STATS_NAME(ble_phy_stats, phy_isrs)
+ STATS_NAME(ble_phy_stats, tx_good)
+ STATS_NAME(ble_phy_stats, tx_fail)
+ STATS_NAME(ble_phy_stats, tx_late)
+ STATS_NAME(ble_phy_stats, tx_bytes)
+ STATS_NAME(ble_phy_stats, rx_starts)
+ STATS_NAME(ble_phy_stats, rx_aborts)
+ STATS_NAME(ble_phy_stats, rx_valid)
+ STATS_NAME(ble_phy_stats, rx_crc_err)
+ STATS_NAME(ble_phy_stats, rx_late)
+ STATS_NAME(ble_phy_stats, radio_state_errs)
+ STATS_NAME(ble_phy_stats, rx_hw_err)
+ STATS_NAME(ble_phy_stats, tx_hw_err)
+STATS_NAME_END(ble_phy_stats)
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+#error LE Coded PHY is not supported
+#endif
+
+/* An easy way to get and set bit field value in CMAC registers */
+#define CMAC_SETREGF(_reg, _field, _val) \
+ CMAC->_reg = (CMAC->_reg & ~(CMAC_ ## _reg ## _ ## _field ## _Msk)) | \
+ ((_val) << (CMAC_ ## _reg ## _ ## _field ## _Pos));
+#define CMAC_GETREGF(_reg, _field) \
+ (CMAC->_reg & (CMAC_ ## _reg ## _ ## _field ## _Msk)) >> \
+ (CMAC_ ## _reg ## _ ## _field ## _Pos)
+
+/* Definitions for fields queue */
+#define FIELD_DATA_REG_DMA_TX(_offset, _len) \
+ ((uint32_t)&g_ble_phy_tx_buf[(_offset)] & 0x3ffff) | ((_len) << 20)
+#define FIELD_DATA_REG_DMA_RX(_offset, _len) \
+ ((uint32_t)&g_ble_phy_rx_buf[(_offset)] & 0x3ffff) | ((_len) << 20)
+
+#if MYNEWT_VAL(BLE_LL_DTM)
+#define PHY_WHITENING (g_ble_phy_data.phy_whitening)
+#else
+#define PHY_WHITENING (1)
+#endif
+
+#define FIELD_CTRL_REG_TX_PREAMBLE \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_TX_DATA_SRC_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos) | \
+ (g_ble_phy_data.phy_mode_pre_len << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_SIZE_M1_Pos)
+#define FIELD_CTRL_REG_TX_ACCESS_ADDR \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EXC_ON_EXP_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_TX_DATA_SRC_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos) | \
+ (31 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_SIZE_M1_Pos)
+#define FIELD_CTRL_REG_TX_PAYLOAD \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (PHY_WHITENING << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_MEM_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos);
+#define FIELD_CTRL_REG_TX_ENC_PAYLOAD \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_CRYPTO_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos)
+#define FIELD_CTRL_REG_TX_MIC \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_CRYPTO_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos)
+#define FIELD_CTRL_REG_TX_CRC \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (PHY_WHITENING << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_TX_DATA_SRC_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_LAST_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_MSB_FIRST_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos) | \
+ (23 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_SIZE_M1_Pos)
+#define FIELD_CTRL_REG_RX_ACCESS_ADDR \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (0 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_TX_DATA_SRC_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CORR_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos) | \
+ (31 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_SIZE_M1_Pos)
+#define FIELD_CTRL_REG_RX_HEADER \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EXC_ON_EXP_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (PHY_WHITENING << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_MEM_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos)
+#define FIELD_CTRL_REG_RX_CRC \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (PHY_WHITENING << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_LAST_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_MSB_FIRST_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_MEM_Pos)
+#define FIELD_CTRL_REG_RX_PAYLOAD \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (PHY_WHITENING << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_MEM_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos)
+#define FIELD_CTRL_REG_RX_PAYLOAD_WITH_EXC \
+ FIELD_CTRL_REG_RX_PAYLOAD | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EXC_ON_EXP_Pos)
+#define FIELD_CTRL_REG_RX_ENC_PAYLOAD \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_CRC_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_WHITENING_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_XL_DMA_CRYPTO_Pos) | \
+ (g_ble_phy_data.phy_mode_evpsym << \
+ CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_EVPSYMBOL_LUT_Pos) | \
+ (1 << CMAC_CM_FIELD_PUSH_CTRL_REG_FIELD_VALID_Pos)
+
+/* RF power up/down delays */
+#define PHY_DELAY_POWER_DN_RX (23)
+#define PHY_DELAY_POWER_DN_TX (23)
+#define PHY_DELAY_POWER_UP_RX (90)
+#define PHY_DELAY_POWER_UP_TX (75)
+#define PHY_DELAY_TX_RX ((PHY_DELAY_POWER_DN_TX) + (PHY_DELAY_POWER_UP_RX))
+#define PHY_DELAY_RX_TX ((PHY_DELAY_POWER_DN_RX) + (PHY_DELAY_POWER_UP_TX))
+
+/* RF TX/RX path delays */
+static const uint8_t g_ble_phy_path_delay_tx[2] = {
+ 4, /* 1M = 3.8us */
+ 0, /* 2M = 0.2us */
+};
+static const uint8_t g_ble_phy_path_delay_rx[2] = {
+ 2, /* 1M = 2.2us */
+ 1, /* 2M = 0.8us */
+};
+
+/* Measured and pre-calculated offsets for transitions */
+static const uint8_t g_ble_phy_frame_offset_txrx[4] = {
+ ((BLE_LL_IFS) - (PHY_DELAY_TX_RX) + (4)), /* 2M/1M */
+ ((BLE_LL_IFS) - (PHY_DELAY_TX_RX) + (5)), /* 1M/1M */
+ ((BLE_LL_IFS) - (PHY_DELAY_TX_RX) + (4)), /* 2M/2M */
+ ((BLE_LL_IFS) - (PHY_DELAY_TX_RX) + (5)), /* 1M/2M */
+};
+static const uint8_t g_ble_phy_frame_offset_rxtx[4] = {
+ ((BLE_LL_IFS) - (PHY_DELAY_RX_TX) - (5)), /* 2M/1M */
+ ((BLE_LL_IFS) - (PHY_DELAY_RX_TX) - (6)), /* 1M/1M */
+ ((BLE_LL_IFS) - (PHY_DELAY_RX_TX) - (3)), /* 2M/2M */
+ ((BLE_LL_IFS) - (PHY_DELAY_RX_TX) - (5)), /* 1M/2M */
+};
+
+/* packet start offsets (in usecs) */
+static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = { 376, 40, 24, 376 };
+
+struct ble_phy_data {
+ uint8_t phy_state; /* Current state */
+ uint8_t channel; /* Current PHY channel */
+ uint8_t phy_mode_cur; /* Current PHY mode */
+ uint8_t phy_mode_tx; /* TX PHY mode */
+ uint8_t phy_mode_rx; /* RX PHY mode */
+ uint8_t phy_mode_pre_len; /* Preamble length - 1 */
+ uint8_t phy_mode_evpsym; /* EVPSYMBOL_LUT value for fields */
+ uint8_t end_transition; /* Scheduled transition */
+ uint8_t path_delay_tx;
+ uint8_t path_delay_rx;
+ uint8_t frame_offset_txrx;
+ uint8_t frame_offset_rxtx;
+ uint8_t phy_rx_started;
+ uint8_t phy_encrypted;
+ uint8_t phy_privacy;
+#if MYNEWT_VAL(BLE_LL_DTM)
+ uint8_t phy_whitening; /* Whitening state (disabled for DTM) */
+#endif
+ uint32_t access_addr; /* Current access address */
+ uint32_t crc_init;
+ uint32_t llt_at_cputime;
+ uint32_t cputime_at_llt;
+ uint64_t start_llt;
+ struct ble_mbuf_hdr rxhdr;
+ ble_phy_tx_end_func txend_cb;
+ void *txend_arg;
+};
+
+static struct ble_phy_data g_ble_phy_data;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+/* Encryption related variables */
+struct ble_phy_encrypt_obj {
+ uint8_t key[16];
+ uint8_t b0[16];
+ uint8_t b1[16];
+ uint8_t ai[16];
+};
+
+struct ble_phy_encrypt_obj g_ble_phy_encrypt_data;
+
+static void ble_phy_tx_enc_start(void);
+static void ble_phy_rx_enc_start(uint8_t len);
+#endif
+
+#define SW_MAC_EXC_NONE (0)
+#define SW_MAC_EXC_LL_RX_END (1)
+#define SW_MAC_EXC_TXEND_CB (2)
+#define SW_MAC_EXC_LL_RX_START (3)
+#define SW_MAC_EXC_WFR_TIMER_EXP (4)
+
+static volatile uint8_t g_sw_mac_exc;
+
+/* Channel index to RF channel mapping */
+static const uint8_t g_ble_phy_chan_to_rf[BLE_PHY_NUM_CHANS] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 0-9 */
+ 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, /* 10-19 */
+ 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, /* 20-29 */
+ 32, 33, 34, 35, 36, 37, 38, 0, 12, 39, /* 30-39 */
+};
+
+__attribute__((aligned(4)))
+static uint8_t g_ble_phy_tx_buf[BLE_PHY_MAX_PDU_LEN + 3];
+__attribute__((aligned(4)))
+static uint8_t g_ble_phy_rx_buf[BLE_PHY_MAX_PDU_LEN + 3];
+
+static void ble_phy_irq_field_tx(void);
+static void ble_phy_irq_field_rx(void);
+static void ble_phy_irq_frame_tx(void);
+static void ble_phy_irq_frame_rx(void);
+static bool ble_phy_rx_start_isr(void);
+static void ble_phy_rx_setup_fields(void);
+static void ble_phy_rx_setup_xcvr(void);
+static void ble_phy_mode_apply(uint8_t phy_mode);
+
+void
+FIELD_IRQHandler(void)
+{
+ MCU_DIAG_SER('E');
+
+ switch (g_ble_phy_data.phy_state) {
+ case BLE_PHY_STATE_TX:
+ ble_phy_irq_field_tx();
+ break;
+ case BLE_PHY_STATE_RX:
+ ble_phy_irq_field_rx();
+ break;
+ default:
+ STATS_INC(ble_phy_stats, radio_state_errs);
+ CMAC->CM_EXC_STAT_REG = 0xfffffffe;
+ break;
+ }
+
+ MCU_DIAG_SER('e');
+}
+
+void
+CALLBACK_IRQHandler(void)
+{
+ MCU_DIAG_SER('C');
+
+ /* XXX: clear these for now. */
+ (void)CMAC->CM_BS_SMPL_D_REG;
+
+ /* Clear IRQ*/
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CALLBACK_VALID_CLR_Msk;
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk;
+
+ /*
+ * Program next frame for transition to TX. CM_EV_LINKUP_REG register to
+ * enable actual transition can be set later, we just need to make sure 2nd
+ * frame is already set before current frame is finished - this guarantees
+ * that frame for transition will be moved to 1st frame once current frame
+ * is popped off the queue.
+ */
+ CMAC->CM_FRAME_2_REG = CMAC_CM_FRAME_2_REG_FRAME_VALID_Msk |
+ CMAC_CM_FRAME_2_REG_FRAME_TX_Msk |
+ CMAC_CM_FRAME_2_REG_FRAME_EXC_ON_BS_START_Msk |
+ ((g_ble_phy_data.frame_offset_rxtx) <<
+ CMAC_CM_FRAME_2_REG_FRAME_START_OFFSET_Pos);
+
+ /*
+ * We just got an access address match so do this as early as possible
+ * to save time in the field rx isr.
+ */
+ ble_phy_rx_start_isr();
+
+ MCU_DIAG_SER('c');
+}
+
+void
+FRAME_IRQHandler(void)
+{
+ MCU_DIAG_SER('F');
+
+ switch (g_ble_phy_data.phy_state) {
+ case BLE_PHY_STATE_TX:
+ ble_phy_irq_frame_tx();
+ break;
+ case BLE_PHY_STATE_RX:
+ ble_phy_irq_frame_rx();
+ break;
+ default:
+ STATS_INC(ble_phy_stats, radio_state_errs);
+ CMAC->CM_EXC_STAT_REG = 0xfffffffe;
+ break;
+ }
+
+ MCU_DIAG_SER('f');
+}
+
+void
+SW_MAC_IRQHandler(void)
+{
+ uint8_t exc;
+ int rc;
+
+ MCU_DIAG_SER('S');
+
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_SW_MAC_Msk;
+ assert(g_sw_mac_exc);
+
+ exc = g_sw_mac_exc;
+ g_sw_mac_exc = 0;
+
+ MCU_DIAG_SER('0' + exc);
+
+ /* Next SW_MAC handover can now be queued */
+ os_arch_cmac_bs_ctrl_irq_unblock();
+
+ switch (exc) {
+ case SW_MAC_EXC_TXEND_CB:
+ assert(g_ble_phy_data.txend_cb);
+ g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
+ break;
+ case SW_MAC_EXC_WFR_TIMER_EXP:
+ ble_ll_wfr_timer_exp(NULL);
+ break;
+ case SW_MAC_EXC_LL_RX_START:
+ /* Call Link Layer receive start function */
+ rc = ble_ll_rx_start(&g_ble_phy_rx_buf[0], g_ble_phy_data.channel,
+ &g_ble_phy_data.rxhdr);
+ if (rc == 0) {
+ /* Set rx started flag and enable rx end ISR */
+ g_ble_phy_data.phy_rx_started = 1;
+
+ /* No transition */
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_PHY_TO_IDLE_2_NONE_Msk |
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_NONE_Msk;
+ } else if (rc > 0) {
+ g_ble_phy_data.phy_rx_started = 1;
+
+ /* Setup transition */
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_PHY_TO_IDLE_2_EXC_Msk |
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_PHY_TO_IDLE_Msk;
+ } else {
+ /* Disable PHY */
+ ble_phy_disable();
+ STATS_INC(ble_phy_stats, rx_aborts);
+ }
+ break;
+ case SW_MAC_EXC_LL_RX_END:
+ /* Call LL end processing */
+ rc = ble_ll_rx_end(&g_ble_phy_rx_buf[0], &g_ble_phy_data.rxhdr);
+ if (rc < 0) {
+ ble_phy_disable();
+ }
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ MCU_DIAG_SER('s');
+}
+
+static inline uint32_t
+ble_phy_convert_and_record_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+ uint64_t ll_val;
+
+ ll_val = cmac_timer_convert_hal2llt(cputime);
+
+ /*
+ * Since we just converted cputime to the LL timer, record both these
+ * values as they will be used to calculate packet reception start time.
+ */
+ g_ble_phy_data.cputime_at_llt = cputime;
+ g_ble_phy_data.llt_at_cputime = ll_val;
+ g_ble_phy_data.start_llt = ll_val + rem_usecs;
+
+ return ll_val;
+}
+
+static inline void
+ble_phy_sw_mac_handover(uint8_t exc)
+{
+ assert(!g_sw_mac_exc);
+
+ g_sw_mac_exc = exc;
+
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_SW_MAC_Msk;
+
+ /*
+ * We want SW_MAC to be fired just after BS_CTRL interrupt so we block
+ * BS_CTRL temporarily and SW_MAC is next in order of interrupts priority.
+ */
+ os_arch_cmac_bs_ctrl_irq_block();
+}
+
+static void
+ble_phy_rx_end_isr(void)
+{
+ struct ble_mbuf_hdr *ble_hdr;
+
+ /* XXX just clear captured timer for now. Handle rx end time */
+ (void)CMAC->CM_TS1_REG;
+
+ /* Set RSSI and CRC status flag in header */
+ ble_hdr = &g_ble_phy_data.rxhdr;
+
+ /* Count PHY crc errors and valid packets */
+ if (CMAC->CM_CRC_REG != 0) {
+ STATS_INC(ble_phy_stats, rx_crc_err);
+ } else {
+ STATS_INC(ble_phy_stats, rx_valid);
+ ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_CRC_OK;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted) {
+ /* Only set MIC failure flag if frame is not zero length */
+ if (g_ble_phy_rx_buf[1] != 0) {
+ if (CMAC->CM_CRYPTO_STAT_REG != 0) {
+ ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE;
+ } else {
+ g_ble_phy_rx_buf[1] = g_ble_phy_rx_buf[1] - 4;
+ }
+ }
+ }
+#endif
+ }
+
+ ble_phy_sw_mac_handover(SW_MAC_EXC_LL_RX_END);
+}
+
+static bool
+ble_phy_rx_start_isr(void)
+{
+ uint32_t llt32;
+ uint32_t llt_10_0;
+ uint32_t llt_10_0_mask;
+ uint32_t timestamp;
+ uint32_t ticks;
+ uint32_t usecs;
+ struct ble_mbuf_hdr *ble_hdr;
+
+ /* Initialize the ble mbuf header */
+ ble_hdr = &g_ble_phy_data.rxhdr;
+ ble_hdr->rxinfo.flags = ble_ll_state_get();
+ ble_hdr->rxinfo.channel = g_ble_phy_data.channel;
+ ble_hdr->rxinfo.handle = 0;
+ ble_hdr->rxinfo.phy = ble_phy_get_cur_phy();
+ ble_hdr->rxinfo.phy_mode = g_ble_phy_data.phy_mode_rx;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+ ble_hdr->rxinfo.user_data = NULL;
+#endif
+
+ /* Read the latched RSSI value */
+ ble_hdr->rxinfo.rssi = ble_rf_get_rssi();
+#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
+ g_cmac_shared_data.debug.last_rx_rssi = ble_hdr->rxinfo.rssi;
+#endif
+
+ /* Count rx starts */
+ STATS_INC(ble_phy_stats, rx_starts);
+
+ /*
+ * Calculate packet start time. Note that we have only received the
+ * access address at this point but we should have the 1st symbol and
+ * thus the timestamp should be set (this is based on looking at the diag
+ * signals). For now, lets make sure that the dirty bit is set. The
+ * dirty bit means that the timestamp was set since the last time cleared.
+ * Note that we need to read the timestamp first to guarantee it was set
+ * before reading the LL timer.
+ */
+ timestamp = CMAC->CM_TS1_REG;
+ assert((timestamp & CMAC_CM_TS1_REG_TS1_DIRTY_Msk) != 0);
+
+ /* Get the LL timer (only need 32 bits) */
+ llt32 = cmac_timer_read32();
+
+ /*
+ * We assume that the timestamp was set within 11 bits, or 2047 usecs, of
+ * when we read the ll timer. We assume this because we need to calculate
+ * the LL timer value at the timestamp. If the low 11 bits of the LL timer
+ * are greater than the timestamp, it means that the upper bits of the
+ * timestamp are correct. If the timestamp value is greater, it means the
+ * timer wrapped the 11 bits and we need to adjust the LL timer value.
+ */
+ llt_10_0_mask = (CMAC_CM_TS1_REG_TS1_TIMER1_9_0_Msk |
+ CMAC_CM_TS1_REG_TS1_TIMER1_10_Msk);
+ timestamp &= llt_10_0_mask;
+ llt_10_0 = llt32 & llt_10_0_mask;
+ llt32 &= ~llt_10_0_mask;
+ if (timestamp > llt_10_0) {
+ llt32 -= 2048;
+ }
+ llt32 |= timestamp;
+
+ /* Actual RX start time needs to account for preamble and access address */
+ llt32 -= g_ble_phy_mode_pkt_start_off[g_ble_phy_data.phy_mode_rx] +
+ g_ble_phy_data.path_delay_rx;
+
+ if (llt32 < g_ble_phy_data.llt_at_cputime) {
+ g_ble_phy_data.llt_at_cputime -= 31;
+ g_ble_phy_data.cputime_at_llt--;
+ }
+
+ /*
+ * We now have the LL timer when the packet was received. Get the cputime
+ * and the leftover usecs.
+ */
+ usecs = llt32 - g_ble_phy_data.llt_at_cputime;
+ ticks = os_cputime_usecs_to_ticks(usecs);
+ ble_hdr->beg_cputime = g_ble_phy_data.cputime_at_llt + ticks;
+ ble_hdr->rem_usecs = usecs - os_cputime_ticks_to_usecs(ticks);
+
+ return true;
+}
+
+static void
+ble_phy_irq_field_tx_exc_bs_start_4this(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_BS_START_4THIS_Msk;
+
+ if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) {
+ /*
+ * Setup 2nd frame that will start after current one.
+ * -2us offset to adjust for allowed active clock accuracy.
+ */
+ CMAC->CM_FRAME_2_REG = CMAC_CM_FRAME_2_REG_FRAME_VALID_Msk |
+ (((g_ble_phy_data.frame_offset_txrx) - 2) <<
+ CMAC_CM_FRAME_2_REG_FRAME_START_OFFSET_Pos);
+
+ /* Next frame starts automatically on phy2idle */
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_PHY_TO_IDLE_2_EXC_Msk |
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_PHY_TO_IDLE_Msk;
+
+ ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, g_ble_phy_data.phy_mode_rx, 0);
+ } else {
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_PHY_TO_IDLE_2_EXC_Msk |
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_NONE_Msk;
+ }
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted && (g_ble_phy_tx_buf[1] != 0)) {
+ ble_phy_tx_enc_start();
+ }
+#endif
+}
+
+static void
+ble_phy_irq_field_tx_exc_field_on_thr_exp(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk;
+ (void)CMAC->CM_TS1_REG;
+
+ /* Set up remaining field (CRC) */
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_CRC;
+}
+
+static void
+ble_phy_irq_field_tx(void)
+{
+ uint32_t stat;
+
+ stat = CMAC->CM_EXC_STAT_REG;
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_BS_START_4THIS_Msk) {
+ MCU_DIAG_SER('6');
+ ble_phy_irq_field_tx_exc_bs_start_4this();
+ }
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk) {
+ MCU_DIAG_SER('7');
+ ble_phy_irq_field_tx_exc_field_on_thr_exp();
+ }
+}
+
+static void
+ble_phy_irq_frame_tx_exc_bs_stop(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_BS_STOP_Msk;
+
+ /* Clear latched timestamp so we do not have error on next frame */
+ (void)CMAC->CM_TS1_REG;
+
+ if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) {
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx);
+#endif
+ ble_phy_rx_setup_fields();
+ } else {
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_PHY_TO_IDLE_2_EXC_Msk |
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_NONE_Msk;
+ }
+
+ if (g_ble_phy_data.txend_cb) {
+ ble_phy_sw_mac_handover(SW_MAC_EXC_TXEND_CB);
+ return;
+ }
+}
+
+static void
+ble_phy_irq_frame_tx_exc_phy_to_idle_4this(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk;
+
+ if (g_ble_phy_data.end_transition == BLE_PHY_TRANSITION_TX_RX) {
+ ble_phy_rx_setup_xcvr();
+
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
+ } else {
+ /*
+ * Disable explicitly in case RX-TX was done (we cannot setup for auto
+ * disable in such case) */
+ ble_rf_stop();
+
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
+ }
+
+ g_ble_phy_data.end_transition = BLE_PHY_TRANSITION_NONE;
+}
+
+static void
+ble_phy_irq_frame_tx(void)
+{
+ uint32_t stat;
+
+ stat = CMAC->CM_EXC_STAT_REG;
+
+ /*
+ * In case of phy2idle this should be first and only exception we handle
+ * here. This is because in case of TX-RX transition frame_start will occur
+ * at the same as phy2idle so we will have 2 exceptions here. To handle this
+ * properly we first need to handle phy2idle in TX state and keep frame_start
+ * pending so it will be called again in RX state.
+ */
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk) {
+ MCU_DIAG_SER('6');
+ ble_phy_irq_frame_tx_exc_phy_to_idle_4this();
+ return;
+ }
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk) {
+ MCU_DIAG_SER('7');
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk;
+ }
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_BS_STOP_Msk) {
+ MCU_DIAG_SER('8');
+ ble_phy_irq_frame_tx_exc_bs_stop();
+ }
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+static void
+ble_phy_field_rx_encrypted(uint32_t len)
+{
+ if (len) {
+ /*
+ * An encrypted frame should have a minimum length of 5
+ * bytes (at least one for payload and 4 for MIC). If the
+ * length is less than 5 this frame is bogus and will most
+ * likely fail CRC. We still need to process this frame
+ * though as we need to call the handover function with
+ * the frame. If this happens we will not bother to
+ * run the remaining bytes through the accelerator; just
+ * process them like normal and generate (a hopefully
+ * incorrect) CRC.
+ */
+ if (len >= 5) {
+ /* Start the crypto accelerator */
+ ble_phy_rx_enc_start(len);
+
+ /*
+ * We have already processed one byte; process remaining
+ * payload and MIC. Note: length contains MIC.
+ */
+ len -= 2;
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4, len);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_ENC_PAYLOAD;
+
+ /* CRC */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4 + len, 3);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_CRC;
+ } else {
+ /* We have processed one byte so far. Send remaining
+ payload bytes to normal rx payload processing */
+ len -= 2;
+ if (len) {
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4, len);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_PAYLOAD;
+ }
+
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4 + len, 3);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_CRC;
+
+ /* Clear crypto pre-buffer */
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_PBUF_CLR_Msk;
+ }
+ } else {
+ /* We programmed one byte, so get next two bytes for CRC */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4, 1);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_CRC;
+ }
+}
+#endif
+
+static void
+ble_phy_field_rx_unencrypted(uint32_t len)
+{
+ uint8_t pduhdr;
+ uint8_t adva_thr;
+
+ if (len) {
+ pduhdr = g_ble_phy_rx_buf[0];
+ adva_thr = 0;
+
+ /*
+ * Setup interrupt after AdvA to start address resolving if
+ * privacy is enabled and TxAdd bit is set.
+ */
+ if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) &&
+ g_ble_phy_data.phy_privacy && (pduhdr & 0x40)) {
+
+ /*
+ * For legacy advertising AdvA ends at 6th byte.
+ * For extended advertising AdvA ends at 8th byte.
+ * We already programmed 2 bytes of payload so need
+ * to adjust threshold accordingly or just reset it
+ * in case there is not enough bytes in PDU to fit AdvA.
+ */
+ adva_thr = (pduhdr & 0x0f) == 0x07 ? 6 : 4;
+ if (len >= adva_thr + 2) {
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4, adva_thr);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_PAYLOAD_WITH_EXC;
+ } else {
+ adva_thr = 0;
+ }
+ }
+
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4 + adva_thr,
+ len - adva_thr);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_PAYLOAD;
+ }
+
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(4 + len, 1);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_CRC;
+}
+
+static void
+ble_phy_irq_field_rx_exc_field_on_thr_exp(void)
+{
+ uint32_t len;
+ uint32_t smpl;
+
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk;
+
+ smpl = CMAC->CM_BS_SMPL_ST_REG;
+
+ if ((smpl & CMAC_CM_BS_SMPL_ST_REG_FIELD_CNT_LATCHED_Msk) == 1) {
+ assert(g_ble_phy_data.phy_rx_started == 0);
+
+ /* Clear this */
+ (void)CMAC->CM_TS1_REG;
+
+ /* Read length of frame */
+ len = CMAC->CM_BS_SMPL_D_REG;
+ len = len & 0xFF;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted) {
+ ble_phy_field_rx_encrypted(len);
+ } else {
+ ble_phy_field_rx_unencrypted(len);
+ }
+#else
+ ble_phy_field_rx_unencrypted(len);
+#endif
+
+ ble_phy_sw_mac_handover(SW_MAC_EXC_LL_RX_START);
+ } else if ((smpl & CMAC_CM_BS_SMPL_ST_REG_FIELD_CNT_LATCHED_Msk) == 3) {
+ (void)CMAC->CM_BS_SMPL_D_REG;
+
+ assert(g_ble_phy_data.phy_privacy);
+
+ /*
+ * Resolve only if RPA is received. AdvA is at different offset
+ * in ExtAdv PDU. TxAdd was already checked before programming
+ * field threshold.
+ */
+ if ((g_ble_phy_rx_buf[0] & 0x0f) == 0x07) {
+ if ((g_ble_phy_rx_buf[9] & 0xc0) == 0x40) {
+ ble_hw_resolv_proc_start(&g_ble_phy_rx_buf[4]);
+ }
+ } else {
+ if ((g_ble_phy_rx_buf[7] & 0xc0) == 0x40) {
+ ble_hw_resolv_proc_start(&g_ble_phy_rx_buf[2]);
+ }
+ }
+ } else {
+ assert(0);
+ }
+}
+
+static void
+ble_phy_irq_field_rx_exc_stat_reg_exc_corr_timeout(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_CORR_TIMEOUT_Msk;
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_BS_STOP_Msk;
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_NONE_Msk;
+
+ ble_phy_sw_mac_handover(SW_MAC_EXC_WFR_TIMER_EXP);
+}
+
+static void
+ble_phy_irq_field_rx(void)
+{
+ uint32_t stat;
+
+ stat = CMAC->CM_EXC_STAT_REG;
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk) {
+ MCU_DIAG_SER('1');
+ ble_phy_irq_field_rx_exc_field_on_thr_exp();
+ }
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_CORR_TIMEOUT_Msk) {
+ MCU_DIAG_SER('2');
+ ble_phy_irq_field_rx_exc_stat_reg_exc_corr_timeout();
+ }
+}
+
+static void
+ble_phy_irq_frame_rx_exc_phy_to_idle_4this(void)
+{
+ uint8_t rf_chan;
+
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk;
+
+ /* We are here only on transition, so switch to TX */
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_mode_tx);
+#endif
+ rf_chan = g_ble_phy_chan_to_rf[g_ble_phy_data.channel];
+ ble_rf_setup_tx(rf_chan, g_ble_phy_data.phy_mode_tx);
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
+}
+
+static void
+ble_phy_irq_frame_rx_exc_frame_start(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk;
+}
+
+static void
+ble_phy_irq_frame_rx_exc_bs_stop(void)
+{
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_BS_STOP_Msk;
+ ble_phy_rx_end_isr();
+}
+
+static void
+ble_phy_irq_frame_rx(void)
+{
+ uint32_t stat;
+
+ stat = CMAC->CM_EXC_STAT_REG;
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk) {
+ MCU_DIAG_SER('3');
+ ble_phy_irq_frame_rx_exc_phy_to_idle_4this();
+ return;
+ }
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk) {
+ MCU_DIAG_SER('1');
+ ble_phy_irq_frame_rx_exc_frame_start();
+ }
+
+ if (stat & CMAC_CM_EXC_STAT_REG_EXC_BS_STOP_Msk) {
+ MCU_DIAG_SER('2');
+ ble_phy_irq_frame_rx_exc_bs_stop();
+ }
+}
+
+static void
+ble_phy_mode_apply(uint8_t phy_mode)
+{
+ if (phy_mode == g_ble_phy_data.phy_mode_cur) {
+ return;
+ }
+
+ switch (phy_mode) {
+ case BLE_PHY_MODE_1M:
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, CORR_CLK_MODE, 3);
+#endif
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, PHY_MODE, 1);
+ g_ble_phy_data.phy_mode_evpsym = 1; /* 1000 ns per symbol */
+ g_ble_phy_data.phy_mode_pre_len = 7;
+ break;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
+ case BLE_PHY_MODE_2M:
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, CORR_CLK_MODE, 2);
+#endif
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, PHY_MODE, 0);
+ g_ble_phy_data.phy_mode_evpsym = 0; /* 500 ns per symbol */
+ g_ble_phy_data.phy_mode_pre_len = 15;
+ break;
+#endif
+ default:
+ assert(0);
+ return;
+ }
+
+ g_ble_phy_data.phy_mode_cur = phy_mode;
+}
+
+void
+ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode)
+{
+ uint8_t txrx;
+ uint8_t rxtx;
+
+ g_ble_phy_data.phy_mode_tx = tx_phy_mode;
+ g_ble_phy_data.phy_mode_rx = rx_phy_mode;
+
+ g_ble_phy_data.path_delay_tx = g_ble_phy_path_delay_tx[tx_phy_mode - 1];
+ g_ble_phy_data.path_delay_rx = g_ble_phy_path_delay_rx[rx_phy_mode - 1];
+
+ /*
+ * Calculate index of transition in frame offset array without tons of
+ * branches. Note that transitions have to be in specific order in array.
+ *
+ * phy_mode 1M = 01b
+ * phy_mode 2M = 10b
+ *
+ * 1M/1M = 01b | 00b = 01b
+ * 1M/2M = 01b | 10b = 11b
+ * 2M/1M = 00b | 00b = 00b
+ * 2M/2M = 00b | 10b = 10b
+ */
+ txrx = (tx_phy_mode & 0x01) | (rx_phy_mode & 0x02);
+ rxtx = (rx_phy_mode & 0x01) | (tx_phy_mode & 0x02);
+ g_ble_phy_data.frame_offset_txrx = g_ble_phy_frame_offset_txrx[txrx];
+ g_ble_phy_data.frame_offset_rxtx = g_ble_phy_frame_offset_rxtx[rxtx];
+}
+
+int
+ble_phy_get_cur_phy(void)
+{
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ switch (g_ble_phy_data.phy_mode_cur) {
+ case BLE_PHY_MODE_1M:
+ return BLE_PHY_1M;
+ case BLE_PHY_MODE_2M:
+ return BLE_PHY_2M;
+ default:
+ assert(0);
+ return -1;
+ }
+#else
+ return BLE_PHY_1M;
+#endif
+}
+
+/**
+ * Copies the data from the phy receive buffer into a mbuf chain.
+ *
+ * @param dptr Pointer to receive buffer
+ * @param rxpdu Pointer to already allocated mbuf chain
+ *
+ * NOTE: the packet header already has the total mbuf length in it. The
+ * lengths of the individual mbufs are not set prior to calling.
+ *
+ */
+void
+ble_phy_rxpdu_copy(uint8_t *dptr, struct os_mbuf *rxpdu)
+{
+ uint32_t rem_len;
+ uint32_t copy_len;
+ uint32_t block_len;
+ uint32_t block_rem_len;
+ void *dst;
+ void *src;
+ struct os_mbuf * om;
+
+ /* Better be aligned */
+ assert(((uint32_t)dptr & 3) == 0);
+
+ block_len = rxpdu->om_omp->omp_databuf_len;
+ rem_len = OS_MBUF_PKTHDR(rxpdu)->omp_len;
+ src = dptr;
+
+ /*
+ * Setup for copying from first mbuf which is shorter due to packet header
+ * and extra leading space
+ */
+ copy_len = block_len - rxpdu->om_pkthdr_len - 4;
+ om = rxpdu;
+ dst = om->om_data;
+
+ while (om) {
+ /*
+ * Always copy blocks of length aligned to word size, only last mbuf
+ * will have remaining non-word size bytes appended.
+ */
+ block_rem_len = copy_len;
+ copy_len = min(copy_len, rem_len);
+ copy_len &= ~3;
+
+ dst = om->om_data;
+ om->om_len = copy_len;
+ rem_len -= copy_len;
+ block_rem_len -= copy_len;
+
+ __asm__ volatile (".syntax unified \n"
+ " mov r4, %[len] \n"
+ " b 2f \n"
+ "1: ldr r3, [%[src], %[len]] \n"
+ " str r3, [%[dst], %[len]] \n"
+ "2: subs %[len], #4 \n"
+ " bpl 1b \n"
+ " adds %[src], %[src], r4 \n"
+ " adds %[dst], %[dst], r4 \n"
+ : [dst] "+l" (dst), [src] "+l" (src),
+ [len] "+l" (copy_len)
+ :
+ : "r3", "r4", "memory");
+
+ if ((rem_len < 4) && (block_rem_len >= rem_len)) {
+ break;
+ }
+
+ /* Move to next mbuf */
+ om = SLIST_NEXT(om, om_next);
+ copy_len = block_len;
+ }
+
+ /* Copy remaining bytes, if any, to last mbuf */
+ om->om_len += rem_len;
+ __asm__ volatile (".syntax unified \n"
+ " b 2f \n"
+ "1: ldrb r3, [%[src], %[len]] \n"
+ " strb r3, [%[dst], %[len]] \n"
+ "2: subs %[len], #1 \n"
+ " bpl 1b \n"
+ : [len] "+l" (rem_len)
+ : [dst] "l" (dst), [src] "l" (src)
+ : "r3", "memory");
+
+ /* Copy header */
+ memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr,
+ sizeof(struct ble_mbuf_hdr));
+}
+
+void
+ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
+{
+ uint64_t llt;
+ uint32_t corr_window;
+ uint32_t llt_z_ticks;
+ uint32_t aa_time;
+
+ /*
+ * RX is started 2us earlier due to allowed clock accuracy and it should end
+ * 2us later for the same reason. Preamble is always 8us (8 symbols on 1M,
+ * 16 symbols on 2M) and Access Address is 32us on 1M and 16us on 2M. Add
+ * 1us just in case...
+ */
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
+ aa_time = 2 + (g_ble_phy_data.phy_mode_rx == BLE_PHY_MODE_1M ? 40 : 24) + 2 + 1;
+#else
+ aa_time = 45;
+#endif
+
+ if (txrx == BLE_PHY_WFR_ENABLE_TXRX) {
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, CORR_WINDOW, aa_time);
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_CORR_TMR_LD_2_CORR_START_Msk;
+ } else if (wfr_usecs < 16384) {
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, CORR_WINDOW, wfr_usecs + aa_time);
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_CORR_TMR_LD_2_CORR_START_Msk;
+ } else {
+ wfr_usecs += aa_time;
+ llt = g_ble_phy_data.start_llt;
+
+ /*
+ * wfr is outside range of CORR_WINDOW so we need to use LLT to start
+ * correlator timeout with some delay. Let's use ~10ms as new CORR_WINDOW
+ * value (does not really matter, just had to pick something) so need to
+ * calculate how many hi-Z ticks of delay we need.
+ */
+ llt_z_ticks = (wfr_usecs - 10000) / 1024;
+
+ /* New CORR_WINDOW is wfr adjusted by hi-Z ticks and remainder of 1st tick. */
+ corr_window = wfr_usecs;
+ corr_window -= llt_z_ticks * 1024;
+ corr_window -= 1024 - (llt & 0x3ff);
+
+ CMAC->CM_LL_TIMER1_36_10_EQ_Z_REG = (llt >> 10) + llt_z_ticks;
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, CORR_WINDOW, corr_window);
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_CORR_TMR_LD_2_TMR1_36_10_EQ_Z_Msk;
+ }
+}
+
+int
+ble_phy_init(void)
+{
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
+#if MYNEWT_VAL(BLE_LL_DTM)
+ g_ble_phy_data.phy_whitening = 1;
+#endif
+
+ ble_rf_init();
+
+ /*
+ * 9_0_EQ_X can be linked to start RX/TX so we'll use this one for
+ * scheduling TX/RX start - make sure it's not linked to LL_TIMER2LLC
+ */
+ CMAC->CM_LL_INT_SEL_REG &= ~CMAC_CM_LL_INT_SEL_REG_LL_TIMER1_9_0_EQ_X_SEL_Msk;
+
+ CMAC->CM_PHY_CTRL_REG = ((PHY_DELAY_POWER_DN_RX - 1) << 24) |
+ ((PHY_DELAY_POWER_DN_TX - 1) << 16) |
+ ((PHY_DELAY_POWER_UP_RX - 1) << 8) |
+ ((PHY_DELAY_POWER_UP_TX - 1));
+
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ CMAC->CM_PHY_CTRL2_REG = CMAC_CM_PHY_CTRL2_REG_PHY_MODE_Msk |
+ (3 << CMAC_CM_PHY_CTRL2_REG_CORR_CLK_MODE_Pos);
+#else
+ CMAC->CM_PHY_CTRL2_REG = CMAC_CM_PHY_CTRL2_REG_PHY_MODE_Msk |
+ (2 << CMAC_CM_PHY_CTRL2_REG_CORR_CLK_MODE_Pos);
+#endif
+
+ CMAC_SETREGF(CM_CTRL2_REG, WHITENING_MODE, 0);
+ CMAC_SETREGF(CM_CTRL2_REG, CRC_MODE, 0);
+
+ /* Setup for 1M by default */
+ ble_phy_mode_set(BLE_PHY_MODE_1M, BLE_PHY_MODE_1M);
+ ble_phy_mode_apply(BLE_PHY_MODE_1M);
+
+ NVIC_SetPriority(FIELD_IRQn, 0);
+ NVIC_SetPriority(CALLBACK_IRQn, 0);
+ NVIC_SetPriority(FRAME_IRQn, 0);
+ NVIC_SetPriority(CRYPTO_IRQn, 1);
+ NVIC_SetPriority(SW_MAC_IRQn, 1);
+ NVIC_EnableIRQ(FIELD_IRQn);
+ NVIC_EnableIRQ(CALLBACK_IRQn);
+ NVIC_EnableIRQ(FRAME_IRQn);
+ NVIC_EnableIRQ(SW_MAC_IRQn);
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ /* Initialize non-zero fixed values in CCM blocks */
+ g_ble_phy_encrypt_data.b0[0] = 0x49;
+ g_ble_phy_encrypt_data.b1[1] = 0x01;
+ g_ble_phy_encrypt_data.ai[0] = 0x01;
+#endif
+
+ return 0;
+}
+
+void
+ble_phy_disable(void)
+{
+ MCU_DIAG_SER('D');
+
+ __disable_irq();
+
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_BS_CLEAR_Msk;
+
+ __NOP();
+ __NOP();
+ __NOP();
+ __NOP();
+ __NOP();
+
+ CMAC->CM_EXC_STAT_REG = CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk |
+ CMAC_CM_EXC_STAT_REG_EXC_BS_START_4THIS_Msk |
+ CMAC_CM_EXC_STAT_REG_EXC_CORR_TIMEOUT_Msk |
+ CMAC_CM_EXC_STAT_REG_EXC_BS_STOP_Msk |
+ CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk |
+ CMAC_CM_EXC_STAT_REG_EXC_PHY_TO_IDLE_4THIS_Msk |
+ CMAC_CM_EXC_STAT_REG_EXC_SW_MAC_Msk;
+
+ NVIC->ICPR[0] = (1 << FIELD_IRQn) | (1 << CALLBACK_IRQn) |
+ (1 << FRAME_IRQn) | (1 << SW_MAC_IRQn);
+
+ os_arch_cmac_bs_ctrl_irq_unblock();
+ g_sw_mac_exc = 0;
+
+ CMAC->CM_ERROR_DIS_REG = 0;
+
+ ble_rf_stop();
+
+ /*
+ * If ble_phy_disable is called precisely when access address was matched,
+ * ts1_dirty may not be cleared properly. This is because bs_clear will
+ * cause bitstream controller to be stopped and we won't get callback_irq,
+ * but seems like demodulator is still active for a while and will trigger
+ * ev1c_ts1_trigger on 1st symbol which will set ts1_dirty. We do not expect
+ * ts1_dirty to be set after bs_clear so we won't clear it. To workaround
+ * his, we can just clear it explicitly here after everything is already
+ * disabled.
+ */
+ (void)CMAC->CM_TS1_REG;
+
+ __enable_irq();
+
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
+}
+
+static void
+ble_phy_rx_setup_fields(void)
+{
+ /* Make sure CRC LFSR initial value is set */
+ CMAC_SETREGF(CM_CRC_REG, CRC_INIT_VAL, g_ble_phy_data.crc_init);
+
+ CMAC->CM_FIELD_PUSH_DATA_REG = g_ble_phy_data.access_addr;
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_ACCESS_ADDR;
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(0, 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_HEADER;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted) {
+ /* Only program one byte for encrypted payloads */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(2, 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_ENC_PAYLOAD;
+ } else {
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(2, 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_PAYLOAD;
+ }
+#else
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_RX(2, 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_RX_PAYLOAD;
+#endif
+}
+
+static void
+ble_phy_rx_setup_xcvr(void)
+{
+ uint8_t rf_chan = g_ble_phy_chan_to_rf[g_ble_phy_data.channel];
+
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV1C_CALLBACK_VALID_SET_Msk;
+
+ ble_rf_setup_rx(rf_chan, g_ble_phy_data.phy_mode_rx);
+
+ g_ble_phy_data.phy_rx_started = 0;
+}
+
+int
+ble_phy_rx(void)
+{
+ MCU_DIAG_SER('R');
+
+ ble_rf_configure();
+ ble_phy_rx_setup_xcvr();
+
+ CMAC->CM_FRAME_1_REG = CMAC_CM_FRAME_1_REG_FRAME_VALID_Msk;
+
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, CORR_WINDOW, 0);
+
+ ble_phy_rx_setup_fields();
+
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
+
+ return 0;
+}
+
+int
+ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+ uint32_t ll_val32;
+ int32_t time_till_start;
+
+ MCU_DIAG_SER('r');
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx);
+#endif
+
+ assert(ble_rf_is_enabled());
+
+ ble_phy_rx();
+
+ /* Get LL timer at cputime */
+ ll_val32 = ble_phy_convert_and_record_start_time(cputime, rem_usecs);
+
+ /* Add remaining usecs to get exact receive start time */
+ ll_val32 += rem_usecs;
+
+ /* Adjust start time for rx delays */
+ ll_val32 -= PHY_DELAY_POWER_UP_RX - g_ble_phy_data.path_delay_rx;
+
+ __disable_irq();
+ CMAC->CM_LL_TIMER1_9_0_EQ_X_REG = ll_val32;
+ CMAC->CM_EV_LINKUP_REG =
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_TMR1_9_0_EQ_X_Msk;
+
+ time_till_start = (int32_t)(ll_val32 - cmac_timer_read32());
+ if (time_till_start <= 0) {
+ /*
+ * Possible we missed the frame start! If we have, we need to start
+ * ASAP.
+ */
+ if ((CMAC->CM_EXC_STAT_REG & CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk) == 0) {
+ /* We missed start. Start now */
+ CMAC->CM_EV_LINKUP_REG =
+ CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_ASAP_Msk;
+ }
+ }
+ __enable_irq();
+
+ return 0;
+}
+
+int
+ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
+{
+ uint8_t *txbuf = g_ble_phy_tx_buf;
+ int rc;
+
+ MCU_DIAG_SER('T');
+
+ assert(CMAC->CM_FRAME_1_REG & CMAC_CM_FRAME_1_REG_FRAME_TX_Msk);
+
+ g_ble_phy_data.end_transition = end_trans;
+
+ /*
+ * Program required fields now so in worst case TX can continue while we
+ * are still preparing header and payload.
+ */
+ CMAC->CM_FIELD_PUSH_DATA_REG = g_ble_phy_data.access_addr & 1 ? 0x5555 : 0xaaaa;
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_PREAMBLE;
+ CMAC->CM_FIELD_PUSH_DATA_REG = g_ble_phy_data.access_addr;
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_ACCESS_ADDR;
+
+ /* Make sure CRC LFSR initial value is set */
+ CMAC_SETREGF(CM_CRC_REG, CRC_INIT_VAL, g_ble_phy_data.crc_init);
+
+ /* txbuf[0] is hdr_byte, txbuf[1] is pkt_len */
+ txbuf[1] = pducb(&txbuf[2], pducb_arg, &txbuf[0]);
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted && (txbuf[1] != 0)) {
+ /* We have to add the MIC to the length */
+ txbuf[1] += BLE_LL_DATA_MIC_LEN;
+
+ /* Program header field */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_TX(0, 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_PAYLOAD;
+
+ /* Program payload (and MIC) */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_TX(2, txbuf[1]);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_ENC_PAYLOAD;
+ } else {
+ /* Program header and payload fields */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_TX(0, txbuf[1] + 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_PAYLOAD;
+ }
+#else
+ /* Program header and payload fields */
+ CMAC->CM_FIELD_PUSH_DATA_REG = FIELD_DATA_REG_DMA_TX(0, txbuf[1] + 2);
+ CMAC->CM_FIELD_PUSH_CTRL_REG = FIELD_CTRL_REG_TX_PAYLOAD;
+#endif
+
+ /*
+ * If there was FIELD_ON_THR exception it means access address was already
+ * sent and we are likely too late here - abort.
+ */
+ if (CMAC->CM_EXC_STAT_REG & CMAC_CM_EXC_STAT_REG_EXC_FIELD_ON_THR_EXP_Msk) {
+ ble_phy_disable();
+ g_ble_phy_data.end_transition = BLE_PHY_TRANSITION_NONE;
+ STATS_INC(ble_phy_stats, tx_late);
+ rc = BLE_PHY_ERR_RADIO_STATE;
+ } else {
+ if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) {
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
+ }
+ STATS_INC(ble_phy_stats, tx_good);
+ STATS_INCN(ble_phy_stats, tx_bytes, txbuf[1] + 2);
+ rc = BLE_ERR_SUCCESS;
+ }
+
+ /* Now we can handle BS_CTRL */
+ CMAC->CM_ERROR_DIS_REG &= ~CMAC_CM_ERROR_DIS_REG_CM_FIELD1_ERR_Msk;
+ NVIC_EnableIRQ(FRAME_IRQn);
+ NVIC_EnableIRQ(FIELD_IRQn);
+
+ return rc;
+}
+
+int
+ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+ uint8_t rf_chan = g_ble_phy_chan_to_rf[g_ble_phy_data.channel];
+ uint32_t ll_val32;
+ int rc;
+
+ MCU_DIAG_SER('t');
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_mode_tx);
+#endif
+
+ assert(ble_rf_is_enabled());
+
+ ble_rf_configure();
+ ble_rf_setup_tx(rf_chan, g_ble_phy_data.phy_mode_tx);
+
+ ll_val32 = ble_phy_convert_and_record_start_time(cputime, rem_usecs);
+ ll_val32 += rem_usecs;
+ ll_val32 -= PHY_DELAY_POWER_UP_TX + g_ble_phy_data.path_delay_tx;
+ /* we can schedule TX only up to 1023us in advance */
+ assert((int32_t)(ll_val32 - cmac_timer_read32()) < 1024);
+
+ /*
+ * We do not want FIELD/FRAME interrupts or FIELD1_ERR until ble_phy_tx()
+ * has finished pushing all the fields. Also we do not want premature
+ * FRAME_ERR so disable it until we program FRAME1 properly. If we won't
+ * make configuration on time, assume tx_late and abort TX.
+ */
+ NVIC_DisableIRQ(FRAME_IRQn);
+ NVIC_DisableIRQ(FIELD_IRQn);
+ CMAC->CM_ERROR_DIS_REG |= CMAC_CM_ERROR_DIS_REG_CM_FIELD1_ERR_Msk |
+ CMAC_CM_ERROR_DIS_REG_CM_FRAME_ERR_Msk;
+
+ CMAC->CM_LL_TIMER1_9_0_EQ_X_REG = ll_val32;
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_TMR1_9_0_EQ_X_Msk;
+
+ if ((int32_t)(ll_val32 - cmac_timer_read32()) < 0) {
+ goto tx_late;
+ }
+
+ /*
+ * Program frame now since it needs to be ready for FRAME_START, we can
+ * push fields later
+ */
+ CMAC->CM_FRAME_1_REG = CMAC_CM_FRAME_1_REG_FRAME_VALID_Msk |
+ CMAC_CM_FRAME_1_REG_FRAME_TX_Msk |
+ CMAC_CM_FRAME_1_REG_FRAME_EXC_ON_BS_START_Msk;
+
+ /*
+ * There should be no EXC_FRAME_START here so if it already happened we
+ * need to assume tx_late and abort.
+ */
+ if (CMAC->CM_EXC_STAT_REG & CMAC_CM_EXC_STAT_REG_EXC_FRAME_START_Msk) {
+ goto tx_late;
+ }
+
+ CMAC->CM_ERROR_DIS_REG &= ~CMAC_CM_ERROR_DIS_REG_CM_FRAME_ERR_Msk;
+ rc = 0;
+
+ goto done;
+
+tx_late:
+ STATS_INC(ble_phy_stats, tx_late);
+ ble_phy_disable();
+ NVIC_EnableIRQ(FRAME_IRQn);
+ NVIC_EnableIRQ(FIELD_IRQn);
+ rc = BLE_PHY_ERR_TX_LATE;
+
+done:
+ return rc;
+}
+
+void
+ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
+{
+ g_ble_phy_data.txend_cb = txend_cb;
+ g_ble_phy_data.txend_arg = arg;
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+void
+ble_phy_tx_enc_start(void)
+{
+ struct ble_phy_encrypt_obj *enc;
+
+ enc = &g_ble_phy_encrypt_data;
+ enc->b0[15] = g_ble_phy_tx_buf[1] - 4;
+ enc->b1[2] = g_ble_phy_tx_buf[0] & BLE_LL_DATA_HDR_LLID_MASK;
+
+ /* XXX: should we check for busy? */
+ /* XXX: might not be needed, but for now terminate any crypto operations. */
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_ABORT_Msk;
+
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_IN_SEL_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_CTR_MAC_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_CTR_PLD_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_AUTH_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_ENC_DECN_Msk;
+
+ /* Start crypto */
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
+}
+
+void
+ble_phy_rx_enc_start(uint8_t len)
+{
+ struct ble_phy_encrypt_obj *enc;
+
+ enc = &g_ble_phy_encrypt_data;
+ enc->b0[15] = len - 4; /* length without MIC as length includes MIC */
+ enc->b1[2] = g_ble_phy_rx_buf[0] & BLE_LL_DATA_HDR_LLID_MASK;
+
+ /* XXX: should we check for busy? */
+ /* XXX: might not be needed, but for now terminate any crypto operations. */
+ //CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_ABORT_Msk;
+
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_OUT_SEL_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_CTR_MAC_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_CTR_PLD_EN_Msk |
+ CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_AUTH_EN_Msk;
+
+ /* Start crypto */
+ CMAC->CM_EV_SET_REG = CMAC_CM_EV_SET_REG_EV_CRYPTO_START_Msk;
+}
+
+void
+ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
+ uint8_t is_master)
+{
+ struct ble_phy_encrypt_obj *enc;
+
+ enc = &g_ble_phy_encrypt_data;
+ memcpy(enc->key, key, 16);
+ memcpy(&enc->b0[6], iv, 8);
+ put_le32(&enc->b0[1], pkt_counter);
+ enc->b0[5] = is_master ? 0x80 : 0;
+ memcpy(&enc->ai[6], iv, 8);
+ put_le32(&enc->ai[1], pkt_counter);
+ enc->ai[5] = enc->b0[5];
+
+ g_ble_phy_data.phy_encrypted = 1;
+
+ /* Program key registers */
+ CMAC->CM_CRYPTO_KEY_31_0_REG = get_le32(&enc->key[0]);
+ CMAC->CM_CRYPTO_KEY_63_32_REG = get_le32(&enc->key[4]);
+ CMAC->CM_CRYPTO_KEY_95_64_REG = get_le32(&enc->key[8]);
+ CMAC->CM_CRYPTO_KEY_127_96_REG = get_le32(&enc->key[12]);
+
+ /* Program ADRx registers */
+ CMAC->CM_CRYPTO_IN_ADR0_REG = (uint32_t)enc->b1;
+ CMAC->CM_CRYPTO_IN_ADR1_REG = (uint32_t)enc->b0;
+ CMAC->CM_CRYPTO_IN_ADR2_REG = (uint32_t)&g_ble_phy_tx_buf[2];
+ CMAC->CM_CRYPTO_IN_ADR3_REG = (uint32_t)enc->ai;
+ CMAC->CM_CRYPTO_OUT_ADR_REG = (uint32_t)&g_ble_phy_rx_buf[2];
+
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_PBUF_CLR_Msk;
+}
+
+void
+ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
+{
+ struct ble_phy_encrypt_obj *enc;
+
+ enc = &g_ble_phy_encrypt_data;
+ put_le32(&enc->b0[1], pkt_counter);
+ enc->b0[5] = dir ? 0x80 : 0;
+ put_le32(&enc->ai[1], pkt_counter);
+ enc->ai[5] = enc->b0[5];
+
+ CMAC->CM_CRYPTO_CTRL_REG = CMAC_CM_CRYPTO_CTRL_REG_CM_CRYPTO_SW_REQ_PBUF_CLR_Msk;
+}
+
+void
+ble_phy_encrypt_disable(void)
+{
+ g_ble_phy_data.phy_encrypted = 0;
+}
+#endif
+
+int
+ble_phy_txpwr_set(int dbm)
+{
+#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
+ if (g_cmac_shared_data.debug.tx_power_override != INT8_MAX) {
+ ble_rf_set_tx_power(g_cmac_shared_data.debug.tx_power_override);
+ } else {
+ ble_rf_set_tx_power(dbm);
+ }
+#else
+ ble_rf_set_tx_power(dbm);
+#endif
+
+ return 0;
+}
+
+int
+ble_phy_txpower_round(int dbm)
+{
+ return 0;
+}
+
+void
+ble_phy_set_rx_pwr_compensation(int8_t compensation)
+{
+}
+
+int
+ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crc_init)
+{
+ uint8_t rf_chan = g_ble_phy_chan_to_rf[chan];
+
+ assert(chan < BLE_PHY_NUM_CHANS);
+
+ if (chan >= BLE_PHY_NUM_CHANS) {
+ return BLE_PHY_ERR_INV_PARAM;
+ }
+
+ g_ble_phy_data.channel = chan;
+ g_ble_phy_data.access_addr = access_addr;
+ g_ble_phy_data.crc_init = crc_init;
+
+ CMAC_SETREGF(CM_PHY_CTRL2_REG, PHY_RF_CHANNEL, rf_chan);
+
+ return 0;
+}
+
+void
+ble_phy_restart_rx(void)
+{
+ /* XXX: for now, we will disable the phy using ble_phy_disable and then
+ re-enable it
+ */
+ ble_phy_disable();
+
+ /* Apply mode before starting RX */
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_mode_rx);
+#endif
+
+ /* Setup phy to rx again */
+ ble_phy_rx();
+
+ /* Start reception now */
+ CMAC->CM_EV_LINKUP_REG = CMAC_CM_EV_LINKUP_REG_LU_FRAME_START_2_ASAP_Msk;
+}
+
+uint32_t
+ble_phy_access_addr_get(void)
+{
+ return g_ble_phy_data.access_addr;
+}
+
+int
+ble_phy_state_get(void)
+{
+ return g_ble_phy_data.phy_state;
+}
+
+int
+ble_phy_rx_started(void)
+{
+ return g_ble_phy_data.phy_rx_started;
+}
+
+uint8_t
+ble_phy_xcvr_state_get(void)
+{
+ return ble_rf_is_enabled();
+}
+
+uint8_t
+ble_phy_max_data_pdu_pyld(void)
+{
+ return BLE_LL_DATA_PDU_MAX_PYLD;
+}
+
+void
+ble_phy_resolv_list_enable(void)
+{
+ g_ble_phy_data.phy_privacy = 1;
+
+ ble_hw_resolv_proc_enable();
+}
+
+void
+ble_phy_resolv_list_disable(void)
+{
+ ble_hw_resolv_proc_disable();
+
+ g_ble_phy_data.phy_privacy = 0;
+}
+
+void
+ble_phy_rfclk_enable(void)
+{
+ ble_rf_enable();
+}
+
+void
+ble_phy_rfclk_disable(void)
+{
+ /* XXX We can't disable RF while PHY_BUSY is asserted so let's wait a bit */
+ while (CMAC->CM_DIAG_WORD2_REG & CMAC_CM_DIAG_WORD2_REG_DIAG2_PHY_BUSY_BUF_Msk);
+
+ ble_rf_disable();
+}
+
+#if MYNEWT_VAL(BLE_LL_DTM)
+void
+ble_phy_enable_dtm(void)
+{
+ g_ble_phy_data.phy_whitening = 0;
+}
+
+void
+ble_phy_disable_dtm(void)
+{
+ g_ble_phy_data.phy_whitening = 1;
+}
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf.c b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf.c
new file mode 100644
index 00000000..806f4ea8
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf.c
@@ -0,0 +1,747 @@
+/*
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include "mcu/mcu.h"
+#include "mcu/cmac_timer.h"
+#include "controller/ble_phy.h"
+#include "cmac_driver/cmac_shared.h"
+#include "ble_rf_priv.h"
+
+#define RF_CALIBRATION_0 (0x01)
+#define RF_CALIBRATION_1 (0x02)
+#define RF_CALIBRATION_2 (0x04)
+
+static const int8_t g_ble_rf_power_lvls[] = {
+ -18, -12, -8, -6, -3, -2, -1, 0, 1, 2, 3, 4, 4, 5, 6
+};
+
+struct ble_phy_rf_data {
+ uint8_t tx_power_cfg0;
+ uint8_t tx_power_cfg1;
+ uint8_t tx_power_cfg2;
+ uint8_t tx_power_cfg3;
+ uint32_t cal_res_1;
+ uint32_t cal_res_2;
+ uint32_t trim_val1_tx_1;
+ uint32_t trim_val1_tx_2;
+ uint32_t trim_val2_tx;
+ uint32_t trim_val2_rx;
+ uint8_t calibrate_req;
+};
+
+static struct ble_phy_rf_data g_ble_phy_rf_data;
+
+static inline uint32_t
+get_reg32(uint32_t addr)
+{
+ volatile uint32_t *reg = (volatile uint32_t *)addr;
+
+ return *reg;
+}
+
+static inline uint32_t
+get_reg32_bits(uint32_t addr, uint32_t mask)
+{
+ volatile uint32_t *reg = (volatile uint32_t *)addr;
+
+ return (*reg & mask) >> __builtin_ctz(mask);
+}
+
+static inline void
+set_reg8(uint32_t addr, uint8_t val)
+{
+ volatile uint8_t *reg = (volatile uint8_t *)addr;
+
+ *reg = val;
+}
+
+static inline void
+set_reg16(uint32_t addr, uint16_t val)
+{
+ volatile uint16_t *reg = (volatile uint16_t *)addr;
+
+ *reg = val;
+}
+
+static inline void
+set_reg32(uint32_t addr, uint32_t val)
+{
+ volatile uint32_t *reg = (volatile uint32_t *)addr;
+
+ *reg = val;
+}
+
+static inline void
+set_reg32_bits(uint32_t addr, uint32_t mask, uint32_t val)
+{
+ volatile uint32_t *reg = (volatile uint32_t *)addr;
+
+ *reg = (*reg & (~mask)) | (val << __builtin_ctz(mask));
+}
+
+static inline void
+set_reg32_mask(uint32_t addr, uint32_t mask, uint32_t val)
+{
+ volatile uint32_t *reg = (volatile uint32_t *)addr;
+
+ *reg = (*reg & (~mask)) | (val & mask);
+}
+
+static inline void
+set_reg16_mask(uint32_t addr, uint16_t mask, uint16_t val)
+{
+ volatile uint16_t *reg = (volatile uint16_t *)addr;
+
+ *reg = (*reg & (~mask)) | (val & mask);
+}
+
+static void
+delay_us(uint32_t delay_us)
+{
+ while (delay_us--) {
+ __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
+ __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
+ __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP();
+ __NOP(); __NOP(); __NOP(); __NOP();
+ }
+}
+
+static void
+ble_rf_apply_trim(volatile uint32_t *tv, unsigned len)
+{
+ while (len) {
+ *(volatile uint32_t *)tv[0] = tv[1];
+ len -= 2;
+ tv += 2;
+ }
+}
+
+static void
+ble_rf_apply_calibration(void)
+{
+ set_reg32(0x40020094, g_ble_phy_rf_data.cal_res_1);
+ if (g_ble_phy_rf_data.cal_res_2) {
+ set_reg32_bits(0x40022018, 0xff800000, g_ble_phy_rf_data.cal_res_2);
+ set_reg32_bits(0x40022018, 0x00007fc0, g_ble_phy_rf_data.cal_res_2);
+ }
+}
+
+static inline void
+ble_rf_ldo_on(void)
+{
+ set_reg8(0x40020004, 9);
+}
+
+static inline void
+ble_rf_ldo_off(void)
+{
+ set_reg8(0x40020004, 0);
+}
+
+static inline void
+ble_rf_rfcu_enable(void)
+{
+ set_reg32_bits(0x50000010, 0x00000020, 1);
+}
+
+static inline void
+ble_rf_rfcu_disable(void)
+{
+ set_reg32_bits(0x50000010, 0x00000020, 0);
+}
+
+static void
+ble_rf_rfcu_apply_recommended_settings(void)
+{
+ set_reg16_mask(0x400200a0, 0x0001, 0x0001);
+ set_reg16_mask(0x40021020, 0x03f0, 0x02f5);
+ set_reg32_mask(0x40021018, 0x001fffff, 0x005a5809);
+ set_reg32_mask(0x4002101c, 0x00001e01, 0x0040128c);
+ set_reg32_mask(0x40021004, 0xffffff1f, 0x64442404);
+ set_reg32_mask(0x40021008, 0xfcfcffff, 0x6b676665);
+ set_reg32_mask(0x4002100c, 0x00fcfcfc, 0x9793736f);
+ set_reg32_mask(0x40021010, 0x1f1f1c1f, 0x04072646);
+ set_reg32_mask(0x40020000, 0x001ff000, 0x0f099820);
+ set_reg16_mask(0x40020348, 0x00ff, 0x0855);
+ set_reg16(0x40020350, 0x0234);
+ set_reg16(0x40020354, 0x0a34);
+ set_reg16(0x40020358, 0x0851);
+ set_reg16(0x4002035c, 0x0a26);
+ set_reg16(0x40020360, 0x0858);
+ set_reg16(0x4002102c, 0xdfe7);
+ set_reg32_mask(0x4002103c, 0x00c00000, 0x0024a19f);
+ set_reg16_mask(0x40021000, 0x0008, 0x000b);
+ set_reg16_mask(0x40020238, 0x03e0, 0x02c0);
+ set_reg16_mask(0x4002023c, 0x03e0, 0x02c0);
+ set_reg16_mask(0x40020244, 0x03e0, 0x0250);
+ set_reg16_mask(0x40020248, 0x03e0, 0x02a0);
+ set_reg16_mask(0x4002024c, 0x03e0, 0x02c0);
+ set_reg16_mask(0x40020288, 0x03e0, 0x0300);
+ set_reg16_mask(0x4002029c, 0x001f, 0x0019);
+ set_reg16_mask(0x4002003c, 0x6000, 0x0788);
+ set_reg16_mask(0x40020074, 0x7f00, 0x2007);
+ set_reg32_mask(0x40020080, 0x00333330, 0x00222224);
+ set_reg32_mask(0x40020068, 0x00000f0f, 0x00000f0d);
+}
+
+static void
+ble_rf_rfcu_apply_settings(void)
+{
+ ble_rf_apply_trim(g_cmac_shared_data.trim.rfcu,
+ g_cmac_shared_data.trim.rfcu_len);
+ ble_rf_rfcu_apply_recommended_settings();
+}
+
+static inline void
+ble_rf_synth_enable(void)
+{
+ set_reg8(0x40020005, 3);
+}
+
+static inline void
+ble_rf_synth_disable(void)
+{
+ set_reg8(0x40020005, 0);
+ __NOP();
+ __NOP();
+}
+
+static bool
+ble_rf_synth_is_enabled(void)
+{
+ return get_reg32_bits(0x40020004, 256);
+}
+
+static void
+ble_rf_synth_apply_recommended_settings(void)
+{
+ set_reg32_mask(0x40022048, 0x0000000c, 0x000000d5);
+ set_reg32_mask(0x40022050, 0x00000300, 0x00000300);
+ set_reg16_mask(0x40022024, 0x0001, 0x0001);
+}
+
+static void
+ble_rf_synth_apply_settings(void)
+{
+ ble_rf_apply_trim(g_cmac_shared_data.trim.synth,
+ g_cmac_shared_data.trim.synth_len);
+ ble_rf_synth_apply_recommended_settings();
+}
+
+static void
+ble_rf_calibration_0(void)
+{
+ uint32_t bkp[10];
+
+ bkp[0] = get_reg32(0x40020208);
+ bkp[1] = get_reg32(0x40020250);
+ bkp[2] = get_reg32(0x40020254);
+ bkp[3] = get_reg32(0x40021028);
+ bkp[4] = get_reg32(0x40020020);
+ bkp[5] = get_reg32(0x40020294);
+ bkp[6] = get_reg32(0x4002103C);
+ bkp[7] = get_reg32(0x400200A8);
+ bkp[8] = get_reg32(0x40020000);
+ bkp[9] = get_reg32(0x40022000);
+
+ set_reg32_bits(0x40020000, 0x00000002, 0);
+ set_reg32_bits(0x40022000, 0x00000001, 0);
+ set_reg32_mask(0x4002103C, 0x00201c00, 0x00001c00);
+ set_reg32_bits(0x400200A8, 0x00000001, 1);
+ set_reg8(0x40020006, 1);
+ set_reg32(0x40020208, 0);
+ set_reg32(0x40020250, 0);
+ set_reg32(0x40020254, 0);
+ set_reg32(0x40021028, 0x00F8A494);
+ set_reg32(0x40020020, 8);
+ set_reg32(0x40020294, 0);
+ set_reg32(0x40020024, 0);
+
+ delay_us(5);
+ if (get_reg32_bits(0x40020020, 0x00000002)) {
+ goto done;
+ }
+
+ set_reg32_bits(0x40020020, 0x00000001, 1);
+ delay_us(15);
+ if (!get_reg32_bits(0x40020020, 0x00000001)) {
+ goto done;
+ }
+
+ delay_us(300);
+ if (get_reg32_bits(0x40020020, 0x00000001)) {
+ goto done;
+ }
+
+done:
+ set_reg32(0x40020024, 0);
+ set_reg32(0x40020208, bkp[0]);
+ set_reg32(0x40020250, bkp[1]);
+ set_reg32(0x40020254, bkp[2]);
+ set_reg32(0x40021028, bkp[3]);
+ set_reg32(0x40020020, bkp[4]);
+ set_reg32(0x40020294, bkp[5]);
+ set_reg32(0x4002103C, bkp[6]);
+ set_reg32(0x400200A8, bkp[7]);
+ set_reg32(0x40020000, bkp[8]);
+ set_reg32(0x40022000, bkp[9]);
+}
+
+static void
+ble_rf_calibration_1(void)
+{
+ uint32_t bkp[12];
+ uint32_t val;
+
+ bkp[0] = get_reg32(0x40020020);
+ bkp[1] = get_reg32(0x40020208);
+ bkp[2] = get_reg32(0x40020250);
+ bkp[3] = get_reg32(0x40020254);
+ bkp[4] = get_reg32(0x40020218);
+ bkp[5] = get_reg32(0x4002021c);
+ bkp[6] = get_reg32(0x40020220);
+ bkp[7] = get_reg32(0x40020270);
+ bkp[8] = get_reg32(0x4002027c);
+ bkp[9] = get_reg32(0x4002101c);
+ bkp[10] = get_reg32(0x40020000);
+ bkp[11] = get_reg32(0x40022000);
+
+ set_reg32(0x4002103c, 0x0124a21f);
+ set_reg32(0x40020208, 0);
+ set_reg32(0x40020250, 0);
+ set_reg32(0x40020254, 0);
+ set_reg32(0x40020218, 0);
+ set_reg32(0x4002021c, 0);
+ set_reg32(0x40020220, 0);
+ set_reg32(0x40020270, 0);
+ set_reg32(0x4002027c, 0);
+ set_reg32(0x40020000, 0x0f168820);
+ set_reg32_bits(0x40022000, 0x00000001, 0);
+ set_reg32_bits(0x4002101c, 0x00001e00, 0);
+ set_reg32_bits(0x4002001c, 0x0000003f, 47);
+ set_reg8(0x40020006, 1);
+ set_reg32(0x40020020, 16);
+ set_reg32_bits(0x4002003c, 0x00000800, 1);
+ set_reg32(0x40020024, 0);
+
+ delay_us(5);
+ if (get_reg32_bits(0x40020020, 0x00000002)) {
+ goto done;
+ }
+
+ set_reg32_bits(0x40020020, 0x00000001, 1);
+ delay_us(15);
+ if (!get_reg32_bits(0x40020020, 0x00000001)) {
+ goto done;
+ }
+
+ delay_us(300);
+ if (get_reg32_bits(0x40020020, 0x00000001)) {
+ goto done;
+ }
+
+ val = get_reg32(0x40020090);
+ set_reg32_bits(0x40020094, 0x0000000f, val);
+ set_reg32_bits(0x40020094, 0x00000f00, val);
+ set_reg32_bits(0x40020094, 0x000f0000, val);
+ set_reg32_bits(0x40020094, 0x0f000000, val);
+ g_ble_phy_rf_data.cal_res_1 = get_reg32(0x40020094);
+
+done:
+ set_reg32(0x40020024, 0);
+ set_reg32(0x40020020, bkp[0]);
+ set_reg32(0x40020208, bkp[1]);
+ set_reg32(0x40020250, bkp[2]);
+ set_reg32(0x40020254, bkp[3]);
+ set_reg32(0x40020218, bkp[4]);
+ set_reg32(0x4002021c, bkp[5]);
+ set_reg32(0x40020220, bkp[6]);
+ set_reg32(0x40020270, bkp[7]);
+ set_reg32(0x4002027c, bkp[8]);
+ set_reg32(0x4002101c, bkp[9]);
+ set_reg32(0x40020000, bkp[10]);
+ set_reg32(0x40022000, bkp[11]);
+ set_reg32_bits(0x4002003c, 0x00000800, 0);
+}
+
+static void
+ble_rf_calibration_2(void)
+{
+ uint32_t bkp[2];
+ uint32_t k1;
+
+ set_reg8(0x40020005, 3);
+ set_reg32(0x40022000, 0x00000300);
+ set_reg32_bits(0x40022004, 0x0000007f, 20);
+ bkp[0] = get_reg32(0x40022040);
+ set_reg32(0x40022040, 0xffffffff);
+ set_reg32_bits(0x40022018, 0x0000003f, 0);
+ set_reg32_bits(0x40022018, 0x00008000, 0);
+ set_reg32_bits(0x4002201c, 0x00000600, 2);
+ set_reg32_bits(0x4002201c, 0x00000070, 4);
+ set_reg32_bits(0x40022030, 0x3f000000, 22);
+ set_reg32_bits(0x40022030, 0x00000fc0, 24);
+ set_reg32_bits(0x40022030, 0x0000003f, 24);
+ set_reg8(0x4002201c, 0x43);
+ set_reg8(0x40020006, 2);
+ delay_us(2);
+ bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
+ set_reg32_bits(0x4002024c, 0x000003e0, 0);
+ set_reg8(0x40020006, 1);
+ set_reg32_bits(0x400200ac, 0x00000003, 3);
+ delay_us(30);
+ delay_us(100);
+ set_reg8(0x40020005, 3);
+ k1 = get_reg32_bits(0x40022088, 0x000001ff);
+ set_reg32(0x400200ac, 0);
+ delay_us(20);
+ set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
+ delay_us(10);
+
+ set_reg32_bits(0x40022018, 0xff800000, k1);
+ set_reg32_bits(0x40022018, 0x00007fc0, k1);
+ set_reg8(0x4002201c, 0x41);
+ set_reg32_bits(0x4002201c, 0x00000600, 2);
+ set_reg8(0x40020006, 2);
+ delay_us(2);
+ bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
+ set_reg32_bits(0x4002024c, 0x000003e0, 0);
+ set_reg8(0x40020006, 1);
+ set_reg32_bits(0x400200ac, 0x00000003, 3);
+ delay_us(30);
+ delay_us(100);
+ set_reg8(0x40020005, 3);
+ k1 = get_reg32_bits(0x40022088, 0x1ff);
+ set_reg32(0x400200ac, 0);
+ delay_us(20);
+ set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
+ delay_us(10);
+
+ set_reg32_bits(0x40022018, 0xff800000, k1);
+ set_reg32_bits(0x40022018, 0x00007fc0, k1);
+ set_reg8(0x4002201c, 0x41);
+ set_reg32_bits(0x4002201c, 0x00000600, 2);
+ set_reg8(0x40020006, 2);
+ delay_us(2);
+ bkp[1] = get_reg32_bits(0x4002024c, 0x000003e0);
+ set_reg32_bits(0x4002024c, 0x000003e0, 0);
+ set_reg8(0x40020006, 1);
+ set_reg32_bits(0x400200ac, 0x00000003, 3);
+ delay_us(30);
+ delay_us(100);
+ set_reg8(0x40020005, 3);
+ k1 = get_reg32_bits(0x40022088, 0x000001ff);
+ set_reg32_bits(0x40022018, 0xff800000, k1);
+ set_reg32_bits(0x40022018, 0x00007fc0, k1);
+ set_reg32_bits(0x4002201c, 0x00000001, 0);
+ set_reg32(0x40022040, bkp[0]);
+ set_reg32_bits(0x40022018, 0x0000003f, 0x1c);
+ set_reg32_bits(0x40022018, 0x00008000, 0);
+ set_reg32_bits(0x40022030, 0x3f000000, 28);
+ set_reg32_bits(0x40022030, 0x00000fc0, 30);
+ set_reg32_bits(0x40022030, 0x0000003f, 30);
+ set_reg32(0x400200ac, 0);
+ delay_us(20);
+ set_reg32_bits(0x4002024c, 0x000003e0, bkp[1]);
+ delay_us(10);
+
+ g_ble_phy_rf_data.cal_res_2 = k1;
+}
+
+static void
+ble_rf_calibrate_int(uint8_t mask)
+{
+ __disable_irq();
+
+ ble_rf_enable();
+ delay_us(20);
+
+ ble_rf_synth_disable();
+ ble_rf_synth_enable();
+ ble_rf_synth_apply_settings();
+ set_reg8(0x40020005, 1);
+
+ if (mask & RF_CALIBRATION_0) {
+ ble_rf_calibration_0();
+ }
+ if (mask & RF_CALIBRATION_1) {
+ ble_rf_calibration_1();
+ }
+ if (mask & RF_CALIBRATION_2) {
+ ble_rf_calibration_2();
+ }
+
+ ble_rf_disable();
+
+ __enable_irq();
+
+#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
+ g_cmac_shared_data.debug.cal_res_1 = g_ble_phy_rf_data.cal_res_1;
+ g_cmac_shared_data.debug.cal_res_2 = g_ble_phy_rf_data.cal_res_2;
+#endif
+}
+
+bool
+ble_rf_try_recalibrate(uint32_t idle_time_us)
+{
+ /* Run recalibration if we have at least 1ms of time to spare and RF is
+ * currently disabled. Calibration is much shorter than 1ms, but that gives
+ * us good margin to make sure we can finish before next event.
+ */
+ if (!g_ble_phy_rf_data.calibrate_req || (idle_time_us < 1000) ||
+ ble_rf_is_enabled()) {
+ return false;
+ }
+
+ ble_rf_calibrate_int(RF_CALIBRATION_2);
+
+ g_ble_phy_rf_data.calibrate_req = 0;
+
+ return true;
+}
+
+static uint32_t
+ble_rf_find_trim_reg(volatile uint32_t *tv, unsigned len, uint32_t reg)
+{
+ while (len) {
+ if (tv[0] == reg) {
+ return tv[1];
+ }
+ len -= 2;
+ tv += 2;
+ }
+
+ return 0;
+}
+
+void
+ble_rf_init(void)
+{
+ static bool done = false;
+ uint32_t val;
+
+ ble_rf_disable();
+
+ if (done) {
+ return;
+ }
+
+ val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode1,
+ g_cmac_shared_data.trim.rfcu_mode1_len,
+ 0x4002004c);
+ g_ble_phy_rf_data.trim_val1_tx_1 = val;
+
+ val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu_mode2,
+ g_cmac_shared_data.trim.rfcu_mode2_len,
+ 0x4002004c);
+ g_ble_phy_rf_data.trim_val1_tx_2 = val;
+
+ if (!g_ble_phy_rf_data.trim_val1_tx_1 || !g_ble_phy_rf_data.trim_val1_tx_2) {
+ val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.rfcu,
+ g_cmac_shared_data.trim.rfcu_len,
+ 0x4002004c);
+ if (!val) {
+ val = 0x0300;
+ }
+ g_ble_phy_rf_data.trim_val1_tx_1 = val;
+ g_ble_phy_rf_data.trim_val1_tx_2 = val;
+ }
+
+ val = ble_rf_find_trim_reg(g_cmac_shared_data.trim.synth,
+ g_cmac_shared_data.trim.synth_len,
+ 0x40022038);
+ if (!val) {
+ val = 0x0198ff03;
+ }
+ g_ble_phy_rf_data.trim_val2_rx = val;
+ g_ble_phy_rf_data.trim_val2_tx = val;
+ set_reg32_bits((uint32_t)&g_ble_phy_rf_data.trim_val2_tx, 0x0001ff00, 0x87);
+
+#if MYNEWT_VAL(CMAC_DEBUG_DATA_ENABLE)
+ g_cmac_shared_data.debug.trim_val1_tx_1 = g_ble_phy_rf_data.trim_val1_tx_1;
+ g_cmac_shared_data.debug.trim_val1_tx_2 = g_ble_phy_rf_data.trim_val1_tx_2;
+ g_cmac_shared_data.debug.trim_val2_tx = g_ble_phy_rf_data.trim_val2_tx;
+ g_cmac_shared_data.debug.trim_val2_rx = g_ble_phy_rf_data.trim_val2_rx;
+#endif
+
+ ble_rf_rfcu_enable();
+ ble_rf_rfcu_apply_settings();
+ g_ble_phy_rf_data.tx_power_cfg1 = get_reg32_bits(0x500000a4, 0xf0);
+ g_ble_phy_rf_data.tx_power_cfg2 = get_reg32_bits(0x40020238, 0x000003e0);
+ g_ble_phy_rf_data.tx_power_cfg3 = 0;
+ ble_rf_rfcu_disable();
+
+ ble_rf_calibrate_int(RF_CALIBRATION_0 | RF_CALIBRATION_1 | RF_CALIBRATION_2);
+
+ done = true;
+}
+
+void
+ble_rf_enable(void)
+{
+ if (ble_rf_is_enabled()) {
+ return;
+ }
+
+ ble_rf_rfcu_enable();
+ ble_rf_rfcu_apply_settings();
+ ble_rf_ldo_on();
+}
+
+void
+ble_rf_configure(void)
+{
+ if (ble_rf_synth_is_enabled()) {
+ return;
+ }
+
+ ble_rf_synth_enable();
+ ble_rf_synth_apply_settings();
+}
+
+void
+ble_rf_stop(void)
+{
+ ble_rf_synth_disable();
+ set_reg8(0x40020006, 0);
+}
+
+void
+ble_rf_disable(void)
+{
+ ble_rf_stop();
+ ble_rf_ldo_off();
+ ble_rf_rfcu_disable();
+}
+
+bool
+ble_rf_is_enabled(void)
+{
+ return get_reg32_bits(0x40020008, 5) == 5;
+}
+
+void
+ble_rf_calibrate_req(void)
+{
+ g_ble_phy_rf_data.calibrate_req = 1;
+}
+
+void
+ble_rf_setup_tx(uint8_t rf_chan, uint8_t phy_mode)
+{
+ set_reg32_bits(0x40020000, 0x0f000000, g_ble_phy_rf_data.tx_power_cfg0);
+ set_reg32_bits(0x500000a4, 0x000000f0, g_ble_phy_rf_data.tx_power_cfg1);
+ set_reg32_bits(0x40020238, 0x000003e0, g_ble_phy_rf_data.tx_power_cfg2);
+ set_reg32_bits(0x40020234, 0x000003e0, g_ble_phy_rf_data.tx_power_cfg3);
+
+ if (g_ble_phy_rf_data.tx_power_cfg0 < 13) {
+ set_reg32(0x4002004c, g_ble_phy_rf_data.trim_val1_tx_1);
+ } else {
+ set_reg32(0x4002004c, g_ble_phy_rf_data.trim_val1_tx_2);
+ }
+ set_reg8(0x40020005, 3);
+ set_reg8(0x40022004, rf_chan);
+ if (phy_mode == BLE_PHY_MODE_2M) {
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ set_reg32(0x40022000, 0x00000303);
+#else
+ set_reg32(0x40022000, 0x00000003);
+#endif
+ } else {
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ set_reg32(0x40022000, 0x00000300);
+#else
+ set_reg32(0x40022000, 0x00000000);
+#endif
+ }
+
+ ble_rf_apply_calibration();
+
+ set_reg32_bits(0x40022050, 0x00000200, 1);
+ set_reg32_bits(0x40022050, 0x00000100, 0);
+ set_reg32_bits(0x40022048, 0x01ffff00, 0x7700);
+ set_reg32(0x40022038, g_ble_phy_rf_data.trim_val2_tx);
+
+ set_reg8(0x40020006, 3);
+}
+
+void
+ble_rf_setup_rx(uint8_t rf_chan, uint8_t phy_mode)
+{
+ set_reg32_bits(0x500000a4, 0x000000f0, g_ble_phy_rf_data.tx_power_cfg1);
+ set_reg8(0x40020005, 3);
+ set_reg8(0x40022004, rf_chan);
+ if (phy_mode == BLE_PHY_MODE_2M) {
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ set_reg32(0x40022000, 0x00000303);
+ set_reg32(0x40020000, 0x0f11b823);
+ set_reg32(0x4002103c, 0x0125261b);
+#else
+ set_reg32(0x40022000, 0x00000003);
+ set_reg32(0x40020000, 0x0f0c2803);
+ set_reg32(0x4002103c, 0x0125a61b);
+#endif
+ set_reg32(0x40021020, 0x000002f5);
+ set_reg32(0x4002102c, 0x0000d1d5);
+ } else {
+#if MYNEWT_VAL(BLE_PHY_RF_HP_MODE)
+ set_reg32(0x40022000, 0x00000300);
+ set_reg32(0x40020000, 0x0f099820);
+ set_reg32(0x4002103c, 0x0124a21f);
+#else
+ set_reg32(0x40022000, 0x00000000);
+ set_reg32(0x40020000, 0x0f062800);
+ set_reg32(0x4002103c, 0x01051e1f);
+#endif
+ set_reg32(0x40021020, 0x000002f5);
+ set_reg32(0x4002102c, 0x0000dfe7);
+ }
+
+ ble_rf_apply_calibration();
+
+ set_reg32_bits(0x40022050, 0x00000200, 1);
+ set_reg32_bits(0x40022050, 0x00000100, 1);
+ set_reg32_bits(0x40022048, 0x01ffff00, 0);
+ set_reg32(0x40022038, g_ble_phy_rf_data.trim_val2_rx);
+
+ set_reg8(0x40020006, 3);
+}
+
+void
+ble_rf_set_tx_power(int dbm)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(g_ble_rf_power_lvls); i++) {
+ if (g_ble_rf_power_lvls[i] >= dbm) {
+ break;
+ }
+ }
+
+ g_ble_phy_rf_data.tx_power_cfg0 = i + 1;
+}
+
+int8_t
+ble_rf_get_rssi(void)
+{
+ return (501 * get_reg32_bits(0x40021038, 0x000003ff) - 493000) / 4096;
+}
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf_priv.h b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf_priv.h
new file mode 100644
index 00000000..50c2e4a7
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/src/ble_rf_priv.h
@@ -0,0 +1,38 @@
+/*
+ * 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 _BLE_RF_PRIV_H_
+#define _BLE_RF_PRIV_H_
+
+void ble_rf_init(void);
+void ble_rf_enable(void);
+void ble_rf_stop(void);
+void ble_rf_disable(void);
+bool ble_rf_is_enabled(void);
+void ble_rf_configure(void);
+
+void ble_rf_calibrate(void);
+
+void ble_rf_setup_tx(uint8_t rf_chan, uint8_t mode);
+void ble_rf_setup_rx(uint8_t rf_chan, uint8_t mode);
+
+void ble_rf_set_tx_power(int dbm);
+int8_t ble_rf_get_rssi(void);
+
+#endif /* _BLE_RF_PRIV_H_ */
diff --git a/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/syscfg.yml b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/syscfg.yml
new file mode 100644
index 00000000..a82b62e5
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/dialog_cmac/syscfg.yml
@@ -0,0 +1,29 @@
+# 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:
+ BLE_PHY_RF_HP_MODE:
+ description: Enable high-performance RF mode.
+ value: 1
+
+ BLE_PHY_DEBUG_DSER:
+ description: Enable DSER output from PHY
+ value: 0
+
+syscfg.restrictions:
+ - BLE_LL_RFMGMT_ENABLE_TIME == 0 || BLE_LL_RFMGMT_ENABLE_TIME >= 20