Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * 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);
}