You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2022/07/29 15:11:40 UTC
[incubator-nuttx] 02/02: stm32wl5: add lower half driver for IPCC
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit e887a4a5b750386b3c7e97f8b62137825d9d283e
Author: Michał Łyszczek <mi...@bofc.pl>
AuthorDate: Tue Jul 5 14:20:53 2022 +0200
stm32wl5: add lower half driver for IPCC
Signed-off-by: Michał Łyszczek <mi...@bofc.pl>
---
arch/arm/src/stm32wl5/Kconfig | 106 ++++
arch/arm/src/stm32wl5/Make.defs | 4 +
arch/arm/src/stm32wl5/hardware/stm32wl5_ipcc.h | 79 +++
arch/arm/src/stm32wl5/stm32wl5_allocateheap.c | 7 +-
arch/arm/src/stm32wl5/stm32wl5_ipcc.c | 812 +++++++++++++++++++++++++
arch/arm/src/stm32wl5/stm32wl5_ipcc.h | 145 +++++
arch/arm/src/stm32wl5/stm32wl5_rcc.c | 6 +
7 files changed, 1158 insertions(+), 1 deletion(-)
diff --git a/arch/arm/src/stm32wl5/Kconfig b/arch/arm/src/stm32wl5/Kconfig
index 6e26709bf1..99e5a6cd68 100644
--- a/arch/arm/src/stm32wl5/Kconfig
+++ b/arch/arm/src/stm32wl5/Kconfig
@@ -201,6 +201,17 @@ config STM32WL5_SPI1
depends on STM32WL5_HAVE_SPI1
select STM32WL5_SPI
+comment "AHB3 Peripherals"
+
+config STM32WL5_IPCC
+ bool "IPCC"
+ select IPCC
+ default n
+ ---help---
+ IPCC - Inter Processor Communication Controller. A very simple
+ character device stream driver to exchange data between
+ CM0 and CM4.
+
endmenu # STM32WL5 Peripheral Support
@@ -300,4 +311,99 @@ config STM32WL5_SPI2S2_DMA_BUFFER
endmenu # SPI Configuration
+menu "IPCC Configuration"
+ depends on STM32WL5_IPCC
+
+config STM32WL5_IPCC_CHAN1_RX_SIZE
+ int "Channel 1 RX size"
+ default 256
+ ---help---
+ Size of the receive buffer. Another CPU will write to this
+ buffer and currently running CPU will read from it.
+
+config STM32WL5_IPCC_CHAN1_TX_SIZE
+ int "Channel 1 TX size"
+ default 256
+ ---help---
+ Size of the send buffer. Another CPU will read from this
+ buffer and currently running CPU will write to it.
+
+config STM32WL5_IPCC_CHAN2
+ bool "Enable channel 2"
+ default n
+
+if STM32WL5_IPCC_CHAN2
+
+config STM32WL5_IPCC_CHAN2_RX_SIZE
+ int "Channel 2 RX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN2_TX_SIZE
+ int "Channel 2 TX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN3
+ bool "Enable channel 3"
+ default n
+
+if STM32WL5_IPCC_CHAN3
+
+config STM32WL5_IPCC_CHAN3_RX_SIZE
+ int "Channel 3 RX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN3_TX_SIZE
+ int "Channel 3 TX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN4
+ bool "Enable channel 4"
+ default n
+
+if STM32WL5_IPCC_CHAN4
+
+config STM32WL5_IPCC_CHAN4_RX_SIZE
+ int "Channel 4 RX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN4_TX_SIZE
+ int "Channel 4 TX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN5
+ bool "Enable channel 5"
+ default n
+
+if STM32WL5_IPCC_CHAN5
+
+config STM32WL5_IPCC_CHAN5_RX_SIZE
+ int "Channel 5 RX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN5_TX_SIZE
+ int "Channel 5 TX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN6
+ bool "Enable channel 6"
+ default n
+
+if STM32WL5_IPCC_CHAN6
+
+config STM32WL5_IPCC_CHAN6_RX_SIZE
+ int "Channel 6 RX size"
+ default 256
+
+config STM32WL5_IPCC_CHAN6_TX_SIZE
+ int "Channel 6 TX size"
+ default 256
+
+endif # STM32WL5_IPCC_CHAN2
+endif # STM32WL5_IPCC_CHAN3
+endif # STM32WL5_IPCC_CHAN4
+endif # STM32WL5_IPCC_CHAN5
+endif # STM32WL5_IPCC_CHAN6
+
+endmenu # IPCC Configuration
+
endif # ARCH_CHIP_STM32WL5
diff --git a/arch/arm/src/stm32wl5/Make.defs b/arch/arm/src/stm32wl5/Make.defs
index 9397b10f63..a4a5ea5ca7 100644
--- a/arch/arm/src/stm32wl5/Make.defs
+++ b/arch/arm/src/stm32wl5/Make.defs
@@ -33,3 +33,7 @@ CHIP_CSRCS += stm32wl5_serial.c stm32wl5_start.c stm32wl5_waste.c stm32wl5_uid.c
CHIP_CSRCS += stm32wl5_lse.c stm32wl5_lsi.c stm32wl5_idle.c
CHIP_CSRCS += stm32wl5_pwr.c stm32wl5_tim.c stm32wl5_flash.c stm32wl5_timerisr.c
CHIP_CSRCS += stm32wl5_spi.c
+
+CSRCS-$(CONFIG_STM32WL5_IPCC) = stm32wl5_ipcc.c
+
+CHIP_CSRCS += $(CSRCS-y)
diff --git a/arch/arm/src/stm32wl5/hardware/stm32wl5_ipcc.h b/arch/arm/src/stm32wl5/hardware/stm32wl5_ipcc.h
new file mode 100644
index 0000000000..47466253c1
--- /dev/null
+++ b/arch/arm/src/stm32wl5/hardware/stm32wl5_ipcc.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+ * arch/arm/src/stm32wl5/hardware/stm32wl5_ipcc.h
+ *
+ * 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 __ARCH_ARM_SRC_STM32WL5_HARDWARE_STM32WL5_IPCC_H
+#define __ARCH_ARM_SRC_STM32WL5_HARDWARE_STM32WL5_IPCC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "chip.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define STM32WL5_IPCC_CPU1_OFFSET 0x00
+#define STM32WL5_IPCC_CPU2_OFFSET 0x10
+
+/* Register Offsets *********************************************************/
+
+#define STM32WL5_IPCC_CR_OFFSET 0x00 /* IPCC control register */
+#define STM32WL5_IPCC_MR_OFFSET 0x04 /* IPCC mask register */
+#define STM32WL5_IPCC_SCR_OFFSET 0x08 /* IPCC status set clear register */
+#define STM32WL5_IPCC_CTOCSR_OFFSET 0x0c /* IPCC processor to processor status register */
+
+/* Register Addresses *******************************************************/
+
+#define STM32WL5_IPCC_C1CR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_CR_OFFSET+STM32WL5_IPCC_CPU1_OFFSET)
+#define STM32WL5_IPCC_C1MR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_MR_OFFSET+STM32WL5_IPCC_CPU1_OFFSET)
+#define STM32WL5_IPCC_C1SCR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_SCR_OFFSET+STM32WL5_IPCC_CPU1_OFFSET)
+#define STM32WL5_IPCC_C1TOC2SR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_CTOCSR_OFFSET+STM32WL5_IPCC_CPU1_OFFSET)
+#define STM32WL5_IPCC_C2CR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_CR_OFFSET+STM32WL5_IPCC_CPU2_OFFSET)
+#define STM32WL5_IPCC_C2MR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_MR_OFFSET+STM32WL5_IPCC_CPU2_OFFSET)
+#define STM32WL5_IPCC_C2SCR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_SCR_OFFSET+STM32WL5_IPCC_CPU2_OFFSET)
+#define STM32WL5_IPCC_C2TOC1SR (STM32WL5_IPCC_BASE+STM32WL5_IPCC_CTOCSR_OFFSET+STM32WL5_IPCC_CPU2_OFFSET)
+
+/* Register Bitfield Definitions ********************************************/
+
+#define STM32WL5_IPCC_TX_SHIFT (16) /* TX shift for all registers */
+
+/* IPCC control register */
+
+#define STM32WL5_IPCC_CR_RXOIE (1 << 0) /* Bit 0: Receive channel occupied interrupt enable */
+#define STM32WL5_IPCC_CR_TXFIE (1 << 16) /* Bit 16: Transmit channel free interrupt enable */
+
+/* IPCC mask register */
+
+#define STM32WL5_IPCC_MR_CHNOM(n) (1 << (n)) /* Bit 0..5: Receive channel n occupied interrupt enable, Channels 0..5 */
+#define STM32WL5_IPCC_MR_CHNFM(n) (1 << (16 + (n))) /* Bit 16..21: Transmit channel n free interrupt enable, Channels 0..5 */
+
+/* IPCC status set clear register */
+
+#define STM32WL5_IPCC_SCR_CHNC(n) (1 << (n)) /* Bit 0..5: Receive channel n status bit clear, Channels 0..5 */
+#define STM32WL5_IPCC_SCR_CHNS(n) (1 << (16 + (n))) /* Bit 16..21: Transmit channel n status bit set, Channels 0..5 */
+
+/* IPCC processor to processor status register */
+
+#define STM32WL5_IPCC_CTOCSR_CHNF(n) (1 << (n)) /* Bit 0..5: Channel n occupied, Channels 0..5 */
+
+#endif /* __ARCH_ARM_SRC_STM32WL5_HARDWARE_STM32WL5_IPCC_H */
diff --git a/arch/arm/src/stm32wl5/stm32wl5_allocateheap.c b/arch/arm/src/stm32wl5/stm32wl5_allocateheap.c
index 06d01bf888..44d13c8880 100644
--- a/arch/arm/src/stm32wl5/stm32wl5_allocateheap.c
+++ b/arch/arm/src/stm32wl5/stm32wl5_allocateheap.c
@@ -41,6 +41,7 @@
#include "arm_internal.h"
#include "arm_internal.h"
#include "stm32wl5_mpuinit.h"
+#include "stm32wl5_ipcc.h"
/****************************************************************************
* Pre-processor Definitions
@@ -69,7 +70,11 @@
/* Set the range of SRAM2 as well, requires a second memory region */
-#define SRAM2_START STM32WL5_SRAM2_BASE
+#ifdef CONFIG_IPCC
+# define SRAM2_START IPCC_END
+#else
+# define SRAM2_START STM32WL5_SRAM2_BASE
+#endif
#define SRAM2_END (SRAM2_START + STM32WL5_SRAM2_SIZE)
/* Some sanity checking. If multiple memory regions are defined, verify
diff --git a/arch/arm/src/stm32wl5/stm32wl5_ipcc.c b/arch/arm/src/stm32wl5/stm32wl5_ipcc.c
new file mode 100644
index 0000000000..8f4565e5c0
--- /dev/null
+++ b/arch/arm/src/stm32wl5/stm32wl5_ipcc.c
@@ -0,0 +1,812 @@
+/****************************************************************************
+ * arch/arm/src/stm32wl5/stm32wl5_ipcc.c
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/ipcc.h>
+#include <nuttx/irq.h>
+#include <nuttx/kmalloc.h>
+
+#include <arm_internal.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <arch/stm32wl5/stm32wl5xxx_cpu1_irq.h>
+#include "hardware/stm32wl5_ipcc.h"
+#include "stm32wl5.h"
+#include "stm32wl5_ipcc.h"
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure describes tx or rx of single channel in memory */
+
+struct stm32wl5_ipcc_chan_mem_s
+{
+ unsigned len; /* Number of valid bytes in data[] */
+ char data[]; /* Data in IPCC memory */
+};
+
+/* Internal stm32wl5 ipcc structure describing channel state. */
+
+struct stm32wl5_ipcc_s
+{
+ /* Pointer to API connecting upper and lower half of the driver */
+
+ struct ipcc_lower_s *ipcc;
+
+ /* Physical memory address where second CPU will write data for us,
+ * we will be reading from this memory.
+ */
+
+ char *rxmem;
+
+ /* Maximum length of data that rxmem can hold. It is size of the
+ * reserved space for rxmem minus sizeof(stm32wl5_ipcc_chan_mem_s.len)
+ */
+
+ unsigned rxlen;
+
+#if CONFIG_IPCC_BUFFERED
+ /* Number of bytes copied from IPCC memory to buffer. Can be less than
+ * stm32wl5_ipcc_chan_mem_s.len after copy operation when buffer is full.
+ * Value can persist between multiple ISR and stm32wl5_ipcc_buffer_data()
+ * calls, until all data from IPCC memory is successfully buffered.
+ */
+
+ unsigned rxcopied;
+#endif
+
+ /* Physical memory address where we will write data for the second
+ * CPU to read.
+ */
+
+ char *txmem;
+
+ /* Maximum length of data that txmem can hold. It is size of the
+ * reserved space for txmem minus sizeof(stm32wl5_ipcc_chan_mem_s.len)
+ */
+
+ unsigned txlen;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static ssize_t stm32wl5_ipcc_read(struct ipcc_lower_s *ipcc,
+ char *buffer, size_t buflen);
+static ssize_t stm32wl5_ipcc_write(struct ipcc_lower_s *ipcc,
+ const char *buffer, size_t buflen);
+static ssize_t stm32wl5_ipcc_buffer_data(struct ipcc_lower_s *ipcc,
+ struct circbuf_s *rxbuf);
+static ssize_t stm32wl5_ipcc_copy_to_buffer(int chan,
+ struct circbuf_s *rxbuf);
+static int stm32wl5_ipcc_rx_isr(int irq, void *context, void *arg);
+static int stm32wl5_ipcc_tx_isr(int irq, void *context, void *arg);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+struct stm32wl5_ipcc_s g_ipccpriv[IPCC_NCHAN] =
+{
+ /* Channel 1 is always enabled when IPCC is enabled */
+
+ {
+ .rxmem = (char *)(IPCC_CHAN1_START),
+ .rxlen = IPCC_CHAN1_RX_SIZE - sizeof(unsigned),
+ .txmem = (char *)(IPCC_CHAN1_START + IPCC_CHAN1_RX_SIZE),
+ .txlen = IPCC_CHAN1_TX_SIZE - sizeof(unsigned)
+ }
+
+#if IPCC_CHAN2
+ ,
+ {
+ .rxmem = (char *)(IPCC_CHAN2_START),
+ .rxlen = IPCC_CHAN2_RX_SIZE - sizeof(unsigned),
+ .txmem = (char *)(IPCC_CHAN2_START + IPCC_CHAN2_RX_SIZE),
+ .txlen = IPCC_CHAN2_TX_SIZE - sizeof(unsigned)
+ }
+#endif
+
+#if IPCC_CHAN3
+ ,
+ {
+ .rxmem = (char *)(IPCC_CHAN3_START),
+ .rxlen = IPCC_CHAN3_RX_SIZE - sizeof(unsigned),
+ .txmem = (char *)(IPCC_CHAN3_START + IPCC_CHAN3_RX_SIZE),
+ .txlen = IPCC_CHAN3_TX_SIZE - sizeof(unsigned)
+ }
+#endif
+
+#if IPCC_CHAN4
+ ,
+ {
+ .rxmem = (char *)(IPCC_CHAN4_START),
+ .rxlen = IPCC_CHAN4_RX_SIZE - sizeof(unsigned),
+ .txmem = (char *)(IPCC_CHAN4_START + IPCC_CHAN4_RX_SIZE),
+ .txlen = IPCC_CHAN4_TX_SIZE - sizeof(unsigned)
+ }
+#endif
+
+#if IPCC_CHAN5
+ ,
+ {
+ .rxmem = (char *)(IPCC_CHAN5_START),
+ .rxlen = IPCC_CHAN5_RX_SIZE - sizeof(unsigned),
+ .txmem = (char *)(IPCC_CHAN5_START + IPCC_CHAN5_RX_SIZE),
+ .txlen = IPCC_CHAN5_TX_SIZE - sizeof(unsigned)
+ }
+#endif
+
+#if IPCC_CHAN6
+ ,
+ {
+ .rxmem = (char *)(IPCC_CHAN6_START),
+ .rxlen = IPCC_CHAN6_RX_SIZE - sizeof(unsigned),
+ .txmem = (char *)(IPCC_CHAN6_START + IPCC_CHAN6_RX_SIZE),
+ .txlen = IPCC_CHAN6_TX_SIZE - sizeof(unsigned)
+ }
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_tx_isr
+ *
+ * Description:
+ * IPCC TX interrupt service routine. This interrupt is called when
+ * second CPU read all data from IPCC TX memory and we are free to
+ * write new data to that memory.
+ *
+ * For buffered IPCC, we will immediately write data from buffer to
+ * IPCC memory and notify second CPU. Also blocked writer will be
+ * notified that there is free space on tx buffer.
+ *
+ * For unbuffered IPCC, we won't copy anything but only notify blocked
+ * writers that IPCC TX memory is free.
+ *
+ * Input Parameters:
+ * irq - Number of IRQ that generated interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ * arg - user data (not used by us)
+ *
+ * Returned Value:
+ * Always OK
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+static int stm32wl5_ipcc_tx_isr(int irq, void *context, void *arg)
+{
+ int chan;
+ size_t nwritten;
+ uint32_t mr;
+ uint32_t sr;
+ uint32_t status;
+ struct stm32wl5_ipcc_s *priv;
+ struct stm32wl5_ipcc_chan_mem_s *txmem;
+
+ (void)context;
+ (void)arg;
+ (void)irq;
+
+ mr = getreg32(STM32WL5_IPCC_C1MR) >> STM32WL5_IPCC_TX_SHIFT;
+ sr = getreg32(STM32WL5_IPCC_C1TOC2SR);
+
+ /* Consider only channels that have tx memory free and are unmasked */
+
+ status = sr | mr;
+
+ /* Check which channels have data ready to read */
+
+ for (chan = 0; chan != IPCC_NCHAN; chan++)
+ {
+ if (status & (1 << chan))
+ {
+ /* Transmit on channel is either masked or TX memory is not
+ * ready to write (second CPU is still read data from it,
+ * CHnF == 1).
+ */
+
+ continue;
+ }
+
+ /* Get internal data structure for current chan */
+
+ priv = &g_ipccpriv[chan];
+ txmem = (struct stm32wl5_ipcc_chan_mem_s *)priv->txmem;
+
+#if CONFIG_IPCC_BUFFERED
+ /* Copy as much as we can into IPCC memory, circbuf won't copy
+ * more than there is in the buffer.
+ */
+
+ nwritten = circbuf_read(&priv->ipcc->txbuf, txmem->data, priv->txlen);
+
+ /* Did we write anything to TX memory? */
+
+ if (nwritten)
+ {
+ /* Yes, tell another CPU that data is available to read */
+
+ txmem->len = nwritten;
+ modifyreg32(STM32WL5_IPCC_C1SCR, 0, STM32WL5_IPCC_SCR_CHNS(chan));
+ }
+#else /* CONFIG_IPCC_BUFFERED */
+ /* In unbuffered operations we only notify blocked writers, these
+ * writers will write to IPCC memory directly.
+ */
+#endif /* CONFIG_IPCC_BUFFERED */
+
+ /* Wake up all blocked writers that there is free space available
+ * in IPCC memory (or txbuffer) to write.
+ */
+
+ ipcc_txfree_notify(priv->ipcc->upper);
+
+ if (circbuf_used(&priv->ipcc->txbuf) == 0)
+ {
+ /* Mask tx free interrupt - if tx buffer is empty and we
+ * did not write anything and we don't mask interrupt, we
+ * will be constantly interrupted by tx free irq.
+ */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, 0, STM32WL5_IPCC_MR_CHNFM(chan));
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_write
+ *
+ * Description:
+ * Function writes buffer to IPCC memory that will be later read by
+ * second CPU.
+ *
+ * Input Parameters:
+ * ipcc - ipcc channel instance to write to
+ * buffer - data to write to IPCC memory
+ * buflen - number of bytes requested to write
+ *
+ * Returned Value:
+ * Number of bytes that has been successfully written, or 0 when no
+ * bytes could be written for any reason.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+static ssize_t stm32wl5_ipcc_write(struct ipcc_lower_s *ipcc,
+ const char *buffer, size_t buflen)
+{
+ size_t to_copy;
+ struct stm32wl5_ipcc_s *priv;
+ struct stm32wl5_ipcc_chan_mem_s *txmem;
+ uint32_t sr;
+
+ sr = getreg32(STM32WL5_IPCC_C1TOC2SR);
+
+ if ((sr & (1 << ipcc->chan)))
+ {
+ /* CHnF == 1 means that channel is occupied and second CPU can read
+ * data from it. In any case second CPU did not yet read all data
+ * and we should not write to that memory. Unmask TX interrupt
+ * so we are notified when we can write to memory.
+ */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, STM32WL5_IPCC_MR_CHNFM(ipcc->chan), 0);
+ return 0;
+ }
+
+ priv = &g_ipccpriv[ipcc->chan];
+ txmem = (struct stm32wl5_ipcc_chan_mem_s *)priv->txmem;
+
+ /* Disable TX interrupt since we will modify shared data */
+
+ up_disable_irq(STM32WL5_IRQ_IPCC_C1_TX_IT);
+
+ /* Copy as much as we can into IPCC memory */
+
+ to_copy = buflen > priv->txlen ? priv->txlen : buflen;
+ memcpy(txmem->data, buffer, to_copy);
+ txmem->len = to_copy;
+
+ /* Tell another CPU that data is available to read */
+
+ modifyreg32(STM32WL5_IPCC_C1SCR, 0, STM32WL5_IPCC_SCR_CHNS(ipcc->chan));
+
+ /* Reenable interrupts */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, STM32WL5_IPCC_MR_CHNFM(ipcc->chan), 0);
+ up_enable_irq(STM32WL5_IRQ_IPCC_C1_TX_IT);
+
+ /* Return number of successfully copied bytes to IPCC memory */
+
+ return to_copy;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_rx_isr
+ *
+ * Description:
+ * Interrupt service routine - this function is called when another CPU
+ * has copied data to IPCC memory. Function will wake up blocked readers.
+ *
+ * If buffering is enabled, function will also try to copy all data from
+ * IPCC memory to buffer. If buffer gets full, we will copy as many bytes
+ * as we can fit into buffer, internally save how many bytes we managed
+ * to copy and set overflow flag to 1.
+ *
+ * Input Parameters:
+ * irq - Number of IRQ that generated interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ * arg - user data (not used by us)
+ *
+ * Returned Value:
+ * Always OK
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+static int stm32wl5_ipcc_rx_isr(int irq, void *context, void *arg)
+{
+ int chan;
+ ssize_t nread;
+ uint32_t mr;
+ uint32_t sr;
+ uint32_t status;
+ struct stm32wl5_ipcc_s *priv;
+
+ (void)context;
+ (void)arg;
+ (void)irq;
+
+ mr = getreg32(STM32WL5_IPCC_C1MR);
+ sr = getreg32(STM32WL5_IPCC_C2TOC1SR);
+
+ /* Consider only channels that have data in rx memory and are unmasked */
+
+ status = sr & ~mr;
+
+ /* Check which channels have data ready to read */
+
+ for (chan = 0; chan != IPCC_NCHAN; chan++)
+ {
+ if (!(status & (1 << chan)))
+ {
+ /* Receive on channel is either masked or there is no data
+ * ready for us to read (CHnF == 0)
+ */
+
+ continue;
+ }
+
+ /* Get internal data structure for current chan */
+
+ priv = &g_ipccpriv[chan];
+
+#if CONFIG_IPCC_BUFFERED
+ nread = stm32wl5_ipcc_copy_to_buffer(chan, &priv->ipcc->rxbuf);
+#else /* CONFIG_IPCC_BUFFERED */
+ /* In unbuffered operations we only notify blocked readers, these
+ * readers will read from IPCC memory directly.
+ */
+#endif /* CONFIG_IPCC_BUFFERED */
+
+ if (nread)
+ {
+ /* Wake up all blocked readers that there is data
+ * available to read
+ */
+
+ ipcc_rxfree_notify(priv->ipcc->upper);
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_read
+ *
+ * Description:
+ * Function will copy requests number of bytes to buffer. If there is not
+ * enough data in IPCC memory, less bytes than requests will be copied.
+ * Buflen does not have to be bigger than IPCC memory - function can be
+ * called multiple times and only new data will be transfered. If we don't
+ * have control over IPCC memory (CHnF is 0 - second CPU is writing data
+ * to memory) then it's assumed no data is there to read and 0 is returned.
+ *
+ * Input Parameters:
+ * ipcc - ipcc channel struct
+ * buffer - location where data shall be copied
+ * buflen - size of buffer and number of requested bytes to copy
+ *
+ * Returned Value:
+ * Number of bytes that have been successfully copied to buffer (which
+ * may be less than buflen), or 0 when there was no data to be copied.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+static ssize_t stm32wl5_ipcc_read(struct ipcc_lower_s *ipcc,
+ char *buffer, size_t buflen)
+{
+ size_t to_copy;
+ uint32_t sr;
+ struct stm32wl5_ipcc_s *priv;
+ struct stm32wl5_ipcc_chan_mem_s *rxmem;
+
+ sr = getreg32(STM32WL5_IPCC_C2TOC1SR);
+
+ if (!(sr & (1 << ipcc->chan)))
+ {
+ /* CHnF == 0 means that channel is free and second CPU can write
+ * data to it. In any case data is not yet ready to read - so no
+ * data can be read.
+ */
+
+ return 0;
+ }
+
+ priv = &g_ipccpriv[ipcc->chan];
+ rxmem = (struct stm32wl5_ipcc_chan_mem_s *)priv->rxmem;
+
+ /* Disable RX interrupt since we will modify shared data */
+
+ up_disable_irq(STM32WL5_IRQ_IPCC_C1_RX_IT);
+
+ /* This function may be called multiple times to get only part
+ * of data from IPCC memory, ie. There are 8 bytes of data in
+ * IPCC memory and upper half calls this function 4 times, each
+ * time only reading 2 bytes. Check how many bytes we can copy
+ */
+
+ to_copy = rxmem->len - priv->rxcopied;
+ to_copy = to_copy > buflen ? buflen : to_copy;
+
+ /* Copy as much data to upper half as possible */
+
+ memcpy(buffer, rxmem->data + priv->rxcopied, to_copy);
+ priv->rxcopied += to_copy;
+ if (priv->rxcopied == priv->rxlen)
+ {
+ /* We have copied all data from IPCC memory */
+
+ priv->rxcopied = 0;
+
+ /* Tell another CPU that IPCC rx buffer is free to be populated */
+
+ modifyreg32(STM32WL5_IPCC_C1SCR, 0,
+ STM32WL5_IPCC_SCR_CHNC(ipcc->chan));
+ }
+
+ /* Reenable interrupt */
+
+ up_enable_irq(STM32WL5_IRQ_IPCC_C1_RX_IT);
+
+ return to_copy;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_copy_to_buffer
+ *
+ * Description:
+ * Copies as much bytes from channel as possible to rxbuf circ buffer.
+ *
+ * Input Parameters:
+ * chan - channel number to get data from
+ * rxbuf - circural buffer to copy data to
+ *
+ * Returned Value:
+ * Number of bytes copied to rxbuf
+ *
+ * Assumptions/Limitations:
+ * This is helper function, it does not perform any locking. It may
+ * be called from interrupt.
+ *
+ ****************************************************************************/
+
+static ssize_t stm32wl5_ipcc_copy_to_buffer(int chan,
+ struct circbuf_s *rxbuf)
+{
+ size_t to_copy;
+ size_t rxbuf_space;
+ struct stm32wl5_ipcc_s *priv;
+ struct stm32wl5_ipcc_chan_mem_s *rxmem;
+ uint32_t sr;
+
+ sr = getreg32(STM32WL5_IPCC_C2TOC1SR);
+
+ if (!(sr & (1 << chan)))
+ {
+ /* CHnF == 0 means that channel is free and second CPU can write
+ * data to it. In any case data is not yet ready to read - so no
+ * data can be read.
+ */
+
+ return 0;
+ }
+
+ priv = &g_ipccpriv[chan];
+ rxmem = (struct stm32wl5_ipcc_chan_mem_s *)priv->rxmem;
+
+ /* If buffer is full, it's possible we did not copy everything from
+ * IPCC memory to buffer in previous interrupt. Then when another
+ * channel triggers interrupt we may only need to copy what is left
+ * in IPCC memory to buffer.
+ */
+
+ to_copy = rxmem->len - priv->rxcopied;
+ rxbuf_space = circbuf_space(rxbuf);
+
+ if (to_copy > rxbuf_space)
+ {
+ /* we can't fit all data into buffer, copy as much as
+ * possible and set overflow flag to 1, to tell upper
+ * half that there is still data in IPCC memory.
+ */
+
+ to_copy = rxbuf_space;
+ priv->ipcc->overflow = 1;
+
+ /* Also disable RX interrupt. If data is still in the ipcc
+ * memory and we don't set rxbuffer as free, we will
+ * immediately get another RX interrupt once we leave
+ * this one.
+ */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, 0, STM32WL5_IPCC_MR_CHNOM(chan));
+ }
+
+ /* Buffer data. This function cannot really fail us if we
+ * pass valid input parameters.
+ */
+
+ circbuf_write(&priv->ipcc->rxbuf, rxmem->data + priv->rxcopied, to_copy);
+
+ /* Increment number of bytes that has been buffered */
+
+ if ((priv->rxcopied += to_copy) == rxmem->len)
+ {
+ /* We have buffered all data from IPCC memory */
+
+ priv->rxcopied = 0;
+ priv->ipcc->overflow = 0;
+
+ /* Tell another CPU that IPCC rx buffer is free to be populated */
+
+ modifyreg32(STM32WL5_IPCC_C1SCR, 0, STM32WL5_IPCC_SCR_CHNC(chan));
+
+ /* Unmask RX interrupt to know when second CPU sends us a message */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, STM32WL5_IPCC_MR_CHNOM(chan), 0);
+ }
+
+ return to_copy;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_buffer_data
+ *
+ * Description:
+ * Copies as many bytes as possible from ipcc channel to rxbuf.
+ *
+ * Input Parameters:
+ * ipcc - ipcc channel to copy data from
+ * rxbuf - circural buffer to copy data to
+ *
+ * Returned Value:
+ * Number of successfully buffered bytes.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+static ssize_t stm32wl5_ipcc_buffer_data(struct ipcc_lower_s *ipcc,
+ struct circbuf_s *rxbuf)
+{
+ int ret;
+
+ /* Disable RX interrupt since we will modify shared data */
+
+ up_disable_irq(STM32WL5_IRQ_IPCC_C1_RX_IT);
+
+ /* Copy data to buffer */
+
+ ret = stm32wl5_ipcc_copy_to_buffer(ipcc->chan, rxbuf);
+
+ /* Reenable interrupt */
+
+ up_enable_irq(STM32WL5_IRQ_IPCC_C1_RX_IT);
+
+ /* Return number of bytes that were successfully buffered */
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_write_notify
+ *
+ * Description:
+ * This function is called when there is new data on circ buffer.
+ * All copy operations from buffer to ipcc memory is done in interrupt,
+ * so we simply unmask the interrupt. Interrupt will arrive once ipcc
+ * TX memory is free to be written.
+ *
+ * Input Parameters:
+ * ipcc - ipcc channel
+ *
+ * Returned Value:
+ * Always OK
+ *
+ ****************************************************************************/
+
+static ssize_t stm32wl5_ipcc_write_notify(struct ipcc_lower_s *ipcc)
+{
+ modifyreg32(STM32WL5_IPCC_C1MR, STM32WL5_IPCC_MR_CHNFM(ipcc->chan), 0);
+ return 0;
+}
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_cleanup
+ *
+ * Description:
+ * Cleans up resources initialized by stm32wl5_ipcc_init(). This will
+ * free() ipcc pointer!
+ *
+ * Input Parameters:
+ * ipcc - ipcc channel to cleanup
+ *
+ * Returned Value:
+ * Always OK
+ *
+ ****************************************************************************/
+
+static int stm32wl5_ipcc_cleanup(FAR struct ipcc_lower_s *ipcc)
+{
+ DEBUGASSERT(ipcc);
+ DEBUGASSERT(ipcc->chan <= IPCC_NCHAN);
+
+ /* Mask interrupts for given channel */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, 1, STM32WL5_IPCC_MR_CHNFM(ipcc->chan));
+ modifyreg32(STM32WL5_IPCC_C1MR, 1, STM32WL5_IPCC_MR_CHNOM(ipcc->chan));
+
+ /* Free allocated ipcc memory */
+
+ kmm_free(ipcc);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: stm32wl5_ipcc_init
+ *
+ * Description:
+ * Function initializes runtime options for IPCC. This function is called
+ * by upper half of the IPCC driver from ipcc_register(). This function
+ * is called once for every registered channel - so it can be called
+ * multiple times with different input parameters during system bring up.
+ *
+ * Input Parameters:
+ * chan - channel to initialize
+ *
+ * Returned Value:
+ * Structure to link lower and upper halfs of the driver, or NULL on
+ * initialization failure.
+ *
+ * Assumptions/Limitations:
+ *
+ ****************************************************************************/
+
+struct ipcc_lower_s *stm32wl5_ipcc_init(int chan)
+{
+ int ret;
+ static int ipcc_fti;
+ struct ipcc_lower_s *ipcc;
+
+ DEBUGASSERT(ipcc);
+ DEBUGASSERT(chan <= IPCC_NCHAN);
+
+ if ((ipcc = kmm_zalloc(sizeof(*ipcc))) == NULL)
+ {
+ return NULL;
+ }
+
+ /* Link internal stm32wl5 ipcc struct with character device driver
+ * via ipcc_lower struct.
+ */
+
+ g_ipccpriv[chan].ipcc = ipcc;
+
+ /* Give upper half driver pointers to mcu specific functions that
+ * upper half needs to call to work properly.
+ */
+
+ ipcc->ops.read = stm32wl5_ipcc_read;
+ ipcc->ops.write = stm32wl5_ipcc_write;
+ ipcc->ops.buffer_data = stm32wl5_ipcc_buffer_data;
+ ipcc->ops.write_notify = stm32wl5_ipcc_write_notify;
+ ipcc->ops.cleanup = stm32wl5_ipcc_cleanup;
+
+ ipcc->chan = chan;
+
+ /* Unmask channel interrupt */
+
+ modifyreg32(STM32WL5_IPCC_C1MR, STM32WL5_IPCC_MR_CHNFM(chan), 0);
+ modifyreg32(STM32WL5_IPCC_C1MR, STM32WL5_IPCC_MR_CHNOM(chan), 0);
+
+ if (ipcc_fti)
+ {
+ return ipcc;
+ }
+
+ /* For the first time initialization we also need to attach rx/tx
+ * interrupt functions
+ */
+
+ ret = irq_attach(STM32WL5_IRQ_IPCC_C1_RX_IT, stm32wl5_ipcc_rx_isr, NULL);
+ if (ret)
+ {
+ kmm_free(ipcc);
+ return NULL;
+ }
+
+ ret = irq_attach(STM32WL5_IRQ_IPCC_C1_TX_IT, stm32wl5_ipcc_tx_isr, NULL);
+ if (ret)
+ {
+ kmm_free(ipcc);
+ return NULL;
+ }
+
+ /* Enable interrupts when:
+ * - we receive data from CPU2
+ * - CPU2 has read message from us and TX memory is free to be used again
+ */
+
+ putreg32(STM32WL5_IPCC_CR_RXOIE | STM32WL5_IPCC_CR_TXFIE,
+ STM32WL5_IPCC_C1CR);
+
+ up_enable_irq(STM32WL5_IRQ_IPCC_C1_RX_IT);
+ up_enable_irq(STM32WL5_IRQ_IPCC_C1_TX_IT);
+
+ ipcc_fti = 1;
+
+ return ipcc;
+}
diff --git a/arch/arm/src/stm32wl5/stm32wl5_ipcc.h b/arch/arm/src/stm32wl5/stm32wl5_ipcc.h
new file mode 100644
index 0000000000..2d2a221fa0
--- /dev/null
+++ b/arch/arm/src/stm32wl5/stm32wl5_ipcc.h
@@ -0,0 +1,145 @@
+/****************************************************************************
+ * arch/arm/src/stm32wl5/stm32wl5_ipcc.h
+ *
+ * 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 __ARCH_ARM_SRC_STM32WL5_IPCC_H
+#define __ARCH_ARM_SRC_STM32WL5_IPCC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/ipcc.h>
+#include "hardware/stm32wl5_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Channels are sequential, that is, if channel 3 is enabled that means
+ * channel 2 and 1 are also enabled. Kconfig makes sure there is no
+ * situation where channel 3 is enabled while channel 2 is not.
+ */
+
+/* channel 1 configuration **************************************************/
+
+#define IPCC_CHAN1_RX_SIZE (CONFIG_STM32WL5_IPCC_CHAN1_RX_SIZE)
+#define IPCC_CHAN1_TX_SIZE (CONFIG_STM32WL5_IPCC_CHAN1_TX_SIZE)
+#define IPCC_CHAN1_START (IPCC_START)
+#define IPCC_CHAN1_SIZE (IPCC_CHAN1_RX_SIZE + IPCC_CHAN1_TX_SIZE)
+#define IPCC_CHAN1 (1)
+
+/* channel 2 configuration **************************************************/
+
+#if defined(CONFIG_STM32WL5_IPCC_CHAN2)
+# define IPCC_CHAN2_RX_SIZE (CONFIG_STM32WL5_IPCC_CHAN2_RX_SIZE)
+# define IPCC_CHAN2_TX_SIZE (CONFIG_STM32WL5_IPCC_CHAN2_TX_SIZE)
+# define IPCC_CHAN2_START (IPCC_CHAN1_START + IPCC_CHAN1_SIZE)
+# define IPCC_CHAN2_SIZE (IPCC_CHAN2_RX_SIZE + IPCC_CHAN2_TX_SIZE)
+# define IPCC_CHAN2 (1)
+#else
+# define IPCC_CHAN2_SIZE (0)
+# define IPCC_CHAN2 (0)
+#endif
+
+/* channel 3 configuration **************************************************/
+
+#if defined(CONFIG_STM32WL5_IPCC_CHAN3)
+# define IPCC_CHAN3_RX_SIZE (CONFIG_STM32WL5_IPCC_CHAN3_RX_SIZE)
+# define IPCC_CHAN3_TX_SIZE (CONFIG_STM32WL5_IPCC_CHAN3_TX_SIZE)
+# define IPCC_CHAN3_START (IPCC_CHAN2_START + IPCC_CHAN2_SIZE)
+# define IPCC_CHAN3_SIZE (IPCC_CHAN3_RX_SIZE + IPCC_CHAN3_TX_SIZE)
+# define IPCC_CHAN3 (1)
+#else
+# define IPCC_CHAN3_SIZE (0)
+# define IPCC_CHAN3 (0)
+#endif
+
+/* channel 4 configuration **************************************************/
+
+#if defined(CONFIG_STM32WL5_IPCC_CHAN4)
+# define IPCC_CHAN4_RX_SIZE (CONFIG_STM32WL5_IPCC_CHAN4_RX_SIZE)
+# define IPCC_CHAN4_TX_SIZE (CONFIG_STM32WL5_IPCC_CHAN4_TX_SIZE)
+# define IPCC_CHAN4_START (IPCC_CHAN3_START + IPCC_CHAN3_SIZE)
+# define IPCC_CHAN4_SIZE (IPCC_CHAN4_RX_SIZE + IPCC_CHAN4_TX_SIZE)
+# define IPCC_CHAN4 (1)
+#else
+# define IPCC_CHAN4_SIZE (0)
+# define IPCC_CHAN4 (0)
+#endif
+
+/* channel 5 configuration **************************************************/
+
+#if defined(CONFIG_STM32WL5_IPCC_CHAN5)
+# define IPCC_CHAN5_RX_SIZE (CONFIG_STM32WL5_IPCC_CHAN5_RX_SIZE)
+# define IPCC_CHAN5_TX_SIZE (CONFIG_STM32WL5_IPCC_CHAN5_TX_SIZE)
+# define IPCC_CHAN5_START (IPCC_CHAN4_START + IPCC_CHAN4_SIZE)
+# define IPCC_CHAN5_SIZE (IPCC_CHAN5_RX_SIZE + IPCC_CHAN5_TX_SIZE)
+# define IPCC_CHAN5 (1)
+#else
+# define IPCC_CHAN5_SIZE (0)
+# define IPCC_CHAN5 (0)
+#endif
+
+/* channel 6 configuration **************************************************/
+
+#if defined(CONFIG_STM32WL5_IPCC_CHAN6)
+# define IPCC_CHAN6_RX_SIZE (CONFIG_STM32WL5_IPCC_CHAN6_RX_SIZE)
+# define IPCC_CHAN6_TX_SIZE (CONFIG_STM32WL5_IPCC_CHAN6_TX_SIZE)
+# define IPCC_CHAN6_START (IPCC_CHAN5_START + IPCC_CHAN5_SIZE)
+# define IPCC_CHAN6_SIZE (IPCC_CHAN6_RX_SIZE + IPCC_CHAN6_TX_SIZE)
+# define IPCC_CHAN6 (1)
+#else
+# define IPCC_CHAN6_SIZE (0)
+# define IPCC_CHAN6 (0)
+#endif
+
+/* ipcc general configuration ***********************************************/
+
+/* Memory layout is:
+ *
+ * +----------+
+ * | CHAN1_RX | CHAN1_START (IPCC_START)
+ * | CHAN1_TX | CHAN1_START + IPCC_CHAN1_RX_SIZE
+ * +----------+
+ * | CHAN2_RX | CHAN2_START
+ * | CHAN2_TX | CHAN2_START + IPCC_CHAN2_RX_SIZE
+ * | . |
+ * | . |
+ * | . |
+ * | CHAN6_RX | CHAN6_START
+ * | CHAN6_TX | CHAN6_START + IPCC_CHAN6_RX_SIZE
+ * +----------+
+ */
+
+/* IPCC needs continous memory of known address that is shared
+ * between CPUs. Because of that we reserve memory at beginning
+ * of SRAM2. SRAM2 region will be right after IPCC reserved memory
+ */
+
+#define IPCC_START STM32WL5_SRAM2_BASE
+#define IPCC_NCHAN (IPCC_CHAN1 + IPCC_CHAN2 + IPCC_CHAN3 + \
+ IPCC_CHAN4 + IPCC_CHAN5 + IPCC_CHAN6)
+#define IPCC_END (IPCC_START + IPCC_CHAN1_SIZE + IPCC_CHAN2_SIZE + \
+ IPCC_CHAN3_SIZE + IPCC_CHAN4_SIZE + \
+ IPCC_CHAN5_SIZE + IPCC_CHAN6_SIZE)
+
+struct ipcc_lower_s *stm32wl5_ipcc_init(int chan);
+
+#endif /* __ARCH_ARM_SRC_STM32WL5_IPCC_H */
diff --git a/arch/arm/src/stm32wl5/stm32wl5_rcc.c b/arch/arm/src/stm32wl5/stm32wl5_rcc.c
index 51b03ca2d8..380d14a50b 100644
--- a/arch/arm/src/stm32wl5/stm32wl5_rcc.c
+++ b/arch/arm/src/stm32wl5/stm32wl5_rcc.c
@@ -294,6 +294,12 @@ static inline void stm32wl5_rcc_enableahb3(void)
regval |= RCC_AHB3ENR_FLASHEN;
#endif
+#ifdef CONFIG_STM32WL5_IPCC
+ /* IPCC interface clock enable */
+
+ regval |= RCC_AHB3ENR_IPCCEN;
+#endif
+
putreg32(regval, STM32WL5_RCC_AHB3ENR); /* Enable peripherals */
}