]> begriffs open source - freertos/blob - portable/GCC/PPC405_Xilinx/port.c
Update SMP branch readme for port migration (#999)
[freertos] / portable / GCC / PPC405_Xilinx / port.c
1 /*
2  * FreeRTOS SMP Kernel V202110.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /*-----------------------------------------------------------
29  * Implementation of functions defined in portable.h for the PPC405 port.
30  *----------------------------------------------------------*/
31
32
33 /* Scheduler includes. */
34 #include "FreeRTOS.h"
35 #include "task.h"
36
37 /* Library includes. */
38 #include "xtime_l.h"
39 #include "xintc.h"
40 #include "xintc_i.h"
41
42 /*-----------------------------------------------------------*/
43
44 /* Definitions to set the initial MSR of each task. */
45 #define portCRITICAL_INTERRUPT_ENABLE   ( 1UL << 17UL )
46 #define portEXTERNAL_INTERRUPT_ENABLE   ( 1UL << 15UL )
47 #define portMACHINE_CHECK_ENABLE                ( 1UL << 12UL )
48
49 #if configUSE_FPU == 1
50         #define portAPU_PRESENT                         ( 1UL << 25UL )
51         #define portFCM_FPU_PRESENT                     ( 1UL << 13UL )
52 #else
53         #define portAPU_PRESENT                         ( 0UL )
54         #define portFCM_FPU_PRESENT                     ( 0UL )
55 #endif
56
57 #define portINITIAL_MSR         ( portCRITICAL_INTERRUPT_ENABLE | portEXTERNAL_INTERRUPT_ENABLE | portMACHINE_CHECK_ENABLE | portAPU_PRESENT | portFCM_FPU_PRESENT )
58
59
60 extern const unsigned _SDA_BASE_;
61 extern const unsigned _SDA2_BASE_;
62
63 /*-----------------------------------------------------------*/
64
65 /*
66  * Setup the system timer to generate the tick interrupt.
67  */
68 static void prvSetupTimerInterrupt( void );
69
70 /*
71  * The handler for the tick interrupt - defined in portasm.s.
72  */
73 extern void vPortTickISR( void );
74
75 /*
76  * The handler for the yield function - defined in portasm.s.
77  */
78 extern void vPortYield( void );
79
80 /*
81  * Function to start the scheduler running by starting the highest
82  * priority task that has thus far been created.
83  */
84 extern void vPortStartFirstTask( void );
85
86 /*-----------------------------------------------------------*/
87
88 /* Structure used to hold the state of the interrupt controller. */
89 static XIntc xInterruptController;
90
91 /*-----------------------------------------------------------*/
92
93 /* 
94  * Initialise the stack of a task to look exactly as if the task had been
95  * interrupted.
96  * 
97  * See the header file portable.h.
98  */
99 StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
100 {
101         /* Place a known value at the bottom of the stack for debugging. */
102         *pxTopOfStack = 0xDEADBEEF;
103         pxTopOfStack--;
104
105         /* EABI stack frame. */
106         pxTopOfStack -= 20;     /* Previous backchain and LR, R31 to R4 inclusive. */
107
108         /* Parameters in R13. */
109         *pxTopOfStack = ( StackType_t ) &_SDA_BASE_; /* address of the first small data area */
110         pxTopOfStack -= 10;
111
112         /* Parameters in R3. */
113         *pxTopOfStack = ( StackType_t ) pvParameters;
114         pxTopOfStack--;
115
116         /* Parameters in R2. */
117         *pxTopOfStack = ( StackType_t ) &_SDA2_BASE_;   /* address of the second small data area */
118         pxTopOfStack--;
119
120         /* R1 is the stack pointer so is omitted. */
121
122         *pxTopOfStack = 0x10000001UL;;  /* R0. */
123         pxTopOfStack--;
124         *pxTopOfStack = 0x00000000UL;   /* USPRG0. */
125         pxTopOfStack--;
126         *pxTopOfStack = 0x00000000UL;   /* CR. */
127         pxTopOfStack--;
128         *pxTopOfStack = 0x00000000UL;   /* XER. */
129         pxTopOfStack--;
130         *pxTopOfStack = 0x00000000UL;   /* CTR. */
131         pxTopOfStack--;
132         *pxTopOfStack = ( StackType_t ) vPortEndScheduler;      /* LR. */
133         pxTopOfStack--;
134         *pxTopOfStack = ( StackType_t ) pxCode; /* SRR0. */
135         pxTopOfStack--;
136         *pxTopOfStack = portINITIAL_MSR;/* SRR1. */
137         pxTopOfStack--;
138         *pxTopOfStack = ( StackType_t ) vPortEndScheduler;/* Next LR. */
139         pxTopOfStack--;
140         *pxTopOfStack = 0x00000000UL;/* Backchain. */
141
142         return pxTopOfStack;
143 }
144 /*-----------------------------------------------------------*/
145
146 BaseType_t xPortStartScheduler( void )
147 {
148         prvSetupTimerInterrupt();
149         XExc_RegisterHandler( XEXC_ID_SYSTEM_CALL, ( XExceptionHandler ) vPortYield, ( void * ) 0 );
150         vPortStartFirstTask();
151
152         /* Should not get here as the tasks are now running! */
153         return pdFALSE;
154 }
155 /*-----------------------------------------------------------*/
156
157 void vPortEndScheduler( void )
158 {
159         /* Not implemented. */
160         for( ;; );
161 }
162 /*-----------------------------------------------------------*/
163
164 /*
165  * Hardware initialisation to generate the RTOS tick.   
166  */
167 static void prvSetupTimerInterrupt( void )
168 {
169 const uint32_t ulInterval = ( ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) - 1UL );
170
171         XTime_PITClearInterrupt();
172         XTime_FITClearInterrupt();
173         XTime_WDTClearInterrupt();
174         XTime_WDTDisableInterrupt();
175         XTime_FITDisableInterrupt();
176
177         XExc_RegisterHandler( XEXC_ID_PIT_INT, ( XExceptionHandler ) vPortTickISR, ( void * ) 0 );
178
179         XTime_PITEnableAutoReload();
180         XTime_PITSetInterval( ulInterval );
181         XTime_PITEnableInterrupt();
182 }
183 /*-----------------------------------------------------------*/
184
185 void vPortISRHandler( void *pvNullDoNotUse )
186 {
187 uint32_t ulInterruptStatus, ulInterruptMask = 1UL;
188 BaseType_t xInterruptNumber;
189 XIntc_Config *pxInterruptController;
190 XIntc_VectorTableEntry *pxTable;
191
192         /* Just to remove compiler warning. */
193         ( void ) pvNullDoNotUse;        
194
195         /* Get the configuration by using the device ID - in this case it is
196         assumed that only one interrupt controller is being used. */
197         pxInterruptController = &XIntc_ConfigTable[ XPAR_XPS_INTC_0_DEVICE_ID ];
198   
199         /* Which interrupts are pending? */
200         ulInterruptStatus = XIntc_mGetIntrStatus( pxInterruptController->BaseAddress );
201   
202         for( xInterruptNumber = 0; xInterruptNumber < XPAR_INTC_MAX_NUM_INTR_INPUTS; xInterruptNumber++ )
203         {
204                 if( ulInterruptStatus & 0x01UL )
205                 {
206                         /* Clear the pending interrupt. */
207                         XIntc_mAckIntr( pxInterruptController->BaseAddress, ulInterruptMask );
208
209                         /* Call the registered handler. */
210                         pxTable = &( pxInterruptController->HandlerTable[ xInterruptNumber ] );
211                         pxTable->Handler( pxTable->CallBackRef );
212                 }
213         
214                 /* Check the next interrupt. */
215                 ulInterruptMask <<= 0x01UL;
216                 ulInterruptStatus >>= 0x01UL;
217
218                 /* Have we serviced all interrupts? */
219                 if( ulInterruptStatus == 0UL )
220                 {
221                         break;
222                 }
223         }
224 }
225 /*-----------------------------------------------------------*/
226
227 void vPortSetupInterruptController( void )
228 {
229 extern void vPortISRWrapper( void );
230
231         /* Perform all library calls necessary to initialise the exception table
232         and interrupt controller.  This assumes only one interrupt controller is in
233         use. */
234         XExc_mDisableExceptions( XEXC_NON_CRITICAL );
235         XExc_Init();
236
237         /* The library functions save the context - we then jump to a wrapper to
238         save the stack into the TCB.  The wrapper then calls the handler defined
239         above. */
240         XExc_RegisterHandler( XEXC_ID_NON_CRITICAL_INT, ( XExceptionHandler ) vPortISRWrapper, NULL );
241         XIntc_Initialize( &xInterruptController, XPAR_XPS_INTC_0_DEVICE_ID );
242         XIntc_Start( &xInterruptController, XIN_REAL_MODE );
243 }
244 /*-----------------------------------------------------------*/
245
246 BaseType_t xPortInstallInterruptHandler( uint8_t ucInterruptID, XInterruptHandler pxHandler, void *pvCallBackRef )
247 {
248 BaseType_t xReturn = pdFAIL;
249
250         /* This function is defined here so the scope of xInterruptController can
251         remain within this file. */
252
253         if( XST_SUCCESS == XIntc_Connect( &xInterruptController, ucInterruptID, pxHandler, pvCallBackRef ) )
254         {
255                 XIntc_Enable( &xInterruptController, ucInterruptID );
256                 xReturn = pdPASS;
257         }
258
259         return xReturn;         
260 }