diff --git a/nimble/drivers/nrf5x/pkg.yml b/nimble/drivers/nrf5x/pkg.yml index b99e669248..354ffdc44e 100644 --- a/nimble/drivers/nrf5x/pkg.yml +++ b/nimble/drivers/nrf5x/pkg.yml @@ -30,7 +30,16 @@ pkg.deps: - nimble - nimble/controller -pkg.ign_dirs.'MCU_TARGET=="nRF5340_NET"': - - nrf52 -pkg.ign_dirs.'MCU_TARGET!="nRF5340_NET"': - - nrf53 +pkg.source_files: + - "src/ble_hw.c" + - "src/ble_phy.c" + - "src/ble_phy_trace.c" + +pkg.source_files.'MCU_TARGET=="nRF52810" || MCU_TARGET=="nRF52811" || MCU_TARGET=="nRF52832" || MCU_TARGET=="nRF52840"': + - "src/nrf52/phy.c" + +pkg.source_files.'MCU_TARGET=="nRF5340_NET"': + - "src/nrf53/phy.c" + +pkg.source_files.'MCU_TARGET=="nRF54L15"': + - "src/nrf54l/phy.c" diff --git a/nimble/drivers/nrf5x/src/ble_hw.c b/nimble/drivers/nrf5x/src/ble_hw.c index f8cd59f098..44b566af1a 100644 --- a/nimble/drivers/nrf5x/src/ble_hw.c +++ b/nimble/drivers/nrf5x/src/ble_hw.c @@ -36,9 +36,25 @@ #include #endif #include "os/os_trace_api.h" +#ifndef NRF54L_SERIES #include +#endif #include "hal/nrf_ecb.h" +#ifdef NRF54L_SERIES +#include + +#define NRF_ECB NRF_ECB00 +#define NRF_AAR NRF_AAR00 + +struct nrf_ecb_job_list { + nrf_vdma_job_t in[2]; + nrf_vdma_job_t out[2]; +}; + +static struct nrf_ecb_job_list g_ecb_job_list; +#endif + /* Total number of resolving list elements */ #define BLE_HW_RESOLV_LIST_SIZE (16) @@ -276,6 +292,47 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) uint32_t end; uint32_t err; +#ifdef NRF54L_SERIES + /* Stop ECB */ + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOP); + + /* Init job lists */ + g_ecb_job_list.in[0].p_buffer = ecb->plain_text; + g_ecb_job_list.in[0].attributes = NRF_VDMA_ATTRIBUTE_CRC; + g_ecb_job_list.in[0].size = BLE_ENC_BLOCK_SIZE; + memset(&g_ecb_job_list.in[1], 0, sizeof(g_ecb_job_list.in[1])); + + g_ecb_job_list.out[0].p_buffer = ecb->cipher_text; + g_ecb_job_list.out[0].attributes = NRF_VDMA_ATTRIBUTE_CRC; + g_ecb_job_list.out[0].size = BLE_ENC_BLOCK_SIZE; + memset(&g_ecb_job_list.out[1], 0, sizeof(g_ecb_job_list.out[1])); + + NRF_ECB->KEY.VALUE[3] = get_be32(&ecb->key[0]); + NRF_ECB->KEY.VALUE[2] = get_be32(&ecb->key[4]); + NRF_ECB->KEY.VALUE[1] = get_be32(&ecb->key[8]); + NRF_ECB->KEY.VALUE[0] = get_be32(&ecb->key[12]); + + NRF_ECB->EVENTS_END = 0; + NRF_ECB->EVENTS_ERROR = 0; + NRF_ECB->IN.PTR = (uint32_t)g_ecb_job_list.in; + NRF_ECB->OUT.PTR = (uint32_t)g_ecb_job_list.out; + + /* Start ECB */ + nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_START); + + /* Wait till error or done */ + rc = 0; + while (1) { + end = NRF_ECB->EVENTS_END; + err = NRF_ECB->EVENTS_ERROR; + if (end || err) { + if (err) { + rc = -1; + } + break; + } + } +#else /* Stop ECB */ nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOPECB); /* XXX: does task stop clear these counters? Anyway to do this quicker? */ @@ -301,7 +358,7 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) tm_tick(); #endif } - +#endif return rc; } @@ -314,7 +371,27 @@ ble_rng_isr(void) uint8_t rnum; os_trace_isr_enter(); +#ifdef NRF54L_SERIES + (void)rnum; + /* No callback? Clear and disable interrupts */ + if (g_ble_rng_isr_cb == NULL) { + nrf_cracen_int_disable(NRF_CRACEN, NRF_CRACEN_INT_RNG_MASK); + NRF_CRACENCORE->RNGCONTROL.CONTROL &= ~CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk; + NRF_CRACEN->EVENTS_RNG = 0; + os_trace_isr_exit(); + return; + } + + if (g_ble_rng_isr_cb) { + /* If there is a value ready in the queue grab it */ + while ((NRF_CRACENCORE->RNGCONTROL.CONTROL & + CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk) && + (NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL > 0)) { + g_ble_rng_isr_cb(ble_hw_rng_read()); + } + } +#else /* No callback? Clear and disable interrupts */ if (g_ble_rng_isr_cb == NULL) { nrf_rng_int_disable(NRF_RNG, NRF_RNG_INT_VALRDY_MASK); @@ -330,7 +407,7 @@ ble_rng_isr(void) rnum = (uint8_t)NRF_RNG->VALUE; (*g_ble_rng_isr_cb)(rnum); } - +#endif os_trace_isr_exit(); } @@ -345,6 +422,24 @@ ble_rng_isr(void) int ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) { +#ifdef NRF54L_SERIES + NRF_CRACEN->ENABLE = CRACEN_ENABLE_CRYPTOMASTER_Msk | + CRACEN_ENABLE_RNG_Msk | + CRACEN_ENABLE_PKEIKG_Msk; + + while (NRF_CRACENCORE->PK.STATUS & CRACENCORE_PK_STATUS_PKBUSY_Msk); + NRF_CRACENCORE->PK.CONTROL &= ~CRACENCORE_IKG_PKECONTROL_CLEARIRQ_Msk; + + NRF_CRACENCORE->RNGCONTROL.CONTROL = CRACENCORE_RNGCONTROL_CONTROL_ResetValue | + CRACENCORE_RNGCONTROL_CONTROL_ENABLE_Msk; + + /* If we were passed a function pointer we need to enable the interrupt */ + if (cb != NULL) { + NVIC_SetVector(CRACEN_IRQn, (uint32_t)ble_rng_isr); + NVIC_EnableIRQ(CRACEN_IRQn); + g_ble_rng_isr_cb = cb; + } +#else /* Set bias */ if (bias) { NRF_RNG->CONFIG = 1; @@ -365,6 +460,7 @@ ble_hw_rng_init(ble_rng_isr_cb_t cb, int bias) NVIC_EnableIRQ(RNG_IRQn); g_ble_rng_isr_cb = cb; } +#endif return 0; } @@ -381,12 +477,23 @@ ble_hw_rng_start(void) /* No need for interrupt if there is no callback */ OS_ENTER_CRITICAL(sr); +#ifdef NRF54L_SERIES + NRF_CRACEN->EVENTS_RNG = 0; + + if (g_ble_rng_isr_cb) { + nrf_cracen_int_enable(NRF_CRACEN, NRF_CRACEN_INT_RNG_MASK); + NRF_CRACENCORE->RNGCONTROL.CONTROL |= CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk; + /* Force regeneration of the samples */ + NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL = 0; + } +#else 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); +#endif OS_EXIT_CRITICAL(sr); return 0; @@ -404,9 +511,15 @@ ble_hw_rng_stop(void) /* No need for interrupt if there is no callback */ OS_ENTER_CRITICAL(sr); +#ifdef NRF54L_SERIES + nrf_cracen_int_disable(NRF_CRACEN, NRF_CRACEN_INT_RNG_MASK); + NRF_CRACENCORE->RNGCONTROL.CONTROL &= ~CRACENCORE_RNGCONTROL_CONTROL_INTENFULL_Msk; + NRF_CRACEN->EVENTS_RNG = 0; +#else 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; +#endif OS_EXIT_CRITICAL(sr); return 0; @@ -421,14 +534,28 @@ uint8_t ble_hw_rng_read(void) { uint8_t rnum; +#ifdef NRF54L_SERIES + uint8_t slot_id; + /* Wait for a sample */ + while (NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL == 0) { + assert((NRF_CRACENCORE->RNGCONTROL.STATUS & + CRACENCORE_RNGCONTROL_STATUS_STATE_Msk) != + (CRACENCORE_RNGCONTROL_STATUS_STATE_ERROR << + CRACENCORE_RNGCONTROL_STATUS_STATE_Pos)); + } + + NRF_CRACEN->EVENTS_RNG = 0; + slot_id = NRF_CRACENCORE->RNGCONTROL.FIFODEPTH - NRF_CRACENCORE->RNGCONTROL.FIFOLEVEL; + rnum = (uint8_t)NRF_CRACENCORE->RNGCONTROL.FIFO[slot_id]; +#else /* Wait for a sample */ while (NRF_RNG->EVENTS_VALRDY == 0) { } NRF_RNG->EVENTS_VALRDY = 0; rnum = (uint8_t)NRF_RNG->VALUE; - +#endif return rnum; } @@ -511,7 +638,11 @@ int ble_hw_resolv_list_match(void) { if (NRF_AAR->ENABLE && NRF_AAR->EVENTS_END && NRF_AAR->EVENTS_RESOLVED) { +#ifdef NRF54L_SERIES + return (int)NRF_AAR->ERRORSTATUS; +#else return (int)NRF_AAR->STATUS; +#endif } return -1; diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c index 8be0771bd4..6ee1063e5c 100644 --- a/nimble/drivers/nrf5x/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -27,6 +27,9 @@ #include #include #include "syscfg/syscfg.h" +#ifdef GRTC_AS_RADIO_TIMER +#include +#endif #include "os/os.h" /* Keep os_cputime explicitly to enable build on non-Mynewt platforms */ #include "os/os_cputime.h" @@ -45,6 +48,9 @@ #ifdef NRF53_SERIES #include #endif +#ifdef NRF54L_SERIES +#include +#endif #include "mcu/cmsis_nvic.h" #include "hal/hal_gpio.h" #else @@ -68,6 +74,13 @@ #endif #endif +#ifdef NRF54L_SERIES +#define EVENTS_ENDCRYPT EVENTS_END +#define MICSTATUS MACSTATUS +#define INTENSET INTENSET00 +#define HEADERMASK ADATAMASK +#endif + #if BABBLESIM extern void tm_tick(void); #endif @@ -103,8 +116,21 @@ extern uint8_t g_nrf_num_irks; extern uint32_t g_nrf_irk_list[]; /* To disable all radio interrupts */ +#ifdef NRF54L_SERIES +#define NRF_RADIO_IRQ_MASK_ALL (RADIO_INTENSET00_READY_Msk | \ + RADIO_INTENSET00_ADDRESS_Msk | \ + RADIO_INTENSET00_PAYLOAD_Msk | \ + RADIO_INTENSET00_END_Msk | \ + RADIO_INTENSET00_PHYEND_Msk | \ + RADIO_INTENSET00_DISABLED_Msk | \ + RADIO_INTENSET00_DEVMATCH_Msk | \ + RADIO_INTENSET00_DEVMISS_Msk | \ + RADIO_INTENSET00_BCMATCH_Msk | \ + RADIO_INTENSET00_CRCOK_Msk | \ + RADIO_INTENSET00_CRCERROR_Msk) +#else #define NRF_RADIO_IRQ_MASK_ALL (0x34FF) - +#endif /* * 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. @@ -121,7 +147,7 @@ extern uint32_t g_nrf_irk_list[]; /* NRF_RADIO->PCNF0 configuration values */ #define NRF_PCNF0 (NRF_LFLEN_BITS << RADIO_PCNF0_LFLEN_Pos) | \ - (RADIO_PCNF0_S1INCL_Msk) | \ + (RADIO_PCNF0_S1INCL_Include << RADIO_PCNF0_S1INCL_Pos) | \ (NRF_S0LEN << RADIO_PCNF0_S0LEN_Pos) | \ (NRF_S1LEN_BITS << RADIO_PCNF0_S1LEN_Pos) #define NRF_PCNF0_1M (NRF_PCNF0) | \ @@ -223,6 +249,42 @@ static const uint8_t g_ble_phy_t_rxenddelay[BLE_PHY_NUM_MODE] = { [BLE_PHY_MODE_1M] = 9, [BLE_PHY_MODE_2M] = 5, }; +#elif defined(NRF54L_SERIES) +/* 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] = 2, /* ~1.6us */ + [BLE_PHY_MODE_2M] = 5, + [BLE_PHY_MODE_CODED_125KBPS] = 5, + [BLE_PHY_MODE_CODED_500KBPS] = 5 +}; +/* delay between EVENTS_ADDRESS and txd access address */ +static const uint8_t g_ble_phy_t_txaddrdelay[BLE_PHY_NUM_MODE] = { + [BLE_PHY_MODE_1M] = 3, /* ~3.2us */ + [BLE_PHY_MODE_2M] = 5, + [BLE_PHY_MODE_CODED_125KBPS] = 17, + [BLE_PHY_MODE_CODED_500KBPS] = 17 +}; +/* 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] = 2, /* ~2.3us */ + [BLE_PHY_MODE_2M] = 4, + [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] = 9, /* ~9.2us */ + [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] = 9, /* ~9.1us */ + [BLE_PHY_MODE_2M] = 1, + [BLE_PHY_MODE_CODED_125KBPS] = 27, + [BLE_PHY_MODE_CODED_500KBPS] = 22 +}; #else /* delay between EVENTS_READY and start of tx */ static const uint8_t g_ble_phy_t_txdelay[BLE_PHY_NUM_MODE] = { @@ -325,7 +387,19 @@ STATS_NAME_END(ble_phy_stats) */ #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#ifdef NRF54L_SERIES +struct nrf_ccm_job_list { + uint16_t in_alen; + uint16_t in_mlen; + uint8_t in_mlen_msb; + uint8_t out_mlen_msb; + uint16_t out_alen; + nrf_vdma_job_t in[6]; + nrf_vdma_job_t out[6]; +}; +struct nrf_ccm_job_list g_ccm_job_list; +#else /* * 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 @@ -348,6 +422,11 @@ struct nrf_ccm_data struct nrf_ccm_data g_nrf_ccm_data; #endif +#endif + +#ifdef GRTC_AS_RADIO_TIMER +uint64_t hal_grtc_counter_get(void); +#endif static void timer0_reset(void) @@ -650,6 +729,10 @@ ble_phy_tifs_set(uint16_t tifs) static int ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) { +#ifdef GRTC_AS_RADIO_TIMER + uint64_t now_grtc; + uint64_t start_us; +#endif uint32_t next_cc; uint32_t cur_cc; uint32_t cntr; @@ -720,8 +803,14 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) * need to account for it. */ next_cc = cputime & 0xffffff; +#ifdef GRTC_AS_RADIO_TIMER + cur_cc = (NRF_GRTC->CC[3].CCL >> 5) & 0xffffff; + now_grtc = hal_grtc_counter_get(); + cntr = (now_grtc >> 5) & 0xffffff; +#else cur_cc = NRF_RTC0->CC[0]; cntr = NRF_RTC0->COUNTER; +#endif delta = (cur_cc - cntr) & 0xffffff; if ((delta <= 3) && (delta != 0)) { @@ -745,10 +834,17 @@ ble_phy_set_start_time(uint32_t cputime, uint8_t rem_us, bool tx) } #endif +#ifdef GRTC_AS_RADIO_TIMER + start_us = now_grtc + (delta << 5); + nrf_grtc_sys_counter_cc_set(NRF_GRTC, 3, start_us); + NRF_GRTC->EVENTS_COMPARE[3] = 0; + nrf_grtc_sys_counter_compare_event_enable(NRF_GRTC, 3); +#else /* 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); +#endif /* Enable PPI */ #if PHY_USE_FEM @@ -776,6 +872,9 @@ static int ble_phy_set_start_now(void) { os_sr_t sr; +#ifdef GRTC_AS_RADIO_TIMER + uint64_t now_grtc; +#endif uint32_t now; uint32_t radio_rem_us; #if PHY_USE_FEM_LNA @@ -813,6 +912,13 @@ ble_phy_set_start_now(void) NRF_TIMER0->EVENTS_COMPARE[2] = 0; #endif +#ifdef GRTC_AS_RADIO_TIMER + now_grtc = hal_grtc_counter_get(); + nrf_grtc_sys_counter_cc_set(NRF_GRTC, 3, now_grtc + 91); + NRF_GRTC->EVENTS_COMPARE[3] = 0; + nrf_grtc_sys_counter_compare_event_enable(NRF_GRTC, 3); + now = (now_grtc >> 5) & 0xffffff; +#else /* * 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 @@ -823,6 +929,7 @@ ble_phy_set_start_now(void) NRF_RTC0->EVENTS_COMPARE[0] = 0; nrf_rtc_cc_set(NRF_RTC0, 0, (now + 3) & 0xffffff); nrf_rtc_event_enable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); +#endif #if PHY_USE_FEM_LNA phy_fem_enable_lna(); @@ -948,9 +1055,17 @@ ble_phy_get_ccm_datarate(void) 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: +#ifdef NRF54L_SERIES + return CCM_MODE_DATARATE_125Kbit << CCM_MODE_DATARATE_Pos; +#else return CCM_MODE_DATARATE_125Kbps << CCM_MODE_DATARATE_Pos; +#endif case BLE_PHY_MODE_CODED_500KBPS: +#ifdef NRF54L_SERIES + return CCM_MODE_DATARATE_500Kbit << CCM_MODE_DATARATE_Pos; +#else return CCM_MODE_DATARATE_500Kbps << CCM_MODE_DATARATE_Pos; +#endif #endif } @@ -975,6 +1090,74 @@ ble_phy_rx_xcvr_setup(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (g_ble_phy_data.phy_encrypted) { +#ifdef NRF54L_SERIES + /* AAD length */ + g_ccm_job_list.in_alen = 1; + g_ccm_job_list.in[0].p_buffer = (uint8_t *) &g_ccm_job_list.in_alen; + g_ccm_job_list.in[0].size = sizeof(g_ccm_job_list.in_alen); + g_ccm_job_list.in[0].attributes = 11; + + /* Encrypted message length LSB */ + g_ccm_job_list.in[1].p_buffer = ((uint8_t *)g_ble_phy_enc_buf) + 1; + g_ccm_job_list.in[1].size = 1; + g_ccm_job_list.in[1].attributes = 12; + + /* Encrypted message length MSB */ + g_ccm_job_list.in[2].p_buffer = &g_ccm_job_list.in_mlen_msb; + g_ccm_job_list.in[2].size = sizeof(g_ccm_job_list.in_mlen_msb); + g_ccm_job_list.in[2].attributes = 12; + + /* AAD */ + g_ccm_job_list.in[3].p_buffer = ((uint8_t *)g_ble_phy_enc_buf); + g_ccm_job_list.in[3].size = 1; + g_ccm_job_list.in[3].attributes = 13; + + /* Encrypted message */ + g_ccm_job_list.in[4].p_buffer = ((uint8_t *)g_ble_phy_enc_buf) + 3; + g_ccm_job_list.in[4].size = NRF_MAXLEN; + g_ccm_job_list.in[4].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.in[5], 0, sizeof(g_ccm_job_list.in[5])); + + /* AAD length */ + g_ccm_job_list.out[0].p_buffer = (uint8_t *) &g_ccm_job_list.out_alen; + g_ccm_job_list.out[0].size = sizeof(g_ccm_job_list.out_alen); + g_ccm_job_list.out[0].attributes = 11; + + /* Decrypted message length LSB */ + g_ccm_job_list.out[1].p_buffer = &dptr[1]; + g_ccm_job_list.out[1].size = 1; + g_ccm_job_list.out[1].attributes = 12; + + /* Decrypted message length MSB */ + g_ccm_job_list.out[2].p_buffer = &g_ccm_job_list.out_mlen_msb; + g_ccm_job_list.out[2].size = sizeof(g_ccm_job_list.out_mlen_msb); + g_ccm_job_list.out[2].attributes = 12; + + /* AAD */ + g_ccm_job_list.out[3].p_buffer = &dptr[0]; + g_ccm_job_list.out[3].size = 1; + g_ccm_job_list.out[3].attributes = 13; + + /* Decrypted message */ + g_ccm_job_list.out[4].p_buffer = &dptr[3]; + g_ccm_job_list.out[4].size = NRF_MAXLEN - 4; + g_ccm_job_list.out[4].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.out[5], 0, sizeof(g_ccm_job_list.out[5])); + + NRF_RADIO->PACKETPTR = (uint32_t)&g_ble_phy_enc_buf[0]; + NRF_CCM->IN.PTR = (uint32_t)g_ccm_job_list.in; + NRF_CCM->OUT.PTR = (uint32_t)g_ccm_job_list.out; + + NRF_CCM->MODE = (CCM_MODE_MACLEN_M4 << CCM_MODE_MACLEN_Pos) | CCM_MODE_MODE_Decryption | + ble_phy_get_ccm_datarate(); + + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->EVENTS_END = 0; +#else 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; @@ -986,6 +1169,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); +#endif phy_ppi_radio_address_to_ccm_crypt_enable(); } else { NRF_RADIO->PACKETPTR = (uint32_t)dptr; @@ -997,8 +1181,13 @@ ble_phy_rx_xcvr_setup(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) if (g_ble_phy_data.phy_privacy) { NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; + /* TODO(m): Find replacement for NRF_AAR->SCRATCHPTR */ +#else NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; NRF_AAR->SCRATCHPTR = (uint32_t)&g_ble_phy_data.phy_aar_scratch; +#endif NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; NRF_AAR->EVENTS_NOTRESOLVED = 0; @@ -1011,7 +1200,7 @@ ble_phy_rx_xcvr_setup(void) /* Turn off trigger TXEN on output compare match and AAR on bcmatch */ phy_ppi_timer0_compare0_to_radio_txen_disable(); - phy_ppi_radio_bcmatch_to_aar_start_disable(); + //phy_ppi_radio_bcmatch_to_aar_start_disable(); TODO(m): this was disabling CCM RADIO SUBSCRIBTION because peripherals share memory. think later what to do with it /* Reset the rx started flag. Used for the wait for response */ g_ble_phy_data.phy_rx_started = 0; @@ -1037,16 +1226,21 @@ ble_phy_rx_xcvr_setup(void) NRF_RADIO->EVENTS_ADDRESS = 0; NRF_RADIO->EVENTS_DEVMATCH = 0; NRF_RADIO->EVENTS_BCMATCH = 0; +#ifndef NRF54L_SERIES NRF_RADIO->EVENTS_RSSIEND = 0; +#endif NRF_RADIO->EVENTS_CRCOK = 0; - NRF_RADIO->SHORTS = RADIO_SHORTS_END_DISABLE_Msk | - RADIO_SHORTS_READY_START_Msk | + NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk | RADIO_SHORTS_ADDRESS_BCSTART_Msk | - RADIO_SHORTS_ADDRESS_RSSISTART_Msk | - RADIO_SHORTS_DISABLED_RSSISTOP_Msk; - + RADIO_SHORTS_ADDRESS_RSSISTART_Msk; +#ifdef NRF54L_SERIES + NRF_RADIO->SHORTS |= RADIO_SHORTS_PHYEND_DISABLE_Msk; +#else + NRF_RADIO->SHORTS |= RADIO_SHORTS_END_DISABLE_Msk | + RADIO_SHORTS_DISABLED_RSSISTOP_Msk; +#endif nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_ADDRESS_Msk | - RADIO_INTENSET_DISABLED_Msk); + RADIO_INTENSET_DISABLED_Msk); } /** @@ -1187,7 +1381,9 @@ ble_phy_tx_end_isr(void) * it should be stopped here. */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); +#ifndef NRF54L_SERIES NRF_TIMER0->TASKS_SHUTDOWN = 1; +#endif phy_ppi_wfr_disable(); phy_ppi_timer0_compare0_to_radio_txen_disable(); phy_ppi_rtc0_compare0_to_timer0_start_disable(); @@ -1240,7 +1436,9 @@ ble_phy_rx_end_isr(void) /* Set RSSI and CRC status flag in header */ ble_hdr = &g_ble_phy_data.rxhdr; +#ifndef NRF54L_SERIES assert(NRF_RADIO->EVENTS_RSSIEND != 0); +#endif ble_hdr->rxinfo.rssi = (-1 * NRF_RADIO->RSSISAMPLE); dptr = (uint8_t *)&g_ble_phy_rx_buf[0]; @@ -1453,7 +1651,11 @@ ble_phy_rx_start_isr(void) * octets for extended header. */ adva_offset = (dptr[3] & 0x0f) == 0x07 ? 2 : 0; +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)(dptr + 3 + adva_offset); +#else NRF_AAR->ADDRPTR = (uint32_t)(dptr + 3 + adva_offset); +#endif /* Trigger AAR after last bit of AdvA is received */ NRF_RADIO->EVENTS_BCMATCH = 0; @@ -1597,9 +1799,11 @@ ble_phy_init(void) g_ble_phy_data.tifs = BLE_LL_IFS; #endif +#ifndef NRF54L_SERIES /* Toggle peripheral power to reset (just in case) */ nrf_radio_power_set(NRF_RADIO, false); nrf_radio_power_set(NRF_RADIO, true); +#endif #ifdef NRF53_SERIES /* Errata 158: load trim values after toggling power */ @@ -1636,8 +1840,13 @@ ble_phy_init(void) RADIO_PCNF1_WHITEEN_Msk; /* Enable radio fast ramp-up */ +#ifdef NRF54L_SERIES + NRF_RADIO->TIMING = (RADIO_TIMING_RU_Fast << RADIO_TIMING_RU_Pos) & + RADIO_TIMING_RU_Msk; +#else NRF_RADIO->MODECNF0 |= (RADIO_MODECNF0_RU_Fast << RADIO_MODECNF0_RU_Pos) & RADIO_MODECNF0_RU_Msk; +#endif /* Set logical address 1 for TX and RX */ NRF_RADIO->TXADDRESS = 0; @@ -1654,9 +1863,11 @@ ble_phy_init(void) #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; +#ifndef NRF54L_SERIES + NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); +#endif #if PHY_USE_HEADERMASK_WORKAROUND NVIC_SetVector(CCM_AAR_IRQn, (uint32_t)ble_phy_ccm_isr); @@ -1667,20 +1878,32 @@ ble_phy_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) g_ble_phy_data.phy_aar_scratch = 0; +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; +#else NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; +#endif nrf_aar_int_disable(NRF_AAR, 0xffffffff); NRF_AAR->EVENTS_END = 0; NRF_AAR->EVENTS_RESOLVED = 0; NRF_AAR->EVENTS_NOTRESOLVED = 0; +#ifdef NRF54L_SERIES + NRF_AAR->MAXRESOLVED = 0; +#else NRF_AAR->NIRK = 0; +#endif #endif /* TIMER0 setup for PHY when using RTC */ nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); +#ifndef NRF54L_SERIES NRF_TIMER0->TASKS_SHUTDOWN = 1; + NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ +#else + NRF_TIMER0->PRESCALER = 5; /* gives us 1 MHz */ +#endif NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ NRF_TIMER0->MODE = 0; /* Timer mode */ - NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ phy_ppi_init(); @@ -1741,7 +1964,7 @@ ble_phy_rx(void) */ nrf_wait_disabled(); if ((NRF_RADIO->STATE != RADIO_STATE_STATE_Disabled) && - ((NRF_RADIO->STATE & 0x07) != RADIO_STATE_STATE_RxIdle)) { + ((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; @@ -1764,11 +1987,19 @@ ble_phy_rx(void) void ble_phy_encrypt_enable(const uint8_t *key) { - memcpy(g_nrf_ccm_data.key, key, 16); - g_ble_phy_data.phy_encrypted = 1; NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Disabled; NRF_CCM->ENABLE = CCM_ENABLE_ENABLE_Enabled; -#ifdef NRF5340_XXAA + g_ble_phy_data.phy_encrypted = 1; + +#ifdef NRF54L_SERIES + NRF_CCM->KEY.VALUE[0] = get_be32(&key[12]); + NRF_CCM->KEY.VALUE[1] = get_be32(&key[8]); + NRF_CCM->KEY.VALUE[2] = get_be32(&key[4]); + NRF_CCM->KEY.VALUE[3] = get_be32(&key[0]); +#else + memcpy(g_nrf_ccm_data.key, key, 16); +#endif +#if defined(NRF5340_XXAA) || defined(NRF54L_SERIES) NRF_CCM->HEADERMASK = BLE_LL_PDU_HEADERMASK_DATA; #endif #if PHY_USE_HEADERMASK_WORKAROUND @@ -1779,7 +2010,7 @@ ble_phy_encrypt_enable(const uint8_t *key) void ble_phy_encrypt_header_mask_set(uint8_t mask) { -#ifdef NRF5340_XXAA +#if defined(NRF5340_XXAA) || defined(NRF54L_SERIES) NRF_CCM->HEADERMASK = mask; #endif #if PHY_USE_HEADERMASK_WORKAROUND @@ -1790,14 +2021,24 @@ ble_phy_encrypt_header_mask_set(uint8_t mask) void ble_phy_encrypt_iv_set(const uint8_t *iv) { +#ifdef NRF54L_SERIES + NRF_CCM->NONCE.VALUE[1] = get_be32(iv); + NRF_CCM->NONCE.VALUE[0] = get_be32(iv + 4); +#else memcpy(g_nrf_ccm_data.iv, iv, 8); +#endif } void ble_phy_encrypt_counter_set(uint64_t counter, uint8_t dir_bit) { +#ifdef NRF54L_SERIES + NRF_CCM->NONCE.VALUE[3] = ((uint8_t *)&counter)[0]; + NRF_CCM->NONCE.VALUE[2] = get_be32(&((uint8_t *)&counter)[1]) | ((!!dir_bit) << 7); +#else g_nrf_ccm_data.pkt_counter = counter; g_nrf_ccm_data.dir_bit = dir_bit; +#endif } void @@ -1958,6 +2199,12 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) 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]; +#ifdef NRF54L_SERIES + NRF_CCM->IN.PTR = (uint32_t)&g_ccm_job_list.in; + NRF_CCM->OUT.PTR = (uint32_t)&g_ccm_job_list.out; + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->MODE = CCM_MODE_MODE_Encryption | (CCM_MODE_MACLEN_M4 << CCM_MODE_MACLEN_Pos) | ble_phy_get_ccm_datarate(); +#else NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; NRF_CCM->INPTR = (uint32_t)dptr; NRF_CCM->OUTPTR = (uint32_t)pktptr; @@ -1965,9 +2212,14 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) 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; +#endif } else { #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) +#ifdef NRF54L_SERIES + NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; +#else NRF_AAR->IRKPTR = (uint32_t)&g_nrf_irk_list[0]; +#endif #endif dptr = (uint8_t *)&g_ble_phy_tx_buf[0]; pktptr = dptr; @@ -1997,7 +2249,65 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) NRF_CCM->INTENSET = CCM_INTENSET_ENDKSGEN_Msk; } #endif +#ifdef NRF54L_SERIES + /* AAD length */ + g_ccm_job_list.in_alen = 1; + g_ccm_job_list.in[0].p_buffer = (uint8_t *) &g_ccm_job_list.in_alen; + g_ccm_job_list.in[0].size = sizeof(g_ccm_job_list.in_alen); + g_ccm_job_list.in[0].attributes = 11; + + /* Unencrypted message length */ + g_ccm_job_list.in_mlen = payload_len; + g_ccm_job_list.in[1].p_buffer = (uint8_t *) &g_ccm_job_list.in_mlen; + g_ccm_job_list.in[1].size = sizeof(g_ccm_job_list.in_mlen); + g_ccm_job_list.in[1].attributes = 12; + + /* AAD */ + g_ccm_job_list.in[2].p_buffer = (uint8_t *) &dptr[0]; + g_ccm_job_list.in[2].size = 1; + g_ccm_job_list.in[2].attributes = 13; + + /* Unencrypted message */ + g_ccm_job_list.in[3].p_buffer = (uint8_t *) &dptr[3]; + g_ccm_job_list.in[3].size = payload_len; + g_ccm_job_list.in[3].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.in[4], 0, sizeof(g_ccm_job_list.in[4])); + + /* AAD length */ + g_ccm_job_list.out[0].p_buffer = (uint8_t *) &g_ccm_job_list.out_alen; + g_ccm_job_list.out[0].size = sizeof(g_ccm_job_list.out_alen); + g_ccm_job_list.out[0].attributes = 11; + + /* Encrypted message length LSB */ + g_ccm_job_list.out[1].p_buffer = (uint8_t *) &pktptr[1]; + g_ccm_job_list.out[1].size = 1; + g_ccm_job_list.out[1].attributes = 12; + + /* Encrypted message length MSB */ + g_ccm_job_list.out[2].p_buffer = (uint8_t *) &g_ccm_job_list.out_mlen_msb; + g_ccm_job_list.out[2].size = sizeof(g_ccm_job_list.out_mlen_msb); + g_ccm_job_list.out[2].attributes = 12; + + /* AAD */ + g_ccm_job_list.out[3].p_buffer = (uint8_t *) &pktptr[0]; + g_ccm_job_list.out[3].size = 1; + g_ccm_job_list.out[3].attributes = 13; + + /* Encrypted message */ + g_ccm_job_list.out[4].p_buffer = (uint8_t *) &pktptr[3]; + g_ccm_job_list.out[4].size = payload_len + 4; + g_ccm_job_list.out[4].attributes = 14; + + /* Job list terminator */ + memset(&g_ccm_job_list.out[5], 0, sizeof(g_ccm_job_list.out[5])); + + /* Start encryption */ + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_START); +#else nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_KSGEN); +#endif } #endif @@ -2005,11 +2315,17 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) /* Clear the ready, end and disabled events */ NRF_RADIO->EVENTS_READY = 0; + NRF_RADIO->EVENTS_ADDRESS = 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; + shortcuts = RADIO_SHORTS_READY_START_Msk; +#ifdef NRF54L_SERIES + shortcuts |= RADIO_SHORTS_PHYEND_DISABLE_Msk; +#else + shortcuts |= RADIO_SHORTS_END_DISABLE_Msk; +#endif NRF_RADIO->SHORTS = shortcuts; nrf_radio_int_enable(NRF_RADIO, RADIO_INTENSET_DISABLED_Msk); @@ -2157,7 +2473,12 @@ ble_phy_setchan(uint8_t chan, uint32_t access_addr, uint32_t 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]; + +#ifdef NRF54L_SERIES + NRF_RADIO->DATAWHITE = RADIO_DATAWHITE_ResetValue | chan; +#else NRF_RADIO->DATAWHITEIV = chan; +#endif return 0; } @@ -2175,8 +2496,12 @@ static void ble_phy_stop_usec_timer(void) { nrf_timer_task_trigger(NRF_TIMER0, NRF_TIMER_TASK_STOP); +#ifndef NRF54L_SERIES NRF_TIMER0->TASKS_SHUTDOWN = 1; +#endif +#ifndef GRTC_AS_RADIO_TIMER nrf_rtc_event_disable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); +#endif } /** @@ -2295,7 +2620,12 @@ ble_phy_max_data_pdu_pyld(void) void ble_phy_resolv_list_enable(void) { +#ifdef NRF54L_SERIES + /* TODO: Is this the right replacement? */ + NRF_AAR->MAXRESOLVED = (uint32_t)g_nrf_num_irks; +#else NRF_AAR->NIRK = (uint32_t)g_nrf_num_irks; +#endif g_ble_phy_data.phy_privacy = 1; } @@ -2348,6 +2678,9 @@ ble_phy_rfclk_enable(void) #ifdef NRF53_SERIES nrf5340_net_clock_hfxo_request(); #endif +#ifdef NRF54L_SERIES + nrf54l_clock_hfxo_request(); +#endif #else nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART); #endif @@ -2363,6 +2696,9 @@ ble_phy_rfclk_disable(void) #ifdef NRF53_SERIES nrf5340_net_clock_hfxo_release(); #endif +#ifdef NRF54L_SERIES + nrf54l_clock_hfxo_release(); +#endif #else nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP); #endif diff --git a/nimble/drivers/nrf5x/src/nrf54l/phy.c b/nimble/drivers/nrf5x/src/nrf54l/phy.c new file mode 100644 index 0000000000..e3804de68c --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l/phy.c @@ -0,0 +1,248 @@ +/* + * 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 +#include +#include + +#include +#include +#include +#include "phy_priv.h" + +#if PHY_USE_DEBUG +void +phy_debug_init(void) +{ +#if PHY_USE_DEBUG_1 + nrf_gpio_cfg_output(MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN)); + nrf_gpiote_task_configure(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_1, + MYNEWT_VAL(BLE_PHY_DBG_TIME_TXRXEN_READY_PIN), + NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_1); + + PPIB_RADIO_PERI_0(TIMER0_EVENTS_COMPARE_0, GPIOTE20_TASKS_SET_0); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_0); + + NRF_RADIO->PUBLISH_READY = DPPI_CH_PUB(RADIO_EVENTS_READY); + PPIB_RADIO_PERI_1(RADIO_EVENTS_READY, GPIOTE20_TASKS_CLR_0); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_1] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_0); +#endif + +#if PHY_USE_DEBUG_2 + nrf_gpio_cfg_output(MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN)); + nrf_gpiote_task_configure(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_2, + MYNEWT_VAL(BLE_PHY_DBG_TIME_ADDRESS_END_PIN), + NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_2); + + PPIB_RADIO_PERI_2(RADIO_EVENTS_ADDRESS, GPIOTE20_TASKS_SET_1); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_1); + + PPIB_RADIO_PERI_3(RADIO_EVENTS_END, GPIOTE20_TASKS_CLR_1); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_2] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_1); +#endif + +#if PHY_USE_DEBUG_3 + nrf_gpio_cfg_output(MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN)); + nrf_gpiote_task_configure(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_3, + MYNEWT_VAL(BLE_PHY_DBG_TIME_WFR_PIN), + NRF_GPIOTE_POLARITY_NONE, + NRF_GPIOTE_INITIAL_VALUE_LOW); + nrf_gpiote_task_enable(NRF_GPIOTE20, PHY_GPIOTE_DEBUG_3); + + NRF_RADIO->PUBLISH_RXREADY = DPPI_CH_PUB(RADIO_EVENTS_RXREADY); + PPIB_RADIO_PERI_4(RADIO_EVENTS_RXREADY, GPIOTE20_TASKS_SET_2); + NRF_GPIOTE20->SUBSCRIBE_SET[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(GPIOTE20_TASKS_SET_2); + + PPIB_RADIO_PERI_5(RADIO_EVENTS_DISABLED, GPIOTE20_TASKS_CLR_2); + NRF_GPIOTE20->SUBSCRIBE_CLR[PHY_GPIOTE_DEBUG_3] = DPPI_CH_SUB(GPIOTE20_TASKS_CLR_2); +#endif +} +#endif /* PHY_USE_DEBUG */ + +void +phy_ppi_init(void) +{ + NRF_RADIO->PUBLISH_ADDRESS = DPPI_CH_PUB(RADIO_EVENTS_ADDRESS); + NRF_RADIO->PUBLISH_END = DPPI_CH_PUB(RADIO_EVENTS_END); + NRF_RADIO->PUBLISH_PAYLOAD = DPPI_CH_PUB(RADIO_EVENTS_PAYLOAD_RADIO); + NRF_RADIO->PUBLISH_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); +#ifdef GRTC_AS_RADIO_TIMER + NRF_GRTC->PUBLISH_COMPARE[3] = DPPI_CH_PUB(DPPI20_GRTC_EVENTS_COMPARE_3); + PPIB_PERI_RADIO_0(DPPI20_GRTC_EVENTS_COMPARE_3, RTC0_EVENTS_COMPARE_0); +#else + NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); +#endif + + 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_TIMER0->SUBSCRIBE_CAPTURE[1] = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + NRF_TIMER0->SUBSCRIBE_CAPTURE[2] = DPPI_CH_SUB(RADIO_EVENTS_END); + + PPIB_RADIO_MCU_0(RADIO_EVENTS_PAYLOAD_RADIO, DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); + + /* Enable channels we publish on */ + NRF_DPPIC10->CHENSET = DPPI_CH_ENABLE_ALL; +} + +void +phy_txpower_set(int8_t dbm) +{ + uint16_t val; + + switch (dbm) { + case 8: + val = RADIO_TXPOWER_TXPOWER_Pos8dBm; + break; + case 7: + val = RADIO_TXPOWER_TXPOWER_Pos7dBm; + break; + case 6: + val = RADIO_TXPOWER_TXPOWER_Pos6dBm; + break; + case 5: + val = RADIO_TXPOWER_TXPOWER_Pos5dBm; + break; + case 4: + val = RADIO_TXPOWER_TXPOWER_Pos4dBm; + break; + case 3: + val = RADIO_TXPOWER_TXPOWER_Pos3dBm; + break; + case 2: + val = RADIO_TXPOWER_TXPOWER_Pos2dBm; + break; + case 1: + val = RADIO_TXPOWER_TXPOWER_Pos1dBm; + break; + case 0: + val = RADIO_TXPOWER_TXPOWER_0dBm; + break; + case -1: + val = RADIO_TXPOWER_TXPOWER_Neg1dBm; + break; + case -2: + val = RADIO_TXPOWER_TXPOWER_Neg2dBm; + break; + case -3: + val = RADIO_TXPOWER_TXPOWER_Neg3dBm; + break; + case -4: + val = RADIO_TXPOWER_TXPOWER_Neg4dBm; + break; + case -5: + val = RADIO_TXPOWER_TXPOWER_Neg5dBm; + break; + case -6: + val = RADIO_TXPOWER_TXPOWER_Neg6dBm; + break; + case -7: + val = RADIO_TXPOWER_TXPOWER_Neg7dBm; + break; + case -8: + val = RADIO_TXPOWER_TXPOWER_Neg8dBm; + break; + case -9: + val = RADIO_TXPOWER_TXPOWER_Neg9dBm; + break; + case -10: + val = RADIO_TXPOWER_TXPOWER_Neg10dBm; + break; + case -12: + val = RADIO_TXPOWER_TXPOWER_Neg12dBm; + break; + case -14: + val = RADIO_TXPOWER_TXPOWER_Neg14dBm; + break; + case -16: + val = RADIO_TXPOWER_TXPOWER_Neg16dBm; + break; + case -18: + val = RADIO_TXPOWER_TXPOWER_Neg18dBm; + break; + case -20: + val = RADIO_TXPOWER_TXPOWER_Neg20dBm; + break; + case -22: + val = RADIO_TXPOWER_TXPOWER_Neg22dBm; + break; + case -28: + val = RADIO_TXPOWER_TXPOWER_Neg28dBm; + break; + case -40: + val = RADIO_TXPOWER_TXPOWER_Neg40dBm; + break; + case -46: + val = RADIO_TXPOWER_TXPOWER_Neg46dBm; + break; + default: + val = RADIO_TXPOWER_TXPOWER_0dBm; + } + + NRF_RADIO->TXPOWER = val; +} + +int8_t +phy_txpower_round(int8_t dbm) +{ + if (dbm >= (int8_t)8) { + return (int8_t)8; + } + + if (dbm >= (int8_t)-10) { + return (int8_t)dbm; + } + + if (dbm >= (int8_t)-12) { + return (int8_t)-12; + } + + if (dbm >= (int8_t)-14) { + return (int8_t)-14; + } + + if (dbm >= (int8_t)-16) { + return (int8_t)-16; + } + + if (dbm >= (int8_t)-18) { + return (int8_t)-18; + } + + if (dbm >= (int8_t)-20) { + return (int8_t)-20; + } + + if (dbm >= (int8_t)-22) { + return (int8_t)-22; + } + + if (dbm >= (int8_t)-28) { + return (int8_t)-28; + } + + if (dbm >= (int8_t)-40) { + return (int8_t)-40; + } + + return (int8_t)-46; +} diff --git a/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h new file mode 100644 index 0000000000..7f6fdae47c --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h @@ -0,0 +1,202 @@ +/* + * 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)) + +/* DPPIC00 [0:7] */ +#define DPPI_CH_DPPIC00_RADIO_EVENTS_PAYLOAD_CCM 0 + +/* DPPIC10 [0:23] */ +#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_RADIO_EVENTS_PAYLOAD_RADIO 10 + +/* DPPIC20 [0:15] */ +#define DPPI_CH_GPIOTE20_TASKS_SET_0 0 +#define DPPI_CH_GPIOTE20_TASKS_CLR_0 1 +#define DPPI_CH_GPIOTE20_TASKS_SET_1 2 +#define DPPI_CH_GPIOTE20_TASKS_CLR_1 3 +#define DPPI_CH_GPIOTE20_TASKS_SET_2 4 +#define DPPI_CH_GPIOTE20_TASKS_CLR_2 5 +#define DPPI_CH_DPPI20_GRTC_EVENTS_COMPARE_3 6 + +#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 | \ + DPPIC_CHEN_CH10_Msk) + +#define DPPI_CH_MASK_FEM (DPPI_CH_MASK(TIMER0_EVENTS_COMPARE_2) | \ + DPPI_CH_MASK(RADIO_EVENTS_DISABLED)) + +/* Create PPIB links between RADIO and PERI power domain. */ +#define PPIB_RADIO_PERI(_ch, _src, _dst) \ + NRF_PPIB11->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB21->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC10->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC20->CHENSET |= 1 << DPPI_CH_ ## _dst; + +#define PPIB_RADIO_PERI_0(_src, _dst) PPIB_RADIO_PERI(0, _src, _dst) +#define PPIB_RADIO_PERI_1(_src, _dst) PPIB_RADIO_PERI(1, _src, _dst) +#define PPIB_RADIO_PERI_2(_src, _dst) PPIB_RADIO_PERI(2, _src, _dst) +#define PPIB_RADIO_PERI_3(_src, _dst) PPIB_RADIO_PERI(3, _src, _dst) +#define PPIB_RADIO_PERI_4(_src, _dst) PPIB_RADIO_PERI(4, _src, _dst) +#define PPIB_RADIO_PERI_5(_src, _dst) PPIB_RADIO_PERI(5, _src, _dst) + +/* Create PPIB links between PERI and RADIO power domain. */ +#define PPIB_PERI_RADIO(_ch, _src, _dst) \ + NRF_PPIB21->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB11->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC20->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC10->CHENSET |= 1 << DPPI_CH_ ## _dst; + +#define PPIB_PERI_RADIO_0(_src, _dst) PPIB_PERI_RADIO(0, _src, _dst) + +/* Create PPIB link from RADIO to MCU power domain. */ +#define PPIB_RADIO_MCU(_ch, _src, _dst) \ + NRF_PPIB10->SUBSCRIBE_SEND[_ch] = DPPI_CH_SUB(_src); \ + NRF_PPIB00->PUBLISH_RECEIVE[_ch] = DPPI_CH_PUB(_dst); \ + NRF_DPPIC10->CHENSET |= 1 << DPPI_CH_ ## _src; \ + NRF_DPPIC00->CHENSET |= 1 << DPPI_CH_ ## _dst; + +#define PPIB_RADIO_MCU_0(_src, _dst) PPIB_RADIO_MCU(0, _src, _dst) + +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_START = DPPI_CH_SUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); +} + +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_RADIO->SUBSCRIBE_START = DPPI_CH_UNSUB(TIMER0_EVENTS_COMPARE_0); + NRF_AAR->SUBSCRIBE_START = DPPI_CH_UNSUB(RADIO_EVENTS_BCMATCH); + NRF_CCM->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); + + phy_ppi_fem_disable(); +} + +#endif /* H_PHY_PPI_ */ diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h index db0664da2b..39fcf8be4e 100644 --- a/nimble/drivers/nrf5x/src/phy_priv.h +++ b/nimble/drivers/nrf5x/src/phy_priv.h @@ -53,6 +53,7 @@ #define PHY_GPIOTE_FEM_LNA (PHY_GPIOTE_FEM_PA - PHY_USE_FEM_LNA) #endif +#ifndef NRF54L_SERIES static inline void phy_gpiote_configure(int idx, int pin) { @@ -61,6 +62,7 @@ phy_gpiote_configure(int idx, int pin) NRF_GPIOTE_INITIAL_VALUE_LOW); nrf_gpiote_task_enable(NRF_GPIOTE, idx); } +#endif #if PHY_USE_DEBUG void phy_debug_init(void); @@ -92,5 +94,57 @@ int8_t phy_txpower_round(int8_t dbm); #ifdef NRF53_SERIES #include "nrf53/phy_ppi.h" #endif +#ifdef NRF54L_SERIES +#define NRF_TIMER0 NRF_TIMER10 +#define TIMER0_IRQn TIMER10_IRQn +#define NRF_DPPIC NRF_DPPIC10 +#define NRF_RTC0 NRF_RTC10 +#define NRF_AAR NRF_AAR00 +#define NRF_CCM NRF_CCM00 +#define NRF_AAR NRF_AAR00 +#define NRF_GPIOTE NRF_GPIOTE20 +#define RADIO_IRQn RADIO_0_IRQn +#define RADIO_INTENCLR_ADDRESS_Msk RADIO_INTENCLR00_ADDRESS_Msk +#define RADIO_INTENSET_DISABLED_Msk RADIO_INTENSET00_DISABLED_Msk +#define RADIO_INTENCLR_DISABLED_Msk RADIO_INTENCLR00_DISABLED_Msk +#define RADIO_INTENSET_END_Msk RADIO_INTENSET00_END_Msk +#define RADIO_INTENCLR_END_Msk RADIO_INTENCLR00_END_Msk +#define RADIO_INTENCLR_PHYEND_Msk RADIO_INTENCLR00_PHYEND_Msk +#define RADIO_INTENSET_ADDRESS_Msk RADIO_INTENSET00_ADDRESS_Msk +#define RADIO_INTENSET_READY_Msk RADIO_INTENSET00_READY_Msk +#include "nrf54l/phy_ppi.h" + +#define GRTC_AS_RADIO_TIMER + +#ifdef GRTC_AS_RADIO_TIMER +#include + +static inline uint64_t +grtc_counter_get(void) +{ + uint32_t counterl_val, counterh_val, counterh; + uint64_t counter; + + nrf_grtc_sys_counter_active_set(NRF_GRTC, true); + do { + counterl_val = nrf_grtc_sys_counter_low_get(NRF_GRTC); + counterh = nrf_grtc_sys_counter_high_get(NRF_GRTC); + } while (counterh & NRF_GRTC_SYSCOUNTERH_BUSY_MASK); + + do { + counterl_val = nrf_grtc_sys_counter_low_get(NRF_GRTC); + counterh = nrf_grtc_sys_counter_high_get(NRF_GRTC); + counterh_val = counterh & NRF_GRTC_SYSCOUNTERH_VALUE_MASK; + } while (counterh & NRF_GRTC_SYSCOUNTERH_BUSY_MASK); + + if (counterh & NRF_GRTC_SYSCOUNTERH_OVERFLOW_MASK) { + --counterh_val; + } + + counter = ((uint64_t)counterh_val << 32) | counterl_val; + return counter; +} +#endif +#endif #endif /* H_PHY_PRIV_ */