Gabriel Fernandez | 3db088a | 2022-11-24 11:36:04 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause */ |
| 2 | /* |
| 3 | * Copyright (C) STMicroelectronics 2022 - All Rights Reserved |
| 4 | * Author: Gabriel Fernandez <gabriel.fernandez@foss.st.com> for STMicroelectronics. |
| 5 | */ |
| 6 | |
| 7 | struct stm32_clock_match_data; |
| 8 | |
| 9 | /** |
| 10 | * struct stm32_mux_cfg - multiplexer configuration |
| 11 | * |
| 12 | * @parent_names: array of string names for all possible parents |
| 13 | * @num_parents: number of possible parents |
| 14 | * @reg_off: register controlling multiplexer |
| 15 | * @shift: shift to multiplexer bit field |
| 16 | * @width: width of the multiplexer bit field |
| 17 | * @mux_flags: hardware-specific flags |
| 18 | * @table: array of register values corresponding to the parent |
| 19 | * index |
| 20 | */ |
| 21 | struct stm32_mux_cfg { |
| 22 | const char * const *parent_names; |
| 23 | u8 num_parents; |
| 24 | u32 reg_off; |
| 25 | u8 shift; |
| 26 | u8 width; |
| 27 | u8 mux_flags; |
| 28 | u32 *table; |
| 29 | }; |
| 30 | |
| 31 | /** |
| 32 | * struct stm32_gate_cfg - gating configuration |
| 33 | * |
| 34 | * @reg_off: register controlling gate |
| 35 | * @bit_idx: single bit controlling gate |
| 36 | * @gate_flags: hardware-specific flags |
| 37 | * @set_clr: 0 : normal gate, 1 : has a register to clear the gate |
| 38 | */ |
| 39 | struct stm32_gate_cfg { |
| 40 | u32 reg_off; |
| 41 | u8 bit_idx; |
| 42 | u8 gate_flags; |
| 43 | u8 set_clr; |
| 44 | }; |
| 45 | |
| 46 | /** |
| 47 | * struct stm32_div_cfg - divider configuration |
| 48 | * |
| 49 | * @reg_off: register containing the divider |
| 50 | * @shift: shift to the divider bit field |
| 51 | * @width: width of the divider bit field |
| 52 | * @table: array of value/divider pairs, last entry should have div = 0 |
| 53 | */ |
| 54 | struct stm32_div_cfg { |
| 55 | u32 reg_off; |
| 56 | u8 shift; |
| 57 | u8 width; |
| 58 | u8 div_flags; |
| 59 | const struct clk_div_table *table; |
| 60 | }; |
| 61 | |
| 62 | #define NO_STM32_MUX -1 |
| 63 | #define NO_STM32_DIV -1 |
| 64 | #define NO_STM32_GATE -1 |
| 65 | |
| 66 | /** |
| 67 | * struct stm32_composite_cfg - composite configuration |
| 68 | * |
| 69 | * @mux: index of a multiplexer |
| 70 | * @gate: index of a gate |
| 71 | * @div: index of a divider |
| 72 | */ |
| 73 | struct stm32_composite_cfg { |
| 74 | int mux; |
| 75 | int gate; |
| 76 | int div; |
| 77 | }; |
| 78 | |
| 79 | /** |
| 80 | * struct clock_config - clock configuration |
| 81 | * |
| 82 | * @id: binding id of the clock |
| 83 | * @name: clock name |
| 84 | * @parent_name: name of the clock parent |
| 85 | * @flags: framework-specific flags |
| 86 | * @sec_id: secure id (use to known if the clock is secured or not) |
| 87 | * @clock_cfg: specific clock data configuration |
| 88 | * @setup: specific call back to reister the clock (will use |
| 89 | * clock_cfg data as input) |
| 90 | */ |
| 91 | struct clock_config { |
| 92 | unsigned long id; |
| 93 | const char *name; |
| 94 | const char *parent_name; |
| 95 | unsigned long flags; |
| 96 | int sec_id; |
| 97 | void *clock_cfg; |
| 98 | |
| 99 | struct clk *(*setup)(struct udevice *dev, |
| 100 | const struct clock_config *cfg); |
| 101 | }; |
| 102 | |
| 103 | /** |
| 104 | * struct clk_stm32_clock_data - clock data |
| 105 | * |
| 106 | * @num_gates: number of defined gates |
| 107 | * @gates: array of gate configuration |
| 108 | * @muxes: array of multiplexer configuration |
| 109 | * @dividers: array of divider configuration |
| 110 | */ |
| 111 | struct clk_stm32_clock_data { |
| 112 | unsigned int num_gates; |
| 113 | const struct stm32_gate_cfg *gates; |
| 114 | const struct stm32_mux_cfg *muxes; |
| 115 | const struct stm32_div_cfg *dividers; |
| 116 | }; |
| 117 | |
| 118 | /** |
| 119 | * struct stm32_clock_match_data - clock match data |
| 120 | * |
| 121 | * @num_gates: number of clocks |
| 122 | * @tab_clocks: array of clock configuration |
| 123 | * @clock_data: definition of all gates / dividers / multiplexers |
| 124 | * @check_security: call back to check if clock is secured or not |
| 125 | */ |
| 126 | struct stm32_clock_match_data { |
| 127 | unsigned int num_clocks; |
| 128 | const struct clock_config *tab_clocks; |
| 129 | const struct clk_stm32_clock_data *clock_data; |
| 130 | int (*check_security)(void __iomem *base, |
| 131 | const struct clock_config *cfg); |
| 132 | }; |
| 133 | |
| 134 | /** |
| 135 | * struct stm32mp_rcc_priv - private struct for stm32mp clocks |
| 136 | * |
| 137 | * @base: base register of RCC driver |
| 138 | * @gate_cpt: array of refcounting for gate with more than one |
| 139 | * clocks as input. See explanation of Peripheral clock enabling |
| 140 | * below. |
| 141 | * @data: data for gate / divider / multiplexer configuration |
| 142 | */ |
| 143 | struct stm32mp_rcc_priv { |
| 144 | void __iomem *base; |
| 145 | u8 *gate_cpt; |
| 146 | const struct clk_stm32_clock_data *data; |
| 147 | }; |
| 148 | |
| 149 | int stm32_rcc_init(struct udevice *dev, |
| 150 | const struct stm32_clock_match_data *data); |
| 151 | |
| 152 | /** |
| 153 | * STM32 Gate |
| 154 | * |
| 155 | * PCE (Peripheral Clock Enabling) Peripheral |
| 156 | * |
| 157 | * ------------------------------ ---------- |
| 158 | * | | | | |
| 159 | * | | | PERx | |
| 160 | * bus_ck | ----- | | | |
| 161 | * ------------->|------------------| | | ckg_bus_perx | | |
| 162 | * | | AND |-----|---------------->| | |
| 163 | * | -----------| | | | | |
| 164 | * | | ----- | | | |
| 165 | * | | | | | |
| 166 | * | ----- | | | |
| 167 | * Perx_EN |-----|---| GCL | Gating | | | |
| 168 | * | ----- Control | | | |
| 169 | * | | Logic | | | |
| 170 | * | | | | | |
| 171 | * | | ----- | | | |
| 172 | * | -----------| | | ckg_ker_perx | | |
| 173 | * perx_ker_ck | | AND |-----|---------------->| | |
| 174 | * ------------->|------------------| | | | | |
| 175 | * | ----- | | | |
| 176 | * | | | | |
| 177 | * | | | | |
| 178 | * ------------------------------ ---------- |
| 179 | |
| 180 | * Each peripheral requires a bus interface clock, named ckg_bus_perx |
| 181 | * (for peripheral ‘x’). |
| 182 | * Some peripherals (SAI, UART...) need also a dedicated clock for their |
| 183 | * communication interface, this clock is generally asynchronous with respect to |
| 184 | * the bus interface clock, and is named kernel clock (ckg_ker_perx). |
| 185 | |
| 186 | * Both clocks can be gated by one Perx_EN enable bit. |
| 187 | * Then we have to manage a refcounting on gate level to avoid gate if one |
| 188 | * the bus or the Kernel was enable. |
| 189 | * |
| 190 | * Example: |
| 191 | * 1) enable the bus clock |
| 192 | * --> bus_clk ref_counting = 1, gate_ref_count = 1 |
| 193 | * 2) enable the kernel clock |
| 194 | * --> perx_ker_ck ref_counting = 1, gate_ref_count = 2 |
| 195 | * 3) disable kernel clock |
| 196 | * ---> perx_ker_ck ref_counting = 0, gate_ref_count = 1 |
| 197 | * ==> then i will not gate because gate_ref_count > 0 |
| 198 | * 4) disable bus clock |
| 199 | * --> bus_clk ref_counting = 0, gate_ref_count = 0 |
| 200 | * ==> then i can gate (write in the register) because |
| 201 | * gate_ref_count = 0 |
| 202 | */ |
| 203 | |
| 204 | struct clk_stm32_gate { |
| 205 | struct clk clk; |
| 206 | struct stm32mp_rcc_priv *priv; |
| 207 | int gate_id; |
| 208 | }; |
| 209 | |
| 210 | #define to_clk_stm32_gate(_clk) container_of(_clk, struct clk_stm32_gate, clk) |
| 211 | |
| 212 | struct clk * |
| 213 | clk_stm32_gate_register(struct udevice *dev, |
| 214 | const struct clock_config *cfg); |
| 215 | |
| 216 | struct clk * |
| 217 | clk_stm32_register_composite(struct udevice *dev, |
| 218 | const struct clock_config *cfg); |
| 219 | |
| 220 | struct stm32_clk_gate_cfg { |
| 221 | int gate_id; |
| 222 | }; |
| 223 | |
| 224 | #define STM32_GATE(_id, _name, _parent, _flags, _gate_id, _sec_id) \ |
| 225 | { \ |
| 226 | .id = _id, \ |
| 227 | .sec_id = _sec_id, \ |
| 228 | .name = _name, \ |
| 229 | .parent_name = _parent, \ |
| 230 | .flags = _flags, \ |
| 231 | .clock_cfg = &(struct stm32_clk_gate_cfg) { \ |
| 232 | .gate_id = _gate_id, \ |
| 233 | }, \ |
| 234 | .setup = clk_stm32_gate_register, \ |
| 235 | } |
| 236 | |
| 237 | struct stm32_clk_composite_cfg { |
| 238 | int gate_id; |
| 239 | int mux_id; |
| 240 | int div_id; |
| 241 | }; |
| 242 | |
| 243 | #define STM32_COMPOSITE(_id, _name, _flags, _sec_id, \ |
| 244 | _gate_id, _mux_id, _div_id) \ |
| 245 | { \ |
| 246 | .id = _id, \ |
| 247 | .name = _name, \ |
| 248 | .sec_id = _sec_id, \ |
| 249 | .flags = _flags, \ |
| 250 | .clock_cfg = &(struct stm32_clk_composite_cfg) { \ |
| 251 | .gate_id = _gate_id, \ |
| 252 | .mux_id = _mux_id, \ |
| 253 | .div_id = _div_id, \ |
| 254 | }, \ |
| 255 | .setup = clk_stm32_register_composite, \ |
| 256 | } |
| 257 | |
| 258 | #define STM32_COMPOSITE_NOMUX(_id, _name, _parent, _flags, _sec_id, \ |
| 259 | _gate_id, _div_id) \ |
| 260 | { \ |
| 261 | .id = _id, \ |
| 262 | .name = _name, \ |
| 263 | .parent_name = _parent, \ |
| 264 | .sec_id = _sec_id, \ |
| 265 | .flags = _flags, \ |
| 266 | .clock_cfg = &(struct stm32_clk_composite_cfg) { \ |
| 267 | .gate_id = _gate_id, \ |
| 268 | .mux_id = NO_STM32_MUX, \ |
| 269 | .div_id = _div_id, \ |
| 270 | }, \ |
| 271 | .setup = clk_stm32_register_composite, \ |
| 272 | } |
| 273 | |
| 274 | extern const struct clk_ops stm32_clk_ops; |
| 275 | |
| 276 | ulong clk_stm32_get_rate_by_name(const char *name); |