xref: /optee_os/core/drivers/clk/sam/at91_clk.h (revision f90d78a655052c92b690b759cc843d42b85cad47)
1538f5068SClément Léger /* SPDX-License-Identifier: GPL-2.0+ or BSD-3-Clause */
2538f5068SClément Léger /*
3538f5068SClément Léger  * include/linux/clk/at91_pmc.h
4538f5068SClément Léger  *
5538f5068SClément Léger  * Copyright (C) 2005 Ivan Kokshaysky
6538f5068SClément Léger  * Copyright (C) SAN People
7538f5068SClément Léger  * Copyright (C) 2021 Microchip
8538f5068SClément Léger  *
9538f5068SClément Léger  * Power Management Controller (PMC) - System peripherals registers.
10538f5068SClément Léger  * Based on AT91RM9200 datasheet revision E.
11538f5068SClément Léger  */
12538f5068SClément Léger 
13538f5068SClément Léger #ifndef AT91_CLK_H
14538f5068SClément Léger #define AT91_CLK_H
15538f5068SClément Léger 
16538f5068SClément Léger #include <drivers/clk.h>
17538f5068SClément Léger #include <drivers/clk_dt.h>
18538f5068SClément Léger 
19538f5068SClément Léger #include "at91_pmc.h"
20538f5068SClément Léger 
21538f5068SClément Léger #define ffs(x)	__builtin_ffs(x)
22538f5068SClément Léger 
23538f5068SClément Léger #define field_get(_mask, _reg) \
24538f5068SClément Léger 	({ \
25538f5068SClément Léger 		typeof(_mask) __mask = _mask; \
26538f5068SClément Léger 		\
27538f5068SClément Léger 		(((_reg) & (__mask)) >> (ffs(__mask) - 1)); \
28538f5068SClément Léger 	})
29538f5068SClément Léger #define field_prep(_mask, _val)  \
30538f5068SClément Léger 	({ \
31538f5068SClément Léger 		typeof(_mask) __mask = _mask; \
32538f5068SClément Léger 		\
33538f5068SClément Léger 		(((_val) << (ffs(__mask) - 1)) & (__mask)); \
34538f5068SClément Léger 	})
35538f5068SClément Léger 
36538f5068SClément Léger struct clk_range {
37538f5068SClément Léger 	unsigned long min;
38538f5068SClément Léger 	unsigned long max;
39538f5068SClément Léger };
40538f5068SClément Léger 
41538f5068SClément Léger #define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
42538f5068SClément Léger 
43538f5068SClément Léger struct pmc_clk {
44538f5068SClément Léger 	struct clk *clk;
45538f5068SClément Léger 	uint8_t id;
46538f5068SClément Léger };
47538f5068SClément Léger 
48538f5068SClément Léger struct pmc_data {
49538f5068SClément Léger 	vaddr_t base;
50538f5068SClément Léger 	unsigned int ncore;
51538f5068SClément Léger 	struct pmc_clk *chws;
52538f5068SClément Léger 	unsigned int nsystem;
53538f5068SClément Léger 	struct pmc_clk *shws;
54538f5068SClément Léger 	unsigned int nperiph;
55538f5068SClément Léger 	struct pmc_clk *phws;
56538f5068SClément Léger 	unsigned int ngck;
57538f5068SClément Léger 	struct pmc_clk *ghws;
58538f5068SClément Léger 	unsigned int npck;
59538f5068SClément Léger 	struct pmc_clk *pchws;
60538f5068SClément Léger 
61538f5068SClément Léger 	struct pmc_clk hwtable[];
62538f5068SClément Léger };
63538f5068SClément Léger 
64538f5068SClément Léger /* PLL */
65538f5068SClément Léger struct clk_pll_layout {
66538f5068SClément Léger 	uint32_t pllr_mask;
67538f5068SClément Léger 	uint32_t mul_mask;
68538f5068SClément Léger 	uint32_t frac_mask;
69538f5068SClément Léger 	uint32_t div_mask;
70538f5068SClément Léger 	uint32_t endiv_mask;
71538f5068SClément Léger 	uint8_t mul_shift;
72538f5068SClément Léger 	uint8_t frac_shift;
73538f5068SClément Léger 	uint8_t div_shift;
74538f5068SClément Léger 	uint8_t endiv_shift;
75538f5068SClément Léger };
76538f5068SClément Léger 
77538f5068SClément Léger struct clk_pcr_layout {
78538f5068SClément Léger 	uint32_t offset;
79538f5068SClément Léger 	uint32_t cmd;
80538f5068SClément Léger 	uint32_t div_mask;
81538f5068SClément Léger 	uint32_t gckcss_mask;
82538f5068SClément Léger 	uint32_t pid_mask;
83538f5068SClément Léger };
84538f5068SClément Léger 
85538f5068SClément Léger struct clk_pll_charac {
86538f5068SClément Léger 	struct clk_range input;
87538f5068SClément Léger 	int num_output;
88538f5068SClément Léger 	const struct clk_range *output;
89538f5068SClément Léger 	uint16_t *icpll;
90538f5068SClément Léger 	uint8_t *out;
91538f5068SClément Léger 	uint8_t upll : 1;
92538f5068SClément Léger };
93538f5068SClément Léger 
94538f5068SClément Léger extern const struct clk_pll_layout sama5d3_pll_layout;
95538f5068SClément Léger 
96538f5068SClément Léger /* Master */
97538f5068SClément Léger struct clk_master_charac {
98538f5068SClément Léger 	struct clk_range output;
99538f5068SClément Léger 	uint32_t divisors[5];
100538f5068SClément Léger 	uint8_t have_div3_pres;
101538f5068SClément Léger };
102538f5068SClément Léger 
103538f5068SClément Léger struct clk_master_layout {
104538f5068SClément Léger 	uint32_t offset;
105538f5068SClément Léger 	uint32_t mask;
106538f5068SClément Léger 	uint8_t pres_shift;
107538f5068SClément Léger };
108538f5068SClément Léger 
109538f5068SClément Léger struct clk_programmable_layout {
110538f5068SClément Léger 	uint8_t pres_mask;
111538f5068SClément Léger 	uint8_t pres_shift;
112538f5068SClément Léger 	uint8_t css_mask;
113538f5068SClément Léger 	uint8_t have_slck_mck;
114538f5068SClément Léger 	uint8_t is_pres_direct;
115538f5068SClément Léger };
116538f5068SClément Léger 
117538f5068SClément Léger extern const struct clk_master_layout at91sam9x5_master_layout;
118538f5068SClément Léger 
119c2e7ca16SClément Léger vaddr_t at91_pmc_get_base(void);
120c2e7ca16SClément Léger 
1215943d3b9SClément Léger TEE_Result at91_pmc_clk_get(unsigned int type, unsigned int idx,
1225943d3b9SClément Léger 			    struct clk **clk);
1235943d3b9SClément Léger 
1245943d3b9SClément Léger TEE_Result pmc_clk_get(struct pmc_data *pmc, unsigned int type,
1255943d3b9SClément Léger 		       unsigned int idx, struct clk **clk);
1265943d3b9SClément Léger 
1277b4f9fb1SClément Léger struct clk *at91_sckc_clk_get(void);
1287b4f9fb1SClément Léger 
129538f5068SClément Léger struct pmc_data *pmc_data_allocate(unsigned int ncore, unsigned int nsystem,
130538f5068SClément Léger 				   unsigned int nperiph, unsigned int ngck,
131538f5068SClément Léger 				   unsigned int npck);
132538f5068SClément Léger 
133b357d34fSEtienne Carriere TEE_Result clk_dt_pmc_get(struct dt_pargs *args, void *data, struct clk **clk);
134538f5068SClément Léger 
135538f5068SClément Léger struct clk *pmc_clk_get_by_name(struct pmc_clk *clks, unsigned int nclk,
136538f5068SClément Léger 				const char *name);
137538f5068SClément Léger 
138538f5068SClément Léger /* Main clock */
139538f5068SClément Léger struct clk *pmc_register_main_rc_osc(struct pmc_data *pmc, const char *name,
140538f5068SClément Léger 				     unsigned long freq);
141538f5068SClément Léger 
142538f5068SClément Léger struct clk *pmc_register_main_osc(struct pmc_data *pmc, const char *name,
143538f5068SClément Léger 				  struct clk *parent, bool bypass);
144538f5068SClément Léger 
145538f5068SClément Léger struct clk *at91_clk_register_sam9x5_main(struct pmc_data *pmc,
146538f5068SClément Léger 					  const char *name,
147538f5068SClément Léger 					  struct clk **parent_clocks,
148538f5068SClément Léger 					  unsigned int num_parents);
149538f5068SClément Léger 
150538f5068SClément Léger /* PLL */
151538f5068SClément Léger struct clk *
152538f5068SClément Léger at91_clk_register_pll(struct pmc_data *pmc, const char *name,
153538f5068SClément Léger 		      struct clk *parent, uint8_t id,
154538f5068SClément Léger 		      const struct clk_pll_layout *layout,
155538f5068SClément Léger 		      const struct clk_pll_charac *charac);
156538f5068SClément Léger 
157538f5068SClément Léger struct clk *
158538f5068SClément Léger at91_clk_register_plldiv(struct pmc_data *pmc, const char *name,
159538f5068SClément Léger 			 struct clk *parent);
160538f5068SClément Léger 
1614318c69fSTony Han struct clk *sam9x60_clk_register_frac_pll(struct pmc_data *pmc,
1624318c69fSTony Han 					  const char *name,
1634318c69fSTony Han 					  struct clk *parent,
1644318c69fSTony Han 					  uint8_t id,
1654318c69fSTony Han 					  const struct clk_pll_charac *charac,
1664318c69fSTony Han 					  const struct clk_pll_layout *layout,
1674318c69fSTony Han 					  uint32_t flags);
1684318c69fSTony Han 
1694318c69fSTony Han struct clk *sam9x60_clk_register_div_pll(struct pmc_data *pmc,
1704318c69fSTony Han 					 const char *name,
1714318c69fSTony Han 					 struct clk *parent,
1724318c69fSTony Han 					 uint8_t id,
1734318c69fSTony Han 					 const struct clk_pll_charac *charac,
1744318c69fSTony Han 					 const struct clk_pll_layout *layout,
1754318c69fSTony Han 					 uint32_t flags,
1764318c69fSTony Han 					 uint32_t safe_div);
1774318c69fSTony Han 
178538f5068SClément Léger /* UTMI */
179538f5068SClément Léger struct clk *
180538f5068SClément Léger at91_clk_register_utmi(struct pmc_data *pmc, const char *name,
181538f5068SClément Léger 		       struct clk *parent);
182538f5068SClément Léger 
183417a10d1STony Han struct clk *at91_clk_sama7g5_register_utmi(struct pmc_data *pmc,
184417a10d1STony Han 					   const char *name,
185417a10d1STony Han 					   struct clk *parent);
186417a10d1STony Han 
18729f0ec71STony Han struct clk *sama7_utmi_clk_register(const char *name,
18829f0ec71STony Han 				    struct clk *parent,
18929f0ec71STony Han 				    uint8_t id);
19029f0ec71STony Han 
191538f5068SClément Léger /* Master */
192538f5068SClément Léger struct clk *
193538f5068SClément Léger at91_clk_register_master_pres(struct pmc_data *pmc,
194538f5068SClément Léger 			      const char *name, int num_parents,
195538f5068SClément Léger 			      struct clk **parents,
196538f5068SClément Léger 			      const struct clk_master_layout *layout,
197538f5068SClément Léger 			      const struct clk_master_charac *charac,
198538f5068SClément Léger 			      int chg_pid);
199538f5068SClément Léger 
200538f5068SClément Léger struct clk *
201538f5068SClément Léger at91_clk_register_master_div(struct pmc_data *pmc,
202538f5068SClément Léger 			     const char *name, struct clk *parent,
203538f5068SClément Léger 			     const struct clk_master_layout *layout,
204538f5068SClément Léger 			     const struct clk_master_charac *charac);
205538f5068SClément Léger 
2065110b3e7STony Han /*
2075110b3e7STony Han  * @mux_table: when @mux_table is not NULL it shall hold @num_parents cells
2085110b3e7STony Han  */
2095110b3e7STony Han struct clk *at91_clk_sama7g5_register_master(struct pmc_data *pmc,
2105110b3e7STony Han 					     const char *name,
2115110b3e7STony Han 					     int num_parents,
2125110b3e7STony Han 					     struct clk **parent,
2135110b3e7STony Han 					     uint32_t *mux_table,
2145110b3e7STony Han 					     uint8_t id,
2155110b3e7STony Han 					     int chg_pid);
2165110b3e7STony Han 
217538f5068SClément Léger /* H32MX */
218538f5068SClément Léger struct clk *
219538f5068SClément Léger at91_clk_register_h32mx(struct pmc_data *pmc, const char *name,
220538f5068SClément Léger 			struct clk *parent);
221538f5068SClément Léger 
222538f5068SClément Léger /* USB */
223538f5068SClément Léger struct clk *
224538f5068SClément Léger at91sam9x5_clk_register_usb(struct pmc_data *pmc, const char *name,
225538f5068SClément Léger 			    struct clk **parents, uint8_t num_parents);
226538f5068SClément Léger 
227538f5068SClément Léger /* Programmable */
228538f5068SClément Léger struct clk *
229538f5068SClément Léger at91_clk_register_programmable(struct pmc_data *pmc,
230538f5068SClément Léger 			       const char *name, struct clk **parents,
231538f5068SClément Léger 			       uint8_t num_parents, uint8_t id,
232538f5068SClément Léger 			       const struct clk_programmable_layout *layout);
233538f5068SClément Léger 
234538f5068SClément Léger struct clk *
235538f5068SClément Léger at91_clk_register_system(struct pmc_data *pmc, const char *name,
236538f5068SClément Léger 			 struct clk *parent, uint8_t id);
237538f5068SClément Léger 
238538f5068SClément Léger struct clk *
239538f5068SClément Léger at91_clk_register_sam9x5_periph(struct pmc_data *pmc,
240538f5068SClément Léger 				const struct clk_pcr_layout *layout,
241538f5068SClément Léger 				const char *name, struct clk *parent,
242538f5068SClément Léger 				uint32_t id, const struct clk_range *range);
243538f5068SClément Léger 
244538f5068SClément Léger struct clk *
245538f5068SClément Léger at91_clk_register_generated(struct pmc_data *pmc,
246538f5068SClément Léger 			    const struct clk_pcr_layout *layout,
247538f5068SClément Léger 			    const char *name, struct clk **parents,
2489aab6fb2STony Han 			    uint32_t *mux_table,
249538f5068SClément Léger 			    uint8_t num_parents, uint8_t id,
250538f5068SClément Léger 			    const struct clk_range *range,
251538f5068SClément Léger 			    int chg_pid);
252538f5068SClément Léger 
253538f5068SClément Léger struct clk *
254538f5068SClément Léger at91_clk_i2s_mux_register(const char *name, struct clk **parents,
255538f5068SClément Léger 			  unsigned int num_parents, uint8_t bus_id);
256538f5068SClément Léger 
257538f5068SClément Léger /* Audio PLL */
258538f5068SClément Léger struct clk *
259538f5068SClément Léger at91_clk_register_audio_pll_frac(struct pmc_data *pmc, const char *name,
260538f5068SClément Léger 				 struct clk *parent);
261538f5068SClément Léger 
262538f5068SClément Léger struct clk *
263538f5068SClément Léger at91_clk_register_audio_pll_pad(struct pmc_data *pmc, const char *name,
264538f5068SClément Léger 				struct clk *parent);
265538f5068SClément Léger 
266538f5068SClément Léger struct clk *
267538f5068SClément Léger at91_clk_register_audio_pll_pmc(struct pmc_data *pmc, const char *name,
268538f5068SClément Léger 				struct clk *parent);
269538f5068SClément Léger 
270f496f2c4STony Han /* CPU OPP (Operation Performance Points) */
271265f4754STony Han struct clk *at91_cpu_opp_clk_get(void);
272265f4754STony Han 
273f496f2c4STony Han TEE_Result at91_clk_register_cpu_opp(const void *fdt, int node,
274f496f2c4STony Han 				     struct clk *clk);
275f496f2c4STony Han 
276*f90d78a6STony Han void sam_set_clock_range(unsigned int pmc_type, unsigned int pmc_id,
277*f90d78a6STony Han 			 const struct clk_range *range);
278*f90d78a6STony Han 
2795e6f824bSClément Léger #ifdef CFG_PM_ARM32
2805e6f824bSClément Léger void pmc_register_id(uint8_t id);
2815e6f824bSClément Léger void pmc_register_pck(uint8_t pck);
2825e6f824bSClément Léger void pmc_register_pm(void);
2835e6f824bSClément Léger #else
pmc_register_id(uint8_t id __unused)2845e6f824bSClément Léger static inline void pmc_register_id(uint8_t id __unused) {}
pmc_register_pck(uint8_t pck __unused)2855e6f824bSClément Léger static inline void pmc_register_pck(uint8_t pck __unused) {}
pmc_register_pm(void)2865e6f824bSClément Léger static inline void pmc_register_pm(void) {}
2875e6f824bSClément Léger #endif
2885e6f824bSClément Léger 
289538f5068SClément Léger #endif
290