hal_ti/simplelink/kernel/zephyr/dpl/HwiP_zephyr.c

301 lines
7.3 KiB
C

/*
* Copyright (c) 2017, Texas Instruments Incorporated
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <sys/__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>
#if defined(CONFIG_SOC_SERIES_CC32XX)
#include <driverlib/rom_map.h>
#endif
#include <driverlib/interrupt.h>
#include "stubs.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 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);
}
}
#if defined(CONFIG_SOC_SERIES_CC32XX)
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};
/* 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);
}
#elif defined(CONFIG_SOC_SERIES_CC13X2_CC26X2)
/* INT_PENDSV is already taken by Zephyr, so let's use INT_SWEV0 to support
* SwiP since this line is usually unused. Change this to a different
* interrupt if desired.
*/
int HwiP_swiPIntNum = INT_SWEV0;
typedef struct _HwiP_Obj {
uint32_t intNum;
struct sl_isr_args * cb;
} HwiP_Obj;
static struct sl_isr_args sl_OSC_COMB_cb = {NULL, 0};
static struct sl_isr_args sl_AUX_COMB_cb = {NULL, 0};
static struct sl_isr_args sl_SWEV0_cb = {NULL, 0};
/*
* ======== HwiP_construct ========
*/
HwiP_Handle HwiP_construct(HwiP_Struct *handle, int interruptNum,
HwiP_Fxn hwiFxn, HwiP_Params *params)
{
HwiP_Obj *obj = (HwiP_Obj *)handle;
uintptr_t arg = 0;
uint8_t priority = INT_PRI_LEVEL7; /* default to lowest priority */
if (handle == NULL) {
return NULL;
}
if (params) {
priority = params->priority;
arg = params->arg;
}
/*
* Currently only support INT_OSC_COMB, INT_AUX_COMB, INT_SWEV0
*/
__ASSERT(INT_OSC_COMB == interruptNum || INT_AUX_COMB == interruptNum
|| INT_SWEV0 == interruptNum,
"Unexpected interruptNum: %d\r\n",
interruptNum);
/*
* Priority expected is either:
* INT_PRI_LEVEL1 to INT_PRI_LEVEL7,
* or ~0 or 255 (meaning lowest priority)
* ~0 and 255 are meant to be the same as INT_PRI_LEVEL7.
* For ~0 or 255, we want 7; but Zephyr IRQ_CONNECT adds +1
* to reserve INT_PRI_LEVEL0,
* so we pass 6 for those TI drivers passing prio = ~0.
*/
__ASSERT((INT_PRI_LEVEL7 == priority) ||
(INT_PRI_LEVEL6 == priority) ||
(INT_PRI_LEVEL5 == priority) ||
(INT_PRI_LEVEL4 == priority) ||
(INT_PRI_LEVEL3 == priority) ||
(INT_PRI_LEVEL2 == priority) ||
(INT_PRI_LEVEL1 == priority) ||
(0xFF == priority),
"Unexpected priority level, got: 0x%x\r\n",
(unsigned int)priority);
if (0xFF == priority) {
priority = INT_PRI_LEVEL7;
}
/* The priority for IRQ_CONNECT is encoded in the top 3 bits */
priority = (priority >> 5) - 1;
switch(interruptNum) {
case INT_OSC_COMB:
sl_OSC_COMB_cb.cb = hwiFxn;
sl_OSC_COMB_cb.arg = arg;
obj->cb = &sl_OSC_COMB_cb;
IRQ_CONNECT(INT_OSC_COMB - 16, priority, sl_isr, &sl_OSC_COMB_cb, 0);
break;
case INT_AUX_COMB:
sl_AUX_COMB_cb.cb = hwiFxn;
sl_AUX_COMB_cb.arg = arg;
obj->cb = &sl_AUX_COMB_cb;
IRQ_CONNECT(INT_AUX_COMB - 16, priority, sl_isr, &sl_AUX_COMB_cb, 0);
break;
case INT_SWEV0:
sl_SWEV0_cb.cb = hwiFxn;
sl_SWEV0_cb.arg = arg;
obj->cb = &sl_SWEV0_cb;
IRQ_CONNECT(INT_SWEV0 - 16, priority, sl_isr, &sl_SWEV0_cb, 0);
break;
default:
return(NULL);
}
irq_enable(interruptNum - 16);
obj->intNum = interruptNum;
return (HwiP_Handle)handle;
}
#endif
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)
{
#if defined(CONFIG_SOC_SERIES_CC13X2_CC26X2)
IntPendClear((unsigned long)interruptNum);
#elif defined(CONFIG_SOC_SERIES_CC32XX)
MAP_IntPendClear((unsigned long)interruptNum);
#endif
}
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);
}
#if defined(CONFIG_SOC_SERIES_CC13X2_CC26X2)
void HwiP_post(int interruptNum)
{
IntPendSet((uint32_t)interruptNum);
}
void HwiP_setFunc(HwiP_Handle hwiP, HwiP_Fxn fxn, uintptr_t arg)
{
HwiP_Obj *obj = (HwiP_Obj *)hwiP;
uintptr_t key = HwiP_disable();
obj->cb->cb = fxn;
obj->cb->arg = arg;
HwiP_restore(key);
}
void HwiP_destruct(HwiP_Struct *hwiP)
{
HwiP_Obj *obj = (HwiP_Obj *)hwiP->data;
int interruptNum = obj->intNum;
irq_disable(interruptNum - 16);
obj->cb->cb = NULL;
obj->cb->arg = (uintptr_t)NULL;
obj->cb = NULL;
}
#endif