2019-06-05 13:29:51 +02:00
|
|
|
/****************************************************************************
|
|
|
|
* arch/arm/src/cxd56xx/cxd56_cpufifo.c
|
|
|
|
*
|
|
|
|
* Copyright 2018 Sony Semiconductor Solutions Corporation
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
*
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
* 3. Neither the name of Sony Semiconductor Solutions Corporation nor
|
|
|
|
* the names of its contributors may be used to endorse or promote
|
|
|
|
* products derived from this software without specific prior written
|
|
|
|
* permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include <nuttx/config.h>
|
|
|
|
#include <nuttx/irq.h>
|
|
|
|
#include <nuttx/arch.h>
|
|
|
|
#include <queue.h>
|
|
|
|
#include <debug.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
#include "up_arch.h"
|
|
|
|
|
|
|
|
#include "chip.h"
|
|
|
|
#include "hardware/cxd56_cpufifo.h"
|
|
|
|
#include "cxd56_cpufifo.h"
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Definitions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#ifdef CONFIG_CXD56_CPUFIFO_ENTRIES
|
|
|
|
#define NR_PUSHBUFENTRIES CONFIG_CXD56_CPUFIFO_ENTRIES
|
|
|
|
#else
|
|
|
|
#define NR_PUSHBUFENTRIES 8
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define MSGFROM(x) (((x)[0] >> 28) & 0xf)
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Types
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
struct cfpushdata_s
|
|
|
|
{
|
|
|
|
FAR sq_entry_t entry;
|
|
|
|
uint32_t data[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Function Prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int cpufifo_txhandler(int irq, FAR void *context, FAR void *arg);
|
|
|
|
static int cpufifo_rxhandler(int irq, FAR void *context, FAR void *arg);
|
|
|
|
static int cpufifo_trypush(uint32_t data[2]);
|
2019-09-26 13:28:26 +02:00
|
|
|
static int cpufifo_reserve(uint32_t data[2]);
|
2019-06-05 13:29:51 +02:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Data
|
|
|
|
****************************************************************************/
|
2019-06-10 15:00:57 +02:00
|
|
|
|
2019-06-05 13:29:51 +02:00
|
|
|
/* Only for SYS, GNSS CPUs */
|
|
|
|
|
|
|
|
static sq_queue_t g_pushqueue;
|
|
|
|
static sq_queue_t g_emptyqueue;
|
|
|
|
static struct cfpushdata_s g_pushbuffer[NR_PUSHBUFENTRIES];
|
|
|
|
static cpufifo_handler_t g_cfrxhandler;
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Private Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
static int cpufifo_txhandler(int irq, FAR void *context, FAR void *arg)
|
|
|
|
{
|
|
|
|
FAR struct cfpushdata_s *pd;
|
|
|
|
|
|
|
|
pd = (FAR struct cfpushdata_s *)sq_remfirst(&g_pushqueue);
|
|
|
|
if (pd)
|
|
|
|
{
|
|
|
|
/* Ignore error because always FIFO is not full at here */
|
|
|
|
|
|
|
|
cpufifo_trypush(pd->data);
|
|
|
|
sq_addlast(&pd->entry, &g_emptyqueue);
|
|
|
|
}
|
2020-01-07 22:29:52 +01:00
|
|
|
|
2019-06-05 13:29:51 +02:00
|
|
|
if (sq_empty(&g_pushqueue))
|
|
|
|
{
|
|
|
|
up_disable_irq(CXD56_IRQ_FIFO_TO);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cpufifo_rxhandler(int irq, FAR void *context, FAR void *arg)
|
|
|
|
{
|
2020-01-07 22:29:52 +01:00
|
|
|
uint32_t word[2] =
|
|
|
|
{
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2019-06-05 13:29:51 +02:00
|
|
|
int cpuid;
|
|
|
|
|
|
|
|
/* Drain from PULL FIFO. But not all data because this handler
|
|
|
|
* will be re-entered when data remaining in PULL FIFO.
|
|
|
|
*/
|
|
|
|
|
|
|
|
cxd56_cfpull(word);
|
|
|
|
cpuid = MSGFROM(word);
|
|
|
|
|
|
|
|
DEBUGASSERT(cpuid >= 0 && cpuid < 8);
|
|
|
|
|
|
|
|
if (g_cfrxhandler)
|
|
|
|
{
|
|
|
|
g_cfrxhandler(cpuid, word);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int cpufifo_trypush(uint32_t data[2])
|
|
|
|
{
|
|
|
|
if (getreg32(CXD56_FIF_PUSH_FULL))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
putreg32(data[0], CXD56_FIF_PUSH_WRD0);
|
|
|
|
putreg32(data[1], CXD56_FIF_PUSH_WRD1);
|
|
|
|
putreg32(1, CXD56_FIF_PUSH_CMP);
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
2019-09-26 13:28:26 +02:00
|
|
|
static int cpufifo_reserve(uint32_t data[2])
|
2019-06-05 13:29:51 +02:00
|
|
|
{
|
|
|
|
FAR struct cfpushdata_s *pd;
|
|
|
|
|
|
|
|
pd = (FAR struct cfpushdata_s *)sq_remfirst(&g_emptyqueue);
|
|
|
|
|
2019-09-26 13:28:26 +02:00
|
|
|
/* This error indicates that need more sending buffer, it can be
|
2019-06-05 13:29:51 +02:00
|
|
|
* configured by CONFIG_CXD56_CPUFIFO_ENTRIES.
|
|
|
|
*/
|
|
|
|
|
2019-09-26 13:28:26 +02:00
|
|
|
if (!pd)
|
|
|
|
{
|
|
|
|
return -EAGAIN;
|
|
|
|
}
|
2019-06-05 13:29:51 +02:00
|
|
|
|
|
|
|
pd->data[0] = data[0];
|
|
|
|
pd->data[1] = data[1];
|
|
|
|
sq_addlast(&pd->entry, &g_pushqueue);
|
2019-09-26 13:28:26 +02:00
|
|
|
return OK;
|
2019-06-05 13:29:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* Public Functions
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
int cxd56_cfpush(uint32_t data[2])
|
|
|
|
{
|
|
|
|
irqstate_t flags;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
flags = enter_critical_section();
|
|
|
|
if (!sq_empty(&g_pushqueue))
|
|
|
|
{
|
2019-09-26 13:28:26 +02:00
|
|
|
ret = cpufifo_reserve(data);
|
2020-01-07 15:21:58 +01:00
|
|
|
leave_critical_section(flags);
|
2019-09-26 13:28:26 +02:00
|
|
|
return ret;
|
2019-06-05 13:29:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ret = cpufifo_trypush(data);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
cpufifo_reserve(data);
|
|
|
|
up_enable_irq(CXD56_IRQ_FIFO_TO);
|
|
|
|
}
|
|
|
|
|
|
|
|
leave_critical_section(flags);
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cxd56_cfpull(uint32_t data[2])
|
|
|
|
{
|
|
|
|
if (getreg32(CXD56_FIF_PULL_EMP))
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
data[0] = getreg32(CXD56_FIF_PULL_WRD0);
|
|
|
|
data[1] = getreg32(CXD56_FIF_PULL_WRD1);
|
|
|
|
putreg32(1, CXD56_FIF_PULL_CMP);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int cxd56_cfregrxhandler(cpufifo_handler_t handler)
|
|
|
|
{
|
|
|
|
irqstate_t flags;
|
|
|
|
int ret = OK;
|
|
|
|
|
|
|
|
flags = enter_critical_section();
|
|
|
|
if (g_cfrxhandler)
|
|
|
|
{
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_cfrxhandler = handler;
|
|
|
|
}
|
2020-01-07 22:29:52 +01:00
|
|
|
|
2019-06-05 13:29:51 +02:00
|
|
|
leave_critical_section(flags);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void cxd56_cfunregrxhandler(void)
|
|
|
|
{
|
|
|
|
irqstate_t flags;
|
|
|
|
flags = enter_critical_section();
|
|
|
|
g_cfrxhandler = NULL;
|
|
|
|
leave_critical_section(flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
int cxd56_cfinitialize(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Setup IRQ handlers. Enable only FROM (RX) interrupt because TO (TX)
|
|
|
|
* interrupt for retry sending when FIFO is full.
|
|
|
|
*/
|
|
|
|
|
|
|
|
irq_attach(CXD56_IRQ_FIFO_FROM, cpufifo_rxhandler, NULL);
|
|
|
|
irq_attach(CXD56_IRQ_FIFO_TO, cpufifo_txhandler, NULL);
|
|
|
|
up_enable_irq(CXD56_IRQ_FIFO_FROM);
|
|
|
|
|
|
|
|
/* Initialize push buffer. */
|
|
|
|
|
|
|
|
sq_init(&g_pushqueue);
|
|
|
|
sq_init(&g_emptyqueue);
|
|
|
|
|
|
|
|
for (i = 0; i < NR_PUSHBUFENTRIES; i++)
|
|
|
|
{
|
|
|
|
sq_addlast((FAR sq_entry_t *)&g_pushbuffer[i], &g_emptyqueue);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clear user defined receive handler. */
|
|
|
|
|
|
|
|
g_cfrxhandler = NULL;
|
|
|
|
|
|
|
|
return OK;
|
|
|
|
}
|