mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-14 23:33:00 +00:00
277 lines
8.2 KiB
C
277 lines
8.2 KiB
C
|
/* 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);
|