/*************************************************************************** * Copyright (c) 2003-2006, Broadcom Corporation * All Rights Reserved * Confidential Property of Broadcom Corporation * * THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE * AGREEMENT BETWEEN THE USER AND BROADCOM. YOU HAVE NO RIGHT TO USE OR * EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT. * * $brcm_Workfile: $ * $brcm_Revision: $ * $brcm_Date: $ * * Module Description: * * Revision History: * * $brcm_Log: $ * ***************************************************************************/ #include "bsettop_display.h" #include "gist.h" #include "bstd.h" #include "bsettop_display_priv.h" #include "bchp_int_id_video_enc_intr2.h" #include "bchp_misc.h" /* custimize BandGap Adjust */ #include "bsettop_hdmi.h" #include "bvbi_priv.h" BDBG_MODULE(bsettop_display); static BERR_Code bdisplay_set_sd_output_options(bdisplay_t display, bsettop_display_id_t id, bdisplay_sd_output_options options); static BERR_Code bdisplay_set_hdmi_output_options(bdisplay_t display); static BFMT_VideoFmt bdisplay_hdmi_format_auto(); static BFMT_VideoFmt bdisplay_hdmi_format_to_bfmt(bsettop_display_format_t fmt); static BERR_Code bdisplay_set_graphics_sharpness(bdisplay_t display, bsettop_display_id_t id, unsigned char index); static bresult bdisplay_p_vbi_connect(bdisplay_t display); static bresult bdisplay_p_vbi_open(bdisplay_t display); static bresult bdisplay_p_vbi_disconnect(bdisplay_t display); static bresult bdisplay_p_vbi_close(bdisplay_t display); struct bdisplay b_displays[B_N_DISPLAYS] = { { false, /* Not opened */ { bdisplay_format_auto, NULL, /* normaly used to notify HDMI of rate change */ NULL, /* passed to rate_change_cb */ NULL, /* RF output */ NULL, /* SPDIF output */ NULL, /* I2S output */ bdisplay_sd_output_options_auto, bdisplay_hd_output_options_auto, }, { 0, 0 }, /* displayInfo */ NULL, NULL, { #if HAS_HDMI { NULL, NULL, NULL, NULL, NULL, NULL}, #endif { NULL, NULL, NULL, NULL, NULL, NULL}, }, BFMT_VideoFmt_e480p, BFMT_AspectRatio_e4_3, BFMT_AspectRatio_e4_3, NULL, NULL, NULL, NULL, #ifdef CONFIG_GFX_ARGB32 BPXL_eA8_R8_G8_B8, #else BPXL_eP4, #endif eBSURFACE_0 }, }; #ifdef CONFIG_SPDIF struct boutput_spdif { bool update; boutput_spdif_settings cfg; }; static struct boutput_spdif b_spdif_output = { true, /* Update S/PDIF settings */ { true, /* Enable S/PDIF Output */ false, /* Disable Copy Protection Toggling */ false, /* Disable channel status and validity bit handling */ eAUDIO_OUT_CH_CFG_NORM, /* Lin->Lout, Rin->Rout */ 1, /* V bit polarity */ 0x00, /* Low channel status bits for left channel [0:31] */ 0x00, /* Low channel status bits for right channel [0:31] */ 0x00, /* High channel status bits for both channels [41:32] */ true, /* Always send PCM audio to SPDIF output */ baudio_format_unknown, /* Compressed output format */ }, }; #endif #ifdef CONFIG_I2S struct boutput_i2s { bool update; boutput_i2s_settings cfg; }; static struct boutput_i2s b_i2s_output = { true, /* Update I2S settings */ { true, /* Enable I2S Output */ eAUDIO_OUT_CH_CFG_NORM, /* Select what channels are output */ 16, /* 16 bits per sample */ true, /* Set to true for MSB */ true, /* Set to true to delay data by one SCLK period */ 0, /* Set to 0 for right samples high, left samples low clock */ }, }; #endif /** Summary: Possible hdmi video auto output formats, from low to high **/ static bsettop_display_format_t s_hdmi_video_auto_format[] = { bdisplay_format_480i, bdisplay_format_480p, bdisplay_format_720p, bdisplay_format_1080i, }; #define HDMI_VIDEO_AUTO_FORMAT_NUM (sizeof(s_hdmi_video_auto_format) / sizeof(BFMT_VideoFmt)) #define VDC_MUTEX_TIMEOUT 500 int b_lock_vdc(void) { return bos_acquire_mutex(&b_displays[0].vdc_mutex, VDC_MUTEX_TIMEOUT); } void b_unlock_vdc(void) { bos_release_mutex(&b_displays[0].vdc_mutex); } /** Summary: Display rate change callback **/ static void bdisplay_rate_change_cb(void *pvParam1, int iParam2, void *pvVdcData) { bdisplay_t display = (bdisplay_t)pvParam1; BVDC_Display_CallbackData *vdcCallbackData = (BVDC_Display_CallbackData*)pvVdcData; display->displayInfo = vdcCallbackData->sDisplayInfo; if (display->settings.rate_change_cb) { display->settings.rate_change_cb(display,display->settings.rate_change_data,&(display->displayInfo)); } } /** Summary: Decoder picture ready callback **/ static void MpegDataReady_isr ( void *pvSourceHandle, int iParm2, void *pvMvdField ) { BAVC_XVD_Picture *pMvdField = (BAVC_XVD_Picture *)pvMvdField; BVDC_Source_MpegDataReady_isr(pvSourceHandle, iParm2, (void*)pMvdField); return; } /** Summary: Allocate and reserve resources for a windows. Expects allocated bapp_nexus_t structure. **/ BERR_Code bdisplay_graphics_window_close(bdisplay_t display, bsettop_display_id_t id) { BERR_Code rc; #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif b_lock_vdc(); if (display->disp[id].hGfxWindow) { rc = BVDC_Window_Destroy(display->disp[id].hGfxWindow); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Window_Destroy failed %d\n", rc)); } display->disp[id].hGfxWindow = NULL; } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } b_unlock_vdc(); return BERR_SUCCESS; } /** Summary: Allocate and reserve resources for a windows. Expects allocated bapp_nexus_t structure. **/ BERR_Code bdisplay_graphics_window_open(bdisplay_t display, bsettop_display_id_t id) { BERR_Code rc; BFMT_VideoInfo formatInfo; BDBG_ASSERT(display); BDBG_ASSERT(display->disp[id].hGfxSource); #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif b_lock_vdc(); #if HAS_HDMI if (id == eBDISPLAY_HDMI) { rc = BFMT_GetVideoFormatInfo(display->hdmiFmt,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); } } else #endif { rc = BFMT_GetVideoFormatInfo(BFMT_VideoFmt_eNTSC,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); } } rc = BVDC_Window_Create(display->disp[id].hCmp,&(display->disp[id].hGfxWindow),BVDC_WindowId_eGfx0,display->disp[id].hGfxSource,NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Window_Create failed %d\n", rc)); goto error; } BVDC_Window_SetAlpha(display->disp[id].hGfxWindow, 0xff); #if 1 BVDC_Window_SetBlendFactor (display->disp[id].hGfxWindow, BVDC_BlendFactor_eSrcAlpha, BVDC_BlendFactor_eOneMinusSrcAlpha, BVDC_ALPHA_MAX); #else BVDC_Window_SetBlendFactor (display->disp[id].hGfxWindow, BVDC_BlendFactor_eConstantAlpha, BVDC_BlendFactor_eOneMinusConstantAlpha, BVDC_ALPHA_MAX); #endif BVDC_Window_SetZOrder(display->disp[id].hGfxWindow, 2); BVDC_Window_SetVisibility(display->disp[id].hGfxWindow, true); BVDC_Window_SetScalerOutput(display->disp[id].hGfxWindow, 0, 0, formatInfo.ulDigitalWidth, formatInfo.ulDigitalHeight); BVDC_Window_SetDstRect(display->disp[id].hGfxWindow, 0, 0, formatInfo.ulDigitalWidth, formatInfo.ulDigitalHeight); //BVDC_Window_SetSrcClip(display->disp[id].hGfxWindow, 0, 0, 600, 320); #if HAS_HDMI if (id == eBDISPLAY_HDMI) { if ((display->pxl_format == BPXL_eP4) && ((formatInfo.eVideoFmt == BFMT_VideoFmt_eNTSC) || (formatInfo.eVideoFmt == BFMT_VideoFmt_e480p))) { BVDC_CoefficientIndex coeff; if (display->settings.sharpness < 25) { coeff.ulSclVertLuma = display->settings.sharpness+101; coeff.ulSclHorzLuma = display->settings.sharpness+101; BVDC_Source_SetHorizontalScaleCoeffs(display->disp[id].hGfxSource, BVDC_FilterCoeffs_eSharp); BVDC_Window_SetCoefficientIndex(display->disp[id].hGfxWindow, &coeff); } } else { BVDC_Source_SetHorizontalScaleCoeffs(display->disp[id].hGfxSource, BVDC_FilterCoeffs_eAnisotropic); } } #endif rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } b_unlock_vdc(); return BERR_SUCCESS; error: b_unlock_vdc(); bdisplay_graphics_window_close(display,id); return rc; } #ifdef HAS_HDMI static BERR_Code bdisplay_set_graphics_sharpness(bdisplay_t display, bsettop_display_id_t id, unsigned char index) { BERR_Code rc; BVDC_CoefficientIndex coeff; if ((display->pxl_format != BPXL_eP4) || (index > 25)) { BDBG_ERR(("Invalid Coefficient index %d", index)); return BERR_SUCCESS; } coeff.ulSclVertLuma = index+101; coeff.ulSclHorzLuma = index+101; BVDC_Source_SetHorizontalScaleCoeffs(display->disp[eBDISPLAY_HDMI].hGfxSource, BVDC_FilterCoeffs_eSharp); BVDC_Window_SetCoefficientIndex(display->disp[eBDISPLAY_HDMI].hGfxWindow, &coeff); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d", rc)); } return BERR_SUCCESS; } #endif /** Summary: Allocate and reserve resources for a windows. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_video_window_close(bdisplay_t display, bsettop_display_id_t id) { BERR_Code rc; BDBG_ASSERT(display); #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif if (display->disp[id].hVideoWindow) { BVDC_Window_Destroy(display->disp[id].hVideoWindow); display->disp[id].hVideoWindow = NULL; } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return BERR_SUCCESS; } /** Summary: Allocate and reserve resources for a windows. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_video_window_open(bdisplay_t display, bsettop_display_id_t id) { BERR_Code rc; BFMT_VideoInfo formatInfo; BVDC_Deinterlace_Settings madSettings; BVDC_Window_Settings winSettings; bool deinterlace; #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif #if HAS_HDMI if (id == eBDISPLAY_HDMI) { rc = BFMT_GetVideoFormatInfo(display->hdmiFmt,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); } } else #endif { rc = BFMT_GetVideoFormatInfo(BFMT_VideoFmt_eNTSC,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); } } BVDC_Window_GetDefaultSettings(BVDC_WindowId_eVideo0, &winSettings); #if (BCHP_CHIP==7552) winSettings.bAllocFullScreen = true; winSettings.bDeinterlacerAllocFull = true; winSettings.pMinSrcFmt = BFMT_GetVideoFormatInfoPtr(BFMT_VideoFmt_e1080i); #if HAS_HDMI if (id == eBDISPLAY_HDMI ) { winSettings.pMinDspFmt = BFMT_GetVideoFormatInfoPtr(BFMT_VideoFmt_e1080i); } #endif #endif rc = BVDC_Window_Create(display->disp[id].hCmp,&(display->disp[id].hVideoWindow),BVDC_WindowId_eVideo0,display->hVideoSource,&winSettings); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Window_Create failed %d\n", rc)); goto error; } BVDC_Window_SetAlpha(display->disp[id].hVideoWindow, 0xff); BVDC_Window_SetMasterFrameRate(display->disp[id].hVideoWindow,true); #if 0 #if 1 BVDC_Window_SetBlendFactor (display->disp[id].hVideoWindow, BVDC_BlendFactor_eSrcAlpha, BVDC_BlendFactor_eOneMinusConstantAlpha, BVDC_ALPHA_MAX); #else BVDC_Window_SetBlendFactor (display->disp[id].hVideoWindow, BVDC_BlendFactor_eConstantAlpha, BVDC_BlendFactor_eOneMinusConstantAlpha, BVDC_ALPHA_MAX); #endif #endif BVDC_Window_SetForceCapture(display->disp[id].hVideoWindow, false); BVDC_Window_SetZOrder(display->disp[id].hVideoWindow, 0); BVDC_Window_SetVisibility(display->disp[id].hVideoWindow, true); BVDC_Window_SetScalerOutput(display->disp[id].hVideoWindow, 0, 0, formatInfo.ulDigitalWidth, formatInfo.ulDigitalHeight); BVDC_Window_SetDstRect(display->disp[id].hVideoWindow, 0, 0, formatInfo.ulDigitalWidth, formatInfo.ulDigitalHeight); BVDC_Window_GetDeinterlaceConfiguration(display->disp[id].hVideoWindow,&deinterlace,&madSettings); #if (BCHP_CHIP==7552) madSettings.stVideoTestFeature1.bEnable = true; madSettings.stVideoTestFeature1.ulBitsPerPixel = 18; #endif #if HAS_HDMI if (id == eBDISPLAY_HDMI) { #ifdef SHRINK_WIDTH rc = BVDC_Window_SetDeinterlaceConfiguration(display->disp[id].hVideoWindow, false, &madSettings); if (rc != BERR_SUCCESS) { BDBG_WRN(("!!!!!! BVDC_Window_SetDeinterlaceConfiguration failed: %d", rc)); } #else rc = BVDC_Window_SetDeinterlaceConfiguration(display->disp[id].hVideoWindow, true, &madSettings); if (rc != BERR_SUCCESS) { BDBG_WRN(("!!!!!! BVDC_Window_SetDeinterlaceConfiguration failed: %d", rc)); } #endif //BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eBypass ); bdisplay_set_hdmi_output_options(display); BVDC_Window_SetPanScanType(display->disp[id].hVideoWindow,BVDC_PanScanType_eStream); BVDC_Window_SetBandwidthEquationParams(display->disp[id].hVideoWindow, 1000000, BVDC_SclCapBias_eSclBeforeCap); } else #endif //HAS_HDMI { #ifdef SHRINK_WIDTH display->settings.shrink_width = true; madSettings.bShrinkWidth = display->settings.shrink_width; BVDC_Window_SetDeinterlaceConfiguration(display->disp[id].hVideoWindow, true, &madSettings); #endif /* for SD, just fixed output */ //BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eBypass ); bdisplay_set_sd_output_options(display, id, display->settings.sd_options); BVDC_Window_SetPanScanType(display->disp[id].hVideoWindow,BVDC_PanScanType_eDisable); } BVDC_Window_SetScaleFactorRounding(display->disp[id].hVideoWindow, 3, 3); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return rc; error: bdisplay_video_window_close(display,id); return rc; } /* because we couldn't enable MAD for both output simultaneously, * should disable MAD for one path to enable deinterlacer for the other path */ void bdisplay_set_deinterlacer(bdisplay_t display, int id, bool enable) { bsettop_display_id_t alt_id; BVDC_Deinterlace_Settings madSettings; bool deinterlace; BERR_Code rc; b_lock_vdc(); #if HAS_HDMI alt_id = (id == eBDISPLAY_HDMI)?eBDISPLAY_COMPOSITE:eBDISPLAY_HDMI; #else alt_id = eBDISPLAY_COMPOSITE; #endif BVDC_Window_GetDeinterlaceConfiguration(display->disp[alt_id].hVideoWindow, &deinterlace, &madSettings); #if (BCHP_CHIP==7552) madSettings.stVideoTestFeature1.bEnable = true; madSettings.stVideoTestFeature1.ulBitsPerPixel = 18; #endif rc = BVDC_Window_SetDeinterlaceConfiguration(display->disp[alt_id].hVideoWindow, false, &madSettings); if (rc != BERR_SUCCESS) { BDBG_WRN(("%s: BVDC_Window_SetDeinterlaceConfiguration failed: %d", __FUNCTION__, rc)); b_unlock_vdc(); return; } BVDC_ApplyChanges(display->hVdc); BVDC_Window_GetDeinterlaceConfiguration(display->disp[id].hVideoWindow, &deinterlace, &madSettings); #ifdef SHRINK_WIDTH if ( (display->hdmiFmt!=BFMT_VideoFmt_e1080p_24Hz) && (display->hdmiFmt!=BFMT_VideoFmt_e1080p_30Hz) && (display->hdmiFmt != BFMT_VideoFmt_e1080p)) { madSettings.bShrinkWidth = display->settings.shrink_width; } #endif #if (BCHP_CHIP==7552) madSettings.stVideoTestFeature1.bEnable = true; madSettings.stVideoTestFeature1.ulBitsPerPixel = 18; #endif rc = BVDC_Window_SetDeinterlaceConfiguration(display->disp[id].hVideoWindow, enable, &madSettings); if (rc != BERR_SUCCESS) { BDBG_WRN(("%s: BVDC_Window_SetDeinterlaceConfiguration failed: %d", __FUNCTION__, rc)); b_unlock_vdc(); return; } BVDC_ApplyChanges(display->hVdc); b_unlock_vdc(); } /* set the sharpness/softness for SD SCL * coeff_idx: 1 (softness) -> 26 (sharpness) */ void bdisplay_set_coefficient_index(bdisplay_t display,bool horiz, int output, int coeff_idx) { BERR_Code rc; BVDC_CoefficientIndex index; #if HAS_HDMI int id = (output == 0) ? eBDISPLAY_HDMI : eBDISPLAY_COMPOSITE; #else int id = eBDISPLAY_COMPOSITE; #endif BKNI_Memset(&index, 0, sizeof(index)); b_lock_vdc(); if (horiz) { /* VDC takes 101 to 126 for index value instead of 1 to 26 */ index.ulSclHorzLuma = index.ulSclHorzChroma = coeff_idx + 100; } else { index.ulSclVertLuma = index.ulSclVertChroma = coeff_idx + 100; } rc = BVDC_Window_SetCoefficientIndex(display->disp[id].hVideoWindow, &index); if (rc != BERR_SUCCESS) { BKNI_Memset(&index, 0, sizeof(index)); BVDC_Window_SetCoefficientIndex(display->disp[id].hVideoWindow, &index); } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_WRN(("Fail to set SCL coefficient:%d", rc)); } b_unlock_vdc(); } /** Summary: Allocate and reserve resources for a display pipeline. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_display_close(bdisplay_t display, bsettop_display_id_t id) { BERR_Code rc; #if HAS_HDMI BVDC_Display_CallbackSettings displayCBSettings; #endif BDBG_ASSERT(display); #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif #if 0 if (display->disp[id].vsyncCbHandle) { BINT_DisableCallback(display->disp[id].vsyncCbHandle); BINT_DestroyCallback(display->disp[id].vsyncCbHandle); display->disp[id].vsyncCbHandle = NULL; } #endif #if HAS_HDMI if (id == eBDISPLAY_HDMI) { BVDC_Display_GetCallbackSettings(display->disp[id].hDisplay, &displayCBSettings); displayCBSettings.stMask.bRateChange=0; BVDC_Display_SetCallbackSettings(display->disp[id].hDisplay, &displayCBSettings); rc = BVDC_Display_InstallCallback(display->disp[id].hDisplay, (BVDC_CallbackFunc_isr)NULL, display, 0); } #endif if (id == eBDISPLAY_COMPOSITE) { bdisplay_p_vbi_disconnect(display); bdisplay_p_vbi_close(display); } if (display->disp[id].hDisplay) { BVDC_Display_Destroy(display->disp[id].hDisplay); display->disp[id].hDisplay = NULL; } if (display->disp[id].hCmp) { BVDC_Compositor_Destroy(display->disp[id].hCmp); display->disp[id].hCmp = NULL; } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return BERR_SUCCESS; } /** Summary: Allocate and reserve resources for a display pipeline. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_display_open(bdisplay_t display, bsettop_display_id_t id) { BERR_Code rc; #ifdef HAS_HDMI BVDC_Display_CallbackSettings displayCBSettings; #endif BDBG_ASSERT(display); #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif rc = BVDC_Compositor_Create(display->hVdc, &(display->disp[id].hCmp), BVDC_CompositorId_eCompositor0 + id, NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Compositor_Create failed %d\n", rc)); goto error; } rc = BVDC_Display_Create( display->disp[id].hCmp, &(display->disp[id].hDisplay), BVDC_DisplayId_eAuto,NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_Create failed %d\n", rc)); goto error; } rc = BVDC_Display_SetTimebase(display->disp[id].hDisplay, BAVC_Timebase_e0);/* XXX Set proper timebase BAVC_Timebase_e0 */ if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_SetTimebase failed %d\n", rc)); } #if HAS_HDMI if (id == eBDISPLAY_HDMI) { BVDC_Display_SetVideoFormat(display->disp[id].hDisplay, display->hdmiFmt); BVDC_Display_GetCallbackSettings(display->disp[id].hDisplay, &displayCBSettings); displayCBSettings.stMask.bRateChange=1; BVDC_Display_SetCallbackSettings(display->disp[id].hDisplay, &displayCBSettings); rc = BVDC_Display_InstallCallback(display->disp[id].hDisplay, (BVDC_CallbackFunc_isr)bdisplay_rate_change_cb, display, 0); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_InstallCallback failed %d\n", rc)); } #ifndef HDMI_SD_WIDE_SCREEN if ((display->hdmiFmt == BFMT_VideoFmt_e480p) || (display->hdmiFmt == BFMT_VideoFmt_eNTSC)) { rc = BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, BFMT_AspectRatio_e4_3); } else { rc = BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, BFMT_AspectRatio_e16_9); } #else rc = BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, BFMT_AspectRatio_e16_9); #endif if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_SetAspectRatio failed %d\n", rc)); } } else #endif { rc = BVDC_Display_SetVideoFormat(display->disp[id].hDisplay, BFMT_VideoFmt_eNTSC); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_SetVideoFormat failed %d\n", rc)); } #if (!defined(ACB612) && !defined(ACB615)) #ifdef BCHP_MISC_DAC_0_CFG_SEL_GRPD_0_CVBS rc = BVDC_Display_SetDacConfiguration( display->disp[id].hDisplay, BVDC_Dac_0, BVDC_DacOutput_eFilteredCvbs); #else rc = BVDC_Display_SetDacConfiguration( display->disp[id].hDisplay, BVDC_Dac_0, BVDC_DacOutput_eComposite); #endif #else rc = BVDC_Display_SetDacConfiguration( display->disp[id].hDisplay, BVDC_Dac_0, BVDC_DacOutput_eComposite); #endif if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_SetDacConfiguration failed %d\n", rc)); } rc = BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, BFMT_AspectRatio_e4_3); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_SetAspectRatio failed %d\n", rc)); } } #if 0 rc = BVDC_Compositor_SetBackgroundColor(display->disp[id].hCmp, 0xFF, 0, 0); BDBG_ASSERT(rc == BERR_SUCCESS); #endif #if 0 rc = BINT_CreateCallback(&(display->disp[id].vsyncCbHandle), GetINT(), intId, bdisplay_vsync_isr, display, id); if (rc) return BERR_TRACE(rc); rc = BINT_EnableCallback(display->disp[id].vsyncCbHandle); if (rc) return BERR_TRACE(rc); #endif /* connect vbi encoder to the composite output */ if (id == eBDISPLAY_COMPOSITE){ rc = bdisplay_p_vbi_open(display); if (rc != BERR_SUCCESS) { BDBG_ERR(("Fail to open VBI %d", rc)); } else { rc = bdisplay_p_vbi_connect(display); if (rc != BERR_SUCCESS) { BDBG_ERR(("Fail to connect VBI %d", rc)); } } } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return BERR_SUCCESS; error: bdisplay_display_close(display,id); return rc; } /** Summary: Allocate and reserve resources. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_vdc_close(bdisplay_t display) { BERR_Code rc; BDBG_ASSERT(display); #if HAS_HDMI rc = bdisplay_video_window_close(display,eBDISPLAY_HDMI); { BDBG_ERR(("bdisplay_video_window_close failed %d\n", rc)); } #endif rc = bdisplay_video_window_close(display,eBDISPLAY_COMPOSITE); { BDBG_ERR(("bdisplay_video_window_close failed %d\n", rc)); } #if HAS_HDMI rc = bdisplay_graphics_window_close(display,eBDISPLAY_HDMI); { BDBG_ERR(("bdisplay_graphics_window_close failed %d\n", rc)); } #endif rc = bdisplay_graphics_window_close(display,eBDISPLAY_COMPOSITE); { BDBG_ERR(("bdisplay_graphics_window_close failed %d\n", rc)); } #if HAS_HDMI rc = bdisplay_display_close(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_close failed %d\n", rc)); } #endif rc = bdisplay_display_close(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_close failed %d\n", rc)); } if (display->hVideoSource) { rc = BVDC_Source_Destroy(display->hVideoSource); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_Create failed %d\n", rc)); } } if (display->hVdc) { rc = BVDC_Close(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Open failed %d\n", rc)); } } if (display->hRdc) { rc = BRDC_Close(display->hRdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BRDC_Open failed %d\n", rc)); } } display->hVideoSource = NULL; display->hVdc = NULL; display->hRdc = NULL; rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return BERR_SUCCESS; } /** Summary: Allocate and reserve resources. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_vdc_open(bdisplay_t display) { BERR_Code rc; BRDC_Settings rdcSettings; BVDC_Settings vdcSettings; BINT_Id TopInterruptName; BINT_Id BotInterruptName; BINT_Id ProgressiveInterruptName; BDBG_ASSERT(display); /* BDBG_SetModuleLevel("bvdc", BDBG_eMsg) ; BDBG_SetModuleLevel("bvdc_window", BDBG_eMsg) ; BDBG_SetModuleLevel("bvdc_window_priv", BDBG_eMsg) ; */ rc = BRDC_GetDefaultSettings(GetCHP(),&rdcSettings); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BRDC_Open(&(display->hRdc), GetCHP(),GetREG(),GetHEAP(),&rdcSettings); if (rc != BERR_SUCCESS) { BDBG_ERR(("BRDC_Open failed %d\n", rc)); goto error; } BVDC_GetDefaultSettings(&vdcSettings); #ifdef SHRINK_WIDTH /* adjust heap memory for using ShrinkWidth feature */ vdcSettings.stHeapSettings.ulBufferCnt_2HD_Pip += 6; vdcSettings.stHeapSettings.ulBufferCnt_SD -= 6; #endif #if (BCHP_CHIP==7552) #if defined(ACB612) /* HD only, 1080p@60 */ /* 2HD__Pip default is 0 */ vdcSettings.stHeapSettings.ulBufferCnt_2HD_Pip = 1; /* 2HD default is 0 */ vdcSettings.stHeapSettings.ulBufferCnt_2HD = 2; /* HD default is 4 */ vdcSettings.stHeapSettings.ulBufferCnt_HD = 3; /* SD default is 18 */ //vdcSettings.stHeapSettings.ulBufferCnt_SD += 4; vdcSettings.stHeapSettings.ulBufferCnt_SD = 0; #else vdcSettings.stHeapSettings.ulBufferCnt_2HD_Pip = 2; vdcSettings.stHeapSettings.ulBufferCnt_2HD += 6; vdcSettings.stHeapSettings.ulBufferCnt_SD += 4; #endif #if defined(ACB615) /* SD and HD, 1080p@60 */ vdcSettings.stHeapSettings.ulBufferCnt_2HD += 1; vdcSettings.stHeapSettings.ulBufferCnt_SD = 4; #endif #else vdcSettings.stHeapSettings.ulBufferCnt_SD = 6; vdcSettings.stHeapSettings.ulBufferCnt_HD = 10; #endif /* Modify BandGapAdjust if necessary */ { int id; for(id = 0; id < BVDC_MAX_DACS; id++) { if (vdcSettings.aulDacBandGapAdjust[id]) { /* currently 26, change to 27 to boost it */ #if (BCHP_CHIP!=7552) #ifdef IREF_ADJ_0x10 #warning "Special tuning: MISC_DAC_BG_CTRL_0.IREF_ADJ = 0x10" vdcSettings.aulDacBandGapAdjust[id] = 0x10; #else vdcSettings.aulDacBandGapAdjust[id] = BCHP_MISC_DAC_BG_CTRL_0_IREF_ADJ_TWENTY_SEVEN; #endif #endif } } } rc = BVDC_Open(&(display->hVdc), GetCHP(),GetREG(),GetHEAP(),GetINT(),display->hRdc,GetTMR(),&vdcSettings); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Open failed %d\n", rc)); goto error; } rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } rc = BVDC_Source_Create(display->hVdc,&(display->hVideoSource),BAVC_SourceId_eMpeg0,NULL); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Source_Create failed %d\n", rc)); goto error; } //BVDC_Source_SetVideoMuteColor(display->hVideoSource,0x00,0xFF,0x00); //RLQ #if HAS_HDMI /* Open display pipelines */ rc = bdisplay_display_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_open failed %d\n", rc)); goto error; } #endif rc = bdisplay_display_open(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_open failed %d\n", rc)); goto error; } rc = BVDC_Source_GetInterruptName(display->hVideoSource,BAVC_Polarity_eTopField,&TopInterruptName); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BVDC_Source_GetInterruptName(display->hVideoSource,BAVC_Polarity_eBotField,&BotInterruptName); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BVDC_Source_GetInterruptName(display->hVideoSource,BAVC_Polarity_eFrame,&ProgressiveInterruptName); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BXVD_RegisterVdcInterrupt(GetXVDCh(),TopInterruptName,BAVC_Polarity_eTopField); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BXVD_RegisterVdcInterrupt(GetXVDCh(),BotInterruptName,BAVC_Polarity_eBotField); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BXVD_RegisterVdcInterrupt(GetXVDCh(),ProgressiveInterruptName,BAVC_Polarity_eFrame); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BXVD_InstallInterruptCallback(GetXVDCh(),BXVD_Interrupt_ePictureDataReady, MpegDataReady_isr,display->hVideoSource, 0 ); BDBG_ASSERT(rc == BERR_SUCCESS); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } #if HAS_HDMI rc = bdisplay_video_window_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_open (HDMI) failed %d\n", rc)); goto error; } #endif rc = bdisplay_video_window_open(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_open (COMPOSITE) failed %d\n", rc)); goto error; } return BERR_SUCCESS; error: bdisplay_vdc_close(display); return rc; } /** Summary: Allocate and reserve resources. Expects allocated bapp_nexus_t structure. **/ static BERR_Code bdisplay_format_change(bdisplay_t display, BFMT_VideoFmt format) { BERR_Code rc; BFMT_VideoFmt original_format; BDBG_ASSERT(display); if (format == display->hdmiFmt) return BERR_SUCCESS; original_format = display->hdmiFmt; rc = bdisplay_video_window_close(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_close failed %d\n", rc)); goto error; } rc = bdisplay_graphics_window_close(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_graphics_window_close failed %d\n", rc)); goto error; } #if HAS_HDMI rc = bdisplay_video_window_close(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_close failed %d\n", rc)); goto error; } rc = bdisplay_graphics_window_close(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_graphics_window_close failed %d\n", rc)); goto error; } rc = bdisplay_display_close(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_close failed %d\n", rc)); goto error; } #endif display->hdmiFmt = format; #if HAS_HDMI rc = bdisplay_display_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_open failed %d\n", rc)); goto error; } #endif #if HAS_HDMI rc = BVDC_Display_SetVideoFormat(display->disp[eBDISPLAY_HDMI].hDisplay, format); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_open failed %d\n", rc)); goto error; } #ifndef HDMI_SD_WIDE_SCREEN if ((display->hdmiFmt == BFMT_VideoFmt_e480p) || (display->hdmiFmt == BFMT_VideoFmt_eNTSC)) { rc = BVDC_Display_SetAspectRatio(display->disp[eBDISPLAY_HDMI].hDisplay, BFMT_AspectRatio_e4_3); } else { rc = BVDC_Display_SetAspectRatio(display->disp[eBDISPLAY_HDMI].hDisplay, BFMT_AspectRatio_e16_9); } if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_Display_SetAspectRatio failed %d\n", rc)); goto error; } #endif rc = bdisplay_video_window_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { bdisplay_display_close(display,eBDISPLAY_HDMI); BDBG_ERR(("bdisplay_video_window_open failed %d\n", rc)); goto error; } rc = bdisplay_graphics_window_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { bdisplay_video_window_close(display,eBDISPLAY_HDMI); bdisplay_display_close(display,eBDISPLAY_HDMI); BDBG_ERR(("bdisplay_graphics_window_open failed %d\n", rc)); goto error; } #endif #ifndef CONFIG_NO_SD_OUTPUT rc = bdisplay_video_window_open(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_open failed %d\n", rc)); goto error; } rc = bdisplay_graphics_window_open(display,eBDISPLAY_COMPOSITE); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_open failed %d\n", rc)); goto error; } #endif return BERR_SUCCESS; error: display->hdmiFmt = original_format; #if HAS_HDMI BVDC_Display_SetVideoFormat(display->disp[eBDISPLAY_HDMI].hDisplay, original_format); rc = bdisplay_display_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_display_open failed %d\n", rc)); } rc = bdisplay_video_window_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_video_window_open failed %d\n", rc)); } rc = bdisplay_graphics_window_open(display,eBDISPLAY_HDMI); if (rc != BERR_SUCCESS) { BDBG_ERR(("bdisplay_graphics_window_open (HDMI) failed %d\n", rc)); } #endif return BERR_UNKNOWN; } #ifdef CONFIG_RFM static bresult boutput_p_rf_set( boutput_rf_t rf, /* handle returned by boutput_rf_open */ boutput_rf_settings *settings /* desired rf settings */ ) { BRFM_OutputChannel rf_out; BRFM_ModulationType modType; if (settings->channel == eRFM_CH4) rf_out = BRFM_OutputChannel_eCh4; else rf_out = BRFM_OutputChannel_eCh3; switch ( (uint16_t)settings->country[0] << 8 | (uint16_t)settings->country[1] ) { default: BDBG_WRN(("Unsupported country ! Using Ntsc Open Cable")); case COUNTRY_CODE('U','S'): modType = BRFM_ModulationType_eNtscOpenCable; break; case COUNTRY_CODE('C','N'): modType = BRFM_ModulationType_ePalDChina; break; } if (rf->handle == NULL) { BRFM_Settings rfm_cfg; BRFM_GetDefaultSettings(&rfm_cfg, 1); #ifdef BQAM_SCRIPT rfm_cfg.audioEncoding = BRFM_AudioEncoding_eStereo; #else rfm_cfg.audioEncoding = BRFM_AudioEncoding_eMono; #endif rfm_cfg.chNbr = rf_out; if (BRFM_Open(&rf->handle, 1, 1, 1, &rfm_cfg) != BERR_SUCCESS) { BDBG_ERR(("%s: BRFM_Open failed\n", __FUNCTION__)); return berr_invalid_parameter; } } if (BRFM_SetModulationType(rf->handle, modType, rf_out) != BERR_SUCCESS) { BDBG_ERR(("%s: BRFM_SetModulationType failed\n", __FUNCTION__)); return berr_invalid_parameter; } if (settings->enable_output) { if (BRFM_EnableRfOutput(rf->handle) != BERR_SUCCESS) { BDBG_ERR(("%s: BRFM_EnableRfOutput failed\n", __FUNCTION__)); return berr_external_error; } } else { if (BRFM_DisableRfOutput(rf->handle) != BERR_SUCCESS) { BDBG_ERR(("%s: BRFM_DisableRfOutput failed\n", __FUNCTION__)); return berr_external_error; } } rf->update = false; SW_TRACE_SET(SW_TRACE_RFM_INIT); return b_ok; } /* Summary: set RFM volume */ static bresult boutput_p_rf_volume_set ( boutput_rf_t rf, unsigned int volume /* with RFM volume to set */ ) { int vol; if (rf->handle == NULL) { return berr_invalid_parameter; } BDBG_MSG(("%s: RFM volume=%d\n", __FUNCTION__, volume)); /* validate range, normalized to 0 - 100 */ if (volume < 0 || volume > 100) return berr_invalid_parameter; /* convert volume to dB based value (-34 - 30) */ vol = (volume * (MX_VOLUME - MN_VOLUME)) / 100 + MN_VOLUME; if (BRFM_SetAudioVolume(rf->handle, vol)) return berr_invalid_parameter; rf->volume = volume; return b_ok; } #endif #ifdef CONFIG_SPDIF static bresult boutput_p_spdif_set( boutput_spdif_t spdif, /* handle returned by boutput_spdif_open */ boutput_spdif_settings *settings /* desired spdif settings */ ) { spdif->update = false; return b_ok; } #endif #ifdef CONFIG_I2S static bresult boutput_p_i2s_set( boutput_i2s_t i2s, /* handle returned by boutput_i2s_open */ boutput_i2s_settings *settings /* desired i2s settings */ ) { return b_ok; } #endif /* Summary: to set initial hdmi video format if not default 720p Description: to set initial hdmi video format if not default 720p */ bresult bdisplay_set_init_format( bobject_t display_id, /* handle used to identify a particular display */ bsettop_display_format_t settop_fmt ) { #if HAS_HDMI if (eBDISPLAY_HDMI != display_id) return berr_not_supported; #endif if (bdisplay_format_auto == settop_fmt) /* likely edid is not available yet */ b_displays[display_id].hdmiFmt = BFMT_VideoFmt_e480p; else b_displays[display_id].hdmiFmt = bdisplay_hdmi_format_to_bfmt(settop_fmt); return b_ok; } /* Summary: Open a display. Description: The new display object will already have default outputs configured. You can change the configuration by calling bdisplay_set, making changes, then calling bdisplay_set. */ bdisplay_t bdisplay_open( bobject_t display_id /* handle used to identify a particular display */ ) { unsigned int index; bdisplay_t display; bos_create_mutex(&b_displays[0].vdc_mutex); index = B_ID_GET_INDEX(display_id); if (index >= B_N_DISPLAYS) { BDBG_ERR(("%s: Display index %d is invalid!\n", __FUNCTION__, index)); return NULL; } display = &b_displays[index]; if (display->open) { BDBG_ERR(("%s: Display %d already opened!\n", __FUNCTION__, index)); return NULL; } #if (defined(ACB612) || defined(ACB615)) display->offscreen = NULL; display->overlay = NULL; display->osd = NULL; #ifdef CONFIG_GFX_ARGB32 display->pxl_format = BPXL_eA8_R8_G8_B8; #else display->pxl_format = BPXL_eP4; #endif display->surface_idx = eBSURFACE_0; #endif b_lock_vdc(); if (bdisplay_vdc_open(display) != BERR_SUCCESS) { BDBG_ERR(("%s: bdisplay_vdc_open error!\n", __FUNCTION__)); b_unlock_vdc(); return NULL; } display->open = true; b_unlock_vdc(); return display; } /* Summary: Close a display. Description: All decode windows opened or cloned for this display should have already been closed, otherwise you get an inconsistent state. */ void bdisplay_close( bdisplay_t display /* handle returned by bdisplay_open */ ) { b_lock_vdc(); if (display->open) { if (bdisplay_vdc_close(display) != BERR_SUCCESS) { BDBG_ERR(("%s: bdisplay_vdc_open error!\n", __FUNCTION__)); b_unlock_vdc(); return; } display->open = false; } b_unlock_vdc(); } /* Summary: Open a RFM output. Description: It must be assigned to a display. */ boutput_rf_t boutput_rf_open( bobject_t rfmod_id ) { #ifdef CONFIG_RFM unsigned index; index = B_ID_GET_INDEX(rfmod_id); if (index!=0) { return NULL; } return &b_rf_output; #else BSTD_UNUSED(rfmod_id); return NULL; #endif } /* Summary: Open a SPDIF audio output. Description: It must be assigned to a display. */ boutput_spdif_t boutput_spdif_open(bobject_t spdif_id) { #ifdef CONFIG_SPDIF unsigned index; index = B_ID_GET_INDEX(spdif_id); if (index!=0) { return NULL; } return &b_spdif_output; #else BSTD_UNUSED(spdif_id); return NULL; #endif } /* Summary: Open a I2S audio output. Description: It must be assigned to a display. */ boutput_i2s_t boutput_i2s_open(bobject_t i2s_id) { #ifdef CONFIG_I2S unsigned index; index = B_ID_GET_INDEX(i2s_id); if (index!=0) { return NULL; } return &b_i2s_output; #else BSTD_UNUSED(i2s_id); return NULL; #endif } bresult boutput_rf_set(boutput_rf_t rf, /* handle returned by boutput_rf_open */ const boutput_rf_settings *settings) /* desired rf settings */ { #ifdef CONFIG_RFM rf->update = true; rf->cfg = *settings; #else BSTD_UNUSED(rf); BSTD_UNUSED(settings); #endif return b_ok; } bresult boutput_spdif_set( boutput_spdif_t spdif, /* handle returned by boutput_spdif_open */ const boutput_spdif_settings *settings /* desired spdif settings */ ) { #ifdef CONFIG_SPDIF spdif->update = true; spdif->cfg = *settings; #else BSTD_UNUSED(spdif); BSTD_UNUSED(settings); #endif return b_ok; } bresult boutput_i2s_set( boutput_i2s_t i2s, /* handle returned by boutput_i2s_open */ const boutput_i2s_settings *settings /* desired i2s settings */ ) { #ifdef CONFIG_I2S i2s->update = true; i2s->cfg = *settings; #else BSTD_UNUSED(i2s); BSTD_UNUSED(settings); #endif return b_ok; } void boutput_rf_get(boutput_rf_t rf, /* handle returned by boutput_rf_open */ boutput_rf_settings *settings) /* desired rf settings */ { #ifdef CONFIG_RFM *settings = rf->cfg; #else BSTD_UNUSED(rf); BSTD_UNUSED(settings); #endif } void boutput_spdif_get( boutput_spdif_t spdif, /* handle returned by boutput_spdif_open */ boutput_spdif_settings *settings /* desired spdif settings */ ) { #ifdef CONFIG_SPDIF *settings = spdif->cfg; #else BSTD_UNUSED(spdif); BSTD_UNUSED(settings); #endif } void boutput_i2s_get( boutput_i2s_t i2s, /* handle returned by boutput_i2s_open */ boutput_i2s_settings *settings /* desired i2s settings */ ) { #ifdef CONFIG_I2S *settings = i2s->cfg; #else BSTD_UNUSED(i2s); BSTD_UNUSED(settings); #endif } /* Summary: to translate bsettop_display_format_t into BFMT_VideoFmt Description: to translate bsettop_display_format_t into BFMT_VideoFmt use EDID to resolve bdisplay_format_auto and invalid fmt */ static BFMT_VideoFmt bdisplay_hdmi_format_to_bfmt(bsettop_display_format_t fmt) { BFMT_VideoFmt bfmt; switch (fmt) { case bdisplay_format_auto: bfmt = bdisplay_hdmi_format_auto(); break; case bdisplay_format_1080i: bfmt = BFMT_VideoFmt_e1080i; break; case bdisplay_format_720p: bfmt = BFMT_VideoFmt_e720p; break; case bdisplay_format_480i: bfmt = BFMT_VideoFmt_eNTSC; break; case bdisplay_format_480p: bfmt = BFMT_VideoFmt_e480p; break; case bdisplay_format_1080p60: /*bfmt = BFMT_VideoFmt_e1080p; break;*/ case bdisplay_format_1080p24: /*bfmt = BFMT_VideoFmt_e1080p_24Hz; break;*/ case bdisplay_format_1080p30: /*bfmt = BFMT_VideoFmt_e1080p_30Hz; break;*/ default: bfmt = bdisplay_hdmi_format_auto(); break; } return bfmt; } static BFMT_VideoFmt bdisplay_hdmi_format_auto() { #if HAS_HDMI int idx; for (idx=HDMI_VIDEO_AUTO_FORMAT_NUM-1; idx>=0; idx--) { if (bsettop_hdmi_is_video_fmt_supported(s_hdmi_video_auto_format[idx])) return bdisplay_hdmi_format_to_bfmt(s_hdmi_video_auto_format[idx]); } /* every TV supports 480p, but NOT necessarily 480i */ #endif return BFMT_VideoFmt_e480p; } void bdisplay_record_hdmi_auto_aspect_ratio( bdisplay_t display, /* handle returned by bdisplay_open */ uint32_t auto_hdmi_480i_aspect_ratio, uint32_t auto_hdmi_480p_aspect_ratio ) { display->auto_hdmi_480i_aspect_ratio = (BFMT_AspectRatio) auto_hdmi_480i_aspect_ratio; display->auto_hdmi_480p_aspect_ratio = (BFMT_AspectRatio) auto_hdmi_480p_aspect_ratio; } bresult bdisplay_set( bdisplay_t display, /* handle returned by bdisplay_open */ bdisplay_settings *settings /* desired display settings */ ) { bresult res = b_ok; #ifdef HAS_HDMI bool format_change = false; BFMT_VideoFmt format; #endif b_lock_vdc(); #ifdef CONFIG_RFM if (settings->rf && settings->rf->update) { res = boutput_p_rf_set(settings->rf, &settings->rf->cfg); if (res == b_ok) res = boutput_p_rf_volume_set(settings->rf, settings->rf->volume); } #endif #ifdef CONFIG_SPDIF if (res == b_ok) { if (settings->spdif && settings->spdif->update) res = boutput_p_spdif_set(settings->spdif, &settings->spdif->cfg); } #endif #ifdef CONFIG_I2S if (res == b_ok) { if (settings->i2s && settings->i2s->update) res = boutput_p_i2s_set(settings->i2s, &settings->i2s->cfg); } #endif #ifdef HAS_HDMI format = bdisplay_hdmi_format_to_bfmt(settings->format); // 1). if settings->format == display->settings.format == bdisplay_format_auto, // display->hdmiFmt might be the initialized value BFMT_VideoFmt_e720p, and // might be diff from format = bdisplay_hdmi_format_auto() // 2). can not call bdisplay_format_change before gfx src is created. if ((format != display->hdmiFmt) && (display->disp[eBDISPLAY_HDMI].hGfxSource)) { res = bdisplay_format_change(display,format); format_change = true; } #endif if (settings->sd_options != display->settings.sd_options) { res = bdisplay_set_sd_output_options(display, eBDISPLAY_COMPOSITE, settings->sd_options); } #ifdef HAS_HDMI format = bdisplay_hdmi_format_to_bfmt(settings->format); if ((settings->hd_options != display->settings.hd_options) || (settings->hd_options == bdisplay_hd_output_options_auto) || (format_change)) { display->settings.hd_options = settings->hd_options; bdisplay_set_hdmi_output_options(display); } /* bdisplay_set_graphics_sharpness only works when pxl_format == BPXL_eP4 */ if (settings->format < bdisplay_format_720p && (settings->sharpness != display->settings.sharpness)) { res = bdisplay_set_graphics_sharpness(display, eBDISPLAY_HDMI, settings->sharpness); } if ((settings->deinterlace != display->settings.deinterlace) || (settings->shrink_width != display->settings.shrink_width) || (settings->deinterlacer_affinity != display->settings.deinterlacer_affinity)) { display->settings.shrink_width = settings->shrink_width; bdisplay_set_deinterlacer(display,settings->deinterlacer_affinity,settings->deinterlace); } #endif display->settings = *settings; #if HAS_HDMI if ((format_change || display->settings.force_change_format) && display->settings.rate_change_cb) { display->settings.force_change_format = false; display->settings.rate_change_cb(display,display->settings.rate_change_data,NULL); BDBG_ERR(("%s: done!\n", __func__)); } b_unlock_vdc(); #endif return res; } /* Summary: Get the current outputs, video format and aspect ratio for a display. */ void bdisplay_get( bdisplay_t display, /* handle returned by bdisplay_open */ bdisplay_settings *settings /* [out] current settings of display */ ) { *settings = display->settings; } /* Summary: Set the audio volume for the rf modulator. Description: This function only sets audio volume. */ bresult boutput_rf_set_audio_volume( boutput_rf_t rf, unsigned int volume /* desired volume */ ) { bresult res = b_ok; #ifdef CONFIG_RFM if (rf->handle == NULL) { BDBG_ERR(("%s: RF not already opened!\n", __FUNCTION__)); return berr_invalid_parameter; } res = boutput_p_rf_volume_set(rf, volume); if (res == b_ok) { rf->volume = volume; } #else BSTD_UNUSED(rf); BSTD_UNUSED(volume); #endif return res; } /* Summary: Get the audio levels for the rf modulator. */ bresult boutput_rf_get_audio_volume( boutput_rf_t rf, unsigned int *volume /* [out] current volume of the rf modulater */ ) { #ifdef CONFIG_RFM if (rf->handle == NULL) { BDBG_ERR(("%s: RF not already opened!\n", __FUNCTION__)); return berr_invalid_parameter; } if (volume == NULL) { BDBG_ERR(("%s: pointer to volume is NULL!\n", __FUNCTION__)); return berr_invalid_parameter; } *volume = rf->volume; #else BSTD_UNUSED(rf); BSTD_UNUSED(volume); #endif return b_ok; } /* Summary: Open a new decode window. Description: Creates a new decode window on the given display. The window_id is a global id, not relative to the display. On PIP systems, B_ID(1) always refers to PIP. */ bdecode_window_t bdecode_window_open( bobject_t window_id, /* window's object id */ bdisplay_t display /* display on which the window appears */ ) { return(bdecode_window_t)window_id; } /* Summary: Hide and close a decode window. Description: Any decode which you started to this decode window should have already been stopped. */ void bdecode_window_close( bdecode_window_t window ) { } /* Summary: Get the current settings of a decode window. */ bresult bdecode_window_get( bdecode_window_t window, bdecode_window_settings *settings /* [out] */ ) { bobject_t id = (bobject_t)window; bdisplay_t display = &b_displays[0]; BFMT_VideoInfo formatInfo; BERR_Code rc; #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif #if HAS_HMDI if (id == eBDISPLAY_HDMI) { rc = BFMT_GetVideoFormatInfo(display->hdmiFmt,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); } } else #endif { rc = BFMT_GetVideoFormatInfo(BFMT_VideoFmt_eNTSC,&formatInfo); if (rc != BERR_SUCCESS) { BDBG_ERR(("BFMT_GetVideoFormatInfo failed %d\n", rc)); } } settings->def_position.x = settings->def_position.y = 0; settings->def_position.width = formatInfo.ulDigitalWidth; settings->def_position.height = formatInfo.ulDigitalHeight; rc = BVDC_Window_GetDstRect(display->disp[id].hVideoWindow, &(settings->position.x), &(settings->position.y), &(settings->position.width), &(settings->position.height)); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc); return berr_not_supported;} return b_ok; } /* Summary: Apply new settings to the decode window. Description: Only those individual settings which have changed will be asserted. */ bresult bdecode_window_set( bdecode_window_t window, bdecode_window_settings *settings ) { bobject_t id = (bobject_t)window; bdisplay_t display = &b_displays[0]; uint32_t scl_x,scl_y,scl_w,scl_h; BERR_Code rc; #ifdef CONFIG_NO_SD_OUTPUT if (id == eBDISPLAY_COMPOSITE) return BERR_SUCCESS; #endif b_lock_vdc(); rc = BVDC_Window_SetDstRect(display->disp[id].hVideoWindow, settings->position.x, settings->position.y, settings->position.width, settings->position.height); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc); return berr_not_supported;} #if 1 rc = BVDC_Window_GetScalerOutput(display->disp[id].hVideoWindow, &scl_x, &scl_y, &scl_w, &scl_h); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc);return berr_not_supported;} rc = BVDC_Window_SetScalerOutput(display->disp[id].hVideoWindow, scl_x, scl_y, settings->position.width, settings->position.height); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc);return berr_not_supported;} #endif rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } b_unlock_vdc(); return b_ok; } /* Summary: Pass new settings to the decode window without BVDC_ApplyChanges. Description: Only those individual settings which have changed will be asserted. */ bresult bdecode_window_preset( bdecode_window_t window, bdecode_window_settings *settings ) { bobject_t id = (bobject_t)window; bdisplay_t display = &b_displays[0]; uint32_t scl_x,scl_y,scl_w,scl_h; BERR_Code rc; b_lock_vdc(); rc = BVDC_Window_SetDstRect(display->disp[id].hVideoWindow, settings->position.x, settings->position.y, settings->position.width, settings->position.height); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc); return berr_not_supported;} #if 1 rc = BVDC_Window_GetScalerOutput(display->disp[id].hVideoWindow, &scl_x, &scl_y, &scl_w, &scl_h); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc);return berr_not_supported;} rc = BVDC_Window_SetScalerOutput(display->disp[id].hVideoWindow, scl_x, scl_y, settings->position.width, settings->position.height); if (rc!=BERR_SUCCESS) {rc = BERR_TRACE(rc);return berr_not_supported;} #endif b_unlock_vdc(); return b_ok; } /** Summary: set HD output options **/ static BERR_Code bdisplay_set_hd_output_options(bdisplay_t display, bdisplay_hd_output_options options) { BERR_Code rc = BERR_SUCCESS; #if HAS_HDMI BVDC_AfdSettings afd; BDBG_MSG(("%s: hd options=%d", __func__, options)); BVDC_Window_GetAfdSettings(display->disp[eBDISPLAY_HDMI].hVideoWindow, &afd); afd.eClip = BVDC_AfdClip_eOptionalLevel2; switch (options) { case bdisplay_hd_output_options_stretch: rc = BVDC_Window_SetAspectRatioMode(display->disp[eBDISPLAY_HDMI].hVideoWindow, BVDC_AspectRatioMode_eBypass); afd.eMode = BVDC_AfdMode_eDisabled; break; case bdisplay_hd_output_options_pillarbox: rc = BVDC_Window_SetAspectRatioMode(display->disp[eBDISPLAY_HDMI].hVideoWindow, BVDC_AspectRatioMode_eUseAllSource); afd.eMode = BVDC_AfdMode_eDisabled; break; case bdisplay_hd_output_options_zoom: rc = BVDC_Window_SetAspectRatioMode(display->disp[eBDISPLAY_HDMI].hVideoWindow, BVDC_AspectRatioMode_eUseAllDestination); afd.eMode = BVDC_AfdMode_eDisabled; break; case bdisplay_hd_output_options_auto: rc = BVDC_Window_SetAspectRatioMode(display->disp[eBDISPLAY_HDMI].hVideoWindow, BVDC_AspectRatioMode_eUseAllSource); if (BVDC_AfdMode_eDisabled == afd.eMode) { afd.eMode = BVDC_AfdMode_eStream; } break; } BVDC_Window_SetAfdSettings(display->disp[eBDISPLAY_HDMI].hVideoWindow, &afd); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } #endif return rc; } /** Summary: set SD output options **/ static BERR_Code bdisplay_set_sd_output_options(bdisplay_t display, bsettop_display_id_t id, bdisplay_sd_output_options options) { BERR_Code rc = BERR_SUCCESS; BVDC_AfdSettings afd; BFMT_AspectRatio eAspectRatio; bdisplay_sd_output_options sd_options = options; #ifdef CONFIG_NO_SD_OUTPUT return BERR_SUCCESS; #endif BDBG_MSG(("%s: sd options=%d", __func__, options)); BVDC_Window_GetAfdSettings(display->disp[id].hVideoWindow, &afd); afd.eClip = BVDC_AfdClip_eOptionalLevel2; #if 0 if (eBDISPLAY_COMPOSITE==id) sd_options = bdisplay_sd_output_options_full; /* out menu aspect-ratio 4:3 */ #endif /* reset clip first */ BVDC_Window_SetSrcClip(display->disp[id].hVideoWindow, 0, 0, 0, 0); switch (sd_options) { case bdisplay_sd_output_options_widescreen: /* out menu aspect-ratio 16:9 */ //BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, BFMT_AspectRatio_e16_9); BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eUseAllSource); afd.eMode = BVDC_AfdMode_eDisabled; break; case bdisplay_sd_output_options_full: /* out menu aspect-ratio 4:3 */ //BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, BFMT_AspectRatio_e4_3); #if SUPPORT_DST_PLATFORM BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eBypass); #else BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eUseAllDestination); #endif afd.eMode = BVDC_AfdMode_eDisabled; break; case bdisplay_sd_output_options_auto: /* out menu aspect-ratio auto */ #if 0 if (display->hdmiFmt == BFMT_VideoFmt_eNTSC) eAspectRatio = display->auto_hdmi_480i_aspect_ratio; else if (display->hdmiFmt == BFMT_VideoFmt_e480p) eAspectRatio = display->auto_hdmi_480p_aspect_ratio; else eAspectRatio = BFMT_AspectRatio_e16_9; BVDC_Display_SetAspectRatio(display->disp[id].hDisplay, eAspectRatio); if (eAspectRatio == BFMT_AspectRatio_e16_9) BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eUseAllSource); else BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eUseAllDestination); #endif BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eUseAllDestination); if (BVDC_AfdMode_eDisabled == afd.eMode) { afd.eMode = BVDC_AfdMode_eStream; } break; case bdisplay_sd_output_options_zoom: /* just clip the source window to show zoom effect */ /* do we need video source format as indicator for clip parameters? */ #if SUPPORT_DST_PLATFORM BVDC_Window_SetAspectRatioMode(display->disp[id].hVideoWindow, BVDC_AspectRatioMode_eBypass); #endif BVDC_Window_SetSrcClip(display->disp[id].hVideoWindow, 40, 40, 30, 30); break; } BVDC_Window_SetAfdSettings(display->disp[id].hVideoWindow, &afd); rc = BVDC_ApplyChanges(display->hVdc); if (rc != BERR_SUCCESS) { BDBG_ERR(("BVDC_ApplyChanges failed %d\n", rc)); } return rc; } /** Summary: set hdmi output options **/ static BERR_Code bdisplay_set_hdmi_output_options(bdisplay_t display) { #if HAS_HDMI #ifndef HDMI_SD_WIDE_SCREEN if ((display->hdmiFmt == BFMT_VideoFmt_e480p) || (display->hdmiFmt == BFMT_VideoFmt_eNTSC)) { return bdisplay_set_sd_output_options(display, eBDISPLAY_HDMI, display->settings.hd_options); } else #endif { return bdisplay_set_hd_output_options(display, display->settings.hd_options); } #else return 0; #endif } /* ------------ vbi ----------------------------- */ bresult bdisplay_enable_vbi(bool enable) { BERR_Code rc = BERR_SUCCESS; bdisplay_t display = &b_displays[0]; rc = BVBI_Encode_SetCC(display->vbi.enc_core, enable); if (rc != BERR_SUCCESS) { BDBG_ERR(("Error to VBI encoder CC mode")); return rc; } rc = BVBI_Encode_ApplyChanges(display->vbi.enc_core); if (rc != BERR_SUCCESS) { BDBG_ERR(("Fail to apply VBI encoder settings.")); } return rc; } #ifdef HAS_VBI #define VBI_BOTTOM_LIST_OFFSET 263 #define VBI_TOP_LINE_BASE 10 static BERR_Code vbi_P_SetGemstarOptions(BVBI_Encode_Handle hVbiEnc) { #if (BVBI_P_GEMSTAR_OPTIONS_STRUCT) BVBI_GSOptions gsOptions = { false, VBI_TOP_LINE_BASE, 0x03e0, VBI_BOTTOM_LIST_OFFSET + VBI_TOP_LINE_BASE, 0x03e0 }; return BVBI_Encode_SetGemstarOptions (hVbiEnc, &gsOptions); #else /* NEED to save values to use later */ return BVBI_Encode_SetGemstarOptions (hVbiEnc, VBI_TOP_LINE_BASE, 0x007C, 274, 0x007C); #endif } /* Summary: enable amol and gs Description: enable/disable amol and gs */ bresult bdisplay_vbi_enable_amol_gs(bool enable) { BERR_Code rc = BERR_SUCCESS; bdisplay_t display = &b_displays[0]; /* if called before bdisplay_p_vbi_connect */ if (!display->vbi.enc_core) return BERR_NOT_INITIALIZED; rc = BVBI_Encode_SetGemstar(display->vbi.enc_core, enable); if (rc != BERR_SUCCESS) { BDBG_ERR(("%s: BVBI_Encode_SetGemstar failed",__func__)); return rc; } vbi_P_SetGemstarOptions(display->vbi.enc_core); rc = BVBI_Encode_SetAMOL(display->vbi.enc_core, enable); if (rc != BERR_SUCCESS) { BDBG_ERR(("%s: BVBI_Encode_GetAMOL failed",__func__)); return rc; } rc = BVBI_Encode_ApplyChanges(display->vbi.enc_core); return rc; } bresult vbi_scte127_write_isr(pscte_127_handle pscte_127, int field_parity) { BVBI_Field_Handle field = NULL; BERR_Code rc = BERR_SUCCESS; bdisplay_t display = &b_displays[0]; static BVBI_GSData gs_data[2]; unsigned int i, gs_ret, amol_ret; int gs_count, line_offset; bool obtained = false; int type = 0; /* AMOL TYPE */ unsigned char amol_data[24]; /* try to reuse pending filed if any */ rc = BVBIlib_Encode_GetOldestDatum_isr(display->vbi.enc, &field); if (!rc) { /* need to chcek field pointer since the function doesn't clear it even if no field available */ if (field) { if (field->ulWhichPresent & BVBI_P_SELECT_GS) { BDBG_WRN(("%s: GS data existed already", __func__)); /* note that we have to make sure to get GS data per field so that buffer is not overflow */ /* currently will reset scte 127 buffers if overflow */ return -1; } if (field->ulWhichPresent & BVBI_P_SELECT_AMOL) { BDBG_WRN(("%s: AMOL data existed already", __func__)); /* note that we have to make sure to get AMOL data per field so that buffer is not overflow */ return -1; } /* need to make sure polarity matches */ BVBI_Field_GetPolarity_isr(field, &i); if (i != (1 << field_parity)) { BDBG_MSG(("%s: wrong polarity, what to do?", __func__)); //return -1; field_parity = !field_parity; } } } gs_ret = scte_127_get_gs_data_buf_isr(pscte_127, field_parity, &line_offset, &gs_count, (uint32_t *)&gs_data[field_parity].ulData); amol_ret = scte_127_get_amol_data_buf_isr_ex(pscte_127, field_parity, &type, amol_data); if (gs_ret || amol_ret) { if (!field) { obtained = true; rc = BVBIlib_List_Obtain_isr(display->vbi.hVbilist, &field); if (rc) { goto done_write; } /* if we can't get one, just let the data stay pending. we still need to fall through and allow VBIlib to empty its queue. */ (void)BVBI_Field_SetPolarity_isr(field, (1 << field_parity)); } if (gs_ret && gs_count) { /* put the data to GSData structure */ gs_data[field_parity].ulDataLines = 0; gs_data[field_parity].ulErrorLines = 0; for (i = 0; i < BAVC_VBI_GS_MAX_LINES; i++) { if (i < gs_count) { gs_data[field_parity].ulDataLines |= (1L << (line_offset + i)); } else { gs_data[field_parity].ulData[i] = 0; } } #if HAS_VBI scte_127_set_gs_line_mask(pscte_127, field_parity, VBI_TOP_LINE_BASE, (gs_data[field_parity].ulDataLines >> VBI_TOP_LINE_BASE)); #endif rc = BVBI_Field_SetGSData_isr(field, &gs_data[field_parity]); if (rc!=BERR_SUCCESS) { BDBG_WRN(("%s: BVBI_Field_SetGSData_isr failed", __func__)); //goto done_write; } } /* should we send NULL data as well? */ if (amol_ret && type) { //TODO check amol module to see if it also check line mask or not */ /* put the data to GSData structure */ rc = BVBI_Field_SetAMOLData_isr(field, type, amol_data,40 /* JPF Liqun to identify correct way to obtain amol length */); if (rc!=BERR_SUCCESS) {goto done_write;} } if (obtained) { /* This actually sends it to the VEC and consumes the field */ if ((rc = BVBIlib_Encode_Enqueue_isr(display->vbi.enc, field))) { /* if it fails, assume it's a queue overflow and we're done */ BDBG_WRN(("%s: VBI encoder queue overflow", __func__)); /* if we can't enqueue, the buffer is probably full. Try to recover by flushing. */ BVBIlib_List_Return_isr(display->vbi.hVbilist, field); //BVBIlib_Encode_Flush_isr(display->vbi.enc); } field = NULL; } done_write: if (BERR_SUCCESS != rc) { BDBG_WRN(("%s: failed (rc=0x%x)", __func__, rc)); } if (field && obtained) { BVBIlib_List_Return_isr(display->vbi.hVbilist, field); } } return rc; } #if 0 bresult vbi_gs_write_isr(pscte_127_handle pscte_127, int field_parity) { BVBI_Field_Handle field = NULL; BERR_Code rc = BERR_SUCCESS; bdisplay_t display = &b_displays[0]; static BVBI_GSData gs_data[2]; unsigned int i; int gs_count, line_offset; bool obtained = false; /* try to reuse pending filed if any */ rc = BVBIlib_Encode_GetOldestDatum_isr(display->vbi.enc, &field); if (!rc) { /* need to chcek field pointer since the function doesn't clear it even if no field available */ if (field) { if (field->ulWhichPresent & BVBI_P_SELECT_GS) { BDBG_WRN(("%s: GS data existed already", __func__)); /* not that we have to make sure to get GS data per field so that buffer is not overflow */ /* so just overwrite gs data if VBI encoder is not fast enough */ return -1; } /* need to make sure polarity matches */ BVBI_Field_GetPolarity_isr(field, &i); if (i != (1 << field_parity)) { BDBG_MSG(("%s: wrong polarity, what to do?", __func__)); //return -1; field_parity = !field_parity; } } } if (scte_127_get_gs_data_buf_isr(pscte_127, field_parity, &line_offset, &gs_count, (uint32_t *)&gs_data[field_parity].ulData)) { if (!field) { obtained = true; rc = BVBIlib_List_Obtain_isr(display->vbi.hVbilist, &field); if (rc) { goto done_write; } /* if we can't get one, just let the data stay pending. we still need to fall through and allow VBIlib to empty its queue. */ (void)BVBI_Field_SetPolarity_isr(field, (1 << field_parity)); } /* put the data to GSData structure */ gs_data[field_parity].ulDataLines = 0; gs_data[field_parity].ulErrorLines = 0; for (i = 0; i < BAVC_VBI_GS_MAX_LINES; i++) { if (i < gs_count) { gs_data[field_parity].ulDataLines |= (1L << (line_offset + i)); } else { gs_data[field_parity].ulData[i] = 0; } } #if HAS_VBI scte_127_set_gs_line_mask(pscte_127, field_parity, VBI_TOP_LINE_BASE, (gs_data[field_parity].ulDataLines >> VBI_TOP_LINE_BASE)); #endif rc = BVBI_Field_SetGSData_isr(field, &gs_data[field_parity]); if (rc!=BERR_SUCCESS) {goto done_write;} if (obtained) { /* This actually sends it to the VEC and consumes the field */ if ((rc = BVBIlib_Encode_Enqueue_isr(display->vbi.enc, field))) { /* if it fails, assume it's a queue overflow and we're done */ BDBG_WRN(("%s: VBI encoder queue overflow", __func__)); /* if we can't enqueue, the buffer is probably full. Try to recover by flushing. */ BVBIlib_List_Return_isr(display->vbi.hVbilist, field); //BVBIlib_Encode_Flush_isr(display->vbi.enc); } field = NULL; } done_write: if (BERR_SUCCESS != rc) { BDBG_WRN(("%s: failed (rc=0x%x)", __func__, rc)); } if (field && obtained) { BVBIlib_List_Return_isr(display->vbi.hVbilist, field); } } return rc; } bresult vbi_amol_write_isr(pscte_127_handle pscte_127, int field_parity) { BVBI_Field_Handle field = NULL; BERR_Code rc = BERR_SUCCESS; bdisplay_t display = &b_displays[0]; pscte_127_data pdata; bool full = false; if (NULL == pscte_127) return BERR_NOT_INITIALIZED; /* not that currently AMOL module doens't take line offset, but it may need later */ /* TODO:: reordering may be required for some streams..*/ /* Set up the field. If we fail, make sure to exit the critical section and free memory */ while ((pdata = scte_127_get_amol_data_buf_isr(pscte_127, field_parity))) { /* get a field */ rc = BVBIlib_List_Obtain_isr(display->vbi.hVbilist, &field); if (rc!=BERR_SUCCESS) {goto done_write;} /* running out of fields is normal flow control */ rc = BVBI_Field_SetPolarity_isr(field, (1 << pdata->field_parity)); /* put the data to GSData structure */ rc = BVBI_Field_SetAMOLData_isr(field, pdata->amol_type, pdata->u.amol96); if (rc!=BERR_SUCCESS) {goto done_write;} /* This actually sends it to the VEC and consumes the field */ if (BVBIlib_Encode_Enqueue_isr(display->vbi.enc, field)) { /* if it fails, assume it's a queue overflow and we're done */ BDBG_MSG(("%s: VBI encoder queue overflow", __func__)); /* if we can't enqueue, the buffer is probably full. Try to recover by flushing. */ BVBIlib_Encode_Flush_isr(display->vbi.enc); full = true; } else { field = NULL; } done_write: if (pdata) { scte_127_queue_buffer_isr(pscte_127, pdata); pdata = NULL; } if (BERR_SUCCESS != rc) { BDBG_WRN(("%s: failed (rc=0x%x)", __func__, rc)); } if (field) { BVBIlib_List_Return_isr(display->vbi.hVbilist, field); } if (full || rc) break; field = NULL; /* consumed */ } return rc; } #endif #endif bresult vbi_cc_write_isr(const unsigned char* ccData, size_t length) { BVBI_Field_Handle field = NULL; BERR_Code rc = BERR_SUCCESS; unsigned int i; int full = 0; bdisplay_t display = &b_displays[0]; /* TODO:: reordering may be required for some streams..*/ for (i=0; ivbi.hVbilist, &field); if (rc!=BERR_SUCCESS) {goto done_write;} /* running out of fields is normal flow control */ rc = BVBI_Field_SetCCData_isr(field, ccData[3*i+1], ccData[3*i+2]); if (rc!=BERR_SUCCESS) {goto done_write;} rc = BVBI_Field_SetPolarity_isr(field, 1<<(ccData[3*i]?1:0)); if (rc!=BERR_SUCCESS) {goto done_write;} /* This actually sends it to the VEC and consumes the field */ if (BVBIlib_Encode_Enqueue_isr(display->vbi.enc, field)) { /* if it fails, assume it's a queue overflow and we're done */ BDBG_MSG(("VBI encoder queue overflow")); full = 1; /* if we can't enqueue, the buffer is probably full. Try to recover by flushing. */ BVBIlib_Encode_Flush_isr(display->vbi.enc); } else { field = NULL; } done_write: if (field) { BVBIlib_List_Return_isr(display->vbi.hVbilist, field); } if (full || rc) break; field = NULL; /* consumed */ } return rc; } bresult bdisplay_vbi_clear_cc(void) { unsigned char ccData[18]; int i; /* Force send EDM command to clear */ for (i=0; i<2; i++) { ccData[i*3] = 0; ccData[i*3+1] = 0x14; ccData[i*3+2] = 0x2c; } /* Force send ENM command to clear */ for (i=2; i<4; i++) { ccData[i*3] = 0; ccData[i*3+1] = 0x14; ccData[i*3+2] = 0x2e; } /* EOC command */ for (i=4; i<6; i++) { ccData[i*3] = 0; ccData[i*3+1] = 0x14; ccData[i*3+2] = 0x2f; } BKNI_EnterCriticalSection(); vbi_cc_write_isr((const unsigned char *)ccData, 6); BKNI_LeaveCriticalSection(); return BERR_SUCCESS; } static bresult bdisplay_p_vbi_open(bdisplay_t display) { BERR_Code rc; BVBIlib_List_Settings vbilistsettings; int queue_size; rc = BVBI_Open(&display->vbi.hVbi, GetCHP(), GetREG(), GetHEAP(), NULL); if (rc != BERR_SUCCESS) { return rc; } rc = BVBIlib_Open(&display->vbi.hVbilib, display->vbi.hVbi); if (rc != BERR_SUCCESS) { return rc; } BVBIlib_List_GetDefaultSettings(&vbilistsettings); queue_size = 17 * 2; #if HAS_VBI vbilistsettings.bAllowGemstar = true; vbilistsettings.bAllowAmol = true; #endif rc = BVBIlib_List_Create(&display->vbi.hVbilist, display->vbi.hVbi, queue_size/* number of entries. This should be one greater than the number passed to BVBIlib_Encode_Create because of vbilib internal resource management. */, &vbilistsettings); //BVBIlib_DCCReorder_Open(&display->vbi.hReorder, 16, 15); #if HAS_VBI bdisplay_vbi_enable_amol_gs(false); #endif return rc; } static bresult bdisplay_p_vbi_close(bdisplay_t display) { if (display->vbi.hVbilist) BVBIlib_List_Destroy(display->vbi.hVbilist); if (display->vbi.hVbilib) BVBIlib_Close(display->vbi.hVbilib); if (display->vbi.hVbi) BVBI_Close(display->vbi.hVbi); return BERR_SUCCESS; } static void bdisplay_p_vbi_isr(void *parm1, int parm2) { bdisplay_t display = (bdisplay_t)parm1; BERR_Code rc; BAVC_Polarity polarity = (BAVC_Polarity)parm2; #ifdef HAS_VBI pscte_127_handle pscte_127; pscte_127 = scte_127_get_handle(); if (pscte_127) { if (scte_127_has_data(pscte_127, polarity)) { //vbi_amol_write_isr(pscte_127, polarity); //vbi_gs_write_isr(pscte_127, polarity); vbi_scte127_write_isr(pscte_127, polarity); } } #endif rc = BVBIlib_Encode_Data_isr(display->vbi.enc, polarity); if (rc!=BERR_SUCCESS) { BDBG_ERR(("BVBIlib_Encode_Data_isr returned error %x, ignored", rc)); } return; } static bresult bdisplay_p_vbi_connect(bdisplay_t display) { BAVC_VbiPath vbi_path; BERR_Code rc; BINT_Id tf_isr, bf_isr; int queue; BDBG_MSG(("connect display %p to vbi", display)); /* connect vbi encoder to the composite display output */ rc = BVDC_Display_GetVbiPath(display->disp[eBDISPLAY_COMPOSITE].hDisplay, &vbi_path); if (rc!=BERR_SUCCESS) { BDBG_ERR(("Couldn't get the VBI path for composite display output : %x", rc)); return rc; } switch (vbi_path) { #if defined(BCHP_INT_ID_VBI_0_0_INTR) case BAVC_VbiPath_eVec0: tf_isr = BCHP_INT_ID_VBI_0_0_INTR; bf_isr = BCHP_INT_ID_VBI_0_1_INTR; break; #if defined BCHP_INT_ID_VBI_1_0_INTR && defined BCHP_INT_ID_VBI_1_1_INTR case BAVC_VbiPath_eVec1: tf_isr = BCHP_INT_ID_VBI_1_0_INTR; bf_isr = BCHP_INT_ID_VBI_1_1_INTR; break; #endif #if defined(BCHP_INT_ID_ANCIL_VBI_0_INTR) case BAVC_VbiPath_eBypass0: tf_isr = BCHP_INT_ID_ANCIL_VBI_0_INTR; bf_isr = BCHP_INT_ID_ANCIL_VBI_1_INTR; break; #endif #if defined(BCHP_INT_ID_VBI_2_0_INTR) case BAVC_VbiPath_eVec2: tf_isr = BCHP_INT_ID_VBI_2_0_INTR; bf_isr = BCHP_INT_ID_VBI_2_1_INTR; break; #endif #else case BAVC_VbiPath_eVec0: tf_isr = BCHP_INT_ID_PRIM_VBI_0_INTR; bf_isr = BCHP_INT_ID_PRIM_VBI_1_INTR; break; #if defined BCHP_INT_ID_SEC_VBI_0_INTR && defined BCHP_INT_ID_SEC_VBI_1_INTR case BAVC_VbiPath_eVec1: tf_isr = BCHP_INT_ID_SEC_VBI_0_INTR; bf_isr = BCHP_INT_ID_SEC_VBI_1_INTR; break; #endif #if defined(BCHP_INT_ID_BYPASS_VBI_0_INTR) case BAVC_VbiPath_eBypass0: tf_isr = BCHP_INT_ID_BYPASS_VBI_0_INTR; bf_isr = BCHP_INT_ID_BYPASS_VBI_1_INTR; break; #endif #if defined(BCHP_INT_ID_TERT_VBI_0_INTR) case BAVC_VbiPath_eVec2: tf_isr = BCHP_INT_ID_TERT_VBI_0_INTR; bf_isr = BCHP_INT_ID_TERT_VBI_1_INTR; break; #endif #endif default: rc = BERR_TRACE(BERR_NOT_SUPPORTED); goto err_vbi_path; } /* unfortunately we have to recreate everything because the vbi_path might change */ rc = BVBI_Encode_Create(display->vbi.hVbi, vbi_path, &display->vbi.enc_core); if (rc!=BERR_SUCCESS) {goto err_vbi_encode;} queue = 32; rc = BVBIlib_Encode_Create(display->vbi.hVbilib, display->vbi.hVbilist, display->vbi.enc_core, queue /* queue size. this was 4 for analog, but must be increase for MVD USERDATA */, &display->vbi.enc); if (rc!=BERR_SUCCESS) {goto err_vbilib_encode;} /* we are using top ISR to feed bottom field data and bottom field isr to feed top field data */ rc = BINT_CreateCallback(&display->vbi.tf_isr, GetINT(), tf_isr, bdisplay_p_vbi_isr, display, BAVC_Polarity_eBotField); if (rc!=BERR_SUCCESS) {goto err_tf_isr;} rc = BINT_CreateCallback(&display->vbi.bf_isr, GetINT(), bf_isr, bdisplay_p_vbi_isr, display, BAVC_Polarity_eTopField); if (rc!=BERR_SUCCESS) {goto err_bf_isr;} rc = BINT_EnableCallback(display->vbi.tf_isr); if (rc!=BERR_SUCCESS) {goto err_isr_cfg;} rc = BINT_EnableCallback(display->vbi.bf_isr); if (rc!=BERR_SUCCESS) {goto err_isr_cfg;} BVBI_Encode_SetVideoFormat(display->vbi.enc_core, BFMT_VideoFmt_eNTSC); rc = BVBI_Encode_SetCC(display->vbi.enc_core, true); if (rc!=BERR_SUCCESS) {goto err_enable_vbi;} #ifdef HAS_VBI rc = BVBI_Encode_SetGemstar(display->vbi.enc_core, true); if (rc!=BERR_SUCCESS) {goto err_enable_vbi;} rc = BVBI_Encode_SetAMOL(display->vbi.enc_core, true); if (rc!=BERR_SUCCESS) {goto err_enable_vbi;} #endif rc = BVBI_Encode_ApplyChanges(display->vbi.enc_core); if (rc!=BERR_SUCCESS) {goto err_enable_vbi;} return rc; err_enable_vbi: err_isr_cfg: BINT_DestroyCallback(display->vbi.bf_isr); err_bf_isr: BINT_DestroyCallback(display->vbi.tf_isr); err_tf_isr: BVBIlib_Encode_Destroy(display->vbi.enc); err_vbilib_encode: BVBI_Encode_Destroy(display->vbi.enc_core); display->vbi.enc_core = NULL; err_vbi_encode: err_vbi_path: return rc; } static bresult bdisplay_p_vbi_disconnect(bdisplay_t display) { #ifdef HAS_VBI BVBI_Encode_SetGemstar(display->vbi.enc_core, false); BVBI_Encode_GetAMOL(display->vbi.enc_core, false); #endif bdisplay_enable_vbi(false); if (display->vbi.bf_isr) BINT_DestroyCallback(display->vbi.bf_isr); if (display->vbi.tf_isr) BINT_DestroyCallback(display->vbi.tf_isr); if (display->vbi.enc) BVBIlib_Encode_Destroy(display->vbi.enc); if (display->vbi.enc_core) BVBI_Encode_Destroy(display->vbi.enc_core); display->vbi.enc_core = NULL; return BERR_SUCCESS; } bresult bdisplay_set_vbi_rating_info( bdisplay_t display, unsigned int ratings_tv, unsigned int ratings_movie, unsigned int content_v, unsigned int content_s, unsigned int content_l, unsigned int content_d) { unsigned char xds_data[9]; xds_data[0] = xds_data[3] = xds_data[6] = 1; xds_data[1] = 0x1; xds_data[2] = 0x05; /* character 1 : x 1 D/a2 a1 a0 r2 r1 r0 * character 2 : x 1 (F)V S L/a3 g2 g1 g0 */ xds_data[4] = ratings_movie|0x40; xds_data[4] |= 0x08; xds_data[4] |= (content_d << 5); xds_data[5] = ratings_tv | 0x40; xds_data[5] |= (content_l<<3); xds_data[5] |= (content_s<<4); xds_data[5] |= (content_v<<5); xds_data[7] = 0x0f; xds_data[8] = 0x1d; BKNI_EnterCriticalSection(); vbi_cc_write_isr(xds_data,3); BKNI_LeaveCriticalSection(); return BERR_SUCCESS; } bresult bdisplay_output_rf_enable( bdisplay_t display, /* handle returned by bdisplay_open */ bool enable ) { bresult res = b_ok; b_lock_vdc(); #ifdef CONFIG_RFM bdisplay_settings settings; bdisplay_get(display, &settings); if (settings->rf) { settings->rf->update = true; settings->rf->enable_output = enable; res = boutput_p_rf_set(settings->rf, &settings->rf->cfg); /* volume to 0 ? */ } #else /* simply to set window invisible? */ res = BVDC_Window_SetVisibility(display->disp[eBDISPLAY_COMPOSITE].hVideoWindow, enable); res = BVDC_ApplyChanges(display->hVdc); #endif b_unlock_vdc(); return res; } /* Summary: enable visibility of HDMI window Description: enable/disable HDMI window in case HDCP authentication failed */ bresult bdisplay_output_hdmi_enable( bdisplay_t display, /* handle returned by bdisplay_open */ bool enable ) { bresult res = b_ok; #if HAS_HDMI if (!display->disp[eBDISPLAY_HDMI].hVideoWindow) return res; b_lock_vdc(); /* simply to set window invisible? */ res = BVDC_Window_SetVisibility(display->disp[eBDISPLAY_HDMI].hVideoWindow, enable); res = BVDC_ApplyChanges(display->hVdc); b_unlock_vdc(); #endif return res; } /* Summary: return default display settings Description: return default display settings */ void bdisplay_get_default_settings(bdisplay_settings *psettings) { if (psettings) { BKNI_Memcpy(psettings, &b_displays[0].settings, sizeof(bdisplay_settings)); } } /* * Summary: * power management for VDC block */ void bdisplay_standby(bdisplay_t display, bool standby) { if (standby) { BVDC_Standby(display->hVdc, NULL); } else { BVDC_Resume(display->hVdc); } }