summaryrefslogtreecommitdiff
path: root/drivers/clk/stm32/clk-stm32-core.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clk/stm32/clk-stm32-core.h')
-rw-r--r--drivers/clk/stm32/clk-stm32-core.h276
1 files changed, 276 insertions, 0 deletions
diff --git a/drivers/clk/stm32/clk-stm32-core.h b/drivers/clk/stm32/clk-stm32-core.h
new file mode 100644
index 00000000000..53c2b467ab8
--- /dev/null
+++ b/drivers/clk/stm32/clk-stm32-core.h
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */
+/*
+ * Copyright (C) STMicroelectronics 2022 - All Rights Reserved
+ * Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics.
+ */
+
+struct stm32_clock_match_data;
+
+/**
+ * struct stm32_mux_cfg - multiplexer configuration
+ *
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @reg_off: register controlling multiplexer
+ * @shift: shift to multiplexer bit field
+ * @width: width of the multiplexer bit field
+ * @mux_flags: hardware-specific flags
+ * @table: array of register values corresponding to the parent
+ * index
+ */
+struct stm32_mux_cfg {
+ const char * const *parent_names;
+ u8 num_parents;
+ u32 reg_off;
+ u8 shift;
+ u8 width;
+ u8 mux_flags;
+ u32 *table;
+};
+
+/**
+ * struct stm32_gate_cfg - gating configuration
+ *
+ * @reg_off: register controlling gate
+ * @bit_idx: single bit controlling gate
+ * @gate_flags: hardware-specific flags
+ * @set_clr: 0 : normal gate, 1 : has a register to clear the gate
+ */
+struct stm32_gate_cfg {
+ u32 reg_off;
+ u8 bit_idx;
+ u8 gate_flags;
+ u8 set_clr;
+};
+
+/**
+ * struct stm32_div_cfg - divider configuration
+ *
+ * @reg_off: register containing the divider
+ * @shift: shift to the divider bit field
+ * @width: width of the divider bit field
+ * @table: array of value/divider pairs, last entry should have div = 0
+ */
+struct stm32_div_cfg {
+ u32 reg_off;
+ u8 shift;
+ u8 width;
+ u8 div_flags;
+ const struct clk_div_table *table;
+};
+
+#define NO_STM32_MUX -1
+#define NO_STM32_DIV -1
+#define NO_STM32_GATE -1
+
+/**
+ * struct stm32_composite_cfg - composite configuration
+ *
+ * @mux: index of a multiplexer
+ * @gate: index of a gate
+ * @div: index of a divider
+ */
+struct stm32_composite_cfg {
+ int mux;
+ int gate;
+ int div;
+};
+
+/**
+ * struct clock_config - clock configuration
+ *
+ * @id: binding id of the clock
+ * @name: clock name
+ * @parent_name: name of the clock parent
+ * @flags: framework-specific flags
+ * @sec_id: secure id (use to known if the clock is secured or not)
+ * @clock_cfg: specific clock data configuration
+ * @setup: specific call back to reister the clock (will use
+ * clock_cfg data as input)
+ */
+struct clock_config {
+ unsigned long id;
+ const char *name;
+ const char *parent_name;
+ unsigned long flags;
+ int sec_id;
+ void *clock_cfg;
+
+ struct clk *(*setup)(struct udevice *dev,
+ const struct clock_config *cfg);
+};
+
+/**
+ * struct clk_stm32_clock_data - clock data
+ *
+ * @num_gates: number of defined gates
+ * @gates: array of gate configuration
+ * @muxes: array of multiplexer configuration
+ * @dividers: array of divider configuration
+ */
+struct clk_stm32_clock_data {
+ unsigned int num_gates;
+ const struct stm32_gate_cfg *gates;
+ const struct stm32_mux_cfg *muxes;
+ const struct stm32_div_cfg *dividers;
+};
+
+/**
+ * struct stm32_clock_match_data - clock match data
+ *
+ * @num_gates: number of clocks
+ * @tab_clocks: array of clock configuration
+ * @clock_data: definition of all gates / dividers / multiplexers
+ * @check_security: call back to check if clock is secured or not
+ */
+struct stm32_clock_match_data {
+ unsigned int num_clocks;
+ const struct clock_config *tab_clocks;
+ const struct clk_stm32_clock_data *clock_data;
+ int (*check_security)(void __iomem *base,
+ const struct clock_config *cfg);
+};
+
+/**
+ * struct stm32mp_rcc_priv - private struct for stm32mp clocks
+ *
+ * @base: base register of RCC driver
+ * @gate_cpt: array of refcounting for gate with more than one
+ * clocks as input. See explanation of Peripheral clock enabling
+ * below.
+ * @data: data for gate / divider / multiplexer configuration
+ */
+struct stm32mp_rcc_priv {
+ void __iomem *base;
+ u8 *gate_cpt;
+ const struct clk_stm32_clock_data *data;
+};
+
+int stm32_rcc_init(struct udevice *dev,
+ const struct stm32_clock_match_data *data);
+
+/**
+ * STM32 Gate
+ *
+ * PCE (Peripheral Clock Enabling) Peripheral
+ *
+ * ------------------------------ ----------
+ * | | | |
+ * | | | PERx |
+ * bus_ck | ----- | | |
+ * ------------->|------------------| | | ckg_bus_perx | |
+ * | | AND |-----|---------------->| |
+ * | -----------| | | | |
+ * | | ----- | | |
+ * | | | | |
+ * | ----- | | |
+ * Perx_EN |-----|---| GCL | Gating | | |
+ * | ----- Control | | |
+ * | | Logic | | |
+ * | | | | |
+ * | | ----- | | |
+ * | -----------| | | ckg_ker_perx | |
+ * perx_ker_ck | | AND |-----|---------------->| |
+ * ------------->|------------------| | | | |
+ * | ----- | | |
+ * | | | |
+ * | | | |
+ * ------------------------------ ----------
+
+ * Each peripheral requires a bus interface clock, named ckg_bus_perx
+ * (for peripheral ‘x’).
+ * Some peripherals (SAI, UART...) need also a dedicated clock for their
+ * communication interface, this clock is generally asynchronous with respect to
+ * the bus interface clock, and is named kernel clock (ckg_ker_perx).
+
+ * Both clocks can be gated by one Perx_EN enable bit.
+ * Then we have to manage a refcounting on gate level to avoid gate if one
+ * the bus or the Kernel was enable.
+ *
+ * Example:
+ * 1) enable the bus clock
+ * --> bus_clk ref_counting = 1, gate_ref_count = 1
+ * 2) enable the kernel clock
+ * --> perx_ker_ck ref_counting = 1, gate_ref_count = 2
+ * 3) disable kernel clock
+ *  ---> perx_ker_ck ref_counting = 0, gate_ref_count = 1
+ *  ==> then i will not gate because gate_ref_count > 0
+ * 4) disable bus clock
+ * --> bus_clk ref_counting = 0, gate_ref_count = 0
+ * ==> then i can gate (write in the register) because
+ * gate_ref_count = 0
+ */
+
+struct clk_stm32_gate {
+ struct clk clk;
+ struct stm32mp_rcc_priv *priv;
+ int gate_id;
+};
+
+#define to_clk_stm32_gate(_clk) container_of(_clk, struct clk_stm32_gate, clk)
+
+struct clk *
+clk_stm32_gate_register(struct udevice *dev,
+ const struct clock_config *cfg);
+
+struct clk *
+clk_stm32_register_composite(struct udevice *dev,
+ const struct clock_config *cfg);
+
+struct stm32_clk_gate_cfg {
+ int gate_id;
+};
+
+#define STM32_GATE(_id, _name, _parent, _flags, _gate_id, _sec_id) \
+{ \
+ .id = _id, \
+ .sec_id = _sec_id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .flags = _flags, \
+ .clock_cfg = &(struct stm32_clk_gate_cfg) { \
+ .gate_id = _gate_id, \
+ }, \
+ .setup = clk_stm32_gate_register, \
+}
+
+struct stm32_clk_composite_cfg {
+ int gate_id;
+ int mux_id;
+ int div_id;
+};
+
+#define STM32_COMPOSITE(_id, _name, _flags, _sec_id, \
+ _gate_id, _mux_id, _div_id) \
+{ \
+ .id = _id, \
+ .name = _name, \
+ .sec_id = _sec_id, \
+ .flags = _flags, \
+ .clock_cfg = &(struct stm32_clk_composite_cfg) { \
+ .gate_id = _gate_id, \
+ .mux_id = _mux_id, \
+ .div_id = _div_id, \
+ }, \
+ .setup = clk_stm32_register_composite, \
+}
+
+#define STM32_COMPOSITE_NOMUX(_id, _name, _parent, _flags, _sec_id, \
+ _gate_id, _div_id) \
+{ \
+ .id = _id, \
+ .name = _name, \
+ .parent_name = _parent, \
+ .sec_id = _sec_id, \
+ .flags = _flags, \
+ .clock_cfg = &(struct stm32_clk_composite_cfg) { \
+ .gate_id = _gate_id, \
+ .mux_id = NO_STM32_MUX, \
+ .div_id = _div_id, \
+ }, \
+ .setup = clk_stm32_register_composite, \
+}
+
+extern const struct clk_ops stm32_clk_ops;
+
+ulong clk_stm32_get_rate_by_name(const char *name);