blob: 0fbfba5c40bac0f4308ac38cb50d1a633a62ca06 [file] [log] [blame]
/*
* STM32L4X5 RCC (Reset and clock control)
*
* Copyright (c) 2023 Arnaud Minier <arnaud.minier@telecom-paris.fr>
* Copyright (c) 2023 Inès Varhol <ines.varhol@telecom-paris.fr>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
* The reference used is the STMicroElectronics RM0351 Reference manual
* for STM32L4x5 and STM32L4x6 advanced Arm ® -based 32-bit MCUs.
*
* Inspired by the BCM2835 CPRMAN clock manager by Luc Michel.
*/
#ifndef HW_STM32L4X5_RCC_H
#define HW_STM32L4X5_RCC_H
#include "hw/sysbus.h"
#include "qom/object.h"
#define TYPE_STM32L4X5_RCC "stm32l4x5-rcc"
OBJECT_DECLARE_SIMPLE_TYPE(Stm32l4x5RccState, STM32L4X5_RCC)
/* In the Stm32l4x5 clock tree, mux have at most 7 sources */
#define RCC_NUM_CLOCK_MUX_SRC 7
typedef enum PllCommonChannels {
RCC_PLL_COMMON_CHANNEL_P = 0,
RCC_PLL_COMMON_CHANNEL_Q = 1,
RCC_PLL_COMMON_CHANNEL_R = 2,
RCC_NUM_CHANNEL_PLL_OUT = 3
} PllCommonChannels;
/* NB: Prescaler are assimilated to mux with one source and one output */
typedef enum RccClockMux {
/* Internal muxes that arent't exposed publicly to other peripherals */
RCC_CLOCK_MUX_SYSCLK,
RCC_CLOCK_MUX_PLL_INPUT,
RCC_CLOCK_MUX_HCLK,
RCC_CLOCK_MUX_PCLK1,
RCC_CLOCK_MUX_PCLK2,
RCC_CLOCK_MUX_HSE_OVER_32,
RCC_CLOCK_MUX_LCD_AND_RTC_COMMON,
/* Muxes with a publicly available output */
RCC_CLOCK_MUX_CORTEX_REFCLK,
RCC_CLOCK_MUX_USART1,
RCC_CLOCK_MUX_USART2,
RCC_CLOCK_MUX_USART3,
RCC_CLOCK_MUX_UART4,
RCC_CLOCK_MUX_UART5,
RCC_CLOCK_MUX_LPUART1,
RCC_CLOCK_MUX_I2C1,
RCC_CLOCK_MUX_I2C2,
RCC_CLOCK_MUX_I2C3,
RCC_CLOCK_MUX_LPTIM1,
RCC_CLOCK_MUX_LPTIM2,
RCC_CLOCK_MUX_SWPMI1,
RCC_CLOCK_MUX_MCO,
RCC_CLOCK_MUX_LSCO,
RCC_CLOCK_MUX_DFSDM1,
RCC_CLOCK_MUX_ADC,
RCC_CLOCK_MUX_CLK48,
RCC_CLOCK_MUX_SAI1,
RCC_CLOCK_MUX_SAI2,
/*
* Mux that have only one input and one output assigned to as peripheral.
* They could be direct lines but it is simpler
* to use the same logic for all outputs.
*/
/* - AHB1 */
RCC_CLOCK_MUX_TSC,
RCC_CLOCK_MUX_CRC,
RCC_CLOCK_MUX_FLASH,
RCC_CLOCK_MUX_DMA2,
RCC_CLOCK_MUX_DMA1,
/* - AHB2 */
RCC_CLOCK_MUX_RNG,
RCC_CLOCK_MUX_AES,
RCC_CLOCK_MUX_OTGFS,
RCC_CLOCK_MUX_GPIOA,
RCC_CLOCK_MUX_GPIOB,
RCC_CLOCK_MUX_GPIOC,
RCC_CLOCK_MUX_GPIOD,
RCC_CLOCK_MUX_GPIOE,
RCC_CLOCK_MUX_GPIOF,
RCC_CLOCK_MUX_GPIOG,
RCC_CLOCK_MUX_GPIOH,
/* - AHB3 */
RCC_CLOCK_MUX_QSPI,
RCC_CLOCK_MUX_FMC,
/* - APB1 */
RCC_CLOCK_MUX_OPAMP,
RCC_CLOCK_MUX_DAC1,
RCC_CLOCK_MUX_PWR,
RCC_CLOCK_MUX_CAN1,
RCC_CLOCK_MUX_SPI3,
RCC_CLOCK_MUX_SPI2,
RCC_CLOCK_MUX_WWDG,
RCC_CLOCK_MUX_LCD,
RCC_CLOCK_MUX_TIM7,
RCC_CLOCK_MUX_TIM6,
RCC_CLOCK_MUX_TIM5,
RCC_CLOCK_MUX_TIM4,
RCC_CLOCK_MUX_TIM3,
RCC_CLOCK_MUX_TIM2,
/* - APB2 */
RCC_CLOCK_MUX_TIM17,
RCC_CLOCK_MUX_TIM16,
RCC_CLOCK_MUX_TIM15,
RCC_CLOCK_MUX_TIM8,
RCC_CLOCK_MUX_SPI1,
RCC_CLOCK_MUX_TIM1,
RCC_CLOCK_MUX_SDMMC1,
RCC_CLOCK_MUX_FW,
RCC_CLOCK_MUX_SYSCFG,
/* - BDCR */
RCC_CLOCK_MUX_RTC,
/* - OTHER */
RCC_CLOCK_MUX_CORTEX_FCLK,
RCC_NUM_CLOCK_MUX
} RccClockMux;
typedef enum RccPll {
RCC_PLL_PLL,
RCC_PLL_PLLSAI1,
RCC_PLL_PLLSAI2,
RCC_NUM_PLL
} RccPll;
typedef struct RccClockMuxState {
DeviceState parent_obj;
RccClockMux id;
Clock *srcs[RCC_NUM_CLOCK_MUX_SRC];
Clock *out;
bool enabled;
uint32_t src;
uint32_t multiplier;
uint32_t divider;
/*
* Used by clock srcs update callback to retrieve both the clock and the
* source number.
*/
struct RccClockMuxState *backref[RCC_NUM_CLOCK_MUX_SRC];
} RccClockMuxState;
typedef struct RccPllState {
DeviceState parent_obj;
RccPll id;
Clock *in;
uint32_t vco_multiplier;
Clock *channels[RCC_NUM_CHANNEL_PLL_OUT];
/* Global pll enabled flag */
bool enabled;
/* 'enabled' refers to the runtime configuration */
bool channel_enabled[RCC_NUM_CHANNEL_PLL_OUT];
/*
* 'exists' refers to the physical configuration
* It should only be set at pll initialization.
* e.g. pllsai2 doesn't have a Q output.
*/
bool channel_exists[RCC_NUM_CHANNEL_PLL_OUT];
uint32_t channel_divider[RCC_NUM_CHANNEL_PLL_OUT];
} RccPllState;
struct Stm32l4x5RccState {
SysBusDevice parent_obj;
MemoryRegion mmio;
uint32_t cr;
uint32_t icscr;
uint32_t cfgr;
uint32_t pllcfgr;
uint32_t pllsai1cfgr;
uint32_t pllsai2cfgr;
uint32_t cier;
uint32_t cifr;
uint32_t ahb1rstr;
uint32_t ahb2rstr;
uint32_t ahb3rstr;
uint32_t apb1rstr1;
uint32_t apb1rstr2;
uint32_t apb2rstr;
uint32_t ahb1enr;
uint32_t ahb2enr;
uint32_t ahb3enr;
uint32_t apb1enr1;
uint32_t apb1enr2;
uint32_t apb2enr;
uint32_t ahb1smenr;
uint32_t ahb2smenr;
uint32_t ahb3smenr;
uint32_t apb1smenr1;
uint32_t apb1smenr2;
uint32_t apb2smenr;
uint32_t ccipr;
uint32_t bdcr;
uint32_t csr;
/* Clock sources */
Clock *gnd;
Clock *hsi16_rc;
Clock *msi_rc;
Clock *hse;
Clock *lsi_rc;
Clock *lse_crystal;
Clock *sai1_extclk;
Clock *sai2_extclk;
/* PLLs */
RccPllState plls[RCC_NUM_PLL];
/* Muxes ~= outputs */
RccClockMuxState clock_muxes[RCC_NUM_CLOCK_MUX];
qemu_irq irq;
uint64_t hse_frequency;
uint64_t sai1_extclk_frequency;
uint64_t sai2_extclk_frequency;
};
#endif /* HW_STM32L4X5_RCC_H */