/*************************************************************************** * Copyright (c) 2008, 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 "bapp_gs.h" //#include "bstd.h" #include "bchp_gse_0.h" #include "bchp_gse_1.h" #include "bchp_vbi_enc.h" #include "bchp_vf_0.h" #include "bstd.h" #include "scte_127.h" #include "ministd.h" #include "gist.h" BDBG_MODULE(bapp_gs); #ifndef BAPP_ASSERT #define BAPP_ASSERT(expr) { \ if (!expr) \ printf("%s failed at %s:%d\n",#expr, __FILE__, __LINE__); \ } #endif #define GS_ENABLE_TIMEOUT (g_ticks_per_second * 2) #define BASE_LINE 10 /* * Main data structure containing references to all interfaces * required throughout the application. */ struct bapp_gs { bool done; bool enabled; b_mutex_t mutex; int baseline_top; /* baseline for top field */ unsigned short linemask_top; /* bit mask for top field */ int baseline_bot; /* baseline for bottom field */ unsigned short linemask_bot; /* bit mask for bottom field */ }; bapp_gs_t s_p_gs = NULL; #define IRE_70 0x5c /* 92 */ #define IRE_80 0x69 /* 105 */ /* Summary: Initialize and allocate resources */ bapp_gs_t bapp_gs_open(void* p_opaque_app) { BDBG_MSG(("%s: enter", __func__)); s_p_gs = (bapp_gs_t)malloc(sizeof(struct bapp_gs)); BAPP_ASSERT(s_p_gs); memset(s_p_gs, 0, sizeof(struct bapp_gs)); BAPP_ASSERT(bos_create_mutex(&s_p_gs->mutex) == b_ok); s_p_gs->linemask_top = 0; /* 0 lines initially starting from baseline_top */ s_p_gs->baseline_top = BASE_LINE; /* baseline for top field */ s_p_gs->linemask_bot = 0; /* 0 lines initially starting from baseline_bot */ s_p_gs->baseline_bot = 17; /* baseline for bottom field */ bapp_gs_init(s_p_gs); BDBG_MSG(("%s: leave", __func__)); return s_p_gs; } /* Summary: Release all resources allocated with bapp_gs_open */ void bapp_gs_close(bapp_gs_t p_gs) { BDBG_WRN(("%s: enter", __func__)); BAPP_ASSERT(p_gs); bos_delete_mutex(&p_gs->mutex); free(p_gs); s_p_gs = NULL; BDBG_WRN(("%s: leave", __func__)); } static void bapp_gs_program_null ( uint32_t ulWritePointer, uint32_t value) { uint32_t ulRegVal = BREG_Read32(GetREG(), BCHP_GSE_0_NULL); switch (ulWritePointer & 0x3) { case 1: if (!value) ulRegVal &= ~BCHP_MASK (GSE_0_NULL, NULL_ENABLE_BANK1); else ulRegVal |= BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK1, 1); break; case 2: if (!value) ulRegVal &= ~BCHP_MASK (GSE_0_NULL, NULL_ENABLE_BANK2); else ulRegVal |= BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK2, 1); break; case 3: if (!value) ulRegVal &= ~BCHP_MASK (GSE_0_NULL, NULL_ENABLE_BANK3); else ulRegVal |= BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK3, 1); break; default: case 0: if (!value) ulRegVal &= ~BCHP_MASK (GSE_0_NULL, NULL_ENABLE_BANK0); else ulRegVal |= BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK0, 1); break; } BREG_Write32(GetREG(), BCHP_GSE_0_NULL, ulRegVal); } /* Summary: Enable/Disable GSE */ void bapp_gs_enable(bapp_gs_t p_gs, bool enable) { uint32_t ulReg; BDBG_MSG(("%s: enter: enable=%d", __func__, enable)); BAPP_ASSERT(p_gs); if (bos_acquire_mutex(&(p_gs->mutex), GS_ENABLE_TIMEOUT) != b_ok) { BDBG_ERR(("%s bos_acquire_mutex failed(enable = %d)\n",__func__,enable)); return; } if (p_gs->enabled == enable) { bos_release_mutex(&(p_gs->mutex)); BDBG_WRN(("%s: no change", __func__)); return; } p_gs->enabled = enable; ulReg = BREG_Read32(GetREG(), BCHP_GSE_0_CONTROL); ulReg &= ~BCHP_MASK(GSE_0_CONTROL, ENABLE); if (enable) { ulReg |= BCHP_FIELD_ENUM (GSE_0_CONTROL, ENABLE, ENABLED); } BREG_Write32(GetREG(), BCHP_GSE_0_CONTROL, ulReg); ulReg = BREG_Read32(GetREG(), BCHP_VF_0_MISC); ulReg &= ~BCHP_MASK(VF_0_MISC, VBI_ENABLE); ulReg &= ~BCHP_MASK(VF_0_MISC, VBI_PREFERRED); if (enable) { ulReg |= BCHP_FIELD_ENUM (VF_0_MISC, VBI_ENABLE, ON); ulReg |= BCHP_FIELD_ENUM (VF_0_MISC, VBI_PREFERRED, ON); } BREG_Write32(GetREG(), BCHP_VF_0_MISC, ulReg); bos_release_mutex(&(p_gs->mutex)); if (!enable) bapp_gs_reset(p_gs); BDBG_MSG(("%s: leave", __func__)); } bool bapp_gs_init( bapp_gs_t p_gs ) { uint32_t ulReg, i; BDBG_MSG(("%s: enter", __func__)); ulReg = 0; ulReg |= ( BCHP_FIELD_DATA (GSE_0_CONTROL, FIFO_FREEZE, 0) | BCHP_FIELD_DATA (GSE_0_CONTROL, NULL_MODE, 1) | #if (DISPLAY_PAL == 1) || (DISPLAY_PAL_NC == 1) BCHP_FIELD_ENUM (GSE_0_CONTROL, BIT_WIDTH, PAL) | /* 429 for NTSC, 432 for PAL */ #else BCHP_FIELD_ENUM (GSE_0_CONTROL, BIT_WIDTH, NTSC) | /* 429 for NTSC, 432 for PAL */ #endif BCHP_FIELD_DATA (GSE_0_CONTROL, DELAY_COUNT, 66) | /* number of 27 MHz cycles to wait */ BCHP_FIELD_ENUM (GSE_0_CONTROL, PARITY_TYPE, EVEN) | BCHP_FIELD_ENUM (GSE_0_CONTROL, TOP_FLD_PARITY, AUTOMATIC) | BCHP_FIELD_ENUM (GSE_0_CONTROL, BOT_FLD_PARITY, AUTOMATIC) | BCHP_FIELD_ENUM (GSE_0_CONTROL, BYTE_SWAP_656_ANCIL, LITTLE_ENDIAN) | BCHP_FIELD_ENUM (GSE_0_CONTROL, BYTE_SWAP_VIDEO_SAMPLE, LITTLE_ENDIAN) | BCHP_FIELD_ENUM (GSE_0_CONTROL, SHIFT_DIRECTION, LSB2MSB) ); BREG_Write32(GetREG(), BCHP_GSE_0_CONTROL, ulReg); /* top field */ ulReg = 0; ulReg |= ( BCHP_FIELD_DATA (GSE_0_ACTIVE_LINE_TOP, ACTIVE_LINE, p_gs->linemask_top) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_TOP, PED_LINE5, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_TOP, PED_LINE4, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_TOP, PED_LINE3, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_TOP, PED_LINE2, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_TOP, PED_LINE1, DISABLE) | BCHP_FIELD_DATA (GSE_0_ACTIVE_LINE_TOP, BASE, p_gs->baseline_top) ); BREG_Write32(GetREG(), BCHP_GSE_0_ACTIVE_LINE_TOP, ulReg); /* bottom field */ ulReg = 0; ulReg |= ( BCHP_FIELD_DATA (GSE_0_ACTIVE_LINE_BOT, ACTIVE_LINE, p_gs->linemask_bot) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_BOT, PED_LINE5, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_BOT, PED_LINE4, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_BOT, PED_LINE3, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_BOT, PED_LINE2, DISABLE) | BCHP_FIELD_ENUM (GSE_0_ACTIVE_LINE_BOT, PED_LINE1, DISABLE) | BCHP_FIELD_DATA (GSE_0_ACTIVE_LINE_BOT, BASE, p_gs->baseline_bot) ); BREG_Write32(GetREG(), BCHP_GSE_0_ACTIVE_LINE_BOT, ulReg); /* IRE */ ulReg = 0; ulReg |= ( BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE4, IRE_80) | BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE3, IRE_80) | BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE2, IRE_80) | BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE1, IRE_80) ); BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_TOP, ulReg); ulReg = IRE_80; BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_EXT_TOP, ulReg); ulReg = 0; ulReg |= ( BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE4, IRE_80) | BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE3, IRE_80) | BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE2, IRE_80) | BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE1, IRE_80) ); BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_BOT, ulReg); ulReg = IRE_80; BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_EXT_BOT, ulReg); ulReg = 0; ulReg |= ( BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK3, 0) | BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK2, 0) | BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK1, 0) | BCHP_FIELD_DATA (GSE_0_NULL, NULL_ENABLE_BANK0, 0) | BCHP_FIELD_DATA (GSE_0_NULL, CHARACTER, 0x20) ); BREG_Write32(GetREG(), BCHP_GSE_0_NULL, ulReg); /* clear data registers */ for (i = 0; i < 5; i++) { BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK0 + (4 * i), 0); BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK1 + (4 * i), 0); BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK2 + (4 * i), 0); BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK3 + (4 * i), 0); } BDBG_MSG(("%s: leave", __func__)); return 0; } void bapp_gs_status( bapp_gs_t p_gs ) { uint32_t ulVal; BDBG_MSG(("%s: enter", __func__)); BAPP_ASSERT(p_gs); if (!p_gs) { BDBG_ERR(("%s: null point", __func__)); return; } if (!p_gs->enabled) { BDBG_ERR(("%s: not enabled yet", __func__)); return; } ulVal = BREG_Read32(GetREG(), BCHP_GSE_0_STATUS); if (ulVal & BCHP_GSE_0_STATUS_FIFO_OVERFLOW_MASK) { BDBG_ERR(("GSE: FIFO overflow")); } if (ulVal & BCHP_GSE_0_STATUS_FIFO_UNDERFLOW_MASK) { BDBG_ERR(("GSE: FIFO underflow")); } if (ulVal & BCHP_GSE_0_STATUS_BANK3_VIDEO_SAMPLE_DATA_MASK) { BDBG_ERR(("GSE: Bank3 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK2_VIDEO_SAMPLE_DATA_MASK) { BDBG_ERR(("GSE: Bank2 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK1_VIDEO_SAMPLE_DATA_MASK) { BDBG_ERR(("GSE: Bank1 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK0_VIDEO_SAMPLE_DATA_MASK) { BDBG_ERR(("GSE: Bank0 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK3_656_ANCIL_DATA_MASK) { BDBG_ERR(("GSE: 656 Ancillary Bank3 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK2_656_ANCIL_DATA_MASK) { BDBG_ERR(("GSE: 656 Ancillary Bank2 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK1_656_ANCIL_DATA_MASK) { BDBG_ERR(("GSE: 656 Ancillary Bank1 XMIT")); } if (ulVal & BCHP_GSE_0_STATUS_BANK0_656_ANCIL_DATA_MASK) { BDBG_ERR(("GSE: 656 Ancillary Bank0 XMIT")); } BDBG_MSG(("%s: leave", __func__)); } uint32_t bapp_gs_set_scte_127_list(bapp_gs_t p_gs, int count, pscte_127_data line_list[]) { uint32_t ulRegVal, ulReg, status; uint32_t ulReadPointer; uint32_t ulWritePointer; uint32_t bankIndex; int i, j; BDBG_MSG(("%s: enter", __func__)); /* Size check for field data */ if (!p_gs || (0 == count || count > SCTE_127_MAX_GS_DATA)) { BDBG_ERR(("%s: null data pointer", __func__)); return -1; } /* Clear status bits. This one should be called only if FIFO overflow error happens */ status = BREG_Read32(GetREG(), BCHP_GSE_0_STATUS) & ~BCHP_GSE_0_STATUS_reserved0_MASK; BREG_Write32(GetREG(), BCHP_GSE_0_STATUS, status); /* Get FIFO pointers */ ulRegVal = BREG_Read32(GetREG(), BCHP_GSE_0_WRPTR); ulWritePointer = BCHP_GET_FIELD_DATA (ulRegVal, GSE_0_WRPTR, VALUE); bankIndex = ulWritePointer & 0x3; ulRegVal = BREG_Read32(GetREG(), BCHP_GSE_0_RDPTR); ulReadPointer = BCHP_GET_FIELD_DATA (ulRegVal, GSE_0_WRPTR, VALUE); /* Check for FIFO full */ if (((ulReadPointer & 0x3) == bankIndex ) && (ulReadPointer != ulWritePointer) ) { if (status & BCHP_GSE_0_STATUS_FIFO_OVERFLOW_MASK) { BDBG_WRN(("OF (idx=%d,W=%d,R=%d,status=0x%08x)", bankIndex, ulReadPointer, ulWritePointer, status)); return -1; } } /* Handle field misalignment */ if (((bankIndex == 0) || (bankIndex == 2)) && /* top field */ (GS_FIELD_TOP != (!line_list[0]->field_parity))) { BDBG_MSG(("%s: field top misalignment, band=%d", __func__, bankIndex)); bapp_gs_program_null(bankIndex, 1); ++ulWritePointer; ulWritePointer %= 8; bankIndex++; bankIndex %= 4; } else if (((bankIndex == 1) || (bankIndex == 3)) && /* bottom filed */ (GS_FIELD_BOT != (!line_list[0]->field_parity))) { BDBG_MSG(("%s: field bottom misalignment, band=%d", __func__, bankIndex)); bapp_gs_program_null(bankIndex, 1); ++ulWritePointer; ulWritePointer %= 8; bankIndex++; bankIndex %= 4; } bapp_gs_program_null(bankIndex, 0); /* the caller should verify that line offset is valid (10 - 22) */ if (!line_list[0]->field_parity) { p_gs->linemask_top = 0; for (i = 0; i < count; i++) { p_gs->linemask_top |= (1L << (line_list[i]->line_offset - BASE_LINE)); } ulRegVal = p_gs->baseline_top; ulRegVal |= BCHP_FIELD_DATA(GSE_0_ACTIVE_LINE_TOP, ACTIVE_LINE, p_gs->linemask_top); BREG_Write32(GetREG(), BCHP_GSE_0_ACTIVE_LINE_TOP, ulRegVal); /* per CEA 2020 spec */ if (line_list[0]->line_offset >= 13 && line_list[0]->line_offset <20) j = IRE_80; else j = IRE_70; ulRegVal = ( BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE4, j) | BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE3, j) | BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE2, j) | BCHP_FIELD_DATA (GSE_0_GAIN_TOP, LINE1, j) ); BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_TOP, ulRegVal); ulRegVal = j; BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_EXT_TOP, ulRegVal); } else { p_gs->linemask_bot = 0; for (i = 0; i < count; i++) { p_gs->linemask_bot |= (1L << (line_list[i]->line_offset - BASE_LINE)); } ulRegVal = p_gs->baseline_bot; ulRegVal |= BCHP_FIELD_DATA(GSE_0_ACTIVE_LINE_BOT, ACTIVE_LINE, p_gs->linemask_bot); BREG_Write32(GetREG(), BCHP_GSE_0_ACTIVE_LINE_BOT, ulRegVal); /* per CEA 2020 spec */ if (line_list[0]->line_offset >= 13 && line_list[0]->line_offset <20) j = IRE_80; else j = IRE_70; ulRegVal = ( BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE4, j) | BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE3, j) | BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE2, j) | BCHP_FIELD_DATA (GSE_0_GAIN_BOT, LINE1, j) ); BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_BOT, ulRegVal); ulRegVal = j; BREG_Write32(GetREG(), BCHP_GSE_0_GAIN_EXT_BOT, ulRegVal); } /* Decide where to put user's data */ switch (bankIndex) { case 1: ulReg = BCHP_GSE_0_DATA_LINE1_BANK1; break; case 2: ulReg = BCHP_GSE_0_DATA_LINE1_BANK2; break; case 3: ulReg = BCHP_GSE_0_DATA_LINE1_BANK3; break; default: case 0: ulReg = BCHP_GSE_0_DATA_LINE1_BANK0; break; } for (i = 0; i < count; i++) { BREG_Write32(GetREG(), ulReg + (i * 4), line_list[i]->u.tvg2x); } /* Program the write pointer into hardware */ ++ulWritePointer; ulWritePointer %= 8; ulRegVal = BCHP_FIELD_DATA (GSE_0_WRPTR, VALUE, ulWritePointer); BREG_Write32(GetREG(), BCHP_GSE_0_WRPTR, ulRegVal); BDBG_MSG(("%s: leave", __func__)); return 0x0; } bool bapp_gs_reset(bapp_gs_t p_gs) { uint32_t i; BDBG_MSG(("%s: enter", __func__)); /* don't use it */ if (!p_gs) return 0; /* top field */ //BREG_Write32(GetREG(), BCHP_GSE_0_ACTIVE_LINE_TOP, 0); /* bottom field */ //BREG_Write32(GetREG(), BCHP_GSE_0_ACTIVE_LINE_BOT, 0); /* clear data registers */ for (i = 0; i < 5; i++) { BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK0 + (4 * i), 0); BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK1 + (4 * i), 0); BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK2 + (4 * i), 0); BREG_Write32(GetREG(), BCHP_GSE_0_DATA_LINE1_BANK3 + (4 * i), 0); } BDBG_MSG(("%s: leave", __func__)); return 1; }