blob: 201854f289f55b6dac422003f39abbcf8d876b63 [file] [log] [blame]
/*
* Copyright (c) 2017, Texas Instruments Incorporated
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <misc/__assert.h>
#include <kernel/zephyr/dpl/dpl.h>
#include <ti/drivers/dpl/HwiP.h>
#include <inc/hw_types.h>
#include <inc/hw_ints.h>
#include <driverlib/rom.h>
#include <driverlib/rom_map.h>
#include <driverlib/interrupt.h>
/*
* IRQ_CONNECT requires we know the ISR signature and argument
* at build time; whereas SimpleLink plugs the interrupts
* at run time, so we create an ISR shim, and register that.
* The callback argument doesn't change after the ISR is registered.
*/
struct sl_isr_args
{
HwiP_Fxn cb;
uintptr_t arg;
};
static struct sl_isr_args sl_UDMA_cb = {NULL, 0};
static struct sl_isr_args sl_UDMAERR_cb = {NULL, 0};
static struct sl_isr_args sl_NWPIC_cb = {NULL, 0};
static struct sl_isr_args sl_LSPI_cb = {NULL, 0};
static void sl_isr(void *isr_arg)
{
HwiP_Fxn cb = ((struct sl_isr_args *)isr_arg)->cb;
uintptr_t arg = ((struct sl_isr_args *)isr_arg)->arg;
/* Call the SimpleLink ISR Handler: */
if (cb) {
cb(arg);
}
}
/* Must hardcode the IRQ for IRQ_CONNECT macro. Must be <= CONFIG_NUM_IRQs.*/
#define EXCEPTION_UDMA 46 /* == INT_UDMA (62) - 16 */
#define EXCEPTION_UDMAERR 47 /* == INT_UDMAERR (63) - 16 */
#define EXCEPTION_NWPIC 171 /* == INT_NWPIC (187) - 16 */
#define EXCEPTION_LSPI 177 /* == INT_LSPI (193) - 16 */
HwiP_Handle HwiP_create(int interruptNum, HwiP_Fxn hwiFxn, HwiP_Params *params)
{
HwiP_Handle handle = 0;
uint32_t priority = ~0;
uintptr_t arg = 0;
if (params) {
priority = params->priority;
arg = params->arg;
}
/*
* SimpleLink only uses the NWPIC, UDMA, UDMAERR and LSPI interrupts:
*/
__ASSERT(INT_NWPIC == interruptNum || INT_UDMA == interruptNum ||
INT_UDMAERR == interruptNum || INT_LSPI == interruptNum,
"Unexpected interruptNum: %d\r\n",
interruptNum);
/*
* Priority expected is either:
* INT_PRIORITY_LVL_1,
* or ~0 or 255 (meaning lowest priority)
* ~0 and 255 are meant to be the same as INT_PRIORITY_LVL_7.
* For ~0 or 255, we want 7; but Zephyr IRQ_CONNECT adds +1,
* so we pass 6 for those TI drivers passing prio = ~0.
*/
__ASSERT((INT_PRIORITY_LVL_1 == priority) ||
(0xff == (priority & 0xff)),
"Expected priority: 0x%x or 0x%x, got: 0x%x\r\n",
INT_PRIORITY_LVL_1, 0xff, (unsigned int)priority);
switch(interruptNum) {
case INT_UDMA:
sl_UDMA_cb.cb = hwiFxn;
sl_UDMA_cb.arg = arg;
IRQ_CONNECT(EXCEPTION_UDMA, 6, sl_isr, &sl_UDMA_cb, 0);
break;
case INT_UDMAERR:
sl_UDMAERR_cb.cb = hwiFxn;
sl_UDMAERR_cb.arg = arg;
IRQ_CONNECT(EXCEPTION_UDMAERR, 6, sl_isr, &sl_UDMAERR_cb, 0);
break;
case INT_NWPIC:
sl_NWPIC_cb.cb = hwiFxn;
sl_NWPIC_cb.arg = arg;
IRQ_CONNECT(EXCEPTION_NWPIC, 1, sl_isr, &sl_NWPIC_cb, 0);
break;
case INT_LSPI:
sl_LSPI_cb.cb = hwiFxn;
sl_LSPI_cb.arg = arg;
IRQ_CONNECT(EXCEPTION_LSPI, 6, sl_isr, &sl_LSPI_cb, 0);
break;
default:
return(handle);
}
irq_enable(interruptNum - 16);
return (HwiP_Handle)interruptNum;
}
/* Can't actually de-register an interrupt in Zephyr, so just disable: */
void HwiP_delete(HwiP_Handle handle)
{
int interruptNum = (int)handle;
__ASSERT(INT_NWPIC == interruptNum || INT_UDMA == interruptNum ||
INT_UDMAERR == interruptNum || INT_LSPI == interruptNum,
"Unexpected interruptNum: %d\r\n",
interruptNum);
irq_disable(interruptNum - 16);
}
void HwiP_Params_init(HwiP_Params *params)
{
params->arg = 0;
params->priority = ~0;
}
/* Zephyr has no functions for clearing an interrupt, so use driverlib: */
void HwiP_clearInterrupt(int interruptNum)
{
MAP_IntPendClear((unsigned long)interruptNum);
}
void HwiP_enableInterrupt(int interruptNum)
{
irq_enable(interruptNum - 16);
}
void HwiP_disableInterrupt(int interruptNum)
{
irq_disable(interruptNum - 16);
}
uintptr_t HwiP_disable(void)
{
uintptr_t key;
key = irq_lock();
return (key);
}
void HwiP_restore(uintptr_t key)
{
irq_unlock(key);
}