Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
10820 views
1
/*****************************************************************************
2
* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
3
*
4
* Unless you and Broadcom execute a separate written software license
5
* agreement governing use of this software, this software is licensed to you
6
* under the terms of the GNU General Public License version 2, available at
7
* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
8
*
9
* Notwithstanding the above, under no circumstances may you combine this
10
* software in any way with any other Broadcom software provided under a
11
* license other than the GPL, without Broadcom's express prior written
12
* consent.
13
*****************************************************************************/
14
15
/****************************************************************************/
16
/**
17
* @file chipcHw.c
18
*
19
* @brief Low level Various CHIP clock controlling routines
20
*
21
* @note
22
*
23
* These routines provide basic clock controlling functionality only.
24
*/
25
/****************************************************************************/
26
27
/* ---- Include Files ---------------------------------------------------- */
28
29
#include <csp/errno.h>
30
#include <csp/stdint.h>
31
#include <csp/module.h>
32
33
#include <mach/csp/chipcHw_def.h>
34
#include <mach/csp/chipcHw_inline.h>
35
36
#include <csp/reg.h>
37
#include <csp/delay.h>
38
39
/* ---- Private Constants and Types --------------------------------------- */
40
41
/* VPM alignment algorithm uses this */
42
#define MAX_PHASE_ADJUST_COUNT 0xFFFF /* Max number of times allowed to adjust the phase */
43
#define MAX_PHASE_ALIGN_ATTEMPTS 10 /* Max number of attempt to align the phase */
44
45
/* Local definition of clock type */
46
#define PLL_CLOCK 1 /* PLL Clock */
47
#define NON_PLL_CLOCK 2 /* Divider clock */
48
49
static int chipcHw_divide(int num, int denom)
50
__attribute__ ((section(".aramtext")));
51
52
/****************************************************************************/
53
/**
54
* @brief Set clock fequency for miscellaneous configurable clocks
55
*
56
* This function sets clock frequency
57
*
58
* @return Configured clock frequency in hertz
59
*
60
*/
61
/****************************************************************************/
62
chipcHw_freq chipcHw_getClockFrequency(chipcHw_CLOCK_e clock /* [ IN ] Configurable clock */
63
) {
64
volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
65
volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
66
volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
67
uint32_t vcoFreqPll1Hz = 0; /* Effective VCO frequency for PLL1 in Hz */
68
uint32_t vcoFreqPll2Hz = 0; /* Effective VCO frequency for PLL2 in Hz */
69
uint32_t dependentClockType = 0;
70
uint32_t vcoHz = 0;
71
72
/* Get VCO frequencies */
73
if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
74
uint64_t adjustFreq = 0;
75
76
vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
77
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
78
((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
79
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
80
81
/* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
82
adjustFreq = (uint64_t) chipcHw_XTAL_FREQ_Hz *
83
(uint64_t) chipcHw_REG_PLL_DIVIDER_NDIV_f_SS *
84
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, (chipcHw_REG_PLL_PREDIVIDER_P2 * (uint64_t) chipcHw_REG_PLL_DIVIDER_FRAC));
85
vcoFreqPll1Hz += (uint32_t) adjustFreq;
86
} else {
87
vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
88
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
89
((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
90
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
91
}
92
vcoFreqPll2Hz =
93
chipcHw_XTAL_FREQ_Hz *
94
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
95
((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
96
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
97
98
switch (clock) {
99
case chipcHw_CLOCK_DDR:
100
pPLLReg = &pChipcHw->DDRClock;
101
vcoHz = vcoFreqPll1Hz;
102
break;
103
case chipcHw_CLOCK_ARM:
104
pPLLReg = &pChipcHw->ARMClock;
105
vcoHz = vcoFreqPll1Hz;
106
break;
107
case chipcHw_CLOCK_ESW:
108
pPLLReg = &pChipcHw->ESWClock;
109
vcoHz = vcoFreqPll1Hz;
110
break;
111
case chipcHw_CLOCK_VPM:
112
pPLLReg = &pChipcHw->VPMClock;
113
vcoHz = vcoFreqPll1Hz;
114
break;
115
case chipcHw_CLOCK_ESW125:
116
pPLLReg = &pChipcHw->ESW125Clock;
117
vcoHz = vcoFreqPll1Hz;
118
break;
119
case chipcHw_CLOCK_UART:
120
pPLLReg = &pChipcHw->UARTClock;
121
vcoHz = vcoFreqPll1Hz;
122
break;
123
case chipcHw_CLOCK_SDIO0:
124
pPLLReg = &pChipcHw->SDIO0Clock;
125
vcoHz = vcoFreqPll1Hz;
126
break;
127
case chipcHw_CLOCK_SDIO1:
128
pPLLReg = &pChipcHw->SDIO1Clock;
129
vcoHz = vcoFreqPll1Hz;
130
break;
131
case chipcHw_CLOCK_SPI:
132
pPLLReg = &pChipcHw->SPIClock;
133
vcoHz = vcoFreqPll1Hz;
134
break;
135
case chipcHw_CLOCK_ETM:
136
pPLLReg = &pChipcHw->ETMClock;
137
vcoHz = vcoFreqPll1Hz;
138
break;
139
case chipcHw_CLOCK_USB:
140
pPLLReg = &pChipcHw->USBClock;
141
vcoHz = vcoFreqPll2Hz;
142
break;
143
case chipcHw_CLOCK_LCD:
144
pPLLReg = &pChipcHw->LCDClock;
145
vcoHz = vcoFreqPll2Hz;
146
break;
147
case chipcHw_CLOCK_APM:
148
pPLLReg = &pChipcHw->APMClock;
149
vcoHz = vcoFreqPll2Hz;
150
break;
151
case chipcHw_CLOCK_BUS:
152
pClockCtrl = &pChipcHw->ACLKClock;
153
pDependentClock = &pChipcHw->ARMClock;
154
vcoHz = vcoFreqPll1Hz;
155
dependentClockType = PLL_CLOCK;
156
break;
157
case chipcHw_CLOCK_OTP:
158
pClockCtrl = &pChipcHw->OTPClock;
159
break;
160
case chipcHw_CLOCK_I2C:
161
pClockCtrl = &pChipcHw->I2CClock;
162
break;
163
case chipcHw_CLOCK_I2S0:
164
pClockCtrl = &pChipcHw->I2S0Clock;
165
break;
166
case chipcHw_CLOCK_RTBUS:
167
pClockCtrl = &pChipcHw->RTBUSClock;
168
pDependentClock = &pChipcHw->ACLKClock;
169
dependentClockType = NON_PLL_CLOCK;
170
break;
171
case chipcHw_CLOCK_APM100:
172
pClockCtrl = &pChipcHw->APM100Clock;
173
pDependentClock = &pChipcHw->APMClock;
174
vcoHz = vcoFreqPll2Hz;
175
dependentClockType = PLL_CLOCK;
176
break;
177
case chipcHw_CLOCK_TSC:
178
pClockCtrl = &pChipcHw->TSCClock;
179
break;
180
case chipcHw_CLOCK_LED:
181
pClockCtrl = &pChipcHw->LEDClock;
182
break;
183
case chipcHw_CLOCK_I2S1:
184
pClockCtrl = &pChipcHw->I2S1Clock;
185
break;
186
}
187
188
if (pPLLReg) {
189
/* Obtain PLL clock frequency */
190
if (*pPLLReg & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
191
/* Return crystal clock frequency when bypassed */
192
return chipcHw_XTAL_FREQ_Hz;
193
} else if (clock == chipcHw_CLOCK_DDR) {
194
/* DDR frequency is configured in PLLDivider register */
195
return chipcHw_divide (vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
196
} else {
197
/* From chip revision number B0, LCD clock is internally divided by 2 */
198
if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
199
vcoHz >>= 1;
200
}
201
/* Obtain PLL clock frequency using VCO dividers */
202
return chipcHw_divide(vcoHz, ((*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*pPLLReg & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
203
}
204
} else if (pClockCtrl) {
205
/* Obtain divider clock frequency */
206
uint32_t div;
207
uint32_t freq = 0;
208
209
if (*pClockCtrl & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
210
/* Return crystal clock frequency when bypassed */
211
return chipcHw_XTAL_FREQ_Hz;
212
} else if (pDependentClock) {
213
/* Identify the dependent clock frequency */
214
switch (dependentClockType) {
215
case PLL_CLOCK:
216
if (*pDependentClock & chipcHw_REG_PLL_CLOCK_BYPASS_SELECT) {
217
/* Use crystal clock frequency when dependent PLL clock is bypassed */
218
freq = chipcHw_XTAL_FREQ_Hz;
219
} else {
220
/* Obtain PLL clock frequency using VCO dividers */
221
div = *pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK;
222
freq = div ? chipcHw_divide(vcoHz, div) : 0;
223
}
224
break;
225
case NON_PLL_CLOCK:
226
if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
227
freq = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
228
} else {
229
if (*pDependentClock & chipcHw_REG_DIV_CLOCK_BYPASS_SELECT) {
230
/* Use crystal clock frequency when dependent divider clock is bypassed */
231
freq = chipcHw_XTAL_FREQ_Hz;
232
} else {
233
/* Obtain divider clock frequency using XTAL dividers */
234
div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
235
freq = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, (div ? div : 256));
236
}
237
}
238
break;
239
}
240
} else {
241
/* Dependent on crystal clock */
242
freq = chipcHw_XTAL_FREQ_Hz;
243
}
244
245
div = *pClockCtrl & chipcHw_REG_DIV_CLOCK_DIV_MASK;
246
return chipcHw_divide(freq, (div ? div : 256));
247
}
248
return 0;
249
}
250
251
/****************************************************************************/
252
/**
253
* @brief Set clock fequency for miscellaneous configurable clocks
254
*
255
* This function sets clock frequency
256
*
257
* @return Configured clock frequency in Hz
258
*
259
*/
260
/****************************************************************************/
261
chipcHw_freq chipcHw_setClockFrequency(chipcHw_CLOCK_e clock, /* [ IN ] Configurable clock */
262
uint32_t freq /* [ IN ] Clock frequency in Hz */
263
) {
264
volatile uint32_t *pPLLReg = (uint32_t *) 0x0;
265
volatile uint32_t *pClockCtrl = (uint32_t *) 0x0;
266
volatile uint32_t *pDependentClock = (uint32_t *) 0x0;
267
uint32_t vcoFreqPll1Hz = 0; /* Effective VCO frequency for PLL1 in Hz */
268
uint32_t desVcoFreqPll1Hz = 0; /* Desired VCO frequency for PLL1 in Hz */
269
uint32_t vcoFreqPll2Hz = 0; /* Effective VCO frequency for PLL2 in Hz */
270
uint32_t dependentClockType = 0;
271
uint32_t vcoHz = 0;
272
uint32_t desVcoHz = 0;
273
274
/* Get VCO frequencies */
275
if ((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASK) != chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER) {
276
uint64_t adjustFreq = 0;
277
278
vcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
279
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
280
((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
281
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
282
283
/* Adjusted frequency due to chipcHw_REG_PLL_DIVIDER_NDIV_f_SS */
284
adjustFreq = (uint64_t) chipcHw_XTAL_FREQ_Hz *
285
(uint64_t) chipcHw_REG_PLL_DIVIDER_NDIV_f_SS *
286
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, (chipcHw_REG_PLL_PREDIVIDER_P2 * (uint64_t) chipcHw_REG_PLL_DIVIDER_FRAC));
287
vcoFreqPll1Hz += (uint32_t) adjustFreq;
288
289
/* Desired VCO frequency */
290
desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
291
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
292
(((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
293
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) + 1);
294
} else {
295
vcoFreqPll1Hz = desVcoFreqPll1Hz = chipcHw_XTAL_FREQ_Hz *
296
chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
297
((pChipcHw->PLLPreDivider & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
298
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
299
}
300
vcoFreqPll2Hz = chipcHw_XTAL_FREQ_Hz * chipcHw_divide(chipcHw_REG_PLL_PREDIVIDER_P1, chipcHw_REG_PLL_PREDIVIDER_P2) *
301
((pChipcHw->PLLPreDivider2 & chipcHw_REG_PLL_PREDIVIDER_NDIV_MASK) >>
302
chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT);
303
304
switch (clock) {
305
case chipcHw_CLOCK_DDR:
306
/* Configure the DDR_ctrl:BUS ratio settings */
307
{
308
REG_LOCAL_IRQ_SAVE;
309
/* Dvide DDR_phy by two to obtain DDR_ctrl clock */
310
pChipcHw->DDRClock = (pChipcHw->DDRClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((((freq / 2) / chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
311
<< chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
312
REG_LOCAL_IRQ_RESTORE;
313
}
314
pPLLReg = &pChipcHw->DDRClock;
315
vcoHz = vcoFreqPll1Hz;
316
desVcoHz = desVcoFreqPll1Hz;
317
break;
318
case chipcHw_CLOCK_ARM:
319
pPLLReg = &pChipcHw->ARMClock;
320
vcoHz = vcoFreqPll1Hz;
321
desVcoHz = desVcoFreqPll1Hz;
322
break;
323
case chipcHw_CLOCK_ESW:
324
pPLLReg = &pChipcHw->ESWClock;
325
vcoHz = vcoFreqPll1Hz;
326
desVcoHz = desVcoFreqPll1Hz;
327
break;
328
case chipcHw_CLOCK_VPM:
329
/* Configure the VPM:BUS ratio settings */
330
{
331
REG_LOCAL_IRQ_SAVE;
332
pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_MASK) | ((chipcHw_divide (freq, chipcHw_getClockFrequency(chipcHw_CLOCK_BUS)) - 1)
333
<< chipcHw_REG_PLL_CLOCK_TO_BUS_RATIO_SHIFT);
334
REG_LOCAL_IRQ_RESTORE;
335
}
336
pPLLReg = &pChipcHw->VPMClock;
337
vcoHz = vcoFreqPll1Hz;
338
desVcoHz = desVcoFreqPll1Hz;
339
break;
340
case chipcHw_CLOCK_ESW125:
341
pPLLReg = &pChipcHw->ESW125Clock;
342
vcoHz = vcoFreqPll1Hz;
343
desVcoHz = desVcoFreqPll1Hz;
344
break;
345
case chipcHw_CLOCK_UART:
346
pPLLReg = &pChipcHw->UARTClock;
347
vcoHz = vcoFreqPll1Hz;
348
desVcoHz = desVcoFreqPll1Hz;
349
break;
350
case chipcHw_CLOCK_SDIO0:
351
pPLLReg = &pChipcHw->SDIO0Clock;
352
vcoHz = vcoFreqPll1Hz;
353
desVcoHz = desVcoFreqPll1Hz;
354
break;
355
case chipcHw_CLOCK_SDIO1:
356
pPLLReg = &pChipcHw->SDIO1Clock;
357
vcoHz = vcoFreqPll1Hz;
358
desVcoHz = desVcoFreqPll1Hz;
359
break;
360
case chipcHw_CLOCK_SPI:
361
pPLLReg = &pChipcHw->SPIClock;
362
vcoHz = vcoFreqPll1Hz;
363
desVcoHz = desVcoFreqPll1Hz;
364
break;
365
case chipcHw_CLOCK_ETM:
366
pPLLReg = &pChipcHw->ETMClock;
367
vcoHz = vcoFreqPll1Hz;
368
desVcoHz = desVcoFreqPll1Hz;
369
break;
370
case chipcHw_CLOCK_USB:
371
pPLLReg = &pChipcHw->USBClock;
372
vcoHz = vcoFreqPll2Hz;
373
desVcoHz = vcoFreqPll2Hz;
374
break;
375
case chipcHw_CLOCK_LCD:
376
pPLLReg = &pChipcHw->LCDClock;
377
vcoHz = vcoFreqPll2Hz;
378
desVcoHz = vcoFreqPll2Hz;
379
break;
380
case chipcHw_CLOCK_APM:
381
pPLLReg = &pChipcHw->APMClock;
382
vcoHz = vcoFreqPll2Hz;
383
desVcoHz = vcoFreqPll2Hz;
384
break;
385
case chipcHw_CLOCK_BUS:
386
pClockCtrl = &pChipcHw->ACLKClock;
387
pDependentClock = &pChipcHw->ARMClock;
388
vcoHz = vcoFreqPll1Hz;
389
desVcoHz = desVcoFreqPll1Hz;
390
dependentClockType = PLL_CLOCK;
391
break;
392
case chipcHw_CLOCK_OTP:
393
pClockCtrl = &pChipcHw->OTPClock;
394
break;
395
case chipcHw_CLOCK_I2C:
396
pClockCtrl = &pChipcHw->I2CClock;
397
break;
398
case chipcHw_CLOCK_I2S0:
399
pClockCtrl = &pChipcHw->I2S0Clock;
400
break;
401
case chipcHw_CLOCK_RTBUS:
402
pClockCtrl = &pChipcHw->RTBUSClock;
403
pDependentClock = &pChipcHw->ACLKClock;
404
dependentClockType = NON_PLL_CLOCK;
405
break;
406
case chipcHw_CLOCK_APM100:
407
pClockCtrl = &pChipcHw->APM100Clock;
408
pDependentClock = &pChipcHw->APMClock;
409
vcoHz = vcoFreqPll2Hz;
410
desVcoHz = vcoFreqPll2Hz;
411
dependentClockType = PLL_CLOCK;
412
break;
413
case chipcHw_CLOCK_TSC:
414
pClockCtrl = &pChipcHw->TSCClock;
415
break;
416
case chipcHw_CLOCK_LED:
417
pClockCtrl = &pChipcHw->LEDClock;
418
break;
419
case chipcHw_CLOCK_I2S1:
420
pClockCtrl = &pChipcHw->I2S1Clock;
421
break;
422
}
423
424
if (pPLLReg) {
425
/* Select XTAL as bypass source */
426
reg32_modify_and(pPLLReg, ~chipcHw_REG_PLL_CLOCK_SOURCE_GPIO);
427
reg32_modify_or(pPLLReg, chipcHw_REG_PLL_CLOCK_BYPASS_SELECT);
428
/* For DDR settings use only the PLL divider clock */
429
if (pPLLReg == &pChipcHw->DDRClock) {
430
/* Set M1DIV for PLL1, which controls the DDR clock */
431
reg32_write(&pChipcHw->PLLDivider, (pChipcHw->PLLDivider & 0x00FFFFFF) | ((chipcHw_REG_PLL_DIVIDER_MDIV (desVcoHz, freq)) << 24));
432
/* Calculate expected frequency */
433
freq = chipcHw_divide(vcoHz, (((pChipcHw->PLLDivider & 0xFF000000) >> 24) ? ((pChipcHw->PLLDivider & 0xFF000000) >> 24) : 256));
434
} else {
435
/* From chip revision number B0, LCD clock is internally divided by 2 */
436
if ((pPLLReg == &pChipcHw->LCDClock) && (chipcHw_getChipRevisionNumber() != chipcHw_REV_NUMBER_A0)) {
437
desVcoHz >>= 1;
438
vcoHz >>= 1;
439
}
440
/* Set MDIV to change the frequency */
441
reg32_modify_and(pPLLReg, ~(chipcHw_REG_PLL_CLOCK_MDIV_MASK));
442
reg32_modify_or(pPLLReg, chipcHw_REG_PLL_DIVIDER_MDIV(desVcoHz, freq));
443
/* Calculate expected frequency */
444
freq = chipcHw_divide(vcoHz, ((*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) ? (*(pPLLReg) & chipcHw_REG_PLL_CLOCK_MDIV_MASK) : 256));
445
}
446
/* Wait for for atleast 200ns as per the protocol to change frequency */
447
udelay(1);
448
/* Do not bypass */
449
reg32_modify_and(pPLLReg, ~chipcHw_REG_PLL_CLOCK_BYPASS_SELECT);
450
/* Return the configured frequency */
451
return freq;
452
} else if (pClockCtrl) {
453
uint32_t divider = 0;
454
455
/* Divider clock should not be bypassed */
456
reg32_modify_and(pClockCtrl,
457
~chipcHw_REG_DIV_CLOCK_BYPASS_SELECT);
458
459
/* Identify the clock source */
460
if (pDependentClock) {
461
switch (dependentClockType) {
462
case PLL_CLOCK:
463
divider = chipcHw_divide(chipcHw_divide (desVcoHz, (*pDependentClock & chipcHw_REG_PLL_CLOCK_MDIV_MASK)), freq);
464
break;
465
case NON_PLL_CLOCK:
466
{
467
uint32_t sourceClock = 0;
468
469
if (pDependentClock == (uint32_t *) &pChipcHw->ACLKClock) {
470
sourceClock = chipcHw_getClockFrequency (chipcHw_CLOCK_BUS);
471
} else {
472
uint32_t div = *pDependentClock & chipcHw_REG_DIV_CLOCK_DIV_MASK;
473
sourceClock = chipcHw_divide (chipcHw_XTAL_FREQ_Hz, ((div) ? div : 256));
474
}
475
divider = chipcHw_divide(sourceClock, freq);
476
}
477
break;
478
}
479
} else {
480
divider = chipcHw_divide(chipcHw_XTAL_FREQ_Hz, freq);
481
}
482
483
if (divider) {
484
REG_LOCAL_IRQ_SAVE;
485
/* Set the divider to obtain the required frequency */
486
*pClockCtrl = (*pClockCtrl & (~chipcHw_REG_DIV_CLOCK_DIV_MASK)) | (((divider > 256) ? chipcHw_REG_DIV_CLOCK_DIV_256 : divider) & chipcHw_REG_DIV_CLOCK_DIV_MASK);
487
REG_LOCAL_IRQ_RESTORE;
488
return freq;
489
}
490
}
491
492
return 0;
493
}
494
495
EXPORT_SYMBOL(chipcHw_setClockFrequency);
496
497
/****************************************************************************/
498
/**
499
* @brief Set VPM clock in sync with BUS clock for Chip Rev #A0
500
*
501
* This function does the phase adjustment between VPM and BUS clock
502
*
503
* @return >= 0 : On success (# of adjustment required)
504
* -1 : On failure
505
*
506
*/
507
/****************************************************************************/
508
static int vpmPhaseAlignA0(void)
509
{
510
uint32_t phaseControl;
511
uint32_t phaseValue;
512
uint32_t prevPhaseComp;
513
int iter = 0;
514
int adjustCount = 0;
515
int count = 0;
516
517
for (iter = 0; (iter < MAX_PHASE_ALIGN_ATTEMPTS) && (adjustCount < MAX_PHASE_ADJUST_COUNT); iter++) {
518
phaseControl = (pChipcHw->VPMClock & chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT;
519
phaseValue = 0;
520
prevPhaseComp = 0;
521
522
/* Step 1: Look for falling PH_COMP transition */
523
524
/* Read the contents of VPM Clock resgister */
525
phaseValue = pChipcHw->VPMClock;
526
do {
527
/* Store previous value of phase comparator */
528
prevPhaseComp = phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP;
529
/* Change the value of PH_CTRL. */
530
reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
531
/* Wait atleast 20 ns */
532
udelay(1);
533
/* Toggle the LOAD_CH after phase control is written. */
534
pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
535
/* Read the contents of VPM Clock resgister. */
536
phaseValue = pChipcHw->VPMClock;
537
538
if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
539
phaseControl = (0x3F & (phaseControl - 1));
540
} else {
541
/* Increment to the Phase count value for next write, if Phase is not stable. */
542
phaseControl = (0x3F & (phaseControl + 1));
543
}
544
/* Count number of adjustment made */
545
adjustCount++;
546
} while (((prevPhaseComp == (phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP)) || /* Look for a transition */
547
((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) != 0x0)) && /* Look for a falling edge */
548
(adjustCount < MAX_PHASE_ADJUST_COUNT) /* Do not exceed the limit while trying */
549
);
550
551
if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
552
/* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
553
return -1;
554
}
555
556
/* Step 2: Keep moving forward to make sure falling PH_COMP transition was valid */
557
558
for (count = 0; (count < 5) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
559
phaseControl = (0x3F & (phaseControl + 1));
560
reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
561
/* Wait atleast 20 ns */
562
udelay(1);
563
/* Toggle the LOAD_CH after phase control is written. */
564
pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
565
phaseValue = pChipcHw->VPMClock;
566
/* Count number of adjustment made */
567
adjustCount++;
568
}
569
570
if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
571
/* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
572
return -1;
573
}
574
575
if (count != 5) {
576
/* Detected false transition */
577
continue;
578
}
579
580
/* Step 3: Keep moving backward to make sure falling PH_COMP transition was stable */
581
582
for (count = 0; (count < 3) && ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0); count++) {
583
phaseControl = (0x3F & (phaseControl - 1));
584
reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
585
/* Wait atleast 20 ns */
586
udelay(1);
587
/* Toggle the LOAD_CH after phase control is written. */
588
pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
589
phaseValue = pChipcHw->VPMClock;
590
/* Count number of adjustment made */
591
adjustCount++;
592
}
593
594
if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
595
/* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
596
return -1;
597
}
598
599
if (count != 3) {
600
/* Detected noisy transition */
601
continue;
602
}
603
604
/* Step 4: Keep moving backward before the original transition took place. */
605
606
for (count = 0; (count < 5); count++) {
607
phaseControl = (0x3F & (phaseControl - 1));
608
reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
609
/* Wait atleast 20 ns */
610
udelay(1);
611
/* Toggle the LOAD_CH after phase control is written. */
612
pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
613
phaseValue = pChipcHw->VPMClock;
614
/* Count number of adjustment made */
615
adjustCount++;
616
}
617
618
if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
619
/* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
620
return -1;
621
}
622
623
if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0) {
624
/* Detected false transition */
625
continue;
626
}
627
628
/* Step 5: Re discover the valid transition */
629
630
do {
631
/* Store previous value of phase comparator */
632
prevPhaseComp = phaseValue;
633
/* Change the value of PH_CTRL. */
634
reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
635
/* Wait atleast 20 ns */
636
udelay(1);
637
/* Toggle the LOAD_CH after phase control is written. */
638
pChipcHw->VPMClock ^=
639
chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
640
/* Read the contents of VPM Clock resgister. */
641
phaseValue = pChipcHw->VPMClock;
642
643
if ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) == 0x0) {
644
phaseControl = (0x3F & (phaseControl - 1));
645
} else {
646
/* Increment to the Phase count value for next write, if Phase is not stable. */
647
phaseControl = (0x3F & (phaseControl + 1));
648
}
649
650
/* Count number of adjustment made */
651
adjustCount++;
652
} while (((prevPhaseComp == (phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP)) || ((phaseValue & chipcHw_REG_PLL_CLOCK_PHASE_COMP) != 0x0)) && (adjustCount < MAX_PHASE_ADJUST_COUNT));
653
654
if (adjustCount >= MAX_PHASE_ADJUST_COUNT) {
655
/* Failed to align VPM phase after MAX_PHASE_ADJUST_COUNT tries */
656
return -1;
657
} else {
658
/* Valid phase must have detected */
659
break;
660
}
661
}
662
663
/* For VPM Phase should be perfectly aligned. */
664
phaseControl = (((pChipcHw->VPMClock >> chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT) - 1) & 0x3F);
665
{
666
REG_LOCAL_IRQ_SAVE;
667
668
pChipcHw->VPMClock = (pChipcHw->VPMClock & ~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT);
669
/* Load new phase value */
670
pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
671
672
REG_LOCAL_IRQ_RESTORE;
673
}
674
/* Return the status */
675
return (int)adjustCount;
676
}
677
678
/****************************************************************************/
679
/**
680
* @brief Set VPM clock in sync with BUS clock
681
*
682
* This function does the phase adjustment between VPM and BUS clock
683
*
684
* @return >= 0 : On success (# of adjustment required)
685
* -1 : On failure
686
*
687
*/
688
/****************************************************************************/
689
int chipcHw_vpmPhaseAlign(void)
690
{
691
692
if (chipcHw_getChipRevisionNumber() == chipcHw_REV_NUMBER_A0) {
693
return vpmPhaseAlignA0();
694
} else {
695
uint32_t phaseControl = chipcHw_getVpmPhaseControl();
696
uint32_t phaseValue = 0;
697
int adjustCount = 0;
698
699
/* Disable VPM access */
700
pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
701
/* Disable HW VPM phase alignment */
702
chipcHw_vpmHwPhaseAlignDisable();
703
/* Enable SW VPM phase alignment */
704
chipcHw_vpmSwPhaseAlignEnable();
705
/* Adjust VPM phase */
706
while (adjustCount < MAX_PHASE_ADJUST_COUNT) {
707
phaseValue = chipcHw_getVpmHwPhaseAlignStatus();
708
709
/* Adjust phase control value */
710
if (phaseValue > 0xF) {
711
/* Increment phase control value */
712
phaseControl++;
713
} else if (phaseValue < 0xF) {
714
/* Decrement phase control value */
715
phaseControl--;
716
} else {
717
/* Enable VPM access */
718
pChipcHw->Spare1 |= chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
719
/* Return adjust count */
720
return adjustCount;
721
}
722
/* Change the value of PH_CTRL. */
723
reg32_write(&pChipcHw->VPMClock, (pChipcHw->VPMClock & (~chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_MASK)) | (phaseControl << chipcHw_REG_PLL_CLOCK_PHASE_CONTROL_SHIFT));
724
/* Wait atleast 20 ns */
725
udelay(1);
726
/* Toggle the LOAD_CH after phase control is written. */
727
pChipcHw->VPMClock ^= chipcHw_REG_PLL_CLOCK_PHASE_UPDATE_ENABLE;
728
/* Count adjustment */
729
adjustCount++;
730
}
731
}
732
733
/* Disable VPM access */
734
pChipcHw->Spare1 &= ~chipcHw_REG_SPARE1_VPM_BUS_ACCESS_ENABLE;
735
return -1;
736
}
737
738
/****************************************************************************/
739
/**
740
* @brief Local Divide function
741
*
742
* This function does the divide
743
*
744
* @return divide value
745
*
746
*/
747
/****************************************************************************/
748
static int chipcHw_divide(int num, int denom)
749
{
750
int r;
751
int t = 1;
752
753
/* Shift denom and t up to the largest value to optimize algorithm */
754
/* t contains the units of each divide */
755
while ((denom & 0x40000000) == 0) { /* fails if denom=0 */
756
denom = denom << 1;
757
t = t << 1;
758
}
759
760
/* Initialize the result */
761
r = 0;
762
763
do {
764
/* Determine if there exists a positive remainder */
765
if ((num - denom) >= 0) {
766
/* Accumlate t to the result and calculate a new remainder */
767
num = num - denom;
768
r = r + t;
769
}
770
/* Continue to shift denom and shift t down to 0 */
771
denom = denom >> 1;
772
t = t >> 1;
773
} while (t != 0);
774
775
return r;
776
}
777
778