interrupt.c 10.2 KB
Newer Older
L
luohui2320@gmail.com 已提交
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
L
luohui2320@gmail.com 已提交
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
L
luohui2320@gmail.com 已提交
5 6 7 8 9 10
 *
 * Change Logs:
 * Date           Author       Notes
 * 2011-01-13     weety      first version
 */

11
#include <rthw.h>
L
luohui2320@gmail.com 已提交
12
#include "at91sam926x.h"
13
#include "interrupt.h"
14
#define MAX_HANDLERS    (AIC_IRQS + PIN_IRQS)
L
luohui2320@gmail.com 已提交
15 16 17 18

extern rt_uint32_t rt_interrupt_nest;

/* exception and interrupt handler table */
19
struct rt_irq_desc irq_desc[MAX_HANDLERS];
20

L
luohui2320@gmail.com 已提交
21
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
D
dzzxzz 已提交
22
rt_uint32_t rt_thread_switch_interrupt_flag;
L
luohui2320@gmail.com 已提交
23 24 25 26 27 28 29 30 31 32 33 34 35 36


/* --------------------------------------------------------------------
 *  Interrupt initialization
 * -------------------------------------------------------------------- */

rt_uint32_t at91_extern_irq;

#define is_extern_irq(irq) ((1 << (irq)) & at91_extern_irq)

/*
 * The default interrupt priority levels (0 = lowest, 7 = highest).
 */
static rt_uint32_t at91sam9260_default_irq_priority[MAX_HANDLERS] = {
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
    7,  /* Advanced Interrupt Controller */
    7,  /* System Peripherals */
    1,  /* Parallel IO Controller A */
    1,  /* Parallel IO Controller B */
    1,  /* Parallel IO Controller C */
    0,  /* Analog-to-Digital Converter */
    5,  /* USART 0 */
    5,  /* USART 1 */
    5,  /* USART 2 */
    0,  /* Multimedia Card Interface */
    2,  /* USB Device Port */
    6,  /* Two-Wire Interface */
    5,  /* Serial Peripheral Interface 0 */
    5,  /* Serial Peripheral Interface 1 */
    5,  /* Serial Synchronous Controller */
    0,
    0,
    0,  /* Timer Counter 0 */
    0,  /* Timer Counter 1 */
    0,  /* Timer Counter 2 */
    2,  /* USB Host port */
    3,  /* Ethernet */
    0,  /* Image Sensor Interface */
    5,  /* USART 3 */
    5,  /* USART 4 */
    5,  /* USART 5 */
    0,  /* Timer Counter 3 */
    0,  /* Timer Counter 4 */
    0,  /* Timer Counter 5 */
    0,  /* Advanced Interrupt Controller */
    0,  /* Advanced Interrupt Controller */
    0,  /* Advanced Interrupt Controller */
L
luohui2320@gmail.com 已提交
69 70 71 72 73 74 75
};

/**
 * @addtogroup AT91SAM926X
 */
/*@{*/

L
luohui2320@gmail.com 已提交
76 77 78
void rt_hw_interrupt_mask(int irq);
void rt_hw_interrupt_umask(int irq);

79
rt_isr_handler_t rt_hw_interrupt_handle(rt_uint32_t vector, void *param)
L
luohui2320@gmail.com 已提交
80
{
81 82
    rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
    return RT_NULL;
L
luohui2320@gmail.com 已提交
83 84
}

85
rt_isr_handler_t at91_gpio_irq_handle(rt_uint32_t vector, void *param)
L
luohui2320@gmail.com 已提交
86
{
87 88 89
    rt_uint32_t isr, pio, irq_n;
    void *parameter;

90
    if (vector == AT91SAM9260_ID_PIOA)
91 92 93 94
    {
        pio = AT91_PIOA;
        irq_n = AIC_IRQS;
    }
95
    else if (vector == AT91SAM9260_ID_PIOB)
96 97 98 99
    {
        pio = AT91_PIOB;
        irq_n = AIC_IRQS + 32;
    }
100
    else if (vector == AT91SAM9260_ID_PIOC)
101 102 103 104 105 106 107
    {
        pio = AT91_PIOC;
        irq_n = AIC_IRQS + 32*2;
    }
    else
        return RT_NULL;
    isr = at91_sys_read(pio+PIO_ISR) & at91_sys_read(pio+PIO_IMR);
108
    while (isr)
109
    {
110
        if (isr & 1)
111 112 113 114 115 116 117 118 119
        {
            parameter = irq_desc[irq_n].param;
            irq_desc[irq_n].handler(irq_n, parameter);
        }
        isr >>= 1;
        irq_n++;
    }

    return RT_NULL;
L
luohui2320@gmail.com 已提交
120 121
}

L
luohui2320@gmail.com 已提交
122 123 124 125 126
/*
 * Initialize the AIC interrupt controller.
 */
void at91_aic_init(rt_uint32_t *priority)
{
127 128 129 130 131 132 133 134
    rt_uint32_t i;

    /*
     * The IVR is used by macro get_irqnr_and_base to read and verify.
     * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
     */
    for (i = 0; i < AIC_IRQS; i++) {
        /* Put irq number in Source Vector Register: */
135
        at91_sys_write(AT91_AIC_SVR(i), i); // no-used
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
        /* Active Low interrupt, with the specified priority */
        at91_sys_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
        //AT91_AIC_SRCTYPE_FALLING

        /* Perform 8 End Of Interrupt Command to make sure AIC will not Lock out nIRQ */
        if (i < 8)
            at91_sys_write(AT91_AIC_EOICR, 0);
    }

    /*
     * Spurious Interrupt ID in Spurious Vector Register is NR_AIC_IRQS
     * When there is no current interrupt, the IRQ Vector Register reads the value stored in AIC_SPU
     */
    at91_sys_write(AT91_AIC_SPU, AIC_IRQS);

    /* No debugging in AIC: Debug (Protect) Control Register */
    at91_sys_write(AT91_AIC_DCR, 0);

    /* Disable and clear all interrupts initially */
    at91_sys_write(AT91_AIC_IDCR, 0xFFFFFFFF);
    at91_sys_write(AT91_AIC_ICCR, 0xFFFFFFFF);
L
luohui2320@gmail.com 已提交
157 158 159
}


L
luohui2320@gmail.com 已提交
160 161
static void at91_gpio_irq_init()
{
162 163
    int i, idx;
    char *name[] = {"PIOA", "PIOB", "PIOC"};
164

165 166 167 168 169 170 171 172 173
    at91_sys_write(AT91_PIOA+PIO_IDR, 0xffffffff);
    at91_sys_write(AT91_PIOB+PIO_IDR, 0xffffffff);
    at91_sys_write(AT91_PIOC+PIO_IDR, 0xffffffff);

    idx = AT91SAM9260_ID_PIOA;
    for (i = 0; i < 3; i++)
    {
        irq_desc[idx].handler = (rt_isr_handler_t)at91_gpio_irq_handle;
        irq_desc[idx].param = RT_NULL;
174 175
#ifdef RT_USING_INTERRUPT_INFO
        rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, name[i]);
176
        irq_desc[idx].counter = 0;
177
#endif
178
        idx++;
179 180 181 182 183
    }

    rt_hw_interrupt_umask(AT91SAM9260_ID_PIOA);
    rt_hw_interrupt_umask(AT91SAM9260_ID_PIOB);
    rt_hw_interrupt_umask(AT91SAM9260_ID_PIOC);
L
luohui2320@gmail.com 已提交
184 185 186
}


L
luohui2320@gmail.com 已提交
187 188 189 190 191
/**
 * This function will initialize hardware interrupt
 */
void rt_hw_interrupt_init(void)
{
192 193
    register rt_uint32_t idx;
    rt_uint32_t *priority = at91sam9260_default_irq_priority;
194

195 196
    at91_extern_irq = (1UL << AT91SAM9260_ID_IRQ0) | (1UL << AT91SAM9260_ID_IRQ1)
            | (1UL << AT91SAM9260_ID_IRQ2);
197 198 199 200 201 202 203 204 205

    /* Initialize the AIC interrupt controller */
    at91_aic_init(priority);

    /* init exceptions table */
    for(idx=0; idx < MAX_HANDLERS; idx++)
    {
        irq_desc[idx].handler = (rt_isr_handler_t)rt_hw_interrupt_handle;
        irq_desc[idx].param = RT_NULL;
206 207 208 209
#ifdef RT_USING_INTERRUPT_INFO
        rt_snprintf(irq_desc[idx].name, RT_NAME_MAX - 1, "default");
        irq_desc[idx].counter = 0;
#endif
210 211 212 213 214 215 216 217 218
    }

    at91_gpio_irq_init();

    /* 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;
L
luohui2320@gmail.com 已提交
219 220
}

L
luohui2320@gmail.com 已提交
221 222
static void at91_gpio_irq_mask(int irq)
{
223 224 225 226
    rt_uint32_t pin, pio, bank;

    bank = (irq - AIC_IRQS)>>5;

227
    if (bank == 0)
228 229 230
    {
        pio = AT91_PIOA;
    }
231
    else if (bank == 1)
232 233 234
    {
        pio = AT91_PIOB;
    }
235
    else if (bank == 2)
236 237 238 239 240 241 242
    {
        pio = AT91_PIOC;
    }
    else
        return;
    pin = 1 << ((irq - AIC_IRQS) & 31);
    at91_sys_write(pio+PIO_IDR, pin);
L
luohui2320@gmail.com 已提交
243 244
}

L
luohui2320@gmail.com 已提交
245 246 247 248 249 250
/**
 * This function will mask a interrupt.
 * @param vector the interrupt number
 */
void rt_hw_interrupt_mask(int irq)
{
251
    if (irq >= AIC_IRQS)
252 253 254 255 256 257 258 259
    {
        at91_gpio_irq_mask(irq);
    }
    else
    {
        /* Disable interrupt on AIC */
        at91_sys_write(AT91_AIC_IDCR, 1 << irq);
    }
L
luohui2320@gmail.com 已提交
260 261 262 263
}

static void at91_gpio_irq_umask(int irq)
{
264 265 266 267
    rt_uint32_t pin, pio, bank;

    bank = (irq - AIC_IRQS)>>5;

268
    if (bank == 0)
269 270 271
    {
        pio = AT91_PIOA;
    }
272
    else if (bank == 1)
273 274 275
    {
        pio = AT91_PIOB;
    }
276
    else if (bank == 2)
277 278 279 280 281 282 283
    {
        pio = AT91_PIOC;
    }
    else
        return;
    pin = 1 << ((irq - AIC_IRQS) & 31);
    at91_sys_write(pio+PIO_IER, pin);
L
luohui2320@gmail.com 已提交
284 285 286 287 288 289 290 291
}

/**
 * This function will un-mask a interrupt.
 * @param vector the interrupt number
 */
void rt_hw_interrupt_umask(int irq)
{
292
    if (irq >= AIC_IRQS)
293 294 295 296 297 298 299 300
    {
        at91_gpio_irq_umask(irq);
    }
    else
    {
        /* Enable interrupt on AIC */
        at91_sys_write(AT91_AIC_IECR, 1 << irq);
    }
L
luohui2320@gmail.com 已提交
301 302 303 304 305
}

/**
 * This function will install a interrupt service routine to a interrupt.
 * @param vector the interrupt number
W
weety 已提交
306 307 308
 * @param handler the interrupt service routine to be installed
 * @param param the interrupt service function parameter
 * @param name the interrupt name
309
 * @return old handler
L
luohui2320@gmail.com 已提交
310
 */
311
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
312
                                    void *param, const char *name)
L
luohui2320@gmail.com 已提交
313
{
314 315 316 317 318 319 320 321 322
    rt_isr_handler_t old_handler = RT_NULL;

    if(vector < MAX_HANDLERS)
    {
        old_handler = irq_desc[vector].handler;
        if (handler != RT_NULL)
        {
            irq_desc[vector].handler = (rt_isr_handler_t)handler;
            irq_desc[vector].param = param;
323 324
#ifdef RT_USING_INTERRUPT_INFO
            rt_snprintf(irq_desc[vector].name, RT_NAME_MAX - 1, "%s", name);
325
            irq_desc[vector].counter = 0;
326
#endif
327 328 329 330
        }
    }

    return old_handler;
L
luohui2320@gmail.com 已提交
331 332 333 334
}

/*@}*/

335
/*
L
luohui2320@gmail.com 已提交
336 337
static int at91_aic_set_type(unsigned irq, unsigned type)
{
338 339 340 341 342 343 344 345 346 347
    unsigned int smr, srctype;

    switch (type) {
    case IRQ_TYPE_LEVEL_HIGH:
        srctype = AT91_AIC_SRCTYPE_HIGH;
        break;
    case IRQ_TYPE_EDGE_RISING:
        srctype = AT91_AIC_SRCTYPE_RISING;
        break;
    case IRQ_TYPE_LEVEL_LOW:
348 349
        // only supported on external interrupts
        if ((irq == AT91_ID_FIQ) || is_extern_irq(irq))
350 351 352 353 354
            srctype = AT91_AIC_SRCTYPE_LOW;
        else
            return -1;
        break;
    case IRQ_TYPE_EDGE_FALLING:
355 356
        // only supported on external interrupts
        if ((irq == AT91_ID_FIQ) || is_extern_irq(irq))
357 358 359 360 361 362 363 364 365 366 367
            srctype = AT91_AIC_SRCTYPE_FALLING;
        else
            return -1;
        break;
    default:
        return -1;
    }

    smr = at91_sys_read(AT91_AIC_SMR(irq)) & ~AT91_AIC_SRCTYPE;
    at91_sys_write(AT91_AIC_SMR(irq), smr | srctype);
    return 0;
L
luohui2320@gmail.com 已提交
368
}
369 370
*/
rt_uint32_t rt_hw_interrupt_get_active(rt_uint32_t fiq_irq)
371 372
{

373 374
    //volatile rt_uint32_t irqstat;
    rt_uint32_t id;
375
    if (fiq_irq == INT_FIQ)
376
        return 0;
377

378 379 380 381 382 383 384
    //IRQ
    /* AIC need this dummy read */
    at91_sys_read(AT91_AIC_IVR);
    /* clear pending register */
    id = at91_sys_read(AT91_AIC_ISR);

    return id;
385 386
}

387
void rt_hw_interrupt_ack(rt_uint32_t fiq_irq, rt_uint32_t id)
388
{
389
    /* new FIQ generation */
390
    if (fiq_irq == INT_FIQ)
391
        return;
392

393 394
    /* new IRQ generation */
    // EIOCR must be write any value after interrupt,
395
    // or else can't response next interrupt
396
    at91_sys_write(AT91_AIC_EOICR, 0x0);
397 398
}

399
#ifdef RT_USING_FINSH
400
#ifdef RT_USING_INTERRUPT_INFO
401 402
void list_irq(void)
{
403 404 405 406 407 408 409 410 411 412
    int irq;

    rt_kprintf("number\tcount\tname\n");
    for (irq = 0; irq < MAX_HANDLERS; irq++)
    {
        if (rt_strncmp(irq_desc[irq].name, "default", sizeof("default")))
        {
            rt_kprintf("%02ld: %10ld  %s\n", irq, irq_desc[irq].counter, irq_desc[irq].name);
        }
    }
413 414 415 416
}

#include <finsh.h>

417 418 419 420 421 422
#ifdef FINSH_USING_MSH
int cmd_list_irq(int argc, char** argv)
{
    list_irq();
    return 0;
}
423
MSH_CMD_EXPORT_ALIAS(cmd_list_irq, list_irq, list system irq);
424 425
#endif
#endif
426 427 428
#endif