dm: clk: add clk driver support for stm32h7 SoCs

This driver implements basic clock setup, only clock gating
is implemented.

This driver doesn't implement .of_match as it's binded
by MFD RCC driver.

Files include/dt-bindings/clock/stm32h7-clks.h and
doc/device-tree-bindings/clock/st,stm32h7-rcc.txt
will be available soon in a kernel tag, as all the
bindings have been acked by Rob Herring [1].

[1] http://lkml.iu.edu/hypermail/linux/kernel/1704.0/00935.html

Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
master
Patrice Chotard 7 years ago committed by Tom Rini
parent 776b2ddbfa
commit 4c3aebd56a
  1. 152
      doc/device-tree-bindings/clock/st,stm32h7-rcc.txt
  2. 1
      drivers/clk/Makefile
  3. 802
      drivers/clk/clk_stm32h7.c
  4. 167
      include/dt-bindings/clock/stm32h7-clks.h

@ -0,0 +1,152 @@
STMicroelectronics STM32H7 Reset and Clock Controller
=====================================================
The RCC IP is both a reset and a clock controller.
Please refer to clock-bindings.txt for common clock controller binding usage.
Please also refer to reset.txt for common reset controller binding usage.
Required properties:
- compatible: Should be:
"st,stm32h743-rcc"
- reg: should be register base and length as documented in the
datasheet
- #reset-cells: 1, see below
- #clock-cells : from common clock binding; shall be set to 1
- clocks: External oscillator clock phandle
- high speed external clock signal (HSE)
- low speed external clock signal (LSE)
- external I2S clock (I2S_CKIN)
- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
write protection (RTC clock).
- pll x node: Allow to register a pll with specific parameters.
Please see PLL section below.
Example:
rcc: rcc@58024400 {
#reset-cells = <1>;
#clock-cells = <2>
compatible = "st,stm32h743-rcc", "st,stm32-rcc";
reg = <0x58024400 0x400>;
clocks = <&clk_hse>, <&clk_lse>, <&clk_i2s_ckin>;
st,syscfg = <&pwrcfg>;
#address-cells = <1>;
#size-cells = <0>;
vco1@58024430 {
#clock-cells = <0>;
compatible = "stm32,pll";
reg = <0>;
};
vco2@58024438 {
#clock-cells = <0>;
compatible = "stm32,pll";
reg = <1>;
st,clock-div = <2>;
st,clock-mult = <40>;
st,frac-status = <0>;
st,frac = <0>;
st,vcosel = <1>;
st,pllrge = <2>;
};
};
STM32H7 PLL
-----------
The VCO of STM32 PLL could be reprensented like this:
Vref --------- --------
---->| / DIVM |---->| x DIVN | ------> VCO
--------- --------
^
|
-------
| FRACN |
-------
When the PLL is configured in integer mode:
- VCO = ( Vref / DIVM ) * DIVN
When the PLL is configured in fractional mode:
- VCO = ( Vref / DIVM ) * ( DIVN + FRACN / 2^13)
Required properties for pll node:
- compatible: Should be:
"stm32,pll"
- #clock-cells: from common clock binding; shall be set to 0
- reg: Should be the pll number.
Optional properties:
- st,clock-div: DIVM division factor : <1..63>
- st,clock-mult: DIVN multiplication factor : <4..512>
- st,frac-status:
- 0 Pll is configured in integer mode
- 1 Pll is configure in fractional mode
- st,frac: Fractional part of the multiplication factor : <0..8191>
- st,vcosel: VCO selection
- 0: Wide VCO range:192 to 836 MHz
- 1: Medium VCO range:150 to 420 MHz
- st,pllrge: PLL input frequency range
- 0: The PLL input (Vref / DIVM) clock range frequency is between 1 and 2 MHz
- 1: The PLL input (Vref / DIVM) clock range frequency is between 2 and 4 MHz
- 2: The PLL input (Vref / DIVM) clock range frequency is between 4 and 8 MHz
- 3: The PLL input (Vref / DIVM) clock range frequency is between 8 and 16 MHz
The peripheral clock consumer should specify the desired clock by
having the clock ID in its "clocks" phandle cell.
All available clocks are defined as preprocessor macros in
dt-bindings/clock/stm32h7-clks.h header and can be used in device
tree sources.
Example:
timer5: timer@40000c00 {
compatible = "st,stm32-timer";
reg = <0x40000c00 0x400>;
interrupts = <50>;
clocks = <&rcc TIM5_CK>;
};
Specifying softreset control of devices
=======================================
Device nodes should specify the reset channel required in their "resets"
property, containing a phandle to the reset device node and an index specifying
which channel to use.
The index is the bit number within the RCC registers bank, starting from RCC
base address.
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
Where bit_offset is the bit offset within the register.
For example, for CRC reset:
crc = AHB4RSTR_offset / 4 * 32 + CRCRST_bit_offset = 0x88 / 4 * 32 + 19 = 1107
All available preprocessor macros for reset are defined dt-bindings//mfd/stm32h7-rcc.h
header and can be used in device tree sources.
example:
timer2 {
resets = <&rcc STM32H7_APB1L_RESET(TIM2)>;
};

@ -22,3 +22,4 @@ obj-$(CONFIG_CLK_BCM6345) += clk_bcm6345.o
obj-$(CONFIG_CLK_BOSTON) += clk_boston.o
obj-$(CONFIG_ARCH_ASPEED) += aspeed/
obj-$(CONFIG_STM32F7) += clk_stm32f7.o
obj-$(CONFIG_STM32H7) += clk_stm32h7.o

@ -0,0 +1,802 @@
/*
* Copyright (C) STMicroelectronics SA 2017
* Author(s): Patrice CHOTARD, <patrice.chotard@st.com> for STMicroelectronics.
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
#include <clk-uclass.h>
#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <dm/root.h>
#include <dt-bindings/clock/stm32h7-clks.h>
DECLARE_GLOBAL_DATA_PTR;
/* RCC CR specific definitions */
#define RCC_CR_HSION BIT(0)
#define RCC_CR_HSIRDY BIT(2)
#define RCC_CR_HSEON BIT(16)
#define RCC_CR_HSERDY BIT(17)
#define RCC_CR_HSEBYP BIT(18)
#define RCC_CR_PLL1ON BIT(24)
#define RCC_CR_PLL1RDY BIT(25)
#define RCC_CR_HSIDIV_MASK GENMASK(4, 3)
#define RCC_CR_HSIDIV_SHIFT 3
#define RCC_CFGR_SW_MASK GENMASK(2, 0)
#define RCC_CFGR_SW_HSI 0
#define RCC_CFGR_SW_CSI 1
#define RCC_CFGR_SW_HSE 2
#define RCC_CFGR_SW_PLL1 3
#define RCC_PLLCKSELR_PLLSRC_HSI 0
#define RCC_PLLCKSELR_PLLSRC_CSI 1
#define RCC_PLLCKSELR_PLLSRC_HSE 2
#define RCC_PLLCKSELR_PLLSRC_NO_CLK 3
#define RCC_PLLCKSELR_PLLSRC_MASK GENMASK(1, 0)
#define RCC_PLLCKSELR_DIVM1_SHIFT 4
#define RCC_PLLCKSELR_DIVM1_MASK GENMASK(9, 4)
#define RCC_PLL1DIVR_DIVN1_MASK GENMASK(8, 0)
#define RCC_PLL1DIVR_DIVP1_SHIFT 9
#define RCC_PLL1DIVR_DIVP1_MASK GENMASK(15, 9)
#define RCC_PLL1DIVR_DIVQ1_SHIFT 16
#define RCC_PLL1DIVR_DIVQ1_MASK GENMASK(22, 16)
#define RCC_PLL1DIVR_DIVR1_SHIFT 24
#define RCC_PLL1DIVR_DIVR1_MASK GENMASK(30, 24)
#define RCC_PLL1FRACR_FRACN1_SHIFT 3
#define RCC_PLL1FRACR_FRACN1_MASK GENMASK(15, 3)
#define RCC_PLLCFGR_PLL1RGE_SHIFT 2
#define PLL1RGE_1_2_MHZ 0
#define PLL1RGE_2_4_MHZ 1
#define PLL1RGE_4_8_MHZ 2
#define PLL1RGE_8_16_MHZ 3
#define RCC_PLLCFGR_DIVP1EN BIT(16)
#define RCC_PLLCFGR_DIVQ1EN BIT(17)
#define RCC_PLLCFGR_DIVR1EN BIT(18)
#define RCC_D1CFGR_HPRE_MASK GENMASK(3, 0)
#define RCC_D1CFGR_HPRE_DIVIDED BIT(3)
#define RCC_D1CFGR_HPRE_DIVIDER GENMASK(2, 0)
#define RCC_D1CFGR_HPRE_DIV2 8
#define RCC_D1CFGR_D1PPRE_SHIFT 4
#define RCC_D1CFGR_D1PPRE_DIVIDED BIT(6)
#define RCC_D1CFGR_D1PPRE_DIVIDER GENMASK(5, 4)
#define RCC_D1CFGR_D1CPRE_SHIFT 8
#define RCC_D1CFGR_D1CPRE_DIVIDER GENMASK(10, 8)
#define RCC_D1CFGR_D1CPRE_DIVIDED BIT(11)
#define RCC_D2CFGR_D2PPRE1_SHIFT 4
#define RCC_D2CFGR_D2PPRE1_DIVIDED BIT(6)
#define RCC_D2CFGR_D2PPRE1_DIVIDER GENMASK(5, 4)
#define RCC_D2CFGR_D2PPRE2_SHIFT 8
#define RCC_D2CFGR_D2PPRE2_DIVIDED BIT(10)
#define RCC_D2CFGR_D2PPRE2_DIVIDER GENMASK(9, 8)
#define RCC_D3CFGR_D3PPRE_SHIFT 4
#define RCC_D3CFGR_D3PPRE_DIVIDED BIT(6)
#define RCC_D3CFGR_D3PPRE_DIVIDER GENMASK(5, 4)
#define RCC_D1CCIPR_FMCSRC_MASK GENMASK(1, 0)
#define FMCSRC_HCLKD1 0
#define FMCSRC_PLL1_Q_CK 1
#define FMCSRC_PLL2_R_CK 2
#define FMCSRC_PER_CK 3
#define RCC_D1CCIPR_QSPISRC_MASK GENMASK(5, 4)
#define RCC_D1CCIPR_QSPISRC_SHIFT 4
#define QSPISRC_HCLKD1 0
#define QSPISRC_PLL1_Q_CK 1
#define QSPISRC_PLL2_R_CK 2
#define QSPISRC_PER_CK 3
#define PWR_CR3 0x0c
#define PWR_CR3_SDEN BIT(2)
#define PWR_D3CR 0x18
#define PWR_D3CR_VOS_MASK GENMASK(15, 14)
#define PWR_D3CR_VOS_SHIFT 14
#define VOS_SCALE_3 1
#define VOS_SCALE_2 2
#define VOS_SCALE_1 3
#define PWR_D3CR_VOSREADY BIT(13)
struct stm32_rcc_regs {
u32 cr; /* 0x00 Source Control Register */
u32 icscr; /* 0x04 Internal Clock Source Calibration Register */
u32 crrcr; /* 0x08 Clock Recovery RC Register */
u32 reserved1; /* 0x0c reserved */
u32 cfgr; /* 0x10 Clock Configuration Register */
u32 reserved2; /* 0x14 reserved */
u32 d1cfgr; /* 0x18 Domain 1 Clock Configuration Register */
u32 d2cfgr; /* 0x1c Domain 2 Clock Configuration Register */
u32 d3cfgr; /* 0x20 Domain 3 Clock Configuration Register */
u32 reserved3; /* 0x24 reserved */
u32 pllckselr; /* 0x28 PLLs Clock Source Selection Register */
u32 pllcfgr; /* 0x2c PLLs Configuration Register */
u32 pll1divr; /* 0x30 PLL1 Dividers Configuration Register */
u32 pll1fracr; /* 0x34 PLL1 Fractional Divider Register */
u32 pll2divr; /* 0x38 PLL2 Dividers Configuration Register */
u32 pll2fracr; /* 0x3c PLL2 Fractional Divider Register */
u32 pll3divr; /* 0x40 PLL3 Dividers Configuration Register */
u32 pll3fracr; /* 0x44 PLL3 Fractional Divider Register */
u32 reserved4; /* 0x48 reserved */
u32 d1ccipr; /* 0x4c Domain 1 Kernel Clock Configuration Register */
u32 d2ccip1r; /* 0x50 Domain 2 Kernel Clock Configuration Register */
u32 d2ccip2r; /* 0x54 Domain 2 Kernel Clock Configuration Register */
u32 d3ccipr; /* 0x58 Domain 3 Kernel Clock Configuration Register */
u32 reserved5; /* 0x5c reserved */
u32 cier; /* 0x60 Clock Source Interrupt Enable Register */
u32 cifr; /* 0x64 Clock Source Interrupt Flag Register */
u32 cicr; /* 0x68 Clock Source Interrupt Clear Register */
u32 reserved6; /* 0x6c reserved */
u32 bdcr; /* 0x70 Backup Domain Control Register */
u32 csr; /* 0x74 Clock Control and Status Register */
u32 reserved7; /* 0x78 reserved */
u32 ahb3rstr; /* 0x7c AHB3 Peripheral Reset Register */
u32 ahb1rstr; /* 0x80 AHB1 Peripheral Reset Register */
u32 ahb2rstr; /* 0x84 AHB2 Peripheral Reset Register */
u32 ahb4rstr; /* 0x88 AHB4 Peripheral Reset Register */
u32 apb3rstr; /* 0x8c APB3 Peripheral Reset Register */
u32 apb1lrstr; /* 0x90 APB1 low Peripheral Reset Register */
u32 apb1hrstr; /* 0x94 APB1 high Peripheral Reset Register */
u32 apb2rstr; /* 0x98 APB2 Clock Register */
u32 apb4rstr; /* 0x9c APB4 Clock Register */
u32 gcr; /* 0xa0 Global Control Register */
u32 reserved8; /* 0xa4 reserved */
u32 d3amr; /* 0xa8 D3 Autonomous mode Register */
u32 reserved9[9];/* 0xac to 0xcc reserved */
u32 rsr; /* 0xd0 Reset Status Register */
u32 ahb3enr; /* 0xd4 AHB3 Clock Register */
u32 ahb1enr; /* 0xd8 AHB1 Clock Register */
u32 ahb2enr; /* 0xdc AHB2 Clock Register */
u32 ahb4enr; /* 0xe0 AHB4 Clock Register */
u32 apb3enr; /* 0xe4 APB3 Clock Register */
u32 apb1lenr; /* 0xe8 APB1 low Clock Register */
u32 apb1henr; /* 0xec APB1 high Clock Register */
u32 apb2enr; /* 0xf0 APB2 Clock Register */
u32 apb4enr; /* 0xf4 APB4 Clock Register */
};
#define RCC_AHB3ENR offsetof(struct stm32_rcc_regs, ahb3enr)
#define RCC_AHB1ENR offsetof(struct stm32_rcc_regs, ahb1enr)
#define RCC_AHB2ENR offsetof(struct stm32_rcc_regs, ahb2enr)
#define RCC_AHB4ENR offsetof(struct stm32_rcc_regs, ahb4enr)
#define RCC_APB3ENR offsetof(struct stm32_rcc_regs, apb3enr)
#define RCC_APB1LENR offsetof(struct stm32_rcc_regs, apb1lenr)
#define RCC_APB1HENR offsetof(struct stm32_rcc_regs, apb1henr)
#define RCC_APB2ENR offsetof(struct stm32_rcc_regs, apb2enr)
#define RCC_APB4ENR offsetof(struct stm32_rcc_regs, apb4enr)
struct clk_cfg {
u32 gate_offset;
u8 gate_bit_idx;
const char *name;
};
#define CLK(_gate_offset, _bit_idx, _name) \
{ \
.gate_offset = _gate_offset,\
.gate_bit_idx = _bit_idx,\
.name = _name,\
}
/*
* the way all these entries are sorted in this array could seem
* unlogical, but we are dependant of kernel DT_bindings,
* where clocks are separate in 2 banks, peripheral clocks and
* kernel clocks.
*/
static const struct clk_cfg clk_map[] = {
CLK(RCC_AHB3ENR, 31, "d1sram1"), /* peripheral clocks */
CLK(RCC_AHB3ENR, 30, "itcm"),
CLK(RCC_AHB3ENR, 29, "dtcm2"),
CLK(RCC_AHB3ENR, 28, "dtcm1"),
CLK(RCC_AHB3ENR, 8, "flitf"),
CLK(RCC_AHB3ENR, 5, "jpgdec"),
CLK(RCC_AHB3ENR, 4, "dma2d"),
CLK(RCC_AHB3ENR, 0, "mdma"),
CLK(RCC_AHB1ENR, 28, "usb2ulpi"),
CLK(RCC_AHB1ENR, 17, "eth1rx"),
CLK(RCC_AHB1ENR, 16, "eth1tx"),
CLK(RCC_AHB1ENR, 15, "eth1mac"),
CLK(RCC_AHB1ENR, 14, "art"),
CLK(RCC_AHB1ENR, 26, "usb1ulpi"),
CLK(RCC_AHB1ENR, 1, "dma2"),
CLK(RCC_AHB1ENR, 0, "dma1"),
CLK(RCC_AHB2ENR, 31, "d2sram3"),
CLK(RCC_AHB2ENR, 30, "d2sram2"),
CLK(RCC_AHB2ENR, 29, "d2sram1"),
CLK(RCC_AHB2ENR, 5, "hash"),
CLK(RCC_AHB2ENR, 4, "crypt"),
CLK(RCC_AHB2ENR, 0, "camitf"),
CLK(RCC_AHB4ENR, 28, "bkpram"),
CLK(RCC_AHB4ENR, 25, "hsem"),
CLK(RCC_AHB4ENR, 21, "bdma"),
CLK(RCC_AHB4ENR, 19, "crc"),
CLK(RCC_AHB4ENR, 10, "gpiok"),
CLK(RCC_AHB4ENR, 9, "gpioj"),
CLK(RCC_AHB4ENR, 8, "gpioi"),
CLK(RCC_AHB4ENR, 7, "gpioh"),
CLK(RCC_AHB4ENR, 6, "gpiog"),
CLK(RCC_AHB4ENR, 5, "gpiof"),
CLK(RCC_AHB4ENR, 4, "gpioe"),
CLK(RCC_AHB4ENR, 3, "gpiod"),
CLK(RCC_AHB4ENR, 2, "gpioc"),
CLK(RCC_AHB4ENR, 1, "gpiob"),
CLK(RCC_AHB4ENR, 0, "gpioa"),
CLK(RCC_APB3ENR, 6, "wwdg1"),
CLK(RCC_APB1LENR, 29, "dac12"),
CLK(RCC_APB1LENR, 11, "wwdg2"),
CLK(RCC_APB1LENR, 8, "tim14"),
CLK(RCC_APB1LENR, 7, "tim13"),
CLK(RCC_APB1LENR, 6, "tim12"),
CLK(RCC_APB1LENR, 5, "tim7"),
CLK(RCC_APB1LENR, 4, "tim6"),
CLK(RCC_APB1LENR, 3, "tim5"),
CLK(RCC_APB1LENR, 2, "tim4"),
CLK(RCC_APB1LENR, 1, "tim3"),
CLK(RCC_APB1LENR, 0, "tim2"),
CLK(RCC_APB1HENR, 5, "mdios"),
CLK(RCC_APB1HENR, 4, "opamp"),
CLK(RCC_APB1HENR, 1, "crs"),
CLK(RCC_APB2ENR, 18, "tim17"),
CLK(RCC_APB2ENR, 17, "tim16"),
CLK(RCC_APB2ENR, 16, "tim15"),
CLK(RCC_APB2ENR, 1, "tim8"),
CLK(RCC_APB2ENR, 0, "tim1"),
CLK(RCC_APB4ENR, 26, "tmpsens"),
CLK(RCC_APB4ENR, 16, "rtcapb"),
CLK(RCC_APB4ENR, 15, "vref"),
CLK(RCC_APB4ENR, 14, "comp12"),
CLK(RCC_APB4ENR, 1, "syscfg"),
CLK(RCC_AHB3ENR, 16, "sdmmc1"), /* kernel clocks */
CLK(RCC_AHB3ENR, 14, "quadspi"),
CLK(RCC_AHB3ENR, 12, "fmc"),
CLK(RCC_AHB1ENR, 27, "usb2otg"),
CLK(RCC_AHB1ENR, 25, "usb1otg"),
CLK(RCC_AHB1ENR, 5, "adc12"),
CLK(RCC_AHB2ENR, 9, "sdmmc2"),
CLK(RCC_AHB2ENR, 6, "rng"),
CLK(RCC_AHB4ENR, 24, "adc3"),
CLK(RCC_APB3ENR, 4, "dsi"),
CLK(RCC_APB3ENR, 3, "ltdc"),
CLK(RCC_APB1LENR, 31, "usart8"),
CLK(RCC_APB1LENR, 30, "usart7"),
CLK(RCC_APB1LENR, 27, "hdmicec"),
CLK(RCC_APB1LENR, 23, "i2c3"),
CLK(RCC_APB1LENR, 22, "i2c2"),
CLK(RCC_APB1LENR, 21, "i2c1"),
CLK(RCC_APB1LENR, 20, "uart5"),
CLK(RCC_APB1LENR, 19, "uart4"),
CLK(RCC_APB1LENR, 18, "usart3"),
CLK(RCC_APB1LENR, 17, "usart2"),
CLK(RCC_APB1LENR, 16, "spdifrx"),
CLK(RCC_APB1LENR, 15, "spi3"),
CLK(RCC_APB1LENR, 14, "spi2"),
CLK(RCC_APB1LENR, 9, "lptim1"),
CLK(RCC_APB1HENR, 8, "fdcan"),
CLK(RCC_APB1HENR, 2, "swp"),
CLK(RCC_APB2ENR, 29, "hrtim"),
CLK(RCC_APB2ENR, 28, "dfsdm1"),
CLK(RCC_APB2ENR, 24, "sai3"),
CLK(RCC_APB2ENR, 23, "sai2"),
CLK(RCC_APB2ENR, 22, "sai1"),
CLK(RCC_APB2ENR, 20, "spi5"),
CLK(RCC_APB2ENR, 13, "spi4"),
CLK(RCC_APB2ENR, 12, "spi1"),
CLK(RCC_APB2ENR, 5, "usart6"),
CLK(RCC_APB2ENR, 4, "usart1"),
CLK(RCC_APB4ENR, 21, "sai4a"),
CLK(RCC_APB4ENR, 21, "sai4b"),
CLK(RCC_APB4ENR, 12, "lptim5"),
CLK(RCC_APB4ENR, 11, "lptim4"),
CLK(RCC_APB4ENR, 10, "lptim3"),
CLK(RCC_APB4ENR, 9, "lptim2"),
CLK(RCC_APB4ENR, 7, "i2c4"),
CLK(RCC_APB4ENR, 5, "spi6"),
CLK(RCC_APB4ENR, 3, "lpuart1"),
};
struct stm32_clk {
struct stm32_rcc_regs *rcc_base;
struct regmap *pwr_regmap;
};
struct pll_psc {
u8 divm;
u16 divn;
u8 divp;
u8 divq;
u8 divr;
};
/*
* OSC_HSE = 25 MHz
* VCO = 500MHz
* pll1_p = 250MHz / pll1_q = 250MHz pll1_r = 250Mhz
*/
struct pll_psc sys_pll_psc = {
.divm = 4,
.divn = 80,
.divp = 2,
.divq = 2,
.divr = 2,
};
int configure_clocks(struct udevice *dev)
{
struct stm32_clk *priv = dev_get_priv(dev);
struct stm32_rcc_regs *regs = priv->rcc_base;
uint8_t *pwr_base = (uint8_t *)regmap_get_range(priv->pwr_regmap, 0);
uint32_t pllckselr = 0;
uint32_t pll1divr = 0;
uint32_t pllcfgr = 0;
/* Switch on HSI */
setbits_le32(&regs->cr, RCC_CR_HSION);
while (!(readl(&regs->cr) & RCC_CR_HSIRDY))
;
/* Reset CFGR, now HSI is the default system clock */
writel(0, &regs->cfgr);
/* Set all kernel domain clock registers to reset value*/
writel(0x0, &regs->d1ccipr);
writel(0x0, &regs->d2ccip1r);
writel(0x0, &regs->d2ccip2r);
/* Set voltage scaling at scale 1 */
clrsetbits_le32(pwr_base + PWR_D3CR, PWR_D3CR_VOS_MASK,
VOS_SCALE_1 << PWR_D3CR_VOS_SHIFT);
/* disable step down converter */
clrbits_le32(pwr_base + PWR_CR3, PWR_CR3_SDEN);
while (!(readl(pwr_base + PWR_D3CR) & PWR_D3CR_VOSREADY))
;
/* disable HSE to configure it */
clrbits_le32(&regs->cr, RCC_CR_HSEON);
while ((readl(&regs->cr) & RCC_CR_HSERDY))
;
/* clear HSE bypass and set it ON */
clrbits_le32(&regs->cr, RCC_CR_HSEBYP);
/* Switch on HSE */
setbits_le32(&regs->cr, RCC_CR_HSEON);
while (!(readl(&regs->cr) & RCC_CR_HSERDY))
;
/* pll setup, disable it */
clrbits_le32(&regs->cr, RCC_CR_PLL1ON);
while ((readl(&regs->cr) & RCC_CR_PLL1RDY))
;
/* Select HSE as PLL clock source */
pllckselr |= RCC_PLLCKSELR_PLLSRC_HSE;
pllckselr |= sys_pll_psc.divm << RCC_PLLCKSELR_DIVM1_SHIFT;
writel(pllckselr, &regs->pllckselr);
pll1divr |= (sys_pll_psc.divr - 1) << RCC_PLL1DIVR_DIVR1_SHIFT;
pll1divr |= (sys_pll_psc.divq - 1) << RCC_PLL1DIVR_DIVQ1_SHIFT;
pll1divr |= (sys_pll_psc.divp - 1) << RCC_PLL1DIVR_DIVP1_SHIFT;
pll1divr |= (sys_pll_psc.divn - 1);
writel(pll1divr, &regs->pll1divr);
pllcfgr |= PLL1RGE_4_8_MHZ << RCC_PLLCFGR_PLL1RGE_SHIFT;
pllcfgr |= RCC_PLLCFGR_DIVP1EN;
pllcfgr |= RCC_PLLCFGR_DIVQ1EN;
pllcfgr |= RCC_PLLCFGR_DIVR1EN;
writel(pllcfgr, &regs->pllcfgr);
/* pll setup, enable it */
setbits_le32(&regs->cr, RCC_CR_PLL1ON);
/* set HPRE (/2) DI clk --> 125MHz */
clrsetbits_le32(&regs->d1cfgr, RCC_D1CFGR_HPRE_MASK,
RCC_D1CFGR_HPRE_DIV2);
/* select PLL1 as system clock source (sys_ck)*/
clrsetbits_le32(&regs->cfgr, RCC_CFGR_SW_MASK, RCC_CFGR_SW_PLL1);
while ((readl(&regs->cfgr) & RCC_CFGR_SW_MASK) != RCC_CFGR_SW_PLL1)
;
/* sdram: use pll1_q as fmc_k clk */
clrsetbits_le32(&regs->d1ccipr, RCC_D1CCIPR_FMCSRC_MASK,
FMCSRC_PLL1_Q_CK);
return 0;
}
static u32 stm32_get_HSI_divider(struct stm32_rcc_regs *regs)
{
u32 divider;
/* get HSI divider value */
divider = readl(&regs->cr) & RCC_CR_HSIDIV_MASK;
divider = divider >> RCC_CR_HSIDIV_SHIFT;
return divider;
};
enum pllsrc {
HSE,
LSE,
HSI,
CSI,
I2S,
TIMER,
PLLSRC_NB,
};
static const char * const pllsrc_name[PLLSRC_NB] = {
[HSE] = "clk-hse",
[LSE] = "clk-lse",
[HSI] = "clk-hsi",
[CSI] = "clk-csi",
[I2S] = "clk-i2s",
[TIMER] = "timer-clk"
};
static ulong stm32_get_rate(struct stm32_rcc_regs *regs, enum pllsrc pllsrc)
{
struct clk clk;
struct udevice *fixed_clock_dev = NULL;
u32 divider;
int ret;
const char *name = pllsrc_name[pllsrc];
debug("%s name %s\n", __func__, name);
clk.id = 0;
ret = uclass_get_device_by_name(UCLASS_CLK, name, &fixed_clock_dev);
if (ret) {
error("Can't find clk %s (%d)", name, ret);
return 0;
}
ret = clk_request(fixed_clock_dev, &clk);
if (ret) {
error("Can't request %s clk (%d)", name, ret);
return 0;
}
divider = 0;
if (pllsrc == HSI)
divider = stm32_get_HSI_divider(regs);
debug("%s divider %d rate %ld\n", __func__,
divider, clk_get_rate(&clk));
return clk_get_rate(&clk) >> divider;
};
enum pll1_output {
PLL1_P_CK,
PLL1_Q_CK,
PLL1_R_CK,
};
static u32 stm32_get_PLL1_rate(struct stm32_rcc_regs *regs,
enum pll1_output output)
{
ulong pllsrc = 0;
u32 divm1, divn1, divp1, divq1, divr1, fracn1;
ulong vco, rate;
/* get the PLLSRC */
switch (readl(&regs->pllckselr) & RCC_PLLCKSELR_PLLSRC_MASK) {
case RCC_PLLCKSELR_PLLSRC_HSI:
pllsrc = stm32_get_rate(regs, HSI);
break;
case RCC_PLLCKSELR_PLLSRC_CSI:
pllsrc = stm32_get_rate(regs, CSI);
break;
case RCC_PLLCKSELR_PLLSRC_HSE:
pllsrc = stm32_get_rate(regs, HSE);
break;
case RCC_PLLCKSELR_PLLSRC_NO_CLK:
/* shouldn't happen */
error("wrong value for RCC_PLLCKSELR register\n");
pllsrc = 0;
break;
}
/* pllsrc = 0 ? no need to go ahead */
if (!pllsrc)
return pllsrc;
/* get divm1, divp1, divn1 and divr1 */
divm1 = readl(&regs->pllckselr) & RCC_PLLCKSELR_DIVM1_MASK;
divm1 = divm1 >> RCC_PLLCKSELR_DIVM1_SHIFT;
divn1 = (readl(&regs->pll1divr) & RCC_PLL1DIVR_DIVN1_MASK) + 1;
divp1 = readl(&regs->pll1divr) & RCC_PLL1DIVR_DIVP1_MASK;
divp1 = (divp1 >> RCC_PLL1DIVR_DIVP1_SHIFT) + 1;
divq1 = readl(&regs->pll1divr) & RCC_PLL1DIVR_DIVQ1_MASK;
divq1 = (divq1 >> RCC_PLL1DIVR_DIVQ1_SHIFT) + 1;
divr1 = readl(&regs->pll1divr) & RCC_PLL1DIVR_DIVR1_MASK;
divr1 = (divr1 >> RCC_PLL1DIVR_DIVR1_SHIFT) + 1;
fracn1 = readl(&regs->pll1fracr) & RCC_PLL1DIVR_DIVR1_MASK;
fracn1 = fracn1 & RCC_PLL1DIVR_DIVR1_SHIFT;
vco = (pllsrc / divm1) * divn1;
rate = (pllsrc * fracn1) / (divm1 * 8192);
debug("%s divm1 = %d divn1 = %d divp1 = %d divq1 = %d divr1 = %d\n",
__func__, divm1, divn1, divp1, divq1, divr1);
debug("%s fracn1 = %d vco = %ld rate = %ld\n",
__func__, fracn1, vco, rate);
switch (output) {
case PLL1_P_CK:
return (vco + rate) / divp1;
break;
case PLL1_Q_CK:
return (vco + rate) / divq1;
break;
case PLL1_R_CK:
return (vco + rate) / divr1;
break;
}
return -EINVAL;
}
static ulong stm32_clk_get_rate(struct clk *clk)
{
struct stm32_clk *priv = dev_get_priv(clk->dev);
struct stm32_rcc_regs *regs = priv->rcc_base;
ulong sysclk = 0;
u32 gate_offset;
u32 d1cfgr;
/* prescaler table lookups for clock computation */
u16 prescaler_table[8] = {2, 4, 8, 16, 64, 128, 256, 512};
u8 source, idx;
/*
* get system clock (sys_ck) source
* can be HSI_CK, CSI_CK, HSE_CK or pll1_p_ck
*/
source = readl(&regs->cfgr) & RCC_CFGR_SW_MASK;
switch (source) {
case RCC_CFGR_SW_PLL1:
sysclk = stm32_get_PLL1_rate(regs, PLL1_P_CK);
break;
case RCC_CFGR_SW_HSE:
sysclk = stm32_get_rate(regs, HSE);
break;
case RCC_CFGR_SW_CSI:
sysclk = stm32_get_rate(regs, CSI);
break;
case RCC_CFGR_SW_HSI:
sysclk = stm32_get_rate(regs, HSI);
break;
}
/* sysclk = 0 ? no need to go ahead */
if (!sysclk)
return sysclk;
debug("%s system clock: source = %d freq = %ld\n",
__func__, source, sysclk);
d1cfgr = readl(&regs->d1cfgr);
if (d1cfgr & RCC_D1CFGR_D1CPRE_DIVIDED) {
/* get D1 domain Core prescaler */
idx = (d1cfgr & RCC_D1CFGR_D1CPRE_DIVIDER) >>
RCC_D1CFGR_D1CPRE_SHIFT;
sysclk = sysclk / prescaler_table[idx];
}
if (d1cfgr & RCC_D1CFGR_HPRE_DIVIDED) {
/* get D1 domain AHB prescaler */
idx = d1cfgr & RCC_D1CFGR_HPRE_DIVIDER;
sysclk = sysclk / prescaler_table[idx];
}
gate_offset = clk_map[clk->id].gate_offset;
debug("%s clk->id=%ld gate_offset=0x%x sysclk=%ld\n",
__func__, clk->id, gate_offset, sysclk);
switch (gate_offset) {
case RCC_AHB3ENR:
case RCC_AHB1ENR:
case RCC_AHB2ENR:
case RCC_AHB4ENR:
return sysclk;
break;
case RCC_APB3ENR:
if (d1cfgr & RCC_D1CFGR_D1PPRE_DIVIDED) {
/* get D1 domain APB3 prescaler */
idx = (d1cfgr & RCC_D1CFGR_D1PPRE_DIVIDER) >>
RCC_D1CFGR_D1PPRE_SHIFT;
sysclk = sysclk / prescaler_table[idx];
}
debug("%s system clock: freq after APB3 prescaler = %ld\n",
__func__, sysclk);
return sysclk;
break;
case RCC_APB4ENR:
if (d1cfgr & RCC_D3CFGR_D3PPRE_DIVIDED) {
/* get D3 domain APB4 prescaler */
idx = (d1cfgr & RCC_D3CFGR_D3PPRE_DIVIDER) >>
RCC_D3CFGR_D3PPRE_SHIFT;
sysclk = sysclk / prescaler_table[idx];
}
debug("%s system clock: freq after APB4 prescaler = %ld\n",
__func__, sysclk);
return sysclk;
break;
case RCC_APB1LENR:
case RCC_APB1HENR:
if (d1cfgr & RCC_D2CFGR_D2PPRE1_DIVIDED) {
/* get D2 domain APB1 prescaler */
idx = (d1cfgr & RCC_D2CFGR_D2PPRE1_DIVIDER) >>
RCC_D2CFGR_D2PPRE1_SHIFT;
sysclk = sysclk / prescaler_table[idx];
}
debug("%s system clock: freq after APB1 prescaler = %ld\n",
__func__, sysclk);
return sysclk;
break;
case RCC_APB2ENR:
if (d1cfgr & RCC_D2CFGR_D2PPRE2_DIVIDED) {
/* get D2 domain APB1 prescaler */
idx = (d1cfgr & RCC_D2CFGR_D2PPRE2_DIVIDER) >>
RCC_D2CFGR_D2PPRE2_SHIFT;
sysclk = sysclk / prescaler_table[idx];
}
debug("%s system clock: freq after APB2 prescaler = %ld\n",
__func__, sysclk);
return sysclk;
break;
default:
error("unexpected gate_offset value (0x%x)\n", gate_offset);
return -EINVAL;
break;
}
}
static int stm32_clk_enable(struct clk *clk)
{
struct stm32_clk *priv = dev_get_priv(clk->dev);
struct stm32_rcc_regs *regs = priv->rcc_base;
u32 gate_offset;
u32 gate_bit_index;
unsigned long clk_id = clk->id;
gate_offset = clk_map[clk_id].gate_offset;
gate_bit_index = clk_map[clk_id].gate_bit_idx;
debug("%s: clkid=%ld gate offset=0x%x bit_index=%d name=%s\n",
__func__, clk->id, gate_offset, gate_bit_index,
clk_map[clk_id].name);
setbits_le32(&regs->cr + (gate_offset / 4), BIT(gate_bit_index));
return 0;
}
static int stm32_clk_probe(struct udevice *dev)
{
struct stm32_clk *priv = dev_get_priv(dev);
struct udevice *syscon;
fdt_addr_t addr;
int err;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
priv->rcc_base = (struct stm32_rcc_regs *)addr;
/* get corresponding syscon phandle */
err = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
"st,syscfg", &syscon);
if (err) {
error("unable to find syscon device\n");
return err;
}
priv->pwr_regmap = syscon_get_regmap(syscon);
if (!priv->pwr_regmap) {
error("unable to find regmap\n");
return -ENODEV;
}
configure_clocks(dev);
return 0;
}
static int stm32_clk_of_xlate(struct clk *clk,
struct ofnode_phandle_args *args)
{
if (args->args_count != 1) {
debug("Invaild args_count: %d\n", args->args_count);
return -EINVAL;
}
if (args->args_count) {
clk->id = args->args[0];
/*
* this computation convert DT clock index which is used to
* point into 2 separate clock arrays (peripheral and kernel
* clocks bank) (see include/dt-bindings/clock/stm32h7-clks.h)
* into index to point into only one array where peripheral
* and kernel clocks are consecutive
*/
if (clk->id >= KERN_BANK) {
clk->id -= KERN_BANK;
clk->id += LAST_PERIF_BANK - PERIF_BANK + 1;
} else {
clk->id -= PERIF_BANK;
}
} else {
clk->id = 0;
}
debug("%s clk->id %ld\n", __func__, clk->id);
return 0;
}
static struct clk_ops stm32_clk_ops = {
.of_xlate = stm32_clk_of_xlate,
.enable = stm32_clk_enable,
.get_rate = stm32_clk_get_rate,
};
U_BOOT_DRIVER(stm32h7_clk) = {
.name = "stm32h7_rcc_clock",
.id = UCLASS_CLK,
.ops = &stm32_clk_ops,
.probe = stm32_clk_probe,
.priv_auto_alloc_size = sizeof(struct stm32_clk),
.flags = DM_FLAG_PRE_RELOC,
};

@ -0,0 +1,167 @@
/* SYS, CORE AND BUS CLOCKS */
#define SYS_D1CPRE 0
#define HCLK 1
#define PCLK1 2
#define PCLK2 3
#define PCLK3 4
#define PCLK4 5
#define HSI_DIV 6
#define HSE_1M 7
#define I2S_CKIN 8
#define CK_DSI_PHY 9
#define HSE_CK 10
#define LSE_CK 11
#define CSI_KER_DIV122 12
#define RTC_CK 13
#define CPU_SYSTICK 14
/* OSCILLATOR BANK */
#define OSC_BANK 18
#define HSI_CK 18
#define HSI_KER_CK 19
#define CSI_CK 20
#define CSI_KER_CK 21
#define RC48_CK 22
#define LSI_CK 23
/* MCLOCK BANK */
#define MCLK_BANK 28
#define PER_CK 28
#define PLLSRC 29
#define SYS_CK 30
#define TRACEIN_CK 31
/* ODF BANK */
#define ODF_BANK 32
#define PLL1_P 32
#define PLL1_Q 33
#define PLL1_R 34
#define PLL2_P 35
#define PLL2_Q 36
#define PLL2_R 37
#define PLL3_P 38
#define PLL3_Q 39
#define PLL3_R 40
/* MCO BANK */
#define MCO_BANK 41
#define MCO1 41
#define MCO2 42
/* PERIF BANK */
#define PERIF_BANK 50
#define D1SRAM1_CK 50
#define ITCM_CK 51
#define DTCM2_CK 52
#define DTCM1_CK 53
#define FLITF_CK 54
#define JPGDEC_CK 55
#define DMA2D_CK 56
#define MDMA_CK 57
#define USB2ULPI_CK 58
#define USB1ULPI_CK 59
#define ETH1RX_CK 60
#define ETH1TX_CK 61
#define ETH1MAC_CK 62
#define ART_CK 63
#define DMA2_CK 64
#define DMA1_CK 65
#define D2SRAM3_CK 66
#define D2SRAM2_CK 67
#define D2SRAM1_CK 68
#define HASH_CK 69
#define CRYPT_CK 70
#define CAMITF_CK 71
#define BKPRAM_CK 72
#define HSEM_CK 73
#define BDMA_CK 74
#define CRC_CK 75
#define GPIOK_CK 76
#define GPIOJ_CK 77
#define GPIOI_CK 78
#define GPIOH_CK 79
#define GPIOG_CK 80
#define GPIOF_CK 81
#define GPIOE_CK 82
#define GPIOD_CK 83
#define GPIOC_CK 84
#define GPIOB_CK 85
#define GPIOA_CK 86
#define WWDG1_CK 87
#define DAC12_CK 88
#define WWDG2_CK 89
#define TIM14_CK 90
#define TIM13_CK 91
#define TIM12_CK 92
#define TIM7_CK 93
#define TIM6_CK 94
#define TIM5_CK 95
#define TIM4_CK 96
#define TIM3_CK 97
#define TIM2_CK 98
#define MDIOS_CK 99
#define OPAMP_CK 100
#define CRS_CK 101
#define TIM17_CK 102
#define TIM16_CK 103
#define TIM15_CK 104
#define TIM8_CK 105
#define TIM1_CK 106
#define TMPSENS_CK 107
#define RTCAPB_CK 108
#define VREF_CK 109
#define COMP12_CK 110
#define SYSCFG_CK 111
/* must be equal to last peripheral clock index */
#define LAST_PERIF_BANK SYSCFG_CK
/* KERNEL BANK */
#define KERN_BANK 120
#define SDMMC1_CK 120
#define QUADSPI_CK 121
#define FMC_CK 122
#define USB2OTG_CK 123
#define USB1OTG_CK 124
#define ADC12_CK 125
#define SDMMC2_CK 126
#define RNG_CK 127
#define ADC3_CK 128
#define DSI_CK 129
#define LTDC_CK 130
#define USART8_CK 131
#define USART7_CK 132
#define HDMICEC_CK 133
#define I2C3_CK 134
#define I2C2_CK 135
#define I2C1_CK 136
#define UART5_CK 137
#define UART4_CK 138
#define USART3_CK 139
#define USART2_CK 140
#define SPDIFRX_CK 141
#define SPI3_CK 142
#define SPI2_CK 143
#define LPTIM1_CK 144
#define FDCAN_CK 145
#define SWP_CK 146
#define HRTIM_CK 147
#define DFSDM1_CK 148
#define SAI3_CK 149
#define SAI2_CK 150
#define SAI1_CK 151
#define SPI5_CK 152
#define SPI4_CK 153
#define SPI1_CK 154
#define USART6_CK 155
#define USART1_CK 156
#define SAI4B_CK 157
#define SAI4A_CK 158
#define LPTIM5_CK 159
#define LPTIM4_CK 160
#define LPTIM3_CK 161
#define LPTIM2_CK 162
#define I2C4_CK 163
#define SPI6_CK 164
#define LPUART1_CK 165
#define STM32H7_MAX_CLKS 166
Loading…
Cancel
Save