xref: /btstack/port/samv71-xplained-atwilc3000/ASF/common/services/clock/samv71/pll.h (revision 1b2596b5303dd8caeea8565532c93cca8dab8cc4)
1*1b2596b5SMatthias Ringwald /**
2*1b2596b5SMatthias Ringwald  * \file
3*1b2596b5SMatthias Ringwald  *
4*1b2596b5SMatthias Ringwald  * \brief Chip-specific PLL definitions.
5*1b2596b5SMatthias Ringwald  *
6*1b2596b5SMatthias Ringwald  * Copyright (c) 2015 Atmel Corporation. All rights reserved.
7*1b2596b5SMatthias Ringwald  *
8*1b2596b5SMatthias Ringwald  * \asf_license_start
9*1b2596b5SMatthias Ringwald  *
10*1b2596b5SMatthias Ringwald  * \page License
11*1b2596b5SMatthias Ringwald  *
12*1b2596b5SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
13*1b2596b5SMatthias Ringwald  * modification, are permitted provided that the following conditions are met:
14*1b2596b5SMatthias Ringwald  *
15*1b2596b5SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright notice,
16*1b2596b5SMatthias Ringwald  *    this list of conditions and the following disclaimer.
17*1b2596b5SMatthias Ringwald  *
18*1b2596b5SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright notice,
19*1b2596b5SMatthias Ringwald  *    this list of conditions and the following disclaimer in the documentation
20*1b2596b5SMatthias Ringwald  *    and/or other materials provided with the distribution.
21*1b2596b5SMatthias Ringwald  *
22*1b2596b5SMatthias Ringwald  * 3. The name of Atmel may not be used to endorse or promote products derived
23*1b2596b5SMatthias Ringwald  *    from this software without specific prior written permission.
24*1b2596b5SMatthias Ringwald  *
25*1b2596b5SMatthias Ringwald  * 4. This software may only be redistributed and used in connection with an
26*1b2596b5SMatthias Ringwald  *    Atmel microcontroller product.
27*1b2596b5SMatthias Ringwald  *
28*1b2596b5SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
29*1b2596b5SMatthias Ringwald  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30*1b2596b5SMatthias Ringwald  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
31*1b2596b5SMatthias Ringwald  * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
32*1b2596b5SMatthias Ringwald  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*1b2596b5SMatthias Ringwald  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*1b2596b5SMatthias Ringwald  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*1b2596b5SMatthias Ringwald  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36*1b2596b5SMatthias Ringwald  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
37*1b2596b5SMatthias Ringwald  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38*1b2596b5SMatthias Ringwald  * POSSIBILITY OF SUCH DAMAGE.
39*1b2596b5SMatthias Ringwald  *
40*1b2596b5SMatthias Ringwald  * \asf_license_stop
41*1b2596b5SMatthias Ringwald  *
42*1b2596b5SMatthias Ringwald  */
43*1b2596b5SMatthias Ringwald /*
44*1b2596b5SMatthias Ringwald  * Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
45*1b2596b5SMatthias Ringwald  */
46*1b2596b5SMatthias Ringwald 
47*1b2596b5SMatthias Ringwald #ifndef CHIP_PLL_H_INCLUDED
48*1b2596b5SMatthias Ringwald #define CHIP_PLL_H_INCLUDED
49*1b2596b5SMatthias Ringwald 
50*1b2596b5SMatthias Ringwald #include <osc.h>
51*1b2596b5SMatthias Ringwald 
52*1b2596b5SMatthias Ringwald /// @cond 0
53*1b2596b5SMatthias Ringwald /**INDENT-OFF**/
54*1b2596b5SMatthias Ringwald #ifdef __cplusplus
55*1b2596b5SMatthias Ringwald extern "C" {
56*1b2596b5SMatthias Ringwald #endif
57*1b2596b5SMatthias Ringwald /**INDENT-ON**/
58*1b2596b5SMatthias Ringwald /// @endcond
59*1b2596b5SMatthias Ringwald 
60*1b2596b5SMatthias Ringwald /**
61*1b2596b5SMatthias Ringwald  * \weakgroup pll_group
62*1b2596b5SMatthias Ringwald  * @{
63*1b2596b5SMatthias Ringwald  */
64*1b2596b5SMatthias Ringwald 
65*1b2596b5SMatthias Ringwald #define PLL_OUTPUT_MIN_HZ       160000000
66*1b2596b5SMatthias Ringwald #define PLL_OUTPUT_MAX_HZ       500000000
67*1b2596b5SMatthias Ringwald 
68*1b2596b5SMatthias Ringwald #define PLL_INPUT_MIN_HZ        3000000
69*1b2596b5SMatthias Ringwald #define PLL_INPUT_MAX_HZ        32000000
70*1b2596b5SMatthias Ringwald 
71*1b2596b5SMatthias Ringwald #define NR_PLLS             2
72*1b2596b5SMatthias Ringwald #define PLLA_ID             0
73*1b2596b5SMatthias Ringwald #define UPLL_ID             1   //!< USB UTMI PLL.
74*1b2596b5SMatthias Ringwald 
75*1b2596b5SMatthias Ringwald #define PLL_UPLL_HZ     480000000
76*1b2596b5SMatthias Ringwald 
77*1b2596b5SMatthias Ringwald #define PLL_COUNT   0x3fU
78*1b2596b5SMatthias Ringwald 
79*1b2596b5SMatthias Ringwald enum pll_source {
80*1b2596b5SMatthias Ringwald 	PLL_SRC_MAINCK_4M_RC   = OSC_MAINCK_4M_RC,  //!< Internal 4MHz RC oscillator.
81*1b2596b5SMatthias Ringwald 	PLL_SRC_MAINCK_8M_RC   = OSC_MAINCK_8M_RC,  //!< Internal 8MHz RC oscillator.
82*1b2596b5SMatthias Ringwald 	PLL_SRC_MAINCK_12M_RC  = OSC_MAINCK_12M_RC, //!< Internal 12MHz RC oscillator.
83*1b2596b5SMatthias Ringwald 	PLL_SRC_MAINCK_XTAL    = OSC_MAINCK_XTAL,   //!< External crystal oscillator.
84*1b2596b5SMatthias Ringwald 	PLL_SRC_MAINCK_BYPASS  = OSC_MAINCK_BYPASS, //!< External bypass oscillator.
85*1b2596b5SMatthias Ringwald 	PLL_NR_SOURCES,                             //!< Number of PLL sources.
86*1b2596b5SMatthias Ringwald };
87*1b2596b5SMatthias Ringwald 
88*1b2596b5SMatthias Ringwald struct pll_config {
89*1b2596b5SMatthias Ringwald 	uint32_t ctrl;
90*1b2596b5SMatthias Ringwald };
91*1b2596b5SMatthias Ringwald 
92*1b2596b5SMatthias Ringwald #define pll_get_default_rate(pll_id)                                     \
93*1b2596b5SMatthias Ringwald 	((osc_get_rate(CONFIG_PLL##pll_id##_SOURCE)                      \
94*1b2596b5SMatthias Ringwald 			* CONFIG_PLL##pll_id##_MUL)                      \
95*1b2596b5SMatthias Ringwald 			/ CONFIG_PLL##pll_id##_DIV)
96*1b2596b5SMatthias Ringwald 
97*1b2596b5SMatthias Ringwald /* Force UTMI PLL parameters (Hardware defined) */
98*1b2596b5SMatthias Ringwald #ifdef CONFIG_PLL1_SOURCE
99*1b2596b5SMatthias Ringwald # undef CONFIG_PLL1_SOURCE
100*1b2596b5SMatthias Ringwald #endif
101*1b2596b5SMatthias Ringwald #ifdef CONFIG_PLL1_MUL
102*1b2596b5SMatthias Ringwald # undef CONFIG_PLL1_MUL
103*1b2596b5SMatthias Ringwald #endif
104*1b2596b5SMatthias Ringwald #ifdef CONFIG_PLL1_DIV
105*1b2596b5SMatthias Ringwald # undef CONFIG_PLL1_DIV
106*1b2596b5SMatthias Ringwald #endif
107*1b2596b5SMatthias Ringwald #define CONFIG_PLL1_SOURCE  PLL_SRC_MAINCK_XTAL
108*1b2596b5SMatthias Ringwald #define CONFIG_PLL1_MUL     0
109*1b2596b5SMatthias Ringwald #define CONFIG_PLL1_DIV     0
110*1b2596b5SMatthias Ringwald 
111*1b2596b5SMatthias Ringwald /**
112*1b2596b5SMatthias Ringwald  * \note The SAMV71 PLL hardware interprets mul as mul+1. For readability the
113*1b2596b5SMatthias Ringwald  * hardware mul+1 is hidden in this implementation. Use mul as mul effective
114*1b2596b5SMatthias Ringwald  * value.
115*1b2596b5SMatthias Ringwald  */
pll_config_init(struct pll_config * p_cfg,enum pll_source e_src,uint32_t ul_div,uint32_t ul_mul)116*1b2596b5SMatthias Ringwald static inline void pll_config_init(struct pll_config *p_cfg,
117*1b2596b5SMatthias Ringwald 		enum pll_source e_src, uint32_t ul_div, uint32_t ul_mul)
118*1b2596b5SMatthias Ringwald {
119*1b2596b5SMatthias Ringwald 	uint32_t vco_hz;
120*1b2596b5SMatthias Ringwald 
121*1b2596b5SMatthias Ringwald 	Assert(e_src < PLL_NR_SOURCES);
122*1b2596b5SMatthias Ringwald 
123*1b2596b5SMatthias Ringwald 	if (ul_div == 0 && ul_mul == 0) { /* Must only be true for UTMI PLL */
124*1b2596b5SMatthias Ringwald 		p_cfg->ctrl = CKGR_UCKR_UPLLCOUNT(PLL_COUNT);
125*1b2596b5SMatthias Ringwald 	} else { /* PLLA */
126*1b2596b5SMatthias Ringwald 	/* Calculate internal VCO frequency */
127*1b2596b5SMatthias Ringwald 	vco_hz = osc_get_rate(e_src) / ul_div;
128*1b2596b5SMatthias Ringwald 	Assert(vco_hz >= PLL_INPUT_MIN_HZ);
129*1b2596b5SMatthias Ringwald 	Assert(vco_hz <= PLL_INPUT_MAX_HZ);
130*1b2596b5SMatthias Ringwald 
131*1b2596b5SMatthias Ringwald 	vco_hz *= ul_mul;
132*1b2596b5SMatthias Ringwald 	Assert(vco_hz >= PLL_OUTPUT_MIN_HZ);
133*1b2596b5SMatthias Ringwald 	Assert(vco_hz <= PLL_OUTPUT_MAX_HZ);
134*1b2596b5SMatthias Ringwald 
135*1b2596b5SMatthias Ringwald 	/* PMC hardware will automatically make it mul+1 */
136*1b2596b5SMatthias Ringwald 		p_cfg->ctrl = CKGR_PLLAR_MULA(ul_mul - 1) | CKGR_PLLAR_DIVA(ul_div)  \
137*1b2596b5SMatthias Ringwald 		| CKGR_PLLAR_PLLACOUNT(PLL_COUNT);
138*1b2596b5SMatthias Ringwald 	}
139*1b2596b5SMatthias Ringwald }
140*1b2596b5SMatthias Ringwald 
141*1b2596b5SMatthias Ringwald #define pll_config_defaults(cfg, pll_id)                                 \
142*1b2596b5SMatthias Ringwald 	pll_config_init(cfg,                                             \
143*1b2596b5SMatthias Ringwald 			CONFIG_PLL##pll_id##_SOURCE,                     \
144*1b2596b5SMatthias Ringwald 			CONFIG_PLL##pll_id##_DIV,                        \
145*1b2596b5SMatthias Ringwald 			CONFIG_PLL##pll_id##_MUL)
146*1b2596b5SMatthias Ringwald 
pll_config_read(struct pll_config * p_cfg,uint32_t ul_pll_id)147*1b2596b5SMatthias Ringwald static inline void pll_config_read(struct pll_config *p_cfg, uint32_t ul_pll_id)
148*1b2596b5SMatthias Ringwald {
149*1b2596b5SMatthias Ringwald 	Assert(ul_pll_id < NR_PLLS);
150*1b2596b5SMatthias Ringwald 
151*1b2596b5SMatthias Ringwald 	if (ul_pll_id == PLLA_ID) {
152*1b2596b5SMatthias Ringwald 		p_cfg->ctrl = PMC->CKGR_PLLAR;
153*1b2596b5SMatthias Ringwald 	} else {
154*1b2596b5SMatthias Ringwald 		p_cfg->ctrl = PMC->CKGR_UCKR;
155*1b2596b5SMatthias Ringwald 	}
156*1b2596b5SMatthias Ringwald }
157*1b2596b5SMatthias Ringwald 
pll_config_write(const struct pll_config * p_cfg,uint32_t ul_pll_id)158*1b2596b5SMatthias Ringwald static inline void pll_config_write(const struct pll_config *p_cfg, uint32_t ul_pll_id)
159*1b2596b5SMatthias Ringwald {
160*1b2596b5SMatthias Ringwald 	Assert(ul_pll_id < NR_PLLS);
161*1b2596b5SMatthias Ringwald 
162*1b2596b5SMatthias Ringwald 	if (ul_pll_id == PLLA_ID) {
163*1b2596b5SMatthias Ringwald 		pmc_disable_pllack(); // Always stop PLL first!
164*1b2596b5SMatthias Ringwald 		PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl;
165*1b2596b5SMatthias Ringwald 	} else {
166*1b2596b5SMatthias Ringwald 		PMC->CKGR_UCKR = p_cfg->ctrl;
167*1b2596b5SMatthias Ringwald 	}
168*1b2596b5SMatthias Ringwald }
169*1b2596b5SMatthias Ringwald 
pll_enable(const struct pll_config * p_cfg,uint32_t ul_pll_id)170*1b2596b5SMatthias Ringwald static inline void pll_enable(const struct pll_config *p_cfg, uint32_t ul_pll_id)
171*1b2596b5SMatthias Ringwald {
172*1b2596b5SMatthias Ringwald 	Assert(ul_pll_id < NR_PLLS);
173*1b2596b5SMatthias Ringwald 
174*1b2596b5SMatthias Ringwald 	if (ul_pll_id == PLLA_ID) {
175*1b2596b5SMatthias Ringwald 		pmc_disable_pllack(); // Always stop PLL first!
176*1b2596b5SMatthias Ringwald 		PMC->CKGR_PLLAR = CKGR_PLLAR_ONE | p_cfg->ctrl;
177*1b2596b5SMatthias Ringwald 	} else {
178*1b2596b5SMatthias Ringwald 		PMC->CKGR_UCKR = p_cfg->ctrl | CKGR_UCKR_UPLLEN;
179*1b2596b5SMatthias Ringwald 	}
180*1b2596b5SMatthias Ringwald }
181*1b2596b5SMatthias Ringwald 
182*1b2596b5SMatthias Ringwald /**
183*1b2596b5SMatthias Ringwald  * \note This will only disable the selected PLL, not the underlying oscillator (mainck).
184*1b2596b5SMatthias Ringwald  */
pll_disable(uint32_t ul_pll_id)185*1b2596b5SMatthias Ringwald static inline void pll_disable(uint32_t ul_pll_id)
186*1b2596b5SMatthias Ringwald {
187*1b2596b5SMatthias Ringwald 	Assert(ul_pll_id < NR_PLLS);
188*1b2596b5SMatthias Ringwald 
189*1b2596b5SMatthias Ringwald 	if (ul_pll_id == PLLA_ID) {
190*1b2596b5SMatthias Ringwald 		pmc_disable_pllack();
191*1b2596b5SMatthias Ringwald 	} else {
192*1b2596b5SMatthias Ringwald 		PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN;
193*1b2596b5SMatthias Ringwald 	}
194*1b2596b5SMatthias Ringwald }
195*1b2596b5SMatthias Ringwald 
pll_is_locked(uint32_t ul_pll_id)196*1b2596b5SMatthias Ringwald static inline uint32_t pll_is_locked(uint32_t ul_pll_id)
197*1b2596b5SMatthias Ringwald {
198*1b2596b5SMatthias Ringwald 	Assert(ul_pll_id < NR_PLLS);
199*1b2596b5SMatthias Ringwald 
200*1b2596b5SMatthias Ringwald 	if (ul_pll_id == PLLA_ID) {
201*1b2596b5SMatthias Ringwald 	return pmc_is_locked_pllack();
202*1b2596b5SMatthias Ringwald 	} else {
203*1b2596b5SMatthias Ringwald 		return pmc_is_locked_upll();
204*1b2596b5SMatthias Ringwald 	}
205*1b2596b5SMatthias Ringwald }
206*1b2596b5SMatthias Ringwald 
pll_enable_source(enum pll_source e_src)207*1b2596b5SMatthias Ringwald static inline void pll_enable_source(enum pll_source e_src)
208*1b2596b5SMatthias Ringwald {
209*1b2596b5SMatthias Ringwald 	switch (e_src) {
210*1b2596b5SMatthias Ringwald 	case PLL_SRC_MAINCK_4M_RC:
211*1b2596b5SMatthias Ringwald 	case PLL_SRC_MAINCK_8M_RC:
212*1b2596b5SMatthias Ringwald 	case PLL_SRC_MAINCK_12M_RC:
213*1b2596b5SMatthias Ringwald 	case PLL_SRC_MAINCK_XTAL:
214*1b2596b5SMatthias Ringwald 	case PLL_SRC_MAINCK_BYPASS:
215*1b2596b5SMatthias Ringwald 		osc_enable(e_src);
216*1b2596b5SMatthias Ringwald 		osc_wait_ready(e_src);
217*1b2596b5SMatthias Ringwald 		break;
218*1b2596b5SMatthias Ringwald 
219*1b2596b5SMatthias Ringwald 	default:
220*1b2596b5SMatthias Ringwald 		Assert(false);
221*1b2596b5SMatthias Ringwald 		break;
222*1b2596b5SMatthias Ringwald 	}
223*1b2596b5SMatthias Ringwald }
224*1b2596b5SMatthias Ringwald 
pll_enable_config_defaults(unsigned int ul_pll_id)225*1b2596b5SMatthias Ringwald static inline void pll_enable_config_defaults(unsigned int ul_pll_id)
226*1b2596b5SMatthias Ringwald {
227*1b2596b5SMatthias Ringwald 	struct pll_config pllcfg;
228*1b2596b5SMatthias Ringwald 
229*1b2596b5SMatthias Ringwald 	if (pll_is_locked(ul_pll_id)) {
230*1b2596b5SMatthias Ringwald 		return; // Pll already running
231*1b2596b5SMatthias Ringwald 	}
232*1b2596b5SMatthias Ringwald 	switch (ul_pll_id) {
233*1b2596b5SMatthias Ringwald #ifdef CONFIG_PLL0_SOURCE
234*1b2596b5SMatthias Ringwald 	case 0:
235*1b2596b5SMatthias Ringwald 		pll_enable_source(CONFIG_PLL0_SOURCE);
236*1b2596b5SMatthias Ringwald 		pll_config_init(&pllcfg,
237*1b2596b5SMatthias Ringwald 				CONFIG_PLL0_SOURCE,
238*1b2596b5SMatthias Ringwald 				CONFIG_PLL0_DIV,
239*1b2596b5SMatthias Ringwald 				CONFIG_PLL0_MUL);
240*1b2596b5SMatthias Ringwald 		break;
241*1b2596b5SMatthias Ringwald #endif
242*1b2596b5SMatthias Ringwald #ifdef CONFIG_PLL1_SOURCE
243*1b2596b5SMatthias Ringwald 	case 1:
244*1b2596b5SMatthias Ringwald 		pll_enable_source(CONFIG_PLL1_SOURCE);
245*1b2596b5SMatthias Ringwald 		pll_config_init(&pllcfg,
246*1b2596b5SMatthias Ringwald 				CONFIG_PLL1_SOURCE,
247*1b2596b5SMatthias Ringwald 				CONFIG_PLL1_DIV,
248*1b2596b5SMatthias Ringwald 				CONFIG_PLL1_MUL);
249*1b2596b5SMatthias Ringwald 		break;
250*1b2596b5SMatthias Ringwald #endif
251*1b2596b5SMatthias Ringwald 	default:
252*1b2596b5SMatthias Ringwald 		Assert(false);
253*1b2596b5SMatthias Ringwald 		break;
254*1b2596b5SMatthias Ringwald 	}
255*1b2596b5SMatthias Ringwald 	pll_enable(&pllcfg, ul_pll_id);
256*1b2596b5SMatthias Ringwald 	while (!pll_is_locked(ul_pll_id));
257*1b2596b5SMatthias Ringwald }
258*1b2596b5SMatthias Ringwald 
259*1b2596b5SMatthias Ringwald //! @}
260*1b2596b5SMatthias Ringwald 
261*1b2596b5SMatthias Ringwald /// @cond 0
262*1b2596b5SMatthias Ringwald /**INDENT-OFF**/
263*1b2596b5SMatthias Ringwald #ifdef __cplusplus
264*1b2596b5SMatthias Ringwald }
265*1b2596b5SMatthias Ringwald #endif
266*1b2596b5SMatthias Ringwald /**INDENT-ON**/
267*1b2596b5SMatthias Ringwald /// @endcond
268*1b2596b5SMatthias Ringwald 
269*1b2596b5SMatthias Ringwald #endif /* CHIP_PLL_H_INCLUDED */
270