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 NIOS2 port.
31 *----------------------------------------------------------*/
32 
33 /* Standard Includes. */
34 #include <string.h>
35 #include <errno.h>
36 
37 /* Altera includes. */
38 #include "sys/alt_irq.h"
39 #include "sys/alt_exceptions.h"
40 #include "altera_avalon_timer_regs.h"
41 #include "priv/alt_irq_table.h"
42 
43 /* Scheduler includes. */
44 #include "FreeRTOS.h"
45 #include "task.h"
46 
47 /* Interrupts are enabled. */
48 #define portINITIAL_ESTATUS    ( StackType_t ) 0x01
49 
50 int _alt_ic_isr_register( alt_u32 ic_id,
51                           alt_u32 irq,
52                           alt_isr_func isr,
53                           void * isr_context,
54                           void * flags );
55 /*-----------------------------------------------------------*/
56 
57 /*
58  * Setup the timer to generate the tick interrupts.
59  */
60 static void prvSetupTimerInterrupt( void );
61 
62 /*
63  * Call back for the alarm function.
64  */
65 void vPortSysTickHandler( void * context );
66 
67 /*-----------------------------------------------------------*/
68 
prvReadGp(uint32_t * ulValue)69 static void prvReadGp( uint32_t * ulValue )
70 {
71     asm ( "stw gp, (%0)" ::"r" ( ulValue ) );
72 }
73 /*-----------------------------------------------------------*/
74 
75 /*
76  * See header file for description.
77  */
pxPortInitialiseStack(StackType_t * pxTopOfStack,TaskFunction_t pxCode,void * pvParameters)78 StackType_t * pxPortInitialiseStack( StackType_t * pxTopOfStack,
79                                      TaskFunction_t pxCode,
80                                      void * pvParameters )
81 {
82     StackType_t * pxFramePointer = pxTopOfStack - 1;
83     StackType_t xGlobalPointer;
84 
85     prvReadGp( &xGlobalPointer );
86 
87     /* End of stack marker. */
88     *pxTopOfStack = 0xdeadbeef;
89     pxTopOfStack--;
90 
91     *pxTopOfStack = ( StackType_t ) pxFramePointer;
92     pxTopOfStack--;
93 
94     *pxTopOfStack = xGlobalPointer;
95 
96     /* Space for R23 to R16. */
97     pxTopOfStack -= 9;
98 
99     *pxTopOfStack = ( StackType_t ) pxCode;
100     pxTopOfStack--;
101 
102     *pxTopOfStack = portINITIAL_ESTATUS;
103 
104     /* Space for R15 to R5. */
105     pxTopOfStack -= 12;
106 
107     *pxTopOfStack = ( StackType_t ) pvParameters;
108 
109     /* Space for R3 to R1, muldiv and RA. */
110     pxTopOfStack -= 5;
111 
112     return pxTopOfStack;
113 }
114 /*-----------------------------------------------------------*/
115 
116 /*
117  * See header file for description.
118  */
xPortStartScheduler(void)119 BaseType_t xPortStartScheduler( void )
120 {
121     /* Start the timer that generates the tick ISR.  Interrupts are disabled
122      * here already. */
123     prvSetupTimerInterrupt();
124 
125     /* Start the first task. */
126     asm volatile ( " movia r2, restore_sp_from_pxCurrentTCB        \n"
127                    " jmp r2                                          " );
128 
129     /* Should not get here! */
130     return 0;
131 }
132 /*-----------------------------------------------------------*/
133 
vPortEndScheduler(void)134 void vPortEndScheduler( void )
135 {
136     /* It is unlikely that the NIOS2 port will require this function as there
137      * is nothing to return to.  */
138 }
139 /*-----------------------------------------------------------*/
140 
141 /*
142  * Setup the systick timer to generate the tick interrupts at the required
143  * frequency.
144  */
prvSetupTimerInterrupt(void)145 void prvSetupTimerInterrupt( void )
146 {
147     /* Try to register the interrupt handler. */
148     if( -EINVAL == _alt_ic_isr_register( SYS_CLK_IRQ_INTERRUPT_CONTROLLER_ID, SYS_CLK_IRQ, vPortSysTickHandler, 0x0, 0x0 ) )
149     {
150         /* Failed to install the Interrupt Handler. */
151         asm ( "break" );
152     }
153     else
154     {
155         /* Configure SysTick to interrupt at the requested rate. */
156         IOWR_ALTERA_AVALON_TIMER_CONTROL( SYS_CLK_BASE, ALTERA_AVALON_TIMER_CONTROL_STOP_MSK );
157         IOWR_ALTERA_AVALON_TIMER_PERIODL( SYS_CLK_BASE, ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) & 0xFFFF );
158         IOWR_ALTERA_AVALON_TIMER_PERIODH( SYS_CLK_BASE, ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) >> 16 );
159         IOWR_ALTERA_AVALON_TIMER_CONTROL( SYS_CLK_BASE, ALTERA_AVALON_TIMER_CONTROL_CONT_MSK | ALTERA_AVALON_TIMER_CONTROL_START_MSK | ALTERA_AVALON_TIMER_CONTROL_ITO_MSK );
160     }
161 
162     /* Clear any already pending interrupts generated by the Timer. */
163     IOWR_ALTERA_AVALON_TIMER_STATUS( SYS_CLK_BASE, ~ALTERA_AVALON_TIMER_STATUS_TO_MSK );
164 }
165 /*-----------------------------------------------------------*/
166 
vPortSysTickHandler(void * context)167 void vPortSysTickHandler( void * context )
168 {
169     /* Increment the kernel tick. */
170     if( xTaskIncrementTick() != pdFALSE )
171     {
172         vTaskSwitchContext();
173     }
174 
175     /* Clear the interrupt. */
176     IOWR_ALTERA_AVALON_TIMER_STATUS( SYS_CLK_BASE, ~ALTERA_AVALON_TIMER_STATUS_TO_MSK );
177 }
178 /*-----------------------------------------------------------*/
179 
180 /** This function is a re-implementation of the Altera provided function.
181  * The function is re-implemented to prevent it from enabling an interrupt
182  * when it is registered. Interrupts should only be enabled after the FreeRTOS.org
183  * kernel has its scheduler started so that contexts are saved and switched
184  * correctly.
185  */
_alt_ic_isr_register(alt_u32 ic_id,alt_u32 irq,alt_isr_func isr,void * isr_context,void * flags)186 int _alt_ic_isr_register( alt_u32 ic_id,
187                           alt_u32 irq,
188                           alt_isr_func isr,
189                           void * isr_context,
190                           void * flags )
191 {
192     int rc = -EINVAL;
193     alt_irq_context status;
194     int id = irq; /* IRQ interpreted as the interrupt ID. */
195 
196     if( id < ALT_NIRQ )
197     {
198         /*
199          * interrupts are disabled while the handler tables are updated to ensure
200          * that an interrupt doesn't occur while the tables are in an inconsistent
201          * state.
202          */
203 
204         status = alt_irq_disable_all();
205 
206         alt_irq[ id ].handler = isr;
207         alt_irq[ id ].context = isr_context;
208 
209         rc = ( isr ) ? alt_ic_irq_enable( ic_id, id ) : alt_ic_irq_disable( ic_id, id );
210 
211         /* alt_irq_enable_all(status); This line is removed to prevent the interrupt from being immediately enabled. */
212     }
213 
214     return rc;
215 }
216 /*-----------------------------------------------------------*/
217