summaryrefslogtreecommitdiff
path: root/bsp/nuvoton/libraries/n9h30/rtt_port/drv_sys.c
blob: ed5164455a8576a9736b591147124ebfe7bd9f79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date            Author           Notes
* 2020-11-11      Wayne            First version
*
******************************************************************************/

#include <rthw.h>
#include <rtthread.h>
#include "NuMicro.h"
#include "drv_sys.h"

#define SYS_MIN_INT_SOURCE       1
#define SYS_MAX_INT_SOURCE       62
#define SYS_NUM_OF_AICREG        16
#define INT_IRQ     0x00
#define INT_FIQ     0x01

extern rt_atomic_t rt_interrupt_nest;

rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;

struct rt_irq_desc irq_desc[SYS_MAX_INT_SOURCE + 1];

void rt_hw_interrupt_dummy_handler(int vector, void *param)
{
    rt_kprintf("Unhandled interrupt %d occurred!!!\n", vector);
    RT_ASSERT(0);
}

void rt_hw_interrupt_set_priority(int vector, int IntTypeLevel)
{
    sysSetInterruptPriorityLevel((IRQn_Type)vector, (UINT32)IntTypeLevel);
}

void rt_interrupt_dispatch(rt_uint32_t fiq_irq)
{
    rt_isr_handler_t isr_func;
    rt_uint32_t volatile _mIPER, _mISNR;
    void *param;

    /* Get irq number */
    _mIPER = (inpw(REG_AIC_IPER) >> 2) & 0x3f;
    _mISNR = inpw(REG_AIC_ISNR) & 0x3f;

    if (_mISNR != 0)
    {
        if (_mIPER == _mISNR)
        {
            /* Get interrupt service routine */
            isr_func = irq_desc[_mISNR].handler;
            param = irq_desc[_mISNR].param;

#ifdef RT_USING_INTERRUPT_INFO
            irq_desc[_mISNR].counter ++;
#endif

            /* Turn to interrupt service routine */
            isr_func(_mISNR, param);
        }
    }

    /* Handled the ISR. */
    outpw(REG_AIC_EOSCR, 1);
}

void rt_hw_interrupt_init(void)
{
    int i;

    outpw(REG_AIC_ISR, 0xFFFFFFFF);  // disable all interrupt channel
    outpw(REG_AIC_ISRH, 0xFFFFFFFF); // disable all interrupt channel
    outpw(REG_AIC_EOSCR, 1);

    /* init interrupt nest, and context in thread sp */
    rt_interrupt_nest               = 0;
    rt_interrupt_from_thread        = 0;
    rt_interrupt_to_thread          = 0;
    rt_thread_switch_interrupt_flag = 0;

    for (i = SYS_MIN_INT_SOURCE; i <= SYS_MAX_INT_SOURCE; i++)
    {
        rt_hw_interrupt_install(i, rt_hw_interrupt_dummy_handler, RT_NULL, (char *)"dummy");
        rt_hw_interrupt_mask(i);
    }
}

rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, void *param, const char *name)
{
    rt_isr_handler_t    old_handler = RT_NULL;

    if (vector > SYS_MAX_INT_SOURCE)
        return RT_NULL;

    /* Set default priority IRQ_LEVEL_7 */
    rt_hw_interrupt_set_priority(vector, IRQ_LEVEL_7);

    old_handler = irq_desc[vector].handler;
    if (handler != RT_NULL)
    {
        irq_desc[vector].handler = (rt_isr_handler_t)handler;
        irq_desc[vector].param = param;
#ifdef RT_USING_INTERRUPT_INFO
        rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
        irq_desc[vector].counter = 0;
#endif
    }

    return old_handler;
}

/* Disable interrupt */
void rt_hw_interrupt_mask(int vector)
{
    sysDisableInterrupt((IRQn_Type)vector);
}

void rt_hw_interrupt_umask(int vector)
{
    sysEnableInterrupt((IRQn_Type)vector);
}

/* TYPE
 *  #define LOW_LEVEL_SENSITIVE        0x00
 *  #define HIGH_LEVEL_SENSITIVE       0x40
 *  #define NEGATIVE_EDGE_TRIGGER      0x80
 *  #define POSITIVE_EDGE_TRIGGER      0xC0
 */
void rt_hw_interrupt_set_type(int vector, int type)
{
    sysSetInterruptType((IRQn_Type)vector, (UINT32) type);
}

void rt_low_level_init(void)
{
    /* Unlock write-protect */
    SYS_UnlockReg();

    /* Close WDT first, to avoid WDT timer is enabled IBR timeout reset. */
    WDT_Close();

    /* Lock write-protect */
    SYS_LockReg();
}

void nu_clock_base_init(void)
{
    nu_sys_ipclk_enable(CPUCKEN);
    nu_sys_ipclk_enable(HCLKCKEN);
    nu_sys_ipclk_enable(HCLK1CKEN);
    nu_sys_ipclk_enable(HCLK3CKEN);
    nu_sys_ipclk_enable(HCLK4CKEN);
    nu_sys_ipclk_enable(PCLKCKEN);
    nu_sys_ipclk_enable(SRAMCKEN);
    nu_sys_ipclk_enable(DDRCKEN);
}

void machine_reset(void)
{
    rt_kprintf("machine_reset...\n");
    rt_hw_interrupt_disable();

    /* Unlock */
    SYS_UnlockReg();

    nu_sys_ip_reset(CHIPRST);

    while (1);
}

void machine_shutdown(void)
{
    rt_kprintf("machine_shutdown...\n");
    rt_hw_interrupt_disable();

    /* Unlock */
    SYS_UnlockReg();

    while (1);
}


void nu_sys_ip_reset(E_SYS_IPRST eIPRstIdx)
{
    uint32_t volatile u32IPRSTRegAddr;
    uint32_t u32IPRSTRegBit;
    rt_uint32_t level;

    if (eIPRstIdx >= SYS_IPRST_CNT)
        return;

    u32IPRSTRegAddr = REG_SYS_AHBIPRST + (4ul * (eIPRstIdx / 32));
    u32IPRSTRegBit  = eIPRstIdx % 32;

    /* Enter critical section */
    level = rt_hw_interrupt_disable();

    /* Unlock write-protect */
    SYS_UnlockReg();

    /* Enable IP reset */
    outpw(u32IPRSTRegAddr, inpw(u32IPRSTRegAddr) | (1 << u32IPRSTRegBit));

    /* Disable IP reset */
    outpw(u32IPRSTRegAddr, inpw(u32IPRSTRegAddr) & ~(1 << u32IPRSTRegBit));

    /* Wait it done. */
    while (inpw(u32IPRSTRegAddr) & (1 << u32IPRSTRegBit)) {}

    /* Lock write protect */
    SYS_LockReg();

    /* Leave critical section */
    rt_hw_interrupt_enable(level);
}

static void _nu_sys_ipclk(E_SYS_IPCLK eIPClkIdx, uint32_t bEnable)
{
    uint32_t volatile u32IPCLKRegAddr;
    uint32_t u32IPCLKRegBit;
    rt_uint32_t level;

    if (eIPClkIdx >= SYS_IPCLK_CNT)
        return;

    u32IPCLKRegAddr = REG_CLK_HCLKEN + (4ul * (eIPClkIdx / 32));
    u32IPCLKRegBit  = eIPClkIdx % 32;

    /* Enter critical section */
    level = rt_hw_interrupt_disable();

    SYS_UnlockReg();

    if (bEnable)
    {
        /* Enable IP CLK */
        outpw(u32IPCLKRegAddr, inpw(u32IPCLKRegAddr) | (1 << u32IPCLKRegBit));
    }
    else
    {
        /* Disable IP CLK */
        outpw(u32IPCLKRegAddr, inpw(u32IPCLKRegAddr) & ~(1 << u32IPCLKRegBit));
    }

    SYS_LockReg();

    /* Leave critical section */
    rt_hw_interrupt_enable(level);
}


void nu_sys_ipclk_enable(E_SYS_IPCLK eIPClkIdx)
{
    _nu_sys_ipclk(eIPClkIdx, 1);
}

void nu_sys_ipclk_disable(E_SYS_IPCLK eIPClkIdx)
{
    _nu_sys_ipclk(eIPClkIdx, 0);
}

E_SYS_USB0_ID nu_sys_usb0_role(void)
{
    /* Check Role on USB0 dual-role port. */
    /*
        [17] USB0_IDS
           USB0_ID Status
           0 = USB port 0 used as a USB device port.
           1 = USB port 0 used as a USB host port.
      */
    return ((inpw(REG_SYS_MISCISR) & (1 << 17)) > 0) ? USB0_ID_HOST : USB0_ID_DEVICE;
}

#ifdef RT_USING_FINSH

#include <finsh.h>

#ifdef FINSH_USING_MSH
int cmd_reset(int argc, char **argv)
{
    rt_hw_cpu_reset();
    return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_reset, reset, restart the system);

int cmd_shutdown(int argc, char **argv)
{
    rt_hw_cpu_shutdown();
    return 0;
}
MSH_CMD_EXPORT_ALIAS(cmd_shutdown, shutdown, shutdown the system);

int nu_clocks(int argc, char **argv)
{
    rt_kprintf("SYS_UPLL = %d MHz\n", sysGetClock(SYS_UPLL));
    rt_kprintf("SYS_APLL = %d MHz\n", sysGetClock(SYS_APLL));
    rt_kprintf("SYS_SYSTEM = %d MHz\n", sysGetClock(SYS_SYSTEM));
    rt_kprintf("SYS_HCLK1 = %d MHz\n", sysGetClock(SYS_HCLK1));
    rt_kprintf("SYS_HCLK234 = %d MHz\n", sysGetClock(SYS_HCLK234));
    rt_kprintf("SYS_PCLK = %d MHz\n", sysGetClock(SYS_PCLK));
    rt_kprintf("SYS_CPU = %d MHz\n", sysGetClock(SYS_CPU));

    rt_kprintf("CLK_HCLKEN = %08X\n", inpw(REG_CLK_HCLKEN));
    rt_kprintf("CLK_PCLKEN0 = %08X\n", inpw(REG_CLK_PCLKEN0));
    rt_kprintf("CLK_PCLKEN1 = %08X\n", inpw(REG_CLK_PCLKEN1));

    return 0;
}
MSH_CMD_EXPORT(nu_clocks, Get all system clocks);

#ifdef RT_USING_INTERRUPT_INFO
int list_interrupt(int argc, char **argv)
{
    int i;

    for (i = SYS_MIN_INT_SOURCE; i <= SYS_MAX_INT_SOURCE; i++)
    {
        if (irq_desc[i].handler != rt_hw_interrupt_dummy_handler)
        {
            rt_kprintf("[%d] %s: %d\n", i, irq_desc[i].name, irq_desc[i].counter);
        }
    }

    return 0;
}
MSH_CMD_EXPORT(list_interrupt, list registered interrupts);
#endif

#endif

#endif