/* DSP/BIOS standard include files */
#include <std.h>
#include <mem.h>
#include <que.h>
#include <tsk.h>
#include <hwi.h>
/* Chip-support library include files */
#include <csl.h>
#include <csl_edma.h>
#include <csl_vphal.h>
#include <csl_irq.h>
/* IOM/GIO driver model include files */
#include <iom.h>
#include <fvid.h>
/* video driver specific include files */
#include <vport.h>
#include <vportcap.h>
#include <edc.h>
#include "_vport.h"
/* debug include files */
/* to minimize code size and cycle count overhead of the driver */
/* error checking is only performed at debug time */
#include <assert.h>
/* type defines and data structures */
/**************************************************************
* data structure for video port object *
**************************************************************/
typedef struct PortObj{
/* port status register, contains information on whether */
/* port is opened, configured, etc. */
Int status;
/* vp base address for all register access */
Int base;
/* two channel objects for channel A & B. */
/* This is only for capture operation */
_VPORT_ChanObj chanObj[2];
} PortObj;
/* mini-driver API functions */
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams);
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args);
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg);
static Int mdDeleteChan(Ptr chanp);
static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet);
/* local functions */
static void captureEdmaISR(Int tcc);
static void captureISR(Int portNum);
static Int _configCh(Ptr chanp, VPORTCAP_Params *params);
static Int _configChan(Ptr chanp, Ptr args);
static Int _configPort(Ptr chanp, Ptr args);
static Int _configTransfer(Ptr chanp,VPORTCAP_Params *params);
static Int _covrRecover(Ptr chanp);
static Int _setVIntCb(Ptr chanp, Ptr args);
static Int _startVPCapture(Ptr chanp);
static Int _stopVPCapture(Ptr chanp);
/* global and static variables */
IOM_Fxns VPORTCAP_Fxns = {
mdBindDev,
(IOM_TmdUnBindDev)IOM_mdNotImpl,
mdControlChan,
mdCreateChan,
mdDeleteChan,
mdSubmitChan
};
/**************************************************************
* Static allocation and initialization of port objects *
**************************************************************/
static PortObj portObjs[_VP_PORT_CNT] = {
/* video port 0 */
{0, _VP_BASE_PORT0,
/* channel A */
{{0, 0, 0, _VP_BASE_CHAPORT0, EDMA_CHA_VP0EVTYA, EDMA_CHA_VP0EVTUA,
EDMA_CHA_VP0EVTVA, _VP_YSRCA0_ADDR, _VP_CBSRCA0_ADDR,
_VP_CRSRCA0_ADDR },
/* channel B */
{0, 0, 1, _VP_BASE_CHBPORT0, EDMA_CHA_VP0EVTYB, EDMA_CHA_VP0EVTUB,
EDMA_CHA_VP0EVTVB, _VP_YSRCB0_ADDR, _VP_CBSRCB0_ADDR,
_VP_CRSRCB0_ADDR}}},
/* video port 1 */
{0, _VP_BASE_PORT1,
/* channel A */
{{0, 1, 0, _VP_BASE_CHAPORT1, EDMA_CHA_VP1EVTYA, EDMA_CHA_VP1EVTUA,
EDMA_CHA_VP1EVTVA, _VP_YSRCA1_ADDR, _VP_CBSRCA1_ADDR,
_VP_CRSRCA1_ADDR },
/* channel B */
{0, 1, 1, _VP_BASE_CHBPORT1, EDMA_CHA_VP1EVTYB, EDMA_CHA_VP1EVTUB,
EDMA_CHA_VP1EVTVB, _VP_YSRCB1_ADDR, _VP_CBSRCB1_ADDR,
_VP_CRSRCB1_ADDR}}},
/* video port 2 */
{0, _VP_BASE_PORT2,
/* channel A */
{{0, 2, 0, _VP_BASE_CHAPORT2, EDMA_CHA_VP2EVTYA, EDMA_CHA_VP2EVTUA,
EDMA_CHA_VP2EVTVA, _VP_YSRCA2_ADDR, _VP_CBSRCA2_ADDR,
_VP_CRSRCA2_ADDR },
/* channel B */
{0, 2, 1, _VP_BASE_CHBPORT2, EDMA_CHA_VP2EVTYB, EDMA_CHA_VP2EVTUB,
EDMA_CHA_VP2EVTVB, _VP_YSRCB2_ADDR, _VP_CBSRCB2_ADDR,
_VP_CRSRCB2_ADDR }}}
};
/*
* =================== mdBindDev ============================
* Register all external devices to video port capture driver
*/
static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams)
{
Int portNum = devid;
volatile Int i;
volatile Int* base = (volatile Int *)portObjs[portNum].base;
assert(portNum < _VP_PORT_CNT);
base[_VP_VPCTL_OFFSET] =
VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT;
for(i = 0; i < 100000; i ++);
*devp = &portObjs[portNum];
return mdControlChan(&portObjs[portNum], VPORT_CMD_CONFIG_PORT, devParams);
}
/*
* ======== mdControlChan ========
*/
static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args)
{
Int retVal = IOM_EBADMODE;
_VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp;
PortObj* port = &portObjs[chan->portNum];
switch (cmd) {
case VPORT_CMD_START:
retVal = _startVPCapture(chanp);
break;
case VPORT_CMD_STOP:
retVal = _stopVPCapture(chanp);
break;
case VPORT_CMD_SET_VINTCB:
retVal = _setVIntCb(chanp, args);
break;
case VPORT_CMD_CONFIG_PORT:
retVal = _configPort(chanp, args);
break;
case VPORT_CMD_COVR_RECOVER:
retVal = _covrRecover(chanp);
break;
case VPORT_CMD_CONFIG_CHAN:
if(! (port->status & _VPORT_CFGED)) {
retVal = _configChan(chanp, args);
}
break;
default:
if(chan->edcFxns!=INV){
retVal = chan->edcFxns->ctrl(chan->edcHandle,
cmd-VPORT_CMD_EDC_BASE,(Arg)args);
}else {
retVal = IOM_ENOTIMPL;
}
break;
}
return retVal;
}
/*
* =================== mdCreateChan ============================
* create a capture channel
*/
static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode,
Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg)
{
Int chanNum;
volatile Int* base;
PortObj* port;
Int retVal = IOM_COMPLETED;
if(mode != IOM_INPUT){
return IOM_EBADARGS;
}
if(*name ++ != '/') {
return IOM_EBADARGS;
}
chanNum = *name ++ - 'A';
assert(chanNum < _VPORT_CHAN_CNT); // hard code
port = (PortObj *)devp;
if(port->chanObj[chanNum].edcFxns != INV) {
/* open external device */
port->chanObj[chanNum].edcHandle
= port->chanObj[chanNum].edcFxns->open(name, (Arg)INV);
}
if(! (port->status & _VPORT_OPENED)) {
port->status |= _VPORT_OPENED;
base = (volatile Int *)port->base;
/* reset both channels */
base[_VP_VCACTL_OFFSET] |=
VP_VCACTL_RSTCH_RESET << _VP_VCACTL_RSTCH_SHIFT;
base[_VP_VCBCTL_OFFSET] |=
VP_VCBCTL_RSTCH_RESET << _VP_VCBCTL_RSTCH_SHIFT;
} /* if(!port->opened) */
/* initialize the channel object */
if(! (port->chanObj[chanNum].status & _VPORT_OPENED)) {
Int j;
_VPORT_ChanObj *chan = &port->chanObj[chanNum];
chan->status |= _VPORT_OPENED;
chan->vIntMask = 0;
QUE_new(&chan->qIn);
chan->cbFxn = cbFxn;
chan->vIntFxn = (VPORT_IntCallBack)INV;
chan->queEmpty = FALSE;
chan->cbArg = (Arg)cbArg;
chan->mrViop = INV;
chan->packetIOM = INV;
chan->numFrms = 0;
chan->vIntCbArg = (Int)INV;
chan->bufSz = 0;
for(j = 0; j < _VPORT_NUM_EDMA_CHANS_RAW && retVal == IOM_COMPLETED; j ++){
if( (chan->hEdma[j] = EDMA_open(chan->edmaChanNum[j],
EDMA_OPEN_RESET))==EDMA_HINV
||