1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

cpu: mips: Add EIC interrupt mode support.

Note this is only supported in unvectored mode currently.
This commit is contained in:
Neil Jones 2016-11-07 13:28:47 +00:00
parent 4dc2028c9b
commit 1838ca575a
2 changed files with 113 additions and 4 deletions

View File

@ -0,0 +1,69 @@
/*
* Copyright 2016, Imagination Technologies Limited and/or its
* affiliated group companies.
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup cpu_mips32r2_commom MIPS32R2 Common
* @ingroup cpu
* @{
*
* @file
* @brief API for supporting External Interrupt Controllers (EIC mode)
*
* @author Neil Jones <neil.jones@imgtec.com>
*/
#ifndef EIC_IRQ_H_
#define EIC_IRQ_H_
#ifdef __cplusplus
extern "C" {
#endif
/**
* @ brief Internal Interrupt numbers
*
* MIPS cores have a few internally generated interrupts from the Timer,
* Performance Counters and Fast Debug Channel hardware, in EIC mode these
* become outputs from the core and are connected to the external controller,
* the external control then loops these back at whichever IPL it decides
*
* We use negative numbers to represent these, leaving positive numbers free for
* the SoC specific interrupts
* @{
*/
#define EIC_IRQ_TIMER (-1)
#define EIC_IRQ_FDC (-2)
#define EIC_IRQ_PC (-3)
/** @} */
/**
* @brief Configure and route the interrupt
*/
void eic_irq_configure(int irq_num);
/**
* @brief Enable an interrupt
*/
void eic_irq_enable(int irq_num);
/**
* @brief Disable an interrupt
*/
void eic_irq_disable(int irq_num);
/**
* @brief Acknowledge an interrupt
*/
void eic_irq_ack(int irq_num);
#ifdef __cplusplus
}
#endif
#endif
/** @} */

View File

@ -21,9 +21,12 @@
#include "irq.h"
#include "timex.h"
#include "div.h"
#include <sys/time.h>
#ifdef EIC_IRQ
#include "../include/eic_irq.h"
#endif
/*
* setting TIMER_ACCURACY_SHIFT lower will improve accuracy
* at the cost of more regular interrupts (hence less power efficient).
@ -40,7 +43,8 @@
/*
* The base MIPS count / compare timer is fixed frequency at core clock / 2
* and is pretty basic This timer is currently only supported in Vectored
* Interrupt Mode (VI), EIC mode is not supported yet.
* Interrupt Mode (VI), EIC mode is partially supported in non-vectored mode
* only.
*
* RIOT's xtimer expects the timer to operate at 1MHZ or any 2^n multiple or
* factor of this, thus we maintain a software timer which counts at 1MHz.
@ -76,7 +80,7 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
{
assert(dev == 0);
(void)freq; /*Cannot adjust Frequency */
(void)freq; /* Cannot adjust Frequency */
timer_isr_ctx.cb = cb;
timer_isr_ctx.arg = arg;
@ -93,7 +97,11 @@ int timer_init(tim_t dev, unsigned long freq, timer_cb_t cb, void *arg)
mips32_bc_c0(C0_CAUSE, CR_DC);
/* Enable Timer Interrupts */
#ifdef EIC_IRQ
eic_irq_configure(EIC_IRQ_TIMER);
#else
mips32_bs_c0(C0_STATUS, SR_HINT5);
#endif
return 0;
@ -160,20 +168,52 @@ void timer_stop(tim_t dev)
void timer_irq_enable(tim_t dev)
{
#ifdef EIC_IRQ
eic_irq_enable(EIC_IRQ_TIMER);
#else
mips32_bs_c0(C0_STATUS, SR_HINT5);
#endif
}
void timer_irq_disable(tim_t dev)
{
#ifdef EIC_IRQ
eic_irq_disable(EIC_IRQ_TIMER);
#else
mips32_bc_c0(C0_STATUS, SR_HINT5);
#endif
}
/* note Compiler inserts GP context save + restore code (to current stack). */
#ifdef EIC_IRQ
/*
* This is a hack - currently the toolchain does not support correct placement
* of EIC mode vectors (it is coming though) But we can support non-vectored EIC
* mode and note the default PIC32 interrupt controller (which uses EIC +
* MCU-ASE) defaults to non vectored mode anyway with all interrupts coming via
* vector 0 which is equivalent to 'sw0' in 'VI' mode.
*
* Thus all EIC interrupts should be decoded here (currently only Timer is
* used)
*
* When toolchain support is available we could move to full vector mode but
* this does take up significant space (MCU-ASE provides 256 vectors at 32B
* spacing (the default) thats 8KB of vector space!), So a single entry point
* may be better anyway.
*
*/
void __attribute__ ((interrupt("vector=sw0"), keep_interrupts_masked)) _mips_isr_sw0(void)
#else
void __attribute__ ((interrupt("vector=hw5"))) _mips_isr_hw5(void)
#endif
{
register int cr = mips_getcr();
if (cr & CR_TI) {
#ifdef EIC_IRQ
eic_irq_ack(EIC_IRQ_TIMER);
#endif
uint32_t status = irq_arch_disable();
counter += TIMER_ACCURACY;
irq_arch_restore(status);