···11+/***************************************************************************
22+ * __________ __ ___.
33+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
44+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
55+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
66+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
77+ * \/ \/ \/ \/ \/
88+ * $Id$
99+ *
1010+ * Copyright (C) 2025 Aidan MacDonald
1111+ *
1212+ * This program is free software; you can redistribute it and/or
1313+ * modify it under the terms of the GNU General Public License
1414+ * as published by the Free Software Foundation; either version 2
1515+ * of the License, or (at your option) any later version.
1616+ *
1717+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
1818+ * KIND, either express or implied.
1919+ *
2020+ ****************************************************************************/
2121+#include "clock-stm32h7.h"
2222+#include "mutex.h"
2323+#include "panic.h"
2424+#include <stdint.h>
2525+2626+struct stm_clock_state
2727+{
2828+ struct mutex mutex;
2929+ uint8_t refcount[STM_NUM_CLOCKS];
3030+};
3131+3232+static struct stm_clock_state stm_clocks;
3333+3434+void stm_clock_init(void)
3535+{
3636+ mutex_init(&stm_clocks.mutex);
3737+3838+ stm_target_clock_init();
3939+}
4040+4141+void stm_clock_enable(enum stm_clock clock)
4242+{
4343+ mutex_lock(&stm_clocks.mutex);
4444+4545+ if (stm_clocks.refcount[clock] == UINT8_MAX)
4646+ panicf("%s: clock %d overflow", __func__, (int)clock);
4747+4848+ if (stm_clocks.refcount[clock]++ == 0)
4949+ stm_target_clock_enable(clock, true);
5050+5151+ mutex_unlock(&stm_clocks.mutex);
5252+}
5353+5454+void stm_clock_disable(enum stm_clock clock)
5555+{
5656+ mutex_lock(&stm_clocks.mutex);
5757+5858+ if (stm_clocks.refcount[clock] == 0)
5959+ panicf("%s: clock %d underflow", __func__, (int)clock);
6060+6161+ if (--stm_clocks.refcount[clock] == 0)
6262+ stm_target_clock_enable(clock, false);
6363+6464+ mutex_unlock(&stm_clocks.mutex);
6565+}
+36
firmware/target/arm/stm32/clock-stm32h7.h
···2222#define __CLOCK_STM32H7_H__
23232424#include "system.h"
2525+#include <stdbool.h>
2626+2727+enum stm_clock
2828+{
2929+ STM_CLOCK_SPI1_KER,
3030+ STM_CLOCK_SPI2_KER,
3131+ STM_CLOCK_SPI3_KER,
3232+ STM_CLOCK_SPI4_KER,
3333+ STM_CLOCK_SPI5_KER,
3434+ STM_CLOCK_SPI6_KER,
3535+ STM_NUM_CLOCKS,
3636+};
25372638/*
2739 * Implemented by the target to initialize all oscillators,
···2941 * early boot.
3042 */
3143void stm_target_clock_init(void) INIT_ATTR;
4444+4545+/*
4646+ * Callback to be implemented by the target when the hardware
4747+ * clock needs to be turned on or off. Clocks are internally
4848+ * reference counted so only the first / last user will change
4949+ * the hardware state.
5050+ *
5151+ * Only clocks that are actually used need to be implemented,
5252+ * and unless otherwise noted it is allowed for enable/disable
5353+ * to be a no-op if the clock is always enabled.
5454+ */
5555+void stm_target_clock_enable(enum stm_clock clock, bool enable);
5656+5757+/*
5858+ * Called from system_init(). Sets up internal book-keeping
5959+ * and then calls stm_target_clock_init().
6060+ */
6161+void stm_clock_init(void) INIT_ATTR;
6262+6363+/*
6464+ * Enable or disable a clock. Not safe to call from an IRQ handler.
6565+ */
6666+void stm_clock_enable(enum stm_clock clock);
6767+void stm_clock_disable(enum stm_clock clock);
32683369#endif /* __CLOCK_STM32H7_H__ */
+1-1
firmware/target/arm/stm32/system-stm32h7.c
···6969 stm_enable_caches();
70707171 /* Initialize system clocks */
7272- stm_target_clock_init();
7272+ stm_clock_init();
73737474 /* TODO: move this */
7575 systick_init(1000/HZ);