From 4c9d405a97b8ed1e14c91129da6483722d9234de Mon Sep 17 00:00:00 2001 From: raiden00pl Date: Mon, 21 Aug 2023 09:40:05 +0200 Subject: [PATCH] arch/stm32h7: add HSEM support --- arch/arm/src/stm32h7/CMakeLists.txt | 7 +- arch/arm/src/stm32h7/Kconfig | 4 + arch/arm/src/stm32h7/Make.defs | 4 + arch/arm/src/stm32h7/hardware/stm32_hsem.h | 83 ++++++ arch/arm/src/stm32h7/stm32_hsem.c | 291 +++++++++++++++++++++ arch/arm/src/stm32h7/stm32_hsem.h | 68 +++++ arch/arm/src/stm32h7/stm32h7x3xx_rcc.c | 6 + 7 files changed, 461 insertions(+), 2 deletions(-) create mode 100644 arch/arm/src/stm32h7/hardware/stm32_hsem.h create mode 100644 arch/arm/src/stm32h7/stm32_hsem.c create mode 100644 arch/arm/src/stm32h7/stm32_hsem.h diff --git a/arch/arm/src/stm32h7/CMakeLists.txt b/arch/arm/src/stm32h7/CMakeLists.txt index 27ed366f2d..34ad2414b1 100644 --- a/arch/arm/src/stm32h7/CMakeLists.txt +++ b/arch/arm/src/stm32h7/CMakeLists.txt @@ -31,13 +31,16 @@ list( stm32_rcc.c stm32_lowputc.c stm32_serial.c - stm32_uid.c -) + stm32_uid.c) if(CONFIG_STM32H7_PROGMEM) list(APPEND SRCS stm32_flash.c) endif() +if(CONFIG_STM32H7_HSEM) + list(APPEND SRCS stm32_hsem.c) +endif() + if(CONFIG_SCHED_TICKLESS) list(APPEND SRCS stm32_tickless.c) else() diff --git a/arch/arm/src/stm32h7/Kconfig b/arch/arm/src/stm32h7/Kconfig index fec677d2c4..f06746ab3f 100644 --- a/arch/arm/src/stm32h7/Kconfig +++ b/arch/arm/src/stm32h7/Kconfig @@ -633,6 +633,10 @@ config STM32H7_LPTIM bool default n +config STM32H7_HSEM + bool "Hardware semaphore" + default n + config STM32H7_RTC bool "RTC" default n diff --git a/arch/arm/src/stm32h7/Make.defs b/arch/arm/src/stm32h7/Make.defs index 8d1433e69f..aeaa171425 100644 --- a/arch/arm/src/stm32h7/Make.defs +++ b/arch/arm/src/stm32h7/Make.defs @@ -29,6 +29,10 @@ ifeq ($(CONFIG_STM32H7_PROGMEM),y) CHIP_CSRCS += stm32_flash.c endif +ifeq ($(CONFIG_STM32H7_HSEM),y) +CHIP_CSRCS += stm32_hsem.c +endif + # Required STM32H7 files CHIP_CSRCS += stm32_allocateheap.c stm32_exti_gpio.c stm32_gpio.c stm32_irq.c diff --git a/arch/arm/src/stm32h7/hardware/stm32_hsem.h b/arch/arm/src/stm32h7/hardware/stm32_hsem.h new file mode 100644 index 0000000000..9aa13fe9c3 --- /dev/null +++ b/arch/arm/src/stm32h7/hardware/stm32_hsem.h @@ -0,0 +1,83 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/hardware/stm32_hsem.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_STM32H7_HARDWARE_STM32_HSEM_H +#define __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_HSEM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include "chip.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define STM32_HSEM_CHANS (32) +#define HSEM_COREID_CPU1 (3) +#define HSEM_COREID_CPU2 (1) + +/* Register Offsets *********************************************************/ + +#define STM32_HSEM_RX_OFFSET(n) (0x0000 + (0x4 * n)) /* HSEM register semaphore x */ +#define STM32_HSEM_RLRX_OFFSET(n) (0x0080 + (0x4 * n)) /* HSEM read lock register semaphore x */ +#define STM32_HSEM_CXIER_OFFSET(n) (0x0100 + (0x10 * n)) /* HSEM interrupt enable register */ +#define STM32_HSEM_CXICR_OFFSET(n) (0x0104 + (0x10 * n)) /* HSEM interrupt clear register */ +#define STM32_HSEM_CXISR_OFFSET(n) (0x0108 + (0x10 * n)) /* HSEM interrupt status register */ +#define STM32_HSEM_CXMISR_OFFSET(n) (0x010c + (0x10 * n)) /* HSEM interrupt status register */ +#define STM32_HSEM_CR_OFFSET (0x0140) /* HSEM clear register */ +#define STM32_HSEM_KEYR_OFFSET (0x0144) /* HSEM semaphore clear key */ + +/* Register Addresses *******************************************************/ + +#define STM32_HSEM_RX(x) (STM32_HSEM_BASE+STM32_HSEM_RX_OFFSET(x)) +#define STM32_HSEM_RLRX(x) (STM32_HSEM_BASE+STM32_HSEM_RLRX_OFFSET(x)) +#define STM32_HSEM_CXIER(x) (STM32_HSEM_BASE+STM32_HSEM_CXIER_OFFSET(x)) +#define STM32_HSEM_CXICR(x) (STM32_HSEM_BASE+STM32_HSEM_CXICR_OFFSET(x)) +#define STM32_HSEM_CXISR(x) (STM32_HSEM_BASE+STM32_HSEM_CXISR_OFFSET(x)) +#define STM32_HSEM_CXMISR(x) (STM32_HSEM_BASE+STM32_HSEM_CXMISR_OFFSET(x)) +#define STM32_HSEM_CXMISRCR (STM32_HSEM_BASE+STM32_HSEM_CR_OFFSET) +#define STM32_HSEM_KEYR (STM32_HSEM_BASE+STM32_HSEM_KEYR_OFFSET) + +/* Register Bitfield Definitions ********************************************/ + +/* Semaphore x registers */ + +#define HSEM_SEMX_PROCID_SHIFT (0) /* Bits 0-8: Semaphore PROCID */ +#define HSEM_SEMX_PROCID_MASK (0xff << HSEM_SEMX_PROCID_SHIFT) +#define HSEM_SEMX_COREID_SHIFT (8) /* Bits 8-11: Semaphore COREID */ +#define HSEM_SEMX_COREID_MASK (0xf << HSEM_SEMX_COREID_SHIFT) + /* Bits 12-30: reserved */ +#define HSEM_SEMX_LOCK (1 << 31) /* Bit 31: Lock indication */ + +/* Clear register */ + +#define HSEM_CR_COREID_SHIFT (8) /* Bits 8-11: COREID of semaphores to be cleared */ +#define HSEM_CR_COREID_MASK (0xf << HSEM_CR_COREID_SHIFT) +#define HSEM_CR_KEY_SHIFT (16) /* Bits 16-31: Semaphore clear Key */ +#define HSEM_CR_KEY_MASK (0xffff << HSEM_CR_KEY_SHIFT) + +/* Interrupts */ + +#define HSEM_CHAN_ID(n) (1 << n) + +#endif /* __ARCH_ARM_SRC_STM32H7_HARDWARE_STM32_HSEM_H */ diff --git a/arch/arm/src/stm32h7/stm32_hsem.c b/arch/arm/src/stm32h7/stm32_hsem.c new file mode 100644 index 0000000000..8bb638501f --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_hsem.c @@ -0,0 +1,291 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_hsem.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 + +#include + +#include "nvic.h" + +#include "arm_internal.h" +#include "stm32_hsem.h" + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* HSEM receive channel configuration */ + +struct stm32_hsem_recv_s +{ + hsem_callback_t callback; + void *args; +}; + +/* HSEM device */ + +struct stm32_hsem_s +{ + struct stm32_hsem_recv_s recv[STM32_HSEM_CHANS]; + uint32_t irq; + uint8_t block; +}; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +struct stm32_hsem_s g_stm32_hsem; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_hsem_interrupt + ****************************************************************************/ + +static int stm32_hsem_interrupt(int irq, void *context, void *args) +{ + struct stm32_hsem_s *dev = args; + uint32_t regval = 0; + int i = 0; + + regval = getreg32(STM32_HSEM_CXMISR(dev->block)); + + _info("HSEM interrupt 0x%" PRIx32 "\n", regval); + + for (i = 0; i < STM32_HSEM_CHANS; i++) + { + if (regval & HSEM_CHAN_ID(i)) + { + if (dev->recv[i].callback) + { + dev->recv[i].callback(i, dev->recv[i].args); + } + } + } + + /* Clear events */ + + putreg32(regval, STM32_HSEM_CXICR(dev->block)); + + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: stm32_hsem_subscribe + * + * Description: + * Subscribe to event on a given semaphore + * + ****************************************************************************/ + +void stm32_hsem_subscribe(uint8_t id, hsem_callback_t callback, void *args) +{ + struct stm32_hsem_s *dev = &g_stm32_hsem; + + DEBUGASSERT(id < STM32_HSEM_CHANS); + + _info("HSEM subscribe %d\n", id); + + /* Register callaback */ + + dev->recv[id].callback = callback; + dev->recv[id].args = args; + + if (callback) + { + /* Clear pending */ + + putreg32(HSEM_CHAN_ID(id), STM32_HSEM_CXICR(dev->block)); + + /* Enable interrupt */ + + modifyreg32(STM32_HSEM_CXIER(dev->block), 0, HSEM_CHAN_ID(id)); + } + else + { + /* Disable interrupts */ + + modifyreg32(STM32_HSEM_CXIER(dev->block), HSEM_CHAN_ID(id), 0); + } +} + +/**************************************************************************** + * Name: stm32_hsem_signal + * + * Description: + * Signal on a semaphore (free and lock again) + * + ****************************************************************************/ + +void stm32_hsem_signal(uint8_t id) +{ + DEBUGASSERT(id < STM32_HSEM_CHANS); + + _info("HSEM signal %d\n", id); + + /* Lock semaphore */ + + while (stm32_hsem_take(id) == 0); + + /* Free semaphore to signal event */ + + stm32_hsem_free(id); +} + +/**************************************************************************** + * Name: stm32_hsem_busywait_lock + * + * Description: + * Busy wait for a semaphore to be locked + * + ****************************************************************************/ + +void stm32_hsem_busywait_lock(uint8_t id) +{ + DEBUGASSERT(id < STM32_HSEM_CHANS); + + _info("HSEM busywait lock %d\n", id); + + /* Wait for semaphore lock */ + + while ((getreg32(STM32_HSEM_RX(id)) & HSEM_SEMX_LOCK) == 0); +} + +/**************************************************************************** + * Name: stm32_hsem_busywait_free + * + * Description: + * Busy wait for a semaphore to be free + * + ****************************************************************************/ + +void stm32_hsem_busywait_free(uint8_t id) +{ + DEBUGASSERT(id < STM32_HSEM_CHANS); + + _info("HSEM busywait free %d\n", id); + + /* Wait for semaphore free */ + + while ((getreg32(STM32_HSEM_RX(id)) & HSEM_SEMX_LOCK) != 0); +} + +/**************************************************************************** + * Name: stm32_hsem_wait_take + * + * Description: + * Take a semaphore (1-step lock) + * + ****************************************************************************/ + +void stm32_hsem_wait_take(uint8_t id) +{ + DEBUGASSERT(id < STM32_HSEM_CHANS); + + _info("HSEM wait take %d\n", id); + + stm32_hsem_busywait_free(id); + while (stm32_hsem_take(id) == 0); +} + +/**************************************************************************** + * Name: stm32_hsem_take + * + * Description: + * Take a semaphore (1-step lock) + * + ****************************************************************************/ + +bool stm32_hsem_take(uint8_t id) +{ + DEBUGASSERT(id < STM32_HSEM_CHANS); + + _info("HSEM take %d\n", id); + + /* Take semaphore */ + +#ifdef CONFIG_ARCH_CHIP_STM32H7_CORTEXM7 + return (getreg32(STM32_HSEM_RLRX(id)) == + ((HSEM_COREID_CPU1 << HSEM_SEMX_COREID_SHIFT) | HSEM_SEMX_LOCK)); +#else + return (getreg32(STM32_HSEM_RLRX(id)) == + ((HSEM_COREID_CPU2 << HSEM_SEMX_COREID_SHIFT) | HSEM_SEMX_LOCK)); +#endif +} + +/**************************************************************************** + * Name: stm32_hsem_free + * + * Description: + * Free a semaphore + * + ****************************************************************************/ + +void stm32_hsem_free(uint8_t id) +{ +#ifdef CONFIG_ARCH_CHIP_STM32H7_CORTEXM7 + putreg32((HSEM_COREID_CPU1 << HSEM_CR_COREID_SHIFT) , STM32_HSEM_RX(id)); +#else + putreg32((HSEM_COREID_CPU2 << HSEM_CR_COREID_SHIFT) , STM32_HSEM_RX(id)); +#endif +} + +/**************************************************************************** + * Name: stm32_hsem_init + * + * Description: + * Initialize the hardware semaphore driver + * + ****************************************************************************/ + +void stm32_hsem_init(void) +{ + struct stm32_hsem_s *dev = &g_stm32_hsem; + + /* Reset device */ + + memset(dev, 0, sizeof(struct stm32_hsem_s)); + + /* Set block id */ + +#ifdef CONFIG_ARCH_CHIP_STM32H7_CORTEXM7 + dev->block = 0; + dev->irq = STM32_IRQ_HSEM0; +#else + dev->block = 1; + dev->irq = STM32_IRQ_HSEM1; +#endif + + /* Attach and enable the IRQ */ + + irq_attach(dev->irq, stm32_hsem_interrupt, dev); + up_enable_irq(dev->irq); +} diff --git a/arch/arm/src/stm32h7/stm32_hsem.h b/arch/arm/src/stm32h7/stm32_hsem.h new file mode 100644 index 0000000000..7cd1c36380 --- /dev/null +++ b/arch/arm/src/stm32h7/stm32_hsem.h @@ -0,0 +1,68 @@ +/**************************************************************************** + * arch/arm/src/stm32h7/stm32_hsem.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_STM32H7_STM32_HSEM_H +#define __ARCH_ARM_SRC_STM32H7_STM32_HSEM_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include "hardware/stm32_hsem.h" + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef void (*hsem_callback_t)(uint8_t id, void *arg); + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifndef __ASSEMBLY__ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +void stm32_hsem_subscribe(uint8_t id, hsem_callback_t callback, void *args); +void stm32_hsem_signal(uint8_t id); +void stm32_hsem_busywait_lock(uint8_t id); +void stm32_hsem_busywait_free(uint8_t id); +void stm32_hsem_wait_take(uint8_t id); +bool stm32_hsem_take(uint8_t id); +void stm32_hsem_free(uint8_t id); +void stm32_hsem_init(void); + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_STM32H7_STM32_HSEM_H */ diff --git a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c index 1068ee493f..81828fdf6e 100644 --- a/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c +++ b/arch/arm/src/stm32h7/stm32h7x3xx_rcc.c @@ -416,6 +416,12 @@ static inline void rcc_enableahb4(void) regval |= RCC_AHB4ENR_BKPSRAMEN; #endif +#ifdef CONFIG_STM32H7_HSEM + /* HSEM clock enable */ + + regval |= RCC_AHB4ENR_HSEMEN; +#endif + putreg32(regval, STM32_RCC_AHB4ENR); /* Enable peripherals */ }