| /* 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); |