blob: 67db873281badb3dedeef8d79e8f715644d44700 [file] [log] [blame]
/*******************************************************************************
* 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 _THINVPP_API_C_
#include "Galois_memmap.h"
#include "GaloisDmaMap.h"
#include "galois_io.h"
#include "global.h"
#include "avpll.h"
#include "thinvpp.h"
#include "vpp_be_hdmitx.h"
#include "bcm_cmds.h"
#include "util.h"
#include "gpio.h"
#define bTST(x, b) (((x) >> (b)) & 1)
static int MV_THINVPP_SetHdmiVideoFmt(int color_fmt, int bit_depth, int pixel_rept);
void THINVPP_BCMBUF_HardwareTrans_Direct(int block, unsigned int *start, int size);
unsigned MV_REG_GET(unsigned addr)
{
return *(volatile unsigned volatile *)(addr);
}
void MV_REG_SET(unsigned addr, unsigned val)
{
*(volatile unsigned volatile *)(addr) = val;
}
void MV_REG_AND(unsigned addr, unsigned val)
{
val = val & (*(volatile unsigned volatile *)(addr));
*(volatile unsigned volatile *)(addr) = val;
}
void MV_REG_ORR(unsigned addr, unsigned val)
{
val = val | (*(volatile unsigned volatile *)(addr));
*(volatile unsigned volatile *)(addr) = val;
}
void MV_REG_MASK(unsigned addr, unsigned mask, unsigned val)
{
val = (mask & (*(volatile unsigned volatile *)(addr))) | val;
*(volatile unsigned volatile *)(addr) = val;
}
void delay_10ns(int delay)
{
int i;
for (i=0; i<delay; i++) {
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
__asm__ __volatile__ ("MOV r0, r0" "\n\t" :::"r0");
}
}
static int GetVCOFreq(int resID, int bit_depth)
{
if (resID == RES_RESET)
return (-1);
int avpll_freq_index, deep_color_index;
if (m_resinfo_table[resID].freq <= 25200) {
avpll_freq_index = 0;
} else if ((m_resinfo_table[resID].freq == 27000) || (m_resinfo_table[resID].freq == 27027)) {
avpll_freq_index = 1;
} else if ((m_resinfo_table[resID].freq == 74250) || (m_resinfo_table[resID].freq == 74176)) {
avpll_freq_index = 3;
} else if ((m_resinfo_table[resID].freq == 148500) || (m_resinfo_table[resID].freq == 148352)) {
avpll_freq_index = 5;
} else
return (-1);
if (bit_depth == OUTPUT_BIT_DEPTH_12BIT)
deep_color_index = 2;
else if (bit_depth == OUTPUT_BIT_DEPTH_10BIT)
deep_color_index = 1;
else if (bit_depth == OUTPUT_BIT_DEPTH_8BIT)
deep_color_index = 0;
else
return (-1);
return (diag_getVCOFreq(deep_color_index, avpll_freq_index));
}
static int NeedAVPLL_PPM1K(int resID)
{
int frame_rate;
int ret;
frame_rate = m_resinfo_table[resID].frame_rate;
if (m_resinfo_table[resID].type == TYPE_SD) {
/* for SD resolution */
if ((frame_rate == FRAME_RATE_59P94) || (frame_rate == FRAME_RATE_50))
ret = 0;
else
ret = 1;
} else {
/* for HD resolution */
if ((frame_rate == FRAME_RATE_59P94) || (frame_rate == FRAME_RATE_29P97) || (frame_rate == FRAME_RATE_23P98) || (frame_rate == FRAME_RATE_119P88) || (frame_rate == FRAME_RATE_47P96))
ret = 0;
else
ret = 1;;
}
return ret;
}
static void VPP_dhub_sem_clear(void)
{
int instat;
HDL_semaphore *pSemHandle = thinvpp_obj->pSemHandle;
instat = semaphore_chk_full(pSemHandle, -1);
if (bTST(instat, avioDhubSemMap_vpp_vppCPCB0_intr)){
semaphore_pop(pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr, 1);
semaphore_clr_full(pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr);
}else if (bTST(instat, avioDhubSemMap_vpp_vppCPCB2_intr)){
semaphore_pop(pSemHandle, avioDhubSemMap_vpp_vppCPCB2_intr, 1);
semaphore_clr_full(pSemHandle, avioDhubSemMap_vpp_vppCPCB2_intr);
}
return;
}
/***********************************************
* FUNCTION: create a VPP object
* PARAMS: base_addr - VPP object base address
* *handle - pointer to object handle
* RETURN: MV_THINVPP_OK - succeed
* MV_THINVPP_EUNCONFIG - not initialized
***********************************************/
int MV_THINVPP_Create(int base_addr, unsigned options)
{
if (!(thinvpp_obj = (THINVPP_OBJ *)THINVPP_MALLOC(sizeof(THINVPP_OBJ)))){
return (MV_THINVPP_ENOMEM);
}
THINVPP_MEMSET(thinvpp_obj, 0, sizeof(THINVPP_OBJ));
thinvpp_obj->options = options;
thinvpp_obj->base_addr = base_addr;
/* create VBI BCM buffer */
if (THINVPP_BCMBUF_Create(&(thinvpp_obj->vbi_bcm_buf[0]), BCM_BUFFER_SIZE) != MV_THINVPP_OK){
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (thinvpp_obj->options & THINVPP_OPTION_SHOWLOGO)
{
if (THINVPP_BCMBUF_Create(&(thinvpp_obj->vbi_bcm_buf[1]), BCM_BUFFER_SIZE) != MV_THINVPP_OK){
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[1]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[1]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[1]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_3].vbi_bcm_cfgQ[0]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[1]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
if (THINVPP_CFGQ_Create(&(thinvpp_obj->dv[CPCB_3].vbi_bcm_cfgQ[1]), DMA_CMD_BUFFER_SIZE) != MV_THINVPP_OK) {
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_bcm_cfgQ[0]));
THINVPP_FREE(thinvpp_obj);
return (MV_THINVPP_ENOMEM);
}
}
return (MV_THINVPP_OK);
}
/***********************************************
* FUNCTION: destroy a VPP object
* PARAMS: handle - VPP object handle
* RETURN: MV_THINVPP_OK - succeed
* MV_THINVPP_EUNCONFIG - not initialized
* MV_THINVPP_ENODEV - no device
* MV_THINVPP_ENOMEM - no memory
***********************************************/
int MV_THINVPP_Destroy(void)
{
if (thinvpp_obj == NULL)
return (MV_THINVPP_ENODEV);
/* free BCM buffer memory */
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[0]));
if (thinvpp_obj->options & THINVPP_OPTION_SHOWLOGO)
{
THINVPP_BCMBUF_Destroy(&(thinvpp_obj->vbi_bcm_buf[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[1]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_bcm_cfgQ[0]));
THINVPP_CFGQ_Destroy(&(thinvpp_obj->dv[CPCB_3].vbi_bcm_cfgQ[1]));
}
/* free vpp object memory */
THINVPP_FREE(thinvpp_obj);
thinvpp_obj = NULL;
return (MV_THINVPP_OK);
}
/***************************************
* FUNCTION: VPP reset
* INPUT: NONE
* RETURN: NONE
**************************************/
int MV_THINVPP_Reset(void)
{
unsigned i;
unsigned reg;
(void)reg;
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
// reset VPP object variable
thinvpp_obj->status = STATUS_INACTIVE;
/* reset planes */
for (i=FIRST_PLANE; i<MAX_NUM_PLANES; i++){
thinvpp_obj->plane[i].status = STATUS_INACTIVE;
thinvpp_obj->plane[i].mode = -1; // invalid
thinvpp_obj->plane[i].srcfmt = -1; // invalid
thinvpp_obj->plane[i].order = -1; // invalid
thinvpp_obj->plane[i].actv_win.x = 0;
thinvpp_obj->plane[i].actv_win.y = 0;
thinvpp_obj->plane[i].actv_win.width = 0;
thinvpp_obj->plane[i].actv_win.height = 0;
thinvpp_obj->plane[i].ref_win = thinvpp_obj->plane[i].actv_win;
}
/* reset channels */
for (i=FIRST_CHAN; i<MAX_NUM_CHANS; i++) {
thinvpp_obj->chan[i].status = STATUS_INACTIVE;
thinvpp_obj->chan[i].dvID = -1; // invalid
thinvpp_obj->chan[i].dvlayerID = -1; // invalid
thinvpp_obj->chan[i].zorder = -1; // invalid
thinvpp_obj->chan[i].disp_win.x = 0;
thinvpp_obj->chan[i].disp_win.y = 0;
thinvpp_obj->chan[i].disp_win.width = 0;
thinvpp_obj->chan[i].disp_win.height = 0;
}
/* reset DVs */
for (i=FIRST_CPCB; i<MAX_NUM_CPCBS; i++) {
thinvpp_obj->dv[i].status = STATUS_INACTIVE;
thinvpp_obj->dv[i].output_res = RES_INVALID; // invalid
thinvpp_obj->dv[i].num_of_vouts = 0;
thinvpp_obj->dv[i].vbi_num = 0;
}
/* reset VOUTs */
for (i=FIRST_VOUT; i<MAX_NUM_VOUTS; i++) {
thinvpp_obj->vout[i].status = STATUS_INACTIVE;
thinvpp_obj->vout[i].dvID = -1; // invalid
}
/* reset VBI BCM buffer */
THINVPP_BCMBUF_Reset(&thinvpp_obj->vbi_bcm_buf[0]);
thinvpp_obj->pVbiBcmBuf = &(thinvpp_obj->vbi_bcm_buf[0]);
if (thinvpp_obj->options & THINVPP_OPTION_SHOWLOGO)
{
THINVPP_BCMBUF_Reset(&thinvpp_obj->vbi_bcm_buf[1]);
thinvpp_obj->pVbiBcmBufCpcb[CPCB_1] = &(thinvpp_obj->vbi_bcm_buf[0]);
thinvpp_obj->pVbiBcmBufCpcb[CPCB_3] = &(thinvpp_obj->vbi_bcm_buf[0]);
thinvpp_obj->dv[CPCB_1].curr_cpcb_vbi_dma_cfgQ = &(thinvpp_obj->dv[CPCB_1].vbi_dma_cfgQ[0]);
thinvpp_obj->dv[CPCB_3].curr_cpcb_vbi_dma_cfgQ = &(thinvpp_obj->dv[CPCB_3].vbi_dma_cfgQ[0]);
thinvpp_obj->dv[CPCB_1].curr_cpcb_vbi_bcm_cfgQ = &(thinvpp_obj->dv[CPCB_1].vbi_bcm_cfgQ[0]);
thinvpp_obj->dv[CPCB_3].curr_cpcb_vbi_bcm_cfgQ = &(thinvpp_obj->dv[CPCB_3].vbi_bcm_cfgQ[0]);
}
/* reset dHub cmdQ */
#if (BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0)
for (i = 0; i < avioDhubChMap_vpp_TT_R; i++)
#else // (BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0)
for (i = 0; i < avioDhubChMap_vpp_SPDIF_W; i++)
#endif // (BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0)
thinvpp_obj->dhub_cmdQ[i] = 0;
{
register unsigned reg = 0xf7f70068;
register unsigned val;
SM_GPIO_PortWrite(1, 1); // set SM GPIO port 1 to high, this is input/output control of SM GPIO port 7
val = MV_REG_GET(reg);
if (0 != (val & 0x3c))
{
// @bit 0, 13..10, 17..14, 18, 31..19
val = (val & 0x1fe) | (8<<10) | (1<<18) | (0x924<<19);
MV_REG_SET(reg, val);
// Set Aux
MV_REG_AND(reg + 0xc, ~(0xff<<9)); // @bit 16..9
// Set Eamp @bit 11..0, 27..12, 31..28
val = MV_REG_GET(reg + 0x4);
val = 0x249 | (0x2222<<12) | (0x7<<28);
MV_REG_SET(reg + 0x4, val);
// Set SVTX and IDRV @bit 11..0, 29..12
val = MV_REG_GET(reg + 0x8);
val = (val & 0xc0000000) | (0xff<<12) | 0x249;
MV_REG_SET(reg + 0x8, val);
// BE_HDMIPHY_EnableTmds:
MV_REG_AND(reg, ~0x3c); // @bit 5..2
MV_REG_ORR(reg, 0x02); // @bit 1
MV_REG_AND(reg, ~0x02);
}
MV_REG_SET(0xf7f644c0, 0x01); // BE_HDMITX_EnablePhyFifo:
MV_REG_MASK(reg, ~(0xfff<<19), (0x492<<19)); // @bit 30..19
MV_REG_MASK(reg + 4, ~0xfff, 0x249); // @bit 11..0
}
THINVPP_BCMBUF_HardwareTrans_Direct(1, cmd_THINVPP_Reset, sizeof(cmd_THINVPP_Reset));
return (MV_THINVPP_OK);
}
/***************************************
* FUNCTION: VPP profile configuration
* INPUT: NONE
* RETURN: NONE
**************************************/
int MV_THINVPP_Config(void)
{
int i;
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
/* VPP module has been configured */
if (thinvpp_obj->status == STATUS_ACTIVE)
return (MV_THINVPP_OK);
thinvpp_obj->pSemHandle = dhub_semaphore(&VPP_dhubHandle.dhub);
/* config planes */
for (i=FIRST_PLANE; i<MAX_NUM_PLANES; i++){
/* set plane's DMA channel ID */
if (i == PLANE_MAIN){
thinvpp_obj->plane[i].dmaRID = avioDhubChMap_vpp_MV_R; // inline read DMA
thinvpp_obj->plane[i].dmaRdhubID = (int)(&VPP_dhubHandle);
thinvpp_obj->plane[i].offline_dmaWID = avioDhubChMap_vpp_MV_FRC_W; // offline write-back DMA
thinvpp_obj->plane[i].offline_dmaWdhubID = (int)(&VPP_dhubHandle);
thinvpp_obj->plane[i].offline_dmaRID = avioDhubChMap_vpp_MV_FRC_R; // offline readd-back DMA
thinvpp_obj->plane[i].offline_dmaRdhubID = (int)(&VPP_dhubHandle);
break;
}
} // <- config FE planes
/* config channels */
#if LOGO_ENABLE_MAIN
thinvpp_obj->chan[CHAN_MAIN].dvID = CPCB_1; //#if LOGO_ENABLE_MAIN
#endif
#if LOGO_ENABLE_PIP
thinvpp_obj->chan[CHAN_PIP].dvID = CPCB_1;
#endif
thinvpp_obj->chan[CHAN_AUX].dvID = CPCB_3;
#if LOGO_ENABLE_MAIN
thinvpp_obj->chan[CHAN_MAIN].zorder = CPCB_ZORDER_7; //#if LOGO_ENABLE_MAIN
#endif
#if LOGO_ENABLE_PIP
thinvpp_obj->chan[CHAN_PIP].zorder = CPCB_ZORDER_2;
#endif
thinvpp_obj->chan[CHAN_AUX].zorder = CPCB_ZORDER_1;
// for B0, channel connection with CPCB is fixed
#if LOGO_ENABLE_MAIN
thinvpp_obj->chan[CHAN_MAIN].dvlayerID = CPCB1_PLANE_1; //#if LOGO_ENABLE_MAIN
#endif
#if LOGO_ENABLE_PIP
thinvpp_obj->chan[CHAN_PIP].dvlayerID = CPCB1_PLANE_2;
#endif
thinvpp_obj->chan[CHAN_AUX].dvlayerID = CPCB1_PLANE_1; // PLANE-1 of CPCB-2
#if LOGO_ENABLE_MAIN
#if LOGO_ENABLE_PIP || ((BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0) && (BERLIN_CHIP_VERSION != BERLIN_BG2CDP))
thinvpp_obj->dv[CPCB_1].num_of_chans = 2;
thinvpp_obj->dv[CPCB_1].chanID[0] = CHAN_MAIN;
thinvpp_obj->dv[CPCB_1].chanID[1] = CHAN_PIP;
#else
thinvpp_obj->dv[CPCB_1].num_of_chans = 1;
thinvpp_obj->dv[CPCB_1].chanID[0] = CHAN_MAIN;
#endif
#else
#if LOGO_ENABLE_PIP
thinvpp_obj->dv[CPCB_1].num_of_chans = 1;
thinvpp_obj->dv[CPCB_1].chanID[0] = CHAN_PIP;
#else
thinvpp_obj->dv[CPCB_1].num_of_chans = 0;
#endif
#endif
thinvpp_obj->dv[CPCB_1].num_of_vouts = 2;
thinvpp_obj->dv[CPCB_1].voutID[0] = VOUT_HDMI;
thinvpp_obj->dv[CPCB_1].voutID[1] = VOUT_HD;
#if (BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0) && (BERLIN_CHIP_VERSION != BERLIN_BG2CDP)
thinvpp_obj->dv[CPCB_3].num_of_chans = 1;
thinvpp_obj->dv[CPCB_3].chanID[0] = CHAN_AUX;
thinvpp_obj->dv[CPCB_3].num_of_vouts = 1;
thinvpp_obj->dv[CPCB_3].voutID[0] = VOUT_SD;
#else // (BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0)
thinvpp_obj->dv[CPCB_3].num_of_chans = 0;
#endif // (BERLIN_CHIP_VERSION != BERLIN_BG2CD_A0)
/* config VOUTs */
thinvpp_obj->vout[VOUT_HDMI].dvID = CPCB_1;
thinvpp_obj->vout[VOUT_HD].dvID = CPCB_1;
thinvpp_obj->vout[VOUT_SD].dvID = CPCB_3;
THINVPP_BCMBUF_HardwareTrans_Direct(1, cmd_THINVPP_Config, sizeof(cmd_THINVPP_Config));
if (thinvpp_obj->options & THINVPP_OPTION_SHOWLOGO)
{
BCM_SCHED_SetMux(BCM_SCHED_Q0, 0); /* CPCB0 VBI -> Q0 */
BCM_SCHED_SetMux(BCM_SCHED_Q1, 1); /* CPCB1 VBI -> Q1 */
BCM_SCHED_SetMux(BCM_SCHED_Q2, 2); /* CPCB2 VBI -> Q2 */
BCM_SCHED_SetMux(BCM_SCHED_Q3, 3); /* CPCB0 VDE -> Q3 */
BCM_SCHED_SetMux(BCM_SCHED_Q4, 4); /* CPCB1 VDE -> Q4 */
BCM_SCHED_SetMux(BCM_SCHED_Q5, 5); /* CPCB2 VDE -> Q5 */
}
/* set VPP module to be configured */
thinvpp_obj->status = STATUS_ACTIVE;
return (MV_THINVPP_OK);
}
/*******************************************************************
* FUNCTION: set CPCB or DV output resolution
* INPUT: cpcbID - CPCB(for Berlin) or DV(for Galois) id
* resID - id of output resolution
* bit_depth - HDMI deep color bit depth
* RETURN: MV_THINVPP_OK - SUCCEED
* MV_EBADPARAM - invalid parameters
* MV_EUNCONFIG - VPP not configured or plane not active
* MV_EFRAMEQFULL - frame queue is full
* Note: this function has to be called before enabling a plane
* which belongs to that CPCB or DV.
*******************************************************************/
int MV_THINVPP_SetCPCBOutputResolution(int cpcbID, int resID, int bit_depth)
{
int vco_freq;
int ppm1k_en;
int avpll_freq_index;
int deep_color_index;
float ovsmp_index;
(void)vco_freq;
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
if (resID<FIRST_RES || resID>=MAX_NUM_RESS)
return (MV_THINVPP_EBADPARAM);
if (thinvpp_obj->status == STATUS_INACTIVE){
/* VPP module is not configured */
return (MV_THINVPP_EUNCONFIG);
}
if (cpcbID<FIRST_CPCB || cpcbID>=MAX_NUM_CPCBS)
return (MV_THINVPP_EBADPARAM);
vco_freq = GetVCOFreq(resID, bit_depth);
if (resID != RES_RESET) {
/* set CPCB new resolution */
if (m_resinfo_table[resID].freq <= 25200) {
avpll_freq_index = 0;
ovsmp_index = 4.0;
} else if ((m_resinfo_table[resID].freq == 27000) || (m_resinfo_table[resID].freq == 27027)) {
avpll_freq_index = 1;
ovsmp_index = 4.0;
} else if ((m_resinfo_table[resID].freq == 74250) || (m_resinfo_table[resID].freq == 74176)) {
avpll_freq_index = 3;
ovsmp_index = 2.0;
} else if ((m_resinfo_table[resID].freq == 148500) || (m_resinfo_table[resID].freq == 148352)) {
avpll_freq_index = 5;
ovsmp_index = 1.0;
} else {
return (MV_THINVPP_EBADPARAM);
}
if (bit_depth == OUTPUT_BIT_DEPTH_12BIT)
deep_color_index = 2;
else if (bit_depth == OUTPUT_BIT_DEPTH_10BIT)
deep_color_index = 1;
else if (bit_depth == OUTPUT_BIT_DEPTH_8BIT)
deep_color_index = 0;
else
return (MV_THINVPP_EBADPARAM);
ppm1k_en = NeedAVPLL_PPM1K(resID);
if (cpcbID == CPCB_1)
diag_videoFreq_A(avpll_freq_index, deep_color_index, ppm1k_en, ovsmp_index, 6);
else if (cpcbID == CPCB_2)
diag_videoFreq_A(avpll_freq_index, deep_color_index, ppm1k_en, ovsmp_index, 5);
else if (cpcbID == CPCB_3)
diag_videoFreq_B(avpll_freq_index, 2 /* always set to 12-bit for AUX */, ppm1k_en, ovsmp_index, 6);
delay_10ns(2000000);
thinvpp_obj->dv[cpcbID].output_res = resID;
THINVPP_BCMBUF_HardwareTrans_Direct(1, cmd_THINVPP_SetCPCBOutputResolution, sizeof(cmd_THINVPP_SetCPCBOutputResolution));
if (cpcbID == CPCB_1)
MV_THINVPP_SetHdmiVideoFmt(OUTPUT_COLOR_FMT_RGB888, bit_depth, 1);
/* set DV status to active */
thinvpp_obj->dv[cpcbID].status = STATUS_ACTIVE;
}
return (MV_THINVPP_OK);
}
int MV_THINVPP_IsCPCBActive(int cpcbID)
{
int vtotal;
if (cpcbID == CPCB_1) {
vtotal = (GLB_REG_READ32(MEMMAP_VPP_REG_BASE+(CPCB0_VT_H << 2)) & 0x0ff);
vtotal <<= 8;
vtotal |= (GLB_REG_READ32(MEMMAP_VPP_REG_BASE+(CPCB0_VT_L << 2)) & 0x0ff);
} else if (cpcbID == CPCB_3) {
vtotal = (GLB_REG_READ32(MEMMAP_VPP_REG_BASE+(CPCB2_VT_H << 2)) & 0x0ff);
vtotal <<= 8;
vtotal |= (GLB_REG_READ32(MEMMAP_VPP_REG_BASE+(CPCB2_VT_L << 2)) & 0x0ff);
} else
vtotal = 0;
return (vtotal);
}
int MV_THINVPP_SetMainRefWindow(const VPP_WIN *win)
{
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
if (!win)
return (MV_THINVPP_EBADPARAM);
#if LOGO_ENABLE_MAIN
thinvpp_obj->plane[PLANE_MAIN].ref_win = *win;
#else
thinvpp_obj->plane[PLANE_PIP].ref_win = *win;
#endif
return (MV_THINVPP_OK);
}
int MV_THINVPP_SetMainDisplayFrame(VBUF_INFO *pinfo)
{
PLANE *plane;
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
if (!pinfo)
return (MV_THINVPP_EBADPARAM);
#if LOGO_ENABLE_MAIN
plane = &(thinvpp_obj->plane[PLANE_MAIN]);
#else
plane = &(thinvpp_obj->plane[PLANE_PIP]);
#endif
plane->pinfo = pinfo;
plane->actv_win.x = pinfo->m_active_left;
plane->actv_win.y = pinfo->m_active_top;
plane->actv_win.width = pinfo->m_active_width;
plane->actv_win.height = pinfo->m_active_height;
return (MV_THINVPP_OK);
}
/******************************************************************************
* FUNCTION: open a window of a video/graphics plane for display.
* the window is defined in end display resolution
* INPUT: planeID - id of a video/grahpics plane
* *win - pointer to a vpp window struct
* *attr - pointer to a vpp window attribute struct
* RETURN: MV_THINVPP_OK - SUCCEED
* MV_EBADPARAM - invalid parameters
* MV_EUNCONFIG - VPP not configured
* MV_EUNSUPPORT - plane not connected in configuration
* MV_ECMDQFULL - command queue is full
******************************************************************************/
int MV_THINVPP_OpenDispWindow(int planeID, const VPP_WIN *win, const VPP_WIN_ATTR *attr)
{
int chanID;
int cpcbID;
PLANE *plane;
CHAN *chan;
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
if (planeID<FIRST_PLANE || planeID>=MAX_NUM_PLANES)
return (MV_THINVPP_EBADPARAM);
if (!win)
return (MV_THINVPP_EBADPARAM);
if ((win->width<=0) || (win->height<=0))
return (MV_THINVPP_EBADPARAM);
if (thinvpp_obj->status == STATUS_INACTIVE){
/* VPP module is not configured */
return (MV_THINVPP_EUNCONFIG);
}
plane = &(thinvpp_obj->plane[planeID]);
chanID = planeID;
chan = &(thinvpp_obj->chan[chanID]);
cpcbID = chan->dvID;
/* update video/graphics channel display window */
chan->disp_win.x = win->x;
chan->disp_win.y = win->y;
chan->disp_win.width = win->width;
chan->disp_win.height = win->height;
if (plane->ref_win.width == 0)
plane->ref_win.width = chan->disp_win.width;
if (plane->ref_win.height == 0)
plane->ref_win.height = chan->disp_win.height;
if (attr){
chan->disp_win_attr.bgcolor = attr->bgcolor;
chan->disp_win_attr.alpha = attr->alpha;
} else {
chan->disp_win_attr.bgcolor = DEFAULT_BGCOLOR;
chan->disp_win_attr.alpha = DEFAULT_ALPHA;
}
/* set video/graphics plane & channel in active status */
plane->status = STATUS_ACTIVE;
chan->status = STATUS_ACTIVE;
THINVPP_Enable_ISR_Interrupt(thinvpp_obj, cpcbID, 1);
VPP_dhub_sem_clear();
return (MV_THINVPP_OK);
}
int MV_THINVPP_CloseDispWindow(void)
{
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
/* wait for CPCB TG reset done */
thinvpp_obj->plane[PLANE_MAIN].status = STATUS_STOP;
thinvpp_obj->plane[PLANE_PIP].status = STATUS_STOP;
thinvpp_obj->plane[PLANE_AUX].status = STATUS_STOP;
while(thinvpp_obj->plane[PLANE_MAIN].status != STATUS_INACTIVE);
return (MV_THINVPP_OK);
}
int MV_THINVPP_Stop(void)
{
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
/* wait for CPCB TG reset done */
MV_REG_AND(0xf7f70068, ~(0x0fff<<19)); // SET32HDMI_ctrl_DAMP(regData, 0);
MV_REG_AND(0xf7f70068 + 4, ~0x0fff); // SET32HDMI_ctrl_EAMP(regData, 0);
thinvpp_obj->dv[CPCB_1].status = STATUS_STOP;
thinvpp_obj->dv[CPCB_3].status = STATUS_STOP;
// if (thinvpp_obj->plane[PLANE_MAIN].status != STATUS_INACTIVE)
while(thinvpp_obj->dv[CPCB_1].status != STATUS_INACTIVE);
// disable CPCB VBI interrupts
THINVPP_Enable_ISR_Interrupt(thinvpp_obj, CPCB_1, 0);
THINVPP_Enable_ISR_Interrupt(thinvpp_obj, CPCB_3, 0);
VPP_dhub_sem_clear();
return (MV_THINVPP_OK);
}
/********************************************************************************
* FUNCTION: Set Hdmi Video format
* INPUT: color_fmt - color format (RGB, YCbCr 444, 422)
* : bit_depth - 8/10/12 bit color
* : pixel_rept - 1/2/4 repetitions of pixel
* RETURN: MV_THINVPP_OK - SUCCEED
* MV_EBADPARAM - invalid parameters
* MV_EUNCONFIG - VPP not configured
* MV_THINVPP_ENODEV - no device
* MV_EUNSUPPORT - channel not connected in configuration
* MV_THINVPP_EBADCALL - channel not connected to DV1
* MV_ECMDQFULL - command queue is full
********************************************************************************/
int MV_THINVPP_SetHdmiVideoFmt(int color_fmt, int bit_depth, int pixel_rept)
{
int cpcbID;
int resID;
int instat;
int avpll_freq_index;
int deep_color_index;
float freq_factor;
int ppm1k_en;
(void)color_fmt;
if (!thinvpp_obj)
return (MV_THINVPP_ENODEV);
if ((cpcbID = CPCB_OF_VOUT(thinvpp_obj, VOUT_HDMI)) == CPCB_INVALID) {
/* Output is not connected to any DV in configuration */
return (MV_THINVPP_EUNSUPPORT);
}
/* Configure AVPLL */
resID = thinvpp_obj->dv[cpcbID].output_res;
if (resID == RES_INVALID)
return (MV_THINVPP_EBADPARAM);
if ((m_resinfo_table[resID].freq == 25200) || (m_resinfo_table[resID].freq == 25175)) {
avpll_freq_index = 0;
} else if ((m_resinfo_table[resID].freq == 27000) || (m_resinfo_table[resID].freq == 27027)) {
avpll_freq_index = 1;
if (pixel_rept == 2) {
if (m_resinfo_table[resID].scan != SCAN_INTERLACED)
avpll_freq_index = 2;
} else if (pixel_rept == 4) {
if (m_resinfo_table[resID].scan != SCAN_INTERLACED)
avpll_freq_index = 4;
else
avpll_freq_index = 2;
}
} else if ((m_resinfo_table[resID].freq == 74250) || (m_resinfo_table[resID].freq == 74176)) {
avpll_freq_index = 3;
} else if ((m_resinfo_table[resID].freq == 148500) || (m_resinfo_table[resID].freq == 148352)) {
if (resID == RES_1080I60 || resID == RES_1080I5994 || resID == RES_1080I50)
avpll_freq_index = 3;
else
avpll_freq_index = 5;
} else {
return (MV_THINVPP_EBADPARAM);
}
if (bit_depth == OUTPUT_BIT_DEPTH_12BIT) {
deep_color_index = 2;
freq_factor = 15.0;
} else if (bit_depth == OUTPUT_BIT_DEPTH_10BIT) {
deep_color_index = 1;
freq_factor = 12.5;
} else if (bit_depth == OUTPUT_BIT_DEPTH_8BIT) {
deep_color_index = 0;
freq_factor = 10.0;
} else {
return (MV_THINVPP_EBADPARAM);
}
ppm1k_en = NeedAVPLL_PPM1K(resID);
diag_videoFreq_A(avpll_freq_index, deep_color_index, ppm1k_en, freq_factor, 7);
delay_10ns(2000000);
semaphore_pop(thinvpp_obj->pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr, 1);
semaphore_clr_full(thinvpp_obj->pSemHandle, avioDhubSemMap_vpp_vppCPCB0_intr);
do {
instat = semaphore_chk_full(thinvpp_obj->pSemHandle, -1);
} while (!(bTST(instat, avioDhubSemMap_vpp_vppCPCB0_intr)));
THINVPP_BCMBUF_HardwareTrans_Direct(1, cmd_THINVPP_SetHdmiVideoFmt, sizeof(cmd_THINVPP_SetHdmiVideoFmt));
return (MV_THINVPP_OK);
}