www.pudn.com > H265+_C64X_2008.8.rar > vportdis.c
/* * Copyright 2003 by Texas Instruments Incorporated. * All rights reserved. Property of Texas Instruments Incorporated. * Restricted rights to use, duplicate or disclose this code are * granted through contract. * */ /* "@(#) DDK 1.10.00.23 07-02-03 (ddk-b12)" */ /* DSP/BIOS standard include files */ #include#include #include #include /* Chip-support library include files */ #include #include #include #include #include #include /* IOM/GIO driver model include files */ #include #include /* video driver specif-ic include files */ #include #include #include #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 /* 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 Int _configChan(Ptr chanp, Ptr args); static Int _configEDMA(Ptr chanp, VPORTDIS_Params *params); static Int _configPort(Ptr chanp, Ptr args); static Int _configRegs(Ptr chanp, VPORTDIS_Params *params); static void displayEdmaISR(Int tcc); static void displayISR(int portNum); static Int _displayStart(Ptr chanp); static Int _displayStop(Ptr chanp); static Int _dundRecover(Ptr chanp); static Int _getlastActiveLine(VPORTDIS_Params* params); static Int _setVIntCb(Ptr chanp, Ptr args); /* global and static variables */ IOM_Fxns VPORTDIS_Fxns = { mdBindDev, (IOM_TmdUnBindDev)IOM_mdNotImpl, mdControlChan, mdCreateChan, mdDeleteChan, mdSubmitChan }; /************************************************************** * Static allocation and initialization of port objects * * as display supports only 1 channel, the same channel * * object for capture is used here for the whoel port * **************************************************************/ _VPORT_ChanObj chanObjs[_VP_PORT_CNT] = { {0, 0, 0, _VP_BASE_PORT0, EDMA_CHA_VP0EVTYA, EDMA_CHA_VP0EVTUA, EDMA_CHA_VP0EVTVA, _VP_YDSTA0_ADDR, _VP_CBDST0_ADDR, _VP_CRDST0_ADDR}, {0, 1, 0, _VP_BASE_PORT1, EDMA_CHA_VP1EVTYA, EDMA_CHA_VP1EVTUA, EDMA_CHA_VP1EVTVA, _VP_YDSTA1_ADDR, _VP_CBDST1_ADDR, _VP_CRDST1_ADDR}, {0, 2, 0, _VP_BASE_PORT2, EDMA_CHA_VP2EVTYA, EDMA_CHA_VP2EVTUA, EDMA_CHA_VP2EVTVA, _VP_YDSTA2_ADDR, _VP_CBDST2_ADDR, _VP_CRDST2_ADDR }, }; /* * ======== mdBindDev ======== * Register all external devices to video port display driver */ static Int mdBindDev(Ptr *devp, Int devid, Ptr devParams) { Int portNum = devid; volatile Int i; volatile Int* base = (volatile Int *)chanObjs[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 = &chanObjs[portNum]; return mdControlChan(&chanObjs[portNum], VPORT_CMD_CONFIG_PORT, devParams); } /* * ======== mdControlChan ======== */ static Int mdControlChan(Ptr chanp, Uns cmd, Ptr args) { Int retVal = IOM_COMPLETED; _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; /* command dispatcher */ switch (cmd){ case VPORT_CMD_START: retVal = _displayStart(chanp); break; case VPORT_CMD_STOP: retVal = _displayStop(chanp); break; case VPORT_CMD_CONFIG_CHAN: retVal = _configChan(chanp, args); break; case VPORT_CMD_SET_VINTCB: _setVIntCb(chanp, args); break; case VPORT_CMD_DUND_RECOVER: retVal = _dundRecover(chanp); break; case VPORT_CMD_CONFIG_PORT: retVal = _configPort(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; } } return retVal; } /* * ======== mdCreateChan ======== * create a channel */ static Int mdCreateChan(Ptr *chanp, Ptr devp, String name, Int mode, Ptr chanParams, IOM_TiomCallback cbFxn, Ptr cbArg) { _VPORT_ChanObj* chan; Int retVal = IOM_COMPLETED; Int j; if(mode != IOM_OUTPUT){ return IOM_EBADARGS; } chan = (_VPORT_ChanObj *)devp; if(chan->edcFxns != INV) { /* open external device */ chan->edcHandle = chan->edcFxns->open(name, (Arg)INV); } if(! (chan->status & _VPORT_OPENED)) { chan->status |= _VPORT_OPENED; chan->vIntMask = 0; QUE_new(&chan->qIn); QUE_new(&chan->qOut); chan->cbFxn = cbFxn; chan->vIntFxn = (VPORT_IntCallBack)INV; chan->queEmpty = FALSE; chan->cbArg = (Arg)cbArg; chan->packetIOM = INV; chan->vIntCbArg = (Int)INV; chan->bufSz = 0; /* allocate EDMA PaRAM and RLD entries */ for(j = 0; j < _VPORT_NUM_EDMA_CHANS && retVal == IOM_COMPLETED; j ++ ) { if((chan->hEdma[j] = EDMA_open(chan->edmaChanNum[j], EDMA_OPEN_RESET)) == EDMA_HINV || (chan->hRld[4 * j] = EDMA_allocTable(-1)) == EDMA_HINV || (chan->hRld[4 * j + 1] =EDMA_allocTable(-1)) == EDMA_HINV || (chan->hRld[4 * j + 2] =EDMA_allocTable(-1)) == EDMA_HINV || (chan->hRld[4 * j + 3] =EDMA_allocTable(-1)) == EDMA_HINV || (chan->tcc[j] = EDMA_intAlloc(chan->edmaChanNum[j])) == -1){ retVal = IOM_EALLOC; retVal = IOM_EALLOC; }/* if((chan->...*/ }/* for(j = 0; j < NUM_EDMA_CHANS; j++) {...*/ /* if EDMA resources are allocated successfully, go ahead */ /* and configure the channel */ if(retVal == IOM_COMPLETED && (void *)chanParams != INV) { retVal = mdControlChan(chan, VPORT_CMD_CONFIG_CHAN, chanParams); } if(! retVal) { /* configured the channel successfully, return handle */ *chanp = chan; }else { /* failed, free all resources and return error */ mdDeleteChan(chan); *chanp = INV; } } /*if(!chan->opened) */ return retVal; } /* * ======== mdDeleteChan ======== * delete the channel */ static Int mdDeleteChan(Ptr chanp) { _VPORT_ChanObj* chan = (_VPORT_ChanObj* )chanp; Int j; volatile Int* base; if(chan->status & _VPORT_OPENED) { chan->status = 0; mdControlChan(chanp, VPORT_CMD_STOP, NULL); for(j = 0; j < _VPORT_NUM_EDMA_CHANS; j ++) { EDMA_disableChannel(chan->hEdma[j]); EDMA_clearChannel(chan->hEdma[j]); EDMA_close(chan->hEdma[j]); EDMA_freeTable(chan->hRld[4 * j]); EDMA_freeTable(chan->hRld[4 * j + 1]); EDMA_freeTable(chan->hRld[4 * j + 2]); EDMA_freeTable(chan->hRld[4 * j + 3]); EDMA_intFree(chan->tcc[j]); } for(j = 0; j < chan->numFrms ; j ++) { MEM_free(chan->segId, chan->viops[j].frame.iFrm.y1, chan->bufSz); } base = (volatile Int *)chan->base; /* reset display */ base[_VP_VDCTL_OFFSET] |= VP_VDCTL_RSTCH_RESET << _VP_VDCTL_RSTCH_SHIFT; /* reset video port */ base[_VP_VPCTL_OFFSET] |= VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT; chan->status = 0; /* close external device */ if(chan->edcFxns != INV) { chan->edcFxns->close(chan->edcHandle); } } return IOM_COMPLETED; } /* * ======== mdSubmitChan ======== */ static Int mdSubmitChan(Ptr chanp, IOM_Packet *packet) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; FVID_Frame* viop; Int retVal = IOM_PENDING; Uint32 gie = IRQ_globalDisable(); if(packet->cmd != FVID_ALLOC && packet->cmd != FVID_FREE && packet->cmd != FVID_EXCHANGE){ /* other commands not supported */ return IOM_ENOTIMPL; } if(packet->cmd != FVID_ALLOC) {/* FVID_FREE or FVID_EXCHANGE */ viop = *(void **)packet->addr; /* pointer of a video I/O packet */ if(chan->queEmpty) { /* check to make sure it is not to at the end of a frame */ /* to avoid any race condition */ volatile Int* base = (volatile Int *)chan->base; short lineNum = (base[_VP_VDSTAT_OFFSET] & _VP_VDSTAT_VDYPOS_MASK) >> _VP_VDSTAT_VDYPOS_SHIFT; /* make sure we are at least five lines before completion */ /* to prevent EDMA reload happening while it is being modified */ if(lineNum <= chan->lastLineNum - 5) { Int offset = chan->nextEDMARlds << 1; chan->nextViop = viop; /* now modify the EDMA rld entries */ if(chan->mergeFlds){ EDMA_RSETH(chan->hRld[offset], SRC, viop->frame.iFrm.y1); EDMA_RSETH(chan->hRld[offset + 1], SRC, viop->frame.iFrm.y2); if(!(chan->mode & _VPORT_MASK_RAW)){ EDMA_RSETH(chan->hRld[4 + offset], SRC, viop->frame.iFrm.cb1); EDMA_RSETH(chan->hRld[5 + offset], SRC, viop->frame.iFrm.cb2); EDMA_RSETH(chan->hRld[8 + offset], SRC, viop->frame.iFrm.cr1); EDMA_RSETH(chan->hRld[9 + offset], SRC, viop->frame.iFrm.cr2); } } else { EDMA_RSETH(chan->hRld[offset], SRC, viop->frame.iFrm.y1); if(!(chan->mode & _VPORT_MASK_RAW)){ EDMA_RSETH(chan->hRld[4 + offset], SRC, viop->frame.iFrm.cb1); EDMA_RSETH(chan->hRld[8 + offset], SRC, viop->frame.iFrm.cr1); } } /* if(chan->mergeFlds) */ } else { QUE_enqueue(&chan->qIn, (QUE_Handle)viop); } chan->queEmpty = FALSE; } else { QUE_enqueue(&chan->qIn, (QUE_Handle)viop); } retVal = packet->status = IOM_COMPLETED; } if(packet->cmd != FVID_FREE) { /* FVID_ALLOC or FVID_EXCHANGE */ if(chan->packetIOM == INV){ if((viop = (FVID_Frame *)QUE_dequeue(&chan->qOut)) !=(FVID_Frame *)&chan->qOut) { /* only when there is no outstanding pending request */ *(void **)packet->addr = (void *)viop; packet->size = sizeof(FVID_Frame); retVal = packet->status = IOM_COMPLETED; } else { chan->packetIOM = packet; retVal = packet->status = IOM_PENDING; } }else retVal = IOM_EINUSE; } IRQ_globalRestore(gie); return retVal; } /* * ======== _configChan ======== */ static Int _configChan(Ptr chanp, Ptr args) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; VPORTDIS_Params* params = (VPORTDIS_Params* )args; Int retVal; if(!(chan->status & _VPORT_CFGED)) { chan->lastLineNum = _getlastActiveLine(params); /* configure video port channel A/B control register */ _configRegs(chanp, params); /* configure EDMA and frame buffer */ retVal = _configEDMA(chanp, params); } else { retVal = IOM_EINUSE; } return retVal; } static const Int fillValue[4] = { 0, 0, 0x80808080, 0x80808080 }; /* * ======== _configEDMA ======== */ static Int _configEDMA(Ptr chanp, VPORTDIS_Params *params) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; Int i; Int j; EDMA_Config cfgEdma; Int thrld; Int edmaChans; Int8* curAddr; Bool success; if(chan->status & _VPORT_CFGED) { assert(params->numFrmBufs >= 2 && params->numFrmBufs <= VPORT_MAX_NUM_FRMBUFS); chan->numFrms = params->numFrmBufs; chan->segId = params->segId; /* allocate frame buffers */ chan->bufSz = chan->yPitch * chan->numLines + chan->cPitch * chan->numLines * 2; for(i = 0; i < chan->numFrms; i ++) { if((curAddr = MEM_alloc(params->segId,chan->bufSz, params->alignment)) == MEM_ILLEGAL){ for(j = 0; j < i ; j ++) { MEM_free(params->segId, chan->viops[j].frame.iFrm.y1, chan->bufSz); } /* memory allocation fails */ return IOM_EALLOC; } /* field 1 */ chan->viops[i].frame.iFrm.y1 = curAddr; curAddr += chan->numLines*chan->yPitch; chan->viops[i].frame.iFrm.cb1 = curAddr; curAddr += chan->numLines*chan->cPitch; chan->viops[i].frame.iFrm.cr1 = curAddr; curAddr += chan->numLines*chan->cPitch; CACHE_clean(CACHE_L2, (void *)fillValue, 16); success = DAT_open(DAT_CHAANY, DAT_PRI_LOW, 0); for( j = 0; j < chan->numLines; j ++) { DAT_fill(chan->viops[i].frame.iFrm.y1 + j * chan->yPitch, chan->yPitch, (Uint32 *)fillValue); DAT_fill(chan->viops[i].frame.iFrm.cb1 + j * chan->cPitch, chan->cPitch, (Uint32 *)&fillValue[2]); DAT_fill(chan->viops[i].frame.iFrm.cr1 + j * chan->cPitch, chan->cPitch, (Uint32 *)&fillValue[2]); } if(success) { DAT_close(); } /* field 2 */ if(params->fldOp == VPORT_FLDOP_FLD2) { chan->viops[i].frame.iFrm.y2 = chan->viops[i].frame.iFrm.y1; chan->viops[i].frame.iFrm.cb2 = chan->viops[i].frame.iFrm.cb1; chan->viops[i].frame.iFrm.cr2 = chan->viops[i].frame.iFrm.cr1; } else if(chan->mergeFlds) { chan->viops[i].frame.iFrm.y2 = chan->viops[i].frame.iFrm.y1 + chan->yPitch; chan->viops[i].frame.iFrm.cb2 = chan->viops[i].frame.iFrm.cb1 + chan->cPitch; chan->viops[i].frame.iFrm.cr2 = chan->viops[i].frame.iFrm.cr1 + chan->cPitch; }else { chan->viops[i].frame.iFrm.y2 = chan->viops[i].frame.iFrm.y1 + (chan->numLinesFld1*chan->yPitch); chan->viops[i].frame.iFrm.cb2 = chan->viops[i].frame.iFrm.cb1 + (chan->numLinesFld1*chan->cPitch); chan->viops[i].frame.iFrm.cr2 = chan->viops[i].frame.iFrm.cr1 + (chan->numLinesFld1*chan->cPitch); } if(i > 0) { /* don't put the first 1 viop into the queue */ QUE_enqueue(&chan->qOut, (QUE_Handle)&chan->viops[i]); } } chan->nextViop = &chan->viops[0]; chan->curViop = &chan->viops[0]; chan->queEmpty = TRUE; CACHE_clean(CACHE_L2ALL, NULL, NULL); if(chan->mode & _VPORT_MASK_RAW) edmaChans = 1; else edmaChans = 3; for(i = 0; i < edmaChans; i ++) { Int optFld1 = EDMA_OPT_RMK( params->edmaPri, EDMA_OPT_ESIZE_32BIT, EDMA_OPT_2DS_YES, EDMA_OPT_SUM_INC, EDMA_OPT_2DD_NO, EDMA_OPT_DUM_NONE, EDMA_OPT_TCINT_NO, EDMA_OPT_TCC_OF(0), EDMA_OPT_TCCM_OF(0), EDMA_OPT_ATCINT_NO, EDMA_OPT_ATCC_DEFAULT, EDMA_OPT_PDTS_DISABLE, EDMA_OPT_PDTD_DISABLE, EDMA_OPT_LINK_YES, EDMA_OPT_FS_NO ); Int optFld2a = EDMA_OPT_RMK( params->edmaPri, EDMA_OPT_ESIZE_32BIT, EDMA_OPT_2DS_YES, EDMA_OPT_SUM_INC, EDMA_OPT_2DD_NO, EDMA_OPT_DUM_NONE, (i == 0 ? EDMA_OPT_TCINT_YES:EDMA_OPT_TCINT_NO), EDMA_OPT_TCC_OF(i == 0 ? chan->tcc[0] & 0x0f : 0), EDMA_OPT_TCCM_OF(i == 0 ? chan->tcc[0] >> 4 : 0), EDMA_OPT_ATCINT_NO, EDMA_OPT_ATCC_DEFAULT, EDMA_OPT_PDTS_DISABLE, EDMA_OPT_PDTD_DISABLE, EDMA_OPT_LINK_YES, EDMA_OPT_FS_NO ); Int optFld2b = EDMA_OPT_RMK( params->edmaPri, EDMA_OPT_ESIZE_32BIT, EDMA_OPT_2DS_YES, EDMA_OPT_SUM_INC, EDMA_OPT_2DD_NO, EDMA_OPT_DUM_NONE, (i == 0 ? EDMA_OPT_TCINT_YES:EDMA_OPT_TCINT_NO), EDMA_OPT_TCC_OF(i == 0 ? chan->tcc[1] & 0x0f : 0), EDMA_OPT_TCCM_OF(i == 0 ? chan->tcc[1] >> 4 : 0), EDMA_OPT_ATCINT_NO, EDMA_OPT_ATCC_DEFAULT, EDMA_OPT_PDTS_DISABLE, EDMA_OPT_PDTD_DISABLE, EDMA_OPT_LINK_YES, EDMA_OPT_FS_NO ); thrld = (i == 0)? chan->yThrld:chan->cThrld; cfgEdma.dst = EDMA_DST_RMK(chan->edmaAddr[i]); if(chan->mergeFlds) { /* to merge the two fields together */ /* EDMA is configured to transfer only field 1 initially */ /* line pitch is twice the line size */ /* this requires that the threlhold is the same as line size*/ /* PaRAM and reload Entries */ /* first field */ cfgEdma.opt = optFld1; cfgEdma.cnt = EDMA_CNT_RMK( (chan->numEventsFld1) - 1, (thrld << 1)); cfgEdma.idx = EDMA_IDX_RMK(thrld << 4, 0); /* hard code the field 1 & 2 of the first */ /* frame buffer as current and reload buffers */ cfgEdma.src = EDMA_SRC_RMK( *((Int *)(&chan->viops[0].frame.iFrm.y1) + i)); cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4*i + 1]); EDMA_config(chan->hEdma[i], &cfgEdma); EDMA_config(chan->hRld[4 * i], &cfgEdma); cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4*i + 3]); EDMA_config(chan->hRld[4 * i + 2], &cfgEdma); /* second field */ cfgEdma.opt = optFld2a; cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 2]); cfgEdma.cnt = EDMA_CNT_RMK( (chan->numEvents-chan->numEventsFld1) - 1, (thrld << 1)); cfgEdma.src = EDMA_SRC_RMK( *((Int *)(&chan->viops[0].frame.iFrm.y2) + i)); EDMA_config(chan->hRld[4 * i + 1], &cfgEdma); cfgEdma.opt = optFld2b; cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4*i]); EDMA_config(chan->hRld[4 * i + 3], &cfgEdma); }else {/* if fields are not merged, configure EDMA to transfer */ /* for both field1 and field 2 */ /* the line pitch is just the line size */ cfgEdma.opt = optFld2a; cfgEdma.cnt = EDMA_CNT_RMK((chan->numEvents) - 1, (thrld << 1)); cfgEdma.idx = EDMA_IDX_RMK(thrld << 3, 0); /* hard code the first frame buffer as current */ /*and reload buffers */ cfgEdma.src = EDMA_SRC_RMK( *((Int *)(&chan->viops[0].frame.iFrm.y1) + i)); cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i + 2]); EDMA_config(chan->hEdma[i], &cfgEdma); cfgEdma.src = EDMA_SRC_RMK( *((Int *)(&chan->viops[0].frame.iFrm.y1) + i)); EDMA_config(chan->hRld[4 * i], &cfgEdma); cfgEdma.opt = optFld2b; cfgEdma.rld = EDMA_RLD_RMK(0, chan->hRld[4 * i]); EDMA_config(chan->hRld[4 * i + 2], &cfgEdma); } } chan->nextEDMARlds = 1; /* enable EDMA channel */ if(!(chan->mode & _VPORT_MASK_RAW)) { EDMA_disableChannel(chan->hEdma[1]); EDMA_clearChannel(chan->hEdma[1]); EDMA_enableChannel(chan->hEdma[1]); EDMA_disableChannel(chan->hEdma[2]); EDMA_clearChannel(chan->hEdma[2]); EDMA_enableChannel(chan->hEdma[2]); } /* * The EDMA interrupt dispatcher will be called by the * BIOS HWI interrupt dispatcher. */ IRQ_map(IRQ_EVT_EDMAINT, params->irqId); HWI_dispatchPlug(params->irqId, (Fxn)EDMA_intDispatcher, -1, NULL); EDMA_disableChannel(chan->hEdma[0]); EDMA_clearChannel(chan->hEdma[0]); EDMA_enableChannel(chan->hEdma[0]); EDMA_intClear(chan->tcc[0]); EDMA_intEnable(chan->tcc[0]); EDMA_intHook(chan->tcc[0], displayEdmaISR); EDMA_intClear(chan->tcc[1]); EDMA_intEnable(chan->tcc[1]); EDMA_intHook(chan->tcc[1], displayEdmaISR); chan->status |= _VPORT_READY; IRQ_enable(IRQ_EVT_EDMAINT); } return IOM_COMPLETED; } /* * ======== _configPort ======== */ static Int _configPort(Ptr chanp, Ptr args) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; VPORT_PortParams* portParams = (VPORT_PortParams*)args; volatile Int* base = (volatile Int *)chan->base; /* reset video port */ base[_VP_VPCTL_OFFSET] = VP_VPCTL_VPRST_RESET << _VP_VPCTL_VPRST_SHIFT; /* enable video port */ base[_VP_PCR_OFFSET] |= VP_PCR_PEREN_ENABLE << _VP_PCR_PEREN_SHIFT; base[_VP_VDCTL_OFFSET] = (Int)VP_VDCTL_RSTCH_RESET << _VP_VDCTL_RSTCH_SHIFT; /* configure video port control register */ base[_VP_VPCTL_OFFSET] = VP_VPCTL_RMK(0,0,1,portParams->vc3Polarity, portParams->vc2Polarity,portParams->vc1Polarity,0,1,0); /* enable video port */ base[_VP_VPCTL_OFFSET] |= (VP_VPCTL_VPHLT_CLEAR << _VP_VPCTL_VPHLT_SHIFT); chan->edcFxns = portParams->edcTbl[0]; return IOM_COMPLETED; } /* * ======== _configRegs ======== * configure video port registers for display */ static Int _configRegs(Ptr chanp, VPORTDIS_Params* params) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; volatile Int* base = (volatile Int *)chan->base; Int numPixels, numLines, numCPixels; Int vdCtl; Int nh1 = 0, nh2 = 0, nv1 = 0, nv2 = 0; if(chan->status & _VPORT_OPENED) { /* configure display settings */ chan->status |= _VPORT_CFGED; vdCtl = VP_VDCTL_RMK(0,1,0,((params->extCtl&4) >> 2), ((params->extCtl&2)>>1), params->extCtl&1,params->vctl3Config, params->vctl2Config,params->vctl1Config,0, params->bpk10Bit, params->rgbX,0,params->defValEn,params->resmpl, params->scale, 1,((params->fldOp & 4) >> 2), ((params->fldOp & 2) >> 1), (params->fldOp & 1), params->dmode); numLines = 0; numPixels = 0; if(params->fldOp != VPORT_FLDOP_FLD2){ // progressive scan, or field 1 or frame numPixels = params->imgHSizeFld1; numLines = params->imgVSizeFld1; } chan->numLinesFld1 = numLines; if(params->fldOp == VPORT_FLDOP_FLD2 || params->fldOp == VPORT_FLDOP_FRAME){ if(!numPixels) numPixels = params->imgHSizeFld2; numLines += params->imgVSizeFld2; } chan->numLines = numLines; base[_VP_VDCTL_OFFSET] = vdCtl; base[_VP_VDFRMSZ_OFFSET] = VP_VDFRMSZ_RMK(params->frmVSize, params->frmHSize); base[_VP_VDHBLNK_OFFSET] = VP_VDHBLNK_RMK(params->hBlnkStop, !(params->dmode&_VPORT_MASK_RAW), params->hBlnkStart); base[_VP_VDVBLKS1_OFFSET] = VP_VDVBLKS1_RMK(params->vBlnkYStartFld1, params->vBlnkXStartFld1); base[_VP_VDVBLKE1_OFFSET] = VP_VDVBLKE1_RMK(params->vBlnkYStopFld1, params->vBlnkXStopFld1); base[_VP_VDVBLKS2_OFFSET] = VP_VDVBLKS2_RMK(params->vBlnkYStartFld2, params->vBlnkXStartFld2); base[_VP_VDVBLKE2_OFFSET] = VP_VDVBLKE2_RMK(params->vBlnkYStopFld2, params->vBlnkXStopFld2); base[_VP_VDVBIT1_OFFSET] = VP_VDVBIT1_RMK(params->vBlnkYStopFld1, params->vBlnkYStartFld1); base[_VP_VDVBIT2_OFFSET] = VP_VDVBIT1_RMK(params->vBlnkYStopFld2, params->vBlnkYStartFld2); if(params->imgHOffsetFld1<0) { nh1 = 1; params->imgHOffsetFld1 = -params->imgHOffsetFld1; } if(params->imgHOffsetFld2<0) { nh2 = 1; params->imgHOffsetFld2 = -params->imgHOffsetFld2; } if(params->imgVOffsetFld1<0) { nv1 = 1; params->imgVOffsetFld1 = -params->imgVOffsetFld1; } if(params->imgHOffsetFld2<0) { nv2 = 1; params->imgVOffsetFld2 = -params->imgVOffsetFld2; } base[_VP_VDIMGOFF1_OFFSET] = VP_VDIMGOFF1_RMK(nv1, params->imgVOffsetFld1, nh1, params->imgHOffsetFld1); base[_VP_VDIMGSZ1_OFFSET] = VP_VDIMGSZ1_RMK(params->imgVSizeFld1, params->imgHSizeFld1); base[_VP_VDIMGOFF2_OFFSET] = VP_VDIMGOFF2_RMK(nv2, params->imgVOffsetFld2, nh2, params->imgHOffsetFld2); base[_VP_VDIMGSZ2_OFFSET] = VP_VDIMGSZ2_RMK(params->imgVSizeFld2, params->imgHSizeFld2); base[_VP_VDFLDT1_OFFSET] = VP_VDFLDT1_RMK(params->yStartFld1, params->xStartFld1); base[_VP_VDFLDT2_OFFSET] = VP_VDFLDT2_RMK(params->yStartFld2, params->xStartFld2); base[_VP_VDFBIT_OFFSET] = VP_VDFBIT_RMK(params->yStartFld2, params->yStartFld1); base[_VP_VDHSYNC_OFFSET] = VP_VDHSYNC_RMK(params->hSyncStop, params->hSyncStart); base[_VP_VDVSYNS1_OFFSET] = VP_VDVSYNS1_RMK(params->vSyncYStartFld1, params->vSyncXStartFld1); base[_VP_VDVSYNE1_OFFSET] = VP_VDVSYNE1_RMK(params->vSyncYStopFld1, params->vSyncXStopFld1); base[_VP_VDVSYNS2_OFFSET] = VP_VDVSYNS2_RMK(params->vSyncYStartFld2, params->vSyncXStartFld2); base[_VP_VDVSYNE2_OFFSET] = VP_VDVSYNE2_RMK(params->vSyncYStopFld2, params->vSyncXStopFld2); base[_VP_VDCLIP_OFFSET] = VP_VDCLIP_RMK(params->cClipHigh, params->cClipLow, params->yClipHigh, params->yClipLow); base[_VP_VDDEFVAL_OFFSET] = params->yDefVal | (params->cbDefVal << 16) | (params->crDefVal << 24); chan->resmpl = params->resmpl; chan->scale = params->scale; numPixels >>= params->scale; chan->numPixels = numPixels; numCPixels = (params->dmode & _VPORT_MASK_RAW) ? 0 : numPixels >> 1; if(params->dmode & _VPORT_MASK_RAW) { /* raw mode */ chan->cPitch = 0; if(params->dmode == VPORT_MODE_RAW_8BIT) { chan->yPitch = (numPixels + 7) & (~ 7); chan->cPitch = (numCPixels + 7) & (~ 7); } else if(params->dmode == VPORT_MODE_RAW_10BIT) { if(params->bpk10Bit == VPORTDIS_BPK_10BIT_DENSE){ chan->yPitch = (numPixels * 4 / 3 + 7) & (~ 7); }else { chan->yPitch = (numPixels * 2 + 7) & (~ 7); } } else if(params->dmode == VPORT_MODE_RAW_16BIT) { chan->yPitch = (numPixels * 2 + 7) & (~ 7); } else { chan->yPitch = (numPixels * 4 + 7) & (~ 7); } } else { if(params->dmode & _VPORT_MASK_10BIT) { if(params->bpk10Bit == VPORTDIS_BPK_10BIT_DENSE){ chan->yPitch = (numPixels * 4 / 3 + 7) & (~ 7); chan->cPitch = (numCPixels* 4 / 3 + 7) & (~ 7); }else { chan->yPitch = (numPixels * 2 + 7) & (~ 7); chan->cPitch = (numCPixels * 2 + 7) & (~ 7); } } else {/* 8 bit mode */ chan->yPitch = (numPixels + 7) & (~ 7); chan->cPitch = (numCPixels + 7) & (~ 7); } } chan->yThrld = params->thrld; if(params->mergeFlds && params->fldOp == VPORT_FLDOP_FRAME) { /* frame capture and merge 2 fields into one frame */ /* make sure threshold is same as line size */ chan->yThrld = chan->yPitch >> 3; chan->numEventsFld1 = chan->numLinesFld1; chan->numEvents = chan->numLines; chan->mergeFlds = TRUE; }else { /* these two asserts make sure that total transfer sizes of */ /* both the whole frame and the first field are multiples */ /* of the threshold */ assert(((chan->yPitch*chan->numLinesFld1)/(chan->yThrld << 3)) *(chan->yThrld << 3) == (chan->yPitch*chan->numLinesFld1)); assert(((chan->yPitch*chan->numLines)/(chan->yThrld << 3)) *(chan->yThrld << 3) == (chan->yPitch*chan->numLines)); chan->numEventsFld1 = chan->yPitch * chan->numLinesFld1 / (chan->yThrld << 3); chan->numEvents = chan->yPitch * chan->numLines / (chan->yThrld << 3); chan->mergeFlds = FALSE; } if(params->dmode & _VPORT_MASK_RAW) { chan->cThrld = 0; } else { chan->cThrld = (chan->yThrld + 1) >> 1; } base[_VP_VDTHRLD_OFFSET] = VP_VDTHRLD_RMK(chan->yThrld,params->incPix,chan->yThrld); base[_VP_VDDISPEVT_OFFSET] = VP_VDDISPEVT_RMK((chan->numEvents-chan->numEventsFld1), chan->numEventsFld1 ); chan->mode = params->dmode; chan->status |= _VPORT_CFGED; } return IOM_COMPLETED; } /* * ======== displayEdmaISR ======== */ static void displayEdmaISR(tcc) { Int i; FVID_Frame *viop, *curViop; Int offset; /* find out the source of the edma interrupt */ for(i = 0; i < _VP_PORT_CNT; i ++) { _VPORT_ChanObj* chan = &chanObjs[i]; if((chan->status & _VPORT_READY) && (tcc == chan->tcc[0] || tcc == chan->tcc[1])){ /* re-sync tcc with activeEDMARlds */ /* they may be out of sync after interrupt over-run */ /* e.g. execution is halted at break-point */ chan->nextEDMARlds = (tcc == chan->tcc[0]) ? 0 : 1; offset = chan->nextEDMARlds << 1; /* update the current and next viop pointers */ curViop = chan->curViop; chan->curViop = chan->nextViop; if((viop = (FVID_Frame *)QUE_dequeue(&chan->qIn)) != (FVID_Frame *)&chan->qIn) { /* queue IS not empty */ chan->nextViop = viop; }else { chan->queEmpty = TRUE; } /* Update the EDMA reload entry */ if(chan->mergeFlds){ EDMA_RSETH(chan->hRld[offset], SRC, chan->nextViop->frame.iFrm.y1); EDMA_RSETH(chan->hRld[offset + 1], SRC, chan->nextViop->frame.iFrm.y2); if(!(chan->mode & _VPORT_MASK_RAW)){ EDMA_RSETH(chan->hRld[4 + offset], SRC, chan->nextViop->frame.iFrm.cb1); EDMA_RSETH(chan->hRld[5 + offset], SRC, chan->nextViop->frame.iFrm.cb2); EDMA_RSETH(chan->hRld[8 + offset], SRC, chan->nextViop->frame.iFrm.cr1); EDMA_RSETH(chan->hRld[9 + offset], SRC, chan->nextViop->frame.iFrm.cr2); } } else { EDMA_RSETH(chan->hRld[offset], SRC, chan->nextViop->frame.iFrm.y1); if(! (chan->mode & _VPORT_MASK_RAW)){ EDMA_RSETH(chan->hRld[offset + 4], SRC, chan->nextViop->frame.iFrm.cb1); EDMA_RSETH(chan->hRld[offset + 8], SRC, chan->nextViop->frame.iFrm.cr1); } }/* if(chan->mergeFlds) {*/ if(curViop != chan->curViop) { if(chan->packetIOM != INV) { /* call the channel's callback function */ *(void **)chan->packetIOM->addr = curViop; chan->packetIOM->size = sizeof(FVID_Frame); chan->cbFxn((Ptr)chan->cbArg, chan->packetIOM); chan->packetIOM = INV; }else { QUE_enqueue(&chan->qOut,curViop); } }/*if(curViop != chan->curViop) {*/ }/*if((chan->status & READY) && tcc == chan->tcc){*/ } /*for(i = 0; i <_VP_PORT_CNT; i++) { */ } /* * ======== displayISR ======== */ static void displayISR(int portNum) { volatile Int *base = (volatile Int *)chanObjs[portNum].base; Int vpis = base[_VP_VPIS_OFFSET]; Int mask = vpis & chanObjs[portNum].vIntMask; if(mask && chanObjs[portNum].vIntFxn != INV) { chanObjs[portNum].vIntFxn(chanObjs[portNum].cbArg, mask); } /* clear interrupts that has been handled */ base[_VP_VPIS_OFFSET] |= vpis; } /* * ======== _displayStart ======== * start video display */ static Int _displayStart(Ptr chanp) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; volatile Int* base = (volatile Int *)chan->base; volatile Int stat; volatile Int i = 0; /* enable port and display */ base[_VP_VPCTL_OFFSET] |= VP_VPCTL_VPHLT_CLEAR << _VP_VPCTL_VPHLT_SHIFT; base[_VP_VDCTL_OFFSET] |= VP_VDCTL_VDEN_ENABLE << _VP_VDCTL_VDEN_SHIFT; /* wait for display counters and control signals to sync up */ do { stat = base[_VP_VDSTAT_OFFSET]; i ++ ; }while(!(stat & 0x70000000) && i < 1000000); base[_VP_VDSTAT_OFFSET] = stat; do { stat = base[_VP_VDSTAT_OFFSET]; i ++; }while(!(stat & 0x70000000) && i < 1000000); base[_VP_VDSTAT_OFFSET] = stat; base[_VP_VDCTL_OFFSET] &= ~ (_VP_VDCTL_BLKDIS_MASK); /* enable interrupt */ base[_VP_VPIE_OFFSET] |= VP_VPIE_VIE_ENABLE << _VP_VPIE_VIE_SHIFT; IRQ_clear(IRQ_EVT_VINT0 + chan->portNum); IRQ_enable(IRQ_EVT_VINT0 + chan->portNum); return IOM_COMPLETED; } /* * ======== _displayStop ======== * stop video display */ static Int _displayStop(Ptr chanp) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; volatile Int* base = (volatile Int *)chan->base; base[_VP_VDCTL_OFFSET] &= ~ (VP_VDCTL_VDEN_ENABLE << _VP_VDCTL_VDEN_SHIFT); return IOM_COMPLETED; } /* * ======== _dundRecover ======== * force recover from display under-run */ static Int _dundRecover(Ptr chanp) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; Int i; Int stat; Int numEvents; volatile Int* base = (volatile Int *)chan->base; /* disable under run interrupt */ base[_VP_VPIE_OFFSET] &= ~ (_VP_VPIE_DUND_MASK); /* clear any pending under-run interrupt */ base[_VP_VPIS_OFFSET] &= ~ (_VP_VPIS_DUND_MASK); /* block display events */ base[_VP_VDCTL_OFFSET] |= _VP_VDCTL_BLKDIS_MASK; /* Disable the edmas before settings them up */ if(!(chan->mode & _VPORT_MASK_RAW)){ EDMA_disableChannel(chan->hEdma[1]); EDMA_clearChannel(chan->hEdma[1]); EDMA_disableChannel(chan->hEdma[2]); EDMA_clearChannel(chan->hEdma[2]); } EDMA_intDisable(chan->tcc[0]); EDMA_intDisable(chan->tcc[1]); EDMA_disableChannel(chan->hEdma[0]); EDMA_clearChannel(chan->hEdma[0]); if(chan->mergeFlds) { numEvents = chan->numEventsFld1; } else { numEvents = chan->numEvents; } /* set up DMA parameters again */ EDMA_RSETH(chan->hEdma[0], SRC, chan->curViop->frame.iFrm.y1); EDMA_RSETH(chan->hEdma[0], CNT, EDMA_CNT_RMK(numEvents - 1, chan->yThrld << 1)); if(!(chan->mode & _VPORT_MASK_RAW)){ EDMA_RSETH(chan->hEdma[1], SRC, chan->curViop->frame.iFrm.cb1); EDMA_RSETH(chan->hEdma[2], SRC, chan->curViop->frame.iFrm.cr1); EDMA_RSETH(chan->hEdma[1], CNT, EDMA_CNT_RMK(numEvents - 1, chan->cThrld << 1)); EDMA_RSETH(chan->hEdma[2], CNT, EDMA_CNT_RMK(numEvents - 1, chan->cThrld << 1)); } /* enable the edma events again before settings them up */ EDMA_enableChannel(chan->hEdma[1]); EDMA_enableChannel(chan->hEdma[2]); EDMA_intEnable(chan->tcc[0]); EDMA_intEnable(chan->tcc[1]); EDMA_enableChannel(chan->hEdma[0]); base[_VP_VDCTL_OFFSET] |= VP_VDCTL_VDEN_ENABLE << _VP_VDCTL_VDEN_SHIFT; /* wait for display counters and control signals to sync up */ do { stat = base[_VP_VDSTAT_OFFSET]; i ++ ; }while(!(stat & 0x70000000) && i < 1000000); base[_VP_VDSTAT_OFFSET] = stat; do { stat = base[_VP_VDSTAT_OFFSET]; i ++; }while(!(stat & 0x70000000) && i < 1000000); base[_VP_VDCTL_OFFSET] &= ~(_VP_VDCTL_BLKDIS_MASK); /* re-enable under run interrupt */ base[_VP_VPIE_OFFSET] |= _VP_VPIE_DUND_MASK; return IOM_COMPLETED; } /* * ======== _getlastActiveLine ======== * get the line number of the last active line */ static Int _getlastActiveLine(VPORTDIS_Params* params) { int lastActiveLine = -1; switch (params->fldOp){ case VPORT_FLDOP_FRAME: case VPORT_FLDOP_FLD2: lastActiveLine = params->vBlnkYStopFld2 + params->imgVOffsetFld2 + params->imgVSizeFld2; break; case VPORT_FLDOP_FLD1: case VPORT_FLDOP_PROGRESSIVE: lastActiveLine = params->vBlnkYStopFld1 + params->imgVOffsetFld1 + params->imgVSizeFld1; break; } return lastActiveLine; } /* * ======== _setVIntCb ======== * set video port interrutp call-back */ static Int _setVIntCb(Ptr chanp, Ptr args) { _VPORT_ChanObj* chan = (_VPORT_ChanObj *)chanp; volatile Int* base = (volatile Int *)chan->base; VPORT_VIntCbParams* vIntCbParams = (void *)args; Int mask = vIntCbParams->vIntMask; Uns vif2 = 0, vInt2 = 0, vif1 = 0, vInt1 = 0; chan->vIntMask = mask; /* check to see if vertical interrupt is enabled */ if(mask & VPORT_INT_VINT1) { vif1 = 1; vInt1 = vIntCbParams->vIntLine; } if(mask & VPORT_INT_VINT2) { vif2 = 1; vInt2 = vIntCbParams->vIntLine; } base[_VP_VDVINT_OFFSET] = VP_VDVINT_RMK(vif2, vInt2, vif1, vInt1); if(mask) { mask |= 1; /* turn on video port interrupt */ IRQ_map(IRQ_EVT_VINT0 + chan->portNum, vIntCbParams->irqId); HWI_dispatchPlug(vIntCbParams->irqId, (Fxn)displayISR, -1, NULL); IRQ_disable(IRQ_EVT_VINT0 + chan->portNum); IRQ_clear(IRQ_EVT_VINT0 + chan->portNum); } base[_VP_VPIE_OFFSET] |= mask; /* register write */ chan->vIntFxn = vIntCbParams->vIntCbFxn; return IOM_COMPLETED; }