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