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 */
 }