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

[mynewt-nimble] branch master updated (084eb382 -> 3b02d6ba)

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

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


    from 084eb382 nimble/ll: Fix scheduling adv PDUs
     new a7b016eb nimble/phy: Introduce common phy for nRF52 and nRF53
     new 4d3b302f nimble/phy/nrf5x: Move out nRF52 code
     new e4b98645 nimble/phy/nrf5x: Rework nRF52 erratas
     new 9dd64d29 nimble/phy/nrf5x: Move out TX power rounding
     new 00246792 nimble/phy/nrf5x: Force FEM disable on ble_phy_disable
     new 9ea411fb nimble/phy/nrf5x: Add nRF53 support
     new f3964418 nimble/phy/nrf5x: Add support for FEM turn on time
     new eaa56fa7 nimble/phy/nrf5x: Adjust scheduling offset for FEM turn on
     new 3b02d6ba nimble/ll: Remove nrf52 and nrf5340 phys

The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 nimble/drivers/nrf52/pkg.yml                       |   13 +-
 nimble/drivers/nrf52/syscfg.yml                    |   81 -
 nimble/drivers/nrf5340/include/ble/xcvr.h          |   50 -
 nimble/drivers/nrf5340/pkg.yml                     |   13 +-
 nimble/drivers/nrf5340/src/ble_hw.c                |  477 -----
 nimble/drivers/nrf5340/src/ble_phy.c               | 2079 --------------------
 nimble/drivers/nrf5340/src/ble_phy_trace.c         |   45 -
 nimble/drivers/{nrf52 => nrf5x}/include/ble/xcvr.h |   15 +-
 nimble/drivers/{nrf51 => nrf5x}/pkg.yml            |   12 +-
 nimble/drivers/{nrf52 => nrf5x}/src/ble_hw.c       |    0
 nimble/drivers/{nrf52 => nrf5x}/src/ble_phy.c      |  623 +++---
 .../drivers/{nrf52 => nrf5x}/src/ble_phy_trace.c   |    0
 nimble/drivers/nrf5x/src/nrf52/phy.c               |  214 ++
 nimble/drivers/nrf5x/src/nrf52/phy_ppi.h           |  113 ++
 nimble/drivers/nrf5x/src/nrf53/phy.c               |  235 +++
 nimble/drivers/nrf5x/src/nrf53/phy_ppi.h           |  159 ++
 nimble/drivers/nrf5x/src/phy_priv.h                |   90 +
 nimble/drivers/{nrf5340 => nrf5x}/syscfg.yml       |   32 +-
 18 files changed, 1117 insertions(+), 3134 deletions(-)
 delete mode 100644 nimble/drivers/nrf52/syscfg.yml
 delete mode 100644 nimble/drivers/nrf5340/include/ble/xcvr.h
 delete mode 100644 nimble/drivers/nrf5340/src/ble_hw.c
 delete mode 100644 nimble/drivers/nrf5340/src/ble_phy.c
 delete mode 100644 nimble/drivers/nrf5340/src/ble_phy_trace.c
 rename nimble/drivers/{nrf52 => nrf5x}/include/ble/xcvr.h (75%)
 copy nimble/drivers/{nrf51 => nrf5x}/pkg.yml (80%)
 rename nimble/drivers/{nrf52 => nrf5x}/src/ble_hw.c (100%)
 rename nimble/drivers/{nrf52 => nrf5x}/src/ble_phy.c (81%)
 rename nimble/drivers/{nrf52 => nrf5x}/src/ble_phy_trace.c (100%)
 create mode 100644 nimble/drivers/nrf5x/src/nrf52/phy.c
 create mode 100644 nimble/drivers/nrf5x/src/nrf52/phy_ppi.h
 create mode 100644 nimble/drivers/nrf5x/src/nrf53/phy.c
 create mode 100644 nimble/drivers/nrf5x/src/nrf53/phy_ppi.h
 create mode 100644 nimble/drivers/nrf5x/src/phy_priv.h
 rename nimble/drivers/{nrf5340 => nrf5x}/syscfg.yml (71%)


[mynewt-nimble] 01/09: nimble/phy: Introduce common phy for nRF52 and nRF53

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit a7b016ebac9189a907412dc6eff8a805b33fde2f
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Tue Sep 6 15:45:10 2022 +0200

    nimble/phy: Introduce common phy for nRF52 and nRF53
    
    This is starting point for common phy for nRF52 and nRF53 which will
    make maintaining both much easier. For now this is just c&p of nrf52
    phy to make changes easier to follow.
    
    Note that nrf5x phy will not support nRF51 since, apart from other
    differences, it does not support hardware tifs which is required for
    nRF51.
---
 nimble/drivers/nrf5x/include/ble/xcvr.h  |   52 +
 nimble/drivers/nrf5x/pkg.yml             |   31 +
 nimble/drivers/nrf5x/src/ble_hw.c        |  517 +++++++
 nimble/drivers/nrf5x/src/ble_phy.c       | 2301 ++++++++++++++++++++++++++++++
 nimble/drivers/nrf5x/src/ble_phy_trace.c |   44 +
 nimble/drivers/nrf5x/syscfg.yml          |   72 +
 6 files changed, 3017 insertions(+)

diff --git a/nimble/drivers/nrf5x/include/ble/xcvr.h b/nimble/drivers/nrf5x/include/ble/xcvr.h
new file mode 100644
index 00000000..757bb80f
--- /dev/null
+++ b/nimble/drivers/nrf5x/include/ble/xcvr.h
@@ -0,0 +1,52 @@
+/*
+ * 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/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml
new file mode 100644
index 00000000..e0b314ea
--- /dev/null
+++ b/nimble/drivers/nrf5x/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/nrf5x
+pkg.description: PHY for nRF52 and nRF53 series
+pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
+pkg.homepage: "https://mynewt.apache.org/"
+pkg.keywords:
+    - ble
+    - bluetooth
+
+pkg.apis: ble_driver
+pkg.deps:
+    - nimble
+    - nimble/controller
diff --git a/nimble/drivers/nrf5x/src/ble_hw.c b/nimble/drivers/nrf5x/src/ble_hw.c
new file mode 100644
index 00000000..0accbbf4
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/ble_hw.c
@@ -0,0 +1,517 @@
+/*
+ * 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 "ble/xcvr.h"
+#include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
+#include "nrfx.h"
+#include "controller/ble_hw.h"
+#if MYNEWT
+#include "mcu/cmsis_nvic.h"
+#else
+#include "core_cm4.h"
+#include <nimble/nimble_npl_os.h>
+#endif
+#include "os/os_trace_api.h"
+#include <hal/nrf_rng.h>
+#include "hal/nrf_ecb.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 */
+ble_rng_isr_cb_t g_ble_rng_isr_cb;
+
+#if BABBLESIM
+extern void tm_tick(void);
+#endif
+
+/* If LL privacy is enabled, allocate memory for AAR */
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+
+/* The NRF51 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;
+
+#if MYNEWT_VAL(BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR)
+    /*
+    * The BMD-345 modules are preprogrammed from the factory with a unique public
+    * The  Bluetooth device address stored in the CUSTOMER[0] and CUSTOMER[1]
+    * registers of the User Information Configuration Registers (UICR).
+    * The Bluetooth device address consists of the IEEE Organizationally Unique
+    * Identifier (OUI) combined with the hexadecimal digits that are printed on
+    * a 2D barcode and in human-readable text on the module label.The Bluetooth
+    * device address is stored in little endian format. The most significant
+    * bytes of the CUSTOMER[1] register are 0xFF to complete the 32-bit register.
+    */
+
+    /* Copy into device address. We can do this because we know platform */
+    addr_low = NRF_UICR->CUSTOMER[0];
+    addr_high = NRF_UICR->CUSTOMER[1];
+#else
+    /* Does FICR have a public address */
+    if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) {
+        return -1;
+    }
+
+    /* Copy into device address. We can do this because we know platform */
+    addr_low = NRF_FICR->DEVICEADDR[0];
+    addr_high = NRF_FICR->DEVICEADDR[1];
+#endif
+
+    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)
+{
+    uint32_t addr_high;
+    uint32_t addr_low;
+    int rc;
+
+    if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
+        addr_low = NRF_FICR->DEVICEADDR[0];
+        addr_high = NRF_FICR->DEVICEADDR[1];
+
+        memcpy(addr->val, &addr_low, 4);
+        memcpy(&addr->val[4], &addr_high, 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->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->DAB[i] = get_le32(addr);
+            NRF_RADIO->DAP[i] = get_le16(addr + 4);
+            if (addr_type == BLE_ADDR_RANDOM) {
+                NRF_RADIO->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;
+    uint8_t cfg_addr;
+    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->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->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
+                cfg_addr = txadd & mask;
+                if (addr_type == BLE_ADDR_RANDOM) {
+                    if (cfg_addr != 0) {
+                        break;
+                    }
+                } else {
+                    if (cfg_addr == 0) {
+                        break;
+                    }
+                }
+            }
+        }
+        mask <<= 1;
+    }
+
+    if (i < BLE_HW_WHITE_LIST_SIZE) {
+        g_ble_hw_whitelist_mask &= ~mask;
+        NRF_RADIO->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->DACNF |= g_ble_hw_whitelist_mask;
+}
+
+/**
+ * Disables the whitelisted devices
+ */
+void
+ble_hw_whitelist_disable(void)
+{
+    /* Disable all whitelist devices */
+    NRF_RADIO->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 (int)NRF_RADIO->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_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB);
+    /* XXX: does task stop clear these counters? Anyway to do this quicker? */
+    NRF_ECB->EVENTS_ENDECB = 0;
+    NRF_ECB->EVENTS_ERRORECB = 0;
+    NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
+
+    /* Start ECB */
+    nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
+
+    /* Wait till error or done */
+    rc = 0;
+    while (1) {
+        end = NRF_ECB->EVENTS_ENDECB;
+        err = NRF_ECB->EVENTS_ERRORECB;
+        if (end || err) {
+            if (err) {
+                rc = -1;
+            }
+            break;
+        }
+#if BABBLESIM
+        tm_tick();
+#endif
+    }
+
+    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 (g_ble_rng_isr_cb == NULL) {
+        nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK);
+        NRF_RNG->EVENTS_VALRDY = 0;
+        (void)NRF_RNG->SHORTS;
+        os_trace_isr_exit();
+        return;
+    }
+
+    /* If there is a value ready grab it */
+    if (NRF_RNG->EVENTS_VALRDY) {
+        NRF_RNG->EVENTS_VALRDY = 0;
+        rnum = (uint8_t)NRF_RNG->VALUE;
+        (*g_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->CONFIG = 1;
+    } else {
+        NRF_RNG->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);
+        g_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->EVENTS_VALRDY = 0;
+
+    if (g_ble_rng_isr_cb) {
+        nrf_rng_int_enable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK);
+    }
+    nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START);
+    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_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK);
+    nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP);
+    NRF_RNG->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->EVENTS_VALRDY == 0) {
+    }
+
+    NRF_RNG->EVENTS_VALRDY = 0;
+    rnum = (uint8_t)NRF_RNG->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)
+{
+    if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) {
+        return (int)NRF_AAR->STATUS;
+    }
+
+    return -1;
+}
+#endif
diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
new file mode 100644
index 00000000..a94cb2a7
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -0,0 +1,2301 @@
+/*
+ * 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 <controller/ble_ll_fem.h>
+#include <hal/nrf_radio.h>
+#include <hal/nrf_ccm.h>
+#include <hal/nrf_aar.h>
+#include <hal/nrf_timer.h>
+#include <hal/nrf_ppi.h>
+#include <hal/nrf_rtc.h>
+#include "syscfg/syscfg.h"
+#include "os/os.h"
+/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */
+#include "os/os_cputime.h"
+#include "ble/xcvr.h"
+#include "nimble/ble.h"
+#include "nimble/nimble_opt.h"
+#include "nimble/nimble_npl.h"
+#include "controller/ble_phy.h"
+#include "controller/ble_phy_trace.h"
+#include "controller/ble_ll.h"
+#include "nrfx.h"
+#if MYNEWT
+#include "mcu/nrf52_clock.h"
+#include "mcu/cmsis_nvic.h"
+#include "hal/hal_gpio.h"
+#else
+#include "core_cm4.h"
+#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811)
+#error LE Coded PHY can only be enabled on nRF52811 or nRF52840
+#endif
+#endif
+
+#if BABBLESIM
+extern void tm_tick(void);
+#endif
+
+/*
+ * NOTE: This code uses a couple of PPI channels so care should be taken when
+ *       using PPI somewhere else.
+ *
+ * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31
+ * Regular channels: CH4, CH5 and optionally CH6, CH7, CH17, CH18, CH19
+ *  - CH4 = cancel wfr timer on address match
+ *  - CH5 = disable radio on wfr timer expiry
+ *  - CH6 = PA/LNA control (enable)
+ *  - CH7 = PA/LNA control (disable)
+ *  - CH17 = (optional) gpio debug for radio ramp-up
+ *  - CH18 = (optional) gpio debug for wfr timer RX enabled
+ *  - CH19 = (optional) gpio debug for wfr timer radio disabled
+ *
+ */
+
+/* XXX: 4) Make sure RF is higher priority interrupt than schedule */
+
+/*
+ * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal
+ * and 16ms for a 30ppm crystal! We need to limit PDU size based on
+ * crystal accuracy. Look at this in the spec.
+ */
+
+/* XXX: private header file? */
+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->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;
+#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
+    uint16_t tifs;
+#endif
+};
+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)
+
+#if BABBLESIM
+/* 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] = 1,
+    [BLE_PHY_MODE_2M] = 1,
+};
+/* 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] = 1,
+    [BLE_PHY_MODE_2M] = 1,
+};
+/* 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] = 9,
+    [BLE_PHY_MODE_2M] = 5,
+};
+/* 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] = 9,
+    [BLE_PHY_MODE_2M] = 5,
+};
+#else
+/* 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
+};
+#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)
+
+/*
+ * NOTE:
+ * Tested the following to see what would happen:
+ *  -> NVIC has radio irq enabled (interrupt # 1, mask 0x2).
+ *  -> Set up nrf to receive. Clear ADDRESS event register.
+ *  -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET.
+ *  -> Enable RX.
+ *  -> Disable interrupts globally using OS_ENTER_CRITICAL().
+ *  -> Wait until a packet is received and the ADDRESS event occurs.
+ *  -> Call ble_phy_disable().
+ *
+ *  At this point I wanted to see the state of the cortex NVIC. The IRQ
+ *  pending bit was TRUE for the radio interrupt (as expected) as we never
+ *  serviced the radio interrupt (interrupts were disabled).
+ *
+ *  What was unexpected was this: without clearing the pending IRQ in the NVIC,
+ *  when radio interrupts were re-enabled (address event bit in INTENSET set to
+ *  1) and the radio ADDRESS event register read 1 (it was never cleared after
+ *  the first address event), the radio did not enter the ISR! I would have
+ *  expected that if the following were true, an interrupt would occur:
+ *      -> NVIC ISER bit set to TRUE
+ *      -> NVIC ISPR bit reads TRUE, meaning interrupt is pending.
+ *      -> Radio peripheral interrupts are enabled for some event (or events).
+ *      -> Corresponding event register(s) in radio peripheral read 1.
+ *
+ *  Not sure what the end result of all this is. We will clear the pending
+ *  bit in the NVIC just to be sure when we disable the PHY.
+ */
+
+#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)
+
+uint32_t g_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));
+
+struct nrf_ccm_data g_nrf_ccm_data;
+#endif
+
+static int g_ble_phy_gpiote_idx;
+
+#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
+
+#define FEM_SINGLE_GPIO \
+    (!MYNEWT_VAL(BLE_LL_FEM_PA) || !MYNEWT_VAL(BLE_LL_FEM_LNA) || \
+     (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)))
+
+#if FEM_SINGLE_GPIO
+static uint8_t fem_idx;
+#else
+#if MYNEWT_VAL(BLE_LL_FEM_PA)
+static uint8_t fem_pa_idx;
+#endif
+#if MYNEWT_VAL(BLE_LL_FEM_LNA)
+static uint8_t fem_lna_idx;
+#endif
+#endif
+
+#endif
+
+#ifndef BABBLESIM
+static void
+ble_phy_apply_errata_102_106_107(void)
+{
+    /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS
+     * [106] RADIO: Higher CRC error rates for some access addresses
+     * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00
+     */
+    *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) &
+                         0xfffffffe) | 0x01000000;
+}
+#endif
+
+#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
+
+/* Packet start offset (in usecs). This is the preamble plus access address.
+ * For LE Coded PHY this also includes CI and TERM1. */
+uint32_t
+ble_phy_mode_pdu_start_off(int phy_mode)
+{
+    return g_ble_phy_mode_pkt_start_off[phy_mode];
+}
+
+#if NRF52840_XXAA
+static inline bool
+ble_phy_mode_is_coded(uint8_t phy_mode)
+{
+    return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) ||
+           (phy_mode == BLE_PHY_MODE_CODED_500KBPS);
+}
+
+static void
+ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode)
+{
+    bool new_coded = ble_phy_mode_is_coded(new_phy_mode);
+    bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode);
+
+    /*
+     * Workarounds should be applied only when switching to/from LE Coded PHY
+     * so no need to apply them every time.
+     *
+     * nRF52840 Engineering A Errata v1.2
+     * [164] RADIO: Low sensitivity in long range mode
+     *
+     * nRF52840 Rev 1 Errata
+     * [191] RADIO: High packet error rate in BLE Long Range mode
+     */
+    if (new_coded == cur_coded) {
+        return;
+    }
+
+    if (new_coded) {
+#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
+        /* [164] */
+        *(volatile uint32_t *)0x4000173C |= 0x80000000;
+        *(volatile uint32_t *)0x4000173C =
+                        ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C);
+#endif
+#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
+        /* [191] */
+        *(volatile uint32_t *) 0x40001740 =
+                        ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) |
+                        0x80000000 | (((uint32_t)(196)) << 8);
+#endif
+    } else {
+#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
+        /* [164] */
+        *(volatile uint32_t *)0x4000173C &= ~0x80000000;
+#endif
+#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
+        /* [191] */
+        *(volatile uint32_t *) 0x40001740 =
+                        ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
+#endif
+    }
+}
+#endif
+
+static void
+ble_phy_mode_apply(uint8_t phy_mode)
+{
+    if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) {
+        return;
+    }
+
+#if NRF52840_XXAA
+    ble_phy_apply_nrf52840_errata(phy_mode);
+#endif
+
+    switch (phy_mode) {
+    case BLE_PHY_MODE_1M:
+        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
+        NRF_RADIO->PCNF0 = NRF_PCNF0_1M;
+        break;
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
+    case BLE_PHY_MODE_2M:
+        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit;
+        NRF_RADIO->PCNF0 = NRF_PCNF0_2M;
+        break;
+#endif
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
+    case BLE_PHY_MODE_CODED_125KBPS:
+        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit;
+        NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
+        break;
+    case BLE_PHY_MODE_CODED_500KBPS:
+        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit;
+        NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
+        break;
+#endif
+    default:
+        assert(0);
+    }
+
+    g_ble_phy_data.phy_cur_phy_mode = phy_mode;
+}
+
+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;
+}
+#endif
+
+static void
+ble_phy_fem_enable_pa(void)
+{
+#if MYNEWT_VAL(BLE_LL_FEM_PA)
+    ble_ll_fem_pa_enable();
+
+#if !FEM_SINGLE_GPIO
+    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_pa_idx]);
+    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_pa_idx]);
+#endif
+
+    NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+#endif
+}
+
+static void
+ble_phy_fem_enable_lna(void)
+{
+#if MYNEWT_VAL(BLE_LL_FEM_LNA)
+    ble_ll_fem_lna_enable();
+
+#if !FEM_SINGLE_GPIO
+    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_lna_idx]);
+    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_lna_idx]);
+#endif
+
+    NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+#endif
+}
+
+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
+}
+
+/**
+ * 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 (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;
+
+#if BABBLESIM
+        memcpy(dst, src, copy_len);
+        dst += copy_len;
+        src += copy_len;
+#else
+        __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"
+                         );
+#endif
+
+        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;
+
+#if BABBLESIM
+    memcpy(dst, src, rem_len);
+#else
+    __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"
+                     );
+#endif
+
+    /* 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->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->STATE == state) {
+                /* If this fails, something is really wrong. Should last
+                 * no more than 6 usecs */
+#if BABBLESIM
+                tm_tick();
+#endif
+            }
+        }
+    }
+}
+
+#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
+static uint16_t
+ble_phy_tifs_get(void)
+{
+    return g_ble_phy_data.tifs;
+}
+
+void
+ble_phy_tifs_set(uint16_t tifs)
+{
+    g_ble_phy_data.tifs = tifs;
+}
+#else
+static uint16_t
+ble_phy_tifs_get(void)
+{
+    return BLE_LL_IFS;
+}
+#endif
+
+/**
+ *
+ *
+ */
+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->CC[0];
+    cntr = NRF_RTC0->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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
+    nrf_timer_cc_set(NRF_TIMER0, 0, rem_usecs);
+    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+
+    /* Set RTC compare to start TIMER0 */
+    NRF_RTC0->EVENTS_COMPARE[0] = 0;
+    nrf_rtc_cc_set(NRF_RTC0, 0, next_cc);
+    nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
+
+    /* Enable PPI */
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
+
+    /* 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
+    nrf_timer_cc_set(NRF_TIMER0, 0, 1);
+    NRF_TIMER0->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->EVENTS_COMPARE[0] = 0;
+    nrf_rtc_cc_set(NRF_RTC0, 0, now + 3);
+    nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
+
+    /* Enable PPI */
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
+    /*
+     * 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;
+}
+
+/**
+ * Function is used to set PPI so that we can time out waiting for a reception
+ * to occur. This happens for two reasons: we have sent a packet and we are
+ * waiting for a response (txrx should be set to ENABLE_TXRX) or we are
+ * starting a connection event and we are a slave and we are waiting for the
+ * master to send us a packet (txrx should be set to ENABLE_RX).
+ *
+ * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there
+ * is no additional time to wait; we know when we should receive the address of
+ * the received frame.
+ *
+ * @param txrx Flag denoting if this wfr is a txrx turn-around or not.
+ * @param tx_phy_mode phy mode for last TX (only valid for TX->RX)
+ * @param wfr_usecs Amount of usecs to wait.
+ */
+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->CC[2] + ble_phy_tifs_get();
+        /* 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->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_timer_cc_set(NRF_TIMER0, 3, end_time);
+    NRF_TIMER0->EVENTS_COMPARE[3] = 0;
+
+    /* Enable wait for response PPI */
+    nrf_ppi_channels_enable(NRF_PPI, (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1);
+    if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) {
+        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+        nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
+    }
+}
+
+#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->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0];
+        NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
+        NRF_CCM->OUTPTR = (uint32_t)dptr;
+        NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
+        NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption |
+                                                    ble_phy_get_ccm_datarate();
+        NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
+        NRF_CCM->SHORTS = 0;
+        NRF_CCM->EVENTS_ERROR = 0;
+        NRF_CCM->EVENTS_ENDCRYPT = 0;
+        nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN);
+        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk);
+    } else {
+        NRF_RADIO->PACKETPTR = (uint32_t)dptr;
+    }
+#else
+    NRF_RADIO->PACKETPTR = (uint32_t)dptr;
+#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+    if (g_ble_phy_data.phy_privacy) {
+        NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
+        NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+        NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
+        NRF_AAR->EVENTS_END = 0;
+        NRF_AAR->EVENTS_RESOLVED = 0;
+        NRF_AAR->EVENTS_NOTRESOLVED = 0;
+    } else {
+        if (g_ble_phy_data.phy_encrypted == 0) {
+            NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+        }
+    }
+#endif
+
+    /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk);
+
+    /* 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_bcc_set(NRF_RADIO, 8 + g_ble_phy_data.phy_bcc_offset); /* in bits */
+    NRF_RADIO->EVENTS_ADDRESS = 0;
+    NRF_RADIO->EVENTS_DEVMATCH = 0;
+    NRF_RADIO->EVENTS_BCMATCH = 0;
+    NRF_RADIO->EVENTS_RSSIEND = 0;
+    NRF_RADIO->EVENTS_CRCOK = 0;
+    NRF_RADIO->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_int_enable(NRF_RADIO, RADIO_INTENSET_ADDRESS_Msk |
+                         RADIO_INTENSET_DISABLED_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 tx_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);
+
+#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->EVENTS_ERROR) {
+            STATS_INC(ble_phy_stats, tx_hw_err);
+            NRF_CCM->EVENTS_ERROR = 0;
+        }
+    }
+#endif
+
+    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->CC[2] + ble_phy_tifs_get();
+        /* 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_timer_cc_set(NRF_TIMER0, 0, rx_time);
+        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+
+        ble_phy_fem_enable_lna();
+    } else if (transition == BLE_PHY_TRANSITION_TX_TX) {
+        /* Schedule TX exactly T_IFS after TX end captured in CC[2] */
+        tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get();
+        /* Adjust for delay between EVENT_END and actual TX end time */
+        tx_time += g_ble_phy_t_txenddelay[tx_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_timer_cc_set(NRF_TIMER0, 0, tx_time);
+        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+
+        nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
+        if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
+            nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+            g_ble_phy_data.phy_transition_late = 1;
+        }
+    } else {
+        /*
+         * XXX: not sure we need to stop the timer here all the time. Or that
+         * it should be stopped here.
+         */
+        nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
+        NRF_TIMER0->TASKS_SHUTDOWN = 1;
+        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
+                                 PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk);
+        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->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;
+
+    /* Disable automatic RXEN */
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
+
+    /* Set RSSI and CRC status flag in header */
+    ble_hdr = &g_ble_phy_data.rxhdr;
+    assert(NRF_RADIO->EVENTS_RSSIEND != 0);
+    ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->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->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) {
+            while (NRF_CCM->EVENTS_ENDCRYPT == 0) {
+                /* Make sure CCM finished */
+            };
+
+            /* Only set MIC failure flag if frame is not zero length */
+            if ((dptr[1] != 0) && (NRF_CCM->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->EVENTS_ERROR) {
+                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->CC[2] + ble_phy_tifs_get();
+    /* 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_timer_cc_set(NRF_TIMER0, 0, tx_time);
+    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+
+    ble_phy_fem_enable_pa();
+
+    /*
+     * 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
+    if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
+        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+        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->EVENTS_ADDRESS = 0;
+    nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk);
+
+    /* Clear wfr timer channels */
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+
+    /* 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->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;
+
+    /* XXX: I wonder if we always have the 1st byte. If we need to wait for
+     * rx chain delay, it could be 18 usecs from address interrupt. The
+       nrf52 may be able to get here early. */
+    /* Wait to get 1st byte of frame */
+    while (1) {
+        state = NRF_RADIO->STATE;
+        if (NRF_RADIO->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_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
+            NRF_RADIO->SHORTS = 0;
+            return false;
+        }
+
+#if BABBLESIM
+        tm_tick();
+#endif
+    }
+
+#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->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset);
+
+        /* Trigger AAR after last bit of AdvA is received */
+        NRF_RADIO->EVENTS_BCMATCH = 0;
+        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk);
+        nrf_radio_bcc_set(NRF_RADIO, (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;
+    } 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->INTENSET;
+
+    /*
+     * 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->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;
+        }
+    }
+
+    /* Handle disabled event. This is enabled for both TX and RX. On RX, we
+     * need to check phy_rx_started flag to make sure we actually were receiving
+     * a PDU, otherwise this is due to wfr.
+     */
+    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
+        BLE_LL_ASSERT(NRF_RADIO->EVENTS_END ||
+                      ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) &&
+                       !g_ble_phy_data.phy_rx_started));
+        NRF_RADIO->EVENTS_END = 0;
+        NRF_RADIO->EVENTS_DISABLED = 0;
+        nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_DISABLED_Msk);
+
+#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
+        g_ble_phy_data.tifs = BLE_LL_IFS;
+#endif
+
+        switch (g_ble_phy_data.phy_state) {
+        case BLE_PHY_STATE_RX:
+#if MYNEWT_VAL(BLE_LL_FEM_LNA)
+            NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+            ble_ll_fem_lna_disable();
+#endif
+            if (g_ble_phy_data.phy_rx_started) {
+                ble_phy_rx_end_isr();
+            } else {
+                ble_ll_wfr_timer_exp(NULL);
+            }
+            break;
+        case BLE_PHY_STATE_TX:
+#if MYNEWT_VAL(BLE_LL_FEM_PA)
+            NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+            ble_ll_fem_pa_disable();
+#endif
+            ble_phy_tx_end_isr();
+            break;
+        default:
+            BLE_LL_ASSERT(0);
+        }
+    }
+
+    g_ble_phy_data.phy_transition_late = 0;
+
+    /* Count # of interrupts */
+    STATS_INC(ble_phy_stats, phy_isrs);
+
+    os_trace_isr_exit();
+}
+
+#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \
+    MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
+    MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \
+    MYNEWT_VAL(BLE_LL_FEM_PA) || \
+    MYNEWT_VAL(BLE_LL_FEM_LNA)
+static int
+ble_phy_gpiote_configure(int pin)
+{
+    NRF_GPIO_Type *port;
+
+    g_ble_phy_gpiote_idx--;
+
+#if NRF52840_XXAA
+    port = pin > 31 ? NRF_P1 : NRF_P0;
+    pin &= 0x1f;
+#else
+    port = NRF_P0;
+#endif
+
+    /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */
+    port->DIRSET = (1 << pin);
+    port->OUTCLR = (1 << pin);
+
+    NRF_GPIOTE->CONFIG[g_ble_phy_gpiote_idx] =
+                        (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
+                        ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) |
+#if NRF52840_XXAA
+                        ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos);
+#else
+                        0;
+#endif
+
+    BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0);
+
+    return g_ble_phy_gpiote_idx;
+}
+#endif
+
+static void
+ble_phy_dbg_time_setup(void)
+{
+    int idx __attribute__((unused));
+
+    /*
+     * We setup GPIOTE starting from last configuration index to minimize risk
+     * of conflict with GPIO setup via hal. It's not great solution, but since
+     * this is just debugging code we can live with this.
+     */
+
+#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
+    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
+
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, (uint32_t)&(NRF_RADIO->EVENTS_READY),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk);
+
+    /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
+#endif
+
+#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
+    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
+
+    /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
+#endif
+
+#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
+    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
+
+#if NRF52840_XXAA
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_RXREADY),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
+#else
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_READY),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
+#endif
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, (uint32_t)&(NRF_RADIO->EVENTS_DISABLED),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk);
+
+    /* CH[4] and CH[5] are always on for wfr */
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
+#endif
+}
+
+/**
+ * ble phy init
+ *
+ * Initialize the PHY.
+ *
+ * @return int 0: success; PHY error code otherwise
+ */
+int
+ble_phy_init(void)
+{
+    int rc;
+
+    g_ble_phy_gpiote_idx = 8;
+
+    /* 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;
+
+#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
+    g_ble_phy_data.tifs = BLE_LL_IFS;
+#endif
+
+    /* Toggle peripheral power to reset (just in case) */
+    nrf_radio_power_set(NRF_RADIO, false);
+    nrf_radio_power_set(NRF_RADIO, true);
+
+    /* Disable all interrupts */
+    nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
+
+    /* Set configuration registers */
+    NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
+    NRF_RADIO->PCNF0 = NRF_PCNF0;
+
+    /* XXX: should maxlen be 251 for encryption? */
+    NRF_RADIO->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->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) &
+                            RADIO_MODECNF0_RU_Msk;
+
+    /* Set logical address 1 for TX and RX */
+    NRF_RADIO->TXADDRESS  = 0;
+    NRF_RADIO->RXADDRESSES  = (1 << 0);
+
+    /* Configure the CRC registers */
+    NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three;
+
+    /* Configure BLE poly */
+    NRF_RADIO->CRCPOLY = 0x0000065B;
+
+    /* Configure IFS */
+    NRF_RADIO->TIFS = BLE_LL_IFS;
+
+    /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk);
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+    nrf_ccm_int_disable(NRF_CCM, 0xffffffff);
+    NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
+    NRF_CCM->EVENTS_ERROR = 0;
+    memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad));
+#endif
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+    g_ble_phy_data.phy_aar_scratch = 0;
+    NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
+    nrf_aar_int_disable(NRF_AAR, 0xffffffff);
+    NRF_AAR->EVENTS_END = 0;
+    NRF_AAR->EVENTS_RESOLVED = 0;
+    NRF_AAR->EVENTS_NOTRESOLVED = 0;
+    NRF_AAR->NIRK = 0;
+#endif
+
+    /* TIMER0 setup for PHY when using RTC */
+    nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
+    NRF_TIMER0->TASKS_SHUTDOWN = 1;
+    NRF_TIMER0->BITMODE = 3;    /* 32-bit timer */
+    NRF_TIMER0->MODE = 0;       /* Timer mode */
+    NRF_TIMER0->PRESCALER = 4;  /* gives us 1 MHz */
+
+    /*
+     * PPI setup.
+     * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
+     *            to cancel the wait for response timer.
+     * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
+     *            for response timer.
+     */
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4,
+        (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS),
+        (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]));
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5,
+        (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]),
+        (uint32_t)&(NRF_RADIO->TASKS_DISABLE));
+
+#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
+#if FEM_SINGLE_GPIO
+    fem_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
+    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_idx]);
+    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_idx]);
+#else
+#if MYNEWT_VAL(BLE_LL_FEM_PA)
+    fem_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
+    NRF_GPIOTE->TASKS_CLR[fem_pa_idx] = 1;
+#endif
+#if MYNEWT_VAL(BLE_LL_FEM_LNA)
+    fem_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
+    NRF_GPIOTE->TASKS_CLR[fem_lna_idx] = 1;
+#endif
+#endif
+
+    NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
+    NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
+    NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+#endif
+
+    /* 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;
+    }
+
+    ble_phy_dbg_time_setup();
+
+    return 0;
+}
+
+/**
+ * Puts the phy into receive mode.
+ *
+ * @return int 0: success; BLE Phy error code otherwise
+ */
+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->STATE != RADIO_STATE_STATE_Disabled) &&
+            ((NRF_RADIO->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_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
+
+    /* Clear events prior to enabling receive */
+    NRF_RADIO->EVENTS_END = 0;
+    NRF_RADIO->EVENTS_DISABLED = 0;
+
+    /* Setup for rx */
+    ble_phy_rx_xcvr_setup();
+
+    /* PPI to start radio automatically shall be set here */
+    assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk);
+
+    return 0;
+}
+
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
+/**
+ * Called to enable encryption at the PHY. Note that this state will persist
+ * in the PHY; in other words, if you call this function you have to call
+ * disable so that future PHY transmits/receives will not be encrypted.
+ *
+ * @param pkt_counter
+ * @param iv
+ * @param key
+ * @param is_master
+ */
+void
+ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
+                       uint8_t is_master)
+{
+    memcpy(g_nrf_ccm_data.key, key, 16);
+    g_nrf_ccm_data.pkt_counter = pkt_counter;
+    memcpy(g_nrf_ccm_data.iv, iv, 8);
+    g_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->ENABLE = AAR_ENABLE_ENABLE_Disabled;
+    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
+}
+
+void
+ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
+{
+    g_nrf_ccm_data.pkt_counter = pkt_counter;
+    g_nrf_ccm_data.dir_bit = dir;
+}
+
+void
+ble_phy_encrypt_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk);
+    nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_STOP);
+    NRF_CCM->EVENTS_ERROR = 0;
+    NRF_CCM->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;
+}
+
+/**
+ * Called to set the start time of a transmission.
+ *
+ * This function is called to set the start time when we are not going from
+ * rx to tx automatically.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime   This is the tick at which the 1st bit of the preamble
+ *                  should be transmitted
+ * @param rem_usecs This is used only when the underlying timing uses a 32.768
+ *                  kHz crystal. It is the # of usecs from the cputime tick
+ *                  at which the first bit of the preamble should be
+ *                  transmitted.
+ * @return int
+ */
+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_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
+
+    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_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+        rc = 0;
+
+        ble_phy_fem_enable_pa();
+    }
+
+    return rc;
+}
+
+/**
+ * Called to set the start time of a reception
+ *
+ * This function acts a bit differently than transmit. If we are late getting
+ * here we will still attempt to receive.
+ *
+ * NOTE: care must be taken when calling this function. The channel should
+ * already be set.
+ *
+ * @param cputime
+ *
+ * @return int
+ */
+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_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+
+    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_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+
+    ble_phy_fem_enable_lna();
+
+    /* 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_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
+                             PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk);
+
+#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->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
+        NRF_CCM->INPTR = (uint32_t)dptr;
+        NRF_CCM->OUTPTR = (uint32_t)pktptr;
+        NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
+        NRF_CCM->EVENTS_ERROR = 0;
+        NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate();
+        NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
+    } else {
+#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
+        NRF_AAR->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_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN);
+    }
+#endif
+
+    NRF_RADIO->PACKETPTR = (uint32_t)pktptr;
+
+    /* Clear the ready, end and disabled events */
+    NRF_RADIO->EVENTS_READY = 0;
+    NRF_RADIO->EVENTS_END = 0;
+    NRF_RADIO->EVENTS_DISABLED = 0;
+
+    /* Enable shortcuts for transmit start/end. */
+    shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;
+    NRF_RADIO->SHORTS = shortcuts;
+    nrf_radio_int_enable(NRF_RADIO, 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->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;
+}
+
+/**
+ * ble phy txpwr set
+ *
+ * Set the transmit output power (in dBm).
+ *
+ * NOTE: If the output power specified is within the BLE limits but outside
+ * the chip limits, we "rail" the power level so we dont exceed the min/max
+ * chip values.
+ *
+ * @param dbm Power output in dBm.
+ *
+ * @return int 0: success; anything else is an error
+ */
+int
+ble_phy_txpwr_set(int dbm)
+{
+    /* "Rail" power level if outside supported range */
+    dbm = ble_phy_txpower_round(dbm);
+
+    NRF_RADIO->TXPOWER = dbm;
+    g_ble_phy_data.phy_txpwr_dbm = dbm;
+
+    return 0;
+}
+
+/**
+ * ble phy txpwr round
+ *
+ * Get the rounded transmit output power (in dBm).
+ *
+ * @param dbm Power output in dBm.
+ *
+ * @return int Rounded power in dBm
+ */
+int ble_phy_txpower_round(int dbm)
+{
+    /* TODO this should be per nRF52XXX */
+
+    /* "Rail" power level if outside supported range */
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm;
+    }
+
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm;
+    }
+
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm;
+    }
+
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm;
+    }
+
+    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_Neg20dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm;
+    }
+
+    return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
+}
+
+/**
+ * ble phy set access addr
+ *
+ * Set access address.
+ *
+ * @param access_addr Access address
+ *
+ * @return int 0: success; PHY error code otherwise
+ */
+static int
+ble_phy_set_access_addr(uint32_t access_addr)
+{
+    NRF_RADIO->BASE0 = (access_addr << 8);
+    NRF_RADIO->PREFIX0 = (NRF_RADIO->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24);
+
+    g_ble_phy_data.phy_access_address = access_addr;
+
+#ifndef BABBLESIM
+    ble_phy_apply_errata_102_106_107();
+#endif
+    return 0;
+}
+
+/**
+ * ble phy txpwr get
+ *
+ * Get the transmit power.
+ *
+ * @return int  The current PHY transmit power, in dBm
+ */
+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;
+}
+
+/**
+ * ble phy setchan
+ *
+ * Sets the logical frequency of the transceiver. The input parameter is the
+ * BLE channel index (0 to 39, inclusive). The NRF frequency register works like
+ * this: logical frequency = 2400 + FREQ (MHz).
+ *
+ * Thus, to get a logical frequency of 2402 MHz, you would program the
+ * FREQUENCY register to 2.
+ *
+ * @param chan This is the Data Channel Index or Advertising Channel index
+ *
+ * @return int 0: success; PHY error code otherwise
+ */
+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->CRCINIT = crcinit;
+
+    /* Set the frequency and the data whitening initial value */
+    g_ble_phy_data.phy_chan = chan;
+    NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan];
+    NRF_RADIO->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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
+    NRF_TIMER0->TASKS_SHUTDOWN = 1;
+    nrf_rtc_event_disable(NRF_RTC0, 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_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
+    NRF_RADIO->SHORTS = 0;
+    nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
+        PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk |
+        PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk);
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
+    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_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+
+    ble_phy_rx();
+}
+
+/**
+ * ble phy disable
+ *
+ * Disables the PHY. This should be called when an event is over. It stops
+ * the usec timer (if used), disables interrupts, disables the RADIO, disables
+ * PPI and sets state to idle.
+ */
+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();
+}
+
+/* Gets the current access address */
+uint32_t ble_phy_access_addr_get(void)
+{
+    return g_ble_phy_data.phy_access_address;
+}
+
+/**
+ * Return the phy state
+ *
+ * @return int The current PHY state.
+ */
+int
+ble_phy_state_get(void)
+{
+    return g_ble_phy_data.phy_state;
+}
+
+/**
+ * Called to see if a reception has started
+ *
+ * @return int
+ */
+int
+ble_phy_rx_started(void)
+{
+    return g_ble_phy_data.phy_rx_started;
+}
+
+/**
+ * Return the transceiver state
+ *
+ * @return int transceiver state.
+ */
+uint8_t
+ble_phy_xcvr_state_get(void)
+{
+    uint32_t state;
+    state = NRF_RADIO->STATE;
+    return (uint8_t)state;
+}
+
+/**
+ * Called to return the maximum data pdu payload length supported by the
+ * phy. For this chip, if encryption is enabled, the maximum payload is 27
+ * bytes.
+ *
+ * @return uint8_t Maximum data channel PDU payload size supported
+ */
+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->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->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk;
+}
+
+void ble_phy_disable_dtm(void)
+{
+    /* Enable whitening */
+    NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk;
+}
+#endif
+
+void
+ble_phy_rfclk_enable(void)
+{
+#if MYNEWT || defined(RIOT_VERSION)
+    nrf52_clock_hfxo_request();
+#else
+    nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
+#endif
+}
+
+void
+ble_phy_rfclk_disable(void)
+{
+#if MYNEWT || defined(RIOT_VERSION)
+    nrf52_clock_hfxo_release();
+#else
+    nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
+#endif
+}
diff --git a/nimble/drivers/nrf5x/src/ble_phy_trace.c b/nimble/drivers/nrf5x/src/ble_phy_trace.c
new file mode 100644
index 00000000..93b2eb32
--- /dev/null
+++ b/nimble/drivers/nrf5x/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/nimble/drivers/nrf5x/syscfg.yml b/nimble/drivers/nrf5x/syscfg.yml
new file mode 100644
index 00000000..3bd49708
--- /dev/null
+++ b/nimble/drivers/nrf5x/syscfg.yml
@@ -0,0 +1,72 @@
+# 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
+
+    BLE_PHY_DBG_TIME_TXRXEN_READY_PIN:
+        description: >
+            When set to proper GPIO pin number, this pin will be set
+            to high state when radio is enabled using PPI channels
+            20 or 21 and back to low state on radio EVENTS_READY.
+            This can be used to measure radio ram-up time.
+        value: -1
+
+    BLE_PHY_DBG_TIME_ADDRESS_END_PIN:
+        description: >
+            When set to proper GPIO pin number, this pin will be set
+            to high state on radio EVENTS_ADDRESS and back to low state
+            on radio EVENTS_END.
+            This can be used to measure radio pipeline delays.
+        value: -1
+
+    BLE_PHY_DBG_TIME_WFR_PIN:
+        description: >
+            When set to proper GPIO pin number, this pin will be set
+            to high state on radio EVENTS_RXREADY and back to low
+            state when wfr timer expires.
+            This can be used to check if wfr is calculated properly.
+        value: -1
+
+    BLE_PHY_NRF52840_ERRATA_164:
+        description: >
+            Enable workaround for anomaly 164 found in nRF52840.
+            "[164] RADIO: Low selectivity in long range mode"
+            This shall be only enabled for:
+            - nRF52840 Engineering A
+        value: 0
+
+    BLE_PHY_NRF52840_ERRATA_191:
+        description: >
+            Enable workaround for anomaly 191 found in nRF52840.
+            "[191] RADIO: High packet error rate in BLE Long Range mode"
+            This shall be only enabled for:
+            - nRF52840 Engineering B
+            - nRF52840 Engineering C
+            - nRF52840 Rev 1 (final silicon)
+        value: 1
+
+    BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR:
+        description: >
+            Ublox BMD-345 modules come with public address preprogrammed
+            in UICR register. If enabled public address will be read from
+            custom UICR instead of FICR register.
+        value: 0


[mynewt-nimble] 07/09: nimble/phy/nrf5x: Add support for FEM turn on time

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit f396441898a9fb80c81d9397fce09b83a93751e4
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Sat Sep 10 15:14:18 2022 +0200

    nimble/phy/nrf5x: Add support for FEM turn on time
    
    This adds proper support for FEM turn on time. Max supported turn on
    time is 90us due to some optimizations in code, but that should be
    enough - we can change it later if needed.
---
 nimble/drivers/nrf5x/src/ble_phy.c   | 196 +++++++++++++++++++++++++----------
 nimble/drivers/nrf5x/src/nrf52/phy.c |   2 +-
 nimble/drivers/nrf5x/syscfg.yml      |   6 ++
 3 files changed, 147 insertions(+), 57 deletions(-)

diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index 0d9b363f..52119d1e 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -606,41 +606,65 @@ ble_phy_tifs_get(void)
  *
  */
 static int
-ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx)
+ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx)
 {
     uint32_t next_cc;
     uint32_t cur_cc;
     uint32_t cntr;
     uint32_t delta;
+    int radio_rem_us;
+#if PHY_USE_FEM
+    int fem_rem_us = 0;
+#endif
+    int rem_us_corr;
+    int min_rem_us;
 
-    /*
-     * 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.
+    /* Calculate rem_us for radio and FEM enable. The result may be a negative
+     * value, but we'll adjust later.
      */
-
-    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];
+        radio_rem_us = rem_us - BLE_PHY_T_TXENFAST -
+                       g_ble_phy_t_txdelay[g_ble_phy_data.phy_cur_phy_mode];
+#if PHY_USE_FEM_PA
+        fem_rem_us = rem_us - MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US);
+#endif
     } else {
-        rem_usecs -= BLE_PHY_T_RXENFAST;
+        radio_rem_us = rem_us - BLE_PHY_T_TXENFAST;
+#if PHY_USE_FEM_LNA
+        fem_rem_us = rem_us - MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US);
+#endif
     }
 
-    /*
-     * 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 PHY_USE_FEM
+    min_rem_us = min(radio_rem_us, fem_rem_us);
+#else
+    min_rem_us = radio_rem_us;
+#endif
+
+    /* We need to adjust rem_us values, so they are >=1 for TIMER0 compare
+     * event to be triggered.
+     *
+     * If FEM is not enabled, calculated rem_us is -45<=rem_us<=-15 since we
+     * only had to adjust earlier for ramp-up and txdelay, i.e. 40+5=45us in
+     * worst case, so we adjust by 1 or 2 tick(s) only.
+     *
+     * If FEM is enabled, turn on time may be a bit longer, so we also allow to
+     * adjust by 3 ticks so up to 90us which should be enough. If needed, we
+     * can extend this by another tick but having FEM with turn on time >90us
+     * means transition may become tricky.
      */
 
-    if (rem_usecs > 30) {
-        cputime++;
-        rem_usecs -= 30;
+    if ((PHY_USE_FEM) && (min_rem_us <= -61)) {
+        cputime -= 3;
+        rem_us_corr = 91;
+    } else if (min_rem_us <= -30) {
+        /* rem_us is -60..-30 */
+        cputime -= 2;
+        rem_us_corr = 61;
+    } else {
+        /* rem_us is -29..0 */
+        cputime -= 1;
+        rem_us_corr = 30;
     }
 
     /*
@@ -668,8 +692,14 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx)
 
     /* Clear and set TIMER0 to fire off at proper time */
     nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
-    nrf_timer_cc_set(NRF_TIMER0, 0, rem_usecs);
+    nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us + rem_us_corr);
     NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+#if PHY_USE_FEM
+    if (fem_rem_us) {
+        nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us + rem_us_corr);
+        NRF_TIMER0->EVENTS_COMPARE[2] = 0;
+    }
+#endif
 
     /* Set RTC compare to start TIMER0 */
     NRF_RTC0->EVENTS_COMPARE[0] = 0;
@@ -677,6 +707,19 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx)
     nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
 
     /* Enable PPI */
+#if PHY_USE_FEM
+    if (fem_rem_us) {
+        if (tx) {
+#if PHY_USE_FEM_PA
+            phy_fem_enable_pa();
+#endif
+        } else {
+#if PHY_USE_FEM_LNA
+            phy_fem_enable_lna();
+#endif
+        }
+    }
+#endif
     phy_ppi_rtc0_compare0_to_timer0_start_enable();
 
     /* Store the cputime at which we set the RTC */
@@ -690,16 +733,41 @@ ble_phy_set_start_now(void)
 {
     os_sr_t sr;
     uint32_t now;
+    uint32_t radio_rem_us;
+#if PHY_USE_FEM_LNA
+    uint32_t fem_rem_us;
+#endif
 
     OS_ENTER_CRITICAL(sr);
 
-    /*
-     * Set TIMER0 to fire immediately. We can't set CC to 0 as compare will not
-     * occur in such case.
+    /* We need to set TIMER0 compare registers to at least 1 as otherwise
+     * compare event won't be triggered. Event (FEM/radio) that have to be
+     * triggered first is set to 1, other event is set to 1+diff.
+     *
+     * Note that this is only used for rx, so only need to handle LNA.
      */
+
+#if PHY_USE_FEM_LNA
+    if (MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US) > BLE_PHY_T_RXENFAST) {
+        radio_rem_us = 1 + MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US) -
+                       BLE_PHY_T_RXENFAST;
+        fem_rem_us = 1;
+    } else {
+        radio_rem_us = 1;
+        fem_rem_us = 1 + BLE_PHY_T_RXENFAST -
+                     MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US);
+    }
+#else
+    radio_rem_us = 1;
+#endif
+
     nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
-    nrf_timer_cc_set(NRF_TIMER0, 0, 1);
+    nrf_timer_cc_set(NRF_TIMER0, 0, radio_rem_us);
     NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+#if PHY_USE_FEM_LNA
+    nrf_timer_cc_set(NRF_TIMER0, 2, fem_rem_us);
+    NRF_TIMER0->EVENTS_COMPARE[2] = 0;
+#endif
 
     /*
      * Set RTC compare to start TIMER0. We need to set it to at least N+2 ticks
@@ -939,6 +1007,10 @@ ble_phy_tx_end_isr(void)
     uint8_t transition;
     uint32_t rx_time;
     uint32_t tx_time;
+#if PHY_USE_FEM_LNA
+    uint32_t fem_time;
+#endif
+    uint32_t radio_time;
 
     /* Store PHY on which we've just transmitted smth */
     tx_phy_mode = g_ble_phy_data.phy_cur_phy_mode;
@@ -983,25 +1055,33 @@ ble_phy_tx_end_isr(void)
         rx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get();
         /* 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_timer_cc_set(NRF_TIMER0, 0, rx_time);
-        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-        phy_ppi_timer0_compare0_to_radio_rxen_enable();
-
 #if PHY_USE_FEM_LNA
+        fem_time = rx_time - MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US);
+        nrf_timer_cc_set(NRF_TIMER0, 2, fem_time);
+        NRF_TIMER0->EVENTS_COMPARE[2] = 0;
         phy_fem_enable_lna();
 #endif
+
+        radio_time = rx_time - BLE_PHY_T_RXENFAST;
+        nrf_timer_cc_set(NRF_TIMER0, 0, radio_time);
+        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
+        phy_ppi_timer0_compare0_to_radio_rxen_enable();
+
+        /* In case TIMER0 did already count past CC[0] and/or CC[2], radio
+         * and/or LNA may not be enabled. In any case we won't be stuck since
+         * wfr will cancel rx if needed.
+         *
+         * FIXME failing to enable LNA may result in unexpected RSSI drop in
+         *       case we still rxd something, so perhaps we could check it here
+         */
     } else if (transition == BLE_PHY_TRANSITION_TX_TX) {
         /* Schedule TX exactly T_IFS after TX end captured in CC[2] */
         tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get();
         /* Adjust for delay between EVENT_END and actual TX end time */
         tx_time += g_ble_phy_t_txenddelay[tx_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];
 
@@ -1009,6 +1089,8 @@ ble_phy_tx_end_isr(void)
         NRF_TIMER0->EVENTS_COMPARE[0] = 0;
         phy_ppi_timer0_compare0_to_radio_txen_enable();
 
+        /* TODO handle PA */
+
         nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
         if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
             phy_ppi_timer0_compare0_to_radio_txen_disable();
@@ -1060,7 +1142,12 @@ ble_phy_rx_end_isr(void)
     uint8_t *dptr;
     uint8_t crcok;
     uint32_t tx_time;
+#if PHY_USE_FEM_PA
+    uint32_t fem_time;
+#endif
+    uint32_t radio_time;
     struct ble_mbuf_hdr *ble_hdr;
+    bool is_late;
 
     /* Disable automatic RXEN */
     phy_ppi_timer0_compare0_to_radio_rxen_disable();
@@ -1128,33 +1215,38 @@ ble_phy_rx_end_isr(void)
     tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get();
     /* 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;
+
+#if PHY_USE_FEM_PA
+    fem_time = tx_time - MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US);
+#endif
+
     /* 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_timer_cc_set(NRF_TIMER0, 0, tx_time);
+    radio_time = tx_time - BLE_PHY_T_TXENFAST;
+    nrf_timer_cc_set(NRF_TIMER0, 0, radio_time);
     NRF_TIMER0->EVENTS_COMPARE[0] = 0;
     phy_ppi_timer0_compare0_to_radio_txen_enable();
 
 #if PHY_USE_FEM_PA
+    nrf_timer_cc_set(NRF_TIMER0, 2, fem_time);
+    NRF_TIMER0->EVENTS_COMPARE[2] = 0;
     phy_fem_enable_pa();
 #endif
 
-    /*
-     * 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.
+    /* Need to check if TIMER0 did not already count past CC[0] and/or CC[2], so
+     * we're not stuck waiting for events in case radio and/or PA was not
+     * started. If event was triggered we're fine regardless of timer value.
      *
      * Note: CC[3] is used only for wfr which we do not need here.
      */
     nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
-    if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
+    is_late = (NRF_TIMER0->CC[3] > radio_time) && !NRF_TIMER0->EVENTS_COMPARE[0];
+#if PHY_USE_FEM_PA
+    is_late = is_late ||
+              ((NRF_TIMER0->CC[3] > fem_time) && !NRF_TIMER0->EVENTS_COMPARE[2]);
+#endif
+    if (is_late) {
         phy_ppi_timer0_compare0_to_radio_txen_disable();
         g_ble_phy_data.phy_transition_late = 1;
     }
@@ -1644,10 +1736,6 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
         /* Enable PPI to automatically start TXEN */
         phy_ppi_timer0_compare0_to_radio_txen_enable();
         rc = 0;
-
-#if PHY_USE_FEM_PA
-        phy_fem_enable_pa();
-#endif
     }
 
     return rc;
@@ -1694,10 +1782,6 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
     /* Enable PPI to automatically start RXEN */
     phy_ppi_timer0_compare0_to_radio_rxen_enable();
 
-#if PHY_USE_FEM_LNA
-    phy_fem_enable_lna();
-#endif
-
     /* Start rx */
     rc = ble_phy_rx();
 
diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c
index d4492464..188d1571 100644
--- a/nimble/drivers/nrf5x/src/nrf52/phy.c
+++ b/nimble/drivers/nrf5x/src/nrf52/phy.c
@@ -102,7 +102,7 @@ phy_fem_init(void)
 #endif
 #endif /* PHY_USE_FEM_SINGLE_GPIO */
 
-    NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
+    NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[2]);
     NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
 
     nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
diff --git a/nimble/drivers/nrf5x/syscfg.yml b/nimble/drivers/nrf5x/syscfg.yml
index f24517ef..1d4027f7 100644
--- a/nimble/drivers/nrf5x/syscfg.yml
+++ b/nimble/drivers/nrf5x/syscfg.yml
@@ -52,3 +52,9 @@ syscfg.defs:
             in UICR register. If enabled public address will be read from
             custom UICR instead of FICR register.
         value: 0
+
+syscfg.restrictions:
+    # code supports turn on times up to 90us due to some optimizations, but it
+    # should be enough for most (all?) cases
+    - "!BLE_LL_FEM_PA || BLE_LL_FEM_PA_TURN_ON_US <= 90"
+    - "!BLE_LL_FEM_LNA || BLE_LL_FEM_LNA_TURN_ON_US <= 90"


[mynewt-nimble] 02/09: nimble/phy/nrf5x: Move out nRF52 code

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 4d3b302fa603fee6cb842341a6e1945ee6e09c19
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Tue Sep 6 23:01:44 2022 +0200

    nimble/phy/nrf5x: Move out nRF52 code
    
    This moves most of code specific to nRF52 series to separate file and
    creates private phy APIs to call that code.
    
    The moved code is anything related to PPI: FEM, GPIO debug and PPI
    itself.
---
 nimble/drivers/nrf5x/src/ble_phy.c       | 267 ++++++-------------------------
 nimble/drivers/nrf5x/src/nrf52/phy.c     | 165 +++++++++++++++++++
 nimble/drivers/nrf5x/src/nrf52/phy_ppi.h | 113 +++++++++++++
 nimble/drivers/nrf5x/src/phy_priv.h      |  79 +++++++++
 4 files changed, 407 insertions(+), 217 deletions(-)

diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index a94cb2a7..93881948 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -25,7 +25,6 @@
 #include <hal/nrf_ccm.h>
 #include <hal/nrf_aar.h>
 #include <hal/nrf_timer.h>
-#include <hal/nrf_ppi.h>
 #include <hal/nrf_rtc.h>
 #include "syscfg/syscfg.h"
 #include "os/os.h"
@@ -46,6 +45,7 @@
 #else
 #include "core_cm4.h"
 #endif
+#include "phy_priv.h"
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
 #if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811)
@@ -319,27 +319,6 @@ struct nrf_ccm_data
 struct nrf_ccm_data g_nrf_ccm_data;
 #endif
 
-static int g_ble_phy_gpiote_idx;
-
-#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
-
-#define FEM_SINGLE_GPIO \
-    (!MYNEWT_VAL(BLE_LL_FEM_PA) || !MYNEWT_VAL(BLE_LL_FEM_LNA) || \
-     (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)))
-
-#if FEM_SINGLE_GPIO
-static uint8_t fem_idx;
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-static uint8_t fem_pa_idx;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-static uint8_t fem_lna_idx;
-#endif
-#endif
-
-#endif
-
 #ifndef BABBLESIM
 static void
 ble_phy_apply_errata_102_106_107(void)
@@ -465,36 +444,6 @@ ble_phy_mode_set(uint8_t tx_phy_mode, uint8_t rx_phy_mode)
 }
 #endif
 
-static void
-ble_phy_fem_enable_pa(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    ble_ll_fem_pa_enable();
-
-#if !FEM_SINGLE_GPIO
-    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_pa_idx]);
-    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_pa_idx]);
-#endif
-
-    NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-#endif
-}
-
-static void
-ble_phy_fem_enable_lna(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    ble_ll_fem_lna_enable();
-
-#if !FEM_SINGLE_GPIO
-    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_lna_idx]);
-    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_lna_idx]);
-#endif
-
-    NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-#endif
-}
-
 int
 ble_phy_get_cur_phy(void)
 {
@@ -741,7 +690,7 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_usecs, bool tx)
     nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
 
     /* Enable PPI */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
+    phy_ppi_rtc0_compare0_to_timer0_start_enable();
 
     /* Store the cputime at which we set the RTC */
     g_ble_phy_data.phy_start_cputime = cputime;
@@ -777,7 +726,8 @@ ble_phy_set_start_now(void)
     nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
 
     /* Enable PPI */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
+    phy_ppi_rtc0_compare0_to_timer0_start_enable();
+
     /*
      * Store the cputime at which we set the RTC
      *
@@ -856,7 +806,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
     NRF_TIMER0->EVENTS_COMPARE[3] = 0;
 
     /* Enable wait for response PPI */
-    nrf_ppi_channels_enable(NRF_PPI, (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk));
+    phy_ppi_wfr_enable();
 
     /*
      * It may happen that if CPU is halted for a brief moment (e.g. during flash
@@ -872,7 +822,7 @@ ble_phy_wfr_enable(int txrx, uint8_t tx_phy_mode, uint32_t wfr_usecs)
      */
     nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1);
     if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) {
-        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+        phy_ppi_wfr_disable();
         nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
     }
 }
@@ -927,7 +877,7 @@ ble_phy_rx_xcvr_setup(void)
         NRF_CCM->EVENTS_ERROR = 0;
         NRF_CCM->EVENTS_ENDCRYPT = 0;
         nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN);
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk);
+        phy_ppi_radio_address_to_ccm_crypt_enable();
     } else {
         NRF_RADIO->PACKETPTR = (uint32_t)dptr;
     }
@@ -951,7 +901,8 @@ ble_phy_rx_xcvr_setup(void)
 #endif
 
     /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk);
+    phy_ppi_timer0_compare0_to_radio_txen_disable();
+    phy_ppi_radio_bcmatch_to_aar_start_disable();
 
     /* Reset the rx started flag. Used for the wait for response */
     g_ble_phy_data.phy_rx_started = 0;
@@ -1052,9 +1003,11 @@ ble_phy_tx_end_isr(void)
 
         nrf_timer_cc_set(NRF_TIMER0, 0, rx_time);
         NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+        phy_ppi_timer0_compare0_to_radio_rxen_enable();
 
-        ble_phy_fem_enable_lna();
+#if PHY_USE_FEM_LNA
+        phy_fem_enable_lna();
+#endif
     } else if (transition == BLE_PHY_TRANSITION_TX_TX) {
         /* Schedule TX exactly T_IFS after TX end captured in CC[2] */
         tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get();
@@ -1067,11 +1020,11 @@ ble_phy_tx_end_isr(void)
 
         nrf_timer_cc_set(NRF_TIMER0, 0, tx_time);
         NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+        phy_ppi_timer0_compare0_to_radio_txen_enable();
 
         nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
         if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
-            nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+            phy_ppi_timer0_compare0_to_radio_txen_disable();
             g_ble_phy_data.phy_transition_late = 1;
         }
     } else {
@@ -1081,8 +1034,9 @@ ble_phy_tx_end_isr(void)
          */
         nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
         NRF_TIMER0->TASKS_SHUTDOWN = 1;
-        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
-                                 PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk);
+        phy_ppi_wfr_disable();
+        phy_ppi_timer0_compare0_to_radio_txen_disable();
+        phy_ppi_rtc0_compare0_to_timer0_start_disable();
         assert(transition == BLE_PHY_TRANSITION_NONE);
     }
 }
@@ -1122,7 +1076,7 @@ ble_phy_rx_end_isr(void)
     struct ble_mbuf_hdr *ble_hdr;
 
     /* Disable automatic RXEN */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
+    phy_ppi_timer0_compare0_to_radio_rxen_disable();
 
     /* Set RSSI and CRC status flag in header */
     ble_hdr = &g_ble_phy_data.rxhdr;
@@ -1194,9 +1148,11 @@ ble_phy_rx_end_isr(void)
 
     nrf_timer_cc_set(NRF_TIMER0, 0, tx_time);
     NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+    phy_ppi_timer0_compare0_to_radio_txen_enable();
 
-    ble_phy_fem_enable_pa();
+#if PHY_USE_FEM_PA
+    phy_fem_enable_pa();
+#endif
 
     /*
      * XXX: Hack warning!
@@ -1212,7 +1168,7 @@ ble_phy_rx_end_isr(void)
      */
     nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
     if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
-        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+        phy_ppi_timer0_compare0_to_radio_txen_disable();
         g_ble_phy_data.phy_transition_late = 1;
     }
 
@@ -1250,7 +1206,7 @@ ble_phy_rx_start_isr(void)
     nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk);
 
     /* Clear wfr timer channels */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+    phy_ppi_wfr_disable();
 
     /* Initialize the ble mbuf header */
     ble_hdr = &g_ble_phy_data.rxhdr;
@@ -1332,7 +1288,7 @@ ble_phy_rx_start_isr(void)
 
         /* Trigger AAR after last bit of AdvA is received */
         NRF_RADIO->EVENTS_BCMATCH = 0;
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk);
+        phy_ppi_radio_bcmatch_to_aar_start_enable();
         nrf_radio_bcc_set(NRF_RADIO, (BLE_LL_PDU_HDR_LEN + adva_offset +
             BLE_DEV_ADDR_LEN) * 8 + g_ble_phy_data.phy_bcc_offset);
     }
@@ -1409,7 +1365,7 @@ ble_phy_isr(void)
         switch (g_ble_phy_data.phy_state) {
         case BLE_PHY_STATE_RX:
 #if MYNEWT_VAL(BLE_LL_FEM_LNA)
-            NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+            phy_ppi_fem_disable();
             ble_ll_fem_lna_disable();
 #endif
             if (g_ble_phy_data.phy_rx_started) {
@@ -1420,7 +1376,7 @@ ble_phy_isr(void)
             break;
         case BLE_PHY_STATE_TX:
 #if MYNEWT_VAL(BLE_LL_FEM_PA)
-            NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+            phy_ppi_fem_disable();
             ble_ll_fem_pa_disable();
 #endif
             ble_phy_tx_end_isr();
@@ -1438,95 +1394,6 @@ ble_phy_isr(void)
     os_trace_isr_exit();
 }
 
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_LL_FEM_PA) || \
-    MYNEWT_VAL(BLE_LL_FEM_LNA)
-static int
-ble_phy_gpiote_configure(int pin)
-{
-    NRF_GPIO_Type *port;
-
-    g_ble_phy_gpiote_idx--;
-
-#if NRF52840_XXAA
-    port = pin > 31 ? NRF_P1 : NRF_P0;
-    pin &= 0x1f;
-#else
-    port = NRF_P0;
-#endif
-
-    /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */
-    port->DIRSET = (1 << pin);
-    port->OUTCLR = (1 << pin);
-
-    NRF_GPIOTE->CONFIG[g_ble_phy_gpiote_idx] =
-                        (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
-                        ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) |
-#if NRF52840_XXAA
-                        ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos);
-#else
-                        0;
-#endif
-
-    BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0);
-
-    return g_ble_phy_gpiote_idx;
-}
-#endif
-
-static void
-ble_phy_dbg_time_setup(void)
-{
-    int idx __attribute__((unused));
-
-    /*
-     * We setup GPIOTE starting from last configuration index to minimize risk
-     * of conflict with GPIO setup via hal. It's not great solution, but since
-     * this is just debugging code we can live with this.
-     */
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
-
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, (uint32_t)&(NRF_RADIO->EVENTS_READY),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk);
-
-    /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
-
-    /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
-
-#if NRF52840_XXAA
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_RXREADY),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-#else
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_READY),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-#endif
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, (uint32_t)&(NRF_RADIO->EVENTS_DISABLED),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk);
-
-    /* CH[4] and CH[5] are always on for wfr */
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-#endif
-}
-
 /**
  * ble phy init
  *
@@ -1539,8 +1406,6 @@ ble_phy_init(void)
 {
     int rc;
 
-    g_ble_phy_gpiote_idx = 8;
-
     /* 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;
@@ -1589,9 +1454,6 @@ ble_phy_init(void)
     /* Configure IFS */
     NRF_RADIO->TIFS = BLE_LL_IFS;
 
-    /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk);
-
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
     nrf_ccm_int_disable(NRF_CCM, 0xffffffff);
     NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
@@ -1616,39 +1478,13 @@ ble_phy_init(void)
     NRF_TIMER0->MODE = 0;       /* Timer mode */
     NRF_TIMER0->PRESCALER = 4;  /* gives us 1 MHz */
 
-    /*
-     * PPI setup.
-     * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
-     *            to cancel the wait for response timer.
-     * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
-     *            for response timer.
-     */
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4,
-        (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS),
-        (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]));
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5,
-        (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]),
-        (uint32_t)&(NRF_RADIO->TASKS_DISABLE));
-
-#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
-#if FEM_SINGLE_GPIO
-    fem_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
-    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_idx]);
-    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_idx]);
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    fem_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
-    NRF_GPIOTE->TASKS_CLR[fem_pa_idx] = 1;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    fem_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
-    NRF_GPIOTE->TASKS_CLR[fem_lna_idx] = 1;
-#endif
-#endif
+    phy_ppi_init();
 
-    NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
-    NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
-    NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
+#if PHY_USE_DEBUG
+    phy_debug_init();
+#endif
+#if PHY_USE_FEM
+    phy_fem_init();
 #endif
 
     /* Set isr in vector table and enable interrupt */
@@ -1674,8 +1510,6 @@ ble_phy_init(void)
         g_ble_phy_data.phy_stats_initialized  = 1;
     }
 
-    ble_phy_dbg_time_setup();
-
     return 0;
 }
 
@@ -1715,9 +1549,6 @@ ble_phy_rx(void)
     /* Setup for rx */
     ble_phy_rx_xcvr_setup();
 
-    /* PPI to start radio automatically shall be set here */
-    assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk);
-
     return 0;
 }
 
@@ -1756,7 +1587,7 @@ ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
 void
 ble_phy_encrypt_disable(void)
 {
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk);
+    phy_ppi_radio_address_to_ccm_crypt_disable();
     nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_STOP);
     NRF_CCM->EVENTS_ERROR = 0;
     NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Disabled;
@@ -1803,7 +1634,7 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
 
     /* XXX: This should not be necessary, but paranoia is good! */
     /* Clear timer0 compare to RXEN since we are transmitting */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
+    phy_ppi_timer0_compare0_to_radio_rxen_disable();
 
     if (ble_phy_set_start_time(cputime, rem_usecs, true) != 0) {
         STATS_INC(ble_phy_stats, tx_late);
@@ -1811,10 +1642,12 @@ ble_phy_tx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
         rc = BLE_PHY_ERR_TX_LATE;
     } else {
         /* Enable PPI to automatically start TXEN */
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+        phy_ppi_timer0_compare0_to_radio_txen_enable();
         rc = 0;
 
-        ble_phy_fem_enable_pa();
+#if PHY_USE_FEM_PA
+        phy_fem_enable_pa();
+#endif
     }
 
     return rc;
@@ -1847,7 +1680,7 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
 
     /* XXX: This should not be necessary, but paranoia is good! */
     /* Clear timer0 compare to TXEN since we are transmitting */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+    phy_ppi_timer0_compare0_to_radio_txen_disable();
 
     if (ble_phy_set_start_time(cputime, rem_usecs, false) != 0) {
         STATS_INC(ble_phy_stats, rx_late);
@@ -1859,9 +1692,11 @@ ble_phy_rx_set_start_time(uint32_t cputime, uint8_t rem_usecs)
     }
 
     /* Enable PPI to automatically start RXEN */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+    phy_ppi_timer0_compare0_to_radio_rxen_enable();
 
-    ble_phy_fem_enable_lna();
+#if PHY_USE_FEM_LNA
+    phy_fem_enable_lna();
+#endif
 
     /* Start rx */
     rc = ble_phy_rx();
@@ -1907,8 +1742,9 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
      * paranoid, and if you are going to clear one, might as well clear them
      * all.
      */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
-                             PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk);
+    phy_ppi_wfr_disable();
+    phy_ppi_radio_bcmatch_to_aar_start_disable();
+    phy_ppi_radio_address_to_ccm_crypt_disable();
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
     if (g_ble_phy_data.phy_encrypted) {
@@ -2158,10 +1994,7 @@ ble_phy_disable_irq_and_ppi(void)
     nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
     NRF_RADIO->SHORTS = 0;
     nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
-        PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk |
-        PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk);
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
+    phy_ppi_disable();
     NVIC_ClearPendingIRQ(RADIO_IRQn);
     g_ble_phy_data.phy_state = BLE_PHY_STATE_IDLE;
 }
@@ -2174,7 +2007,7 @@ ble_phy_restart_rx(void)
 
     ble_phy_set_start_now();
     /* Enable PPI to automatically start RXEN */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+    phy_ppi_timer0_compare0_to_radio_rxen_enable();
 
     ble_phy_rx();
 }
diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c
new file mode 100644
index 00000000..4f825b8f
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/nrf52/phy.c
@@ -0,0 +1,165 @@
+/*
+ * 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 <nrfx.h>
+#include <controller/ble_ll_fem.h>
+#include "../phy_priv.h"
+
+#if PHY_USE_DEBUG
+void
+phy_debug_init(void)
+{
+#if PHY_USE_DEBUG_1
+    phy_gpiote_configure(PHY_GPIOTE_DEBUG_1,
+                         MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
+
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 17,
+                                   (uint32_t)&(NRF_RADIO->EVENTS_READY),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_1]));
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk);
+
+    /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 20,
+                                (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1]));
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 21,
+                                (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_1]));
+#endif
+
+#if PHY_USE_DEBUG_2
+    phy_gpiote_configure(PHY_GPIOTE_DEBUG_2,
+                         MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
+
+    /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 26,
+                                (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_2]));
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 27,
+                                (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_2]));
+#endif
+
+#if PHY_USE_DEBUG_3
+    phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
+
+#if NRF52840_XXAA
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18,
+                                   (uint32_t)&(NRF_RADIO->EVENTS_RXREADY),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_DEBUG_3]));
+#else
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18,
+                                   (uint32_t)&(NRF_RADIO->EVENTS_READY),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[GIDX_DEBUG_3]));
+#endif
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, 19,
+                                   (uint32_t)&(NRF_RADIO->EVENTS_DISABLED),
+                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3]));
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk);
+
+    /* CH[4] and CH[5] are always on for wfr */
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 4,
+                                (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3]));
+    nrf_ppi_fork_endpoint_setup(NRF_PPI, 5,
+                                (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_DEBUG_3]));
+#endif
+}
+#endif /* PHY_USE_DEBUG */
+
+#if PHY_USE_FEM
+void
+phy_fem_init(void)
+{
+#if PHY_USE_FEM_SINGLE_GPIO
+#if PHY_USE_FEM_PA
+    phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
+#else
+    phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
+#endif
+    NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM]);
+    NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM]);
+#else
+#if PHY_USE_FEM_PA
+    phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1;
+#endif
+#if PHY_USE_FEM_LNA
+    phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1;
+#endif
+#endif /* PHY_USE_FEM_SINGLE_GPIO */
+
+    NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
+    NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
+
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
+}
+
+#if PHY_USE_FEM_PA
+void
+phy_fem_enable_pa(void)
+{
+    ble_ll_fem_pa_enable();
+
+#if !PHY_USE_FEM_SINGLE_GPIO
+    /* Switch FEM channels to control PA */
+    NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_PA]);
+    NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA]);
+#endif
+
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
+}
+#endif
+
+#if PHY_USE_FEM_LNA
+void
+phy_fem_enable_lna(void)
+{
+    ble_ll_fem_lna_enable();
+
+#if !PHY_USE_FEM_SINGLE_GPIO
+    /* Switch FEM channels to control LNA */
+    NRF_PPI->CH[6].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_SET[PHY_GPIOTE_FEM_LNA]);
+    NRF_PPI->CH[7].TEP = (uint32_t)&(NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA]);
+#endif
+
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
+}
+#endif
+#endif /* PHY_USE_FEM */
+
+void
+phy_ppi_init(void)
+{
+    /* radio_address_to_timer0_capture1 */
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk);
+    /* radio_end_to_timer0_capture2 */
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH27_Msk);
+
+    /*
+     * PPI setup.
+     * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
+     *            to cancel the wait for response timer.
+     * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
+     *            for response timer.
+     */
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4,
+                                   (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS),
+                                   (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]));
+    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5,
+                                   (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]),
+                                   (uint32_t)&(NRF_RADIO->TASKS_DISABLE));
+}
diff --git a/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h
new file mode 100644
index 00000000..a77b7183
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/nrf52/phy_ppi.h
@@ -0,0 +1,113 @@
+/*
+ * 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_PHY_PPI_
+#define H_PHY_PPI_
+
+#include <nrf_ppi.h>
+
+static inline void
+phy_ppi_rtc0_compare0_to_timer0_start_enable(void)
+{
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
+}
+
+static inline void
+phy_ppi_rtc0_compare0_to_timer0_start_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH31_Msk);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_txen_enable(void)
+{
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_txen_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_rxen_enable(void)
+{
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_rxen_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
+}
+
+static inline void
+phy_ppi_radio_bcmatch_to_aar_start_enable(void)
+{
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk);
+}
+
+static inline void
+phy_ppi_radio_bcmatch_to_aar_start_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH23_Msk);
+}
+
+static inline void
+phy_ppi_radio_address_to_ccm_crypt_enable(void)
+{
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk);
+}
+
+static inline void
+phy_ppi_radio_address_to_ccm_crypt_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk);
+}
+
+static inline void
+phy_ppi_wfr_enable(void)
+{
+    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+}
+
+static inline void
+phy_ppi_wfr_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
+}
+
+static inline void
+phy_ppi_fem_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
+}
+
+static inline void
+phy_ppi_disable(void)
+{
+    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
+                                      PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk |
+                                      PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk |
+                                      PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk |
+                                      PPI_CHEN_CH31_Msk);
+}
+
+#endif /* H_PHY_PPI_ */
diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h
new file mode 100644
index 00000000..881221ad
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/phy_priv.h
@@ -0,0 +1,79 @@
+/*
+ * 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_PHY_PRIV_
+#define H_PHY_PRIV_
+
+#include <nrf_gpio.h>
+#include <nrf_gpiote.h>
+
+#define PHY_USE_DEBUG_1     (MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0)
+#define PHY_USE_DEBUG_2     (MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0)
+#define PHY_USE_DEBUG_3     (MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0)
+#define PHY_USE_DEBUG       (PHY_USE_DEBUG_1 || PHY_USE_DEBUG_2 || PHY_USE_DEBUG_3)
+
+#define PHY_USE_FEM_PA      (MYNEWT_VAL(BLE_LL_FEM_PA) != 0)
+#define PHY_USE_FEM_LNA     (MYNEWT_VAL(BLE_LL_FEM_LNA) != 0)
+#define PHY_USE_FEM         (PHY_USE_FEM_PA || PHY_USE_FEM_LNA)
+#define PHY_USE_FEM_SINGLE_GPIO \
+    (PHY_USE_FEM && (!PHY_USE_FEM_PA || !PHY_USE_FEM_LNA || \
+                     (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == \
+                      MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO))))
+
+/* GPIOTE indexes, start assigning from last one */
+#define PHY_GPIOTE_DEBUG_1  (8 - PHY_USE_DEBUG_1)
+#define PHY_GPIOTE_DEBUG_2  (PHY_GPIOTE_DEBUG_1 - PHY_USE_DEBUG_2)
+#define PHY_GPIOTE_DEBUG_3  (PHY_GPIOTE_DEBUG_2 - PHY_USE_DEBUG_3)
+#if PHY_USE_FEM_SINGLE_GPIO
+#define PHY_GPIOTE_FEM      (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM)
+#else
+#define PHY_GPIOTE_FEM_PA   (PHY_GPIOTE_DEBUG_3 - PHY_USE_FEM_PA)
+#define PHY_GPIOTE_FEM_LNA  (PHY_GPIOTE_FEM_PA - PHY_USE_FEM_LNA)
+#endif
+
+static inline void
+phy_gpiote_configure(int idx, int pin)
+{
+    nrf_gpio_cfg_output(pin);
+    nrf_gpiote_task_configure(NRF_GPIOTE, idx, pin, NRF_GPIOTE_POLARITY_NONE,
+                              NRF_GPIOTE_INITIAL_VALUE_LOW);
+    nrf_gpiote_task_enable(NRF_GPIOTE, idx);
+}
+
+#if PHY_USE_DEBUG
+void phy_debug_init(void);
+#endif
+
+#if PHY_USE_FEM
+void phy_fem_init(void);
+#if PHY_USE_FEM_PA
+void phy_fem_enable_pa(void);
+#endif
+#if PHY_USE_FEM_LNA
+void phy_fem_enable_lna(void);
+#endif
+#endif
+
+void phy_ppi_init(void);
+
+#ifdef NRF52_SERIES
+#include "nrf52/phy_ppi.h"
+#endif
+
+#endif /* H_PHY_PRIV_ */


[mynewt-nimble] 08/09: nimble/phy/nrf5x: Adjust scheduling offset for FEM turn on

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit eaa56fa7e7a90522109e097d34be06a4b65013ee
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Mon Sep 12 16:37:11 2022 +0200

    nimble/phy/nrf5x: Adjust scheduling offset for FEM turn on
    
    Radio enable takes 2 ticks, so if FEM turn on time is more than that we
    need to account for extra tick in scheduling offset.
---
 nimble/drivers/nrf5x/include/ble/xcvr.h | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/nimble/drivers/nrf5x/include/ble/xcvr.h b/nimble/drivers/nrf5x/include/ble/xcvr.h
index 757bb80f..829514b4 100644
--- a/nimble/drivers/nrf5x/include/ble/xcvr.h
+++ b/nimble/drivers/nrf5x/include/ble/xcvr.h
@@ -24,14 +24,23 @@
 extern "C" {
 #endif
 
+#include <syscfg/syscfg.h>
+
 #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.
+/* We need to account for the RTC compare issue, we want it to be 5 ticks.
+ * In case FEM turn on time is more than radio enable (i.e. 2 ticks) we want
+ * to add 1 more tick to compensate for additional delay.
+ *
+ * TODO this file should be refactored...
  */
+#if (MYNEWT_VAL(BLE_LL_FEM_PA) && (MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US) > 60)) || \
+    (MYNEWT_VAL(BLE_LL_FEM_LNA) && (MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US) > 60))
+#define XCVR_PROC_DELAY_USECS         (183)
+#else
 #define XCVR_PROC_DELAY_USECS         (153)
+#endif
 #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     \


[mynewt-nimble] 03/09: nimble/phy/nrf5x: Rework nRF52 erratas

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit e4b98645145927e84de5442850e6e90aa79deffd
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Thu Sep 8 10:12:28 2022 +0200

    nimble/phy/nrf5x: Rework nRF52 erratas
---
 nimble/drivers/nrf5x/src/ble_phy.c | 84 +++++++++++++++-----------------------
 nimble/drivers/nrf5x/syscfg.yml    | 18 --------
 2 files changed, 32 insertions(+), 70 deletions(-)

diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index 93881948..d5113434 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -45,6 +45,7 @@
 #else
 #include "core_cm4.h"
 #endif
+#include <nrf_erratas.h>
 #include "phy_priv.h"
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
@@ -319,19 +320,6 @@ struct nrf_ccm_data
 struct nrf_ccm_data g_nrf_ccm_data;
 #endif
 
-#ifndef BABBLESIM
-static void
-ble_phy_apply_errata_102_106_107(void)
-{
-    /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS
-     * [106] RADIO: Higher CRC error rates for some access addresses
-     * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00
-     */
-    *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) &
-                         0xfffffffe) | 0x01000000;
-}
-#endif
-
 #if (BLE_LL_BT5_PHY_SUPPORTED == 1)
 
 /* Packet start offset (in usecs). This is the preamble plus access address.
@@ -342,8 +330,8 @@ ble_phy_mode_pdu_start_off(int phy_mode)
     return g_ble_phy_mode_pkt_start_off[phy_mode];
 }
 
-#if NRF52840_XXAA
-static inline bool
+#if NRF52_ERRATA_191_ENABLE_WORKAROUND
+static bool
 ble_phy_mode_is_coded(uint8_t phy_mode)
 {
     return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) ||
@@ -351,48 +339,26 @@ ble_phy_mode_is_coded(uint8_t phy_mode)
 }
 
 static void
-ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode)
+phy_nrf52_errata_191(uint8_t new_phy_mode)
 {
-    bool new_coded = ble_phy_mode_is_coded(new_phy_mode);
-    bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode);
+    bool from_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode);
+    bool to_coded = ble_phy_mode_is_coded(new_phy_mode);
 
-    /*
-     * Workarounds should be applied only when switching to/from LE Coded PHY
-     * so no need to apply them every time.
-     *
-     * nRF52840 Engineering A Errata v1.2
-     * [164] RADIO: Low sensitivity in long range mode
-     *
-     * nRF52840 Rev 1 Errata
-     * [191] RADIO: High packet error rate in BLE Long Range mode
+    /* [191] RADIO: High packet error rate in BLE Long Range mode
+     * Should be applied only if switching to/from LE Coded, no need to apply
+     * on each mode change.
      */
-    if (new_coded == cur_coded) {
+    if (from_coded == to_coded) {
         return;
     }
 
-    if (new_coded) {
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
-        /* [164] */
-        *(volatile uint32_t *)0x4000173C |= 0x80000000;
-        *(volatile uint32_t *)0x4000173C =
-                        ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C);
-#endif
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
-        /* [191] */
-        *(volatile uint32_t *) 0x40001740 =
-                        ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) |
-                        0x80000000 | (((uint32_t)(196)) << 8);
-#endif
+    if (to_coded) {
+        *(volatile uint32_t *)0x40001740 =
+            ((*((volatile uint32_t *)0x40001740)) & 0x7fff00ff) |
+            0x80000000 | (((uint32_t)(196)) << 8);
     } else {
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
-        /* [164] */
-        *(volatile uint32_t *)0x4000173C &= ~0x80000000;
-#endif
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
-        /* [191] */
         *(volatile uint32_t *) 0x40001740 =
-                        ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
-#endif
+            ((*((volatile uint32_t *) 0x40001740)) & 0x7fffffff);
     }
 }
 #endif
@@ -404,8 +370,10 @@ ble_phy_mode_apply(uint8_t phy_mode)
         return;
     }
 
-#if NRF52840_XXAA
-    ble_phy_apply_nrf52840_errata(phy_mode);
+#if NRF52_ERRATA_191_ENABLE_WORKAROUND
+    if (nrf52_errata_191()) {
+        phy_nrf52_errata_191(phy_mode);
+    }
 #endif
 
     switch (phy_mode) {
@@ -1906,9 +1874,21 @@ ble_phy_set_access_addr(uint32_t access_addr)
 
     g_ble_phy_data.phy_access_address = access_addr;
 
+#if NRF52_ERRATA_102_ENABLE_WORKAROUND || \
+    NRF52_ERRATA_106_ENABLE_WORKAROUND || \
+    NRF52_ERRATA_107_ENABLE_WORKAROUND
 #ifndef BABBLESIM
-    ble_phy_apply_errata_102_106_107();
+    if (nrf52_errata_102() || nrf52_errata_106() || nrf52_errata_107()) {
+        /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS
+         * [106] RADIO: Higher CRC error rates for some access addresses
+         * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00
+         */
+        *(volatile uint32_t *)0x40001774 =
+            ((*(volatile uint32_t *)0x40001774) & 0xfffffffe) | 0x01000000;
+    }
 #endif
+#endif
+
     return 0;
 }
 
diff --git a/nimble/drivers/nrf5x/syscfg.yml b/nimble/drivers/nrf5x/syscfg.yml
index 3bd49708..f24517ef 100644
--- a/nimble/drivers/nrf5x/syscfg.yml
+++ b/nimble/drivers/nrf5x/syscfg.yml
@@ -46,24 +46,6 @@ syscfg.defs:
             This can be used to check if wfr is calculated properly.
         value: -1
 
-    BLE_PHY_NRF52840_ERRATA_164:
-        description: >
-            Enable workaround for anomaly 164 found in nRF52840.
-            "[164] RADIO: Low selectivity in long range mode"
-            This shall be only enabled for:
-            - nRF52840 Engineering A
-        value: 0
-
-    BLE_PHY_NRF52840_ERRATA_191:
-        description: >
-            Enable workaround for anomaly 191 found in nRF52840.
-            "[191] RADIO: High packet error rate in BLE Long Range mode"
-            This shall be only enabled for:
-            - nRF52840 Engineering B
-            - nRF52840 Engineering C
-            - nRF52840 Rev 1 (final silicon)
-        value: 1
-
     BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR:
         description: >
             Ublox BMD-345 modules come with public address preprogrammed


[mynewt-nimble] 05/09: nimble/phy/nrf5x: Force FEM disable on ble_phy_disable

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0024679216db08366dd0358e6eedfa3022d7627e
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Sat Sep 10 01:24:07 2022 +0200

    nimble/phy/nrf5x: Force FEM disable on ble_phy_disable
---
 nimble/drivers/nrf5x/src/ble_phy.c   |  4 ++++
 nimble/drivers/nrf5x/src/nrf52/phy.c | 15 +++++++++++++++
 nimble/drivers/nrf5x/src/phy_priv.h  |  1 +
 3 files changed, 20 insertions(+)

diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index b4d64d88..36f209c5 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -1976,6 +1976,10 @@ ble_phy_disable(void)
 
     ble_phy_stop_usec_timer();
     ble_phy_disable_irq_and_ppi();
+
+#if PHY_USE_FEM
+    phy_fem_disable();
+#endif
 }
 
 /* Gets the current access address */
diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c
index 763e3eef..d4492464 100644
--- a/nimble/drivers/nrf5x/src/nrf52/phy.c
+++ b/nimble/drivers/nrf5x/src/nrf52/phy.c
@@ -139,6 +139,21 @@ phy_fem_enable_lna(void)
     nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
 }
 #endif
+
+void
+phy_fem_disable(void)
+{
+#if PHY_USE_FEM_SINGLE_GPIO
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1;
+#else
+#if PHY_USE_FEM_PA
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1;
+#endif
+#if PHY_USE_FEM_LNA
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1;
+#endif
+#endif
+}
 #endif /* PHY_USE_FEM */
 
 void
diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h
index b2308e61..1a026a6d 100644
--- a/nimble/drivers/nrf5x/src/phy_priv.h
+++ b/nimble/drivers/nrf5x/src/phy_priv.h
@@ -68,6 +68,7 @@ void phy_fem_enable_pa(void);
 #if PHY_USE_FEM_LNA
 void phy_fem_enable_lna(void);
 #endif
+void phy_fem_disable(void);
 #endif
 
 void phy_ppi_init(void);


[mynewt-nimble] 09/09: nimble/ll: Remove nrf52 and nrf5340 phys

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 3b02d6ba2f9c2fd32b070ff533b1cd3a10d69501
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Thu Sep 8 15:13:43 2022 +0200

    nimble/ll: Remove nrf52 and nrf5340 phys
---
 nimble/drivers/nrf52/include/ble/xcvr.h    |   52 -
 nimble/drivers/nrf52/pkg.yml               |   13 +-
 nimble/drivers/nrf52/src/ble_hw.c          |  517 -------
 nimble/drivers/nrf52/src/ble_phy.c         | 2301 ----------------------------
 nimble/drivers/nrf52/src/ble_phy_trace.c   |   44 -
 nimble/drivers/nrf52/syscfg.yml            |   81 -
 nimble/drivers/nrf5340/include/ble/xcvr.h  |   50 -
 nimble/drivers/nrf5340/pkg.yml             |   13 +-
 nimble/drivers/nrf5340/src/ble_hw.c        |  477 ------
 nimble/drivers/nrf5340/src/ble_phy.c       | 2079 -------------------------
 nimble/drivers/nrf5340/src/ble_phy_trace.c |   45 -
 nimble/drivers/nrf5340/syscfg.yml          |   62 -
 12 files changed, 4 insertions(+), 5730 deletions(-)

diff --git a/nimble/drivers/nrf52/include/ble/xcvr.h b/nimble/drivers/nrf52/include/ble/xcvr.h
deleted file mode 100644
index 757bb80f..00000000
--- a/nimble/drivers/nrf52/include/ble/xcvr.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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/nimble/drivers/nrf52/pkg.yml b/nimble/drivers/nrf52/pkg.yml
index a1ff457e..c9745261 100644
--- a/nimble/drivers/nrf52/pkg.yml
+++ b/nimble/drivers/nrf52/pkg.yml
@@ -18,14 +18,5 @@
 #
 
 pkg.name: nimble/drivers/nrf52
-pkg.description: BLE driver for nRF52 systems.
-pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
-pkg.homepage: "http://mynewt.apache.org/"
-pkg.keywords:
-    - ble
-    - bluetooth
-
-pkg.apis: ble_driver
-pkg.deps:
-    - nimble
-    - nimble/controller
+pkg.type: transient
+pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x"
diff --git a/nimble/drivers/nrf52/src/ble_hw.c b/nimble/drivers/nrf52/src/ble_hw.c
deleted file mode 100644
index 0accbbf4..00000000
--- a/nimble/drivers/nrf52/src/ble_hw.c
+++ /dev/null
@@ -1,517 +0,0 @@
-/*
- * 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 "ble/xcvr.h"
-#include "nimble/ble.h"
-#include "nimble/nimble_opt.h"
-#include "nrfx.h"
-#include "controller/ble_hw.h"
-#if MYNEWT
-#include "mcu/cmsis_nvic.h"
-#else
-#include "core_cm4.h"
-#include <nimble/nimble_npl_os.h>
-#endif
-#include "os/os_trace_api.h"
-#include <hal/nrf_rng.h>
-#include "hal/nrf_ecb.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 */
-ble_rng_isr_cb_t g_ble_rng_isr_cb;
-
-#if BABBLESIM
-extern void tm_tick(void);
-#endif
-
-/* If LL privacy is enabled, allocate memory for AAR */
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
-
-/* The NRF51 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;
-
-#if MYNEWT_VAL(BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR)
-    /*
-    * The BMD-345 modules are preprogrammed from the factory with a unique public
-    * The  Bluetooth device address stored in the CUSTOMER[0] and CUSTOMER[1]
-    * registers of the User Information Configuration Registers (UICR).
-    * The Bluetooth device address consists of the IEEE Organizationally Unique
-    * Identifier (OUI) combined with the hexadecimal digits that are printed on
-    * a 2D barcode and in human-readable text on the module label.The Bluetooth
-    * device address is stored in little endian format. The most significant
-    * bytes of the CUSTOMER[1] register are 0xFF to complete the 32-bit register.
-    */
-
-    /* Copy into device address. We can do this because we know platform */
-    addr_low = NRF_UICR->CUSTOMER[0];
-    addr_high = NRF_UICR->CUSTOMER[1];
-#else
-    /* Does FICR have a public address */
-    if ((NRF_FICR->DEVICEADDRTYPE & 1) != 0) {
-        return -1;
-    }
-
-    /* Copy into device address. We can do this because we know platform */
-    addr_low = NRF_FICR->DEVICEADDR[0];
-    addr_high = NRF_FICR->DEVICEADDR[1];
-#endif
-
-    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)
-{
-    uint32_t addr_high;
-    uint32_t addr_low;
-    int rc;
-
-    if ((NRF_FICR->DEVICEADDRTYPE & 1) == 1) {
-        addr_low = NRF_FICR->DEVICEADDR[0];
-        addr_high = NRF_FICR->DEVICEADDR[1];
-
-        memcpy(addr->val, &addr_low, 4);
-        memcpy(&addr->val[4], &addr_high, 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->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->DAB[i] = get_le32(addr);
-            NRF_RADIO->DAP[i] = get_le16(addr + 4);
-            if (addr_type == BLE_ADDR_RANDOM) {
-                NRF_RADIO->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;
-    uint8_t cfg_addr;
-    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->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->DAB[i]) && (dap == NRF_RADIO->DAP[i])) {
-                cfg_addr = txadd & mask;
-                if (addr_type == BLE_ADDR_RANDOM) {
-                    if (cfg_addr != 0) {
-                        break;
-                    }
-                } else {
-                    if (cfg_addr == 0) {
-                        break;
-                    }
-                }
-            }
-        }
-        mask <<= 1;
-    }
-
-    if (i < BLE_HW_WHITE_LIST_SIZE) {
-        g_ble_hw_whitelist_mask &= ~mask;
-        NRF_RADIO->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->DACNF |= g_ble_hw_whitelist_mask;
-}
-
-/**
- * Disables the whitelisted devices
- */
-void
-ble_hw_whitelist_disable(void)
-{
-    /* Disable all whitelist devices */
-    NRF_RADIO->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 (int)NRF_RADIO->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_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB);
-    /* XXX: does task stop clear these counters? Anyway to do this quicker? */
-    NRF_ECB->EVENTS_ENDECB = 0;
-    NRF_ECB->EVENTS_ERRORECB = 0;
-    NRF_ECB->ECBDATAPTR = (uint32_t)ecb;
-
-    /* Start ECB */
-    nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STARTECB);
-
-    /* Wait till error or done */
-    rc = 0;
-    while (1) {
-        end = NRF_ECB->EVENTS_ENDECB;
-        err = NRF_ECB->EVENTS_ERRORECB;
-        if (end || err) {
-            if (err) {
-                rc = -1;
-            }
-            break;
-        }
-#if BABBLESIM
-        tm_tick();
-#endif
-    }
-
-    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 (g_ble_rng_isr_cb == NULL) {
-        nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK);
-        NRF_RNG->EVENTS_VALRDY = 0;
-        (void)NRF_RNG->SHORTS;
-        os_trace_isr_exit();
-        return;
-    }
-
-    /* If there is a value ready grab it */
-    if (NRF_RNG->EVENTS_VALRDY) {
-        NRF_RNG->EVENTS_VALRDY = 0;
-        rnum = (uint8_t)NRF_RNG->VALUE;
-        (*g_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->CONFIG = 1;
-    } else {
-        NRF_RNG->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);
-        g_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->EVENTS_VALRDY = 0;
-
-    if (g_ble_rng_isr_cb) {
-        nrf_rng_int_enable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK);
-    }
-    nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_START);
-    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_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK);
-    nrf_rng_task_trigger(NRF_RNG, NRF_RNG_TASK_STOP);
-    NRF_RNG->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->EVENTS_VALRDY == 0) {
-    }
-
-    NRF_RNG->EVENTS_VALRDY = 0;
-    rnum = (uint8_t)NRF_RNG->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)
-{
-    if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) {
-        return (int)NRF_AAR->STATUS;
-    }
-
-    return -1;
-}
-#endif
diff --git a/nimble/drivers/nrf52/src/ble_phy.c b/nimble/drivers/nrf52/src/ble_phy.c
deleted file mode 100644
index a94cb2a7..00000000
--- a/nimble/drivers/nrf52/src/ble_phy.c
+++ /dev/null
@@ -1,2301 +0,0 @@
-/*
- * 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 <controller/ble_ll_fem.h>
-#include <hal/nrf_radio.h>
-#include <hal/nrf_ccm.h>
-#include <hal/nrf_aar.h>
-#include <hal/nrf_timer.h>
-#include <hal/nrf_ppi.h>
-#include <hal/nrf_rtc.h>
-#include "syscfg/syscfg.h"
-#include "os/os.h"
-/* Keep os_cputime explicitly to enable build on non-Mynewt platforms */
-#include "os/os_cputime.h"
-#include "ble/xcvr.h"
-#include "nimble/ble.h"
-#include "nimble/nimble_opt.h"
-#include "nimble/nimble_npl.h"
-#include "controller/ble_phy.h"
-#include "controller/ble_phy_trace.h"
-#include "controller/ble_ll.h"
-#include "nrfx.h"
-#if MYNEWT
-#include "mcu/nrf52_clock.h"
-#include "mcu/cmsis_nvic.h"
-#include "hal/hal_gpio.h"
-#else
-#include "core_cm4.h"
-#endif
-
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
-#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811)
-#error LE Coded PHY can only be enabled on nRF52811 or nRF52840
-#endif
-#endif
-
-#if BABBLESIM
-extern void tm_tick(void);
-#endif
-
-/*
- * NOTE: This code uses a couple of PPI channels so care should be taken when
- *       using PPI somewhere else.
- *
- * Pre-programmed channels: CH20, CH21, CH23, CH25, CH31
- * Regular channels: CH4, CH5 and optionally CH6, CH7, CH17, CH18, CH19
- *  - CH4 = cancel wfr timer on address match
- *  - CH5 = disable radio on wfr timer expiry
- *  - CH6 = PA/LNA control (enable)
- *  - CH7 = PA/LNA control (disable)
- *  - CH17 = (optional) gpio debug for radio ramp-up
- *  - CH18 = (optional) gpio debug for wfr timer RX enabled
- *  - CH19 = (optional) gpio debug for wfr timer radio disabled
- *
- */
-
-/* XXX: 4) Make sure RF is higher priority interrupt than schedule */
-
-/*
- * XXX: Maximum possible transmit time is 1 msec for a 60ppm crystal
- * and 16ms for a 30ppm crystal! We need to limit PDU size based on
- * crystal accuracy. Look at this in the spec.
- */
-
-/* XXX: private header file? */
-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->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;
-#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
-    uint16_t tifs;
-#endif
-};
-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)
-
-#if BABBLESIM
-/* 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] = 1,
-    [BLE_PHY_MODE_2M] = 1,
-};
-/* 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] = 1,
-    [BLE_PHY_MODE_2M] = 1,
-};
-/* 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] = 9,
-    [BLE_PHY_MODE_2M] = 5,
-};
-/* 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] = 9,
-    [BLE_PHY_MODE_2M] = 5,
-};
-#else
-/* 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
-};
-#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)
-
-/*
- * NOTE:
- * Tested the following to see what would happen:
- *  -> NVIC has radio irq enabled (interrupt # 1, mask 0x2).
- *  -> Set up nrf to receive. Clear ADDRESS event register.
- *  -> Enable ADDRESS interrupt on nrf5 by writing to INTENSET.
- *  -> Enable RX.
- *  -> Disable interrupts globally using OS_ENTER_CRITICAL().
- *  -> Wait until a packet is received and the ADDRESS event occurs.
- *  -> Call ble_phy_disable().
- *
- *  At this point I wanted to see the state of the cortex NVIC. The IRQ
- *  pending bit was TRUE for the radio interrupt (as expected) as we never
- *  serviced the radio interrupt (interrupts were disabled).
- *
- *  What was unexpected was this: without clearing the pending IRQ in the NVIC,
- *  when radio interrupts were re-enabled (address event bit in INTENSET set to
- *  1) and the radio ADDRESS event register read 1 (it was never cleared after
- *  the first address event), the radio did not enter the ISR! I would have
- *  expected that if the following were true, an interrupt would occur:
- *      -> NVIC ISER bit set to TRUE
- *      -> NVIC ISPR bit reads TRUE, meaning interrupt is pending.
- *      -> Radio peripheral interrupts are enabled for some event (or events).
- *      -> Corresponding event register(s) in radio peripheral read 1.
- *
- *  Not sure what the end result of all this is. We will clear the pending
- *  bit in the NVIC just to be sure when we disable the PHY.
- */
-
-#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)
-
-uint32_t g_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));
-
-struct nrf_ccm_data g_nrf_ccm_data;
-#endif
-
-static int g_ble_phy_gpiote_idx;
-
-#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
-
-#define FEM_SINGLE_GPIO \
-    (!MYNEWT_VAL(BLE_LL_FEM_PA) || !MYNEWT_VAL(BLE_LL_FEM_LNA) || \
-     (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)))
-
-#if FEM_SINGLE_GPIO
-static uint8_t fem_idx;
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-static uint8_t fem_pa_idx;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-static uint8_t fem_lna_idx;
-#endif
-#endif
-
-#endif
-
-#ifndef BABBLESIM
-static void
-ble_phy_apply_errata_102_106_107(void)
-{
-    /* [102] RADIO: PAYLOAD/END events delayed or not triggered after ADDRESS
-     * [106] RADIO: Higher CRC error rates for some access addresses
-     * [107] RADIO: Immediate address match for access addresses containing MSBs 0x00
-     */
-    *(volatile uint32_t *)0x40001774 = ((*(volatile uint32_t *)0x40001774) &
-                         0xfffffffe) | 0x01000000;
-}
-#endif
-
-#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
-
-/* Packet start offset (in usecs). This is the preamble plus access address.
- * For LE Coded PHY this also includes CI and TERM1. */
-uint32_t
-ble_phy_mode_pdu_start_off(int phy_mode)
-{
-    return g_ble_phy_mode_pkt_start_off[phy_mode];
-}
-
-#if NRF52840_XXAA
-static inline bool
-ble_phy_mode_is_coded(uint8_t phy_mode)
-{
-    return (phy_mode == BLE_PHY_MODE_CODED_125KBPS) ||
-           (phy_mode == BLE_PHY_MODE_CODED_500KBPS);
-}
-
-static void
-ble_phy_apply_nrf52840_errata(uint8_t new_phy_mode)
-{
-    bool new_coded = ble_phy_mode_is_coded(new_phy_mode);
-    bool cur_coded = ble_phy_mode_is_coded(g_ble_phy_data.phy_cur_phy_mode);
-
-    /*
-     * Workarounds should be applied only when switching to/from LE Coded PHY
-     * so no need to apply them every time.
-     *
-     * nRF52840 Engineering A Errata v1.2
-     * [164] RADIO: Low sensitivity in long range mode
-     *
-     * nRF52840 Rev 1 Errata
-     * [191] RADIO: High packet error rate in BLE Long Range mode
-     */
-    if (new_coded == cur_coded) {
-        return;
-    }
-
-    if (new_coded) {
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
-        /* [164] */
-        *(volatile uint32_t *)0x4000173C |= 0x80000000;
-        *(volatile uint32_t *)0x4000173C =
-                        ((*(volatile uint32_t *)0x4000173C & 0xFFFFFF00) | 0x5C);
-#endif
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
-        /* [191] */
-        *(volatile uint32_t *) 0x40001740 =
-                        ((*((volatile uint32_t *) 0x40001740)) & 0x7FFF00FF) |
-                        0x80000000 | (((uint32_t)(196)) << 8);
-#endif
-    } else {
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_164)
-        /* [164] */
-        *(volatile uint32_t *)0x4000173C &= ~0x80000000;
-#endif
-#if MYNEWT_VAL(BLE_PHY_NRF52840_ERRATA_191)
-        /* [191] */
-        *(volatile uint32_t *) 0x40001740 =
-                        ((*((volatile uint32_t *) 0x40001740)) & 0x7FFFFFFF);
-#endif
-    }
-}
-#endif
-
-static void
-ble_phy_mode_apply(uint8_t phy_mode)
-{
-    if (phy_mode == g_ble_phy_data.phy_cur_phy_mode) {
-        return;
-    }
-
-#if NRF52840_XXAA
-    ble_phy_apply_nrf52840_errata(phy_mode);
-#endif
-
-    switch (phy_mode) {
-    case BLE_PHY_MODE_1M:
-        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
-        NRF_RADIO->PCNF0 = NRF_PCNF0_1M;
-        break;
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
-    case BLE_PHY_MODE_2M:
-        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit;
-        NRF_RADIO->PCNF0 = NRF_PCNF0_2M;
-        break;
-#endif
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
-    case BLE_PHY_MODE_CODED_125KBPS:
-        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit;
-        NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
-        break;
-    case BLE_PHY_MODE_CODED_500KBPS:
-        NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit;
-        NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
-        break;
-#endif
-    default:
-        assert(0);
-    }
-
-    g_ble_phy_data.phy_cur_phy_mode = phy_mode;
-}
-
-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;
-}
-#endif
-
-static void
-ble_phy_fem_enable_pa(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    ble_ll_fem_pa_enable();
-
-#if !FEM_SINGLE_GPIO
-    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_pa_idx]);
-    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_pa_idx]);
-#endif
-
-    NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-#endif
-}
-
-static void
-ble_phy_fem_enable_lna(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    ble_ll_fem_lna_enable();
-
-#if !FEM_SINGLE_GPIO
-    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_lna_idx]);
-    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_lna_idx]);
-#endif
-
-    NRF_PPI->CHENSET = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-#endif
-}
-
-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
-}
-
-/**
- * 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 (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;
-
-#if BABBLESIM
-        memcpy(dst, src, copy_len);
-        dst += copy_len;
-        src += copy_len;
-#else
-        __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"
-                         );
-#endif
-
-        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;
-
-#if BABBLESIM
-    memcpy(dst, src, rem_len);
-#else
-    __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"
-                     );
-#endif
-
-    /* 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->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->STATE == state) {
-                /* If this fails, something is really wrong. Should last
-                 * no more than 6 usecs */
-#if BABBLESIM
-                tm_tick();
-#endif
-            }
-        }
-    }
-}
-
-#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
-static uint16_t
-ble_phy_tifs_get(void)
-{
-    return g_ble_phy_data.tifs;
-}
-
-void
-ble_phy_tifs_set(uint16_t tifs)
-{
-    g_ble_phy_data.tifs = tifs;
-}
-#else
-static uint16_t
-ble_phy_tifs_get(void)
-{
-    return BLE_LL_IFS;
-}
-#endif
-
-/**
- *
- *
- */
-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->CC[0];
-    cntr = NRF_RTC0->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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
-    nrf_timer_cc_set(NRF_TIMER0, 0, rem_usecs);
-    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-
-    /* Set RTC compare to start TIMER0 */
-    NRF_RTC0->EVENTS_COMPARE[0] = 0;
-    nrf_rtc_cc_set(NRF_RTC0, 0, next_cc);
-    nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
-
-    /* Enable PPI */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
-
-    /* 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CLEAR);
-    nrf_timer_cc_set(NRF_TIMER0, 0, 1);
-    NRF_TIMER0->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->EVENTS_COMPARE[0] = 0;
-    nrf_rtc_cc_set(NRF_RTC0, 0, now + 3);
-    nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk);
-
-    /* Enable PPI */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH31_Msk);
-    /*
-     * 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;
-}
-
-/**
- * Function is used to set PPI so that we can time out waiting for a reception
- * to occur. This happens for two reasons: we have sent a packet and we are
- * waiting for a response (txrx should be set to ENABLE_TXRX) or we are
- * starting a connection event and we are a slave and we are waiting for the
- * master to send us a packet (txrx should be set to ENABLE_RX).
- *
- * NOTE: when waiting for a txrx turn-around, wfr_usecs is not used as there
- * is no additional time to wait; we know when we should receive the address of
- * the received frame.
- *
- * @param txrx Flag denoting if this wfr is a txrx turn-around or not.
- * @param tx_phy_mode phy mode for last TX (only valid for TX->RX)
- * @param wfr_usecs Amount of usecs to wait.
- */
-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->CC[2] + ble_phy_tifs_get();
-        /* 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->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_timer_cc_set(NRF_TIMER0, 3, end_time);
-    NRF_TIMER0->EVENTS_COMPARE[3] = 0;
-
-    /* Enable wait for response PPI */
-    nrf_ppi_channels_enable(NRF_PPI, (PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE1);
-    if (NRF_TIMER0->CC[1] > NRF_TIMER0->CC[3]) {
-        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
-        nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
-    }
-}
-
-#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->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0];
-        NRF_CCM->INPTR = (uint32_t)&g_ble_phy_enc_buf[0];
-        NRF_CCM->OUTPTR = (uint32_t)dptr;
-        NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
-        NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | CCM_MODE_MODE_Decryption |
-                                                    ble_phy_get_ccm_datarate();
-        NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
-        NRF_CCM->SHORTS = 0;
-        NRF_CCM->EVENTS_ERROR = 0;
-        NRF_CCM->EVENTS_ENDCRYPT = 0;
-        nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN);
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH25_Msk);
-    } else {
-        NRF_RADIO->PACKETPTR = (uint32_t)dptr;
-    }
-#else
-    NRF_RADIO->PACKETPTR = (uint32_t)dptr;
-#endif
-
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
-    if (g_ble_phy_data.phy_privacy) {
-        NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled;
-        NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
-        NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch;
-        NRF_AAR->EVENTS_END = 0;
-        NRF_AAR->EVENTS_RESOLVED = 0;
-        NRF_AAR->EVENTS_NOTRESOLVED = 0;
-    } else {
-        if (g_ble_phy_data.phy_encrypted == 0) {
-            NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled;
-        }
-    }
-#endif
-
-    /* Turn off trigger TXEN on output compare match and AAR on bcmatch */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk | PPI_CHEN_CH23_Msk);
-
-    /* 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_bcc_set(NRF_RADIO, 8 + g_ble_phy_data.phy_bcc_offset); /* in bits */
-    NRF_RADIO->EVENTS_ADDRESS = 0;
-    NRF_RADIO->EVENTS_DEVMATCH = 0;
-    NRF_RADIO->EVENTS_BCMATCH = 0;
-    NRF_RADIO->EVENTS_RSSIEND = 0;
-    NRF_RADIO->EVENTS_CRCOK = 0;
-    NRF_RADIO->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_int_enable(NRF_RADIO, RADIO_INTENSET_ADDRESS_Msk |
-                         RADIO_INTENSET_DISABLED_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 tx_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);
-
-#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->EVENTS_ERROR) {
-            STATS_INC(ble_phy_stats, tx_hw_err);
-            NRF_CCM->EVENTS_ERROR = 0;
-        }
-    }
-#endif
-
-    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->CC[2] + ble_phy_tifs_get();
-        /* 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_timer_cc_set(NRF_TIMER0, 0, rx_time);
-        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
-
-        ble_phy_fem_enable_lna();
-    } else if (transition == BLE_PHY_TRANSITION_TX_TX) {
-        /* Schedule TX exactly T_IFS after TX end captured in CC[2] */
-        tx_time = NRF_TIMER0->CC[2] + ble_phy_tifs_get();
-        /* Adjust for delay between EVENT_END and actual TX end time */
-        tx_time += g_ble_phy_t_txenddelay[tx_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_timer_cc_set(NRF_TIMER0, 0, tx_time);
-        NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
-
-        nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
-        if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
-            nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
-            g_ble_phy_data.phy_transition_late = 1;
-        }
-    } else {
-        /*
-         * XXX: not sure we need to stop the timer here all the time. Or that
-         * it should be stopped here.
-         */
-        nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
-        NRF_TIMER0->TASKS_SHUTDOWN = 1;
-        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
-                                 PPI_CHEN_CH20_Msk | PPI_CHEN_CH31_Msk);
-        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->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;
-
-    /* Disable automatic RXEN */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
-
-    /* Set RSSI and CRC status flag in header */
-    ble_hdr = &g_ble_phy_data.rxhdr;
-    assert(NRF_RADIO->EVENTS_RSSIEND != 0);
-    ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->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->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) {
-            while (NRF_CCM->EVENTS_ENDCRYPT == 0) {
-                /* Make sure CCM finished */
-            };
-
-            /* Only set MIC failure flag if frame is not zero length */
-            if ((dptr[1] != 0) && (NRF_CCM->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->EVENTS_ERROR) {
-                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->CC[2] + ble_phy_tifs_get();
-    /* 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_timer_cc_set(NRF_TIMER0, 0, tx_time);
-    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
-
-    ble_phy_fem_enable_pa();
-
-    /*
-     * 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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_CAPTURE3);
-    if (NRF_TIMER0->CC[3] > NRF_TIMER0->CC[0]) {
-        nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
-        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->EVENTS_ADDRESS = 0;
-    nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_ADDRESS_Msk);
-
-    /* Clear wfr timer channels */
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk);
-
-    /* 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->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;
-
-    /* XXX: I wonder if we always have the 1st byte. If we need to wait for
-     * rx chain delay, it could be 18 usecs from address interrupt. The
-       nrf52 may be able to get here early. */
-    /* Wait to get 1st byte of frame */
-    while (1) {
-        state = NRF_RADIO->STATE;
-        if (NRF_RADIO->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_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
-            NRF_RADIO->SHORTS = 0;
-            return false;
-        }
-
-#if BABBLESIM
-        tm_tick();
-#endif
-    }
-
-#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->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset);
-
-        /* Trigger AAR after last bit of AdvA is received */
-        NRF_RADIO->EVENTS_BCMATCH = 0;
-        nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH23_Msk);
-        nrf_radio_bcc_set(NRF_RADIO, (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;
-    } 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->INTENSET;
-
-    /*
-     * 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->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;
-        }
-    }
-
-    /* Handle disabled event. This is enabled for both TX and RX. On RX, we
-     * need to check phy_rx_started flag to make sure we actually were receiving
-     * a PDU, otherwise this is due to wfr.
-     */
-    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) && NRF_RADIO->EVENTS_DISABLED) {
-        BLE_LL_ASSERT(NRF_RADIO->EVENTS_END ||
-                      ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) &&
-                       !g_ble_phy_data.phy_rx_started));
-        NRF_RADIO->EVENTS_END = 0;
-        NRF_RADIO->EVENTS_DISABLED = 0;
-        nrf_radio_int_disable(NRF_RADIO, RADIO_INTENCLR_DISABLED_Msk);
-
-#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
-        g_ble_phy_data.tifs = BLE_LL_IFS;
-#endif
-
-        switch (g_ble_phy_data.phy_state) {
-        case BLE_PHY_STATE_RX:
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-            NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-            ble_ll_fem_lna_disable();
-#endif
-            if (g_ble_phy_data.phy_rx_started) {
-                ble_phy_rx_end_isr();
-            } else {
-                ble_ll_wfr_timer_exp(NULL);
-            }
-            break;
-        case BLE_PHY_STATE_TX:
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-            NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-            ble_ll_fem_pa_disable();
-#endif
-            ble_phy_tx_end_isr();
-            break;
-        default:
-            BLE_LL_ASSERT(0);
-        }
-    }
-
-    g_ble_phy_data.phy_transition_late = 0;
-
-    /* Count # of interrupts */
-    STATS_INC(ble_phy_stats, phy_isrs);
-
-    os_trace_isr_exit();
-}
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_LL_FEM_PA) || \
-    MYNEWT_VAL(BLE_LL_FEM_LNA)
-static int
-ble_phy_gpiote_configure(int pin)
-{
-    NRF_GPIO_Type *port;
-
-    g_ble_phy_gpiote_idx--;
-
-#if NRF52840_XXAA
-    port = pin > 31 ? NRF_P1 : NRF_P0;
-    pin &= 0x1f;
-#else
-    port = NRF_P0;
-#endif
-
-    /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */
-    port->DIRSET = (1 << pin);
-    port->OUTCLR = (1 << pin);
-
-    NRF_GPIOTE->CONFIG[g_ble_phy_gpiote_idx] =
-                        (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
-                        ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) |
-#if NRF52840_XXAA
-                        ((port == NRF_P1) << GPIOTE_CONFIG_PORT_Pos);
-#else
-                        0;
-#endif
-
-    BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0);
-
-    return g_ble_phy_gpiote_idx;
-}
-#endif
-
-static void
-ble_phy_dbg_time_setup(void)
-{
-    int idx __attribute__((unused));
-
-    /*
-     * We setup GPIOTE starting from last configuration index to minimize risk
-     * of conflict with GPIO setup via hal. It's not great solution, but since
-     * this is just debugging code we can live with this.
-     */
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
-
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 17, (uint32_t)&(NRF_RADIO->EVENTS_READY),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH17_Msk);
-
-    /* CH[20] and PPI CH[21] are on to trigger TASKS_TXEN or TASKS_RXEN */
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 20, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 21, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
-
-    /* CH[26] and CH[27] are always on for EVENT_ADDRESS and EVENT_END */
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 26, (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 27, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
-
-#if NRF52840_XXAA
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_RXREADY),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-#else
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 18, (uint32_t)&(NRF_RADIO->EVENTS_READY),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_SET[idx]));
-#endif
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, 19, (uint32_t)&(NRF_RADIO->EVENTS_DISABLED),
-                                   (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH18_Msk | PPI_CHEN_CH19_Msk);
-
-    /* CH[4] and CH[5] are always on for wfr */
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 4, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-    nrf_ppi_fork_endpoint_setup(NRF_PPI, 5, (uint32_t)&(NRF_GPIOTE->TASKS_CLR[idx]));
-#endif
-}
-
-/**
- * ble phy init
- *
- * Initialize the PHY.
- *
- * @return int 0: success; PHY error code otherwise
- */
-int
-ble_phy_init(void)
-{
-    int rc;
-
-    g_ble_phy_gpiote_idx = 8;
-
-    /* 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;
-
-#if MYNEWT_VAL(BLE_PHY_VARIABLE_TIFS)
-    g_ble_phy_data.tifs = BLE_LL_IFS;
-#endif
-
-    /* Toggle peripheral power to reset (just in case) */
-    nrf_radio_power_set(NRF_RADIO, false);
-    nrf_radio_power_set(NRF_RADIO, true);
-
-    /* Disable all interrupts */
-    nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
-
-    /* Set configuration registers */
-    NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
-    NRF_RADIO->PCNF0 = NRF_PCNF0;
-
-    /* XXX: should maxlen be 251 for encryption? */
-    NRF_RADIO->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->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) &
-                            RADIO_MODECNF0_RU_Msk;
-
-    /* Set logical address 1 for TX and RX */
-    NRF_RADIO->TXADDRESS  = 0;
-    NRF_RADIO->RXADDRESSES  = (1 << 0);
-
-    /* Configure the CRC registers */
-    NRF_RADIO->CRCCNF = (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos) | RADIO_CRCCNF_LEN_Three;
-
-    /* Configure BLE poly */
-    NRF_RADIO->CRCPOLY = 0x0000065B;
-
-    /* Configure IFS */
-    NRF_RADIO->TIFS = BLE_LL_IFS;
-
-    /* Captures tx/rx start in timer0 cc 1 and tx/rx end in timer0 cc 2 */
-    nrf_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH26_Msk | PPI_CHEN_CH27_Msk);
-
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
-    nrf_ccm_int_disable(NRF_CCM, 0xffffffff);
-    NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
-    NRF_CCM->EVENTS_ERROR = 0;
-    memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad));
-#endif
-
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
-    g_ble_phy_data.phy_aar_scratch = 0;
-    NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0];
-    nrf_aar_int_disable(NRF_AAR, 0xffffffff);
-    NRF_AAR->EVENTS_END = 0;
-    NRF_AAR->EVENTS_RESOLVED = 0;
-    NRF_AAR->EVENTS_NOTRESOLVED = 0;
-    NRF_AAR->NIRK = 0;
-#endif
-
-    /* TIMER0 setup for PHY when using RTC */
-    nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
-    NRF_TIMER0->TASKS_SHUTDOWN = 1;
-    NRF_TIMER0->BITMODE = 3;    /* 32-bit timer */
-    NRF_TIMER0->MODE = 0;       /* Timer mode */
-    NRF_TIMER0->PRESCALER = 4;  /* gives us 1 MHz */
-
-    /*
-     * PPI setup.
-     * Channel 4: Captures TIMER0 in CC[3] when EVENTS_ADDRESS occurs. Used
-     *            to cancel the wait for response timer.
-     * Channel 5: TIMER0 CC[3] to TASKS_DISABLE on radio. This is the wait
-     *            for response timer.
-     */
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL4,
-        (uint32_t)&(NRF_RADIO->EVENTS_ADDRESS),
-        (uint32_t)&(NRF_TIMER0->TASKS_CAPTURE[3]));
-    nrf_ppi_channel_endpoint_setup(NRF_PPI, NRF_PPI_CHANNEL5,
-        (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]),
-        (uint32_t)&(NRF_RADIO->TASKS_DISABLE));
-
-#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
-#if FEM_SINGLE_GPIO
-    fem_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
-    NRF_PPI->CH[6].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_SET[fem_idx]);
-    NRF_PPI->CH[7].TEP = (uint32_t) &(NRF_GPIOTE->TASKS_CLR[fem_idx]);
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    fem_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
-    NRF_GPIOTE->TASKS_CLR[fem_pa_idx] = 1;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    fem_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
-    NRF_GPIOTE->TASKS_CLR[fem_lna_idx] = 1;
-#endif
-#endif
-
-    NRF_PPI->CH[6].EEP = (uint32_t)&(NRF_RADIO->EVENTS_READY);
-    NRF_PPI->CH[7].EEP = (uint32_t)&(NRF_RADIO->EVENTS_DISABLED);
-    NRF_PPI->CHENCLR = PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk;
-#endif
-
-    /* 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;
-    }
-
-    ble_phy_dbg_time_setup();
-
-    return 0;
-}
-
-/**
- * Puts the phy into receive mode.
- *
- * @return int 0: success; BLE Phy error code otherwise
- */
-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->STATE != RADIO_STATE_STATE_Disabled) &&
-            ((NRF_RADIO->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_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
-
-    /* Clear events prior to enabling receive */
-    NRF_RADIO->EVENTS_END = 0;
-    NRF_RADIO->EVENTS_DISABLED = 0;
-
-    /* Setup for rx */
-    ble_phy_rx_xcvr_setup();
-
-    /* PPI to start radio automatically shall be set here */
-    assert(NRF_PPI->CHEN & PPI_CHEN_CH21_Msk);
-
-    return 0;
-}
-
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
-/**
- * Called to enable encryption at the PHY. Note that this state will persist
- * in the PHY; in other words, if you call this function you have to call
- * disable so that future PHY transmits/receives will not be encrypted.
- *
- * @param pkt_counter
- * @param iv
- * @param key
- * @param is_master
- */
-void
-ble_phy_encrypt_enable(uint64_t pkt_counter, uint8_t *iv, uint8_t *key,
-                       uint8_t is_master)
-{
-    memcpy(g_nrf_ccm_data.key, key, 16);
-    g_nrf_ccm_data.pkt_counter = pkt_counter;
-    memcpy(g_nrf_ccm_data.iv, iv, 8);
-    g_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->ENABLE = AAR_ENABLE_ENABLE_Disabled;
-    NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled;
-}
-
-void
-ble_phy_encrypt_set_pkt_cntr(uint64_t pkt_counter, int dir)
-{
-    g_nrf_ccm_data.pkt_counter = pkt_counter;
-    g_nrf_ccm_data.dir_bit = dir;
-}
-
-void
-ble_phy_encrypt_disable(void)
-{
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH25_Msk);
-    nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_STOP);
-    NRF_CCM->EVENTS_ERROR = 0;
-    NRF_CCM->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;
-}
-
-/**
- * Called to set the start time of a transmission.
- *
- * This function is called to set the start time when we are not going from
- * rx to tx automatically.
- *
- * NOTE: care must be taken when calling this function. The channel should
- * already be set.
- *
- * @param cputime   This is the tick at which the 1st bit of the preamble
- *                  should be transmitted
- * @param rem_usecs This is used only when the underlying timing uses a 32.768
- *                  kHz crystal. It is the # of usecs from the cputime tick
- *                  at which the first bit of the preamble should be
- *                  transmitted.
- * @return int
- */
-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_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH21_Msk);
-
-    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_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH20_Msk);
-        rc = 0;
-
-        ble_phy_fem_enable_pa();
-    }
-
-    return rc;
-}
-
-/**
- * Called to set the start time of a reception
- *
- * This function acts a bit differently than transmit. If we are late getting
- * here we will still attempt to receive.
- *
- * NOTE: care must be taken when calling this function. The channel should
- * already be set.
- *
- * @param cputime
- *
- * @return int
- */
-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_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH20_Msk);
-
-    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_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
-
-    ble_phy_fem_enable_lna();
-
-    /* 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_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
-                             PPI_CHEN_CH23_Msk | PPI_CHEN_CH25_Msk);
-
-#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->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk;
-        NRF_CCM->INPTR = (uint32_t)dptr;
-        NRF_CCM->OUTPTR = (uint32_t)pktptr;
-        NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0];
-        NRF_CCM->EVENTS_ERROR = 0;
-        NRF_CCM->MODE = CCM_MODE_LENGTH_Msk | ble_phy_get_ccm_datarate();
-        NRF_CCM->CNFPTR = (uint32_t)&g_nrf_ccm_data;
-    } else {
-#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
-        NRF_AAR->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_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN);
-    }
-#endif
-
-    NRF_RADIO->PACKETPTR = (uint32_t)pktptr;
-
-    /* Clear the ready, end and disabled events */
-    NRF_RADIO->EVENTS_READY = 0;
-    NRF_RADIO->EVENTS_END = 0;
-    NRF_RADIO->EVENTS_DISABLED = 0;
-
-    /* Enable shortcuts for transmit start/end. */
-    shortcuts = RADIO_SHORTS_END_DISABLE_Msk | RADIO_SHORTS_READY_START_Msk;
-    NRF_RADIO->SHORTS = shortcuts;
-    nrf_radio_int_enable(NRF_RADIO, 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->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;
-}
-
-/**
- * ble phy txpwr set
- *
- * Set the transmit output power (in dBm).
- *
- * NOTE: If the output power specified is within the BLE limits but outside
- * the chip limits, we "rail" the power level so we dont exceed the min/max
- * chip values.
- *
- * @param dbm Power output in dBm.
- *
- * @return int 0: success; anything else is an error
- */
-int
-ble_phy_txpwr_set(int dbm)
-{
-    /* "Rail" power level if outside supported range */
-    dbm = ble_phy_txpower_round(dbm);
-
-    NRF_RADIO->TXPOWER = dbm;
-    g_ble_phy_data.phy_txpwr_dbm = dbm;
-
-    return 0;
-}
-
-/**
- * ble phy txpwr round
- *
- * Get the rounded transmit output power (in dBm).
- *
- * @param dbm Power output in dBm.
- *
- * @return int Rounded power in dBm
- */
-int ble_phy_txpower_round(int dbm)
-{
-    /* TODO this should be per nRF52XXX */
-
-    /* "Rail" power level if outside supported range */
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm;
-    }
-
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm;
-    }
-
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm;
-    }
-
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm;
-    }
-
-    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_Neg20dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm;
-    }
-
-    return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
-}
-
-/**
- * ble phy set access addr
- *
- * Set access address.
- *
- * @param access_addr Access address
- *
- * @return int 0: success; PHY error code otherwise
- */
-static int
-ble_phy_set_access_addr(uint32_t access_addr)
-{
-    NRF_RADIO->BASE0 = (access_addr << 8);
-    NRF_RADIO->PREFIX0 = (NRF_RADIO->PREFIX0 & 0xFFFFFF00) | (access_addr >> 24);
-
-    g_ble_phy_data.phy_access_address = access_addr;
-
-#ifndef BABBLESIM
-    ble_phy_apply_errata_102_106_107();
-#endif
-    return 0;
-}
-
-/**
- * ble phy txpwr get
- *
- * Get the transmit power.
- *
- * @return int  The current PHY transmit power, in dBm
- */
-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;
-}
-
-/**
- * ble phy setchan
- *
- * Sets the logical frequency of the transceiver. The input parameter is the
- * BLE channel index (0 to 39, inclusive). The NRF frequency register works like
- * this: logical frequency = 2400 + FREQ (MHz).
- *
- * Thus, to get a logical frequency of 2402 MHz, you would program the
- * FREQUENCY register to 2.
- *
- * @param chan This is the Data Channel Index or Advertising Channel index
- *
- * @return int 0: success; PHY error code otherwise
- */
-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->CRCINIT = crcinit;
-
-    /* Set the frequency and the data whitening initial value */
-    g_ble_phy_data.phy_chan = chan;
-    NRF_RADIO->FREQUENCY = g_ble_phy_chan_freq[chan];
-    NRF_RADIO->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_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP);
-    NRF_TIMER0->TASKS_SHUTDOWN = 1;
-    nrf_rtc_event_disable(NRF_RTC0, 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_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
-    NRF_RADIO->SHORTS = 0;
-    nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_DISABLE);
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH4_Msk | PPI_CHEN_CH5_Msk |
-        PPI_CHEN_CH20_Msk | PPI_CHEN_CH21_Msk | PPI_CHEN_CH23_Msk |
-        PPI_CHEN_CH25_Msk | PPI_CHEN_CH31_Msk);
-    nrf_ppi_channels_disable(NRF_PPI, PPI_CHEN_CH6_Msk | PPI_CHEN_CH7_Msk);
-    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_ppi_channels_enable(NRF_PPI, PPI_CHEN_CH21_Msk);
-
-    ble_phy_rx();
-}
-
-/**
- * ble phy disable
- *
- * Disables the PHY. This should be called when an event is over. It stops
- * the usec timer (if used), disables interrupts, disables the RADIO, disables
- * PPI and sets state to idle.
- */
-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();
-}
-
-/* Gets the current access address */
-uint32_t ble_phy_access_addr_get(void)
-{
-    return g_ble_phy_data.phy_access_address;
-}
-
-/**
- * Return the phy state
- *
- * @return int The current PHY state.
- */
-int
-ble_phy_state_get(void)
-{
-    return g_ble_phy_data.phy_state;
-}
-
-/**
- * Called to see if a reception has started
- *
- * @return int
- */
-int
-ble_phy_rx_started(void)
-{
-    return g_ble_phy_data.phy_rx_started;
-}
-
-/**
- * Return the transceiver state
- *
- * @return int transceiver state.
- */
-uint8_t
-ble_phy_xcvr_state_get(void)
-{
-    uint32_t state;
-    state = NRF_RADIO->STATE;
-    return (uint8_t)state;
-}
-
-/**
- * Called to return the maximum data pdu payload length supported by the
- * phy. For this chip, if encryption is enabled, the maximum payload is 27
- * bytes.
- *
- * @return uint8_t Maximum data channel PDU payload size supported
- */
-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->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->PCNF1 &= ~RADIO_PCNF1_WHITEEN_Msk;
-}
-
-void ble_phy_disable_dtm(void)
-{
-    /* Enable whitening */
-    NRF_RADIO->PCNF1 |= RADIO_PCNF1_WHITEEN_Msk;
-}
-#endif
-
-void
-ble_phy_rfclk_enable(void)
-{
-#if MYNEWT || defined(RIOT_VERSION)
-    nrf52_clock_hfxo_request();
-#else
-    nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
-#endif
-}
-
-void
-ble_phy_rfclk_disable(void)
-{
-#if MYNEWT || defined(RIOT_VERSION)
-    nrf52_clock_hfxo_release();
-#else
-    nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
-#endif
-}
diff --git a/nimble/drivers/nrf52/src/ble_phy_trace.c b/nimble/drivers/nrf52/src/ble_phy_trace.c
deleted file mode 100644
index 93b2eb32..00000000
--- a/nimble/drivers/nrf52/src/ble_phy_trace.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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/nimble/drivers/nrf52/syscfg.yml b/nimble/drivers/nrf52/syscfg.yml
deleted file mode 100644
index c3ef5ae1..00000000
--- a/nimble/drivers/nrf52/syscfg.yml
+++ /dev/null
@@ -1,81 +0,0 @@
-# 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_VARIABLE_TIFS:
-        description: >
-            Enables API to set custom T_ifs (inter-frame spacing) for each
-            transition. T_ifs is reset to default value after each transition.
-            When disabled, 150us is always used which enables some build-time
-            optimizations by compiler.
-        experimental: 1
-        value: 0
-
-    BLE_PHY_SYSVIEW:
-        description: >
-            Enable SystemView tracing module for radio driver.
-        value: 0
-
-    BLE_PHY_DBG_TIME_TXRXEN_READY_PIN:
-        description: >
-            When set to proper GPIO pin number, this pin will be set
-            to high state when radio is enabled using PPI channels
-            20 or 21 and back to low state on radio EVENTS_READY.
-            This can be used to measure radio ram-up time.
-        value: -1
-
-    BLE_PHY_DBG_TIME_ADDRESS_END_PIN:
-        description: >
-            When set to proper GPIO pin number, this pin will be set
-            to high state on radio EVENTS_ADDRESS and back to low state
-            on radio EVENTS_END.
-            This can be used to measure radio pipeline delays.
-        value: -1
-
-    BLE_PHY_DBG_TIME_WFR_PIN:
-        description: >
-            When set to proper GPIO pin number, this pin will be set
-            to high state on radio EVENTS_RXREADY and back to low
-            state when wfr timer expires.
-            This can be used to check if wfr is calculated properly.
-        value: -1
-
-    BLE_PHY_NRF52840_ERRATA_164:
-        description: >
-            Enable workaround for anomaly 164 found in nRF52840.
-            "[164] RADIO: Low selectivity in long range mode"
-            This shall be only enabled for:
-            - nRF52840 Engineering A
-        value: 0
-
-    BLE_PHY_NRF52840_ERRATA_191:
-        description: >
-            Enable workaround for anomaly 191 found in nRF52840.
-            "[191] RADIO: High packet error rate in BLE Long Range mode"
-            This shall be only enabled for:
-            - nRF52840 Engineering B
-            - nRF52840 Engineering C
-            - nRF52840 Rev 1 (final silicon)
-        value: 1
-
-    BLE_PHY_UBLOX_BMD345_PUBLIC_ADDR:
-        description: >
-            Ublox BMD-345 modules come with public address preprogrammed
-            in UICR register. If enabled public address will be read from
-            custom UICR instead of FICR register.
-        value: 0
diff --git a/nimble/drivers/nrf5340/include/ble/xcvr.h b/nimble/drivers/nrf5340/include/ble/xcvr.h
deleted file mode 100644
index df6ef700..00000000
--- a/nimble/drivers/nrf5340/include/ble/xcvr.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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/nimble/drivers/nrf5340/pkg.yml b/nimble/drivers/nrf5340/pkg.yml
index 3ff44212..794697e9 100644
--- a/nimble/drivers/nrf5340/pkg.yml
+++ b/nimble/drivers/nrf5340/pkg.yml
@@ -18,14 +18,5 @@
 #
 
 pkg.name: nimble/drivers/nrf5340
-pkg.description: BLE driver for nRF5340 systems.
-pkg.author: "Apache Mynewt <de...@mynewt.apache.org>"
-pkg.homepage: "http://mynewt.apache.org/"
-pkg.keywords:
-    - ble
-    - bluetooth
-
-pkg.apis: ble_driver
-pkg.deps:
-    - nimble
-    - nimble/controller
+pkg.type: transient
+pkg.link: "@apache-mynewt-nimble/nimble/drivers/nrf5x"
diff --git a/nimble/drivers/nrf5340/src/ble_hw.c b/nimble/drivers/nrf5340/src/ble_hw.c
deleted file mode 100644
index e578fd05..00000000
--- a/nimble/drivers/nrf5340/src/ble_hw.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * 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)
-{
-    uint32_t addr_high;
-    uint32_t addr_low;
-    int rc;
-
-    if ((NRF_FICR_NS->DEVICEADDRTYPE & 1) == 1) {
-        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->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)
-{
-    if (NRF_AAR_NS->ENABLE && NRF_AAR_NS->EVENTS_END &&
-        NRF_AAR_NS->EVENTS_RESOLVED) {
-        return (int)NRF_AAR_NS->STATUS;
-    }
-
-    return -1;
-}
-#endif
diff --git a/nimble/drivers/nrf5340/src/ble_phy.c b/nimble/drivers/nrf5340/src/ble_phy.c
deleted file mode 100644
index 76c0289e..00000000
--- a/nimble/drivers/nrf5340/src/ble_phy.c
+++ /dev/null
@@ -1,2079 +0,0 @@
-/*
- * 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 <bsp/bsp.h>
-#include <nimble/ble.h>
-#include <nimble/nimble_opt.h>
-#include <nimble/nimble_npl.h>
-#include <controller/ble_phy.h>
-#include "controller/ble_ll_fem.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>
-
-#define DPPI_CH_PUB(_ch)        (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31))
-#define DPPI_CH_SUB(_ch)        (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31))
-#define DPPI_CH_UNSUB(_ch)      (((DPPI_CH_ ## _ch) & 0xff) | (0 << 31))
-#define DPPI_CH_MASK(_ch)       (1 << (DPPI_CH_ ## _ch))
-
-/* Channels 0..5 are always used.
- * Channels 6 and 7 are used for PA/LNA (optionally).
- * Channels 7..9 are used for GPIO debugging (optionally).
- */
-
-#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_TIMER0_EVENTS_COMPARE_4         6
-#define DPPI_CH_RADIO_EVENTS_DISABLED           7
-#define DPPI_CH_RADIO_EVENTS_READY              8
-#define DPPI_CH_RADIO_EVENTS_RXREADY            9
-
-#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_CH_MASK_FEM   (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_4) | \
-                            DPPI_CH_MASK(RADIO_EVENTS_DISABLED))
-
-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
-
-static int g_ble_phy_gpiote_idx;
-
-#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
-
-#define FEM_SINGLE_GPIO \
-    (!MYNEWT_VAL(BLE_LL_FEM_PA) || !MYNEWT_VAL(BLE_LL_FEM_LNA) || \
-     (MYNEWT_VAL(BLE_LL_FEM_PA_GPIO) == MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO)))
-
-#if FEM_SINGLE_GPIO
-static uint8_t fem_idx;
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-static uint8_t fem_pa_idx;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-static uint8_t fem_lna_idx;
-#endif
-#endif
-
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
-static uint8_t phy_dbg_txrxen_ready_idx;
-#endif
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
-static uint8_t phy_dbg_address_end_idx;
-#endif
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
-static uint8_t phy_dbg_wfr_idx;
-#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;
-        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080);
-        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;
-        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084);
-        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;
-        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080);
-        NRF_RADIO_NS->PCNF0 = NRF_PCNF0_CODED;
-        break;
-    case BLE_PHY_MODE_CODED_500KBPS:
-        NRF_RADIO_NS->MODE = RADIO_MODE_MODE_Ble_LR500Kbit;
-        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080);
-        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;
-}
-
-static void
-ble_phy_fem_enable_pa(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    ble_ll_fem_pa_enable();
-
-    /* CC[0] is set to radio enable */
-    NRF_TIMER0_NS->CC[4] = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST -
-                           MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US);
-
-#if FEM_SINGLE_GPIO
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4);
-#else
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4);
-#endif
-#endif
-}
-
-static void
-ble_phy_fem_disable_pa(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    ble_ll_fem_pa_disable();
-
-#if FEM_SINGLE_GPIO
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-#else
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-#endif
-#endif
-}
-
-static void
-ble_phy_fem_enable_lna(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    ble_ll_fem_lna_enable();
-
-    /* CC[0] is set to radio enable */
-    NRF_TIMER0_NS->CC[4] = NRF_TIMER0_NS->CC[0] + BLE_PHY_T_RXENFAST -
-                           MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US);
-
-#if FEM_SINGLE_GPIO
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4);
-#else
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_4);
-#endif
-#endif
-}
-
-static void
-ble_phy_fem_disable_lna(void)
-{
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    ble_ll_fem_lna_disable();
-
-#if FEM_SINGLE_GPIO
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-#else
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-#endif
-#endif
-}
-
-static void
-ble_phy_fem_force_disable(void)
-{
-#if FEM_SINGLE_GPIO
-    NRF_GPIOTE_NS->TASKS_CLR[fem_idx] = 1;
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    NRF_GPIOTE_NS->TASKS_CLR[fem_pa_idx] = 1;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    NRF_GPIOTE_NS->TASKS_CLR[fem_lna_idx] = 1;
-#endif
-#endif
-}
-
-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;
-    }
-
-    /* If PA/LNA is used, make sure CC[0] is set to more than turn-on time since
-     * it's used as a base for turn-on time calculation and thus cannot wrap
-     * around on subtraction.
-     */
-    if (MYNEWT_VAL(BLE_LL_FEM_PA) && tx &&
-        (rem_usecs + BLE_PHY_T_RXENFAST <= MYNEWT_VAL(BLE_LL_FEM_PA_TURN_ON_US))) {
-        cputime--;
-        rem_usecs += 30;
-    }
-
-    if (MYNEWT_VAL(BLE_LL_FEM_LNA) && !tx &&
-        (rem_usecs + BLE_PHY_T_RXENFAST <= MYNEWT_VAL(BLE_LL_FEM_LNA_TURN_ON_US))) {
-        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_CH_SUB(RTC0_EVENTS_COMPARE_0);
-
-    /* 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_CH_SUB(RTC0_EVENTS_COMPARE_0);
-
-    /*
-     * 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_CH_SUB(RADIO_EVENTS_ADDRESS);
-    NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3);
-
-    /*
-     * 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_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-        NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
-
-        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_CH_SUB(RADIO_EVENTS_ADDRESS);
-    } 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_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
-    NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH);
-
-    /* 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 |
-                             RADIO_INTENSET_DISABLED_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;
-
-    /* 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);
-
-#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_CH_SUB(TIMER0_EVENTS_COMPARE_0);
-
-        ble_phy_fem_enable_lna();
-    } else {
-        NRF_TIMER0_NS->TASKS_STOP = 1;
-        NRF_TIMER0_NS->TASKS_SHUTDOWN = 1;
-
-        NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-        NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
-        NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
-        NRF_TIMER0_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_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;
-
-    /* Disable automatic RXEN */
-    NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_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) {
-            while (NRF_CCM_NS->EVENTS_ENDCRYPT == 0) {
-                /* Make sure CCM finished */
-            };
-
-            /* 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;
-            }
-        }
-#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_CH_SUB(TIMER0_EVENTS_COMPARE_0);
-
-    ble_phy_fem_enable_pa();
-
-    /*
-     * 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_CH_UNSUB(TIMER0_EVENTS_COMPARE_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;
-    NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_ADDRESS_Msk;
-
-    /* Clear wfr timer channels and DISABLED interrupt */
-    NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-    NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
-
-    /* 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_CH_SUB(RADIO_EVENTS_BCMATCH);
-        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;
-    } 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;
-        }
-    }
-
-    /* Handle disabled event. This is enabled for both TX and RX. On RX, we
-     * need to check phy_rx_started flag to make sure we actually were receiving
-     * a PDU, otherwise this is due to wfr.
-     */
-    if ((irq_en & RADIO_INTENCLR_DISABLED_Msk) &&
-        NRF_RADIO_NS->EVENTS_DISABLED) {
-        BLE_LL_ASSERT(NRF_RADIO_NS->EVENTS_END ||
-                      ((g_ble_phy_data.phy_state == BLE_PHY_STATE_RX) &&
-                       !g_ble_phy_data.phy_rx_started));
-        NRF_RADIO_NS->EVENTS_END = 0;
-        NRF_RADIO_NS->EVENTS_DISABLED = 0;
-        NRF_RADIO_NS->INTENCLR = RADIO_INTENCLR_DISABLED_Msk;
-
-        switch (g_ble_phy_data.phy_state) {
-        case BLE_PHY_STATE_RX:
-            ble_phy_fem_disable_lna();
-            if (g_ble_phy_data.phy_rx_started) {
-                ble_phy_rx_end_isr();
-            } else {
-                ble_ll_wfr_timer_exp(NULL);
-            }
-            break;
-        case BLE_PHY_STATE_TX:
-            ble_phy_fem_disable_pa();
-            ble_phy_tx_end_isr();
-            break;
-        default:
-            BLE_LL_ASSERT(0);
-        }
-    }
-
-    g_ble_phy_data.phy_transition_late = 0;
-    /* Count # of interrupts */
-    STATS_INC(ble_phy_stats, phy_isrs);
-
-    os_trace_isr_exit();
-}
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0 || \
-    MYNEWT_VAL(BLE_LL_FEM_PA) || \
-    MYNEWT_VAL(BLE_LL_FEM_LNA)
-static int
-ble_phy_gpiote_configure(int pin)
-{
-    NRF_GPIO_Type *port;
-
-    g_ble_phy_gpiote_idx--;
-
-    port = pin > 31 ? NRF_P1_NS : NRF_P0_NS;
-    pin &= 0x1f;
-
-    /* Configure GPIO directly to avoid dependency to hal_gpio (for porting) */
-    port->DIRSET = (1 << pin);
-    port->OUTCLR = (1 << pin);
-
-    NRF_GPIOTE_NS->CONFIG[g_ble_phy_gpiote_idx] =
-            (GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos) |
-            ((pin & 0x1F) << GPIOTE_CONFIG_PSEL_Pos) |
-            ((port == NRF_P1_NS) << GPIOTE_CONFIG_PORT_Pos);
-
-    BLE_LL_ASSERT(g_ble_phy_gpiote_idx >= 0);
-
-    return g_ble_phy_gpiote_idx;
-}
-#endif
-
-static void
-ble_phy_dbg_time_setup(void)
-{
-    int idx __attribute__((unused)) = 8;
-
-    /*
-     * We setup GPIOTE starting from last configuration index to minimize risk
-     * of conflict with GPIO setup via hal. It's not great solution, but since
-     * this is just debugging code we can live with this.
-     */
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
-    phy_dbg_txrxen_ready_idx = idx;
-
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_READY);
-
-    /* Publish RADIO->EVENTS_READY */
-    NRF_RADIO_NS->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY);
-    NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_READY);
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
-    phy_dbg_address_end_idx = idx;
-
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[idx] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_END);
-#endif
-
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
-    idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
-    phy_dbg_wfr_idx = idx;
-
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[idx] = DPPI_CH_SUB(RADIO_EVENTS_RXREADY);
-
-    /* TODO figure out how (if?) to subscribe task to multiple DPPI channels
-     * Currently only last one is working. Also using multiple GPIOTE for same
-     * PIN doesn't work...
-     */
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[idx] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3);
-
-    /* Publish RADIO->EVENTS_RXREADY */
-    NRF_RADIO_NS->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_READY);
-    NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_RXREADY);
-
-    /* Publish RADIO->EVENTS_DISABLED */
-    NRF_RADIO_NS->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED);
-    NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_DISABLED);
-#endif
-}
-
-int
-ble_phy_init(void)
-{
-    int rc;
-
-    g_ble_phy_gpiote_idx = 8;
-
-    /* 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;
-    *(volatile uint32_t *)(NRF_RADIO_NS_BASE + 0x774) = (*(volatile uint32_t* )(NRF_RADIO_NS_BASE + 0x774) & 0xfffffffe) | 0x01000000;
-
-    /* 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_CH_PUB(TIMER0_EVENTS_COMPARE_0);
-    NRF_TIMER0_NS->PUBLISH_COMPARE[3] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_3);
-    NRF_RADIO_NS->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END);
-    NRF_RADIO_NS->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH);
-    NRF_RADIO_NS->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS);
-    NRF_RTC0_NS->PUBLISH_COMPARE[0] = DPPI_CH_PUB(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_CH_SUB(RADIO_EVENTS_ADDRESS);
-    NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END);
-
-#if MYNEWT_VAL(BLE_LL_FEM_PA) || MYNEWT_VAL(BLE_LL_FEM_LNA)
-    /* We keep both channels enabled and CLR task subscribed all the time. It's
-     * enough to just (un)subscribe SET task when needed.
-     * TODO: figure out if this affects power consumption
-     */
-
-    /* Publish TIMER0->EVENTS_COMPARE4 */
-    NRF_TIMER0_NS->PUBLISH_COMPARE[4] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_4);
-    NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_4);
-    /* Publish RADIO->EVENTS_DISABLED */
-    NRF_RADIO_NS->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED);
-    NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_DISABLED);
-
-#if FEM_SINGLE_GPIO
-    fem_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[fem_idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
-    NRF_GPIOTE_NS->TASKS_CLR[fem_idx] = 1;
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    fem_pa_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[fem_pa_idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
-    NRF_GPIOTE_NS->TASKS_CLR[fem_pa_idx] = 1;
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    fem_lna_idx = ble_phy_gpiote_configure(MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-    NRF_GPIOTE_NS->SUBSCRIBE_CLR[fem_lna_idx] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
-    NRF_GPIOTE_NS->TASKS_CLR[fem_lna_idx] = 1;
-#endif
-#endif
-
-    NRF_DPPIC_NS->CHENSET = DPPI_CH_MASK_FEM;
-#endif
-
-    /* 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;
-    }
-
-    ble_phy_dbg_time_setup();
-
-    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_CH_SUB(TIMER0_EVENTS_COMPARE_0));
-
-    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_central)
-{
-    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_central;
-    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_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-    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_CH_UNSUB(TIMER0_EVENTS_COMPARE_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_CH_SUB(TIMER0_EVENTS_COMPARE_0);
-        rc = 0;
-
-        ble_phy_fem_enable_pa();
-    }
-    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_CH_UNSUB(TIMER0_EVENTS_COMPARE_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_CH_SUB(TIMER0_EVENTS_COMPARE_0);
-
-    ble_phy_fem_enable_lna();
-
-    /* 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_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-    NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
-    NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH);
-    NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-
-#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_Neg3dBm;
-    }
-
-    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_CH_UNSUB(RTC0_EVENTS_COMPARE_0);
-    NRF_TIMER0_NS->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-    NRF_RADIO_NS->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
-    NRF_RADIO_NS->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
-    NRF_RADIO_NS->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
-    NRF_AAR_NS->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH);
-    NRF_CCM_NS->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
-
-#if FEM_SINGLE_GPIO
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_idx] = DPPI_CH_UNSUB(RADIO_EVENTS_READY);
-#else
-#if MYNEWT_VAL(BLE_LL_FEM_PA)
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_pa_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-#endif
-#if MYNEWT_VAL(BLE_LL_FEM_LNA)
-    NRF_GPIOTE_NS->SUBSCRIBE_SET[fem_lna_idx] = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_4);
-#endif
-#endif
-
-    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_CH_SUB(TIMER0_EVENTS_COMPARE_0);
-
-    ble_phy_rx();
-}
-
-static void
-ble_phy_dbg_clear_pins(void)
-{
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN) >= 0
-    NRF_GPIOTE_NS->TASKS_CLR[phy_dbg_txrxen_ready_idx] = 1;
-#endif
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN) >= 0
-    NRF_GPIOTE_NS->TASKS_CLR[phy_dbg_address_end_idx] = 1;
-#endif
-#if MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN) >= 0
-    NRF_GPIOTE_NS->TASKS_CLR[phy_dbg_wfr_idx] = 1;
-#endif
-}
-
-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();
-    ble_phy_fem_force_disable();
-    ble_phy_dbg_clear_pins();
-}
-
-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/nimble/drivers/nrf5340/src/ble_phy_trace.c b/nimble/drivers/nrf5340/src/ble_phy_trace.c
deleted file mode 100644
index dad78679..00000000
--- a/nimble/drivers/nrf5340/src/ble_phy_trace.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * 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>
-#include "controller/ble_phy_trace.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/nimble/drivers/nrf5340/syscfg.yml b/nimble/drivers/nrf5340/syscfg.yml
deleted file mode 100644
index ed82f6d6..00000000
--- a/nimble/drivers/nrf5340/syscfg.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-# 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
-
-    BLE_PHY_DBG_TIME_TXRXEN_READY_PIN:
-        description: >
-            When set to proper GPIO pin number, this pin will be set
-            to high state when radio is enabled (TASKS_TXEN or TASKS_RXEN)
-            and back to low state on radio EVENTS_READY.
-            This can be used to measure radio ram-up time.
-
-            Note:
-            GPIO control for selected pin needs to be assigned to Network
-            Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on
-            Application Core.
-        value: -1
-
-    BLE_PHY_DBG_TIME_ADDRESS_END_PIN:
-        description: >
-            When set to proper GPIO pin number, this pin will be set
-            to high state on radio EVENTS_ADDRESS and back to low state
-            on radio EVENTS_END.
-            This can be used to measure radio pipeline delays.
-
-            Note:
-            GPIO control for selected pin needs to be assigned to Network
-            Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on
-            Application Core.
-        value: -1
-
-    BLE_PHY_DBG_TIME_WFR_PIN:
-        description: >
-            When set to proper GPIO pin number, this pin will be set
-            to high state on radio EVENTS_RXREADY and back to low
-            state when wfr timer expires.
-            This can be used to check if wfr is calculated properly.
-
-            Note:
-            GPIO control for selected pin needs to be assigned to Network
-            Core, configure IPC_NRF5340_NET_GPIO in ipc_nrf5340 driver on
-            Application Core.
-        value: -1


[mynewt-nimble] 06/09: nimble/phy/nrf5x: Add nRF53 support

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9ea411fbe637ca4b0e40d32a9741e6ac8cb57a3f
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Thu Sep 8 12:13:15 2022 +0200

    nimble/phy/nrf5x: Add nRF53 support
    
    This adds code for nRF5340 net core.
---
 nimble/drivers/nrf5x/pkg.yml             |   5 +
 nimble/drivers/nrf5x/src/ble_phy.c       |  48 ++++++-
 nimble/drivers/nrf5x/src/nrf53/phy.c     | 235 +++++++++++++++++++++++++++++++
 nimble/drivers/nrf5x/src/nrf53/phy_ppi.h | 159 +++++++++++++++++++++
 nimble/drivers/nrf5x/src/phy_priv.h      |   8 ++
 5 files changed, 452 insertions(+), 3 deletions(-)

diff --git a/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml
index e0b314ea..b99e6692 100644
--- a/nimble/drivers/nrf5x/pkg.yml
+++ b/nimble/drivers/nrf5x/pkg.yml
@@ -29,3 +29,8 @@ pkg.apis: ble_driver
 pkg.deps:
     - nimble
     - nimble/controller
+
+pkg.ign_dirs.'MCU_TARGET=="nRF5340_NET"':
+    - nrf52
+pkg.ign_dirs.'MCU_TARGET!="nRF5340_NET"':
+    - nrf53
diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index 36f209c5..0d9b363f 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -39,7 +39,12 @@
 #include "controller/ble_ll.h"
 #include "nrfx.h"
 #if MYNEWT
-#include "mcu/nrf52_clock.h"
+#ifdef NRF52_SERIES
+#include <mcu/nrf52_clock.h>
+#endif
+#ifdef NRF53_SERIES
+#include <mcu/nrf5340_net_clock.h>
+#endif
 #include "mcu/cmsis_nvic.h"
 #include "hal/hal_gpio.h"
 #else
@@ -49,8 +54,10 @@
 #include "phy_priv.h"
 
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
-#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811)
-#error LE Coded PHY can only be enabled on nRF52811 or nRF52840
+#if !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52840) && \
+    !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF52811) && \
+    !MYNEWT_VAL_CHOICE(MCU_TARGET, nRF5340_NET)
+#error LE Coded PHY can only be enabled on nRF52811, nRF52840 or nRF5340
 #endif
 #endif
 
@@ -379,21 +386,33 @@ ble_phy_mode_apply(uint8_t phy_mode)
     switch (phy_mode) {
     case BLE_PHY_MODE_1M:
         NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_1Mbit;
+#ifdef NRF53_SERIES
+        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080);
+#endif
         NRF_RADIO->PCNF0 = NRF_PCNF0_1M;
         break;
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_2M_PHY)
     case BLE_PHY_MODE_2M:
         NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_2Mbit;
+#ifdef NRF53_SERIES
+        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0084);
+#endif
         NRF_RADIO->PCNF0 = NRF_PCNF0_2M;
         break;
 #endif
 #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_CODED_PHY)
     case BLE_PHY_MODE_CODED_125KBPS:
         NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR125Kbit;
+#ifdef NRF53_SERIES
+        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080);
+#endif
         NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
         break;
     case BLE_PHY_MODE_CODED_500KBPS:
         NRF_RADIO->MODE = RADIO_MODE_MODE_Ble_LR500Kbit;
+#ifdef NRF53_SERIES
+        *((volatile uint32_t *)0x41008588) = *((volatile uint32_t *)0x01FF0080);
+#endif
         NRF_RADIO->PCNF0 = NRF_PCNF0_CODED;
         break;
 #endif
@@ -1392,6 +1411,19 @@ ble_phy_init(void)
     nrf_radio_power_set(NRF_RADIO, false);
     nrf_radio_power_set(NRF_RADIO, true);
 
+#ifdef NRF53_SERIES
+    *(volatile uint32_t *)(NRF_RADIO_NS_BASE + 0x774) =
+        (*(volatile uint32_t* )(NRF_RADIO_NS_BASE + 0x774) & 0xfffffffe) | 0x01000000;
+#if NRF53_ERRATA_16_ENABLE_WORKAROUND
+    if (nrf53_errata_16()) {
+        /* [16] RADIO: POWER register is not functional */
+        NRF_RADIO_NS->SUBSCRIBE_TXEN = 0;
+        NRF_RADIO_NS->SUBSCRIBE_RXEN = 0;
+        NRF_RADIO_NS->SUBSCRIBE_DISABLE = 0;
+    }
+#endif
+#endif
+
     /* Disable all interrupts */
     nrf_radio_int_disable(NRF_RADIO, NRF_RADIO_IRQ_MASK_ALL);
 
@@ -2071,7 +2103,12 @@ void
 ble_phy_rfclk_enable(void)
 {
 #if MYNEWT || defined(RIOT_VERSION)
+#ifdef NRF52_SERIES
     nrf52_clock_hfxo_request();
+#endif
+#ifdef NRF53_SERIES
+    nrf5340_net_clock_hfxo_request();
+#endif
 #else
     nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
 #endif
@@ -2081,7 +2118,12 @@ void
 ble_phy_rfclk_disable(void)
 {
 #if MYNEWT || defined(RIOT_VERSION)
+#ifdef NRF52_SERIES
     nrf52_clock_hfxo_release();
+#endif
+#ifdef NRF53_SERIES
+    nrf5340_net_clock_hfxo_release();
+#endif
 #else
     nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
 #endif
diff --git a/nimble/drivers/nrf5x/src/nrf53/phy.c b/nimble/drivers/nrf5x/src/nrf53/phy.c
new file mode 100644
index 00000000..78b45578
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/nrf53/phy.c
@@ -0,0 +1,235 @@
+/*
+ * 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 <nrfx.h>
+#include <controller/ble_ll_fem.h>
+#include "../phy_priv.h"
+
+#if PHY_USE_DEBUG
+void
+phy_debug_init(void)
+{
+#if PHY_USE_DEBUG_1
+    phy_gpiote_configure(PHY_GPIOTE_DEBUG_1,
+                         MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN));
+
+    NRF_RADIO->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY);
+    NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_READY);
+
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(RADIO_EVENTS_READY);
+#endif
+
+#if PHY_USE_DEBUG_2
+    phy_gpiote_configure(PHY_GPIOTE_DEBUG_2,
+                         MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN));
+
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(RADIO_EVENTS_END);
+#endif
+
+#if PHY_USE_DEBUG_3
+    phy_gpiote_configure(PHY_GPIOTE_DEBUG_3, MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN));
+
+    NRF_RADIO->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_READY);
+    NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED);
+    NRF_DPPIC->CHENSET = DPPI_CH_MASK(RADIO_EVENTS_RXREADY) |
+                         DPPI_CH_MASK(RADIO_EVENTS_DISABLED);
+
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_RXREADY);
+
+    /* TODO figure out how (if?) to subscribe task to multiple DPPI channels
+     * Currently only last one is working. Also using multiple GPIOTE for same
+     * PIN doesn't work...
+     */
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3);
+
+#endif
+}
+#endif /* PHY_USE_DEBUG */
+
+#if PHY_USE_FEM
+void
+phy_fem_init()
+{
+    /* We can keep clear tasks subscribed and published channels always enabled,
+     * it's enough to just (un)subscribe set tasks when needed.
+     * TODO: check if this affects power consumption
+     */
+
+    NRF_TIMER0->PUBLISH_COMPARE[2] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_2);
+    NRF_RADIO->PUBLISH_DISABLED = DPPI_CH_PUB(RADIO_EVENTS_DISABLED);
+
+#if PHY_USE_FEM_SINGLE_GPIO
+#if PHY_USE_FEM_PA
+    phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
+#else
+    phy_gpiote_configure(PHY_GPIOTE_FEM, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
+#endif
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] =
+        DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM] =
+        DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1;
+#else
+#if PHY_USE_FEM_PA
+    phy_gpiote_configure(PHY_GPIOTE_FEM_PA, MYNEWT_VAL(BLE_LL_FEM_PA_GPIO));
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] =
+        DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_PA] =
+        DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1;
+#endif
+#if PHY_USE_FEM_LNA
+    phy_gpiote_configure(PHY_GPIOTE_FEM_LNA, MYNEWT_VAL(BLE_LL_FEM_LNA_GPIO));
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] =
+        DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2);
+    NRF_GPIOTE->SUBSCRIBE_CLR[PHY_GPIOTE_FEM_LNA] =
+        DPPI_CH_SUB(RADIO_EVENTS_DISABLED);
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1;
+#endif
+#endif /* PHY_USE_FEM_SINGLE_GPIO */
+
+    NRF_DPPIC->CHENSET = DPPI_CH_MASK_FEM;
+}
+
+void
+phy_fem_enable_pa(void)
+{
+    ble_ll_fem_pa_enable();
+
+#if PHY_USE_FEM_SINGLE_GPIO
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] =
+        DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2);
+#else
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] =
+        DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2);
+#endif
+}
+
+void
+phy_fem_enable_lna(void)
+{
+    ble_ll_fem_lna_enable();
+
+#if PHY_USE_FEM_SINGLE_GPIO
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] =
+        DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2);
+#else
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] =
+        DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_2);
+#endif
+}
+
+void
+phy_fem_disable(void)
+{
+#if PHY_USE_FEM_SINGLE_GPIO
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM] = 1;
+#else
+#if PHY_USE_FEM_PA
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_PA] = 1;
+#endif
+#if PHY_USE_FEM_LNA
+    NRF_GPIOTE->TASKS_CLR[PHY_GPIOTE_FEM_LNA] = 1;
+#endif
+#endif
+}
+#endif /* PHY_USE_FEM */
+
+void
+phy_ppi_init(void)
+{
+    /* Publish events */
+    NRF_TIMER0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_0);
+    NRF_TIMER0->PUBLISH_COMPARE[3] = DPPI_CH_PUB(TIMER0_EVENTS_COMPARE_3);
+    NRF_RADIO->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END);
+    NRF_RADIO->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH);
+    NRF_RADIO->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS);
+    NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0);
+
+    /* Enable channels we publish on */
+    NRF_DPPIC->CHENSET = DPPI_CH_ENABLE_ALL;
+
+    /* radio_address_to_timer0_capture1 */
+    NRF_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
+    /* radio_end_to_timer0_capture2 */
+    NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END);
+}
+
+int8_t
+phy_txpower_round(int8_t dbm)
+{
+    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_Neg3dBm;
+    }
+
+    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;
+}
diff --git a/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h
new file mode 100644
index 00000000..6412f327
--- /dev/null
+++ b/nimble/drivers/nrf5x/src/nrf53/phy_ppi.h
@@ -0,0 +1,159 @@
+/*
+ * 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_PHY_PPI_
+#define H_PHY_PPI_
+
+#define DPPI_CH_PUB(_ch)        (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31))
+#define DPPI_CH_SUB(_ch)        (((DPPI_CH_ ## _ch) & 0xff) | (1 << 31))
+#define DPPI_CH_UNSUB(_ch)      (((DPPI_CH_ ## _ch) & 0xff) | (0 << 31))
+#define DPPI_CH_MASK(_ch)       (1 << (DPPI_CH_ ## _ch))
+
+/* Channels 0..5 are always used.
+ * Channels 6 and 7 are used for PA/LNA (optionally).
+ * Channels 7..9 are used for GPIO debugging (optionally).
+ */
+
+#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_TIMER0_EVENTS_COMPARE_2         6
+#define DPPI_CH_RADIO_EVENTS_DISABLED           7
+#define DPPI_CH_RADIO_EVENTS_READY              8
+#define DPPI_CH_RADIO_EVENTS_RXREADY            9
+
+#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_CH_MASK_FEM    (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_2) | \
+                             DPPI_CH_MASK(RADIO_EVENTS_DISABLED))
+
+static inline void
+phy_ppi_rtc0_compare0_to_timer0_start_enable(void)
+{
+    NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_SUB(RTC0_EVENTS_COMPARE_0);
+}
+
+static inline void
+phy_ppi_rtc0_compare0_to_timer0_start_disable(void)
+{
+    NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0);
+    NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
+    NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_txen_enable(void)
+{
+    NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_txen_disable(void)
+{
+    NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_rxen_enable(void)
+{
+    NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_0);
+}
+
+static inline void
+phy_ppi_timer0_compare0_to_radio_rxen_disable(void)
+{
+    NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
+}
+
+static inline void
+phy_ppi_radio_address_to_ccm_crypt_enable(void)
+{
+    NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
+}
+
+static inline void
+phy_ppi_radio_address_to_ccm_crypt_disable(void)
+{
+    NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
+}
+
+static inline void
+phy_ppi_radio_bcmatch_to_aar_start_enable(void)
+{
+    NRF_AAR->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_BCMATCH);
+}
+
+static inline void
+phy_ppi_radio_bcmatch_to_aar_start_disable(void)
+{
+    NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH);
+}
+
+static inline void
+phy_ppi_wfr_enable(void)
+{
+    NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS);
+    NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_SUB(TIMER0_EVENTS_COMPARE_3);
+}
+
+static inline void
+phy_ppi_wfr_disable(void)
+{
+    NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
+    NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
+}
+
+static inline void
+phy_ppi_fem_disable(void)
+{
+#if PHY_USE_FEM_SINGLE_GPIO
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM] =
+        DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
+#else
+#if PHY_USE_FEM_PA
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_PA] =
+        DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2);
+#endif
+#if PHY_USE_FEM_LNA
+    NRF_GPIOTE->SUBSCRIBE_SET[PHY_GPIOTE_FEM_LNA] =
+        DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_2);
+#endif
+#endif
+}
+
+static inline void
+phy_ppi_disable(void)
+{
+    NRF_TIMER0->SUBSCRIBE_START = DPPI_CH_UNSUB(RTC0_EVENTS_COMPARE_0);
+    NRF_TIMER0->SUBSCRIBE_CAPTURE[3] = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
+    NRF_RADIO->SUBSCRIBE_DISABLE = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_3);
+    NRF_RADIO->SUBSCRIBE_TXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
+    NRF_RADIO->SUBSCRIBE_RXEN = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0);
+    NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH);
+    NRF_CCM->SUBSCRIBE_CRYPT = DPPI_CH_UNSUB(RADIO_EVENTS_ADDRESS);
+
+    phy_ppi_fem_disable();
+}
+
+#endif /* H_PHY_PPI_ */
\ No newline at end of file
diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h
index 1a026a6d..8cf140ee 100644
--- a/nimble/drivers/nrf5x/src/phy_priv.h
+++ b/nimble/drivers/nrf5x/src/phy_priv.h
@@ -20,6 +20,7 @@
 #ifndef H_PHY_PRIV_
 #define H_PHY_PRIV_
 
+#include <stdint.h>
 #include <nrf_gpio.h>
 #include <nrf_gpiote.h>
 
@@ -79,4 +80,11 @@ void phy_ppi_init(void);
 
 int8_t phy_txpower_round(int8_t dbm);
 
+#ifdef NRF52_SERIES
+#include "nrf52/phy_ppi.h"
+#endif
+#ifdef NRF53_SERIES
+#include "nrf53/phy_ppi.h"
+#endif
+
 #endif /* H_PHY_PRIV_ */


[mynewt-nimble] 04/09: nimble/phy/nrf5x: Move out TX power rounding

Posted by an...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9dd64d2903a670c79493f035013d69d948400178
Author: Andrzej Kaczmarek <an...@codecoup.pl>
AuthorDate: Thu Sep 8 10:34:37 2022 +0200

    nimble/phy/nrf5x: Move out TX power rounding
---
 nimble/drivers/nrf5x/src/ble_phy.c   | 40 +++++-------------------------------
 nimble/drivers/nrf5x/src/nrf52/phy.c | 34 ++++++++++++++++++++++++++++++
 nimble/drivers/nrf5x/src/phy_priv.h  |  2 ++
 3 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c
index d5113434..b4d64d88 100644
--- a/nimble/drivers/nrf5x/src/ble_phy.c
+++ b/nimble/drivers/nrf5x/src/ble_phy.c
@@ -1803,8 +1803,8 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans)
 int
 ble_phy_txpwr_set(int dbm)
 {
-    /* "Rail" power level if outside supported range */
-    dbm = ble_phy_txpower_round(dbm);
+    /* Get actual TX power supported by radio */
+    dbm = phy_txpower_round(dbm);
 
     NRF_RADIO->TXPOWER = dbm;
     g_ble_phy_data.phy_txpwr_dbm = dbm;
@@ -1821,40 +1821,10 @@ ble_phy_txpwr_set(int dbm)
  *
  * @return int Rounded power in dBm
  */
-int ble_phy_txpower_round(int dbm)
+int
+ble_phy_txpower_round(int dbm)
 {
-    /* TODO this should be per nRF52XXX */
-
-    /* "Rail" power level if outside supported range */
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm;
-    }
-
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm;
-    }
-
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm;
-    }
-
-    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm;
-    }
-
-    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_Neg20dBm) {
-        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm;
-    }
-
-    return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
+    return phy_txpower_round(dbm);
 }
 
 /**
diff --git a/nimble/drivers/nrf5x/src/nrf52/phy.c b/nimble/drivers/nrf5x/src/nrf52/phy.c
index 4f825b8f..763e3eef 100644
--- a/nimble/drivers/nrf5x/src/nrf52/phy.c
+++ b/nimble/drivers/nrf5x/src/nrf52/phy.c
@@ -163,3 +163,37 @@ phy_ppi_init(void)
                                    (uint32_t)&(NRF_TIMER0->EVENTS_COMPARE[3]),
                                    (uint32_t)&(NRF_RADIO->TASKS_DISABLE));
 }
+
+int8_t
+phy_txpower_round(int8_t dbm)
+{
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos4dBm;
+    }
+
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Pos3dBm;
+    }
+
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_0dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_0dBm;
+    }
+
+    if (dbm >= (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg4dBm;
+    }
+
+    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_Neg20dBm) {
+        return (int8_t)RADIO_TXPOWER_TXPOWER_Neg20dBm;
+    }
+
+    return (int8_t)RADIO_TXPOWER_TXPOWER_Neg40dBm;
+}
diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h
index 881221ad..b2308e61 100644
--- a/nimble/drivers/nrf5x/src/phy_priv.h
+++ b/nimble/drivers/nrf5x/src/phy_priv.h
@@ -76,4 +76,6 @@ void phy_ppi_init(void);
 #include "nrf52/phy_ppi.h"
 #endif
 
+int8_t phy_txpower_round(int8_t dbm);
+
 #endif /* H_PHY_PRIV_ */