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