1 /*
2 * Copyright 2020 GreenWaves Technologies
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 */
18
19 #include <stdlib.h>
20 #include "hal_fll_pi.h"
21 #include "core-v-mcu-system.h"
22 #include <rtthread.h>
23 /*******************************************************************************
24 * Definitions
25 ******************************************************************************/
26 /*
27 * Fll control
28 * FreqOut = Fref * Mult/2^(Div-1)
29 * With Mult on 16 bits and Div on 4 bits
30 */
31
32 /* Maximum Log2(DCO Frequency) */
33 #define FLL_LOG2_MAXDCO 29
34 /* Maximum Log2(Clok Divider) */
35 #define FLL_LOG2_MAXDIV 15
36 /* Log2(FLL_REF_CLK=32768) */
37 #define FLL_LOG2_REFCLK ARCHI_REF_CLOCK_LOG2
38 /* Maximum Log2(Multiplier) */
39 #define FLL_LOG2_MAXM (FLL_LOG2_MAXDCO - FLL_LOG2_REFCLK)
40
41 /* TODO: we are patching over these macros to make them independent of pulp-gcc */
42 #define __MAX(a, b) \
43 ({ \
44 typeof(a) _a = (a); \
45 typeof(b) _b = (b); \
46 _a > _b ? _a : _b; \
47 })
48
49 #define __FL1(x) (31 - __builtin_clz((x)))
50
51 /*******************************************************************************
52 * Prototypes
53 ******************************************************************************/
54
55 /*******************************************************************************
56 * Variables
57 ******************************************************************************/
58 static volatile uint32_t flls_frequency[FLL_NUM];
59
60 /*******************************************************************************
61 * Code
62 ******************************************************************************/
fll_get_mult_div_from_frequency(uint32_t freq,uint32_t * mult,uint32_t * div)63 static uint32_t fll_get_mult_div_from_frequency(uint32_t freq, uint32_t *mult,
64 uint32_t *div)
65 {
66 unsigned int fref = FLL_REF_CLK;
67 unsigned int Log2M = __FL1(freq) - __FL1(fref);
68 unsigned int D = __MAX(1, (FLL_LOG2_MAXM - Log2M) >> 1);
69 unsigned int M = (freq << D) / fref;
70 unsigned int fres;
71
72 fres = (fref * M + (1 << (D - 1))) >> D; /* Rounding */
73
74 *mult = M;
75 *div = D + 1;
76 return fres;
77 }
78
fll_get_frequency_from_mult_div(uint32_t mult,uint32_t div)79 static uint32_t fll_get_frequency_from_mult_div(uint32_t mult, uint32_t div)
80 {
81 /* FreqOut = Fref * Mult/2^(Div-1) With Mult on 16 bits and Div on 4 bits */
82 uint32_t fref = FLL_REF_CLK;
83 uint32_t fres = (div == 0) ? (fref * mult) : (fref * mult) >> (div - 1);
84 return fres;
85 }
86
pi_fll_set_frequency(fll_type_t which_fll,uint32_t frequency,int check)87 int pi_fll_set_frequency(fll_type_t which_fll, uint32_t frequency, int check)
88 {
89 uint32_t mult, div;
90 uint32_t reg1;
91
92 int irq = __disable_irq();
93
94 /* Frequency calculation from theory */
95 fll_get_mult_div_from_frequency(frequency, &mult, &div);
96
97 /* update mult and div */
98 /* TODO: check if fll is on */
99 reg1 = FLL_CTRL[which_fll].FLL_CONF1;
100
101 reg1 &= ~FLL_CTRL_CONF1_MULTI_FACTOR_MASK;
102 reg1 |= FLL_CTRL_CONF1_MULTI_FACTOR(mult);
103 reg1 &= ~FLL_CTRL_CONF1_CLK_OUT_DIV_MASK;
104 reg1 |= FLL_CTRL_CONF1_CLK_OUT_DIV(div);
105
106 FLL_CTRL[which_fll].FLL_CONF1 = reg1;
107
108 /* finalize */
109 if (which_fll == FLL_SOC)
110 system_core_clock_update();
111
112 flls_frequency[which_fll] = frequency;
113
114 __restore_irq(irq);
115
116 return frequency;
117 }
118
pi_fll_init(fll_type_t which_fll,uint32_t ret_state)119 void pi_fll_init(fll_type_t which_fll, uint32_t ret_state)
120 {
121 uint32_t reg1;
122
123 if (ret_state) {
124 pi_fll_get_frequency(which_fll, 1);
125 } else {
126 reg1 = FLL_CTRL[which_fll].FLL_CONF1;
127
128 /*
129 * Don't set the gain and integrator in case it has already been
130 * set by the boot code as it totally blocks the fll on the RTL
131 * platform. The boot code is anyway setting the same
132 * configuration.
133 */
134 if (!READ_FLL_CTRL_CONF1_MODE(reg1)) {
135 /* set clock ref lock assert count */
136 uint32_t reg2 = FLL_CTRL[which_fll].FLL_CONF2;
137 reg2 &= ~FLL_CTRL_CONF2_ASSERT_CYCLES_MASK;
138 reg2 |= FLL_CTRL_CONF2_ASSERT_CYCLES(0x6);
139 reg2 &= ~FLL_CTRL_CONF2_LOCK_TOLERANCE_MASK;
140 reg2 |= FLL_CTRL_CONF2_LOCK_TOLERANCE(0x50);
141 FLL_CTRL[which_fll].FLL_CONF2 = reg2;
142
143 /*
144 * In order to lock the fll faster, we first setup an
145 * approximated frequency while we are in open loop as
146 * it is set immediately. Then starting from this
147 * frequency, we should reach the target one in lock
148 * mode faster. We are in open loop, prime the fll
149 * forcing dco input, approx 70 MHz
150 */
151 uint32_t regint = FLL_CTRL[which_fll].FLL_INTEGRATOR;
152 regint &= ~FLL_CTRL_INTEGRATOR_INT_PART_MASK;
153 regint |= FLL_CTRL_INTEGRATOR_INT_PART(332);
154 FLL_CTRL[which_fll].FLL_INTEGRATOR = regint;
155
156 /* Lock FLL */
157 reg1 &= ~FLL_CTRL_CONF1_OUTPUT_LOCK_EN_MASK;
158 reg1 |= FLL_CTRL_CONF1_OUTPUT_LOCK_EN(1);
159 reg1 &= ~FLL_CTRL_CONF1_MODE_MASK;
160 reg1 |= FLL_CTRL_CONF1_MODE(1);
161 FLL_CTRL[which_fll].FLL_CONF1 = reg1;
162 }
163
164 /*
165 * In case the FLL frequency was set while it was off, update it
166 * immediately
167 */
168 uint32_t freq = flls_frequency[which_fll];
169 if (freq) {
170 if (pi_fll_set_frequency(which_fll, freq, 0))
171 abort();
172 } else {
173 freq = fll_get_frequency_from_mult_div(
174 READ_FLL_CTRL_CONF1_MULTI_FACTOR(reg1),
175 READ_FLL_CTRL_CONF1_CLK_OUT_DIV(reg1));
176 flls_frequency[which_fll] = DEFAULT_SYSTEM_CLOCK; //freq;
177 }
178 /* TODO: see if we need this
179 if (pi_fll_set_frequency(which_fll, DEFAULT_SYSTEM_CLOCK, 0) ==
180 -1)
181 exit(-1);
182 */
183 }
184 }
185
pi_fll_get_frequency(fll_type_t which_fll,uint8_t real)186 int pi_fll_get_frequency(fll_type_t which_fll, uint8_t real)
187 {
188 if (real) {
189 /* Frequency calculation from real world */
190 int real_freq = 0;
191 real_freq = fll_get_frequency_from_mult_div(
192 FLL_CTRL[which_fll].FLL_STATUS,
193 READ_FLL_CTRL_CONF1_CLK_OUT_DIV(
194 FLL_CTRL[which_fll].FLL_CONF1));
195
196 /* Update Frequency */
197 flls_frequency[which_fll] = real_freq;
198 }
199 return flls_frequency[which_fll];
200 }
201
pi_fll_deinit(fll_type_t which_fll)202 void pi_fll_deinit(fll_type_t which_fll)
203 {
204 flls_frequency[which_fll] = 0;
205 }
206