From 856ab5eecada9c92dd23daca1865b41a68b93d6c Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 7 Jan 2025 11:17:59 +0100 Subject: [PATCH 1/3] nimble/phy: Add initial support for nRF54L15 PHY --- nimble/drivers/nrf5x/pkg.yml | 17 +- nimble/drivers/nrf5x/src/ble_hw.c | 133 +++++++++++- nimble/drivers/nrf5x/src/ble_phy.c | 182 +++++++++++++++- nimble/drivers/nrf5x/src/nrf54l/phy.c | 240 ++++++++++++++++++++++ nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h | 178 ++++++++++++++++ nimble/drivers/nrf5x/src/phy_priv.h | 22 ++ 6 files changed, 754 insertions(+), 18 deletions(-) create mode 100644 nimble/drivers/nrf5x/src/nrf54l/phy.c create mode 100644 nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h 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..96b1bb4133 100644 --- a/nimble/drivers/nrf5x/src/ble_hw.c +++ b/nimble/drivers/nrf5x/src/ble_hw.c @@ -36,9 +36,27 @@ #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 + +/* ECB data structure */ +struct ecb_job_entry { + uint8_t *ptr; + uint32_t attr_and_length; +}; + +static struct ecb_job_entry ecb_input_job_list[2]; +static struct ecb_job_entry ecb_output_job_list[2]; +#endif + /* Total number of resolving list elements */ #define BLE_HW_RESOLV_LIST_SIZE (16) @@ -276,6 +294,43 @@ 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); + + ecb_input_job_list[0].ptr = ecb->plain_text; + ecb_input_job_list[0].attr_and_length = (11 << 24) | (16 & 0x00ffffff); + ecb_output_job_list[0].ptr = ecb->cipher_text; + ecb_output_job_list[0].attr_and_length = (11 << 24) | (16 & 0x00ffffff); + + /* The end of a job list shall be 0 */ + ecb_input_job_list[1].ptr = 0; + ecb_input_job_list[1].attr_and_length = 0; + ecb_output_job_list[1].ptr = 0; + ecb_output_job_list[1].attr_and_length = 0; + + NRF_ECB->EVENTS_END = 0; + NRF_ECB->EVENTS_ERROR = 0; + NRF_ECB->IN.PTR = (uint32_t)ecb_input_job_list; + NRF_ECB->OUT.PTR = (uint32_t)ecb_output_job_list; + memcpy((void *)NRF_ECB->KEY.VALUE, ecb->key, sizeof(uint32_t) * 4); + + /* 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 +356,7 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) tm_tick(); #endif } - +#endif return rc; } @@ -314,7 +369,25 @@ ble_rng_isr(void) uint8_t rnum; os_trace_isr_enter(); +#ifdef NRF54L_SERIES + /* 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 +403,7 @@ ble_rng_isr(void) rnum = (uint8_t)NRF_RNG->VALUE; (*g_ble_rng_isr_cb)(rnum); } - +#endif os_trace_isr_exit(); } @@ -345,6 +418,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 +456,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 +473,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 +507,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 +530,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 +634,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..4d5092c2c4 100644 --- a/nimble/drivers/nrf5x/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -103,8 +103,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 +134,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 +236,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] = { @@ -948,9 +997,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 } @@ -976,6 +1033,19 @@ ble_phy_rx_xcvr_setup(void) #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]; +#ifdef NRF54L_SERIES + NRF_CCM->IN.PTR = (uint32_t)&g_ble_phy_enc_buf[0]; + NRF_CCM->OUT.PTR = (uint32_t)dptr; + /* TODO: Find replacement for removed registers like this one + * NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; + */ + NRF_CCM->MODE = CCM_MODE_MACLEN_Pos | CCM_MODE_MODE_Decryption | + ble_phy_get_ccm_datarate(); + memcpy((uint8_t *)NRF_CCM->KEY.VALUE, &g_nrf_ccm_data.key, sizeof(g_nrf_ccm_data.key)); + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->EVENTS_END = 0; + nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_START); +#else 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]; @@ -986,6 +1056,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 +1068,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: 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; @@ -1037,16 +1113,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 +1268,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 +1323,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]; @@ -1255,12 +1340,21 @@ ble_phy_rx_end_isr(void) 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) { +#ifdef NRF54L_SERIES + while (NRF_CCM->EVENTS_END == 0) { +#else while (NRF_CCM->EVENTS_ENDCRYPT == 0) { +#endif /* Make sure CCM finished */ }; /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { + if ((dptr[1] != 0) && +#ifdef NRF54L_SERIES + (NRF_CCM->MACSTATUS == 0)) { +#else + (NRF_CCM->MICSTATUS == 0)) { +#endif ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; } @@ -1453,7 +1547,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; @@ -1490,7 +1588,11 @@ ble_phy_isr(void) os_trace_isr_enter(); /* Read irq register to determine which interrupts are enabled */ +#ifdef NRF54L_SERIES + irq_en = NRF_RADIO->INTENSET00; +#else irq_en = NRF_RADIO->INTENSET; +#endif /* * NOTE: order of checking is important! Possible, if things get delayed, @@ -1597,9 +1699,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 +1740,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,7 +1763,9 @@ ble_phy_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) nrf_ccm_int_disable(NRF_CCM, 0xffffffff); +#ifndef NRF54L_SERIES NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; +#endif NRF_CCM->EVENTS_ERROR = 0; memset(g_nrf_encrypt_scratchpad, 0, sizeof(g_nrf_encrypt_scratchpad)); @@ -1667,20 +1778,34 @@ 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; +#endif NRF_TIMER0->BITMODE = 3; /* 32-bit timer */ NRF_TIMER0->MODE = 0; /* Timer mode */ +#ifdef NRF54L_SERIES + NRF_TIMER0->PRESCALER = 5; /* gives us 1 MHz */ +#else NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ +#endif phy_ppi_init(); @@ -1741,7 +1866,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; @@ -1958,6 +2083,14 @@ 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)dptr; + NRF_CCM->OUT.PTR = (uint32_t)pktptr; + /* NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; */ + NRF_CCM->EVENTS_ERROR = 0; + NRF_CCM->MODE = CCM_MODE_MACLEN_Pos | ble_phy_get_ccm_datarate(); + memcpy((uint8_t *)NRF_CCM->KEY.VALUE, &g_nrf_ccm_data.key, sizeof(g_nrf_ccm_data.key)); +#else NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; NRF_CCM->INPTR = (uint32_t)dptr; NRF_CCM->OUTPTR = (uint32_t)pktptr; @@ -1965,9 +2098,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 +2135,11 @@ 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 + 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 +2147,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 +2305,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,7 +2328,9 @@ 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 nrf_rtc_event_disable(NRF_RTC0, RTC_EVTENSET_COMPARE0_Msk); } @@ -2295,7 +2450,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; } diff --git a/nimble/drivers/nrf5x/src/nrf54l/phy.c b/nimble/drivers/nrf5x/src/nrf54l/phy.c new file mode 100644 index 0000000000..b06fb72dcf --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l/phy.c @@ -0,0 +1,240 @@ +/* + * 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_BCMATCH = DPPI_CH_PUB(RADIO_EVENTS_BCMATCH); + NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); + + 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); + + /* 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..5f9772b905 --- /dev/null +++ b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h @@ -0,0 +1,178 @@ +/* + * 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)) + +/* 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 + +/* 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_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)) + +/* 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) + +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(RADIO_EVENTS_ADDRESS); +} + +static inline void +phy_ppi_radio_address_to_ccm_crypt_disable(void) +{ + NRF_CCM->SUBSCRIBE_START = 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_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(RADIO_EVENTS_ADDRESS); + + 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..ead8bf05f4 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,25 @@ 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" +#endif #endif /* H_PHY_PRIV_ */ From dd08228c636b7e5c91daa411ca97984afce666cb Mon Sep 17 00:00:00 2001 From: Michal Gorecki Date: Tue, 21 Jan 2025 16:04:19 +0100 Subject: [PATCH 2/3] nimble/phy: Add an initial encryption for nRF54L15 --- nimble/drivers/nrf5x/src/ble_hw.c | 40 ++-- nimble/drivers/nrf5x/src/ble_phy.c | 221 ++++++++++++++++++---- nimble/drivers/nrf5x/src/nrf54l/phy.c | 3 + nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h | 22 ++- 4 files changed, 223 insertions(+), 63 deletions(-) diff --git a/nimble/drivers/nrf5x/src/ble_hw.c b/nimble/drivers/nrf5x/src/ble_hw.c index 96b1bb4133..44b566af1a 100644 --- a/nimble/drivers/nrf5x/src/ble_hw.c +++ b/nimble/drivers/nrf5x/src/ble_hw.c @@ -47,14 +47,12 @@ #define NRF_ECB NRF_ECB00 #define NRF_AAR NRF_AAR00 -/* ECB data structure */ -struct ecb_job_entry { - uint8_t *ptr; - uint32_t attr_and_length; +struct nrf_ecb_job_list { + nrf_vdma_job_t in[2]; + nrf_vdma_job_t out[2]; }; -static struct ecb_job_entry ecb_input_job_list[2]; -static struct ecb_job_entry ecb_output_job_list[2]; +static struct nrf_ecb_job_list g_ecb_job_list; #endif /* Total number of resolving list elements */ @@ -298,22 +296,26 @@ ble_hw_encrypt_block(struct ble_encryption_block *ecb) /* Stop ECB */ nrf_ecb_task_trigger(NRF_ECB, NRF_ECB_TASK_STOP); - ecb_input_job_list[0].ptr = ecb->plain_text; - ecb_input_job_list[0].attr_and_length = (11 << 24) | (16 & 0x00ffffff); - ecb_output_job_list[0].ptr = ecb->cipher_text; - ecb_output_job_list[0].attr_and_length = (11 << 24) | (16 & 0x00ffffff); + /* 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])); - /* The end of a job list shall be 0 */ - ecb_input_job_list[1].ptr = 0; - ecb_input_job_list[1].attr_and_length = 0; - ecb_output_job_list[1].ptr = 0; - ecb_output_job_list[1].attr_and_length = 0; + 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)ecb_input_job_list; - NRF_ECB->OUT.PTR = (uint32_t)ecb_output_job_list; - memcpy((void *)NRF_ECB->KEY.VALUE, ecb->key, sizeof(uint32_t) * 4); + 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); @@ -370,6 +372,8 @@ ble_rng_isr(void) 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); diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c index 4d5092c2c4..7215392731 100644 --- a/nimble/drivers/nrf5x/src/ble_phy.c +++ b/nimble/drivers/nrf5x/src/ble_phy.c @@ -45,6 +45,9 @@ #ifdef NRF53_SERIES #include #endif +#ifdef NRF54L_SERIES +#include +#endif #include "mcu/cmsis_nvic.h" #include "hal/hal_gpio.h" #else @@ -68,6 +71,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 @@ -374,7 +384,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 @@ -397,6 +419,7 @@ struct nrf_ccm_data struct nrf_ccm_data g_nrf_ccm_data; #endif +#endif static void timer0_reset(void) @@ -1032,20 +1055,75 @@ ble_phy_rx_xcvr_setup(void) #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]; #ifdef NRF54L_SERIES - NRF_CCM->IN.PTR = (uint32_t)&g_ble_phy_enc_buf[0]; - NRF_CCM->OUT.PTR = (uint32_t)dptr; - /* TODO: Find replacement for removed registers like this one - * NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; - */ - NRF_CCM->MODE = CCM_MODE_MACLEN_Pos | CCM_MODE_MODE_Decryption | + /* 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(); - memcpy((uint8_t *)NRF_CCM->KEY.VALUE, &g_nrf_ccm_data.key, sizeof(g_nrf_ccm_data.key)); + NRF_CCM->EVENTS_ERROR = 0; NRF_CCM->EVENTS_END = 0; - nrf_ccm_task_trigger(NRF_CCM, NRF_CCM_TASK_START); #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; NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[0]; @@ -1070,7 +1148,7 @@ ble_phy_rx_xcvr_setup(void) NRF_AAR->ENABLE = AAR_ENABLE_ENABLE_Enabled; #ifdef NRF54L_SERIES NRF_AAR->IN.PTR = (uint32_t)&g_nrf_irk_list[0]; - /* TODO: Find replacement for NRF_AAR->SCRATCHPTR */ + /* 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; @@ -1087,7 +1165,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; @@ -1340,21 +1418,12 @@ ble_phy_rx_end_isr(void) 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) { -#ifdef NRF54L_SERIES - while (NRF_CCM->EVENTS_END == 0) { -#else while (NRF_CCM->EVENTS_ENDCRYPT == 0) { -#endif /* Make sure CCM finished */ }; /* Only set MIC failure flag if frame is not zero length */ - if ((dptr[1] != 0) && -#ifdef NRF54L_SERIES - (NRF_CCM->MACSTATUS == 0)) { -#else - (NRF_CCM->MICSTATUS == 0)) { -#endif + if ((dptr[1] != 0) && (NRF_CCM->MICSTATUS == 0)) { ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_MIC_FAILURE; } @@ -1588,11 +1657,7 @@ ble_phy_isr(void) os_trace_isr_enter(); /* Read irq register to determine which interrupts are enabled */ -#ifdef NRF54L_SERIES - irq_en = NRF_RADIO->INTENSET00; -#else irq_en = NRF_RADIO->INTENSET; -#endif /* * NOTE: order of checking is important! Possible, if things get delayed, @@ -1763,11 +1828,11 @@ ble_phy_init(void) #if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION) nrf_ccm_int_disable(NRF_CCM, 0xffffffff); + NRF_CCM->EVENTS_ERROR = 0; #ifndef NRF54L_SERIES NRF_CCM->SHORTS = CCM_SHORTS_ENDKSGEN_CRYPT_Msk; -#endif - NRF_CCM->EVENTS_ERROR = 0; 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); @@ -1798,14 +1863,12 @@ ble_phy_init(void) 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 */ -#ifdef NRF54L_SERIES - NRF_TIMER0->PRESCALER = 5; /* gives us 1 MHz */ -#else - NRF_TIMER0->PRESCALER = 4; /* gives us 1 MHz */ -#endif phy_ppi_init(); @@ -1889,11 +1952,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 @@ -1904,7 +1975,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 @@ -1915,14 +1986,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 @@ -2084,12 +2165,10 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) 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)dptr; - NRF_CCM->OUT.PTR = (uint32_t)pktptr; - /* NRF_CCM->SCRATCHPTR = (uint32_t)&g_nrf_encrypt_scratchpad[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->EVENTS_ERROR = 0; - NRF_CCM->MODE = CCM_MODE_MACLEN_Pos | ble_phy_get_ccm_datarate(); - memcpy((uint8_t *)NRF_CCM->KEY.VALUE, &g_nrf_ccm_data.key, sizeof(g_nrf_ccm_data.key)); + 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; @@ -2136,6 +2215,60 @@ ble_phy_tx(ble_phy_tx_pducb_t pducb, void *pducb_arg, uint8_t end_trans) } #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); @@ -2508,6 +2641,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 @@ -2523,6 +2659,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 index b06fb72dcf..88051f16a9 100644 --- a/nimble/drivers/nrf5x/src/nrf54l/phy.c +++ b/nimble/drivers/nrf5x/src/nrf54l/phy.c @@ -84,6 +84,7 @@ 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); NRF_RTC0->PUBLISH_COMPARE[0] = DPPI_CH_PUB(RTC0_EVENTS_COMPARE_0); @@ -92,6 +93,8 @@ phy_ppi_init(void) 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; } diff --git a/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h index 5f9772b905..a624a95534 100644 --- a/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h +++ b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h @@ -25,6 +25,9 @@ #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 @@ -36,6 +39,7 @@ #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 @@ -47,7 +51,8 @@ #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_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)) @@ -66,6 +71,15 @@ #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 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) { @@ -107,13 +121,13 @@ phy_ppi_timer0_compare0_to_radio_rxen_disable(void) static inline void phy_ppi_radio_address_to_ccm_crypt_enable(void) { - NRF_CCM->SUBSCRIBE_START = DPPI_CH_SUB(RADIO_EVENTS_ADDRESS); + 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(RADIO_EVENTS_ADDRESS); + NRF_CCM->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); } static inline void @@ -170,7 +184,7 @@ phy_ppi_disable(void) 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(RADIO_EVENTS_ADDRESS); + NRF_CCM->SUBSCRIBE_START = DPPI_CH_UNSUB(DPPIC00_RADIO_EVENTS_PAYLOAD_CCM); phy_ppi_fem_disable(); } From 6b37cdc84c0f09173e939407dbfd37c24211707e Mon Sep 17 00:00:00 2001 From: Magdalena Kasenberg Date: Tue, 12 May 2026 20:14:57 +0200 Subject: [PATCH 3/3] nimble/phy: Add support for using GRTC of nRF54L15 In latest nrfx versions the support for RTCx for nRF54L15 has been removed and the GRTC should be used instead. The GRTC SYSCOUNTER has a resolution of 1us, so then optimal cputime freq would be equal to 31250Hz to ensure smooth calculations, but since the LL timing is tuned for 32768Hz, let's simulate the 32768Hz for now. --- nimble/drivers/nrf5x/src/ble_phy.c | 37 +++++++++++++++++++++++ nimble/drivers/nrf5x/src/nrf54l/phy.c | 5 +++ nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h | 10 ++++++ nimble/drivers/nrf5x/src/phy_priv.h | 32 ++++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/nimble/drivers/nrf5x/src/ble_phy.c b/nimble/drivers/nrf5x/src/ble_phy.c index 7215392731..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" @@ -421,6 +424,10 @@ 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) { @@ -722,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; @@ -792,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)) { @@ -817,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 @@ -848,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 @@ -885,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 @@ -895,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(); @@ -2464,7 +2499,9 @@ ble_phy_stop_usec_timer(void) #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 } /** diff --git a/nimble/drivers/nrf5x/src/nrf54l/phy.c b/nimble/drivers/nrf5x/src/nrf54l/phy.c index 88051f16a9..e3804de68c 100644 --- a/nimble/drivers/nrf5x/src/nrf54l/phy.c +++ b/nimble/drivers/nrf5x/src/nrf54l/phy.c @@ -86,7 +86,12 @@ phy_ppi_init(void) 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); diff --git a/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h index a624a95534..7f6fdae47c 100644 --- a/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h +++ b/nimble/drivers/nrf5x/src/nrf54l/phy_ppi.h @@ -48,6 +48,7 @@ #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 | \ @@ -71,6 +72,15 @@ #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); \ diff --git a/nimble/drivers/nrf5x/src/phy_priv.h b/nimble/drivers/nrf5x/src/phy_priv.h index ead8bf05f4..39fcf8be4e 100644 --- a/nimble/drivers/nrf5x/src/phy_priv.h +++ b/nimble/drivers/nrf5x/src/phy_priv.h @@ -113,6 +113,38 @@ int8_t phy_txpower_round(int8_t dbm); #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_ */