Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2022, STMicroelectronics - All Rights Reserved |
| 3 | * |
| 4 | * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
| 5 | */ |
| 6 | |
| 7 | #ifndef CLK_STM32_CORE_H |
| 8 | #define CLK_STM32_CORE_H |
| 9 | |
| 10 | struct mux_cfg { |
| 11 | uint16_t offset; |
| 12 | uint8_t shift; |
| 13 | uint8_t width; |
| 14 | uint8_t bitrdy; |
| 15 | }; |
| 16 | |
| 17 | struct gate_cfg { |
| 18 | uint16_t offset; |
| 19 | uint8_t bit_idx; |
| 20 | uint8_t set_clr; |
| 21 | }; |
| 22 | |
| 23 | struct clk_div_table { |
| 24 | unsigned int val; |
| 25 | unsigned int div; |
| 26 | }; |
| 27 | |
| 28 | struct div_cfg { |
| 29 | uint16_t offset; |
| 30 | uint8_t shift; |
| 31 | uint8_t width; |
| 32 | uint8_t flags; |
| 33 | uint8_t bitrdy; |
| 34 | const struct clk_div_table *table; |
| 35 | }; |
| 36 | |
| 37 | struct parent_cfg { |
| 38 | uint8_t num_parents; |
| 39 | const uint16_t *id_parents; |
| 40 | struct mux_cfg *mux; |
| 41 | }; |
| 42 | |
| 43 | struct stm32_clk_priv; |
| 44 | |
| 45 | struct stm32_clk_ops { |
| 46 | unsigned long (*recalc_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate); |
| 47 | int (*get_parent)(struct stm32_clk_priv *priv, int id); |
| 48 | int (*set_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate, |
| 49 | unsigned long prate); |
| 50 | int (*enable)(struct stm32_clk_priv *priv, int id); |
| 51 | void (*disable)(struct stm32_clk_priv *priv, int id); |
| 52 | bool (*is_enabled)(struct stm32_clk_priv *priv, int id); |
| 53 | void (*init)(struct stm32_clk_priv *priv, int id); |
| 54 | }; |
| 55 | |
| 56 | struct clk_stm32 { |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 57 | uint16_t binding; |
| 58 | uint16_t parent; |
| 59 | uint8_t flags; |
| 60 | void *clock_cfg; |
| 61 | const struct stm32_clk_ops *ops; |
| 62 | }; |
| 63 | |
| 64 | struct stm32_clk_priv { |
| 65 | uintptr_t base; |
| 66 | const uint32_t num; |
| 67 | const struct clk_stm32 *clks; |
| 68 | const struct parent_cfg *parents; |
| 69 | const uint32_t nb_parents; |
| 70 | const struct gate_cfg *gates; |
| 71 | const uint32_t nb_gates; |
| 72 | const struct div_cfg *div; |
| 73 | const uint32_t nb_div; |
| 74 | struct clk_oscillator_data *osci_data; |
| 75 | const uint32_t nb_osci_data; |
| 76 | uint32_t *gate_refcounts; |
| 77 | void *pdata; |
| 78 | }; |
| 79 | |
| 80 | struct stm32_clk_bypass { |
| 81 | uint16_t offset; |
| 82 | uint8_t bit_byp; |
| 83 | uint8_t bit_digbyp; |
| 84 | }; |
| 85 | |
| 86 | struct stm32_clk_css { |
| 87 | uint16_t offset; |
| 88 | uint8_t bit_css; |
| 89 | }; |
| 90 | |
| 91 | struct stm32_clk_drive { |
| 92 | uint16_t offset; |
| 93 | uint8_t drv_shift; |
| 94 | uint8_t drv_width; |
| 95 | uint8_t drv_default; |
| 96 | }; |
| 97 | |
| 98 | struct clk_oscillator_data { |
| 99 | const char *name; |
| 100 | uint16_t id_clk; |
| 101 | unsigned long frequency; |
| 102 | uint16_t gate_id; |
| 103 | uint16_t gate_rdy_id; |
| 104 | struct stm32_clk_bypass *bypass; |
| 105 | struct stm32_clk_css *css; |
| 106 | struct stm32_clk_drive *drive; |
| 107 | }; |
| 108 | |
| 109 | struct clk_fixed_rate { |
| 110 | const char *name; |
| 111 | unsigned long fixed_rate; |
| 112 | }; |
| 113 | |
| 114 | struct clk_gate_cfg { |
| 115 | uint32_t offset; |
| 116 | uint8_t bit_idx; |
| 117 | }; |
| 118 | |
| 119 | /* CLOCK FLAGS */ |
| 120 | #define CLK_IS_CRITICAL BIT(0) |
| 121 | #define CLK_IGNORE_UNUSED BIT(1) |
| 122 | #define CLK_SET_RATE_PARENT BIT(2) |
| 123 | |
| 124 | #define CLK_DIVIDER_ONE_BASED BIT(0) |
| 125 | #define CLK_DIVIDER_POWER_OF_TWO BIT(1) |
| 126 | #define CLK_DIVIDER_ALLOW_ZERO BIT(2) |
| 127 | #define CLK_DIVIDER_HIWORD_MASK BIT(3) |
| 128 | #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) |
| 129 | #define CLK_DIVIDER_READ_ONLY BIT(5) |
| 130 | #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) |
| 131 | #define CLK_DIVIDER_BIG_ENDIAN BIT(7) |
| 132 | |
| 133 | #define MUX_MAX_PARENTS U(0x8000) |
| 134 | #define MUX_PARENT_MASK GENMASK(14, 0) |
| 135 | #define MUX_FLAG U(0x8000) |
| 136 | #define MUX(mux) ((mux) | MUX_FLAG) |
| 137 | |
| 138 | #define NO_GATE 0 |
| 139 | #define _NO_ID UINT16_MAX |
| 140 | #define CLK_IS_ROOT UINT16_MAX |
| 141 | #define MUX_NO_BIT_RDY UINT8_MAX |
| 142 | #define DIV_NO_BIT_RDY UINT8_MAX |
| 143 | |
| 144 | #define MASK_WIDTH_SHIFT(_width, _shift) \ |
| 145 | GENMASK(((_width) + (_shift) - 1U), (_shift)) |
| 146 | |
| 147 | int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base); |
| 148 | void clk_stm32_enable_critical_clocks(void); |
| 149 | |
| 150 | struct stm32_clk_priv *clk_stm32_get_priv(void); |
| 151 | |
| 152 | int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id); |
| 153 | const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id); |
| 154 | |
| 155 | void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass); |
| 156 | void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv); |
| 157 | void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css); |
| 158 | |
| 159 | int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, bool ready_on); |
| 160 | |
| 161 | int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on); |
| 162 | int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id); |
| 163 | int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id); |
| 164 | |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 165 | int clk_stm32_get_counter(unsigned long binding_id); |
| 166 | |
| 167 | void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id); |
| 168 | int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id); |
| 169 | |
| 170 | int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int id, int src_id); |
| 171 | int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel); |
| 172 | |
| 173 | int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int id); |
| 174 | int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx); |
| 175 | int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id); |
| 176 | |
| 177 | unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id); |
| 178 | unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id); |
| 179 | |
| 180 | bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag); |
| 181 | |
| 182 | int _clk_stm32_enable(struct stm32_clk_priv *priv, int id); |
| 183 | void _clk_stm32_disable(struct stm32_clk_priv *priv, int id); |
| 184 | |
| 185 | int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id); |
| 186 | void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id); |
| 187 | |
| 188 | bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id); |
| 189 | |
| 190 | int _clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int div_id, |
| 191 | unsigned long rate, unsigned long parent_rate); |
| 192 | |
| 193 | int clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int id, unsigned long rate, |
| 194 | unsigned long prate); |
| 195 | |
| 196 | unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv, |
| 197 | int div_id, |
| 198 | unsigned long prate); |
| 199 | |
| 200 | unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int idx, |
| 201 | unsigned long prate); |
| 202 | |
| 203 | int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int idx); |
| 204 | void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int idx); |
| 205 | |
| 206 | bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id); |
| 207 | bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int idx); |
| 208 | |
| 209 | uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id); |
| 210 | int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value); |
| 211 | int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel); |
| 212 | int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id); |
| 213 | |
| 214 | int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb); |
| 215 | |
| 216 | #ifdef CFG_STM32_CLK_DEBUG |
| 217 | void clk_stm32_display_clock_info(void); |
| 218 | #endif |
| 219 | |
| 220 | struct clk_stm32_div_cfg { |
| 221 | int id; |
| 222 | }; |
| 223 | |
| 224 | #define STM32_DIV(idx, _binding, _parent, _flags, _div_id) \ |
| 225 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 226 | .binding = (_binding),\ |
| 227 | .parent = (_parent),\ |
| 228 | .flags = (_flags),\ |
| 229 | .clock_cfg = &(struct clk_stm32_div_cfg){\ |
| 230 | .id = (_div_id),\ |
| 231 | },\ |
| 232 | .ops = &clk_stm32_divider_ops,\ |
| 233 | } |
| 234 | |
| 235 | struct clk_stm32_gate_cfg { |
| 236 | int id; |
| 237 | }; |
| 238 | |
| 239 | #define STM32_GATE(idx, _binding, _parent, _flags, _gate_id) \ |
| 240 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 241 | .binding = (_binding),\ |
| 242 | .parent = (_parent),\ |
| 243 | .flags = (_flags),\ |
| 244 | .clock_cfg = &(struct clk_stm32_gate_cfg){\ |
| 245 | .id = (_gate_id),\ |
| 246 | },\ |
| 247 | .ops = &clk_stm32_gate_ops,\ |
| 248 | } |
| 249 | |
| 250 | struct fixed_factor_cfg { |
| 251 | unsigned int mult; |
| 252 | unsigned int div; |
| 253 | }; |
| 254 | |
| 255 | unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv, |
| 256 | int _idx, unsigned long prate); |
| 257 | |
| 258 | #define FIXED_FACTOR(idx, _idx, _parent, _mult, _div) \ |
| 259 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 260 | .binding = (_idx),\ |
| 261 | .parent = (_parent),\ |
| 262 | .clock_cfg = &(struct fixed_factor_cfg){\ |
| 263 | .mult = (_mult),\ |
| 264 | .div = (_div),\ |
| 265 | },\ |
| 266 | .ops = &clk_fixed_factor_ops,\ |
| 267 | } |
| 268 | |
| 269 | #define GATE(idx, _binding, _parent, _flags, _offset, _bit_idx) \ |
| 270 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 271 | .binding = (_binding),\ |
| 272 | .parent = (_parent),\ |
| 273 | .flags = (_flags),\ |
| 274 | .clock_cfg = &(struct clk_gate_cfg){\ |
| 275 | .offset = (_offset),\ |
| 276 | .bit_idx = (_bit_idx),\ |
| 277 | },\ |
| 278 | .ops = &clk_gate_ops,\ |
| 279 | } |
| 280 | |
| 281 | #define STM32_MUX(idx, _binding, _mux_id, _flags) \ |
| 282 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 283 | .binding = (_binding),\ |
| 284 | .parent = (MUX(_mux_id)),\ |
| 285 | .flags = (_flags),\ |
| 286 | .clock_cfg = NULL,\ |
| 287 | .ops = (&clk_mux_ops),\ |
| 288 | } |
| 289 | |
| 290 | struct clk_timer_cfg { |
| 291 | uint32_t apbdiv; |
| 292 | uint32_t timpre; |
| 293 | }; |
| 294 | |
| 295 | #define CK_TIMER(idx, _idx, _parent, _flags, _apbdiv, _timpre) \ |
| 296 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 297 | .binding = (_idx),\ |
| 298 | .parent = (_parent),\ |
| 299 | .flags = (CLK_SET_RATE_PARENT | (_flags)),\ |
| 300 | .clock_cfg = &(struct clk_timer_cfg){\ |
| 301 | .apbdiv = (_apbdiv),\ |
| 302 | .timpre = (_timpre),\ |
| 303 | },\ |
| 304 | .ops = &clk_timer_ops,\ |
| 305 | } |
| 306 | |
| 307 | struct clk_stm32_fixed_rate_cfg { |
| 308 | unsigned long rate; |
| 309 | }; |
| 310 | |
| 311 | #define CLK_FIXED_RATE(idx, _binding, _rate) \ |
| 312 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 313 | .binding = (_binding),\ |
| 314 | .parent = (CLK_IS_ROOT),\ |
| 315 | .clock_cfg = &(struct clk_stm32_fixed_rate_cfg){\ |
| 316 | .rate = (_rate),\ |
| 317 | },\ |
| 318 | .ops = &clk_stm32_fixed_rate_ops,\ |
| 319 | } |
| 320 | |
| 321 | #define BYPASS(_offset, _bit_byp, _bit_digbyp) &(struct stm32_clk_bypass){\ |
| 322 | .offset = (_offset),\ |
| 323 | .bit_byp = (_bit_byp),\ |
| 324 | .bit_digbyp = (_bit_digbyp),\ |
| 325 | } |
| 326 | |
| 327 | #define CSS(_offset, _bit_css) &(struct stm32_clk_css){\ |
| 328 | .offset = (_offset),\ |
| 329 | .bit_css = (_bit_css),\ |
| 330 | } |
| 331 | |
| 332 | #define DRIVE(_offset, _shift, _width, _default) &(struct stm32_clk_drive){\ |
| 333 | .offset = (_offset),\ |
| 334 | .drv_shift = (_shift),\ |
| 335 | .drv_width = (_width),\ |
| 336 | .drv_default = (_default),\ |
| 337 | } |
| 338 | |
| 339 | #define OSCILLATOR(idx_osc, _id, _name, _gate_id, _gate_rdy_id, _bypass, _css, _drive) \ |
| 340 | [(idx_osc)] = (struct clk_oscillator_data){\ |
| 341 | .name = (_name),\ |
| 342 | .id_clk = (_id),\ |
| 343 | .gate_id = (_gate_id),\ |
| 344 | .gate_rdy_id = (_gate_rdy_id),\ |
| 345 | .bypass = (_bypass),\ |
| 346 | .css = (_css),\ |
| 347 | .drive = (_drive),\ |
| 348 | } |
| 349 | |
| 350 | struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id); |
| 351 | |
| 352 | void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id); |
| 353 | bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id); |
| 354 | int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id); |
| 355 | void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id); |
| 356 | |
| 357 | struct stm32_osc_cfg { |
| 358 | int osc_id; |
| 359 | }; |
| 360 | |
| 361 | #define CLK_OSC(idx, _idx, _parent, _osc_id) \ |
| 362 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 363 | .binding = (_idx),\ |
| 364 | .parent = (_parent),\ |
| 365 | .flags = CLK_IS_CRITICAL,\ |
| 366 | .clock_cfg = &(struct stm32_osc_cfg){\ |
| 367 | .osc_id = (_osc_id),\ |
| 368 | },\ |
| 369 | .ops = &clk_stm32_osc_ops,\ |
| 370 | } |
| 371 | |
| 372 | #define CLK_OSC_FIXED(idx, _idx, _parent, _osc_id) \ |
| 373 | [(idx)] = (struct clk_stm32){ \ |
Gabriel Fernandez | 1308d75 | 2020-03-11 11:30:34 +0100 | [diff] [blame] | 374 | .binding = (_idx),\ |
| 375 | .parent = (_parent),\ |
| 376 | .flags = CLK_IS_CRITICAL,\ |
| 377 | .clock_cfg = &(struct stm32_osc_cfg){\ |
| 378 | .osc_id = (_osc_id),\ |
| 379 | },\ |
| 380 | .ops = &clk_stm32_osc_nogate_ops,\ |
| 381 | } |
| 382 | |
| 383 | extern const struct stm32_clk_ops clk_mux_ops; |
| 384 | extern const struct stm32_clk_ops clk_stm32_divider_ops; |
| 385 | extern const struct stm32_clk_ops clk_stm32_gate_ops; |
| 386 | extern const struct stm32_clk_ops clk_fixed_factor_ops; |
| 387 | extern const struct stm32_clk_ops clk_gate_ops; |
| 388 | extern const struct stm32_clk_ops clk_timer_ops; |
| 389 | extern const struct stm32_clk_ops clk_stm32_fixed_rate_ops; |
| 390 | extern const struct stm32_clk_ops clk_stm32_osc_ops; |
| 391 | extern const struct stm32_clk_ops clk_stm32_osc_nogate_ops; |
| 392 | |
| 393 | #endif /* CLK_STM32_CORE_H */ |