forked from Imagelibrary/rtems
This patch changes the license to BSD-2 for all source files where the copyright is held by Aeroflex Gaisler, Cobham Gaisler, or Gaisler Research. Some files also includes copyright right statements from OAR and/or embedded Brains in addition to Gaisler. Updates #3053.
1011 lines
24 KiB
C
1011 lines
24 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
|
|
/* SPWTDP - SpaceWire Time Distribution Protocol. The driver provides
|
|
* device discovery and interrupt management.
|
|
*
|
|
* COPYRIGHT (c) 2017.
|
|
* Cobham Gaisler AB
|
|
*
|
|
* 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.
|
|
*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <rtems.h>
|
|
#include <rtems/bspIo.h>
|
|
#include <drvmgr/drvmgr.h>
|
|
#include <grlib/ambapp.h>
|
|
#include <grlib/ambapp_bus.h>
|
|
#include <bsp.h>
|
|
#include <grlib/spwtdp.h>
|
|
|
|
#include <grlib/grlib_impl.h>
|
|
|
|
/*#define STATIC*/
|
|
#define STATIC static
|
|
|
|
/*#define INLINE*/
|
|
#define INLINE inline
|
|
|
|
/*#define UNUSED*/
|
|
#define UNUSED __attribute__((unused))
|
|
|
|
#define DEBUG 1
|
|
|
|
#ifdef DEBUG
|
|
#define DBG(x...) printf(x)
|
|
#else
|
|
#define DBG(x...)
|
|
#endif
|
|
|
|
/* Memory and HW Registers Access routines. All 32-bit access routines */
|
|
#define REG_WRITE(addr, val) \
|
|
(*(volatile unsigned int *)(addr) = (unsigned int)(val))
|
|
#define REG_READ(addr) (*(volatile unsigned int *)(addr))
|
|
|
|
/*
|
|
* Configuration register definitions
|
|
* DEFINED in header
|
|
*/
|
|
|
|
/*
|
|
* Control register definitions
|
|
* DEFINED in header
|
|
*/
|
|
|
|
/*
|
|
* TSTX Control register definitions
|
|
*/
|
|
#define TSTXCTRL_TSTC (0xff<<TSTXCTRL_TSTC_BIT)
|
|
#define ETCTRL_PF (0xffff<<ETCTRL_PF_BIT)
|
|
|
|
#define TSTXCTRL_TSTC_BIT 24
|
|
#define ETCTRL_PF_BIT 0
|
|
|
|
#define DEVNAME_LEN 11
|
|
/* Private structure of SPWTDP driver. */
|
|
struct spwtdp_priv {
|
|
char devname[DEVNAME_LEN];
|
|
struct drvmgr_dev *dev; /* Device */
|
|
struct spwtdp_regs *regs;
|
|
int open;
|
|
int index;
|
|
int initiator; /* Initiator configured */
|
|
int target; /* Target configured */
|
|
int freq; /* Frequency configured */
|
|
|
|
/* Spin-lock ISR protection */
|
|
SPIN_DECLARE(devlock);
|
|
|
|
/* Driver semaphore */
|
|
rtems_id sem;
|
|
spwtdp_isr_t isr;
|
|
void * isr_arg;
|
|
};
|
|
int spwtdp_count = 0;
|
|
static struct spwtdp_priv *priv_tab[SPWTDP_MAX];
|
|
|
|
|
|
STATIC void spwtdp_isr(void *data);
|
|
STATIC int spwtdp_hw_reset(struct spwtdp_priv *priv);
|
|
STATIC int spwtdp_init2(struct drvmgr_dev *dev);
|
|
|
|
struct drvmgr_drv_ops spwtdp_ops =
|
|
{
|
|
{NULL, spwtdp_init2, NULL, NULL},
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
struct amba_dev_id spwtdp_ids[] =
|
|
{
|
|
{VENDOR_GAISLER, GAISLER_SPWTDP},
|
|
{0, 0} /* Mark end of table */
|
|
};
|
|
|
|
struct amba_drv_info spwtdp_drv_info =
|
|
{
|
|
{
|
|
DRVMGR_OBJ_DRV, /* Driver */
|
|
NULL, /* Next driver */
|
|
NULL, /* Device list */
|
|
DRIVER_AMBAPP_GAISLER_SPWTDP_ID,/* Driver ID */
|
|
"SPWTDP_DRV", /* Driver Name */
|
|
DRVMGR_BUS_TYPE_AMBAPP, /* Bus Type */
|
|
&spwtdp_ops,
|
|
NULL, /* Funcs */
|
|
0, /* No devices yet */
|
|
sizeof(struct spwtdp_priv), /* Let DrvMgr allocate priv */
|
|
},
|
|
&spwtdp_ids[0]
|
|
};
|
|
|
|
/* Register the SPWTDP Driver */
|
|
void spwtdp_register_drv(void)
|
|
{
|
|
DBG("Registering SPWTDP driver\n");
|
|
drvmgr_drv_register(&spwtdp_drv_info.general);
|
|
}
|
|
|
|
STATIC int spwtdp_init(struct spwtdp_priv *priv)
|
|
{
|
|
struct amba_dev_info *ainfo = priv->dev->businfo;
|
|
struct ambapp_apb_info *apb;
|
|
|
|
/* Get device information from AMBA PnP information */
|
|
if (ainfo == NULL) {
|
|
return -1;
|
|
}
|
|
apb = ainfo->info.apb_slv;
|
|
priv->regs = (struct spwtdp_regs *)apb->start;
|
|
|
|
spwtdp_hw_reset(priv);
|
|
/* Only support 56 bits counter */
|
|
if (REG_READ(&priv->regs->dat_ctrl) != 0x2f00) {
|
|
DBG("SPWTDP only supports 56 bit precission counters.\n");
|
|
return -1;
|
|
}
|
|
DBG("SPWTDP driver initialized\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*** INTERFACE TO DRIVER MANAGER ***/
|
|
STATIC int spwtdp_init2(struct drvmgr_dev *dev)
|
|
{
|
|
int status;
|
|
struct spwtdp_priv *priv;
|
|
|
|
DBG("SPWTDP[%d] on bus %s\n", dev->minor_drv, dev->parent->dev->name);
|
|
|
|
if (spwtdp_count >= SPWTDP_MAX)
|
|
return DRVMGR_ENORES;
|
|
|
|
priv = dev->priv;
|
|
if (priv == NULL)
|
|
return DRVMGR_NOMEM;
|
|
|
|
/* Register device */
|
|
priv->dev = dev;
|
|
priv->index = spwtdp_count;
|
|
priv_tab[priv->index] = priv;
|
|
snprintf(priv->devname, DEVNAME_LEN, "spwtdp%01u", priv->index);
|
|
spwtdp_count++;
|
|
|
|
/* Initialize Semaphore */
|
|
if (rtems_semaphore_create(
|
|
rtems_build_name('S', 'T', 'P', '0' + priv->index), 1,
|
|
RTEMS_FIFO | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
|
|
RTEMS_NO_INHERIT_PRIORITY | RTEMS_LOCAL | \
|
|
RTEMS_NO_PRIORITY_CEILING, 0, &priv->sem) != RTEMS_SUCCESSFUL) {
|
|
priv->sem = RTEMS_ID_NONE;
|
|
return DRVMGR_FAIL;
|
|
}
|
|
|
|
/* Initialize SPWTDP Hardware */
|
|
status = spwtdp_init(priv);
|
|
if (status) {
|
|
printk("Failed to initialize spwtdp driver %d\n", status);
|
|
return -1;
|
|
}
|
|
|
|
return DRVMGR_OK;
|
|
}
|
|
|
|
/* Hardware Reset of SPWTDP */
|
|
STATIC int spwtdp_hw_reset(struct spwtdp_priv *priv)
|
|
{
|
|
int i = 1000;
|
|
SPIN_IRQFLAGS(irqflags);
|
|
|
|
SPIN_LOCK_IRQ(&priv->devlock, irqflags);
|
|
|
|
/* Clear interrupts */
|
|
REG_WRITE(&priv->regs->ists, SPWTDP_IRQ_WCLEAR);
|
|
|
|
/* Reset the SPWTDP core */
|
|
REG_WRITE(&priv->regs->conf[0], CONF0_RS);
|
|
|
|
/* Wait for reset */
|
|
while ((REG_READ(&priv->regs->conf[0]) & CONF0_RS) && (i > 0)) {
|
|
i--;
|
|
}
|
|
|
|
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
|
|
|
|
return ((i > 0)? SPWTDP_ERR_OK : SPWTDP_ERR_ERROR);
|
|
}
|
|
|
|
int spwtdp_reset(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv and unregister isr */
|
|
int ret = spwtdp_isr_unregister(spwtdp);
|
|
if (ret != SPWTDP_ERR_OK)
|
|
return ret;
|
|
|
|
priv->initiator=0;
|
|
priv->target=0;
|
|
priv->freq=0;
|
|
|
|
return spwtdp_hw_reset(priv);
|
|
}
|
|
|
|
void *spwtdp_open(int dev_no)
|
|
{
|
|
struct spwtdp_priv *priv;
|
|
|
|
if (dev_no >= spwtdp_count)
|
|
return NULL;
|
|
|
|
/* Get Device */
|
|
priv = priv_tab[dev_no];
|
|
if ((priv == NULL)||(priv->open == 1)) {
|
|
return NULL;
|
|
}
|
|
|
|
/* Set initial state of software */
|
|
priv->open = 1;
|
|
|
|
return priv;
|
|
}
|
|
|
|
int spwtdp_close(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv and reset core */
|
|
int ret = spwtdp_reset(spwtdp);
|
|
if (ret != SPWTDP_ERR_OK)
|
|
return ret;
|
|
|
|
priv->open = 0;
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_freq_setup(void *spwtdp, uint32_t fsinc, uint32_t cv, uint8_t etinc)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
REG_WRITE(&priv->regs->conf[1], fsinc & CONF1_FSINC);
|
|
REG_WRITE(&priv->regs->conf[2],
|
|
((cv<<CONF2_CV_BIT) & CONF2_CV) |
|
|
((uint32_t)etinc & CONF2_ETINC));
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
priv->freq = 1;
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
#define CONF0_INI_MASK (CONF0_EP|CONF0_ET|CONF0_SP|CONF0_SE|CONF0_LE| \
|
|
CONF0_TD)
|
|
int spwtdp_initiator_conf(void *spwtdp, uint8_t mapping, uint32_t options)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as target */
|
|
if (priv->target == 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int conf0 = REG_READ(&priv->regs->conf[0]);
|
|
conf0 &= ~(CONF0_INI_MASK|CONF0_MAP);
|
|
REG_WRITE(&priv->regs->conf[0],
|
|
conf0 | (options & CONF0_INI_MASK) |
|
|
(((uint32_t)mapping << CONF0_MAP_BIT) & CONF0_MAP));
|
|
|
|
priv->initiator = 1;
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
#define CONF0_TAR_MASK (CONF0_JE|CONF0_ST|CONF0_EP|CONF0_ET|CONF0_SP| \
|
|
CONF0_SE|CONF0_LE|CONF0_TD|CONF0_ME)
|
|
int spwtdp_target_conf(void *spwtdp, uint8_t mapping, uint32_t options)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as initiator */
|
|
if (priv->initiator == 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int conf0 = REG_READ(&priv->regs->conf[0]);
|
|
conf0 &= ~(CONF0_TAR_MASK|CONF0_MAP);
|
|
REG_WRITE(&priv->regs->conf[0],
|
|
conf0 | (options & CONF0_TAR_MASK) |
|
|
(((uint32_t)mapping << CONF0_MAP_BIT) & CONF0_MAP));
|
|
|
|
priv->initiator = 1;
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_initiator_int_conf(void *spwtdp, uint8_t stm, uint8_t inrx,
|
|
uint8_t intx)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as initiator */
|
|
if (priv->initiator != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
REG_WRITE(&priv->regs->conf[3],
|
|
(((uint32_t)stm << CONF3_STM_BIT) & CONF3_STM) |
|
|
(((uint32_t)inrx << CONF3_INRX_BIT) & CONF3_INRX) |
|
|
(((uint32_t)intx << CONF3_INTX_BIT) & CONF3_INTX));
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_target_int_conf(void *spwtdp, uint8_t inrx, uint8_t intx,
|
|
uint32_t options)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL) {
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as target */
|
|
if (priv->target != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
REG_WRITE(&priv->regs->conf[3],
|
|
(options & CONF3_DI) |
|
|
(((uint32_t)inrx << CONF3_INRX_BIT) & CONF3_INRX) |
|
|
(((uint32_t)intx << CONF3_INTX_BIT) & CONF3_INTX));
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_initiator_enable(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL) {
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as initiator */
|
|
if (priv->initiator != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if frequency is configured */
|
|
if (priv->freq != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int conf0 = REG_READ(&priv->regs->conf[0]);
|
|
REG_WRITE(&priv->regs->conf[0], conf0 | CONF0_TE);
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_target_enable(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as target */
|
|
if (priv->target != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if frequency is configured */
|
|
if (priv->freq != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int conf0 = REG_READ(&priv->regs->conf[0]);
|
|
REG_WRITE(&priv->regs->conf[0], conf0 | CONF0_RE);
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_initiator_disable(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int conf0 = REG_READ(&priv->regs->conf[0]);
|
|
REG_WRITE(&priv->regs->conf[0], conf0 & ~(CONF0_TE));
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_target_disable(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
/* Check priv */
|
|
if (priv == NULL)
|
|
return SPWTDP_ERR_NOINIT;
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int conf0 = REG_READ(&priv->regs->conf[0]);
|
|
REG_WRITE(&priv->regs->conf[0], conf0 & ~(CONF0_RE));
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
/* Get and Clear status */
|
|
int spwtdp_status(void *spwtdp, uint32_t *sts, uint32_t clrmask)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
unsigned int status = REG_READ(&priv->regs->stat[0]);
|
|
REG_WRITE(&priv->regs->stat[0], status & clrmask);
|
|
|
|
if (sts != NULL)
|
|
*sts = status;
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
/* Get and Clear interrupts */
|
|
int spwtdp_interrupt_status(void *spwtdp, uint32_t *sts, uint32_t clrmask)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
SPIN_IRQFLAGS(irqflags);
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
SPIN_LOCK_IRQ(&priv->devlock, irqflags);
|
|
unsigned int status = REG_READ(&priv->regs->ists);
|
|
REG_WRITE(&priv->regs->ists, status & clrmask);
|
|
SPIN_UNLOCK_IRQ(&priv->devlock, irqflags);
|
|
|
|
if (sts != NULL)
|
|
*sts = status;
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
/* Unmask interrupts */
|
|
int spwtdp_interrupt_unmask(void *spwtdp, uint32_t irqmask)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
unsigned int ctrl = REG_READ(&priv->regs->ien);
|
|
REG_WRITE(&priv->regs->ien, ctrl | irqmask);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
/* Mask interrupts */
|
|
int spwtdp_interrupt_mask(void *spwtdp, uint32_t irqmask)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
unsigned int ctrl = REG_READ(&priv->regs->ien);
|
|
REG_WRITE(&priv->regs->ien, ctrl & ~(irqmask));
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_isr_register(void *spwtdp, spwtdp_isr_t func, void *data)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
SPIN_ISR_IRQFLAGS(irqflags);
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check isr */
|
|
if (func == NULL) {
|
|
/* No ISR */
|
|
return SPWTDP_ERR_EINVAL;
|
|
}
|
|
|
|
priv->isr = func;
|
|
priv->isr_arg = data;
|
|
|
|
/* Register and Enable Interrupt at Interrupt controller */
|
|
drvmgr_interrupt_register(priv->dev, 0, "spwtdp", spwtdp_isr, priv);
|
|
|
|
/* Enable AMBA Interrupts */
|
|
SPIN_LOCK(&priv->devlock, irqflags);
|
|
unsigned int cfg0 = REG_READ(&priv->regs->conf[0]);
|
|
REG_WRITE(&priv->regs->conf[0], cfg0 | CONF0_AE);
|
|
SPIN_UNLOCK(&priv->devlock, irqflags);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_isr_unregister(void *spwtdp)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
SPIN_ISR_IRQFLAGS(irqflags);
|
|
|
|
/* Disable IRQS (and check for priv!=NULL) */
|
|
int ret=spwtdp_interrupt_mask(spwtdp, SPWTDP_IRQ_WCLEAR);
|
|
if (ret != SPWTDP_ERR_OK)
|
|
return ret;
|
|
|
|
/* Disable AMBA Interrupts */
|
|
SPIN_LOCK(&priv->devlock, irqflags);
|
|
unsigned int cfg0 = REG_READ(&priv->regs->conf[0]);
|
|
REG_WRITE(&priv->regs->conf[0], cfg0 & ~(CONF0_AE));
|
|
SPIN_UNLOCK(&priv->devlock, irqflags);
|
|
|
|
/* Disable Interrupt at Interrupt controller */
|
|
drvmgr_interrupt_unregister(priv->dev, 0, spwtdp_isr, priv);
|
|
|
|
/* Unregister isr */
|
|
priv->isr = NULL;
|
|
priv->isr_arg = NULL;
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
STATIC void spwtdp_isr(void *arg)
|
|
{
|
|
struct spwtdp_priv *priv = arg;
|
|
unsigned int ists = REG_READ(&priv->regs->ists);
|
|
SPIN_ISR_IRQFLAGS(irqflags);
|
|
|
|
/* Return if the SPWTDP didn't generate the IRQ */
|
|
if (ists == 0)
|
|
return;
|
|
|
|
SPIN_LOCK(&priv->devlock, irqflags);
|
|
REG_WRITE(&priv->regs->ists, ists); /* clear handled interrupt events */
|
|
SPIN_UNLOCK(&priv->devlock, irqflags);
|
|
|
|
/* Let user Handle Interrupt */
|
|
if (priv->isr!=NULL)
|
|
priv->isr(ists, priv->isr_arg);
|
|
|
|
return;
|
|
}
|
|
|
|
int spwtdp_dat_et_get(void * spwtdp, spwtdp_time_t * val)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check pointer */
|
|
if (val == NULL) {
|
|
return SPWTDP_ERR_EINVAL;
|
|
}
|
|
|
|
val->preamble = REG_READ(&priv->regs->dat_ctrl) & ETCTRL_PF;
|
|
unsigned int * buffer = (unsigned int *) val->data;
|
|
buffer[0] = REG_READ(&priv->regs->dat_et[0]);
|
|
buffer[1] = REG_READ(&priv->regs->dat_et[1]);
|
|
buffer[2] = REG_READ(&priv->regs->dat_et[2]);
|
|
buffer[3] = REG_READ(&priv->regs->dat_et[3]);
|
|
buffer[4] = REG_READ(&priv->regs->dat_et[4]);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_tsrx_et_get(void * spwtdp, spwtdp_time_t * val)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check pointer */
|
|
if (val == NULL) {
|
|
return SPWTDP_ERR_EINVAL;
|
|
}
|
|
|
|
val->preamble = REG_READ(&priv->regs->ts_rx_ctrl) & ETCTRL_PF;
|
|
unsigned int * buffer = (unsigned int *) val->data;
|
|
buffer[0] = REG_READ(&priv->regs->ts_rx_et[0]);
|
|
buffer[1] = REG_READ(&priv->regs->ts_rx_et[1]);
|
|
buffer[2] = REG_READ(&priv->regs->ts_rx_et[2]);
|
|
buffer[3] = REG_READ(&priv->regs->ts_rx_et[3]);
|
|
buffer[4] = REG_READ(&priv->regs->ts_rx_et[4]);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_tstx_et_get(void * spwtdp, spwtdp_time_t * val)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check pointer */
|
|
if (val == NULL) {
|
|
return SPWTDP_ERR_EINVAL;
|
|
}
|
|
|
|
val->preamble = REG_READ(&priv->regs->ts_tx_ctrl) & ETCTRL_PF;
|
|
unsigned int * buffer = (unsigned int *) val->data;
|
|
buffer[0] = REG_READ(&priv->regs->ts_tx_et[0]);
|
|
buffer[1] = REG_READ(&priv->regs->ts_tx_et[1]);
|
|
buffer[2] = REG_READ(&priv->regs->ts_tx_et[2]);
|
|
buffer[3] = REG_READ(&priv->regs->ts_tx_et[3]);
|
|
buffer[4] = REG_READ(&priv->regs->ts_tx_et[4]);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_lat_et_get(void * spwtdp, spwtdp_time_t * val)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check pointer */
|
|
if (val == NULL) {
|
|
return SPWTDP_ERR_EINVAL;
|
|
}
|
|
|
|
val->preamble = REG_READ(&priv->regs->lat_ctrl) & ETCTRL_PF;
|
|
unsigned int * buffer = (unsigned int *) val->data;
|
|
buffer[0] = REG_READ(&priv->regs->lat_et[0]);
|
|
buffer[1] = REG_READ(&priv->regs->lat_et[1]);
|
|
buffer[2] = REG_READ(&priv->regs->lat_et[2]);
|
|
buffer[3] = REG_READ(&priv->regs->lat_et[3]);
|
|
buffer[4] = REG_READ(&priv->regs->lat_et[4]);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_cmd_et_get(void * spwtdp, spwtdp_time_t * val)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check pointer */
|
|
if (val == NULL) {
|
|
return SPWTDP_ERR_EINVAL;
|
|
}
|
|
|
|
val->preamble = REG_READ(&priv->regs->cmd_ctrl) & ETCTRL_PF;
|
|
unsigned int * buffer = (unsigned int *) val->data;
|
|
buffer[0] = REG_READ(&priv->regs->cmd_et[0]);
|
|
buffer[1] = REG_READ(&priv->regs->cmd_et[1]);
|
|
buffer[2] = REG_READ(&priv->regs->cmd_et[2]);
|
|
buffer[3] = REG_READ(&priv->regs->cmd_et[3]);
|
|
buffer[4] = REG_READ(&priv->regs->cmd_et[4]);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_initiator_tstx_conf(void * spwtdp, uint8_t tstc)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as initiator */
|
|
if (priv->initiator != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
REG_WRITE(&priv->regs->ts_tx_ctrl,
|
|
(((uint32_t)tstc) << TSTXCTRL_TSTC_BIT) & TSTXCTRL_TSTC);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_initiator_cmd_et_set(void *spwtdp, spwtdp_time_t val)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as initiator */
|
|
if (priv->initiator != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
unsigned int * buffer = (unsigned int *) val.data;
|
|
REG_WRITE(&priv->regs->lat_et[0], buffer[0]);
|
|
REG_WRITE(&priv->regs->lat_et[1], buffer[1]);
|
|
REG_WRITE(&priv->regs->lat_et[2], buffer[2]);
|
|
REG_WRITE(&priv->regs->lat_et[3], buffer[3]);
|
|
REG_WRITE(&priv->regs->lat_et[4], buffer[4]);
|
|
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
/* Signal new command */
|
|
unsigned int ctrl = REG_READ(&priv->regs->cmd_ctrl);
|
|
REG_WRITE(&priv->regs->cmd_ctrl, ctrl | CTRL_NC);
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_initiator_cmd_spwtc_set(void *spwtdp, uint8_t spwtc)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as initiator */
|
|
if (priv->initiator != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
unsigned int ctrl = (REG_READ(&priv->regs->cmd_ctrl) &~ CTRL_SPWTC);
|
|
REG_WRITE(&priv->regs->cmd_ctrl,
|
|
ctrl | (((uint32_t)spwtc << CTRL_SPWTC_BIT) & CTRL_SPWTC));
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
#define CTRL_TAR_MASK (CTRL_NC|CTRL_IS)
|
|
int spwtdp_target_cmd_conf(void *spwtdp, uint8_t spwtc, uint16_t cpf,
|
|
uint32_t options)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Check if configured as target */
|
|
if (priv->target != 1)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
/* Take SPWTDP lock - Wait until we get semaphore */
|
|
if (rtems_semaphore_obtain(priv->sem, RTEMS_WAIT, RTEMS_NO_TIMEOUT)
|
|
!= RTEMS_SUCCESSFUL)
|
|
return SPWTDP_ERR_ERROR;
|
|
|
|
REG_WRITE(&priv->regs->cmd_ctrl,
|
|
(options & CTRL_TAR_MASK) |
|
|
((cpf << CTRL_CPF_BIT) & CTRL_CPF) |
|
|
(((uint32_t)spwtc << CTRL_SPWTC_BIT) & CTRL_SPWTC));
|
|
|
|
rtems_semaphore_release(priv->sem);
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|
|
int spwtdp_precision_get(void *spwtdp, uint8_t *fine, uint8_t *coarse)
|
|
{
|
|
struct spwtdp_priv *priv = (struct spwtdp_priv *)spwtdp;
|
|
int coarse_precision, fine_precision;
|
|
|
|
if (priv == NULL) {
|
|
/* SPWTDP not initialized */
|
|
return SPWTDP_ERR_NOINIT;
|
|
}
|
|
|
|
if (priv->open == 0)
|
|
return SPWTDP_ERR_EINVAL;
|
|
|
|
unsigned int preamble = REG_READ(&priv->regs->dat_ctrl);
|
|
|
|
if (preamble & 0x80) {
|
|
DBG("Pfield second extension set: unknown format");
|
|
return SPWTDP_ERR_ERROR;
|
|
}
|
|
if (!((preamble & 0x7000) == 0x2000 || (preamble & 0x7000) == 0x1000)) {
|
|
DBG(" PField indicates not unsegmented code: unknown format");
|
|
return SPWTDP_ERR_ERROR;
|
|
}
|
|
/*
|
|
* coarse_precision = 32;
|
|
* fine_precision = 24;
|
|
*/
|
|
coarse_precision = ((preamble >> 10) & 0x3) + 1;
|
|
if (preamble & 0x80)
|
|
coarse_precision += (preamble >> 5) & 0x3;
|
|
fine_precision = (preamble >> 8) & 0x3;
|
|
if (preamble & 0x80)
|
|
fine_precision += (preamble >> 2) & 0x7;
|
|
if (coarse!=NULL)
|
|
*coarse = coarse_precision;
|
|
if (fine!=NULL)
|
|
*fine = fine_precision;
|
|
|
|
return SPWTDP_ERR_OK;
|
|
}
|
|
|