/** @defgroup rcc_defines RCC Defines
@brief <b>Defined Constants and Types for the STM32H7xx Reset and Clock
Control</b>
@ingroup STM32H7xx_defines
@version 1.0.0
LGPL License Terms @ref lgpl_license
 */
/*
 * This file is part of the libopencm3 project.
 *
 * Copyright (C) 2019 Brian Viele <vielster@allocor.tech>
 *
 * This library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef LIBOPENCM3_RCC_H
#define LIBOPENCM3_RCC_H

#include <libopencm3/cm3/common.h>
#include <libopencm3/stm32/h7/pwr.h>

/**@{*/

/** @defgroup rcc_registers RCC Registers
@{*/
#define RCC_CR                    MMIO32(RCC_BASE + 0x000)
#define RCC_ICSCR                 MMIO32(RCC_BASE + 0x004)  /* Y-devices only */
#define RCC_HSICFGR               MMIO32(RCC_BASE + 0x004)  /* V-devices only */
#define RCC_CRRCR                 MMIO32(RCC_BASE + 0x008)
#define RCC_CSICFGR               MMIO32(RCC_BASE + 0x00C)  /* V-devices only */
#define RCC_CFGR                  MMIO32(RCC_BASE + 0x010)
#define RCC_D1CFGR                MMIO32(RCC_BASE + 0x018)
#define RCC_D2CFGR                MMIO32(RCC_BASE + 0x01C)
#define RCC_D3CFGR                MMIO32(RCC_BASE + 0x020)
#define RCC_PLLCKSELR             MMIO32(RCC_BASE + 0x028)
#define RCC_PLLCFGR               MMIO32(RCC_BASE + 0x02C)
/* PLLs are 1-based, so reference macros to 1..3, using index 0 will give undefined behavior. */
#define RCC_PLLDIVR(n)            MMIO32(RCC_BASE + 0x030 + (0x08 * ((n) - 1)))
#define RCC_PLLFRACR(n)           MMIO32(RCC_BASE + 0x030 + (0x08 * ((n) - 1)))
#define RCC_PLL1DIVR              RCC_PLLDIVR(1)
#define RCC_PLL1FRACR             RCC_PLLFRACR(1)
#define RCC_PLL2DIVR              RCC_PLLDIVR(2)
#define RCC_PLL2FRACR             RCC_PLLFRACR(2)
#define RCC_PLL3DIVR              RCC_PLLDIVR(3)
#define RCC_PLL3FRACR             RCC_PLLFRACR(3)
#define RCC_D1CCIPR               MMIO32(RCC_BASE + 0x04C)
#define RCC_D2CCIP1R              MMIO32(RCC_BASE + 0x050)
#define RCC_D2CCIP2R              MMIO32(RCC_BASE + 0x054)
#define RCC_D3CCIPR               MMIO32(RCC_BASE + 0x058)
#define RCC_AHB1RSTR              MMIO32(RCC_BASE + 0x080)
#define RCC_AHB2RSTR              MMIO32(RCC_BASE + 0x084)
#define RCC_AHB3RSTR              MMIO32(RCC_BASE + 0x07C)
#define RCC_AHB4RSTR              MMIO32(RCC_BASE + 0x088)
#define RCC_APB1LRSTR             MMIO32(RCC_BASE + 0x090)
#define RCC_APB1HRSTR             MMIO32(RCC_BASE + 0x094)
#define RCC_APB2RSTR              MMIO32(RCC_BASE + 0x098)
#define RCC_APB3RSTR              MMIO32(RCC_BASE + 0x08C)
#define RCC_APB4RSTR              MMIO32(RCC_BASE + 0x09C)
#define RCC_AHB1ENR               MMIO32(RCC_BASE + 0x0D8)
#define RCC_AHB2ENR               MMIO32(RCC_BASE + 0x0DC)
#define RCC_AHB3ENR               MMIO32(RCC_BASE + 0x0D4)
#define RCC_AHB4ENR               MMIO32(RCC_BASE + 0x0E0)
#define RCC_APB1LENR              MMIO32(RCC_BASE + 0x0E8)
#define RCC_APB1HENR              MMIO32(RCC_BASE + 0x0EC)
#define RCC_APB2ENR               MMIO32(RCC_BASE + 0x0F0)
#define RCC_APB3ENR               MMIO32(RCC_BASE + 0x0E4)
#define RCC_APB4ENR               MMIO32(RCC_BASE + 0x0F4)
#define RCC_AHB1LPENR             MMIO32(RCC_BASE + 0x100)
#define RCC_AHB2LPENR             MMIO32(RCC_BASE + 0x104)
#define RCC_AHB4LPENR             MMIO32(RCC_BASE + 0x108)
#define RCC_APB1LLPENR            MMIO32(RCC_BASE + 0x110)
#define RCC_APB1HLPENR            MMIO32(RCC_BASE + 0x114)
#define RCC_APB2LPENR             MMIO32(RCC_BASE + 0x118)
#define RCC_APB3LPENR             MMIO32(RCC_BASE + 0x10C)
#define RCC_APB4LPENR             MMIO32(RCC_BASE + 0x11C)
#define RCC_BDCR                  MMIO32(RCC_BASE + 0x70)
#define RCC_CSR                   MMIO32(RCC_BASE + 0x74)
#define RCC_SSCGR                 MMIO32(RCC_BASE + 0x80)
#define RCC_PLLI2SCFGR            MMIO32(RCC_BASE + 0x84)
#define RCC_PLLSAICFGR            MMIO32(RCC_BASE + 0x88)
#define RCC_DCKCFGR1              MMIO32(RCC_BASE + 0x8C)
#define RCC_DCKCFGR2              MMIO32(RCC_BASE + 0x90)
/**@}*/

/** @defgroup rcc_cr_values RCC_CR Values
 * @ingroup rcc_registers
@{*/
#define RCC_CR_PLL3RDY            BIT29
#define RCC_CR_PLL3ON             BIT28
#define RCC_CR_PLL2RDY            BIT27
#define RCC_CR_PLL2ON             BIT26
#define RCC_CR_PLL1RDY            BIT25
#define RCC_CR_PLL1ON             BIT24
#define RCC_CR_HSECSSON           BIT19
#define RCC_CR_HSEBYP             BIT18
#define RCC_CR_HSERDY             BIT17
#define RCC_CR_HSEON              BIT16
#define RCC_CR_D2CKRDY            BIT15
#define RCC_CR_D1CKRDY            BIT14
#define RCC_CR_HSI48RDY           BIT13
#define RCC_CR_HSI48ON            BIT12
#define RCC_CR_CSIKERON           BIT9
#define RCC_CR_CSIRDY             BIT8
#define RCC_CR_CSION              BIT7
#define RCC_CR_HSIDIVF            BIT5
#define RCC_CR_HSIDIV_MASK        (0x03)
#define RCC_CR_HSIDIV_SHIFT       3
#define RCC_CR_HSIDIV(n)          (((n) & RCC_CR_HSIDIV_MASK) << RCC_CR_HSIDIV_MASK)
#define RCC_CR_HSIRDY             BIT2
#define RCC_CR_HSIKERON           BIT1
#define RCC_CR_HSION              BIT0
/**@}*/


/** @defgroup rcc_cfgr_values RCC_CFGR Values
 * @ingroup rcc_registers
@{*/
/* MCO2: Microcontroller clock output 2 */
#define RCC_CFGR_MCO2_MASK        0x7
#define RCC_CFGR_MCO2_SHIFT       29
#define RCC_CFGR_MCO2_SYSCLK      0x0
#define RCC_CFGR_MCO2_PLL2        0x1
#define RCC_CFGR_MCO2_HSE         0x2
#define RCC_CFGR_MCO2_PLL1        0x3
#define RCC_CFGR_MCO2_CSI         0x4
#define RCC_CFGR_MCO2_LSI         0x5

/* MCO1/2PRE: MCO Prescalers */
#define RCC_CFGR_MCOPRE_MASK      0xf
#define RCC_CFGR_MCO2PRE_SHIFT    25
#define RCC_CFGR_MCO1PRE_SHIFT    18
#define RCC_CFGR_MCOPRE_DIV_NONE  0x0
#define RCC_CFGR_MCOPRE_DIV_BYP   0x1
#define RCC_CFGR_MCOPRE_DIV_2     0x2
#define RCC_CFGR_MCOPRE_DIV_3     0x3
#define RCC_CFGR_MCOPRE_DIV_4     0x4
/* Note: MCOPRE_DIV can go from 1 - 15  */

/* MCO1: Microcontroller clock output 1 */
#define RCC_CFGR_MCO1_MASK        0x7
#define RCC_CFGR_MCO1_SHIFT       22
#define RCC_CFGR_MCO1_HSI         0x0
#define RCC_CFGR_MCO1_LSE         0x1
#define RCC_CFGR_MCO1_HSE         0x2
#define RCC_CFGR_MCO1_PLL1        0x3
#define RCC_CFGR_MCO1_HSI48       0x4
#define RCC_CFGR_MCO_SHIFT        RCC_CFGR_MCO1_SHIFT
#define RCC_CFGR_MCO_MASK         RCC_CFGR_MCO1_MASK

/* RTCPRE: HSE division factor for RTC clock */
#define RCC_CFGR_RTCPRE_SHIFT     8
#define RCC_CFGR_RTCPRE_MASK      0x3f

/* SWS: System clock switch status */
#define RCC_CFGR_SWS_SHIFT        3
#define RCC_CFGR_SWS_MASK         0x7
#define RCC_CFGR_SWS_HSI          0x0
#define RCC_CFGR_SWS_CSI          0x1
#define RCC_CFGR_SWS_HSE          0x2
#define RCC_CFGR_SWS_PLL1         0x3

/* SW: System clock switch */
#define RCC_CFGR_SW_SHIFT         0
#define RCC_CFGR_SW_MASK          0x7
#define RCC_CFGR_SW_HSI           0x0
#define RCC_CFGR_SW_CSI           0x1
#define RCC_CFGR_SW_HSE           0x2
#define RCC_CFGR_SW_PLL1          0x3
/**@}*/

/** @defgroup rcc_d1cfgr_values RCC_D1CFGR Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_D1CFGR_D1CPRE_BYP       0x0
#define RCC_D1CFGR_D1CPRE_DIV2      0x8
#define RCC_D1CFGR_D1CPRE_DIV4      0x9
#define RCC_D1CFGR_D1CPRE_DIV8      0xA
#define RCC_D1CFGR_D1CPRE_DIV16     0xB
#define RCC_D1CFGR_D1CPRE_DIV64     0xC
#define RCC_D1CFGR_D1CPRE_DIV128    0xD
#define RCC_D1CFGR_D1CPRE_DIV256    0xE
#define RCC_D1CFGR_D1CPRE_DIV512    0xF
#define RCC_D1CFGR_D1PPRE_BYP       0x0
#define RCC_D1CFGR_D1PPRE_DIV2      0x4
#define RCC_D1CFGR_D1PPRE_DIV4      0x5
#define RCC_D1CFGR_D1PPRE_DIV8      0x6
#define RCC_D1CFGR_D1PPRE_DIV16     0x7
#define RCC_D1CFGR_D1HPRE_BYP       0x0
#define RCC_D1CFGR_D1HPRE_DIV2      0x8
#define RCC_D1CFGR_D1HPRE_DIV4      0x9
#define RCC_D1CFGR_D1HPRE_DIV8      0xA
#define RCC_D1CFGR_D1HPRE_DIV16     0xB
#define RCC_D1CFGR_D1HPRE_DIV64     0xC
#define RCC_D1CFGR_D1HPRE_DIV128    0xD
#define RCC_D1CFGR_D1HPRE_DIV256    0xE
#define RCC_D1CFGR_D1HPRE_DIV512    0xF

#define RCC_D1CFGR_D1CPRE_SHIFT     8
#define RCC_D1CFGR_D1PPRE_SHIFT     4
#define RCC_D1CFGR_D1CPRE(cpre)     (cpre << RCC_D1CFGR_D1CPRE_SHIFT)
#define RCC_D1CFGR_D1PPRE(ppre)     (ppre << RCC_D1CFGR_D1PPRE_SHIFT)
#define RCC_D1CFGR_D1HPRE(hpre)     (hpre)
/**@}*/

/** @defgroup rcc_d2cfgr_values RCC_D2CFGR Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_D2CFGR_D2PPRE_BYP       0x0
#define RCC_D2CFGR_D2PPRE_DIV2      0x4
#define RCC_D2CFGR_D2PPRE_DIV4      0x5
#define RCC_D2CFGR_D2PPRE_DIV8      0x6
#define RCC_D2CFGR_D2PPRE_DIV16     0x7

#define RCC_D2CFGR_D2PPRE2_SHIFT    8
#define RCC_D2CFGR_D2PPRE1_SHIFT    4
#define RCC_D2CFGR_D2PPRE2(ppre)    (ppre << RCC_D2CFGR_D2PPRE2_SHIFT)
#define RCC_D2CFGR_D2PPRE1(ppre)    (ppre << RCC_D2CFGR_D2PPRE1_SHIFT)
/**@}*/

/** @defgroup rcc_d3cfgr_values RCC_D3CFGR Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_D3CFGR_D3PPRE_BYP       0x0
#define RCC_D3CFGR_D3PPRE_DIV2      0x4
#define RCC_D3CFGR_D3PPRE_DIV4      0x5
#define RCC_D3CFGR_D3PPRE_DIV8      0x6
#define RCC_D3CFGR_D3PPRE_DIV16     0x7
#define RCC_D3CFGR_D3PPRE_SHIFT     4
#define RCC_D3CFGR_D3PPRE(ppre)     (ppre << RCC_D3CFGR_D3PPRE_SHIFT)
/**@}*/

/** @defgroup rcc_pllckselr_values RCC_PLLCKSELR Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_PLLCKSELR_PLLSRC_HSI    0x0
#define RCC_PLLCKSELR_PLLSRC_CSI    0x1
#define RCC_PLLCKSELR_PLLSRC_HSE    0x2
#define RCC_PLLCKSELR_PLLSRC_NONE   0x3
#define RCC_PLLCKSELR_DIVM_DIS      0
#define RCC_PLLCKSELR_DIVM_BYP      1
#define RCC_PLLCKSELR_DIVM_MASK     0x3f

#define RCC_PLLCKSELR_DIVM3_SHIFT   20
#define RCC_PLLCKSELR_DIVM2_SHIFT   12
#define RCC_PLLCKSELR_DIVM1_SHIFT   4

#define RCC_PLLCKSELR_DIVM3(n)      ((n) << RCC_PLLCKSELR_DIVM3_SHIFT)
#define RCC_PLLCKSELR_DIVM2(n)      ((n) << RCC_PLLCKSELR_DIVM2_SHIFT)
#define RCC_PLLCKSELR_DIVM1(n)      ((n) << RCC_PLLCKSELR_DIVM1_SHIFT)
/**@}*/

/** @defgroup rcc_pllcfgr_values RCC_PLLCFGR Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_PLLCFGR_PLLRGE_1_2MHZ   0
#define RCC_PLLCFGR_PLLRGE_2_4MHZ   1
#define RCC_PLLCFGR_PLLRGE_4_8MHZ   2
#define RCC_PLLCFGR_PLLRGE_8_16MHZ  3

#define RCC_PLLCFGR_DIVR3EN         BIT24
#define RCC_PLLCFGR_DIVQ3EN         BIT23
#define RCC_PLLCFGR_DIVP3EN         BIT22
#define RCC_PLLCFGR_DIVR2EN         BIT21
#define RCC_PLLCFGR_DIVQ2EN         BIT20
#define RCC_PLLCFGR_DIVP2EN         BIT19
#define RCC_PLLCFGR_DIVR1EN         BIT18
#define RCC_PLLCFGR_DIVQ1EN         BIT17
#define RCC_PLLCFGR_DIVP1EN         BIT16
#define RCC_PLLCFGR_PLL3RGE_SHIFT   10
#define RCC_PLLCFGR_PLL3VCO_WIDE    0       /* 192 - 836MHz base output. */
#define RCC_PLLCFGR_PLL3VCO_MED     BIT9    /* 150 - 420MHz base output. */
#define RCC_PLLCFGR_PLL3FRACEN      BIT8
#define RCC_PLLCFGR_PLL2RGE_SHIFT   6
#define RCC_PLLCFGR_PLL2VCO_WIDE    0       /* 192 - 836MHz base output. */
#define RCC_PLLCFGR_PLL2VCO_MED     BIT5    /* 150 - 420MHz base output. */
#define RCC_PLLCFGR_PLL2FRACEN      BIT4
#define RCC_PLLCFGR_PLL1RGE_SHIFT   2
#define RCC_PLLCFGR_PLL1VCO_WIDE    0       /* 192 - 836MHz base output. */
#define RCC_PLLCFGR_PLL1VCO_MED     BIT1    /* 150 - 420MHz base output. */
#define RCC_PLLCFGR_PLL1FRACEN      BIT0
/**@}*/

/** @defgroup rcc_plldivr_values RCC_PLLnDIVR Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_PLLNDIVR_DIVR_SHIFT     24
#define RCC_PLLNDIVR_DIVQ_SHIFT     16
#define RCC_PLLNDIVR_DIVP_SHIFT     9
#define RCC_PLLNDIVR_DIVN_SHIFT     0

/* Need to preserve reserved bits, so give easy mask shortcut. */
#define RCC_PLLNDIVR_DIVR(n)        (((n) - 1) << RCC_PLLNDIVR_DIVR_SHIFT)
#define RCC_PLLNDIVR_DIVQ(n)        (((n) - 1) << RCC_PLLNDIVR_DIVQ_SHIFT)
#define RCC_PLLNDIVR_DIVP(n)        (((n) - 1) << RCC_PLLNDIVR_DIVP_SHIFT)
#define RCC_PLLNDIVR_DIVN(n)        (((n) - 1) << RCC_PLLNDIVR_DIVN_SHIFT)
/**@}*/

/** @defgroup rcc_bdcr_values RCC_BDCR Values
 * @ingroup rcc_registers
@{*/
#define RCC_BDCR_BDRST            (1 << 16)
#define RCC_BDCR_RTCEN            (1 << 15)
#define RCC_BDCR_RTCSEL_MASK      0x3
#define RCC_BDCR_RTCSEL_SHIFT     8
#define RCC_BDCR_RTCSEL_NONE      0
#define RCC_BDCR_RTCSEL_LSE       1
#define RCC_BDCR_RTCSEL_LSI       2
#define RCC_BDCR_RTCSEL_HSE       3
#define RCC_BDCR_LSEDRV_MASK      0x3
#define RCC_BDCR_LSEDRV_SHIFT     3
#define RCC_BDCR_LSEDRV_LOW       0
#define RCC_BDCR_LSEDRV_MEDH      1 /* good job st */
#define RCC_BDCR_LSEDRV_MEDL      2
#define RCC_BDCR_LSEDRV_HIGH      3
#define RCC_BDCR_LSEBYP           (1 << 2)
#define RCC_BDCR_LSERDY           (1 << 1)
#define RCC_BDCR_LSEON            (1 << 0)
/**@}*/

/** @defgroup rcc_csr_values RCC_CSR Values.
 * @ingroup rcc_registers
@{*/
#define RCC_CSR_LSIRDY            (1 << 1)
#define RCC_CSR_LSION             (1 << 0)
/**@}*/

/** @defgroup rcc_d1ccipr_values RCC_D1CCIP1R Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_D1CCIPR_CKPERSEL_HSI       0
#define RCC_D1CCIPR_CKPERSEL_CSI       1
#define RCC_D1CCIPR_CKPERSEL_HSE       2
#define RCC_D1CCIPR_CKPERSEL_DISABLE   3
/**@}*/
#define RCC_D1CCIPR_CKPERSEL_SHIFT     28
#define RCC_D1CCIPR_CKPERSEL_MASK      3

#define RCC_D2CCIP1R_SWPSEL_SHIFT       31
#define RCC_D2CCIP1R_FDCANSEL_SHIFT     28
#define RCC_D2CCIP1R_FDCANSEL_MASK      0x3
#define RCC_D2CCIP1R_DFSDM1SEL_SHIFT    24
#define RCC_D2CCIP1R_SPDIFSEL_SHIFT     20
#define RCC_D2CCIP1R_SPI45SEL_SHIFT     16
#define RCC_D2CCIP1R_SPI45SEL_MASK      0x7
#define RCC_D2CCIP1R_SPI123SEL_SHIFT    12
#define RCC_D2CCIP1R_SPI123SEL_MASK     0x7
#define RCC_D2CCIP1R_SAI23SEL_SHIFT     6
#define RCC_D2CCIP1R_SAISEL_MASK        0x7

/** @defgroup rcc_d2ccip1r_values RCC_D2CCIP1R Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_D2CCIP1R_SWPSEL_PCLK        0x0
#define RCC_D2CCIP1R_SWPSEL_HSI         0x1
#define RCC_D2CCIP1R_FDCANSEL_HSE       0x0
#define RCC_D2CCIP1R_FDCANSEL_PLL1Q     0x1
#define RCC_D2CCIP1R_FDCANSEL_PLL2Q     0x2
#define RCC_D2CCIP1R_DFSDM1SEL_PCLK2    0x0
#define RCC_D2CCIP1R_DFSDM1SEL_SYSCLK   0x1
#define RCC_D2CCIP1R_SPDIFSEL_PLL1Q     0x0
#define RCC_D2CCIP1R_SPDIFSEL_PLL2R     0x1
#define RCC_D2CCIP1R_SPDIFSEL_PLL3R     0x2
#define RCC_D2CCIP1R_SPDIFSEL_HSI       0x3
#define RCC_D2CCIP1R_SPI45SEL_APB4      0x0
#define RCC_D2CCIP1R_SPI45SEL_PLL2Q     0x1
#define RCC_D2CCIP1R_SPI45SEL_PLL3Q     0x2
#define RCC_D2CCIP1R_SPI45SEL_HSI       0x3
#define RCC_D2CCIP1R_SPI45SEL_CSI       0x4
#define RCC_D2CCIP1R_SPI45SEL_HSE       0x5
#define RCC_D2CCIP1R_SPI123SEL_PLL1Q    0x0
#define RCC_D2CCIP1R_SPI123SEL_PLL2P    0x1
#define RCC_D2CCIP1R_SPI123SEL_PLL3P    0x2
#define RCC_D2CCIP1R_SPI123SEL_I2SCKIN  0x3
#define RCC_D2CCIP1R_SPI123SEL_PERCK    0x4
#define RCC_D2CCIP1R_SAISEL_PLL1Q       0x0
#define RCC_D2CCIP1R_SAISEL_PLL2P       0x1
#define RCC_D2CCIP1R_SAISEL_PLL3P       0x2
#define RCC_D2CCIP1R_SAISEL_I2SCKIN     0x3
#define RCC_D2CCIP1R_SAISEL_PERCK       0x4
/**@}*/

#define RCC_D2CCIP2R_LPTIM1SEL_SHIFT        28
#define RCC_D2CCIP2R_CECSEL_SHIFT           22
#define RCC_D2CCIP2R_USBSEL_SHIFT           20
#define RCC_D2CCIP2R_I2C123SEL_SHIFT        12
#define RCC_D2CCIP2R_RNGSEL_MASK            0x3
#define RCC_D2CCIP2R_RNGSEL_SHIFT           8
#define RCC_D2CCIP2R_USART16SEL_SHIFT       3
#define RCC_D2CCIP2R_USART234578SEL_SHIFT   0
#define RCC_D2CCIP2R_USARTSEL_MASK          7

/** @defgroup rcc_d2ccip2r_values RCC_D2CCIP2R Values
 * @ingroup rcc_registers
 * @{*/
#define RCC_D2CCIP2R_RNGSEL_HSI48           0
#define RCC_D2CCIP2R_RNGSEL_PLL1Q           1
#define RCC_D2CCIP2R_RNGSEL_LSE             2
#define RCC_D2CCIP2R_RNGSEL_LSI             3
#define RCC_D2CCIP2R_USART16SEL_PCLK2       0
#define RCC_D2CCIP2R_USART234578SEL_PCLK1   0
#define RCC_D2CCIP2R_USARTSEL_PCLK          0
#define RCC_D2CCIP2R_USARTSEL_PLL2Q         1
#define RCC_D2CCIP2R_USARTSEL_PLL3Q         2
#define RCC_D2CCIP2R_USARTSEL_HSI           3
#define RCC_D2CCIP2R_USARTSEL_CSI           4
#define RCC_D2CCIP2R_USARTSEL_LSE           5
/**@}*/


#define RCC_HSI_BASE_FREQUENCY              64000000UL

/** Enumerations for core system/bus clocks for user/driver/system access to base bus clocks
  * not directly associated with a peripheral. */
enum rcc_clock_source {
	RCC_CPUCLK,
	RCC_SYSCLK,
	RCC_PERCLK,
	RCC_SYSTICKCLK,
	RCC_HCLK3,
	RCC_AHBCLK,           /* AHB1,2,4 all share base HCLK. */
	RCC_APB1CLK,          /* Note: APB1 and PCLK1 in manual */
	RCC_APB2CLK,          /* Note: APB2 and PCLK2 in manual */
	RCC_APB3CLK,          /* Note: APB3 and PCLK3 in manual */
	RCC_APB4CLK,          /* Note: APB4 and PCLK4 in manual */
};

enum rcc_osc {
	RCC_PLL,
	RCC_HSE,
	RCC_HSI,
	RCC_LSE,
	RCC_LSI
};

/** PLL Configuration structure. */
struct rcc_pll_config {
	enum rcc_osc sysclock_source;     /**< SYSCLK source input selection. */
	uint8_t pll_source;               /**< RCC_PLLCKSELR_PLLSRC_xxx value. */
	uint32_t hse_frequency;           /**< User specified HSE frequency, 0 if none. */
	struct pll_config {
		uint8_t divm;                   /**< Pre-divider value for each PLL. 0-64 integers. */
		uint16_t divn;                  /**< Multiplier, 0-512 integer. */
		uint8_t divp;                   /**< Post divider for PLLP clock. */
		uint8_t divq;                   /**< Post divider for PLLQ clock. */
		uint8_t divr;                   /**< Post divider for PLLR clock. */
	} pll1, pll2, pll3;               /**< PLL1-PLL3 configurations. */
	uint8_t core_pre;                 /**< Core prescaler  note: domain 1. */
	uint8_t hpre;                     /**< HCLK3 prescaler note: domain 1. */
	uint8_t ppre1;                    /**< APB1 Peripheral prescaler note: domain 2. */
	uint8_t ppre2;                    /**< APB2 Peripheral prescaler note: domain 2. */
	uint8_t ppre3;                    /**< APB3 Peripheral prescaler note: domain 1. */
	uint8_t ppre4;                    /**< APB4 Peripheral prescaler note: domain 3. */
	uint8_t flash_waitstates;         /**< Latency Value to set for flahs. */
	enum pwr_vos_scale voltage_scale; /**< LDO/SMPS Voltage scale used for this frequency. */
	enum pwr_sys_mode power_mode;     /**< LDO/SMPS configuration for device. */
	uint8_t smps_level;               /**< If using SMPS, voltage level to set. */
};

#define _REG_BIT(base, bit)       (((base) << 5) + (bit))

enum rcc_periph_clken {
	/* AHB1 peripherals */
	RCC_DMA1        = _REG_BIT(0xD8, 0),
	RCC_DMA2        = _REG_BIT(0xD8, 1),
	RCC_ADC12       = _REG_BIT(0xD8, 5),
	RCC_ETH1MAC     = _REG_BIT(0xD8, 15),
	RCC_ETH1TX      = _REG_BIT(0xD8, 16),
	RCC_ETH1RX      = _REG_BIT(0xD8, 17),
	RCC_USB2OTGHSULPIEN = _REG_BIT(0xD8, 18),
	RCC_USB1OTGHSEN = _REG_BIT(0xD8, 25),
	RCC_USB1OTGHSULPIEN = _REG_BIT(0xD8, 26),
	RCC_USB2OTGHSEN = _REG_BIT(0xD8, 27),

	/* AHB2 peripherals */
	RCC_DCMI        = _REG_BIT(0xDC, 0),
	RCC_CRYP        = _REG_BIT(0xDC, 4),
	RCC_HASH        = _REG_BIT(0xDC, 5),
	RCC_RNG         = _REG_BIT(0xDC, 6),
	RCC_SDMMC2      = _REG_BIT(0xDC, 9),
	RCC_SRAM1       = _REG_BIT(0xDC, 29),
	RCC_SRAM2       = _REG_BIT(0xDC, 30),
	RCC_SRAM3       = _REG_BIT(0xDC, 31),

	/* AHB3 peripherals */
	RCC_MDMA        = _REG_BIT(0xD4, 0),
	RCC_DMA2D       = _REG_BIT(0xD4, 4),
	RCC_JPGDEC      = _REG_BIT(0xD4, 5),
	RCC_FMC         = _REG_BIT(0xD4, 12),
	RCC_QSPI        = _REG_BIT(0xD4, 14),
	RCC_SDMMC1      = _REG_BIT(0xD4, 16),

	/* AHB4 peripherals*/
	RCC_GPIOA       = _REG_BIT(0xE0, 0),
	RCC_GPIOB       = _REG_BIT(0xE0, 1),
	RCC_GPIOC       = _REG_BIT(0xE0, 2),
	RCC_GPIOD       = _REG_BIT(0xE0, 3),
	RCC_GPIOE       = _REG_BIT(0xE0, 4),
	RCC_GPIOF       = _REG_BIT(0xE0, 5),
	RCC_GPIOG       = _REG_BIT(0xE0, 6),
	RCC_GPIOH       = _REG_BIT(0xE0, 7),
	RCC_GPIOI       = _REG_BIT(0xE0, 8),
	RCC_GPIOJ       = _REG_BIT(0xE0, 9),
	RCC_GPIOK       = _REG_BIT(0xE0, 10),
	RCC_CRC         = _REG_BIT(0xE0, 19),
	RCC_BDMA        = _REG_BIT(0xE0, 21),
	RCC_ADC3        = _REG_BIT(0xE0, 24),
	RCC_HSEM        = _REG_BIT(0xE0, 25),
	RCC_BKPSRAM     = _REG_BIT(0xE0, 28),

	/* APB1L peripherals*/
	RCC_TIM2        = _REG_BIT(0xE8, 0),
	RCC_TIM3        = _REG_BIT(0xE8, 1),
	RCC_TIM4        = _REG_BIT(0xE8, 2),
	RCC_TIM5        = _REG_BIT(0xE8, 3),
	RCC_TIM6        = _REG_BIT(0xE8, 4),
	RCC_TIM7        = _REG_BIT(0xE8, 5),
	RCC_TIM12       = _REG_BIT(0xE8, 6),
	RCC_TIM13       = _REG_BIT(0xE8, 7),
	RCC_TIM14       = _REG_BIT(0xE8, 8),
	RCC_LPTIM1      = _REG_BIT(0xE8, 9),
	RCC_SPI2        = _REG_BIT(0xE8, 14),
	RCC_SPI3        = _REG_BIT(0xE8, 15),
	RCC_SPDIFRX     = _REG_BIT(0xE8, 16),
	RCC_USART2      = _REG_BIT(0xE8, 17),
	RCC_USART3      = _REG_BIT(0xE8, 18),
	RCC_UART4       = _REG_BIT(0xE8, 19),
	RCC_UART5       = _REG_BIT(0xE8, 20),
	RCC_I2C1        = _REG_BIT(0xE8, 21),
	RCC_I2C2        = _REG_BIT(0xE8, 22),
	RCC_I2C3        = _REG_BIT(0xE8, 23),
	RCC_CEC         = _REG_BIT(0xE8, 27),
	RCC_DAC         = _REG_BIT(0xE8, 29),
	RCC_UART7       = _REG_BIT(0xE8, 30),
	RCC_UART8       = _REG_BIT(0xE8, 31),

	/* APB1H peripherals*/
	RCC_CRS         = _REG_BIT(0xEC, 1),
	RCC_SWP         = _REG_BIT(0xEC, 2),
	RCC_OPAMP       = _REG_BIT(0xEC, 4),
	RCC_MDIO        = _REG_BIT(0xEC, 5),
	RCC_FDCAN       = _REG_BIT(0xEC, 8),

	/* APB2 peripherals */
	RCC_TIM1        = _REG_BIT(0xF0, 0),
	RCC_TIM8        = _REG_BIT(0xF0, 1),
	RCC_USART1      = _REG_BIT(0xF0, 4),
	RCC_USART6      = _REG_BIT(0xF0, 5),
	RCC_SPI1        = _REG_BIT(0xF0, 12),
	RCC_SPI4        = _REG_BIT(0xF0, 13),
	RCC_TIM15       = _REG_BIT(0xF0, 16),
	RCC_TIM16       = _REG_BIT(0xF0, 17),
	RCC_TIM17       = _REG_BIT(0xF0, 18),
	RCC_SPI5        = _REG_BIT(0xF0, 20),
	RCC_SAI1        = _REG_BIT(0xF0, 22),
	RCC_SAI2        = _REG_BIT(0xF0, 23),
	RCC_SAI3        = _REG_BIT(0xF0, 24),
	RCC_DFSDM       = _REG_BIT(0xF0, 28),
	RCC_HRTIM       = _REG_BIT(0xF0, 29),

	/* APB3 peripherals */
	RCC_LTDCEN      = _REG_BIT(0xE4, 3),
	RCC_WWDG1EN     = _REG_BIT(0xE4, 6),

	/* APB4 peripherals */
	RCC_SYSCFG      = _REG_BIT(0xF4, 1),
	RCC_LPUART1     = _REG_BIT(0xF4, 3),
	RCC_SPI6        = _REG_BIT(0xF4, 5),
	RCC_I2C4        = _REG_BIT(0xF4, 7),
	RCC_LPTIM2      = _REG_BIT(0xF4, 9),
	RCC_LPTIM3      = _REG_BIT(0xF4, 10),
	RCC_LPTIM4      = _REG_BIT(0xF4, 11),
	RCC_LPTIM5      = _REG_BIT(0xF4, 12),
	RCC_COMP12      = _REG_BIT(0xF4, 14),
	RCC_VREF        = _REG_BIT(0xF4, 15),
	RCC_RTCAPB      = _REG_BIT(0xF4, 16),
	RCC_SAI4        = _REG_BIT(0xF4, 21),
};

enum rcc_periph_rst {
	/* AHB1 peripherals */
	RST_DMA1        = _REG_BIT(0x80, 0),
	RST_DMA2        = _REG_BIT(0x80, 1),
	RST_ADC12       = _REG_BIT(0x80, 5),
	RST_ETH1MAC     = _REG_BIT(0x80, 15),
	RST_USB1OTGRST  = _REG_BIT(0x80, 25),
	RST_USB2OTGRST  = _REG_BIT(0x80, 27),

	/* AHB2 peripherals */
	RST_DCMI        = _REG_BIT(0xDC, 0),
	RST_CRYP        = _REG_BIT(0xDC, 4),
	RST_HASH        = _REG_BIT(0xDC, 5),
	RST_RNG         = _REG_BIT(0xDC, 6),
	RST_SDMMC2      = _REG_BIT(0xDC, 9),

	/* AHB3 peripherals */
	RST_MDMA        = _REG_BIT(0x7C, 0),
	RST_DMA2D       = _REG_BIT(0x7C, 4),
	RST_JPGDEC      = _REG_BIT(0x7C, 5),
	RST_FMC         = _REG_BIT(0x7C, 12),
	RST_QSPI        = _REG_BIT(0x7C, 14),
	RST_SDMMC1      = _REG_BIT(0x7C, 16),

	/* AHB4 peripherals*/
	RST_GPIOA       = _REG_BIT(0x88, 0),
	RST_GPIOB       = _REG_BIT(0x88, 1),
	RST_GPIOC       = _REG_BIT(0x88, 2),
	RST_GPIOD       = _REG_BIT(0x88, 3),
	RST_GPIOE       = _REG_BIT(0x88, 4),
	RST_GPIOF       = _REG_BIT(0x88, 5),
	RST_GPIOG       = _REG_BIT(0x88, 6),
	RST_GPIOH       = _REG_BIT(0x88, 7),
	RST_GPIOI       = _REG_BIT(0x88, 8),
	RST_GPIOJ       = _REG_BIT(0x88, 9),
	RST_GPIOK       = _REG_BIT(0x88, 10),
	RST_CRC         = _REG_BIT(0x88, 19),
	RST_BDMA        = _REG_BIT(0x88, 21),
	RST_ADC3        = _REG_BIT(0x88, 24),
	RST_HSEM        = _REG_BIT(0x88, 25),

	/* APB1L peripherals*/
	RST_TIM2        = _REG_BIT(0x90, 0),
	RST_TIM3        = _REG_BIT(0x90, 1),
	RST_TIM4        = _REG_BIT(0x90, 2),
	RST_TIM5        = _REG_BIT(0x90, 3),
	RST_TIM6        = _REG_BIT(0x90, 4),
	RST_TIM7        = _REG_BIT(0x90, 5),
	RST_TIM12       = _REG_BIT(0x90, 6),
	RST_TIM13       = _REG_BIT(0x90, 7),
	RST_TIM14       = _REG_BIT(0x90, 8),
	RST_LPTIM1      = _REG_BIT(0x90, 9),
	RST_SPI2        = _REG_BIT(0x90, 14),
	RST_SPI3        = _REG_BIT(0x90, 15),
	RST_SPDIFRX     = _REG_BIT(0x90, 16),
	RST_USART2      = _REG_BIT(0x90, 17),
	RST_USART3      = _REG_BIT(0x90, 18),
	RST_UART4       = _REG_BIT(0x90, 19),
	RST_UART5       = _REG_BIT(0x90, 20),
	RST_I2C1        = _REG_BIT(0x90, 21),
	RST_I2C2        = _REG_BIT(0x90, 22),
	RST_I2C3        = _REG_BIT(0x90, 23),
	RST_CEC         = _REG_BIT(0x90, 27),
	RST_DAC         = _REG_BIT(0x90, 29),
	RST_UART7       = _REG_BIT(0x90, 30),
	RST_UART8       = _REG_BIT(0x90, 31),

	/* APB1H peripherals*/
	RST_CRS         = _REG_BIT(0x94, 1),
	RST_SWP         = _REG_BIT(0x94, 2),
	RST_OPAMP       = _REG_BIT(0x94, 4),
	RST_MDIO        = _REG_BIT(0x94, 5),
	RST_FDCAN       = _REG_BIT(0x94, 8),

	/* APB2 peripherals */
	RST_TIM1        = _REG_BIT(0x98, 0),
	RST_TIM8        = _REG_BIT(0x98, 1),
	RST_USART1      = _REG_BIT(0x98, 4),
	RST_USART6      = _REG_BIT(0x98, 5),
	RST_SPI1        = _REG_BIT(0x98, 12),
	RST_SPI4        = _REG_BIT(0x98, 13),
	RST_TIM15       = _REG_BIT(0x98, 16),
	RST_TIM16       = _REG_BIT(0x98, 17),
	RST_TIM17       = _REG_BIT(0x98, 18),
	RST_SPI5        = _REG_BIT(0x98, 20),
	RST_SAI1        = _REG_BIT(0x98, 22),
	RST_SAI2        = _REG_BIT(0x98, 23),
	RST_SAI3        = _REG_BIT(0x98, 24),
	RST_DFSDM       = _REG_BIT(0x98, 28),
	RST_HRTIM       = _REG_BIT(0x98, 29),

	/* APB3 peripherals */
	RST_LTDCRST     = _REG_BIT(0x8C, 3),

	/* APB4 peripherals */
	RST_SYSCFG      = _REG_BIT(0x9C, 1),
	RST_LPUART1     = _REG_BIT(0x9C, 3),
	RST_SPI6        = _REG_BIT(0x9C, 5),
	RST_I2C4        = _REG_BIT(0x9C, 7),
	RST_LPTIM2      = _REG_BIT(0x9C, 9),
	RST_LPTIM3      = _REG_BIT(0x9C, 10),
	RST_LPTIM4      = _REG_BIT(0x9C, 11),
	RST_LPTIM5      = _REG_BIT(0x9C, 12),
	RST_COMP12      = _REG_BIT(0x9C, 14),
	RST_VREF        = _REG_BIT(0x9C, 15),
	RST_SAI4        = _REG_BIT(0x9C, 21),
};

#undef _REG_BIT
/**@}*/


/** @defgroup rcc_file RCC peripheral API
 *
 * @ingroup peripheral_apis
 * @{
 */
#include <libopencm3/stm32/common/rcc_common_all.h>

BEGIN_DECLS

/**
 * Setup the base PLLs and clock domains for the STM32H7. This function will
 * utilize the users input parameters to configure all 3 PLLs, as well as the
 * core clock domains (namely SYSCLK, CPU, HCLK, AHB, PCLK1-4) with the
 * specified dividers. Given the dividers, the RCC module will track the
 * the configured frequency for each of these clock domains.
 *
 *   Note: If clock sources, configs, divider, etc. are modified outside of
 *         this module, the frequency tracking may be undefined.
 *   Note: Clock tree is fairly complex, see RM0433 Section 7
 *         for details.
 * @param[in] config  Input config structure defining desired setup.
 */
void rcc_clock_setup_pll(const struct rcc_pll_config *config);

/**
 * Get the clock rate (in Hz) of the specified clock source. There are
 * numerous clock sources and configurations on the H7, so rates for each
 * configured peripheral clock are aimed to be discoverd/calculated by this
 * module such that the user does not need to know how the MCU is configured
 * in order to utilize a peripheral clock.
 * @param[in] source  Clock source desired to be fetched.
 * @return Clock rate in Hz for the specified clock. 0 if undefined or error.
 */
uint32_t rcc_get_bus_clk_freq(enum rcc_clock_source source);

/**
 * Get the peripheral clock speed for the USART at base specified.
 * @param usart  Base address of USART to get clock frequency for (e.g. USART1_BASE).
 */
uint32_t rcc_get_usart_clk_freq(uint32_t usart);

/**
 * Get the peripheral clock speed for the Timer at base specified.
 * @param timer  Base address of TIMER to get clock frequency for (e.g. TIM1_BASE).
 */
uint32_t rcc_get_timer_clk_freq(uint32_t timer);

/**
 * Get the peripheral clock speed for the I2C device at base specified.
 * @param i2c  Base address of I2C to get clock frequency for (e.g. I2C1_BASE).
 */
uint32_t rcc_get_i2c_clk_freq(uint32_t i2c);

/**
 * Get the peripheral clock speed for the SPI device at base specified.
 * @param spi  Base address of SPI device to get clock frequency for (e.g. SPI1_BASE).
 */
uint32_t rcc_get_spi_clk_freq(uint32_t spi);

/**
 * Get the peripheral clock speed for the FDCAN device at base specified.
 * @param fdcan  Base address of FDCAN to get clock frequency for (e.g. FDCAN1_BASE).
 */
uint32_t rcc_get_fdcan_clk_freq(uint32_t fdcan);

/**
 * Set the clksel value for the specified peripheral. This code will determine
 * the appropriate register, shift and mask values to apply to the selection to
 * and set the values appropriately.
 *
 * Peripheral specific clksels functions are also available,
 * eg rcc_set_<periph>_clksel. These provide the same functionality, you only
 * need one of them. for instance @ref rcc_set_fdcan_clksel or
 * @ref rcc_set_spi123_clksel
 * @param[in] periph Base address of the peripheral to set the clock sel for
 * @param[in] clksel Raw, unshifted selection value for the clock, depending
 * on peripheral, see @ref rcc_d1ccipr_values or @ref rcc_d2ccip1r_values or
 * @ref rcc_d2ccip2r_values
 */
void rcc_set_peripheral_clk_sel(uint32_t periph, uint32_t clksel);

/**
 * Set the clock select for the FDCAN devices.
 * @param[in] clksel  Clock source to configure for, @ref rcc_d2ccip1r_values
 * appropriate for the FDCAN peripherals, eg RCC_D2CCIP1R_FDCANSEL_XXX
 * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
 */
void rcc_set_fdcan_clksel(uint8_t clksel);

/**
 * Set the clock select for the SPI 1/2/3 devices.
 * @param[in] clksel  Clock source to configure for, @ref rcc_d2ccip1r_values
 * appropriate for the SPI1/2/3 peripherals, eg RCC_D2CCIP1R_SPI123_XXX
 * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
 */
void rcc_set_spi123_clksel(uint8_t clksel);

/**
 * Set the clock select for the SPI 4/5 devices.
 * @param[in] clksel  Clock source to configure for. @ref rcc_d2ccip1r_values
 * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
 */
void rcc_set_spi45_clksel(uint8_t clksel);

/**
 * Set the clock select for the RNG device.
 * @param[in] clksel  Clock source to configure for. @ref rcc_d2ccip2r_values
 * @sa rcc_set_peripheral_clk_sel for equivalent generic functionality
 */
void rcc_set_rng_clksel(uint8_t clksel);

END_DECLS
/**@}*/

#endif
