1 /*
2  * FreeRTOS Kernel V11.1.0
3  * Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  * https://www.FreeRTOS.org
25  * https://github.com/FreeRTOS
26  *
27  */
28 
29 /*-----------------------------------------------------------
30 * Implementation of functions defined in portable.h for the SH2A port.
31 *----------------------------------------------------------*/
32 
33 /* Standard C includes. */
34 #include "limits.h"
35 
36 /* Scheduler includes. */
37 #include "FreeRTOS.h"
38 #include "task.h"
39 
40 /* Library includes. */
41 #include "string.h"
42 
43 /* Hardware specifics. */
44 #include "machine.h"
45 
46 /*-----------------------------------------------------------*/
47 
48 /* Tasks should start with interrupts enabled and in Supervisor mode, therefore
49  * PSW is set with U and I set, and PM and IPL clear. */
50 #define portINITIAL_PSW    ( ( StackType_t ) 0x00030000 )
51 
52 /* The peripheral clock is divided by this value before being supplying the
53  * CMT. */
54 #if ( configUSE_TICKLESS_IDLE == 0 )
55     /* If tickless idle is not used then the divisor can be fixed. */
56     #define portCLOCK_DIVISOR    8UL
57 #elif ( configPERIPHERAL_CLOCK_HZ >= 12000000 )
58     #define portCLOCK_DIVISOR    512UL
59 #elif ( configPERIPHERAL_CLOCK_HZ >= 6000000 )
60     #define portCLOCK_DIVISOR    128UL
61 #elif ( configPERIPHERAL_CLOCK_HZ >= 1000000 )
62     #define portCLOCK_DIVISOR    32UL
63 #else
64     #define portCLOCK_DIVISOR    8UL
65 #endif
66 
67 
68 /* Keys required to lock and unlock access to certain system registers
69  * respectively. */
70 #define portUNLOCK_KEY    0xA50B
71 #define portLOCK_KEY      0xA500
72 
73 /*-----------------------------------------------------------*/
74 
75 /*
76  * Function to start the first task executing - written in asm code as direct
77  * access to registers is required.
78  */
79 extern void prvStartFirstTask( void );
80 
81 /*
82  * The tick ISR handler.  The peripheral used is configured by the application
83  * via a hook/callback function.
84  */
85 __interrupt static void prvTickISR( void );
86 
87 /*
88  * Sets up the periodic ISR used for the RTOS tick using the CMT.
89  * The application writer can define configSETUP_TICK_INTERRUPT() (in
90  * FreeRTOSConfig.h) such that their own tick interrupt configuration is used
91  * in place of prvSetupTimerInterrupt().
92  */
93 static void prvSetupTimerInterrupt( void );
94 #ifndef configSETUP_TICK_INTERRUPT
95 
96 /* The user has not provided their own tick interrupt configuration so use
97  * the definition in this file (which uses the interval timer). */
98     #define configSETUP_TICK_INTERRUPT()    prvSetupTimerInterrupt()
99 #endif /* configSETUP_TICK_INTERRUPT */
100 
101 /*
102  * Called after the sleep mode registers have been configured, prvSleep()
103  * executes the pre and post sleep macros, and actually calls the wait
104  * instruction.
105  */
106 #if configUSE_TICKLESS_IDLE == 1
107     static void prvSleep( TickType_t xExpectedIdleTime );
108 #endif /* configUSE_TICKLESS_IDLE */
109 
110 /*-----------------------------------------------------------*/
111 
112 extern void * pxCurrentTCB;
113 
114 /*-----------------------------------------------------------*/
115 
116 /* Calculate how many clock increments make up a single tick period. */
117 static const uint32_t ulMatchValueForOneTick = ( ( configPERIPHERAL_CLOCK_HZ / portCLOCK_DIVISOR ) / configTICK_RATE_HZ );
118 
119 #if configUSE_TICKLESS_IDLE == 1
120 
121 /* Holds the maximum number of ticks that can be suppressed - which is
122  * basically how far into the future an interrupt can be generated. Set
123  * during initialisation.  This is the maximum possible value that the
124  * compare match register can hold divided by ulMatchValueForOneTick. */
125     static const TickType_t xMaximumPossibleSuppressedTicks = USHRT_MAX / ( ( configPERIPHERAL_CLOCK_HZ / portCLOCK_DIVISOR ) / configTICK_RATE_HZ );
126 
127 /* Flag set from the tick interrupt to allow the sleep processing to know if
128  * sleep mode was exited because of a tick interrupt, or an interrupt
129  * generated by something else. */
130     static volatile uint32_t ulTickFlag = pdFALSE;
131 
132 /* The CMT counter is stopped temporarily each time it is re-programmed.
133  * The following constant offsets the CMT counter match value by the number of
134  * CMT counts that would typically be missed while the counter was stopped to
135  * compensate for the lost time.  The large difference between the divided CMT
136  * clock and the CPU clock means it is likely ulStoppedTimerCompensation will
137  * equal zero - and be optimised away. */
138     static const uint32_t ulStoppedTimerCompensation = 100UL / ( configCPU_CLOCK_HZ / ( configPERIPHERAL_CLOCK_HZ / portCLOCK_DIVISOR ) );
139 
140 #endif /* if configUSE_TICKLESS_IDLE == 1 */
141 
142 /*-----------------------------------------------------------*/
143 
144 /*
145  * See header file for description.
146  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)147 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
148                                      TaskFunction_t pxCode,
149                                      void * pvParameters )
150 {
151     /* Offset to end up on 8 byte boundary. */
152     pxTopOfStack--;
153 
154     /* R0 is not included as it is the stack pointer. */
155     *pxTopOfStack = 0x00;
156     pxTopOfStack--;
157     *pxTopOfStack = 0x00;
158     pxTopOfStack--;
159     *pxTopOfStack = portINITIAL_PSW;
160     pxTopOfStack--;
161     *pxTopOfStack = ( StackType_t ) pxCode;
162 
163     /* When debugging it can be useful if every register is set to a known
164      * value.  Otherwise code space can be saved by just setting the registers
165      * that need to be set. */
166     #ifdef USE_FULL_REGISTER_INITIALISATION
167     {
168         pxTopOfStack--;
169         *pxTopOfStack = 0x12345678; /* r15. */
170         pxTopOfStack--;
171         *pxTopOfStack = 0xaaaabbbb;
172         pxTopOfStack--;
173         *pxTopOfStack = 0xdddddddd;
174         pxTopOfStack--;
175         *pxTopOfStack = 0xcccccccc;
176         pxTopOfStack--;
177         *pxTopOfStack = 0xbbbbbbbb;
178         pxTopOfStack--;
179         *pxTopOfStack = 0xaaaaaaaa;
180         pxTopOfStack--;
181         *pxTopOfStack = 0x99999999;
182         pxTopOfStack--;
183         *pxTopOfStack = 0x88888888;
184         pxTopOfStack--;
185         *pxTopOfStack = 0x77777777;
186         pxTopOfStack--;
187         *pxTopOfStack = 0x66666666;
188         pxTopOfStack--;
189         *pxTopOfStack = 0x55555555;
190         pxTopOfStack--;
191         *pxTopOfStack = 0x44444444;
192         pxTopOfStack--;
193         *pxTopOfStack = 0x33333333;
194         pxTopOfStack--;
195         *pxTopOfStack = 0x22222222;
196         pxTopOfStack--;
197     }
198     #else /* ifdef USE_FULL_REGISTER_INITIALISATION */
199     {
200         /* Leave space for the registers that will get popped from the stack
201          * when the task first starts executing. */
202         pxTopOfStack -= 15;
203     }
204     #endif /* ifdef USE_FULL_REGISTER_INITIALISATION */
205 
206     *pxTopOfStack = ( StackType_t ) pvParameters; /* R1 */
207     pxTopOfStack--;
208     *pxTopOfStack = 0x12345678;                   /* Accumulator. */
209     pxTopOfStack--;
210     *pxTopOfStack = 0x87654321;                   /* Accumulator. */
211 
212     return pxTopOfStack;
213 }
214 /*-----------------------------------------------------------*/
215 
xPortStartScheduler(void)216 BaseType_t xPortStartScheduler( void )
217 {
218     /* Use pxCurrentTCB just so it does not get optimised away. */
219     if( pxCurrentTCB != NULL )
220     {
221         /* Call an application function to set up the timer that will generate
222          * the tick interrupt.  This way the application can decide which
223          * peripheral to use.  If tickless mode is used then the default
224          * implementation defined in this file (which uses CMT0) should not be
225          * overridden. */
226         configSETUP_TICK_INTERRUPT();
227 
228         /* Enable the software interrupt. */
229         _IEN( _ICU_SWINT ) = 1;
230 
231         /* Ensure the software interrupt is clear. */
232         _IR( _ICU_SWINT ) = 0;
233 
234         /* Ensure the software interrupt is set to the kernel priority. */
235         _IPR( _ICU_SWINT ) = configKERNEL_INTERRUPT_PRIORITY;
236 
237         /* Start the first task. */
238         prvStartFirstTask();
239     }
240 
241     /* Execution should not reach here as the tasks are now running!
242      * prvSetupTimerInterrupt() is called here to prevent the compiler outputting
243      * a warning about a statically declared function not being referenced in the
244      * case that the application writer has provided their own tick interrupt
245      * configuration routine (and defined configSETUP_TICK_INTERRUPT() such that
246      * their own routine will be called in place of prvSetupTimerInterrupt()). */
247     prvSetupTimerInterrupt();
248 
249     /* Should not get here. */
250     return pdFAIL;
251 }
252 /*-----------------------------------------------------------*/
253 
254 #pragma vector = configTICK_VECTOR
prvTickISR(void)255 __interrupt static void prvTickISR( void )
256 {
257     /* Re-enable interrupts. */
258     __enable_interrupt();
259 
260     /* Increment the tick, and perform any processing the new tick value
261      * necessitates. */
262     __set_interrupt_level( configMAX_SYSCALL_INTERRUPT_PRIORITY );
263     {
264         if( xTaskIncrementTick() != pdFALSE )
265         {
266             taskYIELD();
267         }
268     }
269     __set_interrupt_level( configKERNEL_INTERRUPT_PRIORITY );
270 
271     #if configUSE_TICKLESS_IDLE == 1
272     {
273         /* The CPU woke because of a tick. */
274         ulTickFlag = pdTRUE;
275 
276         /* If this is the first tick since exiting tickless mode then the CMT
277          * compare match value needs resetting. */
278         CMT0.CMCOR = ( uint16_t ) ulMatchValueForOneTick;
279     }
280     #endif
281 }
282 /*-----------------------------------------------------------*/
283 
vPortEndScheduler(void)284 void vPortEndScheduler( void )
285 {
286     /* Not implemented in ports where there is nothing to return to.
287      * Artificially force an assert. */
288     configASSERT( pxCurrentTCB == NULL );
289 }
290 /*-----------------------------------------------------------*/
291 
prvSetupTimerInterrupt(void)292 static void prvSetupTimerInterrupt( void )
293 {
294     /* Unlock. */
295     SYSTEM.PRCR.WORD = portUNLOCK_KEY;
296 
297     /* Enable CMT0. */
298     MSTP( CMT0 ) = 0;
299 
300     /* Lock again. */
301     SYSTEM.PRCR.WORD = portLOCK_KEY;
302 
303     /* Interrupt on compare match. */
304     CMT0.CMCR.BIT.CMIE = 1;
305 
306     /* Set the compare match value. */
307     CMT0.CMCOR = ( uint16_t ) ulMatchValueForOneTick;
308 
309     /* Divide the PCLK. */
310     #if portCLOCK_DIVISOR == 512
311     {
312         CMT0.CMCR.BIT.CKS = 3;
313     }
314     #elif portCLOCK_DIVISOR == 128
315     {
316         CMT0.CMCR.BIT.CKS = 2;
317     }
318     #elif portCLOCK_DIVISOR == 32
319     {
320         CMT0.CMCR.BIT.CKS = 1;
321     }
322     #elif portCLOCK_DIVISOR == 8
323     {
324         CMT0.CMCR.BIT.CKS = 0;
325     }
326     #else /* if portCLOCK_DIVISOR == 512 */
327     {
328         #error Invalid portCLOCK_DIVISOR setting
329     }
330     #endif /* if portCLOCK_DIVISOR == 512 */
331 
332 
333     /* Enable the interrupt... */
334     _IEN( _CMT0_CMI0 ) = 1;
335 
336     /* ...and set its priority to the application defined kernel priority. */
337     _IPR( _CMT0_CMI0 ) = configKERNEL_INTERRUPT_PRIORITY;
338 
339     /* Start the timer. */
340     CMT.CMSTR0.BIT.STR0 = 1;
341 }
342 /*-----------------------------------------------------------*/
343 
344 #if configUSE_TICKLESS_IDLE == 1
345 
prvSleep(TickType_t xExpectedIdleTime)346     static void prvSleep( TickType_t xExpectedIdleTime )
347     {
348         /* Allow the application to define some pre-sleep processing. */
349         configPRE_SLEEP_PROCESSING( xExpectedIdleTime );
350 
351         /* xExpectedIdleTime being set to 0 by configPRE_SLEEP_PROCESSING()
352          * means the application defined code has already executed the WAIT
353          * instruction. */
354         if( xExpectedIdleTime > 0 )
355         {
356             __wait_for_interrupt();
357         }
358 
359         /* Allow the application to define some post sleep processing. */
360         configPOST_SLEEP_PROCESSING( xExpectedIdleTime );
361     }
362 
363 #endif /* configUSE_TICKLESS_IDLE */
364 /*-----------------------------------------------------------*/
365 
366 #if configUSE_TICKLESS_IDLE == 1
367 
vPortSuppressTicksAndSleep(TickType_t xExpectedIdleTime)368     void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime )
369     {
370         uint32_t ulMatchValue, ulCompleteTickPeriods, ulCurrentCount;
371         eSleepModeStatus eSleepAction;
372 
373         /* THIS FUNCTION IS CALLED WITH THE SCHEDULER SUSPENDED. */
374 
375         /* Make sure the CMT reload value does not overflow the counter. */
376         if( xExpectedIdleTime > xMaximumPossibleSuppressedTicks )
377         {
378             xExpectedIdleTime = xMaximumPossibleSuppressedTicks;
379         }
380 
381         /* Calculate the reload value required to wait xExpectedIdleTime tick
382          * periods. */
383         ulMatchValue = ulMatchValueForOneTick * xExpectedIdleTime;
384 
385         if( ulMatchValue > ulStoppedTimerCompensation )
386         {
387             /* Compensate for the fact that the CMT is going to be stopped
388              * momentarily. */
389             ulMatchValue -= ulStoppedTimerCompensation;
390         }
391 
392         /* Stop the CMT momentarily.  The time the CMT is stopped for is
393          * accounted for as best it can be, but using the tickless mode will
394          * inevitably result in some tiny drift of the time maintained by the
395          * kernel with respect to calendar time. */
396         CMT.CMSTR0.BIT.STR0 = 0;
397 
398         while( CMT.CMSTR0.BIT.STR0 == 1 )
399         {
400             /* Nothing to do here. */
401         }
402 
403         /* Critical section using the global interrupt bit as the i bit is
404          * automatically reset by the WAIT instruction. */
405         __disable_interrupt();
406 
407         /* The tick flag is set to false before sleeping.  If it is true when
408          * sleep mode is exited then sleep mode was probably exited because the
409          * tick was suppressed for the entire xExpectedIdleTime period. */
410         ulTickFlag = pdFALSE;
411 
412         /* If a context switch is pending then abandon the low power entry as
413          * the context switch might have been pended by an external interrupt that
414          * requires processing. */
415         eSleepAction = eTaskConfirmSleepModeStatus();
416 
417         if( eSleepAction == eAbortSleep )
418         {
419             /* Restart tick. */
420             CMT.CMSTR0.BIT.STR0 = 1;
421             __enable_interrupt();
422         }
423         else if( eSleepAction == eNoTasksWaitingTimeout )
424         {
425             /* Protection off. */
426             SYSTEM.PRCR.WORD = portUNLOCK_KEY;
427 
428             /* Ready for software standby with all clocks stopped. */
429             SYSTEM.SBYCR.BIT.SSBY = 1;
430 
431             /* Protection on. */
432             SYSTEM.PRCR.WORD = portLOCK_KEY;
433 
434             /* Sleep until something happens.  Calling prvSleep() will
435              * automatically reset the i bit in the PSW. */
436             prvSleep( xExpectedIdleTime );
437 
438             /* Restart the CMT. */
439             CMT.CMSTR0.BIT.STR0 = 1;
440         }
441         else
442         {
443             /* Protection off. */
444             SYSTEM.PRCR.WORD = portUNLOCK_KEY;
445 
446             /* Ready for deep sleep mode. */
447             SYSTEM.MSTPCRC.BIT.DSLPE = 1;
448             SYSTEM.MSTPCRA.BIT.MSTPA28 = 1;
449             SYSTEM.SBYCR.BIT.SSBY = 0;
450 
451             /* Protection on. */
452             SYSTEM.PRCR.WORD = portLOCK_KEY;
453 
454             /* Adjust the match value to take into account that the current
455              * time slice is already partially complete. */
456             ulMatchValue -= ( uint32_t ) CMT0.CMCNT;
457             CMT0.CMCOR = ( uint16_t ) ulMatchValue;
458 
459             /* Restart the CMT to count up to the new match value. */
460             CMT0.CMCNT = 0;
461             CMT.CMSTR0.BIT.STR0 = 1;
462 
463             /* Sleep until something happens.  Calling prvSleep() will
464              * automatically reset the i bit in the PSW. */
465             prvSleep( xExpectedIdleTime );
466 
467             /* Stop CMT.  Again, the time the SysTick is stopped for is
468              * accounted for as best it can be, but using the tickless mode will
469              * inevitably result in some tiny drift of the time maintained by the
470              * kernel with respect to calendar time. */
471             CMT.CMSTR0.BIT.STR0 = 0;
472 
473             while( CMT.CMSTR0.BIT.STR0 == 1 )
474             {
475                 /* Nothing to do here. */
476             }
477 
478             ulCurrentCount = ( uint32_t ) CMT0.CMCNT;
479 
480             if( ulTickFlag != pdFALSE )
481             {
482                 /* The tick interrupt has already executed, although because
483                  * this function is called with the scheduler suspended the actual
484                  * tick processing will not occur until after this function has
485                  * exited.  Reset the match value with whatever remains of this
486                  * tick period. */
487                 ulMatchValue = ulMatchValueForOneTick - ulCurrentCount;
488                 CMT0.CMCOR = ( uint16_t ) ulMatchValue;
489 
490                 /* The tick interrupt handler will already have pended the tick
491                  * processing in the kernel.  As the pending tick will be
492                  * processed as soon as this function exits, the tick value
493                  * maintained by the tick is stepped forward by one less than the
494                  * time spent sleeping.  The actual stepping of the tick appears
495                  * later in this function. */
496                 ulCompleteTickPeriods = xExpectedIdleTime - 1UL;
497             }
498             else
499             {
500                 /* Something other than the tick interrupt ended the sleep.
501                  * How many complete tick periods passed while the processor was
502                  * sleeping? */
503                 ulCompleteTickPeriods = ulCurrentCount / ulMatchValueForOneTick;
504 
505                 /* The match value is set to whatever fraction of a single tick
506                  * period remains. */
507                 ulMatchValue = ulCurrentCount - ( ulCompleteTickPeriods * ulMatchValueForOneTick );
508                 CMT0.CMCOR = ( uint16_t ) ulMatchValue;
509             }
510 
511             /* Restart the CMT so it runs up to the match value.  The match value
512              * will get set to the value required to generate exactly one tick period
513              * the next time the CMT interrupt executes. */
514             CMT0.CMCNT = 0;
515             CMT.CMSTR0.BIT.STR0 = 1;
516 
517             /* Wind the tick forward by the number of tick periods that the CPU
518              * remained in a low power state. */
519             vTaskStepTick( ulCompleteTickPeriods );
520         }
521     }
522 
523 #endif /* configUSE_TICKLESS_IDLE */
524