summaryrefslogtreecommitdiffstats
path: root/drivers/st/clk/clk-stm32-core.h
blob: 8bfb5134f44b174524c6db704c1de8b1f19856c0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
/*
 * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
 *
 * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
 */

#ifndef CLK_STM32_CORE_H
#define CLK_STM32_CORE_H

struct mux_cfg {
	uint16_t offset;
	uint8_t shift;
	uint8_t width;
	uint8_t bitrdy;
};

struct gate_cfg {
	uint16_t offset;
	uint8_t bit_idx;
	uint8_t set_clr;
};

struct clk_div_table {
	unsigned int val;
	unsigned int div;
};

struct div_cfg {
	uint16_t offset;
	uint8_t shift;
	uint8_t width;
	uint8_t flags;
	uint8_t bitrdy;
	const struct clk_div_table *table;
};

struct parent_cfg {
	uint8_t num_parents;
	const uint16_t *id_parents;
	struct mux_cfg *mux;
};

struct stm32_clk_priv;

struct stm32_clk_ops {
	unsigned long (*recalc_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate);
	int (*get_parent)(struct stm32_clk_priv *priv, int id);
	int (*set_rate)(struct stm32_clk_priv *priv, int id, unsigned long rate,
			unsigned long prate);
	int (*enable)(struct stm32_clk_priv *priv, int id);
	void (*disable)(struct stm32_clk_priv *priv, int id);
	bool (*is_enabled)(struct stm32_clk_priv *priv, int id);
	void (*init)(struct stm32_clk_priv *priv, int id);
};

struct clk_stm32 {
	uint16_t binding;
	uint16_t parent;
	uint8_t flags;
	void *clock_cfg;
	const struct stm32_clk_ops *ops;
};

struct stm32_clk_priv {
	uintptr_t base;
	const uint32_t num;
	const struct clk_stm32 *clks;
	const struct parent_cfg *parents;
	const uint32_t nb_parents;
	const struct gate_cfg *gates;
	const uint32_t nb_gates;
	const struct div_cfg *div;
	const uint32_t nb_div;
	struct clk_oscillator_data *osci_data;
	const uint32_t nb_osci_data;
	uint32_t *gate_refcounts;
	void *pdata;
};

struct stm32_clk_bypass {
	uint16_t offset;
	uint8_t bit_byp;
	uint8_t bit_digbyp;
};

struct stm32_clk_css {
	uint16_t offset;
	uint8_t bit_css;
};

struct stm32_clk_drive {
	uint16_t offset;
	uint8_t drv_shift;
	uint8_t drv_width;
	uint8_t drv_default;
};

struct clk_oscillator_data {
	const char *name;
	uint16_t id_clk;
	unsigned long frequency;
	uint16_t gate_id;
	uint16_t gate_rdy_id;
	struct stm32_clk_bypass *bypass;
	struct stm32_clk_css *css;
	struct stm32_clk_drive *drive;
};

struct clk_fixed_rate {
	const char *name;
	unsigned long fixed_rate;
};

struct clk_gate_cfg {
	uint32_t offset;
	uint8_t bit_idx;
};

/* CLOCK FLAGS */
#define CLK_IS_CRITICAL			BIT(0)
#define CLK_IGNORE_UNUSED		BIT(1)
#define CLK_SET_RATE_PARENT		BIT(2)

#define CLK_DIVIDER_ONE_BASED		BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO	BIT(1)
#define CLK_DIVIDER_ALLOW_ZERO		BIT(2)
#define CLK_DIVIDER_HIWORD_MASK		BIT(3)
#define CLK_DIVIDER_ROUND_CLOSEST	BIT(4)
#define CLK_DIVIDER_READ_ONLY		BIT(5)
#define CLK_DIVIDER_MAX_AT_ZERO		BIT(6)
#define CLK_DIVIDER_BIG_ENDIAN		BIT(7)

#define MUX_MAX_PARENTS			U(0x8000)
#define MUX_PARENT_MASK			GENMASK(14, 0)
#define MUX_FLAG			U(0x8000)
#define MUX(mux)			((mux) | MUX_FLAG)

#define NO_GATE				0
#define _NO_ID				UINT16_MAX
#define CLK_IS_ROOT			UINT16_MAX
#define MUX_NO_BIT_RDY			UINT8_MAX
#define DIV_NO_BIT_RDY			UINT8_MAX

#define MASK_WIDTH_SHIFT(_width, _shift) \
	GENMASK(((_width) + (_shift) - 1U), (_shift))

int clk_stm32_init(struct stm32_clk_priv *priv, uintptr_t base);
void clk_stm32_enable_critical_clocks(void);

struct stm32_clk_priv *clk_stm32_get_priv(void);

int clk_get_index(struct stm32_clk_priv *priv, unsigned long binding_id);
const struct clk_stm32 *_clk_get(struct stm32_clk_priv *priv, int id);

void clk_oscillator_set_bypass(struct stm32_clk_priv *priv, int id, bool digbyp, bool bypass);
void clk_oscillator_set_drive(struct stm32_clk_priv *priv, int id, uint8_t lsedrv);
void clk_oscillator_set_css(struct stm32_clk_priv *priv, int id, bool css);

int _clk_stm32_gate_wait_ready(struct stm32_clk_priv *priv, uint16_t gate_id, bool ready_on);

int clk_oscillator_wait_ready(struct stm32_clk_priv *priv, int id, bool ready_on);
int clk_oscillator_wait_ready_on(struct stm32_clk_priv *priv, int id);
int clk_oscillator_wait_ready_off(struct stm32_clk_priv *priv, int id);

int clk_stm32_get_counter(unsigned long binding_id);

void _clk_stm32_gate_disable(struct stm32_clk_priv *priv, uint16_t gate_id);
int _clk_stm32_gate_enable(struct stm32_clk_priv *priv, uint16_t gate_id);

int _clk_stm32_set_parent(struct stm32_clk_priv *priv, int id, int src_id);
int _clk_stm32_set_parent_by_index(struct stm32_clk_priv *priv, int clk, int sel);

int _clk_stm32_get_parent(struct stm32_clk_priv *priv, int id);
int _clk_stm32_get_parent_by_index(struct stm32_clk_priv *priv, int clk_id, int idx);
int _clk_stm32_get_parent_index(struct stm32_clk_priv *priv, int clk_id);

unsigned long _clk_stm32_get_rate(struct stm32_clk_priv *priv, int id);
unsigned long _clk_stm32_get_parent_rate(struct stm32_clk_priv *priv, int id);

bool _stm32_clk_is_flags(struct stm32_clk_priv *priv, int id, uint8_t flag);

int _clk_stm32_enable(struct stm32_clk_priv *priv, int id);
void _clk_stm32_disable(struct stm32_clk_priv *priv, int id);

int clk_stm32_enable_call_ops(struct stm32_clk_priv *priv, uint16_t id);
void clk_stm32_disable_call_ops(struct stm32_clk_priv *priv, uint16_t id);

bool _clk_stm32_is_enabled(struct stm32_clk_priv *priv, int id);

int _clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int div_id,
				unsigned long rate, unsigned long parent_rate);

int clk_stm32_divider_set_rate(struct stm32_clk_priv *priv, int id, unsigned long rate,
			       unsigned long prate);

unsigned long _clk_stm32_divider_recalc(struct stm32_clk_priv *priv,
					int div_id,
					unsigned long prate);

unsigned long clk_stm32_divider_recalc(struct stm32_clk_priv *priv, int idx,
				       unsigned long prate);

int clk_stm32_gate_enable(struct stm32_clk_priv *priv, int idx);
void clk_stm32_gate_disable(struct stm32_clk_priv *priv, int idx);

bool _clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int gate_id);
bool clk_stm32_gate_is_enabled(struct stm32_clk_priv *priv, int idx);

uint32_t clk_stm32_div_get_value(struct stm32_clk_priv *priv, int div_id);
int clk_stm32_set_div(struct stm32_clk_priv *priv, uint32_t div_id, uint32_t value);
int clk_mux_set_parent(struct stm32_clk_priv *priv, uint16_t pid, uint8_t sel);
int clk_mux_get_parent(struct stm32_clk_priv *priv, uint32_t mux_id);

int stm32_clk_parse_fdt_by_name(void *fdt, int node, const char *name, uint32_t *tab, uint32_t *nb);

#ifdef CFG_STM32_CLK_DEBUG
void clk_stm32_display_clock_info(void);
#endif

struct clk_stm32_div_cfg {
	int id;
};

#define STM32_DIV(idx, _binding, _parent, _flags, _div_id) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_binding),\
		.parent		=  (_parent),\
		.flags		= (_flags),\
		.clock_cfg	= &(struct clk_stm32_div_cfg){\
			.id	= (_div_id),\
		},\
		.ops		= &clk_stm32_divider_ops,\
	}

struct clk_stm32_gate_cfg {
	int id;
};

#define STM32_GATE(idx, _binding, _parent, _flags, _gate_id) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_binding),\
		.parent		=  (_parent),\
		.flags		= (_flags),\
		.clock_cfg	= &(struct clk_stm32_gate_cfg){\
			.id	= (_gate_id),\
		},\
		.ops		= &clk_stm32_gate_ops,\
	}

struct fixed_factor_cfg {
	unsigned int mult;
	unsigned int div;
};

unsigned long fixed_factor_recalc_rate(struct stm32_clk_priv *priv,
				       int _idx, unsigned long prate);

#define FIXED_FACTOR(idx, _idx, _parent, _mult, _div) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_idx),\
		.parent		= (_parent),\
		.clock_cfg	= &(struct fixed_factor_cfg){\
			.mult	= (_mult),\
			.div	= (_div),\
		},\
		.ops		= &clk_fixed_factor_ops,\
	}

#define GATE(idx, _binding, _parent, _flags, _offset, _bit_idx) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_binding),\
		.parent		=  (_parent),\
		.flags		= (_flags),\
		.clock_cfg	= &(struct clk_gate_cfg){\
			.offset		= (_offset),\
			.bit_idx	= (_bit_idx),\
		},\
		.ops		= &clk_gate_ops,\
	}

#define STM32_MUX(idx, _binding, _mux_id, _flags) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_binding),\
		.parent		= (MUX(_mux_id)),\
		.flags		= (_flags),\
		.clock_cfg	= NULL,\
		.ops		= (&clk_mux_ops),\
	}

struct clk_timer_cfg {
	uint32_t apbdiv;
	uint32_t timpre;
};

#define CK_TIMER(idx, _idx, _parent, _flags, _apbdiv, _timpre) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_idx),\
		.parent		= (_parent),\
		.flags		= (CLK_SET_RATE_PARENT | (_flags)),\
		.clock_cfg	= &(struct clk_timer_cfg){\
			.apbdiv = (_apbdiv),\
			.timpre = (_timpre),\
		},\
		.ops		= &clk_timer_ops,\
	}

struct clk_stm32_fixed_rate_cfg {
	unsigned long rate;
};

#define CLK_FIXED_RATE(idx, _binding, _rate) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_binding),\
		.parent		= (CLK_IS_ROOT),\
		.clock_cfg	= &(struct clk_stm32_fixed_rate_cfg){\
			.rate	= (_rate),\
		},\
		.ops		= &clk_stm32_fixed_rate_ops,\
	}

#define BYPASS(_offset, _bit_byp, _bit_digbyp) &(struct stm32_clk_bypass){\
	.offset		= (_offset),\
	.bit_byp	= (_bit_byp),\
	.bit_digbyp	= (_bit_digbyp),\
}

#define CSS(_offset, _bit_css)	&(struct stm32_clk_css){\
	.offset		= (_offset),\
	.bit_css	= (_bit_css),\
}

#define DRIVE(_offset, _shift, _width, _default) &(struct stm32_clk_drive){\
	.offset		= (_offset),\
	.drv_shift	= (_shift),\
	.drv_width	= (_width),\
	.drv_default	= (_default),\
}

#define OSCILLATOR(idx_osc, _id, _name, _gate_id, _gate_rdy_id, _bypass, _css, _drive) \
	[(idx_osc)] = (struct clk_oscillator_data){\
		.name		= (_name),\
		.id_clk		= (_id),\
		.gate_id	= (_gate_id),\
		.gate_rdy_id	= (_gate_rdy_id),\
		.bypass		= (_bypass),\
		.css		= (_css),\
		.drive		= (_drive),\
	}

struct clk_oscillator_data *clk_oscillator_get_data(struct stm32_clk_priv *priv, int id);

void clk_stm32_osc_init(struct stm32_clk_priv *priv, int id);
bool clk_stm32_osc_gate_is_enabled(struct stm32_clk_priv *priv, int id);
int clk_stm32_osc_gate_enable(struct stm32_clk_priv *priv, int id);
void clk_stm32_osc_gate_disable(struct stm32_clk_priv *priv, int id);

struct stm32_osc_cfg {
	int osc_id;
};

#define CLK_OSC(idx, _idx, _parent, _osc_id) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_idx),\
		.parent		= (_parent),\
		.flags		= CLK_IS_CRITICAL,\
		.clock_cfg	= &(struct stm32_osc_cfg){\
			.osc_id = (_osc_id),\
		},\
		.ops		= &clk_stm32_osc_ops,\
	}

#define CLK_OSC_FIXED(idx, _idx, _parent, _osc_id) \
	[(idx)] = (struct clk_stm32){ \
		.binding	= (_idx),\
		.parent		= (_parent),\
		.flags		= CLK_IS_CRITICAL,\
		.clock_cfg	= &(struct stm32_osc_cfg){\
			.osc_id	= (_osc_id),\
		},\
		.ops		= &clk_stm32_osc_nogate_ops,\
	}

extern const struct stm32_clk_ops clk_mux_ops;
extern const struct stm32_clk_ops clk_stm32_divider_ops;
extern const struct stm32_clk_ops clk_stm32_gate_ops;
extern const struct stm32_clk_ops clk_fixed_factor_ops;
extern const struct stm32_clk_ops clk_gate_ops;
extern const struct stm32_clk_ops clk_timer_ops;
extern const struct stm32_clk_ops clk_stm32_fixed_rate_ops;
extern const struct stm32_clk_ops clk_stm32_osc_ops;
extern const struct stm32_clk_ops clk_stm32_osc_nogate_ops;

#endif /* CLK_STM32_CORE_H */