| /******************************************************************************* |
| * Copyright (C) Marvell International Ltd. and its affiliates |
| * |
| * Marvell GPL License Option |
| * |
| * If you received this File from Marvell, you may opt to use, redistribute and/or |
| * modify this File in accordance with the terms and conditions of the General |
| * Public License Version 2, June 1991 (the "GPL License"), a copy of which is |
| * available along with the File in the license.txt file or by writing to the Free |
| * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 or |
| * on the worldwide web at http://www.gnu.org/licenses/gpl.txt. |
| * |
| * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY |
| * DISCLAIMED. The GPL License provides additional details about this warranty |
| * disclaimer. |
| ********************************************************************************/ |
| |
| |
| #define _VPP_ISR_C_ |
| |
| #include "string.h" |
| #include "thinvpp.h" |
| |
| #include "vpp_fe_dlr.h" |
| #include "api_avio_dhub.h" |
| #include "avioDhub.h" |
| |
| #include "bcm_cmdi.h" |
| |
| |
| ///////////////////////////////////////////////////// |
| // |
| // Interrupt Service Routines for FastLogo |
| // |
| ///////////////////////////////////////////////////// |
| |
| static void set_bcm_cmd(THINVPP_OBJ *vpp_obj, const unsigned * cmd, unsigned bytes) |
| { |
| BCMBUF *pbcmbuf = vpp_obj->pVbiBcmBuf; |
| |
| memcpy(pbcmbuf->writer, cmd, bytes); |
| pbcmbuf->writer += (bytes/sizeof(*pbcmbuf->writer)); |
| } |
| |
| static void set_dma_cmd(THINVPP_OBJ *vpp_obj, PLANE *plane) |
| { |
| VBUF_INFO *pinfo = plane->pinfo; |
| unsigned frame_addr = (unsigned) pinfo->m_pbuf_start + (unsigned) pinfo->m_disp_offset; |
| |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ->len += START_2DDMA(plane->dmaRdhubID, plane->dmaRID, |
| frame_addr, pinfo->m_buf_stride, plane->wpl*8, plane->actv_win.height, |
| (unsigned int (*)[2])(vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ->addr |
| + vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ->len*2)); |
| } |
| |
| static void set_bcm_loader(THINVPP_OBJ *vpp_obj) |
| { |
| /* start read-back data loader */ |
| *vpp_obj->pVbiBcmBuf->writer++ = 1; |
| *vpp_obj->pVbiBcmBuf->writer++ = 0xf7f70420; |
| } |
| |
| static unsigned *m_Set80000000(unsigned *cmd, unsigned alpha, unsigned bgcolor) |
| { |
| cmd[0] = bgcolor&0xff; |
| cmd[2] = (bgcolor>>8)&0xff; |
| cmd[4] = (bgcolor>>16)&0xff; |
| cmd[6] = alpha&0xff; |
| cmd[8] = alpha&0xff; |
| return &cmd[10]; |
| } |
| |
| static unsigned *m_Set90000000(unsigned *cmd, unsigned hres, unsigned vres, unsigned CropWpl) |
| { |
| cmd[0] = (vres&0xffff) | (hres<<16); |
| cmd[2] = CropWpl; |
| return &cmd[4]; |
| } |
| |
| static unsigned *m_SetA0000000(unsigned *cmd, unsigned hres, unsigned vres) |
| { |
| cmd[0] = hres - 1; |
| cmd[2] = (vres/2) - 1; |
| cmd[4] = hres + 22 - 1; |
| cmd[6] = vres + 10 - 1; |
| cmd[8] = vres + 10 - 1; |
| cmd[10] = 1; |
| return &cmd[12]; |
| } |
| |
| static unsigned *m_SetB0000000(unsigned *cmd, unsigned hres, unsigned vres) |
| { |
| cmd[0] = (vres + 10) + ((hres + 20) << 16); |
| cmd[2] = (hres + 8) + (7 << 16); |
| cmd[4] = (vres + 3) + (2 << 16); |
| return &cmd[6]; |
| } |
| |
| static unsigned *m_SetC0000000(unsigned *cmd, unsigned hres, unsigned vres) |
| { |
| unsigned pix; |
| |
| pix = hres * vres; |
| cmd[0] = pix; |
| cmd[2] = pix; |
| pix += hres; |
| cmd[4] = pix; |
| cmd[6] = (pix * 26 + 63)/64; |
| return &cmd[8]; |
| } |
| |
| static unsigned *m_SetD0000000(unsigned *cmd, unsigned x, unsigned y, unsigned w, unsigned h) |
| { |
| w += x; |
| h += y; |
| cmd[0] = x & 0xff; |
| cmd[2] = (x>>8) & 0xff; |
| cmd[4] = w & 0xff; |
| cmd[6] = (w>>8) & 0xff; |
| cmd[8] = y & 0xff; |
| cmd[10] = (y>>8) & 0xff; |
| cmd[12] = h & 0xff; |
| cmd[14] = (h>>8) & 0xff; |
| return &cmd[16]; |
| } |
| |
| static void init_bcm_cmd(THINVPP_OBJ *vpp_obj, unsigned * Cmd, unsigned bytes) |
| { |
| PLANE *plane = &vpp_obj->plane[PLANE_MAIN]; |
| unsigned *CmdEnd = &Cmd[bytes/(sizeof(unsigned))]; |
| VBUF_INFO * pinfo; |
| unsigned active_left, active_width; |
| unsigned CropWpl; |
| |
| pinfo = plane->pinfo; |
| vpp_obj->chan[CHAN_MAIN].disp_win_attr.bgcolor = pinfo->bgcolor; |
| vpp_obj->chan[CHAN_MAIN].disp_win_attr.alpha = pinfo->alpha; |
| |
| active_left = (pinfo->m_active_left) & ~1; //has to be even num |
| active_width = ((pinfo->m_active_left + pinfo->m_active_width) & ~1) - active_left; //has to be even num |
| |
| plane->actv_win.x = active_left; |
| plane->actv_win.y = pinfo->m_active_top; |
| plane->actv_win.width = active_width; |
| plane->actv_win.height = pinfo->m_active_height; |
| |
| CropWpl = (((plane->actv_win.width + PIXEL_PER_BEAT_YUV_422 - 1) / PIXEL_PER_BEAT_YUV_422) << 16); |
| plane->wpl = (CropWpl >> 16); |
| |
| while (Cmd < CmdEnd) |
| { |
| switch (*Cmd) |
| { |
| case 0x80000000: |
| Cmd = m_Set80000000(Cmd, pinfo->alpha, pinfo->bgcolor); |
| break; |
| case 0x90000000: |
| Cmd = m_Set90000000(Cmd, pinfo->m_active_width, pinfo->m_active_height, CropWpl); |
| break; |
| case 0xa0000000: |
| Cmd = m_SetA0000000(Cmd, pinfo->m_active_width, pinfo->m_active_height); |
| break; |
| case 0xb0000000: |
| Cmd = m_SetB0000000(Cmd, pinfo->m_active_width, pinfo->m_active_height); |
| break; |
| case 0xc0000000: |
| Cmd = m_SetC0000000(Cmd, pinfo->m_active_width, pinfo->m_active_height); |
| break; |
| case 0xd0000000: |
| Cmd = m_SetD0000000(Cmd, pinfo->m_active_left, pinfo->m_active_top, |
| pinfo->m_active_width, pinfo->m_active_height); |
| break; |
| default: |
| Cmd += 2; |
| break; |
| } |
| } |
| } |
| |
| static int startChannelDataLoader(THINVPP_OBJ *vpp_obj, int chanID) |
| { |
| if (chanID == CHAN_MAIN) |
| { |
| PLANE *plane = &vpp_obj->plane[PLANE_MAIN]; |
| |
| switch (plane->status) { |
| case STATUS_ACTIVE: |
| set_bcm_cmd(vpp_obj, cmd_startChannelDataLoader_active, sizeof(cmd_startChannelDataLoader_active)); |
| plane->mode = MODE_INLINE; |
| set_dma_cmd(vpp_obj, plane); |
| set_bcm_loader(vpp_obj); |
| plane->status = STATUS_DISP; |
| break; |
| |
| case STATUS_DISP: |
| set_dma_cmd(vpp_obj, plane); |
| set_bcm_loader(vpp_obj); |
| break; |
| |
| case STATUS_STOP: |
| set_bcm_cmd(vpp_obj, cmd_startChannelDataLoader_stop, sizeof(cmd_startChannelDataLoader_stop)); |
| plane->status = STATUS_INACTIVE; |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| return (MV_THINVPP_OK); |
| } |
| |
| static void prepareQ(THINVPP_OBJ *vpp_obj) |
| { |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ->len = 0; |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ->len = 0; |
| vpp_obj->pVbiBcmBuf = vpp_obj->pVbiBcmBufCpcb[CPCB_1]; |
| THINVPP_BCMBUF_Select(vpp_obj->pVbiBcmBuf, CPCB_1); |
| } |
| |
| static void toggleQ(THINVPP_OBJ *vpp_obj) |
| { |
| THINVPP_CFGQ_To_CFGQ(vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ, vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ); |
| THINVPP_BCMBUF_To_CFGQ(vpp_obj->pVbiBcmBuf, vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ); |
| THINVPP_BCMDHUB_CFGQ_Commit(vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ, CPCB_1); |
| |
| if (vpp_obj->pVbiBcmBufCpcb[CPCB_1] == &vpp_obj->vbi_bcm_buf[0]) |
| vpp_obj->pVbiBcmBufCpcb[CPCB_1] = &vpp_obj->vbi_bcm_buf[1]; |
| else |
| vpp_obj->pVbiBcmBufCpcb[CPCB_1] = &vpp_obj->vbi_bcm_buf[0]; |
| |
| if (vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ == &vpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]) |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ = &(vpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]); |
| else |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ = &(vpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]); |
| |
| if (vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ == &vpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]) |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ = &(vpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[1]); |
| else |
| vpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ = &(vpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]); |
| } |
| |
| /* interrupt service routine for CPCB TG interrupt */ |
| void THINVPP_CPCB_ISR_service(THINVPP_OBJ *vpp_obj, int cpcbID) |
| { |
| DV *pDV; |
| |
| if (!vpp_obj || (cpcbID != CPCB_1)) |
| return; |
| |
| pDV = &(vpp_obj->dv[cpcbID]); |
| |
| if(pDV->status == STATUS_ACTIVE){ |
| prepareQ(vpp_obj); |
| pDV->vbi_num ++; // VBI counter |
| startChannelDataLoader(vpp_obj, CHAN_MAIN); |
| toggleQ(vpp_obj); |
| } else if (pDV->status == STATUS_STOP) { |
| prepareQ(vpp_obj); |
| vpp_obj->dv[CPCB_1].vbi_num = 0; // reset VBI counter |
| vpp_obj->dv[CPCB_1].status = STATUS_INACTIVE; |
| toggleQ(vpp_obj); |
| } |
| } |
| |
| void THINVPP_Enable_ISR_Interrupt(THINVPP_OBJ *vpp_obj, int cpcbID, int flag) |
| { |
| if (cpcbID != CPCB_1) |
| return; |
| if (flag) { |
| flag = 1; |
| init_bcm_cmd(vpp_obj, cmd_startChannelDataLoader_active, sizeof(cmd_startChannelDataLoader_active)); |
| } |
| |
| /* configure and enable CPCB0 interrupt */ |
| semaphore_cfg(vpp_obj->pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr, 1, 0); |
| semaphore_pop(vpp_obj->pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr, 1); |
| semaphore_clr_full(vpp_obj->pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr); |
| semaphore_intr_enable(vpp_obj->pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr, |
| 0/*empty*/, flag/*full*/, 0/*almost empty*/, 0/*almost full*/, 0/*cpu id*/); |
| } |
| |