summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/nimble/drivers
diff options
context:
space:
mode:
authorJean-François Milants <jf@codingfield.com>2021-02-02 22:09:00 +0100
committerJean-François Milants <jf@codingfield.com>2021-02-02 22:09:00 +0100
commitd90b7274fa8bbfa09f79660b45b550d91f7b0125 (patch)
tree434e4aa362b0083eb9df7bea4f1358787174e5b4 /src/libs/mynewt-nimble/nimble/drivers
parent9c35b6fe5dc889b589b979dd7c650c70f302854b (diff)
Update to nimble 1.3 master branch commit 82153e744833821e20e9a8b0d61c38b2b0dbcfe1
WARNING : heartbeat task is disabled!
Diffstat (limited to 'src/libs/mynewt-nimble/nimble/drivers')
-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
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/native/src/ble_hw.c23
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/nrf5340/include/ble/xcvr.h50
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/nrf5340/pkg.yml31
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_hw.c475
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy.c1820
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy_trace.c44
-rw-r--r--src/libs/mynewt-nimble/nimble/drivers/nrf5340/syscfg.yml23
16 files changed, 5583 insertions, 4 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
diff --git a/src/libs/mynewt-nimble/nimble/drivers/native/src/ble_hw.c b/src/libs/mynewt-nimble/nimble/drivers/native/src/ble_hw.c
index 5eb1eb95..8aa29d32 100644
--- a/src/libs/mynewt-nimble/nimble/drivers/native/src/ble_hw.c
+++ b/src/libs/mynewt-nimble/nimble/drivers/native/src/ble_hw.c
@@ -20,6 +20,8 @@
#include <stdint.h>
#include <assert.h>
#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
#include "syscfg/syscfg.h"
#include "os/os.h"
#include "nimble/ble.h"
@@ -32,6 +34,9 @@
/* We use this to keep track of which entries are set to valid addresses */
static uint8_t g_ble_hw_whitelist_mask;
+static ble_rng_isr_cb_t rng_cb;
+static bool rng_started;
+
/* Returns public device address or -1 if not present */
int
ble_hw_get_public_addr(ble_addr_t *addr)
@@ -143,7 +148,8 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb)
int
ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
{
- return -1;
+ rng_cb = cb;
+ return 0;
}
/**
@@ -154,7 +160,15 @@ ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
int
ble_hw_rng_start(void)
{
- return -1;
+ rng_started = true;
+
+ if (rng_cb) {
+ while (rng_started) {
+ rng_cb(rand());
+ }
+ }
+
+ return 0;
}
/**
@@ -165,7 +179,8 @@ ble_hw_rng_start(void)
int
ble_hw_rng_stop(void)
{
- return -1;
+ rng_started = false;
+ return 0;
}
/**
@@ -176,7 +191,7 @@ ble_hw_rng_stop(void)
uint8_t
ble_hw_rng_read(void)
{
- return 0;
+ return rand();
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
diff --git a/src/libs/mynewt-nimble/nimble/drivers/nrf5340/include/ble/xcvr.h b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/include/ble/xcvr.h
new file mode 100644
index 00000000..df6ef700
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/include/ble/xcvr.h
@@ -0,0 +1,50 @@
+/*
+ * 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_RX_RADIO_RAMPUP_USECS (40)
+#define XCVR_TX_RADIO_RAMPUP_USECS (40)
+
+/*
+ * NOTE: we have to account for the RTC output compare issue. We want it to be
+ * 5 ticks.
+ */
+#define XCVR_PROC_DELAY_USECS (153)
+#define XCVR_RX_START_DELAY_USECS (XCVR_RX_RADIO_RAMPUP_USECS)
+#define XCVR_TX_START_DELAY_USECS (XCVR_TX_RADIO_RAMPUP_USECS)
+#define XCVR_TX_SCHED_DELAY_USECS (XCVR_TX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
+#define XCVR_RX_SCHED_DELAY_USECS (XCVR_RX_START_DELAY_USECS + XCVR_PROC_DELAY_USECS)
+
+/*
+ * 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/nrf5340/pkg.yml b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/pkg.yml
new file mode 100644
index 00000000..3ff44212
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/pkg.yml
@@ -0,0 +1,31 @@
+#
+# 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/nrf5340
+pkg.description: BLE driver for nRF5340 systems.
+pkg.author: "Apache Mynewt <dev@mynewt.apache.org>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+ - ble
+ - bluetooth
+
+pkg.apis: ble_driver
+pkg.deps:
+ - nimble
+ - nimble/controller
diff --git a/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_hw.c b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_hw.c
new file mode 100644
index 00000000..bbe61697
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_hw.c
@@ -0,0 +1,475 @@
+/*
+ * 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 <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <syscfg/syscfg.h>
+#include <os/os.h>
+#include <nimble/ble.h>
+#include <nimble/nimble_opt.h>
+#include <controller/ble_hw.h>
+
+#include <ble/xcvr.h>
+#include <mcu/cmsis_nvic.h>
+#include <os/os_trace_api.h>
+
+/* Total number of resolving list elements */
+#define BLE_HW_RESOLV_LIST_SIZE (16)
+
+/* We use this to keep track of which entries are set to valid addresses */
+static uint8_t g_ble_hw_whitelist_mask;
+
+/* Random number generator isr callback */
+static ble_rng_isr_cb_t ble_rng_isr_cb;
+
+/* If LL privacy is enabled, allocate memory for AAR */
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+
+/* The NRF5340 supports up to 16 IRK entries */
+#if (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE) < 16)
+#define NRF_IRK_LIST_ENTRIES (MYNEWT_VAL(BLE_LL_RESOLV_LIST_SIZE))
+#else
+#define NRF_IRK_LIST_ENTRIES (16)
+#endif
+
+/* NOTE: each entry is 16 bytes long. */
+uint32_t g_nrf_irk_list[NRF_IRK_LIST_ENTRIES * 4];
+
+/* Current number of IRK entries */
+uint8_t g_nrf_num_irks;
+
+#endif
+
+/* Returns public device address or -1 if not present */
+int
+ble_hw_get_public_addr(ble_addr_t *addr)
+{
+ uint32_t addr_high;
+ uint32_t addr_low;
+
+ /* Does FICR have a public address */
+ if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) != 0) {
+ return -1;
+ }
+
+ /* Copy into device address. We can do this because we know platform */
+ addr_low = NRF_FICR_NS->DEVICEADDR[0];
+ addr_high = NRF_FICR_NS->DEVICEADDR[1];
+ memcpy(addr->val, &addr_low, 4);
+ memcpy(&addr->val[4], &addr_high, 2);
+ addr->type = BLE_ADDR_PUBLIC;
+
+ return 0;
+}
+
+/* Returns random static address or -1 if not present */
+int
+ble_hw_get_static_addr(ble_addr_t *addr)
+{
+ int rc;
+
+ if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) == 1) {
+ memcpy(addr->val, (void *)&NRF_FICR_NS->DEVICEADDR[0], 4);
+ memcpy(&addr->val[4], (void *)&NRF_FICR_NS->DEVICEADDR[1], 2);
+ addr->val[5] |= 0xc0;
+ addr->type = BLE_ADDR_RANDOM;
+ rc = 0;
+ } else {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+/**
+ * Clear the whitelist
+ *
+ * @return int
+ */
+void
+ble_hw_whitelist_clear(void)
+{
+ NRF_RADIO_NS->DACNF = 0;
+ g_ble_hw_whitelist_mask = 0;
+}
+
+/**
+ * Add a device to the hw whitelist
+ *
+ * @param addr
+ * @param addr_type
+ *
+ * @return int 0: success, BLE error code otherwise
+ */
+int
+ble_hw_whitelist_add(const uint8_t *addr, uint8_t addr_type)
+{
+ int i;
+ uint32_t mask;
+
+ /* Find first ununsed device address match element */
+ mask = 0x01;
+ for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
+ if ((mask & g_ble_hw_whitelist_mask) == 0) {
+ NRF_RADIO_NS->DAB[i] = get_le32(addr);
+ NRF_RADIO_NS->DAP[i] = get_le16(addr + 4);
+ if (addr_type == BLE_ADDR_RANDOM) {
+ NRF_RADIO_NS->DACNF |= (mask << 8);
+ }
+ g_ble_hw_whitelist_mask |= mask;
+ return BLE_ERR_SUCCESS;
+ }
+ mask <<= 1;
+ }
+
+ return BLE_ERR_MEM_CAPACITY;
+}
+
+/**
+ * Remove a device from the hw whitelist
+ *
+ * @param addr
+ * @param addr_type
+ *
+ */
+void
+ble_hw_whitelist_rmv(const uint8_t *addr, uint8_t addr_type)
+{
+ int i;
+ uint16_t dap;
+ uint16_t txadd;
+ uint32_t dab;
+ uint32_t mask;
+
+ /* Find first ununsed device address match element */
+ dab = get_le32(addr);
+ dap = get_le16(addr + 4);
+ txadd = NRF_RADIO_NS->DACNF >> 8;
+ mask = 0x01;
+ for (i = 0; i < BLE_HW_WHITE_LIST_SIZE; ++i) {
+ if (mask & g_ble_hw_whitelist_mask) {
+ if ((dab == NRF_RADIO_NS->DAB[i]) && (dap == NRF_RADIO_NS->DAP[i])) {
+ if (addr_type == !!(txadd & mask)) {
+ break;
+ }
+ }
+ }
+ mask <<= 1;
+ }
+
+ if (i < BLE_HW_WHITE_LIST_SIZE) {
+ g_ble_hw_whitelist_mask &= ~mask;
+ NRF_RADIO_NS->DACNF &= ~mask;
+ }
+}
+
+/**
+ * Returns the size of the whitelist in HW
+ *
+ * @return int Number of devices allowed in whitelist
+ */
+uint8_t
+ble_hw_whitelist_size(void)
+{
+ return BLE_HW_WHITE_LIST_SIZE;
+}
+
+/**
+ * Enable the whitelisted devices
+ */
+void
+ble_hw_whitelist_enable(void)
+{
+ /* Enable the configured device addresses */
+ NRF_RADIO_NS->DACNF |= g_ble_hw_whitelist_mask;
+}
+
+/**
+ * Disables the whitelisted devices
+ */
+void
+ble_hw_whitelist_disable(void)
+{
+ /* Disable all whitelist devices */
+ NRF_RADIO_NS->DACNF &= 0x0000ff00;
+}
+
+/**
+ * Boolean function which returns true ('1') if there is a match on the
+ * whitelist.
+ *
+ * @return int
+ */
+int
+ble_hw_whitelist_match(void)
+{
+ return NRF_RADIO_NS->EVENTS_DEVMATCH;
+}
+
+/* Encrypt data */
+int
+ble_hw_encrypt_block(struct ble_encryption_block *ecb)
+{
+ int rc;
+ uint32_t end;
+ uint32_t err;
+
+ /* Stop ECB */
+ NRF_ECB_NS->TASKS_STOPECB = 1;
+ /* XXX: does task stop clear these counters? Anyway to do this quicker? */
+ NRF_ECB_NS->EVENTS_ENDECB = 0;
+ NRF_ECB_NS->EVENTS_ERRORECB = 0;
+ NRF_ECB_NS->ECBDATAPTR = (uint32_t)ecb;
+
+ /* Start ECB */
+ NRF_ECB_NS->TASKS_STARTECB = 1;
+
+ /* Wait till error or done */
+ rc = 0;
+ while (1) {
+ end = NRF_ECB_NS->EVENTS_ENDECB;
+ err = NRF_ECB_NS->EVENTS_ERRORECB;
+ if (end || err) {
+ if (err) {
+ rc = -1;
+ }
+ break;
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * Random number generator ISR.
+ */
+static void
+ble_rng_isr(void)
+{
+ uint8_t rnum;
+
+ os_trace_isr_enter();
+
+ /* No callback? Clear and disable interrupts */
+ if (ble_rng_isr_cb == NULL) {
+ NRF_RNG_NS->INTENCLR = 1;
+ NRF_RNG_NS->EVENTS_VALRDY = 0;
+ (void)NRF_RNG_NS->SHORTS;
+ os_trace_isr_exit();
+ return;
+ }
+
+ /* If there is a value ready grab it */
+ if (NRF_RNG_NS->EVENTS_VALRDY) {
+ NRF_RNG_NS->EVENTS_VALRDY = 0;
+ rnum = (uint8_t)NRF_RNG_NS->VALUE;
+ (*ble_rng_isr_cb)(rnum);
+ }
+
+ os_trace_isr_exit();
+}
+
+/**
+ * Initialize the random number generator
+ *
+ * @param cb
+ * @param bias
+ *
+ * @return int
+ */
+int
+ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias)
+{
+ /* Set bias */
+ if (bias) {
+ NRF_RNG_NS->CONFIG = 1;
+ } else {
+ NRF_RNG_NS->CONFIG = 0;
+ }
+
+ /* If we were passed a function pointer we need to enable the interrupt */
+ if (cb != NULL) {
+#ifndef RIOT_VERSION
+ NVIC_SetPriority(RNG_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
+#endif
+#if MYNEWT
+ NVIC_SetVector(RNG_IRQn, (uint32_t)ble_rng_isr);
+#else
+ ble_npl_hw_set_isr(RNG_IRQn, ble_rng_isr);
+#endif
+ NVIC_EnableIRQ(RNG_IRQn);
+ ble_rng_isr_cb = cb;
+ }
+
+ return 0;
+}
+
+/**
+ * Start the random number generator
+ *
+ * @return int
+ */
+int
+ble_hw_rng_start(void)
+{
+ os_sr_t sr;
+
+ /* No need for interrupt if there is no callback */
+ OS_ENTER_CRITICAL(sr);
+ NRF_RNG_NS->EVENTS_VALRDY = 0;
+ if (ble_rng_isr_cb) {
+ NRF_RNG_NS->INTENSET = 1;
+ }
+ NRF_RNG_NS->TASKS_START = 1;
+ OS_EXIT_CRITICAL(sr);
+
+ return 0;
+}
+
+/**
+ * Stop the random generator
+ *
+ * @return int
+ */
+int
+ble_hw_rng_stop(void)
+{
+ os_sr_t sr;
+
+ /* No need for interrupt if there is no callback */
+ OS_ENTER_CRITICAL(sr);
+ NRF_RNG_NS->INTENCLR = 1;
+ NRF_RNG_NS->TASKS_STOP = 1;
+ NRF_RNG_NS->EVENTS_VALRDY = 0;
+ OS_EXIT_CRITICAL(sr);
+
+ return 0;
+}
+
+/**
+ * Read the random number generator.
+ *
+ * @return uint8_t
+ */
+uint8_t
+ble_hw_rng_read(void)
+{
+ uint8_t rnum;
+
+ /* Wait for a sample */
+ while (NRF_RNG_NS->EVENTS_VALRDY == 0) {
+ }
+
+ NRF_RNG_NS->EVENTS_VALRDY = 0;
+ rnum = (uint8_t)NRF_RNG_NS->VALUE;
+
+ return rnum;
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+/**
+ * Clear the resolving list
+ *
+ * @return int
+ */
+void
+ble_hw_resolv_list_clear(void)
+{
+ g_nrf_num_irks = 0;
+}
+
+/**
+ * Add a device to the hw resolving list
+ *
+ * @param irk Pointer to IRK to add
+ *
+ * @return int 0: success, BLE error code otherwise
+ */
+int
+ble_hw_resolv_list_add(uint8_t *irk)
+{
+ uint32_t *nrf_entry;
+
+ /* Find first ununsed device address match element */
+ if (g_nrf_num_irks == NRF_IRK_LIST_ENTRIES) {
+ return BLE_ERR_MEM_CAPACITY;
+ }
+
+ /* Copy into irk list */
+ nrf_entry = &g_nrf_irk_list[4 * g_nrf_num_irks];
+ memcpy(nrf_entry, irk, 16);
+
+ /* Add to total */
+ ++g_nrf_num_irks;
+ return BLE_ERR_SUCCESS;
+}
+
+/**
+ * Remove a device from the hw resolving list
+ *
+ * @param index Index of IRK to remove
+ */
+void
+ble_hw_resolv_list_rmv(int index)
+{
+ uint32_t *irk_entry;
+
+ if (index < g_nrf_num_irks) {
+ --g_nrf_num_irks;
+ irk_entry = &g_nrf_irk_list[index];
+ if (g_nrf_num_irks > index) {
+ memmove(irk_entry, irk_entry + 4, 16 * (g_nrf_num_irks - index));
+ }
+ }
+}
+
+/**
+ * Returns the size of the resolving list. NOTE: this returns the maximum
+ * allowable entries in the HW. Configuration options may limit this.
+ *
+ * @return int Number of devices allowed in resolving list
+ */
+uint8_t
+ble_hw_resolv_list_size(void)
+{
+ return BLE_HW_RESOLV_LIST_SIZE;
+}
+
+/**
+ * Called to determine if the address received was resolved.
+ *
+ * @return int Negative values indicate unresolved address; positive values
+ * indicate index in resolving list of resolved address.
+ */
+int
+ble_hw_resolv_list_match(void)
+{
+ uint32_t index;
+
+ if (NRF_AAR_NS->EVENTS_END) {
+ if (NRF_AAR_NS->EVENTS_RESOLVED) {
+ index = NRF_AAR_NS->STATUS;
+ return (int)index;
+ }
+ }
+
+ return -1;
+}
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy.c b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy.c
new file mode 100644
index 00000000..e07bbaa1
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy.c
@@ -0,0 +1,1820 @@
+/*
+ * 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 <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <syscfg/syscfg.h>
+#include <os/os.h>
+#include <nimble/ble.h>
+#include <nimble/nimble_opt.h>
+#include <nimble/nimble_npl.h>
+#include <controller/ble_phy.h>
+
+#include <ble/xcvr.h>
+#include <controller/ble_phy_trace.h>
+#include <controller/ble_ll.h>
+#include <mcu/nrf5340_net_clock.h>
+#include <mcu/cmsis_nvic.h>
+
+/*
+ * NOTE: This code uses 0-5 DPPI channels so care should be taken when using
+ * DPPI somewhere else.
+ * TODO maybe we could reduce number of used channels if we reuse same channel
+ * for mutually exclusive events but for now make it simpler to debug.
+ */
+
+#define DPPI_CH_TIMER0_EVENTS_COMPARE_0 0
+#define DPPI_CH_TIMER0_EVENTS_COMPARE_3 1
+#define DPPI_CH_RADIO_EVENTS_END 2
+#define DPPI_CH_RADIO_EVENTS_BCMATCH 3
+#define DPPI_CH_RADIO_EVENTS_ADDRESS 4
+#define DPPI_CH_RTC0_EVENTS_COMPARE_0 5
+
+#define DPPI_CH_ENABLE_ALL (DPPIC_CHEN_CH0_Msk | DPPIC_CHEN_CH1_Msk | DPPIC_CHEN_CH2_Msk | \
+ DPPIC_CHEN_CH3_Msk | DPPIC_CHEN_CH4_Msk | DPPIC_CHEN_CH5_Msk)
+
+#define DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_0 ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << TIMER_PUBLISH_COMPARE_CHIDX_Pos) | \
+ (TIMER_PUBLISH_COMPARE_EN_Enabled << TIMER_PUBLISH_COMPARE_EN_Pos))
+#define DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_3 ((DPPI_CH_TIMER0_EVENTS_COMPARE_3 << TIMER_PUBLISH_COMPARE_CHIDX_Pos) | \
+ (TIMER_PUBLISH_COMPARE_EN_Enabled << TIMER_PUBLISH_COMPARE_EN_Pos))
+#define DPPI_PUBLISH_RADIO_EVENTS_END ((DPPI_CH_RADIO_EVENTS_END << RADIO_PUBLISH_END_CHIDX_Pos) | \
+ (RADIO_PUBLISH_END_EN_Enabled << RADIO_PUBLISH_END_EN_Pos))
+#define DPPI_PUBLISH_RADIO_EVENTS_BCMATCH ((DPPI_CH_RADIO_EVENTS_BCMATCH << RADIO_PUBLISH_BCMATCH_CHIDX_Pos) | \
+ (RADIO_PUBLISH_BCMATCH_EN_Enabled << RADIO_PUBLISH_BCMATCH_EN_Pos))
+#define DPPI_PUBLISH_RADIO_EVENTS_ADDRESS ((DPPI_CH_RADIO_EVENTS_ADDRESS << RADIO_PUBLISH_ADDRESS_CHIDX_Pos) | \
+ (RADIO_PUBLISH_ADDRESS_EN_Enabled << RADIO_PUBLISH_ADDRESS_EN_Pos))
+#define DPPI_PUBLISH_RTC0_EVENTS_COMPARE_0 ((DPPI_CH_RTC0_EVENTS_COMPARE_0 << RTC_PUBLISH_COMPARE_CHIDX_Pos) | \
+ (RTC_PUBLISH_COMPARE_EN_Enabled << RTC_PUBLISH_COMPARE_EN_Pos))
+
+#define DPPI_SUBSCRIBE_TIMER0_TASKS_START(_enable) ((DPPI_CH_RTC0_EVENTS_COMPARE_0 << TIMER_SUBSCRIBE_START_CHIDX_Pos) | \
+ ((_enable) << TIMER_SUBSCRIBE_START_EN_Pos))
+#define DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE1(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << TIMER_SUBSCRIBE_CAPTURE_CHIDX_Pos) | \
+ ((_enable) << TIMER_SUBSCRIBE_CAPTURE_EN_Pos))
+#define DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE2(_enable) ((DPPI_CH_RADIO_EVENTS_END << TIMER_SUBSCRIBE_CAPTURE_CHIDX_Pos) | \
+ ((_enable) << TIMER_SUBSCRIBE_CAPTURE_EN_Pos))
+#define DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << TIMER_SUBSCRIBE_CAPTURE_CHIDX_Pos) | \
+ ((_enable) << TIMER_SUBSCRIBE_CAPTURE_EN_Pos))
+#define DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(_enable) ((DPPI_CH_TIMER0_EVENTS_COMPARE_3 << RADIO_SUBSCRIBE_DISABLE_CHIDX_Pos) | \
+ ((_enable) << RADIO_SUBSCRIBE_DISABLE_EN_Pos))
+#define DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(_enable) ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << RADIO_SUBSCRIBE_RXEN_CHIDX_Pos) | \
+ ((_enable) << RADIO_SUBSCRIBE_RXEN_EN_Pos))
+#define DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(_enable) ((DPPI_CH_TIMER0_EVENTS_COMPARE_0 << RADIO_SUBSCRIBE_TXEN_CHIDX_Pos) | \
+ ((_enable) << RADIO_SUBSCRIBE_TXEN_EN_Pos))
+#define DPPI_SUBSCRIBE_AAR_TASKS_START(_enable) ((DPPI_CH_RADIO_EVENTS_BCMATCH << AAR_SUBSCRIBE_START_CHIDX_Pos) | \
+ ((_enable) << AAR_SUBSCRIBE_START_EN_Pos))
+#define DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(_enable) ((DPPI_CH_RADIO_EVENTS_ADDRESS << CCM_SUBSCRIBE_CRYPT_CHIDX_Pos) | \
+ ((_enable) << CCM_SUBSCRIBE_CRYPT_EN_Pos))
+
+extern uint8_t g_nrf_num_irks;
+extern uint32_t g_nrf_irk_list[];
+
+/* To disable all radio interrupts */
+#define NRF_RADIO_IRQ_MASK_ALL (0x34FF)
+
+/*
+ * We configure the nrf with a 1 byte S0 field, 8 bit length field, and
+ * zero bit S1 field. The preamble is 8 bits long.
+ */
+#define NRF_LFLEN_BITS (8)
+#define NRF_S0LEN (1)
+#define NRF_S1LEN_BITS (0)
+#define NRF_CILEN_BITS (2)
+#define NRF_TERMLEN_BITS (3)
+
+/* Maximum length of frames */
+#define NRF_MAXLEN (255)
+#define NRF_BALEN (3) /* For base address of 3 bytes */
+
+/* NRF_RADIO_NS->PCNF0 configuration values */
+#define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \
+ (RADIO_PCNF0_S1INCL_Msk) | \
+ (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \
+ (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos)
+#define NRF_PCNF0_1M (NRF_PCNF0) | \
+ (RADIO_PCNF0_PLEN_8bit << RADIO_PCNF0_PLEN_Pos)
+#define NRF_PCNF0_2M (NRF_PCNF0) | \
+ (RADIO_PCNF0_PLEN_16bit << RADIO_PCNF0_PLEN_Pos)
+#define NRF_PCNF0_CODED (NRF_PCNF0) | \
+ (RADIO_PCNF0_PLEN_LongRange << RADIO_PCNF0_PLEN_Pos) | \
+ (NRF_CILEN_BITS << RADIO_PCNF0_CILEN_Pos) | \
+ (NRF_TERMLEN_BITS << RADIO_PCNF0_TERMLEN_Pos)
+
+/* BLE PHY data structure */
+struct ble_phy_obj {
+ uint8_t phy_stats_initialized;
+ int8_t phy_txpwr_dbm;
+ uint8_t phy_chan;
+ uint8_t phy_state;
+ uint8_t phy_transition;
+ uint8_t phy_transition_late;
+ uint8_t phy_rx_started;
+ uint8_t phy_encrypted;
+ uint8_t phy_privacy;
+ uint8_t phy_tx_pyld_len;
+ uint8_t phy_cur_phy_mode;
+ uint8_t phy_tx_phy_mode;
+ uint8_t phy_rx_phy_mode;
+ uint8_t phy_bcc_offset;
+ int8_t rx_pwr_compensation;
+ uint32_t phy_aar_scratch;
+ uint32_t phy_access_address;
+ struct ble_mbuf_hdr rxhdr;
+ void *txend_arg;
+ ble_phy_tx_end_func txend_cb;
+ uint32_t phy_start_cputime;
+};
+struct ble_phy_obj g_ble_phy_data;
+
+/* XXX: if 27 byte packets desired we can make this smaller */
+/* Global transmit/receive buffer */
+static uint32_t g_ble_phy_tx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
+static uint32_t g_ble_phy_rx_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+/* Make sure word-aligned for faster copies */
+static uint32_t g_ble_phy_enc_buf[(BLE_PHY_MAX_PDU_LEN + 3) / 4];
+#endif
+
+/* RF center frequency for each channel index (offset from 2400 MHz) */
+static const uint8_t g_ble_phy_chan_freq[BLE_PHY_NUM_CHANS] = {
+ 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, /* 0-9 */
+ 24, 28, 30, 32, 34, 36, 38, 40, 42, 44, /* 10-19 */
+ 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, /* 20-29 */
+ 66, 68, 70, 72, 74, 76, 78, 2, 26, 80, /* 30-39 */
+};
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+/* packet start offsets (in usecs) */
+static const uint16_t g_ble_phy_mode_pkt_start_off[BLE_PHY_NUM_MODE] = {
+ [BLE_PHY_MODE_1M] = 40,
+ [BLE_PHY_MODE_2M] = 24,
+ [BLE_PHY_MODE_CODED_125KBPS] = 376,
+ [BLE_PHY_MODE_CODED_500KBPS] = 376
+};
+#endif
+
+/* Various radio timings */
+/* Radio ramp-up times in usecs (fast mode) */
+#define BLE_PHY_T_TXENFAST (XCVR_TX_RADIO_RAMPUP_USECS)
+#define BLE_PHY_T_RXENFAST (XCVR_RX_RADIO_RAMPUP_USECS)
+
+/* delay between EVENTS_READY and start of tx */
+static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = {
+ [BLE_PHY_MODE_1M] = 4,
+ [BLE_PHY_MODE_2M] = 3,
+ [BLE_PHY_MODE_CODED_125KBPS] = 5,
+ [BLE_PHY_MODE_CODED_500KBPS] = 5
+};
+/* delay between EVENTS_END and end of txd packet */
+static const uint8_t g_ble_phy_t_txenddelay[BLE_PHY_NUM_MODE] = {
+ [BLE_PHY_MODE_1M] = 4,
+ [BLE_PHY_MODE_2M] = 3,
+ [BLE_PHY_MODE_CODED_125KBPS] = 9,
+ [BLE_PHY_MODE_CODED_500KBPS] = 3
+};
+/* delay between rxd access address (w/ TERM1 for coded) and EVENTS_ADDRESS */
+static const uint8_t g_ble_phy_t_rxaddrdelay[BLE_PHY_NUM_MODE] = {
+ [BLE_PHY_MODE_1M] = 6,
+ [BLE_PHY_MODE_2M] = 2,
+ [BLE_PHY_MODE_CODED_125KBPS] = 17,
+ [BLE_PHY_MODE_CODED_500KBPS] = 17
+};
+/* delay between end of rxd packet and EVENTS_END */
+static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = {
+ [BLE_PHY_MODE_1M] = 6,
+ [BLE_PHY_MODE_2M] = 2,
+ [BLE_PHY_MODE_CODED_125KBPS] = 27,
+ [BLE_PHY_MODE_CODED_500KBPS] = 22
+};
+
+/* 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_ENCRYPTION)
+/*
+ * Per nordic, the number of bytes needed for scratch is 16 + MAX_PKT_SIZE.
+ * However, when I used a smaller size it still overwrote the scratchpad. Until
+ * I figure this out I am just going to allocate 67 words so we have enough
+ * space for 267 bytes of scratch. I used 268 bytes since not sure if this
+ * needs to be aligned and burning a byte is no big deal.
+ *
+ *#define NRF_ENC_SCRATCH_WORDS (((MYNEWT_VAL(BLE_LL_MAX_PKT_SIZE) + 16) + 3) / 4)
+ */
+#define NRF_ENC_SCRATCH_WORDS (67)
+
+static uint32_t nrf_encrypt_scratchpad[NRF_ENC_SCRATCH_WORDS];
+
+struct nrf_ccm_data {
+ uint8_t key[16];
+ uint64_t pkt_counter;
+ uint8_t dir_bit;
+ uint8_t iv[8];
+} __attribute__((packed));
+
+static struct nrf_ccm_data nrf_ccm_data;
+#endif
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+
+uint32_t
+ble_phy_mode_pdu_start_off(int phy_mode)
+{
+ return g_ble_phy_mode_pkt_start_off[phy_mode];
+}
+
+static void
+ble_phy_mode_apply(uint8_t phy_mode)
+{
+ if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) {
+ return;
+ }
+
+ switch (phy_mode) {
+ case BLE_PHY_MODE_1M:
+ NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_1Mbit;
+ NRF_RADIO_NS->PCNF0 = NRF_PCNF0_1M;
+ break;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
+ case BLE_PHY_MODE_2M:
+ NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_2Mbit;
+ NRF_RADIO_NS->PCNF0 = NRF_PCNF0_2M;
+ break;
+#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+ case BLE_PHY_MODE_CODED_125KBPS:
+ NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR125Kbit;
+ NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED;
+ break;
+ case BLE_PHY_MODE_CODED_500KBPS:
+ NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR500Kbit;
+ NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED;
+ break;
+#endif
+ default:
+ assert(0);
+ }
+
+ g_ble_phy_data.phy_cur_phy_mode = phy_mode;
+}
+#endif
+
+void
+ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode)
+{
+ g_ble_phy_data.phy_tx_phy_mode = tx_phy_mode;
+ g_ble_phy_data.phy_rx_phy_mode = rx_phy_mode;
+}
+
+int
+ble_phy_get_cur_phy(void)
+{
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ switch (g_ble_phy_data.phy_cur_phy_mode) {
+ case BLE_PHY_MODE_1M:
+ return BLE_PHY_1M;
+ case BLE_PHY_MODE_2M:
+ return BLE_PHY_2M;
+ case BLE_PHY_MODE_CODED_125KBPS:
+ case BLE_PHY_MODE_CODED_500KBPS:
+ return BLE_PHY_CODED;
+ default:
+ assert(0);
+ return -1;
+ }
+#else
+ return BLE_PHY_1M;
+#endif
+}
+
+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 (true) {
+ /*
+ * 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] "+r" (dst), [src] "+r" (src),
+ [len] "+r" (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] "+r" (rem_len)
+ : [dst] "r" (dst), [src] "r" (src)
+ : "r3", "memory"
+ );
+
+ /* Copy header */
+ memcpy(BLE_MBUF_HDR_PTR(rxpdu), &g_ble_phy_data.rxhdr,
+ sizeof(struct ble_mbuf_hdr));
+}
+
+/**
+ * Called when we want to wait if the radio is in either the rx or tx
+ * disable states. We want to wait until that state is over before doing
+ * anything to the radio
+ */
+static void
+nrf_wait_disabled(void)
+{
+ uint32_t state;
+
+ state = NRF_RADIO_NS->STATE;
+ if (state != RADIO_STATE_STATE_Disabled) {
+ if ((state == RADIO_STATE_STATE_RxDisable) ||
+ (state == RADIO_STATE_STATE_TxDisable)) {
+ /* This will end within a short time (6 usecs). Just poll */
+ while (NRF_RADIO_NS->STATE == state) {
+ /* If this fails, something is really wrong. Should last
+ * no more than 6 usecs
+ */
+ }
+ }
+ }
+}
+
+static int
+ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx)
+{
+ uint32_t next_cc;
+ uint32_t cur_cc;
+ uint32_t cntr;
+ uint32_t delta;
+
+ /*
+ * We need to adjust start time to include radio ramp-up and TX pipeline
+ * delay (the latter only if applicable, so only for TX).
+ *
+ * Radio ramp-up time is 40 usecs and TX delay is 3 or 5 usecs depending on
+ * phy, thus we'll offset RTC by 2 full ticks (61 usecs) and then compensate
+ * using TIMER0 with 1 usec precision.
+ */
+
+ cputime -= 2;
+ rem_usecs += 61;
+ if (tx) {
+ rem_usecs -= BLE_PHY_T_TXENFAST;
+ rem_usecs -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode];
+ } else {
+ rem_usecs -= BLE_PHY_T_RXENFAST;
+ }
+
+ /*
+ * rem_usecs will be no more than 2 ticks, but if it is more than single
+ * tick then we should better count one more low-power tick rather than
+ * 30 high-power usecs. Also make sure we don't set TIMER0 CC to 0 as the
+ * compare won't occur.
+ */
+
+ if (rem_usecs > 30) {
+ cputime++;
+ rem_usecs -= 30;
+ }
+
+ /*
+ * Can we set the RTC compare to start TIMER0? We can do it if:
+ * a) Current compare value is not N+1 or N+2 ticks from current
+ * counter.
+ * b) The value we want to set is not at least N+2 from current
+ * counter.
+ *
+ * NOTE: since the counter can tick 1 while we do these calculations we
+ * need to account for it.
+ */
+ next_cc = cputime & 0xffffff;
+ cur_cc = NRF_RTC0_NS->CC[0];
+ cntr = NRF_RTC0_NS->COUNTER;
+
+ delta = (cur_cc - cntr) & 0xffffff;
+ if ((delta <= 3) && (delta != 0)) {
+ return -1;
+ }
+ delta = (next_cc - cntr) & 0xffffff;
+ if ((delta & 0x800000) || (delta < 3)) {
+ return -1;
+ }
+
+ /* Clear and set TIMER0 to fire off at proper time */
+ NRF_TIMER0_NS->TASKS_CLEAR = 1;
+ NRF_TIMER0_NS->CC[0] = rem_usecs;
+ NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0;
+
+ /* Set RTC compare to start TIMER0 */
+ NRF_RTC0_NS->EVENTS_COMPARE[0] = 0;
+ NRF_RTC0_NS->CC[0] = next_cc;
+ NRF_RTC0_NS->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
+
+ /* Enable PPI */
+ NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(1);
+
+ /* Store the cputime at which we set the RTC */
+ g_ble_phy_data.phy_start_cputime = cputime;
+
+ return 0;
+}
+
+static int
+ble_phy_set_start_now(void)
+{
+ os_sr_t sr;
+ uint32_t now;
+
+ OS_ENTER_CRITICAL(sr);
+
+ /*
+ * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not
+ * occur in such case.
+ */
+ NRF_TIMER0_NS->TASKS_CLEAR = 1;
+ NRF_TIMER0_NS->CC[0] = 1;
+ NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0;
+
+ /*
+ * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks
+ * from current value to guarantee triggering compare event, but let's set
+ * it to N+3 to account for possible extra tick on RTC0 during these
+ * operations.
+ */
+ now = os_cputime_get32();
+ NRF_RTC0_NS->EVENTS_COMPARE[0] = 0;
+ NRF_RTC0_NS->CC[0] = now + 3;
+ NRF_RTC0_NS->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
+
+ /* Enable PPI */
+ NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(1);
+
+ /*
+ * Store the cputime at which we set the RTC
+ *
+ * XXX Compare event may be triggered on previous CC value (if it was set to
+ * less than N+2) so in rare cases actual start time may be 2 ticks earlier
+ * than what we expect. Since this is only used on RX, it may cause AUX scan
+ * to be scheduled 1 or 2 ticks too late so we'll miss it - it's acceptable
+ * for now.
+ */
+ g_ble_phy_data.phy_start_cputime = now + 3;
+
+ OS_EXIT_CRITICAL(sr);
+
+ return 0;
+}
+
+void
+ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
+{
+ uint32_t end_time;
+ uint8_t phy;
+
+ phy = g_ble_phy_data.phy_cur_phy_mode;
+
+ if (txrx == BLE_PHY_WFR_ENABLE_TXRX) {
+ /* RX shall start exactly T_IFS after TX end captured in CC[2] */
+ end_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS;
+ /* Adjust for delay between EVENT_END and actual TX end time */
+ end_time += g_ble_phy_t_txenddelay[tx_phy_mode];
+ /* Wait a bit longer due to allowed active clock accuracy */
+ end_time += 2;
+ /*
+ * It's possible that we'll capture PDU start time at the end of timer
+ * cycle and since wfr expires at the beginning of calculated timer
+ * cycle it can be almost 1 usec too early. Let's compensate for this
+ * by waiting 1 usec more.
+ */
+ end_time += 1;
+ } else {
+ /*
+ * RX shall start no later than wfr_usecs after RX enabled.
+ * CC[0] is the time of RXEN so adjust for radio ram-up.
+ * Do not add jitter since this is already covered by LL.
+ */
+ end_time = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST + wfr_usecs;
+ }
+
+ /*
+ * Note: on LE Coded EVENT_ADDRESS is fired after TERM1 is received, so
+ * we are actually calculating relative to start of packet payload
+ * which is fine.
+ */
+
+ /* Adjust for receiving access address since this triggers EVENT_ADDRESS */
+ end_time += ble_phy_mode_pdu_start_off(phy);
+ /* Adjust for delay between actual access address RX and EVENT_ADDRESS */
+ end_time += g_ble_phy_t_rxaddrdelay[phy];
+
+ /* wfr_secs is the time from rxen until timeout */
+ NRF_TIMER0_NS->CC[3] = end_time;
+ NRF_TIMER0_NS->EVENTS_COMPARE[3] = 0;
+
+ /* Subscribe for wait for response events */
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(1);
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(1);
+
+ /* Enable the disabled interrupt so we time out on events compare */
+ NRF_RADIO_NS->INTENSET = RADIO_INTENSET_DISABLED_Msk;
+
+ /*
+ * It may happen that if CPU is halted for a brief moment (e.g. during flash
+ * erase or write), TIMER0 already counted past CC[3] and thus wfr will not
+ * fire as expected. In case this happened, let's just disable PPIs for wfr
+ * and trigger wfr manually (i.e. disable radio).
+ *
+ * Note that the same applies to RX start time set in CC[0] but since it
+ * should fire earlier than wfr, fixing wfr is enough.
+ *
+ * CC[1] is only used as a reference on RX start, we do not need it here so
+ * it can be used to read TIMER0 counter.
+ */
+ NRF_TIMER0_NS->TASKS_CAPTURE[1] = 1;
+ if (NRF_TIMER0_NS->CC[1] > NRF_TIMER0_NS->CC[3]) {
+ /* Unsubscribe from wfr events */
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0);
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0);
+
+ NRF_RADIO_NS->TASKS_DISABLE = 1;
+ }
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+static uint32_t
+ble_phy_get_ccm_datarate(void)
+{
+#if BLE_LL_BT5_PHY_SUPPORTED
+ switch (g_ble_phy_data.phy_cur_phy_mode) {
+ case BLE_PHY_MODE_1M:
+ return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos;
+ case BLE_PHY_MODE_2M:
+ return CCM_MODE_DATARATE_2Mbit << CCM_MODE_DATARATE_Pos;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+ case BLE_PHY_MODE_CODED_125KBPS:
+ return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos;
+ case BLE_PHY_MODE_CODED_500KBPS:
+ return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos;
+#endif
+ }
+
+ assert(0);
+ return 0;
+#else
+ return CCM_MODE_DATARATE_1Mbit << CCM_MODE_DATARATE_Pos;
+#endif
+}
+#endif
+
+/**
+ * Setup transceiver for receive.
+ */
+static void
+ble_phy_rx_xcvr_setup(void)
+{
+ uint8_t *dptr;
+
+ dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
+ dptr += 3;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted) {
+ NRF_RADIO_NS->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0];
+ NRF_CCM_NS->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
+ NRF_CCM_NS->OUTPTR = (uint32_t)dptr;
+ NRF_CCM_NS->SCRATCHPTR = (uint32_t)&nrf_encrypt_scratchpad[0];
+ NRF_CCM_NS->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption |
+ ble_phy_get_ccm_datarate();
+ NRF_CCM_NS->CNFPTR = (uint32_t)&nrf_ccm_data;
+ NRF_CCM_NS->SHORTS = 0;
+ NRF_CCM_NS->EVENTS_ERROR = 0;
+ NRF_CCM_NS->EVENTS_ENDCRYPT = 0;
+ NRF_CCM_NS->TASKS_KSGEN = 1;
+
+ /* Subscribe to radio address event */
+ NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(1);
+ } else {
+ NRF_RADIO_NS->PACKETPTR = (uint32_t)dptr;
+ }
+#else
+ NRF_RADIO_NS->PACKETPTR = (uint32_t)dptr;
+#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+ if (g_ble_phy_data.phy_privacy) {
+ NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Enabled;
+ NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+ NRF_AAR_NS->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
+ NRF_AAR_NS->EVENTS_END = 0;
+ NRF_AAR_NS->EVENTS_RESOLVED = 0;
+ NRF_AAR_NS->EVENTS_NOTRESOLVED = 0;
+ } else {
+ if (g_ble_phy_data.phy_encrypted == 0) {
+ NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+ }
+ }
+#endif
+
+ /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0);
+ NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(0);
+
+ /* Reset the rx started flag. Used for the wait for response */
+ g_ble_phy_data.phy_rx_started = 0;
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_RX;
+
+#if BLE_LL_BT5_PHY_SUPPORTED
+ /*
+ * On Coded PHY there are CI and TERM1 fields before PDU starts so we need
+ * to take this into account when setting up BCC.
+ */
+ if (g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_125KBPS ||
+ g_ble_phy_data.phy_cur_phy_mode == BLE_PHY_MODE_CODED_500KBPS) {
+ g_ble_phy_data.phy_bcc_offset = 5;
+ } else {
+ g_ble_phy_data.phy_bcc_offset = 0;
+ }
+#else
+ g_ble_phy_data.phy_bcc_offset = 0;
+#endif
+
+ /* I want to know when 1st byte received (after address) */
+ NRF_RADIO_NS->BCC = 8 + g_ble_phy_data.phy_bcc_offset; /* in bits */
+ NRF_RADIO_NS->EVENTS_ADDRESS = 0;
+ NRF_RADIO_NS->EVENTS_DEVMATCH = 0;
+ NRF_RADIO_NS->EVENTS_BCMATCH = 0;
+ NRF_RADIO_NS->EVENTS_RSSIEND = 0;
+ NRF_RADIO_NS->EVENTS_CRCOK = 0;
+ NRF_RADIO_NS->SHORTS = RADIO_SHORTS_END_DISABLE_Msk |
+ RADIO_SHORTS_READY_START_Msk |
+ RADIO_SHORTS_ADDRESS_BCSTART_Msk |
+ RADIO_SHORTS_ADDRESS_RSSISTART_Msk |
+ RADIO_SHORTS_DISABLED_RSSISTOP_Msk;
+
+ NRF_RADIO_NS->INTENSET = RADIO_INTENSET_ADDRESS_Msk;
+}
+
+/**
+ * Called from interrupt context when the transmit ends
+ *
+ */
+static void
+ble_phy_tx_end_isr(void)
+{
+ uint8_t tx_phy_mode;
+ uint8_t was_encrypted;
+ uint8_t transition;
+ uint32_t rx_time;
+ uint32_t wfr_time;
+
+ /* Store PHY on which we've just transmitted smth */
+ tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode;
+
+ /* If this transmission was encrypted we need to remember it */
+ was_encrypted = g_ble_phy_data.phy_encrypted;
+ (void)was_encrypted;
+
+ /* Better be in TX state! */
+ assert(g_ble_phy_data.phy_state == BLE_PHY_STATE_TX);
+
+ /* Clear events and clear interrupt on disabled event */
+ NRF_RADIO_NS->EVENTS_DISABLED = 0;
+ NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
+ NRF_RADIO_NS->EVENTS_END = 0;
+ wfr_time = NRF_RADIO_NS->SHORTS;
+ (void)wfr_time;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ /*
+ * XXX: not sure what to do. We had a HW error during transmission.
+ * For now I just count a stat but continue on like all is good.
+ */
+ if (was_encrypted) {
+ if (NRF_CCM_NS->EVENTS_ERROR) {
+ STATS_INC(ble_phy_stats, tx_hw_err);
+ NRF_CCM_NS->EVENTS_ERROR = 0;
+ }
+ }
+#endif
+
+ /* Call transmit end callback */
+ if (g_ble_phy_data.txend_cb) {
+ g_ble_phy_data.txend_cb(g_ble_phy_data.txend_arg);
+ }
+
+ transition = g_ble_phy_data.phy_transition;
+ if (transition == BLE_PHY_TRANSITION_TX_RX) {
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode);
+#endif
+
+ /* Packet pointer needs to be reset. */
+ ble_phy_rx_xcvr_setup();
+
+ ble_phy_wfr_enable(BLE_PHY_WFR_ENABLE_TXRX, tx_phy_mode, 0);
+
+ /* Schedule RX exactly T_IFS after TX end captured in CC[2] */
+ rx_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS;
+ /* Adjust for delay between EVENT_END and actual TX end time */
+ rx_time += g_ble_phy_t_txenddelay[tx_phy_mode];
+ /* Adjust for radio ramp-up */
+ rx_time -= BLE_PHY_T_RXENFAST;
+ /* Start listening a bit earlier due to allowed active clock accuracy */
+ rx_time -= 2;
+
+ NRF_TIMER0_NS->CC[0] = rx_time;
+ NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0;
+
+ /* Start radio on timer */
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1);
+
+ } else {
+ NRF_TIMER0_NS->TASKS_STOP = 1;
+ NRF_TIMER0_NS->TASKS_SHUTDOWN = 1;
+
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0);
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0);
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0);
+ NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(0);
+
+ assert(transition == BLE_PHY_TRANSITION_NONE);
+ }
+}
+
+static inline uint8_t
+ble_phy_get_cur_rx_phy_mode(void)
+{
+ uint8_t phy;
+
+ phy = g_ble_phy_data.phy_cur_phy_mode;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+ /*
+ * For Coded PHY mode can be set to either codings since actual coding is
+ * set in packet header. However, here we need actual coding of received
+ * packet as this determines pipeline delays so need to figure this out
+ * using CI field.
+ */
+ if ((phy == BLE_PHY_MODE_CODED_125KBPS) ||
+ (phy == BLE_PHY_MODE_CODED_500KBPS)) {
+ phy = NRF_RADIO_NS->PDUSTAT & RADIO_PDUSTAT_CISTAT_Msk ?
+ BLE_PHY_MODE_CODED_500KBPS : BLE_PHY_MODE_CODED_125KBPS;
+ }
+#endif
+
+ return phy;
+}
+
+static void
+ble_phy_rx_end_isr(void)
+{
+ int rc;
+ uint8_t *dptr;
+ uint8_t crcok;
+ uint32_t tx_time;
+ struct ble_mbuf_hdr *ble_hdr;
+
+ /* Clear events and clear interrupt */
+ NRF_RADIO_NS->EVENTS_END = 0;
+ NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_END_Msk;
+
+ /* Disable automatic RXEN */
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(0);
+
+ /* Set RSSI and CRC status flag in header */
+ ble_hdr = &g_ble_phy_data.rxhdr;
+ assert(NRF_RADIO_NS->EVENTS_RSSIEND != 0);
+ ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO_NS->RSSISAMPLE) +
+ g_ble_phy_data.rx_pwr_compensation;
+
+ dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
+ dptr += 3;
+
+ /* Count PHY crc errors and valid packets */
+ crcok = NRF_RADIO_NS->EVENTS_CRCOK;
+ if (!crcok) {
+ 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 ((dptr[1] != 0) && (NRF_CCM_NS->MICSTATUS == 0)) {
+ ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE;
+ }
+
+ /*
+ * XXX: not sure how to deal with this. This should not
+ * be a MIC failure but we should not hand it up. I guess
+ * this is just some form of rx error and that is how we
+ * handle it? For now, just set CRC error flags
+ */
+ if (NRF_CCM_NS->EVENTS_ERROR) {
+ STATS_INC(ble_phy_stats, rx_hw_err);
+ ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
+ }
+
+ /*
+ * XXX: This is a total hack work-around for now but I dont
+ * know what else to do. If ENDCRYPT is not set and we are
+ * encrypted we need to not trust this frame and drop it.
+ */
+ if (NRF_CCM_NS->EVENTS_ENDCRYPT == 0) {
+ STATS_INC(ble_phy_stats, rx_hw_err);
+ ble_hdr->rxinfo.flags &= ~BLE_MBUF_HDR_F_CRC_OK;
+ }
+ }
+#endif
+ }
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode);
+#endif
+
+ /*
+ * Let's schedule TX now and we will just cancel it after processing RXed
+ * packet if we don't need TX.
+ *
+ * We need this to initiate connection in case AUX_CONNECT_REQ was sent on
+ * LE Coded S8. In this case the time we process RXed packet is roughly the
+ * same as the limit when we need to have TX scheduled (i.e. TIMER0 and PPI
+ * armed) so we may simply miss the slot and set the timer in the past.
+ *
+ * When TX is scheduled in advance, we may event process packet a bit longer
+ * during radio ramp-up - this gives us extra 40 usecs which is more than
+ * enough.
+ */
+
+ /* Schedule TX exactly T_IFS after RX end captured in CC[2] */
+ tx_time = NRF_TIMER0_NS->CC[2] + BLE_LL_IFS;
+ /* Adjust for delay between actual RX end time and EVENT_END */
+ tx_time -= g_ble_phy_t_rxenddelay[ble_hdr->rxinfo.phy_mode];
+ /* Adjust for radio ramp-up */
+ tx_time -= BLE_PHY_T_TXENFAST;
+ /* Adjust for delay between EVENT_READY and actual TX start time */
+ tx_time -= g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode];
+
+ NRF_TIMER0_NS->CC[0] = tx_time;
+ NRF_TIMER0_NS->EVENTS_COMPARE[0] = 0;
+
+ /* Enable automatic TX */
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(1);
+
+ /*
+ * XXX: Hack warning!
+ *
+ * It may happen (during flash erase) that CPU is stopped for a moment and
+ * TIMER0 already counted past CC[0]. In such case we will be stuck waiting
+ * for TX to start since EVENTS_COMPARE[0] will not happen any time soon.
+ * For now let's set a flag denoting that we are late in RX-TX transition so
+ * ble_phy_tx() will fail - this allows everything to cleanup nicely without
+ * the need for extra handling in many places.
+ *
+ * Note: CC[3] is used only for wfr which we do not need here.
+ */
+ NRF_TIMER0_NS->TASKS_CAPTURE[3] = 1;
+ if (NRF_TIMER0_NS->CC[3] > NRF_TIMER0_NS->CC[0]) {
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0);
+
+ g_ble_phy_data.phy_transition_late = 1;
+ }
+
+ /*
+ * XXX: This is a horrible ugly hack to deal with the RAM S1 byte
+ * that is not sent over the air but is present here. Simply move the
+ * data pointer to deal with it. Fix this later.
+ */
+ dptr[2] = dptr[1];
+ dptr[1] = dptr[0];
+ rc = ble_ll_rx_end(dptr + 1, ble_hdr);
+ if (rc < 0) {
+ ble_phy_disable();
+ }
+}
+
+static bool
+ble_phy_rx_start_isr(void)
+{
+ int rc;
+ uint32_t state;
+ uint32_t usecs;
+ uint32_t pdu_usecs;
+ uint32_t ticks;
+ struct ble_mbuf_hdr *ble_hdr;
+ uint8_t *dptr;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+ int adva_offset;
+#endif
+
+ dptr = (uint8_t *)&g_ble_phy_rx_buf[0];
+
+ /* Clear events and clear interrupt */
+ NRF_RADIO_NS->EVENTS_ADDRESS = 0;
+
+ /* Clear wfr timer channels and DISABLED interrupt */
+ NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_DISABLED_Msk | RADIO_INTENCLR_ADDRESS_Msk;
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0);
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0);
+
+ /* 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.phy_chan;
+ ble_hdr->rxinfo.handle = 0;
+ ble_hdr->rxinfo.phy = ble_phy_get_cur_phy();
+ ble_hdr->rxinfo.phy_mode = ble_phy_get_cur_rx_phy_mode();
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
+ ble_hdr->rxinfo.user_data = NULL;
+#endif
+
+ /*
+ * Calculate accurate packets start time (with remainder)
+ *
+ * We may start receiving packet somewhere during preamble in which case
+ * it is possible that actual transmission started before TIMER0 was
+ * running - need to take this into account.
+ */
+ ble_hdr->beg_cputime = g_ble_phy_data.phy_start_cputime;
+
+ usecs = NRF_TIMER0_NS->CC[1];
+ pdu_usecs = ble_phy_mode_pdu_start_off(ble_hdr->rxinfo.phy_mode) +
+ g_ble_phy_t_rxaddrdelay[ble_hdr->rxinfo.phy_mode];
+ if (usecs < pdu_usecs) {
+ g_ble_phy_data.phy_start_cputime--;
+ usecs += 30;
+ }
+ usecs -= pdu_usecs;
+
+ ticks = os_cputime_usecs_to_ticks(usecs);
+ usecs -= os_cputime_ticks_to_usecs(ticks);
+ if (usecs == 31) {
+ usecs = 0;
+ ++ticks;
+ }
+
+ ble_hdr->beg_cputime += ticks;
+ ble_hdr->rem_usecs = usecs;
+
+ /* Wait to get 1st byte of frame */
+ while (1) {
+ state = NRF_RADIO_NS->STATE;
+ if (NRF_RADIO_NS->EVENTS_BCMATCH != 0) {
+ break;
+ }
+
+ /*
+ * If state is disabled, we should have the BCMATCH. If not,
+ * something is wrong!
+ */
+ if (state == RADIO_STATE_STATE_Disabled) {
+ NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
+ NRF_RADIO_NS->SHORTS = 0;
+ return false;
+ }
+ }
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+ /*
+ * If privacy is enabled and received PDU has TxAdd bit set (i.e. random
+ * address) we try to resolve address using AAR.
+ */
+ if (g_ble_phy_data.phy_privacy && (dptr[3] & 0x40)) {
+ /*
+ * AdvA is located at 4th octet in RX buffer (after S0, length an S1
+ * fields). In case of extended advertising PDU we need to add 2 more
+ * octets for extended header.
+ */
+ adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0;
+ NRF_AAR_NS->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset);
+
+ /* Trigger AAR after last bit of AdvA is received */
+ NRF_RADIO_NS->EVENTS_BCMATCH = 0;
+ NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(1);
+ NRF_RADIO_NS->BCC = (BLE_LL_PDU_HDR_LEN + adva_offset + BLE_DEV_ADDR_LEN) * 8 +
+ g_ble_phy_data.phy_bcc_offset;
+ }
+#endif
+
+ /* Call Link Layer receive start function */
+ rc = ble_ll_rx_start(dptr + 3,
+ g_ble_phy_data.phy_chan,
+ &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;
+ NRF_RADIO_NS->INTENSET = RADIO_INTENSET_END_Msk;
+ } else {
+ /* Disable PHY */
+ ble_phy_disable();
+ STATS_INC(ble_phy_stats, rx_aborts);
+ }
+
+ /* Count rx starts */
+ STATS_INC(ble_phy_stats, rx_starts);
+
+ return true;
+}
+
+static void
+ble_phy_isr(void)
+{
+ uint32_t irq_en;
+
+ os_trace_isr_enter();
+
+ /* Read irq register to determine which interrupts are enabled */
+ irq_en = NRF_RADIO_NS->INTENCLR;
+
+ /*
+ * NOTE: order of checking is important! Possible, if things get delayed,
+ * we have both an ADDRESS and DISABLED interrupt in rx state. If we get
+ * an address, we disable the DISABLED interrupt.
+ */
+
+ /* We get this if we have started to receive a frame */
+ if ((irq_en & RADIO_INTENCLR_ADDRESS_Msk) && NRF_RADIO_NS->EVENTS_ADDRESS) {
+ /*
+ * wfr timer is calculated to expire at the exact time we should start
+ * receiving a packet (with 1 usec precision) so it is possible it will
+ * fire at the same time as EVENT_ADDRESS. If this happens, radio will
+ * be disabled while we are waiting for EVENT_BCCMATCH after 1st byte
+ * of payload is received and ble_phy_rx_start_isr() will fail. In this
+ * case we should not clear DISABLED irq mask so it will be handled as
+ * regular radio disabled event below. In other case radio was disabled
+ * on purpose and there's nothing more to handle so we can clear mask.
+ */
+ if (ble_phy_rx_start_isr()) {
+ irq_en &= ~RADIO_INTENCLR_DISABLED_Msk;
+ }
+ }
+
+ /* Check for disabled event. This only happens for transmits now */
+ if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO_NS->EVENTS_DISABLED) {
+ if (g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) {
+ NRF_RADIO_NS->EVENTS_DISABLED = 0;
+ ble_ll_wfr_timer_exp(NULL);
+ } else if (g_ble_phy_data.phy_state == BLE_PHY_STATE_IDLE) {
+ assert(0);
+ } else {
+ ble_phy_tx_end_isr();
+ }
+ }
+
+ /* Receive packet end (we dont enable this for transmit) */
+ if ((irq_en & RADIO_INTENCLR_END_Msk) && NRF_RADIO_NS->EVENTS_END) {
+ ble_phy_rx_end_isr();
+ }
+
+ g_ble_phy_data.phy_transition_late = 0;
+
+ /* Ensures IRQ is cleared */
+ irq_en = NRF_RADIO_NS->SHORTS;
+
+ /* Count # of interrupts */
+ STATS_INC(ble_phy_stats, phy_isrs);
+
+ os_trace_isr_exit();
+}
+
+int
+ble_phy_init(void)
+{
+ int rc;
+
+ /* Default phy to use is 1M */
+ g_ble_phy_data.phy_cur_phy_mode = BLE_PHY_MODE_1M;
+ g_ble_phy_data.phy_tx_phy_mode = BLE_PHY_MODE_1M;
+ g_ble_phy_data.phy_rx_phy_mode = BLE_PHY_MODE_1M;
+
+ g_ble_phy_data.rx_pwr_compensation = 0;
+
+ /* Set phy channel to an invalid channel so first set channel works */
+ g_ble_phy_data.phy_chan = BLE_PHY_NUM_CHANS;
+
+ /* Toggle peripheral power to reset (just in case) */
+ NRF_RADIO_NS->POWER = 0;
+ NRF_RADIO_NS->POWER = 1;
+
+ /* Errata 16 - RADIO: POWER register is not functional
+ * Workaround: Reset all RADIO registers in firmware.
+ */
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = 0;
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = 0;
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0;
+
+ /* Disable all interrupts */
+ NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
+
+ /* Set configuration registers */
+ NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_1Mbit;
+ NRF_RADIO_NS->PCNF0 = NRF_PCNF0;
+
+ /* XXX: should maxlen be 251 for encryption? */
+ NRF_RADIO_NS->PCNF1 = NRF_MAXLEN |
+ (RADIO_PCNF1_ENDIAN_Little << RADIO_PCNF1_ENDIAN_Pos) |
+ (NRF_BALEN << RADIO_PCNF1_BALEN_Pos) |
+ RADIO_PCNF1_WHITEEN_Msk;
+
+ /* Enable radio fast ramp-up */
+ NRF_RADIO_NS->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & RADIO_MODECNF0_RU_Msk;
+
+ /* Set logical address 1 for TX and RX */
+ NRF_RADIO_NS->TXADDRESS = 0;
+ NRF_RADIO_NS->RXADDRESSES = (1 << 0);
+
+ /* Configure the CRC registers */
+ NRF_RADIO_NS->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three;
+
+ /* Configure BLE poly */
+ NRF_RADIO_NS->CRCPOLY = 0x0000065B;
+
+ /* Configure IFS */
+ NRF_RADIO_NS->TIFS = BLE_LL_IFS;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ NRF_CCM_NS->INTENCLR = 0xffffffff;
+ NRF_CCM_NS->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
+ NRF_CCM_NS->EVENTS_ERROR = 0;
+ memset(nrf_encrypt_scratchpad, 0, sizeof(nrf_encrypt_scratchpad));
+#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+ g_ble_phy_data.phy_aar_scratch = 0;
+ NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+ NRF_AAR_NS->INTENCLR = 0xffffffff;
+ NRF_AAR_NS->EVENTS_END = 0;
+ NRF_AAR_NS->EVENTS_RESOLVED = 0;
+ NRF_AAR_NS->EVENTS_NOTRESOLVED = 0;
+ NRF_AAR_NS->NIRK = 0;
+#endif
+
+ /* TIMER0 setup for PHY when using RTC */
+ NRF_TIMER0_NS->TASKS_STOP = 1;
+ NRF_TIMER0_NS->TASKS_SHUTDOWN = 1;
+ NRF_TIMER0_NS->BITMODE = 3; /* 32-bit timer */
+ NRF_TIMER0_NS->MODE = 0; /* Timer mode */
+ NRF_TIMER0_NS->PRESCALER = 4; /* gives us 1 MHz */
+
+ /* Publish events */
+ NRF_TIMER0_NS->PUBLISH_COMPARE[0] = DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_0;
+ NRF_TIMER0_NS->PUBLISH_COMPARE[3] = DPPI_PUBLISH_TIMER0_EVENTS_COMPARE_3;
+ NRF_RADIO_NS->PUBLISH_END = DPPI_PUBLISH_RADIO_EVENTS_END;
+ NRF_RADIO_NS->PUBLISH_BCMATCH = DPPI_PUBLISH_RADIO_EVENTS_BCMATCH;
+ NRF_RADIO_NS->PUBLISH_ADDRESS = DPPI_PUBLISH_RADIO_EVENTS_ADDRESS;
+ NRF_RTC0_NS->PUBLISH_COMPARE[0] = DPPI_PUBLISH_RTC0_EVENTS_COMPARE_0;
+
+ /* Enable channels we publish on */
+ NRF_DPPIC_NS->CHENSET = DPPI_CH_ENABLE_ALL;
+
+ /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[1] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE1(1);
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[2] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE2(1);
+
+ /* Set isr in vector table and enable interrupt */
+#ifndef RIOT_VERSION
+ NVIC_SetPriority(RADIO_IRQn, 0);
+#endif
+#if MYNEWT
+ NVIC_SetVector(RADIO_IRQn, (uint32_t)ble_phy_isr);
+#else
+ ble_npl_hw_set_isr(RADIO_IRQn, ble_phy_isr);
+#endif
+ NVIC_EnableIRQ(RADIO_IRQn);
+
+ /* Register phy statistics */
+ if (!g_ble_phy_data.phy_stats_initialized) {
+ rc = stats_init_and_reg(STATS_HDR(ble_phy_stats),
+ STATS_SIZE_INIT_PARMS(ble_phy_stats,
+ STATS_SIZE_32),
+ STATS_NAME_INIT_PARMS(ble_phy_stats),
+ "ble_phy");
+ assert(rc == 0);
+
+ g_ble_phy_data.phy_stats_initialized = 1;
+ }
+
+ return 0;
+}
+
+int
+ble_phy_rx(void)
+{
+ /*
+ * Check radio state.
+ *
+ * In case radio is now disabling we'll wait for it to finish, but if for
+ * any reason it's just in idle state we proceed with RX as usual since
+ * nRF52 radio can ramp-up from idle state as well.
+ *
+ * Note that TX and RX states values are the same except for 3rd bit so we
+ * can make a shortcut here when checking for idle state.
+ */
+ nrf_wait_disabled();
+ if ((NRF_RADIO_NS->STATE != RADIO_STATE_STATE_Disabled) &&
+ ((NRF_RADIO_NS->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) {
+ ble_phy_disable();
+ STATS_INC(ble_phy_stats, radio_state_errs);
+ return BLE_PHY_ERR_RADIO_STATE;
+ }
+
+ /* Make sure all interrupts are disabled */
+ NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
+
+ /* Clear events prior to enabling receive */
+ NRF_RADIO_NS->EVENTS_END = 0;
+ NRF_RADIO_NS->EVENTS_DISABLED = 0;
+
+ /* Setup for rx */
+ ble_phy_rx_xcvr_setup();
+
+ /* task to start RX should be subscribed here */
+ assert(NRF_RADIO_NS->SUBSCRIBE_RXEN & DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1));
+
+ return 0;
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+void
+ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
+ uint8_t is_master)
+{
+ memcpy(nrf_ccm_data.key, key, 16);
+ nrf_ccm_data.pkt_counter = pkt_counter;
+ memcpy(nrf_ccm_data.iv, iv, 8);
+ nrf_ccm_data.dir_bit = is_master;
+ g_ble_phy_data.phy_encrypted = 1;
+ /* Enable the module (AAR cannot be on while CCM on) */
+ NRF_AAR_NS->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+ NRF_CCM_NS->ENABLE = CCM_ENABLE_ENABLE_Enabled;
+}
+
+void
+ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
+{
+ nrf_ccm_data.pkt_counter = pkt_counter;
+ nrf_ccm_data.dir_bit = dir;
+}
+
+void
+ble_phy_encrypt_disable(void)
+{
+ NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(0);
+ NRF_CCM_NS->TASKS_STOP = 1;
+ NRF_CCM_NS->EVENTS_ERROR = 0;
+ NRF_CCM_NS->ENABLE = CCM_ENABLE_ENABLE_Disabled;
+
+ g_ble_phy_data.phy_encrypted = 0;
+}
+#endif
+
+void
+ble_phy_set_txend_cb(ble_phy_tx_end_func txend_cb, void *arg)
+{
+ /* Set transmit end callback and arg */
+ g_ble_phy_data.txend_cb = txend_cb;
+ g_ble_phy_data.txend_arg = arg;
+}
+
+int
+ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+ int rc;
+
+ ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_TX, cputime, rem_usecs);
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_tx_phy_mode);
+#endif
+
+ /* XXX: This should not be necessary, but paranoia is good! */
+ /* Clear timer0 compare to RXEN since we are transmitting */
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(0);
+
+ if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) {
+ STATS_INC(ble_phy_stats, tx_late);
+ ble_phy_disable();
+ rc = BLE_PHY_ERR_TX_LATE;
+ } else {
+ /* Enable PPI to automatically start TXEN */
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(1);
+ rc = 0;
+ }
+ return rc;
+}
+
+int
+ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
+{
+ bool late = false;
+ int rc = 0;
+
+ ble_phy_trace_u32x2(BLE_PHY_TRACE_ID_START_RX, cputime, rem_usecs);
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+ ble_phy_mode_apply(g_ble_phy_data.phy_rx_phy_mode);
+#endif
+
+ /* XXX: This should not be necessary, but paranoia is good! */
+ /* Clear timer0 compare to TXEN since we are transmitting */
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0);
+
+ if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) {
+ STATS_INC(ble_phy_stats, rx_late);
+
+ /* We're late so let's just try to start RX as soon as possible */
+ ble_phy_set_start_now();
+
+ late = true;
+ }
+
+ /* Enable PPI to automatically start RXEN */
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1);
+
+ /* Start rx */
+ rc = ble_phy_rx();
+
+ /*
+ * If we enabled receiver but were late, let's return proper error code so
+ * caller can handle this.
+ */
+ if (!rc && late) {
+ rc = BLE_PHY_ERR_RX_LATE;
+ }
+
+ return rc;
+}
+
+int
+ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
+{
+ int rc;
+ uint8_t *dptr;
+ uint8_t *pktptr;
+ uint8_t payload_len;
+ uint8_t hdr_byte;
+ uint32_t state;
+ uint32_t shortcuts;
+
+ if (g_ble_phy_data.phy_transition_late) {
+ ble_phy_disable();
+ STATS_INC(ble_phy_stats, tx_late);
+ return BLE_PHY_ERR_TX_LATE;
+ }
+
+ /*
+ * This check is to make sure that the radio is not in a state where
+ * it is moving to disabled state. If so, let it get there.
+ */
+ nrf_wait_disabled();
+
+ /*
+ * XXX: Although we may not have to do this here, I clear all the PPI
+ * that should not be used when transmitting. Some of them are only enabled
+ * if encryption and/or privacy is on, but I dont care. Better to be
+ * paranoid, and if you are going to clear one, might as well clear them
+ * all.
+ */
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0);
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0);
+ NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(0);
+ NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(0);
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ if (g_ble_phy_data.phy_encrypted) {
+ dptr = (uint8_t *)&g_ble_phy_enc_buf[0];
+ pktptr = (uint8_t *)&g_ble_phy_tx_buf[0];
+ NRF_CCM_NS->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
+ NRF_CCM_NS->INPTR = (uint32_t)dptr;
+ NRF_CCM_NS->OUTPTR = (uint32_t)pktptr;
+ NRF_CCM_NS->SCRATCHPTR = (uint32_t)&nrf_encrypt_scratchpad[0];
+ NRF_CCM_NS->EVENTS_ERROR = 0;
+ NRF_CCM_NS->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate();
+ NRF_CCM_NS->CNFPTR = (uint32_t)&nrf_ccm_data;
+ } else {
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+ NRF_AAR_NS->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+#endif
+ dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
+ pktptr = dptr;
+ }
+#else
+ dptr = (uint8_t *)&g_ble_phy_tx_buf[0];
+ pktptr = dptr;
+#endif
+
+ /* Set PDU payload */
+ payload_len = pducb(&dptr[3], pducb_arg, &hdr_byte);
+
+ /* RAM representation has S0, LENGTH and S1 fields. (3 bytes) */
+ dptr[0] = hdr_byte;
+ dptr[1] = payload_len;
+ dptr[2] = 0;
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+ /* Start key-stream generation and encryption (via short) */
+ if (g_ble_phy_data.phy_encrypted) {
+ NRF_CCM_NS->TASKS_KSGEN = 1;
+ }
+#endif
+
+ NRF_RADIO_NS->PACKETPTR = (uint32_t)pktptr;
+
+ /* Clear the ready, end and disabled events */
+ NRF_RADIO_NS->EVENTS_READY = 0;
+ NRF_RADIO_NS->EVENTS_END = 0;
+ NRF_RADIO_NS->EVENTS_DISABLED = 0;
+
+ /* Enable shortcuts for transmit start/end. */
+ shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;
+ NRF_RADIO_NS->SHORTS = shortcuts;
+ NRF_RADIO_NS->INTENSET = RADIO_INTENSET_DISABLED_Msk;
+
+ /* Set the PHY transition */
+ g_ble_phy_data.phy_transition = end_trans;
+
+ /* Set transmitted payload length */
+ g_ble_phy_data.phy_tx_pyld_len = payload_len;
+
+ /* If we already started transmitting, abort it! */
+ state = NRF_RADIO_NS->STATE;
+ if (state != RADIO_STATE_STATE_Tx) {
+ /* Set phy state to transmitting and count packet statistics */
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_TX;
+ STATS_INC(ble_phy_stats, tx_good);
+ STATS_INCN(ble_phy_stats, tx_bytes, payload_len + BLE_LL_PDU_HDR_LEN);
+ rc = BLE_ERR_SUCCESS;
+ } else {
+ ble_phy_disable();
+ STATS_INC(ble_phy_stats, tx_late);
+ rc = BLE_PHY_ERR_RADIO_STATE;
+ }
+
+ return rc;
+}
+
+int
+ble_phy_txpwr_set(int dbm)
+{
+ /* "Rail" power level if outside supported range */
+ dbm = ble_phy_txpower_round(dbm);
+
+ NRF_RADIO_NS->TXPOWER = dbm;
+ g_ble_phy_data.phy_txpwr_dbm = dbm;
+
+ return 0;
+}
+
+int
+ble_phy_txpower_round(int dbm)
+{
+ /* "Rail" power level if outside supported range */
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg1dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg2dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg3dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg5dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg6dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg7dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg8dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg12dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg16dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm;
+ }
+
+ if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm) {
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
+ }
+
+ return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
+}
+
+static int
+ble_phy_set_access_addr(uint32_t access_addr)
+{
+ NRF_RADIO_NS->BASE0 = (access_addr << 8);
+ NRF_RADIO_NS->PREFIX0 = (NRF_RADIO_NS->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24);
+
+ g_ble_phy_data.phy_access_address = access_addr;
+
+ return 0;
+}
+
+int
+ble_phy_txpwr_get(void)
+{
+ return g_ble_phy_data.phy_txpwr_dbm;
+}
+
+void
+ble_phy_set_rx_pwr_compensation(int8_t compensation)
+{
+ g_ble_phy_data.rx_pwr_compensation = compensation;
+}
+
+int
+ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t crcinit)
+{
+ assert(chan < BLE_PHY_NUM_CHANS);
+
+ /* Check for valid channel range */
+ if (chan >= BLE_PHY_NUM_CHANS) {
+ return BLE_PHY_ERR_INV_PARAM;
+ }
+
+ /* Set current access address */
+ ble_phy_set_access_addr(access_addr);
+
+ /* Configure crcinit */
+ NRF_RADIO_NS->CRCINIT = crcinit;
+
+ /* Set the frequency and the data whitening initial value */
+ g_ble_phy_data.phy_chan = chan;
+ NRF_RADIO_NS->FREQUENCY = g_ble_phy_chan_freq[chan];
+ NRF_RADIO_NS->DATAWHITEIV = chan;
+
+ return 0;
+}
+
+/**
+ * Stop the timer used to count microseconds when using RTC for cputime
+ */
+static void
+ble_phy_stop_usec_timer(void)
+{
+ NRF_TIMER0_NS->TASKS_STOP = 1;
+ NRF_TIMER0_NS->TASKS_SHUTDOWN = 1;
+ NRF_RTC0_NS->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk;
+}
+
+/**
+ * ble phy disable irq and ppi
+ *
+ * This routine is to be called when reception was stopped due to either a
+ * wait for response timeout or a packet being received and the phy is to be
+ * restarted in receive mode. Generally, the disable routine is called to stop
+ * the phy.
+ */
+static void
+ble_phy_disable_irq_and_ppi(void)
+{
+ NRF_RADIO_NS->INTENCLR = NRF_RADIO_IRQ_MASK_ALL;
+ NRF_RADIO_NS->SHORTS = 0;
+ NRF_RADIO_NS->TASKS_DISABLE = 1;
+
+ NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_TIMER0_TASKS_START(0);
+ NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_SUBSCRIBE_TIMER0_TASKS_CAPTURE3(0);
+ NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_SUBSCRIBE_RADIO_TASKS_DISABLE(0);
+ NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_SUBSCRIBE_RADIO_TASKS_TXEN(0);
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(0);
+ NRF_AAR_NS->SUBSCRIBE_START = DPPI_SUBSCRIBE_AAR_TASKS_START(0);
+ NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_SUBSCRIBE_CCM_TASKS_CRYPT(0);
+
+ NVIC_ClearPendingIRQ(RADIO_IRQn);
+ g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
+}
+
+void
+ble_phy_restart_rx(void)
+{
+ ble_phy_stop_usec_timer();
+ ble_phy_disable_irq_and_ppi();
+
+ ble_phy_set_start_now();
+ /* Enable PPI to automatically start RXEN */
+ NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_SUBSCRIBE_RADIO_TASKS_RXEN(1);
+
+ ble_phy_rx();
+}
+
+void
+ble_phy_disable(void)
+{
+ ble_phy_trace_void(BLE_PHY_TRACE_ID_DISABLE);
+
+ ble_phy_stop_usec_timer();
+ ble_phy_disable_irq_and_ppi();
+}
+
+uint32_t
+ble_phy_access_addr_get(void)
+{
+ return g_ble_phy_data.phy_access_address;
+}
+
+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)
+{
+ uint32_t state;
+ state = NRF_RADIO_NS->STATE;
+ return (uint8_t)state;
+}
+
+uint8_t
+ble_phy_max_data_pdu_pyld(void)
+{
+ return BLE_LL_DATA_PDU_MAX_PYLD;
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+void
+ble_phy_resolv_list_enable(void)
+{
+ NRF_AAR_NS->NIRK = (uint32_t)g_nrf_num_irks;
+ g_ble_phy_data.phy_privacy = 1;
+}
+
+void
+ble_phy_resolv_list_disable(void)
+{
+ g_ble_phy_data.phy_privacy = 0;
+}
+#endif
+
+#if MYNEWT_VAL(BLE_LL_DTM)
+void
+ble_phy_enable_dtm(void)
+{
+ /* When DTM is enabled we need to disable whitening as per
+ * Bluetooth v5.0 Vol 6. Part F. 4.1.1
+ */
+ NRF_RADIO_NS->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk;
+}
+
+void
+ble_phy_disable_dtm(void)
+{
+ /* Enable whitening */
+ NRF_RADIO_NS->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk;
+}
+#endif
+
+void
+ble_phy_rfclk_enable(void)
+{
+#if MYNEWT
+ nrf5340_net_clock_hfxo_request();
+#else
+ NRF_CLOCK_NS->TASKS_HFCLKSTART = 1;
+#endif
+}
+
+void
+ble_phy_rfclk_disable(void)
+{
+#if MYNEWT
+ nrf5340_net_clock_hfxo_release();
+#else
+ NRF_CLOCK_NS->TASKS_HFCLKSTOP = 1;
+#endif
+}
diff --git a/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy_trace.c b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy_trace.c
new file mode 100644
index 00000000..6967c3f7
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/src/ble_phy_trace.c
@@ -0,0 +1,44 @@
+/*
+ * 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 <stdint.h>
+#include <syscfg/syscfg.h>
+#include <os/os_trace_api.h>
+
+#if MYNEWT_VAL(BLE_PHY_SYSVIEW)
+
+static os_trace_module_t g_ble_phy_trace_mod;
+uint32_t ble_phy_trace_off;
+
+static void
+ble_phy_trace_module_send_desc(void)
+{
+ os_trace_module_desc(&g_ble_phy_trace_mod, "0 phy_set_tx cputime=%u usecs=%u");
+ os_trace_module_desc(&g_ble_phy_trace_mod, "1 phy_set_rx cputime=%u usecs=%u");
+ os_trace_module_desc(&g_ble_phy_trace_mod, "2 phy_disable");
+}
+
+void
+ble_phy_trace_init(void)
+{
+ ble_phy_trace_off =
+ os_trace_module_register(&g_ble_phy_trace_mod, "ble_phy", 3,
+ ble_phy_trace_module_send_desc);
+}
+#endif
diff --git a/src/libs/mynewt-nimble/nimble/drivers/nrf5340/syscfg.yml b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/syscfg.yml
new file mode 100644
index 00000000..dd8b9304
--- /dev/null
+++ b/src/libs/mynewt-nimble/nimble/drivers/nrf5340/syscfg.yml
@@ -0,0 +1,23 @@
+# 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_SYSVIEW:
+ description: >
+ Enable SystemView tracing module for radio driver.
+ value: 0