1 /*
2 * Copyright 2020 ETH Zurich
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * SPDX-License-Identifier: Apache-2.0
17 * Author: Robert Balas (balasr@iis.ee.ethz.ch)
18 * Change Logs:
19 * Date Author Notes
20 * 2022-12-08 WangShun Remove FreeRTOS related code and add RT-Thread code
21 */
22
23 #include <stdint.h>
24 #include <assert.h>
25
26 #include <core_pulp_cluster.h>
27 #include <core-v-mcu-config.h>
28 #include "hal_fc_event.h"
29 /* TODO: weird include */
30 #include "core-v-mcu-properties.h"
31 #include "hal_irq.h"
32 #include "hal_soc_eu.h"
33 #include "hal_apb_soc_ctrl_reg_defs.h"
34 #include "udma_uart_driver.h"
35 #include "hal_udma_ctrl_reg_defs.h"
36 #include "hal_udma_uart_reg_defs.h"
37 #include <rthw.h>
38 #include <rtthread.h>
39 #include "rtconfig.h"
40 #ifdef PKG_USING_FREERTOS_WRAPPER
41 #include "N25Q.h"
42 #include "hal_apb_i2cs.h"
43 FLASH_DEVICE_OBJECT gFlashDeviceObject[N_QSPIM];
44 uint8_t gQSPIFlashPresentFlg[N_QSPIM] = {0};
45 uint8_t gMicronFlashDetectedFlg[N_QSPIM] = {0};
46 #endif
47
48 #define HEAP_SIZE (( unsigned int) (64 * 1024 ))
49
50 #define FOR_SIMULATION_TESTING 0
51
52 #if (FOR_SIMULATION_TESTING == 1)
53
54 typedef struct
55 {
56 volatile uint32_t *rx_saddr; // 0x00
57 volatile uint32_t rx_size; // 0x04
58 volatile uint32_t rx_cfg; // 0x08
59 volatile uint32_t rx_initcfg; // 0x0C
60 volatile uint32_t *tx_saddr; // 0x10
61 volatile uint32_t tx_size; // 0x14
62 volatile uint32_t tx_cfg; // 0x18
63 volatile uint32_t tx_initcfg; // 0x1C
64 volatile uint32_t cfg_glob; // 0x20
65 volatile uint32_t cfg_ll; // 0x24
66 volatile uint32_t cfg_ur; // 0x28
67 volatile uint32_t cfg_size; // 0x2C
68 volatile uint32_t cfg_filter; // 0x30
69 volatile uint32_t vsync_pol; // 0x34
70
71 } camera_struct_t;
72
73 void forSimulationTesting(void);
74 #endif
75
76 /* test some assumptions we make about compiler settings */
77 static_assert(sizeof(uintptr_t) == 4,
78 "uintptr_t is not 4 bytes. Make sure you are using -mabi=ilp32*");
79
80 /* Allocate heap to special section. Note that we have no references in the
81 * whole program to this variable (since its just here to allocate space in the
82 * section for our heap), so when using LTO it will be removed. We force it to
83 * stay with the "used" attribute
84 */
85 __attribute__((section(".heap"), used)) uint8_t ucHeap[HEAP_SIZE];
86
87 /* Inform linker script about .heap section size. Note: GNU ld seems to
88 * internally represent integers with the bfd_vma type, that is a type that can
89 * contain memory addresses (typdefd to some int type depending on the
90 * architecture). uint32_t seems to me the most fitting candidate for rv32.
91 */
92 uint32_t __heap_size = HEAP_SIZE;
93
94 volatile uint32_t system_core_clock = 5000000u;
95
96 /* interrupt handling */
97 void timer_irq_handler(uint32_t mcause);
98 void undefined_handler(uint32_t mcause);
99 extern void fc_soc_event_handler1(uint32_t mcause);
100 void (*isr_table[32])(uint32_t);
101 void flash_readid(const struct cli_cmd_entry *pEntry);
102 /**
103 * Board init code. Always call this before anything else.
104 */
105
setFLLFrequencyInIntegerMode(uint8_t aFLLNum,uint8_t aRefFreqInMHz,uint16_t aMultiplier,uint8_t aDivideRatio_R_Prescale,uint8_t aPS0_L1,uint8_t aPS0_L2)106 uint8_t setFLLFrequencyInIntegerMode(uint8_t aFLLNum, uint8_t aRefFreqInMHz, uint16_t aMultiplier, uint8_t aDivideRatio_R_Prescale, uint8_t aPS0_L1, uint8_t aPS0_L2)
107 {
108 uint8_t lSts = 0;
109 volatile uint32_t *lPLLStartAddress = (uint32_t *)NULL;
110 uint32_t lCounter = 0;
111 uint32_t lCfgVal = 0;
112
113 uint8_t lPS0_L1 = aPS0_L1 & 0x03;
114 uint8_t lPS0_L2 = aPS0_L2 & 0xFF;
115
116 if (aFLLNum == 0)
117 lPLLStartAddress = (uint32_t *)FLL1_START_ADDR;
118 else if (aFLLNum == 1)
119 lPLLStartAddress = (uint32_t *)FLL2_START_ADDR;
120 else if (aFLLNum == 2)
121 lPLLStartAddress = (uint32_t *)FLL3_START_ADDR;
122 else
123 lPLLStartAddress = (uint32_t *)NULL;
124
125 if (lPLLStartAddress != NULL)
126 {
127 if ((aRefFreqInMHz >= 5) && (aRefFreqInMHz <= 500))
128 {
129 if ((aMultiplier > 0) && (aMultiplier < 2048))
130 {
131 if (aDivideRatio_R_Prescale < 16)
132 {
133 *lPLLStartAddress |= (1 << 19); // Bypass on;
134 *lPLLStartAddress |= (1 << 2); // Reset high
135 *lPLLStartAddress &= ~(1 << 2); // Reset low;
136 *lPLLStartAddress &= ~(1 << 18); // PS0_EN is set to low
137 *lPLLStartAddress |= (lPS0_L1 << 0); // PS0_L1 0 which gives L01 = 1
138 *lPLLStartAddress |= (lPS0_L2 << 4); // PS0_L2_INT 0 and PS0_L2_FRAC 0 which gives L02 = 1
139 *lPLLStartAddress |= (0 << 12); // PS0_L2_INT 0 and PS0_L2_FRAC 0 which gives L02 = 1
140
141 // FLL1 Config 1 register not configuring PS1
142 *(lPLLStartAddress + 1) = 0;
143
144 // FLL1 Config 2 register
145 lCfgVal = 0;
146 lCfgVal |= (aMultiplier << 4); // MULT_INT 0x28 = 40 (40*10 = 400MHz) Multiplier cannot hold 0
147 lCfgVal |= (1 << 27); // INTEGER_MODE is enabled
148 lCfgVal |= (aDivideRatio_R_Prescale << 28); // PRESCALE value (Divide Ratio R = 1)
149
150 *(lPLLStartAddress + 2) = lCfgVal;
151
152 // FLL1 Config 3 register not configuring SSC
153 *(lPLLStartAddress + 3) = 0;
154
155 // FLL1 Config 4 register
156 *(lPLLStartAddress + 4) = 0x64;
157
158 // FLL1 Config 5 register
159 *(lPLLStartAddress + 5) = 0x269;
160
161 *lPLLStartAddress |= (1 << 2); // Reset high
162 *lPLLStartAddress |= (1 << 18); // PS0_EN;
163 // lCounter = 0;
164 while ((*(lPLLStartAddress + 4) & 0x80000000) == 0) // Wait for lock detect to go high
165 {
166 lCounter++;
167 if (lCounter >= 0x00010000)
168 {
169 lSts = 5; // Unable to achieve lock
170 lCounter = 0;
171 break;
172 }
173 }
174 if (lSts == 0)
175 *(lPLLStartAddress) &= ~(1 << 19); // Bypass off;
176 }
177 else
178 {
179 lSts = 1; // aDivideRatio_R_Prescale
180 }
181 }
182 else
183 {
184 lSts = 2; // Invalid aMultiplier
185 }
186 }
187 else
188 {
189 lSts = 3; // Invalid reference freq
190 }
191 }
192 else
193 {
194 lSts = 4; // Invalid PLL number
195 }
196 return lSts;
197 }
198
199 int handler_count[32];
200 uint32_t gSpecialHandlingIRQCnt = 0;
201 uint8_t gQSPIIdNum = 0;
202
system_init(void)203 void system_init(void)
204 {
205 uint32_t lFlashID = 0;
206 SocCtrl_t *soc = APB_SOC_CTRL_ADDR;
207 soc->soft_reset = 1;
208 uint32_t val = 0;
209 uint8_t i = 0;
210 timer_irq_disable();
211
212 uint32_t *lFFL1StartAddress = (uint32_t *)FLL1_START_ADDR;
213 uint32_t *lFFL2StartAddress = (uint32_t *)FLL2_START_ADDR;
214 uint32_t *lFFL3StartAddress = (uint32_t *)FLL3_START_ADDR;
215
216 setFLLFrequencyInIntegerMode(0, 10, 40, 1, 0, 1); // 400
217
218 setFLLFrequencyInIntegerMode(1, 10, 40, 1, 0, 2); // 200
219
220 setFLLFrequencyInIntegerMode(2, 10, 40, 1, 0, 4); // 100
221
222 /* Hook up isr table. This table is temporary until we figure out how to do proper vectored interrupts. */
223 for (int i = 0; i < 32; i++)
224 {
225 isr_table[i] = undefined_handler;
226 handler_count[i] = 0;
227 }
228 isr_table[0x7] = timer_irq_handler;
229 isr_table[0xb] = (void (*)(uint32_t))fc_soc_event_handler1; // 11 for cv32
230
231 rt_hw_interrupt_init();
232 rt_hw_interrupt_install(0x7, timer_irq_handler, RT_NULL, "timerirq");
233 rt_hw_interrupt_install(0xb, fc_soc_event_handler1, RT_NULL, "eventirq");
234 /* mtvec is set in crt0.S */
235
236 /* deactivate all soc events as they are enabled by default */
237 pulp_soc_eu_event_init();
238
239 /* Setup soc events handler. */
240 pi_fc_event_handler_init(11);
241
242 val = csr_read(CSR_MIE);
243
244 /* TODO: enable uart */
245 for (uint8_t id = 0; id != N_UART; id++)
246 {
247 udma_uart_open(id, 115200);
248 }
249
250 #if (FOR_SIMULATION_TESTING == 1)
251 forSimulationTesting();
252 #endif
253 }
254
system_core_clock_update(void)255 void system_core_clock_update(void)
256 {
257 system_core_clock = pi_fll_get_frequency(FLL_SOC, 0);
258 }
259
system_core_clock_get(void)260 void system_core_clock_get(void)
261 {
262 system_core_clock_update();
263 return;
264 }
265
Writeraw(uint8_t uart_id,uint16_t write_len,uint8_t * write_buffer)266 uint16_t Writeraw(uint8_t uart_id, uint16_t write_len, uint8_t* write_buffer) {
267 UdmaUart_t* puart = (UdmaUart_t*)(UDMA_CH_ADDR_UART + uart_id * UDMA_CH_SIZE);
268
269 while (puart->status_b.tx_busy) { // ToDo: Why is this necessary? Thought the semaphore should have protected
270 }
271
272 puart->tx_saddr = (uint32_t)write_buffer;
273 puart->tx_size = write_len;
274 puart->tx_cfg_b.en = 1; //enable the transfer
275
276 return 0;
277 }
278
timer_irq_handler(uint32_t mcause)279 void timer_irq_handler(uint32_t mcause)
280 {
281 #warning requires critical section if interrupt nesting is used.
282 rt_interrupt_enter();
283 rt_tick_increase();
284 rt_interrupt_leave();
285 }
286
vSystemIrqHandler(uint32_t mcause)287 void vSystemIrqHandler(uint32_t mcause)
288 {
289 isr_table[mcause & 0x1f](mcause & 0x1f);
290 }
291
undefined_handler(uint32_t mcause)292 void undefined_handler(uint32_t mcause)
293 {
294 uint32_t RegReadVal = 0;
295 #ifdef __PULP_USE_LIBC
296 abort();
297 #else
298 if ((mcause == 18) || (mcause == 19) || (mcause == 31))
299 {
300 gSpecialHandlingIRQCnt++;
301 if (gSpecialHandlingIRQCnt >= 20)
302 {
303 RegReadVal = csr_read(CSR_MIE);
304 if ((RegReadVal & BIT(mcause)) != 0) // Check if the event interrupt mask is open.
305 {
306 // close the event interrupt mask.
307 csr_read_clear(CSR_MIE, BIT(mcause));
308 }
309 }
310 }
311 else
312 {
313 handler_count[mcause]++;
314 }
315 #endif
316 }
317
rt_systick_config(void)318 void rt_systick_config(void)
319 {
320 extern int timer_irq_init(uint32_t ticks);
321 timer_irq_init(ARCHI_FPGA_FREQUENCY / RT_TICK_PER_SECOND);
322 }
323