1 //*****************************************************************************
2 //
3 // peci.c - Driver for the Platform Environment Control Interface (PECI)
4 //          module.
5 //
6 // Copyright (c) 2010-2011 Texas Instruments Incorporated.  All rights reserved.
7 // Software License Agreement
8 //
9 // Texas Instruments (TI) is supplying this software for use solely and
10 // exclusively on TI's microcontroller products. The software is owned by
11 // TI and/or its suppliers, and is protected under applicable copyright
12 // laws. You may not combine this software with "viral" open-source
13 // software in order to form a larger program.
14 //
15 // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
16 // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
17 // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
19 // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
20 // DAMAGES, FOR ANY REASON WHATSOEVER.
21 //
22 // This is part of revision 8264 of the Stellaris Peripheral Driver Library.
23 //
24 //*****************************************************************************
25 
26 //*****************************************************************************
27 //
28 //! \addtogroup peci_api
29 //! @{
30 //
31 //*****************************************************************************
32 
33 #include "inc/hw_ints.h"
34 #include "inc/hw_memmap.h"
35 #include "inc/hw_peci.h"
36 #include "inc/hw_sysctl.h"
37 #include "inc/hw_types.h"
38 #include "driverlib/debug.h"
39 #include "driverlib/interrupt.h"
40 #include "driverlib/peci.h"
41 
42 //*****************************************************************************
43 //
44 // The following defines provide characteristics of the PECI module that are
45 // important to the driver but which can not be gleaned from the register
46 // definitions.
47 //
48 //*****************************************************************************
49 #define PECI_MAX_BAUD           2000000     // Maximum baud rate
50 #define PECI_MIN_BAUD           2000        // Minimum baud rate
51 #define PECI_MIN_RATIO          8           // Minimum baud rate divider
52 #define PECI_MAX_RATIO          65535       // Maximum baud rate divider
53 #define PECI_POLL_PRESCALE      4096        // Polling timer prescaler
54 #define PECI_MIN_POLL           2           // Minimum polling interval (ms)
55 #define PECI_MAX_POLL           1000        // Maximum polling interval (ms)
56 
57 //*****************************************************************************
58 //
59 //! \internal
60 //! Checks a PECI domain.
61 //!
62 //! \param ulDomain is the PECI domain identifier.
63 //!
64 //! This function determines if a domain identifier is valid.
65 //!
66 //! \return Returns \b true if the domain identifier is valid and \b false
67 //! otherwise.
68 //
69 //*****************************************************************************
70 #ifdef DEBUG
71 static tBoolean
PECIDomainValid(unsigned long ulDomain)72 PECIDomainValid(unsigned long ulDomain)
73 {
74     return((ulDomain == PECI_DOMAIN_M0D0) ||
75            (ulDomain == PECI_DOMAIN_M0D1) ||
76            (ulDomain == PECI_DOMAIN_M1D0) ||
77            (ulDomain == PECI_DOMAIN_M1D1));
78 }
79 #endif
80 
81 //*****************************************************************************
82 //
83 //! Sets the configuration of the PECI module.
84 //!
85 //! \param ulBase is the base address of the PECI module.
86 //! \param ulPECIClk is the rate of the clock supplied to the PECI module.
87 //! \param ulBaud is the bit rate that should be used for the PECI transfers.
88 //! \param ulPoll is the polling rate, in ms, that should be used for the
89 //! time between PECI polls.
90 //! \param ulOffset is the offset to be applied to all temperature values to
91 //! convert from relative to absolute.
92 //! \param ulRetry is the number of retry attempts for a PECI transaction.
93 //!
94 //! This function initializes operation of the PECI block.  It programs the bit
95 //! rate, polling rate and retry counts for PECI transactions.  It also
96 //! programs the offset value to be used to translate relative temperature
97 //! values from PECI transactions to absolute values.  At the end of this
98 //! function, no host/domain combinations are enabled.  Each desired
99 //! host/domain combination can be configured/enabled with a call to
100 //! PECIDomainEnable().
101 //!
102 //! The peripheral clock is the same as the processor clock.  This value is
103 //! returned by SysCtlClockGet(), or it can be explicitly hard coded if it is
104 //! constant and known (to save the code/execution overhead of a call to
105 //! SysCtlClockGet()).
106 //!
107 //! The \e ulBaud parameter defines the bit rate for the PECI transactions.
108 //! This value is used to calculate a divisor value based on the specified
109 //! \e ulPECIClk.  If the exact baud rate cannot be achieved (due to rounding),
110 //! the baud rate is programmed to the nearest value that is less than the
111 //! specified value.
112 //!
113 //! The \e ulPoll parameter defines the polling rate, in milliseconds, used
114 //! for PECI transactions.  For generation of the polling rate, the \e
115 //! ulPECIClk is pre-divided by \b 4096.  A value of 0 disables the polling
116 //! feature.  If the exact polling rate cannot be achieved (due to rounding),
117 //! the polling rate is programmed to the nearest value that is greater than
118 //! the specified value.
119 //!
120 //! The \e ulRetry parameter defines the number of PECI transactions that are
121 //! attempted before indicating an error condition.
122 //!
123 //! \return None.
124 //
125 //*****************************************************************************
126 void
PECIConfigSet(unsigned long ulBase,unsigned long ulPECIClk,unsigned long ulBaud,unsigned long ulPoll,unsigned long ulOffset,unsigned long ulRetry)127 PECIConfigSet(unsigned long ulBase, unsigned long ulPECIClk,
128               unsigned long ulBaud, unsigned long ulPoll,
129               unsigned long ulOffset, unsigned long ulRetry)
130 {
131     unsigned long ulTemp, ulDiv;
132 
133     //
134     // Check the arguments.
135     //
136     ASSERT(ulBase == PECI0_BASE);
137     ASSERT(ulPECIClk != 0);
138     ASSERT((ulBaud != 0) && (ulBaud <= PECI_MAX_BAUD) &&
139            (ulBaud >= PECI_MIN_BAUD) &&
140            ((ulBaud * 4 * PECI_MIN_RATIO) < ulPECIClk));
141     ASSERT((ulPoll == 0) ||
142            ((ulPoll >= PECI_MIN_POLL) && (ulPoll <= PECI_MAX_POLL)));
143 
144     //
145     // Generate value for the PECI Control Register.
146     //
147     ulTemp = ((ulOffset << PECI_CTL_OFFSET_S) & PECI_CTL_OFFSET_M);
148     ulTemp |= ((ulRetry << PECI_CTL_CRETRY_S) & PECI_CTL_CRETRY_M);
149     HWREG(ulBase + PECI_O_CTL) = ulTemp;
150 
151     //
152     // Compute the divisor for the PECI baud rate clock.
153     // Round up, to ensure programmed baud rate is <= specified rate.
154     // Ensure that proper ratio is maintained for clock:baud.
155     //
156     ulDiv = (ulPECIClk + (4 * ulBaud) - 1) / (4 * ulBaud);
157     ulDiv = (ulDiv < PECI_MIN_RATIO) ? PECI_MIN_RATIO : ulDiv;
158     ulDiv = (ulDiv > PECI_MAX_RATIO) ? PECI_MAX_RATIO : ulDiv;
159     ulTemp = ((ulDiv << PECI_DIV_BAUD_S) & PECI_DIV_BAUD_M);
160 
161     //
162     // Compute the divisor for the PECI polling rate.
163     // Round up, to ensure programmed polling rate is >= specified rate.
164     //
165     ulDiv = ((ulPoll == 0) ? 0 : ((((ulPECIClk * ulPoll) / 1000) +
166                                    (PECI_POLL_PRESCALE - 1)) /
167                                   PECI_POLL_PRESCALE));
168     ulTemp |= ((ulDiv << PECI_DIV_POLL_S) & PECI_DIV_POLL_M);;
169     HWREG(ulBase + PECI_O_DIV) = ulTemp;
170 }
171 
172 //*****************************************************************************
173 //
174 //! Gets the current configuration of the PECI module.
175 //!
176 //! \param ulBase is the base address of the PECI module.
177 //! \param ulPECIClk is the rate of the clock supplied to the PECI module.
178 //! \param pulBaud is a pointer to storage for the bit rate.
179 //! \param pulPoll is a pointer to storage for the polling rate.
180 //! \param pulOffset is a pointer to stoarage for the offset.
181 //! \param pulRetry is a pointer to storage for the retry count.
182 //!
183 //! The baud rate and poll rate for the PECI module are determined, given an
184 //! explicitly provided peripheral clock.  The returned rates are the actual
185 //! rates being used; they may not be the same as the requested rates, due to
186 //! rounding in the calculations.
187 //!
188 //! The peripheral clock is the same as the processor clock.  This value is
189 //! returned by SysCtlClockGet(), or it can be explicitly hard coded if it is
190 //! constant and known (to save the code/execution overhead of a call to
191 //! SysCtlClockGet()).
192 //!
193 //! \return None.
194 //
195 //*****************************************************************************
196 void
PECIConfigGet(unsigned long ulBase,unsigned long ulPECIClk,unsigned long * pulBaud,unsigned long * pulPoll,unsigned long * pulOffset,unsigned long * pulRetry)197 PECIConfigGet(unsigned long ulBase, unsigned long ulPECIClk,
198               unsigned long *pulBaud, unsigned long *pulPoll,
199               unsigned long *pulOffset, unsigned long *pulRetry)
200 {
201     unsigned long ulTemp;
202 
203     //
204     // Check the arguments.
205     //
206     ASSERT(ulBase == PECI0_BASE);
207     ASSERT(ulPECIClk != 0);
208     ASSERT(*pulBaud != 0);
209     ASSERT(*pulPoll != 0);
210     ASSERT(*pulOffset != 0);
211     ASSERT(*pulRetry != 0);
212 
213     //
214     // Retrieve the Offset and Retry values
215     //
216     ulTemp = HWREG(ulBase + PECI_O_CTL);
217     *pulOffset = ((ulTemp & PECI_CTL_OFFSET_M) >> PECI_CTL_OFFSET_S);
218     *pulRetry = ((ulTemp & PECI_CTL_CRETRY_M) >> PECI_CTL_CRETRY_S);
219 
220     //
221     // Calculate the baud rate.
222     //
223     ulTemp = HWREG(ulBase + PECI_O_DIV);
224     *pulBaud = ulPECIClk / ((ulTemp & PECI_DIV_BAUD_M) >> PECI_DIV_BAUD_S);
225 
226     //
227     // Compute the divisor for the PECI polling rate.
228     // Round up, to ensure programmed polling rate is >= specified rate.
229     //
230     *pulPoll = ((((ulTemp & PECI_DIV_POLL_M) >> PECI_DIV_POLL_S) * 1000) /
231         (ulPECIClk / PECI_POLL_PRESCALE));
232 }
233 
234 //*****************************************************************************
235 //
236 //! Enables bypassing of negotiation errors.
237 //!
238 //! \param ulBase is the base address of the PECI module.
239 //!
240 //! This function enables bypassing of negotiation errors that might occur
241 //! during a PECI transaction.  When enabled, negotiation errors are ignored.
242 //!
243 //! \return None.
244 //
245 //*****************************************************************************
246 void
PECIBypassEnable(unsigned long ulBase)247 PECIBypassEnable(unsigned long ulBase)
248 {
249     //
250     // Check the arguments.
251     //
252     ASSERT(ulBase == PECI0_BASE);
253 
254     //
255     // Enable bypass.
256     //
257     HWREG(ulBase + PECI_O_CTL) |= PECI_CTL_BYERR;
258 }
259 
260 //*****************************************************************************
261 //
262 //! Disables bypassing of negotiation errors.
263 //!
264 //! \param ulBase is the base address of the PECI module.
265 //!
266 //! This function disables bypassing of negotiation errors that might occur
267 //! during a PECI transaction.  When disabled, negotiation errors are reported
268 //! and the remainder of the transaction is aborted.
269 //!
270 //! \return None.
271 //
272 //*****************************************************************************
273 void
PECIBypassDisable(unsigned long ulBase)274 PECIBypassDisable(unsigned long ulBase)
275 {
276     //
277     // Check the arguments.
278     //
279     ASSERT(ulBase == PECI0_BASE);
280 
281     //
282     // Disable bypass.
283     //
284     HWREG(ulBase + PECI_O_CTL) &= ~PECI_CTL_BYERR;
285 }
286 
287 //*****************************************************************************
288 //
289 //! Sets the configuration of the specified PECI domain.
290 //!
291 //! \param ulBase is the base address of the PECI module.
292 //! \param ulDomain is the PECI domain that should be configured.
293 //! \param ulHigh is the high temperature threshold value.
294 //! \param ulLow is the low temperature threshold value.
295 //!
296 //! This function configures the specified PECI domain for temperature
297 //! monitoring  operations.  The values for \e ulHigh and \e ulLow can be
298 //! specified as values relative to the maximum temperature allowed, or they
299 //! can be specified as absolute temperatures if an offset was programmed
300 //! in the PECIConfigSet() function.
301 //!
302 //! The \e ulDomain parameter can be one of the following values:
303 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
304 //! \b PECI_DOMAIN_M1D1.
305 //!
306 //! \return None.
307 //
308 //*****************************************************************************
309 void
PECIDomainConfigSet(unsigned long ulBase,unsigned long ulDomain,unsigned long ulHigh,unsigned long ulLow)310 PECIDomainConfigSet(unsigned long ulBase, unsigned long ulDomain,
311                     unsigned long ulHigh, unsigned long ulLow)
312 {
313     //
314     // Check the arguments.
315     //
316     ASSERT(ulBase == PECI0_BASE);
317     ASSERT(PECIDomainValid(ulDomain));
318     ASSERT(ulHigh <= 0xFFFF);
319     ASSERT(ulLow <= 0xFFFF);
320     ASSERT(ulHigh > ulLow);
321 
322     //
323     // Set the HTHRESH and LTHRESH fields in the domain control/status
324     // register.
325     //
326     HWREG(ulBase + PECI_O_M0D0C + (ulDomain * 4)) =
327         (((ulHigh << PECI_M0D0C_HITHR_S) & PECI_M0D0C_HITHR_M) |
328          ((ulLow << PECI_M0D0C_LOTHR_S) & PECI_M0D0C_LOTHR_M));
329 }
330 
331 //*****************************************************************************
332 //
333 //! Gets the configuration of the specified PECI domain.
334 //!
335 //! \param ulBase is the base address of the PECI module.
336 //! \param ulDomain is the PECI domain that should be configured.
337 //! \param pulHigh is a pointer to storage for the high threshold.
338 //! \param pulLow is a pointer to storage for the low threshold.
339 //!
340 //! This function configures the specified PECI domain for temperature
341 //! monitoring  operations.  The values for \e ulHigh and \e ulLow can be
342 //! specified as values relative to the maximum temperature allowed, or they
343 //! can be specified as absolute temperatures if an offset was programmed
344 //! in the PECIConfigSet() function.
345 //!
346 //! The \e ulDomain parameter can be one of the following values:
347 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
348 //! \b PECI_DOMAIN_M1D1.
349 //!
350 //! \return None.
351 //
352 //*****************************************************************************
353 void
PECIDomainConfigGet(unsigned long ulBase,unsigned long ulDomain,unsigned long * pulHigh,unsigned long * pulLow)354 PECIDomainConfigGet(unsigned long ulBase, unsigned long ulDomain,
355                     unsigned long *pulHigh, unsigned long *pulLow)
356 {
357     unsigned long ulTemp;
358 
359     //
360     // Check the arguments.
361     //
362     ASSERT(ulBase == PECI0_BASE);
363     ASSERT(PECIDomainValid(ulDomain));
364     ASSERT(pulHigh != 0);
365     ASSERT(pulLow != 0);
366 
367     //
368     // Get the HTHRESH and LTHRESH fields in the domain control/status
369     // register.
370     //
371     ulTemp = HWREG(ulBase + PECI_O_M0D0C + (ulDomain * 4));
372     *pulHigh = ((ulTemp && PECI_M0D0C_HITHR_M) >> PECI_M0D0C_HITHR_S);
373     *pulLow = ((ulTemp && PECI_M0D0C_LOTHR_M) >> PECI_M0D0C_LOTHR_S);
374 }
375 
376 //*****************************************************************************
377 //
378 //! Enables a domain within the PECI module.
379 //!
380 //! \param ulBase is the base address of the PECI module.
381 //! \param ulDomain is the PECI domain that should be enabled.
382 //!
383 //! This function enables the specified PECI domain for temperature monitoring
384 //! operations.
385 //!
386 //! The \e ulDomain parameter can be one of the following values:
387 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
388 //! \b PECI_DOMAIN_M1D1.
389 //!
390 //! \return None.
391 //
392 //*****************************************************************************
393 void
PECIDomainEnable(unsigned long ulBase,unsigned long ulDomain)394 PECIDomainEnable(unsigned long ulBase, unsigned long ulDomain)
395 {
396     //
397     // Check the arguments.
398     //
399     ASSERT(ulBase == PECI0_BASE);
400     ASSERT(PECIDomainValid(ulDomain));
401 
402     //
403     // Enable the specified domain.
404     //
405     HWREG(ulBase + PECI_O_CTL) |= (1 << ulDomain);
406 }
407 
408 //*****************************************************************************
409 //
410 //! Disables a domain within the PECI module.
411 //!
412 //! \param ulBase is the base address of the PECI module.
413 //! \param ulDomain is the PECI domain that should be disabled.
414 //!
415 //! This function disables the specified PECI domain.
416 //!
417 //! The \e ulDomain parameter can be one of the following values:
418 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
419 //! \b PECI_DOMAIN_M1D1.
420 //!
421 //! \return None.
422 //
423 //*****************************************************************************
424 void
PECIDomainDisable(unsigned long ulBase,unsigned long ulDomain)425 PECIDomainDisable(unsigned long ulBase, unsigned long ulDomain)
426 {
427     //
428     // Check the arguments.
429     //
430     ASSERT(ulBase == PECI0_BASE);
431     ASSERT(PECIDomainValid(ulDomain));
432 
433     //
434     // Disable the specified domain.
435     //
436     HWREG(ulBase + PECI_O_CTL) &= ~(1 << ulDomain);
437 }
438 
439 //*****************************************************************************
440 //
441 //! Reads the current temperature value for the specified domain.
442 //!
443 //! \param ulBase is the base address of the PECI module.
444 //! \param ulDomain is the PECI domain that should be disabled.
445 //!
446 //! This function returns the most recently read temperature value from the
447 //! specified domain.
448 //!
449 //! The \e ulDomain parameter can be one of the following values:
450 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
451 //! \b PECI_DOMAIN_M1D1.
452 //!
453 //! \return None.
454 //
455 //*****************************************************************************
456 unsigned long
PECIDomainValueGet(unsigned long ulBase,unsigned long ulDomain)457 PECIDomainValueGet(unsigned long ulBase, unsigned long ulDomain)
458 {
459     //
460     // Check the arguments.
461     //
462     ASSERT(ulBase == PECI0_BASE);
463     ASSERT(PECIDomainValid(ulDomain));
464 
465     //
466     // Return the most recently polled temperature value
467     //
468     return(((HWREG(ulBase + PECI_O_M0D0 + (ulDomain * 4)) &
469              PECI_M0D0_VALUE_M)));
470 }
471 
472 //*****************************************************************************
473 //
474 //! Reads the maximum/error value for the specified domain.
475 //!
476 //! \param ulBase is the base address of the PECI module.
477 //! \param ulDomain is the PECI domain that should be disabled.
478 //!
479 //! This function returns the maximum temperature value for the specified
480 //! domain.
481 //!
482 //! The \e ulDomain parameter can be one of the following values:
483 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
484 //! \b PECI_DOMAIN_M1D1.
485 //!
486 //! \return None.
487 //
488 //*****************************************************************************
489 unsigned long
PECIDomainMaxReadGet(unsigned long ulBase,unsigned long ulDomain)490 PECIDomainMaxReadGet(unsigned long ulBase, unsigned long ulDomain)
491 {
492     //
493     // Check the arguments.
494     //
495     ASSERT(ulBase == PECI0_BASE);
496     ASSERT(PECIDomainValid(ulDomain));
497 
498     //
499     // Return the most recently polled temperature value
500     //
501     return(((HWREG(ulBase + PECI_O_M0D0 + (ulDomain * 4)) &
502              PECI_M0D0_MAXREAD_M) >> PECI_M0D0_MAXREAD_S));
503 }
504 
505 //*****************************************************************************
506 //
507 //! Clears the current temperature value for the specified domain.
508 //!
509 //! \param ulBase is the base address of the PECI module.
510 //! \param ulDomain is the PECI domain that should be disabled.
511 //!
512 //! This function clears the current and maximum values for the specified
513 //! domain.
514 //!
515 //! The \e ulDomain parameter can be one of the following values:
516 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
517 //! \b PECI_DOMAIN_M1D1.
518 //!
519 //! \return None.
520 //
521 //*****************************************************************************
522 void
PECIDomainValueClear(unsigned long ulBase,unsigned long ulDomain)523 PECIDomainValueClear(unsigned long ulBase, unsigned long ulDomain)
524 {
525     //
526     // Check the arguments.
527     //
528     ASSERT(ulBase == PECI0_BASE);
529     ASSERT(PECIDomainValid(ulDomain));
530 
531     //
532     // Clear the temperature value.
533     //
534     HWREG(ulBase + PECI_O_M0D0 + (ulDomain * 4) ) &= ~PECI_M0D0_VALUE_M;
535 }
536 
537 //*****************************************************************************
538 //
539 //! Clears the maximum/error value for the specified domain.
540 //!
541 //! \param ulBase is the base address of the PECI module.
542 //! \param ulDomain is the PECI domain that should be disabled.
543 //!
544 //! This function clears the current and maximum values for the specified
545 //! domain.
546 //!
547 //! The \e ulDomain parameter can be one of the following values:
548 //! \b PECI_DOMAIN_M0D0, \b PECI_DOMAIN_M0D1, \b PECI_DOMAIN_M1D0, or
549 //! \b PECI_DOMAIN_M1D1.
550 //!
551 //! \return None.
552 //
553 //*****************************************************************************
554 void
PECIDomainMaxReadClear(unsigned long ulBase,unsigned long ulDomain)555 PECIDomainMaxReadClear(unsigned long ulBase, unsigned long ulDomain)
556 {
557     //
558     // Check the arguments.
559     //
560     ASSERT(ulBase == PECI0_BASE);
561     ASSERT(PECIDomainValid(ulDomain));
562 
563     //
564     // Clear the maximum/error value.
565     //
566     HWREG(ulBase + PECI_O_M0D0 + (ulDomain * 4) ) &= ~PECI_M0D0_MAXREAD_M;
567 }
568 
569 //*****************************************************************************
570 //
571 //! Registers an interrupt handler for the PECI module.
572 //!
573 //! \param ulBase specifies the PECI module base address.
574 //! \param pfnHandler is a pointer to the function to be called when the
575 //! PECI interrupt occurs.
576 //!
577 //! This function registers the handler to be called when an PECI interrupt
578 //! occurs. This function enables the global interrupt in the interrupt
579 //! controller; specific PECI interrupts must be enabled via PECIIntEnable().
580 //! If necessary, it is the interrupt handler's responsibility to clear the
581 //! interrupt source via PECIIntClear().
582 //!
583 //! \sa IntRegister() for important information about registering interrupt
584 //! handlers.
585 //!
586 //! \return None.
587 //
588 //*****************************************************************************
589 void
PECIIntRegister(unsigned long ulBase,void (* pfnHandler)(void))590 PECIIntRegister(unsigned long ulBase, void (*pfnHandler)(void))
591 {
592     //
593     // Check the arguments.
594     //
595     ASSERT(ulBase == PECI0_BASE);
596     ASSERT(pfnHandler != 0);
597 
598     //
599     // Register the interrupt handler.
600     //
601     IntRegister(INT_PECI0, pfnHandler);
602 
603     //
604     // Enable the PECI interrupt.
605     //
606     IntEnable(INT_PECI0);
607 }
608 
609 //*****************************************************************************
610 //
611 //! Unregisters an interrupt handler for the PECI module.
612 //!
613 //! \param ulBase specifies the PECI module base address.
614 //!
615 //! This function unregisters the handler to be called when a PECI interrupt
616 //! occurs.  This function also masks off the interrupt in the interrupt
617 //! controller so that the interrupt handler no longer is called.
618 //!
619 //! \sa IntRegister() for important information about registering interrupt
620 //! handlers.
621 //!
622 //! \return None.
623 //
624 //*****************************************************************************
625 void
PECIIntUnregister(unsigned long ulBase)626 PECIIntUnregister(unsigned long ulBase)
627 {
628     //
629     // Check the arguments.
630     //
631     ASSERT(ulBase == PECI0_BASE);
632 
633     //
634     // Disable the PECI interrupt.
635     //
636     IntDisable(INT_PECI0);
637 
638     //
639     // Unregister the interrupt handler.
640     //
641     IntUnregister(INT_PECI0);
642 }
643 
644 //*****************************************************************************
645 //
646 //! Enables individual PECI interrupt sources.
647 //!
648 //! \param ulBase specifies the PECI module base address.
649 //! \param ulIntFlags is a bit mask of the interrupt sources to be enabled.
650 //! \param ulIntMode is the mode for the PECI domain interrupts.
651 //!
652 //! This function enables the indicated PECI interrupt sources.  Only the
653 //! sources that are enabled can be reflected to the processor interrupt;
654 //! disabled sources have no effect on the processor.
655 //!
656 //! The \e ulIntFlags parameter can be any of the following values:
657 //! \b PECI_READ, \b PECI_ERR, \b PECI_AC, \b PECI_M0D0, \b PECI_M0D1,
658 //! \b PECI_M1D0, or \b PECI_M1D1.
659 //!
660 //! The \e ulIntMode parameter is used to configure the interrupt mode for
661 //! the corresponding \b PECI_DOMAIN_MnDm field, and can be any of the
662 //! following values:  \b PECI_M0D0_MODE1, \b PECI_M0D0_MODE2,
663 //! \b PECI_M0D0_MODE3, \b PECI_M0D1_MODE1, \b PECI_M0D1_MODE2,
664 //! \b PECI_M0D1_MODE3. \b PECI_M1D0_MODE1, \b PECI_M1D0_MODE2,
665 //! \b PECI_M1D0_MODE3, \b PECI_M1D1_MODE1, \b PECI_M1D1_MODE2, or
666 //! \b PECI_M1D1_MODE3.
667 //!
668 //! \return None.
669 //
670 //*****************************************************************************
671 void
PECIIntEnable(unsigned long ulBase,unsigned long ulIntFlags,unsigned long ulIntMode)672 PECIIntEnable(unsigned long ulBase, unsigned long ulIntFlags,
673               unsigned long ulIntMode)
674 {
675     unsigned long ulTemp;
676 
677     //
678     // Check the arguments.
679     //
680     ASSERT(ulBase == PECI0_BASE);
681 
682     //
683     // Get the current mask value.
684     //
685     ulTemp = HWREG(ulBase + PECI_O_IM);
686 
687     //
688     // Clear the bit/bit-fields that are configured, based on the value
689     // in the flags parameter.
690     //
691     ulTemp &= ~ulIntFlags;
692 
693     //
694     // Set/Enable the bit/bit-fields based on the value in the flags and mode
695     // parameter.  The flags parameter alters the bits in the lower half
696     // of the mask, while the mode alters the bit fields in the upper
697     // half of the mask.
698     //
699     ulTemp |= (0x0000FFFF & ulIntFlags);
700     ulTemp |= (0xFFFF0000 & ulIntMode);
701     HWREG(ulBase + PECI_O_IM) = ulTemp;
702 }
703 
704 //*****************************************************************************
705 //
706 //! Disables individual PECI interrupt sources.
707 //!
708 //! \param ulBase specifies the PECI module base address.
709 //! \param ulIntFlags is a bit mask of the interrupt sources to be disabled.
710 //!
711 //! This function disables the indicated PECI interrupt sources.  Only the
712 //! sources that are enabled can be reflected to the processor interrupt;
713 //! disabled sources have no effect on the processor.
714 //!
715 //! The \e ulIntFlags parameter can be any of the following values:
716 //! \b PECI_READ, \b PECI_ERR, \b PECI_AC, \b PECI_M0D0, \b PECI_M0D1,
717 //! \b PECI_M1D0, or \b PECI_M1D1.
718 //!
719 //! \return None.
720 //
721 //*****************************************************************************
722 void
PECIIntDisable(unsigned long ulBase,unsigned long ulIntFlags)723 PECIIntDisable(unsigned long ulBase, unsigned long ulIntFlags)
724 {
725     //
726     // Check the arguments.
727     //
728     ASSERT(ulBase == PECI0_BASE);
729 
730     //
731     // Disable the specified interrupts.
732     //
733     HWREG(ulBase + PECI_O_IM) &= ~ulIntFlags;
734 }
735 
736 //*****************************************************************************
737 //
738 //! Gets the current interrupt status.
739 //!
740 //! \param ulBase specifies the PECI module base address.
741 //! \param bMasked is \b false if the raw interrupt status is required or
742 //! \b true if the masked interrupt status is required.
743 //!
744 //! This function returns the interrupt status for the PECI module.  Either the
745 //! raw interrupt status or the status of interrupts that are allowed to
746 //! reflect to the processor can be returned.
747 //!
748 //! The interpretation of the PECI_DOMAIN_MnDm fields vary based on the mode
749 //! value programed using the PECIIntEnable() function for the field.  Each
750 //! field may take on one of the following values:
751 //! \b PECI_MnDm_MODE1_HIGH, \b PECI_MnDm_MODE2_MID, \b PECI_MnDm_MODE2_HIGH,
752 //! \b PECI_MnDm_MODE3_LOW, \b PECI_MnDm_MODE3_MID, or \b PECI_MnDm_MODE3_HIGH.
753 //!
754 //! \return The current interrupt status, enumerated as a bit field of
755 //! \b PECI_READ, \b PECI_ERR, \b PECI_AC, \b PECI_M0D0, \b PECI_M0D1,
756 //! \b PECI_M1D0, or \b PECI_M1D1.
757 //
758 //*****************************************************************************
759 unsigned long
PECIIntStatus(unsigned long ulBase,tBoolean bMasked)760 PECIIntStatus(unsigned long ulBase, tBoolean bMasked)
761 {
762     //
763     // Check the arguments.
764     //
765     ASSERT(ulBase == PECI0_BASE);
766 
767     //
768     // Return either the interrupt status or the raw interrupt status as
769     // requested.
770     //
771     if(bMasked)
772     {
773         return(HWREG(ulBase + PECI_O_MIS));
774     }
775     else
776     {
777         return(HWREG(ulBase + PECI_O_RIS));
778     }
779 }
780 
781 //*****************************************************************************
782 //
783 //! Clears PECI interrupt sources.
784 //!
785 //! \param ulBase specifies the PECI module base address.
786 //! \param ulIntFlags is a bit mask of the interrupt sources to be cleared.
787 //!
788 //! This function clears the specified PECI interrupt sources so that they no
789 //! longer assert.  This function must be called in the interrupt handler to
790 //! keep the interrupts from being recognized again immediately upon exit.
791 //! The \e ulIntFlags parameter can consist of any combination of the
792 //! \b PECI_READ, \b PECI_ERR, \b PECI_AC, \b PECI_M0D0, \b PECI_M0D1,
793 //! \b PECI_M1D0, or \b PECI_M1D1 values.
794 //!
795 //! \note Because there is a write buffer in the Cortex-M processor, it may
796 //! take several clock cycles before the interrupt source is actually cleared.
797 //! Therefore, it is recommended that the interrupt source be cleared early in
798 //! the interrupt handler (as opposed to the very last action) to avoid
799 //! returning from the interrupt handler before the interrupt source is
800 //! actually cleared.  Failure to do so may result in the interrupt handler
801 //! being immediately reentered (because the interrupt controller still sees
802 //! the interrupt source asserted).
803 //!
804 //! \return None.
805 //
806 //*****************************************************************************
807 void
PECIIntClear(unsigned long ulBase,unsigned long ulIntFlags)808 PECIIntClear(unsigned long ulBase, unsigned long ulIntFlags)
809 {
810     //
811     // Check the arguments.
812     //
813     ASSERT(ulBase == PECI0_BASE);
814 
815     //
816     // Clear the requested interrupt sources.
817     //
818     HWREG(ulBase + PECI_O_IC) = ulIntFlags;
819 }
820 
821 //*****************************************************************************
822 //
823 //! Sends a PECI Advanced Command.
824 //!
825 //! \param ulBase specifies the PECI module base address.
826 //!
827 //! This function sends a PECI Advanced Command.  If the interface is not IDLE,
828 //! it waits for the interface to become IDLE then sends the command.  The
829 //! function parameters are used to populate the message control fields before
830 //! activating the command.
831 //!
832 //! \return None.
833 //
834 //*****************************************************************************
835 void
PECIAdvCmdSend(unsigned long ulBase,unsigned char ucCmd,unsigned char ucHidRe,unsigned char ucDomain,unsigned char ucProcAdd,unsigned long ulArg,unsigned char ucSize,unsigned long ulData0,unsigned long ulData1)836 PECIAdvCmdSend(unsigned long ulBase, unsigned char ucCmd,
837                unsigned char ucHidRe, unsigned char ucDomain,
838                unsigned char ucProcAdd, unsigned long ulArg,
839                unsigned char ucSize, unsigned long ulData0,
840                unsigned long ulData1)
841 {
842     //
843     // Check the arguments.
844     //
845     ASSERT(ulBase == PECI0_BASE);
846 
847     //
848     // Wait for the interface to be idle.
849     //
850     while(HWREG(ulBase + PECI_O_ACCODE) == 0xFFFFFFFF)
851     {
852     }
853 
854     //
855     // Fill in the registers for the advanced command.
856     //
857     HWREG(ulBase + PECI_O_ACARG) = ulArg;
858     HWREG(ulBase + PECI_O_ACRDWR0) = ulData0;
859     HWREG(ulBase + PECI_O_ACRDWR1) = ulData1;
860     HWREG(ulBase + PECI_O_ACADDR) = (ucHidRe << 24) |
861                                     (ucSize  << 16) |
862                                     (ucDomain << 8) |
863                                     (ucProcAdd << 0);
864 
865     //
866     // Now, issue the command.
867     //
868     HWREG(ulBase + PECI_O_ACCMD) = ucCmd;
869 }
870 
871 //*****************************************************************************
872 //
873 //! Sends a PECI Advanced Command (non blocking).
874 //!
875 //! \param ulBase specifies the PECI module base address.
876 //!
877 //! This function sends a PECI Advanced Command.  If the interface is not IDLE,
878 //! it returns immediately.  Otherwise, it sends the the command.  The function
879 //! paramters are used to populate the message control fields before activating
880 //! the command.
881 //!
882 //! \return None.
883 //
884 //*****************************************************************************
885 unsigned long
PECIAdvCmdSendNonBlocking(unsigned long ulBase,unsigned char ucCmd,unsigned char ucHidRe,unsigned char ucDomain,unsigned char ucProcAdd,unsigned long ulArg,unsigned char ucSize,unsigned long ulData0,unsigned long ulData1)886 PECIAdvCmdSendNonBlocking(unsigned long ulBase, unsigned char ucCmd,
887                           unsigned char ucHidRe, unsigned char ucDomain,
888                           unsigned char ucProcAdd, unsigned long ulArg,
889                           unsigned char ucSize, unsigned long ulData0,
890                           unsigned long ulData1)
891 {
892     //
893     // Check the arguments.
894     //
895     ASSERT(ulBase == PECI0_BASE);
896 
897     //
898     // Check for the interface to be idle.
899     // If not, return immediately.
900     //
901     if(HWREG(ulBase + PECI_O_ACCODE) == 0xFFFFFFFF)
902     {
903         return(0);
904     }
905 
906     //
907     // Send the command.
908     //
909     PECIAdvCmdSend(ulBase, ucCmd, ucHidRe, ucDomain, ucProcAdd, ulArg,
910                    ucSize, ulData0, ulData1);
911 
912     //
913     // Return, indicating that the command has been issued.
914     //
915     return(1);
916 }
917 
918 //*****************************************************************************
919 //
920 //! Obtains status of previous PECI Advanced Command.
921 //!
922 //! \param ulBase specifies the PECI module base address.
923 //!
924 //! This function gets the status of a previously issued PECI Advanced Command.
925 //! If the command has completed, and the data pointers are non-zero, the data
926 //! registers are read and saved.
927 //!
928 //! \return -1 if command has not yet been completed, otherwise, the return
929 //! code associated with the Advanced Command.
930 //
931 //*****************************************************************************
932 unsigned long
PECIAdvCmdStatusGet(unsigned long ulBase,unsigned long * pulData0,unsigned long * pulData1)933 PECIAdvCmdStatusGet(unsigned long ulBase, unsigned long *pulData0,
934                     unsigned long *pulData1)
935 {
936     unsigned long ulCode;
937 
938     //
939     // Check the arguments.
940     //
941     ASSERT(ulBase == PECI0_BASE);
942 
943     //
944     // If the command has completed, optionally read and save the data
945     // registers.
946     //
947     ulCode = HWREG(ulBase + PECI_O_ACCODE);
948     if(ulCode != 0xFFFFFFFF)
949     {
950         if(pulData0 != (void *)0)
951         {
952             *pulData0 = HWREG(ulBase + PECI_O_ACRDWR0);
953         }
954         if(pulData1 != (void *)0)
955         {
956             *pulData1 = HWREG(ulBase + PECI_O_ACRDWR1);
957         }
958     }
959 
960     //
961     // Return the command code from the most recently completed command.
962     //
963     return(ulCode);
964 }
965 
966 //*****************************************************************************
967 //
968 // Close the Doxygen group.
969 //! @}
970 //
971 //*****************************************************************************
972