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