aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-bcmring/csp
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-bcmring/csp')
-rw-r--r--arch/arm/mach-bcmring/csp/Makefile3
-rw-r--r--arch/arm/mach-bcmring/csp/chipc/Makefile1
-rw-r--r--arch/arm/mach-bcmring/csp/chipc/chipcHw.c776
-rw-r--r--arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c293
-rw-r--r--arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c124
-rw-r--r--arch/arm/mach-bcmring/csp/chipc/chipcHw_str.c64
-rw-r--r--arch/arm/mach-bcmring/csp/dmac/Makefile1
-rw-r--r--arch/arm/mach-bcmring/csp/dmac/dmacHw.c917
-rw-r--r--arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c1017
-rw-r--r--arch/arm/mach-bcmring/csp/tmr/Makefile1
-rw-r--r--arch/arm/mach-bcmring/csp/tmr/tmrHw.c576
11 files changed, 3773 insertions, 0 deletions
diff --git a/arch/arm/mach-bcmring/csp/Makefile b/arch/arm/mach-bcmring/csp/Makefile
new file mode 100644
index 00000000000..648c0377530
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/Makefile
@@ -0,0 +1,3 @@
1obj-y += dmac/
2obj-y += tmr/
3obj-y += chipc/
diff --git a/arch/arm/mach-bcmring/csp/chipc/Makefile b/arch/arm/mach-bcmring/csp/chipc/Makefile
new file mode 100644
index 00000000000..673952768ee
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/chipc/Makefile
@@ -0,0 +1 @@
obj-y += chipcHw.o chipcHw_str.o chipcHw_reset.o chipcHw_init.o
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
new file mode 100644
index 00000000000..96273ff3495
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw.c
@@ -0,0 +1,776 @@
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
49static 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/****************************************************************************/
62chipcHw_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/****************************************************************************/
261chipcHw_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
495EXPORT_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/****************************************************************************/
508static 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/****************************************************************************/
689int 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/****************************************************************************/
748static 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}
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
new file mode 100644
index 00000000000..367df75d4bb
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_init.c
@@ -0,0 +1,293 @@
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_init.c
18*
19* @brief Low level CHIPC PLL configuration functions
20*
21* @note
22*
23* These routines provide basic PLL 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/* ---- Private Constants and Types --------------------------------------- */
39
40/*
41 Calculation for NDIV_i to obtain VCO frequency
42 -----------------------------------------------
43
44 Freq_vco = Freq_ref * (P2 / P1) * (PLL_NDIV_i + PLL_NDIV_f)
45 for Freq_vco = VCO_FREQ_MHz
46 Freq_ref = chipcHw_XTAL_FREQ_Hz
47 PLL_P1 = PLL_P2 = 1
48 and
49 PLL_NDIV_f = 0
50
51 We get:
52 PLL_NDIV_i = Freq_vco / Freq_ref = VCO_FREQ_MHz / chipcHw_XTAL_FREQ_Hz
53
54 Calculation for PLL MDIV to obtain frequency Freq_x for channel x
55 -----------------------------------------------------------------
56 Freq_x = chipcHw_XTAL_FREQ_Hz * PLL_NDIV_i / PLL_MDIV_x = VCO_FREQ_MHz / PLL_MDIV_x
57
58 PLL_MDIV_x = VCO_FREQ_MHz / Freq_x
59*/
60
61/* ---- Private Variables ------------------------------------------------- */
62/****************************************************************************/
63/**
64* @brief Initializes the PLL2
65*
66* This function initializes the PLL2
67*
68*/
69/****************************************************************************/
70void chipcHw_pll2Enable(uint32_t vcoFreqHz)
71{
72 uint32_t pllPreDivider2 = 0;
73
74 {
75 REG_LOCAL_IRQ_SAVE;
76 pChipcHw->PLLConfig2 =
77 chipcHw_REG_PLL_CONFIG_D_RESET |
78 chipcHw_REG_PLL_CONFIG_A_RESET;
79
80 pllPreDivider2 = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
81 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
82 (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) <<
83 chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
84 (chipcHw_REG_PLL_PREDIVIDER_P1 <<
85 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
86 (chipcHw_REG_PLL_PREDIVIDER_P2 <<
87 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
88
89 /* Enable CHIPC registers to control the PLL */
90 pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
91
92 /* Set pre divider to get desired VCO frequency */
93 pChipcHw->PLLPreDivider2 = pllPreDivider2;
94 /* Set NDIV Frac */
95 pChipcHw->PLLDivider2 = chipcHw_REG_PLL_DIVIDER_NDIV_f;
96
97 /* This has to be removed once the default values are fixed for PLL2. */
98 pChipcHw->PLLControl12 = 0x38000700;
99 pChipcHw->PLLControl22 = 0x00000015;
100
101 /* Reset PLL2 */
102 if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
103 pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
104 chipcHw_REG_PLL_CONFIG_A_RESET |
105 chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
106 chipcHw_REG_PLL_CONFIG_POWER_DOWN;
107 } else {
108 pChipcHw->PLLConfig2 = chipcHw_REG_PLL_CONFIG_D_RESET |
109 chipcHw_REG_PLL_CONFIG_A_RESET |
110 chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
111 chipcHw_REG_PLL_CONFIG_POWER_DOWN;
112 }
113 REG_LOCAL_IRQ_RESTORE;
114 }
115
116 /* Insert certain amount of delay before deasserting ARESET. */
117 udelay(1);
118
119 {
120 REG_LOCAL_IRQ_SAVE;
121 /* Remove analog reset and Power on the PLL */
122 pChipcHw->PLLConfig2 &=
123 ~(chipcHw_REG_PLL_CONFIG_A_RESET |
124 chipcHw_REG_PLL_CONFIG_POWER_DOWN);
125
126 REG_LOCAL_IRQ_RESTORE;
127
128 }
129
130 /* Wait until PLL is locked */
131 while (!(pChipcHw->PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
132 ;
133
134 {
135 REG_LOCAL_IRQ_SAVE;
136 /* Remove digital reset */
137 pChipcHw->PLLConfig2 &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
138
139 REG_LOCAL_IRQ_RESTORE;
140 }
141}
142
143EXPORT_SYMBOL(chipcHw_pll2Enable);
144
145/****************************************************************************/
146/**
147* @brief Initializes the PLL1
148*
149* This function initializes the PLL1
150*
151*/
152/****************************************************************************/
153void chipcHw_pll1Enable(uint32_t vcoFreqHz, chipcHw_SPREAD_SPECTRUM_e ssSupport)
154{
155 uint32_t pllPreDivider = 0;
156
157 {
158 REG_LOCAL_IRQ_SAVE;
159
160 pChipcHw->PLLConfig =
161 chipcHw_REG_PLL_CONFIG_D_RESET |
162 chipcHw_REG_PLL_CONFIG_A_RESET;
163 /* Setting VCO frequency */
164 if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
165 pllPreDivider =
166 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_MASH_1_8 |
167 ((chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) -
168 1) << chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
169 (chipcHw_REG_PLL_PREDIVIDER_P1 <<
170 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
171 (chipcHw_REG_PLL_PREDIVIDER_P2 <<
172 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
173 } else {
174 pllPreDivider = chipcHw_REG_PLL_PREDIVIDER_POWER_DOWN |
175 chipcHw_REG_PLL_PREDIVIDER_NDIV_MODE_INTEGER |
176 (chipcHw_REG_PLL_PREDIVIDER_NDIV_i(vcoFreqHz) <<
177 chipcHw_REG_PLL_PREDIVIDER_NDIV_SHIFT) |
178 (chipcHw_REG_PLL_PREDIVIDER_P1 <<
179 chipcHw_REG_PLL_PREDIVIDER_P1_SHIFT) |
180 (chipcHw_REG_PLL_PREDIVIDER_P2 <<
181 chipcHw_REG_PLL_PREDIVIDER_P2_SHIFT);
182 }
183
184 /* Enable CHIPC registers to control the PLL */
185 pChipcHw->PLLStatus |= chipcHw_REG_PLL_STATUS_CONTROL_ENABLE;
186
187 /* Set pre divider to get desired VCO frequency */
188 pChipcHw->PLLPreDivider = pllPreDivider;
189 /* Set NDIV Frac */
190 if (ssSupport == chipcHw_SPREAD_SPECTRUM_ALLOW) {
191 pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
192 chipcHw_REG_PLL_DIVIDER_NDIV_f_SS;
193 } else {
194 pChipcHw->PLLDivider = chipcHw_REG_PLL_DIVIDER_M1DIV |
195 chipcHw_REG_PLL_DIVIDER_NDIV_f;
196 }
197
198 /* Reset PLL1 */
199 if (vcoFreqHz > chipcHw_REG_PLL_CONFIG_VCO_SPLIT_FREQ) {
200 pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
201 chipcHw_REG_PLL_CONFIG_A_RESET |
202 chipcHw_REG_PLL_CONFIG_VCO_1601_3200 |
203 chipcHw_REG_PLL_CONFIG_POWER_DOWN;
204 } else {
205 pChipcHw->PLLConfig = chipcHw_REG_PLL_CONFIG_D_RESET |
206 chipcHw_REG_PLL_CONFIG_A_RESET |
207 chipcHw_REG_PLL_CONFIG_VCO_800_1600 |
208 chipcHw_REG_PLL_CONFIG_POWER_DOWN;
209 }
210
211 REG_LOCAL_IRQ_RESTORE;
212
213 /* Insert certain amount of delay before deasserting ARESET. */
214 udelay(1);
215
216 {
217 REG_LOCAL_IRQ_SAVE;
218 /* Remove analog reset and Power on the PLL */
219 pChipcHw->PLLConfig &=
220 ~(chipcHw_REG_PLL_CONFIG_A_RESET |
221 chipcHw_REG_PLL_CONFIG_POWER_DOWN);
222 REG_LOCAL_IRQ_RESTORE;
223 }
224
225 /* Wait until PLL is locked */
226 while (!(pChipcHw->PLLStatus & chipcHw_REG_PLL_STATUS_LOCKED)
227 || !(pChipcHw->
228 PLLStatus2 & chipcHw_REG_PLL_STATUS_LOCKED))
229 ;
230
231 /* Remove digital reset */
232 {
233 REG_LOCAL_IRQ_SAVE;
234 pChipcHw->PLLConfig &= ~chipcHw_REG_PLL_CONFIG_D_RESET;
235 REG_LOCAL_IRQ_RESTORE;
236 }
237 }
238}
239
240EXPORT_SYMBOL(chipcHw_pll1Enable);
241
242/****************************************************************************/
243/**
244* @brief Initializes the chipc module
245*
246* This function initializes the PLLs and core system clocks
247*
248*/
249/****************************************************************************/
250
251void chipcHw_Init(chipcHw_INIT_PARAM_t *initParam /* [ IN ] Misc chip initialization parameter */
252 ) {
253#if !(defined(__KERNEL__) && !defined(STANDALONE))
254 delay_init();
255#endif
256
257 /* Do not program PLL, when warm reset */
258 if (!(chipcHw_getStickyBits() & chipcHw_REG_STICKY_CHIP_WARM_RESET)) {
259 chipcHw_pll1Enable(initParam->pllVcoFreqHz,
260 initParam->ssSupport);
261 chipcHw_pll2Enable(initParam->pll2VcoFreqHz);
262 } else {
263 /* Clear sticky bits */
264 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_WARM_RESET);
265 }
266 /* Clear sticky bits */
267 chipcHw_clearStickyBits(chipcHw_REG_STICKY_CHIP_SOFT_RESET);
268
269 /* Before configuring the ARM clock, atleast we need to make sure BUS clock maintains the proper ratio with ARM clock */
270 pChipcHw->ACLKClock =
271 (pChipcHw->
272 ACLKClock & ~chipcHw_REG_ACLKClock_CLK_DIV_MASK) | (initParam->
273 armBusRatio &
274 chipcHw_REG_ACLKClock_CLK_DIV_MASK);
275
276 /* Set various core component frequencies. The order in which this is done is important for some. */
277 /* The RTBUS (DDR PHY) is derived from the BUS, and the BUS from the ARM, and VPM needs to know BUS */
278 /* frequency to find its ratio with the BUS. Hence we must set the ARM first, followed by the BUS, */
279 /* then VPM and RTBUS. */
280
281 chipcHw_setClockFrequency(chipcHw_CLOCK_ARM,
282 initParam->busClockFreqHz *
283 initParam->armBusRatio);
284 chipcHw_setClockFrequency(chipcHw_CLOCK_BUS, initParam->busClockFreqHz);
285 chipcHw_setClockFrequency(chipcHw_CLOCK_VPM,
286 initParam->busClockFreqHz *
287 initParam->vpmBusRatio);
288 chipcHw_setClockFrequency(chipcHw_CLOCK_DDR,
289 initParam->busClockFreqHz *
290 initParam->ddrBusRatio);
291 chipcHw_setClockFrequency(chipcHw_CLOCK_RTBUS,
292 initParam->busClockFreqHz / 2);
293}
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
new file mode 100644
index 00000000000..2671d8896bb
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_reset.c
@@ -0,0 +1,124 @@
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/* ---- Include Files ---------------------------------------------------- */
16#include <csp/stdint.h>
17#include <mach/csp/chipcHw_def.h>
18#include <mach/csp/chipcHw_inline.h>
19#include <csp/intcHw.h>
20#include <csp/cache.h>
21
22/* ---- Private Constants and Types --------------------------------------- */
23/* ---- Private Variables ------------------------------------------------- */
24void chipcHw_reset_run_from_aram(void);
25
26typedef void (*RUNFUNC) (void);
27
28/****************************************************************************/
29/**
30* @brief warmReset
31*
32* @note warmReset configures the clocks which are not reset back to the state
33* required to execute on reset. To do so we need to copy the code into internal
34* memory to change the ARM clock while we are not executing from DDR.
35*/
36/****************************************************************************/
37void chipcHw_reset(uint32_t mask)
38{
39 int i = 0;
40 RUNFUNC runFunc = (RUNFUNC) (unsigned long)MM_ADDR_IO_ARAM;
41
42 /* Disable all interrupts */
43 intcHw_irq_disable(INTCHW_INTC0, 0xffffffff);
44 intcHw_irq_disable(INTCHW_INTC1, 0xffffffff);
45 intcHw_irq_disable(INTCHW_SINTC, 0xffffffff);
46
47 {
48 REG_LOCAL_IRQ_SAVE;
49 if (mask & chipcHw_REG_SOFT_RESET_CHIP_SOFT) {
50 chipcHw_softReset(chipcHw_REG_SOFT_RESET_CHIP_SOFT);
51 }
52 /* Bypass the PLL clocks before reboot */
53 pChipcHw->UARTClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
54 pChipcHw->SPIClock |= chipcHw_REG_PLL_CLOCK_BYPASS_SELECT;
55
56 /* Copy the chipcHw_warmReset_run_from_aram function into ARAM */
57 do {
58 ((uint32_t *) MM_IO_BASE_ARAM)[i] =
59 ((uint32_t *) &chipcHw_reset_run_from_aram)[i];
60 i++;
61 } while (((uint32_t *) MM_IO_BASE_ARAM)[i - 1] != 0xe1a0f00f); /* 0xe1a0f00f == asm ("mov r15, r15"); */
62
63 CSP_CACHE_FLUSH_ALL;
64
65 /* run the function from ARAM */
66 runFunc();
67
68 /* Code will never get here, but include it to balance REG_LOCAL_IRQ_SAVE above */
69 REG_LOCAL_IRQ_RESTORE;
70 }
71}
72
73/* This function must run from internal memory */
74void chipcHw_reset_run_from_aram(void)
75{
76/* Make sure, pipeline is filled with instructions coming from ARAM */
77__asm (" nop \n\t"
78 " nop \n\t"
79#if defined(__KERNEL__) && !defined(STANDALONE)
80 " MRC p15,#0x0,r0,c1,c0,#0 \n\t"
81 " BIC r0,r0,#0xd \n\t"
82 " MCR p15,#0x0,r0,c1,c0,#0 \n\t"
83 " nop \n\t"
84 " nop \n\t"
85 " nop \n\t"
86 " nop \n\t"
87 " nop \n\t"
88 " nop \n\t"
89#endif
90 " nop \n\t"
91 " nop \n\t"
92/* Bypass the ARM clock and switch to XTAL clock */
93 " MOV r2,#0x80000000 \n\t"
94 " LDR r3,[r2,#8] \n\t"
95 " ORR r3,r3,#0x20000 \n\t"
96 " STR r3,[r2,#8] \n\t"
97
98 " nop \n\t"
99 " nop \n\t"
100 " nop \n\t"
101 " nop \n\t"
102 " nop \n\t"
103 " nop \n\t"
104 " nop \n\t"
105 " nop \n\t"
106 " nop \n\t"
107 " nop \n\t"
108 " nop \n\t"
109 " nop \n\t"
110 " nop \n\t"
111 " nop \n\t"
112 " nop \n\t"
113 " nop \n\t"
114 " nop \n\t"
115 " nop \n\t"
116 " nop \n\t"
117 " nop \n\t"
118/* Issue reset */
119 " MOV r3,#0x2 \n\t"
120 " STR r3,[r2,#0x80] \n\t"
121/* End here */
122 " MOV pc,pc \n\t");
123/* 0xe1a0f00f == asm ("mov r15, r15"); */
124}
diff --git a/arch/arm/mach-bcmring/csp/chipc/chipcHw_str.c b/arch/arm/mach-bcmring/csp/chipc/chipcHw_str.c
new file mode 100644
index 00000000000..54ad964fe94
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/chipc/chipcHw_str.c
@@ -0,0 +1,64 @@
1/*****************************************************************************
2* Copyright 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* @file chipcHw_str.c
17*
18* @brief Contains strings which are useful to linux and csp
19*
20* @note
21*/
22/****************************************************************************/
23
24/* ---- Include Files ---------------------------------------------------- */
25
26#include <mach/csp/chipcHw_inline.h>
27
28/* ---- Private Constants and Types --------------------------------------- */
29
30static const char *gMuxStr[] = {
31 "GPIO", /* 0 */
32 "KeyPad", /* 1 */
33 "I2C-Host", /* 2 */
34 "SPI", /* 3 */
35 "Uart", /* 4 */
36 "LED-Mtx-P", /* 5 */
37 "LED-Mtx-S", /* 6 */
38 "SDIO-0", /* 7 */
39 "SDIO-1", /* 8 */
40 "PCM", /* 9 */
41 "I2S", /* 10 */
42 "ETM", /* 11 */
43 "Debug", /* 12 */
44 "Misc", /* 13 */
45 "0xE", /* 14 */
46 "0xF", /* 15 */
47};
48
49/****************************************************************************/
50/**
51* @brief Retrieves a string representation of the mux setting for a pin.
52*
53* @return Pointer to a character string.
54*/
55/****************************************************************************/
56
57const char *chipcHw_getGpioPinFunctionStr(int pin)
58{
59 if ((pin < 0) || (pin >= chipcHw_GPIO_COUNT)) {
60 return "";
61 }
62
63 return gMuxStr[chipcHw_getGpioPinFunction(pin)];
64}
diff --git a/arch/arm/mach-bcmring/csp/dmac/Makefile b/arch/arm/mach-bcmring/csp/dmac/Makefile
new file mode 100644
index 00000000000..fb1104fe56b
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/dmac/Makefile
@@ -0,0 +1 @@
obj-y += dmacHw.o dmacHw_extra.o \ No newline at end of file
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
new file mode 100644
index 00000000000..6b9be2e98e5
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw.c
@@ -0,0 +1,917 @@
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 dmacHw.c
18*
19* @brief Low level DMA controller driver routines
20*
21* @note
22*
23* These routines provide basic DMA functionality only.
24*/
25/****************************************************************************/
26
27/* ---- Include Files ---------------------------------------------------- */
28#include <csp/stdint.h>
29#include <csp/string.h>
30#include <stddef.h>
31
32#include <csp/dmacHw.h>
33#include <mach/csp/dmacHw_reg.h>
34#include <mach/csp/dmacHw_priv.h>
35#include <mach/csp/chipcHw_inline.h>
36
37/* ---- External Function Prototypes ------------------------------------- */
38
39/* Allocate DMA control blocks */
40dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT];
41
42uint32_t dmaChannelCount_0 = dmacHw_MAX_CHANNEL_COUNT / 2;
43uint32_t dmaChannelCount_1 = dmacHw_MAX_CHANNEL_COUNT / 2;
44
45/****************************************************************************/
46/**
47* @brief Get maximum FIFO for a DMA channel
48*
49* @return Maximum allowable FIFO size
50*
51*
52*/
53/****************************************************************************/
54static uint32_t GetFifoSize(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
55 ) {
56 uint32_t val = 0;
57 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
58 dmacHw_MISC_t *pMiscReg =
59 (dmacHw_MISC_t *) dmacHw_REG_MISC_BASE(pCblk->module);
60
61 switch (pCblk->channel) {
62 case 0:
63 val = (pMiscReg->CompParm2.lo & 0x70000000) >> 28;
64 break;
65 case 1:
66 val = (pMiscReg->CompParm3.hi & 0x70000000) >> 28;
67 break;
68 case 2:
69 val = (pMiscReg->CompParm3.lo & 0x70000000) >> 28;
70 break;
71 case 3:
72 val = (pMiscReg->CompParm4.hi & 0x70000000) >> 28;
73 break;
74 case 4:
75 val = (pMiscReg->CompParm4.lo & 0x70000000) >> 28;
76 break;
77 case 5:
78 val = (pMiscReg->CompParm5.hi & 0x70000000) >> 28;
79 break;
80 case 6:
81 val = (pMiscReg->CompParm5.lo & 0x70000000) >> 28;
82 break;
83 case 7:
84 val = (pMiscReg->CompParm6.hi & 0x70000000) >> 28;
85 break;
86 }
87
88 if (val <= 0x4) {
89 return 8 << val;
90 } else {
91 dmacHw_ASSERT(0);
92 }
93 return 0;
94}
95
96/****************************************************************************/
97/**
98* @brief Program channel register to initiate transfer
99*
100* @return void
101*
102*
103* @note
104* - Descriptor buffer MUST ALWAYS be flushed before calling this function
105* - This function should also be called from ISR to program the channel with
106* pending descriptors
107*/
108/****************************************************************************/
109void dmacHw_initiateTransfer(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
110 dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
111 void *pDescriptor /* [ IN ] Descriptor buffer */
112 ) {
113 dmacHw_DESC_RING_t *pRing;
114 dmacHw_DESC_t *pProg;
115 dmacHw_CBLK_t *pCblk;
116
117 pCblk = dmacHw_HANDLE_TO_CBLK(handle);
118 pRing = dmacHw_GET_DESC_RING(pDescriptor);
119
120 if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
121 /* Not safe yet to program the channel */
122 return;
123 }
124
125 if (pCblk->varDataStarted) {
126 if (pCblk->descUpdated) {
127 pCblk->descUpdated = 0;
128 pProg =
129 (dmacHw_DESC_t *) ((uint32_t)
130 dmacHw_REG_LLP(pCblk->module,
131 pCblk->channel) +
132 pRing->virt2PhyOffset);
133
134 /* Load descriptor if not loaded */
135 if (!(pProg->ctl.hi & dmacHw_REG_CTL_DONE)) {
136 dmacHw_SET_SAR(pCblk->module, pCblk->channel,
137 pProg->sar);
138 dmacHw_SET_DAR(pCblk->module, pCblk->channel,
139 pProg->dar);
140 dmacHw_REG_CTL_LO(pCblk->module,
141 pCblk->channel) =
142 pProg->ctl.lo;
143 dmacHw_REG_CTL_HI(pCblk->module,
144 pCblk->channel) =
145 pProg->ctl.hi;
146 } else if (pProg == (dmacHw_DESC_t *) pRing->pEnd->llp) {
147 /* Return as end descriptor is processed */
148 return;
149 } else {
150 dmacHw_ASSERT(0);
151 }
152 } else {
153 return;
154 }
155 } else {
156 if (pConfig->transferMode == dmacHw_TRANSFER_MODE_PERIODIC) {
157 /* Do not make a single chain, rather process one descriptor at a time */
158 pProg = pRing->pHead;
159 /* Point to the next descriptor for next iteration */
160 dmacHw_NEXT_DESC(pRing, pHead);
161 } else {
162 /* Return if no more pending descriptor */
163 if (pRing->pEnd == NULL) {
164 return;
165 }
166
167 pProg = pRing->pProg;
168 if (pConfig->transferMode ==
169 dmacHw_TRANSFER_MODE_CONTINUOUS) {
170 /* Make sure a complete ring can be formed */
171 dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pEnd->
172 llp == pRing->pProg);
173 /* Make sure pProg pointing to the pHead */
174 dmacHw_ASSERT((dmacHw_DESC_t *) pRing->pProg ==
175 pRing->pHead);
176 /* Make a complete ring */
177 do {
178 pRing->pProg->ctl.lo |=
179 (dmacHw_REG_CTL_LLP_DST_EN |
180 dmacHw_REG_CTL_LLP_SRC_EN);
181 pRing->pProg =
182 (dmacHw_DESC_t *) pRing->pProg->llp;
183 } while (pRing->pProg != pRing->pHead);
184 } else {
185 /* Make a single long chain */
186 while (pRing->pProg != pRing->pEnd) {
187 pRing->pProg->ctl.lo |=
188 (dmacHw_REG_CTL_LLP_DST_EN |
189 dmacHw_REG_CTL_LLP_SRC_EN);
190 pRing->pProg =
191 (dmacHw_DESC_t *) pRing->pProg->llp;
192 }
193 }
194 }
195
196 /* Program the channel registers */
197 dmacHw_SET_SAR(pCblk->module, pCblk->channel, pProg->sar);
198 dmacHw_SET_DAR(pCblk->module, pCblk->channel, pProg->dar);
199 dmacHw_SET_LLP(pCblk->module, pCblk->channel,
200 (uint32_t) pProg - pRing->virt2PhyOffset);
201 dmacHw_REG_CTL_LO(pCblk->module, pCblk->channel) =
202 pProg->ctl.lo;
203 dmacHw_REG_CTL_HI(pCblk->module, pCblk->channel) =
204 pProg->ctl.hi;
205 if (pRing->pEnd) {
206 /* Remember the descriptor to use next */
207 pRing->pProg = (dmacHw_DESC_t *) pRing->pEnd->llp;
208 }
209 /* Indicate no more pending descriptor */
210 pRing->pEnd = (dmacHw_DESC_t *) NULL;
211 }
212 /* Start DMA operation */
213 dmacHw_DMA_START(pCblk->module, pCblk->channel);
214}
215
216/****************************************************************************/
217/**
218* @brief Initializes DMA
219*
220* This function initializes DMA CSP driver
221*
222* @note
223* Must be called before using any DMA channel
224*/
225/****************************************************************************/
226void dmacHw_initDma(void)
227{
228
229 uint32_t i = 0;
230
231 dmaChannelCount_0 = dmacHw_GET_NUM_CHANNEL(0);
232 dmaChannelCount_1 = dmacHw_GET_NUM_CHANNEL(1);
233
234 /* Enable access to the DMA block */
235 chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC0);
236 chipcHw_busInterfaceClockEnable(chipcHw_REG_BUS_CLOCK_DMAC1);
237
238 if ((dmaChannelCount_0 + dmaChannelCount_1) > dmacHw_MAX_CHANNEL_COUNT) {
239 dmacHw_ASSERT(0);
240 }
241
242 memset((void *)dmacHw_gCblk, 0,
243 sizeof(dmacHw_CBLK_t) * (dmaChannelCount_0 + dmaChannelCount_1));
244 for (i = 0; i < dmaChannelCount_0; i++) {
245 dmacHw_gCblk[i].module = 0;
246 dmacHw_gCblk[i].channel = i;
247 }
248 for (i = 0; i < dmaChannelCount_1; i++) {
249 dmacHw_gCblk[i + dmaChannelCount_0].module = 1;
250 dmacHw_gCblk[i + dmaChannelCount_0].channel = i;
251 }
252}
253
254/****************************************************************************/
255/**
256* @brief Exit function for DMA
257*
258* This function isolates DMA from the system
259*
260*/
261/****************************************************************************/
262void dmacHw_exitDma(void)
263{
264 /* Disable access to the DMA block */
265 chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC0);
266 chipcHw_busInterfaceClockDisable(chipcHw_REG_BUS_CLOCK_DMAC1);
267}
268
269/****************************************************************************/
270/**
271* @brief Gets a handle to a DMA channel
272*
273* This function returns a handle, representing a control block of a particular DMA channel
274*
275* @return -1 - On Failure
276* handle - On Success, representing a channel control block
277*
278* @note
279* None Channel ID must be created using "dmacHw_MAKE_CHANNEL_ID" macro
280*/
281/****************************************************************************/
282dmacHw_HANDLE_t dmacHw_getChannelHandle(dmacHw_ID_t channelId /* [ IN ] DMA Channel Id */
283 ) {
284 int idx;
285
286 switch ((channelId >> 8)) {
287 case 0:
288 dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_0);
289 idx = (channelId & 0xff);
290 break;
291 case 1:
292 dmacHw_ASSERT((channelId & 0xff) < dmaChannelCount_1);
293 idx = dmaChannelCount_0 + (channelId & 0xff);
294 break;
295 default:
296 dmacHw_ASSERT(0);
297 return (dmacHw_HANDLE_t) -1;
298 }
299
300 return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[idx]);
301}
302
303/****************************************************************************/
304/**
305* @brief Initializes a DMA channel for use
306*
307* This function initializes and resets a DMA channel for use
308*
309* @return -1 - On Failure
310* 0 - On Success
311*
312* @note
313* None
314*/
315/****************************************************************************/
316int dmacHw_initChannel(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
317 ) {
318 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
319 int module = pCblk->module;
320 int channel = pCblk->channel;
321
322 /* Reinitialize the control block */
323 memset((void *)pCblk, 0, sizeof(dmacHw_CBLK_t));
324 pCblk->module = module;
325 pCblk->channel = channel;
326
327 /* Enable DMA controller */
328 dmacHw_DMA_ENABLE(pCblk->module);
329 /* Reset DMA channel */
330 dmacHw_RESET_CONTROL_LO(pCblk->module, pCblk->channel);
331 dmacHw_RESET_CONTROL_HI(pCblk->module, pCblk->channel);
332 dmacHw_RESET_CONFIG_LO(pCblk->module, pCblk->channel);
333 dmacHw_RESET_CONFIG_HI(pCblk->module, pCblk->channel);
334
335 /* Clear all raw interrupt status */
336 dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
337 dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
338 dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
339
340 /* Mask event specific interrupts */
341 dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
342 dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
343 dmacHw_STRAN_INT_DISABLE(pCblk->module, pCblk->channel);
344 dmacHw_DTRAN_INT_DISABLE(pCblk->module, pCblk->channel);
345 dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
346
347 return 0;
348}
349
350/****************************************************************************/
351/**
352* @brief Finds amount of memory required to form a descriptor ring
353*
354*
355* @return Number of bytes required to form a descriptor ring
356*
357*
358*/
359/****************************************************************************/
360uint32_t dmacHw_descriptorLen(uint32_t descCnt /* [ IN ] Number of descriptor in the ring */
361 ) {
362 /* Need extra 4 byte to ensure 32 bit alignment */
363 return (descCnt * sizeof(dmacHw_DESC_t)) + sizeof(dmacHw_DESC_RING_t) +
364 sizeof(uint32_t);
365}
366
367/****************************************************************************/
368/**
369* @brief Initializes descriptor ring
370*
371* This function will initializes the descriptor ring of a DMA channel
372*
373*
374* @return -1 - On failure
375* 0 - On success
376* @note
377* - "len" parameter should be obtained from "dmacHw_descriptorLen"
378* - Descriptor buffer MUST be 32 bit aligned and uncached as it is
379* accessed by ARM and DMA
380*/
381/****************************************************************************/
382int dmacHw_initDescriptor(void *pDescriptorVirt, /* [ IN ] Virtual address of uncahced buffer allocated to form descriptor ring */
383 uint32_t descriptorPhyAddr, /* [ IN ] Physical address of pDescriptorVirt (descriptor buffer) */
384 uint32_t len, /* [ IN ] Size of the pBuf */
385 uint32_t num /* [ IN ] Number of descriptor in the ring */
386 ) {
387 uint32_t i;
388 dmacHw_DESC_RING_t *pRing;
389 dmacHw_DESC_t *pDesc;
390
391 /* Check the alignment of the descriptor */
392 if ((uint32_t) pDescriptorVirt & 0x00000003) {
393 dmacHw_ASSERT(0);
394 return -1;
395 }
396
397 /* Check if enough space has been allocated for descriptor ring */
398 if (len < dmacHw_descriptorLen(num)) {
399 return -1;
400 }
401
402 pRing = dmacHw_GET_DESC_RING(pDescriptorVirt);
403 pRing->pHead =
404 (dmacHw_DESC_t *) ((uint32_t) pRing + sizeof(dmacHw_DESC_RING_t));
405 pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
406 pRing->pProg = dmacHw_DESC_INIT;
407 /* Initialize link item chain, starting from the head */
408 pDesc = pRing->pHead;
409 /* Find the offset between virtual to physical address */
410 pRing->virt2PhyOffset = (uint32_t) pDescriptorVirt - descriptorPhyAddr;
411
412 /* Form the descriptor ring */
413 for (i = 0; i < num - 1; i++) {
414 /* Clear link list item */
415 memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
416 /* Point to the next item in the physical address */
417 pDesc->llpPhy = (uint32_t) (pDesc + 1) - pRing->virt2PhyOffset;
418 /* Point to the next item in the virtual address */
419 pDesc->llp = (uint32_t) (pDesc + 1);
420 /* Mark descriptor is ready to use */
421 pDesc->ctl.hi = dmacHw_DESC_FREE;
422 /* Look into next link list item */
423 pDesc++;
424 }
425
426 /* Clear last link list item */
427 memset((void *)pDesc, 0, sizeof(dmacHw_DESC_t));
428 /* Last item pointing to the first item in the
429 physical address to complete the ring */
430 pDesc->llpPhy = (uint32_t) pRing->pHead - pRing->virt2PhyOffset;
431 /* Last item pointing to the first item in the
432 virtual address to complete the ring
433 */
434 pDesc->llp = (uint32_t) pRing->pHead;
435 /* Mark descriptor is ready to use */
436 pDesc->ctl.hi = dmacHw_DESC_FREE;
437 /* Set the number of descriptors in the ring */
438 pRing->num = num;
439 return 0;
440}
441
442/****************************************************************************/
443/**
444* @brief Configure DMA channel
445*
446* @return 0 : On success
447* -1 : On failure
448*/
449/****************************************************************************/
450int dmacHw_configChannel(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
451 dmacHw_CONFIG_t *pConfig /* [ IN ] Configuration settings */
452 ) {
453 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
454 uint32_t cfgHigh = 0;
455 int srcTrSize;
456 int dstTrSize;
457
458 pCblk->varDataStarted = 0;
459 pCblk->userData = NULL;
460
461 /* Configure
462 - Burst transaction when enough data in available in FIFO
463 - AHB Access protection 1
464 - Source and destination peripheral ports
465 */
466 cfgHigh =
467 dmacHw_REG_CFG_HI_FIFO_ENOUGH | dmacHw_REG_CFG_HI_AHB_HPROT_1 |
468 dmacHw_SRC_PERI_INTF(pConfig->
469 srcPeripheralPort) |
470 dmacHw_DST_PERI_INTF(pConfig->dstPeripheralPort);
471 /* Set priority */
472 dmacHw_SET_CHANNEL_PRIORITY(pCblk->module, pCblk->channel,
473 pConfig->channelPriority);
474
475 if (pConfig->dstStatusRegisterAddress != 0) {
476 /* Destination status update enable */
477 cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_DST_STAT;
478 /* Configure status registers */
479 dmacHw_SET_DSTATAR(pCblk->module, pCblk->channel,
480 pConfig->dstStatusRegisterAddress);
481 }
482
483 if (pConfig->srcStatusRegisterAddress != 0) {
484 /* Source status update enable */
485 cfgHigh |= dmacHw_REG_CFG_HI_UPDATE_SRC_STAT;
486 /* Source status update enable */
487 dmacHw_SET_SSTATAR(pCblk->module, pCblk->channel,
488 pConfig->srcStatusRegisterAddress);
489 }
490 /* Configure the config high register */
491 dmacHw_GET_CONFIG_HI(pCblk->module, pCblk->channel) = cfgHigh;
492
493 /* Clear all raw interrupt status */
494 dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
495 dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
496 dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
497
498 /* Configure block interrupt */
499 if (pConfig->blockTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
500 dmacHw_BLOCK_INT_ENABLE(pCblk->module, pCblk->channel);
501 } else {
502 dmacHw_BLOCK_INT_DISABLE(pCblk->module, pCblk->channel);
503 }
504 /* Configure complete transfer interrupt */
505 if (pConfig->completeTransferInterrupt == dmacHw_INTERRUPT_ENABLE) {
506 dmacHw_TRAN_INT_ENABLE(pCblk->module, pCblk->channel);
507 } else {
508 dmacHw_TRAN_INT_DISABLE(pCblk->module, pCblk->channel);
509 }
510 /* Configure error interrupt */
511 if (pConfig->errorInterrupt == dmacHw_INTERRUPT_ENABLE) {
512 dmacHw_ERROR_INT_ENABLE(pCblk->module, pCblk->channel);
513 } else {
514 dmacHw_ERROR_INT_DISABLE(pCblk->module, pCblk->channel);
515 }
516 /* Configure gather register */
517 if (pConfig->srcGatherWidth) {
518 srcTrSize =
519 dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
520 if (!
521 ((pConfig->srcGatherWidth % srcTrSize)
522 && (pConfig->srcGatherJump % srcTrSize))) {
523 dmacHw_REG_SGR_LO(pCblk->module, pCblk->channel) =
524 ((pConfig->srcGatherWidth /
525 srcTrSize) << 20) | (pConfig->srcGatherJump /
526 srcTrSize);
527 } else {
528 return -1;
529 }
530 }
531 /* Configure scatter register */
532 if (pConfig->dstScatterWidth) {
533 dstTrSize =
534 dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
535 if (!
536 ((pConfig->dstScatterWidth % dstTrSize)
537 && (pConfig->dstScatterJump % dstTrSize))) {
538 dmacHw_REG_DSR_LO(pCblk->module, pCblk->channel) =
539 ((pConfig->dstScatterWidth /
540 dstTrSize) << 20) | (pConfig->dstScatterJump /
541 dstTrSize);
542 } else {
543 return -1;
544 }
545 }
546 return 0;
547}
548
549/****************************************************************************/
550/**
551* @brief Indicates whether DMA transfer is in progress or completed
552*
553* @return DMA transfer status
554* dmacHw_TRANSFER_STATUS_BUSY: DMA Transfer ongoing
555* dmacHw_TRANSFER_STATUS_DONE: DMA Transfer completed
556* dmacHw_TRANSFER_STATUS_ERROR: DMA Transfer error
557*
558*/
559/****************************************************************************/
560dmacHw_TRANSFER_STATUS_e dmacHw_transferCompleted(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
561 ) {
562 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
563
564 if (CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
565 return dmacHw_TRANSFER_STATUS_BUSY;
566 } else if (dmacHw_REG_INT_RAW_ERROR(pCblk->module) &
567 (0x00000001 << pCblk->channel)) {
568 return dmacHw_TRANSFER_STATUS_ERROR;
569 }
570
571 return dmacHw_TRANSFER_STATUS_DONE;
572}
573
574/****************************************************************************/
575/**
576* @brief Set descriptors for known data length
577*
578* When DMA has to work as a flow controller, this function prepares the
579* descriptor chain to transfer data
580*
581* from:
582* - Memory to memory
583* - Peripheral to memory
584* - Memory to Peripheral
585* - Peripheral to Peripheral
586*
587* @return -1 - On failure
588* 0 - On success
589*
590*/
591/****************************************************************************/
592int dmacHw_setDataDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
593 void *pDescriptor, /* [ IN ] Descriptor buffer */
594 void *pSrcAddr, /* [ IN ] Source (Peripheral/Memory) address */
595 void *pDstAddr, /* [ IN ] Destination (Peripheral/Memory) address */
596 size_t dataLen /* [ IN ] Data length in bytes */
597 ) {
598 dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
599 dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
600 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
601 dmacHw_DESC_t *pStart;
602 dmacHw_DESC_t *pProg;
603 int srcTs = 0;
604 int blkTs = 0;
605 int oddSize = 0;
606 int descCount = 0;
607 int count = 0;
608 int dstTrSize = 0;
609 int srcTrSize = 0;
610 uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
611
612 dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
613 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
614
615 /* Skip Tx if buffer is NULL or length is unknown */
616 if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
617 /* Do not initiate transfer */
618 return -1;
619 }
620
621 /* Ensure scatter and gather are transaction aligned */
622 if ((pConfig->srcGatherWidth % srcTrSize)
623 || (pConfig->dstScatterWidth % dstTrSize)) {
624 return -2;
625 }
626
627 /*
628 Background 1: DMAC can not perform DMA if source and destination addresses are
629 not properly aligned with the channel's transaction width. So, for successful
630 DMA transfer, transaction width must be set according to the alignment of the
631 source and destination address.
632 */
633
634 /* Adjust destination transaction width if destination address is not aligned properly */
635 dstTrWidth = pConfig->dstMaxTransactionWidth;
636 while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
637 dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
638 dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
639 }
640
641 /* Adjust source transaction width if source address is not aligned properly */
642 srcTrWidth = pConfig->srcMaxTransactionWidth;
643 while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
644 srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
645 srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
646 }
647
648 /* Find the maximum transaction per descriptor */
649 if (pConfig->maxDataPerBlock
650 && ((pConfig->maxDataPerBlock / srcTrSize) <
651 dmacHw_MAX_BLOCKSIZE)) {
652 maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
653 }
654
655 /* Find number of source transactions needed to complete the DMA transfer */
656 srcTs = dataLen / srcTrSize;
657 /* Find the odd number of bytes that need to be transferred as single byte transaction width */
658 if (srcTs && (dstTrSize > srcTrSize)) {
659 oddSize = dataLen % dstTrSize;
660 /* Adjust source transaction count due to "oddSize" */
661 srcTs = srcTs - (oddSize / srcTrSize);
662 } else {
663 oddSize = dataLen % srcTrSize;
664 }
665 /* Adjust "descCount" due to "oddSize" */
666 if (oddSize) {
667 descCount++;
668 }
669 /* Find the number of descriptor needed for total "srcTs" */
670 if (srcTs) {
671 descCount += ((srcTs - 1) / maxBlockSize) + 1;
672 }
673
674 /* Check the availability of "descCount" discriptors in the ring */
675 pProg = pRing->pHead;
676 for (count = 0; (descCount <= pRing->num) && (count < descCount);
677 count++) {
678 if ((pProg->ctl.hi & dmacHw_DESC_FREE) == 0) {
679 /* Sufficient descriptors are not available */
680 return -3;
681 }
682 pProg = (dmacHw_DESC_t *) pProg->llp;
683 }
684
685 /* Remember the link list item to program the channel registers */
686 pStart = pProg = pRing->pHead;
687 /* Make a link list with "descCount(=count)" number of descriptors */
688 while (count) {
689 /* Reset channel control information */
690 pProg->ctl.lo = 0;
691 /* Enable source gather if configured */
692 if (pConfig->srcGatherWidth) {
693 pProg->ctl.lo |= dmacHw_REG_CTL_SG_ENABLE;
694 }
695 /* Enable destination scatter if configured */
696 if (pConfig->dstScatterWidth) {
697 pProg->ctl.lo |= dmacHw_REG_CTL_DS_ENABLE;
698 }
699 /* Set source and destination address */
700 pProg->sar = (uint32_t) pSrcAddr;
701 pProg->dar = (uint32_t) pDstAddr;
702 /* Use "devCtl" to mark that user memory need to be freed later if needed */
703 if (pProg == pRing->pHead) {
704 pProg->devCtl = dmacHw_FREE_USER_MEMORY;
705 } else {
706 pProg->devCtl = 0;
707 }
708
709 blkTs = srcTs;
710
711 /* Special treatmeant for last descriptor */
712 if (count == 1) {
713 /* Mark the last descriptor */
714 pProg->ctl.lo &=
715 ~(dmacHw_REG_CTL_LLP_DST_EN |
716 dmacHw_REG_CTL_LLP_SRC_EN);
717 /* Treatment for odd data bytes */
718 if (oddSize) {
719 /* Adjust for single byte transaction width */
720 switch (pConfig->transferType) {
721 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
722 dstTrWidth =
723 dmacHw_DST_TRANSACTION_WIDTH_8;
724 blkTs =
725 (oddSize / srcTrSize) +
726 ((oddSize % srcTrSize) ? 1 : 0);
727 break;
728 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
729 srcTrWidth =
730 dmacHw_SRC_TRANSACTION_WIDTH_8;
731 blkTs = oddSize;
732 break;
733 case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
734 srcTrWidth =
735 dmacHw_SRC_TRANSACTION_WIDTH_8;
736 dstTrWidth =
737 dmacHw_DST_TRANSACTION_WIDTH_8;
738 blkTs = oddSize;
739 break;
740 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
741 /* Do not adjust the transaction width */
742 break;
743 }
744 } else {
745 srcTs -= blkTs;
746 }
747 } else {
748 if (srcTs / maxBlockSize) {
749 blkTs = maxBlockSize;
750 }
751 /* Remaining source transactions for next iteration */
752 srcTs -= blkTs;
753 }
754 /* Must have a valid source transactions */
755 dmacHw_ASSERT(blkTs > 0);
756 /* Set control information */
757 if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
758 pProg->ctl.lo |= pConfig->transferType |
759 pConfig->srcUpdate |
760 pConfig->dstUpdate |
761 srcTrWidth |
762 dstTrWidth |
763 pConfig->srcMaxBurstWidth |
764 pConfig->dstMaxBurstWidth |
765 pConfig->srcMasterInterface |
766 pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
767 } else {
768 uint32_t transferType = 0;
769 switch (pConfig->transferType) {
770 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
771 transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
772 break;
773 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
774 transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
775 break;
776 default:
777 dmacHw_ASSERT(0);
778 }
779 pProg->ctl.lo |= transferType |
780 pConfig->srcUpdate |
781 pConfig->dstUpdate |
782 srcTrWidth |
783 dstTrWidth |
784 pConfig->srcMaxBurstWidth |
785 pConfig->dstMaxBurstWidth |
786 pConfig->srcMasterInterface |
787 pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
788 }
789
790 /* Set block transaction size */
791 pProg->ctl.hi = blkTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
792 /* Look for next descriptor */
793 if (count > 1) {
794 /* Point to the next descriptor */
795 pProg = (dmacHw_DESC_t *) pProg->llp;
796
797 /* Update source and destination address for next iteration */
798 switch (pConfig->transferType) {
799 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
800 if (pConfig->dstScatterWidth) {
801 pDstAddr =
802 (char *)pDstAddr +
803 blkTs * srcTrSize +
804 (((blkTs * srcTrSize) /
805 pConfig->dstScatterWidth) *
806 pConfig->dstScatterJump);
807 } else {
808 pDstAddr =
809 (char *)pDstAddr +
810 blkTs * srcTrSize;
811 }
812 break;
813 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
814 if (pConfig->srcGatherWidth) {
815 pSrcAddr =
816 (char *)pDstAddr +
817 blkTs * srcTrSize +
818 (((blkTs * srcTrSize) /
819 pConfig->srcGatherWidth) *
820 pConfig->srcGatherJump);
821 } else {
822 pSrcAddr =
823 (char *)pSrcAddr +
824 blkTs * srcTrSize;
825 }
826 break;
827 case dmacHw_TRANSFER_TYPE_MEM_TO_MEM:
828 if (pConfig->dstScatterWidth) {
829 pDstAddr =
830 (char *)pDstAddr +
831 blkTs * srcTrSize +
832 (((blkTs * srcTrSize) /
833 pConfig->dstScatterWidth) *
834 pConfig->dstScatterJump);
835 } else {
836 pDstAddr =
837 (char *)pDstAddr +
838 blkTs * srcTrSize;
839 }
840
841 if (pConfig->srcGatherWidth) {
842 pSrcAddr =
843 (char *)pDstAddr +
844 blkTs * srcTrSize +
845 (((blkTs * srcTrSize) /
846 pConfig->srcGatherWidth) *
847 pConfig->srcGatherJump);
848 } else {
849 pSrcAddr =
850 (char *)pSrcAddr +
851 blkTs * srcTrSize;
852 }
853 break;
854 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_PERIPHERAL:
855 /* Do not adjust the address */
856 break;
857 default:
858 dmacHw_ASSERT(0);
859 }
860 } else {
861 /* At the end of transfer "srcTs" must be zero */
862 dmacHw_ASSERT(srcTs == 0);
863 }
864 count--;
865 }
866
867 /* Remember the descriptor to initialize the registers */
868 if (pRing->pProg == dmacHw_DESC_INIT) {
869 pRing->pProg = pStart;
870 }
871 /* Indicate that the descriptor is updated */
872 pRing->pEnd = pProg;
873 /* Head pointing to the next descriptor */
874 pRing->pHead = (dmacHw_DESC_t *) pProg->llp;
875 /* Update Tail pointer if destination is a peripheral,
876 because no one is going to read from the pTail
877 */
878 if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
879 pRing->pTail = pRing->pHead;
880 }
881 return 0;
882}
883
884/****************************************************************************/
885/**
886* @brief Provides DMA controller attributes
887*
888*
889* @return DMA controller attributes
890*
891* @note
892* None
893*/
894/****************************************************************************/
895uint32_t dmacHw_getDmaControllerAttribute(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
896 dmacHw_CONTROLLER_ATTRIB_e attr /* [ IN ] DMA Controller attribute of type dmacHw_CONTROLLER_ATTRIB_e */
897 ) {
898 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
899
900 switch (attr) {
901 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_NUM:
902 return dmacHw_GET_NUM_CHANNEL(pCblk->module);
903 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_MAX_BLOCK_SIZE:
904 return (1 <<
905 (dmacHw_GET_MAX_BLOCK_SIZE
906 (pCblk->module, pCblk->module) + 2)) - 8;
907 case dmacHw_CONTROLLER_ATTRIB_MASTER_INTF_NUM:
908 return dmacHw_GET_NUM_INTERFACE(pCblk->module);
909 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_BUS_WIDTH:
910 return 32 << dmacHw_GET_CHANNEL_DATA_WIDTH(pCblk->module,
911 pCblk->channel);
912 case dmacHw_CONTROLLER_ATTRIB_CHANNEL_FIFO_SIZE:
913 return GetFifoSize(handle);
914 }
915 dmacHw_ASSERT(0);
916 return 0;
917}
diff --git a/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
new file mode 100644
index 00000000000..a1f328357aa
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/dmac/dmacHw_extra.c
@@ -0,0 +1,1017 @@
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 dmacHw_extra.c
18*
19* @brief Extra Low level DMA controller driver routines
20*
21* @note
22*
23* These routines provide basic DMA functionality only.
24*/
25/****************************************************************************/
26
27/* ---- Include Files ---------------------------------------------------- */
28
29#include <csp/stdint.h>
30#include <stddef.h>
31
32#include <csp/dmacHw.h>
33#include <mach/csp/dmacHw_reg.h>
34#include <mach/csp/dmacHw_priv.h>
35
36extern dmacHw_CBLK_t dmacHw_gCblk[dmacHw_MAX_CHANNEL_COUNT]; /* Declared in dmacHw.c */
37
38/* ---- External Function Prototypes ------------------------------------- */
39
40/* ---- Internal Use Function Prototypes --------------------------------- */
41/****************************************************************************/
42/**
43* @brief Overwrites data length in the descriptor
44*
45* This function overwrites data length in the descriptor
46*
47*
48* @return void
49*
50* @note
51* This is only used for PCM channel
52*/
53/****************************************************************************/
54void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
55 void *pDescriptor, /* [ IN ] Descriptor buffer */
56 size_t dataLen /* [ IN ] Data length in bytes */
57 );
58
59/****************************************************************************/
60/**
61* @brief Helper function to display DMA registers
62*
63* @return void
64*
65*
66* @note
67* None
68*/
69/****************************************************************************/
70static void DisplayRegisterContents(int module, /* [ IN ] DMA Controller unit (0-1) */
71 int channel, /* [ IN ] DMA Channel (0-7) / -1(all) */
72 int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
73 ) {
74 int chan;
75
76 (*fpPrint) ("Displaying register content \n\n");
77 (*fpPrint) ("Module %d: Interrupt raw transfer 0x%X\n",
78 module, (uint32_t) (dmacHw_REG_INT_RAW_TRAN(module)));
79 (*fpPrint) ("Module %d: Interrupt raw block 0x%X\n",
80 module, (uint32_t) (dmacHw_REG_INT_RAW_BLOCK(module)));
81 (*fpPrint) ("Module %d: Interrupt raw src transfer 0x%X\n",
82 module, (uint32_t) (dmacHw_REG_INT_RAW_STRAN(module)));
83 (*fpPrint) ("Module %d: Interrupt raw dst transfer 0x%X\n",
84 module, (uint32_t) (dmacHw_REG_INT_RAW_DTRAN(module)));
85 (*fpPrint) ("Module %d: Interrupt raw error 0x%X\n",
86 module, (uint32_t) (dmacHw_REG_INT_RAW_ERROR(module)));
87 (*fpPrint) ("--------------------------------------------------\n");
88 (*fpPrint) ("Module %d: Interrupt stat transfer 0x%X\n",
89 module, (uint32_t) (dmacHw_REG_INT_STAT_TRAN(module)));
90 (*fpPrint) ("Module %d: Interrupt stat block 0x%X\n",
91 module, (uint32_t) (dmacHw_REG_INT_STAT_BLOCK(module)));
92 (*fpPrint) ("Module %d: Interrupt stat src transfer 0x%X\n",
93 module, (uint32_t) (dmacHw_REG_INT_STAT_STRAN(module)));
94 (*fpPrint) ("Module %d: Interrupt stat dst transfer 0x%X\n",
95 module, (uint32_t) (dmacHw_REG_INT_STAT_DTRAN(module)));
96 (*fpPrint) ("Module %d: Interrupt stat error 0x%X\n",
97 module, (uint32_t) (dmacHw_REG_INT_STAT_ERROR(module)));
98 (*fpPrint) ("--------------------------------------------------\n");
99 (*fpPrint) ("Module %d: Interrupt mask transfer 0x%X\n",
100 module, (uint32_t) (dmacHw_REG_INT_MASK_TRAN(module)));
101 (*fpPrint) ("Module %d: Interrupt mask block 0x%X\n",
102 module, (uint32_t) (dmacHw_REG_INT_MASK_BLOCK(module)));
103 (*fpPrint) ("Module %d: Interrupt mask src transfer 0x%X\n",
104 module, (uint32_t) (dmacHw_REG_INT_MASK_STRAN(module)));
105 (*fpPrint) ("Module %d: Interrupt mask dst transfer 0x%X\n",
106 module, (uint32_t) (dmacHw_REG_INT_MASK_DTRAN(module)));
107 (*fpPrint) ("Module %d: Interrupt mask error 0x%X\n",
108 module, (uint32_t) (dmacHw_REG_INT_MASK_ERROR(module)));
109 (*fpPrint) ("--------------------------------------------------\n");
110 (*fpPrint) ("Module %d: Interrupt clear transfer 0x%X\n",
111 module, (uint32_t) (dmacHw_REG_INT_CLEAR_TRAN(module)));
112 (*fpPrint) ("Module %d: Interrupt clear block 0x%X\n",
113 module, (uint32_t) (dmacHw_REG_INT_CLEAR_BLOCK(module)));
114 (*fpPrint) ("Module %d: Interrupt clear src transfer 0x%X\n",
115 module, (uint32_t) (dmacHw_REG_INT_CLEAR_STRAN(module)));
116 (*fpPrint) ("Module %d: Interrupt clear dst transfer 0x%X\n",
117 module, (uint32_t) (dmacHw_REG_INT_CLEAR_DTRAN(module)));
118 (*fpPrint) ("Module %d: Interrupt clear error 0x%X\n",
119 module, (uint32_t) (dmacHw_REG_INT_CLEAR_ERROR(module)));
120 (*fpPrint) ("--------------------------------------------------\n");
121 (*fpPrint) ("Module %d: SW source req 0x%X\n",
122 module, (uint32_t) (dmacHw_REG_SW_HS_SRC_REQ(module)));
123 (*fpPrint) ("Module %d: SW dest req 0x%X\n",
124 module, (uint32_t) (dmacHw_REG_SW_HS_DST_REQ(module)));
125 (*fpPrint) ("Module %d: SW source signal 0x%X\n",
126 module, (uint32_t) (dmacHw_REG_SW_HS_SRC_SGL_REQ(module)));
127 (*fpPrint) ("Module %d: SW dest signal 0x%X\n",
128 module, (uint32_t) (dmacHw_REG_SW_HS_DST_SGL_REQ(module)));
129 (*fpPrint) ("Module %d: SW source last 0x%X\n",
130 module, (uint32_t) (dmacHw_REG_SW_HS_SRC_LST_REQ(module)));
131 (*fpPrint) ("Module %d: SW dest last 0x%X\n",
132 module, (uint32_t) (dmacHw_REG_SW_HS_DST_LST_REQ(module)));
133 (*fpPrint) ("--------------------------------------------------\n");
134 (*fpPrint) ("Module %d: misc config 0x%X\n",
135 module, (uint32_t) (dmacHw_REG_MISC_CFG(module)));
136 (*fpPrint) ("Module %d: misc channel enable 0x%X\n",
137 module, (uint32_t) (dmacHw_REG_MISC_CH_ENABLE(module)));
138 (*fpPrint) ("Module %d: misc ID 0x%X\n",
139 module, (uint32_t) (dmacHw_REG_MISC_ID(module)));
140 (*fpPrint) ("Module %d: misc test 0x%X\n",
141 module, (uint32_t) (dmacHw_REG_MISC_TEST(module)));
142
143 if (channel == -1) {
144 for (chan = 0; chan < 8; chan++) {
145 (*fpPrint)
146 ("--------------------------------------------------\n");
147 (*fpPrint)
148 ("Module %d: Channel %d Source 0x%X\n",
149 module, chan,
150 (uint32_t) (dmacHw_REG_SAR(module, chan)));
151 (*fpPrint)
152 ("Module %d: Channel %d Destination 0x%X\n",
153 module, chan,
154 (uint32_t) (dmacHw_REG_DAR(module, chan)));
155 (*fpPrint)
156 ("Module %d: Channel %d LLP 0x%X\n",
157 module, chan,
158 (uint32_t) (dmacHw_REG_LLP(module, chan)));
159 (*fpPrint)
160 ("Module %d: Channel %d Control (LO) 0x%X\n",
161 module, chan,
162 (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
163 (*fpPrint)
164 ("Module %d: Channel %d Control (HI) 0x%X\n",
165 module, chan,
166 (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
167 (*fpPrint)
168 ("Module %d: Channel %d Source Stats 0x%X\n",
169 module, chan,
170 (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
171 (*fpPrint)
172 ("Module %d: Channel %d Dest Stats 0x%X\n",
173 module, chan,
174 (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
175 (*fpPrint)
176 ("Module %d: Channel %d Source Stats Addr 0x%X\n",
177 module, chan,
178 (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
179 (*fpPrint)
180 ("Module %d: Channel %d Dest Stats Addr 0x%X\n",
181 module, chan,
182 (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
183 (*fpPrint)
184 ("Module %d: Channel %d Config (LO) 0x%X\n",
185 module, chan,
186 (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
187 (*fpPrint)
188 ("Module %d: Channel %d Config (HI) 0x%X\n",
189 module, chan,
190 (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
191 }
192 } else {
193 chan = channel;
194 (*fpPrint)
195 ("--------------------------------------------------\n");
196 (*fpPrint)
197 ("Module %d: Channel %d Source 0x%X\n",
198 module, chan, (uint32_t) (dmacHw_REG_SAR(module, chan)));
199 (*fpPrint)
200 ("Module %d: Channel %d Destination 0x%X\n",
201 module, chan, (uint32_t) (dmacHw_REG_DAR(module, chan)));
202 (*fpPrint)
203 ("Module %d: Channel %d LLP 0x%X\n",
204 module, chan, (uint32_t) (dmacHw_REG_LLP(module, chan)));
205 (*fpPrint)
206 ("Module %d: Channel %d Control (LO) 0x%X\n",
207 module, chan,
208 (uint32_t) (dmacHw_REG_CTL_LO(module, chan)));
209 (*fpPrint)
210 ("Module %d: Channel %d Control (HI) 0x%X\n",
211 module, chan,
212 (uint32_t) (dmacHw_REG_CTL_HI(module, chan)));
213 (*fpPrint)
214 ("Module %d: Channel %d Source Stats 0x%X\n",
215 module, chan, (uint32_t) (dmacHw_REG_SSTAT(module, chan)));
216 (*fpPrint)
217 ("Module %d: Channel %d Dest Stats 0x%X\n",
218 module, chan, (uint32_t) (dmacHw_REG_DSTAT(module, chan)));
219 (*fpPrint)
220 ("Module %d: Channel %d Source Stats Addr 0x%X\n",
221 module, chan,
222 (uint32_t) (dmacHw_REG_SSTATAR(module, chan)));
223 (*fpPrint)
224 ("Module %d: Channel %d Dest Stats Addr 0x%X\n",
225 module, chan,
226 (uint32_t) (dmacHw_REG_DSTATAR(module, chan)));
227 (*fpPrint)
228 ("Module %d: Channel %d Config (LO) 0x%X\n",
229 module, chan,
230 (uint32_t) (dmacHw_REG_CFG_LO(module, chan)));
231 (*fpPrint)
232 ("Module %d: Channel %d Config (HI) 0x%X\n",
233 module, chan,
234 (uint32_t) (dmacHw_REG_CFG_HI(module, chan)));
235 }
236}
237
238/****************************************************************************/
239/**
240* @brief Helper function to display descriptor ring
241*
242* @return void
243*
244*
245* @note
246* None
247*/
248/****************************************************************************/
249static void DisplayDescRing(void *pDescriptor, /* [ IN ] Descriptor buffer */
250 int (*fpPrint) (const char *, ...) /* [ IN ] Callback to the print function */
251 ) {
252 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
253 dmacHw_DESC_t *pStart;
254
255 if (pRing->pHead == NULL) {
256 return;
257 }
258
259 pStart = pRing->pHead;
260
261 while ((dmacHw_DESC_t *) pStart->llp != pRing->pHead) {
262 if (pStart == pRing->pHead) {
263 (*fpPrint) ("Head\n");
264 }
265 if (pStart == pRing->pTail) {
266 (*fpPrint) ("Tail\n");
267 }
268 if (pStart == pRing->pProg) {
269 (*fpPrint) ("Prog\n");
270 }
271 if (pStart == pRing->pEnd) {
272 (*fpPrint) ("End\n");
273 }
274 if (pStart == pRing->pFree) {
275 (*fpPrint) ("Free\n");
276 }
277 (*fpPrint) ("0x%X:\n", (uint32_t) pStart);
278 (*fpPrint) ("sar 0x%0X\n", pStart->sar);
279 (*fpPrint) ("dar 0x%0X\n", pStart->dar);
280 (*fpPrint) ("llp 0x%0X\n", pStart->llp);
281 (*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
282 (*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
283 (*fpPrint) ("sstat 0x%0X\n", pStart->sstat);
284 (*fpPrint) ("dstat 0x%0X\n", pStart->dstat);
285 (*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
286
287 pStart = (dmacHw_DESC_t *) pStart->llp;
288 }
289 if (pStart == pRing->pHead) {
290 (*fpPrint) ("Head\n");
291 }
292 if (pStart == pRing->pTail) {
293 (*fpPrint) ("Tail\n");
294 }
295 if (pStart == pRing->pProg) {
296 (*fpPrint) ("Prog\n");
297 }
298 if (pStart == pRing->pEnd) {
299 (*fpPrint) ("End\n");
300 }
301 if (pStart == pRing->pFree) {
302 (*fpPrint) ("Free\n");
303 }
304 (*fpPrint) ("0x%X:\n", (uint32_t) pStart);
305 (*fpPrint) ("sar 0x%0X\n", pStart->sar);
306 (*fpPrint) ("dar 0x%0X\n", pStart->dar);
307 (*fpPrint) ("llp 0x%0X\n", pStart->llp);
308 (*fpPrint) ("ctl.lo 0x%0X\n", pStart->ctl.lo);
309 (*fpPrint) ("ctl.hi 0x%0X\n", pStart->ctl.hi);
310 (*fpPrint) ("sstat 0x%0X\n", pStart->sstat);
311 (*fpPrint) ("dstat 0x%0X\n", pStart->dstat);
312 (*fpPrint) ("devCtl 0x%0X\n", pStart->devCtl);
313}
314
315/****************************************************************************/
316/**
317* @brief Check if DMA channel is the flow controller
318*
319* @return 1 : If DMA is a flow controller
320* 0 : Peripheral is the flow controller
321*
322* @note
323* None
324*/
325/****************************************************************************/
326static inline int DmaIsFlowController(void *pDescriptor /* [ IN ] Descriptor buffer */
327 ) {
328 uint32_t ttfc =
329 (dmacHw_GET_DESC_RING(pDescriptor))->pTail->ctl.
330 lo & dmacHw_REG_CTL_TTFC_MASK;
331
332 switch (ttfc) {
333 case dmacHw_REG_CTL_TTFC_MM_DMAC:
334 case dmacHw_REG_CTL_TTFC_MP_DMAC:
335 case dmacHw_REG_CTL_TTFC_PM_DMAC:
336 case dmacHw_REG_CTL_TTFC_PP_DMAC:
337 return 1;
338 }
339
340 return 0;
341}
342
343/****************************************************************************/
344/**
345* @brief Overwrites data length in the descriptor
346*
347* This function overwrites data length in the descriptor
348*
349*
350* @return void
351*
352* @note
353* This is only used for PCM channel
354*/
355/****************************************************************************/
356void dmacHw_setDataLength(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
357 void *pDescriptor, /* [ IN ] Descriptor buffer */
358 size_t dataLen /* [ IN ] Data length in bytes */
359 ) {
360 dmacHw_DESC_t *pProg;
361 dmacHw_DESC_t *pHead;
362 int srcTs = 0;
363 int srcTrSize = 0;
364
365 pHead = (dmacHw_GET_DESC_RING(pDescriptor))->pHead;
366 pProg = pHead;
367
368 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
369 srcTs = dataLen / srcTrSize;
370 do {
371 pProg->ctl.hi = srcTs & dmacHw_REG_CTL_BLOCK_TS_MASK;
372 pProg = (dmacHw_DESC_t *) pProg->llp;
373 } while (pProg != pHead);
374}
375
376/****************************************************************************/
377/**
378* @brief Clears the interrupt
379*
380* This function clears the DMA channel specific interrupt
381*
382*
383* @return void
384*
385* @note
386* Must be called under the context of ISR
387*/
388/****************************************************************************/
389void dmacHw_clearInterrupt(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
390 ) {
391 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
392
393 dmacHw_TRAN_INT_CLEAR(pCblk->module, pCblk->channel);
394 dmacHw_BLOCK_INT_CLEAR(pCblk->module, pCblk->channel);
395 dmacHw_ERROR_INT_CLEAR(pCblk->module, pCblk->channel);
396}
397
398/****************************************************************************/
399/**
400* @brief Returns the cause of channel specific DMA interrupt
401*
402* This function returns the cause of interrupt
403*
404* @return Interrupt status, each bit representing a specific type of interrupt
405*
406* @note
407* Should be called under the context of ISR
408*/
409/****************************************************************************/
410dmacHw_INTERRUPT_STATUS_e dmacHw_getInterruptStatus(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
411 ) {
412 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
413 dmacHw_INTERRUPT_STATUS_e status = dmacHw_INTERRUPT_STATUS_NONE;
414
415 if (dmacHw_REG_INT_STAT_TRAN(pCblk->module) &
416 ((0x00000001 << pCblk->channel))) {
417 status |= dmacHw_INTERRUPT_STATUS_TRANS;
418 }
419 if (dmacHw_REG_INT_STAT_BLOCK(pCblk->module) &
420 ((0x00000001 << pCblk->channel))) {
421 status |= dmacHw_INTERRUPT_STATUS_BLOCK;
422 }
423 if (dmacHw_REG_INT_STAT_ERROR(pCblk->module) &
424 ((0x00000001 << pCblk->channel))) {
425 status |= dmacHw_INTERRUPT_STATUS_ERROR;
426 }
427
428 return status;
429}
430
431/****************************************************************************/
432/**
433* @brief Indentifies a DMA channel causing interrupt
434*
435* This functions returns a channel causing interrupt of type dmacHw_INTERRUPT_STATUS_e
436*
437* @return NULL : No channel causing DMA interrupt
438* ! NULL : Handle to a channel causing DMA interrupt
439* @note
440* dmacHw_clearInterrupt() must be called with a valid handle after calling this function
441*/
442/****************************************************************************/
443dmacHw_HANDLE_t dmacHw_getInterruptSource(void)
444{
445 uint32_t i;
446
447 for (i = 0; i < dmaChannelCount_0 + dmaChannelCount_1; i++) {
448 if ((dmacHw_REG_INT_STAT_TRAN(dmacHw_gCblk[i].module) &
449 ((0x00000001 << dmacHw_gCblk[i].channel)))
450 || (dmacHw_REG_INT_STAT_BLOCK(dmacHw_gCblk[i].module) &
451 ((0x00000001 << dmacHw_gCblk[i].channel)))
452 || (dmacHw_REG_INT_STAT_ERROR(dmacHw_gCblk[i].module) &
453 ((0x00000001 << dmacHw_gCblk[i].channel)))
454 ) {
455 return dmacHw_CBLK_TO_HANDLE(&dmacHw_gCblk[i]);
456 }
457 }
458 return dmacHw_CBLK_TO_HANDLE(NULL);
459}
460
461/****************************************************************************/
462/**
463* @brief Estimates number of descriptor needed to perform certain DMA transfer
464*
465*
466* @return On failure : -1
467* On success : Number of descriptor count
468*
469*
470*/
471/****************************************************************************/
472int dmacHw_calculateDescriptorCount(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
473 void *pSrcAddr, /* [ IN ] Source (Peripheral/Memory) address */
474 void *pDstAddr, /* [ IN ] Destination (Peripheral/Memory) address */
475 size_t dataLen /* [ IN ] Data length in bytes */
476 ) {
477 int srcTs = 0;
478 int oddSize = 0;
479 int descCount = 0;
480 int dstTrSize = 0;
481 int srcTrSize = 0;
482 uint32_t maxBlockSize = dmacHw_MAX_BLOCKSIZE;
483 dmacHw_TRANSACTION_WIDTH_e dstTrWidth;
484 dmacHw_TRANSACTION_WIDTH_e srcTrWidth;
485
486 dstTrSize = dmacHw_GetTrWidthInBytes(pConfig->dstMaxTransactionWidth);
487 srcTrSize = dmacHw_GetTrWidthInBytes(pConfig->srcMaxTransactionWidth);
488
489 /* Skip Tx if buffer is NULL or length is unknown */
490 if ((pSrcAddr == NULL) || (pDstAddr == NULL) || (dataLen == 0)) {
491 /* Do not initiate transfer */
492 return -1;
493 }
494
495 /* Ensure scatter and gather are transaction aligned */
496 if (pConfig->srcGatherWidth % srcTrSize
497 || pConfig->dstScatterWidth % dstTrSize) {
498 return -1;
499 }
500
501 /*
502 Background 1: DMAC can not perform DMA if source and destination addresses are
503 not properly aligned with the channel's transaction width. So, for successful
504 DMA transfer, transaction width must be set according to the alignment of the
505 source and destination address.
506 */
507
508 /* Adjust destination transaction width if destination address is not aligned properly */
509 dstTrWidth = pConfig->dstMaxTransactionWidth;
510 while (dmacHw_ADDRESS_MASK(dstTrSize) & (uint32_t) pDstAddr) {
511 dstTrWidth = dmacHw_GetNextTrWidth(dstTrWidth);
512 dstTrSize = dmacHw_GetTrWidthInBytes(dstTrWidth);
513 }
514
515 /* Adjust source transaction width if source address is not aligned properly */
516 srcTrWidth = pConfig->srcMaxTransactionWidth;
517 while (dmacHw_ADDRESS_MASK(srcTrSize) & (uint32_t) pSrcAddr) {
518 srcTrWidth = dmacHw_GetNextTrWidth(srcTrWidth);
519 srcTrSize = dmacHw_GetTrWidthInBytes(srcTrWidth);
520 }
521
522 /* Find the maximum transaction per descriptor */
523 if (pConfig->maxDataPerBlock
524 && ((pConfig->maxDataPerBlock / srcTrSize) <
525 dmacHw_MAX_BLOCKSIZE)) {
526 maxBlockSize = pConfig->maxDataPerBlock / srcTrSize;
527 }
528
529 /* Find number of source transactions needed to complete the DMA transfer */
530 srcTs = dataLen / srcTrSize;
531 /* Find the odd number of bytes that need to be transferred as single byte transaction width */
532 if (srcTs && (dstTrSize > srcTrSize)) {
533 oddSize = dataLen % dstTrSize;
534 /* Adjust source transaction count due to "oddSize" */
535 srcTs = srcTs - (oddSize / srcTrSize);
536 } else {
537 oddSize = dataLen % srcTrSize;
538 }
539 /* Adjust "descCount" due to "oddSize" */
540 if (oddSize) {
541 descCount++;
542 }
543
544 /* Find the number of descriptor needed for total "srcTs" */
545 if (srcTs) {
546 descCount += ((srcTs - 1) / maxBlockSize) + 1;
547 }
548
549 return descCount;
550}
551
552/****************************************************************************/
553/**
554* @brief Check the existence of pending descriptor
555*
556* This function confirmes if there is any pending descriptor in the chain
557* to program the channel
558*
559* @return 1 : Channel need to be programmed with pending descriptor
560* 0 : No more pending descriptor to programe the channel
561*
562* @note
563* - This function should be called from ISR in case there are pending
564* descriptor to program the channel.
565*
566* Example:
567*
568* dmac_isr ()
569* {
570* ...
571* if (dmacHw_descriptorPending (handle))
572* {
573* dmacHw_initiateTransfer (handle);
574* }
575* }
576*
577*/
578/****************************************************************************/
579uint32_t dmacHw_descriptorPending(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
580 void *pDescriptor /* [ IN ] Descriptor buffer */
581 ) {
582 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
583 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
584
585 /* Make sure channel is not busy */
586 if (!CHANNEL_BUSY(pCblk->module, pCblk->channel)) {
587 /* Check if pEnd is not processed */
588 if (pRing->pEnd) {
589 /* Something left for processing */
590 return 1;
591 }
592 }
593 return 0;
594}
595
596/****************************************************************************/
597/**
598* @brief Program channel register to stop transfer
599*
600* Ensures the channel is not doing any transfer after calling this function
601*
602* @return void
603*
604*/
605/****************************************************************************/
606void dmacHw_stopTransfer(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
607 ) {
608 dmacHw_CBLK_t *pCblk;
609
610 pCblk = dmacHw_HANDLE_TO_CBLK(handle);
611
612 /* Stop the channel */
613 dmacHw_DMA_STOP(pCblk->module, pCblk->channel);
614}
615
616/****************************************************************************/
617/**
618* @brief Deallocates source or destination memory, allocated
619*
620* This function can be called to deallocate data memory that was DMAed successfully
621*
622* @return On failure : -1
623* On success : Number of buffer freed
624*
625* @note
626* This function will be called ONLY, when source OR destination address is pointing
627* to dynamic memory
628*/
629/****************************************************************************/
630int dmacHw_freeMem(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
631 void *pDescriptor, /* [ IN ] Descriptor buffer */
632 void (*fpFree) (void *) /* [ IN ] Function pointer to free data memory */
633 ) {
634 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
635 uint32_t count = 0;
636
637 if (fpFree == NULL) {
638 return -1;
639 }
640
641 while ((pRing->pFree != pRing->pTail)
642 && (pRing->pFree->ctl.lo & dmacHw_DESC_FREE)) {
643 if (pRing->pFree->devCtl == dmacHw_FREE_USER_MEMORY) {
644 /* Identify, which memory to free */
645 if (dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
646 (*fpFree) ((void *)pRing->pFree->dar);
647 } else {
648 /* Destination was a peripheral */
649 (*fpFree) ((void *)pRing->pFree->sar);
650 }
651 /* Unmark user memory to indicate it is freed */
652 pRing->pFree->devCtl = ~dmacHw_FREE_USER_MEMORY;
653 }
654 dmacHw_NEXT_DESC(pRing, pFree);
655
656 count++;
657 }
658
659 return count;
660}
661
662/****************************************************************************/
663/**
664* @brief Prepares descriptor ring, when source peripheral working as a flow controller
665*
666* This function will update the discriptor ring by allocating buffers, when source peripheral
667* has to work as a flow controller to transfer data from:
668* - Peripheral to memory.
669*
670* @return On failure : -1
671* On success : Number of descriptor updated
672*
673*
674* @note
675* Channel must be configured for peripheral to memory transfer
676*
677*/
678/****************************************************************************/
679int dmacHw_setVariableDataDescriptor(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
680 dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
681 void *pDescriptor, /* [ IN ] Descriptor buffer */
682 uint32_t srcAddr, /* [ IN ] Source peripheral address */
683 void *(*fpAlloc) (int len), /* [ IN ] Function pointer that provides destination memory */
684 int len, /* [ IN ] Number of bytes "fpAlloc" will allocate for destination */
685 int num /* [ IN ] Number of descriptor to set */
686 ) {
687 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
688 dmacHw_DESC_t *pProg = NULL;
689 dmacHw_DESC_t *pLast = NULL;
690 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
691 uint32_t dstAddr;
692 uint32_t controlParam;
693 int i;
694
695 dmacHw_ASSERT(pConfig->transferType ==
696 dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM);
697
698 if (num > pRing->num) {
699 return -1;
700 }
701
702 pLast = pRing->pEnd; /* Last descriptor updated */
703 pProg = pRing->pHead; /* First descriptor in the new list */
704
705 controlParam = pConfig->srcUpdate |
706 pConfig->dstUpdate |
707 pConfig->srcMaxTransactionWidth |
708 pConfig->dstMaxTransactionWidth |
709 pConfig->srcMasterInterface |
710 pConfig->dstMasterInterface |
711 pConfig->srcMaxBurstWidth |
712 pConfig->dstMaxBurstWidth |
713 dmacHw_REG_CTL_TTFC_PM_PERI |
714 dmacHw_REG_CTL_LLP_DST_EN |
715 dmacHw_REG_CTL_LLP_SRC_EN | dmacHw_REG_CTL_INT_EN;
716
717 for (i = 0; i < num; i++) {
718 /* Allocate Rx buffer only for idle descriptor */
719 if (((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) ||
720 ((dmacHw_DESC_t *) pRing->pHead->llp == pRing->pTail)
721 ) {
722 /* Rx descriptor is not idle */
723 break;
724 }
725 /* Set source address */
726 pRing->pHead->sar = srcAddr;
727 if (fpAlloc) {
728 /* Allocate memory for buffer in descriptor */
729 dstAddr = (uint32_t) (*fpAlloc) (len);
730 /* Check the destination address */
731 if (dstAddr == 0) {
732 if (i == 0) {
733 /* Not a single descriptor is available */
734 return -1;
735 }
736 break;
737 }
738 /* Set destination address */
739 pRing->pHead->dar = dstAddr;
740 }
741 /* Set control information */
742 pRing->pHead->ctl.lo = controlParam;
743 /* Use "devCtl" to mark the memory that need to be freed later */
744 pRing->pHead->devCtl = dmacHw_FREE_USER_MEMORY;
745 /* Descriptor is now owned by the channel */
746 pRing->pHead->ctl.hi = 0;
747 /* Remember the descriptor last updated */
748 pRing->pEnd = pRing->pHead;
749 /* Update next descriptor */
750 dmacHw_NEXT_DESC(pRing, pHead);
751 }
752
753 /* Mark the end of the list */
754 pRing->pEnd->ctl.lo &=
755 ~(dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN);
756 /* Connect the list */
757 if (pLast != pProg) {
758 pLast->ctl.lo |=
759 dmacHw_REG_CTL_LLP_DST_EN | dmacHw_REG_CTL_LLP_SRC_EN;
760 }
761 /* Mark the descriptors are updated */
762 pCblk->descUpdated = 1;
763 if (!pCblk->varDataStarted) {
764 /* LLP must be pointing to the first descriptor */
765 dmacHw_SET_LLP(pCblk->module, pCblk->channel,
766 (uint32_t) pProg - pRing->virt2PhyOffset);
767 /* Channel, handling variable data started */
768 pCblk->varDataStarted = 1;
769 }
770
771 return i;
772}
773
774/****************************************************************************/
775/**
776* @brief Read data DMAed to memory
777*
778* This function will read data that has been DMAed to memory while transferring from:
779* - Memory to memory
780* - Peripheral to memory
781*
782* @param handle -
783* @param ppBbuf -
784* @param pLen -
785*
786* @return 0 - No more data is available to read
787* 1 - More data might be available to read
788*
789*/
790/****************************************************************************/
791int dmacHw_readTransferredData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
792 dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
793 void *pDescriptor, /* [ IN ] Descriptor buffer */
794 void **ppBbuf, /* [ OUT ] Data received */
795 size_t *pLlen /* [ OUT ] Length of the data received */
796 ) {
797 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
798
799 (void)handle;
800
801 if (pConfig->transferMode != dmacHw_TRANSFER_MODE_CONTINUOUS) {
802 if (((pRing->pTail->ctl.hi & dmacHw_DESC_FREE) == 0) ||
803 (pRing->pTail == pRing->pHead)
804 ) {
805 /* No receive data available */
806 *ppBbuf = (char *)NULL;
807 *pLlen = 0;
808
809 return 0;
810 }
811 }
812
813 /* Return read buffer and length */
814 *ppBbuf = (char *)pRing->pTail->dar;
815
816 /* Extract length of the received data */
817 if (DmaIsFlowController(pDescriptor)) {
818 uint32_t srcTrSize = 0;
819
820 switch (pRing->pTail->ctl.lo & dmacHw_REG_CTL_SRC_TR_WIDTH_MASK) {
821 case dmacHw_REG_CTL_SRC_TR_WIDTH_8:
822 srcTrSize = 1;
823 break;
824 case dmacHw_REG_CTL_SRC_TR_WIDTH_16:
825 srcTrSize = 2;
826 break;
827 case dmacHw_REG_CTL_SRC_TR_WIDTH_32:
828 srcTrSize = 4;
829 break;
830 case dmacHw_REG_CTL_SRC_TR_WIDTH_64:
831 srcTrSize = 8;
832 break;
833 default:
834 dmacHw_ASSERT(0);
835 }
836 /* Calculate length from the block size */
837 *pLlen =
838 (pRing->pTail->ctl.hi & dmacHw_REG_CTL_BLOCK_TS_MASK) *
839 srcTrSize;
840 } else {
841 /* Extract length from the source peripheral */
842 *pLlen = pRing->pTail->sstat;
843 }
844
845 /* Advance tail to next descriptor */
846 dmacHw_NEXT_DESC(pRing, pTail);
847
848 return 1;
849}
850
851/****************************************************************************/
852/**
853* @brief Set descriptor carrying control information
854*
855* This function will be used to send specific control information to the device
856* using the DMA channel
857*
858*
859* @return -1 - On failure
860* 0 - On success
861*
862* @note
863* None
864*/
865/****************************************************************************/
866int dmacHw_setControlDescriptor(dmacHw_CONFIG_t *pConfig, /* [ IN ] Configuration settings */
867 void *pDescriptor, /* [ IN ] Descriptor buffer */
868 uint32_t ctlAddress, /* [ IN ] Address of the device control register */
869 uint32_t control /* [ IN ] Device control information */
870 ) {
871 dmacHw_DESC_RING_t *pRing = dmacHw_GET_DESC_RING(pDescriptor);
872
873 if (ctlAddress == 0) {
874 return -1;
875 }
876
877 /* Check the availability of descriptors in the ring */
878 if ((pRing->pHead->ctl.hi & dmacHw_DESC_FREE) == 0) {
879 return -1;
880 }
881 /* Set control information */
882 pRing->pHead->devCtl = control;
883 /* Set source and destination address */
884 pRing->pHead->sar = (uint32_t) &pRing->pHead->devCtl;
885 pRing->pHead->dar = ctlAddress;
886 /* Set control parameters */
887 if (pConfig->flowControler == dmacHw_FLOW_CONTROL_DMA) {
888 pRing->pHead->ctl.lo = pConfig->transferType |
889 dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
890 dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
891 dmacHw_SRC_TRANSACTION_WIDTH_32 |
892 pConfig->dstMaxTransactionWidth |
893 dmacHw_SRC_BURST_WIDTH_0 |
894 dmacHw_DST_BURST_WIDTH_0 |
895 pConfig->srcMasterInterface |
896 pConfig->dstMasterInterface | dmacHw_REG_CTL_INT_EN;
897 } else {
898 uint32_t transferType = 0;
899 switch (pConfig->transferType) {
900 case dmacHw_TRANSFER_TYPE_PERIPHERAL_TO_MEM:
901 transferType = dmacHw_REG_CTL_TTFC_PM_PERI;
902 break;
903 case dmacHw_TRANSFER_TYPE_MEM_TO_PERIPHERAL:
904 transferType = dmacHw_REG_CTL_TTFC_MP_PERI;
905 break;
906 default:
907 dmacHw_ASSERT(0);
908 }
909 pRing->pHead->ctl.lo = transferType |
910 dmacHw_SRC_ADDRESS_UPDATE_MODE_INC |
911 dmacHw_DST_ADDRESS_UPDATE_MODE_INC |
912 dmacHw_SRC_TRANSACTION_WIDTH_32 |
913 pConfig->dstMaxTransactionWidth |
914 dmacHw_SRC_BURST_WIDTH_0 |
915 dmacHw_DST_BURST_WIDTH_0 |
916 pConfig->srcMasterInterface |
917 pConfig->dstMasterInterface |
918 pConfig->flowControler | dmacHw_REG_CTL_INT_EN;
919 }
920
921 /* Set block transaction size to one 32 bit transaction */
922 pRing->pHead->ctl.hi = dmacHw_REG_CTL_BLOCK_TS_MASK & 1;
923
924 /* Remember the descriptor to initialize the registers */
925 if (pRing->pProg == dmacHw_DESC_INIT) {
926 pRing->pProg = pRing->pHead;
927 }
928 pRing->pEnd = pRing->pHead;
929
930 /* Advance the descriptor */
931 dmacHw_NEXT_DESC(pRing, pHead);
932
933 /* Update Tail pointer if destination is a peripheral */
934 if (!dmacHw_DST_IS_MEMORY(pConfig->transferType)) {
935 pRing->pTail = pRing->pHead;
936 }
937 return 0;
938}
939
940/****************************************************************************/
941/**
942* @brief Sets channel specific user data
943*
944* This function associates user data to a specific DMA channel
945*
946*/
947/****************************************************************************/
948void dmacHw_setChannelUserData(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
949 void *userData /* [ IN ] User data */
950 ) {
951 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
952
953 pCblk->userData = userData;
954}
955
956/****************************************************************************/
957/**
958* @brief Gets channel specific user data
959*
960* This function returns user data specific to a DMA channel
961*
962* @return user data
963*/
964/****************************************************************************/
965void *dmacHw_getChannelUserData(dmacHw_HANDLE_t handle /* [ IN ] DMA Channel handle */
966 ) {
967 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
968
969 return pCblk->userData;
970}
971
972/****************************************************************************/
973/**
974* @brief Resets descriptor control information
975*
976* @return void
977*/
978/****************************************************************************/
979void dmacHw_resetDescriptorControl(void *pDescriptor /* [ IN ] Descriptor buffer */
980 ) {
981 int i;
982 dmacHw_DESC_RING_t *pRing;
983 dmacHw_DESC_t *pDesc;
984
985 pRing = dmacHw_GET_DESC_RING(pDescriptor);
986 pDesc = pRing->pHead;
987
988 for (i = 0; i < pRing->num; i++) {
989 /* Mark descriptor is ready to use */
990 pDesc->ctl.hi = dmacHw_DESC_FREE;
991 /* Look into next link list item */
992 pDesc++;
993 }
994 pRing->pFree = pRing->pTail = pRing->pEnd = pRing->pHead;
995 pRing->pProg = dmacHw_DESC_INIT;
996}
997
998/****************************************************************************/
999/**
1000* @brief Displays channel specific registers and other control parameters
1001*
1002* @return void
1003*
1004*
1005* @note
1006* None
1007*/
1008/****************************************************************************/
1009void dmacHw_printDebugInfo(dmacHw_HANDLE_t handle, /* [ IN ] DMA Channel handle */
1010 void *pDescriptor, /* [ IN ] Descriptor buffer */
1011 int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */
1012 ) {
1013 dmacHw_CBLK_t *pCblk = dmacHw_HANDLE_TO_CBLK(handle);
1014
1015 DisplayRegisterContents(pCblk->module, pCblk->channel, fpPrint);
1016 DisplayDescRing(pDescriptor, fpPrint);
1017}
diff --git a/arch/arm/mach-bcmring/csp/tmr/Makefile b/arch/arm/mach-bcmring/csp/tmr/Makefile
new file mode 100644
index 00000000000..244a61ab769
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/tmr/Makefile
@@ -0,0 +1 @@
obj-y += tmrHw.o
diff --git a/arch/arm/mach-bcmring/csp/tmr/tmrHw.c b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
new file mode 100644
index 00000000000..16225e43f3c
--- /dev/null
+++ b/arch/arm/mach-bcmring/csp/tmr/tmrHw.c
@@ -0,0 +1,576 @@
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 tmrHw.c
18*
19* @brief Low level Timer driver routines
20*
21* @note
22*
23* These routines provide basic timer functionality only.
24*/
25/****************************************************************************/
26
27/* ---- Include Files ---------------------------------------------------- */
28
29#include <csp/errno.h>
30#include <csp/stdint.h>
31
32#include <csp/tmrHw.h>
33#include <mach/csp/tmrHw_reg.h>
34
35#define tmrHw_ASSERT(a) if (!(a)) *(char *)0 = 0
36#define tmrHw_MILLISEC_PER_SEC (1000)
37
38#define tmrHw_LOW_1_RESOLUTION_COUNT (tmrHw_LOW_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
39#define tmrHw_LOW_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_1_RESOLUTION_COUNT)
40#define tmrHw_LOW_16_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 16)
41#define tmrHw_LOW_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_16_RESOLUTION_COUNT)
42#define tmrHw_LOW_256_RESOLUTION_COUNT (tmrHw_LOW_1_RESOLUTION_COUNT / 256)
43#define tmrHw_LOW_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_LOW_256_RESOLUTION_COUNT)
44
45#define tmrHw_HIGH_1_RESOLUTION_COUNT (tmrHw_HIGH_RESOLUTION_CLOCK / tmrHw_MILLISEC_PER_SEC)
46#define tmrHw_HIGH_1_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_1_RESOLUTION_COUNT)
47#define tmrHw_HIGH_16_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 16)
48#define tmrHw_HIGH_16_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_16_RESOLUTION_COUNT)
49#define tmrHw_HIGH_256_RESOLUTION_COUNT (tmrHw_HIGH_1_RESOLUTION_COUNT / 256)
50#define tmrHw_HIGH_256_MAX_MILLISEC (0xFFFFFFFF / tmrHw_HIGH_256_RESOLUTION_COUNT)
51
52static void ResetTimer(tmrHw_ID_t timerId)
53 __attribute__ ((section(".aramtext")));
54static int tmrHw_divide(int num, int denom)
55 __attribute__ ((section(".aramtext")));
56
57/****************************************************************************/
58/**
59* @brief Get timer capability
60*
61* This function returns various capabilities/attributes of a timer
62*
63* @return Capability
64*
65*/
66/****************************************************************************/
67uint32_t tmrHw_getTimerCapability(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
68 tmrHw_CAPABILITY_e capability /* [ IN ] Timer capability */
69) {
70 switch (capability) {
71 case tmrHw_CAPABILITY_CLOCK:
72 return (timerId <=
73 1) ? tmrHw_LOW_RESOLUTION_CLOCK :
74 tmrHw_HIGH_RESOLUTION_CLOCK;
75 case tmrHw_CAPABILITY_RESOLUTION:
76 return 32;
77 default:
78 return 0;
79 }
80 return 0;
81}
82
83/****************************************************************************/
84/**
85* @brief Resets a timer
86*
87* This function initializes timer
88*
89* @return void
90*
91*/
92/****************************************************************************/
93static void ResetTimer(tmrHw_ID_t timerId /* [ IN ] Timer Id */
94) {
95 /* Reset timer */
96 pTmrHw[timerId].LoadValue = 0;
97 pTmrHw[timerId].CurrentValue = 0xFFFFFFFF;
98 pTmrHw[timerId].Control = 0;
99 pTmrHw[timerId].BackgroundLoad = 0;
100 /* Always configure as a 32 bit timer */
101 pTmrHw[timerId].Control |= tmrHw_CONTROL_32BIT;
102 /* Clear interrupt only if raw status interrupt is set */
103 if (pTmrHw[timerId].RawInterruptStatus) {
104 pTmrHw[timerId].InterruptClear = 0xFFFFFFFF;
105 }
106}
107
108/****************************************************************************/
109/**
110* @brief Sets counter value for an interval in ms
111*
112* @return On success: Effective counter value set
113* On failure: 0
114*
115*/
116/****************************************************************************/
117static tmrHw_INTERVAL_t SetTimerPeriod(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
118 tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */
119) {
120 uint32_t scale = 0;
121 uint32_t count = 0;
122
123 if (timerId == 0 || timerId == 1) {
124 if (msec <= tmrHw_LOW_1_MAX_MILLISEC) {
125 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
126 scale = tmrHw_LOW_1_RESOLUTION_COUNT;
127 } else if (msec <= tmrHw_LOW_16_MAX_MILLISEC) {
128 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
129 scale = tmrHw_LOW_16_RESOLUTION_COUNT;
130 } else if (msec <= tmrHw_LOW_256_MAX_MILLISEC) {
131 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
132 scale = tmrHw_LOW_256_RESOLUTION_COUNT;
133 } else {
134 return 0;
135 }
136
137 count = msec * scale;
138 /* Set counter value */
139 pTmrHw[timerId].LoadValue = count;
140 pTmrHw[timerId].BackgroundLoad = count;
141
142 } else if (timerId == 2 || timerId == 3) {
143 if (msec <= tmrHw_HIGH_1_MAX_MILLISEC) {
144 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
145 scale = tmrHw_HIGH_1_RESOLUTION_COUNT;
146 } else if (msec <= tmrHw_HIGH_16_MAX_MILLISEC) {
147 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
148 scale = tmrHw_HIGH_16_RESOLUTION_COUNT;
149 } else if (msec <= tmrHw_HIGH_256_MAX_MILLISEC) {
150 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
151 scale = tmrHw_HIGH_256_RESOLUTION_COUNT;
152 } else {
153 return 0;
154 }
155
156 count = msec * scale;
157 /* Set counter value */
158 pTmrHw[timerId].LoadValue = count;
159 pTmrHw[timerId].BackgroundLoad = count;
160 }
161 return count / scale;
162}
163
164/****************************************************************************/
165/**
166* @brief Configures a periodic timer in terms of timer interrupt rate
167*
168* This function initializes a periodic timer to generate specific number of
169* timer interrupt per second
170*
171* @return On success: Effective timer frequency
172* On failure: 0
173*
174*/
175/****************************************************************************/
176tmrHw_RATE_t tmrHw_setPeriodicTimerRate(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
177 tmrHw_RATE_t rate /* [ IN ] Number of timer interrupt per second */
178) {
179 uint32_t resolution = 0;
180 uint32_t count = 0;
181 ResetTimer(timerId);
182
183 /* Set timer mode periodic */
184 pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
185 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
186 /* Set timer in highest resolution */
187 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
188
189 if (rate && (timerId == 0 || timerId == 1)) {
190 if (rate > tmrHw_LOW_RESOLUTION_CLOCK) {
191 return 0;
192 }
193 resolution = tmrHw_LOW_RESOLUTION_CLOCK;
194 } else if (rate && (timerId == 2 || timerId == 3)) {
195 if (rate > tmrHw_HIGH_RESOLUTION_CLOCK) {
196 return 0;
197 } else {
198 resolution = tmrHw_HIGH_RESOLUTION_CLOCK;
199 }
200 } else {
201 return 0;
202 }
203 /* Find the counter value */
204 count = resolution / rate;
205 /* Set counter value */
206 pTmrHw[timerId].LoadValue = count;
207 pTmrHw[timerId].BackgroundLoad = count;
208
209 return resolution / count;
210}
211
212/****************************************************************************/
213/**
214* @brief Configures a periodic timer to generate timer interrupt after
215* certain time interval
216*
217* This function initializes a periodic timer to generate timer interrupt
218* after every time interval in millisecond
219*
220* @return On success: Effective interval set in milli-second
221* On failure: 0
222*
223*/
224/****************************************************************************/
225tmrHw_INTERVAL_t tmrHw_setPeriodicTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
226 tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */
227) {
228 ResetTimer(timerId);
229
230 /* Set timer mode periodic */
231 pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
232 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
233
234 return SetTimerPeriod(timerId, msec);
235}
236
237/****************************************************************************/
238/**
239* @brief Configures a periodic timer to generate timer interrupt just once
240* after certain time interval
241*
242* This function initializes a periodic timer to generate a single ticks after
243* certain time interval in millisecond
244*
245* @return On success: Effective interval set in milli-second
246* On failure: 0
247*
248*/
249/****************************************************************************/
250tmrHw_INTERVAL_t tmrHw_setOneshotTimerInterval(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
251 tmrHw_INTERVAL_t msec /* [ IN ] Interval in milli-second */
252) {
253 ResetTimer(timerId);
254
255 /* Set timer mode oneshot */
256 pTmrHw[timerId].Control |= tmrHw_CONTROL_PERIODIC;
257 pTmrHw[timerId].Control |= tmrHw_CONTROL_ONESHOT;
258
259 return SetTimerPeriod(timerId, msec);
260}
261
262/****************************************************************************/
263/**
264* @brief Configures a timer to run as a free running timer
265*
266* This function initializes a timer to run as a free running timer
267*
268* @return Timer resolution (count / sec)
269*
270*/
271/****************************************************************************/
272tmrHw_RATE_t tmrHw_setFreeRunningTimer(tmrHw_ID_t timerId, /* [ IN ] Timer Id */
273 uint32_t divider /* [ IN ] Dividing the clock frequency */
274) {
275 uint32_t scale = 0;
276
277 ResetTimer(timerId);
278 /* Set timer as free running mode */
279 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_PERIODIC;
280 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_ONESHOT;
281
282 if (divider >= 64) {
283 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_256;
284 scale = 256;
285 } else if (divider >= 8) {
286 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_16;
287 scale = 16;
288 } else {
289 pTmrHw[timerId].Control |= tmrHw_CONTROL_PRESCALE_1;
290 scale = 1;
291 }
292
293 if (timerId == 0 || timerId == 1) {
294 return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, scale);
295 } else if (timerId == 2 || timerId == 3) {
296 return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, scale);
297 }
298
299 return 0;
300}
301
302/****************************************************************************/
303/**
304* @brief Starts a timer
305*
306* This function starts a preconfigured timer
307*
308* @return -1 - On Failure
309* 0 - On Success
310*
311*/
312/****************************************************************************/
313int tmrHw_startTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */
314) {
315 pTmrHw[timerId].Control |= tmrHw_CONTROL_TIMER_ENABLE;
316 return 0;
317}
318
319/****************************************************************************/
320/**
321* @brief Stops a timer
322*
323* This function stops a running timer
324*
325* @return -1 - On Failure
326* 0 - On Success
327*
328*/
329/****************************************************************************/
330int tmrHw_stopTimer(tmrHw_ID_t timerId /* [ IN ] Timer id */
331) {
332 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_TIMER_ENABLE;
333 return 0;
334}
335
336/****************************************************************************/
337/**
338* @brief Gets current timer count
339*
340* This function returns the current timer value
341*
342* @return Current downcounting timer value
343*
344*/
345/****************************************************************************/
346uint32_t tmrHw_GetCurrentCount(tmrHw_ID_t timerId /* [ IN ] Timer id */
347) {
348 /* return 32 bit timer value */
349 switch (pTmrHw[timerId].Control & tmrHw_CONTROL_MODE_MASK) {
350 case tmrHw_CONTROL_FREE_RUNNING:
351 if (pTmrHw[timerId].CurrentValue) {
352 return tmrHw_MAX_COUNT - pTmrHw[timerId].CurrentValue;
353 }
354 break;
355 case tmrHw_CONTROL_PERIODIC:
356 case tmrHw_CONTROL_ONESHOT:
357 return pTmrHw[timerId].BackgroundLoad -
358 pTmrHw[timerId].CurrentValue;
359 }
360 return 0;
361}
362
363/****************************************************************************/
364/**
365* @brief Gets timer count rate
366*
367* This function returns the number of counts per second
368*
369* @return Count rate
370*
371*/
372/****************************************************************************/
373tmrHw_RATE_t tmrHw_getCountRate(tmrHw_ID_t timerId /* [ IN ] Timer id */
374) {
375 uint32_t divider = 0;
376
377 switch (pTmrHw[timerId].Control & tmrHw_CONTROL_PRESCALE_MASK) {
378 case tmrHw_CONTROL_PRESCALE_1:
379 divider = 1;
380 break;
381 case tmrHw_CONTROL_PRESCALE_16:
382 divider = 16;
383 break;
384 case tmrHw_CONTROL_PRESCALE_256:
385 divider = 256;
386 break;
387 default:
388 tmrHw_ASSERT(0);
389 }
390
391 if (timerId == 0 || timerId == 1) {
392 return tmrHw_divide(tmrHw_LOW_RESOLUTION_CLOCK, divider);
393 } else {
394 return tmrHw_divide(tmrHw_HIGH_RESOLUTION_CLOCK, divider);
395 }
396 return 0;
397}
398
399/****************************************************************************/
400/**
401* @brief Enables timer interrupt
402*
403* This function enables the timer interrupt
404*
405* @return N/A
406*
407*/
408/****************************************************************************/
409void tmrHw_enableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */
410) {
411 pTmrHw[timerId].Control |= tmrHw_CONTROL_INTERRUPT_ENABLE;
412}
413
414/****************************************************************************/
415/**
416* @brief Disables timer interrupt
417*
418* This function disable the timer interrupt
419*
420* @return N/A
421*
422*/
423/****************************************************************************/
424void tmrHw_disableInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */
425) {
426 pTmrHw[timerId].Control &= ~tmrHw_CONTROL_INTERRUPT_ENABLE;
427}
428
429/****************************************************************************/
430/**
431* @brief Clears the interrupt
432*
433* This function clears the timer interrupt
434*
435* @return N/A
436*
437* @note
438* Must be called under the context of ISR
439*/
440/****************************************************************************/
441void tmrHw_clearInterrupt(tmrHw_ID_t timerId /* [ IN ] Timer id */
442) {
443 pTmrHw[timerId].InterruptClear = 0x1;
444}
445
446/****************************************************************************/
447/**
448* @brief Gets the interrupt status
449*
450* This function returns timer interrupt status
451*
452* @return Interrupt status
453*/
454/****************************************************************************/
455tmrHw_INTERRUPT_STATUS_e tmrHw_getInterruptStatus(tmrHw_ID_t timerId /* [ IN ] Timer id */
456) {
457 if (pTmrHw[timerId].InterruptStatus) {
458 return tmrHw_INTERRUPT_STATUS_SET;
459 } else {
460 return tmrHw_INTERRUPT_STATUS_UNSET;
461 }
462}
463
464/****************************************************************************/
465/**
466* @brief Indentifies a timer causing interrupt
467*
468* This functions returns a timer causing interrupt
469*
470* @return 0xFFFFFFFF : No timer causing an interrupt
471* ! 0xFFFFFFFF : timer causing an interrupt
472* @note
473* tmrHw_clearIntrrupt() must be called with a valid timer id after calling this function
474*/
475/****************************************************************************/
476tmrHw_ID_t tmrHw_getInterruptSource(void /* void */
477) {
478 int i;
479
480 for (i = 0; i < tmrHw_TIMER_NUM_COUNT; i++) {
481 if (pTmrHw[i].InterruptStatus) {
482 return i;
483 }
484 }
485
486 return 0xFFFFFFFF;
487}
488
489/****************************************************************************/
490/**
491* @brief Displays specific timer registers
492*
493*
494* @return void
495*
496*/
497/****************************************************************************/
498void tmrHw_printDebugInfo(tmrHw_ID_t timerId, /* [ IN ] Timer id */
499 int (*fpPrint) (const char *, ...) /* [ IN ] Print callback function */
500) {
501 (*fpPrint) ("Displaying register contents \n\n");
502 (*fpPrint) ("Timer %d: Load value 0x%X\n", timerId,
503 pTmrHw[timerId].LoadValue);
504 (*fpPrint) ("Timer %d: Background load value 0x%X\n", timerId,
505 pTmrHw[timerId].BackgroundLoad);
506 (*fpPrint) ("Timer %d: Control 0x%X\n", timerId,
507 pTmrHw[timerId].Control);
508 (*fpPrint) ("Timer %d: Interrupt clear 0x%X\n", timerId,
509 pTmrHw[timerId].InterruptClear);
510 (*fpPrint) ("Timer %d: Interrupt raw interrupt 0x%X\n", timerId,
511 pTmrHw[timerId].RawInterruptStatus);
512 (*fpPrint) ("Timer %d: Interrupt status 0x%X\n", timerId,
513 pTmrHw[timerId].InterruptStatus);
514}
515
516/****************************************************************************/
517/**
518* @brief Use a timer to perform a busy wait delay for a number of usecs.
519*
520* @return N/A
521*/
522/****************************************************************************/
523void tmrHw_udelay(tmrHw_ID_t timerId, /* [ IN ] Timer id */
524 unsigned long usecs /* [ IN ] usec to delay */
525) {
526 tmrHw_RATE_t usec_tick_rate;
527 tmrHw_COUNT_t start_time;
528 tmrHw_COUNT_t delta_time;
529
530 start_time = tmrHw_GetCurrentCount(timerId);
531 usec_tick_rate = tmrHw_divide(tmrHw_getCountRate(timerId), 1000000);
532 delta_time = usecs * usec_tick_rate;
533
534 /* Busy wait */
535 while (delta_time > (tmrHw_GetCurrentCount(timerId) - start_time))
536 ;
537}
538
539/****************************************************************************/
540/**
541* @brief Local Divide function
542*
543* This function does the divide
544*
545* @return divide value
546*
547*/
548/****************************************************************************/
549static int tmrHw_divide(int num, int denom)
550{
551 int r;
552 int t = 1;
553
554 /* Shift denom and t up to the largest value to optimize algorithm */
555 /* t contains the units of each divide */
556 while ((denom & 0x40000000) == 0) { /* fails if denom=0 */
557 denom = denom << 1;
558 t = t << 1;
559 }
560
561 /* Initialize the result */
562 r = 0;
563
564 do {
565 /* Determine if there exists a positive remainder */
566 if ((num - denom) >= 0) {
567 /* Accumlate t to the result and calculate a new remainder */
568 num = num - denom;
569 r = r + t;
570 }
571 /* Continue to shift denom and shift t down to 0 */
572 denom = denom >> 1;
573 t = t >> 1;
574 } while (t != 0);
575 return r;
576}