lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20170315121554.ir3v23hyvzozestb@dell>
Date:   Wed, 15 Mar 2017 12:15:54 +0000
From:   Lee Jones <lee.jones@...aro.org>
To:     gabriel.fernandez@...com
Cc:     Rob Herring <robh+dt@...nel.org>,
        Mark Rutland <mark.rutland@....com>,
        Russell King <linux@...linux.org.uk>,
        Maxime Coquelin <mcoquelin.stm32@...il.com>,
        Alexandre Torgue <alexandre.torgue@...com>,
        Michael Turquette <mturquette@...libre.com>,
        Stephen Boyd <sboyd@...eaurora.org>,
        Nicolas Pitre <nico@...aro.org>, Arnd Bergmann <arnd@...db.de>,
        daniel.thompson@...aro.org, andrea.merello@...il.com,
        radoslaw.pietrzyk@...il.com, devicetree@...r.kernel.org,
        linux-arm-kernel@...ts.infradead.org, linux-kernel@...r.kernel.org,
        linux-clk@...r.kernel.org, ludovic.barre@...com,
        olivier.bideau@...com, amelie.delaunay@...com
Subject: Re: [PATCH] clk: stm32h7: Add stm32h743 clock driver

On Wed, 15 Mar 2017, gabriel.fernandez@...com wrote:

> From: Gabriel Fernandez <gabriel.fernandez@...com>
> 
> This patch enables clocks for STM32H743 boards.
> 
> Signed-off-by: Gabriel Fernandez <gabriel.fernandez@...com>
> ---
>  .../devicetree/bindings/clock/st,stm32h7-rcc.txt   |  152 ++
>  drivers/clk/Makefile                               |    1 +
>  drivers/clk/clk-stm32h7.c                          | 1586 ++++++++++++++++++++
>  include/dt-bindings/clock/stm32h7-clks.h           |  165 ++

>  include/dt-bindings/mfd/stm32h7-rcc.h              |  138 ++

Just for the MFD changes:
  Acked-by: Lee Jones <lee.jones@...aro.org>

>  5 files changed, 2042 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
>  create mode 100644 drivers/clk/clk-stm32h7.c
>  create mode 100644 include/dt-bindings/clock/stm32h7-clks.h
>  create mode 100644 include/dt-bindings/mfd/stm32h7-rcc.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
> new file mode 100644
> index 0000000..9d4b587
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/st,stm32h7-rcc.txt
> @@ -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@...24400 {
> +		#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@...24430 {
> +			#clock-cells = <0>;
> +			compatible = "stm32,pll";
> +			reg = <0>;
> +		};
> +
> +		vco2@...24438 {
> +			#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@...00c00 {
> +			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)>;
> +	};
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 92c12b8..734aa02 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -42,6 +42,7 @@ obj-$(CONFIG_COMMON_CLK_SI5351)		+= clk-si5351.o
>  obj-$(CONFIG_COMMON_CLK_SI514)		+= clk-si514.o
>  obj-$(CONFIG_COMMON_CLK_SI570)		+= clk-si570.o
>  obj-$(CONFIG_ARCH_STM32)		+= clk-stm32f4.o
> +obj-$(CONFIG_ARCH_STM32)		+= clk-stm32h7.o
>  obj-$(CONFIG_ARCH_TANGO)		+= clk-tango4.o
>  obj-$(CONFIG_CLK_TWL6040)		+= clk-twl6040.o
>  obj-$(CONFIG_ARCH_U300)			+= clk-u300.o
> diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c
> new file mode 100644
> index 0000000..c8eb729
> --- /dev/null
> +++ b/drivers/clk/clk-stm32h7.c
> @@ -0,0 +1,1586 @@
> +/*
> + * Copyright (C) Gabriel Fernandez 2017
> + * Author: Gabriel Fernandez <gabriel.fernandez@...com>
> + *
> + * License terms: GPL V2.0.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/regmap.h>
> +
> +#include <dt-bindings/clock/stm32h7-clks.h>
> +
> +/* Reset Clock Control Registers */
> +#define RCC_CR		0x00
> +#define RCC_CFGR	0x10
> +#define RCC_D1CFGR	0x18
> +#define RCC_D2CFGR	0x1C
> +#define RCC_D3CFGR	0x20
> +#define RCC_PLLCKSELR	0x28
> +#define RCC_PLLCFGR	0x2C
> +#define RCC_PLL1DIVR	0x30
> +#define RCC_PLL1FRACR	0x34
> +#define RCC_PLL2DIVR	0x38
> +#define RCC_PLL2FRACR	0x3C
> +#define RCC_PLL3DIVR	0x40
> +#define RCC_PLL3FRACR	0x44
> +#define RCC_D1CCIPR	0x4C
> +#define RCC_D2CCIP1R	0x50
> +#define RCC_D2CCIP2R	0x54
> +#define RCC_D3CCIPR	0x58
> +#define RCC_BDCR	0x70
> +#define RCC_CSR		0x74
> +#define RCC_AHB3ENR	0xD4
> +#define RCC_AHB1ENR	0xD8
> +#define RCC_AHB2ENR	0xDC
> +#define RCC_AHB4ENR	0xE0
> +#define RCC_APB3ENR	0xE4
> +#define RCC_APB1LENR	0xE8
> +#define RCC_APB1HENR	0xEC
> +#define RCC_APB2ENR	0xF0
> +#define RCC_APB4ENR	0xF4
> +
> +static DEFINE_SPINLOCK(rlock);
> +
> +static void __iomem *base;
> +static struct regmap *pdrm;
> +static struct clk_hw **hws;
> +
> +/* System clock parent */
> +static const char * const sys_src[] = {
> +	"hsi_ck", "csi_ck", "hse_ck", "pll1_p" };
> +
> +static const char * const tracein_src[] = {
> +	"hsi_ck", "csi_ck", "hse_ck", "pll1_r" };
> +
> +static const char * const per_src[] = {
> +	"hsi_ker", "csi_ker", "hse_ck", "disabled" };
> +
> +static const char * const pll_src[] = {
> +	"hsi_ck", "csi_ck", "hse_ck", "no clock" };
> +
> +static const char * const sdmmc_src[] = { "pll1_q", "pll2_r" };
> +
> +static const char * const dsi_src[] = { "ck_dsi_phy", "pll2_q" };
> +
> +static const char * const qspi_src[] = {
> +	"hclk", "pll1_q", "pll2_r", "per_ck" };
> +
> +static const char * const fmc_src[] = {
> +	"hclk", "pll1_q", "pll2_r", "per_ck" };
> +
> +/* Kernel clock parent */
> +static const char * const swp_src[] = {	"pclk1", "hsi_ker" };
> +
> +static const char * const fdcan_src[] = { "hse_ck", "pll1_q", "pll2_q" };
> +
> +static const char * const dfsdm1_src[] = { "pclk2", "sys_ck" };
> +
> +static const char * const spdifrx_src[] = {
> +	"pll1_q", "pll2_r", "pll3_r", "hsi_ker" };
> +
> +static const char *spi_src1[5] = {
> +	"pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
> +
> +static const char * const spi_src2[] = {
> +	"pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
> +
> +static const char * const spi_src3[] = {
> +	"pclk4", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "hse_ck" };
> +
> +static const char * const lptim_src1[] = {
> +	"pclk1", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
> +
> +static const char * const lptim_src2[] = {
> +	"pclk4", "pll2_p", "pll3_r", "lse_ck", "lsi_ck", "per_ck" };
> +
> +static const char * const cec_src[] = {"lse_ck", "lsi_ck", "csi_ker_div122" };
> +
> +static const char * const usbotg_src[] = {"pll1_q", "pll3_q", "rc48_ck" };
> +
> +/* i2c 1,2,3 src */
> +static const char * const i2c_src1[] = {
> +	"pclk1", "pll3_r", "hsi_ker", "csi_ker" };
> +
> +static const char * const i2c_src2[] = {
> +	"pclk4", "pll3_r", "hsi_ker", "csi_ker" };
> +
> +static const char * const rng_src[] = {
> +	"rc48_ck", "pll1_q", "lse_ck", "lsi_ck" };
> +
> +/* usart 1,6 src */
> +static const char * const usart_src1[] = {
> +	"pclk2", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
> +
> +/* usart 2,3,4,5,7,8 src */
> +static const char * const usart_src2[] = {
> +	"pclk1", "pll2_q", "pll3_q", "hsi_ker", "csi_ker", "lse_ck" };
> +
> +static const char *sai_src[5] = {
> +	"pll1_q", "pll2_p", "pll3_p", NULL, "per_ck" };
> +
> +static const char * const adc_src[] = { "pll2_p", "pll3_r", "per_ck" };
> +
> +/* lptim 2,3,4,5 src */
> +static const char * const lpuart1_src[] = {
> +	"pclk3", "pll2_q", "pll3_q", "csi_ker", "lse_ck" };
> +
> +static const char * const hrtim_src[] = { "tim2_ker", "d1cpre" };
> +
> +/* RTC clock parent */
> +static const char * const rtc_src[] = { "off", "lse_ck", "lsi_ck", "hse_1M" };
> +
> +/* Micro-controller output clock parent */
> +static const char * const mco_src1[] = {
> +	"hsi_ck", "lse_ck", "hse_ck", "pll1_q",	"rc48_ck" };
> +
> +static const char * const mco_src2[] = {
> +	"sys_ck", "pll2_p", "hse_ck", "pll1_p", "csi", "lsi_ck" };
> +
> +/* LCD clock */
> +static const char * const ltdc_src[] = {"pll3_r"};
> +
> +/* Power domain helper */
> +static inline void disable_power_domain_write_protection(void)
> +{
> +	if (pdrm)
> +		regmap_update_bits(pdrm, 0x00, (1 << 8), (1 << 8));
> +}
> +
> +static inline void enable_power_domain_write_protection(void)
> +{
> +	if (pdrm)
> +		regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8));
> +}
> +
> +static inline int is_enable_power_domain_write_protection(void)
> +{
> +	if (pdrm) {
> +		u32 val;
> +
> +		regmap_read(pdrm, 0x00, &val);
> +
> +		return !(val & 0x100);
> +	}
> +	return -1;
> +}
> +
> +/* Gate clock with ready bit and backup domain management */
> +struct stm32_ready_gate {
> +	struct	clk_gate gate;
> +	u8	bit_rdy;
> +	u8	backup_domain;
> +};
> +
> +#define to_ready_gate_clk(_rgate) container_of(_rgate, struct stm32_ready_gate,\
> +		gate)
> +
> +#define RGATE_TIMEOUT 10000
> +
> +static int ready_gate_clk_is_enabled(struct clk_hw *hw)
> +{
> +	return clk_gate_ops.is_enabled(hw);
> +}
> +
> +static int ready_gate_clk_enable(struct clk_hw *hw)
> +{
> +	struct clk_gate *gate = to_clk_gate(hw);
> +	struct stm32_ready_gate *rgate = to_ready_gate_clk(gate);
> +	int dbp_status;
> +	int bit_status;
> +	unsigned int timeout = RGATE_TIMEOUT;
> +
> +	if (clk_gate_ops.is_enabled(hw))
> +		return 0;
> +
> +	dbp_status = is_enable_power_domain_write_protection();
> +
> +	if (rgate->backup_domain && dbp_status)
> +		disable_power_domain_write_protection();
> +
> +	clk_gate_ops.enable(hw);
> +
> +	do {
> +		bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy));
> +
> +		if (bit_status)
> +			udelay(100);
> +
> +	} while (bit_status && --timeout);
> +
> +	if (rgate->backup_domain && dbp_status)
> +		enable_power_domain_write_protection();
> +
> +	return bit_status;
> +}
> +
> +static void ready_gate_clk_disable(struct clk_hw *hw)
> +{
> +	clk_gate_ops.disable(hw);
> +}
> +
> +static const struct clk_ops ready_gate_clk_ops = {
> +	.enable		= ready_gate_clk_enable,
> +	.disable	= ready_gate_clk_disable,
> +	.is_enabled	= ready_gate_clk_is_enabled,
> +};
> +
> +static struct clk_hw *clk_register_ready_gate(struct device *dev,
> +		const char *name, const char *parent_name,
> +		void __iomem *reg, u8 bit_idx, u8 bit_rdy,
> +		u8 backup_domain, unsigned long flags, spinlock_t *lock)
> +{
> +	struct stm32_ready_gate *rgate;
> +	struct clk_init_data init = { NULL };
> +	struct clk_hw *hw;
> +	int ret;
> +
> +	rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
> +	if (!rgate)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &ready_gate_clk_ops;
> +	init.flags = flags;
> +	init.parent_names = &parent_name;
> +	init.num_parents = 1;
> +
> +	rgate->bit_rdy = bit_rdy;
> +	rgate->backup_domain = backup_domain;
> +
> +	rgate->gate.lock = lock;
> +	rgate->gate.reg = reg;
> +	rgate->gate.bit_idx = bit_idx;
> +	rgate->gate.hw.init = &init;
> +
> +	hw = &rgate->gate.hw;
> +	ret = clk_hw_register(dev, hw);
> +	if (ret) {
> +		kfree(rgate);
> +		hw = ERR_PTR(ret);
> +	}
> +
> +	return hw;
> +}
> +
> +struct gate_cfg {
> +	u32 offset;
> +	u8  bit_idx;
> +};
> +
> +struct muxdiv_cfg {
> +	u32 offset;
> +	u8 shift;
> +	u8 width;
> +};
> +
> +struct composite_clk_cfg {
> +	struct gate_cfg *gate;
> +	struct muxdiv_cfg *mux;
> +	struct muxdiv_cfg *div;
> +	const char *name;
> +	const char * const *parent_name;
> +	int num_parents;
> +	u32 flags;
> +};
> +
> +struct composite_clk_gcfg_t {
> +	u8 flags;
> +	const struct clk_ops *ops;
> +};
> +
> +/*
> + * General config definition of a composite clock (only clock diviser for rate)
> + */
> +struct composite_clk_gcfg {
> +	struct composite_clk_gcfg_t *mux;
> +	struct composite_clk_gcfg_t *div;
> +	struct composite_clk_gcfg_t *gate;
> +};
> +
> +#define M_CFG_MUX(_mux_ops, _mux_flags)\
> +	.mux = &(struct composite_clk_gcfg_t) { _mux_flags, _mux_ops}
> +
> +#define M_CFG_DIV(_rate_ops, _rate_flags)\
> +	.div = &(struct composite_clk_gcfg_t) {_rate_flags, _rate_ops}
> +
> +#define M_CFG_GATE(_gate_ops, _gate_flags)\
> +	.gate = &(struct composite_clk_gcfg_t) { _gate_flags, _gate_ops}
> +
> +static struct clk_mux *_get_cmux(void __iomem *reg, u8 shift, u8 width,
> +		u32 flags, spinlock_t *lock)
> +{
> +	struct clk_mux *mux;
> +
> +	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +	if (!mux)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mux->reg	= reg;
> +	mux->shift	= shift;
> +	mux->mask	= (1 << width) - 1;
> +	mux->flags	= flags;
> +	mux->lock	= lock;
> +
> +	return mux;
> +}
> +
> +static struct clk_divider *_get_cdiv(void __iomem *reg, u8 shift, u8 width,
> +		u32 flags, spinlock_t *lock)
> +{
> +	struct clk_divider *div;
> +
> +	div = kzalloc(sizeof(*div), GFP_KERNEL);
> +
> +	if (!div)
> +		return ERR_PTR(-ENOMEM);
> +
> +	div->reg   = reg;
> +	div->shift = shift;
> +	div->width = width;
> +	div->flags = flags;
> +	div->lock  = lock;
> +
> +	return div;
> +}
> +
> +static struct clk_gate *_get_cgate(void __iomem *reg, u8 bit_idx, u32 flags,
> +		spinlock_t *lock)
> +{
> +	struct clk_gate *gate;
> +
> +	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +	if (!gate)
> +		return ERR_PTR(-ENOMEM);
> +
> +	gate->reg	= reg;
> +	gate->bit_idx	= bit_idx;
> +	gate->flags	= flags;
> +	gate->lock	= lock;
> +
> +	return gate;
> +}
> +
> +struct composite_cfg {
> +	struct clk_hw *mux_hw;
> +	struct clk_hw *div_hw;
> +	struct clk_hw *gate_hw;
> +
> +	const struct clk_ops *mux_ops;
> +	const struct clk_ops *div_ops;
> +	const struct clk_ops *gate_ops;
> +};
> +
> +static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg,
> +		const struct composite_clk_cfg *cfg,
> +		struct composite_cfg *composite, spinlock_t *lock)
> +{
> +	struct clk_mux     *mux = NULL;
> +	struct clk_divider *div = NULL;
> +	struct clk_gate    *gate = NULL;
> +	const struct clk_ops *mux_ops, *div_ops, *gate_ops;
> +	struct clk_hw *mux_hw;
> +	struct clk_hw *div_hw;
> +	struct clk_hw *gate_hw;
> +
> +	mux_ops = div_ops = gate_ops = NULL;
> +	mux_hw = div_hw = gate_hw = NULL;
> +
> +	if (gcfg->mux) {
> +		mux = _get_cmux(base + cfg->mux->offset,
> +				cfg->mux->shift,
> +				cfg->mux->width,
> +				gcfg->mux->flags, lock);
> +
> +		if (!IS_ERR(mux)) {
> +			mux_hw = &mux->hw;
> +			mux_ops = gcfg->mux->ops ?
> +				  gcfg->mux->ops : &clk_mux_ops;
> +		}
> +	}
> +
> +	if (gcfg->div) {
> +		div = _get_cdiv(base + cfg->div->offset,
> +				cfg->div->shift,
> +				cfg->div->width,
> +				gcfg->div->flags, lock);
> +
> +		if (!IS_ERR(div)) {
> +			div_hw = &div->hw;
> +			div_ops = gcfg->div->ops ?
> +				  gcfg->div->ops : &clk_divider_ops;
> +		}
> +
> +	}
> +
> +	if (gcfg->gate) {
> +		gate = _get_cgate(base + cfg->gate->offset,
> +				cfg->gate->bit_idx,
> +				gcfg->gate->flags, lock);
> +
> +		if (!IS_ERR(gate)) {
> +			gate_hw = &gate->hw;
> +			gate_ops = gcfg->gate->ops ?
> +				   gcfg->gate->ops : &clk_gate_ops;
> +		}
> +
> +	}
> +
> +	composite->mux_hw = mux_hw;
> +	composite->mux_ops = mux_ops;
> +
> +	composite->div_hw = div_hw;
> +	composite->div_ops = div_ops;
> +
> +	composite->gate_hw = gate_hw;
> +	composite->gate_ops = gate_ops;
> +}
> +
> +/* Kernel Timer */
> +struct timer_ker {
> +	u8 dppre_shift;
> +	struct clk_hw hw;
> +	spinlock_t *lock;
> +};
> +
> +#define to_timer_ker(_hw) container_of(_hw, struct timer_ker, hw)
> +
> +static unsigned long timer_ker_recalc_rate(struct clk_hw *hw,
> +		unsigned long parent_rate)
> +{
> +	struct timer_ker *clk_elem = to_timer_ker(hw);
> +	u32 timpre;
> +	u32 dppre_shift = clk_elem->dppre_shift;
> +	u32 prescaler;
> +	u32 mul;
> +
> +	timpre = (readl(base + RCC_CFGR) >> 15) & 0x01;
> +
> +	prescaler = (readl(base + RCC_D2CFGR) >> dppre_shift) & 0x03;
> +
> +	mul = 2;
> +
> +	if (prescaler < 4)
> +		mul = 1;
> +
> +	else if (timpre && prescaler > 4)
> +		mul = 4;
> +
> +	return parent_rate * mul;
> +}
> +
> +static const struct clk_ops timer_ker_ops = {
> +	.recalc_rate = timer_ker_recalc_rate,
> +};
> +
> +static struct clk_hw *clk_register_stm32_timer_ker(struct device *dev,
> +		const char *name, const char *parent_name,
> +		unsigned long flags,
> +		u8 dppre_shift,
> +		spinlock_t lock)
> +{
> +	struct timer_ker *element;
> +	struct clk_init_data init;
> +	struct clk_hw *hw;
> +	int err;
> +
> +	element = kzalloc(sizeof(*element), GFP_KERNEL);
> +	if (!element)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &timer_ker_ops;
> +	init.flags = flags;
> +	init.parent_names = &parent_name;
> +	init.num_parents = 1;
> +
> +	element->hw.init = &init;
> +	element->lock = &lock;
> +	element->dppre_shift = dppre_shift;
> +
> +	hw = &element->hw;
> +	err = clk_hw_register(dev, hw);
> +
> +	if (err) {
> +		kfree(element);
> +		return ERR_PTR(err);
> +	}
> +
> +	return hw;
> +}
> +
> +static const struct clk_div_table d1cpre_div_table[] = {
> +	{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
> +	{ 4, 1 }, { 5, 1 }, { 6, 1 }, { 7, 1},
> +	{ 8, 2 }, { 9, 4 }, { 10, 8 }, { 11, 16 },
> +	{ 12, 64 }, { 13, 128 }, { 14, 256 },
> +	{ 15, 512 },
> +	{ 0 },
> +};
> +
> +static const struct clk_div_table ppre_div_table[] = {
> +	{ 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1},
> +	{ 4, 2 }, { 5, 4 }, { 6, 8 }, { 7, 16 },
> +	{ 0 },
> +};
> +
> +static void register_core_and_bus_clocks(void)
> +{
> +	/* CORE AND BUS */
> +	hws[SYS_D1CPRE] = clk_hw_register_divider_table(NULL, "d1cpre",
> +			"sys_ck", CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 8, 4, 0,
> +			d1cpre_div_table, &rlock);
> +
> +	hws[HCLK] = clk_hw_register_divider_table(NULL, "hclk", "d1cpre",
> +			CLK_IGNORE_UNUSED, base + RCC_D1CFGR, 0, 4, 0,
> +			d1cpre_div_table, &rlock);
> +
> +	/* D1 DOMAIN */
> +	/* * CPU Systick */
> +	hws[CPU_SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick",
> +			"d1cpre", 0, 1, 8);
> +
> +	/* * APB3 peripheral */
> +	hws[PCLK3] = clk_hw_register_divider_table(NULL, "pclk3", "hclk", 0,
> +			base + RCC_D1CFGR, 4, 3, 0,
> +			ppre_div_table, &rlock);
> +
> +	/* D2 DOMAIN */
> +	/* * APB1 peripheral */
> +	hws[PCLK1] = clk_hw_register_divider_table(NULL, "pclk1", "hclk", 0,
> +			base + RCC_D2CFGR, 4, 3, 0,
> +			ppre_div_table, &rlock);
> +
> +	/* Timers prescaler clocks */
> +	clk_register_stm32_timer_ker(NULL, "tim1_ker", "pclk1", 0,
> +			4, rlock);
> +
> +	/* * APB2 peripheral */
> +	hws[PCLK2] = clk_hw_register_divider_table(NULL, "pclk2", "hclk", 0,
> +			base + RCC_D2CFGR, 8, 3, 0, ppre_div_table, &rlock);
> +
> +	clk_register_stm32_timer_ker(NULL, "tim2_ker", "pclk2", 0, 8, rlock);
> +
> +	/* D3 DOMAIN */
> +	/* * APB4 peripheral */
> +	hws[PCLK4] = clk_hw_register_divider_table(NULL, "pclk4", "hclk", 0,
> +			base + RCC_D3CFGR, 4, 3, 0,
> +			ppre_div_table, &rlock);
> +}
> +
> +/* MUX clock configuration */
> +struct stm32_mux_clk {
> +	const char *name;
> +	const char * const *parents;
> +	u8 num_parents;
> +	u32 offset;
> +	u8 shift;
> +	u8 width;
> +	u32 flags;
> +};
> +
> +#define M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, _flags)\
> +{\
> +	.name		= _name,\
> +	.parents	= _parents,\
> +	.num_parents	= ARRAY_SIZE(_parents),\
> +	.offset		= _mux_offset,\
> +	.shift		= _mux_shift,\
> +	.width		= _mux_width,\
> +	.flags		= _flags,\
> +}
> +#define M_MCLOC(_name, _parents, _mux_offset, _mux_shift, _mux_width)\
> +	M_MCLOCF(_name, _parents, _mux_offset, _mux_shift, _mux_width, 0)\
> +
> +static const struct stm32_mux_clk stm32_mclk[] __initconst = {
> +	M_MCLOC("per_ck",	per_src,	RCC_D1CCIPR,	28, 3),
> +	M_MCLOC("pllsrc",	pll_src,	RCC_PLLCKSELR,	 0, 3),
> +	M_MCLOC("sys_ck",	sys_src,	RCC_CFGR,	 0, 3),
> +	M_MCLOC("tracein_ck",	tracein_src,	RCC_CFGR,	 0, 3),
> +};
> +
> +/* Oscillary clock configuration */
> +struct stm32_osc_clk {
> +	const char *name;
> +	const char *parent;
> +	u32 gate_offset;
> +	u8 bit_idx;
> +	u8 bit_rdy;
> +	u32 flags;
> +};
> +
> +#define OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, _flags)\
> +{\
> +	.name		= _name,\
> +	.parent		= _parent,\
> +	.gate_offset	= _gate_offset,\
> +	.bit_idx	= _bit_idx,\
> +	.bit_rdy	= _bit_rdy,\
> +	.flags		= _flags,\
> +}
> +#define OSC_CLK(_name, _parent, _gate_offset, _bit_idx, _bit_rdy)\
> +	OSC_CLKF(_name, _parent, _gate_offset, _bit_idx, _bit_rdy, 0)
> +
> +static const struct stm32_osc_clk stm32_oclk[] __initconst = {
> +	OSC_CLK("hsi_ck",  "hsidiv",   RCC_CR,   0,  2),
> +	OSC_CLK("hsi_ker", "hsidiv",   RCC_CR,   1,  2),
> +	OSC_CLK("csi_ck",  "clk-csi",  RCC_CR,   7,  8),
> +	OSC_CLK("csi_ker", "clk-csi",  RCC_CR,   9,  8),
> +	OSC_CLK("rc48_ck", "clk-rc48", RCC_CR,  12, 13),
> +	OSC_CLK("lsi_ck",  "clk-lsi",  RCC_CSR,  0,  1),
> +};
> +
> +/* PLL configuration */
> +struct st32h7_pll_cfg {
> +	u8 bit_idx;
> +	u32 offset_divr;
> +	u8 bit_frac_en;
> +	u32 offset_frac;
> +	u8 divm;
> +};
> +
> +struct stm32_pll_data {
> +	const char *name;
> +	const char *parent_name;
> +	unsigned long flags;
> +	const struct st32h7_pll_cfg *cfg;
> +};
> +
> +static const struct st32h7_pll_cfg stm32h7_pll1 = {
> +	.bit_idx = 24,
> +	.offset_divr = RCC_PLL1DIVR,
> +	.bit_frac_en = 0,
> +	.offset_frac = RCC_PLL1FRACR,
> +	.divm = 4,
> +};
> +
> +static const struct st32h7_pll_cfg stm32h7_pll2 = {
> +	.bit_idx = 26,
> +	.offset_divr = RCC_PLL2DIVR,
> +	.bit_frac_en = 4,
> +	.offset_frac = RCC_PLL2FRACR,
> +	.divm = 12,
> +};
> +
> +static const struct st32h7_pll_cfg stm32h7_pll3 = {
> +	.bit_idx = 28,
> +	.offset_divr = RCC_PLL3DIVR,
> +	.bit_frac_en = 8,
> +	.offset_frac = RCC_PLL3FRACR,
> +	.divm = 20,
> +};
> +
> +static const struct stm32_pll_data stm32_pll[] = {
> +	{ "vco1", "pllsrc", 0, &stm32h7_pll1 },
> +	{ "vco2", "pllsrc", 0, &stm32h7_pll2 },
> +	{ "vco3", "pllsrc", 0, &stm32h7_pll3 },
> +};
> +
> +struct stm32_fractional_divider {
> +	void __iomem	*mreg;
> +	u8		mshift;
> +	u8		mwidth;
> +	u32		mmask;
> +
> +	void __iomem	*nreg;
> +	u8		nshift;
> +	u8		nwidth;
> +
> +	void __iomem	*freg_status;
> +	u8		freg_bit;
> +	void __iomem	*freg_value;
> +	u8		fshift;
> +	u8		fwidth;
> +
> +	u8		flags;
> +	struct clk_hw	hw;
> +	spinlock_t	*lock;
> +};
> +
> +struct stm32_pll_obj {
> +	spinlock_t *lock;
> +	struct stm32_fractional_divider div;
> +	struct stm32_ready_gate rgate;
> +	struct clk_hw hw;
> +};
> +
> +#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw)
> +
> +static int pll_is_enabled(struct clk_hw *hw)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
> +
> +	__clk_hw_set_clk(_hw, hw);
> +
> +	return ready_gate_clk_ops.is_enabled(_hw);
> +}
> +
> +static int pll_enable(struct clk_hw *hw)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
> +
> +	__clk_hw_set_clk(_hw, hw);
> +
> +	return ready_gate_clk_ops.enable(_hw);
> +}
> +
> +static void pll_disable(struct clk_hw *hw)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct clk_hw *_hw = &clk_elem->rgate.gate.hw;
> +
> +	__clk_hw_set_clk(_hw, hw);
> +
> +	ready_gate_clk_ops.disable(_hw);
> +}
> +
> +static int pll_frac_is_enabled(struct clk_hw *hw)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct stm32_fractional_divider *fd = &clk_elem->div;
> +
> +	return (readl(fd->freg_status) >> fd->freg_bit) & 0x01;
> +}
> +
> +static unsigned long pll_read_frac(struct clk_hw *hw)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct stm32_fractional_divider *fd = &clk_elem->div;
> +
> +	return (readl(fd->freg_value) >> fd->fshift) &
> +		GENMASK(fd->fwidth - 1, 0);
> +}
> +
> +static unsigned long pll_fd_recalc_rate(struct clk_hw *hw,
> +		unsigned long parent_rate)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct stm32_fractional_divider *fd = &clk_elem->div;
> +	unsigned long m, n;
> +	u32 val, mask;
> +	u64 rate, rate1 = 0;
> +
> +	val = clk_readl(fd->mreg);
> +	mask = (GENMASK(fd->mwidth - 1, 0) << fd->mshift);
> +	m = (val & mask) >> fd->mshift;
> +
> +	val = clk_readl(fd->nreg);
> +	mask = (GENMASK(fd->nwidth - 1, 0) << fd->nshift);
> +	n = ((val & mask) >> fd->nshift) + 1;
> +
> +	if (!n || !m)
> +		return parent_rate;
> +
> +	rate = (u64)parent_rate * n;
> +	do_div(rate, m);
> +
> +	if (pll_frac_is_enabled(hw)) {
> +		val = pll_read_frac(hw);
> +		rate1 = (u64) parent_rate * (u64) val;
> +		do_div(rate1, (m * 8191));
> +	}
> +
> +	return rate + rate1;
> +}
> +
> +static const struct clk_ops pll_ops = {
> +	.enable		= pll_enable,
> +	.disable	= pll_disable,
> +	.is_enabled	= pll_is_enabled,
> +	.recalc_rate	= pll_fd_recalc_rate,
> +};
> +
> +static struct clk_hw *clk_register_stm32_pll(struct device *dev,
> +		const char *name,
> +		const char *parent,
> +		unsigned long flags,
> +		const struct st32h7_pll_cfg *cfg,
> +		spinlock_t *lock)
> +{
> +
> +	struct stm32_pll_obj *pll;
> +	struct clk_init_data init = { NULL };
> +	struct clk_hw *hw;
> +	int ret;
> +	struct stm32_fractional_divider *div = NULL;
> +	struct stm32_ready_gate *rgate;
> +
> +
> +	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
> +	if (!pll)
> +		return ERR_PTR(-ENOMEM);
> +
> +	init.name = name;
> +	init.ops = &pll_ops;
> +	init.flags = flags;
> +	init.parent_names = &parent;
> +	init.num_parents = 1;
> +	pll->hw.init = &init;
> +
> +	hw = &pll->hw;
> +	rgate = &pll->rgate;
> +
> +	rgate->bit_rdy = cfg->bit_idx + 1;
> +	rgate->gate.lock = lock;
> +	rgate->gate.reg = base + RCC_CR;
> +	rgate->gate.bit_idx = cfg->bit_idx;
> +
> +	div = &pll->div;
> +	div->flags = 0;
> +	div->mreg = base + RCC_PLLCKSELR;
> +	div->mshift = cfg->divm;
> +	div->mwidth = 6;
> +	div->nreg = base +  cfg->offset_divr;
> +	div->nshift = 0;
> +	div->nwidth = 9;
> +
> +	div->freg_status = base + RCC_PLLCFGR;
> +	div->freg_bit = cfg->bit_frac_en;
> +	div->freg_value = base +  cfg->offset_frac;
> +	div->fshift = 3;
> +	div->fwidth = 13;
> +
> +	div->lock = lock;
> +
> +	ret = clk_hw_register(dev, hw);
> +	if (ret) {
> +		kfree(pll);
> +		hw = ERR_PTR(ret);
> +	}
> +
> +	return hw;
> +}
> +
> +/* ODF CLOCKS */
> +static unsigned long odf_divider_recalc_rate(struct clk_hw *hw,
> +		unsigned long parent_rate)
> +{
> +	return clk_divider_ops.recalc_rate(hw, parent_rate);
> +}
> +
> +static long odf_divider_round_rate(struct clk_hw *hw, unsigned long rate,
> +		unsigned long *prate)
> +{
> +	return clk_divider_ops.round_rate(hw, rate, prate);
> +}
> +
> +static int odf_divider_set_rate(struct clk_hw *hw, unsigned long rate,
> +		unsigned long parent_rate)
> +{
> +	struct clk_hw *hwp;
> +	int pll_status;
> +	int ret;
> +
> +	hwp = clk_hw_get_parent(hw);
> +
> +	pll_status = pll_is_enabled(hwp);
> +
> +	if (pll_status)
> +		pll_disable(hwp);
> +
> +	ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
> +
> +	if (pll_status)
> +		pll_enable(hwp);
> +
> +	return ret;
> +}
> +
> +static const struct clk_ops odf_divider_ops = {
> +	.recalc_rate	= odf_divider_recalc_rate,
> +	.round_rate	= odf_divider_round_rate,
> +	.set_rate	= odf_divider_set_rate,
> +};
> +
> +static int odf_gate_enable(struct clk_hw *hw)
> +{
> +	struct clk_hw *hwp;
> +	int pll_status;
> +	int ret;
> +
> +	hwp = clk_hw_get_parent(hw);
> +
> +	pll_status = pll_is_enabled(hwp);
> +
> +	if (pll_status)
> +		pll_disable(hwp);
> +
> +	ret = clk_gate_ops.enable(hw);
> +
> +	if (pll_status)
> +		pll_enable(hwp);
> +
> +	return ret;
> +}
> +
> +static void odf_gate_disable(struct clk_hw *hw)
> +{
> +	clk_gate_ops.disable(hw);
> +}
> +
> +static int odf_gate_is_enabled(struct clk_hw *hw)
> +{
> +	return clk_gate_ops.is_enabled(hw);
> +}
> +
> +static const struct clk_ops odf_gate_ops = {
> +	.enable		= odf_gate_enable,
> +	.disable	= odf_gate_disable,
> +	.is_enabled	= odf_gate_is_enabled,
> +};
> +
> +static struct composite_clk_gcfg odf_clk_gcfg = {
> +	M_CFG_DIV(&odf_divider_ops, 0),
> +	M_CFG_GATE(&odf_gate_ops, 0),
> +};
> +
> +#define M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
> +		_rate_shift, _rate_width, _flags)\
> +{\
> +	.mux = NULL,\
> +	.div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
> +	.gate = &(struct gate_cfg) {_gate_offset, _bit_idx },\
> +	.name = _name,\
> +	.parent_name = &(const char *) {_parent},\
> +	.num_parents = 1,\
> +	.flags = _flags,\
> +}
> +
> +#define M_ODF(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
> +		_rate_shift, _rate_width)\
> +M_ODF_F(_name, _parent, _gate_offset,  _bit_idx, _rate_offset,\
> +		_rate_shift, _rate_width, 0)\
> +
> +static const struct composite_clk_cfg stm32_odf[3][3] = {
> +	{
> +		M_ODF("pll1_p", "vco1", RCC_PLLCFGR, 16, RCC_PLL1DIVR,  9, 7),
> +		M_ODF("pll1_q", "vco1", RCC_PLLCFGR, 17, RCC_PLL1DIVR, 16, 7),
> +		M_ODF("pll1_r", "vco1", RCC_PLLCFGR, 18, RCC_PLL1DIVR, 24, 7),
> +	},
> +
> +	{
> +		M_ODF("pll2_p", "vco2", RCC_PLLCFGR, 19, RCC_PLL2DIVR,  9, 7),
> +		M_ODF("pll2_q", "vco2", RCC_PLLCFGR, 20, RCC_PLL2DIVR, 16, 7),
> +		M_ODF("pll2_r", "vco2", RCC_PLLCFGR, 21, RCC_PLL2DIVR, 24, 7),
> +	},
> +	{
> +		M_ODF("pll3_p", "vco3", RCC_PLLCFGR, 22, RCC_PLL3DIVR,  9, 7),
> +		M_ODF("pll3_q", "vco3", RCC_PLLCFGR, 23, RCC_PLL3DIVR, 16, 7),
> +		M_ODF("pll3_r", "vco3", RCC_PLLCFGR, 24, RCC_PLL3DIVR, 24, 7),
> +	}
> +};
> +
> +/* PLL config structure from DT */
> +struct pll_param {
> +	u32 index;
> +	u32 mult;
> +	u32 div;
> +	u32 frac_en;
> +	u32 frac;
> +	u32 vcosel;
> +	u32 pllrge;
> +};
> +
> +static int of_get_stm32_pll(struct device_node *np, struct pll_param *param)
> +{
> +	if (of_property_read_u32(np, "reg", &param->index) ||
> +			param->index >= ARRAY_SIZE(stm32_pll))
> +		return -EINVAL;
> +
> +	of_property_read_u32(np, "st,clock-div", &param->div);
> +
> +	of_property_read_u32(np, "st,clock-mult", &param->mult);
> +
> +	param->frac_en = ~0;
> +	of_property_read_u32(np, "st,frac-status", &param->frac_en);
> +
> +	of_property_read_u32(np, "st,frac", &param->frac);
> +
> +	param->vcosel = ~0;
> +	of_property_read_u32(np, "st,vcosel", &param->vcosel);
> +
> +	param->pllrge = ~0;
> +	of_property_read_u32(np, "st,pllrge", &param->pllrge);
> +
> +	return 0;
> +}
> +
> +static void stm32_pll_save_param(struct clk_hw *hw,
> +		struct pll_param *pll_dt_cfg)
> +{
> +	struct stm32_pll_obj *clk_elem = to_pll(hw);
> +	struct stm32_fractional_divider *fd = &clk_elem->div;
> +	unsigned long m, n;
> +	u32 val;
> +	int pll_status;
> +
> +	/* Save PLL parameters from DT if needed */
> +	pll_status = pll_ops.is_enabled(hw);
> +
> +	if (pll_status)
> +		pll_ops.disable(hw);
> +
> +	m = pll_dt_cfg->div;
> +	if (m) {
> +		val = clk_readl(fd->mreg);
> +		val &= ~(GENMASK(fd->mwidth - 1, 0) << fd->mshift);
> +		val |= (m << fd->mshift);
> +		writel(val, fd->mreg);
> +	}
> +
> +	n = pll_dt_cfg->mult;
> +	if (n)  {
> +		val = clk_readl(fd->nreg);
> +		val &= ~((GENMASK(fd->nwidth - 1, 0) << fd->nshift));
> +		val |= ((n - 1) << fd->nshift);
> +		writel(val, fd->nreg);
> +	}
> +
> +	if (pll_dt_cfg->frac_en != ~0) {
> +		int status;
> +
> +		status = !!pll_dt_cfg->frac_en;
> +
> +		/* write frac status */
> +		val = readl(fd->freg_status);
> +
> +		val &= ~BIT(fd->freg_bit);
> +		val |= status << fd->freg_bit;
> +		writel(val, fd->freg_status);
> +
> +		/* write frac value */
> +		val = clk_readl(fd->freg_value);
> +		val &= ~((GENMASK(fd->fshift - 1, 0) << fd->fshift));
> +
> +		/* if enable, set to '0' before */
> +		if (status)
> +			writel(val, fd->freg_value);
> +
> +		val |= ((pll_dt_cfg->frac) << fd->fshift);
> +		writel(val, fd->freg_value);
> +	}
> +
> +	if (pll_dt_cfg->vcosel != ~0) {
> +		val = readl(fd->freg_status);
> +		val &= ~BIT(fd->freg_bit + 1);
> +		val |= (pll_dt_cfg->vcosel & 0x01) << (fd->freg_bit + 1);
> +		writel(val, fd->freg_status);
> +
> +	}
> +
> +	if (pll_dt_cfg->pllrge != ~0) {
> +		val = readl(fd->freg_status);
> +		val &= ~(0x3 << (fd->freg_bit + 2));
> +		val |= (pll_dt_cfg->pllrge & 0x3) << (fd->freg_bit + 2);
> +		writel(val, fd->freg_status);
> +	}
> +
> +	if (pll_status)
> +		pll_ops.enable(hw);
> +}
> +
> +static void stm32_h7_pll_init(struct device_node *np)
> +{
> +	struct pll_param pll_dt_cfg = { };
> +	struct clk_hw *hw;
> +	int idx, n;
> +
> +	if (of_get_stm32_pll(np, &pll_dt_cfg))
> +		return;
> +
> +	idx = pll_dt_cfg.index;
> +
> +	/* Register the VCO */
> +	hw = clk_register_stm32_pll(NULL, stm32_pll[idx].name,
> +			stm32_pll[idx].parent_name, stm32_pll[idx].flags,
> +			stm32_pll[idx].cfg,
> +			&rlock);
> +
> +	stm32_pll_save_param(hw, &pll_dt_cfg);
> +
> +	/* Register the 3 output dividers */
> +	for (n = 0; n < 3; n++) {
> +		struct composite_cfg c_cfg;
> +
> +		get_cfg_composite_div(&odf_clk_gcfg, &stm32_odf[idx][n],
> +				&c_cfg,	&rlock);
> +
> +		hws[ODF_BANK + (idx * 3) + n] = clk_hw_register_composite(NULL,
> +				stm32_odf[idx][n].name,
> +				stm32_odf[idx][n].parent_name,
> +				stm32_odf[idx][n].num_parents,
> +				c_cfg.mux_hw, c_cfg.mux_ops,
> +				c_cfg.div_hw, c_cfg.div_ops,
> +				c_cfg.gate_hw, c_cfg.gate_ops,
> +				stm32_odf[idx][n].flags);
> +	}
> +}
> +
> +/* PERIF CLOCKS */
> +struct pclk_t {
> +	u32 gate_offset;
> +	u8 bit_idx;
> +	const char *name;
> +	const char *parent;
> +	u32 flags;
> +};
> +
> +#define PER_CLKF(_gate_offset, _bit_idx, _name, _parent, _flags)\
> +{\
> +	.gate_offset	= _gate_offset,\
> +	.bit_idx	= _bit_idx,\
> +	.name		= _name,\
> +	.parent		= _parent,\
> +	.flags		= _flags,\
> +}
> +#define PER_CLK(_gate_offset, _bit_idx, _name, _parent)\
> +	PER_CLKF(_gate_offset, _bit_idx, _name, _parent, 0)
> +
> +static const struct pclk_t pclk[] = {
> +	PER_CLK(RCC_AHB3ENR, 31, "d1sram1", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 30, "itcm", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 29, "dtcm2", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 28, "dtcm1", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 8, "flitf", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 5, "jpgdec", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 4, "dma2d", "hclk"),
> +	PER_CLK(RCC_AHB3ENR, 0, "mdma", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 28, "usb2ulpi", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 26, "usb1ulpi", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 17, "eth1rx", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 16, "eth1tx", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 15, "eth1mac", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 14, "art", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 1, "dma2", "hclk"),
> +	PER_CLK(RCC_AHB1ENR, 0, "dma1", "hclk"),
> +	PER_CLK(RCC_AHB2ENR, 31, "d2sram3", "hclk"),
> +	PER_CLK(RCC_AHB2ENR, 30, "d2sram2", "hclk"),
> +	PER_CLK(RCC_AHB2ENR, 29, "d2sram1", "hclk"),
> +	PER_CLK(RCC_AHB2ENR, 5, "hash", "hclk"),
> +	PER_CLK(RCC_AHB2ENR, 4, "crypt", "hclk"),
> +	PER_CLK(RCC_AHB2ENR, 0, "camitf", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 28, "bkpram", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 25, "hsem", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 21, "bdma", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 19, "crc", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 10, "gpiok", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 9, "gpioj", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 8, "gpioi", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 7, "gpioh", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 6, "gpiog", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 5, "gpiof", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 4, "gpioe", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 3, "gpiod", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 2, "gpioc", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 1, "gpiob", "hclk"),
> +	PER_CLK(RCC_AHB4ENR, 0, "gpioa", "hclk"),
> +	PER_CLK(RCC_APB3ENR, 6, "wwdg1", "pclk3"),
> +	PER_CLK(RCC_APB1LENR, 29, "dac12", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 11, "wwdg2", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 8, "tim14", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 7, "tim13", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 6, "tim12", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 5, "tim7", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 4, "tim6", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 3, "tim5", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 2, "tim4", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 1, "tim3", "pclk1"),
> +	PER_CLK(RCC_APB1LENR, 0, "tim2", "pclk1"),
> +	PER_CLK(RCC_APB1HENR, 5, "mdios", "pclk1"),
> +	PER_CLK(RCC_APB1HENR, 4, "opamp", "pclk1"),
> +	PER_CLK(RCC_APB1HENR, 1, "crs", "pclk1"),
> +	PER_CLK(RCC_APB2ENR, 18, "tim17", "pclk2"),
> +	PER_CLK(RCC_APB2ENR, 17, "tim16", "pclk2"),
> +	PER_CLK(RCC_APB2ENR, 16, "tim15", "pclk2"),
> +	PER_CLK(RCC_APB2ENR, 1, "tim8", "pclk2"),
> +	PER_CLK(RCC_APB2ENR, 0, "tim1", "pclk2"),
> +	PER_CLK(RCC_APB4ENR, 26, "tmpsens", "pclk4"),
> +	PER_CLK(RCC_APB4ENR, 16, "rtcapb", "pclk4"),
> +	PER_CLK(RCC_APB4ENR, 15, "vref", "pclk4"),
> +	PER_CLK(RCC_APB4ENR, 14, "comp12", "pclk4"),
> +	PER_CLK(RCC_APB4ENR, 1, "syscfg", "pclk4"),
> +};
> +
> +/* KERNEL CLOCKS */
> +#define KER_CLKF(_gate_offset, _bit_idx,\
> +		_mux_offset, _mux_shift, _mux_width,\
> +		_name, _parent_name,\
> +		_flags) \
> +{ \
> +	.gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
> +	.mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
> +	.name = _name, \
> +	.parent_name = _parent_name, \
> +	.num_parents = ARRAY_SIZE(_parent_name),\
> +	.flags = _flags,\
> +}
> +#define KER_CLK(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
> +		_name, _parent_name) \
> +KER_CLKF(_gate_offset, _bit_idx, _mux_offset, _mux_shift, _mux_width,\
> +		_name, _parent_name, 0)\
> +
> +#define KER_CLKF_NOMUX(_gate_offset, _bit_idx,\
> +		_name, _parent_name,\
> +		_flags) \
> +{ \
> +	.gate = &(struct gate_cfg) {_gate_offset, _bit_idx},\
> +	.mux = NULL,\
> +	.name = _name, \
> +	.parent_name = _parent_name, \
> +	.num_parents = 1,\
> +	.flags = _flags,\
> +}
> +
> +static const struct composite_clk_cfg kclk[] = {
> +	KER_CLK(RCC_AHB3ENR,  16, RCC_D1CCIPR,	16, 1, "sdmmc1", sdmmc_src),
> +	KER_CLKF(RCC_AHB3ENR, 14, RCC_D1CCIPR,	 4, 2, "quadspi", qspi_src,
> +			CLK_IGNORE_UNUSED),
> +	KER_CLKF(RCC_AHB3ENR, 12, RCC_D1CCIPR,	 0, 2, "fmc", fmc_src,
> +			CLK_IGNORE_UNUSED),
> +	KER_CLK(RCC_AHB1ENR,  27, RCC_D2CCIP2R,	20, 2, "usb2otg", usbotg_src),
> +	KER_CLK(RCC_AHB1ENR,  25, RCC_D2CCIP2R, 20, 2, "usb1otg", usbotg_src),
> +	KER_CLK(RCC_AHB1ENR,   5, RCC_D3CCIPR,	16, 2, "adc12", adc_src),
> +	KER_CLK(RCC_AHB2ENR,   9, RCC_D1CCIPR,	16, 1, "sdmmc2", sdmmc_src),
> +	KER_CLK(RCC_AHB2ENR,   6, RCC_D2CCIP2R,	 8, 2, "rng", rng_src),
> +	KER_CLK(RCC_AHB4ENR,  24, RCC_D3CCIPR,  16, 2, "adc3", adc_src),
> +	KER_CLK(RCC_APB3ENR,   4, RCC_D1CCIPR,	 8, 1, "dsi", dsi_src),
> +	KER_CLKF_NOMUX(RCC_APB3ENR, 3, "ltdc", ltdc_src, 0),
> +	KER_CLK(RCC_APB1LENR, 31, RCC_D2CCIP2R,  0, 3, "usart8", usart_src2),
> +	KER_CLK(RCC_APB1LENR, 30, RCC_D2CCIP2R,  0, 3, "usart7", usart_src2),
> +	KER_CLK(RCC_APB1LENR, 27, RCC_D2CCIP2R, 22, 2, "hdmicec", cec_src),
> +	KER_CLK(RCC_APB1LENR, 23, RCC_D2CCIP2R, 12, 2, "i2c3", i2c_src1),
> +	KER_CLK(RCC_APB1LENR, 22, RCC_D2CCIP2R, 12, 2, "i2c2", i2c_src1),
> +	KER_CLK(RCC_APB1LENR, 21, RCC_D2CCIP2R, 12, 2, "i2c1", i2c_src1),
> +	KER_CLK(RCC_APB1LENR, 20, RCC_D2CCIP2R,	 0, 3, "uart5", usart_src2),
> +	KER_CLK(RCC_APB1LENR, 19, RCC_D2CCIP2R,  0, 3, "uart4", usart_src2),
> +	KER_CLK(RCC_APB1LENR, 18, RCC_D2CCIP2R,  0, 3, "usart3", usart_src2),
> +	KER_CLK(RCC_APB1LENR, 17, RCC_D2CCIP2R,  0, 3, "usart2", usart_src2),
> +	KER_CLK(RCC_APB1LENR, 16, RCC_D2CCIP1R, 20, 2, "spdifrx", spdifrx_src),
> +	KER_CLK(RCC_APB1LENR, 15, RCC_D2CCIP1R, 16, 3, "spi3", spi_src1),
> +	KER_CLK(RCC_APB1LENR, 14, RCC_D2CCIP1R, 16, 3, "spi2", spi_src1),
> +	KER_CLK(RCC_APB1LENR,  9, RCC_D2CCIP2R, 28, 3, "lptim1", lptim_src1),
> +	KER_CLK(RCC_APB1HENR,  8, RCC_D2CCIP1R, 28, 2, "fdcan", fdcan_src),
> +	KER_CLK(RCC_APB1HENR,  2, RCC_D2CCIP1R, 31, 1, "swp", swp_src),
> +	KER_CLK(RCC_APB2ENR,  29, RCC_CFGR,	14, 1, "hrtim", hrtim_src),
> +	KER_CLK(RCC_APB2ENR,  28, RCC_D2CCIP1R, 24, 1, "dfsdm1", dfsdm1_src),
> +	KER_CLK(RCC_APB2ENR,  24, RCC_D2CCIP1R,  6, 3, "sai3", sai_src),
> +	KER_CLK(RCC_APB2ENR,  23, RCC_D2CCIP1R,  6, 3, "sai2", sai_src),
> +	KER_CLK(RCC_APB2ENR,  22, RCC_D2CCIP1R,  0, 3, "sai1", sai_src),
> +	KER_CLK(RCC_APB2ENR,  20, RCC_D2CCIP1R, 16, 3, "spi5", spi_src2),
> +	KER_CLK(RCC_APB2ENR,  13, RCC_D2CCIP1R, 16, 3, "spi4", spi_src2),
> +	KER_CLK(RCC_APB2ENR,  12, RCC_D2CCIP1R, 16, 3, "spi1", spi_src1),
> +	KER_CLK(RCC_APB2ENR,   5, RCC_D2CCIP2R,  3, 3, "usart6", usart_src1),
> +	KER_CLK(RCC_APB2ENR,   4, RCC_D2CCIP2R,  3, 3, "usart1", usart_src1),
> +	KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,	24, 3, "sai4b", sai_src),
> +	KER_CLK(RCC_APB4ENR,  21, RCC_D3CCIPR,	21, 3, "sai4a", sai_src),
> +	KER_CLK(RCC_APB4ENR,  12, RCC_D3CCIPR,	13, 3, "lptim5", lptim_src2),
> +	KER_CLK(RCC_APB4ENR,  11, RCC_D3CCIPR,	13, 3, "lptim4", lptim_src2),
> +	KER_CLK(RCC_APB4ENR,  10, RCC_D3CCIPR,	13, 3, "lptim3", lptim_src2),
> +	KER_CLK(RCC_APB4ENR,   9, RCC_D3CCIPR,	10, 3, "lptim2", lptim_src2),
> +	KER_CLK(RCC_APB4ENR,   7, RCC_D3CCIPR,	 8, 2, "i2c4", i2c_src2),
> +	KER_CLK(RCC_APB4ENR,   5, RCC_D3CCIPR,	28, 3, "spi6", spi_src3),
> +	KER_CLK(RCC_APB4ENR,   3, RCC_D3CCIPR,	 0, 3, "lpuart1", lpuart1_src),
> +};
> +
> +static struct composite_clk_gcfg kernel_clk_cfg = {
> +	M_CFG_MUX(NULL, 0),
> +	M_CFG_GATE(NULL, 0),
> +};
> +
> +/* RTC clock */
> +static u8 rtc_mux_get_parent(struct clk_hw *hw)
> +{
> +	return clk_mux_ops.get_parent(hw);
> +}
> +
> +static int rtc_mux_set_parent(struct clk_hw *hw, u8 index)
> +{
> +	int dbp_status;
> +	int err;
> +
> +	dbp_status = is_enable_power_domain_write_protection();
> +
> +	if (dbp_status)
> +		disable_power_domain_write_protection();
> +
> +	err = clk_mux_ops.set_parent(hw, index);
> +
> +	if (dbp_status)
> +		enable_power_domain_write_protection();
> +
> +	return err;
> +}
> +
> +static int rtc_mux_determine_rate(struct clk_hw *hw,
> +		struct clk_rate_request *req)
> +{
> +	return clk_mux_ops.determine_rate(hw, req);
> +}
> +
> +static const struct clk_ops rtc_mux_ops = {
> +	.get_parent	= rtc_mux_get_parent,
> +	.set_parent	= rtc_mux_set_parent,
> +	.determine_rate = rtc_mux_determine_rate,
> +};
> +
> +/* Clock gate with backup domain protection management */
> +static int bd_gate_enable(struct clk_hw *hw)
> +{
> +	int dbp_status;
> +	int err;
> +
> +	dbp_status = is_enable_power_domain_write_protection();
> +
> +	if (dbp_status)
> +		disable_power_domain_write_protection();
> +
> +	err = clk_gate_ops.enable(hw);
> +
> +	if (dbp_status)
> +		enable_power_domain_write_protection();
> +
> +	return err;
> +}
> +
> +static void bd_gate_disable(struct clk_hw *hw)
> +{
> +	clk_gate_ops.disable(hw);
> +}
> +
> +static int bd_gate_is_enabled(struct clk_hw *hw)
> +{
> +	return clk_gate_ops.is_enabled(hw);
> +}
> +
> +static const struct clk_ops bd_gate_ops = {
> +	.enable		= bd_gate_enable,
> +	.disable	= bd_gate_disable,
> +	.is_enabled	= bd_gate_is_enabled,
> +};
> +
> +static struct composite_clk_gcfg rtc_clk_cfg = {
> +	M_CFG_MUX(&rtc_mux_ops, 0),
> +	M_CFG_GATE(&bd_gate_ops, 0),
> +};
> +
> +static const struct composite_clk_cfg rtc_clk =
> +	KER_CLK(RCC_BDCR, 15, RCC_BDCR, 8, 2, "rtc_ck", rtc_src);
> +
> +/* Micro-controller output clock */
> +static struct composite_clk_gcfg mco_clk_cfg = {
> +	M_CFG_MUX(NULL, 0),
> +	M_CFG_DIV(NULL,	CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO),
> +};
> +
> +#define M_MCO_F(_name, _parents, _mux_offset,  _mux_shift, _mux_width,\
> +		_rate_offset, _rate_shift, _rate_width,\
> +		_flags)\
> +{\
> +	.mux = &(struct muxdiv_cfg) {_mux_offset, _mux_shift, _mux_width },\
> +	.div = &(struct muxdiv_cfg) {_rate_offset, _rate_shift, _rate_width},\
> +	.gate = NULL,\
> +	.name = _name,\
> +	.parent_name = _parents,\
> +	.num_parents = ARRAY_SIZE(_parents),\
> +	.flags = _flags,\
> +}
> +
> +static const struct composite_clk_cfg mco_clk[] = {
> +	M_MCO_F("mco1", mco_src1, RCC_CFGR, 22, 4, RCC_CFGR, 18, 4, 0),
> +	M_MCO_F("mco2", mco_src2, RCC_CFGR, 29, 3, RCC_CFGR, 25, 4, 0),
> +};
> +
> +static void __init stm32h7_rcc_init(struct device_node *np)
> +{
> +	struct clk_hw_onecell_data *clk_data;
> +	struct device_node *node;
> +	struct composite_cfg c_cfg;
> +	int n;
> +	const char *hse_clk, *lse_clk, *i2s_clk;
> +
> +	clk_data = kzalloc(sizeof(*clk_data) +
> +			sizeof(*clk_data->hws) * STM32H7_MAX_CLKS,
> +			GFP_KERNEL);
> +	if (!clk_data)
> +		return;
> +
> +	clk_data->num = STM32H7_MAX_CLKS;
> +
> +	hws = clk_data->hws;
> +
> +	for (n = 0; n < STM32H7_MAX_CLKS; n++)
> +		hws[n] = ERR_PTR(-ENOENT);
> +
> +	/* get RCC base @ from DT */
> +	base = of_iomap(np, 0);
> +	if (!base) {
> +		pr_err("%s: unable to map resource", np->name);
> +		goto err_free_clks;
> +	}
> +
> +	pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
> +	if (IS_ERR(pdrm)) {
> +		pdrm = NULL;
> +		pr_warn("%s: Unable to get syscfg\n", __func__);
> +	}
> +
> +	/* Put parent names from DT */
> +	hse_clk = of_clk_get_parent_name(np, 0);
> +	lse_clk = of_clk_get_parent_name(np, 1);
> +	i2s_clk = of_clk_get_parent_name(np, 2);
> +
> +	sai_src[3] = i2s_clk;
> +	spi_src1[3] = i2s_clk;
> +
> +	/* Register Internal oscillators */
> +	clk_hw_register_fixed_rate(NULL, "clk-hsi", NULL, 0, 64000000);
> +	clk_hw_register_fixed_rate(NULL, "clk-csi", NULL, 0, 4000000);
> +	clk_hw_register_fixed_rate(NULL, "clk-lsi", NULL, 0, 32000);
> +	clk_hw_register_fixed_rate(NULL, "clk-rc48", NULL, 0, 48000);
> +
> +	/* This clock is coming from outside. Frequencies unknown */
> +	hws[CK_DSI_PHY] = clk_hw_register_fixed_rate(NULL, "ck_dsi_phy", NULL,
> +			0, 0);
> +
> +	hws[HSI_DIV] = clk_hw_register_divider(NULL, "hsidiv", "clk-hsi", 0,
> +			base + RCC_CR, 3, 2, CLK_DIVIDER_POWER_OF_TWO,
> +			&rlock);
> +
> +	hws[HSE_1M] = clk_hw_register_divider(NULL, "hse_1M", "hse_ck",	0,
> +			base + RCC_CFGR, 8, 6, CLK_DIVIDER_ONE_BASED |
> +			CLK_DIVIDER_ALLOW_ZERO,
> +			&rlock);
> +
> +	/* Mux system clocks */
> +	for (n = 0; n < ARRAY_SIZE(stm32_mclk); n++)
> +		hws[MCLK_BANK + n] = clk_hw_register_mux(NULL,
> +				stm32_mclk[n].name,
> +				stm32_mclk[n].parents,
> +				stm32_mclk[n].num_parents,
> +				stm32_mclk[n].flags,
> +				stm32_mclk[n].offset + base,
> +				stm32_mclk[n].shift,
> +				stm32_mclk[n].width,
> +				0,
> +				&rlock);
> +
> +	register_core_and_bus_clocks();
> +
> +	/* Oscillary clocks */
> +	for (n = 0; n < ARRAY_SIZE(stm32_oclk); n++)
> +		hws[OSC_BANK + n] = clk_register_ready_gate(NULL,
> +				stm32_oclk[n].name,
> +				stm32_oclk[n].parent,
> +				stm32_oclk[n].gate_offset + base,
> +				stm32_oclk[n].bit_idx,
> +				stm32_oclk[n].bit_rdy,
> +				0,
> +				stm32_oclk[n].flags,
> +				&rlock);
> +
> +	hws[HSE_CK] = clk_register_ready_gate(NULL,
> +				"hse_ck",
> +				hse_clk,
> +				RCC_CR + base,
> +				16, 17,
> +				0,
> +				0,
> +				&rlock);
> +
> +	hws[LSE_CK] = clk_register_ready_gate(NULL,
> +				"lse_ck",
> +				lse_clk,
> +				RCC_BDCR + base,
> +				0, 1,
> +				1,
> +				0,
> +				&rlock);
> +
> +	hws[CSI_KER_DIV122 + n] = clk_hw_register_fixed_factor(NULL,
> +			"csi_ker_div122", "csi_ker", 0, 1, 122);
> +
> +	/* PLLs */
> +	for_each_compatible_node(node, NULL, "stm32,pll")
> +		stm32_h7_pll_init(node);
> +
> +	/* Peripheral clocks */
> +	for (n = 0; n < ARRAY_SIZE(pclk); n++)
> +		hws[PERIF_BANK + n] = clk_hw_register_gate(NULL, pclk[n].name,
> +				pclk[n].parent,
> +				pclk[n].flags, base + pclk[n].gate_offset,
> +				pclk[n].bit_idx, pclk[n].flags, &rlock);
> +
> +	/* Kernel clocks */
> +	for (n = 0; n < ARRAY_SIZE(kclk); n++) {
> +		get_cfg_composite_div(&kernel_clk_cfg, &kclk[n], &c_cfg,
> +				&rlock);
> +
> +		hws[KERN_BANK + n] = clk_hw_register_composite(NULL,
> +				kclk[n].name,
> +				kclk[n].parent_name,
> +				kclk[n].num_parents,
> +				c_cfg.mux_hw, c_cfg.mux_ops,
> +				c_cfg.div_hw, c_cfg.div_ops,
> +				c_cfg.gate_hw, c_cfg.gate_ops,
> +				kclk[n].flags);
> +	}
> +
> +	/* RTC clock (default state is off) */
> +	clk_hw_register_fixed_rate(NULL, "off", NULL, 0, 0);
> +
> +	get_cfg_composite_div(&rtc_clk_cfg, &rtc_clk, &c_cfg, &rlock);
> +
> +	hws[RTC_CK] = clk_hw_register_composite(NULL,
> +			rtc_clk.name,
> +			rtc_clk.parent_name,
> +			rtc_clk.num_parents,
> +			c_cfg.mux_hw, c_cfg.mux_ops,
> +			c_cfg.div_hw, c_cfg.div_ops,
> +			c_cfg.gate_hw, c_cfg.gate_ops,
> +			rtc_clk.flags);
> +
> +	/* Micro-controller clocks */
> +	for (n = 0; n < ARRAY_SIZE(mco_clk); n++) {
> +		get_cfg_composite_div(&mco_clk_cfg, &mco_clk[n], &c_cfg,
> +				&rlock);
> +
> +		hws[MCO_BANK + n] = clk_hw_register_composite(NULL,
> +				mco_clk[n].name,
> +				mco_clk[n].parent_name,
> +				mco_clk[n].num_parents,
> +				c_cfg.mux_hw, c_cfg.mux_ops,
> +				c_cfg.div_hw, c_cfg.div_ops,
> +				c_cfg.gate_hw, c_cfg.gate_ops,
> +				mco_clk[n].flags);
> +	}
> +
> +	of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data);
> +
> +	return;
> +
> +err_free_clks:
> +	kfree(clk_data);
> +}
> +CLK_OF_DECLARE_DRIVER(stm32h7_rcc, "st,stm32h743-rcc", stm32h7_rcc_init);
> diff --git a/include/dt-bindings/clock/stm32h7-clks.h b/include/dt-bindings/clock/stm32h7-clks.h
> new file mode 100644
> index 0000000..6637272
> --- /dev/null
> +++ b/include/dt-bindings/clock/stm32h7-clks.h
> @@ -0,0 +1,165 @@
> +/* 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
> +
> +/* 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
> diff --git a/include/dt-bindings/mfd/stm32h7-rcc.h b/include/dt-bindings/mfd/stm32h7-rcc.h
> new file mode 100644
> index 0000000..b96b3c3
> --- /dev/null
> +++ b/include/dt-bindings/mfd/stm32h7-rcc.h
> @@ -0,0 +1,138 @@
> +/*
> + * This header provides constants for the STM32H7 RCC IP
> + */
> +
> +#ifndef _DT_BINDINGS_MFD_STM32H7_RCC_H
> +#define _DT_BINDINGS_MFD_STM32H7_RCC_H
> +
> +/* AHB3 */
> +#define STM32H7_RCC_AHB3_MDMA		0
> +#define STM32H7_RCC_AHB3_DMA2D		4
> +#define STM32H7_RCC_AHB3_JPGDEC		5
> +#define STM32H7_RCC_AHB3_FMC		12
> +#define STM32H7_RCC_AHB3_QUADSPI	14
> +#define STM32H7_RCC_AHB3_SDMMC1		16
> +#define STM32H7_RCC_AHB3_CPU1		31
> +
> +#define STM32H7_AHB3_RESET(bit) (STM32H7_RCC_AHB3_##bit + (0x7C * 8))
> +
> +/* AHB1 */
> +#define STM32H7_RCC_AHB1_DMA1		0
> +#define STM32H7_RCC_AHB1_DMA2		1
> +#define STM32H7_RCC_AHB1_ADC12		5
> +#define STM32H7_RCC_AHB1_ART		14
> +#define STM32H7_RCC_AHB1_ETH1MAC	15
> +#define STM32H7_RCC_AHB1_USB1OTG	25
> +#define STM32H7_RCC_AHB1_USB2OTG	27
> +#define STM32H7_RCC_AHB1_CPU2		31
> +
> +#define STM32H7_AHB1_RESET(bit) (STM32H7_RCC_AHB1_##bit + (0x80 * 8))
> +
> +/* AHB2 */
> +#define STM32H7_RCC_AHB2_CAMITF		0
> +#define STM32H7_RCC_AHB2_CRYPT		4
> +#define STM32H7_RCC_AHB2_HASH		5
> +#define STM32H7_RCC_AHB2_RNG		6
> +#define STM32H7_RCC_AHB2_SDMMC2		9
> +
> +#define STM32H7_AHB2_RESET(bit) (STM32H7_RCC_AHB2_##bit + (0x84 * 8))
> +
> +/* AHB4 */
> +#define STM32H7_RCC_AHB4_GPIOA		0
> +#define STM32H7_RCC_AHB4_GPIOB		1
> +#define STM32H7_RCC_AHB4_GPIOC		2
> +#define STM32H7_RCC_AHB4_GPIOD		3
> +#define STM32H7_RCC_AHB4_GPIOE		4
> +#define STM32H7_RCC_AHB4_GPIOF		5
> +#define STM32H7_RCC_AHB4_GPIOG		6
> +#define STM32H7_RCC_AHB4_GPIOH		7
> +#define STM32H7_RCC_AHB4_GPIOI		8
> +#define STM32H7_RCC_AHB4_GPIOJ		9
> +#define STM32H7_RCC_AHB4_GPIOK		10
> +#define STM32H7_RCC_AHB4_CRC		19
> +#define STM32H7_RCC_AHB4_BDMA		21
> +#define STM32H7_RCC_AHB4_ADC3		24
> +#define STM32H7_RCC_AHB4_HSEM		25
> +
> +#define STM32H7_AHB4_RESET(bit) (STM32H7_RCC_AHB4_##bit + (0x88 * 8))
> +
> +
> +/* APB3 */
> +#define STM32H7_RCC_APB3_LTDC		3
> +#define STM32H7_RCC_APB3_DSI		4
> +
> +#define STM32H7_APB3_RESET(bit) (STM32H7_RCC_APB3_##bit + (0x8C * 8))
> +
> +/* APB1L */
> +#define STM32H7_RCC_APB1L_TIM2		0
> +#define STM32H7_RCC_APB1L_TIM3		1
> +#define STM32H7_RCC_APB1L_TIM4		2
> +#define STM32H7_RCC_APB1L_TIM5		3
> +#define STM32H7_RCC_APB1L_TIM6		4
> +#define STM32H7_RCC_APB1L_TIM7		5
> +#define STM32H7_RCC_APB1L_TIM12		6
> +#define STM32H7_RCC_APB1L_TIM13		7
> +#define STM32H7_RCC_APB1L_TIM14		8
> +#define STM32H7_RCC_APB1L_LPTIM1	9
> +#define STM32H7_RCC_APB1L_SPI2		14
> +#define STM32H7_RCC_APB1L_SPI3		15
> +#define STM32H7_RCC_APB1L_SPDIF_RX	16
> +#define STM32H7_RCC_APB1L_USART2	17
> +#define STM32H7_RCC_APB1L_USART3	18
> +#define STM32H7_RCC_APB1L_UART4		19
> +#define STM32H7_RCC_APB1L_UART5		20
> +#define STM32H7_RCC_APB1L_I2C1		21
> +#define STM32H7_RCC_APB1L_I2C2		22
> +#define STM32H7_RCC_APB1L_I2C3		23
> +#define STM32H7_RCC_APB1L_HDMICEC	27
> +#define STM32H7_RCC_APB1L_DAC12		29
> +#define STM32H7_RCC_APB1L_USART7	30
> +#define STM32H7_RCC_APB1L_USART8	31
> +
> +#define STM32H7_APB1L_RESET(bit) (STM32H7_RCC_APB1L_##bit + (0x90 * 8))
> +
> +/* APB1H */
> +#define STM32H7_RCC_APB1H_CRS		1
> +#define STM32H7_RCC_APB1H_SWP		2
> +#define STM32H7_RCC_APB1H_OPAMP		4
> +#define STM32H7_RCC_APB1H_MDIOS		5
> +#define STM32H7_RCC_APB1H_FDCAN		8
> +
> +#define STM32H7_APB1H_RESET(bit) (STM32H7_RCC_APB1H_##bit + (0x94 * 8))
> +
> +/* APB2 */
> +#define STM32H7_RCC_APB2_TIM1		0
> +#define STM32H7_RCC_APB2_TIM8		1
> +#define STM32H7_RCC_APB2_USART1		4
> +#define STM32H7_RCC_APB2_USART6		5
> +#define STM32H7_RCC_APB2_SPI1		12
> +#define STM32H7_RCC_APB2_SPI4		13
> +#define STM32H7_RCC_APB2_TIM15		16
> +#define STM32H7_RCC_APB2_TIM16		17
> +#define STM32H7_RCC_APB2_TIM17		18
> +#define STM32H7_RCC_APB2_SPI5		20
> +#define STM32H7_RCC_APB2_SAI1		22
> +#define STM32H7_RCC_APB2_SAI2		23
> +#define STM32H7_RCC_APB2_SAI3		24
> +#define STM32H7_RCC_APB2_DFSDM1		28
> +#define STM32H7_RCC_APB2_HRTIM		29
> +
> +#define STM32H7_APB2_RESET(bit) (STM32H7_RCC_APB2_##bit + (0x98 * 8))
> +
> +/* APB4 */
> +#define STM32H7_RCC_APB4_SYSCFG		1
> +#define STM32H7_RCC_APB4_LPUART1	3
> +#define STM32H7_RCC_APB4_SPI6		5
> +#define STM32H7_RCC_APB4_I2C4		7
> +#define STM32H7_RCC_APB4_LPTIM2		9
> +#define STM32H7_RCC_APB4_LPTIM3		10
> +#define STM32H7_RCC_APB4_LPTIM4		11
> +#define STM32H7_RCC_APB4_LPTIM5		12
> +#define STM32H7_RCC_APB4_COMP12		14
> +#define STM32H7_RCC_APB4_VREF		15
> +#define STM32H7_RCC_APB4_SAI4		21
> +#define STM32H7_RCC_APB4_TMPSENS	26
> +
> +#define STM32H7_APB4_RESET(bit) (STM32H7_RCC_APB4_##bit + (0x9C * 8))
> +
> +#endif /* _DT_BINDINGS_MFD_STM32H7_RCC_H */

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ