From 9711b57cc4bd327c2c7ed1777790d39e2cef9c11 Mon Sep 17 00:00:00 2001 From: Joel A Fernandes Date: Tue, 13 Nov 2012 11:41:09 -0500 Subject: [PATCH] Import old working HDMI driver from 3.2 kernel 6a3b828 hdmi: Fix Video port mapping in NXP driver ac8ac07 Replace entire code with version recommended by NXP, add late_initcall to tda988x.c so now we have: OLD: drivers/video/display/nxp NEW: drivers/video/display/nxp-hdmi Signed-off-by: Joel A Fernandes --- drivers/video/nxp/MakeModules | 59 + drivers/video/nxp/Makefile | 204 + .../comps/tmbslHdmiTx/inc/tmbslHdmiTx_types.h | 1804 ++++ .../inc/tmbslHdmiTx_funcMapping.h | 141 + .../tmbslTDA9989/inc/tmbslTDA9989_Functions.h | 3060 +++++++ .../tmbslTDA9989/src/tmbslTDA9989_Edid.c | 1572 ++++ .../tmbslTDA9989/src/tmbslTDA9989_Edid_l.h | 62 + .../tmbslTDA9989/src/tmbslTDA9989_HDCP.c | 655 ++ .../tmbslTDA9989/src/tmbslTDA9989_HDCP_l.h | 72 + .../tmbslTDA9989/src/tmbslTDA9989_InOut.c | 5101 +++++++++++ .../tmbslTDA9989/src/tmbslTDA9989_InOut_l.h | 112 + .../tmbslTDA9989/src/tmbslTDA9989_Misc.c | 2512 ++++++ .../tmbslTDA9989/src/tmbslTDA9989_Misc_l.h | 62 + .../tmbslTDA9989/src/tmbslTDA9989_State.c | 240 + .../tmbslTDA9989/src/tmbslTDA9989_State_l.h | 56 + .../tmbslTDA9989/src/tmbslTDA9989_local.c | 670 ++ .../tmbslTDA9989/src/tmbslTDA9989_local.h | 2056 +++++ .../tmbslTDA9989/src/tmbslTDA9989_local_otp.h | 54 + .../comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_IW.h | 305 + .../comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_Linux.c | 436 + .../comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_cfg.h | 107 + .../docs/02_sw_req_an/tmdlHdmiCEC_API.zip | Bin 0 -> 148480 bytes .../docs/14_user_doc/HDMI_CEC_User_Manual.pdf | Bin 0 -> 171295 bytes .../nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC.h | 46 + .../tmdlHdmiCEC/inc/tmdlHdmiCEC_Functions.h | 3166 +++++++ .../comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h | 1083 +++ .../nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC.c | 7575 +++++++++++++++++ .../comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.c | 280 + .../comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.h | 221 + .../cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c | 570 ++ .../tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_cfg.c | 624 ++ .../nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_IW.h | 290 + .../nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_cfg.h | 298 + .../docs/02_sw_req_an/tmdlHdmiTx_API.zip | Bin 0 -> 131083 bytes .../TRANSMITTER_TDA998X_SW_UM_Devlib.pdf | Bin 0 -> 610544 bytes .../nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx.h | 52 + .../tmdlHdmiTx/inc/tmdlHdmiTx_Functions.h | 1806 ++++ .../comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h | 1066 +++ .../nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx.c | 7166 ++++++++++++++++ .../comps/tmdlHdmiTx/src/tmdlHdmiTx_local.c | 342 + .../comps/tmdlHdmiTx/src/tmdlHdmiTx_local.h | 702 ++ drivers/video/nxp/inc/tmFlags.h | 237 + drivers/video/nxp/inc/tmNxCompId.h | 1743 ++++ drivers/video/nxp/inc/tmNxTypes.h | 366 + drivers/video/nxp/linux_hdmi_release_note.txt | 417 + drivers/video/nxp/tda998x.c | 2307 +++++ drivers/video/nxp/tda998x.h | 143 + drivers/video/nxp/tda998x_cec.c | 2157 +++++ drivers/video/nxp/tda998x_cec.h | 140 + drivers/video/nxp/tda998x_ioctl.h | 1123 +++ drivers/video/nxp/tda998x_version.h | 17 + drivers/video/nxp/test/Makefile | 28 + drivers/video/nxp/test/demo_tda.c | 758 ++ 53 files changed, 54063 insertions(+) create mode 100755 drivers/video/nxp/MakeModules create mode 100755 drivers/video/nxp/Makefile create mode 100755 drivers/video/nxp/comps/tmbslHdmiTx/inc/tmbslHdmiTx_types.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslHdmiTx_funcMapping.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslTDA9989_Functions.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid.c create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid_l.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP.c create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP_l.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut.c create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut_l.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc.c create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc_l.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State.c create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State_l.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.c create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.h create mode 100755 drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local_otp.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_IW.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_Linux.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_cfg.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/docs/02_sw_req_an/tmdlHdmiCEC_API.zip create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/docs/14_user_doc/HDMI_CEC_User_Manual.pdf create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Functions.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_cfg.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_IW.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_cfg.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/docs/02_sw_req_an/tmdlHdmiTx_API.zip create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/docs/14_user_doc/TRANSMITTER_TDA998X_SW_UM_Devlib.pdf create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Functions.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.c create mode 100755 drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.h create mode 100755 drivers/video/nxp/inc/tmFlags.h create mode 100755 drivers/video/nxp/inc/tmNxCompId.h create mode 100755 drivers/video/nxp/inc/tmNxTypes.h create mode 100755 drivers/video/nxp/linux_hdmi_release_note.txt create mode 100755 drivers/video/nxp/tda998x.c create mode 100755 drivers/video/nxp/tda998x.h create mode 100755 drivers/video/nxp/tda998x_cec.c create mode 100755 drivers/video/nxp/tda998x_cec.h create mode 100755 drivers/video/nxp/tda998x_ioctl.h create mode 100755 drivers/video/nxp/tda998x_version.h create mode 100755 drivers/video/nxp/test/Makefile create mode 100755 drivers/video/nxp/test/demo_tda.c diff --git a/drivers/video/nxp/MakeModules b/drivers/video/nxp/MakeModules new file mode 100755 index 0000000000000..fae8495133b07 --- /dev/null +++ b/drivers/video/nxp/MakeModules @@ -0,0 +1,59 @@ +PACKAGE_NAME:=hdmi + +RULES:=compile + +ARCH:=arm +CROSS_COMPILE:=/home/joel/oe-arm-angstrom-linux-gnueabi- +VARS:= ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) +# VARS:= V=1 ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) + +# module to be put in driver/video/hdmi + +LINUX_DIR=/home/joel/work/code/kernel/linux-dvi-audio/git/ +LINUXKERNEL_SRC=$(LINUX_DIR) + +all: $(RULES) + +compile: + @echo "\t-----> $(PACKAGE_NAME):$@" +# @rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.* +# @mv tda998x_version.h temp && cat temp | awk '$$2~"PATCHLEVEL" {$$3=$$3+1};{print};' >tda998x_version.h && rm temp + $(MAKE) -C $(LINUXKERNEL_SRC) M=`pwd` $(VARS) modules +# @touch $@ + +uptx: + adb shell hdmi_off + adb shell rm hdmitx.ko + adb shell rmmod hdmitx + adb push hdmitx.ko hdmitx.ko + adb shell insmod hdmitx.ko verbose=1 + adb shell hdmi_on + +upcec: + adb shell rm hdmicec.ko + adb shell rmmod hdmicec + adb push hdmicec.ko hdmicec.ko + adb shell insmod hdmicec.ko verbose=1 device=4 + +strip: + strip -g -I elf32-little hdmitx.ko -o hdmitx_striped.ko + strip -g -I elf32-little hdmicec.ko -o hdmicec_striped.ko + +clean: + @echo "\t-----> $(PACKAGE_NAME):$@" + @rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.* *.symvers *.order + @if [ -e comps/tmdlHdmiTx/src ]; then cd comps/tmdlHdmiTx/src && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmdlHdmiTx/cfg/TDA9989 ]; then cd comps/tmdlHdmiTx/cfg/TDA9989 && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmdlHdmiCEC/src ]; then cd comps/tmdlHdmiCEC/src && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmdlHdmiCEC/cfg ]; then cd comps/tmdlHdmiCEC/cfg && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmdlTDA9983/src ]; then cd comps/tmdlTDA9983/src && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmdlTDA9983/cfg ]; then cd comps/tmdlTDA9983/cfg && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmbslTDA9989/src ]; then cd comps/tmbslTDA9989/src && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmbslTDA9984NoHdcp/src ]; then cd comps/tmbslTDA9984NoHdcp/src && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + @if [ -e comps/tmbslTDA9983/src ]; then cd comps/tmbslTDA9983/src && rm -rf *.o *.ko *.mod.c .*.cmd .tmp_versions *.c.* *.h.*; fi + + @if [ -e .compiled ]; then rm .compiled; fi + +# install: .install +# .install: +# cp .... diff --git a/drivers/video/nxp/Makefile b/drivers/video/nxp/Makefile new file mode 100755 index 0000000000000..ba2aa5ee985fc --- /dev/null +++ b/drivers/video/nxp/Makefile @@ -0,0 +1,204 @@ + +############### select your chip + platform here ################### + +# TDA_TX := TDA19989 +TDA_TX := TDA19988 +# TDA_TX := TDA9984 +# TDA_TX := TDA9983 +# TDA_TX := TDA9981 + +TDA_PLATFORM := ZOOMII +# TDA_PLATFORM := OTHERS + +############### features on demand ################################# + +#TDA_HDCP := 0 +TDA_HDCP := TMFL_HDCP_SUPPORT +TDA_CEC := TDA9950 + +# add this if INTERRUPT is wired, otherwise polling with timer is used +#EXTRA_CFLAGS += -DIRQ + +# add this to get PC video format +# EXTRA_CFLAGS += -DFORMAT_PC + +# add this to disable automatic set of input/output video resolution +# EXTRA_CFLAGS += -DUSER_SET_INPUT_OUTPUT + +#################################################################### + +EXTRA_CFLAGS += -DFUNC_PTR=" " -DCONST_DAT="const " -DRAM_DAT=" " +EXTRA_CFLAGS += -DTDA_NAME=$(TDA_TX) +EXTRA_CFLAGS += -DTMFL_LINUX_OS_KERNEL_DRIVER +EXTRA_CFLAGS += -DTMFL_NO_RTOS +# EXTRA_CFLAGS += -DI2C_DBG + +ifeq ($(TDA_PLATFORM),ZOOMII) +EXTRA_CFLAGS += -DTMFL_CFG_ZOOMII +EXTRA_CFLAGS += -DZOOMII_PATCH +EXTRA_CFLAGS += -DTWL4030_HACK +# EXTRA_CFLAGS += -DANDROID_DSS +EXTRA_CFLAGS += -DGUI_OVER_HDMI +endif + +ifeq ($(TDA_TX),TDA19988) +EXTRA_CFLAGS += -DTMFL_TDA19988 +TDA_TX := TDA19989 +endif + +ifeq ($(TDA_TX),TDA19989) +EXTRA_CFLAGS += -DTMFL_TDA19989 -DTMFL_TDA9989 +ifeq ($(TDA_HDCP),TMFL_HDCP_SUPPORT) +EXTRA_CFLAGS += -D$(TDA_HDCP) +else +EXTRA_CFLAGS += -DNO_HDCP +endif +endif + +ifeq ($(TDA_TX),TDA9984) +EXTRA_CFLAGS += -DNO_HDCP +endif + +ifeq ($(TDA_TX),TDA9981) +EXTRA_CFLAGS += -DTMFL_TDA9981_SUPPORT -DTMFL_RX_SENSE_ON +endif + +########## devlib ################################################## + +ifeq ($(TDA_TX),TDA19989) +TXSRC := comps/tmdlHdmiTx/src +TXCFG := comps/tmdlHdmiTx/cfg/TDA9989 +CECSRC := comps/tmdlHdmiCEC/src +CECCFG := comps/tmdlHdmiCEC/cfg +endif + +ifeq ($(TDA_TX),TDA9984) +TXSRC := comps/tmdlHdmiTx/src +TXCFG := comps/tmdlHdmiTx/cfg/TDA9989 +endif + +ifeq ($(TDA_TX),TDA9983) +TXSRC := comps/tmdlTDA9983/src +TXCFG := comps/tmdlTDA9983/cfg +endif + +ifeq ($(TDA_TX),TDA9981) +TXSRC := comps/tmdlTDA9983/src +TXCFG := comps/tmdlTDA9983/cfg +endif + +########## board service layer ##################################### + +ifeq ($(TDA_TX),TDA19989) +BSL := comps/tmbslTDA9989/src +endif + +ifeq ($(TDA_TX),TDA9984) +BSL := comps/tmbslTDA9984NoHdcp/src +endif + +ifeq ($(TDA_TX),TDA9983) +BSL := comps/tmbslTDA9983/src +endif + +ifeq ($(TDA_TX),TDA9981) +BSL := comps/tmbslTDA9983/src +endif + +#################################################################### + +obj-y += hdmitx.o +ifeq ($(TDA_CEC),TDA9950) +obj-m += hdmicec.o +endif + +# Linux module +hdmitx-objs := tda998x.o +hdmicec-objs := tda998x_cec.o + +# NXP comps +ifeq ($(TDA_TX),TDA19989) +hdmitx-objs += $(TXSRC)/tmdlHdmiTx.o +hdmitx-objs += $(TXSRC)/tmdlHdmiTx_local.o +hdmitx-objs += $(TXCFG)/tmdlHdmiTx_cfg.o +hdmitx-objs += $(BSL)/tmbslTDA9989_local.o +hdmitx-objs += $(BSL)/tmbslTDA9989_InOut.o +hdmitx-objs += $(BSL)/tmbslTDA9989_HDCP.o +hdmitx-objs += $(BSL)/tmbslTDA9989_State.o +hdmitx-objs += $(BSL)/tmbslTDA9989_Misc.o +hdmitx-objs += $(BSL)/tmbslTDA9989_Edid.o +hdmicec-objs += $(CECSRC)/tmdlHdmiCEC.o +hdmicec-objs += $(CECSRC)/tmdlHdmiCEC_local.o +hdmicec-objs += $(CECCFG)/tmdlHdmiCEC_Linux.o +endif + +ifeq ($(TDA_TX),TDA9984) +hdmitx-objs += $(TXSRC)/tmdlHdmiTx.o +hdmitx-objs += $(TXSRC)/tmdlHdmiTx_local.o +hdmitx-objs += $(TXCFG)/tmdlHdmiTx_Linux.o +hdmitx-objs += $(BSL)/tmbslTDA9984_local.o +hdmitx-objs += $(BSL)/tmbslTDA9984_InOut.o +hdmitx-objs += $(BSL)/tmbslTDA9984_HDCP.o +hdmitx-objs += $(BSL)/tmbslTDA9984_State.o +hdmitx-objs += $(BSL)/tmbslTDA9984_Misc.o +hdmitx-objs += $(BSL)/tmbslTDA9984_Edid.o +endif + +ifeq ($(TDA_TX),TDA9983) +hdmitx-objs += $(BSL)/tmbslHdmiTx_2.o +hdmitx-objs += $(BSL)/tmbslHdmiTx_1.o +hdmitx-objs += $(BSL)/tmbslHdmiTx_local.o +hdmitx-objs += $(TXSRC)/tmdlHdmiTx.o +hdmitx-objs += $(TXCFG)/tmdlHdmiTx_Linux.o +endif + +ifeq ($(TDA_TX),TDA9981) +hdmitx-objs += $(BSL)/tmbslHdmiTx_2.o +hdmitx-objs += $(BSL)/tmbslHdmiTx_1.o +hdmitx-objs += $(BSL)/tmbslHdmiTx_local.o +hdmitx-objs += $(TXSRC)/tmdlHdmiTx.o +hdmitx-objs += $(TXCFG)/tmdlHdmiTx_Linux.o +endif + +#################################################################### + +EXTRA_CFLAGS += -I$(obj) +EXTRA_CFLAGS += -I$(obj)/inc + +ifeq ($(TDA_TX),TDA19989) +EXTRA_CFLAGS += -I$(obj)/comps/tmbslHdmiTx/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiTx/src +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiTx/cfg +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiTx/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmbslTDA9989/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmbslTDA9989/src +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiCEC/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiCEC/src +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiCEC/cfg +endif + +ifeq ($(TDA_TX),TDA9984) +EXTRA_CFLAGS += -I$(obj)/comps/tmbslHdmiTx/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiTx/src +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiTx/cfg +EXTRA_CFLAGS += -I$(obj)/comps/tmdlHdmiTx/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmbslTDA9984NoHdcp/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmbslTDA9984NoHdcp/src +endif + +ifeq ($(TDA_TX),TDA9983) +EXTRA_CFLAGS += -I$(obj)/comps/tmbslTDA9983/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlTDA9983/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlTDA9983/src +EXTRA_CFLAGS += -I$(obj)/comps/tmdlTDA9983/cfg +endif + +ifeq ($(TDA_TX),TDA9981) +EXTRA_CFLAGS += -I$(obj)/comps/tmbslTDA9983/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlTDA9983/inc +EXTRA_CFLAGS += -I$(obj)/comps/tmdlTDA9983/src +EXTRA_CFLAGS += -I$(obj)/comps/tmdlTDA9983/cfg +endif + + + diff --git a/drivers/video/nxp/comps/tmbslHdmiTx/inc/tmbslHdmiTx_types.h b/drivers/video/nxp/comps/tmbslHdmiTx/inc/tmbslHdmiTx_types.h new file mode 100755 index 0000000000000..a15170c563693 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslHdmiTx/inc/tmbslHdmiTx_types.h @@ -0,0 +1,1804 @@ +/** + * Copyright (C) 2007 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslHdmiTx_types.h + * + * \version $Revision: 18 $ + * + * \date $Date: 17/03/08 $ + * + * \brief HDMI Transmitter common types + * + * \section refs Reference Documents + * + * \section info Change Information + * + * \verbatim + + $History: tmbslHdmiTx_types.h $ + * + * + * **************** Version 18 ****************** + * User: G.Burnouf Date: 01/04/08 + * Updated in $/Source/tmbslHdmiTx/inc + * PR1468 : add new function tmbslTDA9984GetSinkCategory + * + * + * **************** Version 17 ****************** + * User: G.Burnouf Date: 17/03/08 + * Updated in $/Source/tmbslHdmiTx/inc + * PR1430 : Increase size of table for + * Short Audio Descriptor + * + * **************** Version 16 ****************** + * User: G.Burnouf Date: 06/03/08 + * Updated in $/Source/tmbslHdmiTx/inc + * PR1406 : new reset audio fifo sequence + * + * **************** Version 15 ****************** + * User: G.Burnouf Date: 05/02/08 + * Updated in $/Source/tmbslHdmiTx/inc + * PR1251 : add new type for function + * tmbslTDA9984EdidGetBasicDisplayParam + * + ****************** Version 14 ****************** + * User: G.Burnouf Date: 14/01/08 + * Updated in $/Source/tmbslHdmiTx/inc + * PR580 - Change BSL error base address + * + ****************** Version 13 ****************** + * User: G.Burnouf Date: 10/01/08 + * Updated in $/Source/tmbslHdmiTx/inc + * PR606 - Apply audio port config in function + * of audio format + * + * **************** Version 12 ****************** + * User: G.Burnouf Date: 10/12/07 Time: 08:30 + * Updated in $/Source/tmbslHdmiTx/inc + * PR1145 : return DTD and monitor description + * + * ***************** Version 11 ***************** + * User: G.Burnouf Date: 04/12/07 + * Updated in $/Source/tmbslHdmiTx/inc + * PR948 : add new formats, 1080p24/25/30 + * + * ***************** Version 10 ***************** + * User: C. Diehl Date: 27/11/07 + * Updated in $/Source/tmbslHdmiTx/inc + * PR1030 : - Align with the common interface + * reworked for the LIPP4200 + * + * ***************** Version 9 ***************** + * User: J.Lamotte Date: 23/11/07 Time: 09:35 + * Updated in $/Source/tmbslHdmiTx/src + * PR1078 : - update HDMI_TX_SVD_MAX_CNT from 30 + * to 113 + * + * ***************** Version 8 ***************** + * User: G.Burnouf Date: 13/11/07 Time: 09:29 + * Updated in $/Source/tmbslHdmiTx/src + * PR1008 : - update type tmbslHdmiTxHwFeature_t + * + * ***************** Version 7 ***************** + * User: G.Burnouf Date: 16/10/07 Time: 14:32 + * Updated in $/Source/tmbslHdmiTx/src + * PR882 : - add type tmbslHdmiTxPowerState_t + * - add type tmbslHdmiTxPktGmt_t for gamut + * - add new interrupt callback for VS + * + * ***************** Version 6 ***************** + * User: G.Burnouf Date: 05/10/07 Time: 14:32 + * Updated in $/Source/tmbslHdmiTx/src + * PR824 : add type for enum _tmbslHdmiTxCallbackInt + * + * ***************** Version 5 ***************** + * User: J.Turpin Date: 13/09/07 Time: 14:32 + * Updated in $/Source/tmbslHdmiTx/src + * PR693 : add black pattern functionality + * - add HDMITX_PATTERN_BLACK in + * enum tmbslHdmiTxTestPattern_t + * + * ***************** Version 4 ***************** + * User: G.Burnouf Date: 06/09/07 Time: 17:22 + * Updated in $/Source/tmbslTDA9984/Inc + * PR656 : - add HBR format + * - add format I2s Philips left and right justified + * + * ***************** Version 3 ***************** + * User: G. Burnouf Date: 07/08/07 Time: 10:30 + * Updated in $/Source/tmbslTDA9984/Inc + * PR572 - change type name of tmbslTDA9984_ to tmbslHdmiTx_ + * + * ***************** Version 2 ***************** + * User: B.Vereecke Date: 07/08/07 Time: 10:30 + * Updated in $/Source/tmbslTDA9984/Inc + * PR551 - Add a new Pattern type in tmbslHdmiTxTestPattern_t + * it is used for set the bluescreen + * + * ***************** Version 1 ***************** + * User: G. Burnouf Date: 05/07/07 Time: 17:00 + * Updated in $/Source/tmbslTDA9984/Inc + * PR 414 : Add new edid management + * + \endverbatim + * +*/ + +#ifndef TMBSLHDMITX_TYPES_H +#define TMBSLHDMITX_TYPES_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmNxCompId.h" + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + +/** + * The maximum number of supported HDMI Transmitter units + */ +#define HDMITX_UNITS_MAX 2 + +/** \name Errors + * The group of error codes returned by all API and internal functions + */ +/*@{*/ +/** The base offset for all error codes. + * This needs defining as non-zero if this component is integrated with others + * and all component error ranges are to be kept separate. + */ +#define TMBSL_ERR_HDMI_BASE CID_BSL_HDMITX + +/** Define the OK code if not defined already */ +#ifndef TM_OK +#define TM_OK 0 +#endif + +/** SW interface compatibility error */ +#define TMBSL_ERR_HDMI_COMPATIBILITY (TMBSL_ERR_HDMI_BASE + 0x001U) + +/** SW major version error */ +#define TMBSL_ERR_HDMI_MAJOR_VERSION (TMBSL_ERR_HDMI_BASE + 0x002U) + +/** SW component version error */ +#define TMBSL_ERR_HDMI_COMP_VERSION (TMBSL_ERR_HDMI_BASE + 0x003U) + +/** Invalid device unit number */ +#define TMBSL_ERR_HDMI_BAD_UNIT_NUMBER (TMBSL_ERR_HDMI_BASE + 0x005U) + +/** Invalid input parameter other than unit number */ +#define TMBSL_ERR_HDMI_BAD_PARAMETER (TMBSL_ERR_HDMI_BASE + 0x009U) + +/* Ressource not available */ +#define TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE (TMBSL_ERR_HDMI_BASE + 0x00CU) + +/** Inconsistent input parameters */ +#define TMBSL_ERR_HDMI_INCONSISTENT_PARAMS (TMBSL_ERR_HDMI_BASE + 0x010U) + +/** Component is not initialized */ +#define TMBSL_ERR_HDMI_NOT_INITIALIZED (TMBSL_ERR_HDMI_BASE + 0x011U) + +/** Command not supported for current device */ +#define TMBSL_ERR_HDMI_NOT_SUPPORTED (TMBSL_ERR_HDMI_BASE + 0x013U) + +/** Initialization failed */ +#define TMBSL_ERR_HDMI_INIT_FAILED (TMBSL_ERR_HDMI_BASE + 0x014U) + +/** Component is busy and cannot do a new operation */ +#define TMBSL_ERR_HDMI_BUSY (TMBSL_ERR_HDMI_BASE + 0x015U) + +/** I2C read error */ +#define TMBSL_ERR_HDMI_I2C_READ (TMBSL_ERR_HDMI_BASE + 0x017U) + +/** I2C write error */ +#define TMBSL_ERR_HDMI_I2C_WRITE (TMBSL_ERR_HDMI_BASE + 0x018U) + +/** Assertion failure */ +#define TMBSL_ERR_HDMI_ASSERTION (TMBSL_ERR_HDMI_BASE + 0x049U) + +/** Bad EDID block checksum */ +#define TMBSL_ERR_HDMI_INVALID_STATE (TMBSL_ERR_HDMI_BASE + 0x066U) +#define TMBSL_ERR_HDMI_INVALID_CHECKSUM TMBSL_ERR_HDMI_INVALID_STATE + +/** No connection to HPD pin */ +#define TMBSL_ERR_HDMI_NULL_CONNECTION (TMBSL_ERR_HDMI_BASE + 0x067U) + +/** Not allowed in DVI mode */ +#define TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED (TMBSL_ERR_HDMI_BASE + 0x068U) + +/** Maximum error code defined */ +#define TMBSL_ERR_HDMI_MAX TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED + +/*============================================================================*/ + +#define HDMITX_ENABLE_VP_TABLE_LEN 3 +#define HDMITX_GROUND_VP_TABLE_LEN 3 + +/** EDID block size */ +#define EDID_BLOCK_SIZE 128 + +/** size descriptor block of monitor descriptor */ +#define EDID_MONITOR_DESCRIPTOR_SIZE 13 + +/*@}*/ + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +/** +* \brief TX IP/IC versions +*/ +typedef enum +{ + BSLHDMITX_UNKNOWN = 0x00, /**< IC/IP is not recognized */ + BSLHDMITX_TDA9984, /**< IC is a TDA9984 */ + BSLHDMITX_TDA9989, /**< IC is a TDA9989 (TDA9989N2 64 balls) */ + BSLHDMITX_TDA9981, /**< IC is a TDA9981 */ + BSLHDMITX_TDA9983, /**< IC is a TDA9983 */ + BSLHDMITX_TDA19989, /**< IC is a TDA19989 */ + BSLHDMITX_TDA19988, /**< ok, u got it, it's a 19988 :p */ +} tmbslHdmiTxVersion_t; + + +/** + * \brief System function pointer type, to call user I2C read/write functions + * \param slaveAddr The I2C slave address + * \param firstRegister The first device register address to read or write + * \param lenData Length of data to read or write (i.e. no. of registers) + * \param pData Pointer to data to write, or to buffer to receive data + * \return The call result: + * - TM_OK: the call was successful + * - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing + * - TMBSL_ERR_HDMI_I2C_READ: failed when reading + */ +typedef struct _tmbslHdmiTxSysArgs_t +{ + UInt8 slaveAddr; + UInt8 firstRegister; + UInt8 lenData; + UInt8 *pData; +} tmbslHdmiTxSysArgs_t; +typedef tmErrorCode_t (FUNC_PTR * ptmbslHdmiTxSysFunc_t) + (tmbslHdmiTxSysArgs_t *pSysArgs); + +/** + * \brief System function pointer type, to call user I2C EDID read function + * \param segPtrAddr The EDID segment pointer address 0 to 7Fh + * \param segPtr The EDID segment pointer 0 to 7Fh + * \param dataRegAddr The EDID data register address 0 to 7Fh + * \param wordOffset The first word offset 0 to FFh to read + * \param lenData Length of data to read (i.e. number of registers), + 1 to max starting at wordOffset + * \param pData Pointer to buffer to receive lenData data bytes + * \return The call result: + * - TM_OK: the call was successful + * - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing + * - TMBSL_ERR_HDMI_I2C_READ: failed when reading + */ +typedef struct _tmbslHdmiTxSysArgsEdid_t +{ + UInt8 segPtrAddr; + UInt8 segPtr; + UInt8 dataRegAddr; + UInt8 wordOffset; + UInt8 lenData; + UInt8 *pData; +} tmbslHdmiTxSysArgsEdid_t; + + +/** + * \brief EDID function pointer type, to call application EDID read function + * \param pSysArgs pointer to the structure containing necessary information to read EDID + */ +typedef tmErrorCode_t (FUNC_PTR * ptmbslHdmiTxSysFuncEdid_t) + (tmbslHdmiTxSysArgsEdid_t *pSysArgs); + +/** + * \brief Timer function pointer type, to call an application timer + * \param ms delay in milliseconds + */ +typedef Void (FUNC_PTR * ptmbslHdmiTxSysFuncTimer_t) (UInt16 ms); + +/*============================================================================*/ +/** + * \brief Callback function pointer type, to call a user interrupt handler + * \param txUnit: The transmitter unit that interrupted, 0 to max + */ +typedef Void (FUNC_PTR * ptmbslHdmiTxCallback_t) (tmUnitSelect_t txUnit); + +/*============================================================================*/ +/** + * EIA/CEA-861B video format type + */ +typedef enum +{ + HDMITX_VFMT_NULL = 0, /**< Not a valid format... */ + HDMITX_VFMT_NO_CHANGE = 0, /**< ...or no change required */ + HDMITX_VFMT_TV_MIN = 1, /**< Lowest valid TV format */ + HDMITX_VFMT_01_640x480p_60Hz = 1, /**< Format 01 640 x 480p 60Hz */ + HDMITX_VFMT_02_720x480p_60Hz = 2, /**< Format 02 720 x 480p 60Hz */ + HDMITX_VFMT_03_720x480p_60Hz = 3, /**< Format 03 720 x 480p 60Hz */ + HDMITX_VFMT_04_1280x720p_60Hz = 4, /**< Format 04 1280 x 720p 60Hz */ + HDMITX_VFMT_05_1920x1080i_60Hz = 5, /**< Format 05 1920 x 1080i 60Hz */ + HDMITX_VFMT_06_720x480i_60Hz = 6, /**< Format 06 720 x 480i 60Hz */ + HDMITX_VFMT_07_720x480i_60Hz = 7, /**< Format 07 720 x 480i 60Hz */ + HDMITX_VFMT_08_720x240p_60Hz = 8, /**< Format 08 720 x 240p 60Hz */ + HDMITX_VFMT_09_720x240p_60Hz = 9, /**< Format 09 720 x 240p 60Hz */ + HDMITX_VFMT_10_720x480i_60Hz = 10, /**< Format 10 720 x 480i 60Hz */ + HDMITX_VFMT_11_720x480i_60Hz = 11, /**< Format 11 720 x 480i 60Hz */ + HDMITX_VFMT_12_720x240p_60Hz = 12, /**< Format 12 720 x 240p 60Hz */ + HDMITX_VFMT_13_720x240p_60Hz = 13, /**< Format 13 720 x 240p 60Hz */ + HDMITX_VFMT_14_1440x480p_60Hz = 14, /**< Format 14 1440 x 480p 60Hz */ + HDMITX_VFMT_15_1440x480p_60Hz = 15, /**< Format 15 1440 x 480p 60Hz */ + HDMITX_VFMT_16_1920x1080p_60Hz = 16, /**< Format 16 1920 x 1080p 60Hz */ + HDMITX_VFMT_17_720x576p_50Hz = 17, /**< Format 17 720 x 576p 50Hz */ + HDMITX_VFMT_18_720x576p_50Hz = 18, /**< Format 18 720 x 576p 50Hz */ + HDMITX_VFMT_19_1280x720p_50Hz = 19, /**< Format 19 1280 x 720p 50Hz */ + HDMITX_VFMT_20_1920x1080i_50Hz = 20, /**< Format 20 1920 x 1080i 50Hz */ + HDMITX_VFMT_21_720x576i_50Hz = 21, /**< Format 21 720 x 576i 50Hz */ + HDMITX_VFMT_22_720x576i_50Hz = 22, /**< Format 22 720 x 576i 50Hz */ + HDMITX_VFMT_23_720x288p_50Hz = 23, /**< Format 23 720 x 288p 50Hz */ + HDMITX_VFMT_24_720x288p_50Hz = 24, /**< Format 24 720 x 288p 50Hz */ + HDMITX_VFMT_25_720x576i_50Hz = 25, /**< Format 25 720 x 576i 50Hz */ + HDMITX_VFMT_26_720x576i_50Hz = 26, /**< Format 26 720 x 576i 50Hz */ + HDMITX_VFMT_27_720x288p_50Hz = 27, /**< Format 27 720 x 288p 50Hz */ + HDMITX_VFMT_28_720x288p_50Hz = 28, /**< Format 28 720 x 288p 50Hz */ + HDMITX_VFMT_29_1440x576p_50Hz = 29, /**< Format 29 1440 x 576p 50Hz */ + HDMITX_VFMT_30_1440x576p_50Hz = 30, /**< Format 30 1440 x 576p 50Hz */ + HDMITX_VFMT_31_1920x1080p_50Hz = 31, /**< Format 31 1920 x 1080p 50Hz */ + HDMITX_VFMT_32_1920x1080p_24Hz = 32, /**< Format 32 1920 x 1080p 24Hz */ + + HDMITX_VFMT_TV_NO_REG_MIN = 32, /**< Lowest TV format without prefetched table */ + + HDMITX_VFMT_33_1920x1080p_25Hz = 33, /**< Format 33 1920 x 1080p 25Hz */ + HDMITX_VFMT_34_1920x1080p_30Hz = 34, /**< Format 34 1920 x 1080p 30Hz */ + HDMITX_VFMT_35_2880x480p_60Hz = 35, /**< Format 35 2880 x 480p 60Hz 4:3 */ + HDMITX_VFMT_36_2880x480p_60Hz = 36, /**< Format 36 2880 x 480p 60Hz 16:9 */ + HDMITX_VFMT_37_2880x576p_50Hz = 37, /**< Format 37 2880 x 576p 50Hz 4:3 */ + HDMITX_VFMT_38_2880x576p_50Hz = 38, /**< Format 38 2880 x 576p 50Hz 16:9 */ + + HDMITX_VFMT_INDEX_60_1280x720p_24Hz = 39,/**< Index of HDMITX_VFMT_60_1280x720p_24Hz */ + HDMITX_VFMT_60_1280x720p_24Hz = 60, /**< Format 60 1280 x 720p 23.97/24Hz 16:9 */ + HDMITX_VFMT_61_1280x720p_25Hz = 61, /**< Format 61 1280 x 720p 25Hz 16:9 */ + HDMITX_VFMT_62_1280x720p_30Hz = 62, /**< Format 60 1280 x 720p 29.97/30Hz 16:9 */ + + HDMITX_VFMT_TV_MAX = 62, /**< Highest valid TV format value */ + HDMITX_VFMT_TV_NUM = 42, /**< Number of TV formats + null, it is also the Index of PC_MIN */ + + HDMITX_VFMT_PC_MIN = 128, /**< Lowest valid PC format */ + HDMITX_VFMT_PC_640x480p_60Hz = 128, /**< PC format 128 */ + HDMITX_VFMT_PC_800x600p_60Hz = 129, /**< PC format 129 */ + HDMITX_VFMT_PC_1152x960p_60Hz = 130, /**< PC format 130 */ + HDMITX_VFMT_PC_1024x768p_60Hz = 131, /**< PC format 131 */ + HDMITX_VFMT_PC_1280x768p_60Hz = 132, /**< PC format 132 */ + HDMITX_VFMT_PC_1280x1024p_60Hz = 133, /**< PC format 133 */ + HDMITX_VFMT_PC_1360x768p_60Hz = 134, /**< PC format 134 */ + HDMITX_VFMT_PC_1400x1050p_60Hz = 135, /**< PC format 135 */ + HDMITX_VFMT_PC_1600x1200p_60Hz = 136, /**< PC format 136 */ + HDMITX_VFMT_PC_1024x768p_70Hz = 137, /**< PC format 137 */ + HDMITX_VFMT_PC_640x480p_72Hz = 138, /**< PC format 138 */ + HDMITX_VFMT_PC_800x600p_72Hz = 139, /**< PC format 139 */ + HDMITX_VFMT_PC_640x480p_75Hz = 140, /**< PC format 140 */ + HDMITX_VFMT_PC_1024x768p_75Hz = 141, /**< PC format 141 */ + HDMITX_VFMT_PC_800x600p_75Hz = 142, /**< PC format 142 */ + HDMITX_VFMT_PC_1024x864p_75Hz = 143, /**< PC format 143 */ + HDMITX_VFMT_PC_1280x1024p_75Hz = 144, /**< PC format 144 */ + HDMITX_VFMT_PC_640x350p_85Hz = 145, /**< PC format 145 */ + HDMITX_VFMT_PC_640x400p_85Hz = 146, /**< PC format 146 */ + HDMITX_VFMT_PC_720x400p_85Hz = 147, /**< PC format 147 */ + HDMITX_VFMT_PC_640x480p_85Hz = 148, /**< PC format 148 */ + HDMITX_VFMT_PC_800x600p_85Hz = 149, /**< PC format 149 */ + HDMITX_VFMT_PC_1024x768p_85Hz = 150, /**< PC format 150 */ + HDMITX_VFMT_PC_1152x864p_85Hz = 151, /**< PC format 151 */ + HDMITX_VFMT_PC_1280x960p_85Hz = 152, /**< PC format 152 */ + HDMITX_VFMT_PC_1280x1024p_85Hz = 153, /**< PC format 153 */ + HDMITX_VFMT_PC_1024x768i_87Hz = 154, /**< PC format 154 */ + HDMITX_VFMT_PC_MAX = 154, /**< Highest valid PC format */ + HDMITX_VFMT_PC_NUM = (1+154-128) /**< Number of PC formats */ +} tmbslHdmiTxVidFmt_t; + +/*============================================================================*/ +/** + * tmbslTDA9984AudioInSetConfig() parameter types + */ +/** Audio input formats */ +typedef enum +{ + HDMITX_AFMT_SPDIF = 0, /**< SPDIF */ + HDMITX_AFMT_I2S = 1, /**< I2S */ + HDMITX_AFMT_OBA = 2, /**< One bit audio / DSD */ + HDMITX_AFMT_DST = 3, /**< DST */ + HDMITX_AFMT_HBR = 4, /**< HBR */ + HDMITX_AFMT_NUM = 5, /**< Number of Audio input format */ + HDMITX_AFMT_INVALID = 5 /**< Invalid format */ +} tmbslHdmiTxaFmt_t; + +/** I2s formats */ +typedef enum +{ + HDMITX_I2SFOR_PHILIPS_L = 0, /**< Philips like format */ + HDMITX_I2SFOR_OTH_L = 2, /**< Other non Philips left justified */ + HDMITX_I2SFOR_OTH_R = 3, /**< Other non Philips right justified */ + HDMITX_I2SFOR_INVALID = 4 /**< Invalid format*/ +} tmbslHdmiTxI2sFor_t; + +/** DSD clock polarities */ +typedef enum +{ + HDMITX_CLKPOLDSD_ACLK = 0, /**< Same as ACLK */ + HDMITX_CLKPOLDSD_NACLK = 1, /**< Not ACLK, i.e. inverted */ + HDMITX_CLKPOLDSD_NO_CHANGE = 2, /**< No change */ + HDMITX_CLKPOLDSD_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxClkPolDsd_t; + +/** DSD data swap values */ +typedef enum +{ + HDMITX_SWAPDSD_OFF = 0, /**< No swap */ + HDMITX_SWAPDSD_ON = 1, /**< Swap */ + HDMITX_SWAPDSD_NO_CHANGE = 2, /**< No change */ + HDMITX_SWAPDSD_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxSwapDsd_t; + +/** DST data transfer rates */ +typedef enum +{ + HDMITX_DSTRATE_SINGLE = 0, /**< Single transfer rate */ + HDMITX_DSTRATE_DOUBLE = 1, /**< Double data rate */ + HDMITX_DSTRATE_NO_CHANGE = 2, /**< No change */ + HDMITX_DSTRATE_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxDstRate_t; + +/** I2S, SPDIF and DSD channel allocation values */ +enum _tmbslHdmiTxChan +{ + HDMITX_CHAN_MIN = 0, + HDMITX_CHAN_MAX = 31, + HDMITX_CHAN_NO_CHANGE = 32, + HDMITX_CHAN_INVALID = 33 +}; + +/** Audio layout values */ +enum _tmbslHdmiTxLayout +{ + HDMITX_LAYOUT_MIN = 0, + HDMITX_LAYOUT_MAX = 1, + HDMITX_LAYOUT_NO_CHANGE = 2, + HDMITX_LAYOUT_INVALID = 3 +}; + +/** Audio FIFO read latency values */ +enum _tmbslHdmiTxlatency_rd +{ + HDMITX_LATENCY_MIN = 0x000, + HDMITX_LATENCY_CURRENT = 0x080, + HDMITX_LATENCY_MAX = 0x0FF, + HDMITX_LATENCY_NO_CHANGE = 0x100, + HDMITX_LATENCY_INVALID = 0x101 +}; + +/*============================================================================*/ +/** + * tmbslTDA9984AudioInSetCts() parameter types + */ +/** Clock Time Stamp reference source */ +typedef enum +{ + HDMITX_CTSREF_ACLK = 0, /**< Clock input pin for I2S */ + HDMITX_CTSREF_MCLK = 1, /**< Clock input pin for EXTREF */ + HDMITX_CTSREF_FS64SPDIF = 2, /**< 64xsample rate, for SPDIF */ + HDMITX_CTSREF_INVALID = 3 /**< Invalid value */ +} tmbslHdmiTxctsRef_t; + +/** Audio sample rate kHz indexes */ +typedef enum +{ + HDMITX_AFS_32k = 0, /**< 32kHz */ + HDMITX_AFS_44_1k = 1, /**< 44.1kHz */ + HDMITX_AFS_48K = 2, /**< 48kHz */ + HDMITX_AFS_88_2K = 3, /**< 88.2kHz */ + HDMITX_AFS_96K = 4, /**< 96kHz */ + HDMITX_AFS_176_4K = 5, /**< 176.4kHz */ + HDMITX_AFS_192K = 6, /**< 192kHz */ + HDMITX_AFS_768K = 7, /**< 768kHz */ + HDMITX_AFS_NOT_INDICATED = 8, /**< Not Indicated (Channel Status) */ + HDMITX_AFS_INVALID = 8, /**< Invalid */ + HDMITX_AFS_NUM = 8 /**< # rates */ +} tmbslHdmiTxafs_t; + +/** Vertical output frequencies */ +typedef enum +{ + HDMITX_VFREQ_24Hz = 0, /**< 24Hz */ + HDMITX_VFREQ_25Hz = 1, /**< 25Hz */ + HDMITX_VFREQ_30Hz = 2, /**< 30Hz */ + HDMITX_VFREQ_50Hz = 3, /**< 50Hz */ + HDMITX_VFREQ_59Hz = 4, /**< 59.94Hz */ + HDMITX_VFREQ_60Hz = 5, /**< 60Hz */ +#ifndef FORMAT_PC + HDMITX_VFREQ_INVALID = 6, /**< Invalid */ + HDMITX_VFREQ_NUM = 6 /**< No. of values */ +#else /* FORMAT_PC */ + HDMITX_VFREQ_70Hz = 6, /**< 70Hz */ + HDMITX_VFREQ_72Hz = 7, /**< 72Hz */ + HDMITX_VFREQ_75Hz = 8, /**< 75Hz */ + HDMITX_VFREQ_85Hz = 9, /**< 85Hz */ + HDMITX_VFREQ_87Hz = 10, /**< 87Hz */ + HDMITX_VFREQ_INVALID = 11, /**< Invalid */ + HDMITX_VFREQ_NUM = 11 /**< No. of values */ +#endif /* FORMAT_PC */ +} tmbslHdmiTxVfreq_t; + +/** Clock Time Stamp predivider - scales N */ +typedef enum +{ + HDMITX_CTSK1 = 0, /**< k=1 */ + HDMITX_CTSK2 = 1, /**< k=2 */ + HDMITX_CTSK3 = 2, /**< k=3 */ + HDMITX_CTSK4 = 3, /**< k=4 */ + HDMITX_CTSK8 = 4, /**< k=8 */ + HDMITX_CTSK_USE_CTSX = 5, /**< Calculate from ctsX factor */ + HDMITX_CTSK_INVALID = 6 /**< Invalid */ +} tmbslHdmiTxctsK_t; + +/** Clock Time Stamp postdivider measured time stamp */ +typedef enum +{ + HDMITX_CTSMTS = 0, /**< =mts */ + HDMITX_CTSMTS2 = 1, /**< =mts%2 */ + HDMITX_CTSMTS4 = 2, /**< =mts%4 */ + HDMITX_CTSMTS8 = 3, /**< =mts%8 */ + HDMITX_CTSMTS_USE_CTSX = 4, /**< Calculate from ctsX factor */ + HDMITX_CTSMTS_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxctsM_t; + +/** Cycle Time Stamp values */ +enum _tmbslHdmiTxCts +{ + HDMITX_CTS_AUTO = 0, + HDMITX_CTS_MIN = 0x000001 +}; + +/** Cycle Time Stamp X factors */ +enum _tmbslHdmiTxCtsX +{ + HDMITX_CTSX_16 = 0, + HDMITX_CTSX_32 = 1, + HDMITX_CTSX_48 = 2, + HDMITX_CTSX_64 = 3, + HDMITX_CTSX_128 = 4, + HDMITX_CTSX_NUM = 5, + HDMITX_CTSX_UNUSED = 5, /**< CTX value unused when K and Mts used */ + HDMITX_CTSX_INVALID = 6 +}; + + +/*============================================================================*/ +/** + * tmbslTDA9984AudioOutSetChanStatus() parameter types + */ + +typedef enum +{ + HDMITX_AUDIO_DATA_PCM = 0, /**< Main data field represents linear PCM samples. */ + HDMITX_AUDIO_DATA_OTHER = 1, /**< Main data field used for purposes other purposes. */ + HDMITX_AUDIO_DATA_INVALID = 2 /**< Invalid value */ +} tmbslHdmiTxAudioData_t; + +/** BYTE 0: Channel Status Format information */ +typedef enum +{ + HDMITX_CSFI_PCM_2CHAN_NO_PRE = 0, /**< PCM 2 channels without pre-emphasis */ + HDMITX_CSFI_PCM_2CHAN_PRE = 1, /**< PCM 2 channels with 50us/15us pre-emphasis */ + HDMITX_CSFI_PCM_2CHAN_PRE_RSVD1 = 2, /**< PCM Reserved for 2 channels with pre-emphasis */ + HDMITX_CSFI_PCM_2CHAN_PRE_RSVD2 = 3, /**< PCM Reserved for 2 channels with pre-emphasis */ + HDMITX_CSFI_NOTPCM_DEFAULT = 4, /**< Non-PCM Default state */ + HDMITX_CSFI_INVALID = 5 /**< Invalid value */ +} tmbslHdmiTxCSformatInfo_t; + +/** BYTE 0: Channel Status Copyright assertion */ +typedef enum +{ + HDMITX_CSCOPYRIGHT_PROTECTED = 0, /**< Copyright protected */ + HDMITX_CSCOPYRIGHT_UNPROTECTED = 1, /**< Not copyright protected */ + HDMITX_CSCOPYRIGHT_INVALID = 2 /**< Invalid value */ +} tmbslHdmiTxCScopyright_t; + +/** BYTE 3: Channel Status Clock Accuracy */ +typedef enum +{ + HDMITX_CSCLK_LEVEL_II = 0, /**< Level II */ + HDMITX_CSCLK_LEVEL_I = 1, /**< Level I */ + HDMITX_CSCLK_LEVEL_III = 2, /**< Level III */ + HDMITX_CSCLK_NOT_MATCHED = 3, /**< Not matched to sample freq. */ + HDMITX_CSCLK_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxCSclkAcc_t; + +/** BYTE 4: Channel Status Maximum sample word length */ +typedef enum +{ + HDMITX_CSMAX_LENGTH_20 = 0, /**< Max word length is 20 bits */ + HDMITX_CSMAX_LENGTH_24 = 1, /**< Max word length is 24 bits */ + HDMITX_CSMAX_INVALID = 2 /**< Invalid value */ +} tmbslHdmiTxCSmaxWordLength_t; + + +/** BYTE 4: Channel Status Sample word length */ +typedef enum +{ + HDMITX_CSWORD_DEFAULT = 0, /**< Word length is not indicated */ + HDMITX_CSWORD_20_OF_24 = 1, /**< Sample length is 20 bits out of max 24 possible */ + HDMITX_CSWORD_16_OF_20 = 1, /**< Sample length is 16 bits out of max 20 possible */ + HDMITX_CSWORD_22_OF_24 = 2, /**< Sample length is 22 bits out of max 24 possible */ + HDMITX_CSWORD_18_OF_20 = 2, /**< Sample length is 18 bits out of max 20 possible */ + HDMITX_CSWORD_RESVD = 3, /**< Reserved - shall not be used */ + HDMITX_CSWORD_23_OF_24 = 4, /**< Sample length is 23 bits out of max 24 possible */ + HDMITX_CSWORD_19_OF_20 = 4, /**< Sample length is 19 bits out of max 20 possible */ + HDMITX_CSWORD_24_OF_24 = 5, /**< Sample length is 24 bits out of max 24 possible */ + HDMITX_CSWORD_20_OF_20 = 5, /**< Sample length is 20 bits out of max 20 possible */ + HDMITX_CSWORD_21_OF_24 = 6, /**< Sample length is 21 bits out of max 24 possible */ + HDMITX_CSWORD_17_OF_20 = 6, /**< Sample length is 17 bits out of max 20 possible */ + HDMITX_CSWORD_INVALID = 7 /**< Invalid */ +} tmbslHdmiTxCSwordLength_t; + +/** BYTE 4: Channel Status Original sample frequency */ +typedef enum +{ + HDMITX_CSOFREQ_NOT_INDICATED = 0, /**< Not Indicated */ + HDMITX_CSOFREQ_192k = 1, /**< 192kHz */ + HDMITX_CSOFREQ_12k = 2, /**< 12kHz */ + HDMITX_CSOFREQ_176_4k = 3, /**< 176.4kHz */ + HDMITX_CSOFREQ_RSVD1 = 4, /**< Reserved */ + HDMITX_CSOFREQ_96k = 5, /**< 96kHz */ + HDMITX_CSOFREQ_8k = 6, /**< 8kHz */ + HDMITX_CSOFREQ_88_2k = 7, /**< 88.2kHz */ + HDMITX_CSOFREQ_16k = 8, /**< 16kHz */ + HDMITX_CSOFREQ_24k = 9, /**< 24kHz */ + HDMITX_CSOFREQ_11_025k = 10, /**< 11.025kHz */ + HDMITX_CSOFREQ_22_05k = 11, /**< 22.05kHz */ + HDMITX_CSOFREQ_32k = 12, /**< 32kHz */ + HDMITX_CSOFREQ_48k = 13, /**< 48kHz */ + HDMITX_CSOFREQ_RSVD2 = 14, /**< Reserved */ + HDMITX_CSOFREQ_44_1k = 15, /**< 44.1kHz */ + HDMITX_CSAFS_INVALID = 16 /**< Invalid value */ +} tmbslHdmiTxCSorigAfs_t; + +/*============================================================================*/ +/** + * tmbslTDA9984AudioOutSetChanStatusMapping() parameter types + */ +/** Channel Status source/channel number limits */ +enum _tmbslHdmiTxChanStatusChanLimits +{ + HDMITX_CS_CHANNELS_MAX = 0x0F, + HDMITX_CS_SOURCES_MAX = 0x0F +}; + +/*============================================================================*/ +/** + * tmbslTDA9984AudioOutSetMute() parameter type + */ +/** Audio mute state */ +typedef enum +{ + HDMITX_AMUTE_OFF = 0, /**< Mute off */ + HDMITX_AMUTE_ON = 1, /**< Mute on */ + HDMITX_AMUTE_INVALID = 2 /**< Invalid */ +} tmbslHdmiTxaMute_t; + +/** Number of 3 byte Short Audio Descriptors stored in pEdidAFmts */ +#define HDMI_TX_SAD_MAX_CNT 30 + +/*============================================================================*/ +/** + * tmbslTDA9984EdidGetBlockData() parameter types + */ +/** An enum to represent the current EDID status */ +enum _tmbslHdmiTxEdidSta_t +{ + HDMITX_EDID_READ = 0, /* All blocks read OK */ + HDMITX_EDID_READ_INCOMPLETE = 1, /* All blocks read OK but buffer too + small to return all of them */ + HDMITX_EDID_ERROR_CHK_BLOCK_0 = 2, /* Block 0 checksum error */ + + HDMITX_EDID_ERROR_CHK = 3, /* Block 0 OK, checksum error in one + or more other blocks */ + HDMITX_EDID_NOT_READ = 4, /* EDID not read */ + + HDMITX_EDID_STATUS_INVALID = 5 /**< Invalid */ + +}; + +/*============================================================================*/ +/** + * tmbslTDA9984EdidGetSinkType() parameter types + */ +/** Sink device type */ +typedef enum +{ + HDMITX_SINK_DVI = 0, /**< DVI */ + HDMITX_SINK_HDMI = 1, /**< HDMI */ + HDMITX_SINK_EDID = 2, /**< As currently defined in EDID */ + HDMITX_SINK_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxSinkType_t; + +/*============================================================================*/ +/** + * \brief The tmbslTDA9984EdidGetVideoPreferred() parameter type + * Detailed timining description structure + */ +typedef struct _tmbslHdmiTxEdidDtd_t +{ + UInt16 uPixelClock; /**< Pixel Clock/10,000 */ + UInt16 uHActivePixels; /**< Horizontal Active Pixels */ + UInt16 uHBlankPixels; /**< Horizontal Blanking Pixels */ + UInt16 uVActiveLines; /**< Vertical Active Lines */ + UInt16 uVBlankLines; /**< Vertical Blanking Lines */ + UInt16 uHSyncOffset; /**< Horizontal Sync Offset */ + UInt16 uHSyncWidth; /**< Horiz. Sync Pulse Width */ + UInt16 uVSyncOffset; /**< Vertical Sync Offset */ + UInt16 uVSyncWidth; /**< Vertical Sync Pulse Width */ + UInt16 uHImageSize; /**< Horizontal Image Size */ + UInt16 uVImageSize; /**< Vertical Image Size */ + UInt16 uHBorderPixels; /**< Horizontal Border */ + UInt16 uVBorderPixels; /**< Vertical Border */ + UInt8 Flags; /**< Interlace/sync info */ +} tmbslHdmiTxEdidDtd_t; + + +/*============================================================================*/ +/** + * First monitor descriptor structure + */ +typedef struct _tmbslHdmiTxEdidFirstMD_t +{ + Bool bDescRecord; /**< True when parameters of struct are available */ + UInt8 uMonitorName[EDID_MONITOR_DESCRIPTOR_SIZE]; /**< Monitor Name */ +} tmbslHdmiTxEdidFirstMD_t; + +/*============================================================================*/ +/** + * Second monitor descriptor structure + */ +typedef struct _tmbslHdmiTxEdidSecondMD_t +{ + Bool bDescRecord; /**< True when parameters of struct are available */ + UInt8 uMinVerticalRate; /**< Min vertical rate in Hz */ + UInt8 uMaxVerticalRate; /**< Max vertical rate in Hz */ + UInt8 uMinHorizontalRate; /**< Min horizontal rate in Hz */ + UInt8 uMaxHorizontalRate; /**< Max horizontal rate in Hz */ + UInt8 uMaxSupportedPixelClk; /**< Max suuported pixel clock rate in MHz */ +} tmbslHdmiTxEdidSecondMD_t; + +/*============================================================================*/ +/** + * Other monitor descriptor structure + */ +typedef struct _tmbslHdmiTxEdidOtherMD_t +{ + Bool bDescRecord; /**< True when parameters of struct are available */ + UInt8 uOtherDescriptor[EDID_MONITOR_DESCRIPTOR_SIZE]; /**< Other monitor Descriptor */ +} tmbslHdmiTxEdidOtherMD_t; + +/*============================================================================*/ +/** + * basic display parameters structure + */ +typedef struct _tmbslHdmiTxEdidBDParam_t +{ + UInt8 uVideoInputDef; /**< Video Input Definition */ + UInt8 uMaxHorizontalSize; /**< Max. Horizontal Image Size in cm */ + UInt8 uMaxVerticalSize; /**< Max. Vertical Image Size in cm */ + UInt8 uGamma; /**< Gamma */ + UInt8 uFeatureSupport; /**< Feature support */ +} tmbslHdmiTxEdidBDParam_t; + +/*============================================================================*/ +/** + * \brief The tmbslTDA9984EdidGetAudioCapabilities() parameter type + */ +typedef struct _tmbslHdmiTxEdidSad_t +{ + UInt8 ModeChans; /* Bits[6:3]: EIA/CEA861 mode; Bits[2:0]: channels */ + UInt8 Freqs; /* Bits for each supported frequency */ + UInt8 Byte3; /* EIA/CEA861B p83: data depending on audio mode */ +}tmbslHdmiTxEdidSad_t; + +/*============================================================================*/ +/** + * \brief struc to store parameter provide by function tmbslTDA9984EdidRequestBlockData() + */ +typedef struct _tmbslHdmiTxEdidToApp_t +{ + UInt8 *pRawEdid; /* pointer on a tab to store edid requested by application */ + Int numBlocks; /* number of edid block requested by application */ +}tmbslHdmiTxEdidToApp_t; + +/*============================================================================*/ +/** + * tmbslTDA9984EdidGetVideoCapabilities() parameter types + */ +/** Number of 1 byte Short Video Descriptors stored in pEdidVFmts */ +#define HDMI_TX_SVD_MAX_CNT 113 + +/** number of detailed timing descriptor stored in BSL */ +#define NUMBER_DTD_STORED 10 + + + +/** Flag set in Short Video Descriptor to indicate native format */ +#define HDMI_TX_SVD_NATIVE_MASK 0x80 +#define HDMI_TX_SVD_NATIVE_NOT 0x7F + +/** Video capability flags */ +enum _tmbslHdmiTxVidCap_t +{ + HDMITX_VIDCAP_UNDERSCAN = 0x80, /**< Underscan supported */ + HDMITX_VIDCAP_YUV444 = 0x40, /**< YCbCr 4:4:4 supported */ + HDMITX_VIDCAP_YUV422 = 0x20, /**< YCbCr 4:2:2 supported */ + HDMITX_VIDCAP_UNUSED = 0x1F /**< Unused flags */ +}; + +/*============================================================================*/ +/** + * tmbslTDA9984HdcpCheck() parameter type + */ +/** HDCP check result */ +typedef enum +{ + HDMITX_HDCP_CHECK_NOT_STARTED = 0, /**< Check not started */ + HDMITX_HDCP_CHECK_IN_PROGRESS = 1, /**< No failures, more to do */ + HDMITX_HDCP_CHECK_PASS = 2, /**< Final check has passed */ + HDMITX_HDCP_CHECK_FAIL_FIRST = 3, /**< First check failure code */ + HDMITX_HDCP_CHECK_FAIL_DRIVER_STATE = 3, /**< Driver not AUTHENTICATED */ + HDMITX_HDCP_CHECK_FAIL_DEVICE_T0 = 4, /**< A T0 interrupt occurred */ + HDMITX_HDCP_CHECK_FAIL_DEVICE_RI = 5, /**< Device RI changed */ + HDMITX_HDCP_CHECK_FAIL_DEVICE_FSM = 6, /**< Device FSM not 10h */ + HDMITX_HDCP_CHECK_NUM = 7 /**< Number of check results */ +}tmbslHdmiTxHdcpCheck_t; + +/*============================================================================*/ +/** + * tmbslTDA9984HdcpConfigure() parameter type + */ +/** HDCP DDC slave addresses */ +enum _tmbslHdmiTxHdcpSlaveAddress +{ + HDMITX_HDCP_SLAVE_PRIMARY = 0x74, + HDMITX_HDCP_SLAVE_SECONDARY = 0x76 +}; + +/** HDCP transmitter modes */ +typedef enum +{ + HDMITX_HDCP_TXMODE_NOT_SET = 0, + HDMITX_HDCP_TXMODE_REPEATER = 1, + HDMITX_HDCP_TXMODE_TOP_LEVEL = 2, + HDMITX_HDCP_TXMODE_MAX = 2 +}tmbslHdmiTxHdcpTxMode_t; + +/** HDCP option flags */ +typedef enum +{ + HDMITX_HDCP_OPTION_FORCE_PJ_IGNORED = 0x01,/* Not set: obey PJ result */ + HDMITX_HDCP_OPTION_FORCE_SLOW_DDC = 0x02,/* Not set: obey BCAPS setting */ + HDMITX_HDCP_OPTION_FORCE_NO_1_1 = 0x04,/* Not set: obey BCAPS setting */ + HDMITX_HDCP_OPTION_FORCE_REPEATER = 0x08,/* Not set: obey BCAPS setting */ + HDMITX_HDCP_OPTION_FORCE_NO_REPEATER= 0x10,/* Not set: obey BCAPS setting */ + HDMITX_HDCP_OPTION_FORCE_V_EQU_VBAR = 0x20,/* Not set: obey V=V' result */ + HDMITX_HDCP_OPTION_FORCE_VSLOW_DDC = 0x40,/* Set: 50kHz DDC */ + HDMITX_HDCP_OPTION_DEFAULT = 0x00,/* All the above Not Set vals */ + HDMITX_HDCP_OPTION_MASK = 0x7F,/* Only these bits are allowed */ + HDMITX_HDCP_OPTION_MASK_BAD = 0x80 /* These bits are not allowed */ +}tmbslHdmiTxHdcpOptions_t; + +/*============================================================================*/ +/** + * tmbslTDA9984HdcpDownloadKeys() parameter type + */ +/** HDCP decryption mode */ +typedef enum +{ + HDMITX_HDCP_DECRYPT_DISABLE = 0, + HDMITX_HDCP_DECRYPT_ENABLE = 1, + HDMITX_HDCP_DECRYPT_MAX = 1 +}tmbslHdmiTxDecrypt_t; + +/*============================================================================*/ +/** + * tmbslTDA9984HdcpHandleBSTATUS() parameter type + */ +/** BSTATUS bit fields */ +enum _tmbslHdmiTxHdcpHandleBSTATUS +{ + HDMITX_HDCP_BSTATUS_HDMI_MODE = 0x1000, + HDMITX_HDCP_BSTATUS_MAX_CASCADE_EXCEEDED = 0x0800, + HDMITX_HDCP_BSTATUS_CASCADE_DEPTH = 0x0700, + HDMITX_HDCP_BSTATUS_MAX_DEVS_EXCEEDED = 0x0080, + HDMITX_HDCP_BSTATUS_DEVICE_COUNT = 0x007F +}; + +/*============================================================================*/ +/** + * tmbslTDA9984HdcpHandleSHA_1() parameter types + */ +/** KSV list sizes */ +enum _tmbslHdmiTxHdcpHandleSHA_1 +{ + HDMITX_KSV_LIST_MAX_DEVICES = 128, + HDMITX_KSV_BYTES_PER_DEVICE = 5 +}; + +/*============================================================================*/ +/** + * tmbslTDA9984HotPlugGetStatus() parameter type + */ +/** Current hotplug status */ +typedef enum +{ + HDMITX_HOTPLUG_INACTIVE = 0, /**< Hotplug inactive */ + HDMITX_HOTPLUG_ACTIVE = 1, /**< Hotplug active */ + HDMITX_HOTPLUG_INVALID = 2 /**< Invalid Hotplug */ +} tmbslHdmiTxHotPlug_t; + +/*============================================================================*/ +/** + * tmbslTDA9984RxSenseGetStatus() parameter type + */ +/** Current RX Sense status */ +typedef enum +{ + HDMITX_RX_SENSE_INACTIVE = 0, /**< RxSense inactive */ + HDMITX_RX_SENSE_ACTIVE = 1, /**< RxSense active */ + HDMITX_RX_SENSE_INVALID = 2 /**< Invalid RxSense */ +} tmbslHdmiTxRxSense_t; + +/*============================================================================*/ +/** + * tmbslTDA9984HwGetCapabilities() parameter type + */ +/** List of HW features that may be supported by HW */ +typedef enum +{ + HDMITX_FEATURE_HW_HDCP = 0, /**< HDCP feature */ + HDMITX_FEATURE_HW_SCALER = 1, /**< Scaler feature */ + HDMITX_FEATURE_HW_AUDIO_OBA = 2, /**< One Bit Audio feature */ + HDMITX_FEATURE_HW_AUDIO_DST = 3, /**< DST Audio feature */ + HDMITX_FEATURE_HW_AUDIO_HBR = 4, /**< HBR Audio feature */ + HDMITX_FEATURE_HW_HDMI_1_1 = 5, /**< HDMI 1.1 feature */ + HDMITX_FEATURE_HW_HDMI_1_2A = 6, /**< HDMI 1.2a feature */ + HDMITX_FEATURE_HW_HDMI_1_3A = 7, /**< HDMI 1.3a feature */ + HDMITX_FEATURE_HW_DEEP_COLOR_30 = 8, /**< 30 bits deep color support */ + HDMITX_FEATURE_HW_DEEP_COLOR_36 = 9, /**< 36 bits deep color support */ + HDMITX_FEATURE_HW_DEEP_COLOR_48 = 11, /**< 48 bits deep color support */ + HDMITX_FEATURE_HW_UPSAMPLER = 12, /**< Up sampler feature */ + HDMITX_FEATURE_HW_DOWNSAMPLER = 13, /**< Down sampler feature */ + HDMITX_FEATURE_HW_COLOR_CONVERSION = 14 /**< Color conversion matrix */ +} tmbslHdmiTxHwFeature_t; + +/*============================================================================*/ +/** + * tmbslTDA9984Init() parameter types + */ +/** Supported range of I2C slave addresses */ +enum _tmbslHdmiTxSlaveAddress +{ + HDMITX_SLAVE_ADDRESS_MIN = 1, + HDMITX_SLAVE_ADDRESS_MAX = 127 +}; + +/** + * Indexes into the funcCallback[] array of interrupt callback function pointers + */ +typedef enum _tmbslHdmiTxCallbackInt +{ + HDMITX_CALLBACK_INT_SECURITY = 0, /**< HDCP encryption switched off */ + HDMITX_CALLBACK_INT_ENCRYPT = 0, /**< HDCP encrypt as above (Obsolete) */ + HDMITX_CALLBACK_INT_HPD = 1, /**< Transition on HPD input */ + HDMITX_CALLBACK_INT_T0 = 2, /**< HDCP state machine in state T0 */ + HDMITX_CALLBACK_INT_BCAPS = 3, /**< BCAPS available */ + HDMITX_CALLBACK_INT_BSTATUS = 4, /**< BSTATUS available */ + HDMITX_CALLBACK_INT_SHA_1 = 5, /**< sha-1(ksv,bstatus,m0)=V' */ + HDMITX_CALLBACK_INT_PJ = 6, /**< pj=pj' check fails */ + HDMITX_CALLBACK_INT_R0 = 7, /**< R0 interrupt */ + HDMITX_CALLBACK_INT_SW_INT = 8, /**< SW DEBUG interrupt */ + HDMITX_CALLBACK_INT_RX_SENSE = 9, /**< RX SENSE interrupt */ + HDMITX_CALLBACK_INT_EDID_BLK_READ = 10, /**< EDID BLK READ interrupt */ + HDMITX_CALLBACK_INT_PLL_LOCK = 11, /**< Pll Lock (Serial or Formatter) */ + HDMITX_CALLBACK_INT_VS_RPT = 12, /**< VS Interrupt for Gamut packets */ + HDMITX_CALLBACK_INT_NUM = 13 /**< Number of callbacks */ +}tmbslHdmiTxCallbackInt_t; + +/** Pixel rate */ +typedef enum +{ + HDMITX_PIXRATE_DOUBLE = 0, /**< Double pixel rate */ + HDMITX_PIXRATE_SINGLE = 1, /**< Single pixel rate */ + HDMITX_PIXRATE_SINGLE_REPEATED = 2, /**< Single pixel repeated */ + HDMITX_PIXRATE_NO_CHANGE = 3, /**< No Change */ + HDMITX_PIXRATE_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxPixRate_t; + +/** + * \brief The tmbslTDA9984Init() parameter structure + */ +typedef struct _tmbslHdmiTxCallbackList_t +{ + /** Interrupt callback function pointers (each ptr if null = not used) */ + ptmbslHdmiTxCallback_t funcCallback[HDMITX_CALLBACK_INT_NUM]; + +} tmbslHdmiTxCallbackList_t; + +/*============================================================================*/ +/** + * tmbslTDA9984MatrixSetCoeffs() parameter type + */ +/** Parameter structure array size */ +enum _tmbslHdmiTxMatCoeff +{ + HDMITX_MAT_COEFF_NUM = 9 +}; + + +/** \brief The tmbslTDA9984MatrixSetCoeffs() parameter structure */ +/** Array of coefficients (values -1024 to +1023) */ +typedef struct _tmbslHdmiTxMatCoeff_t +{ + /** Array of coefficients (values -1024 to +1023) */ + Int16 Coeff[HDMITX_MAT_COEFF_NUM]; +} tmbslHdmiTxMatCoeff_t; + +/*============================================================================*/ +/** + * tmbslTDA9984MatrixSetConversion() parameter type + */ +/** Video input mode */ +typedef enum +{ + HDMITX_VINMODE_CCIR656 = 0, /**< ccir656 */ + HDMITX_VINMODE_RGB444 = 1, /**< RGB444 */ + HDMITX_VINMODE_YUV444 = 2, /**< YUV444 */ + HDMITX_VINMODE_YUV422 = 3, /**< YUV422 */ + HDMITX_VINMODE_NO_CHANGE = 4, /**< No change */ + HDMITX_VINMODE_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxVinMode_t; + +/** Video output mode */ +typedef enum +{ + HDMITX_VOUTMODE_RGB444 = 0, /**< RGB444 */ + HDMITX_VOUTMODE_YUV422 = 1, /**< YUV422 */ + HDMITX_VOUTMODE_YUV444 = 2, /**< YUV444 */ + HDMITX_VOUTMODE_NO_CHANGE = 3, /**< No change */ + HDMITX_VOUTMODE_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxVoutMode_t; + +/*============================================================================*/ +/** + * tmbslTDA9984MatrixSetMode() parameter types + */ +/** Matrix control values */ +typedef enum +{ + HDMITX_MCNTRL_ON = 0, /**< Matrix on */ + HDMITX_MCNTRL_OFF = 1, /**< Matrix off */ + HDMITX_MCNTRL_NO_CHANGE = 2, /**< Matrix unchanged */ + HDMITX_MCNTRL_MAX = 2, /**< Max value */ + HDMITX_MCNTRL_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxmCntrl_t; + +/** Matrix scale values */ +typedef enum +{ + HDMITX_MSCALE_256 = 0, /**< Factor 1/256 */ + HDMITX_MSCALE_512 = 1, /**< Factor 1/512 */ + HDMITX_MSCALE_1024 = 2, /**< Factor 1/1024 */ + HDMITX_MSCALE_NO_CHANGE = 3, /**< Factor unchanged */ + HDMITX_MSCALE_MAX = 3, /**< Max value */ + HDMITX_MSCALE_INVALID = 4 /**< Invalid value */ +} tmbslHdmiTxmScale_t; + +/*============================================================================*/ +/** + * Data Island Packet structure + */ +/** Parameter structure array sizes */ +enum _tmbslHdmiTxPkt +{ + HDMITX_PKT_DATA_BYTE_CNT = 28 +}; + +/** \brief The parameter structure for tmbslTDA9984Pkt*() APIs */ +typedef struct _tmbslHdmiTxPkt_t +{ + UInt8 dataByte[HDMITX_PKT_DATA_BYTE_CNT]; /**< Packet Data */ +} tmbslHdmiTxPkt_t; + +/*============================================================================*/ +/** + * \brief The Audio Infoframe Parameter structure + */ +typedef struct _tmbslHdmiTxPktAif_t +{ + UInt8 CodingType; /**< Coding Type 0 to 0Fh */ + UInt8 ChannelCount; /**< Channel Count 0 to 07h */ + UInt8 SampleFreq; /**< Sample Frequency 0 to 07h */ + UInt8 SampleSize; /**< Sample Size 0 to 03h */ + UInt8 ChannelAlloc; /**< Channel Allocation 0 to FFh */ + Bool DownMixInhibit; /**< Downmix inhibit flag 0/1 */ + UInt8 LevelShift; /**< Level Shift 0 to 0Fh */ +} tmbslHdmiTxPktAif_t; + +/*============================================================================*/ +/** + * tmbslTDA9984PktSetMpegInfoframe() parameter types + */ +/** MPEG frame types */ +typedef enum +{ + HDMITX_MPEG_FRAME_UNKNOWN = 0, /**< Unknown */ + HDMITX_MPEG_FRAME_I = 1, /**< i-frame */ + HDMITX_MPEG_FRAME_B = 2, /**< b-frame */ + HDMITX_MPEG_FRAME_P = 3, /**< p-frame */ + HDMITX_MPEG_FRAME_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxMpegFrame_t; + +/** \brief The MPEG Infoframe Parameter structure */ +typedef struct _tmbslHdmiTxPktMpeg_t +{ + UInt32 bitRate; /**< MPEG bit rate in Hz */ + tmbslHdmiTxMpegFrame_t frameType; /**< MPEG frame type */ + Bool bFieldRepeat; /**< 0: new field, 1:repeated field */ +}tmbslHdmiTxPktMpeg_t; + +/*============================================================================*/ +/** + * Source Product Description Infoframe Parameter types + */ +/** SDI frame types */ +typedef enum +{ + HDMITX_SPD_INFO_UNKNOWN = 0, + HDMITX_SPD_INFO_DIGITAL_STB = 1, + HDMITX_SPD_INFO_DVD = 2, + HDMITX_SPD_INFO_DVHS = 3, + HDMITX_SPD_INFO_HDD_VIDEO = 4, + HDMITX_SPD_INFO_DVC = 5, + HDMITX_SPD_INFO_DSC = 6, + HDMITX_SPD_INFO_VIDEO_CD = 7, + HDMITX_SPD_INFO_GAME = 8, + HDMITX_SPD_INFO_PC = 9, + HDMITX_SPD_INFO_INVALID = 10 +} tmbslHdmiTxSourceDev_t; + +#define HDMI_TX_SPD_VENDOR_SIZE 8 +#define HDMI_TX_SPD_DESCR_SIZE 16 +#define HDMI_TX_SPD_LENGTH 25 + +/** \brief The Source Product Description Infoframe Parameter structure */ +typedef struct _tmbslHdmiTxPktSpd_t +{ + UInt8 VendorName[HDMI_TX_SPD_VENDOR_SIZE]; /**< Vendor name */ + UInt8 ProdDescr[HDMI_TX_SPD_DESCR_SIZE]; /**< Product Description */ + tmbslHdmiTxSourceDev_t SourceDevInfo; /**< Source Device Info */ +} tmbslHdmiTxPktSpd_t; + +/*============================================================================*/ +/** + * \brief The Video Infoframe Parameter structure + */ +typedef struct _tmbslHdmiTxPktVif_t +{ + UInt8 Colour; /**< 0 to 03h */ + Bool ActiveInfo; /**< 0/1 */ + UInt8 BarInfo; /**< 0 to 03h */ + UInt8 ScanInfo; /**< 0 to 03h */ + UInt8 Colorimetry; /**< 0 to 03h */ + UInt8 PictureAspectRatio; /**< 0 to 03h */ + UInt8 ActiveFormatRatio; /**< 0 to 0Fh */ + UInt8 Scaling; /**< 0 to 03h */ + UInt8 VidFormat; /**< 0 to 7Fh */ + UInt8 PixelRepeat; /**< 0 to 0Fh */ + UInt16 EndTopBarLine; + UInt16 StartBottomBarLine; + UInt16 EndLeftBarPixel; + UInt16 StartRightBarPixel; +} tmbslHdmiTxPktVif_t; + +/*============================================================================*/ +/** + * tmbslTDA9984ScalerGetMode() parameter types + */ +/** Scaler modes */ +typedef enum +{ + HDMITX_SCAMODE_OFF = 0, /**< Off */ + HDMITX_SCAMODE_ON = 1, /**< On */ + HDMITX_SCAMODE_AUTO = 2, /**< Auto */ + HDMITX_SCAMODE_NO_CHANGE = 3, /**< No change */ + HDMITX_SCAMODE_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxScaMode_t; + +/*============================================================================*/ +/** + * \brief The tmbslTDA9984ScalerGet() parameter type + */ +typedef struct _tmbslHdmiTxScalerDiag_t +{ + UInt16 maxBuffill_p; /**< Filling primary video buffer */ + UInt16 maxBuffill_d; /**< Filling video deinterlaced buffer */ + UInt8 maxFifofill_pi; /**< Filling primary video input FIFO */ + UInt8 minFifofill_po1; /**< Filling primary video output FIFO #1 */ + UInt8 minFifofill_po2; /**< Filling primary video output FIFO #2 */ + UInt8 minFifofill_po3; /**< Filling primary video output FIFO #3 */ + UInt8 minFifofill_po4; /**< Filling primary video output FIFO #4 */ + UInt8 maxFifofill_di; /**< Filling deinterlaced video input FIFO */ + UInt8 maxFifofill_do; /**< Filling deinterlaced video output FIFO */ +} tmbslHdmiTxScalerDiag_t; + +/*============================================================================*/ +/** + * tmbslTDA9984ScalerSetCoeffs() parameter types + */ +/** Scaler lookup table selection */ +typedef enum +{ + HDMITX_SCALUT_DEFAULT_TAB1 = 0, /**< Use default table 1 */ + HDMITX_SCALUT_DEFAULT_TAB2 = 1, /**< Use default table 2 */ + HDMITX_SCALUT_USE_VSLUT = 2, /**< Use vsLut parameter */ + HDMITX_SCALUT_INVALID = 3 /**< Invalid value */ +} tmbslHdmiTxScaLut_t; + +/** Scaler control parameter structure array size */ +enum _tmbslHdmiTxvsLut +{ + HDMITX_VSLUT_COEFF_NUM = 45 +}; +/*============================================================================*/ +/** + * tmbslTDA9984ScalerSetFieldOrder() parameter types + */ +/** IntExt values */ +typedef enum +{ + HDMITX_INTEXT_INTERNAL = 0, /**< Internal */ + HDMITX_INTEXT_EXTERNAL = 1, /**< External */ + HDMITX_INTEXT_NO_CHANGE = 2, /**< No change */ + HDMITX_INTEXT_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxIntExt_t; + +/** TopSel values */ +typedef enum +{ + HDMITX_TOPSEL_INTERNAL = 0, /**< Internal */ + HDMITX_TOPSEL_VRF = 1, /**< VRF */ + HDMITX_TOPSEL_NO_CHANGE = 2, /**< No change */ + HDMITX_TOPSEL_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxTopSel_t; + +/** TopTgl values */ +typedef enum +{ + HDMITX_TOPTGL_NO_ACTION = 0, /**< NO action */ + HDMITX_TOPTGL_TOGGLE = 1, /**< Toggle */ + HDMITX_TOPTGL_NO_CHANGE = 2, /**< No change */ + HDMITX_TOPTGL_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxTopTgl_t; + +/*============================================================================*/ +/** + * tmbslTDA9984ScalerSetPhase() parameter types + */ +/** Phases_h values */ +typedef enum +{ + HDMITX_H_PHASES_16 = 0, /**< 15 horizontal phases */ + HDMITX_H_PHASES_15 = 1, /**< 16 horizontal phases */ + HDMITX_H_PHASES_INVALID = 2 /**< Invalid */ +} tmbslHdmiTxHPhases_t; + +/*============================================================================*/ +/** + * tmbslTDA9984ScalerSetFine() parameter types + */ +/** Reference pixel values */ +enum _tmbslHdmiTxScalerFinePixelLimits +{ + HDMITX_SCALER_FINE_PIXEL_MIN = 0x0000, + HDMITX_SCALER_FINE_PIXEL_MAX = 0x1FFF, + HDMITX_SCALER_FINE_PIXEL_NO_CHANGE = 0x2000, + HDMITX_SCALER_FINE_PIXEL_INVALID = 0x2001 +}; + +/** Reference line values */ +enum _tmbslHdmiTxScalerFineLineLimits +{ + HDMITX_SCALER_FINE_LINE_MIN = 0x0000, + HDMITX_SCALER_FINE_LINE_MAX = 0x07FF, + HDMITX_SCALER_FINE_LINE_NO_CHANGE = 0x0800, + HDMITX_SCALER_FINE_LINE_INVALID = 0x0801 +}; +/*============================================================================*/ +/** + * tmbslTDA9984ScalerSetSync() parameter types + */ +/** Video sync method */ +typedef enum +{ + HDMITX_VSMETH_V_H = 0, /**< V and H */ + HDMITX_VSMETH_V_XDE = 1, /**< V and X-DE */ + HDMITX_VSMETH_NO_CHANGE = 2, /**< No change */ + HDMITX_VSMETH_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxVsMeth_t; + +/** Line/pixel counters sync */ +typedef enum +{ + HDMITX_VSONCE_EACH_FRAME = 0, /**< Sync on each frame */ + HDMITX_VSONCE_ONCE = 1, /**< Sync once only */ + HDMITX_VSONCE_NO_CHANGE = 2, /**< No change */ + HDMITX_VSONCE_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxVsOnce_t; + +/*============================================================================*/ +/** + * tmbslTDA9984TmdsSetOutputs() parameter types + */ +/** TMDS output mode */ +typedef enum +{ + HDMITX_TMDSOUT_NORMAL = 0, /**< Normal outputs */ + HDMITX_TMDSOUT_NORMAL1 = 1, /**< Normal outputs, same as 0 */ + HDMITX_TMDSOUT_FORCED0 = 2, /**< Forced 0 outputs */ + HDMITX_TMDSOUT_FORCED1 = 3, /**< Forced 1 outputs */ + HDMITX_TMDSOUT_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxTmdsOut_t; + +/*============================================================================*/ +/** + * tmbslTDA9984TmdsSetSerializer() parameter types + */ +/** Serializer phase limits */ +enum _tmbslHdmiTxTmdsPhase +{ + HDMITX_TMDSPHASE_MIN = 0, + HDMITX_TMDSPHASE_MAX = 15, + HDMITX_TMDSPHASE_INVALID = 16 +}; + +/*============================================================================*/ +/** + * tmbslTDA9984TestSetPattern() parameter types + */ +/** Test pattern types */ +typedef enum +{ + HDMITX_PATTERN_OFF = 0, /**< Insert test pattern */ + HDMITX_PATTERN_CBAR4 = 1, /**< Insert 4-bar colour bar */ + HDMITX_PATTERN_CBAR8 = 2, /**< Insert 8-bar colour bar */ + HDMITX_PATTERN_BLUE = 3, /**< Insert Blue screen */ + HDMITX_PATTERN_BLACK = 4, /**< Insert Blue screen */ + HDMITX_PATTERN_INVALID = 5 /**< Invalid pattern */ +} tmbslHdmiTxTestPattern_t; + +/*============================================================================*/ +/** + * tmbslTDA9984TestSetMode() parameter types + */ +/** Test modes */ +typedef enum +{ + HDMITX_TESTMODE_PAT = 0,/**< Insert test pattern */ + HDMITX_TESTMODE_656 = 1,/**< Inject CCIR-656 video via audio port */ + HDMITX_TESTMODE_SERPHOE = 2,/**< Activate srl_tst_ph2_o & srl_tst_ph3_o */ + HDMITX_TESTMODE_NOSC = 3,/**< Input nosc predivider = PLL-ref input */ + HDMITX_TESTMODE_HVP = 4,/**< Test high voltage protection cells */ + HDMITX_TESTMODE_PWD = 5,/**< Test PLLs in sleep mode */ + HDMITX_TESTMODE_DIVOE = 6,/**< Enable scaler PLL divider test output */ + HDMITX_TESTMODE_INVALID = 7 /**< Invalid test */ +} tmbslHdmiTxTestMode_t; + +/** Test states */ +typedef enum +{ + HDMITX_TESTSTATE_OFF = 0, /**< Disable the selected test */ + HDMITX_TESTSTATE_ON = 1, /**< Enable the selected test */ + HDMITX_TESTSTATE_INVALID = 2 /**< Invalid value */ +} tmbslHdmiTxTestState_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoInSetBlanking() parameter types + */ +/** Blankit Source */ +typedef enum +{ + HDMITX_BLNKSRC_NOT_DE = 0, /**< Source=Not DE */ + HDMITX_BLNKSRC_VS_HS = 1, /**< Source=VS And HS */ + HDMITX_BLNKSRC_VS_NOT_HS = 2, /**< Source=VS And Not HS */ + HDMITX_BLNKSRC_VS_HEMB_VEMB = 3, /**< Source=Hemb And Vemb */ + HDMITX_BLNKSRC_NO_CHANGE = 4, /**< No change */ + HDMITX_BLNKSRC_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxBlnkSrc_t; + +/** Blanking Codes */ +typedef enum +{ + HDMITX_BLNKCODE_ALL_0 = 0, /**< Code=All Zero */ + HDMITX_BLNKCODE_RGB444 = 1, /**< Code=RGB444 */ + HDMITX_BLNKCODE_YUV444 = 2, /**< Code=YUV444 */ + HDMITX_BLNKCODE_YUV422 = 3, /**< Code=YUV422 */ + HDMITX_BLNKCODE_NO_CHANGE = 4, /**< No change */ + HDMITX_BLNKCODE_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxBlnkCode_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoInSetConfig() parameter types + */ +/** Sample edge */ +typedef enum +{ + HDMITX_PIXEDGE_CLK_POS = 0, /**< Pixel Clock Positive Edge */ + HDMITX_PIXEDGE_CLK_NEG = 1, /**< Pixel Clock Negative Edge */ + HDMITX_PIXEDGE_NO_CHANGE = 2, /**< No Change */ + HDMITX_PIXEDGE_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxPixEdge_t; + +/** Upsample modes */ +typedef enum +{ + HDMITX_UPSAMPLE_BYPASS = 0, /**< Bypass */ + HDMITX_UPSAMPLE_COPY = 1, /**< Copy */ + HDMITX_UPSAMPLE_INTERPOLATE = 2, /**< Interpolate */ + HDMITX_UPSAMPLE_AUTO = 3, /**< Auto: driver chooses best value */ + HDMITX_UPSAMPLE_NO_CHANGE = 4, /**< No Change */ + HDMITX_UPSAMPLE_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxUpsampleMode_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoInSetFine() parameter types + */ +/** Subpacket count */ +typedef enum +{ + HDMITX_PIXSUBPKT_FIX_0 = 0, /**< Fix At 0 */ + HDMITX_PIXSUBPKT_FIX_1 = 1, /**< Fix At 1 */ + HDMITX_PIXSUBPKT_FIX_2 = 2, /**< Fix At 2 */ + HDMITX_PIXSUBPKT_FIX_3 = 3, /**< Fix At 3 */ + HDMITX_PIXSUBPKT_SYNC_FIRST = 4, /**< First Sync value */ + HDMITX_PIXSUBPKT_SYNC_HEMB = 4, /**< Sync By Hemb */ + HDMITX_PIXSUBPKT_SYNC_DE = 5, /**< Sync By Rising Edge DE */ + HDMITX_PIXSUBPKT_SYNC_HS = 6, /**< Sync By Rising Edge HS */ + HDMITX_PIXSUBPKT_NO_CHANGE = 7, /**< No Change */ + HDMITX_PIXSUBPKT_INVALID = 8, /**< Invalid */ + HDMITX_PIXSUBPKT_SYNC_FIXED = 3 /**< Not used as a parameter value, + * but used internally when + * Fix at 0/1/2/3 values are set */ +} tmbslHdmiTxPixSubpkt_t; + +/** Toggling */ +typedef enum +{ + HDMITX_PIXTOGL_NO_ACTION = 0, /**< No Action */ + HDMITX_PIXTOGL_ENABLE = 1, /**< Toggle */ + HDMITX_PIXTOGL_NO_CHANGE = 2, /**< No Change */ + HDMITX_PIXTOGL_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxPixTogl_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoInSetMapping() parameter types + */ +/** Video input port parameter structure array size and limits */ +enum _tmbslHdmiTxVinPortMap +{ + HDMITX_VIN_PORT_MAP_TABLE_LEN = 6, + + HDMITX_VIN_PORT_SWAP_NO_CHANGE = 6, + HDMITX_VIN_PORT_SWAP_INVALID = 7, + + HDMITX_VIN_PORT_MIRROR_NO_CHANGE = 2, + HDMITX_VIN_PORT_MIRROR_INVALID = 3 +}; + + +/*============================================================================*/ +/** + * tmbslTDA9984VideoInSetSyncAuto() parameter types + */ +/** Sync source - was Embedded sync HDMITX_PIXEMBSYNC_ */ +typedef enum +{ + HDMITX_SYNCSRC_EMBEDDED = 0, /**< Embedded sync */ + HDMITX_SYNCSRC_EXT_VREF = 1, /**< External sync Vref, Href, Fref */ + HDMITX_SYNCSRC_EXT_VS = 2, /**< External sync Vs, Hs */ + HDMITX_SYNCSRC_NO_CHANGE = 3, /**< No Change */ + HDMITX_SYNCSRC_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxSyncSource_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoInSetSyncManual() parameter types + */ +/** Video output frame pixel values */ +enum _tmbslHdmiTxVoutFinePixelLimits +{ + HDMITX_VOUT_FINE_PIXEL_MIN = 0x0000, + HDMITX_VOUT_FINE_PIXEL_MAX = 0x1FFF, + HDMITX_VOUT_FINE_PIXEL_NO_CHANGE = 0x2000, + HDMITX_VOUT_FINE_PIXEL_INVALID = 0x2001 +}; + +/** Video output frame line values */ +enum _tmbslHdmiTxVoutFineLineLimits +{ + HDMITX_VOUT_FINE_LINE_MIN = 0x0000, + HDMITX_VOUT_FINE_LINE_MAX = 0x07FF, + HDMITX_VOUT_FINE_LINE_NO_CHANGE = 0x0800, + HDMITX_VOUT_FINE_LINE_INVALID = 0x0801 +}; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoOutSetConfig() parameter types + */ +/** Prefilter */ +typedef enum +{ + HDMITX_VOUT_PREFIL_OFF = 0, /**< Off */ + HDMITX_VOUT_PREFIL_121 = 1, /**< 121 */ + HDMITX_VOUT_PREFIL_109 = 2, /**< 109 */ + HDMITX_VOUT_PREFIL_CCIR601 = 3, /**< CCIR601 */ + HDMITX_VOUT_PREFIL_NO_CHANGE = 4, /**< No Change */ + HDMITX_VOUT_PREFIL_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxVoutPrefil_t; + +/** YUV blanking */ +typedef enum +{ + HDMITX_VOUT_YUV_BLNK_16 = 0, /**< 16 */ + HDMITX_VOUT_YUV_BLNK_0 = 1, /**< 0 */ + HDMITX_VOUT_YUV_BLNK_NO_CHANGE = 2, /**< No Change */ + HDMITX_VOUT_YUV_BLNK_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxVoutYuvBlnk_t; + +/** Video quantization range */ +typedef enum +{ + HDMITX_VOUT_QRANGE_FS = 0, /**< Full Scale */ + HDMITX_VOUT_QRANGE_RGB_YUV = 1, /**< RGB Or YUV */ + HDMITX_VOUT_QRANGE_YUV = 2, /**< YUV */ + HDMITX_VOUT_QRANGE_NO_CHANGE = 3, /**< No Change */ + HDMITX_VOUT_QRANGE_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxVoutQrange_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoOutSetSync() parameter types + */ +/** Video sync source */ +typedef enum +{ + HDMITX_VSSRC_INTERNAL = 0, /**< Internal */ + HDMITX_VSSRC_EXTERNAL = 1, /**< External */ + HDMITX_VSSRC_NO_CHANGE = 2, /**< No change */ + HDMITX_VSSRC_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxVsSrc_t; + +/** Video sync toggle */ +typedef enum +{ + HDMITX_VSTGL_TABLE = 0, /**< Vs/Hs polarity from table */ + HDMITX_VSTGL_UNUSED_1 = 1, /**< Unused */ + HDMITX_VSTGL_UNUSED_2 = 2, /**< Unused */ + HDMITX_VSTGL_UNUSED_3 = 3, /**< Unused */ + HDMITX_VSTGL_NO_ACTION = 4, /**< No toggle */ + HDMITX_VSTGL_HS = 5, /**< Toggle Hs */ + HDMITX_VSTGL_VS = 6, /**< Toggle Vs */ + HDMITX_VSTGL_HS_VS = 7, /**< Toggle Hs & Vs */ + HDMITX_VSTGL_NO_CHANGE = 8, /**< No change */ + HDMITX_VSTGL_INVALID = 9 /**< Invalid */ +} tmbslHdmiTxVsTgl_t; + +/*============================================================================*/ +/** + * tmbslTDA9984VideoSetInOut() parameter types + */ +/** Pixel repetition values */ +enum _tmbslHdmiTxPixRepeat +{ + HDMITX_PIXREP_NONE = 0, /**< No repetition */ + HDMITX_PIXREP_MIN = 0, /**< 1 repetition */ + + HDMITX_PIXREP_0 = 0, + HDMITX_PIXREP_1 = 1, + HDMITX_PIXREP_2 = 2, + HDMITX_PIXREP_3 = 3, + HDMITX_PIXREP_4 = 4, + HDMITX_PIXREP_5 = 5, + HDMITX_PIXREP_6 = 6, + HDMITX_PIXREP_7 = 7, + HDMITX_PIXREP_8 = 8, + HDMITX_PIXREP_9 = 9, + + HDMITX_PIXREP_MAX = 9, /**< 10 repetitions */ + HDMITX_PIXREP_DEFAULT = 10, /**< Default repetitions for output format */ + HDMITX_PIXREP_NO_CHANGE = 11, /**< No change */ + HDMITX_PIXREP_INVALID = 12 /**< Invalid */ +}; + +/** Matrix modes */ +typedef enum +{ + HDMITX_MATMODE_OFF = 0, /**< Off */ + HDMITX_MATMODE_AUTO = 1, /**< Auto */ + HDMITX_MATMODE_NO_CHANGE = 2, /**< No change */ + HDMITX_MATMODE_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxMatMode_t; + +/** Datapath bitwidth */ +typedef enum +{ + HDMITX_VOUT_DBITS_12 = 0, /**< 12 bits */ + HDMITX_VOUT_DBITS_8 = 1, /**< 8 bits */ + HDMITX_VOUT_DBITS_10 = 2, /**< 10 bits */ + HDMITX_VOUT_DBITS_NO_CHANGE = 3, /**< No change */ + HDMITX_VOUT_DBITS_INVALID = 4 /**< Invalid */ +} tmbslHdmiTxVoutDbits_t; + +/** Color depth */ +typedef enum +{ + HDMITX_COLORDEPTH_24 = 0, /**< 24 bits per pixel */ + HDMITX_COLORDEPTH_30 = 1, /**< 30 bits per pixel */ + HDMITX_COLORDEPTH_36 = 2, /**< 36 bits per pixel */ + HDMITX_COLORDEPTH_48 = 3, /**< 48 bits per pixel */ + HDMITX_COLORDEPTH_NO_CHANGE = 4, /**< No change */ + HDMITX_COLORDEPTH_INVALID = 5 /**< Invalid */ +} tmbslHdmiTxColorDepth; + +/** the supported transmission formats of 3D video data */ +typedef enum +{ + HDMITX_3D_NONE = 0, /**< 3D video data not present */ + HDMITX_3D_FRAME_PACKING = 1, /**< 3D video data Frame Packing structure */ + HDMITX_3D_TOP_AND_BOTTOM = 2, /**< 3D video data Top and Bottom structure */ + HDMITX_3D_SIDE_BY_SIDE_HALF = 3, /**< 3D video data Side by Side Half structure */ + HDMITX_3D_INVALID = 4 /**< Invalid */ +} tmbslHdmiTx3DStructure_t; + +/*============================================================================*/ +/** + * tmbslTDA9984MatrixSetInputOffset() parameter type + */ +/** Parameter structure array size */ +enum _tmbslHdmiTxMatOffset +{ + HDMITX_MAT_OFFSET_NUM = 3 +}; + +/** \brief The tmbslTDA9984MatrixSetInputOffset() parameter structure */ +typedef struct _tmbslHdmiTxMatOffset_t +{ + /** Offset array (values -1024 to +1023) */ + Int16 Offset[HDMITX_MAT_OFFSET_NUM]; +} tmbslHdmiTxMatOffset_t; + +/** Matrix numeric limits */ +enum _tmbslHdmiTxMatLimits +{ + HDMITX_MAT_OFFSET_MIN = -1024, + HDMITX_MAT_OFFSET_MAX = 1023 +}; + +/*============================================================================*/ +/** + * tmbslTDA9989PowerSetState() and tmbslTDA9989PowerGetState() parameter types + */ +typedef enum +{ + HDMITX_POWER_STATE_STAND_BY = 0, /**< Stand by mode */ + HDMITX_POWER_STATE_SLEEP_MODE = 1, /**< Sleep mode */ + HDMITX_POWER_STATE_ON = 2, /**< On mode */ + HDMITX_POWER_STATE_INVALID = 3 /**< Invalid format */ +} tmbslHdmiTxPowerState_t; + +/** + * \brief Structure describing gamut metadata packet (P0 or P1 profiles) + */ +typedef struct +{ + UInt8 HB[3]; /**< Header bytes (HB0, HB1 & HB2) */ + UInt8 PB[28]; /**< Payload bytes 0..27 */ +} tmbslHdmiTxPktGamut_t; + + +/** + * \brief Structure describing RAW AVI infoframe + */ +typedef struct +{ + UInt8 HB[3]; /**< Header bytes (HB0, HB1 & HB2) */ + UInt8 PB[28]; /**< Payload bytes 0..27 */ +} tmbslHdmiTxPktRawAvi_t; + + +/** Sink category */ +typedef enum +{ + HDMITX_SINK_CAT_NOT_REPEATER = 0, /**< Not repeater */ + HDMITX_SINK_CAT_REPEATER = 1, /**< repeater */ + HDMITX_SINK_CAT_INVALID = 3 /**< Invalid */ +} tmbslHdmiTxSinkCategory_t; + + +typedef struct +{ + Bool latency_available; + Bool Ilatency_available; + UInt8 Edidvideo_latency; + UInt8 Edidaudio_latency; + UInt8 EdidIvideo_latency; + UInt8 EdidIaudio_latency; + +} tmbslHdmiTxEdidLatency_t; + +/** + * \brief Structure defining additional VSDB data + */ +typedef struct +{ + UInt8 maxTmdsClock; /* maximum supported TMDS clock */ + UInt8 cnc0; /* content type Graphics (text) */ + UInt8 cnc1; /* content type Photo */ + UInt8 cnc2; /* content type Cinema */ + UInt8 cnc3; /* content type Game */ + UInt8 hdmiVideoPresent; /* additional video format */ + UInt8 h3DPresent; /* 3D support by the HDMI Sink */ + UInt8 h3DMultiPresent; /* 3D multi strctures present */ + UInt8 imageSize; /* additional info for the values in the image size area */ + UInt8 hdmi3DLen; /* total length of 3D video formats */ + UInt8 hdmiVicLen; /* total length of extended video formats */ + UInt8 ext3DData[21]; /* max_len-10, ie: 31-10=21 */ +} tmbslHdmiTxEdidExtraVsdbData_t; + +/** + * \brief Enum defining possible quantization range + */ +typedef enum +{ + HDMITX_VQR_DEFAULT = 0, /* Follow HDMI spec. */ + HDMITX_RGB_FULL = 1, /* Force RGB FULL , DVI only */ + HDMITX_RGB_LIMITED = 2 /* Force RGB LIMITED , DVI only */ +} tmbslHdmiTxVQR_t; + + + + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLHDMITX_TYPES_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslHdmiTx_funcMapping.h b/drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslHdmiTx_funcMapping.h new file mode 100755 index 0000000000000..f7da28315b72c --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslHdmiTx_funcMapping.h @@ -0,0 +1,141 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslHdmiTx_funcMapping.h + * + * \version $Revision: 2 $ + * +*/ + + + +#ifndef TMDLHDMITXTDA9989_CFG_H +#define TMDLHDMITXTDA9989_CFG_H + +#include "tmbslTDA9989_Functions.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define tmbslHdmiTxInit tmbslTDA9989Init +#define tmbslHdmiTxEdidRequestBlockData tmbslTDA9989EdidRequestBlockData +#define tmbslHdmiTxVideoOutSetConfig tmbslTDA9989VideoOutSetConfig +#define tmbslHdmiTxAudioInResetCts tmbslTDA9989AudioInResetCts +#define tmbslHdmiTxAudioInSetConfig tmbslTDA9989AudioInSetConfig +#define tmbslHdmiTxAudioInSetCts tmbslTDA9989AudioInSetCts +#define tmbslHdmiTxAudioOutSetChanStatus tmbslTDA9989AudioOutSetChanStatus +#define tmbslHdmiTxAudioOutSetChanStatusMapping tmbslTDA9989AudioOutSetChanStatusMapping +#define tmbslHdmiTxAudioOutSetMute tmbslTDA9989AudioOutSetMute +#define tmbslHdmiTxDeinit tmbslTDA9989Deinit +#define tmbslHdmiTxEdidGetAudioCapabilities tmbslTDA9989EdidGetAudioCapabilities +#define tmbslHdmiTxEdidGetBlockCount tmbslTDA9989EdidGetBlockCount +#define tmbslHdmiTxEdidGetStatus tmbslTDA9989EdidGetStatus +#define tmbslHdmiTxEdidGetSinkType tmbslTDA9989EdidGetSinkType +#define tmbslHdmiTxEdidGetSourceAddress tmbslTDA9989EdidGetSourceAddress +#define tmbslHdmiTxEdidGetVideoCapabilities tmbslTDA9989EdidGetVideoCapabilities +#define tmbslHdmiTxEdidGetVideoPreferred tmbslTDA9989EdidGetVideoPreferred +#define tmbslHdmiTxHdcpCheck tmbslTDA9989HdcpCheck +#define tmbslHdmiTxHdcpConfigure tmbslTDA9989HdcpConfigure +#define tmbslHdmiTxHdcpDownloadKeys tmbslTDA9989HdcpDownloadKeys +#define tmbslHdmiTxHdcpEncryptionOn tmbslTDA9989HdcpEncryptionOn +#define tmbslHdmiTxHdcpGetOtp tmbslTDA9989HdcpGetOtp +#define tmbslHdmiTxHdcpGetT0FailState tmbslTDA9989HdcpGetT0FailState +#define tmbslHdmiTxHdcpHandleBCAPS tmbslTDA9989HdcpHandleBCAPS +#define tmbslHdmiTxHdcpHandleBKSV tmbslTDA9989HdcpHandleBKSV +#define tmbslHdmiTxHdcpHandleBKSVResult tmbslTDA9989HdcpHandleBKSVResult +#define tmbslHdmiTxHdcpHandleBSTATUS tmbslTDA9989HdcpHandleBSTATUS +#define tmbslHdmiTxHdcpHandleENCRYPT tmbslTDA9989HdcpHandleENCRYPT +#define tmbslHdmiTxHdcpHandlePJ tmbslTDA9989HdcpHandlePJ +#define tmbslHdmiTxHdcpHandleSHA_1 tmbslTDA9989HdcpHandleSHA_1 +#define tmbslHdmiTxHdcpHandleSHA_1Result tmbslTDA9989HdcpHandleSHA_1Result +#define tmbslHdmiTxHdcpHandleT0 tmbslTDA9989HdcpHandleT0 +#define tmbslHdmiTxHdcpInit tmbslTDA9989HdcpInit +#define tmbslHdmiTxHdcpRun tmbslTDA9989HdcpRun +#define tmbslHdmiTxHdcpStop tmbslTDA9989HdcpStop +#define tmbslHdmiTxHotPlugGetStatus tmbslTDA9989HotPlugGetStatus +#define tmbslHdmiTxRxSenseGetStatus tmbslTDA9989RxSenseGetStatus +#define tmbslHdmiTxHwGetRegisters tmbslTDA9989HwGetRegisters +#define tmbslHdmiTxHwGetVersion tmbslTDA9989HwGetVersion +#define tmbslHdmiTxHwGetCapabilities tmbslTDA9989HwGetCapabilities +#define tmbslHdmiTxHwHandleInterrupt tmbslTDA9989HwHandleInterrupt +#define tmbslHdmiTxHwSetRegisters tmbslTDA9989HwSetRegisters +#define tmbslHdmiTxHwStartup tmbslTDA9989HwStartup +#define tmbslHdmiTxMatrixSetCoeffs tmbslTDA9989MatrixSetCoeffs +#define tmbslHdmiTxMatrixSetConversion tmbslTDA9989MatrixSetConversion +#define tmbslHdmiTxMatrixSetInputOffset tmbslTDA9989MatrixSetInputOffset +#define tmbslHdmiTxMatrixSetMode tmbslTDA9989MatrixSetMode +#define tmbslHdmiTxMatrixSetOutputOffset tmbslTDA9989MatrixSetOutputOffset +#define tmbslHdmiTxPktSetAclkRecovery tmbslTDA9989PktSetAclkRecovery +#define tmbslHdmiTxPktSetAcp tmbslTDA9989PktSetAcp +#define tmbslHdmiTxPktSetAudioInfoframe tmbslTDA9989PktSetAudioInfoframe +#define tmbslHdmiTxPktSetGeneralCntrl tmbslTDA9989PktSetGeneralCntrl +#define tmbslHdmiTxPktSetIsrc1 tmbslTDA9989PktSetIsrc1 +#define tmbslHdmiTxPktSetIsrc2 tmbslTDA9989PktSetIsrc2 +#define tmbslHdmiTxPktSetMpegInfoframe tmbslTDA9989PktSetMpegInfoframe +#define tmbslHdmiTxPktSetNullInsert tmbslTDA9989PktSetNullInsert +#define tmbslHdmiTxPktSetNullSingle tmbslTDA9989PktSetNullSingle +#define tmbslHdmiTxPktSetSpdInfoframe tmbslTDA9989PktSetSpdInfoframe +#define tmbslHdmiTxPktSetVideoInfoframe tmbslTDA9989PktSetVideoInfoframe +#define tmbslHdmiTxPktSetVsInfoframe tmbslTDA9989PktSetVsInfoframe +#define tmbslHdmiTxPktSetRawVideoInfoframe tmbslTDA9989PktSetRawVideoInfoframe +#define tmbslHdmiTxPowerGetState tmbslTDA9989PowerGetState +#define tmbslHdmiTxPowerSetState tmbslTDA9989PowerSetState +#define tmbslHdmiTxReset tmbslTDA9989Reset +#define tmbslHdmiTxScalerGet tmbslTDA9989ScalerGet +#define tmbslHdmiTxScalerGetMode tmbslTDA9989ScalerGetMode +#define tmbslHdmiTxScalerInDisable tmbslTDA9989ScalerInDisable +#define tmbslHdmiTxScalerSetCoeffs tmbslTDA9989ScalerSetCoeffs +#define tmbslHdmiTxScalerSetFieldOrder tmbslTDA9989ScalerSetFieldOrder +#define tmbslHdmiTxScalerSetFine tmbslTDA9989ScalerSetFine +#define tmbslHdmiTxScalerSetPhase tmbslTDA9989ScalerSetPhase +#define tmbslHdmiTxScalerSetLatency tmbslTDA9989ScalerSetLatency +#define tmbslHdmiTxScalerSetSync tmbslTDA9989ScalerSetSync +#define tmbslHdmiTxSwGetVersion tmbslTDA9989SwGetVersion +#define tmbslHdmiTxSysTimerWait tmbslTDA9989SysTimerWait +#define tmbslHdmiTxTmdsSetOutputs tmbslTDA9989TmdsSetOutputs +#define tmbslHdmiTxTmdsSetSerializer tmbslTDA9989TmdsSetSerializer +#define tmbslHdmiTxTestSetPattern tmbslTDA9989TestSetPattern +#define tmbslHdmiTxTestSetMode tmbslTDA9989TestSetMode +#define tmbslHdmiTxVideoInSetBlanking tmbslTDA9989VideoInSetBlanking +#define tmbslHdmiTxVideoInSetConfig tmbslTDA9989VideoInSetConfig +#define tmbslHdmiTxVideoInSetFine tmbslTDA9989VideoInSetFine +#define tmbslHdmiTxVideoInSetMapping tmbslTDA9989VideoInSetMapping +#define tmbslHdmiTxSetVideoPortConfig tmbslTDA9989SetVideoPortConfig +#define tmbslHdmiTxSetAudioPortConfig tmbslTDA9989SetAudioPortConfig +#define tmbslHdmiTxSetAudioClockPortConfig tmbslTDA9989SetAudioClockPortConfig +#define tmbslHdmiTxVideoInSetSyncAuto tmbslTDA9989VideoInSetSyncAuto +#define tmbslHdmiTxVideoInSetSyncManual tmbslTDA9989VideoInSetSyncManual +#define tmbslHdmiTxVideoOutDisable tmbslTDA9989VideoOutDisable +#define tmbslHdmiTxVideoOutSetSync tmbslTDA9989VideoOutSetSync +#define tmbslHdmiTxVideoSetInOut tmbslTDA9989VideoSetInOut +#define tmbslHdmiTxFlagSwInt tmbslTDA9989FlagSwInt +#define tmbslHdmiTxSet5vpower tmbslTDA9989Set5vpower +#define tmbslHdmiTxEnableCallback tmbslTDA9989EnableCallback +#define tmbslHdmiTxSetColorDepth tmbslTDA9989SetColorDepth +#define tmbslHdmiTxSetDefaultPhase tmbslTDA9989SetDefaultPhase +#define tmbslHdmiTxPktFillGamut tmbslTDA9989PktFillGamut +#define tmbslHdmiTxPktSendGamut tmbslTDA9989PktSendGamut +#define tmbslHdmiTxEdidGetMonitorDescriptors tmbslTDA9989EdidGetMonitorDescriptors +#define tmbslHdmiTxEdidGetDetailedTimingDescriptors tmbslTDA9989EdidGetDetailedTimingDescriptors +#define tmbslHdmiTxEdidGetBasicDisplayParam tmbslTDA9989EdidGetBasicDisplayParam +#define tmbslHdmiTxHdcpGetSinkCategory tmbslTDA9989HdcpGetSinkCategory +#define tmbslHdmiTxEdidGetLatencyInfo tmbslTDA9989EdidGetLatencyInfo +#define tmbslHdmiTxEdidGetExtraVsdbData tmbslTDA9989EdidGetExtraVsdbData +#ifdef TMFL_TDA19989 +#define tmbslHdmiTxHdcpPowerDown tmbslTDA9989HdcpPowerDown +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMITXTDA9989_CFG_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslTDA9989_Functions.h b/drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslTDA9989_Functions.h new file mode 100755 index 0000000000000..da9b27f11808a --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/inc/tmbslTDA9989_Functions.h @@ -0,0 +1,3060 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_functions.h + * + * \version $Revision: 2 $ + * + * +*/ + +#ifndef TMBSLTDA9989_FUNCTIONS_H +#define TMBSLTDA9989_FUNCTIONS_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmNxCompId.h" +#include "tmbslHdmiTx_types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/*============================================================================*/ +/** + \brief Reset the Clock Time Stamp generator in HDMI mode only + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: in DVI mode + */ +tmErrorCode_t +tmbslTDA9989AudioInResetCts +( + tmUnitSelect_t txUnit +); + +/** + \brief Set audio input configuration in HDMI mode only + + \param[in] txUnit Transmitter unit number + \param[in] aFmt Audio input format + \param[in] i2sFormat I2s format type + \param[in] chanI2s I2S channel allocation + \param[in] chanDsd DSD channel allocation + \param[in] clkPolDsd DSD clock polarity + \param[in] swapDsd DSD data swap + \param[in] layout Sample layout + \param[in] latency_rd Audio FIFO read latency + \param[in] dstRate Dst rate (not used) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: in DVI mode + */ +tmErrorCode_t +tmbslTDA9989AudioInSetConfig +( + tmUnitSelect_t txUnit, + tmbslHdmiTxaFmt_t aFmt, + tmbslHdmiTxI2sFor_t i2sFormat, + UInt8 chanI2s, + UInt8 chanDsd, + tmbslHdmiTxClkPolDsd_t clkPolDsd, + tmbslHdmiTxSwapDsd_t swapDsd, + UInt8 layout, + UInt16 latency_rd, + tmbslHdmiTxDstRate_t dstRate +); + + +/** + \brief Set the Clock Time Stamp generator in HDMI mode only + + \param[in] txUnit Transmitter unit number + \param[in] ctsRef Clock Time Stamp reference source + \param[in] afs Audio input sample frequency + \param[in] voutFmt Video output format + \param[in] voutFreq Vertical output frequency + \param[in] uCts Manual Cycle Time Stamp + \param[in] uCtsX Clock Time Stamp factor x + \param[in] ctsK Clock Time Stamp predivider k + \param[in] ctsM Clock Time Stamp postdivider m + \param[in] dstRate Dst rate (not used) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: in DVI mode + */ +tmErrorCode_t +tmbslTDA9989AudioInSetCts +( + tmUnitSelect_t txUnit, + tmbslHdmiTxctsRef_t ctsRef, + tmbslHdmiTxafs_t afs, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVfreq_t voutFreq, + UInt32 uCts, + UInt16 uCtsX, + tmbslHdmiTxctsK_t ctsK, + tmbslHdmiTxctsM_t ctsM, + tmbslHdmiTxDstRate_t dstRate +); + +/** + \brief Set the Channel Status Bytes 0,1,3 & 4 + + \param[in] txUnit Transmitter unit number + \param[in] copyright Byte 0 Copyright bit (bit2) + \param[in] formatInfo Byte 0 Audio sample format (bit1) and additional info (bit345) + \param[in] categoryCode Byte 1 Category code (bits8-15) + \param[in] sampleFreq Byte 3 Sample Frequency (bits24-27) + \param[in] clockAccuracy Byte 3 Clock Accuracy (bits38-31) + \param[in] maxWordLength Byte 4 Maximum word length (bit32) + \param[in] wordLength Byte 4 Word length (bits33-35) + \param[in] origSampleFreq Byte 4 Original Sample Frequency (bits36-39) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: in DVI mode + + \note The consumer use bit (bit0) and Mode bits (bits6-7) are forced to zero. + Use tmbslTDA9989AudioOutSetChanStatusMapping to set CS Byte 2. + + */ +tmErrorCode_t +tmbslTDA9989AudioOutSetChanStatus +( + tmUnitSelect_t txUnit, + tmbslHdmiTxAudioData_t pcmIdentification, + tmbslHdmiTxCSformatInfo_t formatInfo, + tmbslHdmiTxCScopyright_t copyright, + UInt8 categoryCode, + tmbslHdmiTxafs_t sampleFreq, + tmbslHdmiTxCSclkAcc_t clockAccuracy, + tmbslHdmiTxCSmaxWordLength_t maxWordLength, + tmbslHdmiTxCSwordLength_t wordLength, + tmbslHdmiTxCSorigAfs_t origSampleFreq +); + +/** + \brief Set the Channel Status Byte2 for Audio Port 0 + + \param[in] txUnit Transmitter unit number + \param[in] sourceLeft L Source Number: 0 don't take into account, 1-15 + \param[in] channelLeft L Channel Number: 0 don't take into account, 1-15 + \param[in] sourceRight R Source Number: 0 don't take into account, 1-15 + \param[in] channelRight R Channel Number: 0 don't take into account, 1-15 + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: in DVI mode + + \note Use tmbslTDA9989AudioOutSetChanStatus to set all other CS bytes + This function only sets the mapping for Audio Port 0. + + */ +tmErrorCode_t +tmbslTDA9989AudioOutSetChanStatusMapping +( + tmUnitSelect_t txUnit, + UInt8 sourceLeft[4], + UInt8 channelLeft[4], + UInt8 sourceRight[4], + UInt8 channelRight[4] +); + +/** + \brief Mute or un-mute the audio output by controlling the audio FIFO, + in HDMI mode only + + \param[in] txUnit Transmitter unit number + \param[in] aMute Audio mute: On, Off + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: in DVI mode + + \note tmbslTDA9989PktSetGeneralCntrl must be used to control the audio + mute in outgoing data island packets + + */ +tmErrorCode_t +tmbslTDA9989AudioOutSetMute +( + tmUnitSelect_t txUnit, + tmbslHdmiTxaMute_t aMute +); + + +/*============================================================================*/ +/** + \brief Disable an HDMI Transmitter output and destroy its driver + instance + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: the unit is not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989Deinit +( + tmUnitSelect_t txUnit +); + + +/** + \brief Get supported audio format(s) from previously read EDID + + \param[in] txUnit Transmitter unit number + \param[out] pEdidAFmts Pointer to the array of structures to receive the + supported Short Audio Descriptors + \param[in] aFmtLength Number of SADs supported in buffer pEdidAFmts, + up to HDMI_TX_SAD_MAX_CNT + \param[out] pAFmtsAvail Pointer to receive the number of SADs available + \param[out] pAudioFlags Pointer to the byte to receive the Audio Capability + Flags + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + + \note \verbatim + Supported Short Audio Descriptors array: + EdidAFmts[0].ModeChans SAD 1 - Mode byte + EdidAFmts[0].Freqs SAD 1 - Frequencies byte + EdidAFmts[0].Byte3 SAD 1 - Byte 3 + ... + EdidAFmts[n-1].ModeChans SAD n - Mode byte + EdidAFmts[n-1].Freqs SAD n - Frequencies byte + EdidAFmts[n-1].Byte3 SAD n - Byte 3 + (Where n is the smaller of aFmtLength and pAFmtAvail) + \endverbatim + */ +tmErrorCode_t +tmbslTDA9989EdidGetAudioCapabilities +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidSad_t *pEdidAFmts, + UInt aFmtLength, + UInt *pAFmtsAvail, + UInt8 *pAudioFlags +); + +/*============================================================================*/ +/** + \brief Get the EDID block count + + \param[in] txUnit Transmitter unit number + \param[out] puEdidBlockCount Pointer to data byte in which to return the + block count + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989EdidGetBlockCount +( + tmUnitSelect_t txUnit, + UInt8 *puEdidBlockCount +); + +/*============================================================================*/ +/** + \brief Get the EDID status + + \param[in] txUnit Transmitter unit number + \param[out] puEdidBlockCount Pointer to data byte in which to return the + edid status + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989EdidGetStatus +( + tmUnitSelect_t txUnit, + UInt8 *puEdidStatus +); + +/** + \brief Request read of EDID blocks from the sink device via DDC + function not synchronous edid will available on + EDID_BLK_READ callback + + + \param[in] txUnit Transmitter unit number + \param[out] pRawEdid Pointer to a buffer supplied by the caller to accept + the raw EDID data. + \param[in] numBlocks Number of blocks to read + \param[in] lenRawEdid Length in bytes of the supplied buffer + \param[out] pEdidStatus Pointer to status value E_EDID_READ or E_EDID_ERROR + valid only when the return value is TM_OK + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE: EDID not read + + \note NA + + */ + +tmErrorCode_t +tmbslTDA9989EdidRequestBlockData +( + tmUnitSelect_t txUnit, + UInt8 *pRawEdid, + Int numBlocks, /* Only relevant if pRawEdid valid */ + Int lenRawEdid /* Only relevant if pRawEdid valid */ +); + + +/** + \brief Get Sink Type by analysis of EDID content + + \param[in] txUnit Transmitter unit number + \param[out] pSinkType Pointer to returned Sink Type: DVI or HDMI + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : edid not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NULL_CONNECTION: HPD pin is inactive + + \sa tmbslTDA9989EdidGetBlockData + */ +tmErrorCode_t +tmbslTDA9989EdidGetSinkType +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkType_t *pSinkType +); + +/*============================================================================*/ +/** + \brief Get Source Physical Address by analysis of EDID content + + \param[in] txUnit Transmitter unit number + \param[out] pSourceAddress Pointer to returned Source Physical Address (ABCDh) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + + \sa tmbslTDA9989EdidGetBlockData + */ +tmErrorCode_t +tmbslTDA9989EdidGetSourceAddress +( + tmUnitSelect_t txUnit, + UInt16 *pSourceAddress +); + +/** + \brief Get supported video format(s) from previously read EDID + + \param[in] txUnit Transmitter unit number + \param[out] pEdidVFmts Pointer to the array to receive the supported Short + Video Descriptors + \param[in] vFmtLength Number of SVDs supported in buffer pEdidVFmts, + up to HDMI_TX_SVD_MAX_CNT + \param[out] pVFmtsAvail Pointer to receive the number of SVDs available + \param[out] pVidFlags Ptr to the byte to receive Video Capability Flags + b7: underscan supported + b6: YCbCr 4:4:4 supported + b5: YCbCr 4:2:2 supported + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NULL_CONNECTION: HPD pin is inactive + + \note \verbatim + Supported Short Video Descriptors array: + (HDMI_TX_SVD_NATIVE_MASK bit set to indicate native format) + EdidVFmts[0] EIA/CEA Short Video Descriptor 1, or 0 + ... + EdidVFmts[n-1] EIA/CEA Short Video Descriptor 32, or 0 + (Where n is the smaller of vFmtLength and pVFmtAvail) + \endverbatim + \sa tmbslTDA9989EdidGetBlockData + */ +tmErrorCode_t +tmbslTDA9989EdidGetVideoCapabilities +( + tmUnitSelect_t txUnit, + UInt8 *pEdidVFmts, + UInt vFmtLength, + UInt *pVFmtsAvail, + UInt8 *pVidFlags +); +/** + \brief Get detailed timing descriptor from previously read EDID + + \param[in] txUnit Transmitter unit number + \param[out] pEdidDTD Pointer to the array to receive the Detailed timing descriptor + + \param[in] nb_size Number of DTD supported in buffer pEdidDTD + + \param[out] pDTDAvail Pointer to receive the number of DTD available + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized +*/ +tmErrorCode_t +tmbslTDA9989EdidGetDetailedTimingDescriptors +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidDtd_t *pEdidDTD, + UInt8 nb_size, + UInt8 *pDTDAvail +); + +/** + \brief Get detailed Monitor descriptor from previously read EDID + + \param[in] txUnit Transmitter unit number + \param[out] pEdidFirstMD Pointer to the First Monitor descriptor + \param[out] pEdidSecondMD Pointer to the Second Monitor descriptor + \param[out] pEdidOtherMD Pointer to the Other Monitor descriptor + \param[in] sizeOtherMD Not used + \param[out] pOtherMDAvail Not used + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized +*/ +tmErrorCode_t +tmbslTDA9989EdidGetMonitorDescriptors +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidFirstMD_t *pEdidFirstMD, + tmbslHdmiTxEdidSecondMD_t *pEdidSecondMD, + tmbslHdmiTxEdidOtherMD_t *pEdidOtherMD, + UInt8 sizeOtherMD, + UInt8 *pOtherMDAvail +); + +/** + \brief Get basic display parameters from previously read EDID + + \param[in] txUnit Transmitter unit number + \param[out] pEdidBDParam Pointer to the Basic Display Parameters + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized +*/ +tmErrorCode_t +tmbslTDA9989EdidGetBasicDisplayParam +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidBDParam_t *pEdidBDParam +); + + +/** + \brief Get preferred video format from previously read EDID + + \param[in] txUnit Transmitter unit number + \param[out] pEdidDTD Pointer to the structure to receive the Detailed + Timing Descriptor parameters of the preferred video + format + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NULL_CONNECTION: HPD pin is inactive + + \note \verbatim + Detailed Timing Descriptor parameters output structure: + UInt16 uPixelClock Pixel Clock (MHz/10,000) + UInt16 uHActivePixels Horizontal Active Pixels + UInt16 uHBlankPixels Horizontal Blanking Pixels + UInt16 uVActiveLines Vertical Active Lines + UInt16 uVBlankLines Vertical Blanking Lines + UInt16 uHSyncOffset Horizontal Sync Offset (Pixels) + UInt16 uHSyncWidth Horizontal Sync Pulse Width (Pixels) + UInt16 uVSyncOffset Vertical Sync Offset (Lines) + UInt16 uVSyncWidth Vertical Sync Pulse Width (Lines) + UInt16 uHImageSize Horizontal Image Size (mm) + UInt16 uVImageSize Vertical Image Size (mm) + UInt16 uHBorderPixels Horizontal Border (Pixels) + UInt16 uVborderPixels Vertical Border (Pixels) + UInt8 Flags Interlace/sync info + \endverbatim + \sa tmbslTDA9989EdidGetBlockData + */ +tmErrorCode_t +tmbslTDA9989EdidGetVideoPreferred +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidDtd_t *pEdidDTD +); + +/** + \brief Check the result of an HDCP encryption attempt, called at + intervals (set by uTimeSinceLastCallMs) after tmbslTDA9989HdcpRun + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] uTimeSinceLastCallMs Time in ms since this was last called + \param[out] pResult The outcome of the check + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + */ +tmErrorCode_t +tmbslTDA9989HdcpCheck +( + tmUnitSelect_t txUnit, + UInt16 uTimeSinceLastCallMs, + tmbslHdmiTxHdcpCheck_t *pResult +); + +/** + \brief Configure various HDCP parameters + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] slaveAddress DDC I2C slave address + \param[in] txMode Mode of our transmitter device + \param[in] options Options flags to control behaviour of HDCP + \param[in] uCheckIntervalMs HDCP check interval in milliseconds + \param[in] uChecksToDo Number of HDCP checks to do after HDCP starts + A value of 2 or more is valid for checking + May be set to 0 to disabling checking + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + + \note Must be called before all other HDCP APIs + */ +tmErrorCode_t +tmbslTDA9989HdcpConfigure +( + tmUnitSelect_t txUnit, + UInt8 slaveAddress, + tmbslHdmiTxHdcpTxMode_t txMode, + tmbslHdmiTxHdcpOptions_t options, + UInt16 uCheckIntervalMs, + UInt8 uChecksToDo +); + +/** + \brief Download keys and AKSV data from OTP memory to the device + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[in] seed Seed value + \param[in] keyDecryption State of key decryption 0 to 1 (disabled, enabled) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + */ +tmErrorCode_t +tmbslTDA9989HdcpDownloadKeys +( + tmUnitSelect_t txUnit, + UInt16 seed, + tmbslHdmiTxDecrypt_t keyDecryption +); + +/*============================================================================*/ +/** + \brief Switch HDCP encryption on or off without disturbing Infoframes + (Not normally used) + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] bOn Encryption state: 1=on, 0=off + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP +*/ +tmErrorCode_t +tmbslTDA9989HdcpEncryptionOn +( + tmUnitSelect_t txUnit, + Bool bOn +); + +/*============================================================================*/ +/** + \brief Get HDCP OTP registers + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] otpAddress OTP start address 0-FF + \param[out] pOtpData Ptr to a three-byte array to hold the data read: + [0] = OTP_DATA_MSB + [1] = OTP_DATA_ISB + [2] = OTP_DATA_LSB + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP +*/ +tmErrorCode_t +tmbslTDA9989HdcpGetOtp +( + tmUnitSelect_t txUnit, + UInt8 otpAddress, + UInt8 *pOtpData +); + +/*============================================================================*/ +/** + \brief Return the failure state that caused the last T0 interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[out] pFailState Ptr to the unit's last T0 fail state + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP +*/ +tmErrorCode_t +tmbslTDA9989HdcpGetT0FailState +( + tmUnitSelect_t txUnit, + UInt8 *pFailState +); + +/*============================================================================*/ +/** + \brief Handle BCAPS interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note The user BCAPS interrupt handler (registered with + tmbslTDA9989Init) calls this API before calling + tmbslTDA9989HdcpHandleBKSV +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBCAPS +( + tmUnitSelect_t txUnit +); + +/*============================================================================*/ +/** + \brief Read BKSV registers + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[out] pBksv Pointer to 5-byte BKSV array returned to caller + (1st byte is MSB) + \param[out] pbCheckRequired Pointer to a result variable to tell the caller + whether to check for BKSV in a revocation list: + 0 or 1 (check not required, check required) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note The user BCAPS interrupt handler (registered with + tmbslTDA9989Init) calls this API after calling + tmbslTDA9989HdcpHandleBCAPS +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBKSV +( + tmUnitSelect_t txUnit, + UInt8 *pBksv, + Bool *pbCheckRequired +); + +/*============================================================================*/ +/** + \brief Declare BKSV result to be secure or not secure + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[in] bSecure Result of user's check of BKSV against a + revocation list: + 0 (not secure: BKSV found in revocation list) + 1 (secure: BKSV not found in revocation list) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note The user BCAPS interrupt handler (registered with + tmbslTDA9989Init) calls this API after calling + tmbslTDA9989HdcpHandleBKSV +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBKSVResult +( + tmUnitSelect_t txUnit, + Bool bSecure +); + +/** + \brief Handle BSTATUS interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[out] pBstatus Pointer to 16-bit BSTATUS value returned to caller + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note Called by user's BSTATUS interrupt handler registered with + tmbslTDA9989Init +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBSTATUS +( + tmUnitSelect_t txUnit, + UInt16 *pBstatus +); + +/*============================================================================*/ +/** + \brief Handle ENCRYPT interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note Called by user's ENCRYPT interrupt handler registered with + tmbslTDA9989Init +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleENCRYPT +( + tmUnitSelect_t txUnit +); + +/*============================================================================*/ +/** + \brief Handle PJ interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note Called by user's PJ interrupt handler registered with + tmbslTDA9989Init +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandlePJ +( + tmUnitSelect_t txUnit +); + +/** + \brief Handle SHA-1 interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[in] maxKsvDevices Maximum number of 5-byte devices that will fit + in *pKsvList: 0 to 128 devices + If 0, no KSV read is done and it is treated as + secure + \param[out] pKsvList Pointer to KSV list array supplied by caller: + Sets of 5-byte KSVs, 1 per device, 1st byte is + LSB of 1st device + May be null if maxKsvDevices is 0 + \param[out] pnKsvDevices Pointer to number of KSV devices copied to + *pKsvList: 0 to 128 + If 0, no KSV check is needed and it is treated + as secure + May be null if maxKsvDevices is 0 + \param[out] pDepth Connection tree depth + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: two parameters disagree + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note Called by user's SHA-1 interrupt handler registered with + tmbslTDA9989Init +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleSHA_1 +( + tmUnitSelect_t txUnit, + UInt8 maxKsvDevices, + UInt8 *pKsvList, + UInt8 *pnKsvDevices, + UInt8 *pDepth +); + +/*============================================================================*/ +/** + \brief Declare KSV list result to be secure or not secure + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[in] bSecure Result of user's check of KSV list against a + revocation list: + 0 (not secure: one or more KSVs are in r.list) + 1 (secure: no KSV found in revocation list) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note The user SHA_1 interrupt handler (registered with + tmbslTDA9989Init) calls this API after calling + tmbslTDA9989HdcpHandleSHA_1 +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleSHA_1Result +( + tmUnitSelect_t txUnit, + Bool bSecure +); + +/*============================================================================*/ +/** + \brief Handle T0 interrupt + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + + \note Called by user's T0 interrupt handler registered with + tmbslTDA9989Init +*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleT0 +( + tmUnitSelect_t txUnit +); + +/*============================================================================*/ +/** + \brief Prepare for HDCP operation + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] voutFmt Video output format + \param[in] voutFreq Vertical output frequency + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + + \note Must be called before tmbslTDA9989HdcpRun +*/ +tmErrorCode_t +tmbslTDA9989HdcpInit +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVfreq_t voutFreq +); + +/*============================================================================*/ +/** + \brief Start HDCP operation + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + + \note Must be called after tmbslTDA9989HdcpInit +*/ +tmErrorCode_t +tmbslTDA9989HdcpRun +( + tmUnitSelect_t txUnit +); + +/*============================================================================*/ +/** + \brief Stop HDCP operation, and cease encrypting the output + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + + \note This will trigger an Encrypt interrupt +*/ +tmErrorCode_t +tmbslTDA9989HdcpStop +( + tmUnitSelect_t txUnit +); +/** + \brief Get the hot plug input status last read by tmbslTDA9989Init + or tmbslTDA9989HwHandleInterrupt + + \param[in] txUnit Transmitter unit number + \param[out] pHotPlugStatus Pointer to returned Hot Plug Detect status + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989HotPlugGetStatus +( + tmUnitSelect_t txUnit, + tmbslHdmiTxHotPlug_t *pHotPlugStatus, + Bool client /* Used to determine whether the request comes from the application */ +); + +/** + \brief Get the rx sense input status last read by tmbslTDA9989Init + or tmbslTDA9989HwHandleInterrupt + + \param[in] txUnit Transmitter unit number + \param[out] pRxSenseStatus Pointer to returned Rx Sense Detect status + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989RxSenseGetStatus +( + tmUnitSelect_t txUnit, + tmbslHdmiTxRxSense_t *pRxSenseStatus, + Bool client /* Used to determine whether the request comes from the application */ +); + +/*============================================================================*/ +/** + \brief Get one or more hardware I2C register values + + \param[in] txUnit Transmitter unit number + \param[in] regPage The device register's page: 00h, 01h, 02h, 11h, 12h + \param[in] regAddr The starting register address on the page: 0 to FFh + \param[out] pRegBuf Pointer to buffer to receive the register data + \param[in] nRegs Number of contiguous registers to read: 1 to 254 + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + */ +tmErrorCode_t +tmbslTDA9989HwGetRegisters +( + tmUnitSelect_t txUnit, + Int regPage, + Int regAddr, + UInt8 *pRegBuf, + Int nRegs +); + +/*============================================================================*/ +/** + \brief Get the transmitter device version read at initialization + + \param[in] txUnit Transmitter unit number + \param[out] puDeviceVersion Pointer to returned hardware version + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989HwGetVersion +( + tmUnitSelect_t txUnit, + UInt8 *puDeviceVersion +); + + +/** + \brief Get the transmitter device feature read at initialization + + \param[in] txUnit Transmitter unit number + \param[in] deviceFeature Hardware feature to check + \param[out] pFeatureSupported Hardware feature supported or not + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + */ +tmErrorCode_t +tmbslTDA9989HwGetCapabilities +( + tmUnitSelect_t txUnit, + tmbslHdmiTxHwFeature_t deviceCapability, + Bool *pFeatureSupported +); + + +/*============================================================================*/ +/** + \brief Handle all hardware interrupts from a transmitter unit + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + \note This function must be called at task level not interrupt level, + as I2C access is required + */ +tmErrorCode_t +tmbslTDA9989HwHandleInterrupt +( + tmUnitSelect_t txUnit +); + + +/*============================================================================*/ +/** + \brief Set one or more hardware I2C registers + + \param[in] txUnit Transmitter unit number + \param[in] regPage The device register's page: 00h, 01h, 02h, 11h, 12h + \param[in] regAddr The starting register address on the page: 0 to FFh + \param[in] pRegBuf Ptr to buffer from which to write the register data + \param[in] nRegs Number of contiguous registers to write: 0 to 254. + The page register (255) may not be written - it is + written to automatically here. If nRegs is 0, the + page register is the only register written. + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989HwSetRegisters +( + tmUnitSelect_t txUnit, + Int regPage, + Int regAddr, + UInt8 *pRegBuf, + Int nRegs +); + + +/*============================================================================*/ +/** + \brief Handle hardware startup by resetting Device Instance Data + */ +void +tmbslTDA9989HwStartup +( + void +); + +/** + \brief Create an instance of an HDMI Transmitter: initialize the + driver, reset the transmitter device and get the current + Hot Plug state + + \param[in] txUnit Transmitter unit number + \param[in] uHwAddress Device I2C slave address + \param[in] sysFuncWrite System function to write I2C + \param[in] sysFuncRead System function to read I2C + \param[in] sysFuncEdidRead System function to read EDID blocks via I2C + \param[in] sysFuncTimer System function to run a timer + \param[in] funcIntCallbacks Pointer to interrupt callback function list + The list pointer is null for no callbacks; + each pointer in the list may also be null. + \param[in] bEdidAltAddr Use alternative i2c address for EDID data + register between Driver and TDA9983/2: + 0 - use default address (A0) + 1 - use alternative address (A2) + \param[in] vinFmt EIA/CEA Video input format: 1 to 31, 0 = No Change + \param[in] pixRate Single data (repeated or not) or double data rate + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the transmitter instance is already initialised + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_INIT_FAILED: the unit instance is already + initialised + - TMBSL_ERR_HDMI_COMPATIBILITY: the driver is not compatiable + with the internal device version code + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + */ +tmErrorCode_t +tmbslTDA9989Init +( + tmUnitSelect_t txUnit, + UInt8 uHwAddress, + ptmbslHdmiTxSysFunc_t sysFuncWrite, + ptmbslHdmiTxSysFunc_t sysFuncRead, + ptmbslHdmiTxSysFuncEdid_t sysFuncEdidRead, + ptmbslHdmiTxSysFuncTimer_t sysFuncTimer, + tmbslHdmiTxCallbackList_t *funcIntCallbacks, + Bool bEdidAltAddr, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTxPixRate_t pixRate +); + +/** + \brief Set colour space converter matrix coefficients + + \param[in] txUnit Transmitter unit number + \param[in] pMatCoeff Pointer to Matrix Coefficient structure + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note Matrix Coefficient parameter structure: + Int16 Coeff[9]: Array of coefficients (values -1024 to +1023) + */ +tmErrorCode_t +tmbslTDA9989MatrixSetCoeffs +( + tmUnitSelect_t txUnit, + tmbslHdmiTxMatCoeff_t *pMatCoeff +); + +/** + \brief Set colour space conversion using preset values + + \param[in] txUnit Transmitter unit number + \param[in] vinFmt Input video format + \param[in] vinMode Input video mode + \param[in] voutFmt Output video format + \param[in] voutMode Output video mode + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989MatrixSetConversion +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVoutMode_t voutMode, + tmbslHdmiTxVQR_t dviVqr +); + +/** + \brief Set colour space converter matrix offset at input + + \param[in] txUnit Transmitter unit number + \param[in] pMatOffset Pointer to Matrix Offset structure + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + + \note Matrix Offset structure parameter structure: + Int16 Offset[3]: Offset array (values -1024 to +1023) + */ +tmErrorCode_t +tmbslTDA9989MatrixSetInputOffset +( + tmUnitSelect_t txUnit, + tmbslHdmiTxMatOffset_t *pMatOffset +); + +/** + \brief Set colour space converter matrix mode + + \param[in] txUnit Transmitter unit number + \param[in] mControl Matrix Control: On, Off, No change + \param[in] mScale Matrix Scale Factor: 1/256, 1/512, 1/1024, No change + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + + \note NA + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989MatrixSetMode +( + tmUnitSelect_t txUnit, + tmbslHdmiTxmCntrl_t mControl, + tmbslHdmiTxmScale_t mScale +); + +/*============================================================================*/ +/** + \brief Set colour space converter matrix offset at output + + \param[in] txUnit Transmitter unit number + \param[in] pMatOffset Pointer to Matrix Offset structure + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + + \note Matrix Offset parameter structure: + nt16 Offset[3]: Offset array (values -1024 to +1023) + */ +tmErrorCode_t +tmbslTDA9989MatrixSetOutputOffset +( + tmUnitSelect_t txUnit, + tmbslHdmiTxMatOffset_t *pMatOffset +); + +/*============================================================================*/ +/** + \brief Enable audio clock recovery packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: when in DVI mode + + \note tmbslTDA9989AudioInSetCts sets CTS and N values + */ +tmErrorCode_t +tmbslTDA9989PktSetAclkRecovery +( + tmUnitSelect_t txUnit, + Bool bEnable +); + +/** + \brief Set audio content protection packet & enable/disable packet + insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Data Island Packet structure + \param[in] byteCnt Packet buffer byte count + \param[in] uAcpType Content protection type + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: pointer suppied with byte count of zero + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: not possible with this device + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Data Island Packet parameter structure: + UInt8 dataByte[28] Packet Data + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989PktSetAcp +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + UInt8 uAcpType, + Bool bEnable +); + +/** + \brief Set audio info frame packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Audio Infoframe structure + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Audio Infoframe structure: + UInt8 CodingType + UInt8 ChannelCount + UInt8 SampleFreq + UInt8 SampleSize + UInt8 ChannelAlloc + Bool DownMixInhibit + UInt8 LevelShift + */ +tmErrorCode_t +tmbslTDA9989PktSetAudioInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktAif_t *pPkt, + Bool bEnable +); + + +/*============================================================================*/ +/** + \brief Set contents of general control packet & enable/disable + packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] paMute Pointer to Audio Mute; if Null, no change to packet + contents is made + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note tmbslTDA9989AudioOutSetMute must be used to mute the audio output + */ +tmErrorCode_t +tmbslTDA9989PktSetGeneralCntrl +( + tmUnitSelect_t txUnit, + tmbslHdmiTxaMute_t *paMute, + Bool bEnable +); + +/*============================================================================*/ +/** + \brief Set ISRC1 packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Data Island Packet structure + \param[in] byteCnt Packet buffer byte count + \param[in] bIsrcCont ISRC continuation flag + \param[in] bIsrcValid ISRC valid flag + \param[in] uIsrcStatus ISRC Status + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: pointer suppied with byte count of zero + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: not possible with this device + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Data Island Packet parameter structure: + UInt8 dataByte[28] Packet Data + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989PktSetIsrc1 +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + Bool bIsrcCont, + Bool bIsrcValid, + UInt8 uIsrcStatus, + Bool bEnable +); + +/*============================================================================*/ +/** + \brief Set ISRC2 packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Data Island Packet structure + \param[in] byteCnt Packet buffer byte count + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: pointer suppied with byte count of zero + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: not possible with this device + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Data Island Packet parameter structure: + UInt8 dataByte[28] Packet Data + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989PktSetIsrc2 +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + Bool bEnable +); + +/** + \brief Set MPEG infoframe packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to MPEG Infoframe structure + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: not possible with this device + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note MPEG Infoframe structure: + UInt32 bitRate + tmbslHdmiTxMpegFrame_t frameType + Bool bFieldRepeat + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989PktSetMpegInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktMpeg_t *pPkt, + Bool bEnable +); + +/*============================================================================*/ +/** + \brief Enable NULL packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + */ +tmErrorCode_t +tmbslTDA9989PktSetNullInsert +( + tmUnitSelect_t txUnit, + Bool bEnable +); + +/*============================================================================*/ +/** + \brief Set single Null packet insertion (flag auto-resets after + transmission) + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Operation resets after single transmission + */ +tmErrorCode_t +tmbslTDA9989PktSetNullSingle +( + tmUnitSelect_t txUnit +); + +/** + \brief Set audio info frame packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Audio Infoframe structure + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: not possible with this device + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Audio Infoframe structure: + UInt8 VendorName[8] + UInt8 ProdDescr[16] + tmbslHdmiTxSourceDev_t SourceDevInfo + */ +tmErrorCode_t +tmbslTDA9989PktSetSpdInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktSpd_t *pPkt, + Bool bEnable +); + +/** + \brief Set video infoframe packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Video Infoframe structure + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Video Infoframe structure: + UInt8 Colour + Bool ActiveInfo + UInt8 BarInfo + UInt8 ScanInfo + UInt8 Colorimetry + UInt8 PictureAspectRatio + UInt8 ActiveFormatRatio + UInt8 Scaling + UInt8 VidFormat + UInt8 PixelRepeat + UInt16 EndTopBarLine + UInt16 StartBottomBarLine + UInt16 EndLeftBarPixel + UInt16 StartRightBarPixel (incorrectly named in [HDMI1.2]) + */ +tmErrorCode_t +tmbslTDA9989PktSetVideoInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktVif_t *pPkt, + Bool bEnable +); + +/*============================================================================*/ +/** + \brief Set Vendor Specific Infoframe packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to Data Island Packet structure + \param[in] byteCnt Packet buffer byte count + \param[in] uVersion Version number for packet header + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: pointer suppied with byte count of zero + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_NOT_SUPPORTED: not possible with this device + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Data Island Packet parameter structure: + UInt8 dataByte[28] Packet Data (only use 27 bytes max) + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989PktSetVsInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + UInt8 uVersion, + Bool bEnable +); + +/*============================================================================*/ +/** + \brief Set raw video Infoframe packet & enable/disable packet insertion + + \param[in] txUnit Transmitter unit number + \param[in] pPkt Pointer to raw Packet structure + \param[in] bEnable Enable or disable packet insertion + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + \note Data Island Packet parameter structure: + UInt8 dataByte[28] Packet Data + + \sa NA + */ +tmErrorCode_t tmbslTDA9989PktSetRawVideoInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktRawAvi_t *pPkt, + Bool bEnable +); + + +/*============================================================================*/ +/** + \brief Get the power state of the transmitter + + \param[in] txUnit Transmitter unit number + \param[out] pePowerState Pointer to the power state of the device now + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + + \note Power states: + - tmPowerOn + - tmPowerStandby + */ +tmErrorCode_t +tmbslTDA9989PowerGetState +( + tmUnitSelect_t txUnit, + tmPowerState_t *pePowerState +); + +/*============================================================================*/ +/** + \brief Set the power state of the transmitter + + \param[in] txUnit Transmitter unit number + \param[in] ePowerState Power state to set + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note Power states (Off and Suspend are treated the same as Standby): + - tmPowerOn + - tmPowerStandby + - tmPowerSuspend + - tmPowerOff + */ +tmErrorCode_t +tmbslTDA9989PowerSetState +( + tmUnitSelect_t txUnit, + tmPowerState_t ePowerState +); + + +/*============================================================================*/ +/** + \brief Reset the HDMI transmitter + + \param[in] txUnit Transmitter unit number + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note NA + + \sa tmbslTDA9989Init + */ +tmErrorCode_t +tmbslTDA9989Reset +( + tmUnitSelect_t txUnit +); + +/** + \brief Get diagnostic counters from the scaler + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[out] pScalerDiag Pointer to structure to receive scaler diagnostic + registers + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + + \note scaler diagnostic registers structure: + UInt16 maxBuffill_p Filling primary video buffer + UInt16 maxBuffill_d Filling video deinterlaced buffer + UInt8 maxFifofill_pi Filling primary video input FIFO + UInt8 minFifofill_po1 Filling primary video output FIFO #1 + UInt8 minFifofill_po2 Filling primary video output FIFO #2 + UInt8 minFifofill_po3 Filling primary video output FIFO #3 + UInt8 minFifofill_po4 Filling primary video output FIFO #4 + UInt8 maxFifofill_di Filling deinterlaced video input FIFO + UInt8 maxFifofill_do Filling deinterlaced video output FIFO + */ +tmErrorCode_t +tmbslTDA9989ScalerGet +( + tmUnitSelect_t txUnit, + tmbslHdmiTxScalerDiag_t *pScalerDiag +); + + + +/** + \brief Get the current scaler mode + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[out] pScalerMode Pointer to variable to receive scaler mode + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized +*/ +tmErrorCode_t +tmbslTDA9989ScalerGetMode +( + tmUnitSelect_t txUnit, + tmbslHdmiTxScaMode_t *pScalerMode +); + + +/*============================================================================*/ +/** + \brief Enable or disable scaler input frame + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + + \param[in] txUnit Transmitter unit number + \param[in] bDisable Enable or disable scaler input + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989ScalerInDisable +( + tmUnitSelect_t txUnit, + Bool bDisable +); + +/** + \brief Set the active coefficient lookup table for the vertical scaler + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] lutSel Coefficient lookup table selection + \param[in] pVsLut Table of HDMITX_VSLUT_COEFF_NUM coefficient values + (may be null if lutSel not HDMITX_SCALUT_USE_VSLUT) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: two parameters disagree + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989ScalerSetCoeffs +( + tmUnitSelect_t txUnit, + tmbslHdmiTxScaLut_t lutSel, + UInt8 *pVsLut +); + +/** + \brief Set scaler field positions + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] topExt Internal, External, No Change + \param[in] deExt Internal, External, No Change + \param[in] topSel Internal, VRF, No Change + \param[in] topTgl No Action, Toggle, No Change + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989ScalerSetFieldOrder +( + tmUnitSelect_t txUnit, + tmbslHdmiTxIntExt_t topExt, + tmbslHdmiTxIntExt_t deExt, + tmbslHdmiTxTopSel_t topSel, + tmbslHdmiTxTopTgl_t topTgl +); + +/** + \brief Set scaler fine adjustment options + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] uRefPix Ref. pixel preset 0 to 1FFFh (2000h = No Change) + \param[in] uRefLine Ref. line preset 0 to 7FFh (800h = No Change) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989ScalerSetFine +( + tmUnitSelect_t txUnit, + UInt16 uRefPix, + UInt16 uRefLine +); + +/** + \brief Set scaler phase for scaling 1080p + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] tmbslHdmiTxHPhases_t Ref. 0 to 15_horizontal_phases 1 to 16_horizontal_phases + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ + +tmErrorCode_t +tmbslTDA9989ScalerSetPhase +( + tmUnitSelect_t txUnit, + tmbslHdmiTxHPhases_t horizontalPhases +); + +/** + \brief configure scaler latency to set run in run out + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] UInt8 Ref. 0 to 255 + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989ScalerSetLatency +( + tmUnitSelect_t txUnit, + UInt8 scaler_latency +); + +/** + \brief Set scaler synchronization options + On a TDA9989 this function is not supported and + return result TMBSL_ERR_HDMI_NOT_SUPPORTED + + \param[in] txUnit Transmitter unit number + \param[in] method Sync. combination method + \param[in] once Line/pixel counters sync once or each frame + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989ScalerSetSync +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVsMeth_t method, + tmbslHdmiTxVsOnce_t once +); + + +/*============================================================================*/ +/** + \brief Get the driver software version and compatibility numbers + + \param[out] pSWVersion Pointer to the software version structure returned + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989SwGetVersion +( + ptmSWVersion_t pSWVersion +); + + +/*============================================================================*/ +/** + \brief Get the driver software version and compatibility numbers + + \param[in] txUnit Transmitter unit number + \param[in] waitMs Period in milliseconds to wait + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989SysTimerWait +( + tmUnitSelect_t txUnit, + UInt16 waitMs +); + +/** + \brief Set the TMDS outputs to normal active operation or to a forced + state + + \param[in] txUnit Transmitter unit number + \param[in] tmdsOut TMDS output mode + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989TmdsSetOutputs +( + tmUnitSelect_t txUnit, + tmbslHdmiTxTmdsOut_t tmdsOut +); + +/** + \brief Fine-tune the TMDS serializer + + \param[in] txUnit Transmitter unit number + \param[in] uPhase2 Serializer phase 2 + \param[in] uPhase3 Serializer phase 3 + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + */ +tmErrorCode_t +tmbslTDA9989TmdsSetSerializer +( + tmUnitSelect_t txUnit, + UInt8 uPhase2, + UInt8 uPhase3 +); + +/** + \brief Set a colour bar test pattern + + \param[in] txUnit Transmitter unit number + \param[in] pattern Test pattern + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989TestSetPattern +( + tmUnitSelect_t txUnit, + tmbslHdmiTxTestPattern_t pattern +); + +/** + \brief Set or clear one or more simultaneous test modes + + \param[in] txUnit Transmitter unit number + \param[in] testMode Mode: tst_pat, tst_656, tst_serphoe, tst_nosc, + tst_hvp, tst_pwd, tst_divoe + \param[in] testState State: 1=On, 0=Off + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989TestSetMode +( + tmUnitSelect_t txUnit, + tmbslHdmiTxTestMode_t testMode, + tmbslHdmiTxTestState_t testState +); + +/** + \brief Enable blanking between active data + + \param[in] txUnit Transmitter unit number + \param[in] blankitSource Blankit Source: Not DE, VS And HS, + VS And Not HS, Hemb And Vemb, No Change + \param[in] blankingCodes Blanking Codes: All Zero, RGB444, YUV444, + YUV422, No Change + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note NA + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989VideoInSetBlanking +( + tmUnitSelect_t txUnit, + tmbslHdmiTxBlnkSrc_t blankitSource, + tmbslHdmiTxBlnkCode_t blankingCodes +); + +/** + \brief Configure video input options and control the upsampler + + \param[in] txUnit Transmitter unit number + \param[in] vinMode Video input mode + \param[in] voutFmt EIA/CEA Video output format: 1 to 31, 0 = No Change + \param[in] sampleEdge Sample edge: + Pixel Clock Positive Edge, + Pixel Clock Negative Edge, No Change + \param[in] pixRate Single data or double data rate + \param[in] upsampleMode Upsample mode + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoInSetConfig +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTx3DStructure_t structure3D, + tmbslHdmiTxPixEdge_t sampleEdge, + tmbslHdmiTxPixRate_t pixRate, + tmbslHdmiTxUpsampleMode_t upsampleMode +); + +/** + \brief Set fine image position + + \param[in] txUnit Transmitter unit number + \param[in] subpacketCount Subpacket Count fixed values and sync options + \param[in] toggleClk1 Toggle clock 1 phase w.r.t. clock 2 + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note NA + + \sa NA + */ +tmErrorCode_t +tmbslTDA9989VideoInSetFine +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPixSubpkt_t subpacketCount, + tmbslHdmiTxPixTogl_t toggleClk1 +); + +/** + \brief Set video input port swapping and mirroring + + \param[in] txUnit Transmitter unit number + \param[in] pSwapTable Pointer to 6-byte port swap table + \param[in] pMirrorTable Pointer to 6-byte port mirror table + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note UInt8 pSwapTable[6] + + Each table position 0 to 5 represents a group of 4 port bits: + [0]=23:20, [1]=16:19, [2]=15:12, [3]=11:8, [4]=4:7, [5]=0:3 + Table position values are 0 to 6, denoting the group of 4 port + bits to swap to: 0=23:20, 1=16:19, 2=15:12, 3=11:8, 4=4:7, 5=0:3. + For example, to swap port bits 15:12 to bits 4:7: pSwapTable[2]=4 + + UInt8 pMirrorTable[6] + + Each table position 0 to 5 represents a group of 4 port bits: + [0]=23:20, [1]=16:19, [2]=15:12, [3]=11:8, [4]=4:7, [5]=0:3. + Cell values are 0 to 2 (Not Mirrored, Mirrored, No Change). + For example, to mirror port bits 11:8 to bits 8:11: + pMirrorTable[3]=1. + */ +tmErrorCode_t +tmbslTDA9989VideoInSetMapping +#ifdef TMFL_RGB_DDR_12BITS +( + tmUnitSelect_t txUnit, + UInt8 *pSwapTable, + UInt8 *pMirrorTable, + UInt8 *pMux +); +#else +( + tmUnitSelect_t txUnit, + UInt8 *pSwapTable, + UInt8 *pMirrorTable +); +#endif +/** + \brief Set video input port (enable, ground) + + \param[in] txUnit Transmitter unit number + \param[in] pEnaVideoPortTable Pointer to 3-byte video port enable table + \param[in] pGndVideoPortTable Pointer to 3-byte video port ground table + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note UInt8 pEnaVideoPortTable[3] + + Each table position 0 to 2 represents a group of 8 port bits: + [0]=7:0, [1]=15:8, [2]=23:16 + bitn = '1' means enable port n + bitn = '0' means disable port n + For example, to enable port 0 to 7 only : pEnaVideoPortTable[0]= 0xFF + pEnaVideoPortTable[1]= 0x00, pEnaVideoPortTable[2]= 0x00 + + UInt8 pGndVideoPortTable[3] + + Each table position 0 to 2 represents a group of 8 port bits: + [0]=7:0, [1]=15:8, [2]=23:16 + bitn = '1' means pulldown port n + bitn = '0' means not pulldown port n + For example, to pulldown port 8 to 15 only : pEnaVideoPortTable[0]= 0x00 + pEnaVideoPortTable[1]= 0xFF, pEnaVideoPortTable[2]= 0x00 + */ +tmErrorCode_t +tmbslTDA9989SetVideoPortConfig +( + tmUnitSelect_t txUnit, + UInt8 *pEnaVideoPortTable, + UInt8 *pGndVideoPortTable +); + +/*============================================================================*/ +/** + \brief Set audio input port (enable, ground) + + \param[in] txUnit Transmitter unit number + \param[in] pEnaAudioPortTable Pointer to 1-byte audio port enable configuration + \param[in] pGndAudioPortTable Pointer to 1-byte audio port ground configuration + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note UInt8 pEnaAudioPortTable[1] + bitn = '1' means enable port n + bitn = '0' means disable port n + For example, to enable all audio port (0:7) : pEnaAudioPortTable[0]= 0xFF + + UInt8 pGndAudioPortTable[1] + bitn = '1' means pulldown port n + bitn = '0' means not pulldown port n + For example, to pulldown audio port (0:7) : pEnaAudioPortTable[0]= 0xFF +*/ +tmErrorCode_t +tmbslTDA9989SetAudioPortConfig +( + tmUnitSelect_t txUnit, + UInt8 *pEnaAudioPortTable, + UInt8 *pGndAudioPortTable +); + +/*============================================================================*/ +/** + \brief Set audio input Clock port (enable, ground) + + \param[in] txUnit Transmitter unit number + \param[in] pEnaAudioClockPortTable Pointer to 1-byte audio Clock port enable configuration + \param[in] pGndAudioClockPortTable Pointer to 1-byte audio Clock port ground configuration + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + + \note UInt8 pEnaAudioClockPortTable[1] + bitn = '1' means enable port n + bitn = '0' means disable port n + For example, to enable all audio Clock port (0) : pEnaAudioPortTable[0]= 0x01 + + UInt8 pGndAudioClockPortTable[1] + bitn = '1' means pulldown port n + bitn = '0' means not pulldown port n + For example, to pulldown audio Clock port (0:7) : pEnaAudioPortTable[0]= 0x01 +*/ +tmErrorCode_t +tmbslTDA9989SetAudioClockPortConfig +( + tmUnitSelect_t txUnit, + UInt8 *pEnaAudioClockPortTable, + UInt8 *pGndAudioClockPortTable +); + +/** + \brief Configure video input sync automatically + + \param[in] txUnit Transmitter unit number + \param[in] syncSource Sync Source: + Embedded, External Vref, External Vs + No Change + \param[in] vinFmt EIA/CEA Video input format: 1 to 31, 0 = No Change + \param[in] vinMode Input video mode + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoInSetSyncAuto +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSyncSource_t syncSource, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTx3DStructure_t structure3D +); + +/** + \brief Configure video input sync with manual parameters + + \param[in] txUnit Transmitter unit number + \param[in] syncSource Sync Source: + Embedded, External Vref, External Vs + No Change + \param[in] syncMethod Sync method: V And H, V And X-DE, No Change + \param[in] toggleV VS Toggle: + No Action, Toggle VS/Vref, No Change + \param[in] toggleH HS Toggle: + No Action, Toggle HS/Href, No Change + \param[in] toggleX DE/FREF Toggle: + No Action, Toggle DE/Fref, No Change + \param[in] uRefPix Ref. pixel preset 0 to 1FFFh (2000h = No Change) + \param[in] uRefLine Ref. line preset 0 to 7FFh (800h = No Change) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoInSetSyncManual +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSyncSource_t syncSource, + tmbslHdmiTxVsMeth_t syncMethod, + tmbslHdmiTxPixTogl_t toggleV, + tmbslHdmiTxPixTogl_t toggleH, + tmbslHdmiTxPixTogl_t toggleX, + UInt16 uRefPix, + UInt16 uRefLine +); + + +/*============================================================================*/ +/** + \brief Enable or disable output video frame + + \param[in] txUnit Transmitter unit number + \param[in] bDisable Enable or disable scaler input + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoOutDisable +( + tmUnitSelect_t txUnit, + Bool bDisable +); + +/** + \brief Configure sink type, configure video output colour and + quantization, control the downsampler, and force RGB output + and mute audio in DVI mode + + \param[in] txUnit Transmitter unit number: + \param[in] sinkType Sink device type: DVI or HDMI or copy from EDID + \param[in] voutMode Video output mode + \param[in] preFilter Prefilter: Off, 121, 109, CCIR601, No Change + \param[in] yuvBlank YUV blanking: 16, 0, No Change + \param[in] quantization Video quantization range: + Full Scale, RGB Or YUV, YUV, No Change + + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoOutSetConfig +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkType_t sinkType, + tmbslHdmiTxVoutMode_t voutMode, + tmbslHdmiTxVoutPrefil_t preFilter, + tmbslHdmiTxVoutYuvBlnk_t yuvBlank, + tmbslHdmiTxVoutQrange_t quantization +); + +/** + \brief Set video synchronization + + \param[in] txUnit Transmitter unit number + \param[in] srcH Horizontal sync source: Internal, Exter'l, No Change + \param[in] srcV Vertical sync source: Internal, Exter'l, No Change + \param[in] srcX X sync source: Internal, Exter'l, No Change + \param[in] toggle Sync toggle: Hs, Vs, Off, No Change + \param[in] once Line/pixel counters sync once or each frame + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoOutSetSync +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVsSrc_t srcH, + tmbslHdmiTxVsSrc_t srcV, + tmbslHdmiTxVsSrc_t srcX, + tmbslHdmiTxVsTgl_t toggle, + tmbslHdmiTxVsOnce_t once +); + +/** + \brief Set main video input and output parameters + + \param[in] txUnit Transmitter unit number + \param[in] vinFmt EIA/CEA Video input format: 1 to 31, 0 = No Change + \param[in] scaMode Scaler mode: Off, On, Auto, No Change + On TDA9989, only scaler mode off is possible + \param[in] voutFmt EIA/CEA Video output format: 1 to 31, 0 = No Change + \param[in] uPixelRepeat Pixel repetition factor: 0 to 9, 10 = default, + 11 = no change + \param[in] matMode Matrix mode: 0 = off, 1 = auto + \param[in] datapathBits Datapath bitwidth: 0 to 3 (8, 10, 12, No Change) + \param[in] Desired VQR in dvi mode + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: params are inconsistent + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989VideoSetInOut +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTx3DStructure_t structure3D, + tmbslHdmiTxScaMode_t scaMode, + tmbslHdmiTxVidFmt_t voutFmt, + UInt8 uPixelRepeat, + tmbslHdmiTxMatMode_t matMode, + tmbslHdmiTxVoutDbits_t datapathBits, + tmbslHdmiTxVQR_t dviVqr +); + +/** + \brief Use only for debug to flag the software debug interrupt + + \param[in] txUnit Transmitter unit number + \param[in] uSwInt Interrupt to be generated (not relevant) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ +tmErrorCode_t +tmbslTDA9989FlagSwInt +( + tmUnitSelect_t txUnit, + UInt32 uSwInt +); + + +/** + \brief Enable or disable 5v power + + \param[in] txUnit Transmitter unit number + \param[in] pwrEnable 5v Power enable(True)/disable(False) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: functionnality not supported by this device + */ +tmErrorCode_t +tmbslTDA9989Set5vpower +( + tmUnitSelect_t txUnit, + Bool pwrEnable +); + +/** + \brief Enable or disable a callback source + + \param[in] txUnit Transmitter unit number + \param[in] callbackSource Callback source + \param[in] enable Callback source enable(True)/disable(False) + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: impossible to disable this interrupt + */ +tmErrorCode_t +tmbslTDA9989EnableCallback +( + tmUnitSelect_t txUnit, + tmbslHdmiTxCallbackInt_t callbackSource, + Bool enable +); + +/** + \brief Configure the deep color mode + + \param[in] txUnit Transmitter unit number + \param[in] colorDepth Number of bits per pixel to be processed + \param[in] termEnable Enable transmitter termination + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: mode not supported + */ +tmErrorCode_t +tmbslTDA9989SetColorDepth +( + tmUnitSelect_t txUnit, + tmbslHdmiTxColorDepth colorDepth, + Bool termEnable +); + +/** + \brief Configure the default phase for a specific deep color mode + + \param[in] txUnit Transmitter unit number + \param[in] bEnable Enable(true)/disable(False) default phase + \param[in] colorDepth Concerned deepcolor mode + \param[in] videoFormat Number of bits per pixel to be processed + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: functionnality not supported by this device + */ +tmErrorCode_t +tmbslTDA9989SetDefaultPhase +( + tmUnitSelect_t txUnit, + Bool bEnable, + tmbslHdmiTxColorDepth colorDepth, + UInt8 videoFormat +); + + + +/** + \brief Control (Enable/Disable) VS interrupt + + \param[in] txUnit Transmitter unit number + \param[in] uIntFlag Enable/Disable VS interrupt + + \return The call result: + - TM_OK: the call was successful + - Else a problem has been detected: + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + */ + +tmErrorCode_t +tmbslTDA9989CtlVsInterrupt +( + tmUnitSelect_t txUnit, + Bool uIntFlag +); + +/*============================================================================*/ +/** + \brief Fill Gamut metadata packet into one of the gamut HW buffer. this + function is not sending any gamut metadata into the HDMI stream, + it is only loading data into the HW. + + \param txUnit Transmitter unit number + \param pPkt pointer to the gamut packet structure + \param bufSel number of the gamut buffer to fill + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C + bus + + ******************************************************************************/ +tmErrorCode_t tmbslTDA9989PktFillGamut +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktGamut_t *pPkt, + UInt8 bufSel +); + +/*============================================================================*/ +/** + \brief Enable transmission of gamut metadata packet. Calling this function + tells HW which gamut buffer to send into the HDMI stream. HW will + only take into account this command at the next VS, not during the + current one. + + \param txUnit Transmitter unit number + \param bufSel Number of the gamut buffer to be sent + \param enable Enable/disable gamut packet transmission + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C + bus + + ******************************************************************************/ +tmErrorCode_t tmbslTDA9989PktSendGamut +( + tmUnitSelect_t txUnit, + UInt8 bufSel, + Bool bEnable +); + + +/** + \brief Return the category of equipement connected + + \param txUnit Transmitter unit number + \param category return category type + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: params are inconsistent + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE hdcp not started + +*/ +tmErrorCode_t tmbslTDA9989HdcpGetSinkCategory +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkCategory_t *category +); + + +/** + \brief Return the sink latency information if any + + \param txUnit Transmitter unit number + \param pEdidLatency latency data structure to return + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: params are inconsistent + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE hdcp not started + +*/ +tmErrorCode_t tmbslTDA9989EdidGetLatencyInfo +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidLatency_t * pEdidLatency +); + + +/** + \brief Return the sink additional VSDB data information if any + + \param txUnit Transmitter unit number + \param p3Ddata 3D data structure to return + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: params are inconsistent + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE hdcp not started + +*/ +tmErrorCode_t tmbslTDA9989EdidGetExtraVsdbData +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidExtraVsdbData_t **pExtraVsdbData +); + + +#ifdef TMFL_HDCP_OPTIMIZED_POWER +/** + \brief Optimized power by frozing useless clocks related to HDCP + + \param txUnit Transmitter unit number + \param request power down request + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_HDMI_INCONSISTENT_PARAMS: params are inconsistent + +*/ +tmErrorCode_t +tmbslTDA9989HdcpPowerDown +( + tmUnitSelect_t txUnit, + Bool requested +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_FUNCTIONS_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid.c b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid.c new file mode 100755 index 0000000000000..e2eabd1289c9d --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid.c @@ -0,0 +1,1572 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_edid.c + * + * \version $Revision: 2 $ + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmbslHdmiTx_types.h" +#include "tmbslTDA9989_Functions.h" +#include "tmbslTDA9989_local.h" +#include "tmbslTDA9989_State_l.h" +#include "tmbslTDA9989_Edid_l.h" + + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ +#define EDID_NUMBER_MAX_DTD_BLK_1 6 +/** EDID block 0 parse start point */ +#define EDID_BLK0_BASE_DTD 0x36 + +#define EDID_BLK1_OFFSET_BASE_DTD 2 + +/** EDID block 0 extension block count */ +#define EDID_BLK0_EXT_CNT 0x7E + +/** EDID extension block parse start point */ +#define EDID_BLK_EXT_BASE 0x04 + +/** CEA extension block type */ +#define EDID_CEA_EXTENSION 0x02 + +/** CEA Block Map */ +#define EDID_BLOCK_MAP 0xF0 + +/** NB Max of descriptor DTD or monitor in block 0 */ +#define EDID_NB_MAX_DESCRIP_BLK_IN_BLK_0 4 + +#define EDID_MONITOR_NAME_DESC_DATA_TYPE 252 + +#define EDID_MONITOR_RANGE_DESC_DATA_TYPE 253 + +/*============================================================================*/ +/* DEFINES DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + +static tmErrorCode_t requestEdidBlock(tmHdmiTxobject_t *pDis); + +static tmErrorCode_t parseEdidBlock (tmHdmiTxobject_t *pDis, + Int blockNumber); +static Bool storeDtdBlock (tmHdmiTxobject_t *pDis, + UInt8 blockPtr); + +static Bool storeMonitorDescriptor (tmHdmiTxobject_t *pDis, + UInt8 blockPtr); + + + +/*============================================================================*/ +/* tmbslTDA9989HwGetCapabilities */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HwGetCapabilities +( + tmUnitSelect_t txUnit, + tmbslHdmiTxHwFeature_t deviceCapability, + Bool *pFeatureSupported + ) +{ + tmHdmiTxobject_t *pDis; + tmErrorCode_t err = TM_OK; + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + RETIF_BADPARAM(pFeatureSupported == Null) + + *pFeatureSupported = False; + + + switch (deviceCapability) + { + case HDMITX_FEATURE_HW_HDCP: + if((pDis->uDeviceFeatures & E_MASKREG_P00_VERSION_not_h) == 0) + { + *pFeatureSupported = True; + } + break; + case HDMITX_FEATURE_HW_SCALER: + if((pDis->uDeviceFeatures & E_MASKREG_P00_VERSION_not_s) == 0) + { + *pFeatureSupported = True; + } + break; + case HDMITX_FEATURE_HW_AUDIO_OBA: + *pFeatureSupported = True; + break; + case HDMITX_FEATURE_HW_AUDIO_DST: + *pFeatureSupported = False; + break; + case HDMITX_FEATURE_HW_AUDIO_HBR: + *pFeatureSupported = False; + break; + case HDMITX_FEATURE_HW_HDMI_1_1: + *pFeatureSupported = True; + break; + case HDMITX_FEATURE_HW_HDMI_1_2A: + *pFeatureSupported = True; + break; + case HDMITX_FEATURE_HW_HDMI_1_3A: + *pFeatureSupported = False; + break; + + case HDMITX_FEATURE_HW_DEEP_COLOR_30: + *pFeatureSupported = False; + break; + + case HDMITX_FEATURE_HW_DEEP_COLOR_36: + *pFeatureSupported = False; + break; + + case HDMITX_FEATURE_HW_DEEP_COLOR_48: + *pFeatureSupported = False; + break; + + case HDMITX_FEATURE_HW_UPSAMPLER: + *pFeatureSupported = True; + break; + + case HDMITX_FEATURE_HW_DOWNSAMPLER: + *pFeatureSupported = True; + break; + + case HDMITX_FEATURE_HW_COLOR_CONVERSION: + *pFeatureSupported = True; + break; + + default: + *pFeatureSupported = False; + break; + } + + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetAudioCapabilities */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetAudioCapabilities +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidSad_t *pEdidAFmts, + UInt aFmtLength, + UInt *pAFmtsAvail, + UInt8 *pAudioFlags +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt i; /* Loop index */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidAFmts == Null) + RETIF_BADPARAM(aFmtLength < 1) + RETIF_BADPARAM(pAFmtsAvail == Null) + RETIF_BADPARAM(pAudioFlags == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + + /* Copy the Device Instance Structure EdidAFmts descriptors to + * pEdidAFmts until we run out or no more space in structure. + */ + if (pDis->EdidSadCnt > 0) + { + for (i = 0; (i < (UInt)pDis->EdidSadCnt) && (i < aFmtLength); i++) + { + pEdidAFmts[i].ModeChans = pDis->EdidAFmts[i].ModeChans; + pEdidAFmts[i].Freqs = pDis->EdidAFmts[i].Freqs; + pEdidAFmts[i].Byte3 = pDis->EdidAFmts[i].Byte3; + } + } + else + { + /* No pEdidAFmts to copy so set a zero format to be safe */ + pEdidAFmts[0].ModeChans = 0; + pEdidAFmts[0].Freqs = 0; + pEdidAFmts[0].Byte3 = 0; + } + + /* Fill Audio Flags parameter */ + *pAudioFlags = ((pDis->EdidCeaFlags & 0x40) << 1); /* Basic audio */ + if (pDis->EdidSinkAi == True) + { + *pAudioFlags += 0x40; /* Mask in AI support */ + } + + /* Fill number of SADs available parameter */ + *pAFmtsAvail = pDis->EdidSadCnt; + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989EdidGetBlockCount */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetBlockCount +( + tmUnitSelect_t txUnit, + UInt8 *puEdidBlockCount +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(puEdidBlockCount == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + *puEdidBlockCount = pDis->EdidBlockCnt; + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetStatus */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetStatus +( + tmUnitSelect_t txUnit, + UInt8 *puEdidStatus +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(puEdidStatus == Null) + + if (puEdidStatus) + { + *puEdidStatus = pDis->EdidStatus; + } + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidRequestBlockData */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidRequestBlockData +( + tmUnitSelect_t txUnit, + UInt8 *pRawEdid, + Int numBlocks, /* Only relevant if pRawEdid valid */ + Int lenRawEdid /* Only relevant if pRawEdid valid */ +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regval; /* Byte value write to register */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + #ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC + + if ( (pDis->vinFmt == HDMITX_VFMT_16_1920x1080p_60Hz) || (pDis->vinFmt == HDMITX_VFMT_31_1920x1080p_50Hz)) { + + err = setHwRegisterField(pDis, + E_REG_P02_PLL_SERIAL_3_RW, + E_MASKREG_P02_PLL_SERIAL_3_srl_ccir, + 0x01); + RETIF_REG_FAIL(err) + + } + + #endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + +#ifdef TMFL_RGB_DDR_12BITS + /* RAM on */ + setHwRegisterField(pDis, E_REG_P12_TX4_RW, E_MASKREG_P12_TX4_pd_ram, 0); +#endif + + /* enable edid read */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_2_RW, + E_MASKREG_P00_INT_FLAGS_2_edid_blk_rd); + + /* Check remaining parameter(s) + * We do allow a null pRawEdid pointer, in which case buffer length is + * irrelevant. If pRawEdid pointer is valid, there is no point in + * continuing if insufficient space for at least one block. + */ + RETIF_BADPARAM((pRawEdid != Null) && (lenRawEdid < EDID_BLOCK_SIZE)) + /* Sensible value of numBlocks? */ + RETIF((pRawEdid != Null) && ((numBlocks < 1) || (numBlocks > 255)), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + /* Enough space for the data requested? */ + RETIF((pRawEdid != Null) && (lenRawEdid < (numBlocks * EDID_BLOCK_SIZE)), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + + /* Read the HPD pin via the hpd_in flag in the first interrupt status + * register and return a TMBSL_ERR_HDMI_NULL_CONNECTION error if it is + * not set. + * We must use the flag in the Device Instance Structure to avoid + * clearing pending interrupt flags. + */ + RETIF(pDis->hotPlugStatus != HDMITX_HOTPLUG_ACTIVE, + TMBSL_ERR_HDMI_NULL_CONNECTION) + + if (pDis->EdidReadStarted == False) + { + + /* Reset the EdidStatus in the Device Instance Structure */ + pDis->EdidStatus = HDMITX_EDID_NOT_READ; + + pDis->EdidReadStarted = True; + + /* Reset stored parameters from EDID in the Device Instance Structure */ + pDis->EdidSinkType = HDMITX_SINK_DVI; + pDis->EdidSinkAi = False; + pDis->EdidCeaFlags = 0; + pDis->EdidCeaXVYCCFlags = 0; + pDis->EdidSvdCnt = 0; + pDis->EdidSadCnt = 0; + pDis->EdidSourceAddress = 0; /* 0.0.0.0 */ + pDis->NbDTDStored = 0; + pDis->EdidFirstMonitorDescriptor.bDescRecord = False; + pDis->EdidSecondMonitorDescriptor.bDescRecord = False; + pDis->EdidOtherMonitorDescriptor.bDescRecord = False; + + pDis->EdidLatency.latency_available = False; + pDis->EdidLatency.Ilatency_available = False; + + pDis->EdidExtraVsdbData.hdmiVideoPresent = False; + + + pDis->EdidToApp.pRawEdid = pRawEdid; + pDis->EdidToApp.numBlocks = numBlocks; + + /* Enable the T0 interrupt for detecting the Read_EDID failure */ + regval = E_MASKREG_P00_INT_FLAGS_0_t0 ; + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_0_RW, regval); + RETIF(err != TM_OK, err); + + + /* Launch the read of first EDID block into Device Instance workspace */ + pDis->EdidBlockRequested = 0; + err = requestEdidBlock(pDis); + } + else + { + /* Not allowed if read edid is on going */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return err; +} + + +/*============================================================================*/ +/* EdidBlockAvailable */ +/*============================================================================*/ + +tmErrorCode_t +EdidBlockAvailable (tmUnitSelect_t txUnit, Bool * pSendEDIDCallback) +{ + + tmErrorCode_t err; /* Error code */ + UInt8 chksum; /* Checksum value */ + UInt8 LoopIndex; /* Loop index */ + UInt8 extBlockCnt; + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + + err = TM_OK; + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pSendEDIDCallback == Null) + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + if (pDis->EdidReadStarted == True) + { + + err = tmbslTDA9989HwGetRegisters(txUnit, kPageIndexToPage[E_PAGE_09], + SPA2ADDR(E_REG_P09_EDID_DATA_0_R), pDis->EdidBlock, EDID_BLOCK_SIZE); + RETIF(err != TM_OK, err) + + if(pSendEDIDCallback) + { + *pSendEDIDCallback = False; + } + + if (pDis->EdidStatus == HDMITX_EDID_NOT_READ) + { + err = getHwRegisters(pDis, E_REG_P09_EDID_DATA_0_R, pDis->EdidBlock, + EDID_BLOCK_SIZE); + RETIF_REG_FAIL(err) + + /* Add up all the values of the EDID block bytes, including the + * checksum byte + */ + chksum = 0; + for (LoopIndex = 0; LoopIndex < EDID_BLOCK_SIZE; LoopIndex++) + { + chksum = chksum + pDis->EdidBlock[LoopIndex]; + } + + /* IF the EDID block does not yield a checksum of zero + */ + if(chksum != 0) + { + if (pDis->EdidBlockRequested == 0) + { + /* THEN return a HDMITX_EDID_ERROR error.*/ + pDis->EdidStatus = HDMITX_EDID_ERROR_CHK_BLOCK_0; + } + else + { + /* THEN return a HDMITX_EDID_ERROR_CHK error.*/ + pDis->EdidStatus = HDMITX_EDID_ERROR_CHK; + } + } + } + + if (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK_BLOCK_0) + { + /* PR11 : On i2c error or bad checksum in block 0 */ + /* allow driver to go in state CONNECTED */ + /* On the other block, we also accept INVALID_CHECKSUM which means + * there was a checksum error */ + + if(pSendEDIDCallback) + { + *pSendEDIDCallback = True; + } + + setState(pDis, EV_GETBLOCKDATA); + if (pDis->rxSenseStatus == HDMITX_RX_SENSE_ACTIVE) + { + setState(pDis, EV_SINKON); + } + pDis->EdidReadStarted = False; + return err; + } + + /* Check if block 0 */ + if (pDis->EdidBlockRequested == 0) + { + /* Could check block 0 header (0x00,6 x 0xFF,0x00) here but not + * certain to be future proof [CEA861C A.2.3] + */ + + /* Read block count from penultimate byte of block and store in DIS */ + extBlockCnt = pDis->EdidBlock[EDID_BLK0_EXT_CNT]; + + pDis->EdidBlockCnt = extBlockCnt + 1; /* Total = Block 0 + extensions */ + + } + + /* If pointer was supplied, copy block from DIS to buffer */ + if (pDis->EdidToApp.pRawEdid != Null) + { + /* Check if we've copied as many as requested yet? */ + if (pDis->EdidBlockRequested < pDis->EdidToApp.numBlocks) + { + lmemcpy(pDis->EdidToApp.pRawEdid + (pDis->EdidBlockRequested * EDID_BLOCK_SIZE), + pDis->EdidBlock, + EDID_BLOCK_SIZE); + } + } + parseEdidBlock(pDis, pDis->EdidBlockRequested); + + /* If extension blocks are present, process them */ + if ( (pDis->EdidBlockRequested + 1) < pDis->EdidBlockCnt) + { + pDis->EdidBlockRequested = pDis->EdidBlockRequested + 1; + /* Launch an edid block read */ + err = requestEdidBlock(pDis); + } + else + { + if (pDis->EdidStatus == HDMITX_EDID_NOT_READ) + { + pDis->EdidStatus = HDMITX_EDID_READ; + +#ifdef TMFL_RGB_DDR_12BITS + /* RAM off */ + setHwRegisterField(pDis, E_REG_P12_TX4_RW, E_MASKREG_P12_TX4_pd_ram, 1); +#endif + } + + if(pSendEDIDCallback) + { + *pSendEDIDCallback = True; + } + + setState(pDis, EV_GETBLOCKDATA); + + if (pDis->rxSenseStatus == HDMITX_RX_SENSE_ACTIVE) + { + setState(pDis, EV_SINKON); + } + pDis->EdidReadStarted = False; + } + } + else + { + /* function called in an invalid state */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return err; + +} + +/*============================================================================*/ +/* ClearEdidRequest */ +/*============================================================================*/ + +tmErrorCode_t +ClearEdidRequest (tmUnitSelect_t txUnit) +{ + + tmErrorCode_t err; /* Error code */ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + + err = TM_OK; + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + + /* Reset the EdidStatus in the Device Instance Structure */ + pDis->EdidStatus = HDMITX_EDID_NOT_READ; + + pDis->EdidReadStarted = False; + + /* Reset stored parameters from EDID in the Device Instance Structure */ + pDis->EdidSinkType = HDMITX_SINK_DVI; + pDis->EdidSinkAi = False; + pDis->EdidCeaFlags = 0; + pDis->EdidCeaXVYCCFlags = 0; + pDis->EdidSvdCnt = 0; + pDis->EdidSadCnt = 0; + pDis->EdidSourceAddress = 0; /* 0.0.0.0 */ + pDis->NbDTDStored = 0; + pDis->EdidFirstMonitorDescriptor.bDescRecord = False; + pDis->EdidSecondMonitorDescriptor.bDescRecord = False; + pDis->EdidOtherMonitorDescriptor.bDescRecord = False; + + pDis->EdidLatency.latency_available = False; + pDis->EdidLatency.Ilatency_available = False; + + pDis->EdidExtraVsdbData.hdmiVideoPresent = False; + + /* Launch the read of first EDID block into Device Instance workspace */ + pDis->EdidBlockRequested = 0; + + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetSinkType */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetSinkType +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkType_t *pSinkType +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pSinkType == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + + *pSinkType = pDis->EdidSinkType; + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + return err; + +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetSourceAddress */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989EdidGetSourceAddress +( + tmUnitSelect_t txUnit, + UInt16 *pSourceAddress +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pSourceAddress == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + + *pSourceAddress = pDis->EdidSourceAddress; + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + return err; + +} + + +/*============================================================================*/ +/* tmbslTDA9989EdidGetDetailedTimingDescriptors */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetDetailedTimingDescriptors +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidDtd_t *pEdidDTD, + UInt8 nb_size, + UInt8 *pDTDAvail +) +{ + + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidDTD == Null) + RETIF_BADPARAM(pDTDAvail == Null) + RETIF_BADPARAM(nb_size == 0) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + if (nb_size > pDis->NbDTDStored) + { + *pDTDAvail = pDis->NbDTDStored; + } + else + { + *pDTDAvail = nb_size; + } + + lmemcpy(pEdidDTD, pDis->EdidDTD, sizeof(tmbslHdmiTxEdidDtd_t) * (*pDTDAvail)); + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetMonitorDescriptors */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetMonitorDescriptors +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidFirstMD_t *pEdidFirstMD, + tmbslHdmiTxEdidSecondMD_t *pEdidSecondMD, + tmbslHdmiTxEdidOtherMD_t *pEdidOtherMD, + UInt8 sizeOtherMD, + UInt8 *pOtherMDAvail +) +{ + + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidFirstMD == Null) + RETIF_BADPARAM(pEdidSecondMD == Null) + RETIF_BADPARAM(pEdidOtherMD == Null) + + DUMMY_ACCESS(pOtherMDAvail); + DUMMY_ACCESS(sizeOtherMD); + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + *pOtherMDAvail = 1; + lmemcpy(pEdidFirstMD, &(pDis->EdidFirstMonitorDescriptor), sizeof(tmbslHdmiTxEdidFirstMD_t)); + lmemcpy(pEdidSecondMD, &(pDis->EdidSecondMonitorDescriptor), sizeof(tmbslHdmiTxEdidSecondMD_t)); + lmemcpy(pEdidOtherMD, &(pDis->EdidOtherMonitorDescriptor), sizeof(tmbslHdmiTxEdidOtherMD_t)); + } + else + { + /* Not allowed if EdidStatus value is not valid */ + *pOtherMDAvail = 0; + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return TM_OK; + +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetBasicDisplayParam */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetBasicDisplayParam +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidBDParam_t *pEdidBDParam +) +{ + + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidBDParam == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + lmemcpy(pEdidBDParam, &(pDis->EDIDBasicDisplayParam), sizeof(tmbslHdmiTxEdidBDParam_t)); + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetVideoCapabilities */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetVideoCapabilities +( + tmUnitSelect_t txUnit, + UInt8 *pEdidVFmts, + UInt vFmtLength, + UInt *pVFmtsAvail, + UInt8 *pVidFlags +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt i; /* Loop index */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidVFmts == Null) + RETIF_BADPARAM(vFmtLength < 1) + RETIF_BADPARAM(pVFmtsAvail == Null) + RETIF_BADPARAM(pVidFlags == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + + /* Copy the Device Instance Structure EdidVFmts descriptors to + * pEdidVFmts until we run out or no more space in structure. + */ + if (pDis->EdidSvdCnt > 0) + { + for (i = 0; (i < (UInt)pDis->EdidSvdCnt) && (i < vFmtLength); i++) + { + pEdidVFmts[i] = pDis->EdidVFmts[i]; + } + } + else + { + /* No pEdidVFmts to copy so set a zero format to be safe */ + pEdidVFmts[0] = HDMITX_VFMT_NULL; + } + + /* Fill Video Flags parameter */ + *pVidFlags = ((pDis->EdidCeaFlags & 0x80) | /* Underscan */ + ((pDis->EdidCeaFlags & 0x30) << 1) ); /* YUV444, YUV422 */ + + + /* Add info regarding xvYCC support */ + *pVidFlags = *pVidFlags | (pDis->EdidCeaXVYCCFlags & 0x03); + + /* Fill number of SVDs available parameter */ + *pVFmtsAvail = pDis->EdidSvdCnt; + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetVideoPreferred */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989EdidGetVideoPreferred +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidDtd_t *pEdidDTD +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidDTD == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + + /* Populate the Detailed Timing Descriptor structure pEdidDTD from + * EdidDtd in the Device Instance Structure. + */ + lmemcpy(pEdidDTD, &pDis->EdidDTD, sizeof(tmbslHdmiTxEdidDtd_t)); + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + return err; + +} + + +/*============================================================================*/ +/* STATIC FUNCTION */ +/*============================================================================*/ + +/*============================================================================*/ +/* requestEdidBlock - reads an entire edid block */ +/*============================================================================*/ +static tmErrorCode_t +requestEdidBlock +( + tmHdmiTxobject_t *pDis /* Device instance strucure to use */ + ) +{ + tmErrorCode_t err; /* Error code */ + UInt8 segptr; /* Segment ptr value */ + UInt8 offset; /* Word offset value */ + + /* Check block number is valid [CEA861C A.2.1] */ + RETIF_BADPARAM(pDis->EdidBlockRequested >= 255) + + err = setHwRegister(pDis, E_REG_P09_DDC_ADDR_RW, DDC_EDID_ADDRESS); + RETIF_REG_FAIL(err) + + /* For even blocks we need an offset of 0, odd blocks we need 128 */ + offset = (((UInt8)pDis->EdidBlockRequested & 1) == 1) ? 128 : 0; + + err = setHwRegister(pDis, E_REG_P09_DDC_OFFS_RW, offset); + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, E_REG_P09_DDC_SEGM_ADDR_RW, DDC_SGMT_PTR_ADDRESS); + RETIF_REG_FAIL(err) + + /* Calculate which segment of the EDID we need (2 blocks per segment) */ + segptr = (UInt8)pDis->EdidBlockRequested / 2; + + err = setHwRegister(pDis, E_REG_P09_DDC_SEGM_RW, segptr); + RETIF_REG_FAIL(err) + + /* Enable reading EDID */ + err = setHwRegister(pDis, E_REG_P09_EDID_CTRL_RW, 0x1); + RETIF_REG_FAIL(err) + + /* The flag to start the EDID reading must cleared by software*/ + err = setHwRegister(pDis, E_REG_P09_EDID_CTRL_RW, 0x0); + RETIF_REG_FAIL(err) + + return err; +} + +/*============================================================================*/ +/* parseEdidBlock */ +/*============================================================================*/ +static tmErrorCode_t +parseEdidBlock +( + tmHdmiTxobject_t *pDis, /* Device instance strucure holding block */ + Int blockNumber /* Block number */ + ) +{ + UInt8 i; /* Loop index */ + UInt8 blockPtr, endPtr; /* Parsing pointers */ + UInt8 blockType, blockLength; + Bool dtdFound; + UInt8 NbBlkRead, offset3D=0; + + /* Check block number is valid [CEA861C A.2.1] */ + RETIF_BADPARAM(blockNumber >= 255) + + NbBlkRead = 0; + dtdFound = True; + blockPtr = 0; + + if (blockNumber == 0) + { + pDis->EDIDBasicDisplayParam.uVideoInputDef = pDis->EdidBlock[0x14]; + pDis->EDIDBasicDisplayParam.uMaxHorizontalSize = pDis->EdidBlock[0x15]; + pDis->EDIDBasicDisplayParam.uMaxVerticalSize = pDis->EdidBlock[0x16]; + pDis->EDIDBasicDisplayParam.uGamma = pDis->EdidBlock[0x17]; + pDis->EDIDBasicDisplayParam.uFeatureSupport = pDis->EdidBlock[0x18]; + + /* Block 0 - contains DTDs but no video data block (SVDs) */ + for (i = 0; (i < 2) && (dtdFound); i++) /* search 2 possible DTD blocks in block 0 */ + { + blockPtr = (UInt8)(EDID_BLK0_BASE_DTD + (i * EDID_DTD_BLK_SIZE)); + if ((blockPtr + EDID_DTD_BLK_SIZE - 1) < EDID_BLOCK_SIZE) + { + dtdFound = storeDtdBlock(pDis, blockPtr); + if (dtdFound) + { + NbBlkRead++; + } + } + } + + dtdFound = True; + + /* Parse monitor descriptor */ + for (i = NbBlkRead; (i < EDID_NB_MAX_DESCRIP_BLK_IN_BLK_0) && (dtdFound); i++) + { + blockPtr = (UInt8)(EDID_BLK0_BASE_DTD + (i * EDID_DTD_BLK_SIZE)); + if ((blockPtr + EDID_DTD_BLK_SIZE - 1) < EDID_BLOCK_SIZE) + { + dtdFound = storeMonitorDescriptor(pDis, blockPtr); + } + } + } + else if (blockNumber >= 1) + { + switch (pDis->EdidBlock[0]) + { + /* CEA EXTENSION */ + case EDID_CEA_EXTENSION: + /* Read CEA flag bits here - lockout when read once??? */ + pDis->EdidCeaFlags = pDis->EdidBlock[3]; + + blockPtr = EDID_BLK_EXT_BASE; /* data block start always fixed */ + endPtr = pDis->EdidBlock[2]; /* byte after end of data blocks */ + if (endPtr >= (EDID_BLK_EXT_BASE + 2) && (endPtr <= EDID_BLOCK_SIZE)) + /* Only try reading if data blocks take up 2 bytes or more, since + * a video data block must be at least 2 bytes + */ + { + while (blockPtr < endPtr) + { + blockType = (UInt8)((pDis->EdidBlock[blockPtr] & 0xE0) >> 5); + blockLength = (pDis->EdidBlock[blockPtr] & 0x1F); + + switch((Int)blockType) + { + case E_CEA_VIDEO_BLOCK: /* We have a video data block */ + for (i = 1; i <= blockLength; i++) + { + if ((blockPtr + i) < (EDID_BLOCK_SIZE)) + { + /* If space, store non-zero SVDs */ + if ((pDis->EdidBlock[blockPtr + i] != 0) && + (pDis->EdidSvdCnt < HDMI_TX_SVD_MAX_CNT)) + { + pDis->EdidVFmts[pDis->EdidSvdCnt] = + pDis->EdidBlock[blockPtr + i]; + pDis->EdidSvdCnt++; + } + } + else + { + /* do nothing */ + } + } + break; + case E_CEA_AUDIO_BLOCK: /* We have an audio data block */ + for (i = 1; (i + 2) <= blockLength; i += 3) + { /* Must loop in steps of 3 (SAD size) */ + /* If space, store non-zero SADs */ + if ((blockPtr) < (EDID_BLOCK_SIZE -(i +2))) + { + if (((pDis->EdidBlock[blockPtr + i] & 0x78) != 0) && + (pDis->EdidSadCnt < HDMI_TX_SAD_MAX_CNT)) + { + pDis->EdidAFmts[pDis->EdidSadCnt].ModeChans = + pDis->EdidBlock[blockPtr + i]; + pDis->EdidAFmts[pDis->EdidSadCnt].Freqs = + pDis->EdidBlock[blockPtr + i + 1]; + pDis->EdidAFmts[pDis->EdidSadCnt].Byte3 = + pDis->EdidBlock[blockPtr + i + 2]; + pDis->EdidSadCnt++; + } + } + else + { + /* do nothing */ + } + } + break; + case E_CEA_VSDB: /* We have a VSDB */ + /* 5 bytes expected, but this is EDID land so double check*/ + if (blockLength >= 5) + { + if ((blockPtr) < (EDID_BLOCK_SIZE - 5)) + { + if ((pDis->EdidBlock[blockPtr + 1] == 0x03) && + (pDis->EdidBlock[blockPtr + 2] == 0x0C) && + (pDis->EdidBlock[blockPtr + 3] == 0x00)) + { + pDis->EdidSinkType = HDMITX_SINK_HDMI; + if ((blockPtr) < (EDID_BLOCK_SIZE - 5)) + { + pDis->EdidSourceAddress = + ((UInt16)pDis->EdidBlock[blockPtr + 4] << 8) + + pDis->EdidBlock[blockPtr + 5]; + } + else + { + /* do nothing */ + } + } + else + { + pDis->EdidSinkType = HDMITX_SINK_DVI; + } + } + else + { + /* do nothing */ + } + } + + if (blockLength >= 6) /* Space for byte with AI flag */ + { /* Mask AI bit */ + if ((blockPtr ) < (EDID_BLOCK_SIZE - 6)) + { + if((pDis->EdidBlock[blockPtr + 6] & 0x80) == 0x80) + { + pDis->EdidSinkAi = True; + } + } + else + { + /* do nothing */ + } + } + + /* Read Max_TMDS_Clock */ + if (blockLength >= 7) + pDis->EdidExtraVsdbData.maxTmdsClock = pDis->EdidBlock[blockPtr + 7]; + else + pDis->EdidExtraVsdbData.maxTmdsClock = 0; + + + /* latency, HDMI Video present and content type fields */ + if (blockLength >= 8) { + if ((blockPtr) < (EDID_BLOCK_SIZE - 10)) + { + /* Read CNC0~3 */ + pDis->EdidExtraVsdbData.cnc0 = pDis->EdidBlock[blockPtr + 8] & 0x01; /* 1=True, 0=False */ + pDis->EdidExtraVsdbData.cnc1 = (pDis->EdidBlock[blockPtr + 8] & 0x02) >> 1; + pDis->EdidExtraVsdbData.cnc2 = (pDis->EdidBlock[blockPtr + 8] & 0x04) >> 2; + pDis->EdidExtraVsdbData.cnc3 = (pDis->EdidBlock[blockPtr + 8] & 0x08) >> 3; + + if( (pDis->EdidBlock[blockPtr + 8] & 0xC0) == 0xC0 ) { + /* Read video_latency, audio_latency, I_video_latency, I_audio_latency */ + + if ((blockPtr) < (EDID_BLOCK_SIZE - 12)) + { + pDis->EdidLatency.Edidvideo_latency = pDis->EdidBlock[blockPtr + 9]; + pDis->EdidLatency.Edidaudio_latency = pDis->EdidBlock[blockPtr + 10]; + pDis->EdidLatency.EdidIvideo_latency = pDis->EdidBlock[blockPtr + 11]; + pDis->EdidLatency.EdidIaudio_latency = pDis->EdidBlock[blockPtr + 12]; + + pDis->EdidLatency.latency_available = True; + pDis->EdidLatency.Ilatency_available = True; + + offset3D = 13; /* offset to the '3D_present' field */ + + } + else + { + /* do nothing */ + } + } + else if ((pDis->EdidBlock[blockPtr + 8] & 0x80) == 0x80) { + /* Read video_latency, audio_latency */ + + pDis->EdidLatency.Edidvideo_latency = pDis->EdidBlock[blockPtr + 9]; + pDis->EdidLatency.Edidaudio_latency = pDis->EdidBlock[blockPtr + 10]; + + pDis->EdidLatency.latency_available = True; + + offset3D = 11; + } + else { + pDis->EdidLatency.latency_available = False; + pDis->EdidLatency.Ilatency_available = False; + offset3D = 9; + } + + /* Read HDMI_Video_present */ + pDis->EdidExtraVsdbData.hdmiVideoPresent = (pDis->EdidBlock[blockPtr + 8] & 0x20) >> 5; + + } + else + { + /* do nothing */ + } + } + else { + pDis->EdidLatency.latency_available = False; + pDis->EdidLatency.Ilatency_available = False; + pDis->EdidExtraVsdbData.hdmiVideoPresent = False; + pDis->EdidExtraVsdbData.cnc0 = False; + pDis->EdidExtraVsdbData.cnc1 = False; + pDis->EdidExtraVsdbData.cnc2 = False; + pDis->EdidExtraVsdbData.cnc3 = False; + } + + + /* 3D data fields according to HDMI 1.4a standard */ + if (pDis->EdidExtraVsdbData.hdmiVideoPresent) { + + /* read 3D_present */ + pDis->EdidExtraVsdbData.h3DPresent = (pDis->EdidBlock[blockPtr + offset3D] & 0x80) >> 7; + /* read 3D_Multi_present */ + pDis->EdidExtraVsdbData.h3DMultiPresent = (pDis->EdidBlock[blockPtr + offset3D] & 0x60) >> 5; + /* read image_Size */ + pDis->EdidExtraVsdbData.imageSize = (pDis->EdidBlock[blockPtr + offset3D] & 0x18) >> 3; + + /* read HDMI_3D_LEN and HDMI_XX_LEN */ + offset3D += 1; + pDis->EdidExtraVsdbData.hdmi3DLen = pDis->EdidBlock[blockPtr + offset3D] & 0x1F; + pDis->EdidExtraVsdbData.hdmiVicLen = (pDis->EdidBlock[blockPtr + offset3D] & 0xE0) >> 5; + + if((pDis->EdidExtraVsdbData.hdmi3DLen + pDis->EdidExtraVsdbData.hdmiVicLen) > 0) + { + /* copy the rest of the bytes*/ + lmemcpy(pDis->EdidExtraVsdbData.ext3DData, &(pDis->EdidBlock[blockPtr + offset3D + 1]), blockLength-offset3D); + } + } + else { + pDis->EdidExtraVsdbData.h3DPresent = False; + pDis->EdidExtraVsdbData.h3DMultiPresent = 0; + pDis->EdidExtraVsdbData.imageSize = 0; + pDis->EdidExtraVsdbData.hdmi3DLen = 0; + pDis->EdidExtraVsdbData.hdmiVicLen = 0; + } + + + break; + + + case E_CEA_EXTENDED: /* Use extended Tag */ + + /* we need to read the extended tag code */ + + if ((blockPtr ) < (EDID_BLOCK_SIZE -2)) + { + switch ( pDis->EdidBlock[blockPtr + 1]) + { + case EXT_CEA_COLORIMETRY_DB: + + /* look at xvYCC709 and xvYCC601 support */ + pDis->EdidCeaXVYCCFlags = pDis->EdidBlock[blockPtr + 2]; + + break; + } + } + else + { + /* do nothing */ + } + break; /* E_CEA_EXTENDED */ + + + + default: + break; + } + blockPtr += (blockLength + 1); /* Point to next block */ + } + } + dtdFound = True; + + for (i = 0; (i < EDID_NUMBER_MAX_DTD_BLK_1) && (dtdFound); i++) /* search possible DTD blocks in block 1 */ + { + blockPtr = ((UInt8)pDis->EdidBlock[EDID_BLK1_OFFSET_BASE_DTD]) + ((UInt8)(i * EDID_DTD_BLK_SIZE)); + if ((blockPtr + EDID_DTD_BLK_SIZE - 1) < EDID_BLOCK_SIZE) + { + dtdFound = storeDtdBlock(pDis, blockPtr); + } + } + + break; + + + case EDID_BLOCK_MAP: + /* BLOCK MAP */ + + if (pDis->EdidBlockCnt > 1) { + if ((pDis->EdidBlockCnt - 1) < EDID_BLOCK_SIZE) + { + if (pDis->EdidBlock[pDis->EdidBlockCnt - 1] == EDID_CEA_EXTENSION) { + /* Some devices have been incorrectly designed so that the block map is not counted in the */ + /* extension count. Design of compliant devices should take compatibility with those non-compliant */ + /* devices into consideration. */ + pDis->EdidBlockCnt = pDis->EdidBlockCnt + 1; + } + } + else + { + /* do nothing */ + } + } + + + break; + + + } + + } + + return TM_OK; +} + +/*============================================================================*/ +/* storeDtdBlock */ +/*============================================================================*/ +static Bool +storeDtdBlock +( + tmHdmiTxobject_t *pDis, /* Device instance strucure holding block */ + UInt8 blockPtr +) +{ + + Bool dtdFound = False; + + if (blockPtr >= (EDID_BLOCK_SIZE-17)) + { + /* do nothing */ + return dtdFound; + } + + /* First, select blocks that are DTDs [CEA861C A.2.10] */ + if (((pDis->EdidBlock[blockPtr+0] != 0) || + (pDis->EdidBlock[blockPtr+1] != 0) || + (pDis->EdidBlock[blockPtr+2] != 0) || + (pDis->EdidBlock[blockPtr+4] != 0)) + && + (pDis->NbDTDStored < NUMBER_DTD_STORED)) + { /* Store the first DTD we find, others will be skipped */ + pDis->EdidDTD[pDis->NbDTDStored].uPixelClock = + ((UInt16)pDis->EdidBlock[blockPtr+1] << 8) | + (UInt16)pDis->EdidBlock[blockPtr+0]; + + pDis->EdidDTD[pDis->NbDTDStored].uHActivePixels = + (((UInt16)pDis->EdidBlock[blockPtr+4] & 0x00F0) << 4) | + (UInt16)pDis->EdidBlock[blockPtr+2]; + + pDis->EdidDTD[pDis->NbDTDStored].uHBlankPixels = + (((UInt16)pDis->EdidBlock[blockPtr+4] & 0x000F) << 8) | + (UInt16)pDis->EdidBlock[blockPtr+3]; + + pDis->EdidDTD[pDis->NbDTDStored].uVActiveLines = + (((UInt16)pDis->EdidBlock[blockPtr+7] & 0x00F0) << 4) | + (UInt16)pDis->EdidBlock[blockPtr+5]; + + pDis->EdidDTD[pDis->NbDTDStored].uVBlankLines = + (((UInt16)pDis->EdidBlock[blockPtr+7] & 0x000F) << 8) | + (UInt16)pDis->EdidBlock[blockPtr+6]; + + pDis->EdidDTD[pDis->NbDTDStored].uHSyncOffset = + (((UInt16)pDis->EdidBlock[blockPtr+11] & 0x00C0) << 2) | + (UInt16)pDis->EdidBlock[blockPtr+8]; + + pDis->EdidDTD[pDis->NbDTDStored].uHSyncWidth = + (((UInt16)pDis->EdidBlock[blockPtr+11] & 0x0030) << 4) | + (UInt16)pDis->EdidBlock[blockPtr+9]; + + pDis->EdidDTD[pDis->NbDTDStored].uVSyncOffset = + (((UInt16)pDis->EdidBlock[blockPtr+11] & 0x000C) << 2) | + (((UInt16)pDis->EdidBlock[blockPtr+10] & 0x00F0) >> 4); + + pDis->EdidDTD[pDis->NbDTDStored].uVSyncWidth = + (((UInt16)pDis->EdidBlock[blockPtr+11] & 0x0003) << 4) | + ((UInt16)pDis->EdidBlock[blockPtr+10] & 0x000F); + + pDis->EdidDTD[pDis->NbDTDStored].uHImageSize = + (((UInt16)pDis->EdidBlock[blockPtr+14] & 0x00F0) << 4) | + (UInt16)pDis->EdidBlock[blockPtr+12]; + + pDis->EdidDTD[pDis->NbDTDStored].uVImageSize = + (((UInt16)pDis->EdidBlock[blockPtr+14] & 0x000F) << 8) | + (UInt16)pDis->EdidBlock[blockPtr+13]; + + pDis->EdidDTD[pDis->NbDTDStored].uHBorderPixels = + (UInt16)pDis->EdidBlock[blockPtr+15]; + + pDis->EdidDTD[pDis->NbDTDStored].uVBorderPixels = + (UInt16)pDis->EdidBlock[blockPtr+16]; + + pDis->EdidDTD[pDis->NbDTDStored].Flags = pDis->EdidBlock[blockPtr+17]; + + pDis->NbDTDStored++; + + dtdFound = True; /* Stop any more DTDs being parsed */ + } + + return (dtdFound); +} + + +/*============================================================================*/ +/* storeMonitorBlock */ +/*============================================================================*/ +static Bool +storeMonitorDescriptor +( + tmHdmiTxobject_t *pDis, /* Device instance strucure holding block */ + UInt8 blockPtr +) +{ + + Bool dtdFound = False; + + if (blockPtr >= (EDID_BLOCK_SIZE-5)) + { + /* do nothing */ + return dtdFound; + } + + /* First, select blocks that are DTDs [CEA861C A.2.10] */ + if ((pDis->EdidBlock[blockPtr+0] == 0) && + (pDis->EdidBlock[blockPtr+1] == 0) && + (pDis->EdidBlock[blockPtr+2] == 0) + ) + { + if (pDis->EdidBlock[blockPtr+3] == EDID_MONITOR_NAME_DESC_DATA_TYPE) + { + if (pDis->EdidFirstMonitorDescriptor.bDescRecord == False) + { + pDis->EdidFirstMonitorDescriptor.bDescRecord = True; + lmemcpy(&(pDis->EdidFirstMonitorDescriptor.uMonitorName) , + &(pDis->EdidBlock[blockPtr+5]), EDID_MONITOR_DESCRIPTOR_SIZE); + dtdFound = True; + } + else if ((pDis->EdidOtherMonitorDescriptor.bDescRecord == False)) + { + pDis->EdidOtherMonitorDescriptor.bDescRecord = True; + lmemcpy(&(pDis->EdidOtherMonitorDescriptor.uOtherDescriptor) , + &(pDis->EdidBlock[blockPtr+5]), EDID_MONITOR_DESCRIPTOR_SIZE); + dtdFound = True; + } + } + else if (pDis->EdidBlock[blockPtr+3] == EDID_MONITOR_RANGE_DESC_DATA_TYPE) + { + if (pDis->EdidSecondMonitorDescriptor.bDescRecord == False) + { + if (blockPtr < (EDID_BLOCK_SIZE-9)) + { + pDis->EdidSecondMonitorDescriptor.bDescRecord = True; + pDis->EdidSecondMonitorDescriptor.uMinVerticalRate = pDis->EdidBlock[blockPtr+5]; + pDis->EdidSecondMonitorDescriptor.uMaxVerticalRate = pDis->EdidBlock[blockPtr+6]; + pDis->EdidSecondMonitorDescriptor.uMinHorizontalRate = pDis->EdidBlock[blockPtr+7]; + pDis->EdidSecondMonitorDescriptor.uMaxHorizontalRate = pDis->EdidBlock[blockPtr+8]; + pDis->EdidSecondMonitorDescriptor.uMaxSupportedPixelClk = pDis->EdidBlock[blockPtr+9]; + dtdFound = True; + } + else + { + /* do nothing */ + } + } + } + } + + return (dtdFound); + +} + + +/*============================================================================*/ +/* tmbslTDA9989EdidGetLatencyInfo */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EdidGetLatencyInfo +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidLatency_t * pEdidLatency +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pEdidLatency == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + + *pEdidLatency = pDis->EdidLatency; + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + return err; + +} + +/*============================================================================*/ +/* tmbslTDA9989EdidGetExtraVsdbData */ +/*============================================================================*/ +tmErrorCode_t tmbslTDA9989EdidGetExtraVsdbData +( + tmUnitSelect_t txUnit, + tmbslHdmiTxEdidExtraVsdbData_t **pExtraVsdbData +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pExtraVsdbData == Null) + + if ((pDis->EdidStatus == HDMITX_EDID_READ) || + (pDis->EdidStatus == HDMITX_EDID_ERROR_CHK)) + { + /* allow if edid are read or if there are a chk error on an other block than block 0 */ + *pExtraVsdbData = &(pDis->EdidExtraVsdbData); + } + else + { + /* Not allowed if EdidStatus value is not valid */ + err = TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE; + } + return err; +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid_l.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid_l.h new file mode 100755 index 0000000000000..289347fe93344 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Edid_l.h @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2009 Koninklijke Philips Electronics N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of Koninklijke Philips Electronics N.V. and is confidential in + * nature. Under no circumstances is this software to be exposed to or placed + * under an Open Source License of any type without the expressed written + * permission of Koninklijke Philips Electronics N.V. + * + * \file tmbslTDA9989_Edid_l.h + * + * \version $Revision: 2 $ + * + * \date $Date: 04/07/07 17:00 $ + * + * +*/ + +#ifndef TMBSLTDA9989_EDID_L_H +#define TMBSLTDA9989_EDID_L_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* EXTERN DATA DEFINITION */ +/*============================================================================*/ + +extern tmErrorCode_t +EdidBlockAvailable (tmUnitSelect_t txUnit, Bool * pSendEDIDCallback); + +extern tmErrorCode_t +ClearEdidRequest (tmUnitSelect_t txUnit); + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + + + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_EDID_L_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP.c b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP.c new file mode 100755 index 0000000000000..5c12a3a48f6b0 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP.c @@ -0,0 +1,655 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_HDCP.c + * + * \version $Revision: 2 $ + * + */ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmbslHdmiTx_types.h" +#include "tmbslTDA9989_Functions.h" +#include "tmbslTDA9989_local.h" +#include "tmbslTDA9989_State_l.h" +#include "tmbslTDA9989_InOut_l.h" + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS EXPORTED */ +/*============================================================================*/ + +/** + * Table of registers to switch HDMI HDCP mode off for DVI + */ + +CONST_DAT tmHdmiTxRegMaskVal_t kVoutHdcpOff[] = + { + {E_REG_P00_TBG_CNTRL_1_W, E_MASKREG_P00_TBG_CNTRL_1_dwin_dis, 1}, + {E_REG_P12_TX33_RW, E_MASKREG_P12_TX33_hdmi, 0}, + {0,0,0} + }; + +/** + * Table of registers to switch HDMI HDCP mode on for HDMI + */ +CONST_DAT tmHdmiTxRegMaskVal_t kVoutHdcpOn[] = + { + {E_REG_P00_TBG_CNTRL_1_W, E_MASKREG_P00_TBG_CNTRL_1_dwin_dis, 0}, + {E_REG_P11_ENC_CNTRL_RW, E_MASKREG_P11_ENC_CNTRL_ctl_code, 1}, + {E_REG_P12_TX33_RW, E_MASKREG_P12_TX33_hdmi, 1}, + {0,0,0} + }; + +#ifdef __LINUX_ARM_ARCH__ + +#include + +typedef struct { + tmErrorCode_t + (*tmbslTDA9989HdcpCheck) + ( + tmUnitSelect_t txUnit, + UInt16 uTimeSinceLastCallMs, + tmbslHdmiTxHdcpCheck_t *pResult + ); + tmErrorCode_t + (*tmbslTDA9989HdcpConfigure) + ( + tmUnitSelect_t txUnit, + UInt8 slaveAddress, + tmbslHdmiTxHdcpTxMode_t txMode, + tmbslHdmiTxHdcpOptions_t options, + UInt16 uCheckIntervalMs, + UInt8 uChecksToDo + ); + tmErrorCode_t + (*tmbslTDA9989HdcpDownloadKeys) + ( + tmUnitSelect_t txUnit, + UInt16 seed, + tmbslHdmiTxDecrypt_t keyDecryption + ); + tmErrorCode_t + (*tmbslTDA9989HdcpEncryptionOn) + ( + tmUnitSelect_t txUnit, + Bool bOn + ); + tmErrorCode_t + (*tmbslTDA9989HdcpGetOtp) + ( + tmUnitSelect_t txUnit, + UInt8 otpAddress, + UInt8 *pOtpData + ); + tmErrorCode_t + (*tmbslTDA9989HdcpGetT0FailState) + ( + tmUnitSelect_t txUnit, + UInt8 *pFailState + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleBCAPS) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleBKSV) + ( + tmUnitSelect_t txUnit, + UInt8 *pBksv, + Bool *pbCheckRequired /* May be null, but only for testing */ + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleBKSVResult) + ( + tmUnitSelect_t txUnit, + Bool bSecure + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleBSTATUS) + ( + tmUnitSelect_t txUnit, + UInt16 *pBstatus /* May be null */ + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleENCRYPT) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandlePJ) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleSHA_1) + ( + tmUnitSelect_t txUnit, + UInt8 maxKsvDevices, + UInt8 *pKsvList, /* May be null if maxKsvDevices is 0 */ + UInt8 *pnKsvDevices, /* May be null if maxKsvDevices is 0 */ + UInt8 *pDepth /* Connection tree depth returned with KSV list */ + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleSHA_1Result) + ( + tmUnitSelect_t txUnit, + Bool bSecure + ); + tmErrorCode_t + (*tmbslTDA9989HdcpHandleT0) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t + (*tmbslTDA9989HdcpInit) + ( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVfreq_t voutFreq + ); + tmErrorCode_t + (*tmbslTDA9989HdcpRun) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t + (*tmbslTDA9989HdcpStop) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t + (*tmbslTDA9989HdcpGetSinkCategory) + ( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkCategory_t *category + ); + tmErrorCode_t + (*tmbslTDA9989handleBKSVResultSecure) + ( + tmUnitSelect_t txUnit + ); + tmErrorCode_t (*f1)(tmHdmiTxobject_t *pDis); + int (*f2)(tmHdmiTxobject_t *pDis); +} hdcp_private_t; + +#include /* need for EXPORT_SYMBOL */ + +hdcp_private_t *h; + +void register_hdcp_private(hdcp_private_t *hdcp) +{ + h = hdcp; +} +EXPORT_SYMBOL(register_hdcp_private); + +tmErrorCode_t rej_f1(tmHdmiTxobject_t *pDis) { + return (h?h->f1(pDis):0); +} + +int rej_f2(tmHdmiTxobject_t *pDis) { + return (h?h->f2(pDis):0); +} + +tmErrorCode_t rej_f3(tmUnitSelect_t txUnit) { + return (h?h->tmbslTDA9989handleBKSVResultSecure(txUnit):TM_OK); +} + +#endif + +/*============================================================================*/ +/* tmbslTDA9989HdcpCheck */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpCheck +( + tmUnitSelect_t txUnit, + UInt16 uTimeSinceLastCallMs, + tmbslHdmiTxHdcpCheck_t *pResult + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpCheck + ( + txUnit, + uTimeSinceLastCallMs, + pResult + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpConfigure */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpConfigure +( + tmUnitSelect_t txUnit, + UInt8 slaveAddress, + tmbslHdmiTxHdcpTxMode_t txMode, + tmbslHdmiTxHdcpOptions_t options, + UInt16 uCheckIntervalMs, + UInt8 uChecksToDo + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpConfigure + ( + txUnit, + slaveAddress, + txMode, + options, + uCheckIntervalMs, + uChecksToDo + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpDownloadKeys */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpDownloadKeys +( + tmUnitSelect_t txUnit, + UInt16 seed, + tmbslHdmiTxDecrypt_t keyDecryption + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpDownloadKeys + ( + txUnit, + seed, + keyDecryption + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpEncryptionOn */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpEncryptionOn +( + tmUnitSelect_t txUnit, + Bool bOn + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpEncryptionOn + ( + txUnit, + bOn + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + + +/*============================================================================*/ +/* tmbslTDA9989HdcpGetOtp */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpGetOtp +( + tmUnitSelect_t txUnit, + UInt8 otpAddress, + UInt8 *pOtpData + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpGetOtp + ( + txUnit, + otpAddress, + pOtpData + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpGetT0FailState */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpGetT0FailState +( + tmUnitSelect_t txUnit, + UInt8 *pFailState + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpGetT0FailState + ( + txUnit, + pFailState + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleBCAPS */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBCAPS +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleBCAPS + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleBKSV */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBKSV +( + tmUnitSelect_t txUnit, + UInt8 *pBksv, + Bool *pbCheckRequired /* May be null, but only for testing */ + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleBKSV + ( + txUnit, + pBksv, + pbCheckRequired /* May be null, but only for testing */ + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleBKSVResult */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBKSVResult +( + tmUnitSelect_t txUnit, + Bool bSecure + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleBKSVResult + ( + txUnit, + bSecure + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleBSTATUS */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleBSTATUS +( + tmUnitSelect_t txUnit, + UInt16 *pBstatus /* May be null */ + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleBSTATUS + ( + txUnit, + pBstatus /* May be null */ + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleENCRYPT */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleENCRYPT +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleENCRYPT + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandlePJ */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandlePJ +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandlePJ + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleSHA_1 */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleSHA_1 +( + tmUnitSelect_t txUnit, + UInt8 maxKsvDevices, + UInt8 *pKsvList, /* May be null if maxKsvDevices is 0 */ + UInt8 *pnKsvDevices, /* May be null if maxKsvDevices is 0 */ + UInt8 *pDepth /* Connection tree depth returned with KSV list */ + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleSHA_1 + ( + txUnit, + maxKsvDevices, + pKsvList, /* May be null if maxKsvDevices is 0 */ + pnKsvDevices, /* May be null if maxKsvDevices is 0 */ + pDepth /* Connection tree depth returned with KSV list */ + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleSHA_1Result */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleSHA_1Result +( + tmUnitSelect_t txUnit, + Bool bSecure + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleSHA_1Result + ( + txUnit, + bSecure + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpHandleT0 */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpHandleT0 +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpHandleT0 + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpInit */ +/* RETIF_REG_FAIL NOT USED HERE AS ALL ERRORS SHOULD BE TRAPPED IN ALL BUILDS */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpInit +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVfreq_t voutFreq + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpInit + ( + txUnit, + voutFmt, + voutFreq + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpRun */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpRun +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpRun + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpStop */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpStop +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpStop + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989HdcpGetSinkCategory */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpGetSinkCategory +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkCategory_t *category + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989HdcpGetSinkCategory + ( + txUnit, + category + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + + + + +/*============================================================================*/ +/* tmbslTDA9989handleBKSVResultSecure */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989handleBKSVResultSecure +( + tmUnitSelect_t txUnit + ) +{ +#ifdef __LINUX_ARM_ARCH__ + if (h) return h->tmbslTDA9989handleBKSVResultSecure + ( + txUnit + ); +/* else {printk("%s is empty\n",__func__);}*/ +#endif + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP_l.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP_l.h new file mode 100755 index 0000000000000..a1d6a4b4f3ce3 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_HDCP_l.h @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2008 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_HDCP_l.h + * + * \version %version: 2 % + * + * \date %date_modified: % + * + * \brief BSL driver component local definitions for the TDA998x + * HDMI Transmitter. + * + * \section info Change Information + * + * +*/ + +#ifndef TMBSLTDA9989_HDCP_L_H +#define TMBSLTDA9989_HDCP_L_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __LINUX_ARM_ARCH__ + +#define HDCP_F1 { \ + int rej_f2(tmHdmiTxobject_t *pDis); \ + regVal = rej_f2(pDis); \ + } + +#define HDCP_F2 { \ + tmErrorCode_t rej_f1(tmHdmiTxobject_t *pDis); \ + err = rej_f1(pDis); \ + RETIF(err != TM_OK, err); \ +} + +#define HDCP_F3 { \ + if (fInterruptStatus & (1 << HDMITX_CALLBACK_INT_R0)) \ + { \ + tmErrorCode_t rej_f3(tmUnitSelect_t txUnit); \ + err = rej_f3(txUnit); \ + RETIF(err != TM_OK, err); \ + } \ +} + +#else + +#define HDCP_F1 {regVal = 0;} + +#define HDCP_F2 {} + +#define HDCP_F3 {} + +#endif /*TMFL_HDCP_SUPPORT*/ + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_HDCP_L_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut.c b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut.c new file mode 100755 index 0000000000000..7d34fa65fbb03 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut.c @@ -0,0 +1,5101 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_InOut.c + * + * \version %version: 3 % + * + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#include +#endif + +#include "tmbslHdmiTx_types.h" +#include "tmbslTDA9989_Functions.h" +#include "tmbslTDA9989_local.h" +#include "tmbslTDA9989_HDCP_l.h" +#include "tmbslTDA9989_State_l.h" +#include "tmbslTDA9989_Misc_l.h" +#include "tmbslTDA9989_InOut_l.h" + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + +#define SSD_UNUSED_VALUE 0xF0 + +#ifdef FORMAT_PC +#define DEPTH_COLOR_PC 1 /* PC_FORMAT only 8 bits available */ +#endif /* FORMAT_PC */ + +#define REG_VAL_SEL_AIP_SPDIF 0 +#define REG_VAL_SEL_AIP_I2S 1 +#define REG_VAL_SEL_AIP_OBA 2 +#define REG_VAL_SEL_AIP_DST 3 +#define REG_VAL_SEL_AIP_HBR 5 + +struct vic2reg { + unsigned char vic; + unsigned char reg; +}; + +struct sync_desc { + UInt16 Vs2; + UInt8 pix_rep; + UInt8 v_toggle; + UInt8 h_toggle; + UInt16 hfp; /* Output values for Vs/Hs input sync */ + UInt16 vfp; + UInt16 href; /* Output values for all other input sync sources */ + UInt16 vref; +}; + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS EXPORTED */ +/*============================================================================*/ + +extern CONST_DAT tmHdmiTxRegMaskVal_t kVoutHdcpOff[]; +extern CONST_DAT tmHdmiTxRegMaskVal_t kVoutHdcpOn[]; + +/** + * Lookup table of input port control registers and their swap and mirror masks + */ +CONST_DAT tmbslTDA9989RegVip + kRegVip[HDMITX_VIN_PORT_MAP_TABLE_LEN] = +{ + {E_REG_P00_VIP_CNTRL_0_W, + E_MASKREG_P00_VIP_CNTRL_0_swap_a, + E_MASKREG_P00_VIP_CNTRL_0_mirr_a + }, /* Port group 0 */ + {E_REG_P00_VIP_CNTRL_0_W, + E_MASKREG_P00_VIP_CNTRL_0_swap_b, + E_MASKREG_P00_VIP_CNTRL_0_mirr_b + }, /* Port group 1 */ + {E_REG_P00_VIP_CNTRL_1_W, + E_MASKREG_P00_VIP_CNTRL_1_swap_c, + E_MASKREG_P00_VIP_CNTRL_1_mirr_c + }, /* Port group 2 */ + {E_REG_P00_VIP_CNTRL_1_W, + E_MASKREG_P00_VIP_CNTRL_1_swap_d, + E_MASKREG_P00_VIP_CNTRL_1_mirr_d + }, /* Port group 3 */ + {E_REG_P00_VIP_CNTRL_2_W, + E_MASKREG_P00_VIP_CNTRL_2_swap_e, + E_MASKREG_P00_VIP_CNTRL_2_mirr_e + }, /* Port group 4 */ + {E_REG_P00_VIP_CNTRL_2_W, + E_MASKREG_P00_VIP_CNTRL_2_swap_f, + E_MASKREG_P00_VIP_CNTRL_2_mirr_f + } /* Port group 5 */ +}; + +/** + * Table of PLL settings registers to configure for all video input format (vinFmt) + */ +CONST_DAT tmHdmiTxRegMaskVal_t kCommonPllCfg[] = +{ + {E_REG_P02_PLL_SERIAL_1_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_PLL_SERIAL_2_RW, E_MASKREG_ALL, 0x01}, + {E_REG_P02_PLL_SERIAL_3_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_SERIALIZER_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_BUFFER_OUT_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_PLL_SCG1_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_AUDIO_DIV_RW, E_MASKREG_ALL, 0x03}, + /*{E_REG_P02_TEST2_RW, E_MASKREG_ALL, 0x00},*/ + {E_REG_P02_SEL_CLK_RW, E_MASKREG_ALL, 0x09}, + {0,0,0} +}; + +/** + * Table of PLL settings registers to configure double mode pixel rate, + * vinFmt other than 480i or 576i + */ +CONST_DAT tmHdmiTxRegMaskVal_t kDoublePrateVfmtOtherPllCfg[] = +{ + {E_REG_P02_PLL_SCG2_RW, E_MASKREG_ALL, 0x00}, + {0,0,0} +}; + +/** + * Table of PLL settings registers to configure for single mode pixel rate, + * vinFmt 480i or 576i only + */ +CONST_DAT tmHdmiTxRegMaskVal_t kSinglePrateVfmt480i576iPllCfg[] = +{ + {E_REG_P02_PLL_SCG2_RW, E_MASKREG_ALL, 0x11}, + {0,0,0} +}; + +/** + * Table of PLL settings registers to configure single mode pixel rate, + * vinFmt other than 480i or 576i + */ +CONST_DAT tmHdmiTxRegMaskVal_t kSinglePrateVfmtOtherPllCfg[] = +{ + {E_REG_P02_PLL_SCG2_RW, E_MASKREG_ALL, 0x10}, + {0,0,0} +}; + +/** + * Table of PLL settings registers to configure for single repeated mode pixel rate, + * vinFmt 480i or 576i only + */ +CONST_DAT tmHdmiTxRegMaskVal_t kSrepeatedPrateVfmt480i576iPllCfg[] = +{ + {E_REG_P02_PLL_SCG2_RW, E_MASKREG_ALL, 0x01}, + {0,0,0} +}; + +/** + * Table of PLL settings registers to configure for 480i and 576i vinFmt + */ +CONST_DAT tmHdmiTxRegMaskVal_t kVfmt480i576iPllCfg[] = +{ + {E_REG_P02_PLL_SCGN1_RW, E_MASKREG_ALL, 0x14}, + {E_REG_P02_PLL_SCGN2_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_PLL_SCGR1_RW, E_MASKREG_ALL, 0x0A}, + {E_REG_P02_PLL_SCGR2_RW, E_MASKREG_ALL, 0x00}, + {0,0,0} +}; + +/** + * Table of PLL settings registers to configure for other vinFmt than 480i and 576i + */ +CONST_DAT tmHdmiTxRegMaskVal_t kVfmtOtherPllCfg[] = +{ + {E_REG_P02_PLL_SCGN1_RW, E_MASKREG_ALL, 0xFA}, + {E_REG_P02_PLL_SCGN2_RW, E_MASKREG_ALL, 0x00}, + {E_REG_P02_PLL_SCGR1_RW, E_MASKREG_ALL, 0x5B}, + {E_REG_P02_PLL_SCGR2_RW, E_MASKREG_ALL, 0x00}, + {0,0,0} +}; + +/** + * Lookup table to convert from EIA/CEA TV video formats used in the EDID and + * in API parameters to pixel clock frequencies, according to SCS Table + * "HDMI Pixel Clock Frequencies per EIA/CEA-861B Video Output Format". + * The other index is the veritical frame frequency. + */ + +CONST_DAT UInt8 kVfmtToPixClk_TV[HDMITX_VFMT_TV_MAX][HDMITX_VFREQ_NUM] = +{ + /* HDMITX_VFREQ_24Hz HDMITX_VFREQ_25Hz HDMITX_VFREQ_30Hz HDMITX_VFREQ_50Hz HDMITX_VFREQ_59Hz HDMITX_VFREQ_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_25175, E_PIXCLK_25200}, /* HDMITX_VFMT_01_640x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_27027}, /* HDMITX_VFMT_02_720x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_27027}, /* HDMITX_VFMT_03_720x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_74175, E_PIXCLK_74250}, /* HDMITX_VFMT_04_1280x720p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_74175, E_PIXCLK_74250}, /* HDMITX_VFMT_05_1920x1080i_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_27027}, /* HDMITX_VFMT_06_720x480i_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_27027}, /* HDMITX_VFMT_07_720x480i_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_27027}, /* HDMITX_VFMT_08_720x240p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_27027}, /* HDMITX_VFMT_09_720x240p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_54054}, /* HDMITX_VFMT_10_720x480i_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_54054}, /* HDMITX_VFMT_11_720x480i_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_54054}, /* HDMITX_VFMT_12_720x240p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_54054}, /* HDMITX_VFMT_13_720x240p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_54054}, /* HDMITX_VFMT_14_1440x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_54054}, /* HDMITX_VFMT_15_1440x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_148350, E_PIXCLK_148500}, /* HDMITX_VFMT_16_1920x1080p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_17_720x576p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_18_720x576p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_19_1280x720p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_20_1920x1080i_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_21_720x576i_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_22_720x576i_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_23_720x288p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_27000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_24_720x288p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_25_720x576i_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_26_720x576i_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_27_720x288p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_28_720x288p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_29_1440x576p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_54000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_30_1440x576p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_148500, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_31_1920x1080p_50Hz */ + {E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_32_1920x1080p_24Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_33_1920x1080p_25Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_34_1920x1080p_30Hz */ + + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_108000, E_PIXCLK_108108}, /* HDMITX_VFMT_35_2880x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_108000, E_PIXCLK_108108}, /* HDMITX_VFMT_36_2880x480p_60Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_108000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_37_2880x576p_50Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_108000, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_38_2880x576p_50Hz */ + + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_39_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_40_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_41_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_42_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_43_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_44_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_45_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_46_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_47_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_48_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_49_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_50_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_51_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_52_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_53_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_54_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_55_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_56_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_57_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_58_ */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_59_ */ + + {E_PIXCLK_59400, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_60_1280x720p_24Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID}, /* HDMITX_VFMT_61_1280x720p_25Hz */ + {E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_74250, E_PIXCLK_INVALID, E_PIXCLK_INVALID, E_PIXCLK_INVALID} /* HDMITX_VFMT_62_1280x720p_30Hz */ +}; + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ + + +/** + * Lookup table to convert PC formats used in API parameters to pixel clock + * frequencies. + * The other index is the veritical frame frequency. + */ +#ifdef FORMAT_PC +CONST_DAT UInt8 kVfmtToPixClk_PC[HDMITX_VFMT_PC_NUM] = +{ + /* HDMITX_VFREQ_60Hz HDMITX_VFREQ_70Hz HDMITX_VFREQ_72Hz HDMITX_VFREQ_75Hz HDMITX_VFREQ_85Hz HDMITX_VFREQ_87Hz*/ + E_PIXCLK_25175 , /* HDMITX_VFMT_PC_640x480p_60Hz */ + E_PIXCLK_40000 , /* HDMITX_VFMT_PC_800x600p_60Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1152x960p_60Hz */ + E_PIXCLK_65000 , /* HDMITX_VFMT_PC_1024x768p_60Hz */ + E_PIXCLK_79500 , /* HDMITX_VFMT_PC_1280x768p_60Hz */ + E_PIXCLK_108000 , /* HDMITX_VFMT_PC_1280x1024p_60Hz */ + E_PIXCLK_85500 , /* HDMITX_VFMT_PC_1360x768p_60Hz */ + E_PIXCLK_121750 , /* HDMITX_VFMT_PC_1400x1050p_60Hz */ + E_PIXCLK_162000 , /* HDMITX_VFMT_PC_1600x1200p_60Hz */ + E_PIXCLK_75000 , /* HDMITX_VFMT_PC_1024x768p_70Hz */ + E_PIXCLK_31500 , /* HDMITX_VFMT_PC_640x480p_72Hz */ + E_PIXCLK_50000 , /* HDMITX_VFMT_PC_800x600p_72Hz */ + E_PIXCLK_31500 , /* HDMITX_VFMT_PC_640x480p_75Hz */ + E_PIXCLK_78750 , /* HDMITX_VFMT_PC_1024x768p_75Hz */ + E_PIXCLK_49500 , /* HDMITX_VFMT_PC_800x600p_75Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1024x864p_75Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1280x1024p_75Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_640x350p_85Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_640x400p_85Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_720x400p_85Hz */ + E_PIXCLK_36000 , /* HDMITX_VFMT_PC_640x480p_85Hz */ + E_PIXCLK_56250 , /* HDMITX_VFMT_PC_800x600p_85Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1024x768p_85Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1152x864p_85Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1280x960p_85Hz */ + E_PIXCLK_INVALID, /* HDMITX_VFMT_PC_1280x1024p_85Hz */ /* PR1570 FIXED */ + E_PIXCLK_INVALID /* HDMITX_VFMT_PC_1024x768i_87Hz */ +}; +#endif + +/** + * Lookup table to convert from EIA/CEA TV video formats used in the EDID and in + * API parameters to the format used in the E_REG_P00_VIDFORMAT_W register + */ + +#ifdef TMFL_RGB_DDR_12BITS +static CONST_DAT struct vic2reg vic2reg_TV[] = { + {HDMITX_VFMT_01_640x480p_60Hz, E_REGVFMT_640x480p_60Hz}, + {HDMITX_VFMT_02_720x480p_60Hz, E_REGVFMT_720x480p_60Hz}, + {HDMITX_VFMT_03_720x480p_60Hz, E_REGVFMT_720x480p_60Hz}, + {HDMITX_VFMT_04_1280x720p_60Hz, E_REGVFMT_1280x720p_60Hz}, + {HDMITX_VFMT_05_1920x1080i_60Hz,E_REGVFMT_1920x1080i_60Hz}, + {HDMITX_VFMT_06_720x480i_60Hz, E_REGVFMT_720x480i_60Hz}, + {HDMITX_VFMT_07_720x480i_60Hz, E_REGVFMT_720x480i_60Hz}, + {HDMITX_VFMT_08_720x240p_60Hz, E_REGVFMT_720x240p_60Hz}, + {HDMITX_VFMT_09_720x240p_60Hz, E_REGVFMT_720x240p_60Hz}, + {HDMITX_VFMT_10_720x480i_60Hz, E_REGVFMT_2880x480i_60Hz_PR4}, + {HDMITX_VFMT_11_720x480i_60Hz, E_REGVFMT_2880x480i_60Hz_PR4}, + {HDMITX_VFMT_14_1440x480p_60Hz, E_REGVFMT_1440x480p_60Hz}, + {HDMITX_VFMT_15_1440x480p_60Hz, E_REGVFMT_1440x480p_60Hz}, + {HDMITX_VFMT_16_1920x1080p_60Hz,E_REGVFMT_1920x1080p_60Hz}, + {HDMITX_VFMT_17_720x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_18_720x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_19_1280x720p_50Hz, E_REGVFMT_1280x720p_50Hz}, + {HDMITX_VFMT_20_1920x1080i_50Hz,E_REGVFMT_1920x1080i_50Hz}, + {HDMITX_VFMT_21_720x576i_50Hz, E_REGVFMT_720x576i_50Hz}, + {HDMITX_VFMT_22_720x576i_50Hz, E_REGVFMT_720x576i_50Hz}, + {HDMITX_VFMT_23_720x288p_50Hz, E_REGVFMT_720x288p_50Hz}, + {HDMITX_VFMT_24_720x288p_50Hz, E_REGVFMT_720x288p_50Hz}, + {HDMITX_VFMT_25_720x576i_50Hz, E_REGVFMT_2880x576i_50Hz}, /* FIXME PR 2 */ + {HDMITX_VFMT_26_720x576i_50Hz, E_REGVFMT_2880x576i_50Hz}, /* FIXME PR 2 */ + {HDMITX_VFMT_29_1440x576p_50Hz, E_REGVFMT_1440x576p_50Hz}, + {HDMITX_VFMT_30_1440x576p_50Hz, E_REGVFMT_1440x576p_50Hz}, + {HDMITX_VFMT_31_1920x1080p_50Hz,E_REGVFMT_1920x1080p_50Hz}, + {HDMITX_VFMT_32_1920x1080p_24Hz,E_REGVFMT_1920x1080p_24Hz}, + {HDMITX_VFMT_33_1920x1080p_25Hz,E_REGVFMT_1920x1080p_25Hz}, + {HDMITX_VFMT_34_1920x1080p_30Hz,E_REGVFMT_1920x1080p_30Hz}, + {HDMITX_VFMT_35_2880x480p_60Hz, E_REGVFMT_2880x480p_60Hz}, + {HDMITX_VFMT_36_2880x480p_60Hz, E_REGVFMT_2880x480p_60Hz}, + {HDMITX_VFMT_37_2880x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_38_2880x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_60_1280x720p_24Hz, E_REGVFMT_1280x720p_24Hz}, + {HDMITX_VFMT_61_1280x720p_25Hz, E_REGVFMT_1280x720p_25Hz}, + {HDMITX_VFMT_62_1280x720p_30Hz, E_REGVFMT_1280x720p_30Hz} +}; +static CONST_DAT struct vic2reg vic2reg_TV_FP[] = { + {HDMITX_VFMT_01_640x480p_60Hz, E_REGVFMT_720x480p_60Hz_FP}, + {HDMITX_VFMT_02_720x480p_60Hz, E_REGVFMT_720x480p_60Hz_FP}, + {HDMITX_VFMT_03_720x480p_60Hz, E_REGVFMT_720x480p_60Hz_FP}, + {HDMITX_VFMT_04_1280x720p_60Hz, E_REGVFMT_1280x720p_60Hz_FP}, + {HDMITX_VFMT_05_1920x1080i_60Hz,E_REGVFMT_1920x1080i_60Hz_FP}, + {HDMITX_VFMT_17_720x576p_50Hz, E_REGVFMT_720x576p_50Hz_FP}, + {HDMITX_VFMT_18_720x576p_50Hz, E_REGVFMT_720x576p_50Hz_FP}, + {HDMITX_VFMT_19_1280x720p_50Hz, E_REGVFMT_1280x720p_50Hz_FP}, + {HDMITX_VFMT_20_1920x1080i_50Hz,E_REGVFMT_1920x1080i_50Hz_FP}, + {HDMITX_VFMT_32_1920x1080p_24Hz,E_REGVFMT_1920x1080p_24Hz_FP}, + {HDMITX_VFMT_33_1920x1080p_25Hz,E_REGVFMT_1920x1080p_25Hz_FP}, + {HDMITX_VFMT_34_1920x1080p_30Hz,E_REGVFMT_1920x1080p_30Hz_FP}, + {HDMITX_VFMT_60_1280x720p_24Hz, E_REGVFMT_1280x720p_24Hz_FP}, + {HDMITX_VFMT_61_1280x720p_25Hz, E_REGVFMT_1280x720p_25Hz_FP}, + {HDMITX_VFMT_62_1280x720p_30Hz, E_REGVFMT_1280x720p_30Hz_FP} +}; +#else +static CONST_DAT struct vic2reg vic2reg_TV[] = { + {HDMITX_VFMT_01_640x480p_60Hz, E_REGVFMT_640x480p_60Hz}, + {HDMITX_VFMT_02_720x480p_60Hz, E_REGVFMT_720x480p_60Hz}, + {HDMITX_VFMT_03_720x480p_60Hz, E_REGVFMT_720x480p_60Hz}, + {HDMITX_VFMT_04_1280x720p_60Hz, E_REGVFMT_1280x720p_60Hz}, + {HDMITX_VFMT_05_1920x1080i_60Hz,E_REGVFMT_1920x1080i_60Hz}, + {HDMITX_VFMT_06_720x480i_60Hz, E_REGVFMT_720x480i_60Hz}, + {HDMITX_VFMT_07_720x480i_60Hz, E_REGVFMT_720x480i_60Hz}, + {HDMITX_VFMT_08_720x240p_60Hz, E_REGVFMT_720x240p_60Hz}, + {HDMITX_VFMT_09_720x240p_60Hz, E_REGVFMT_720x240p_60Hz}, + {HDMITX_VFMT_16_1920x1080p_60Hz,E_REGVFMT_1920x1080p_60Hz}, + {HDMITX_VFMT_17_720x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_18_720x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_19_1280x720p_50Hz, E_REGVFMT_1280x720p_50Hz}, + {HDMITX_VFMT_20_1920x1080i_50Hz,E_REGVFMT_1920x1080i_50Hz}, + {HDMITX_VFMT_21_720x576i_50Hz, E_REGVFMT_720x576i_50Hz}, + {HDMITX_VFMT_22_720x576i_50Hz, E_REGVFMT_720x576i_50Hz}, + {HDMITX_VFMT_23_720x288p_50Hz, E_REGVFMT_720x288p_50Hz}, + {HDMITX_VFMT_24_720x288p_50Hz, E_REGVFMT_720x288p_50Hz}, + {HDMITX_VFMT_31_1920x1080p_50Hz,E_REGVFMT_1920x1080p_50Hz}, + {HDMITX_VFMT_32_1920x1080p_24Hz,E_REGVFMT_1920x1080p_24Hz}, + {HDMITX_VFMT_33_1920x1080p_25Hz,E_REGVFMT_1920x1080p_25Hz}, + {HDMITX_VFMT_34_1920x1080p_30Hz,E_REGVFMT_1920x1080p_30Hz}, + {HDMITX_VFMT_35_2880x480p_60Hz, E_REGVFMT_720x480p_60Hz}, + {HDMITX_VFMT_36_2880x480p_60Hz, E_REGVFMT_720x480p_60Hz}, + {HDMITX_VFMT_37_2880x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_38_2880x576p_50Hz, E_REGVFMT_720x576p_50Hz}, + {HDMITX_VFMT_60_1280x720p_24Hz, E_REGVFMT_1280x720p_24Hz}, + {HDMITX_VFMT_61_1280x720p_25Hz, E_REGVFMT_1280x720p_25Hz}, + {HDMITX_VFMT_62_1280x720p_30Hz, E_REGVFMT_1280x720p_30Hz} +}; +static CONST_DAT struct vic2reg vic2reg_TV_FP[] = { + {HDMITX_VFMT_04_1280x720p_60Hz, E_REGVFMT_1280x720p_60Hz_FP}, + {HDMITX_VFMT_05_1920x1080i_60Hz,E_REGVFMT_1920x1080i_60Hz_FP}, + {HDMITX_VFMT_19_1280x720p_50Hz, E_REGVFMT_1280x720p_50Hz_FP}, + {HDMITX_VFMT_20_1920x1080i_50Hz,E_REGVFMT_1920x1080i_50Hz_FP}, + {HDMITX_VFMT_32_1920x1080p_24Hz,E_REGVFMT_1920x1080p_24Hz_FP}, + {HDMITX_VFMT_33_1920x1080p_25Hz,E_REGVFMT_1920x1080p_25Hz_FP}, + {HDMITX_VFMT_34_1920x1080p_30Hz,E_REGVFMT_1920x1080p_30Hz_FP}, + {HDMITX_VFMT_60_1280x720p_24Hz, E_REGVFMT_1280x720p_24Hz_FP}, + {HDMITX_VFMT_61_1280x720p_25Hz, E_REGVFMT_1280x720p_25Hz_FP}, + {HDMITX_VFMT_62_1280x720p_30Hz, E_REGVFMT_1280x720p_30Hz_FP} +}; +#endif + +#ifdef FORMAT_PC +static CONST_DAT struct vic2reg vic2reg_PC[HDMITX_VFMT_PC_NUM] = { + {HDMITX_VFMT_PC_640x480p_60Hz, E_REGVFMT_640x480p_60Hz}, + {HDMITX_VFMT_PC_800x600p_60Hz, E_REGVFMT_800x600p_60Hz}, + {HDMITX_VFMT_PC_1024x768p_60Hz, E_REGVFMT_1024x768p_60Hz}, + {HDMITX_VFMT_PC_1280x768p_60Hz, E_REGVFMT_1280x768p_60Hz}, + {HDMITX_VFMT_PC_1280x1024p_60Hz,E_REGVFMT_1280x1024p_60Hz}, + {HDMITX_VFMT_PC_1360x768p_60Hz, E_REGVFMT_1360x768p_60Hz}, + {HDMITX_VFMT_PC_1400x1050p_60Hz,E_REGVFMT_1400x1050p_60Hz}, + {HDMITX_VFMT_PC_1600x1200p_60Hz,E_REGVFMT_1600x1200p_60Hz}, + {HDMITX_VFMT_PC_1024x768p_70Hz, E_REGVFMT_1024x768p_70Hz}, + {HDMITX_VFMT_PC_640x480p_72Hz, E_REGVFMT_640x480p_72Hz}, + {HDMITX_VFMT_PC_800x600p_72Hz, E_REGVFMT_800x600p_72Hz}, + {HDMITX_VFMT_PC_640x480p_75Hz, E_REGVFMT_640x480p_75Hz}, + {HDMITX_VFMT_PC_1024x768p_75Hz, E_REGVFMT_1024x768p_75Hz}, + {HDMITX_VFMT_PC_800x600p_75Hz, E_REGVFMT_800x600p_75Hz}, + {HDMITX_VFMT_PC_640x480p_85Hz, E_REGVFMT_640x480p_85Hz}, + {HDMITX_VFMT_PC_800x600p_85Hz, E_REGVFMT_800x600p_85Hz}, + {HDMITX_VFMT_PC_1280x1024p_85Hz,E_REGVFMT_1280x1024p_85Hz} +}; +#endif /* FORMAT PC */ + + +/** + * Lookup table to convert from video format codes used in the + * E_REG_P00_VIDFORMAT_W register to corresponding VS_PIX_STRT_2 + * register values, to correct the output window for interlaced + * output formats, with or without the scaler. + * + * The correction is VS_PIX_STRT_2=VS_PIX_STRT_2+VS_PIX_STRT_1. + * The same value is also applied to VS_PIX_END_2. + */ + +/** + * Lookup table to convert from video format codes used in the + * E_REG_P00_VIDFORMAT_W register to corresponding + * pixel repetition values in the PLL_SERIAL_2 register. + * 0=no repetition (pixel sent once) + * 1=one repetition (pixel sent twice) etc + */ + +/** + * Lookup table to convert from video format codes used in the + * E_REG_P00_VIDFORMAT_W register to corresponding + * trios of 2-bit values in the srl_nosc, scg_nosc and de_nosc + * PLL control registers + * + * Rational for dummies by André ;) + * ----------------------------- + * the TMDS serializer multiply x10 the pixclk (this is a PLL;) + * --> --> -->
+ * 576i or 480i 13.5 Mhz (*2) 270 Mhz 4 + * 576p 27 Mhz 270 Mhz 4 + * 720p or 1080i 74.25 Mhz 742 Mhz 2 + * 1080p 148.5 Mhz 1485 Mhz 1 + * + */ + +static CONST_DAT UInt8 pll[] = { + /* prefetch */ + 2, /* E_REGVFMT_640x480p_60Hz */ + 2, /* E_REGVFMT_720x480p_60Hz */ + 1, /* E_REGVFMT_1280x720p_60Hz */ + 1, /* E_REGVFMT_1920x1080i_60Hz */ + 3, /* E_REGVFMT_720x480i_60Hz */ + 0, /* E_REGVFMT_720x240p_60Hz */ /** \todo Need nosc PLL value */ + 0, /* E_REGVFMT_1920x1080p_60Hz */ + 2, /* E_REGVFMT_720x576p_50Hz */ + 1, /* E_REGVFMT_1280x720p_50Hz */ + 1, /* E_REGVFMT_1920x1080i_50Hz */ + 3, /* E_REGVFMT_720x576i_50Hz */ + 0, /* E_REGVFMT_720x288p_50Hz */ /** \todo Need nosc PLL value */ + 0, /* E_REGVFMT_1920x1080p_50Hz */ +#ifdef TMFL_RGB_DDR_12BITS + 0, /* E_REGVFMT_1920x1080p_24Hz */ + 1, /* E_REGVFMT_1440x576p_50Hz */ + 1, /* E_REGVFMT_1440x480p_50Hz */ + 0, /* E_REGVFMT_2880x480p_50Hz */ + 0, /* E_REGVFMT_2880x576p_50Hz */ + 1, /* E_REGVFMT_2880x480i_60Hz */ + 2, /* E_REGVFMT_2880x480i_60Hz_PR2*/ + 2, /* E_REGVFMT_2880x480i_60Hz_PR4*/ + 1, /* E_REGVFMT_2880x576i_50Hz */ + 2, /* E_REGVFMT_2880x576i_50Hz_PR2*/ + 1, /* E_REGVFMT_720x480p_60Hz_FP */ + 0, /* E_REGVFMT_1280x720p_60Hz_FP */ + 1, /* E_REGVFMT_720x576p_50Hz_FP */ + 0, /* E_REGVFMT_1280x720p_50Hz_FP */ + 0, /* E_REGVFMT_1920x1080p_23Hz_FP*/ + 0, /* E_REGVFMT_1920x1080p_25Hz_FP*/ + 0, /* E_REGVFMT_1920x1080p_29Hz_FP*/ + 0, /* E_REGVFMT_1920x1080i_60Hz_FP*/ + 0, /* E_REGVFMT_1920x1080i_50Hz_FP*/ +#endif + /* extra list */ +#ifndef TMFL_RGB_DDR_12BITS + 1, /* E_REGVFMT_1920x1080p_24Hz */ +#endif + 1, /* E_REGVFMT_1920x1080p_25Hz */ + 1, /* E_REGVFMT_1920x1080p_30Hz */ + 1, /* E_REGVFMT_1280x720p_24Hz */ + 1, /* E_REGVFMT_1280x720p_25Hz */ + 1, /* E_REGVFMT_1280x720p_30Hz */ +#ifndef TMFL_RGB_DDR_12BITS + 0, /* E_REGVFMT_1280x720p_60Hz_FP */ + 0, /* E_REGVFMT_1920x1080i_60Hz_FP */ + 0, /* E_REGVFMT_1280x720p_50Hz_FP */ + 0, /* E_REGVFMT_1920x1080i_50Hz_FP */ + 0, /* E_REGVFMT_1920x1080p_24Hz_FP */ + 0, /* E_REGVFMT_1920x1080p_25Hz_FP */ + 0, /* E_REGVFMT_1920x1080p_30Hz_FP */ +#endif + 0, /* E_REGVFMT_1280x720p_24Hz_FP */ + 0, /* E_REGVFMT_1280x720p_25Hz_FP */ + 0, /* E_REGVFMT_1280x720p_30Hz_FP */ +#ifdef FORMAT_PC + 2, /* E_REGVFMT_640x480p_72Hz */ + 2, /* E_REGVFMT_640x480p_75Hz */ + 2, /* E_REGVFMT_640x480p_85Hz */ + 1, /* E_REGVFMT_800x600p_60Hz */ + 1, /* E_REGVFMT_800x600p_72Hz */ + 1, /* E_REGVFMT_800x600p_75Hz */ + 1, /* E_REGVFMT_800x600p_85Hz */ + 1, /* E_REGVFMT_1024x768p_60Hz */ + 1, /* E_REGVFMT_1024x768p_70Hz */ + 1, /* E_REGVFMT_1024x768p_75Hz */ + 0, /* E_REGVFMT_1280x768p_60Hz */ + 0, /* E_REGVFMT_1280x1024p_60Hz */ + 0, /* E_REGVFMT_1360x768p_60Hz */ + 0, /* E_REGVFMT_1400x1050p_60Hz */ + 0, /* E_REGVFMT_1600x1200p_60Hz */ + 1 /* E_REGVFMT_1280x1024p_85Hz */ +#endif /* FORMAT_PC */ +}; + + + +/** + * Lokup table to convert from video format codes used in the + * E_REG_P00_VIDFORMAT_W register to RefPix and RefLine values + * according to sync source + */ +/* prefetch list */ +static CONST_DAT struct sync_desc ref_sync[] = +{ + /* + designer world <==> CEA-861 reader world + ---------------------------------------- + t_hs_s : hfp+1 + t_vsl_s1 : vfp+1 + t_de_s : href+1 + t_vw_s1 : vref+1 + + For the story, designer have defined VsPixRef and VsLineRef concept + that are the position of VSync in pixel and line starting from the top + of the frame. + So we have in fact : VSync that is hfp + vfp*total_h_active away from top + + */ + /* Vs2 PR Vtg Htg HFP VFP HREF VREF */ + {0, 0, 1, 1, 17, 2, 161, 36}, /* E_REGVFMT_640x480p_60Hz */ + {0, 0, 1, 1, 17, 8, 139, 43}, /* E_REGVFMT_720x480p_60Hz */ + {0, 0, 0, 0, 111, 2, 371, 26}, /* E_REGVFMT_1280x720p_60Hz */ + {1100+88, 0, 0, 0, 89, 2, 281, 21}, /* E_REGVFMT_1920x1080i_60Hz */ + {429+19, 1, 1, 1, 20, 5, 139, 22}, /* E_REGVFMT_720x480i_60Hz */ + {0, 1, 1, 1, 20, 5, 139, 22}, /* E_REGVFMT_720x240p_60Hz */ + {0, 0, 0, 0, 89, 2, 281, 42}, /* E_REGVFMT_1920x1080p_60Hz */ + {0, 0, 1, 1, 13, 2, 145, 45}, /* E_REGVFMT_720x576p_50Hz */ + {0, 0, 0, 0, 441, 2, 701, 26}, /* E_REGVFMT_1280x720p_50Hz */ + {1320+528,0, 0, 0, 529, 2, 721, 21}, /* E_REGVFMT_1920x1080i_50Hz */ + {432+12, 1, 1, 1, 13, 2, 145, 23}, /* E_REGVFMT_720x576i_50Hz */ + {0, 1, 1, 1, 13, 2, 145, 23}, /* E_REGVFMT_720x288p_50Hz */ + {0, 0, 0, 0, 529, 2, 721, 42}, /* E_REGVFMT_1920x1080p_50Hz */ +#ifdef TMFL_RGB_DDR_12BITS + {0, 0, 0, 0, 639, 2, 831, 42}, /* E_REGVFMT_1920x1080p_24Hz */ + {0, 0, 1, 1, 25, 2, 289, 45}, /* E_REGVFMT_1440x576p_50Hz */ + {0, 0, 1, 1, 33, 8, 277, 43}, /* E_REGVFMT_1440x480p_50Hz */ + {0, 0, 1, 1, 65, 8, 553, 43}, /* E_REGVFMT_2880x480p_50Hz */ + {0, 0, 1, 1, 49, 2, 577, 45}, /* E_REGVFMT_2880x576p_50Hz */ + {1716+76, 0, 1, 1, 77, 5, 553, 22}, /* E_REGVFMT_2880x480i_60Hz */ + {858+38, 1, 1, 1, 39, 5, 277, 22}, /* E_REGVFMT_2880x480i_60Hz_PR2*/ + {429+19, 2, 1, 1, 20, 5, 139, 22}, /* E_REGVFMT_2880x480i_60Hz_PR4*/ + {1728+48, 0, 1, 1, 49, 2, 577, 23}, /* E_REGVFMT_2880x576i_50Hz */ + {864+24, 1, 1, 1, 25, 2, 289, 23} /* E_REGVFMT_2880x576i_50Hz_PR*/ +#endif +}; + +/* extra list */ +static CONST_DAT struct sync_desc ref_sync_extra[] = +{ + /* Vs2 PR Vtg Htg HFP VFP HREF VREF */ +#ifndef TMFL_RGB_DDR_12BITS + {0, 0, 0, 0, 639, 2, 831, 42}, /* E_REGVFMT_1920x1080p_24Hz */ +#endif + {0, 0, 0, 0, 529, 2, 721, 42}, /* E_REGVFMT_1920x1080p_25Hz */ + {0, 0, 0, 0, 89, 2, 281, 42}, /* E_REGVFMT_1920x1080p_30Hz */ + {0, 0, 0, 0, 1761, 2, 2021,26}, /* E_REGVFMT_1280x720p_24Hz */ + {0, 0, 0, 0, 2421, 2, 2681,26}, /* E_REGVFMT_1280x720p_25Hz */ + {0, 0, 0, 0, 1761, 2, 2021,26} /* E_REGVFMT_1280x720p_30Hz */ +}; + +#ifdef FORMAT_PC + /* PC list */ +static CONST_DAT struct sync_desc ref_sync_PC[] = +{ + /* Vs2 PR Vtg Htg HFP VFP HREF VREF */ + {0, 0, 1, 1, 25, 2, 195, 32}, /* E_REGVFMT_640x480p_72Hz */ + {0, 0, 1, 1, 17, 2, 203, 20}, /* E_REGVFMT_640x480p_75Hz */ + {0, 0, 1, 1, 57, 2, 195, 29}, /* E_REGVFMT_640x480p_85Hz */ + {0, 0, 0, 0, 41, 2, 259, 28}, /* E_REGVFMT_800x600p_60Hz */ + {0, 0, 0, 0, 57, 2, 243, 30}, /* E_REGVFMT_800x600p_72Hz */ + {0, 0, 0, 0, 17, 2, 259, 25}, /* E_REGVFMT_800x600p_75Hz */ + {0, 0, 0, 0, 33, 2, 251, 31}, /* E_REGVFMT_800x600p_85Hz */ + {0, 0, 1, 1, 25, 2, 323, 36}, /* E_REGVFMT_1024x768p_60Hz */ + {0, 0, 1, 1, 25, 2, 307, 36}, /* E_REGVFMT_1024x768p_70Hz */ + {0, 0, 0, 0, 17, 2, 291, 32}, /* E_REGVFMT_1024x768p_75Hz */ + {0, 0, 0, 1, 65, 2, 387, 28}, /* E_REGVFMT_1280x768p_60Hz */ + {0, 0, 0, 0, 49, 2, 411, 42}, /* E_REGVFMT_1280x1024p_60Hz */ + {0, 0, 0, 0, 65, 2, 435, 25}, /* E_REGVFMT_1360x768p_60Hz */ + {0, 0, 0, 1, 89, 2, 467, 37}, /* E_REGVFMT_1400x1050p_60Hz */ + {0, 0, 0, 0, 65, 2, 563, 50}, /* E_REGVFMT_1600x1200p_60Hz */ + {0, 0, 0, 0, 65, 2, 451, 48} /* E_REGVFMT_1280x1024p_85Hz */ +}; +#endif/* FORMAT_PC */ + +static CONST_DAT tmHdmiTxVidReg_t format_param_extra[] = { + /* NPIX NLINE VsLineStart VsPixStart VsLineEnd VsPixEnd HsStart HsEnd ActiveVideoStart ActiveVideoEnd DeStart DeEnd */ + /* npix nline vsl_s1 vsp_s1 vsl_e1 vsp_e1 hs_e hs_e vw_s1 vw_e1 de_s de_e */ +#ifndef TMFL_RGB_DDR_12BITS + {2750, 1125, 1, 638, 6, 638, 638, 682, 41, 1121, 830, 2750, 0, 0},/* E_REGVFMT_1920x1080p_24Hz */ +#endif + {2640, 1125, 1, 528, 6, 528, 528, 572, 41, 1121, 720, 2640, 0, 0},/* E_REGVFMT_1920x1080p_25Hz */ + {2200, 1125, 1, 88, 6, 88, 88, 132, 41, 1121, 280, 2200, 0, 0},/* E_REGVFMT_1920x1080p_30Hz */ + {3300, 750, 1, 1760, 6, 1760, 1760, 1800, 25, 745, 2020, 3300, 0, 0},/* E_REGVFMT_1280x720p_24Hz */ + {3960, 750, 1, 2420, 6, 2420, 2420, 2460, 25, 745, 2680, 3960, 0, 0},/* E_REGVFMT_1280x720p_25Hz */ + {3300, 750, 1, 1760, 6, 1760, 1760, 1800, 25, 745, 2020, 3300, 0, 0},/* E_REGVFMT_1280x720p_30Hz */ +#ifndef TMFL_RGB_DDR_12BITS + {1650, 1500, 1, 110, 6, 110, 110, 150, 25, 1495, 370, 1650, 746, 776},/* E_REGVFMT_1280x720p_60Hz_FP */ + {2200, 2250, 1, 88, 6, 88, 88, 132, 20, 2248, 280, 2200, 0, 0},/* E_REGVFMT_1920x1080i_60Hz_FP */ + {1980, 1500, 1, 440, 6, 440, 440, 480, 25, 1495, 700, 1980, 746, 776},/* E_REGVFMT_1280x720p_50Hz_FP */ + {2640, 2250, 1, 528, 6, 528, 528, 572, 20, 2248, 720, 2640, 0, 0},/* E_REGVFMT_1920x1080i_50Hz_FP */ + {2750, 2250, 1, 638, 6, 638, 638, 682, 41, 2246, 830, 2750, 1122, 1167},/* E_REGVFMT_1920x1080p_24Hz_FP */ + {2640, 2250, 1, 528, 6, 528, 528, 572, 41, 2246, 720, 2640, 1122, 1167},/* E_REGVFMT_1920x1080p_25Hz_FP */ + {2200, 2250, 1, 88, 6, 88, 88, 132, 41, 2246, 280, 2200, 1122, 1167},/* E_REGVFMT_1920x1080p_30Hz_FP */ +#endif + {3300, 1500, 1, 1760, 6, 1760, 1760, 1800, 25, 1495, 2020, 3300, 0, 0},/* E_REGVFMT_1280x720p_24Hz_FP */ + {3960, 1500, 1, 2420, 6, 2420, 2420, 2460, 25, 1495, 2680, 3960, 0, 0},/* E_REGVFMT_1280x720p_25Hz_FP */ + {3300, 1500, 1, 1760, 6, 1760, 1760, 1800, 25, 1495, 2020, 3300, 0, 0},/* E_REGVFMT_1280x720p_30Hz_FP */ +}; + +#ifdef FORMAT_PC +static CONST_DAT tmHdmiTxVidReg_t format_param_PC[HDMITX_VFMT_PC_NUM] = +{ + /* NPIX NLINE VsLineStart VsPixStart VsLineEnd VsPixEnd HsStart HsEnd ActiveVideoStart ActiveVideoEnd DeStart DeEnd */ + /* npix nline vsl_s1 vsp_s1 vsl_e1 vsp_e1 hs_e hs_e vw_s1 vw_e1 de_s de_e */ + {832, 520, 1, 24, 4, 24, 24, 64, 31, 511, 192, 832, 0, 0},/* E_REGVFMT_640x480p_72Hz */ + {840, 500, 1, 16, 4, 16, 16, 80, 19, 499, 200, 840, 0, 0},/* E_REGVFMT_640x480p_75Hz */ + {832, 509, 1, 56, 4, 56, 56, 112, 28, 508, 192, 832, 0, 0},/* E_REGVFMT_640x480p_85Hz */ + {1056, 628, 1, 40, 5, 40, 40, 168, 27, 627, 256, 1056, 0, 0},/* E_REGVFMT_800x600p_60Hz */ + {1040, 666, 1, 56, 7, 56, 56, 176, 29, 619, 240, 1040, 0, 0},/* E_REGVFMT_800x600p_72Hz */ + {1056, 625, 1, 16, 4, 16, 16, 96, 24, 624, 256, 1056, 0, 0},/* E_REGVFMT_800x600p_75Hz */ + {1048, 631, 1, 32, 4, 32, 32, 96, 30, 630, 248, 1048, 0, 0},/* E_REGVFMT_800x600p_85Hz */ + {1344, 806, 1, 24, 7, 24, 24, 160, 35, 803, 320, 1344, 0, 0},/* E_REGVFMT_1024x768p_60Hz */ + {1328, 806, 1, 24, 7, 24, 24, 160, 35, 803, 304, 1328, 0, 0},/* E_REGVFMT_1024x768p_70Hz */ + {1312, 800, 1, 16, 4, 16, 16, 112, 31, 799, 288, 1312, 0, 0},/* E_REGVFMT_1024x768p_75Hz */ + {1664, 798, 1, 64, 8, 64, 64, 192, 27, 795, 384, 1664, 0, 0},/* E_REGVFMT_1280x768p_60Hz */ + {1688, 1066, 1, 48, 4, 48, 48, 160, 41, 1065, 408, 1688, 0, 0},/* E_REGVFMT_1280x1024p_60Hz */ + {1792, 795, 1, 64, 7, 64, 64, 176, 24, 792, 432, 1792, 0, 0},/* E_REGVFMT_1360x768p_60Hz */ + {1864, 1089, 1, 88, 5, 88, 88, 232, 36, 1086, 464, 1864, 0, 0},/* E_REGVFMT_1400x1050p_60Hz */ + {2160, 1250, 1, 64, 4, 64, 64, 256, 49, 1249, 560, 2160, 0, 0},/* E_REGVFMT_1600x1200p_60Hz */ + {1728, 1072, 1, 64, 4, 64, 64, 224, 47, 1071, 448, 1728, 0, 0} /* E_REGVFMT_1280x1024p_85Hz */ +}; +#endif/* FORMAT_PC */ + + /** + * Lookup table for each pixel clock frequency's CTS value in kHz + * according to SCS table "Audio Clock Recovery CTS Values" + */ +static CONST_DAT UInt32 kPixClkToAcrCts[E_PIXCLK_NUM][HDMITX_AFS_NUM] = +{ + /* HDMITX_AFS_32k _AFS_48K _AFS_96K _AFS_192K */ + /* _AFS_44_1k _AFS_88_2K _AFS_176_4K */ + { 28125, 31250, 28125, 31250, 28125, 31250, 28125}, /* E_PIXCLK_25175 */ + { 25200, 28000, 25200, 28000, 25200, 28000, 25200}, /* E_PIXCLK_25200 */ + { 27000, 30000, 27000, 30000, 27000, 30000, 27000}, /* E_PIXCLK_27000 */ + { 27027, 30030, 27027, 30030, 27027, 30030, 27027}, /* E_PIXCLK_27027 */ + { 54000, 60000, 54000, 60000, 54000, 60000, 54000}, /* E_PIXCLK_54000 */ + { 54054, 60060, 54054, 60060, 54054, 60060, 54054}, /* E_PIXCLK_54054 */ + { 59400, 65996, 59400, 65996, 59400, 65996, 59400}, /* E_PIXCLK_59400 */ + {210937, 234375, 140625, 234375, 140625, 234375, 140625}, /* E_PIXCLK_74175 */ + { 74250, 82500, 74250, 82500, 74250, 82500, 74250}, /* E_PIXCLK_74250 */ + {421875, 234375, 140625, 234375, 140625, 234375, 140625}, /* E_PIXCLK_148350*/ + {148500, 165000, 148500, 165000, 148500, 165000, 148500} /* E_PIXCLK_148500*/ +#ifdef FORMAT_PC + ,{ 31500, 35000, 31500, 35000, 31500, 35000, 31500}, /* E_PIXCLK_31500 */ + { 36000, 40000, 36000, 40000, 36000, 40000, 36000}, /* E_PIXCLK_36000 */ + { 40000, 44444, 40000, 44444, 40000, 44444, 40000}, /* E_PIXCLK_40000 */ + { 49500, 55000, 49500, 55000, 49500, 55000, 49500}, /* E_PIXCLK_49500 */ + { 50000, 55556, 50000, 55556, 50000, 55556, 50000}, /* E_PIXCLK_50000 */ + { 56250, 62500, 56250, 62500, 56250, 62500, 56250}, /* E_PIXCLK_56250 */ + { 65000, 72222, 65000, 72222, 65000, 72222, 65000}, /* E_PIXCLK_65000 */ + { 75000, 83333, 75000, 83333, 75000, 83333, 75000}, /* E_PIXCLK_75000 */ + { 78750, 87500, 78750, 87500, 78750, 87500, 78750}, /* E_PIXCLK_78750 */ + {162000, 180000, 162000, 180000, 162000, 180000, 162000}, /* E_PIXCLK_162000*/ + {157500, 175000, 157500, 175000, 157500, 175000, 157500} /* E_PIXCLK_157500 */ +#endif /* FORMAT_PC */ +}; + +/** + * Lookup table for each pixel clock frequency's Audio Clock Regeneration N, + * according to SCS Table "Audio Clock Recovery N Values" + */ +static CONST_DAT UInt32 kPixClkToAcrN[E_PIXCLK_NUM][HDMITX_AFS_NUM] = +{ + /* HDMITX_AFS_32k _AFS_48K _AFS_96K _AFS_192K */ + /* _AFS_44_1k _AFS_88_2K _AFS_176_4K */ + { 4576, 7007, 6864, 14014, 13728, 28028, 27456}, /* E_PIXCLK_25175 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_25200 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_27000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_27027 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_54000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_54054 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_59400 */ + {11648, 17836, 11648, 35672, 23296, 71344, 46592}, /* E_PIXCLK_74175 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_74250 */ + {11648, 8918, 5824, 17836, 11648, 35672, 23296}, /* E_PIXCLK_148350*/ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576} /* E_PIXCLK_148500*/ +#ifdef FORMAT_PC + ,{ 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_31500 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_36000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_40000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_49500 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_50000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_56250 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_65000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_75000 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_78750 */ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576}, /* E_PIXCLK_162000*/ + { 4096, 6272, 6144, 12544, 12288, 25088, 24576} /* E_PIXCLK_157500*/ +#endif /* FORMAT_PC */ +}; + +/** + * Lookup table for each pixel clock frequency's Audio Divider, according to + * SCS Table "Audio Clock Recovery Divider Values" + */ +static CONST_DAT UInt8 kPixClkToAdiv[E_PIXCLK_NUM][HDMITX_AFS_NUM] = +{ + /* HDMITX_AFS_32k _AFS_48K _AFS_96K _AFS_192K */ + /* _AFS_44_1k _AFS_88_2K _AFS_176_4K */ + {2, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_25175 */ + {2, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_25200 */ + {2, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_27000 */ + {2, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_27027 */ + {3, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_54000 */ + {3, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_54054 */ + {3, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_59400 */ + {4, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_74175 */ + {4, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_74250 */ + {5, 4, 4, 3, 3, 2, 2}, /* E_PIXCLK_148350 */ + {5, 4, 4, 3, 3, 2, 2} /* E_PIXCLK_148500 */ +#ifdef FORMAT_PC + ,{2, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_31500 */ + {3, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_36000 */ + {3, 2, 2, 1, 1, 0, 0}, /* E_PIXCLK_40000 */ + {3, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_49500 */ + {3, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_50000 */ + {3, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_56250 */ + {4, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_65000 */ + {4, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_75000 */ + {4, 3, 3, 2, 2, 1, 1}, /* E_PIXCLK_78750 */ + {5, 4, 4, 3, 3, 2, 2}, /* E_PIXCLK_162000 */ + {5, 4, 4, 3, 3, 2, 2} /* E_PIXCLK_157500 */ +#endif /* FORMAT_PC */ + +}; + +/** + * Lookup table for converting a sampling frequency into the values + * required in channel status byte 3 according to IEC60958-3 + */ +static CONST_DAT UInt8 kAfsToCSbyte3[HDMITX_AFS_NUM+1] = +{ + 3, /* HDMITX_AFS_32k */ + 0, /* HDMITX_AFS_44_1k */ + 2, /* HDMITX_AFS_48k */ + 8, /* HDMITX_AFS_88_2k */ + 10, /* HDMITX_AFS_96k */ + 12, /* HDMITX_AFS_176_4k */ + 14, /* HDMITX_AFS_192k */ + 9, /* HDMITX_AFS_768k */ + 1, /* HDMITX_AFS_NOT_INDICATED */ +}; + + + +/** + * Lookup table for each CTS X factor's k and m register values + */ +static CONST_DAT UInt8 kCtsXToMK[HDMITX_CTSX_NUM][2] = +{ +/* Register values Actual values */ +/* m k m, k */ + {3, 0}, /* 8, 1 */ + {3, 1}, /* 8, 2 */ + {3, 2}, /* 8, 3 */ + {3, 3}, /* 8, 4 */ + {0, 0} /* 1, 1 */ +}; + +/** + * Table of registers to reset and release the CTS generator + */ +static CONST_DAT tmHdmiTxRegMaskVal_t kResetCtsGenerator[] = +{ + {E_REG_P11_AIP_CNTRL_0_RW, E_MASKREG_P11_AIP_CNTRL_0_rst_cts, 1}, + {E_REG_P11_AIP_CNTRL_0_RW, E_MASKREG_P11_AIP_CNTRL_0_rst_cts, 0}, + {0,0,0} +}; + +/** + * Table of registers to bypass colour processing (up/down sampler & matrix) + */ +static CONST_DAT tmHdmiTxRegMaskVal_t kBypassColourProc[] = +{ + /* Bypass upsampler for RGB colourbars */ + {E_REG_P00_HVF_CNTRL_0_W, E_MASKREG_P00_HVF_CNTRL_0_intpol, 0}, + /* Bypass matrix for RGB colourbars */ + {E_REG_P00_MAT_CONTRL_W, E_MASKREG_P00_MAT_CONTRL_mat_bp, 1}, + /* Bypass downsampler for RGB colourbars */ + {E_REG_P00_HVF_CNTRL_1_W, E_MASKREG_P00_HVF_CNTRL_1_for, 0}, + {0,0,0} +}; + +/** + * Table of registers to configure video input mode CCIR656*/ +static CONST_DAT tmHdmiTxRegMaskVal_t kVinModeCCIR656[] = +{ + {E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_ccir656, 1}, + {E_REG_P00_HVF_CNTRL_1_W, E_MASKREG_P00_HVF_CNTRL_1_semi_planar, 1}, + /*{E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_clk1, 1},*/ + {E_REG_P02_PLL_SERIAL_3_RW, E_MASKREG_P02_PLL_SERIAL_3_srl_ccir, 1}, + {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_vrf_clk, 1}, + {0,0,0} +}; + + /* Table of registers to configure video input mode for CCIR656 DDR with 1280*720p and 1920*1080i formats*/ +static CONST_DAT tmHdmiTxRegMaskVal_t kVinModeCCIR656_DDR_above720p[] = +{ + {E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_ccir656, 1}, + {E_REG_P00_HVF_CNTRL_1_W, E_MASKREG_P00_HVF_CNTRL_1_semi_planar, 1},/*To be defined*/ + /*{E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_clk1, 0},To be defined*/ + {E_REG_P02_PLL_SERIAL_3_RW, E_MASKREG_P02_PLL_SERIAL_3_srl_ccir, 0}, + {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_vrf_clk, 0}, + {0,0,0} +}; +/** + * Table of registers to configure video input mode RGB444 or YUV444 + */ +static CONST_DAT tmHdmiTxRegMaskVal_t kVinMode444[] = +{ + {E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_ccir656, 0}, + {E_REG_P00_HVF_CNTRL_1_W, E_MASKREG_P00_HVF_CNTRL_1_semi_planar, 0}, + /* {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_clk1, 0},*/ + {E_REG_P02_PLL_SERIAL_3_RW, E_MASKREG_P02_PLL_SERIAL_3_srl_ccir, 0}, + {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_vrf_clk, 0}, + {0,0,0} +}; + +/** + * Table of registers to configure video input mode YUV422 + */ +static CONST_DAT tmHdmiTxRegMaskVal_t kVinModeYUV422[] = +{ + {E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_ccir656, 0}, + {E_REG_P00_HVF_CNTRL_1_W, E_MASKREG_P00_HVF_CNTRL_1_semi_planar, 1}, + /*{E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_clk1, 0},*/ + {E_REG_P02_PLL_SERIAL_3_RW, E_MASKREG_P02_PLL_SERIAL_3_srl_ccir, 0}, + {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_sel_vrf_clk, 0}, + {0,0,0} +}; + + +/** + * Lookup table for colour space conversion matrix register sets. + * Each array consists of 31 register values from MAT_CONTROL through + * to MAT_OO3_LSB + */ +static CONST_DAT UInt8 kMatrixPreset[MATRIX_PRESET_QTY][MATRIX_PRESET_SIZE] = +{ + {0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x6F, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x3, 0x6F, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, + 0x6F, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40 + }, /* RGB Full to RGB Limited */ + + {0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x4, 0x1, 0x7, 0x0, + 0x64, 0x6, 0x88, 0x1, 0xC2, 0x7, 0xB7, 0x6, 0xD6, 0x7, 0x68, 0x1, + 0xC2, 0x0, 0x40, 0x2, 0x0, 0x2, 0x0 + }, /* RGB Full to BT601 */ + + {0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x75, 0x0, 0xBB, 0x0, + 0x3F, 0x6, 0x68, 0x1, 0xC2, 0x7, 0xD7, 0x6, 0xA6, 0x7, 0x99, 0x1, + 0xC2, 0x0, 0x40, 0x2, 0x0, 0x2, 0x0 + }, /* RGB Full to BT709 */ + + {0x1, 0x7, 0xC0, 0x7, 0xC0, 0x7, 0xC0, 0x2, 0x54, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, + 0x54, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, /* RGB Limited to RGB Full */ + + {0x2, 0x7, 0xC0, 0x7, 0xC0, 0x7, 0xC0, 0x2, 0x59, 0x1, 0x32, 0x0, + 0x75, 0x6, 0x4A, 0x2, 0x0C, 0x7, 0xAB, 0x6, 0xA5, 0x7, 0x4F, 0x2, + 0x0C, 0x0, 0x40, 0x2, 0x0, 0x2, 0x0 + }, /* RGB Limited to BT601 */ + + {0x2, 0x7, 0xC0, 0x7, 0xC0, 0x7, 0xC0, 0x2, 0xDC, 0x0, 0xDA, 0x0, + 0x4A, 0x6, 0x24, 0x2, 0x0C, 0x7, 0xD0, 0x6, 0x6C, 0x7, 0x88, 0x2, + 0x0C, 0x0, 0x40, 0x2, 0x0, 0x2, 0x0 + }, /* RGB Limited to BT709 */ + + {0x0, 0x7, 0xC0, 0x6, 0x0, 0x6, 0x0, 0x1, 0x2A, 0x7, 0x30, 0x7, + 0x9C, 0x1, 0x2A, 0x1, 0x99, 0x0, 0x0, 0x1, 0x2A, 0x0, 0x0, 0x2, + 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, /* BT601 to RGB Full */ + + {0x1, 0x7, 0xC0, 0x6, 0x0, 0x6, 0x0, 0x2, 0x0, 0x6, 0x9A, 0x7, + 0x54, 0x2, 0x0, 0x2, 0xBE, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, + 0x77, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40 + }, /* BT601 to RGB Limited */ + + {0x1, 0x7, 0xC0, 0x6, 0x0, 0x6, 0x0, 0x2, 0x0, 0x7, 0x96, 0x7, + 0xC5, 0x0, 0x0, 0x2, 0x0D, 0x0, 0x26, 0x0, 0x0, 0x0, 0x3B, 0x2, + 0x0A, 0x0, 0x40, 0x2, 0x0, 0x2, 0x0 + }, /* BT601 to BT709 */ + + {0x0, 0x7, 0xC0, 0x6, 0x0, 0x6, 0x0, 0x1, 0x2A, 0x7, 0x77, 0x7, + 0xC9, 0x1, 0x2A, 0x1, 0xCB, 0x0, 0x0, 0x1, 0x2A, 0x0, 0x0, 0x2, + 0x1D, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, /* BT709 to RGB Full */ + + {0x1, 0x7, 0xC0, 0x6, 0x0, 0x6, 0x0, 0x2, 0x0, 0x7, 0x16, 0x7, + 0xA2, 0x2, 0x0, 0x3, 0x14, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, + 0xA1, 0x0, 0x40, 0x0, 0x40, 0x0, 0x40 + }, /* BT709 to RGB Limited */ + + {0x1, 0x7, 0xC0, 0x6, 0x0, 0x6, 0x0, 0x2, 0x0, 0x0, 0x62, 0x0, + 0x33, 0x0, 0x0, 0x1, 0xF7, 0x7, 0xDB, 0x0, 0x0, 0x7, 0xC7, 0x1, + 0xFB, 0x0, 0x40, 0x2, 0x0, 0x2, 0x0 + } /* BT709 to BT601 */ +}; + +/** + * This table gives us the index into the kMatrixPreset array, based + * on the input and output colourspaces. + * The co-ordinates into this array are tmbslTDA9989Colourspace_t enums. + * The value of -1 is returned for matching input/output colourspaces. + */ +static CONST_DAT Int kMatrixIndex[HDMITX_CS_NUM][HDMITX_CS_NUM] = +{ + {-1, E_MATRIX_RGBF_2_RGBL, E_MATRIX_RGBF_2_BT601, E_MATRIX_RGBF_2_BT709}, + {E_MATRIX_RGBL_2_RGBF, -1, E_MATRIX_RGBL_2_BT601, E_MATRIX_RGBL_2_BT709}, + {E_MATRIX_BT601_2_RGBF, E_MATRIX_BT601_2_RGBL, -1, E_MATRIX_BT601_2_BT709}, + {E_MATRIX_BT709_2_RGBF, E_MATRIX_BT709_2_RGBL, E_MATRIX_BT709_2_BT601, -1} +}; + +/** + * Blue filter Lookup table for colour space conversion. + * Each array consists of 31 register values from MAT_CONTROL through + * to MAT_OO3_LSB + */ +static CONST_DAT UInt8 MatrixCoeffBlueScreen[][MATRIX_PRESET_SIZE] = +{ + {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0 + }, /* blue screen for RGB output color space */ + + {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x0 + }, /* blue screen for YCbCr422 output color space */ + + {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1, 0x0, 0x3, 0x0 + }, /* blue screen for YCbCr444 output color space */ +}; + +/** + * Black filter Lookup table for colour space conversion. + * Each array consists of 31 register values from MAT_CONTROL through + * to MAT_OO3_LSB + */ +static CONST_DAT UInt8 MatrixCoeffBlackScreen[][MATRIX_PRESET_SIZE] = +{ + {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 + }, /* black screen for RGB output color space */ + + {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0 + }, /* black screen for YCbCr422 output color space */ + + {0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x2, 0x0, 0x2, 0x0 + }, /* black screen for YCbCr444 output color space */ +}; + + +/*============================================================================*/ +/* DEFINES DECLARATIONS */ +/*============================================================================*/ +#define HDMITX_LAT_SCO_MAX_VAL 40 +#define HDMITX_LAT_SCO_MIN_VAL 34 + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + +/* Register values per device to restore colour processing after test pattern */ +static RAM_DAT UInt8 gMatContrl[HDMITX_UNITS_MAX]; +static RAM_DAT UInt8 gHvfCntrl0[HDMITX_UNITS_MAX]; +static RAM_DAT UInt8 gHvfCntrl1[HDMITX_UNITS_MAX]; + +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + +static tmErrorCode_t setDeVs(tmHdmiTxobject_t *pDis, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTx3DStructure_t structure3D); +static tmErrorCode_t setPixelRepeat(tmHdmiTxobject_t *pDis, + tmbslHdmiTxVidFmt_t voutFmt, + UInt8 uPixelRepeat, + tmbslHdmiTx3DStructure_t structure3D); +static tmErrorCode_t setSampling(tmHdmiTxobject_t *pDis); +static UInt8 calculateChecksum(UInt8 *pData, Int numBytes); +static UInt8 reg_vid_fmt(tmbslHdmiTxVidFmt_t fmt, \ + tmbslHdmiTx3DStructure_t structure3D, \ + UInt8 *idx, \ + UInt8 *idx3d, \ + struct sync_desc **sync); +UInt8 pix_clk(tmbslHdmiTxVidFmt_t fmt, tmbslHdmiTxVfreq_t freq, UInt8 *pclk); +static tmErrorCode_t InputConfig(tmHdmiTxobject_t *pDis, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTxPixEdge_t sampleEdge, + tmbslHdmiTxPixRate_t pixRate, + tmbslHdmiTxUpsampleMode_t upsampleMode, + UInt8 uPixelRepeat, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTx3DStructure_t structure3D); +/*============================================================================*/ +/* tmbslTDA9989AudioInResetCts */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989AudioInResetCts +( + tmUnitSelect_t txUnit +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if sink is not an HDMI device */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Reset and release the CTS generator */ + err = setHwRegisterFieldTable(pDis, &kResetCtsGenerator[0]); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989AudioInSetConfig */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989AudioInSetConfig +( + tmUnitSelect_t txUnit, + tmbslHdmiTxaFmt_t aFmt, + tmbslHdmiTxI2sFor_t i2sFormat, + UInt8 chanI2s, + UInt8 chanDsd, + tmbslHdmiTxClkPolDsd_t clkPolDsd, + tmbslHdmiTxSwapDsd_t swapDsd, + UInt8 layout, + UInt16 uLatency_rd, + tmbslHdmiTxDstRate_t dstRate +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; /* Value to write in register */ + + DUMMY_ACCESS(dstRate); + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if sink is not an HDMI device */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameters */ +#ifdef TMFL_HBR_SUPPORT + RETIF_BADPARAM((aFmt != HDMITX_AFMT_SPDIF) && + (aFmt != HDMITX_AFMT_I2S) && + (aFmt != HDMITX_AFMT_OBA) && + (aFmt != HDMITX_AFMT_HBR)) + +#else /* TMFL_HBR_SUPPORT */ + RETIF_BADPARAM((aFmt != HDMITX_AFMT_SPDIF) && + (aFmt != HDMITX_AFMT_I2S) && + (aFmt != HDMITX_AFMT_OBA)) + + +#endif /* TMFL_HBR_SUPPORT */ + + RETIF_BADPARAM(chanI2s >= HDMITX_CHAN_INVALID) + RETIF_BADPARAM(chanDsd >= HDMITX_CHAN_INVALID) + RETIF_BADPARAM(clkPolDsd >= HDMITX_CLKPOLDSD_INVALID) + RETIF_BADPARAM(swapDsd >= HDMITX_SWAPDSD_INVALID) + RETIF_BADPARAM(layout >= HDMITX_LAYOUT_INVALID) + RETIF_BADPARAM(uLatency_rd >= HDMITX_LATENCY_INVALID) + + if ((aFmt == HDMITX_AFMT_I2S) +#ifdef TMFL_HBR_SUPPORT + || (aFmt == HDMITX_AFMT_HBR) +#endif /* TMFL_HBR_SUPPORT */ + ) + { + RETIF_BADPARAM((i2sFormat != HDMITX_I2SFOR_PHILIPS_L) && + (i2sFormat != HDMITX_I2SFOR_OTH_L) && + (i2sFormat != HDMITX_I2SFOR_OTH_R) + ) + } + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + /* + power management : + freeze/wakeup SPDIF clock + */ + err = setHwRegisterField(pDis, E_REG_FEAT_POWER_DOWN, \ + E_MASKREG_FEAT_POWER_DOWN_spdif, \ + (aFmt != HDMITX_AFMT_SPDIF)); + RETIF_REG_FAIL(err); +#endif + + switch (aFmt) + { + case HDMITX_AFMT_SPDIF: + regVal = (UInt8)REG_VAL_SEL_AIP_SPDIF; + /* configure MUX_AP */ + err = setHwRegister(pDis, E_REG_P00_MUX_AP_RW, TDA19989_MUX_AP_SELECT_SPDIF); + RETIF_REG_FAIL(err) + break; + + case HDMITX_AFMT_I2S: + regVal = (UInt8)REG_VAL_SEL_AIP_I2S; + /* configure MUX_AP */ + err = setHwRegister(pDis, E_REG_P00_MUX_AP_RW, TDA19989_MUX_AP_SELECT_I2S); + RETIF_REG_FAIL(err) + break; + + case HDMITX_AFMT_OBA: + regVal = (UInt8)REG_VAL_SEL_AIP_OBA; + break; + + case HDMITX_AFMT_HBR: + regVal = (UInt8)REG_VAL_SEL_AIP_HBR; + break; + + default: + return TMBSL_ERR_HDMI_BAD_PARAMETER; + } + + + /* Set the audio input processor format to aFmt. */ + err = setHwRegisterField(pDis, + E_REG_P00_AIP_CLKSEL_W, + E_MASKREG_P00_AIP_CLKSEL_sel_aip, + regVal); + RETIF_REG_FAIL(err) + + /* Channel status on 1 channel */ + err = setHwRegisterField(pDis, + E_REG_P11_CA_I2S_RW, + E_MASKREG_P11_CA_I2S_hbr_chstat_4, + 0); + RETIF_REG_FAIL(err) + + /* Select the audio format */ + if ((aFmt == HDMITX_AFMT_I2S) +#ifdef TMFL_HBR_SUPPORT + || (aFmt == HDMITX_AFMT_HBR) +#endif /* TMFL_HBR_SUPPORT */ + ) + { + if (chanI2s != HDMITX_CHAN_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P11_CA_I2S_RW, + E_MASKREG_P11_CA_I2S_ca_i2s, + (UInt8)chanI2s); + } + + /* Select the I2S format */ + err = setHwRegisterField(pDis, + E_REG_P00_I2S_FORMAT_RW, + E_MASKREG_P00_I2S_FORMAT_i2s_format, + (UInt8)i2sFormat); + RETIF_REG_FAIL(err) + +//#ifdef TMFL_HBR_SUPPORT + //if (aFmt == HDMITX_AFMT_HBR) + // { + /* Channel status on 1 channel */ + // err = setHwRegisterField(pDis, + // E_REG_P11_CA_I2S_RW, + // E_MASKREG_P11_CA_I2S_hbr_chstat_4, + // 1); + // RETIF_REG_FAIL(err) + // } +//#endif /* TMFL_HBR_SUPPORT */ + } + else if (aFmt == HDMITX_AFMT_OBA) + { + if (chanDsd != HDMITX_CHAN_NO_CHANGE) + { + err = setHwRegister(pDis, E_REG_P11_CA_DSD_RW, chanDsd); + RETIF_REG_FAIL(err) + } + if (clkPolDsd != HDMITX_CLKPOLDSD_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_AIP_CLKSEL_W, + E_MASKREG_P00_AIP_CLKSEL_sel_pol_clk, + (UInt8)clkPolDsd); + RETIF_REG_FAIL(err) + } + if (swapDsd != HDMITX_SWAPDSD_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_swap, + (UInt8)swapDsd); + RETIF_REG_FAIL(err) + } + } + + /* Set layout and latency */ + if (layout != HDMITX_LAYOUT_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_layout, + layout); + RETIF_REG_FAIL(err) + } + if (uLatency_rd != HDMITX_LATENCY_NO_CHANGE) + { + err = setHwRegister(pDis, E_REG_P11_LATENCY_RD_RW, (UInt8)uLatency_rd); + RETIF_REG_FAIL(err) + } + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989AudioInSetCts */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989AudioInSetCts +( + tmUnitSelect_t txUnit, + tmbslHdmiTxctsRef_t ctsRef, + tmbslHdmiTxafs_t afs, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVfreq_t voutFreq, + UInt32 uCts, + UInt16 uCtsX, + tmbslHdmiTxctsK_t ctsK, + tmbslHdmiTxctsM_t ctsM, + tmbslHdmiTxDstRate_t dstRate +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; /* Register value */ + UInt8 pixClk; /* Pixel clock index */ + UInt32 acrN; /* Audio clock recovery N */ + + DUMMY_ACCESS(dstRate); + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if sink is not an HDMI device */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameters */ + RETIF_BADPARAM(ctsRef >= HDMITX_CTSREF_INVALID) + RETIF_BADPARAM(afs >= HDMITX_AFS_INVALID) + RETIF_BADPARAM(!IS_VALID_FMT(voutFmt)) + RETIF_BADPARAM(voutFreq >= HDMITX_VFREQ_INVALID) + RETIF_BADPARAM(uCtsX >= HDMITX_CTSX_INVALID) + RETIF_BADPARAM(ctsK >= HDMITX_CTSK_INVALID) + RETIF_BADPARAM(ctsM >= HDMITX_CTSMTS_INVALID) + + + if (IS_TV(voutFmt)) + { + if (voutFreq == HDMITX_VFREQ_50Hz) + { + RETIF(((voutFmt < HDMITX_VFMT_17_720x576p_50Hz) \ + || (voutFmt > HDMITX_VFMT_31_1920x1080p_50Hz)), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + else if (voutFreq == HDMITX_VFREQ_24Hz) + { + RETIF((voutFmt != HDMITX_VFMT_32_1920x1080p_24Hz) \ + && (voutFmt != HDMITX_VFMT_60_1280x720p_24Hz), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + else if (voutFreq == HDMITX_VFREQ_25Hz) + { + RETIF((voutFmt != HDMITX_VFMT_33_1920x1080p_25Hz) \ + && (voutFmt != HDMITX_VFMT_20_1920x1080i_50Hz) \ + && (voutFmt != HDMITX_VFMT_61_1280x720p_25Hz), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + else if (voutFreq == HDMITX_VFREQ_30Hz) + { + RETIF((voutFmt != HDMITX_VFMT_34_1920x1080p_30Hz) \ + && (voutFmt != HDMITX_VFMT_05_1920x1080i_60Hz) \ + && (voutFmt != HDMITX_VFMT_62_1280x720p_30Hz), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + else + { + RETIF(voutFmt >= HDMITX_VFMT_17_720x576p_50Hz, + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + } + +#ifdef FORMAT_PC + if (IS_PC(voutFmt)) + { + if (voutFreq == HDMITX_VFREQ_60Hz) + { + RETIF(voutFmt > HDMITX_VFMT_PC_1600x1200p_60Hz, + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + } + else if (voutFreq == HDMITX_VFREQ_70Hz) + { + RETIF(voutFmt != HDMITX_VFMT_PC_1024x768p_70Hz, + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + } + else if (voutFreq == HDMITX_VFREQ_72Hz) + { + RETIF( ((voutFmt < HDMITX_VFMT_PC_640x480p_72Hz) || + (voutFmt > HDMITX_VFMT_PC_800x600p_72Hz)), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + } + else if (voutFreq == HDMITX_VFREQ_75Hz) + { + RETIF( ((voutFmt < HDMITX_VFMT_PC_640x480p_75Hz) || + (voutFmt > HDMITX_VFMT_PC_1280x1024p_75Hz)), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + } + else if (voutFreq == HDMITX_VFREQ_85Hz) + { + RETIF( ((voutFmt < HDMITX_VFMT_PC_640x350p_85Hz) || + (voutFmt > HDMITX_VFMT_PC_1280x1024p_85Hz)), + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + } + else + { + RETIF(voutFmt != HDMITX_VFMT_PC_1024x768i_87Hz, + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + } + } +#endif /* FORMAT_PC */ + + /* Check for auto or manual CTS */ + if (uCts == HDMITX_CTS_AUTO) + { + /* Auto */ + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_acr_man, + 0); + RETIF_REG_FAIL(err) + } + else + { + /* Manual */ + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_acr_man, + 1); + RETIF_REG_FAIL(err) + } + + /* Derive M and K from X? */ + if ((ctsM == HDMITX_CTSMTS_USE_CTSX) || (ctsK == HDMITX_CTSK_USE_CTSX)) + { + RETIF_BADPARAM(uCtsX == HDMITX_CTSX_UNUSED) + ctsM = (tmbslHdmiTxctsM_t) kCtsXToMK[uCtsX][0]; + ctsK = (tmbslHdmiTxctsK_t)kCtsXToMK[uCtsX][1]; + } + + /* Set the Post-divider measured timestamp factor */ + regVal = (UInt8)ctsM; + err = setHwRegisterField(pDis, + E_REG_P11_CTS_N_RW, + E_MASKREG_P11_CTS_N_m_sel, + regVal); + RETIF_REG_FAIL(err) + + /* Set the Pre-divider scale */ + regVal = (UInt8)ctsK; + err = setHwRegisterField(pDis, + E_REG_P11_CTS_N_RW, + E_MASKREG_P11_CTS_N_k_sel, + regVal); + RETIF_REG_FAIL(err); + + /* Use voutFmt and voutFreq to index into a lookup table to get + * the current pixel clock value. */ + pix_clk(voutFmt, voutFreq, &pixClk); + + if (pixClk != E_PIXCLK_INVALID) + { + /* Set the Audio Clock Recovery N multiplier based on the audio sample + * frequency afs and current pixel clock. */ + acrN = kPixClkToAcrN[pixClk][afs]; + + /* Set ACR N multiplier [19 to 16] */ + regVal = (UInt8)(acrN >> 16); + err = setHwRegister(pDis, E_REG_P11_ACR_N_2_RW, regVal); + RETIF_REG_FAIL(err) + /* Set ACR N multiplier [15 to 8] */ + regVal = (UInt8)(acrN >> 8); + err = setHwRegister(pDis, E_REG_P11_ACR_N_1_RW, regVal); + RETIF_REG_FAIL(err) + /* Set ACR N multiplier [7 to 0] */ + regVal = (UInt8)acrN; + err = setHwRegister(pDis, E_REG_P11_ACR_N_0_RW, regVal); + RETIF_REG_FAIL(err) + + /* Set the CDC Audio Divider register based on the audio sample frequency + * afs and current pixel clock. */ + regVal = kPixClkToAdiv[pixClk][afs]; + err = setHwRegister(pDis, E_REG_P02_AUDIO_DIV_RW, regVal); + RETIF_REG_FAIL(err) + + /* If auto CTS, get CTS value based on the audio sample + * frequency afs and current pixel clock. */ + if (uCts == HDMITX_CTS_AUTO) + { + uCts = kPixClkToAcrCts[pixClk][afs]; + } + } + + /* Set manual or pixel clock CTS */ + if (uCts != HDMITX_CTS_AUTO) + { + /* Set manual ACR CTS [19 to 16 */ + regVal = (UInt8)(uCts >> 16); + err = setHwRegister(pDis, E_REG_P11_ACR_CTS_2_RW, regVal); + RETIF_REG_FAIL(err) + /* Set manual ACR CTS [15 to 8] */ + regVal = (UInt8)(uCts >> 8); + err = setHwRegister(pDis, E_REG_P11_ACR_CTS_1_RW, regVal); + RETIF_REG_FAIL(err) + /* Set manual ACR CTS [7 to 0] */ + regVal = (UInt8)uCts; + err = setHwRegister(pDis, E_REG_P11_ACR_CTS_0_RW, regVal); + RETIF_REG_FAIL(err) + } + + /* Set the CTS clock reference register according to ctsRef */ + regVal = (UInt8)ctsRef; + err = setHwRegisterField(pDis, + E_REG_P00_AIP_CLKSEL_W, + E_MASKREG_P00_AIP_CLKSEL_sel_fs, + regVal); + RETIF_REG_FAIL(err) + + /* Reset and release the CTS generator */ + err = setHwRegisterFieldTable(pDis, &kResetCtsGenerator[0]); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989AudioOutSetChanStatus */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989AudioOutSetChanStatus +( + tmUnitSelect_t txUnit, + tmbslHdmiTxAudioData_t pcmIdentification, + tmbslHdmiTxCSformatInfo_t formatInfo, + tmbslHdmiTxCScopyright_t copyright, + UInt8 categoryCode, + tmbslHdmiTxafs_t sampleFreq, + tmbslHdmiTxCSclkAcc_t clockAccuracy, + tmbslHdmiTxCSmaxWordLength_t maxWordLength, + tmbslHdmiTxCSwordLength_t wordLength, + tmbslHdmiTxCSorigAfs_t origSampleFreq +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[4]; /* Buffer to hold channel status data */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if sink is not an HDMI device */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameters */ + RETIF_BADPARAM(formatInfo >= HDMITX_CSFI_INVALID) + RETIF_BADPARAM(copyright >= HDMITX_CSCOPYRIGHT_INVALID) + RETIF_BADPARAM(sampleFreq > HDMITX_AFS_NOT_INDICATED) + RETIF_BADPARAM(clockAccuracy >= HDMITX_CSCLK_INVALID) + RETIF_BADPARAM(maxWordLength >= HDMITX_CSMAX_INVALID) + RETIF_BADPARAM(wordLength >= HDMITX_CSWORD_INVALID) + RETIF_BADPARAM(wordLength == HDMITX_CSWORD_RESVD) + RETIF_BADPARAM(origSampleFreq >= HDMITX_CSAFS_INVALID) + RETIF_BADPARAM(pcmIdentification >=HDMITX_AUDIO_DATA_INVALID) + + /* Prepare Byte 0 */ + buf[0] = ((UInt8)formatInfo << 3) | ((UInt8)copyright << 2) | ((UInt8)pcmIdentification<< 1); + + /* Prepare Byte 1 */ + buf[1] = categoryCode; + + /* Prepare Byte 3 - note Byte 2 not in sequence in TDA9983 register map */ + buf[2] = ((UInt8)clockAccuracy << 4) | kAfsToCSbyte3[sampleFreq]; + + /* Prepare Byte 4 */ + buf[3] = ((UInt8)origSampleFreq << 4) | ((UInt8)wordLength << 1) | + (UInt8)maxWordLength; + + /* Write 4 Channel Status bytes */ + err = setHwRegisters(pDis, E_REG_P11_CH_STAT_B_0_RW, &buf[0], 4); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989AudioOutSetChanStatusMapping */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989AudioOutSetChanStatusMapping +( + tmUnitSelect_t txUnit, + UInt8 sourceLeft[4], + UInt8 channelLeft[4], + UInt8 sourceRight[4], + UInt8 channelRight[4] +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[2]; /* Buffer to hold channel status data */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if sink is not an HDMI device */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameters */ + RETIF_BADPARAM(sourceLeft[0] > HDMITX_CS_SOURCES_MAX) + RETIF_BADPARAM(channelLeft[0] > HDMITX_CS_CHANNELS_MAX) + RETIF_BADPARAM(sourceRight[0] > HDMITX_CS_SOURCES_MAX) + RETIF_BADPARAM(channelRight[0] > HDMITX_CS_CHANNELS_MAX) + + /* Prepare Left byte */ + buf[0] = ((UInt8)channelLeft[0] << 4) | (UInt8)sourceLeft[0]; + + /* Prepare Right byte */ + buf[1] = ((UInt8)channelRight[0] << 4) | (UInt8)sourceRight[0]; + + /* Write 2 Channel Status bytes */ + err = setHwRegisters(pDis, E_REG_P11_CH_STAT_B_2_ap0_l_RW, &buf[0], 2); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989AudioOutSetMute */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989AudioOutSetMute +( + tmUnitSelect_t txUnit, + tmbslHdmiTxaMute_t aMute +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if sink is not an HDMI device */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameters */ + RETIF_BADPARAM(aMute >= HDMITX_AMUTE_INVALID) + + /* audio mute workaround, un-map audio input before muting */ + if (aMute == HDMITX_AMUTE_ON) + { + err = setHwRegisterField(pDis, + E_REG_P00_SR_REG_W, + E_MASKREG_P00_SR_REG_sr_audio, + (UInt8)aMute); + RETIF(err != TM_OK, err) + + + err = setHwRegisterField(pDis, + E_REG_P00_SR_REG_W, + E_MASKREG_P00_SR_REG_sr_audio, + (UInt8) !aMute); + RETIF(err != TM_OK, err) + + } + + /* Reset the audio FIFO to mute audio */ + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_rst_fifo, + (UInt8)aMute); + RETIF(err != TM_OK, err) + + + return TM_OK; + +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerGet */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989ScalerGet +( + tmUnitSelect_t txUnit, + tmbslHdmiTxScalerDiag_t *pScalerDiag +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(pScalerDiag); /* else not referenced */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + + +/*============================================================================*/ +/* tmbslTDA9989ScalerGetMode */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerGetMode +( + tmUnitSelect_t txUnit, + tmbslHdmiTxScaMode_t *pScalerMode +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(pScalerMode); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerInDisable */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerInDisable +( + tmUnitSelect_t txUnit, + Bool bDisable +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(bDisable); + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerSetCoeffs */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989ScalerSetCoeffs +( + tmUnitSelect_t txUnit, + tmbslHdmiTxScaLut_t lutSel, + UInt8 *pVsLut +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(lutSel); /* else is declared but not used */ + DUMMY_ACCESS(pVsLut); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + + +/*============================================================================*/ +/* tmbslTDA9989ScalerSetFieldOrder */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerSetFieldOrder +( + tmUnitSelect_t txUnit, + tmbslHdmiTxIntExt_t topExt, + tmbslHdmiTxIntExt_t deExt, + tmbslHdmiTxTopSel_t topSel, + tmbslHdmiTxTopTgl_t topTgl +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(deExt); /* else is declared but not used */ + DUMMY_ACCESS(topExt); /* else is declared but not used */ + DUMMY_ACCESS(topSel); /* else is declared but not used */ + DUMMY_ACCESS(topTgl); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerSetPhase */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerSetPhase +( + tmUnitSelect_t txUnit, + tmbslHdmiTxHPhases_t horizontalPhases +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(horizontalPhases); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerSetLatency */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerSetLatency +( + tmUnitSelect_t txUnit, + UInt8 scaler_latency +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(scaler_latency); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerSetFine */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerSetFine +( + tmUnitSelect_t txUnit, + UInt16 uRefPix, + UInt16 uRefLine +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(uRefPix); /* else is declared but not used */ + DUMMY_ACCESS(uRefLine); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989ScalerSetSync */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989ScalerSetSync +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVsMeth_t method, + tmbslHdmiTxVsOnce_t once +) +{ + DUMMY_ACCESS(txUnit); /* else not referenced */ + DUMMY_ACCESS(method); /* else is declared but not used */ + DUMMY_ACCESS(once); /* else is declared but not used */ + return TMBSL_ERR_HDMI_NOT_SUPPORTED; + +} + +/*============================================================================*/ +/* tmbslTDA9989TmdsSetOutputs */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989TmdsSetOutputs +( + tmUnitSelect_t txUnit, + tmbslHdmiTxTmdsOut_t tmdsOut +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(tmdsOut >= HDMITX_TMDSOUT_INVALID) + + /* Set the TMDS output mode */ + err = setHwRegisterField(pDis, + E_REG_P02_BUFFER_OUT_RW, + E_MASKREG_P02_BUFFER_OUT_srl_force, + (UInt8)tmdsOut); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989TmdsSetSerializer */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989TmdsSetSerializer +( + tmUnitSelect_t txUnit, + UInt8 uPhase2, + UInt8 uPhase3 +) +{ + + DUMMY_ACCESS(txUnit); + DUMMY_ACCESS(uPhase2); + DUMMY_ACCESS(uPhase3); + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989TestSetPattern */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989TestSetPattern +( + tmUnitSelect_t txUnit, + tmbslHdmiTxTestPattern_t pattern +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 serviceMode; /* Register value */ + UInt8 bars8; /* Register value */ + UInt8 buf[MATRIX_PRESET_SIZE]; /* Temp buffer */ + UInt8 i; /* Loop index */ + UInt8 *MatrixCoeff=Null; + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check pattern parameters */ + switch (pattern) + { + case HDMITX_PATTERN_CBAR4: + serviceMode = 1; + bars8 = 0; + break; + case HDMITX_PATTERN_BLUE: + MatrixCoeff = (UInt8*)&MatrixCoeffBlueScreen[pDis->voutMode][0]; //point to the blue matrix + serviceMode = 1; + bars8 = 1; + break; + case HDMITX_PATTERN_BLACK: + MatrixCoeff = (UInt8*)&MatrixCoeffBlackScreen[pDis->voutMode][0]; //point to the black matrix + case HDMITX_PATTERN_CBAR8: + serviceMode = 1; + bars8 = 1; + break; + case HDMITX_PATTERN_OFF: + serviceMode = 0; + bars8 = 0; + break; + default: + return TMBSL_ERR_HDMI_BAD_PARAMETER; + } + + if (serviceMode) + { + if (!pDis->prevPattern) /* if a pattern is on, registers are already saved */ + { + /* The kBypassColourProc registers are saved in tmbslTDA9989VideoSetInOut API */ + /* Bypass up/down sampler and matrix for RGB colourbars */ + setHwRegisterFieldTable(pDis, &kBypassColourProc[0]); + } + if (( pattern == HDMITX_PATTERN_BLUE )||( pattern == HDMITX_PATTERN_BLACK )) /* blue or black screen pattern */ + { + + /* To create blue or black screen, we use the internal color bar 8 on which we apply a matrix to change it to blue or black */ + /* Set the first block byte separately, as it is shadowed and can't + * be set by setHwRegisters */ + + /* Set the first block byte separately, as it is shadowed and can't + * be set by setHwRegisters */ + err = setHwRegister(pDis, + E_REG_P00_MAT_CONTRL_W, + MatrixCoeff[0]); + RETIF_REG_FAIL(err) + + for (i = 0; i < MATRIX_PRESET_SIZE; i++) + { + buf[i] = MatrixCoeff[i]; + } + + /* Set the rest of the block */ + err = setHwRegisters(pDis, + E_REG_P00_MAT_OI1_MSB_W, + &buf[1], + MATRIX_PRESET_SIZE - 1); + RETIF_REG_FAIL(err) + pDis->prevFilterPattern = True; + } + else /* colour bars patterns */ + { + /* Set number of colour bars */ + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_0_W, + E_MASKREG_P00_HVF_CNTRL_0_rwb, + bars8); + RETIF_REG_FAIL(err) + + /* Bypass up/down sampler and matrix for RGB colourbars */ + setHwRegisterFieldTable(pDis, &kBypassColourProc[0]); + } + pDis->prevPattern = True; + } + else /* serviceMode == 0 */ + { + if (pDis->prevFilterPattern) + { + /* Restore the previous Matrix when pattern goes off */ + err = tmbslTDA9989MatrixSetConversion ( txUnit, pDis->vinFmt, pDis->vinMode, pDis->voutFmt, pDis->voutMode,pDis->dviVqr); + RETIF_REG_FAIL(err) + + pDis->prevFilterPattern = False; + } + /* Restore kBypassColourProc registers when pattern goes off */ + setHwRegister(pDis, E_REG_P00_MAT_CONTRL_W, gMatContrl[txUnit]); + setHwRegister(pDis, E_REG_P00_HVF_CNTRL_0_W, gHvfCntrl0[txUnit]); + setHwRegister(pDis, E_REG_P00_HVF_CNTRL_1_W, gHvfCntrl1[txUnit]); + pDis->prevPattern = False; + } + + /* Set Service Mode on or off */ + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_0_W, + E_MASKREG_P00_HVF_CNTRL_0_sm, + serviceMode); +#ifdef TMFL_HDCP_SUPPORT + pDis->HDCPIgnoreEncrypt = True; /* Skip the next encrypt IT */ +#endif /* TMFL_HDCP_SUPPORT */ + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoInSetBlanking */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoInSetBlanking +( + tmUnitSelect_t txUnit, + tmbslHdmiTxBlnkSrc_t blankitSource, + tmbslHdmiTxBlnkCode_t blankingCodes +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(blankitSource >= HDMITX_BLNKSRC_INVALID) + RETIF_BADPARAM(blankingCodes >= HDMITX_BLNKCODE_INVALID) + + /* For each parameter that is not No Change, set its register */ + if (blankitSource != HDMITX_BLNKSRC_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_blankit, + (UInt8)blankitSource); + RETIF_REG_FAIL(err) + } + if (blankingCodes != HDMITX_BLNKCODE_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_blc, + (UInt8)blankingCodes); + RETIF_REG_FAIL(err) + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoInSetConfig */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoInSetConfig +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTx3DStructure_t structure3D, + tmbslHdmiTxPixEdge_t sampleEdge, + tmbslHdmiTxPixRate_t pixRate, + tmbslHdmiTxUpsampleMode_t upsampleMode +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(vinMode >= HDMITX_VINMODE_INVALID) + RETIF_BADPARAM(sampleEdge >= HDMITX_PIXEDGE_INVALID) + RETIF_BADPARAM(pixRate >= HDMITX_PIXRATE_INVALID) + RETIF_BADPARAM(upsampleMode >= HDMITX_UPSAMPLE_INVALID) + + err = InputConfig(pDis, + vinMode, + sampleEdge, + pixRate, + upsampleMode, + HDMITX_PIXREP_NO_CHANGE, + voutFmt, + structure3D); + RETIF_REG_FAIL(err) + + return TM_OK; +} +/*============================================================================*/ +/* tmbslTDA9989VideoInSetFine */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoInSetFine +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPixSubpkt_t subpacketCount, + tmbslHdmiTxPixTogl_t toggleClk1 +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(subpacketCount >= HDMITX_PIXSUBPKT_INVALID) + RETIF_BADPARAM(toggleClk1 >= HDMITX_PIXTOGL_INVALID) + + /* IF subpacketCount is Fix at 0/1/2/3 THEN set subpacket count register + * to 0/1/2/3 and set subpacket sync register to 3 + */ + if (subpacketCount <= HDMITX_PIXSUBPKT_FIX_3) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_5_W, + E_MASKREG_P00_VIP_CNTRL_5_sp_cnt, + (UInt8)subpacketCount); + RETIF_REG_FAIL(err) + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_sp_sync, + HDMITX_PIXSUBPKT_SYNC_FIXED); + RETIF_REG_FAIL(err) + } + /* ELSE IF subpacketCount is Sync by Hemb/ Sync by Rising Edge DE/ + * Sync by Rising Edge HS THEN set the unused subpacket count to zero and + * set subpacket sync register to 0/1/2 + */ + else if (subpacketCount != HDMITX_PIXSUBPKT_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_5_W, + E_MASKREG_P00_VIP_CNTRL_5_sp_cnt, + HDMITX_PIXSUBPKT_FIX_0); + RETIF_REG_FAIL(err) + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_sp_sync, + (UInt8)(subpacketCount - HDMITX_PIXSUBPKT_SYNC_FIRST)); + RETIF_REG_FAIL(err) + } + + /* IF toggleClk1 is not No Change THEN set ckcase bitfield */ + if (toggleClk1 != HDMITX_PIXTOGL_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_5_W, + E_MASKREG_P00_VIP_CNTRL_5_ckcase, + (UInt8)toggleClk1); + RETIF_REG_FAIL(err) + } + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoInSetMapping */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoInSetMapping +#ifdef TMFL_RGB_DDR_12BITS +( + tmUnitSelect_t txUnit, + UInt8 *pSwapTable, + UInt8 *pMirrorTable, + UInt8 *pMux +) +#else +( + tmUnitSelect_t txUnit, + UInt8 *pSwapTable, + UInt8 *pMirrorTable +) +#endif +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop counter */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(pSwapTable == Null) + RETIF_BADPARAM(pMirrorTable == Null) + for (i = 0; i < HDMITX_VIN_PORT_MAP_TABLE_LEN; i++) + { + RETIF_BADPARAM(pSwapTable[i] >= HDMITX_VIN_PORT_SWAP_INVALID) + RETIF_BADPARAM(pMirrorTable[i] >= HDMITX_VIN_PORT_MIRROR_INVALID) + } + + /* IF pswapTable[n] is not No Change THEN set the port swap registers from + * pswapTable[n] + */ + for (i = 0; i < HDMITX_VIN_PORT_MAP_TABLE_LEN; i++) + { + if (pSwapTable[0] < HDMITX_VIN_PORT_SWAP_NO_CHANGE) + { + err = setHwRegisterField(pDis, + kRegVip[i].Register, + kRegVip[i].MaskSwap, + pSwapTable[i]); + RETIF_REG_FAIL(err) + } + } + + /* IF pMirrorTable[n] is not No Change THEN set the port mirror registers + * from pMirrorTable[n] + */ + for (i = 0; i < HDMITX_VIN_PORT_MAP_TABLE_LEN; i++) + { + if (pMirrorTable[0] < HDMITX_VIN_PORT_MIRROR_NO_CHANGE) + { + err = setHwRegisterField(pDis, + kRegVip[i].Register, + kRegVip[i].MaskMirror, + pMirrorTable[i]); + RETIF_REG_FAIL(err) + } + } + +#ifdef TMFL_RGB_DDR_12BITS + /* + mux for RGB_DDR_12bits + */ + err = setHwRegister(pDis,E_REG_P00_MUX_VP_VIP_OUT_RW, *pMux); + RETIF_REG_FAIL(err); +#endif + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989SetVideoPortConfig */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SetVideoPortConfig +( + tmUnitSelect_t txUnit, + UInt8 *pEnaVideoPortTable, + UInt8 *pGndVideoPortTable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(pEnaVideoPortTable == Null) + RETIF_BADPARAM(pGndVideoPortTable == Null) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_0_RW, + pEnaVideoPortTable[0]); + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_1_RW, + pEnaVideoPortTable[1]); + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_2_RW, + pEnaVideoPortTable[2]); + RETIF_REG_FAIL(err) + + /* err = setHwRegister(pDis, + E_REG_P00_GND_VP_0_RW, + pGndVideoPortTable[0]); + RETIF_REG_FAIL(err)*/ + + /* err = setHwRegister(pDis, + E_REG_P00_GND_VP_1_RW, + pGndVideoPortTable[1]); + RETIF_REG_FAIL(err)*/ + + /* err = setHwRegister(pDis, + E_REG_P00_GND_VP_2_RW, + pGndVideoPortTable[2]); + RETIF_REG_FAIL(err)*/ + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989SetAudioPortConfig */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SetAudioPortConfig +( + tmUnitSelect_t txUnit, + UInt8 *pEnaAudioPortTable, + UInt8 *pGndAudioPortTable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(pEnaAudioPortTable == Null) + RETIF_BADPARAM(pGndAudioPortTable == Null) + + err = setHwRegister(pDis, + E_REG_P00_ENA_AP_RW, + pEnaAudioPortTable[0]); + RETIF_REG_FAIL(err) + + /* err = setHwRegister(pDis, + E_REG_P00_GND_AP_RW, + pGndAudioPortTable[0]); + RETIF_REG_FAIL(err)*/ + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989SetAudioClockPortConfig */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SetAudioClockPortConfig +( + tmUnitSelect_t txUnit, + UInt8 *pEnaAudioClockPortTable, + UInt8 *pGndAudioClockPortTable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(pEnaAudioClockPortTable == Null) + RETIF_BADPARAM(pGndAudioClockPortTable == Null) + + err = setHwRegister(pDis, + E_REG_P00_ENA_ACLK_RW, + pEnaAudioClockPortTable[0]); + RETIF_REG_FAIL(err) + + /*err = setHwRegister(pDis, + E_REG_P00_GND_ACLK_RW, + pGndAudioClockPortTable[0]); + RETIF_REG_FAIL(err)*/ + + return TM_OK; +} + +/*============================================================================*/ +/* set_video replace E_REG_P00_VIDFORMAT_W register */ +/* use it for new video format */ +/*============================================================================*/ +tmErrorCode_t set_video(tmHdmiTxobject_t *pDis,tmbslHdmiTxVidFmt_t reg_idx,tmHdmiTxVidReg_t *format_param) +{ + tmErrorCode_t err; + UInt8 regVal; + + regVal = 0x00;/* PR1570 FIXED */ + err = setHwRegister(pDis, E_REG_P00_VIDFORMAT_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].nPix; + err = setHwRegister(pDis, E_REG_P00_NPIX_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].nPix>>8); + err = setHwRegister(pDis, E_REG_P00_NPIX_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].nLine; + err = setHwRegister(pDis, E_REG_P00_NLINE_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].nLine>>8); + err = setHwRegister(pDis, E_REG_P00_NLINE_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].VsLineStart; + err = setHwRegister(pDis, E_REG_P00_VS_LINE_STRT_1_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].VsPixStart; + err = setHwRegister(pDis, E_REG_P00_VS_PIX_STRT_1_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].VsPixStart>>8); + err = setHwRegister(pDis, E_REG_P00_VS_PIX_STRT_1_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].VsLineEnd; + err = setHwRegister(pDis, E_REG_P00_VS_LINE_END_1_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].VsPixEnd; + err = setHwRegister(pDis, E_REG_P00_VS_PIX_END_1_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].VsPixEnd>>8); + err = setHwRegister(pDis, E_REG_P00_VS_PIX_END_1_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].HsStart; + err = setHwRegister(pDis, E_REG_P00_HS_PIX_START_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].HsStart>>8); + err = setHwRegister(pDis, E_REG_P00_HS_PIX_START_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].HsEnd; + err = setHwRegister(pDis, E_REG_P00_HS_PIX_STOP_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].HsEnd>>8); + err = setHwRegister(pDis, E_REG_P00_HS_PIX_STOP_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].ActiveVideoStart; + err = setHwRegister(pDis, E_REG_P00_VWIN_START_1_LSB_W, regVal); + RETIF_REG_FAIL(err); + err = setHwRegister(pDis, E_REG_P00_VWIN_START_1_MSB_W, 0); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].ActiveVideoEnd; + err = setHwRegister(pDis, E_REG_P00_VWIN_END_1_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].ActiveVideoEnd>>8); + err = setHwRegister(pDis, E_REG_P00_VWIN_END_1_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].DeStart; + err = setHwRegister(pDis, E_REG_P00_DE_START_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].DeStart>>8); + err = setHwRegister(pDis, E_REG_P00_DE_START_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].DeEnd; + err = setHwRegister(pDis, E_REG_P00_DE_STOP_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)(format_param[reg_idx].DeEnd>>8); + err = setHwRegister(pDis, E_REG_P00_DE_STOP_MSB_W, regVal); + RETIF_REG_FAIL(err); + +#ifdef TMFL_RGB_DDR_12BITS + if (format_param[reg_idx].ActiveSpaceStart) { + /* enable active space */ + err = setHwRegisterField(pDis, E_REG_P00_ENABLE_SPACE_W, 0x01, 0x01); + RETIF_REG_FAIL(err); + + /* set active space to black */ + err = setHwRegister(pDis, E_REG_P00_VSPACE_Y_DATA_W, 0x00); + RETIF_REG_FAIL(err); + + err = setHwRegister(pDis, E_REG_P00_VSPACE_U_DATA_W, 0x80); + RETIF_REG_FAIL(err); + + err = setHwRegister(pDis, E_REG_P00_VSPACE_V_DATA_W, 0x80); + RETIF_REG_FAIL(err); + + /* active space definition */ + regVal = (UInt8)format_param[reg_idx].ActiveSpaceStart; + err = setHwRegister(pDis, E_REG_P00_VSPACE_START_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)((format_param[reg_idx].ActiveSpaceStart>>8) & 0x0F); + err = setHwRegister(pDis, E_REG_P00_VSPACE_START_MSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)format_param[reg_idx].ActiveSpaceEnd; + err = setHwRegister(pDis, E_REG_P00_VSPACE_END_LSB_W, regVal); + RETIF_REG_FAIL(err); + + regVal = (UInt8)((format_param[reg_idx].ActiveSpaceEnd>>8) & 0x0F); + err = setHwRegister(pDis, E_REG_P00_VSPACE_END_MSB_W, regVal); + RETIF_REG_FAIL(err); + } + else { + /* let incoming pixels feel the active space (if any) */ + err = setHwRegisterField(pDis, E_REG_P00_ENABLE_SPACE_W, 0x01, 0x00); + RETIF_REG_FAIL(err); + } +#endif + + return TM_OK; +} + + +/*============================================================================*/ +/* tmbslTDA9989VideoInSetSyncAuto */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoInSetSyncAuto +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSyncSource_t syncSource, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTx3DStructure_t structure3D +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 reg_idx,reg_idx3D; /* Video i/p fmt value used for comparison */ + UInt8 embedded; /* Register value */ + UInt8 syncMethod; /* Sync method */ + UInt8 toggleV; /* V toggle */ + UInt8 toggleH; /* H toggle */ + UInt8 toggleX; /* X toggle */ + UInt16 uRefPix; /* Output refpix */ + UInt16 uRefLine; /* Output refline */ +#ifdef FORMAT_PC + UInt8 regVal;/* PR1570 FIXED */ +#endif /* FORMAT_PC */ + struct sync_desc *sync; + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err); + + /* Check parameters - syncSource must be specified */ + RETIF_BADPARAM(syncSource >= HDMITX_SYNCSRC_NO_CHANGE); + RETIF_BADPARAM(!IS_VALID_FMT(vinFmt)); + + /* Look up the VIDFORMAT register format from the register format table */ + /* Quit if the input format does not map to the register format */ + RETIF_BADPARAM(reg_vid_fmt(vinFmt,structure3D,®_idx,®_idx3D,&sync)); + + /* Select values according to sync source */ + embedded = 0; + switch (syncSource) + { + case HDMITX_SYNCSRC_EXT_VS: + syncMethod = 0; + toggleV = sync[BASE(reg_idx)].v_toggle; + toggleH = sync[BASE(reg_idx)].h_toggle; + toggleX = 0; + uRefPix = sync[BASE(reg_idx)].hfp; + uRefLine = sync[BASE(reg_idx)].vfp; + break; + case HDMITX_SYNCSRC_EMBEDDED: + embedded++; + /* fall thru */ + case HDMITX_SYNCSRC_EXT_VREF: + default: + syncMethod = 1; + toggleV = 1; + toggleH = 1; + toggleX = 1; + uRefPix = sync[BASE(reg_idx)].href; + uRefLine = sync[BASE(reg_idx)].vref; + break; + } + /* Table has +1 added to refpix values which are not needed in + RGB444, YUV444 and YUV422 modes, but +2 is required in those cases */ + if (vinMode != HDMITX_VINMODE_CCIR656) + { + uRefPix = uRefPix + 2; + } + + /* ---------------------------------------------------------- */ + /* Synchronicity software workaround issue number 106 */ + /* ---------------------------------------------------------- */ + if (vinMode == HDMITX_VINMODE_CCIR656) { + if (syncSource == HDMITX_SYNCSRC_EXT_VS) { + if (pDis->pixRate == HDMITX_PIXRATE_DOUBLE) { + + switch (reg_idx) { + case E_REGVFMT_720x480p_60Hz: + case E_REGVFMT_720x480i_60Hz: + case E_REGVFMT_720x576p_50Hz: + case E_REGVFMT_720x576i_50Hz: + uRefPix = uRefPix + 1; + break; + default: + /* do nothing... well I would say : FIXME */ + break; + } + + } + } + } + + + /* Set embedded sync */ + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_emb, + embedded); + RETIF_REG_FAIL(err) + + /* Set sync method */ + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_0_W, + E_MASKREG_P00_TBG_CNTRL_0_sync_mthd, + syncMethod); + RETIF_REG_FAIL(err) + +/* printk("DBG auto toggle X:%d V:%d H:%d\n",toggleX,toggleV,toggleH); */ + /* Set VH toggle */ + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_v_tgl, + toggleV); + RETIF_REG_FAIL(err) + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_h_tgl, + toggleH); + RETIF_REG_FAIL(err) + + /* Set X toggle */ + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_x_tgl, + toggleX); + RETIF_REG_FAIL(err); + +#ifdef TMFL_RGB_DDR_12BITS + if (syncSource == HDMITX_SYNCSRC_EXT_VREF) { + if (structure3D == HDMITX_3D_FRAME_PACKING) { + /* + stereo sync signaling : + ----------------------- + + When there is a positive sync at the input pins, therefore a negative sync + at input of the TBG, then 3d_neg_vs signal has to be set at 1 (OR-function) + to create the correct VS to preset the line and pixel counters + + case Vs > 0: + ----------- + Vs : __/¨¨\__ + Vs(TBG): ¨¨\__/¨¨ where Vs(TBG)=NOT(Vs) + 3D : ¨¨\_____ + Stereo : ¨¨\__/¨¨ where Stereo = Vs(TBG) OR 3D because 3d_neg_vs = 1 + + case Vs < 0: + ----------- + Vs : ¨¨\__/¨¨ + Vs(TBG): __/¨¨\__ where Vs(TBG)=NOT(Vs) + 3D : ¨¨\_____ + Stereo : __/¨¨\__ where Stereo = Vs(TBG) AND NOT(3D) because 3d_neg_vs = 0 + + + It is possible to invert the incoming VS, HS and DE. In case of 3D format + the DE input will be the 3D signal. This signal will only be used to remove + 1 of the VS depending on the polarity of the 3D signal. When there is a need + to switch the Left or Right it is possible to invert the 3D signal with an + already existing register. + + */ + + err = setHwRegisterField(pDis, + E_REG_P00_VIDFORMAT_W, + E_MASKREG_P00_VIDFORMAT_3d_neg_vs, + toggleV); + RETIF_REG_FAIL(err); + } + err = setHwRegisterField(pDis, + E_REG_P00_VIDFORMAT_W, + E_MASKREG_P00_VIDFORMAT_3d, + (structure3D == HDMITX_3D_FRAME_PACKING)); + RETIF_REG_FAIL(err); + } +#endif + + + if (EXTRA(reg_idx) && (structure3D != HDMITX_3D_FRAME_PACKING)) { + /* 2d extra video format */ + RETIF_REG_FAIL(set_video(pDis,BASE(reg_idx),(tmHdmiTxVidReg_t *)format_param_extra)); + } + else if (EXTRA(reg_idx3D) && (structure3D == HDMITX_3D_FRAME_PACKING)) { + /* 3d extra frame packing */ + RETIF_REG_FAIL(set_video(pDis,BASE(reg_idx3D),(tmHdmiTxVidReg_t *)format_param_extra)); + } + else { + /* see video set up using E_REG_P00_VIDFORMAT_W */ + } + + +#ifdef FORMAT_PC + + if (IS_PC(vinFmt)) + { + RETIF_REG_FAIL(set_video(pDis,reg_idx,(tmHdmiTxVidReg_t *)format_param_PC)); + + regVal = DEPTH_COLOR_PC; + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_pad, + regVal); + RETIF_REG_FAIL(err); + } +#endif /* FORMAT_PC */ + + /* Set refpix, refline */ + err = setHwRegisterMsbLsb(pDis, E_REG_P00_REFPIX_MSB_W, uRefPix); + RETIF_REG_FAIL(err) + err = setHwRegisterMsbLsb(pDis, E_REG_P00_REFLINE_MSB_W, uRefLine); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoInSetSyncManual */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoInSetSyncManual +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSyncSource_t syncSource, + tmbslHdmiTxVsMeth_t syncMethod, + tmbslHdmiTxPixTogl_t toggleV, + tmbslHdmiTxPixTogl_t toggleH, + tmbslHdmiTxPixTogl_t toggleX, + UInt16 uRefPix, + UInt16 uRefLine +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 embedded; /* Register value */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(syncSource >= HDMITX_SYNCSRC_INVALID) + RETIF_BADPARAM(syncMethod >= HDMITX_VSMETH_INVALID) + RETIF_BADPARAM(toggleV >= HDMITX_PIXTOGL_INVALID) + RETIF_BADPARAM(toggleH >= HDMITX_PIXTOGL_INVALID) + RETIF_BADPARAM(toggleX >= HDMITX_PIXTOGL_INVALID) + RETIF_BADPARAM(uRefPix >= HDMITX_VOUT_FINE_PIXEL_INVALID) + RETIF_BADPARAM(uRefLine >= HDMITX_VOUT_FINE_LINE_INVALID) + + if (syncSource != HDMITX_SYNCSRC_NO_CHANGE) + { + if (syncSource == HDMITX_SYNCSRC_EMBEDDED) + { + embedded = 1; + } + else + { + embedded = 0; + } + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_emb, + embedded); + RETIF_REG_FAIL(err) + } + if (syncMethod != HDMITX_VSMETH_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_0_W, + E_MASKREG_P00_TBG_CNTRL_0_sync_mthd, + (UInt8)syncMethod); + RETIF_REG_FAIL(err) + } +/* printk("DBG manual toggle X:%d V:%d H:%d\n",toggleX,toggleV,toggleH); */ + if (toggleV != HDMITX_PIXTOGL_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_v_tgl, + (UInt8)toggleV); + RETIF_REG_FAIL(err) + } + if (toggleH != HDMITX_PIXTOGL_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_h_tgl, + (UInt8)toggleH); + RETIF_REG_FAIL(err) + } + if (toggleX != HDMITX_PIXTOGL_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_x_tgl, + (UInt8)toggleX); + RETIF_REG_FAIL(err) + } + if (uRefPix < HDMITX_VOUT_FINE_PIXEL_NO_CHANGE) + { + err = setHwRegisterMsbLsb(pDis, E_REG_P00_REFPIX_MSB_W, uRefPix); + RETIF_REG_FAIL(err) + } + if (uRefLine < HDMITX_VOUT_FINE_LINE_NO_CHANGE) + { + err = setHwRegisterMsbLsb(pDis, E_REG_P00_REFLINE_MSB_W, uRefLine); + RETIF_REG_FAIL(err) + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoOutDisable */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989VideoOutDisable +( + tmUnitSelect_t txUnit, + Bool bDisable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(bDisable > True) + + /* Set or clear frame_dis in the scaler Timebase Control 0 register + * according to bDisable + */ + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_0_W, + E_MASKREG_P00_TBG_CNTRL_0_frame_dis, + (UInt8)bDisable); + if (bDisable) + { + setState(pDis, EV_OUTDISABLE); + } + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989VideoOutSetConfig */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoOutSetConfig +( + tmUnitSelect_t txUnit, + tmbslHdmiTxSinkType_t sinkType, + tmbslHdmiTxVoutMode_t voutMode, + tmbslHdmiTxVoutPrefil_t preFilter, + tmbslHdmiTxVoutYuvBlnk_t yuvBlank, + tmbslHdmiTxVoutQrange_t quantization +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; /* Register value */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(sinkType >= HDMITX_SINK_INVALID) + RETIF_BADPARAM(voutMode >= HDMITX_VOUTMODE_INVALID) + RETIF_BADPARAM(preFilter >= HDMITX_VOUT_PREFIL_INVALID) + RETIF_BADPARAM(yuvBlank >= HDMITX_VOUT_YUV_BLNK_INVALID) + RETIF_BADPARAM(quantization >= HDMITX_VOUT_QRANGE_INVALID) + + if (sinkType == HDMITX_SINK_EDID) + { + if (pDis->EdidStatus == HDMITX_EDID_NOT_READ) + { + /* EDID has not been read so assume simplest sink */ + pDis->sinkType = HDMITX_SINK_DVI; + } + else + { + /* EDID has been read so set sink to the type that was read */ + pDis->sinkType = pDis->EdidSinkType; + } + } + else + { + /* Set demanded sink type */ + pDis->sinkType = sinkType; + } + + /* Is DVI sink required? */ + if (pDis->sinkType == HDMITX_SINK_DVI) + { + /* Mute the audio FIFO */ + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_rst_fifo, + 1); + RETIF_REG_FAIL(err) + + /* Force RGB mode for DVI sink */ + voutMode = HDMITX_VOUTMODE_RGB444; + + /* Set HDMI HDCP mode off for DVI */ + err = setHwRegisterFieldTable(pDis, &kVoutHdcpOff[0]); + RETIF_REG_FAIL(err); + + HDCP_F1; + + err = setHwRegisterField(pDis, + E_REG_P11_ENC_CNTRL_RW, + E_MASKREG_P11_ENC_CNTRL_ctl_code, + regVal); + RETIF_REG_FAIL(err) + } + else + { + /* Unmute the audio FIFO */ + err = setHwRegisterField(pDis, + E_REG_P11_AIP_CNTRL_0_RW, + E_MASKREG_P11_AIP_CNTRL_0_rst_fifo, + 0); + RETIF_REG_FAIL(err) + + /* Set HDMI HDCP mode on for HDMI */ + /* Also sets E_MASKREG_P11_ENC_CNTRL_ctl_code */ + err = setHwRegisterFieldTable(pDis, &kVoutHdcpOn[0]); + RETIF_REG_FAIL(err) + } + + /* For each parameter that is not No Change, set its register */ + if (voutMode != HDMITX_VOUTMODE_NO_CHANGE) + { + /* Save the output mode for later use by the matrix & downsampler */ + pDis->voutMode = voutMode; + } + if (preFilter < HDMITX_VOUT_PREFIL_NO_CHANGE) + { +#ifdef TMFL_HDCP_OPTIMIZED_POWER + /* + power management : + freeze/wakeup SPDIF clock + */ + err = setHwRegisterField(pDis, E_REG_FEAT_POWER_DOWN, \ + E_MASKREG_FEAT_POWER_DOWN_prefilt, \ + (preFilter == HDMITX_VOUT_PREFIL_OFF)); + RETIF_REG_FAIL(err); +#endif + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_0_W, + E_MASKREG_P00_HVF_CNTRL_0_prefil, + (UInt8)preFilter); + RETIF_REG_FAIL(err) + } + if (yuvBlank < HDMITX_VOUT_YUV_BLNK_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_yuvblk, + (UInt8)yuvBlank); + RETIF_REG_FAIL(err) + } + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoOutSetSync */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoOutSetSync +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVsSrc_t srcH, + tmbslHdmiTxVsSrc_t srcV, + tmbslHdmiTxVsSrc_t srcX, + tmbslHdmiTxVsTgl_t toggle, + tmbslHdmiTxVsOnce_t once +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 reg_idx; + struct sync_desc *sync; + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(srcH >= HDMITX_VSSRC_INVALID) + RETIF_BADPARAM(srcV >= HDMITX_VSSRC_INVALID) + RETIF_BADPARAM(srcX >= HDMITX_VSSRC_INVALID) + RETIF_BADPARAM(toggle >= HDMITX_VSTGL_INVALID) + RETIF_BADPARAM(once >= HDMITX_VSONCE_INVALID) + + /* For each parameter that is not No Change, set its register */ + if (srcH != HDMITX_VSSRC_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_1_W, + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext_hs, + (UInt8)srcH); + RETIF_REG_FAIL(err) + } + if (srcV != HDMITX_VSSRC_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_1_W, + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext_vs, + (UInt8)srcV); + RETIF_REG_FAIL(err) + } + if (srcX != HDMITX_VSSRC_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_1_W, + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext_de, + (UInt8)srcX); + RETIF_REG_FAIL(err) + } + { + /* Hs Vs polarity fix */ + /* set polarity back when VIDFORMAT_TABLE (E_REG_P00_VIDFORMAT_W) is not used */ + RETIF_BADPARAM(reg_vid_fmt(pDis->vinFmt,0,®_idx,0,&sync)); + if (EXTRA(reg_idx)) { + toggle= E_MASKREG_P00_TBG_CNTRL_1_vh_tgl & \ + (0x04 | sync[BASE(reg_idx)].v_toggle | sync[BASE(reg_idx)].h_toggle); + } + } + + + if (toggle != HDMITX_VSTGL_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_1_W, + E_MASKREG_P00_TBG_CNTRL_1_vh_tgl, + (UInt8)toggle); +/* printk("DBG toogl CNTRL1:%d\n",toggle); */ + RETIF_REG_FAIL(err) + } + if (once != HDMITX_VSONCE_NO_CHANGE) + { + /* Must be last register set */ + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_0_W, + E_MASKREG_P00_TBG_CNTRL_0_sync_once, + (UInt8)once); + RETIF_REG_FAIL(err) + } + + /* Toggle TMDS serialiser force flags - stability fix */ + err = setHwRegisterField(pDis, + E_REG_P02_BUFFER_OUT_RW, + E_MASKREG_P02_BUFFER_OUT_srl_force, + (UInt8)HDMITX_TMDSOUT_FORCED0); + RETIF_REG_FAIL(err) + err = setHwRegisterField(pDis, + E_REG_P02_BUFFER_OUT_RW, + E_MASKREG_P02_BUFFER_OUT_srl_force, + (UInt8)HDMITX_TMDSOUT_NORMAL); + RETIF_REG_FAIL(err) + + + if (once == HDMITX_VSONCE_ONCE) + { + /* Toggle output Sync Once flag for settings to take effect */ + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_0_W, + E_MASKREG_P00_TBG_CNTRL_0_sync_once, + (UInt8)HDMITX_VSONCE_EACH_FRAME); + RETIF_REG_FAIL(err) + err = setHwRegisterField(pDis, + E_REG_P00_TBG_CNTRL_0_W, + E_MASKREG_P00_TBG_CNTRL_0_sync_once, + (UInt8)HDMITX_VSONCE_ONCE); + RETIF_REG_FAIL(err) + } + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989VideoSetInOut */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989VideoSetInOut +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTx3DStructure_t structure3D, + tmbslHdmiTxScaMode_t scaModeRequest, + tmbslHdmiTxVidFmt_t voutFmt, + UInt8 uPixelRepeat, + tmbslHdmiTxMatMode_t matMode, + tmbslHdmiTxVoutDbits_t datapathBits, + tmbslHdmiTxVQR_t dviVqr +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + tmbslHdmiTxScaMode_t scaMode; /* Scaler mode */ + UInt8 reg_idx,reg_idx3D; /* Video o/p format value used for register */ + UInt8 regVal; + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(!IS_VALID_FMT(vinFmt)) + RETIF_BADPARAM(!IS_VALID_FMT(voutFmt)) + + RETIF_BADPARAM(scaModeRequest >= HDMITX_SCAMODE_INVALID) + RETIF_BADPARAM(uPixelRepeat >= HDMITX_PIXREP_INVALID) + RETIF_BADPARAM(matMode >= HDMITX_MATMODE_INVALID) + RETIF_BADPARAM(datapathBits >= HDMITX_VOUT_DBITS_INVALID) + + scaMode = HDMITX_SCAMODE_OFF; + pDis->scaMode = HDMITX_SCAMODE_OFF; + + /* Get current input format if it must not change */ + if (vinFmt == HDMITX_VFMT_NO_CHANGE) + { + RETIF(pDis->vinFmt == HDMITX_VFMT_NULL, + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + vinFmt = pDis->vinFmt; + } + else + { + pDis->vinFmt = vinFmt; + pDis->h3dFpOn = (structure3D == HDMITX_3D_FRAME_PACKING); + +#ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC + + if (IS_TV(pDis->vinFmt)) { + + err = setHwRegister(pDis, E_REG_P00_TIMER_H_W, 0); + RETIF(err != TM_OK, err); + + err = setHwRegister(pDis, E_REG_P00_NDIV_IM_W, kndiv_im[vinFmt]); + RETIF(err != TM_OK, err); + + err = setHwRegister(pDis, E_REG_P12_TX3_RW, kclk_div[vinFmt]); + RETIF(err != TM_OK, err); + + } + else { + + err = setHwRegister(pDis, E_REG_P00_TIMER_H_W, E_MASKREG_P00_TIMER_H_im_clksel); + RETIF(err != TM_OK, err); + err = setHwRegister(pDis, E_REG_P12_TX3_RW, 17); + RETIF(err != TM_OK, err); + } +#endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + + + } + + /* Get current output format if it must not change */ + if (voutFmt == HDMITX_VFMT_NO_CHANGE) + { + RETIF(pDis->voutFmt == HDMITX_VFMT_NULL, + TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + voutFmt = pDis->voutFmt; + } + else + { + pDis->voutFmt = voutFmt; + } + if (pDis->voutMode == HDMITX_VOUTMODE_RGB444) + { + if ((pDis->voutFmt >= HDMITX_VFMT_02_720x480p_60Hz) && (IS_TV(pDis->voutFmt))) + { + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_vqr, + (UInt8) HDMITX_VOUT_QRANGE_RGB_YUV); + RETIF_REG_FAIL(err) + } + else /*Format PC or VGA*/ + { + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_vqr, + (UInt8) HDMITX_VOUT_QRANGE_FS); + RETIF_REG_FAIL(err) + } + } + else + { + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_vqr, + (UInt8) HDMITX_VOUT_QRANGE_YUV); + RETIF_REG_FAIL(err); + } + + /* Set pixel repetition - sets pixelRepeatCount, used by setScalerFormat */ + err = setPixelRepeat(pDis, voutFmt, uPixelRepeat, structure3D); + RETIF(err != TM_OK, err); + + /* If scaler mode is auto then set mode based on input and output format */ + if (scaMode != HDMITX_SCAMODE_NO_CHANGE) + { + /* Set scaler clock */ + regVal = 0; + if ((pDis->pixelRepeatCount > HDMITX_PIXREP_MIN) && + (pDis->pixelRepeatCount <= HDMITX_PIXREP_MAX)) + { + regVal = 2; + } + else if (pDis->vinMode == HDMITX_VINMODE_CCIR656) + { + regVal = (UInt8)((pDis->scaMode == HDMITX_SCAMODE_ON) ? 0 : 1); + + if (pDis->pixRate == HDMITX_PIXRATE_DOUBLE) + { + regVal = 0; + } + } + + err = setHwRegisterField(pDis, + E_REG_P02_SEL_CLK_RW, + E_MASKREG_P02_SEL_CLK_sel_vrf_clk, + regVal); + RETIF_REG_FAIL(err); + + /* Look up the VIDFORMAT register format from the register format table */ + RETIF_BADPARAM(reg_vid_fmt(vinFmt,structure3D,®_idx,®_idx3D,0)); + + /* Set format register for the selected output format voutFmt */ + if (PREFETCH(reg_idx3D) && (structure3D == HDMITX_3D_FRAME_PACKING)) { + /* embedded 3D video format */ + err = setHwRegister(pDis, E_REG_P00_VIDFORMAT_W,reg_idx3D); + } + else if (PREFETCH(reg_idx) && (structure3D != HDMITX_3D_FRAME_PACKING)) { + /* embedded 2D video format */ +/* printk("DBG %s E_REG_P00_VIDFORMAT_W used\n",__func__); */ + err = setHwRegister(pDis, E_REG_P00_VIDFORMAT_W,reg_idx); + } + else { + /* see video set up using set_video() */ + } + RETIF_REG_FAIL(err); + + } + + /* Set VS and optional DE */ + err = setDeVs(pDis, voutFmt, structure3D); + RETIF(err != TM_OK, err); + + /* If matrix mode is auto then set mode based on input and output format */ + if (matMode != HDMITX_MATMODE_NO_CHANGE) + { + if (matMode == HDMITX_MATMODE_AUTO) + { + err = tmbslTDA9989MatrixSetConversion(txUnit, vinFmt, + pDis->vinMode, voutFmt, pDis->voutMode,pDis->dviVqr); + } + else + { + err = tmbslTDA9989MatrixSetMode(txUnit, HDMITX_MCNTRL_OFF, + HDMITX_MSCALE_NO_CHANGE); + } + RETIF(err != TM_OK, err) + } + + /* Set upsampler and downsampler */ + err = setSampling(pDis); + RETIF(err != TM_OK, err) + + /* Set colour component bit depth */ + if (datapathBits != HDMITX_VOUT_DBITS_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_pad, + (UInt8)datapathBits); + RETIF_REG_FAIL(err) + } + + /* Save kBypassColourProc registers before pattern goes on */ + getHwRegister(pDis, E_REG_P00_MAT_CONTRL_W, &gMatContrl[txUnit]); + getHwRegister(pDis, E_REG_P00_HVF_CNTRL_0_W, &gHvfCntrl0[txUnit]); + getHwRegister(pDis, E_REG_P00_HVF_CNTRL_1_W, &gHvfCntrl1[txUnit]); + + setState(pDis, EV_SETINOUT); + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989MatrixSetCoeffs */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989MatrixSetCoeffs +( + tmUnitSelect_t txUnit, + tmbslHdmiTxMatCoeff_t *pMatCoeff +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop index */ + UInt8 buf[HDMITX_MAT_COEFF_NUM * 2]; /* Temp buffer */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pMatCoeff == (tmbslHdmiTxMatCoeff_t *)0) + for (i = 0; i < HDMITX_MAT_COEFF_NUM; i++) + { + RETIF_BADPARAM((pMatCoeff->Coeff[i] < HDMITX_MAT_OFFSET_MIN) || + (pMatCoeff->Coeff[i] > HDMITX_MAT_OFFSET_MAX)) + } + + /* Convert signed 11 bit values from Coeff array to pairs of MSB-LSB + * register values, and write to register pairs + */ + for (i = 0; i < HDMITX_MAT_COEFF_NUM; i++) + { + /* Mask & copy MSB */ + buf[i*2] = (UInt8)(((UInt16)pMatCoeff->Coeff[i] & 0x0700) >> 8); + /* Copy LSB */ + buf[(i*2)+1] = (UInt8)((UInt16)pMatCoeff->Coeff[i] & 0x00FF); + } + err = setHwRegisters(pDis, + E_REG_P00_MAT_P11_MSB_W, + &buf[0], + HDMITX_MAT_COEFF_NUM * 2); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989MatrixSetConversion */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989MatrixSetConversion +( + tmUnitSelect_t txUnit, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTxVoutMode_t voutMode, + tmbslHdmiTxVQR_t dviVqr +) +{ + tmHdmiTxobject_t *pDis; /* Ptr to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + tmbslTDA9989Colourspace_t cspace_in; /* Input colourspaces */ + tmbslTDA9989Colourspace_t cspace_out; /* Output colourspaces */ + Int matrixIndex;/* Index into matrix preset array */ + UInt8 buf[MATRIX_PRESET_SIZE]; /* Temp buffer */ + UInt8 i; /* Loop index */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(!IS_VALID_FMT(vinFmt)) + RETIF_BADPARAM(!IS_VALID_FMT(voutFmt)) + /* NB: NO_CHANGE is not valid for this function, so limit to actual values*/ + RETIF_BADPARAM(vinMode >= HDMITX_VINMODE_NO_CHANGE) + /* NB: NO_CHANGE is not valid for this function, so limit to actual values*/ + RETIF_BADPARAM(voutMode >= HDMITX_VOUTMODE_NO_CHANGE) + + /* Since vinMode and voutMode are different types, we don't use a local + function to do this and use inline code twice */ + + + /* Calculate input colour space */ + switch (vinFmt) + { /* Catch the HD modes */ + case HDMITX_VFMT_04_1280x720p_60Hz: + case HDMITX_VFMT_05_1920x1080i_60Hz: + case HDMITX_VFMT_16_1920x1080p_60Hz: + case HDMITX_VFMT_19_1280x720p_50Hz: + case HDMITX_VFMT_20_1920x1080i_50Hz: + case HDMITX_VFMT_31_1920x1080p_50Hz: + case HDMITX_VFMT_32_1920x1080p_24Hz: + case HDMITX_VFMT_33_1920x1080p_25Hz: + case HDMITX_VFMT_34_1920x1080p_30Hz: + case HDMITX_VFMT_60_1280x720p_24Hz: + case HDMITX_VFMT_61_1280x720p_25Hz: + case HDMITX_VFMT_62_1280x720p_30Hz: + + if(vinMode == HDMITX_VINMODE_RGB444) /* RGB */ + { + cspace_in = HDMITX_CS_RGB_LIMITED; + } + else /* CCIR656, YUV444, YU422 */ + { + cspace_in = HDMITX_CS_YUV_ITU_BT709; + } + break; + default: /* Now all the SD modes */ + if(vinMode == HDMITX_VINMODE_RGB444) /* we're RGB */ + { + cspace_in = HDMITX_CS_RGB_LIMITED; + } + else /* CCIR656, YUV444, YU422 */ + { + cspace_in = HDMITX_CS_YUV_ITU_BT601; + } + break; + } + +/* } */ + + /* Calculate output colour space */ +#ifdef FORMAT_PC + if(IS_PC(voutFmt)) + { + /* Catch the PC formats */ + cspace_in = HDMITX_CS_RGB_FULL; /* PR1570 FIXED */ + cspace_out = HDMITX_CS_RGB_FULL; + } + else + { +#endif + switch (voutFmt) + { /* Catch the HD modes */ + case HDMITX_VFMT_04_1280x720p_60Hz: + case HDMITX_VFMT_05_1920x1080i_60Hz: + case HDMITX_VFMT_16_1920x1080p_60Hz: + case HDMITX_VFMT_19_1280x720p_50Hz: + case HDMITX_VFMT_20_1920x1080i_50Hz: + case HDMITX_VFMT_31_1920x1080p_50Hz: + case HDMITX_VFMT_32_1920x1080p_24Hz: + case HDMITX_VFMT_33_1920x1080p_25Hz: + case HDMITX_VFMT_34_1920x1080p_30Hz: + case HDMITX_VFMT_60_1280x720p_24Hz: + case HDMITX_VFMT_61_1280x720p_25Hz: + case HDMITX_VFMT_62_1280x720p_30Hz: + + if(voutMode == HDMITX_VOUTMODE_RGB444) /* RGB */ + { + cspace_out = HDMITX_CS_RGB_LIMITED; + } + else /* YUV444 or YUV422 */ + { + cspace_out = HDMITX_CS_YUV_ITU_BT709; + } + break; + default: /* Now all the SD modes */ + if(voutMode == HDMITX_VOUTMODE_RGB444) /* RGB */ + { + cspace_out = HDMITX_CS_RGB_LIMITED; + } + else /* YUV444 or YUV422 */ + { + cspace_out = HDMITX_CS_YUV_ITU_BT601; + } + break; + } +#ifdef FORMAT_PC + } +#endif + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + /* + power management : + freeze/wakeup color space conversion clock + */ + err = setHwRegisterField(pDis, E_REG_FEAT_POWER_DOWN, \ + E_MASKREG_FEAT_POWER_DOWN_csc, \ + (cspace_in == cspace_out)); + RETIF_REG_FAIL(err); +#endif + + if (cspace_in == cspace_out) + { + /* Switch off colour matrix by setting bypass flag */ + err = setHwRegisterField(pDis, + E_REG_P00_MAT_CONTRL_W, + E_MASKREG_P00_MAT_CONTRL_mat_bp, + 1); + } + else + { + /* Load appropriate values into matrix - we have preset blocks of + * 31 register vales in a table, just need to work out which set to use + */ + matrixIndex = kMatrixIndex[cspace_in][cspace_out]; + + /* Set the first block byte separately, as it is shadowed and can't + * be set by setHwRegisters */ + err = setHwRegister(pDis, + E_REG_P00_MAT_CONTRL_W, + kMatrixPreset[matrixIndex][0]); + RETIF_REG_FAIL(err) + + for (i = 0; i < MATRIX_PRESET_SIZE; i++) + { + buf[i] = kMatrixPreset[matrixIndex][i]; + } + + /* Set the rest of the block */ + err = setHwRegisters(pDis, + E_REG_P00_MAT_OI1_MSB_W, + &buf[1], + MATRIX_PRESET_SIZE - 1); + } + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989MatrixSetInputOffset */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989MatrixSetInputOffset +( + tmUnitSelect_t txUnit, + tmbslHdmiTxMatOffset_t *pMatOffset +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop index */ + UInt8 buf[HDMITX_MAT_OFFSET_NUM * 2]; /* Temp buffer */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pMatOffset == (tmbslHdmiTxMatOffset_t *)0) + for (i = 0; i < HDMITX_MAT_OFFSET_NUM; i++) + { + RETIF_BADPARAM((pMatOffset->Offset[i] < HDMITX_MAT_OFFSET_MIN) || + (pMatOffset->Offset[i] > HDMITX_MAT_OFFSET_MAX)) + } + + /* Convert signed 11 bit values from Offset array to pairs of MSB-LSB + * register values, and write to register pairs + */ + for (i = 0; i < HDMITX_MAT_OFFSET_NUM; i++) + { + /* Mask & copy MSB */ + buf[i*2] = (UInt8)(((UInt16)pMatOffset->Offset[i] & 0x0700) >> 8); + /* Copy LSB */ + buf[(i*2)+1] = (UInt8)((UInt16)pMatOffset->Offset[i] & 0x00FF); + } + err = setHwRegisters(pDis, + E_REG_P00_MAT_OI1_MSB_W, + &buf[0], + HDMITX_MAT_OFFSET_NUM * 2); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989MatrixSetMode */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989MatrixSetMode +( + tmUnitSelect_t txUnit, + tmbslHdmiTxmCntrl_t mControl, + tmbslHdmiTxmScale_t mScale +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM((mControl > HDMITX_MCNTRL_MAX) || + (mScale > HDMITX_MSCALE_MAX)) + + /* For each value that is not NoChange, update the appropriate register */ + if (mControl != HDMITX_MCNTRL_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_MAT_CONTRL_W, + E_MASKREG_P00_MAT_CONTRL_mat_bp, + (UInt8)mControl); + RETIF_REG_FAIL(err) + } + + if (mScale != HDMITX_MSCALE_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_MAT_CONTRL_W, + E_MASKREG_P00_MAT_CONTRL_mat_sc, + (UInt8)mScale); + RETIF_REG_FAIL(err) + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989MatrixSetOutputOffset */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989MatrixSetOutputOffset +( + tmUnitSelect_t txUnit, + tmbslHdmiTxMatOffset_t *pMatOffset +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop index */ + UInt8 buf[HDMITX_MAT_OFFSET_NUM * 2]; /* Temp buffer */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM(pMatOffset == (tmbslHdmiTxMatOffset_t *)0) + for (i = 0; i < HDMITX_MAT_OFFSET_NUM; i++) + { + RETIF_BADPARAM((pMatOffset->Offset[i] < HDMITX_MAT_OFFSET_MIN) || + (pMatOffset->Offset[i] > HDMITX_MAT_OFFSET_MAX)) + } + + /* Convert signed 11 bit values from Offset array to pairs of MSB-LSB + * register values, and write to register pairs + */ + for (i = 0; i < HDMITX_MAT_OFFSET_NUM; i++) + { + /* Mask & copy MSB */ + buf[i*2] = (UInt8)(((UInt16)pMatOffset->Offset[i] & 0x0700) >> 8); + /* Copy LSB */ + buf[(i*2)+1] = (UInt8)((UInt16)pMatOffset->Offset[i] & 0x00FF); + } + err = setHwRegisters(pDis, + E_REG_P00_MAT_OO1_MSB_W, + &buf[0], + HDMITX_MAT_OFFSET_NUM * 2); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989PktSetAclkRecovery */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989PktSetAclkRecovery +( + tmUnitSelect_t txUnit, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + /* Write the ACR packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_acr, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetAcp */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetAcp +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + UInt8 uAcpType, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[3]; /* Temp buffer to hold header bytes */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Only supported for device N4 or later */ + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM(byteCnt > HDMITX_PKT_DATA_BYTE_CNT) + RETIF(byteCnt == 0, TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + + /* Data to change, start by clearing ACP packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_acp, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare ACP header */ + buf[0] = 0x04; /* ACP packet */ + buf[1] = uAcpType; + buf[2] = 0; /* Reserved [HDMI 1.2] */ + + + /* Write 3 header bytes to registers */ + err = setHwRegisters(pDis, + E_REG_P11_ACP_HB0_RW, + &buf[0], + 3); + RETIF_REG_FAIL(err) + + /* Write "byteCnt" bytes of data to registers */ + err = setHwRegisters(pDis, + E_REG_P11_ACP_PB0_RW, + &pPkt->dataByte[0], + (UInt16)byteCnt); + RETIF_REG_FAIL(err) + } + + /* Write the ACP packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_acp, + (UInt8)bEnable); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989PktSetAudioInfoframe */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetAudioInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktAif_t *pPkt, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[9]; /* Temp buffer to hold header/packet bytes */ + UInt16 bufReg; /* Base register used for writing InfoFrame*/ + UInt16 flagReg;/* Flag register to be used */ + UInt8 flagMask;/* Mask used for writing flag register */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM(pPkt->CodingType > 0x0F) + RETIF_BADPARAM(pPkt->ChannelCount > 0x07) + RETIF_BADPARAM(pPkt->SampleFreq > 0x07) + RETIF_BADPARAM(pPkt->SampleSize > 0x03) + /* No need to check ChannelAlloc - all values are allowed */ + RETIF_BADPARAM((pPkt->DownMixInhibit != True) && + (pPkt->DownMixInhibit != False)) + RETIF_BADPARAM(pPkt->LevelShift > 0x0F) + } + + /* Only supported for device N4 or later */ + + /* We're using n4 or later, use IF4 buffer for Audio InfoFrame */ + bufReg = E_REG_P10_IF4_HB0_RW; + flagReg = E_REG_P11_DIP_IF_FLAGS_RW; + flagMask = E_MASKREG_P11_DIP_IF_FLAGS_if4; + + if(pPkt != Null) + { + /* Data to change, start by clearing AIF packet insertion flag */ + err = setHwRegisterField(pDis, + flagReg, + flagMask, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare AIF header */ + buf[0] = 0x84; /* Audio InfoFrame */ + buf[1] = 0x01; /* Version 1 [HDMI 1.2] */ + buf[2] = 0x0A; /* Length [HDMI 1.2] */ + + /* Prepare AIF packet (byte numbers offset by 3) */ + buf[0+3] = 0; /* Preset checksum to zero so calculation works! */ + buf[1+3] = ((pPkt->CodingType & 0x0F) << 4) | + (pPkt->ChannelCount & 0x07); /* CT3-0, CC2-0 */ + buf[2+3] = ((pPkt->SampleFreq & 0x07) << 2) | + (pPkt->SampleSize & 0x03); /* SF2-0, SS1-0 */ + buf[3+3] = 0; /* [HDMI 1.2] */ + buf[4+3] = pPkt->ChannelAlloc; /* CA7-0 */ + buf[5+3] = ((pPkt->LevelShift & 0x0F) << 3); /* LS3-0 */ + if(pPkt->DownMixInhibit == True) + { + buf[5+3] += 0x80; /* DMI bit */ + } + + /* Calculate checksum - this is worked out on "Length" bytes of the + * packet, the checksum (which we've preset to zero), and the three + * header bytes. We exclude bytes PB6 to PB10 (which we + * are not writing) since they are zero. + */ + buf[0+3] = calculateChecksum(&buf[0], 0x0A+1+3-5); + + /* Write header and packet bytes in one operation */ + err = setHwRegisters(pDis, + bufReg, + &buf[0], + 9); + RETIF_REG_FAIL(err) + } + + /* Write AIF packet insertion flag */ + err = setHwRegisterField(pDis, + flagReg, + flagMask, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetGeneralCntrl */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989PktSetGeneralCntrl +( + tmUnitSelect_t txUnit, + tmbslHdmiTxaMute_t *paMute, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(paMute != Null) + { + RETIF_BADPARAM((*paMute != HDMITX_AMUTE_OFF) && (*paMute != HDMITX_AMUTE_ON)) + + if (*paMute == HDMITX_AMUTE_ON) + { + err = setHwRegister(pDis, E_REG_P11_GC_AVMUTE_RW, 0x02); + RETIF_REG_FAIL(err) + } + else + { + err = setHwRegister(pDis, E_REG_P11_GC_AVMUTE_RW, 0x01); + RETIF_REG_FAIL(err) + } + } + + /* Set or clear GC packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_gc, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetIsrc1 */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetIsrc1 +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + Bool bIsrcCont, + Bool bIsrcValid, + UInt8 uIsrcStatus, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[3]; /* Temp buffer to hold header bytes */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Only supported for device N4 or later */ + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM((bIsrcCont != True) && (bIsrcCont != False)) + RETIF_BADPARAM((bIsrcValid != True) && (bIsrcValid != False)) + RETIF_BADPARAM(uIsrcStatus > 7) /* 3 bits */ + RETIF_BADPARAM(byteCnt > HDMITX_PKT_DATA_BYTE_CNT) + RETIF(byteCnt == 0, TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + + /* Data to change, start by clearing ISRC1 packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_isrc1, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare ISRC1 header */ + buf[0] = 0x05; /* ISRC1 packet */ + buf[1] = (uIsrcStatus & 0x07); + if(bIsrcValid == True) + { + buf[1] += 0x40; + } + if(bIsrcCont == True) + { + buf[1] += 0x80; + } + buf[2] = 0; /* Reserved [HDMI 1.2] */ + + /* Write 3 header bytes to registers */ + err = setHwRegisters(pDis, + E_REG_P11_ISRC1_HB0_RW, + &buf[0], + 3); + RETIF_REG_FAIL(err) + + /* Write "byteCnt" bytes of data to registers */ + err = setHwRegisters(pDis, + E_REG_P11_ISRC1_PB0_RW, + &pPkt->dataByte[0], + (UInt16)byteCnt); + RETIF_REG_FAIL(err) + } + + /* Write the ISRC1 packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_isrc1, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetIsrc2 */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetIsrc2 +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[3]; /* Temp buffer to hold header bytes */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Only supported for device N4 or later */ + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM(byteCnt > HDMITX_PKT_DATA_BYTE_CNT) + RETIF(byteCnt == 0, TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + + /* Data to change, start by clearing ISRC2 packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_isrc2, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare ISRC2 header */ + buf[0] = 0x06; /* ISRC2 packet */ + buf[1] = 0; /* Reserved [HDMI 1.2] */ + buf[2] = 0; /* Reserved [HDMI 1.2] */ + + /* Write 3 header bytes to registers */ + err = setHwRegisters(pDis, + E_REG_P11_ISRC2_HB0_RW, + &buf[0], + 3); + RETIF_REG_FAIL(err) + + /* Write "byteCnt" bytes of data to registers */ + err = setHwRegisters(pDis, + E_REG_P11_ISRC2_PB0_RW, + &pPkt->dataByte[0], + (UInt16)byteCnt); + RETIF_REG_FAIL(err) + } + + /* Write the ISRC2 packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_isrc2, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetMpegInfoframe */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetMpegInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktMpeg_t *pPkt, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[9]; /* Temp buffer to hold packet */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Only supported for device N4 or later */ + + /* Check remaining parameter(s) */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM((pPkt->bFieldRepeat != True) && (pPkt->bFieldRepeat != False)) + RETIF_BADPARAM(pPkt->frameType >= HDMITX_MPEG_FRAME_INVALID) + + /* Data to change, start by clearing MPEG packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if5, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare MPEG header */ + buf[0] = 0x85; /* MPEG Source InfoFrame */ + buf[1] = 0x01; /* Version 1 [HDMI 1.2] */ + buf[2] = 0x0A; /* Length [HDMI 1.2] */ + + /* Prepare MPEG packet (byte numbers offset by 3) */ + buf[0+3] = 0; /* Preset checksum to zero so calculation works! */ + buf[1+3] = (UInt8)(pPkt->bitRate & 0x000000FF); + buf[2+3] = (UInt8)((pPkt->bitRate & 0x0000FF00) >> 8); + buf[3+3] = (UInt8)((pPkt->bitRate & 0x00FF0000) >> 16); + buf[4+3] = (UInt8)((pPkt->bitRate & 0xFF000000) >> 24); + buf[5+3] = pPkt->frameType; /* MF1-0 */ + if(pPkt->bFieldRepeat == True) + { + buf[5+3] += 0x10; /* FR0 bit */ + } + + /* Calculate checksum - this is worked out on "Length" bytes of the + * packet, the checksum (which we've preset to zero), and the three + * header bytes. We exclude bytes PB6 to PB10 (which we + * are not writing) since they are zero. + */ + buf[0+3] = calculateChecksum(&buf[0], 0x0A+1+3-5); + + /* Write header and packet bytes in one operation */ + err = setHwRegisters(pDis, + E_REG_P10_IF5_HB0_RW, + &buf[0], + 9); + RETIF_REG_FAIL(err) + } + + /* Write the MPEG packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if5, + (UInt8)bEnable); + return err; +} +/*============================================================================*/ +/* tmbslTDA9989PktSetNullInsert */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetNullInsert +( + tmUnitSelect_t txUnit, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameter(s) */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + /* Set or clear FORCE_NULL packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_force_null, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetNullSingle */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetNullSingle +( + tmUnitSelect_t txUnit +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Set NULL packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_FLAGS_RW, + E_MASKREG_P11_DIP_FLAGS_null, + 0x01); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetSpdInfoframe */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetSpdInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktSpd_t *pPkt, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[29];/* Temp buffer to hold packet */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Only supported for device N4 or later */ + + /* Check remaining parameter(s) */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM(pPkt->SourceDevInfo >= HDMITX_SPD_INFO_INVALID) + + /* Data to change, start by clearing SPD packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if3, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare SPD header */ + buf[0] = 0x83; /* Source. Product Descriptor InfoFrame */ + buf[1] = 0x01; /* Version 1 [CEA 861B] */ + buf[2] = 0x19; /* Length [HDMI 1.2] */ + + /* Prepare SPD packet (byte numbers offset by 3) */ + buf[0+3] = 0; /* Preset checksum to zero so calculation works! */ + lmemcpy(&buf[1+3], &pPkt->VendorName[0], HDMI_TX_SPD_VENDOR_SIZE); + lmemcpy(&buf[1+3+HDMI_TX_SPD_VENDOR_SIZE], &pPkt->ProdDescr[0], + HDMI_TX_SPD_DESCR_SIZE); + + + buf[HDMI_TX_SPD_LENGTH+3] = pPkt->SourceDevInfo; + + /* Calculate checksum - this is worked out on "Length" bytes of the + * packet, the checksum (which we've preset to zero), and the three + * header bytes. + */ + buf[0+3] = calculateChecksum(&buf[0], HDMI_TX_SPD_LENGTH+1+3); + + /* Write header and packet bytes in one operation */ + err = setHwRegisters(pDis, + E_REG_P10_IF3_HB0_RW, + &buf[0], + 29); + RETIF_REG_FAIL(err) + } + + /* Write the SPD packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if3, + (UInt8)bEnable); + return err; +} + + +/*============================================================================*/ +/* tmbslTDA9989PktSetVideoInfoframe */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PktSetVideoInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktVif_t *pPkt, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[17];/* Temp buffer to hold header/packet bytes */ + UInt16 bufReg; /* Base register used for writing InfoFrame*/ + UInt16 flagReg;/* Flag register to be used */ + UInt8 flagMask;/* Mask used for writing flag register */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + RETIF_BADPARAM(pPkt->Colour > 0x03) + RETIF_BADPARAM((pPkt->ActiveInfo != True) && (pPkt->ActiveInfo != False)) + RETIF_BADPARAM(pPkt->BarInfo > 0x03) + RETIF_BADPARAM(pPkt->ScanInfo > 0x03) + RETIF_BADPARAM(pPkt->Colorimetry > 0x03) + RETIF_BADPARAM(pPkt->PictureAspectRatio > 0x03) + RETIF_BADPARAM(pPkt->ActiveFormatRatio > 0x0F) + RETIF_BADPARAM(pPkt->Scaling > 0x03) + RETIF_BADPARAM(pPkt->VidFormat > 0x7F) + RETIF_BADPARAM(pPkt->PixelRepeat > 0x0F) + } + + /* Only supported for device N4 or later */ + + /* We're using n4 or later, use IF2 buffer for Video InfoFrame */ + bufReg = E_REG_P10_IF2_HB0_RW; + flagReg = E_REG_P11_DIP_IF_FLAGS_RW; + flagMask = E_MASKREG_P11_DIP_IF_FLAGS_if2; + + if(pPkt != Null) + { + /* Data to change, start by clearing VIF packet insertion flag */ + err = setHwRegisterField(pDis, + flagReg, + flagMask, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare VIF header */ + buf[0] = 0x82; /* Video InfoFrame */ + buf[1] = 0x02; /* Version 2 [HDMI 1.2] */ + buf[2] = 0x0D; /* Length [HDMI 1.2] */ + + /* Prepare VIF packet (byte numbers offset by 3) */ + buf[0+3] = 0; /* Preset checksum to zero so calculation works! */ + buf[1+3] = ((pPkt->Colour & 0x03) << 5) | /* Y1-0, B1-0,S1-0 */ + ((pPkt->BarInfo & 0x03) << 2) | + (pPkt->ScanInfo & 0x03); + if(pPkt->ActiveInfo == True) + { + buf[1+3] += 0x10; /* AI bit */ + } + buf[2+3] = ((pPkt->Colorimetry & 0x03) << 6) | /* C1-0, M1-0, R3-0 */ + ((pPkt->PictureAspectRatio & 0x03) << 4) | + (pPkt->ActiveFormatRatio & 0x0F); + buf[3+3] = (pPkt->Scaling & 0x03); /* SC1-0 */ /* [HDMI 1.2] */ + buf[4+3] = (pPkt->VidFormat & 0x7F); /* VIC6-0 */ + buf[5+3] = (pPkt->PixelRepeat & 0x0F); /* PR3-0 */ + buf[6+3] = (UInt8)(pPkt->EndTopBarLine & 0x00FF); + buf[7+3] = (UInt8)((pPkt->EndTopBarLine & 0xFF00) >> 8); + buf[8+3] = (UInt8)(pPkt->StartBottomBarLine & 0x00FF); + buf[9+3] = (UInt8)((pPkt->StartBottomBarLine & 0xFF00) >> 8); + buf[10+3] = (UInt8)(pPkt->EndLeftBarPixel & 0x00FF); + buf[11+3] = (UInt8)((pPkt->EndLeftBarPixel & 0xFF00) >> 8); + buf[12+3] = (UInt8)(pPkt->StartRightBarPixel & 0x00FF); + buf[13+3] = (UInt8)((pPkt->StartRightBarPixel & 0xFF00) >> 8); + + /* Calculate checksum - this is worked out on "Length" bytes of the + * packet, the checksum (which we've preset to zero), and the three + * header bytes. + */ + buf[0+3] = calculateChecksum(&buf[0], 0x0D+1+3); + + /* Write header and packet bytes in one operation */ + err = setHwRegisters(pDis, + bufReg, + &buf[0], + 17); + RETIF_REG_FAIL(err) + } + + /* Write VIF packet insertion flag */ + err = setHwRegisterField(pDis, + flagReg, + flagMask, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetRawVideoInfoframe */ +/*============================================================================*/ +tmErrorCode_t tmbslTDA9989PktSetRawVideoInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktRawAvi_t *pPkt, + Bool bEnable +) +{ + + + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + /* use IF2 buffer */ + if(pPkt != Null) + { + /* Data to change, start by clearing VIF packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if2, + 0x00); + RETIF_REG_FAIL(err) + + + /* Write VIF raw header bytes 0-2 */ + err = setHwRegisters(pDis, + E_REG_P10_IF2_HB0_RW, + pPkt->HB, + 3); + RETIF_REG_FAIL(err) + + /* Write VIF raw payload bytes 0-27 */ + err = setHwRegisters(pDis, + E_REG_P10_IF2_PB0_RW, + pPkt->PB, + 28); + + RETIF_REG_FAIL(err) + + } + + /* Write VIF packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if2, + (UInt8)bEnable); + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PktSetVsInfoframe */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989PktSetVsInfoframe +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPkt_t *pPkt, + UInt byteCnt, + UInt8 uVersion, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 buf[31];/* Temp buffer to hold packet */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED error if the + * sinkType is not HDMI + */ + RETIF(pDis->sinkType != HDMITX_SINK_HDMI, + TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + + /* Only supported for device N4 or later */ + + /* Check remaining parameter(s) - NULL pointer allowed */ + RETIF_BADPARAM((bEnable != True) && (bEnable != False)) + + if(pPkt != Null) + { + /* Pointer to structure provided so check parameters */ + /* InfoFrame needs a checksum, so 1 usable byte less than full pkt */ + RETIF_BADPARAM(byteCnt > (HDMITX_PKT_DATA_BYTE_CNT-1)) + RETIF(byteCnt == 0, TMBSL_ERR_HDMI_INCONSISTENT_PARAMS) + + /* Data to change, start by clearing VS_IF packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if1, + 0x00); + RETIF_REG_FAIL(err) + + /* Prepare VS_IF header */ + lmemset(&buf[0], 0, 31); /* Clear buffer as user may vary length used */ + buf[0] = 0x81; /* Vendor Specific InfoFrame */ + buf[1] = uVersion; /* Vendor defined version */ + buf[2] = (UInt8)byteCnt; /* Length [HDMI 1.2] */ + + /* Prepare VS_IF packet (byte numbers offset by 3) */ + buf[0+3] = 0; /* Preset checksum to zero so calculation works! */ + lmemcpy(&buf[1+3], &pPkt->dataByte[0], byteCnt); + + /* Calculate checksum - this is worked out on "Length" bytes of the + * packet, the checksum (which we've preset to zero), and the three + * header bytes. + */ + buf[0+3] = calculateChecksum(&buf[0], byteCnt+1+3); + + /* Write header and packet bytes in one operation - write entire + * buffer even though we may not be using it all so that zeros + * are placed in the unused registers. */ + err = setHwRegisters(pDis, + E_REG_P10_IF1_HB0_RW, + &buf[0], + 31); + RETIF_REG_FAIL(err) + } + + /* Write the VS_IF packet insertion flag */ + err = setHwRegisterField(pDis, + E_REG_P11_DIP_IF_FLAGS_RW, + E_MASKREG_P11_DIP_IF_FLAGS_if1, + (UInt8)bEnable); + return err; +} + +/*============================================================================*/ +/* STATIC FUNCTIONS */ +/*============================================================================*/ + +/*===============================================================================*/ +/* reg_vid_fmt(): get register index for normal and 3D, plus sync table */ +/*===============================================================================*/ +static UInt8 reg_vid_fmt(tmbslHdmiTxVidFmt_t fmt, \ + tmbslHdmiTx3DStructure_t structure3D, \ + UInt8 *idx, \ + UInt8 *idx3d, \ + struct sync_desc **sync) +{ + struct vic2reg *hash; + int i; + + (*idx)=REGVFMT_INVALID; + if (idx3d) (*idx3d)=REGVFMT_INVALID; + if (IS_TV(fmt)) { + VIC2REG_LOOP(vic2reg_TV,idx); + if (idx3d) { + if (structure3D == HDMITX_3D_FRAME_PACKING) { + /* any 3D FP prefetch ? */ + VIC2REG_LOOP(vic2reg_TV_FP,idx3d); + } + } + } +#ifdef FORMAT_PC + else { + VIC2REG_LOOP(vic2reg_PC,idx); + } +#endif + /* PR1570 FIXED */ + if (sync) { + if PREFETCH(*idx) { + *sync = (struct sync_desc *)ref_sync; + } +#ifdef FORMAT_PC + else if PCFORMAT(*idx) { + *sync = (struct sync_desc *)ref_sync_PC; + *idx = *idx - E_REGVFMT_MAX_EXTRA; + } +#endif //FORMAT_PC + else { + *sync = (struct sync_desc *)ref_sync_extra; + } + } + return ((*idx)==REGVFMT_INVALID); +} + +/*===============================================================================*/ +/* pix_clk(): get pixel clock */ +/*===============================================================================*/ +UInt8 pix_clk(tmbslHdmiTxVidFmt_t fmt, tmbslHdmiTxVfreq_t freq, UInt8 *pclk) +{ + + (*pclk)=REGVFMT_INVALID; +#ifdef FORMAT_PC + if (IS_PC(fmt)) { + (*pclk)=kVfmtToPixClk_PC[fmt - HDMITX_VFMT_PC_MIN]; + } +#endif + if (IS_TV(fmt)) { + (*pclk)=kVfmtToPixClk_TV[fmt - HDMITX_VFMT_TV_MIN][freq]; + } + return ((*pclk)==REGVFMT_INVALID); +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(pix_clk); +#endif + +/*===============================================================================*/ +/* calculateVidFmtIndex(): Calculate table index according to video format value */ +/*===============================================================================*/ +tmbslHdmiTxVidFmt_t calculateVidFmtIndex(tmbslHdmiTxVidFmt_t vidFmt) +{ + tmbslHdmiTxVidFmt_t vidFmtIndex = vidFmt; + + /* Hanlde VIC or table index discontinuity */ + if((vidFmt >= HDMITX_VFMT_60_1280x720p_24Hz) && (vidFmt <= HDMITX_VFMT_62_1280x720p_30Hz)) + { + vidFmtIndex = (tmbslHdmiTxVidFmt_t)(HDMITX_VFMT_INDEX_60_1280x720p_24Hz + (vidFmt - HDMITX_VFMT_60_1280x720p_24Hz)); + } +#ifdef FORMAT_PC + else if (IS_PC(vidFmt)) + { + vidFmtIndex = (tmbslHdmiTxVidFmt_t)(HDMITX_VFMT_TV_NUM + (vidFmt - HDMITX_VFMT_PC_MIN)); + } +#endif /* FORMAT_PC */ + return(vidFmtIndex); +} + +/*============================================================================*/ +/* setDeVs */ +/*============================================================================*/ +static tmErrorCode_t +setDeVs +( + tmHdmiTxobject_t *pDis, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTx3DStructure_t structure3D +) +{ + tmErrorCode_t err; /* Error code */ + UInt16 vsPixStrt2; /* VS pixel number for start pulse in field 2 */ + UInt8 reg_idx; /* Video format value used for register */ + struct sync_desc *sync; + + /* IF voutFmt = No Change THEN return TM_OK */ + RETIF(voutFmt == HDMITX_VFMT_NO_CHANGE, TM_OK); + + /* Quit if the output format does not map to the register format */ + RETIF_BADPARAM(reg_vid_fmt(voutFmt,structure3D,®_idx,0,&sync)); + + /* DE_START & DE_STOP no longer set because N2 device no longer supported */ + + /* Adjust VS_PIX_STRT_2 and VS_PIX_END_2 for interlaced output formats */ + vsPixStrt2 = sync[BASE(reg_idx)].Vs2; + err = setHwRegisterMsbLsb(pDis, E_REG_P00_VS_PIX_STRT_2_MSB_W, vsPixStrt2); + RETIF_REG_FAIL(err) + err = setHwRegisterMsbLsb(pDis, E_REG_P00_VS_PIX_END_2_MSB_W, vsPixStrt2); +/* printk("DBG %s vs2:%d\n",__func__,vsPixStrt2); */ + + return err; +} + +/*============================================================================*/ +/* setPixelRepeat */ +/*============================================================================*/ +static tmErrorCode_t +setPixelRepeat +( + tmHdmiTxobject_t *pDis, + tmbslHdmiTxVidFmt_t voutFmt, + UInt8 uPixelRepeat, + tmbslHdmiTx3DStructure_t structure3D +) +{ + tmErrorCode_t err = TM_OK; /* Error code */ + + RETIF(voutFmt == HDMITX_VFMT_NO_CHANGE, TM_OK) + + err = InputConfig(pDis, + HDMITX_VINMODE_NO_CHANGE, + HDMITX_PIXEDGE_NO_CHANGE, + HDMITX_PIXRATE_NO_CHANGE, + HDMITX_UPSAMPLE_NO_CHANGE, + uPixelRepeat, + voutFmt, + structure3D); + + return err; +} +/*============================================================================*/ +/* setSampling */ +/*============================================================================*/ +static tmErrorCode_t +setSampling +( + tmHdmiTxobject_t *pDis +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 upSample; /* 1 if upsampler must be enabled */ + UInt8 downSample; /* 1 if downsampler must be enabled */ + UInt8 matrixBypass; /*>0 if matrix has been bypassed */ + + if ((pDis->vinMode == HDMITX_VINMODE_YUV422) + || (pDis->vinMode == HDMITX_VINMODE_CCIR656)) + { + if (pDis->voutMode == HDMITX_VOUTMODE_YUV422) + { + /* Input 422/656, output 422 */ + err = getHwRegister(pDis, E_REG_P00_MAT_CONTRL_W, &matrixBypass); + RETIF_REG_FAIL(err) + matrixBypass &= E_MASKREG_P00_MAT_CONTRL_mat_bp; + /* Has matrix been bypassed? */ + if (matrixBypass > 0) + { + upSample = 0; + downSample = 0; + } + else + { + upSample = 1; + downSample = 1; + } + } + else + { + /* Input 422/656, output not 422 */ + upSample = 1; + downSample = 0; + } + } + else + { + if (pDis->voutMode == HDMITX_VOUTMODE_YUV422) + { + /* Input not 422/656, output 422 */ + upSample = 0; + downSample = 1; + } + else + { + /* Input not 422/656, output not 422 */ + upSample = 0; + downSample = 0; + } + } + + /* Check upsample mode saved by tmbslTDA9989VideoInSetConfig */ + if (pDis->upsampleMode != HDMITX_UPSAMPLE_AUTO) + { + /* Saved upsample mode overrides local one */ + upSample = pDis->upsampleMode; + } + + /* Set upsampler */ + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_0_W, + E_MASKREG_P00_HVF_CNTRL_0_intpol, + upSample); + RETIF_REG_FAIL(err) + + /* Set downsampler */ + err = setHwRegisterField(pDis, + E_REG_P00_HVF_CNTRL_1_W, + E_MASKREG_P00_HVF_CNTRL_1_for, + downSample); + return err; +} + + +/*============================================================================*/ +/* calculateChecksum - returns the byte needed to yield a checksum of zero */ +/*============================================================================*/ +static UInt8 +calculateChecksum +( + UInt8 *pData, /* Pointer to checksum data */ + Int numBytes /* Number of bytes over which to calculate */ + ) +{ + UInt8 checksum = 0; /* Working checksum calculation */ + UInt8 result = 0; /* Value to be returned */ + Int i; + + if((pData != Null) && (numBytes > 0)) + { + for (i = 0; i < numBytes; i++) + { + checksum = checksum + (*(pData + i)); + } + result = (255 - checksum) + 1; + } + return result; /* returns 0 in the case of null ptr or 0 bytes */ +} + +/*============================================================================*/ +/* InputConfig */ +/*============================================================================*/ +static tmErrorCode_t +InputConfig +( + tmHdmiTxobject_t *pDis, + tmbslHdmiTxVinMode_t vinMode, + tmbslHdmiTxPixEdge_t sampleEdge, + tmbslHdmiTxPixRate_t pixRate, + tmbslHdmiTxUpsampleMode_t upsampleMode, + UInt8 uPixelRepeat, + tmbslHdmiTxVidFmt_t voutFmt, + tmbslHdmiTx3DStructure_t structure3D +) +{ + tmErrorCode_t err = TM_OK; /* Error code */ + UInt8 reg_idx,reg_idx3D; /* Video format value used for register */ + UInt8 ssd=0; /* Packed srl, scg and de */ + struct sync_desc *sync; + + /****************Check Parameters********************/ + /* Check parameters */ + RETIF_BADPARAM(vinMode >= HDMITX_VINMODE_INVALID); + RETIF_BADPARAM(sampleEdge >= HDMITX_PIXEDGE_INVALID); + RETIF_BADPARAM(pixRate >= HDMITX_PIXRATE_INVALID); + RETIF_BADPARAM(upsampleMode >= HDMITX_UPSAMPLE_INVALID); + + RETIF(voutFmt == HDMITX_VFMT_NO_CHANGE, TM_OK); + RETIF_BADPARAM(!IS_VALID_FMT(voutFmt)); + + /* Quit if the output format does not map to the register format */ + RETIF_BADPARAM(reg_vid_fmt(voutFmt,structure3D,®_idx,®_idx3D,&sync)); + +/****************Set the VinMode************************ +- P00_VIP_CNTRL_4_ccir656 +- P00_HVF_CNTRL_1_semi_planar +- P02_PLL_SERIAL_3_srl_ccir +- P02_SEL_CLK_sel_vrf_clk +*/ + if (vinMode != HDMITX_VINMODE_NO_CHANGE) + { + pDis->vinMode = vinMode; + } +/****************Set the sampleEdge*********************** +-P00_VIP_CNTRL_3_edge*/ + + if (sampleEdge != HDMITX_PIXEDGE_NO_CHANGE) + { + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_3_W, + E_MASKREG_P00_VIP_CNTRL_3_edge, + (UInt8)sampleEdge); + RETIF_REG_FAIL(err) + } + +/****************Set the Pixel Rate*********************** +-P02_CCIR_DIV_refdiv2 +-P02_P02_PLL_SCG2_selpllclkin +-P02_P02_PLL_DE_bypass_pllde +-P00_VIP_CNTRL_4_656_alt */ + + if (pixRate != HDMITX_PIXRATE_NO_CHANGE) + { + pDis->pixRate = pixRate; + } + + if ((pixRate != HDMITX_PIXRATE_NO_CHANGE)||(vinMode != HDMITX_VINMODE_NO_CHANGE)) + { + switch (pDis->vinMode) + { + case HDMITX_VINMODE_RGB444: + case HDMITX_VINMODE_YUV444: + + if (pDis->pixRate == HDMITX_PIXRATE_SINGLE) + { + err = setHwRegisterFieldTable(pDis, &kVinMode444[0]); + + RETIF_REG_FAIL(err) + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 0); + RETIF_REG_FAIL(err) + + } + else if (pDis->pixRate == HDMITX_PIXRATE_SINGLE_REPEATED) + { + err = setHwRegisterFieldTable(pDis, &kVinMode444[0]); + + RETIF_REG_FAIL(err) + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 0); + RETIF_REG_FAIL(err) + + } + else + { + /* Not supported*/ + } + break; + case HDMITX_VINMODE_YUV422: + if (pDis->pixRate == HDMITX_PIXRATE_SINGLE) + { + err = setHwRegisterFieldTable(pDis, &kVinModeYUV422[0]); + + RETIF_REG_FAIL(err) + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 0); + RETIF_REG_FAIL(err) + + } + else if (pDis->pixRate == HDMITX_PIXRATE_SINGLE_REPEATED) + { + err = setHwRegisterFieldTable(pDis, &kVinModeYUV422[0]); + + RETIF_REG_FAIL(err) + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 0); + RETIF_REG_FAIL(err) + + } + else + { + /* Not supported*/ + return TMBSL_ERR_HDMI_BAD_PARAMETER; + } + break; + case HDMITX_VINMODE_CCIR656: + if(pDis->pixRate == HDMITX_PIXRATE_SINGLE) + { + + err = setHwRegisterFieldTable(pDis, &kVinModeCCIR656[0]); + + RETIF_REG_FAIL(err) + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 0); + RETIF_REG_FAIL(err) + + } + else if (pDis->pixRate == HDMITX_PIXRATE_SINGLE_REPEATED) + { + err = setHwRegisterFieldTable(pDis, &kVinModeCCIR656[0]); + + RETIF_REG_FAIL(err) + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 0); + RETIF_REG_FAIL(err) + + } + else if (pDis->pixRate == HDMITX_PIXRATE_DOUBLE) + { + err = setHwRegisterFieldTable(pDis, &kVinModeCCIR656_DDR_above720p[0]); + + RETIF_REG_FAIL(err) + + + + + err = setHwRegisterField(pDis, + E_REG_P00_VIP_CNTRL_4_W, + E_MASKREG_P00_VIP_CNTRL_4_656_alt, + 1); + RETIF_REG_FAIL(err) + + } + break; + default: + err = setHwRegisterFieldTable(pDis, &kVinMode444[0]); + + RETIF_REG_FAIL(err) + break; + } + + } + /****************Update the Sample Mode***********************/ + + if (upsampleMode != HDMITX_UPSAMPLE_NO_CHANGE) { + pDis->upsampleMode = upsampleMode; + } + +/****************Set the Pixel repeat PLL Value *********************** +- P02_PLL_SERIAL_2_srl_nosc +- P02_PLL_DE_pllde_nosc */ + + if ((structure3D == HDMITX_3D_FRAME_PACKING) && \ + (reg_idx3D != REGVFMT_INVALID)) { + /* embedded 3D video format */ + ssd = pll[reg_idx3D]; + } + else { + /* embedded 2D video format */ + ssd = pll[reg_idx]; + } + + if ( ssd < SSD_UNUSED_VALUE) { + err = setHwRegisterField(pDis, E_REG_P02_PLL_SERIAL_2_RW, + E_MASKREG_P02_PLL_SERIAL_2_srl_nosc, + ssd); +/* printk("DBG nosc:%d\n",ssd); */ + } + +/*****************Set the Pixel Repetition*********************** +- P02_PLL_SERIAL_2_srl_pr*/ + + /* Set pixel repetition */ + if (uPixelRepeat != HDMITX_PIXREP_NO_CHANGE) + { + if (uPixelRepeat == HDMITX_PIXREP_DEFAULT) + { + /* Look up default pixel repeat value for this output format */ + uPixelRepeat = sync[BASE(reg_idx)].pix_rep; + } + + /* Update current pixel repetition count */ + pDis->pixelRepeatCount = uPixelRepeat; + + err = setHwRegisterField(pDis, + E_REG_P02_PLL_SERIAL_2_RW, + E_MASKREG_P02_PLL_SERIAL_2_srl_pr, + uPixelRepeat); + RETIF_REG_FAIL(err) + /* Set pixel repetition count for Repetitor module */ + err = setHwRegister(pDis, E_REG_P00_RPT_CNTRL_W, uPixelRepeat); + } + +/*******************Fixe other settings********************* +- P02_PLL_SERIAL_1_srl_man_iz = 0 +- P02_PLL_SERIAL_3_srl_de = 0 +- Pol Clk Sel = P02_SERIALIZER_RW = 0 +- P02_BUFFER_OUT_srl_force = 0 +- P02_BUFFER_OUT_srl_clk = 0 +- P02_PLL_DE_pllde_iz = 0 +*/ + + err = setHwRegisterField(pDis, + E_REG_P02_PLL_SERIAL_1_RW, + E_MASKREG_P02_PLL_SERIAL_1_srl_man_iz, + 0); + + +RETIF_REG_FAIL(err) + + err = setHwRegisterField(pDis, + E_REG_P02_PLL_SERIAL_3_RW, + E_MASKREG_P02_PLL_SERIAL_3_srl_de, + 0); +RETIF_REG_FAIL(err) + +err = setHwRegister(pDis, E_REG_P02_SERIALIZER_RW, 0); +RETIF_REG_FAIL(err) + +return err; +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut_l.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut_l.h new file mode 100755 index 0000000000000..5a94001fdbfc1 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_InOut_l.h @@ -0,0 +1,112 @@ +/** + * Copyright (C) 2009 Koninklijke Philips Electronics N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of Koninklijke Philips Electronics N.V. and is confidential in + * nature. Under no circumstances is this software to be exposed to or placed + * under an Open Source License of any type without the expressed written + * permission of Koninklijke Philips Electronics N.V. + * + * \file tmbslTDA9989_InOut_l.h + * + * \version $Revision: 2 $ + * + * +*/ + +#ifndef TMBSLTDA9989_INOUT_L_H +#define TMBSLTDA9989_INOUT_L_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + +#define IS_TV(fmt) (fmt >= HDMITX_VFMT_TV_MIN && fmt <= HDMITX_VFMT_TV_MAX) +#define IS_VALID_FMT(fmt) IS_TV(fmt) +#ifdef FORMAT_PC +#define IS_PC(fmt) (fmt >= HDMITX_VFMT_PC_MIN && fmt <= HDMITX_VFMT_PC_MAX) +#define IS_VALID_FMT(fmt) (IS_TV(fmt)||IS_PC(fmt)) +#endif +#define VIC2REG_LOOP(array,idx) do { \ + hash=(struct vic2reg *)(array); \ + for (i=0;i<(sizeof(array)/sizeof(struct vic2reg));i++) { \ + if (hash[i].vic==fmt) { \ + (*idx)=hash[i].reg; \ + break; \ + } \ + } \ +} while (0); + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +typedef struct +{ + UInt16 Register; + UInt8 MaskSwap; + UInt8 MaskMirror; +} tmbslTDA9989RegVip; + +/*============================================================================*/ +/* EXTERN DATA DEFINITION */ +/*============================================================================*/ + +extern CONST_DAT tmHdmiTxRegMaskVal_t kCommonPllCfg[]; + +/** + * Table of PLL settings registers to configure for 480i and 576i vinFmt + */ +extern CONST_DAT tmHdmiTxRegMaskVal_t kVfmt480i576iPllCfg[]; + +/** + * Table of PLL settings registers to configure for single mode pixel rate, + * vinFmt 480i or 576i only + */ +extern CONST_DAT tmHdmiTxRegMaskVal_t kSinglePrateVfmt480i576iPllCfg[]; + +/** + * Table of PLL settings registers to configure for single repeated mode pixel rate, + * vinFmt 480i or 576i only + */ +extern CONST_DAT tmHdmiTxRegMaskVal_t kSrepeatedPrateVfmt480i576iPllCfg[]; + +/** + * Table of PLL settings registers to configure for other vinFmt than 480i and 576i + */ +extern CONST_DAT tmHdmiTxRegMaskVal_t kVfmtOtherPllCfg[]; + +/** + * Table of PLL settings registers to configure single mode pixel rate, + * vinFmt other than 480i or 576i + */ +extern CONST_DAT tmHdmiTxRegMaskVal_t kSinglePrateVfmtOtherPllCfg[]; + +/** + * Table of PLL settings registers to configure double mode pixel rate, + * vinFmt other than 480i or 576i + */ +extern CONST_DAT tmHdmiTxRegMaskVal_t kDoublePrateVfmtOtherPllCfg[]; + + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ +extern tmbslHdmiTxVidFmt_t calculateVidFmtIndex(tmbslHdmiTxVidFmt_t vidFmt); + + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_INOUT_L_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc.c b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc.c new file mode 100755 index 0000000000000..9bf8a71415124 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc.c @@ -0,0 +1,2512 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_misc.c + * + * \version %version: 3 % + * + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#endif +#include "tmbslHdmiTx_types.h" +#include "tmbslTDA9989_Functions.h" +#include "tmbslTDA9989_local.h" +#include "tmbslTDA9989_HDCP_l.h" +#include "tmbslTDA9989_State_l.h" +#include "tmbslTDA9989_InOut_l.h" +#include "tmbslTDA9989_Edid_l.h" +#include "tmbslTDA9989_Misc_l.h" + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS EXPORTED */ +/*============================================================================*/ + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ + +/** Preset default values for an object instance */ +static CONST_DAT tmHdmiTxobject_t kHdmiTxInstanceDefault += +{ + ST_UNINITIALIZED, /* state */ + 0, /* nIgnoredEvents */ + tmUnit0, /* txUnit */ + 0, /* uHwAddress */ + (ptmbslHdmiTxSysFunc_t)0, /* sysFuncWrite */ + (ptmbslHdmiTxSysFunc_t)0, /* sysFuncRead */ + (ptmbslHdmiTxSysFuncEdid_t)0, /* sysFuncEdidRead */ + (ptmbslHdmiTxSysFuncTimer_t)0, /* sysFuncTimer */ + { /* funcIntCallbacks[] */ + (ptmbslHdmiTxCallback_t)0 + }, + 0, /* InterruptsEnable */ + { /* uSupportedVersions[] */ + E_DEV_VERSION_N2, + E_DEV_VERSION_TDA19989, + E_DEV_VERSION_TDA19989_N2, + E_DEV_VERSION_TDA19988, + E_DEV_VERSION_LIST_END + }, + E_DEV_VERSION_LIST_END, /* uDeviceVersion */ + E_DEV_VERSION_LIST_END, /* uDeviceFeatures */ + (tmbslHdmiTxPowerState_t)tmPowerOff, /* ePowerState */ + False, /* EdidAlternateAddr */ + HDMITX_SINK_DVI, /* sinkType */ + HDMITX_SINK_DVI, /* EdidSinkType */ + False, /* EdidSinkAi */ + 0, /* EdidCeaFlags */ + + 0, /* EdidCeaXVYCCFlags */ + { + False, /* latency_available */ + False, /* Ilatency_available */ + 0, /* Edidvideo_latency */ + 0, /* Edidaudio_latency */ + 0, /* EdidIvideo_latency */ + 0}, /* EdidIaudio_latency */ + + { + 0, /* maximum supported TMDS clock */ + 0, /* content type Graphics (text) */ + 0, /* content type Photo */ + 0, /* content type Cinema */ + 0, /* content type Game */ + 0, /* additional video format */ + 0, /* 3D support by the HDMI Sink */ + 0, /* 3D multi strctures present */ + 0, /* additional info for the values in the image size area */ + 0, /* total length of 3D video formats */ + 0, /* total length of extended video formats */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} /* max_len-10, ie: 31-10=21 */ + }, + + HDMITX_EDID_NOT_READ, /* EdidStatus */ + 0, /* NbDTDStored */ + { /* EdidDTD: */ /* * NUMBER_DTD_STORED */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*1 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*2 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*3 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*4 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*5 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*6 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*7 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*8 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0}, /*9 */ + {0,0,0,0,0,0,0,0,0,0,0,0,0,0} /*10*/ + }, + { /* EdidMonitorDescriptor */ + False, /* bDescRecord */ + {0,0,0,0,0,0,0,0,0,0,0,0,0} /* uMonitorName[EDID_MONITOR_DESCRIPTOR_SIZE] */ + }, + { + False, /* bDescRecord */ + 0, /* uMinVerticalRate */ + 0, /* uMaxVerticalRate */ + 0, /* uMinHorizontalRate */ + 0, /* uMaxHorizontalRate */ + 0 /* uMaxSupportedPixelClk */ + }, + { + False, /* bDescRecord */ + {0,0,0,0,0,0,0,0,0,0,0,0,0} /* uOtherDescriptor[EDID_MONITOR_DESCRIPTOR_SIZE] */ + }, + { /* EdidVFmts[] */ + HDMITX_VFMT_NULL + }, + 0, /* EdidSvdCnt */ + { /* EdidAFmts[]. */ + {0,0,0} /* {ModeChans, Freqs, Byte3} */ + }, + 0, /* EdidSadCnt */ + { + 0 /* EdidBlock[ ] */ + }, + 0, /* EdidBlockCnt */ + 0, /* EdidSourceAddress */ + 0, /* EdidBlockRequested */ + False, /* EdidReadStarted */ + { /* EdidToApp */ + 0, /* pRawEdid */ + 0 /* numBlocks */ + }, + { /* EDIDBasicDisplayParam */ + 0, /* uVideoInputDef */ + 0, /* uMaxHorizontalSize */ + 0, /* uMaxVerticalSize */ + 0, /* uGamma */ + 0, /* uFeatureSupport */ + }, +#ifdef TMFL_HDCP_SUPPORT + False, /* HDCPIgnoreEncrypt */ + 0, /* HdcpPortAddress */ + HDMITX_HDCP_TXMODE_NOT_SET, /* HdcpTxMode */ + HDMITX_HDCP_OPTION_DEFAULT, /* HdcpOptions */ + 0, /* HdcpBcaps */ + 0, /* HdcpBstatus */ + 0, /* HdcpRi */ + 0, /* HdcpFsmState */ + 0, /* HdcpT0FailState */ + 0, /* HdcpSeed */ + {0, 0, 0, 0, 0}, /* HdcpAksv */ + (ptmHdmiTxFunc_t)0, /* HdcpFuncScheduled */ + 0, /* HdcpFuncRemainingMs */ + 0, /* HdcpCheckIntervalMs */ + 0, /* HdcpCheckRemainingMs */ + 0, /* HdcpCheckNum */ + 0, /* HdcpChecksToDo */ +#endif /* TMFL_HDCP_SUPPORT */ + HDMITX_VFMT_NULL, /* vinFmt */ + HDMITX_VFMT_NULL, /* voutFmt */ + HDMITX_PIXRATE_DOUBLE, /* pixRate */ + HDMITX_VINMODE_RGB444, /* vinMode */ + HDMITX_VOUTMODE_RGB444, /* voutMode */ + HDMITX_VFREQ_INVALID, /* voutFreq */ + HDMITX_SCAMODE_OFF, /* scaMode */ + HDMITX_UPSAMPLE_AUTO, /* upsampleMode */ + HDMITX_PIXREP_MIN, /* pixelRepeatCount */ + HDMITX_HOTPLUG_INVALID, /* hotPlugStatus */ + HDMITX_RX_SENSE_INVALID, /* rxSenseStatus */ + E_PAGE_INVALID, /* curRegPage */ + { + /* These match power-up defaults. shadowReg[]: */ + 0x00, /* E_SP00_INT_FLAGS_0 */ + 0x00, /* E_SP00_INT_FLAGS_1 */ + 0x00, /* E_SP00_INT_FLAGS_2 */ + 0x01, /* E_SP00_VIP_CNTRL_0 */ + 0x24, /* E_SP00_VIP_CNTRL_1 */ + 0x56, /* E_SP00_VIP_CNTRL_2 */ + 0x17, /* E_SP00_VIP_CNTRL_3 */ + 0x01, /* E_SP00_VIP_CNTRL_4 */ + 0x00, /* E_SP00_VIP_CNTRL_5 */ + 0x05, /* E_SP00_MAT_CONTRL */ + 0x00, /* E_SP00_TBG_CNTRL_0 */ + 0x00, /* E_SP00_TBG_CNTRL_1 */ + 0x00, /* E_SP00_HVF_CNTRL_0 */ + 0x00, /* E_SP00_HVF_CNTRL_1 */ + 0x00, /* E_SP00_TIMER_H */ + 0x00, /* E_SP00_DEBUG_PROBE */ + 0x00 /* E_SP00_AIP_CLKSEL */ + ,0x00 /* E_SP01_SC_VIDFORMAT*/ + ,0x00 /* E_SP01_SC_CNTRL */ + ,0x00 /* E_SP01_TBG_CNTRL_0 */ +#ifdef TMFL_HDCP_SUPPORT + ,0x00 /* E_SP12_CTRL */ + ,0x00 /* E_SP12_BCAPS */ +#endif /* TMFL_HDCP_SUPPORT */ + }, + False, /* Init prevFilterPattern to false */ + False, /* Init prevPattern to false */ + False, /* bInitialized */ + HDMITX_VQR_DEFAULT +}; + + +/** + * Table of shadow registers, as packed Shad/Page/Addr codes. + * This allows shadow index values to be searched for using register page + * and address values. + */ +static CONST_DAT UInt16 kShadowReg[E_SNUM] = +{/* Shadow Index Packed Shad/Page/Addr */ + E_REG_P00_INT_FLAGS_0_RW, /* E_SP00_INT_FLAGS_0 */ + E_REG_P00_INT_FLAGS_1_RW, /* E_SP00_INT_FLAGS_1 */ + E_REG_P00_INT_FLAGS_2_RW, /* E_SP00_INT_FLAGS_2 */ + E_REG_P00_VIP_CNTRL_0_W , /* E_SP00_VIP_CNTRL_0 */ + E_REG_P00_VIP_CNTRL_1_W , /* E_SP00_VIP_CNTRL_1 */ + E_REG_P00_VIP_CNTRL_2_W , /* E_SP00_VIP_CNTRL_2 */ + E_REG_P00_VIP_CNTRL_3_W , /* E_SP00_VIP_CNTRL_3 */ + E_REG_P00_VIP_CNTRL_4_W , /* E_SP00_VIP_CNTRL_4 */ + E_REG_P00_VIP_CNTRL_5_W , /* E_SP00_VIP_CNTRL_5 */ + E_REG_P00_MAT_CONTRL_W , /* E_SP00_MAT_CONTRL */ + E_REG_P00_TBG_CNTRL_0_W , /* E_SP00_TBG_CNTRL_0 */ + E_REG_P00_TBG_CNTRL_1_W , /* E_SP00_TBG_CNTRL_1 */ + E_REG_P00_HVF_CNTRL_0_W , /* E_SP00_HVF_CNTRL_0 */ + E_REG_P00_HVF_CNTRL_1_W , /* E_SP00_HVF_CNTRL_1 */ + E_REG_P00_TIMER_H_W , /* E_SP00_TIMER_H */ + E_REG_P00_DEBUG_PROBE_W , /* E_SP00_DEBUG_PROBE */ + E_REG_P00_AIP_CLKSEL_W, /* E_SP00_AIP_CLKSEL */ + E_REG_P01_SC_VIDFORMAT_W, /* E_SP01_SC_VIDFORMAT */ + E_REG_P01_SC_CNTRL_W, /* E_SP01_SC_CNTRL */ + E_REG_P01_TBG_CNTRL_0_W /* E_SP01_TBG_CNTRL_0 */ +#ifdef TMFL_HDCP_SUPPORT + ,E_REG_P12_CTRL_W /* E_SP12_CTRL */ + ,E_REG_P12_BCAPS_W /* E_SP12_BCAPS */ +#endif /* TMFL_HDCP_SUPPORT */ +}; + + +/** + * Table of registers to switch to low power (standby) + +static CONST_DAT tmHdmiTxRegMaskVal_t kPowerOff[] = +{ + {E_REG_P02_TEST2_RW, E_MASKREG_P02_TEST2_pwd1v8, 1}, + {E_REG_P02_PLL_SCG1_RW, E_MASKREG_P02_PLL_SCG1_scg_fdn, 1}, + {E_REG_P02_PLL_SERIAL_1_RW, E_MASKREG_P02_PLL_SERIAL_1_srl_fdn, 1}, + {E_REG_P02_PLL_DE_RW, E_MASKREG_P02_PLL_DE_pllde_fdn, 1}, + {E_REG_P02_BUFFER_OUT_RW, E_MASKREG_P02_BUFFER_OUT_srl_force, 2}, + {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_ena_sc_clk, 0}, + {E_REG_P00_CCLK_ON_RW, E_MASKREG_P00_CCLK_ON_cclk_on, 0}, + {0,0,0} +}; +*/ +/** + * Table of registers to switch to normal power (resume) + +static CONST_DAT tmHdmiTxRegMaskVal_t kPowerOn[] = +{ + {E_REG_P02_TEST2_RW, E_MASKREG_P02_TEST2_pwd1v8, 0}, + {E_REG_P02_PLL_SERIAL_1_RW, E_MASKREG_P02_PLL_SERIAL_1_srl_fdn, 0}, + {E_REG_P02_PLL_DE_RW, E_MASKREG_P02_PLL_DE_pllde_fdn, 0}, + {E_REG_P02_PLL_SCG1_RW, E_MASKREG_P02_PLL_SCG1_scg_fdn, 0}, + {E_REG_P02_SEL_CLK_RW, E_MASKREG_P02_SEL_CLK_ena_sc_clk, 1}, + {E_REG_P02_BUFFER_OUT_RW, E_MASKREG_P02_BUFFER_OUT_srl_force, 0}, + {E_REG_P00_TBG_CNTRL_0_W, E_MASKREG_P00_TBG_CNTRL_0_sync_once,0}, + {E_REG_P00_CCLK_ON_RW, E_MASKREG_P00_CCLK_ON_cclk_on, 1}, + {0,0,0} +}; +*/ + +static CONST_DAT tmbslHdmiTxCallbackInt_t kITCallbackPriority[HDMITX_CALLBACK_INT_NUM] = +{ + HDMITX_CALLBACK_INT_R0, /**< R0 interrupt */ + HDMITX_CALLBACK_INT_ENCRYPT, /**< HDCP encryption switched off */ + HDMITX_CALLBACK_INT_HPD, /**< Transition on HPD input */ + HDMITX_CALLBACK_INT_T0, /**< HDCP state machine in state T0 */ + HDMITX_CALLBACK_INT_BCAPS, /**< BCAPS available */ + HDMITX_CALLBACK_INT_BSTATUS, /**< BSTATUS available */ + HDMITX_CALLBACK_INT_SHA_1, /**< sha-1(ksv,bstatus,m0)=V' */ + HDMITX_CALLBACK_INT_PJ, /**< pj=pj' check fails */ + HDMITX_CALLBACK_INT_SW_INT, /**< SW DEBUG interrupt */ + HDMITX_CALLBACK_INT_RX_SENSE, /**< RX SENSE interrupt */ + HDMITX_CALLBACK_INT_EDID_BLK_READ, /**< EDID BLK READ interrupt */ + HDMITX_CALLBACK_INT_VS_RPT, /**< VS interrupt */ + HDMITX_CALLBACK_INT_PLL_LOCK /** PLL LOCK not present on TDA9984 */ +}; + + + +#ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC + + CONST_DAT UInt8 kndiv_im[] = +{ + 0, /* HDMITX_VFMT_NO_CHANGE */ + 4, /* HDMITX_VFMT_01_640x480p_60Hz */ + 4, /* HDMITX_VFMT_02_720x480p_60Hz */ + 4, /* HDMITX_VFMT_03_720x480p_60Hz */ + 12, /* HDMITX_VFMT_04_1280x720p_60Hz */ + 12, /* HDMITX_VFMT_05_1920x1080i_60Hz */ + 4, /* HDMITX_VFMT_06_720x480i_60Hz */ + 4, /* HDMITX_VFMT_07_720x480i_60Hz */ + 4, /* HDMITX_VFMT_08_720x240p_60Hz */ + 4, /* HDMITX_VFMT_09_720x240p_60Hz */ + 4, /* HDMITX_VFMT_10_720x480i_60Hz */ + 4, /* HDMITX_VFMT_11_720x480i_60Hz */ + 4, /* HDMITX_VFMT_12_720x240p_60Hz */ + 4, /* HDMITX_VFMT_13_720x240p_60Hz */ + 4, /* HDMITX_VFMT_14_1440x480p_60Hz */ + 4, /* HDMITX_VFMT_15_1440x480p_60Hz */ + 12,/* HDMITX_VFMT_16_1920x1080p_60Hz */ + 4, /* HDMITX_VFMT_17_720x576p_50Hz */ + 4, /* HDMITX_VFMT_18_720x576p_50Hz */ + 12, /* HDMITX_VFMT_19_1280x720p_50Hz */ + 12, /* HDMITX_VFMT_20_1920x1080i_50Hz */ + 4, /* HDMITX_VFMT_21_720x576i_50Hz */ + 4, /* HDMITX_VFMT_22_720x576i_50Hz */ + 4, /* HDMITX_VFMT_23_720x288p_50Hz */ + 4, /* HDMITX_VFMT_24_720x288p_50Hz */ + 4, /* HDMITX_VFMT_25_720x576i_50Hz */ + 4, /* HDMITX_VFMT_26_720x576i_50Hz */ + 4, /* HDMITX_VFMT_27_720x288p_50Hz */ + 4, /* HDMITX_VFMT_28_720x288p_50Hz */ + 4, /* HDMITX_VFMT_29_1440x576p_50Hz */ + 4, /* HDMITX_VFMT_30_1440x576p_50Hz */ + 12,/* HDMITX_VFMT_31_1920x1080p_50Hz */ + 12, /* HDMITX_VFMT_32_1920x1080p_24Hz */ + 12, /* HDMITX_VFMT_33_1920x1080p_25Hz */ + 12, /* HDMITX_VFMT_34_1920x1080p_30Hz */ + +}; + + CONST_DAT UInt8 kclk_div[] = + { + 0, /* HDMITX_VFMT_NO_CHANGE */ + 44, /* HDMITX_VFMT_01_640x480p_60Hz */ + 44, /* HDMITX_VFMT_02_720x480p_60Hz */ + 44, /* HDMITX_VFMT_03_720x480p_60Hz */ + 44, /* HDMITX_VFMT_04_1280x720p_60Hz */ + 44, /* HDMITX_VFMT_05_1920x1080i_60Hz */ + 44, /* HDMITX_VFMT_06_720x480i_60Hz */ + 44, /* HDMITX_VFMT_07_720x480i_60Hz */ + 44, /* HDMITX_VFMT_08_720x240p_60Hz */ + 44, /* HDMITX_VFMT_09_720x240p_60Hz */ + 44, /* HDMITX_VFMT_10_720x480i_60Hz */ + 44, /* HDMITX_VFMT_11_720x480i_60Hz */ + 44, /* HDMITX_VFMT_12_720x240p_60Hz */ + 44, /* HDMITX_VFMT_13_720x240p_60Hz */ + 44, /* HDMITX_VFMT_14_1440x480p_60Hz */ + 44, /* HDMITX_VFMT_15_1440x480p_60Hz */ + 44,/* HDMITX_VFMT_16_1920x1080p_60Hz */ + 44, /* HDMITX_VFMT_17_720x576p_50Hz */ + 44, /* HDMITX_VFMT_18_720x576p_50Hz */ + 44, /* HDMITX_VFMT_19_1280x720p_50Hz */ + 44, /* HDMITX_VFMT_20_1920x1080i_50Hz */ + 44, /* HDMITX_VFMT_21_720x576i_50Hz */ + 44, /* HDMITX_VFMT_22_720x576i_50Hz */ + 44, /* HDMITX_VFMT_23_720x288p_50Hz */ + 44, /* HDMITX_VFMT_24_720x288p_50Hz */ + 44, /* HDMITX_VFMT_25_720x576i_50Hz */ + 44, /* HDMITX_VFMT_26_720x576i_50Hz */ + 44, /* HDMITX_VFMT_27_720x288p_50Hz */ + 44, /* HDMITX_VFMT_28_720x288p_50Hz */ + 44, /* HDMITX_VFMT_29_1440x576p_50Hz */ + 44, /* HDMITX_VFMT_30_1440x576p_50Hz */ + 44,/* HDMITX_VFMT_31_1920x1080p_50Hz */ + 44, /* HDMITX_VFMT_32_1920x1080p_24Hz */ + 44, /* HDMITX_VFMT_33_1920x1080p_25Hz */ + 44, /* HDMITX_VFMT_34_1920x1080p_30Hz */ + }; + +#endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + + +/*============================================================================*/ +/* FUNCTIONS DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + +#ifdef TMFL_HDCP_SUPPORT +static UInt32 sgBcapsCounter = 0; +#endif /* TMFL_HDCP_SUPPORT */ + +#define TDA19989_DDC_SPEED_FACTOR 39 + +static Bool gMiscInterruptHpdRxEnable = False; /* Enable HPD and RX sense IT after */ + /* first call done by init function */ +static UInt8 int_level=0xFF; +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/*============================================================================*/ +/* tmbslTDA9989Deinit */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989Deinit +( + tmUnitSelect_t txUnit +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 EnableModeMask = 0; /* Local Variable */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* patch to get successfull soft reset even if powerstate has been set to standby mode */ + /*Write data in ENAMODS CEC Register */ + EnableModeMask = 0x40; + EnableModeMask |= E_MASKREG_CEC_ENAMODS_ena_hdmi; /*Enable HDMI Mode*/ + EnableModeMask &= ~E_MASKREG_CEC_ENAMODS_dis_fro; /* Enable FRO */ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, EnableModeMask); + RETIF_REG_FAIL(err) + + /* Hold the device in reset to disable it */ + err = setHwRegisterField(pDis, E_REG_P00_MAIN_CNTRL0_RW, + E_MASKREG_P00_MAIN_CNTRL0_sr, 1); + RETIF_REG_FAIL(err) + + /* patch to get successfull soft reset even if powerstate has been set to standby mode */ + EnableModeMask &= ~E_MASKREG_CEC_ENAMODS_ena_hdmi; /* Disable HDMI Mode*/ + EnableModeMask &= ~E_MASKREG_CEC_ENAMODS_ena_rxs; /* Reset RxSense Mode*/ + EnableModeMask |= E_MASKREG_CEC_ENAMODS_dis_fro; /* Disable FRO */ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, EnableModeMask); + RETIF_REG_FAIL(err) + + /* Clear the Initialized flag to destroy the device instance */ + pDis->bInitialized = False; + + setState(pDis, EV_DEINIT); + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989HotPlugGetStatus */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HotPlugGetStatus +( + tmUnitSelect_t txUnit, + tmbslHdmiTxHotPlug_t *pHotPlugStatus, + Bool client /* Used to determine whether the request comes from the application */ +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; /* Register value */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameters */ + RETIF_BADPARAM(pHotPlugStatus == (tmbslHdmiTxHotPlug_t *)0) + + /* Read HPD RXS level */ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,®Val); + RETIF(err != TM_OK, err) + + /* Read Hot Plug input status to know the actual level that caused the interrupt */ + if (client) + { + *pHotPlugStatus = (regVal & E_MASKREG_CEC_RXSHPDLEV_hpd_level) ? + HDMITX_HOTPLUG_ACTIVE : HDMITX_HOTPLUG_INACTIVE; + } + else { + + *pHotPlugStatus = pDis->hotPlugStatus; + + } + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989RxSenseGetStatus */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989RxSenseGetStatus +( + tmUnitSelect_t txUnit, + tmbslHdmiTxRxSense_t *pRxSenseStatus, + Bool client /* Used to determine whether the request comes from the application */ +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; /* Register value */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameters */ + RETIF_BADPARAM(pRxSenseStatus == (tmbslHdmiTxRxSense_t *)0) + + + /* Read HPD RXS level */ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,®Val); + RETIF(err != TM_OK, err) + + + /*Read RXS_FIL status to know the actual level that caused the interrupt */ + if (client) + { + *pRxSenseStatus = (regVal & E_MASKREG_CEC_RXSHPDLEV_rxs_level) ? + HDMITX_RX_SENSE_ACTIVE : HDMITX_RX_SENSE_INACTIVE; + } + else { + *pRxSenseStatus = pDis->rxSenseStatus; + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989HwGetRegisters */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HwGetRegisters +( + tmUnitSelect_t txUnit, + Int regPage, + Int regAddr, + UInt8 *pRegBuf, + Int nRegs +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop index */ + UInt8 newRegPage; /* The register's new page number */ + UInt8 regShad; /* Index to the register's shadow copy */ + UInt16 regShadPageAddr;/* Packed shadowindex/page/address */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameters */ + RETIF_BADPARAM((regPage < kPageIndexToPage[E_PAGE_00]) + || ((regPage > kPageIndexToPage[E_PAGE_02]) + && (regPage < kPageIndexToPage[E_PAGE_09])) + || ((regPage > kPageIndexToPage[E_PAGE_09]) + && (regPage < kPageIndexToPage[E_PAGE_11])) + || (regPage > kPageIndexToPage[E_PAGE_12])) + RETIF_BADPARAM((regAddr < E_REG_MIN_ADR) || (regAddr >= E_REG_CURPAGE_ADR_W)) + RETIF_BADPARAM(pRegBuf == (pUInt8)0) + RETIF_BADPARAM((nRegs < 1) || ((nRegs + regAddr) > E_REG_CURPAGE_ADR_W)) + + /* Set page register if required */ + newRegPage = (UInt8)regPage; + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + /* Read each register in the range. nRegs must start at 1 or more */ + for ( ; nRegs > 0; pRegBuf++, regAddr++, nRegs--) + { + /* Find shadow register index. + * This loop is not very efficient, but it is assumed that this API + * will not be used often. The alternative is to use a huge sparse + * array indexed by page and address and containing the shadow index. + */ + regShad = E_SNONE; + for (i = 0; i < E_SNUM; i++) + { + /* Check lookup table for match with page and address */ + regShadPageAddr = kShadowReg[i]; + if ((SPA2PAGE(regShadPageAddr) == newRegPage) + && (SPA2ADDR(regShadPageAddr) == regAddr)) + { + /* Found page and address - look up the shadow index */ + regShad = SPA2SHAD(regShadPageAddr); + break; + } + } + /* Read the shadow register if available, as device registers that + * are shadowed cannot be read directly */ + if (regShad != E_SNONE) + { + *pRegBuf = pDis->shadowReg[regShad]; + } + else + { + /* Read the device register - all non-OK results are errors. + * Note that some non-shadowed registers are also write-only and + * cannot be read. */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = (UInt8)regAddr; + sysArgs.lenData = 1; + sysArgs.pData = pRegBuf; + err = pDis->sysFuncRead(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_READ) + } + } + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989HwGetVersion */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989HwGetVersion +( + tmUnitSelect_t txUnit, + pUInt8 pHwVersion +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameters */ + RETIF_BADPARAM(pHwVersion == (pUInt8)0) + + /* Get MSB version Value*/ + err = getHwRegister(pDis, E_REG_P00_VERSION_MSB_RW, ®Val); + RETIF(err != TM_OK, err) + + switch (regVal) + { + case 0x01: + *pHwVersion = (UInt8)(BSLHDMITX_TDA9989); + break; + case 0x02: + *pHwVersion = (UInt8)(BSLHDMITX_TDA19989); + break; + case 0x03: + *pHwVersion = (UInt8)(BSLHDMITX_TDA19988); + break; + default: + *pHwVersion = (UInt8)(BSLHDMITX_UNKNOWN); + break; + } + + return TM_OK; +} + + +/*============================================================================*/ +/* tmbslTDA9989HwHandleInterrupt */ +/* RETIF_REG_FAIL NOT USED HERE AS ALL ERRORS SHOULD BE TRAPPED IN ALL BUILDS */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HwHandleInterrupt +( + tmUnitSelect_t txUnit +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; /* Register value */ + UInt8 regVal1; /* Register value */ + UInt16 fInterruptStatus; /* Interrupt flags */ + UInt16 fInterruptMask; /* Mask to test each interrupt bit */ + tmbslHdmiTxRxSense_t newRxs_fil; /* Latest copy of rx_sense */ + Int i; /* Loop counter */ + tmbslHdmiTxHotPlug_t newHpdIn; /* Latest copy of hpd input */ + Bool sendEdidCallback; + Bool hpdOrRxsLevelHasChanged = False; + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + fInterruptStatus = 0; + sendEdidCallback = False; + + + + /* Read HPD RXS int status */ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINT_R,®Val); + RETIF(err != TM_OK, err); + + /* Read HPD RXS level */ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,®Val1); + RETIF(err != TM_OK, err); + + if (int_level!=0xFF) { /* init should be done */ + /* check multi-transition */ + if ((regVal==0) && (int_level!=regVal1)) { +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER + printk("HDMI Int multi-transition\n"); +#endif + err = setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, 0x00); + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, \ + E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int | \ + E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,®Val1); + RETIF(err != TM_OK, err) + } + } + int_level=regVal1; + + /* Read Hot Plug input status to know the actual level that caused the interrupt */ + newHpdIn = (regVal1 & E_MASKREG_CEC_RXSHPDLEV_hpd_level) ? + HDMITX_HOTPLUG_ACTIVE : HDMITX_HOTPLUG_INACTIVE; + + /*Read RXS_FIL status to know the actual level that caused the interrupt */ + newRxs_fil = (regVal1 & E_MASKREG_CEC_RXSHPDLEV_rxs_level) ? + HDMITX_RX_SENSE_ACTIVE : HDMITX_RX_SENSE_INACTIVE; + + /*Fill fInterruptStatus with HPD Interrupt flag*/ + + if (newHpdIn != pDis->hotPlugStatus) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_HPD); + /* Yes: save new HPD level */ + pDis->hotPlugStatus = newHpdIn; + hpdOrRxsLevelHasChanged = True; + } + + /*Fill fInterruptStatus with RX Sense Interrupt flag*/ + if (newRxs_fil != pDis->rxSenseStatus) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_RX_SENSE); + /* Yes: save new rxSense level */ + pDis->rxSenseStatus = newRxs_fil; + hpdOrRxsLevelHasChanged = True; + } + + + + /* is it HDMI interrupt ? */ + err = getCECHwRegister(pDis, E_REG_CEC_INTERRUPTSTATUS_R,®Val); + RETIF(err != TM_OK, err) + + /* there is no HDMI int to handle, give up */ + if ((regVal & E_MASKREG_CEC_INTERRUPTSTATUS_hdmi_int) == 0x00) { + + if (hpdOrRxsLevelHasChanged == True) { + } + else { + return TM_OK; + } + } + + + + /************************************************************************************************/ + /***********************************End of Temporary code****************************************/ + /************************************************************************************************/ + + /* Do only if HDMI is On*/ + if(pDis->ePowerState == tmPowerOn) + { + /* Read the main interrupt flags register to determine the source(s) + * of the interrupt. (The device resets these register flags after they + * have been read.) + */ + err = getHwRegister(pDis, E_REG_P00_INT_FLAGS_0_RW, ®Val); + RETIF(err != TM_OK, err) + +#ifdef TMFL_HDCP_SUPPORT + /* encrypt */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_encrypt) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_ENCRYPT); + } +#endif /* TMFL_HDCP_SUPPORT */ + + /* get TO interrupt Flag*/ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_t0) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_T0); + } + +#ifdef TMFL_HDCP_SUPPORT + /* bcaps */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_bcaps) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_BCAPS); + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + /* WA: HDCP ATC Test 1B_03 */ + + sgBcapsCounter++; + + if (sgBcapsCounter == 49) { + sgBcapsCounter = 0; + /* force a T0 interrupt */ + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_T0); + } + + } /* TDA19989 N1 only */ + + } + + /* bstatus */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_bstatus) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_BSTATUS); + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + /* WA: HDCP ATC Test 1B_03 */ + sgBcapsCounter = 0; + + } /* TDA19989 N1 only */ + + } + + /* sha_1 */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_sha_1) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_SHA_1); + } + + /* pj */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_pj) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_PJ); + } + + /* r0 */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_0_r0) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_R0); + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + /* WA: HDCP ATC Test 1B_03 */ + sgBcapsCounter = 0; + + } /* TDA19989 N1 only */ + + } +#endif /* TMFL_HDCP_SUPPORT */ + + + err = getHwRegister(pDis, E_REG_P00_INT_FLAGS_1_RW, ®Val); + RETIF(err != TM_OK, err) + + + /* Read the software interrupt flag */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_1_sw_int) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_SW_INT); + } + + /* Read the VS_rpt interrupt flag */ + if (((pDis->InterruptsEnable & E_MASKREG_P00_INT_FLAGS_1_vs_rpt) != 0) && + ((regVal & E_MASKREG_P00_INT_FLAGS_1_vs_rpt) != 0) + ) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_VS_RPT); + } + + /* Read INT_FLAGS_2 interrupt flag register. + *(The device resets these register flags after they + * have been read.) */ + err = getHwRegister(pDis, E_REG_P00_INT_FLAGS_2_RW, ®Val); + RETIF(err != TM_OK, err) + + /* Has the EDID_blk_rd interrupt occurs */ + if ((regVal & E_MASKREG_P00_INT_FLAGS_2_edid_blk_rd) != 0) + { + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_EDID_BLK_READ); + } + } + + + /* Handle the HPD Interrupt */ + if ((fInterruptStatus & (1 << HDMITX_CALLBACK_INT_HPD))!=0 ) + { + /* Callback disable on first tmbslTDA9989HwHandleInterrupt call */ + if(gMiscInterruptHpdRxEnable) + { + /* Reset EDID status */ + err = ClearEdidRequest(txUnit); + + /* Reset all simultaneous HDCP interrupts on hot plug, + * preserving only the high-priority hpd interrupt rx_sense and sw interrupt for debug*/ + fInterruptStatus &= (1 << HDMITX_CALLBACK_INT_HPD) | + (1 << HDMITX_CALLBACK_INT_RX_SENSE) | + (1 << HDMITX_CALLBACK_INT_SW_INT); + + if(pDis->ePowerState == tmPowerOn) + { + if ((pDis->hotPlugStatus == HDMITX_HOTPLUG_ACTIVE)) + { + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + err = tmbslTDA9989Reset(txUnit); + RETIF(err != TM_OK, err) + + err = hotPlugRestore(txUnit); + RETIF(err != TM_OK, err) + + } /* TDA19989 N1 only */ + + else { /* TDA19989 N2 */ + + HDCP_F2; + } + + #ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC + + err = tmbslTDA9989Reset(txUnit); + RETIF(err != TM_OK, err) + + err = hotPlugRestore(txUnit); + RETIF(err != TM_OK, err) + + #endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + + + + setState(pDis, EV_PLUGGEDIN); + } + else + { + setState(pDis, EV_UNPLUGGED); + } + } + } + } + else + { + /* Clear HPD status if level has not changed */ + fInterruptStatus &= ~(1 << HDMITX_CALLBACK_INT_HPD); + + if (fInterruptStatus & (1 << HDMITX_CALLBACK_INT_EDID_BLK_READ)) + { + err = EdidBlockAvailable(txUnit,&sendEdidCallback); + RETIF(err != TM_OK, err) + if (sendEdidCallback == False) + { + /* Read EDID not finished clear callback */ + fInterruptStatus &= ~(1 << HDMITX_CALLBACK_INT_EDID_BLK_READ); + } + else { + #ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC + + if ( (pDis->vinFmt == HDMITX_VFMT_16_1920x1080p_60Hz) || (pDis->vinFmt == HDMITX_VFMT_31_1920x1080p_50Hz)) { + + err = setHwRegisterField(pDis, + E_REG_P02_PLL_SERIAL_3_RW, + E_MASKREG_P02_PLL_SERIAL_3_srl_ccir, + 0x00); + RETIF_REG_FAIL(err) + } + + #endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + } + + + } + } + + /*Handle RxSense Interrupt*/ + if ((fInterruptStatus &( 1 << HDMITX_CALLBACK_INT_RX_SENSE))!= 0) + { + /* Callback disable on first tmbslTDA9989HwHandleInterrupt call */ + if(gMiscInterruptHpdRxEnable) + { + + + fInterruptStatus &= (1 << HDMITX_CALLBACK_INT_HPD) | + (1 << HDMITX_CALLBACK_INT_RX_SENSE) | + (1 << HDMITX_CALLBACK_INT_SW_INT); + + if (pDis->rxSenseStatus == HDMITX_RX_SENSE_ACTIVE) + { + setState(pDis, EV_SINKON); + } + else + { + setState(pDis, EV_SINKOFF); + } + } + } + else + { + /* Clear RX_sense IT if level has not changed */ + fInterruptStatus &= ~(1 << HDMITX_CALLBACK_INT_RX_SENSE); + } + + /* Ignore other simultaneous HDCP interrupts if T0 interrupt, + * preserving any hpd interrupt */ + + if (fInterruptStatus & (1 << HDMITX_CALLBACK_INT_T0)) + { + if (pDis->EdidReadStarted) + { + +#ifdef TMFL_HDCP_SUPPORT + err = getHwRegister(pDis, E_REG_P12_TX0_RW, ®Val); + RETIF(err != TM_OK, err) + + /* EDID read failure */ + if ((regVal & E_MASKREG_P12_TX0_sr_hdcp) != 0) { + +#endif /* TMFL_HDCP_SUPPORT */ + + + /* Reset EDID status */ + err = ClearEdidRequest(txUnit); + RETIF(err != TM_OK, err) + + /* enable EDID callback */ + fInterruptStatus = (UInt16) (fInterruptStatus & (~(1 << HDMITX_CALLBACK_INT_T0))); + fInterruptStatus = fInterruptStatus | (1 << HDMITX_CALLBACK_INT_EDID_BLK_READ); + +#ifdef TMFL_HDCP_SUPPORT + } +#endif /* TMFL_HDCP_SUPPORT */ + + } + else + { + fInterruptStatus &= + ( + (1 << HDMITX_CALLBACK_INT_HPD) + |(1 << HDMITX_CALLBACK_INT_T0) + |(1 << HDMITX_CALLBACK_INT_RX_SENSE) + |(1 << HDMITX_CALLBACK_INT_SW_INT) + ); + } + } + + HDCP_F3; + + /* For each interrupt flag that is set, check the corresponding registered + * callback function pointer in the Device Instance Structure + * funcIntCallbacks array. + */ + fInterruptMask = 1; + for (i = 0; i < HDMITX_CALLBACK_INT_NUM; i++) + { + if ( i != HDMITX_CALLBACK_INT_PLL_LOCK) /* PLL LOCK not present on TDA9989 */ + { + + fInterruptMask = 1; + fInterruptMask = fInterruptMask << ((UInt16)kITCallbackPriority[i]); + + if (fInterruptStatus & fInterruptMask) + { + /* IF a registered callback pointer is non-null THEN call it. */ + if (pDis->funcIntCallbacks[kITCallbackPriority[i]] != (ptmbslHdmiTxCallback_t)0) + { + pDis->funcIntCallbacks[kITCallbackPriority[i]](txUnit); + } + } + + } + } + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989FlagSwInt */ +/* Use only for debug to flag the software debug interrupt */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989FlagSwInt +( + tmUnitSelect_t txUnit, + UInt32 uSwInt + ) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + DUMMY_ACCESS(uSwInt); + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + err = setHwRegister(pDis, E_REG_P00_SW_INT_W, + E_MASKREG_P00_SW_INT_sw_int); + + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989HwSetRegisters */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989HwSetRegisters +( + tmUnitSelect_t txUnit, + Int regPage, + Int regAddr, + UInt8 *pRegBuf, + Int nRegs +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop index */ + UInt8 newRegPage; /* The register's new page number */ + UInt8 regShad; /* Index to the register's shadow copy */ + UInt16 regShadPageAddr;/* Packed shadowindex/page/address */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameters */ + RETIF_BADPARAM((regPage < kPageIndexToPage[E_PAGE_00]) + || ((regPage > kPageIndexToPage[E_PAGE_02]) + && (regPage < kPageIndexToPage[E_PAGE_11])) + || (regPage > kPageIndexToPage[E_PAGE_12])) + RETIF_BADPARAM((regAddr < E_REG_MIN_ADR) || (regAddr >= E_REG_CURPAGE_ADR_W)) + RETIF_BADPARAM(pRegBuf == (pUInt8)0) + RETIF_BADPARAM((nRegs < 0) || ((nRegs + regAddr) > E_REG_CURPAGE_ADR_W)) + + /* Set page register if required */ + newRegPage = (UInt8)regPage; + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + /* Write each register in the range. nRegs = 0 is ok, to allow only + * the page register to be written if required (above) + */ + for ( ; nRegs > 0; pRegBuf++, regAddr++, nRegs--) + { + /* Find shadow register index. + * This loop is not very efficient, but it is assumed that this API + * will not be used often. The alternative is to use a huge sparse + * array indexed by page and address and containing the shadow index. + */ + for (i = 0; i < E_SNUM; i++) + { + /* Check lookup table for match with page and address */ + regShadPageAddr = kShadowReg[i]; + if ((SPA2PAGE(regShadPageAddr) == newRegPage) + && (SPA2ADDR(regShadPageAddr) == regAddr)) + { + /* Found index - write the shadow register */ + regShad = SPA2SHAD(regShadPageAddr); + pDis->shadowReg[regShad] = *pRegBuf; + break; + } + } + /* Write the device register - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = (UInt8)regAddr; + sysArgs.lenData = 1; + sysArgs.pData = pRegBuf; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + } + + return TM_OK; +} + + +/*============================================================================*/ +/* tmbslTDA9989HwStartup */ +/*============================================================================*/ +void +tmbslTDA9989HwStartup +( + void +) +{ + /* Reset device instance data for when compiler doesn't do it */ + lmemset(&gHdmiTxInstance, 0, sizeof(gHdmiTxInstance)); +} + +/*============================================================================*/ +/* tmbslTDA9989Init */ +/* RETIF_REG_FAIL NOT USED HERE AS ALL ERRORS SHOULD BE TRAPPED IN ALL BUILDS */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989Init +( + tmUnitSelect_t txUnit, + UInt8 uHwAddress, + ptmbslHdmiTxSysFunc_t sysFuncWrite, + ptmbslHdmiTxSysFunc_t sysFuncRead, + ptmbslHdmiTxSysFuncEdid_t sysFuncEdidRead, + ptmbslHdmiTxSysFuncTimer_t sysFuncTimer, + tmbslHdmiTxCallbackList_t *funcIntCallbacks, + Bool bEdidAltAddr, + tmbslHdmiTxVidFmt_t vinFmt, + tmbslHdmiTxPixRate_t pixRate +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + Int i; /* Loop index */ + Bool bFound; /* T=found, F=not found */ + UInt8 EnableIntMask = 0; /* Mask used to enable HPD and RX Sense interrupt*/ + UInt8 EnableModeMask; /* Mask used to Set HDMI and RxSense modes*/ + UInt16 val16Bits; /* Value on 16 bit */ + UInt8 regVal; /* Register value */ + + /* Check unit parameter and point to its object */ + RETIF(txUnit < tmUnit0, TMBSL_ERR_HDMI_BAD_UNIT_NUMBER) + RETIF(txUnit >= HDMITX_UNITS_MAX, TMBSL_ERR_HDMI_BAD_UNIT_NUMBER) + pDis = &gHdmiTxInstance[txUnit]; + + /* IF the bInitialized flag is set THEN return (only Init does this) */ + RETIF(pDis->bInitialized, TMBSL_ERR_HDMI_INIT_FAILED) + + /* Check remaining parameters */ + RETIF_BADPARAM(uHwAddress < HDMITX_SLAVE_ADDRESS_MIN) + RETIF_BADPARAM(uHwAddress > HDMITX_SLAVE_ADDRESS_MAX) + RETIF_BADPARAM(sysFuncWrite == (ptmbslHdmiTxSysFunc_t)0) + RETIF_BADPARAM(sysFuncRead == (ptmbslHdmiTxSysFunc_t)0) + /*RETIF_BADPARAM(sysFuncEdidRead == (ptmbslHdmiTxSysFuncEdid_t)0)*/ /*Previously on TDA9983*/ + /*RETIF_BADPARAM(sysFuncTimer == (ptmbslHdmiTxSysFuncTimer_t)0)*/ + RETIF_BADPARAM((bEdidAltAddr != True) && (bEdidAltAddr != False)) + RETIF_BADPARAM(!IS_VALID_FMT(vinFmt)) + RETIF_BADPARAM(pixRate >= HDMITX_PIXRATE_INVALID) + + /* Set all Device Instance Structure members to default values */ + lmemcpy(pDis, &kHdmiTxInstanceDefault, sizeof(*pDis)); + + /* Copy txUnit, uHwAddress, sysFuncWrite and sysFuncRead values to + * the defaulted Device Instance Structure BEFORE FIRST DEVICE ACCESS. + */ + pDis->txUnit = txUnit; +#ifdef UNIT_TEST + /* Unit test build can't support 127 device sets of dummy registers, so use + * smaller range instead, indexed by unit number not I2C address */ + pDis->uHwAddress = (UInt8)txUnit; +#else + /* Store actual I2C address */ + pDis->uHwAddress = uHwAddress; +#endif + pDis->sysFuncWrite = sysFuncWrite; + pDis->sysFuncRead = sysFuncRead; + pDis->sysFuncEdidRead = sysFuncEdidRead; + pDis->sysFuncTimer = sysFuncTimer; + + /* IF the funcIntCallbacks array pointer is defined + * THEN for each funcIntCallbacks pointer that is not null: + * - Copy the pointer to the Device Instance Structure + * funcIntCallbacks array. + */ + + for (i = 0; i < HDMITX_CALLBACK_INT_NUM; i++) + { + if ((funcIntCallbacks != (tmbslHdmiTxCallbackList_t *)0) + && (funcIntCallbacks->funcCallback[i] != (ptmbslHdmiTxCallback_t)0)) + { + pDis->funcIntCallbacks[i] = funcIntCallbacks->funcCallback[i]; + } + else + { + pDis->funcIntCallbacks[i] = (ptmbslHdmiTxCallback_t)0; + } + } + + /* Set the EDID alternate address flag if needed*/ + pDis->bEdidAlternateAddr = bEdidAltAddr; + +//*****************************************************************************************// +//*****************************************************************************************// +//**********************Enable HDMI and RxSense************************/// + + /* reset ENAMODS */ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, 0x40); + RETIF_REG_FAIL(err) + + + + + + /*Read data out of ENAMODS CEC Register */ + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &EnableModeMask); + + /*Enable required modes*/ + EnableModeMask |= E_MASKREG_CEC_ENAMODS_ena_hdmi; /*Enable HDMI Mode*/ + EnableModeMask |= E_MASKREG_CEC_ENAMODS_ena_rxs; /*Enable RxSense Mode*/ + EnableModeMask &= ~E_MASKREG_CEC_ENAMODS_dis_fro; /* Enable FRO */ + + /*Write data in ENAMODS CEC Register */ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, EnableModeMask); + + pDis->ePowerState = (tmbslHdmiTxPowerState_t) tmPowerOn; + + /* Set the bInitialized flag to enable other APIs */ + pDis->bInitialized = True; + + /* Reset the device */ + err = tmbslTDA9989Reset(txUnit); + RETIF(err != TM_OK, err) + +//***************************************************************************************// +//****************Get Device Version and Capabilities************************************// + /* Read the device version register to uDeviceVersion in the + * Device Instance Structure + */ + err = getHwRegister(pDis, E_REG_P00_VERSION_R, ®Val); + RETIF(err != TM_OK, err) + + /* Copy N4 features bits to DIS */ + pDis->uDeviceFeatures = regVal & + (E_MASKREG_P00_VERSION_not_h | E_MASKREG_P00_VERSION_not_s); + + pDis->uDeviceVersion = regVal; + + /* Get MSB version Value*/ + err = getHwRegister(pDis, E_REG_P00_VERSION_MSB_RW, ®Val); + RETIF(err != TM_OK, err) + + /* Build Device Version Info */ + val16Bits = regVal; + pDis->uDeviceVersion = pDis->uDeviceVersion | (val16Bits << 8); + val16Bits = pDis->uDeviceFeatures; + pDis->uDeviceVersion &= ~val16Bits; + + if (pDis->uDeviceVersion != E_DEV_VERSION_LIST_END) + { + /* Search for the device version in the Supported Version + * List in the Device Instance Structure. + */ + for (i = 0, bFound = False; i < E_DEV_VERSION_LIST_NUM; i++) + { + if (pDis->uDeviceVersion == pDis->uSupportedVersions[i]) + { + bFound = True; + } + } + if (bFound == False) + { + /* IF the device version is not found in the Supported Version List THEN + * this driver component is not compatible with the device.*/ + err = tmbslTDA9989Deinit(txUnit); + RETIF(err != TM_OK, err) + return TMBSL_ERR_HDMI_COMPATIBILITY; + } + } + else + { + /* Quit if version reads zero */ + err = tmbslTDA9989Deinit(txUnit); + RETIF(err != TM_OK, err) + return TMBSL_ERR_HDMI_COMPATIBILITY; + } + +/***************************************************************************************/ +/************Set the BIAS_tmds Value (general control for Analogu module)***************/ + regVal = HDMI_TX_VSWING_VALUE; + + err = setHwRegister(pDis, E_REG_P02_ANA_GENERAL_RW, regVal); + RETIF(err != TM_OK, err) + +/*****************************************************************************************/ +/*****************************************************************************************/ + + /* Set the PLL before resetting the device */ + /* PLL registers common configuration */ + err = setHwRegisterFieldTable(pDis, &kCommonPllCfg[0]); + RETIF_REG_FAIL(err) + + /*Reset 656_Alt bit in VIP_CONTROL_4 Register*/ + err = setHwRegisterField( pDis, E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_656_alt, 0); + + switch (vinFmt) + { + /* 480i or 576i video input format */ + case HDMITX_VFMT_06_720x480i_60Hz: + case HDMITX_VFMT_07_720x480i_60Hz: + case HDMITX_VFMT_21_720x576i_50Hz: + case HDMITX_VFMT_22_720x576i_50Hz: + err = setHwRegisterFieldTable(pDis, &kVfmt480i576iPllCfg[0]); + RETIF_REG_FAIL(err) + + switch (pixRate) + { + case HDMITX_PIXRATE_SINGLE: + /* Single edge mode, vinFmt 480i or 576i */ + err = setHwRegisterFieldTable(pDis, &kSinglePrateVfmt480i576iPllCfg[0]); + RETIF_REG_FAIL(err) + + break; + case HDMITX_PIXRATE_SINGLE_REPEATED: + /* Single repeated edge mode, vinFmt 480i or 576i */ + err = setHwRegisterFieldTable(pDis, &kSrepeatedPrateVfmt480i576iPllCfg[0]); + RETIF_REG_FAIL(err) + + break; + default: + /* Double edge mode doesn't exist for vinFmt 480i or 576i */ + return(TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + + break; + + + /* Others video input format */ + default: + err = setHwRegisterFieldTable(pDis, &kVfmtOtherPllCfg[0]); + RETIF_REG_FAIL(err) + + switch (pixRate) + { + case HDMITX_PIXRATE_SINGLE: + /* Single edge mode, vinFmt other than 480i or 576i */ + err = setHwRegisterFieldTable(pDis, &kSinglePrateVfmtOtherPllCfg[0]); + RETIF_REG_FAIL(err) + break; + case HDMITX_PIXRATE_DOUBLE: + /* Double edge mode, vinFmt other than 480i or 576i */ + err = setHwRegisterFieldTable(pDis, &kDoublePrateVfmtOtherPllCfg[0]); + RETIF_REG_FAIL(err) + break; + default: + /* Single repeated edge mode doesn't exist for other vinFmt */ + return(TMBSL_ERR_HDMI_INCONSISTENT_PARAMS); + } + break; + + } + + /* DDC interface is disable for TDA9989 after reset, enable it */ + err = setHwRegister(pDis, E_REG_P00_DDC_DISABLE_RW, 0x00); + RETIF(err != TM_OK, err) + + /* Set clock speed of the DDC channel */ + + err = setHwRegister(pDis, E_REG_P12_TX3_RW, TDA19989_DDC_SPEED_FACTOR); + RETIF(err != TM_OK, err) + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + err = setHwRegisterField(pDis, + E_REG_P00_I2C_MASTER_RW, + E_MASKREG_P00_I2C_MASTER_dis_mm, + 0); /* 0: enable multi master mode */ + RETIF_REG_FAIL(err) + + } /* TDA19989 N1 only */ + + + err = setCECHwRegister(pDis, E_REG_CEC_FRO_IM_CLK_CTRL_RW, E_MASKREG_CEC_FRO_IM_CLK_CTRL_ghost_dis | E_MASKREG_CEC_FRO_IM_CLK_CTRL_imclk_sel); + RETIF_REG_FAIL(err) + + /* The DIS hotplug status is HDMITX_HOTPLUG_INVALID, so call the main + * interrupt handler to read the current Hot Plug status and run any + * registered HPD callback before interrupts are enabled below */ + //err = tmbslTDA9989HwHandleInterrupt(txUnit); + RETIF(err != TM_OK, err) + + /* enable sw _interrupt and VS_interrupt for debug */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_1_RW, + E_MASKREG_P00_INT_FLAGS_1_sw_int); + + /* enable edid read */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_2_RW, + E_MASKREG_P00_INT_FLAGS_2_edid_blk_rd); + + + /* Read HPD RXS level */ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,®Val); + RETIF(err != TM_OK, err) + + /* Read Hot Plug input status to know the actual level that caused the interrupt */ + pDis->hotPlugStatus = (regVal & E_MASKREG_CEC_RXSHPDLEV_hpd_level) ? + HDMITX_HOTPLUG_ACTIVE : HDMITX_HOTPLUG_INACTIVE; + + /*Read RXS_FIL status to know the actual level that caused the interrupt */ + pDis->rxSenseStatus = (regVal & E_MASKREG_CEC_RXSHPDLEV_rxs_level) ? + HDMITX_RX_SENSE_ACTIVE : HDMITX_RX_SENSE_INACTIVE; + + /*Disable required Interrupts*/ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, &EnableIntMask); + EnableIntMask |= E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int; /* Enable RxSense Interrupt*/ + EnableIntMask |= E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int; /* Enable HPD Interrupt*/ + + /* Switch BSL State machine into UNINITIALIZED State */ + setState(pDis, EV_INIT); + + /*Write data in RXSHPD Register*/ + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, EnableIntMask); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,&int_level); + + /* Enable HPD and RX sense IT after first call done by init function */ + gMiscInterruptHpdRxEnable = True; + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989PowerGetState */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989PowerGetState +( + tmUnitSelect_t txUnit, + tmPowerState_t *pePowerState +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check remaining parameters */ + RETIF_BADPARAM(pePowerState == (tmPowerState_t)0) + + /*return parameter*/ + *pePowerState = (tmPowerState_t) pDis->ePowerState; + + return TM_OK; +} + + +/*============================================================================*/ +/* tmbslTDA9989PowerSetState */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989PowerSetState +( + tmUnitSelect_t txUnit, + tmPowerState_t ePowerState +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 RegVal = 0; /* Local Variable */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + if (ePowerState == tmPowerOff) { + ePowerState = tmPowerStandby; + } + + + /* Check remaining parameters */ + RETIF_BADPARAM((ePowerState != tmPowerStandby) + &&(ePowerState != tmPowerSuspend) + &&(ePowerState != tmPowerOn) + ) + + if ((ePowerState == tmPowerStandby)&&(pDis->ePowerState != tmPowerStandby)) + { + /*Disable HPD and RxSense Interrupts*/ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, &RegVal); + RegVal &= ~E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int; + RegVal &= ~E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int; + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, RegVal); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,&int_level); + RETIF_REG_FAIL(err) + + /* Disable if coming from ACTIVE */ + if (pDis->ePowerState == tmPowerOn) + { + + /* Disable audio and video ports */ + err = setHwRegister(pDis, + E_REG_P00_ENA_AP_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_0_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_1_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_2_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + /* Disable DDC */ + err = setHwRegisterField(pDis, + E_REG_P00_DDC_DISABLE_RW, + E_MASKREG_P00_DDC_DISABLE_ddc_dis, + 1); /* 1: disable */ + RETIF_REG_FAIL(err); + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + /* power down clocks */ + tmbslTDA9989HdcpPowerDown(txUnit,True); + err = setHwRegisterField(pDis, E_REG_FEAT_POWER_DOWN, \ + E_MASKREG_FEAT_POWER_DOWN_all, \ + 0x0F); +#endif + } + + /*Disable HDMI and RxSense Modes AND FRO if required*/ + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RegVal &= ~E_MASKREG_CEC_ENAMODS_ena_hdmi; /* Reset HDMI Mode*/ + + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RETIF_REG_FAIL(err) + RegVal |= E_MASKREG_CEC_ENAMODS_ena_hdmi; /* Set HDMI Mode*/ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RegVal &= ~E_MASKREG_CEC_ENAMODS_ena_hdmi; /* Reset HDMI Mode*/ + + RegVal &= ~E_MASKREG_CEC_ENAMODS_ena_rxs; /* Reset RxSense Mode*/ + + + /* disable FRO */ + RegVal |= E_MASKREG_CEC_ENAMODS_dis_fro; + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + + /*Send STANDBY event to the BSL State Machine */ + setState(pDis, EV_STANDBY); + } + else if ((ePowerState == tmPowerSuspend)&&(pDis->ePowerState != tmPowerSuspend)) + { + + /* Disable if coming from ACTIVE */ + if (pDis->ePowerState == tmPowerOn) + { + /* Disable audio and video ports */ + err = setHwRegister(pDis, + E_REG_P00_ENA_AP_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_0_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_1_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_2_RW, + 0x00); /* 0: disable */ + RETIF_REG_FAIL(err); + + /* Disable DDC */ + err = setHwRegisterField(pDis, + E_REG_P00_DDC_DISABLE_RW, + E_MASKREG_P00_DDC_DISABLE_ddc_dis, + 1); /* 1: disable */ + RETIF_REG_FAIL(err); + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + /* power down clocks */ + tmbslTDA9989HdcpPowerDown(txUnit,True); + err = setHwRegisterField(pDis, E_REG_FEAT_POWER_DOWN, \ + E_MASKREG_FEAT_POWER_DOWN_all, \ + 0x0F); +#endif + } + + /*Enable RxSense Mode and Disable HDMI Mode*/ + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RegVal &= ~E_MASKREG_CEC_ENAMODS_ena_hdmi; /* Reset HDMI Mode*/ + RegVal |= E_MASKREG_CEC_ENAMODS_ena_rxs; /* Set RxSense Mode*/ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + /*Enable HPD and RxS Interupt in case of the current Device Power States is STANDBY*/ + /*In other cases, those interrupts have already been enabled*/ + if(pDis->ePowerState == tmPowerStandby) + { + /* Enable FRO if coming from STANDBY */ + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RegVal &= ~E_MASKREG_CEC_ENAMODS_dis_fro; /* Enable FRO */ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + /*Enable HPD and RxS Interupt*/ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, &RegVal); + RegVal |= E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int; /* Enable HPD Interrupt*/ + RegVal |= E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int; /* Enable RxSense Interrupt*/ + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, RegVal); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,&int_level); + RETIF_REG_FAIL(err) + + /* force interrupt HPD and RXS level reading */ + err = tmbslTDA9989HwHandleInterrupt(txUnit); + RETIF(err != TM_OK, err) + + + } + + /*Send the SLEEP event to the BSL State Machine */ + setState(pDis, EV_SLEEP); + + } + + else if ((ePowerState == tmPowerOn)&&(pDis->ePowerState != tmPowerOn)) + { + + /* Enable RxSense HDMI Modes */ + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RegVal |= E_MASKREG_CEC_ENAMODS_ena_hdmi; /* Set HDMI Mode*/ + RegVal |= E_MASKREG_CEC_ENAMODS_ena_rxs; /* Set RxSense Mode*/ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + /*Enable HPD and RxS Interupt in case of the current Device Power States is STANDBY*/ + /*In other cases, those interrupts have already been enabled*/ + if(pDis->ePowerState == tmPowerStandby) + { + /* Enable FRO if coming from STANDBY */ + err = getCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, &RegVal); + RegVal &= ~E_MASKREG_CEC_ENAMODS_dis_fro; /* Enable FRO */ + err = setCECHwRegister(pDis, E_REG_CEC_ENAMODS_RW, RegVal); + RETIF_REG_FAIL(err) + + + /*Apply the required mode, Reset RxS and HDMI bits*/ + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, &RegVal); + RegVal |= E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int; /* Enable HPD Interrupt*/ + RegVal |= E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int; /* Enable RxSense Interrupt*/ + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, RegVal); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,&int_level); + RETIF_REG_FAIL(err) + } + + + /* Restore BIAS TMDS */ + RegVal = HDMI_TX_VSWING_VALUE; + err = setHwRegister(pDis, E_REG_P02_ANA_GENERAL_RW, RegVal); + RETIF(err != TM_OK, err) + + + err = tmbslTDA9989Reset(txUnit); + RETIF(err != TM_OK, err) + + + err = setHwRegisterField( pDis, E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_656_alt, 0); + + err = setHwRegister(pDis, E_REG_P12_TX3_RW, TDA19989_DDC_SPEED_FACTOR); + RETIF(err != TM_OK, err) + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + err = setHwRegisterField(pDis, + E_REG_P00_I2C_MASTER_RW, + E_MASKREG_P00_I2C_MASTER_dis_mm, + 0); + RETIF_REG_FAIL(err) + + } /* TDA19989 N1 only */ + + err = setCECHwRegister(pDis, E_REG_CEC_FRO_IM_CLK_CTRL_RW, E_MASKREG_CEC_FRO_IM_CLK_CTRL_ghost_dis | E_MASKREG_CEC_FRO_IM_CLK_CTRL_imclk_sel); + RETIF_REG_FAIL(err) + +#ifdef TMFL_HDCP_SUPPORT + if (pDis->HdcpSeed) { + err = tmbslTDA9989HdcpDownloadKeys(txUnit, pDis->HdcpSeed, HDMITX_HDCP_DECRYPT_ENABLE); + } +#endif /* TMFL_HDCP_SUPPORT */ + + + /* Enable DDC */ + err = setHwRegisterField(pDis, + E_REG_P00_DDC_DISABLE_RW, + E_MASKREG_P00_DDC_DISABLE_ddc_dis, + 0); /* 0: enable */ + RETIF_REG_FAIL(err) + + /* Enable audio and video ports */ + err = setHwRegister(pDis, + E_REG_P00_ENA_AP_RW, + 0xFF); /* 1: enable */ + RETIF_REG_FAIL(err) + + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_0_RW, + 0xFF); /* 1: enable */ + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_1_RW, + 0xFF); /* 1: enable */ + RETIF_REG_FAIL(err) + + err = setHwRegister(pDis, + E_REG_P00_ENA_VP_2_RW, + 0xFF); /* 1: enable */ + RETIF_REG_FAIL(err) + + + /*Send the Hot Plug detection status event to the BSL State Machine */ + if (pDis->hotPlugStatus == HDMITX_HOTPLUG_ACTIVE) + { + setState(pDis, EV_PLUGGEDIN); + } + else + { + setState(pDis, EV_UNPLUGGED); + } + + } + + /* Set the current Device Power status to the required Power Status */ + pDis->ePowerState = (tmbslHdmiTxPowerState_t) ePowerState; + + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989Reset */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989Reset +( + tmUnitSelect_t txUnit +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to its object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Reset I2C master and Audio*/ + (void)setHwRegisterField(pDis, E_REG_P00_SR_REG_W, + E_MASKREG_P00_SR_REG_sr_i2c_ms | + E_MASKREG_P00_SR_REG_sr_audio, 1); + + pDis->sysFuncTimer(50); /* ms */ + + (void)setHwRegisterField(pDis, E_REG_P00_SR_REG_W, + E_MASKREG_P00_SR_REG_sr_i2c_ms | + E_MASKREG_P00_SR_REG_sr_audio, 0); + + pDis->sysFuncTimer(50); /* ms */ + + /* Write to the transmitter to do a soft reset. Don't abort after any + * error here, to ensure full reset. + */ + (void)setHwRegisterField(pDis, E_REG_P00_MAIN_CNTRL0_RW, + E_MASKREG_P00_MAIN_CNTRL0_sr, 1); + /* pDis->sysFuncTimer(50); */ /* ms */ + (void)setHwRegisterField(pDis, E_REG_P00_MAIN_CNTRL0_RW, + E_MASKREG_P00_MAIN_CNTRL0_sr, 0); + /* pDis->sysFuncTimer(50); */ /* ms */ + /* Clear any colourbars */ + (void)setHwRegisterField(pDis, E_REG_P00_HVF_CNTRL_0_W, + E_MASKREG_P00_HVF_CNTRL_0_sm, 0); + +#ifdef TMFL_HDCP_SUPPORT + /* Disable any scheduled function and HDCP check timer */ + pDis->HdcpFuncRemainingMs = 0; + pDis->HdcpCheckNum = 0; +#endif /* TMFL_HDCP_SUPPORT */ + + /* Switch BSL State machine into UNINITIALIZED State */ + setState(pDis, EV_DEINIT); + /* Switch Power State into STAND_BY State */ + //pDis->ePowerState = tmPowerStandby; + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989SwGetVersion */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SwGetVersion +( + ptmSWVersion_t pSWVersion +) +{ + /* Check parameters */ + RETIF_BADPARAM(pSWVersion == (ptmSWVersion_t)0) + + /* Get the version details of the component. */ + pSWVersion->compatibilityNr = HDMITX_BSL_COMP_NUM; + pSWVersion->majorVersionNr = HDMITX_BSL_MAJOR_VER; + pSWVersion->minorVersionNr = HDMITX_BSL_MINOR_VER; + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989SysTimerWait */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SysTimerWait +( + tmUnitSelect_t txUnit, + UInt16 waitMs +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Return if this device timer is not set up */ + RETIF(!pDis->sysFuncTimer, TMBSL_ERR_HDMI_NOT_INITIALIZED) + + /* Wait for the requested time */ + pDis->sysFuncTimer(waitMs); + + return TM_OK; +} + +/*============================================================================*/ +/* tmbslTDA9989TestSetMode */ +/*============================================================================*/ + +tmErrorCode_t +tmbslTDA9989TestSetMode +( + tmUnitSelect_t txUnit, + tmbslHdmiTxTestMode_t testMode, + tmbslHdmiTxTestState_t testState +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + /* Register used to activate a test */ + UInt16 testReg = E_REG_P00_VIP_CNTRL_4_W; + /* Register bitfield mask used */ + UInt8 testMask = E_MASKREG_P00_VIP_CNTRL_4_tst_pat; + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM(testMode >= HDMITX_TESTMODE_INVALID) + RETIF_BADPARAM(testState >= HDMITX_TESTSTATE_INVALID) + + /* Set the mode selected by testMode to the state indicated by testState */ + switch (testMode) + { + case HDMITX_TESTMODE_PAT: + testReg = E_REG_P00_VIP_CNTRL_4_W; + testMask = E_MASKREG_P00_VIP_CNTRL_4_tst_pat; + break; + case HDMITX_TESTMODE_656: + testReg = E_REG_P00_VIP_CNTRL_4_W; + testMask = E_MASKREG_P00_VIP_CNTRL_4_tst_656; + break; + case HDMITX_TESTMODE_SERPHOE: + /*testReg = E_REG_P02_TEST1_RW; + testMask = E_MASKREG_P02_TEST1_tstserphoe;*/ + break; + case HDMITX_TESTMODE_NOSC: + testReg = E_REG_P02_TEST1_RW; + testMask = E_MASKREG_P02_TEST1_tst_nosc; + break; + case HDMITX_TESTMODE_HVP: + /*testReg = E_REG_P02_TEST1_RW; + testMask = E_MASKREG_P02_TEST1_tst_hvp;*/ + break; + case HDMITX_TESTMODE_PWD: + /*testReg = E_REG_P02_TEST2_RW; + testMask = E_MASKREG_P02_TEST2_pwd1v8;*/ + break; + case HDMITX_TESTMODE_DIVOE: + /*testReg = E_REG_P02_TEST2_RW; + testMask = E_MASKREG_P02_TEST2_divtestoe;*/ + break; + case HDMITX_TESTMODE_INVALID: + break; + } + err = setHwRegisterField(pDis, testReg, testMask, (UInt8)testState); + return err; +} + +/*============================================================================*/ +/** + \brief Fill Gamut metadata packet into one of the gamut HW buffer. this + function is not sending any gamut metadata into the HDMI stream, + it is only loading data into the HW. + + \param txUnit Transmitter unit number + \param pPkt pointer to the gamut packet structure + \param bufSel number of the gamut buffer to fill + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_BSLHDMIRX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_BSLHDMIRX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_BSLHDMIRX_I2C_WRITE: failed when writing to the I2C + bus + + ******************************************************************************/ +tmErrorCode_t tmbslTDA9989PktFillGamut +( + tmUnitSelect_t txUnit, + tmbslHdmiTxPktGamut_t *pPkt, + UInt8 bufSel +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM((bufSel != 0) && (bufSel != 1)) + + /* Fill Gamut registers*/ + /*Fill buffer 0*/ + if(bufSel == 0) + { + /*Write Header*/ + err = setHwRegisters(pDis, E_REG_P13_GMD_0_HB0_RW, &pPkt->HB[0], 3); + RETIF(err != TM_OK, err) + /*Write Payload*/ + err = setHwRegisters(pDis, E_REG_P13_GMD_0_PB0_RW, &pPkt->PB[0], 28); + RETIF(err != TM_OK, err) + } + + /*Fill buffer 1*/ + else + { + /*Write Header*/ + err = setHwRegisters(pDis, E_REG_P13_GMD_1_HB0_RW, &pPkt->HB[0], 3); + RETIF(err != TM_OK, err) + /*Write Payload*/ + err = setHwRegisters(pDis, E_REG_P13_GMD_1_PB0_RW, &pPkt->PB[0], 28); + RETIF(err != TM_OK, err) + } + +return err; +} + +/*============================================================================*/ +/** + \brief Enable transmission of gamut metadata packet. Calling this function + tells HW which gamut buffer to send into the HDMI stream. HW will + only take into account this command at the next VS, not during the + current one. + + \param txUnit Transmitter unit number + \param bufSel Number of the gamut buffer to be sent + \param enable Enable/disable gamut packet transmission + + \return The call result: + - TM_OK: the call was successful + - TMBSL_ERR_BSLHDMIRX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMBSL_ERR_BSLHDMIRX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_BSLHDMIRX_I2C_WRITE: failed when writing to the I2C + bus + + ******************************************************************************/ +tmErrorCode_t tmbslTDA9989PktSendGamut +( + tmUnitSelect_t txUnit, + UInt8 bufSel, + Bool bEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 GMD_Ctrl_Val; /*GMD control Value*/ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM((bufSel != 0) && (bufSel != 1)) + + /*Init Value*/ + GMD_Ctrl_Val = 0x00; + + /*Enable Send of Gamut MetaData*/ + if(bEnable) + { + /*Send Buffer 0*/ + if(bufSel == 0) + { + GMD_Ctrl_Val |= E_MASKREG_P13_GMD_CONTROL_enable; + GMD_Ctrl_Val &= ~E_MASKREG_P13_GMD_CONTROL_buf_sel; + err = setHwRegister(pDis, E_REG_P13_GMD_CONTROL_RW, GMD_Ctrl_Val); + RETIF(err != TM_OK, err) + } + /*Send Buffer 1*/ + else + { + GMD_Ctrl_Val |= E_MASKREG_P13_GMD_CONTROL_enable; + GMD_Ctrl_Val |= E_MASKREG_P13_GMD_CONTROL_buf_sel; + err = setHwRegister(pDis, E_REG_P13_GMD_CONTROL_RW, GMD_Ctrl_Val); + RETIF(err != TM_OK, err) + } + } + /*Disable Send of Gamut MetaData*/ + else + { + GMD_Ctrl_Val &= ~E_MASKREG_P13_GMD_CONTROL_enable; + GMD_Ctrl_Val &= ~E_MASKREG_P13_GMD_CONTROL_buf_sel; + err = setHwRegister(pDis, E_REG_P13_GMD_CONTROL_RW, GMD_Ctrl_Val); + RETIF(err != TM_OK, err) + } + + return err; +} + + + + +/*============================================================================*/ +/* tmbslTDA9989EnableCallback */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989EnableCallback +( + tmUnitSelect_t txUnit, + tmbslHdmiTxCallbackInt_t callbackSource, + Bool enable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err = TM_OK; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM( callbackSource >= HDMITX_CALLBACK_INT_NUM ) + + switch (callbackSource) + { + case HDMITX_CALLBACK_INT_VS_RPT: + /* Enable or disable VS Interrupt */ + err = setHwRegisterField(pDis, + E_REG_P00_INT_FLAGS_1_RW, + E_MASKREG_P00_INT_FLAGS_1_vs_rpt, + (UInt8)enable); + if (enable) + { + pDis->InterruptsEnable |= (1 << callbackSource); + } + else + { + pDis->InterruptsEnable &= ~(1 << callbackSource); + } + break; + default: + err = TMBSL_ERR_HDMI_NOT_SUPPORTED; + break; + } + + return err; +} + +/*============================================================================*/ +/* tmbslTDA9989SetColorDepth */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SetColorDepth +( + tmUnitSelect_t txUnit, + tmbslHdmiTxColorDepth colorDepth, + Bool termEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err = TM_OK; /* Error code */ + + DUMMY_ACCESS(termEnable); + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Check parameters */ + RETIF_BADPARAM( colorDepth >= HDMITX_COLORDEPTH_INVALID ) + + switch (colorDepth) + { + case HDMITX_COLORDEPTH_NO_CHANGE: + break; + + case HDMITX_COLORDEPTH_24: + + break; + + default: + err = TMBSL_ERR_HDMI_NOT_SUPPORTED; + break; + } + + return err; + +} + + +/*============================================================================*/ +/* tmbslTDA9989Set5vpower */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989Set5vpower +( + tmUnitSelect_t txUnit, + Bool pwrEnable +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + DUMMY_ACCESS(pwrEnable); + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + +/*============================================================================*/ +/* tmbslTDA9989SetDefaultPhase */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989SetDefaultPhase +( + tmUnitSelect_t txUnit, + Bool bEnable, + tmbslHdmiTxColorDepth colorDepth, + UInt8 videoFormat +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + DUMMY_ACCESS(bEnable); + DUMMY_ACCESS(colorDepth); + DUMMY_ACCESS(videoFormat); + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + return TMBSL_ERR_HDMI_NOT_SUPPORTED; +} + + + +/*============================================================================*/ +/* tmbslDebugWriteFakeRegPage */ +/*============================================================================*/ +tmErrorCode_t tmbslDebugWriteFakeRegPage( tmUnitSelect_t txUnit ) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + err = checkUnitSetDis(txUnit, &pDis); + + pDis->curRegPage = 0x20; + + return err; +} + + +/*============================================================================*/ +/* hotPlugRestore */ +/*============================================================================*/ +tmErrorCode_t hotPlugRestore ( tmUnitSelect_t txUnit ) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; + UInt8 EnableIntMask = 0; /* Mask used to enable HPD and RX Sense interrupt*/ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Set the BIAS_tmds Value */ + regVal = HDMI_TX_VSWING_VALUE; + err = setHwRegister(pDis, E_REG_P02_ANA_GENERAL_RW, regVal); + RETIF(err != TM_OK, err) + + /* PLL registers common configuration */ + err = setHwRegisterFieldTable(pDis, &kCommonPllCfg[0]); + RETIF_REG_FAIL(err) + + /*Reset 656_Alt bit in VIP_CONTROL_4 Register*/ + err = setHwRegisterField( pDis, E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_656_alt, 0); + + /* DDC interface is disable for TDA9989 after reset, enable it */ + err = setHwRegister(pDis, E_REG_P00_DDC_DISABLE_RW, 0x00); + RETIF(err != TM_OK, err) + + err = setHwRegister(pDis, E_REG_P12_TX3_RW, TDA19989_DDC_SPEED_FACTOR); + RETIF(err != TM_OK, err) + + /* TDA19989 N1 only */ + if (pDis->uDeviceVersion == E_DEV_VERSION_TDA19989) { + + err = setHwRegisterField(pDis, + E_REG_P00_I2C_MASTER_RW, + E_MASKREG_P00_I2C_MASTER_dis_mm, + 0); /* 0: enable multi master mode */ + RETIF_REG_FAIL(err) + + } /* TDA19989 N1 only */ + + + err = setCECHwRegister(pDis, E_REG_CEC_FRO_IM_CLK_CTRL_RW, E_MASKREG_CEC_FRO_IM_CLK_CTRL_ghost_dis | E_MASKREG_CEC_FRO_IM_CLK_CTRL_imclk_sel); + RETIF_REG_FAIL(err) + + + + + /* enable sw_interrupt for debug */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_1_RW, + E_MASKREG_P00_INT_FLAGS_1_sw_int); + + /* enable edid read */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_2_RW, + E_MASKREG_P00_INT_FLAGS_2_edid_blk_rd); + + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, &EnableIntMask); + EnableIntMask |= E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int; /* Enable RxSense Interrupt*/ + EnableIntMask |= E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int; /* Enable HPD Interrupt*/ + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, EnableIntMask); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,&int_level); + +#ifdef TMFL_HDCP_SUPPORT + + if (pDis->HdcpSeed) + { + err = tmbslTDA9989HdcpDownloadKeys(txUnit, pDis->HdcpSeed, HDMITX_HDCP_DECRYPT_ENABLE); + } + +#endif /* TMFL_HDCP_SUPPORT */ + + setState(pDis, EV_INIT); + + return err; +} + +#ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC + +tmErrorCode_t hotPlugRestore ( tmUnitSelect_t txUnit ) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + UInt8 regVal; + UInt8 EnableIntMask = 0; /* Mask used to enable HPD and RX Sense interrupt*/ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err) + + /* Set the BIAS_tmds Value */ + regVal = HDMI_TX_VSWING_VALUE; + err = setHwRegister(pDis, E_REG_P02_ANA_GENERAL_RW, regVal); + RETIF(err != TM_OK, err) + + /* PLL registers common configuration */ + err = setHwRegisterFieldTable(pDis, &kCommonPllCfg[0]); + RETIF_REG_FAIL(err) + + /*Reset 656_Alt bit in VIP_CONTROL_4 Register*/ + err = setHwRegisterField( pDis, E_REG_P00_VIP_CNTRL_4_W, E_MASKREG_P00_VIP_CNTRL_4_656_alt, 0); + + /* DDC interface is disable for TDA9989 after reset, enable it */ + err = setHwRegister(pDis, E_REG_P00_DDC_DISABLE_RW, 0x00); + RETIF(err != TM_OK, err) + + + + if ( (pDis->vinFmt != HDMITX_VFMT_NO_CHANGE) && (pDis->vinFmt <= HDMITX_VFMT_TV_MAX ) ) { + + err = setHwRegister(pDis, E_REG_P00_TIMER_H_W, 0); + RETIF(err != TM_OK, err) + + err = setHwRegister(pDis, E_REG_P00_NDIV_IM_W, kndiv_im[pDis->vinFmt]); + RETIF(err != TM_OK, err) + + err = setHwRegister(pDis, E_REG_P12_TX3_RW, kclk_div[pDis->vinFmt]); + RETIF(err != TM_OK, err) + + } + else if (pDis->vinFmt > HDMITX_VFMT_TV_MAX) { + + err = setHwRegister(pDis, E_REG_P00_TIMER_H_W, E_MASKREG_P00_TIMER_H_im_clksel); + RETIF(err != TM_OK, err) + err = setHwRegister(pDis, E_REG_P12_TX3_RW, 17); + RETIF(err != TM_OK, err) + } + + + + + + /* enable sw_interrupt for debug */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_1_RW, + E_MASKREG_P00_INT_FLAGS_1_sw_int); + + /* enable edid read */ + err = setHwRegister(pDis, E_REG_P00_INT_FLAGS_2_RW, + E_MASKREG_P00_INT_FLAGS_2_edid_blk_rd); + + err = getCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, &EnableIntMask); + EnableIntMask |= E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int; /* Enable RxSense Interrupt*/ + EnableIntMask |= E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int; /* Enable HPD Interrupt*/ + err += setCECHwRegister(pDis, E_REG_CEC_RXSHPDINTENA_RW, EnableIntMask); + err += getCECHwRegister(pDis, E_REG_CEC_RXSHPDLEV_R,&int_level); + + return err; +} + +#endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + +#ifdef TMFL_HDCP_OPTIMIZED_POWER +/*============================================================================*/ +/* tmbslTDA9989HdcpPowerDown */ +/* RETIF_REG_FAIL NOT USED HERE AS ALL ERRORS SHOULD BE TRAPPED IN ALL BUILDS */ +/*============================================================================*/ +tmErrorCode_t +tmbslTDA9989HdcpPowerDown +( + tmUnitSelect_t txUnit, + Bool requested +) +{ + tmHdmiTxobject_t *pDis; /* Pointer to Device Instance Structure */ + tmErrorCode_t err; /* Error code */ + + /* Check unit parameter and point to TX unit object */ + err = checkUnitSetDis(txUnit, &pDis); + RETIF(err != TM_OK, err); + + err = setHwRegisterField(pDis, E_REG_P12_TX4_RW, \ + E_MASKREG_P12_TX4_pd_all, \ + (requested?0x07:0x00)); + return err; + +} +#endif + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc_l.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc_l.h new file mode 100755 index 0000000000000..e221ccb196924 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_Misc_l.h @@ -0,0 +1,62 @@ +/** + * Copyright (C) 2009 Koninklijke Philips Electronics N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of Koninklijke Philips Electronics N.V. and is confidential in + * nature. Under no circumstances is this software to be exposed to or placed + * under an Open Source License of any type without the expressed written + * permission of Koninklijke Philips Electronics N.V. + * + * \file tmbslTDA9989_Misc_l.h + * + * \version $Revision: 2 $ + * +*/ + +#ifndef TMBSLTDA9989_MISC_L_H +#define TMBSLTDA9989_MISC_L_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* EXTERN DATA DEFINITION */ +/*============================================================================*/ + +#ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC +extern CONST_DAT UInt8 kndiv_im[]; +extern CONST_DAT UInt8 kclk_div[]; +#endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +tmErrorCode_t hotPlugRestore ( tmUnitSelect_t txUnit ); + +#ifdef TMFL_TDA9989_PIXEL_CLOCK_ON_DDC +tmErrorCode_t hotPlugRestore ( tmUnitSelect_t txUnit ); +#endif /* TMFL_TDA9989_PIXEL_CLOCK_ON_DDC */ + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_MISC_L_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State.c b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State.c new file mode 100755 index 0000000000000..64abb913a5c80 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State.c @@ -0,0 +1,240 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_state.c + * + * \version $Revision: 2 $ + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#include +#endif + +#include "tmbslTDA9989_Functions.h" +#include "tmbslTDA9989_local.h" +#include "tmbslTDA9989_State_l.h" + + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* DEFINES DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/*============================================================================*/ +/* setState */ +/*============================================================================*/ +tmErrorCode_t +setState +( + tmHdmiTxobject_t *pDis, + tmbslTDA9989Event_t event +) +{ + tmbslTDA9989State_t state = pDis->state; + UInt8 nIgnoredEvents = pDis->nIgnoredEvents; + + switch (state) + { + case ST_UNINITIALIZED: + switch (event) + { + case EV_INIT: state = ST_STANDBY; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_PLUGGEDIN: state = ST_AWAIT_EDID; break; + default: nIgnoredEvents++; break; + } + break; + + case ST_STANDBY: + switch (event) + { + case EV_UNPLUGGED: state = ST_DISCONNECTED; break; /*Only when PowerSetState(ON)*/ + case EV_PLUGGEDIN: state = ST_AWAIT_EDID; break; /*Only when PowerSetState(ON)*/ + case EV_SLEEP: state = ST_SLEEP; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_SETINOUT: state = ST_VIDEO_NO_HDCP; break; + case EV_STANDBY: state = ST_STANDBY; break; + + default: nIgnoredEvents++; break; + } + break; + case ST_SLEEP: + switch (event) + { + case EV_UNPLUGGED: state = ST_DISCONNECTED; break; /*Only when PowerSetState(ON)*/ + case EV_PLUGGEDIN: state = ST_AWAIT_EDID; break; /*Only when PowerSetState(ON)*/ + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + default: nIgnoredEvents++; break; + } + break; + + case ST_DISCONNECTED: + switch (event) + { + case EV_PLUGGEDIN: state = ST_AWAIT_EDID; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + case ST_AWAIT_EDID: + switch (event) + { + case EV_GETBLOCKDATA: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + + case ST_AWAIT_RX_SENSE: + switch (event) + { + case EV_SINKON: state = ST_SINK_CONNECTED; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + + case ST_SINK_CONNECTED: + switch (event) + { + case EV_SETINOUT: state = ST_VIDEO_NO_HDCP; break; + case EV_SINKOFF: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + case ST_VIDEO_NO_HDCP: + switch (event) + { + case EV_OUTDISABLE: state = ST_SINK_CONNECTED; break; + case EV_HDCP_RUN: state = ST_HDCP_WAIT_RX; break; + case EV_SINKOFF: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + case ST_HDCP_WAIT_RX: + switch (event) + { + case EV_HDCP_BKSV_NREPEAT: state = ST_HDCP_AUTHENTICATED;break; + case EV_HDCP_BKSV_REPEAT: state = ST_HDCP_WAIT_BSTATUS; break; + case EV_HDCP_BKSV_NSECURE: state = ST_HDCP_WAIT_RX; break; + case EV_HDCP_T0: state = ST_HDCP_WAIT_RX; break; + case EV_HDCP_STOP: state = ST_VIDEO_NO_HDCP; break; + case EV_SINKOFF: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + case ST_HDCP_WAIT_BSTATUS: + switch (event) + { + case EV_HDCP_BSTATUS_GOOD: state = ST_HDCP_WAIT_SHA_1; break; + case EV_HDCP_T0: state = ST_HDCP_WAIT_RX; break; + case EV_HDCP_STOP: state = ST_VIDEO_NO_HDCP; break; + case EV_SINKOFF: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + case ST_HDCP_WAIT_SHA_1: + switch (event) + { + case EV_HDCP_KSV_SECURE: state = ST_HDCP_AUTHENTICATED;break; + case EV_HDCP_T0: state = ST_HDCP_WAIT_RX; break; + case EV_HDCP_STOP: state = ST_VIDEO_NO_HDCP; break; + case EV_SINKOFF: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + case ST_HDCP_AUTHENTICATED: + switch (event) + { + case EV_HDCP_T0: state = ST_HDCP_WAIT_RX; break; + case EV_HDCP_STOP: state = ST_VIDEO_NO_HDCP; break; + case EV_SINKOFF: state = ST_AWAIT_RX_SENSE; break; + case EV_DEINIT: state = ST_UNINITIALIZED; break; + case EV_STANDBY: state = ST_STANDBY; break; + case EV_SLEEP: state = ST_SLEEP; break; + case EV_UNPLUGGED: state = ST_SLEEP; break; + default: nIgnoredEvents++; break; + } + break; + + case ST_INVALID: + nIgnoredEvents++; + break; + + default: + break; + } + + pDis->state = state; + pDis->nIgnoredEvents = nIgnoredEvents; + + if (nIgnoredEvents) + { + /* int cbeDebug = 1; */ + } + + return TM_OK; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setState); +#endif + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State_l.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State_l.h new file mode 100755 index 0000000000000..d55512311c1e2 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_State_l.h @@ -0,0 +1,56 @@ +/** + * Copyright (C) 2009 Koninklijke Philips Electronics N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of Koninklijke Philips Electronics N.V. and is confidential in + * nature. Under no circumstances is this software to be exposed to or placed + * under an Open Source License of any type without the expressed written + * permission of Koninklijke Philips Electronics N.V. + * + * \file tmbslTDA9989_State.h + * + * \version $Revision: 2 $ + * + * +*/ + +#ifndef TMBSLTDA9989_STATE_L_H +#define TMBSLTDA9989_STATE_L_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + + + +/*============================================================================*/ +/* EXTERN DATA DEFINITION */ +/*============================================================================*/ + + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +tmErrorCode_t setState (tmHdmiTxobject_t *pDis, tmbslTDA9989Event_t event); + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_STATE_L_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.c b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.c new file mode 100755 index 0000000000000..295ebd3e45fdc --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.c @@ -0,0 +1,670 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_local.c + * + * \version $Revision: 2 $ + * + * +*/ + +/*============================================================================*/ +/* FILE CONFIGURATION */ +/*============================================================================*/ + +/* Defining this symbol on the compiler command line excludes some API checks */ +/* #define NO_RETIF_BADPARAM */ + +/*============================================================================*/ +/* STANDARD INCLUDE FILES */ +/*============================================================================*/ + + +/*============================================================================*/ +/* PROJECT INCLUDE FILES */ +/*============================================================================*/ +#include "tmbslHdmiTx_types.h" +#include "tmbslTDA9989_Functions.h" +#include "tmbslTDA9989_local.h" + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* TYPE DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* PUBLIC VARIABLE DEFINITIONS */ +/*============================================================================*/ + +/** The array of object instances for all concurrently supported HDMI + * Transmitter units + */ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#ifdef USE_SHARED_HDMI_INSTANCE +extern tmHdmiTxobject_t gHdmiTxInstance[HDMITX_UNITS_MAX]; +#else +#include +#include +RAM_DAT tmHdmiTxobject_t gHdmiTxInstance[HDMITX_UNITS_MAX]; +EXPORT_SYMBOL(gHdmiTxInstance); +#endif +#else +RAM_DAT tmHdmiTxobject_t gHdmiTxInstance[HDMITX_UNITS_MAX]; +#endif + +/** + * Lookup table to map register page index to actual page number + */ +CONST_DAT UInt8 kPageIndexToPage[E_PAGE_NUM] = +{ + 0x00, /* E_PAGE_00 */ + 0x01, /* E_PAGE_01 */ + 0x02, /* E_PAGE_02 */ + 0x09, /* E_PAGE_09 */ + 0x10, /* E_PAGE_10 */ + 0x11, /* E_PAGE_11 */ + 0x12, /* E_PAGE_12 */ + 0x13 /* E_PAGE_13 */ +}; + + +/*============================================================================*/ +/* STATIC VARIABLE DECLARATIONS */ +/*============================================================================*/ + +/** + * Lookup table to map an 8-bit mask to a number of left shifts + * needed to shift a value starting at bit 0 onto the mask. + * Indexed by mask 0-255. For example, mask 0x00 and 0x01 need + * no shift, mask 0x02 needs one shift, mask 0x03 needs no shift, + * mask 0x04 needs 2 shifts, etc. + * Rows were formatted by "HDMI Driver - Register List.xls" and pasted here + */ +static CONST_DAT UInt8 kMaskToShift[256] = +{/* Mask index: */ + /*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 1x */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 2x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 3x */ + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 4x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 5x */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 6x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 7x */ + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 8x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 9x */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Ax */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Bx */ + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Cx */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Dx */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Ex */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* Fx */ +}; + +/*============================================================================*/ +/* STATIC FUNCTION DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* PUBLIC FUNCTION DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* checkUnitSetDis */ +/*============================================================================*/ +tmErrorCode_t +checkUnitSetDis +( + tmUnitSelect_t txUnit, + tmHdmiTxobject_t **ppDis +) +{ + /* Return error if unit numbr is out of range */ + RETIF(txUnit < tmUnit0, TMBSL_ERR_HDMI_BAD_UNIT_NUMBER) + RETIF(txUnit >= HDMITX_UNITS_MAX, TMBSL_ERR_HDMI_BAD_UNIT_NUMBER) + + /* Point to unit's Device Instance Structure */ + *ppDis = &gHdmiTxInstance[txUnit]; + + /* Return if this device instance is not initialised */ + if(!(*ppDis)->bInitialized) + { + return TMBSL_ERR_HDMI_NOT_INITIALIZED; + } + + return TM_OK; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(checkUnitSetDis); +#endif + +/*============================================================================*/ +/* getHwRegisters */ +/*============================================================================*/ +tmErrorCode_t +getHwRegisters +( + tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 *pData, + UInt16 lenData + ) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regShad; /* The index to the register's shadow copy */ + UInt8 regPage; /* The index to the register's page */ + UInt8 regAddr; /* The register's address on the page */ + UInt8 newRegPage; /* The register's new page number */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack 1st register's shadow index, page index and address */ + regShad = SPA2SHAD(regShadPageAddr); + regPage = SPA2PAGE(regShadPageAddr); + regAddr = SPA2ADDR(regShadPageAddr); + newRegPage = kPageIndexToPage[regPage]; + + /* Check length does not overflow page */ + RETIF_BADPARAM((regAddr+lenData) > E_REG_CURPAGE_ADR_W) + + /* Check 1st reg does not have a shadow - whole range assumed likewise */ + RETIF_BADPARAM(regShad != E_SNONE) + + /* Set page register if required */ + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + /* Get I2C register range - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = (UInt8)lenData; + sysArgs.pData = pData; + err = pDis->sysFuncRead(&sysArgs); + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_READ; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(getHwRegisters); +#endif + +/*============================================================================*/ +/* getHwRegister */ +/*============================================================================*/ +tmErrorCode_t +getHwRegister +( + tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 *pRegValue +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regShad; /* The index to the register's shadow copy */ + UInt8 regPage; /* The index to the register's page */ + UInt8 regAddr; /* The register's address on the page */ + UInt8 newRegPage; /* The register's new page number */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack register shadow index, page index and address */ + regShad = SPA2SHAD(regShadPageAddr); + regPage = SPA2PAGE(regShadPageAddr); + regAddr = SPA2ADDR(regShadPageAddr); + newRegPage = kPageIndexToPage[regPage]; + + /* Set page register if required */ + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + if ((regShad != E_SNONE) + && (regShadPageAddr != E_REG_P00_INT_FLAGS_0_RW) + && (regShadPageAddr != E_REG_P00_INT_FLAGS_1_RW) + && (regShadPageAddr != E_REG_P00_INT_FLAGS_2_RW)) + { + /* Get shadow copy - shadowed registers can't be read */ + /* Don't read shadow copy of interrupt status flags! */ + *pRegValue = pDis->shadowReg[regShad]; + return TM_OK; + } + else + { + /* Get I2C register - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = pRegValue; + err = pDis->sysFuncRead(&sysArgs); + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_READ; + } +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(getHwRegister); +#endif + +/*============================================================================*/ +/* setHwRegisters */ +/*============================================================================*/ +tmErrorCode_t +setHwRegisters +( + tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 *pData, + UInt16 lenData + ) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regShad; /* The index to the register's shadow copy */ + UInt8 regPage; /* The index to the register's page */ + UInt8 regAddr; /* The register's address on the page */ + UInt8 newRegPage; /* The register's new page number */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack 1st register's shadow index, page index and address */ + regShad = SPA2SHAD(regShadPageAddr); + regPage = SPA2PAGE(regShadPageAddr); + regAddr = SPA2ADDR(regShadPageAddr); + newRegPage = kPageIndexToPage[regPage]; + + /* Check length does not overflow page */ + RETIF_BADPARAM((regAddr+lenData) > E_REG_CURPAGE_ADR_W) + + /* Check 1st reg does not have a shadow - whole range assumed likewise */ + RETIF_BADPARAM(regShad != E_SNONE) + + /* Set page register if required - whole range is on same page */ + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + /* Write to I2C register range - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = (UInt8)lenData; + sysArgs.pData = pData; + err = pDis->sysFuncWrite(&sysArgs); + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_WRITE; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setHwRegisters); +#endif + + +/*============================================================================*/ +/* setHwRegisterMsbLsb */ +/*============================================================================*/ +tmErrorCode_t +setHwRegisterMsbLsb +( + tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt16 regWord +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regPage; /* The index to the register's page */ + UInt8 regAddr; /* The register's address on the page */ + UInt8 newRegPage; /* The register's new page number */ + UInt8 msbLsb[2]; /* The bytes from regWord */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack register shadow index, page index and address */ + regPage = SPA2PAGE(regShadPageAddr); + regAddr = SPA2ADDR(regShadPageAddr); + newRegPage = kPageIndexToPage[regPage]; + + /* Unpack regWord bytes, MSB first */ + msbLsb[0] = (UInt8)(regWord >> 8); + msbLsb[1] = (UInt8)(regWord & 0xFF); + + /* Set page register if required */ + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + /* No word registers are shadowed */ + + /* Write to I2C - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 2; + sysArgs.pData = &msbLsb[0]; + err = pDis->sysFuncWrite(&sysArgs); + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_WRITE; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setHwRegisterMsbLsb); +#endif + +/*============================================================================*/ +/* setHwRegister */ +/*============================================================================*/ +tmErrorCode_t +setHwRegister_main +( + tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 regValue +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regShad; /* The index to the register's shadow copy */ + UInt8 regPage; /* The index to the register's page */ + UInt8 regAddr; /* The register's address on the page */ + UInt8 newRegPage; /* The register's new page number */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack register shadow index, page index and address */ + regShad = SPA2SHAD(regShadPageAddr); + regPage = SPA2PAGE(regShadPageAddr); + regAddr = SPA2ADDR(regShadPageAddr); + newRegPage = kPageIndexToPage[regPage]; + + /* Set page register if required */ + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + /* Set shadow copy */ + if (regShad != E_SNONE) + { + pDis->shadowReg[regShad] = regValue; + } + + /* Write to I2C - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + err = pDis->sysFuncWrite(&sysArgs); + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_WRITE; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setHwRegister_main); +#endif + +/*============================================================================*/ +/* setHwRegisterField */ +/*============================================================================*/ +tmErrorCode_t +setHwRegisterField +( + tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 fieldMask, + UInt8 fieldValue +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regShad; /* The index to the register's shadow copy */ + UInt8 regPage; /* The index to the register's page */ + UInt8 regAddr; /* The register's address on the page */ + UInt8 newRegPage; /* The register's new page number */ + UInt8 regValue; /* The register's current value */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack register shadow index, page index and address */ + regShad = SPA2SHAD(regShadPageAddr); + regPage = SPA2PAGE(regShadPageAddr); + regAddr = SPA2ADDR(regShadPageAddr); + newRegPage = kPageIndexToPage[regPage]; + + /* Set page register if required */ + if (pDis->curRegPage != newRegPage) + { + /* All non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = E_REG_CURPAGE_ADR_W; + sysArgs.lenData = 1; + sysArgs.pData = &newRegPage; + err = pDis->sysFuncWrite(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_WRITE) + pDis->curRegPage = newRegPage; + } + + if (regShad != E_SNONE) + { + /* Get shadow copy */ + regValue = pDis->shadowReg[regShad]; + } + else + { + /* Read I2C register value. + * All bitfield registers are either shadowed or can be read. + */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + err = pDis->sysFuncRead(&sysArgs); + RETIF(err != TM_OK, TMBSL_ERR_HDMI_I2C_READ) + } + + /* Reset register bits that are set in the mask */ + regValue = regValue & (UInt8)(~fieldMask); + + /* Shift the field value left to align its bits with the mask */ + fieldValue <<= kMaskToShift[fieldMask]; + + /* Reset shifted field bits that are not set in the mask */ + fieldValue &= fieldMask; + + /* Set the shifted bitfield */ + regValue |= fieldValue; + + /* Set shadow copy */ + if (regShad != E_SNONE) + { + pDis->shadowReg[regShad] = regValue; + } + + /* Write to I2C - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->uHwAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + err = pDis->sysFuncWrite(&sysArgs); + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_WRITE; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setHwRegisterField); +#endif + +/*============================================================================*/ +/* getCECHwRegister */ +/*============================================================================*/ +tmErrorCode_t +getCECHwRegister +( + tmHdmiTxobject_t *pDis, + UInt16 regAddr, + UInt8 *pRegValue +) +{ + tmErrorCode_t err; /* Error code */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + UInt8 CECAddress; /* CEC Address deduced from uHwAddress */ + + /*Convert HwAddress into CEC Address*/ + CECAddress = pDis->uHwAddress; + CECAddress = CECAddress ^ 0x44; /*Convert address to obtain the correspondance in CEC*/ + /*CECAddress = ((~CECAddress & 0x44)||(CECAddress & 0xBB)); */ + /*Prepare Write operation*/ + sysArgs.slaveAddr = CECAddress; + sysArgs.firstRegister = (UInt8)regAddr; + sysArgs.lenData = 1; + sysArgs.pData = pRegValue; + + /*Read data in Chip*/ + err = pDis->sysFuncRead(&sysArgs); /* Call IC Read function*/ + + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_READ; + +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(getCECHwRegister); +#endif + +/*============================================================================*/ +/* setCECHwRegister */ +/*============================================================================*/ +tmErrorCode_t +setCECHwRegister +( + tmHdmiTxobject_t *pDis, + UInt16 regAddr, + UInt8 regValue +) +{ + tmErrorCode_t err; /* Error code */ + tmbslHdmiTxSysArgs_t sysArgs; /* Arguments passed to system function */ + UInt8 CECAddress; /* CEC Address deduced from uHwAddress */ + + /*Convert HwAddress into CEC Address*/ + CECAddress = pDis->uHwAddress; + CECAddress = CECAddress ^ 0x44; /*Convert address to obtain the correspondance in CEC*/ + + /*Prepare Write operation*/ + sysArgs.slaveAddr = CECAddress; + sysArgs.firstRegister = (UInt8)regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + + /*Write data in Chip*/ + err = pDis->sysFuncWrite(&sysArgs); /* Call IC Write function*/ + + return (err == TM_OK) ? TM_OK : TMBSL_ERR_HDMI_I2C_WRITE; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setCECHwRegister); +#endif + +/*============================================================================*/ +/* setHwRegisterFieldTable */ +/*============================================================================*/ +tmErrorCode_t +setHwRegisterFieldTable +( + tmHdmiTxobject_t *pDis, + const tmHdmiTxRegMaskVal_t *pTable +) +{ + tmErrorCode_t err; /* Error code */ + Int i; /* Table index */ + + /* Set register, mask and value from table until terminator is reached */ + for (i = 0; pTable[i].Reg > 0; i++) + { + err = setHwRegisterField(pDis, pTable[i].Reg, pTable[i].Mask, pTable[i].Val); + RETIF(err != TM_OK, err) + } + return TM_OK; +} +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +EXPORT_SYMBOL(setHwRegisterFieldTable); +#endif + + +/*============================================================================*/ +/* lmemcpy */ +/*============================================================================*/ +tmErrorCode_t +lmemcpy +( + void *pTable1, + const void * pTable2, + UInt Size +) +{ + char *ptrSource = (char*) pTable1; + char *endSource = (char*)pTable1 + Size; + char *ptrDest = (char *)pTable2; + + RETIF_BADPARAM(pTable1 == Null) + RETIF_BADPARAM(pTable2 == Null) + + while (endSource > ptrSource) + { + *(ptrSource++) = *(ptrDest++); + } + return TM_OK; +} + +/*============================================================================*/ +/* lmemset */ +/*============================================================================*/ +tmErrorCode_t +lmemset +( + void *pTable1, + const UInt8 value, + UInt Size +) +{ + char *ptrSource = (char*) pTable1; + char *endSource = (char*)pTable1 + Size; + + RETIF_BADPARAM(pTable1 == Null) + + while (endSource > ptrSource) + { + *(ptrSource++) = value; + } + return TM_OK; +} + +/*============================================================================*/ +/* STATIC FUNCTION DEFINTIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.h new file mode 100755 index 0000000000000..02843e2bec7fb --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local.h @@ -0,0 +1,2056 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_local.h + * + * \version %version: 3 % + * +*/ + +#ifndef TMBSLTDA9989_LOCAL_H +#define TMBSLTDA9989_LOCAL_H +#define setHwRegister(pDis, regShadPageAddr, regValue) setHwRegister_main(pDis, regShadPageAddr, regValue); printk("Setting " # regShadPageAddr "\n"); + +/* + + INCLUDE FILES */ +/*============================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ +#ifndef DUMMY_ACCESS +#ifdef _WINDOWS +#define DUMMY_ACCESS(x) x +#else +#define DUMMY_ACCESS(x) +#endif +#endif /* DUMMY_ACCESS */ + +/** \name Versions + * A group of macros to set the software component number and version + */ +/*@{*/ +/** Compatibility number */ +#define HDMITX_BSL_COMP_NUM 1 + +/** Major software version 1 to 255 */ +#define HDMITX_BSL_MAJOR_VER 5 + +/** Minor software version 0 to 9 */ +#define HDMITX_BSL_MINOR_VER 4 +/*@}*/ + +/** \name ErrorChecks + * A group of checks ensuring that public error codes match DVP standard errors + */ +/*@{*/ +/** SW interface compatibility error */ +#if TMBSL_ERR_HDMI_COMPATIBILITY != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_COMPATIBILITY) +#error +#endif + +/** SW major version error */ +#if TMBSL_ERR_HDMI_MAJOR_VERSION != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_MAJOR_VERSION) +#error +#endif + +/** SW component version error */ +#if TMBSL_ERR_HDMI_COMP_VERSION != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_COMP_VERSION) +#error +#endif + +/** Invalid device unit number */ +#if TMBSL_ERR_HDMI_BAD_UNIT_NUMBER != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_BAD_UNIT_NUMBER) +#error +#endif + +/** Invalid input parameter other than unit number */ +#if TMBSL_ERR_HDMI_BAD_PARAMETER != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_BAD_PARAMETER) +#error +#endif + +/** Inconsistent input parameters */ +#if TMBSL_ERR_HDMI_INCONSISTENT_PARAMS != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_INCONSISTENT_PARAMS) +#error +#endif + +/** Component is not initialized */ +#if TMBSL_ERR_HDMI_NOT_INITIALIZED != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_NOT_INITIALIZED) +#error +#endif + +/** Command not supported for current device */ +#if TMBSL_ERR_HDMI_NOT_SUPPORTED != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_NOT_SUPPORTED) +#error +#endif + +/** Initialization failed */ +#if TMBSL_ERR_HDMI_INIT_FAILED != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_INIT_FAILED) +#error +#endif + +/** Component is busy and cannot do a new operation */ +#if TMBSL_ERR_HDMI_BUSY != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_BUSY) +#error +#endif + +/** I2C read error */ +#if TMBSL_ERR_HDMI_I2C_READ != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_READ) +#error +#endif + +/** I2C write error */ +#if TMBSL_ERR_HDMI_I2C_WRITE != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_WRITE) +#error +#endif + +/** Assertion failure */ +#if TMBSL_ERR_HDMI_ASSERTION != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_ASSERTION) +#error +#endif + +/** Bad EDID block checksum */ +#if TMBSL_ERR_HDMI_INVALID_CHECKSUM != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_INVALID_STATE) +#error +#endif + +/** No connection to HPD pin */ +#if TMBSL_ERR_HDMI_NULL_CONNECTION != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_NULL_CONNECTION) +#error +#endif + +/** Not allowed in DVI mode */ +#if TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_OPERATION_NOT_PERMITTED) +#error +#endif + +/** Ressource not available*/ +#if TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE != \ +(TMBSL_ERR_HDMI_BASE + TM_ERR_NO_RESOURCES) +#error +#endif + + +/*@}*/ + +/** + * A macro to check a condition and if true return a result + */ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#define RETIF(cond, rslt) if ((cond)){printk(KERN_INFO "%s %d\n",__func__,__LINE__);return (rslt);} +#else +#define RETIF(cond, rslt) if ((cond)){return (rslt);} +#endif + +/** + * A macro to check a condition and if true return + * TMBSL_ERR_HDMI_BAD_PARAMETER. + * To save code space, it can be compiled out by defining NO_RETIF_BADPARAM on + * the compiler command line. + */ +#ifdef NO_RETIF_BADPARAM +#define RETIF_BADPARAM(cond) +#else +#define RETIF_BADPARAM(cond) if ((cond)){return TMBSL_ERR_HDMI_BAD_PARAMETER;} +#endif + +/** + * A macro to check the result of a register API and if not TM_OK to return it. + * To save code space, it can be compiled out by defining NO_RETIF_REG_FAIL on + * the compiler command line. + */ +#ifdef NO_RETIF_REG_FAIL +#define RETIF_REG_FAIL(result) +#else +#define RETIF_REG_FAIL(result) if ((result) != TM_OK){return (result);} +#endif + +/** + * Check the consistancy of BSL structure + */ +/* #define BSL_CONSISTANCY(_x_,_y_) do { \ */ +/* #if ((_x_) != (_y_) * (_x_)[0]) \ */ +/* #error "BSL HAS WRONG ARRAY SIZE" \ */ +/* #endif \ */ +/* } while (0) */ + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +/** + * Driver events and states used for diagnosis + */ +typedef enum _tmbslTDA9989Event +{ + EV_DEINIT = 0, + EV_INIT = 1, + EV_STANDBY = 2, + EV_SLEEP = 3, + EV_ON = 4, + EV_UNPLUGGED = 5, + EV_PLUGGEDIN = 6, + EV_RESUME_UNPLUGGED = 7, + EV_RESUME_PLUGGEDIN = 8, + EV_GETBLOCKDATA = 9, + EV_SETINOUT = 10, + EV_OUTDISABLE = 11, + EV_HDCP_RUN = 12, + EV_HDCP_BKSV_NREPEAT = 13, + EV_HDCP_BKSV_NSECURE = 14, + EV_HDCP_BKSV_REPEAT = 15, + EV_HDCP_BSTATUS_GOOD = 16, + EV_HDCP_KSV_SECURE = 17, + EV_HDCP_T0 = 18, + EV_HDCP_STOP = 19, + EV_SINKON = 20, + EV_SINKOFF = 21, + EV_INVALID = 22 +} tmbslTDA9989Event_t; + +typedef enum _tmbslTDA9989State +{ + ST_UNINITIALIZED = 0, + ST_STANDBY = 1, + ST_SLEEP = 2, + ST_DISCONNECTED = 3, + ST_AWAIT_EDID = 4, + ST_SINK_CONNECTED = 5, + ST_VIDEO_NO_HDCP = 6, + ST_HDCP_WAIT_RX = 7, + ST_HDCP_WAIT_BSTATUS = 8, + ST_HDCP_WAIT_SHA_1 = 9, + ST_HDCP_AUTHENTICATED = 10, + ST_AWAIT_RX_SENSE = 11, + ST_INVALID = 12, + ST_NUM = 13 +} tmbslTDA9989State_t; + +/** + * An enum to index into the Device Instance Data shadowReg array + */ +enum _eShad +{ + E_SP00_INT_FLAGS_0 = 0, + E_SP00_INT_FLAGS_1 = 1, + E_SP00_INT_FLAGS_2 = 2, + E_SP00_VIP_CNTRL_0 = 3, + E_SP00_VIP_CNTRL_1 = 4, + E_SP00_VIP_CNTRL_2 = 5, + E_SP00_VIP_CNTRL_3 = 6, + E_SP00_VIP_CNTRL_4 = 7, + E_SP00_VIP_CNTRL_5 = 8, + E_SP00_MAT_CONTRL = 9, + E_SP00_TBG_CNTRL_0 = 10, + E_SP00_TBG_CNTRL_1 = 11, + E_SP00_HVF_CNTRL_0 = 12, + E_SP00_HVF_CNTRL_1 = 13, + E_SP00_TIMER_H = 14, + E_SP00_DEBUG_PROBE = 15, + E_SP00_AIP_CLKSEL = 16, + E_SP01_SC_VIDFORMAT = 17, + E_SP01_SC_CNTRL = 18, + E_SP01_TBG_CNTRL_0 = 19, +#ifdef TMFL_HDCP_SUPPORT + E_SP12_CTRL = 20, + E_SP12_BCAPS = 21, + E_SNUM = 22, /* Number of shadow registers */ + E_SNONE = 22 /* Index value indicating no shadow register */ +#else /* TMFL_HDCP_SUPPORT */ + E_SNUM = 20, /* Number of shadow registers */ + E_SNONE = 20 /* Index value indicating no shadow register */ +#endif /* TMFL_HDCP_SUPPORT */ +}; + +/** + * Page list + * These are indexes to the allowed register page numbers + */ +enum _ePage +{ + E_PAGE_00 = 0, + E_PAGE_01 = 1, + E_PAGE_02 = 2, + E_PAGE_09 = 3, + E_PAGE_10 = 4, + E_PAGE_11 = 5, + E_PAGE_12 = 6, + E_PAGE_13 = 7, + E_PAGE_NUM = 8, /* Number of pages */ + E_PAGE_INVALID = 8 /* Index value indicating invalid page */ +}; + +/** + * Macros to initialize and access the following register list enum _eReg + */ +/* Pack shadow index s, page index p and register address a into UInt16 */ +#define SPA(s,p,a) (UInt16)(((s)<<11)|((p)<<8)|(a)) +/* Unpacks shadow index s from UInt16 */ +#define SPA2SHAD(spa) (UInt8)((spa)>>11) +/* Unpacks page index p from UInt16 */ +#define SPA2PAGE(spa) (UInt8)(((spa)>>8)&0x0007) +/* Unpacks register address a from UInt16 */ +#define SPA2ADDR(spa) (UInt8)((spa)&0x00FF) + +/** + * Register list + * + * Each register symbol has these fields: E_REG_page_register_access + * + * The symbols have a 16-bit value as follows, including an index to + * the Device Instance Data shadowReg[] array: + * + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * |15 |14 |13 |12 |11 |10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * | Shadow Index |Page Index | Register Address | + * +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ + * + */ +enum _eReg +{ + /*************************************************************************/ + /** Rows formatted in "HDMI Driver - Register List.xls" and pasted here **/ + /*************************************************************************/ + E_REG_MIN_ADR = 0x00, /* First register on all pages */ + E_REG_CURPAGE_ADR_W = 0xFF, /* Address register on all pages */ + /*CEC Registers*/ + + E_REG_CEC_INTERRUPTSTATUS_R = 0xEE, + E_REG_CEC_RXSHPDINTENA_RW = 0xFC, + E_REG_CEC_RXSHPDINT_R = 0xFD, + E_REG_CEC_RXSHPDLEV_R = 0xFE, + E_REG_CEC_ENAMODS_RW = 0xFF, + E_REG_CEC_FRO_IM_CLK_CTRL_RW = 0xFB, + + E_REG_P00_VERSION_R = SPA(E_SNONE , E_PAGE_00, 0x00), + E_REG_P00_MAIN_CNTRL0_RW = SPA(E_SNONE , E_PAGE_00, 0x01), + E_REG_P00_VERSION_MSB_RW = SPA(E_SNONE , E_PAGE_00, 0x02), + E_REG_P00_PACKAGE_TYPE_R = SPA(E_SNONE , E_PAGE_00, 0x03), + E_REG_P00_SR_REG_W = SPA(E_SNONE , E_PAGE_00, 0x0A), + E_REG_P00_DDC_DISABLE_RW = SPA(E_SNONE , E_PAGE_00, 0x0B), + E_REG_P00_CCLK_ON_RW = SPA(E_SNONE , E_PAGE_00, 0x0C), + E_REG_P00_I2C_MASTER_RW = SPA(E_SNONE , E_PAGE_00, 0x0D), +#ifdef TMFL_HDCP_OPTIMIZED_POWER + E_REG_FEAT_POWER_DOWN = SPA(E_SNONE , E_PAGE_00, 0x0E), +#endif + + E_REG_P00_INT_FLAGS_0_RW = SPA(E_SP00_INT_FLAGS_0 , E_PAGE_00, 0x0F), + E_REG_P00_INT_FLAGS_1_RW = SPA(E_SP00_INT_FLAGS_1 , E_PAGE_00, 0x10), + E_REG_P00_INT_FLAGS_2_RW = SPA(E_SP00_INT_FLAGS_2 , E_PAGE_00, 0x11), + /*E_REG_P00_INT_FLAGS_3_R = SPA(E_SNONE , E_PAGE_00, 0x12),*/ + E_REG_P00_SW_INT_W = SPA(E_SNONE , E_PAGE_00, 0x15), + E_REG_P00_ENA_ACLK_RW = SPA(E_SNONE , E_PAGE_00, 0x16), + E_REG_P00_ENA_VP_0_RW = SPA(E_SNONE , E_PAGE_00, 0x18), + E_REG_P00_ENA_VP_1_RW = SPA(E_SNONE , E_PAGE_00, 0x19), + E_REG_P00_ENA_VP_2_RW = SPA(E_SNONE , E_PAGE_00, 0x1A), + E_REG_P00_ENA_AP_RW = SPA(E_SNONE , E_PAGE_00, 0x1E), + E_REG_P00_VIP_CNTRL_0_W = SPA(E_SP00_VIP_CNTRL_0 , E_PAGE_00, 0x20), + E_REG_P00_VIP_CNTRL_1_W = SPA(E_SP00_VIP_CNTRL_1 , E_PAGE_00, 0x21), + E_REG_P00_VIP_CNTRL_2_W = SPA(E_SP00_VIP_CNTRL_2 , E_PAGE_00, 0x22), + E_REG_P00_VIP_CNTRL_3_W = SPA(E_SP00_VIP_CNTRL_3 , E_PAGE_00, 0x23), + E_REG_P00_VIP_CNTRL_4_W = SPA(E_SP00_VIP_CNTRL_4 , E_PAGE_00, 0x24), + E_REG_P00_VIP_CNTRL_5_W = SPA(E_SP00_VIP_CNTRL_5 , E_PAGE_00, 0x25), + E_REG_P00_MUX_AP_RW = SPA(E_SNONE , E_PAGE_00, 0x26), + E_REG_P00_MUX_VP_VIP_OUT_RW = SPA(E_SNONE , E_PAGE_00, 0x27), + E_REG_P00_MAT_CONTRL_W = SPA(E_SP00_MAT_CONTRL , E_PAGE_00, 0x80), + E_REG_P00_MAT_OI1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x81), + E_REG_P00_MAT_OI1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x82), + E_REG_P00_MAT_OI2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x83), + E_REG_P00_MAT_OI2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x84), + E_REG_P00_MAT_OI3_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x85), + E_REG_P00_MAT_OI3_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x86), + E_REG_P00_MAT_P11_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x87), + E_REG_P00_MAT_P11_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x88), + E_REG_P00_MAT_P12_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x89), + E_REG_P00_MAT_P12_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x8A), + E_REG_P00_MAT_P13_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x8B), + E_REG_P00_MAT_P13_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x8C), + E_REG_P00_MAT_P21_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x8D), + E_REG_P00_MAT_P21_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x8E), + E_REG_P00_MAT_P22_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x8F), + E_REG_P00_MAT_P22_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x90), + E_REG_P00_MAT_P23_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x91), + E_REG_P00_MAT_P23_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x92), + E_REG_P00_MAT_P31_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x93), + E_REG_P00_MAT_P31_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x94), + E_REG_P00_MAT_P32_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x95), + E_REG_P00_MAT_P32_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x96), + E_REG_P00_MAT_P33_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x97), + E_REG_P00_MAT_P33_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x98), + E_REG_P00_MAT_OO1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x99), + E_REG_P00_MAT_OO1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x9A), + E_REG_P00_MAT_OO2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x9B), + E_REG_P00_MAT_OO2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x9C), + E_REG_P00_MAT_OO3_MSB_W = SPA(E_SNONE , E_PAGE_00, 0x9D), + E_REG_P00_MAT_OO3_LSB_W = SPA(E_SNONE , E_PAGE_00, 0x9E), + E_REG_P00_VIDFORMAT_W = SPA(E_SNONE , E_PAGE_00, 0xA0), + E_REG_P00_REFPIX_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xA1), + E_REG_P00_REFPIX_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xA2), + E_REG_P00_REFLINE_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xA3), + E_REG_P00_REFLINE_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xA4), + E_REG_P00_NPIX_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xA5), + E_REG_P00_NPIX_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xA6), + E_REG_P00_NLINE_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xA7), + E_REG_P00_NLINE_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xA8), + E_REG_P00_VS_LINE_STRT_1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xA9), + E_REG_P00_VS_LINE_STRT_1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xAA), + E_REG_P00_VS_PIX_STRT_1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xAB), + E_REG_P00_VS_PIX_STRT_1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xAC), + E_REG_P00_VS_LINE_END_1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xAD), + E_REG_P00_VS_LINE_END_1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xAE), + E_REG_P00_VS_PIX_END_1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xAF), + E_REG_P00_VS_PIX_END_1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xB0), + E_REG_P00_VS_LINE_STRT_2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xB1), + E_REG_P00_VS_LINE_STRT_2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xB2), + E_REG_P00_VS_PIX_STRT_2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xB3), + E_REG_P00_VS_PIX_STRT_2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xB4), + E_REG_P00_VS_LINE_END_2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xB5), + E_REG_P00_VS_LINE_END_2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xB6), + E_REG_P00_VS_PIX_END_2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xB7), + E_REG_P00_VS_PIX_END_2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xB8), + E_REG_P00_HS_PIX_START_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xB9), + E_REG_P00_HS_PIX_START_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xBA), + E_REG_P00_HS_PIX_STOP_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xBB), + E_REG_P00_HS_PIX_STOP_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xBC), + E_REG_P00_VWIN_START_1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xBD), + E_REG_P00_VWIN_START_1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xBE), + E_REG_P00_VWIN_END_1_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xBF), + E_REG_P00_VWIN_END_1_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xC0), + E_REG_P00_VWIN_START_2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xC1), + E_REG_P00_VWIN_START_2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xC2), + E_REG_P00_VWIN_END_2_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xC3), + E_REG_P00_VWIN_END_2_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xC4), + E_REG_P00_DE_START_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xC5), + E_REG_P00_DE_START_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xC6), + E_REG_P00_DE_STOP_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xC7), + E_REG_P00_DE_STOP_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xC8), + E_REG_P00_COLBAR_WIDTH_W = SPA(E_SNONE , E_PAGE_00, 0xC9), + E_REG_P00_TBG_CNTRL_0_W = SPA(E_SP00_TBG_CNTRL_0 , E_PAGE_00, 0xCA), + E_REG_P00_TBG_CNTRL_1_W = SPA(E_SP00_TBG_CNTRL_1 , E_PAGE_00, 0xCB), + E_REG_P00_VBL_OFFSET_START_W = SPA(E_SNONE , E_PAGE_00, 0xCC), + E_REG_P00_VBL_OFFSET_END_W = SPA(E_SNONE , E_PAGE_00, 0xCD), + E_REG_P00_HBL_OFFSET_START_W = SPA(E_SNONE , E_PAGE_00, 0xCE), + E_REG_P00_HBL_OFFSET_END_W = SPA(E_SNONE , E_PAGE_00, 0xCF), + E_REG_P00_DWIN_RE_DE_W = SPA(E_SNONE , E_PAGE_00, 0xD0), + E_REG_P00_DWIN_FE_DE_W = SPA(E_SNONE , E_PAGE_00, 0xD1), +#ifdef TMFL_RGB_DDR_12BITS + E_REG_P00_VSPACE_START_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xD2), + E_REG_P00_VSPACE_START_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xD3), + E_REG_P00_VSPACE_END_MSB_W = SPA(E_SNONE , E_PAGE_00, 0xD4), + E_REG_P00_VSPACE_END_LSB_W = SPA(E_SNONE , E_PAGE_00, 0xD5), + E_REG_P00_ENABLE_SPACE_W = SPA(E_SNONE , E_PAGE_00, 0xD6), + E_REG_P00_VSPACE_Y_DATA_W = SPA(E_SNONE , E_PAGE_00, 0xD7), + E_REG_P00_VSPACE_U_DATA_W = SPA(E_SNONE , E_PAGE_00, 0xD8), + E_REG_P00_VSPACE_V_DATA_W = SPA(E_SNONE , E_PAGE_00, 0xD9), +#endif + + E_REG_P00_TIMER_RI_PJ_RW = SPA(E_SNONE , E_PAGE_00, 0xE1), + E_REG_P00_BCAPS_POLL_RW = SPA(E_SNONE , E_PAGE_00, 0xE2), + E_REG_P00_100us_RW = SPA(E_SNONE , E_PAGE_00, 0xE3), + + E_REG_P00_HVF_CNTRL_0_W = SPA(E_SP00_HVF_CNTRL_0 , E_PAGE_00, 0xE4), + E_REG_P00_HVF_CNTRL_1_W = SPA(E_SP00_HVF_CNTRL_1 , E_PAGE_00, 0xE5), + + E_REG_P00_TIMER_H_W = SPA(E_SP00_TIMER_H , E_PAGE_00, 0xE8), + E_REG_P00_TIMER_M_W = SPA(E_SNONE , E_PAGE_00, 0xE9), + E_REG_P00_TIMER_L_W = SPA(E_SNONE , E_PAGE_00, 0xEA), + E_REG_P00_TIMER_2SEC_W = SPA(E_SNONE , E_PAGE_00, 0xEB), + E_REG_P00_TIMER_5SEC_W = SPA(E_SNONE , E_PAGE_00, 0xEC), + E_REG_P00_NDIV_IM_W = SPA(E_SNONE , E_PAGE_00, 0xEE), + E_REG_P00_NDIV_PF_W = SPA(E_SNONE , E_PAGE_00, 0xEF), + E_REG_P00_RPT_CNTRL_W = SPA(E_SNONE , E_PAGE_00, 0xF0), + E_REG_P00_LEAD_OFF_W = SPA(E_SNONE , E_PAGE_00, 0xF1), + E_REG_P00_TRAIL_OFF_W = SPA(E_SNONE , E_PAGE_00, 0xF2), + E_REG_P00_MISR_EXP_0_RW = SPA(E_SNONE , E_PAGE_00, 0xF3), + E_REG_P00_MISR_EXP_1_RW = SPA(E_SNONE , E_PAGE_00, 0xF4), + E_REG_P00_MISR_EXP_2_RW = SPA(E_SNONE , E_PAGE_00, 0xF5), + E_REG_P00_MISR_0_R = SPA(E_SNONE , E_PAGE_00, 0xF6), + E_REG_P00_MISR_1_R = SPA(E_SNONE , E_PAGE_00, 0xF7), + E_REG_P00_DEBUG_PROBE_W = SPA(E_SP00_DEBUG_PROBE , E_PAGE_00, 0xF8), + E_REG_P00_GHOST_XADDR_W = SPA(E_SNONE , E_PAGE_00, 0xF9), + E_REG_P00_MISR_2_R = SPA(E_SNONE , E_PAGE_00, 0xFA), + E_REG_P00_I2S_FORMAT_RW = SPA(E_SNONE , E_PAGE_00, 0xFC), + E_REG_P00_AIP_CLKSEL_W = SPA(E_SP00_AIP_CLKSEL , E_PAGE_00, 0xFD), + E_REG_P00_GHOST_ADDR_W = SPA(E_SNONE , E_PAGE_00, 0xFE), + E_REG_P01_SC_VIDFORMAT_W = SPA(E_SP01_SC_VIDFORMAT, E_PAGE_01, 0x00), + + E_REG_P01_SC_CNTRL_W = SPA(E_SP01_SC_CNTRL , E_PAGE_01, 0x01), + E_REG_P01_SC_DELTA_PHASE_V_W = SPA(E_SNONE , E_PAGE_01, 0x02), + E_REG_P01_SC_DELTA_PHASE_H_W = SPA(E_SNONE , E_PAGE_01, 0x03), + E_REG_P01_SC_START_PHASE_H_W = SPA(E_SNONE , E_PAGE_01, 0x04), + E_REG_P01_SC_NPIX_IN_LSB_W = SPA(E_SNONE , E_PAGE_01, 0x05), + E_REG_P01_SC_NPIX_IN_MSB_W = SPA(E_SNONE , E_PAGE_01, 0x06), + E_REG_P01_SC_NPIX_OUT_LSB_W = SPA(E_SNONE , E_PAGE_01, 0x07), + E_REG_P01_SC_NPIX_OUT_MSB_W = SPA(E_SNONE , E_PAGE_01, 0x08), + E_REG_P01_SC_NLINE_IN_LSB_W = SPA(E_SNONE , E_PAGE_01, 0x09), + E_REG_P01_SC_NLINE_IN_MSB_W = SPA(E_SNONE , E_PAGE_01, 0x0A), + E_REG_P01_SC_NLINE_OUT_LSB_W = SPA(E_SNONE , E_PAGE_01, 0x0B), + E_REG_P01_SC_NLINE_OUT_MSB_W = SPA(E_SNONE , E_PAGE_01, 0x0C), + E_REG_P01_SC_NLINE_SKIP_W = SPA(E_SNONE , E_PAGE_01, 0x0D), + E_REG_P01_SC_SAMPLE_BUFFILL_R = SPA(E_SNONE , E_PAGE_01, 0x0E), + E_REG_P01_SC_MAX_BUFFILL_P_0_R = SPA(E_SNONE , E_PAGE_01, 0x0F), + E_REG_P01_SC_MAX_BUFFILL_P_1_R = SPA(E_SNONE , E_PAGE_01, 0x10), + E_REG_P01_SC_MAX_BUFFILL_D_0_R = SPA(E_SNONE , E_PAGE_01, 0x11), + E_REG_P01_SC_MAX_BUFFILL_D_1_R = SPA(E_SNONE , E_PAGE_01, 0x12), + E_REG_P01_SC_SAMPLE_FIFOFILL_R = SPA(E_SNONE , E_PAGE_01, 0x13), + E_REG_P01_SC_MAX_FIFOFILL_PI_R = SPA(E_SNONE , E_PAGE_01, 0x14), + E_REG_P01_SC_MIN_FIFOFILL_PO1_R = SPA(E_SNONE , E_PAGE_01, 0x15), + E_REG_P01_SC_MIN_FIFOFILL_PO2_R = SPA(E_SNONE , E_PAGE_01, 0x16), + E_REG_P01_SC_MIN_FIFOFILL_PO3_R = SPA(E_SNONE , E_PAGE_01, 0x17), + E_REG_P01_SC_MIN_FIFOFILL_PO4_R = SPA(E_SNONE , E_PAGE_01, 0x18), + E_REG_P01_SC_MAX_FIFOFILL_DI_R = SPA(E_SNONE , E_PAGE_01, 0x19), + E_REG_P01_SC_MAX_FIFOFILL_DO_R = SPA(E_SNONE , E_PAGE_01, 0x1A), + E_REG_P01_SC_VS_LUT_0_W = SPA(E_SNONE , E_PAGE_01, 0x1B), + E_REG_P01_SC_VS_LUT_1_W = SPA(E_SNONE , E_PAGE_01, 0x1C), + E_REG_P01_SC_VS_LUT_2_W = SPA(E_SNONE , E_PAGE_01, 0x1D), + E_REG_P01_SC_VS_LUT_3_W = SPA(E_SNONE , E_PAGE_01, 0x1E), + E_REG_P01_SC_VS_LUT_4_W = SPA(E_SNONE , E_PAGE_01, 0x1F), + E_REG_P01_SC_VS_LUT_5_W = SPA(E_SNONE , E_PAGE_01, 0x20), + E_REG_P01_SC_VS_LUT_6_W = SPA(E_SNONE , E_PAGE_01, 0x21), + E_REG_P01_SC_VS_LUT_7_W = SPA(E_SNONE , E_PAGE_01, 0x22), + E_REG_P01_SC_VS_LUT_8_W = SPA(E_SNONE , E_PAGE_01, 0x23), + E_REG_P01_SC_VS_LUT_9_W = SPA(E_SNONE , E_PAGE_01, 0x24), + E_REG_P01_SC_VS_LUT_10_W = SPA(E_SNONE , E_PAGE_01, 0x25), + E_REG_P01_SC_VS_LUT_11_W = SPA(E_SNONE , E_PAGE_01, 0x26), + E_REG_P01_SC_VS_LUT_12_W = SPA(E_SNONE , E_PAGE_01, 0x27), + E_REG_P01_SC_VS_LUT_13_W = SPA(E_SNONE , E_PAGE_01, 0x28), + E_REG_P01_SC_VS_LUT_14_W = SPA(E_SNONE , E_PAGE_01, 0x29), + E_REG_P01_SC_VS_LUT_15_W = SPA(E_SNONE , E_PAGE_01, 0x2A), + E_REG_P01_SC_VS_LUT_16_W = SPA(E_SNONE , E_PAGE_01, 0x2B), + E_REG_P01_SC_VS_LUT_17_W = SPA(E_SNONE , E_PAGE_01, 0x2C), + E_REG_P01_SC_VS_LUT_18_W = SPA(E_SNONE , E_PAGE_01, 0x2D), + E_REG_P01_SC_VS_LUT_19_W = SPA(E_SNONE , E_PAGE_01, 0x2E), + E_REG_P01_SC_VS_LUT_20_W = SPA(E_SNONE , E_PAGE_01, 0x2F), + E_REG_P01_SC_VS_LUT_21_W = SPA(E_SNONE , E_PAGE_01, 0x30), + E_REG_P01_SC_VS_LUT_22_W = SPA(E_SNONE , E_PAGE_01, 0x31), + E_REG_P01_SC_VS_LUT_23_W = SPA(E_SNONE , E_PAGE_01, 0x32), + E_REG_P01_SC_VS_LUT_24_W = SPA(E_SNONE , E_PAGE_01, 0x33), + E_REG_P01_SC_VS_LUT_25_W = SPA(E_SNONE , E_PAGE_01, 0x34), + E_REG_P01_SC_VS_LUT_26_W = SPA(E_SNONE , E_PAGE_01, 0x35), + E_REG_P01_SC_VS_LUT_27_W = SPA(E_SNONE , E_PAGE_01, 0x36), + E_REG_P01_SC_VS_LUT_28_W = SPA(E_SNONE , E_PAGE_01, 0x37), + E_REG_P01_SC_VS_LUT_29_W = SPA(E_SNONE , E_PAGE_01, 0x38), + E_REG_P01_SC_VS_LUT_30_W = SPA(E_SNONE , E_PAGE_01, 0x39), + E_REG_P01_SC_VS_LUT_31_W = SPA(E_SNONE , E_PAGE_01, 0x3A), + E_REG_P01_SC_VS_LUT_32_W = SPA(E_SNONE , E_PAGE_01, 0x3B), + E_REG_P01_SC_VS_LUT_33_W = SPA(E_SNONE , E_PAGE_01, 0x3C), + E_REG_P01_SC_VS_LUT_34_W = SPA(E_SNONE , E_PAGE_01, 0x3D), + E_REG_P01_SC_VS_LUT_35_W = SPA(E_SNONE , E_PAGE_01, 0x3E), + E_REG_P01_SC_VS_LUT_36_W = SPA(E_SNONE , E_PAGE_01, 0x3F), + E_REG_P01_SC_VS_LUT_37_W = SPA(E_SNONE , E_PAGE_01, 0x40), + E_REG_P01_SC_VS_LUT_38_W = SPA(E_SNONE , E_PAGE_01, 0x41), + E_REG_P01_SC_VS_LUT_39_W = SPA(E_SNONE , E_PAGE_01, 0x42), + E_REG_P01_SC_VS_LUT_40_W = SPA(E_SNONE , E_PAGE_01, 0x43), + E_REG_P01_SC_VS_LUT_41_W = SPA(E_SNONE , E_PAGE_01, 0x44), + E_REG_P01_SC_VS_LUT_42_W = SPA(E_SNONE , E_PAGE_01, 0x45), + E_REG_P01_SC_VS_LUT_43_W = SPA(E_SNONE , E_PAGE_01, 0x46), + E_REG_P01_SC_VS_LUT_44_W = SPA(E_SNONE , E_PAGE_01, 0x47), + E_REG_P01_SC_LAT_SCO_RW = SPA(E_SNONE , E_PAGE_01, 0x48), + E_REG_P01_VIDFORMAT_W = SPA(E_SNONE , E_PAGE_01, 0xA0), + E_REG_P01_REFPIX_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xA1), + E_REG_P01_REFPIX_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xA2), + E_REG_P01_REFLINE_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xA3), + E_REG_P01_REFLINE_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xA4), + E_REG_P01_NPIX_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xA5), + E_REG_P01_NPIX_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xA6), + E_REG_P01_NLINE_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xA7), + E_REG_P01_NLINE_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xA8), + E_REG_P01_VWIN_START_1_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xBD), + E_REG_P01_VWIN_START_1_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xBE), + E_REG_P01_VWIN_END_1_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xBF), + E_REG_P01_VWIN_END_1_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xC0), + E_REG_P01_VWIN_START_2_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xC1), + E_REG_P01_VWIN_START_2_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xC2), + E_REG_P01_VWIN_END_2_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xC3), + E_REG_P01_VWIN_END_2_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xC4), + E_REG_P01_DE_START_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xC5), + E_REG_P01_DE_START_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xC6), + E_REG_P01_DE_STOP_MSB_W = SPA(E_SNONE , E_PAGE_01, 0xC7), + E_REG_P01_DE_STOP_LSB_W = SPA(E_SNONE , E_PAGE_01, 0xC8), + E_REG_P01_TBG_CNTRL_0_W = SPA(E_SP01_TBG_CNTRL_0 , E_PAGE_01, 0xCA), + E_REG_P02_PLL_SERIAL_1_RW = SPA(E_SNONE , E_PAGE_02, 0x00), + E_REG_P02_PLL_SERIAL_2_RW = SPA(E_SNONE , E_PAGE_02, 0x01), + E_REG_P02_PLL_SERIAL_3_RW = SPA(E_SNONE , E_PAGE_02, 0x02), + E_REG_P02_SERIALIZER_RW = SPA(E_SNONE , E_PAGE_02, 0x03), + E_REG_P02_BUFFER_OUT_RW = SPA(E_SNONE , E_PAGE_02, 0x04), + E_REG_P02_PLL_SCG1_RW = SPA(E_SNONE , E_PAGE_02, 0x05), + E_REG_P02_PLL_SCG2_RW = SPA(E_SNONE , E_PAGE_02, 0x06), + E_REG_P02_PLL_SCGN1_RW = SPA(E_SNONE , E_PAGE_02, 0x07), + E_REG_P02_PLL_SCGN2_RW = SPA(E_SNONE , E_PAGE_02, 0x08), + E_REG_P02_PLL_SCGR1_RW = SPA(E_SNONE , E_PAGE_02, 0x09), + E_REG_P02_PLL_SCGR2_RW = SPA(E_SNONE , E_PAGE_02, 0x0A), + E_REG_P02_VAI_PLL_R = SPA(E_SNONE , E_PAGE_02, 0x0D), + E_REG_P02_AUDIO_DIV_RW = SPA(E_SNONE , E_PAGE_02, 0x0E), + E_REG_P02_TEST1_RW = SPA(E_SNONE , E_PAGE_02, 0x0F), + /*E_REG_P02_TEST2_RW = SPA(E_SNONE , E_PAGE_02, 0x10),*/ + E_REG_P02_SEL_CLK_RW = SPA(E_SNONE , E_PAGE_02, 0x11), + E_REG_P02_ANA_GENERAL_RW = SPA(E_SNONE , E_PAGE_02, 0x12), + E_REG_P02_BUFFER_OUT2_RW = SPA(E_SNONE , E_PAGE_02, 0x13), + E_REG_P02_SRL_TSTPAT0_RW = SPA(E_SNONE , E_PAGE_02, 0x14), + E_REG_P02_SRL_TSTPAT1_RW = SPA(E_SNONE , E_PAGE_02, 0x15), + E_REG_P02_SRL_TSTPAT2_RW = SPA(E_SNONE , E_PAGE_02, 0x16), + E_REG_P02_SRL_TSTPAT3_RW = SPA(E_SNONE , E_PAGE_02, 0x17), + + E_REG_P09_EDID_DATA_0_R = SPA(E_SNONE , E_PAGE_09, 0x00), + E_REG_P09_EDID_DATA_1_R = SPA(E_SNONE , E_PAGE_09, 0x01), + E_REG_P09_EDID_DATA_2_R = SPA(E_SNONE , E_PAGE_09, 0x02), + E_REG_P09_EDID_DATA_3_R = SPA(E_SNONE , E_PAGE_09, 0x03), + E_REG_P09_EDID_DATA_4_R = SPA(E_SNONE , E_PAGE_09, 0x04), + E_REG_P09_EDID_DATA_5_R = SPA(E_SNONE , E_PAGE_09, 0x05), + E_REG_P09_EDID_DATA_6_R = SPA(E_SNONE , E_PAGE_09, 0x06), + E_REG_P09_EDID_DATA_7_R = SPA(E_SNONE , E_PAGE_09, 0x07), + E_REG_P09_EDID_DATA_8_R = SPA(E_SNONE , E_PAGE_09, 0x08), + E_REG_P09_EDID_DATA_9_R = SPA(E_SNONE , E_PAGE_09, 0x09), + E_REG_P09_EDID_DATA_10_R = SPA(E_SNONE , E_PAGE_09, 0x0A), + E_REG_P09_EDID_DATA_11_R = SPA(E_SNONE , E_PAGE_09, 0x0B), + E_REG_P09_EDID_DATA_12_R = SPA(E_SNONE , E_PAGE_09, 0x0C), + E_REG_P09_EDID_DATA_13_R = SPA(E_SNONE , E_PAGE_09, 0x0D), + E_REG_P09_EDID_DATA_14_R = SPA(E_SNONE , E_PAGE_09, 0x0E), + E_REG_P09_EDID_DATA_15_R = SPA(E_SNONE , E_PAGE_09, 0x0F), + E_REG_P09_EDID_DATA_16_R = SPA(E_SNONE , E_PAGE_09, 0x10), + E_REG_P09_EDID_DATA_17_R = SPA(E_SNONE , E_PAGE_09, 0x11), + E_REG_P09_EDID_DATA_18_R = SPA(E_SNONE , E_PAGE_09, 0x12), + E_REG_P09_EDID_DATA_19_R = SPA(E_SNONE , E_PAGE_09, 0x13), + E_REG_P09_EDID_DATA_20_R = SPA(E_SNONE , E_PAGE_09, 0x14), + E_REG_P09_EDID_DATA_21_R = SPA(E_SNONE , E_PAGE_09, 0x15), + E_REG_P09_EDID_DATA_22_R = SPA(E_SNONE , E_PAGE_09, 0x16), + E_REG_P09_EDID_DATA_23_R = SPA(E_SNONE , E_PAGE_09, 0x17), + E_REG_P09_EDID_DATA_24_R = SPA(E_SNONE , E_PAGE_09, 0x18), + E_REG_P09_EDID_DATA_25_R = SPA(E_SNONE , E_PAGE_09, 0x19), + E_REG_P09_EDID_DATA_26_R = SPA(E_SNONE , E_PAGE_09, 0x1A), + E_REG_P09_EDID_DATA_27_R = SPA(E_SNONE , E_PAGE_09, 0x1B), + E_REG_P09_EDID_DATA_28_R = SPA(E_SNONE , E_PAGE_09, 0x1C), + E_REG_P09_EDID_DATA_29_R = SPA(E_SNONE , E_PAGE_09, 0x1D), + E_REG_P09_EDID_DATA_30_R = SPA(E_SNONE , E_PAGE_09, 0x1E), + E_REG_P09_EDID_DATA_31_R = SPA(E_SNONE , E_PAGE_09, 0x1F), + E_REG_P09_EDID_DATA_32_R = SPA(E_SNONE , E_PAGE_09, 0x20), + E_REG_P09_EDID_DATA_33_R = SPA(E_SNONE , E_PAGE_09, 0x21), + E_REG_P09_EDID_DATA_34_R = SPA(E_SNONE , E_PAGE_09, 0x22), + E_REG_P09_EDID_DATA_35_R = SPA(E_SNONE , E_PAGE_09, 0x23), + E_REG_P09_EDID_DATA_36_R = SPA(E_SNONE , E_PAGE_09, 0x24), + E_REG_P09_EDID_DATA_37_R = SPA(E_SNONE , E_PAGE_09, 0x25), + E_REG_P09_EDID_DATA_38_R = SPA(E_SNONE , E_PAGE_09, 0x26), + E_REG_P09_EDID_DATA_39_R = SPA(E_SNONE , E_PAGE_09, 0x27), + E_REG_P09_EDID_DATA_40_R = SPA(E_SNONE , E_PAGE_09, 0x28), + E_REG_P09_EDID_DATA_41_R = SPA(E_SNONE , E_PAGE_09, 0x29), + E_REG_P09_EDID_DATA_42_R = SPA(E_SNONE , E_PAGE_09, 0x2A), + E_REG_P09_EDID_DATA_43_R = SPA(E_SNONE , E_PAGE_09, 0x2B), + E_REG_P09_EDID_DATA_44_R = SPA(E_SNONE , E_PAGE_09, 0x2C), + E_REG_P09_EDID_DATA_45_R = SPA(E_SNONE , E_PAGE_09, 0x2D), + E_REG_P09_EDID_DATA_46_R = SPA(E_SNONE , E_PAGE_09, 0x2E), + E_REG_P09_EDID_DATA_47_R = SPA(E_SNONE , E_PAGE_09, 0x2F), + E_REG_P09_EDID_DATA_48_R = SPA(E_SNONE , E_PAGE_09, 0x30), + E_REG_P09_EDID_DATA_49_R = SPA(E_SNONE , E_PAGE_09, 0x31), + E_REG_P09_EDID_DATA_50_R = SPA(E_SNONE , E_PAGE_09, 0x32), + E_REG_P09_EDID_DATA_51_R = SPA(E_SNONE , E_PAGE_09, 0x33), + E_REG_P09_EDID_DATA_52_R = SPA(E_SNONE , E_PAGE_09, 0x34), + E_REG_P09_EDID_DATA_53_R = SPA(E_SNONE , E_PAGE_09, 0x35), + E_REG_P09_EDID_DATA_54_R = SPA(E_SNONE , E_PAGE_09, 0x36), + E_REG_P09_EDID_DATA_55_R = SPA(E_SNONE , E_PAGE_09, 0x37), + E_REG_P09_EDID_DATA_56_R = SPA(E_SNONE , E_PAGE_09, 0x38), + E_REG_P09_EDID_DATA_57_R = SPA(E_SNONE , E_PAGE_09, 0x39), + E_REG_P09_EDID_DATA_58_R = SPA(E_SNONE , E_PAGE_09, 0x3A), + E_REG_P09_EDID_DATA_59_R = SPA(E_SNONE , E_PAGE_09, 0x3B), + E_REG_P09_EDID_DATA_60_R = SPA(E_SNONE , E_PAGE_09, 0x3C), + E_REG_P09_EDID_DATA_61_R = SPA(E_SNONE , E_PAGE_09, 0x3D), + E_REG_P09_EDID_DATA_62_R = SPA(E_SNONE , E_PAGE_09, 0x3E), + E_REG_P09_EDID_DATA_63_R = SPA(E_SNONE , E_PAGE_09, 0x3F), + E_REG_P09_EDID_DATA_64_R = SPA(E_SNONE , E_PAGE_09, 0x40), + E_REG_P09_EDID_DATA_65_R = SPA(E_SNONE , E_PAGE_09, 0x41), + E_REG_P09_EDID_DATA_66_R = SPA(E_SNONE , E_PAGE_09, 0x42), + E_REG_P09_EDID_DATA_67_R = SPA(E_SNONE , E_PAGE_09, 0x43), + E_REG_P09_EDID_DATA_68_R = SPA(E_SNONE , E_PAGE_09, 0x44), + E_REG_P09_EDID_DATA_69_R = SPA(E_SNONE , E_PAGE_09, 0x45), + E_REG_P09_EDID_DATA_70_R = SPA(E_SNONE , E_PAGE_09, 0x46), + E_REG_P09_EDID_DATA_71_R = SPA(E_SNONE , E_PAGE_09, 0x47), + E_REG_P09_EDID_DATA_72_R = SPA(E_SNONE , E_PAGE_09, 0x48), + E_REG_P09_EDID_DATA_73_R = SPA(E_SNONE , E_PAGE_09, 0x49), + E_REG_P09_EDID_DATA_74_R = SPA(E_SNONE , E_PAGE_09, 0x4A), + E_REG_P09_EDID_DATA_75_R = SPA(E_SNONE , E_PAGE_09, 0x4B), + E_REG_P09_EDID_DATA_76_R = SPA(E_SNONE , E_PAGE_09, 0x4C), + E_REG_P09_EDID_DATA_77_R = SPA(E_SNONE , E_PAGE_09, 0x4D), + E_REG_P09_EDID_DATA_78_R = SPA(E_SNONE , E_PAGE_09, 0x4E), + E_REG_P09_EDID_DATA_79_R = SPA(E_SNONE , E_PAGE_09, 0x4F), + E_REG_P09_EDID_DATA_80_R = SPA(E_SNONE , E_PAGE_09, 0x50), + E_REG_P09_EDID_DATA_81_R = SPA(E_SNONE , E_PAGE_09, 0x51), + E_REG_P09_EDID_DATA_82_R = SPA(E_SNONE , E_PAGE_09, 0x52), + E_REG_P09_EDID_DATA_83_R = SPA(E_SNONE , E_PAGE_09, 0x53), + E_REG_P09_EDID_DATA_84_R = SPA(E_SNONE , E_PAGE_09, 0x54), + E_REG_P09_EDID_DATA_85_R = SPA(E_SNONE , E_PAGE_09, 0x55), + E_REG_P09_EDID_DATA_86_R = SPA(E_SNONE , E_PAGE_09, 0x56), + E_REG_P09_EDID_DATA_87_R = SPA(E_SNONE , E_PAGE_09, 0x57), + E_REG_P09_EDID_DATA_88_R = SPA(E_SNONE , E_PAGE_09, 0x58), + E_REG_P09_EDID_DATA_89_R = SPA(E_SNONE , E_PAGE_09, 0x59), + E_REG_P09_EDID_DATA_90_R = SPA(E_SNONE , E_PAGE_09, 0x5A), + E_REG_P09_EDID_DATA_91_R = SPA(E_SNONE , E_PAGE_09, 0x5B), + E_REG_P09_EDID_DATA_92_R = SPA(E_SNONE , E_PAGE_09, 0x5C), + E_REG_P09_EDID_DATA_93_R = SPA(E_SNONE , E_PAGE_09, 0x5D), + E_REG_P09_EDID_DATA_94_R = SPA(E_SNONE , E_PAGE_09, 0x5E), + E_REG_P09_EDID_DATA_95_R = SPA(E_SNONE , E_PAGE_09, 0x5F), + E_REG_P09_EDID_DATA_96_R = SPA(E_SNONE , E_PAGE_09, 0x60), + E_REG_P09_EDID_DATA_97_R = SPA(E_SNONE , E_PAGE_09, 0x61), + E_REG_P09_EDID_DATA_98_R = SPA(E_SNONE , E_PAGE_09, 0x62), + E_REG_P09_EDID_DATA_99_R = SPA(E_SNONE , E_PAGE_09, 0x63), + E_REG_P09_EDID_DATA_100_R = SPA(E_SNONE , E_PAGE_09, 0x64), + E_REG_P09_EDID_DATA_101_R = SPA(E_SNONE , E_PAGE_09, 0x65), + E_REG_P09_EDID_DATA_102_R = SPA(E_SNONE , E_PAGE_09, 0x66), + E_REG_P09_EDID_DATA_103_R = SPA(E_SNONE , E_PAGE_09, 0x67), + E_REG_P09_EDID_DATA_104_R = SPA(E_SNONE , E_PAGE_09, 0x68), + E_REG_P09_EDID_DATA_105_R = SPA(E_SNONE , E_PAGE_09, 0x69), + E_REG_P09_EDID_DATA_106_R = SPA(E_SNONE , E_PAGE_09, 0x6A), + E_REG_P09_EDID_DATA_107_R = SPA(E_SNONE , E_PAGE_09, 0x6B), + E_REG_P09_EDID_DATA_108_R = SPA(E_SNONE , E_PAGE_09, 0x6C), + E_REG_P09_EDID_DATA_109_R = SPA(E_SNONE , E_PAGE_09, 0x6D), + E_REG_P09_EDID_DATA_110_R = SPA(E_SNONE , E_PAGE_09, 0x6E), + E_REG_P09_EDID_DATA_111_R = SPA(E_SNONE , E_PAGE_09, 0x6F), + E_REG_P09_EDID_DATA_112_R = SPA(E_SNONE , E_PAGE_09, 0x70), + E_REG_P09_EDID_DATA_113_R = SPA(E_SNONE , E_PAGE_09, 0x71), + E_REG_P09_EDID_DATA_114_R = SPA(E_SNONE , E_PAGE_09, 0x72), + E_REG_P09_EDID_DATA_115_R = SPA(E_SNONE , E_PAGE_09, 0x73), + E_REG_P09_EDID_DATA_116_R = SPA(E_SNONE , E_PAGE_09, 0x74), + E_REG_P09_EDID_DATA_117_R = SPA(E_SNONE , E_PAGE_09, 0x75), + E_REG_P09_EDID_DATA_118_R = SPA(E_SNONE , E_PAGE_09, 0x76), + E_REG_P09_EDID_DATA_119_R = SPA(E_SNONE , E_PAGE_09, 0x77), + E_REG_P09_EDID_DATA_120_R = SPA(E_SNONE , E_PAGE_09, 0x78), + E_REG_P09_EDID_DATA_121_R = SPA(E_SNONE , E_PAGE_09, 0x79), + E_REG_P09_EDID_DATA_122_R = SPA(E_SNONE , E_PAGE_09, 0x7A), + E_REG_P09_EDID_DATA_123_R = SPA(E_SNONE , E_PAGE_09, 0x7B), + E_REG_P09_EDID_DATA_124_R = SPA(E_SNONE , E_PAGE_09, 0x7C), + E_REG_P09_EDID_DATA_125_R = SPA(E_SNONE , E_PAGE_09, 0x7D), + E_REG_P09_EDID_DATA_126_R = SPA(E_SNONE , E_PAGE_09, 0x7E), + E_REG_P09_EDID_DATA_127_R = SPA(E_SNONE , E_PAGE_09, 0x7F), + E_REG_P09_EDID_CTRL_RW = SPA(E_SNONE , E_PAGE_09, 0xFA), + E_REG_P09_DDC_ADDR_RW = SPA(E_SNONE , E_PAGE_09, 0xFB), + E_REG_P09_DDC_OFFS_RW = SPA(E_SNONE , E_PAGE_09, 0xFC), + E_REG_P09_DDC_SEGM_ADDR_RW = SPA(E_SNONE , E_PAGE_09, 0xFD), + E_REG_P09_DDC_SEGM_RW = SPA(E_SNONE , E_PAGE_09, 0xFE), + + E_REG_P10_IF1_HB0_RW = SPA(E_SNONE , E_PAGE_10, 0x20), + E_REG_P10_IF1_HB1_RW = SPA(E_SNONE , E_PAGE_10, 0x21), + E_REG_P10_IF1_HB2_RW = SPA(E_SNONE , E_PAGE_10, 0x22), + E_REG_P10_IF1_PB0_RW = SPA(E_SNONE , E_PAGE_10, 0x23), + E_REG_P10_IF1_PB1_RW = SPA(E_SNONE , E_PAGE_10, 0x24), + E_REG_P10_IF1_PB2_RW = SPA(E_SNONE , E_PAGE_10, 0x25), + E_REG_P10_IF1_PB3_RW = SPA(E_SNONE , E_PAGE_10, 0x26), + E_REG_P10_IF1_PB4_RW = SPA(E_SNONE , E_PAGE_10, 0x27), + E_REG_P10_IF1_PB5_RW = SPA(E_SNONE , E_PAGE_10, 0x28), + E_REG_P10_IF1_PB6_RW = SPA(E_SNONE , E_PAGE_10, 0x29), + E_REG_P10_IF1_PB7_RW = SPA(E_SNONE , E_PAGE_10, 0x2A), + E_REG_P10_IF1_PB8_RW = SPA(E_SNONE , E_PAGE_10, 0x2B), + E_REG_P10_IF1_PB9_RW = SPA(E_SNONE , E_PAGE_10, 0x2C), + E_REG_P10_IF1_PB10_RW = SPA(E_SNONE , E_PAGE_10, 0x2D), + E_REG_P10_IF1_PB11_RW = SPA(E_SNONE , E_PAGE_10, 0x2E), + E_REG_P10_IF1_PB12_RW = SPA(E_SNONE , E_PAGE_10, 0x2F), + E_REG_P10_IF1_PB13_RW = SPA(E_SNONE , E_PAGE_10, 0x30), + E_REG_P10_IF1_PB14_RW = SPA(E_SNONE , E_PAGE_10, 0x31), + E_REG_P10_IF1_PB15_RW = SPA(E_SNONE , E_PAGE_10, 0x32), + E_REG_P10_IF1_PB16_RW = SPA(E_SNONE , E_PAGE_10, 0x33), + E_REG_P10_IF1_PB17_RW = SPA(E_SNONE , E_PAGE_10, 0x34), + E_REG_P10_IF1_PB18_RW = SPA(E_SNONE , E_PAGE_10, 0x35), + E_REG_P10_IF1_PB19_RW = SPA(E_SNONE , E_PAGE_10, 0x36), + E_REG_P10_IF1_PB20_RW = SPA(E_SNONE , E_PAGE_10, 0x37), + E_REG_P10_IF1_PB21_RW = SPA(E_SNONE , E_PAGE_10, 0x38), + E_REG_P10_IF1_PB22_RW = SPA(E_SNONE , E_PAGE_10, 0x39), + E_REG_P10_IF1_PB23_RW = SPA(E_SNONE , E_PAGE_10, 0x3A), + E_REG_P10_IF1_PB24_RW = SPA(E_SNONE , E_PAGE_10, 0x3B), + E_REG_P10_IF1_PB25_RW = SPA(E_SNONE , E_PAGE_10, 0x3C), + E_REG_P10_IF1_PB26_RW = SPA(E_SNONE , E_PAGE_10, 0x3D), + E_REG_P10_IF1_PB27_RW = SPA(E_SNONE , E_PAGE_10, 0x3E), + E_REG_P10_IF2_HB0_RW = SPA(E_SNONE , E_PAGE_10, 0x40), + E_REG_P10_IF2_HB1_RW = SPA(E_SNONE , E_PAGE_10, 0x41), + E_REG_P10_IF2_HB2_RW = SPA(E_SNONE , E_PAGE_10, 0x42), + E_REG_P10_IF2_PB0_RW = SPA(E_SNONE , E_PAGE_10, 0x43), + E_REG_P10_IF2_PB1_RW = SPA(E_SNONE , E_PAGE_10, 0x44), + E_REG_P10_IF2_PB2_RW = SPA(E_SNONE , E_PAGE_10, 0x45), + E_REG_P10_IF2_PB3_RW = SPA(E_SNONE , E_PAGE_10, 0x46), + E_REG_P10_IF2_PB4_RW = SPA(E_SNONE , E_PAGE_10, 0x47), + E_REG_P10_IF2_PB5_RW = SPA(E_SNONE , E_PAGE_10, 0x48), + E_REG_P10_IF2_PB6_RW = SPA(E_SNONE , E_PAGE_10, 0x49), + E_REG_P10_IF2_PB7_RW = SPA(E_SNONE , E_PAGE_10, 0x4A), + E_REG_P10_IF2_PB8_RW = SPA(E_SNONE , E_PAGE_10, 0x4B), + E_REG_P10_IF2_PB9_RW = SPA(E_SNONE , E_PAGE_10, 0x4C), + E_REG_P10_IF2_PB10_RW = SPA(E_SNONE , E_PAGE_10, 0x4D), + E_REG_P10_IF2_PB11_RW = SPA(E_SNONE , E_PAGE_10, 0x4E), + E_REG_P10_IF2_PB12_RW = SPA(E_SNONE , E_PAGE_10, 0x4F), + E_REG_P10_IF2_PB13_RW = SPA(E_SNONE , E_PAGE_10, 0x50), + E_REG_P10_IF2_PB14_RW = SPA(E_SNONE , E_PAGE_10, 0x51), + E_REG_P10_IF2_PB15_RW = SPA(E_SNONE , E_PAGE_10, 0x52), + E_REG_P10_IF2_PB16_RW = SPA(E_SNONE , E_PAGE_10, 0x53), + E_REG_P10_IF2_PB17_RW = SPA(E_SNONE , E_PAGE_10, 0x54), + E_REG_P10_IF2_PB18_RW = SPA(E_SNONE , E_PAGE_10, 0x55), + E_REG_P10_IF2_PB19_RW = SPA(E_SNONE , E_PAGE_10, 0x56), + E_REG_P10_IF2_PB20_RW = SPA(E_SNONE , E_PAGE_10, 0x57), + E_REG_P10_IF2_PB21_RW = SPA(E_SNONE , E_PAGE_10, 0x58), + E_REG_P10_IF2_PB22_RW = SPA(E_SNONE , E_PAGE_10, 0x59), + E_REG_P10_IF2_PB23_RW = SPA(E_SNONE , E_PAGE_10, 0x5A), + E_REG_P10_IF2_PB24_RW = SPA(E_SNONE , E_PAGE_10, 0x5B), + E_REG_P10_IF2_PB25_RW = SPA(E_SNONE , E_PAGE_10, 0x5C), + E_REG_P10_IF2_PB26_RW = SPA(E_SNONE , E_PAGE_10, 0x5D), + E_REG_P10_IF2_PB27_RW = SPA(E_SNONE , E_PAGE_10, 0x5E), + E_REG_P10_IF3_HB0_RW = SPA(E_SNONE , E_PAGE_10, 0x60), + E_REG_P10_IF3_HB1_RW = SPA(E_SNONE , E_PAGE_10, 0x61), + E_REG_P10_IF3_HB2_RW = SPA(E_SNONE , E_PAGE_10, 0x62), + E_REG_P10_IF3_PB0_RW = SPA(E_SNONE , E_PAGE_10, 0x63), + E_REG_P10_IF3_PB1_RW = SPA(E_SNONE , E_PAGE_10, 0x64), + E_REG_P10_IF3_PB2_RW = SPA(E_SNONE , E_PAGE_10, 0x65), + E_REG_P10_IF3_PB3_RW = SPA(E_SNONE , E_PAGE_10, 0x66), + E_REG_P10_IF3_PB4_RW = SPA(E_SNONE , E_PAGE_10, 0x67), + E_REG_P10_IF3_PB5_RW = SPA(E_SNONE , E_PAGE_10, 0x68), + E_REG_P10_IF3_PB6_RW = SPA(E_SNONE , E_PAGE_10, 0x69), + E_REG_P10_IF3_PB7_RW = SPA(E_SNONE , E_PAGE_10, 0x6A), + E_REG_P10_IF3_PB8_RW = SPA(E_SNONE , E_PAGE_10, 0x6B), + E_REG_P10_IF3_PB9_RW = SPA(E_SNONE , E_PAGE_10, 0x6C), + E_REG_P10_IF3_PB10_RW = SPA(E_SNONE , E_PAGE_10, 0x6D), + E_REG_P10_IF3_PB11_RW = SPA(E_SNONE , E_PAGE_10, 0x6E), + E_REG_P10_IF3_PB12_RW = SPA(E_SNONE , E_PAGE_10, 0x6F), + E_REG_P10_IF3_PB13_RW = SPA(E_SNONE , E_PAGE_10, 0x70), + E_REG_P10_IF3_PB14_RW = SPA(E_SNONE , E_PAGE_10, 0x71), + E_REG_P10_IF3_PB15_RW = SPA(E_SNONE , E_PAGE_10, 0x72), + E_REG_P10_IF3_PB16_RW = SPA(E_SNONE , E_PAGE_10, 0x73), + E_REG_P10_IF3_PB17_RW = SPA(E_SNONE , E_PAGE_10, 0x74), + E_REG_P10_IF3_PB18_RW = SPA(E_SNONE , E_PAGE_10, 0x75), + E_REG_P10_IF3_PB19_RW = SPA(E_SNONE , E_PAGE_10, 0x76), + E_REG_P10_IF3_PB20_RW = SPA(E_SNONE , E_PAGE_10, 0x77), + E_REG_P10_IF3_PB21_RW = SPA(E_SNONE , E_PAGE_10, 0x78), + E_REG_P10_IF3_PB22_RW = SPA(E_SNONE , E_PAGE_10, 0x79), + E_REG_P10_IF3_PB23_RW = SPA(E_SNONE , E_PAGE_10, 0x7A), + E_REG_P10_IF3_PB24_RW = SPA(E_SNONE , E_PAGE_10, 0x7B), + E_REG_P10_IF3_PB25_RW = SPA(E_SNONE , E_PAGE_10, 0x7C), + E_REG_P10_IF3_PB26_RW = SPA(E_SNONE , E_PAGE_10, 0x7D), + E_REG_P10_IF3_PB27_RW = SPA(E_SNONE , E_PAGE_10, 0x7E), + E_REG_P10_IF4_HB0_RW = SPA(E_SNONE , E_PAGE_10, 0x80), + E_REG_P10_IF4_HB1_RW = SPA(E_SNONE , E_PAGE_10, 0x81), + E_REG_P10_IF4_HB2_RW = SPA(E_SNONE , E_PAGE_10, 0x82), + E_REG_P10_IF4_PB0_RW = SPA(E_SNONE , E_PAGE_10, 0x83), + E_REG_P10_IF4_PB1_RW = SPA(E_SNONE , E_PAGE_10, 0x84), + E_REG_P10_IF4_PB2_RW = SPA(E_SNONE , E_PAGE_10, 0x85), + E_REG_P10_IF4_PB3_RW = SPA(E_SNONE , E_PAGE_10, 0x86), + E_REG_P10_IF4_PB4_RW = SPA(E_SNONE , E_PAGE_10, 0x87), + E_REG_P10_IF4_PB5_RW = SPA(E_SNONE , E_PAGE_10, 0x88), + E_REG_P10_IF4_PB6_RW = SPA(E_SNONE , E_PAGE_10, 0x89), + E_REG_P10_IF4_PB7_RW = SPA(E_SNONE , E_PAGE_10, 0x8A), + E_REG_P10_IF4_PB8_RW = SPA(E_SNONE , E_PAGE_10, 0x8B), + E_REG_P10_IF4_PB9_RW = SPA(E_SNONE , E_PAGE_10, 0x8C), + E_REG_P10_IF4_PB10_RW = SPA(E_SNONE , E_PAGE_10, 0x8D), + E_REG_P10_IF4_PB11_RW = SPA(E_SNONE , E_PAGE_10, 0x8E), + E_REG_P10_IF4_PB12_RW = SPA(E_SNONE , E_PAGE_10, 0x8F), + E_REG_P10_IF4_PB13_RW = SPA(E_SNONE , E_PAGE_10, 0x90), + E_REG_P10_IF4_PB14_RW = SPA(E_SNONE , E_PAGE_10, 0x91), + E_REG_P10_IF4_PB15_RW = SPA(E_SNONE , E_PAGE_10, 0x92), + E_REG_P10_IF4_PB16_RW = SPA(E_SNONE , E_PAGE_10, 0x93), + E_REG_P10_IF4_PB17_RW = SPA(E_SNONE , E_PAGE_10, 0x94), + E_REG_P10_IF4_PB18_RW = SPA(E_SNONE , E_PAGE_10, 0x95), + E_REG_P10_IF4_PB19_RW = SPA(E_SNONE , E_PAGE_10, 0x96), + E_REG_P10_IF4_PB20_RW = SPA(E_SNONE , E_PAGE_10, 0x97), + E_REG_P10_IF4_PB21_RW = SPA(E_SNONE , E_PAGE_10, 0x98), + E_REG_P10_IF4_PB22_RW = SPA(E_SNONE , E_PAGE_10, 0x99), + E_REG_P10_IF4_PB23_RW = SPA(E_SNONE , E_PAGE_10, 0x9A), + E_REG_P10_IF4_PB24_RW = SPA(E_SNONE , E_PAGE_10, 0x9B), + E_REG_P10_IF4_PB25_RW = SPA(E_SNONE , E_PAGE_10, 0x9C), + E_REG_P10_IF4_PB26_RW = SPA(E_SNONE , E_PAGE_10, 0x9D), + E_REG_P10_IF4_PB27_RW = SPA(E_SNONE , E_PAGE_10, 0x9E), + E_REG_P10_IF5_HB0_RW = SPA(E_SNONE , E_PAGE_10, 0xA0), + E_REG_P10_IF5_HB1_RW = SPA(E_SNONE , E_PAGE_10, 0xA1), + E_REG_P10_IF5_HB2_RW = SPA(E_SNONE , E_PAGE_10, 0xA2), + E_REG_P10_IF5_PB0_RW = SPA(E_SNONE , E_PAGE_10, 0xA3), + E_REG_P10_IF5_PB1_RW = SPA(E_SNONE , E_PAGE_10, 0xA4), + E_REG_P10_IF5_PB2_RW = SPA(E_SNONE , E_PAGE_10, 0xA5), + E_REG_P10_IF5_PB3_RW = SPA(E_SNONE , E_PAGE_10, 0xA6), + E_REG_P10_IF5_PB4_RW = SPA(E_SNONE , E_PAGE_10, 0xA7), + E_REG_P10_IF5_PB5_RW = SPA(E_SNONE , E_PAGE_10, 0xA8), + E_REG_P10_IF5_PB6_RW = SPA(E_SNONE , E_PAGE_10, 0xA9), + E_REG_P10_IF5_PB7_RW = SPA(E_SNONE , E_PAGE_10, 0xAA), + E_REG_P10_IF5_PB8_RW = SPA(E_SNONE , E_PAGE_10, 0xAB), + E_REG_P10_IF5_PB9_RW = SPA(E_SNONE , E_PAGE_10, 0xAC), + E_REG_P10_IF5_PB10_RW = SPA(E_SNONE , E_PAGE_10, 0xAD), + E_REG_P10_IF5_PB11_RW = SPA(E_SNONE , E_PAGE_10, 0xAE), + E_REG_P10_IF5_PB12_RW = SPA(E_SNONE , E_PAGE_10, 0xAF), + E_REG_P10_IF5_PB13_RW = SPA(E_SNONE , E_PAGE_10, 0xB0), + E_REG_P10_IF5_PB14_RW = SPA(E_SNONE , E_PAGE_10, 0xB1), + E_REG_P10_IF5_PB15_RW = SPA(E_SNONE , E_PAGE_10, 0xB2), + E_REG_P10_IF5_PB16_RW = SPA(E_SNONE , E_PAGE_10, 0xB3), + E_REG_P10_IF5_PB17_RW = SPA(E_SNONE , E_PAGE_10, 0xB4), + E_REG_P10_IF5_PB18_RW = SPA(E_SNONE , E_PAGE_10, 0xB5), + E_REG_P10_IF5_PB19_RW = SPA(E_SNONE , E_PAGE_10, 0xB6), + E_REG_P10_IF5_PB20_RW = SPA(E_SNONE , E_PAGE_10, 0xB7), + E_REG_P10_IF5_PB21_RW = SPA(E_SNONE , E_PAGE_10, 0xB8), + E_REG_P10_IF5_PB22_RW = SPA(E_SNONE , E_PAGE_10, 0xB9), + E_REG_P10_IF5_PB23_RW = SPA(E_SNONE , E_PAGE_10, 0xBA), + E_REG_P10_IF5_PB24_RW = SPA(E_SNONE , E_PAGE_10, 0xBB), + E_REG_P10_IF5_PB25_RW = SPA(E_SNONE , E_PAGE_10, 0xBC), + E_REG_P10_IF5_PB26_RW = SPA(E_SNONE , E_PAGE_10, 0xBD), + E_REG_P10_IF5_PB27_RW = SPA(E_SNONE , E_PAGE_10, 0xBE), + E_REG_P11_AIP_CNTRL_0_RW = SPA(E_SNONE , E_PAGE_11, 0x00), + E_REG_P11_CA_I2S_RW = SPA(E_SNONE , E_PAGE_11, 0x01), + E_REG_P11_CA_DSD_RW = SPA(E_SNONE , E_PAGE_11, 0x02), + E_REG_P11_OBA_PH_RW = SPA(E_SNONE , E_PAGE_11, 0x03), + E_REG_P11_LATENCY_RD_RW = SPA(E_SNONE , E_PAGE_11, 0x04), + E_REG_P11_ACR_CTS_0_RW = SPA(E_SNONE , E_PAGE_11, 0x05), + E_REG_P11_ACR_CTS_1_RW = SPA(E_SNONE , E_PAGE_11, 0x06), + E_REG_P11_ACR_CTS_2_RW = SPA(E_SNONE , E_PAGE_11, 0x07), + E_REG_P11_ACR_N_0_RW = SPA(E_SNONE , E_PAGE_11, 0x08), + E_REG_P11_ACR_N_1_RW = SPA(E_SNONE , E_PAGE_11, 0x09), + E_REG_P11_ACR_N_2_RW = SPA(E_SNONE , E_PAGE_11, 0x0A), + E_REG_P11_GC_AVMUTE_RW = SPA(E_SNONE , E_PAGE_11, 0x0B), + E_REG_P11_CTS_N_RW = SPA(E_SNONE , E_PAGE_11, 0x0C), + E_REG_P11_ENC_CNTRL_RW = SPA(E_SNONE , E_PAGE_11, 0x0D), + E_REG_P11_DIP_FLAGS_RW = SPA(E_SNONE , E_PAGE_11, 0x0E), + E_REG_P11_DIP_IF_FLAGS_RW = SPA(E_SNONE , E_PAGE_11, 0x0F), + E_REG_P11_CH_STAT_B_0_RW = SPA(E_SNONE , E_PAGE_11, 0x14), + E_REG_P11_CH_STAT_B_1_RW = SPA(E_SNONE , E_PAGE_11, 0x15), + E_REG_P11_CH_STAT_B_3_RW = SPA(E_SNONE , E_PAGE_11, 0x16), + E_REG_P11_CH_STAT_B_4_RW = SPA(E_SNONE , E_PAGE_11, 0x17), + E_REG_P11_CH_STAT_B_2_ap0_l_RW = SPA(E_SNONE , E_PAGE_11, 0x18), + E_REG_P11_CH_STAT_B_2_ap0_r_RW = SPA(E_SNONE , E_PAGE_11, 0x19), + E_REG_P11_CH_STAT_B_2_ap1_l_RW = SPA(E_SNONE , E_PAGE_11, 0x1A), + E_REG_P11_CH_STAT_B_2_ap1_r_RW = SPA(E_SNONE , E_PAGE_11, 0x1B), + E_REG_P11_CH_STAT_B_2_ap2_l_RW = SPA(E_SNONE , E_PAGE_11, 0x1C), + E_REG_P11_CH_STAT_B_2_ap2_r_RW = SPA(E_SNONE , E_PAGE_11, 0x1D), + E_REG_P11_CH_STAT_B_2_ap3_l_RW = SPA(E_SNONE , E_PAGE_11, 0x1E), + E_REG_P11_CH_STAT_B_2_ap3_r_RW = SPA(E_SNONE , E_PAGE_11, 0x1F), + E_REG_P11_ISRC1_HB0_RW = SPA(E_SNONE , E_PAGE_11, 0x20), + E_REG_P11_ISRC1_HB1_RW = SPA(E_SNONE , E_PAGE_11, 0x21), + E_REG_P11_ISRC1_HB2_RW = SPA(E_SNONE , E_PAGE_11, 0x22), + E_REG_P11_ISRC1_PB0_RW = SPA(E_SNONE , E_PAGE_11, 0x23), + E_REG_P11_ISRC1_PB1_RW = SPA(E_SNONE , E_PAGE_11, 0x24), + E_REG_P11_ISRC1_PB2_RW = SPA(E_SNONE , E_PAGE_11, 0x25), + E_REG_P11_ISRC1_PB3_RW = SPA(E_SNONE , E_PAGE_11, 0x26), + E_REG_P11_ISRC1_PB4_RW = SPA(E_SNONE , E_PAGE_11, 0x27), + E_REG_P11_ISRC1_PB5_RW = SPA(E_SNONE , E_PAGE_11, 0x28), + E_REG_P11_ISRC1_PB6_RW = SPA(E_SNONE , E_PAGE_11, 0x29), + E_REG_P11_ISRC1_PB7_RW = SPA(E_SNONE , E_PAGE_11, 0x2A), + E_REG_P11_ISRC1_PB8_RW = SPA(E_SNONE , E_PAGE_11, 0x2B), + E_REG_P11_ISRC1_PB9_RW = SPA(E_SNONE , E_PAGE_11, 0x2C), + E_REG_P11_ISRC1_PB10_RW = SPA(E_SNONE , E_PAGE_11, 0x2D), + E_REG_P11_ISRC1_PB11_RW = SPA(E_SNONE , E_PAGE_11, 0x2E), + E_REG_P11_ISRC1_PB12_RW = SPA(E_SNONE , E_PAGE_11, 0x2F), + E_REG_P11_ISRC1_PB13_RW = SPA(E_SNONE , E_PAGE_11, 0x30), + E_REG_P11_ISRC1_PB14_RW = SPA(E_SNONE , E_PAGE_11, 0x31), + E_REG_P11_ISRC1_PB15_RW = SPA(E_SNONE , E_PAGE_11, 0x32), + E_REG_P11_ISRC1_PB16_RW = SPA(E_SNONE , E_PAGE_11, 0x33), + E_REG_P11_ISRC1_PB17_RW = SPA(E_SNONE , E_PAGE_11, 0x34), + E_REG_P11_ISRC1_PB18_RW = SPA(E_SNONE , E_PAGE_11, 0x35), + E_REG_P11_ISRC1_PB19_RW = SPA(E_SNONE , E_PAGE_11, 0x36), + E_REG_P11_ISRC1_PB20_RW = SPA(E_SNONE , E_PAGE_11, 0x37), + E_REG_P11_ISRC1_PB21_RW = SPA(E_SNONE , E_PAGE_11, 0x38), + E_REG_P11_ISRC1_PB22_RW = SPA(E_SNONE , E_PAGE_11, 0x39), + E_REG_P11_ISRC1_PB23_RW = SPA(E_SNONE , E_PAGE_11, 0x3A) , + E_REG_P11_ISRC1_PB24_RW = SPA(E_SNONE , E_PAGE_11, 0x3B) , + E_REG_P11_ISRC1_PB25_RW = SPA(E_SNONE , E_PAGE_11, 0x3C), + E_REG_P11_ISRC1_PB26_RW = SPA(E_SNONE , E_PAGE_11, 0x3D), + E_REG_P11_ISRC1_PB27_RW = SPA(E_SNONE , E_PAGE_11, 0x3E), + E_REG_P11_ISRC2_HB0_RW = SPA(E_SNONE , E_PAGE_11, 0x40), + E_REG_P11_ISRC2_HB1_RW = SPA(E_SNONE , E_PAGE_11, 0x41), + E_REG_P11_ISRC2_HB2_RW = SPA(E_SNONE , E_PAGE_11, 0x42), + E_REG_P11_ISRC2_PB0_RW = SPA(E_SNONE , E_PAGE_11, 0x43), + E_REG_P11_ISRC2_PB1_RW = SPA(E_SNONE , E_PAGE_11, 0x44), + E_REG_P11_ISRC2_PB2_RW = SPA(E_SNONE , E_PAGE_11, 0x45), + E_REG_P11_ISRC2_PB3_RW = SPA(E_SNONE , E_PAGE_11, 0x46), + E_REG_P11_ISRC2_PB4_RW = SPA(E_SNONE , E_PAGE_11, 0x47), + E_REG_P11_ISRC2_PB5_RW = SPA(E_SNONE , E_PAGE_11, 0x48), + E_REG_P11_ISRC2_PB6_RW = SPA(E_SNONE , E_PAGE_11, 0x49), + E_REG_P11_ISRC2_PB7_RW = SPA(E_SNONE , E_PAGE_11, 0x4A), + E_REG_P11_ISRC2_PB8_RW = SPA(E_SNONE , E_PAGE_11, 0x4B), + E_REG_P11_ISRC2_PB9_RW = SPA(E_SNONE , E_PAGE_11, 0x4C), + E_REG_P11_ISRC2_PB10_RW = SPA(E_SNONE , E_PAGE_11, 0x4D), + E_REG_P11_ISRC2_PB11_RW = SPA(E_SNONE , E_PAGE_11, 0x4E), + E_REG_P11_ISRC2_PB12_RW = SPA(E_SNONE , E_PAGE_11, 0x4F), + E_REG_P11_ISRC2_PB13_RW = SPA(E_SNONE , E_PAGE_11, 0x50), + E_REG_P11_ISRC2_PB14_RW = SPA(E_SNONE , E_PAGE_11, 0x51), + E_REG_P11_ISRC2_PB15_RW = SPA(E_SNONE , E_PAGE_11, 0x52), + E_REG_P11_ISRC2_PB16_RW = SPA(E_SNONE , E_PAGE_11, 0x53), + E_REG_P11_ISRC2_PB17_RW = SPA(E_SNONE , E_PAGE_11, 0x54), + E_REG_P11_ISRC2_PB18_RW = SPA(E_SNONE , E_PAGE_11, 0x55), + E_REG_P11_ISRC2_PB19_RW = SPA(E_SNONE , E_PAGE_11, 0x56), + E_REG_P11_ISRC2_PB20_RW = SPA(E_SNONE , E_PAGE_11, 0x57), + E_REG_P11_ISRC2_PB21_RW = SPA(E_SNONE , E_PAGE_11, 0x58), + E_REG_P11_ISRC2_PB22_RW = SPA(E_SNONE , E_PAGE_11, 0x59), + E_REG_P11_ISRC2_PB23_RW = SPA(E_SNONE , E_PAGE_11, 0x5A), + E_REG_P11_ISRC2_PB24_RW = SPA(E_SNONE , E_PAGE_11, 0x5B), + E_REG_P11_ISRC2_PB25_RW = SPA(E_SNONE , E_PAGE_11, 0x5C), + E_REG_P11_ISRC2_PB26_RW = SPA(E_SNONE , E_PAGE_11, 0x5D), + E_REG_P11_ISRC2_PB27_RW = SPA(E_SNONE , E_PAGE_11, 0x5E), + E_REG_P11_ACP_HB0_RW = SPA(E_SNONE , E_PAGE_11, 0x60), + E_REG_P11_ACP_HB1_RW = SPA(E_SNONE , E_PAGE_11, 0x61), + E_REG_P11_ACP_HB2_RW = SPA(E_SNONE , E_PAGE_11, 0x62), + E_REG_P11_ACP_PB0_RW = SPA(E_SNONE , E_PAGE_11, 0x63), + E_REG_P11_ACP_PB1_RW = SPA(E_SNONE , E_PAGE_11, 0x64), + E_REG_P11_ACP_PB2_RW = SPA(E_SNONE , E_PAGE_11, 0x65), + E_REG_P11_ACP_PB3_RW = SPA(E_SNONE , E_PAGE_11, 0x66), + E_REG_P11_ACP_PB4_RW = SPA(E_SNONE , E_PAGE_11, 0x67), + E_REG_P11_ACP_PB5_RW = SPA(E_SNONE , E_PAGE_11, 0x68), + E_REG_P11_ACP_PB6_RW = SPA(E_SNONE , E_PAGE_11, 0x69), + E_REG_P11_ACP_PB7_RW = SPA(E_SNONE , E_PAGE_11, 0x6A), + E_REG_P11_ACP_PB8_RW = SPA(E_SNONE , E_PAGE_11, 0x6B), + E_REG_P11_ACP_PB9_RW = SPA(E_SNONE , E_PAGE_11, 0x6C), + E_REG_P11_ACP_PB10_RW = SPA(E_SNONE , E_PAGE_11, 0x6D), + E_REG_P11_ACP_PB11_RW = SPA(E_SNONE , E_PAGE_11, 0x6E), + E_REG_P11_ACP_PB12_RW = SPA(E_SNONE , E_PAGE_11, 0x6F), + E_REG_P11_ACP_PB13_RW = SPA(E_SNONE , E_PAGE_11, 0x70), + E_REG_P11_ACP_PB14_RW = SPA(E_SNONE , E_PAGE_11, 0x71), + E_REG_P11_ACP_PB15_RW = SPA(E_SNONE , E_PAGE_11, 0x72), + E_REG_P11_ACP_PB16_RW = SPA(E_SNONE , E_PAGE_11, 0x73), + E_REG_P11_ACP_PB17_RW = SPA(E_SNONE , E_PAGE_11, 0x74), + E_REG_P11_ACP_PB18_RW = SPA(E_SNONE , E_PAGE_11, 0x75), + E_REG_P11_ACP_PB19_RW = SPA(E_SNONE , E_PAGE_11, 0x76), + E_REG_P11_ACP_PB20_RW = SPA(E_SNONE , E_PAGE_11, 0x77), + E_REG_P11_ACP_PB21_RW = SPA(E_SNONE , E_PAGE_11, 0x78), + E_REG_P11_ACP_PB22_RW = SPA(E_SNONE , E_PAGE_11, 0x79), + E_REG_P11_ACP_PB23_RW = SPA(E_SNONE , E_PAGE_11, 0x7A), + E_REG_P11_ACP_PB24_RW = SPA(E_SNONE , E_PAGE_11, 0x7B), + E_REG_P11_ACP_PB25_RW = SPA(E_SNONE , E_PAGE_11, 0x7C), + E_REG_P11_ACP_PB26_RW = SPA(E_SNONE , E_PAGE_11, 0x7D), + E_REG_P11_ACP_PB27_RW = SPA(E_SNONE , E_PAGE_11, 0x7E), + E_REG_P13_GMD_0_HB0_RW = SPA(E_SNONE , E_PAGE_13, 0x00), + E_REG_P13_GMD_0_HB1_RW = SPA(E_SNONE , E_PAGE_13, 0x01), + E_REG_P13_GMD_0_HB2_RW = SPA(E_SNONE , E_PAGE_13, 0x02), + E_REG_P13_GMD_0_PB0_RW = SPA(E_SNONE , E_PAGE_13, 0x03), + E_REG_P13_GMD_0_PB1_RW = SPA(E_SNONE , E_PAGE_13, 0x04), + E_REG_P13_GMD_0_PB2_RW = SPA(E_SNONE , E_PAGE_13, 0x05), + E_REG_P13_GMD_0_PB3_RW = SPA(E_SNONE , E_PAGE_13, 0x06), + E_REG_P13_GMD_0_PB4_RW = SPA(E_SNONE , E_PAGE_13, 0x07), + E_REG_P13_GMD_0_PB5_RW = SPA(E_SNONE , E_PAGE_13, 0x08), + E_REG_P13_GMD_0_PB6_RW = SPA(E_SNONE , E_PAGE_13, 0x09), + E_REG_P13_GMD_0_PB7_RW = SPA(E_SNONE , E_PAGE_13, 0x0A), + E_REG_P13_GMD_0_PB8_RW = SPA(E_SNONE , E_PAGE_13, 0x0B), + E_REG_P13_GMD_0_PB9_RW = SPA(E_SNONE , E_PAGE_13, 0x0C), + E_REG_P13_GMD_0_PB10_RW = SPA(E_SNONE , E_PAGE_13, 0x0D), + E_REG_P13_GMD_0_PB11_RW = SPA(E_SNONE , E_PAGE_13, 0x0E), + E_REG_P13_GMD_0_PB12_RW = SPA(E_SNONE , E_PAGE_13, 0x0F), + E_REG_P13_GMD_0_PB13_RW = SPA(E_SNONE , E_PAGE_13, 0x10), + E_REG_P13_GMD_0_PB14_RW = SPA(E_SNONE , E_PAGE_13, 0x11), + E_REG_P13_GMD_0_PB15_RW = SPA(E_SNONE , E_PAGE_13, 0x12), + E_REG_P13_GMD_0_PB16_RW = SPA(E_SNONE , E_PAGE_13, 0x13), + E_REG_P13_GMD_0_PB17_RW = SPA(E_SNONE , E_PAGE_13, 0x14), + E_REG_P13_GMD_0_PB18_RW = SPA(E_SNONE , E_PAGE_13, 0x15), + E_REG_P13_GMD_0_PB19_RW = SPA(E_SNONE , E_PAGE_13, 0x16), + E_REG_P13_GMD_0_PB20_RW = SPA(E_SNONE , E_PAGE_13, 0x17), + E_REG_P13_GMD_0_PB21_RW = SPA(E_SNONE , E_PAGE_13, 0x18), + E_REG_P13_GMD_0_PB22_RW = SPA(E_SNONE , E_PAGE_13, 0x19), + E_REG_P13_GMD_0_PB23_RW = SPA(E_SNONE , E_PAGE_13, 0x1A), + E_REG_P13_GMD_0_PB24_RW = SPA(E_SNONE , E_PAGE_13, 0x1B), + E_REG_P13_GMD_0_PB25_RW = SPA(E_SNONE , E_PAGE_13, 0x1C), + E_REG_P13_GMD_0_PB26_RW = SPA(E_SNONE , E_PAGE_13, 0x1D), + E_REG_P13_GMD_0_PB27_RW = SPA(E_SNONE , E_PAGE_13, 0x1E), + E_REG_P13_GMD_CONTROL_RW = SPA(E_SNONE , E_PAGE_13, 0x1F), + E_REG_P13_GMD_1_HB0_RW = SPA(E_SNONE , E_PAGE_13, 0x20), + E_REG_P13_GMD_1_HB1_RW = SPA(E_SNONE , E_PAGE_13, 0x21), + E_REG_P13_GMD_1_HB2_RW = SPA(E_SNONE , E_PAGE_13, 0x22), + E_REG_P13_GMD_1_PB0_RW = SPA(E_SNONE , E_PAGE_13, 0x23), + E_REG_P13_GMD_1_PB1_RW = SPA(E_SNONE , E_PAGE_13, 0x24), + E_REG_P13_GMD_1_PB2_RW = SPA(E_SNONE , E_PAGE_13, 0x25), + E_REG_P13_GMD_1_PB3_RW = SPA(E_SNONE , E_PAGE_13, 0x26), + E_REG_P13_GMD_1_PB4_RW = SPA(E_SNONE , E_PAGE_13, 0x27), + E_REG_P13_GMD_1_PB5_RW = SPA(E_SNONE , E_PAGE_13, 0x28), + E_REG_P13_GMD_1_PB6_RW = SPA(E_SNONE , E_PAGE_13, 0x29), + E_REG_P13_GMD_1_PB7_RW = SPA(E_SNONE , E_PAGE_13, 0x2A), + E_REG_P13_GMD_1_PB8_RW = SPA(E_SNONE , E_PAGE_13, 0x2B), + E_REG_P13_GMD_1_PB9_RW = SPA(E_SNONE , E_PAGE_13, 0x2C), + E_REG_P13_GMD_1_PB10_RW = SPA(E_SNONE , E_PAGE_13, 0x2D), + E_REG_P13_GMD_1_PB11_RW = SPA(E_SNONE , E_PAGE_13, 0x2E), + E_REG_P13_GMD_1_PB12_RW = SPA(E_SNONE , E_PAGE_13, 0x2F), + E_REG_P13_GMD_1_PB13_RW = SPA(E_SNONE , E_PAGE_13, 0x30), + E_REG_P13_GMD_1_PB14_RW = SPA(E_SNONE , E_PAGE_13, 0x31), + E_REG_P13_GMD_1_PB15_RW = SPA(E_SNONE , E_PAGE_13, 0x32), + E_REG_P13_GMD_1_PB16_RW = SPA(E_SNONE , E_PAGE_13, 0x33), + E_REG_P13_GMD_1_PB17_RW = SPA(E_SNONE , E_PAGE_13, 0x34), + E_REG_P13_GMD_1_PB18_RW = SPA(E_SNONE , E_PAGE_13, 0x35), + E_REG_P13_GMD_1_PB19_RW = SPA(E_SNONE , E_PAGE_13, 0x36), + E_REG_P13_GMD_1_PB20_RW = SPA(E_SNONE , E_PAGE_13, 0x37), + E_REG_P13_GMD_1_PB21_RW = SPA(E_SNONE , E_PAGE_13, 0x38), + E_REG_P13_GMD_1_PB22_RW = SPA(E_SNONE , E_PAGE_13, 0x39), + E_REG_P13_GMD_1_PB23_RW = SPA(E_SNONE , E_PAGE_13, 0x3A), + E_REG_P13_GMD_1_PB24_RW = SPA(E_SNONE , E_PAGE_13, 0x3B), + E_REG_P13_GMD_1_PB25_RW = SPA(E_SNONE , E_PAGE_13, 0x3C), + E_REG_P13_GMD_1_PB26_RW = SPA(E_SNONE , E_PAGE_13, 0x3D), + E_REG_P13_GMD_1_PB27_RW = SPA(E_SNONE , E_PAGE_13, 0x3E) +}; +#undef SPR + +/** + * Register bitfield masks, with a macro to allow binary initializers. + * Enum names are derived directly from TDA998x register and bitfield names. + */ +#define BINARY(d7,d6,d5,d4,d3,d2,d1,d0) \ + (((d7)<<7)|((d6)<<6)|((d5)<<5)|((d4)<<4)|((d3)<<3)|((d2)<<2)|((d1)<<1)|(d0)) + +enum _eMaskReg +{ + E_MASKREG_NONE = BINARY(0,0,0,0, 0,0,0,0), + E_MASKREG_ALL = BINARY(1,1,1,1, 1,1,1,1), + + /* N4 features flags read from version register: + * not_h = no HDCP support + * not_s = no scaler support + * + * N5 = a flag that is not a register bit, but is derived by the + * driver from the new N5 registers DWIN_RE_DE and DWIN_FE_DE, + * because the N5 device still uses the N4 version register value. + * This bit position would clash with version register, so is not + * present in the driver's copy (uDeviceVersion) of the version + * register, but only in the driver's features byte (uDeviceFeatures). + */ + + /* CEC Masks*/ + + E_MASKREG_CEC_INTERRUPTSTATUS_hdmi_int = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_CEC_INTERRUPTSTATUS_cec_int = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_CEC_RXSHPDINTENA_ena_hpd_int = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_CEC_RXSHPDINTENA_ena_rxs_int = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_CEC_RXSHPDINT_hpd_int = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_CEC_RXSHPDINT_rxs_int = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_CEC_RXSHPDLEV_hpd_level = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_CEC_RXSHPDLEV_rxs_level = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_CEC_ENAMODS_dis_fro = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_CEC_ENAMODS_dis_cclk = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_CEC_ENAMODS_ena_rxs = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_CEC_ENAMODS_ena_hdmi = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_CEC_ENAMODS_ena_cec = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_CEC_FRO_IM_CLK_CTRL_ghost_dis = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_CEC_FRO_IM_CLK_CTRL_ena_otp = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_CEC_FRO_IM_CLK_CTRL_imclk_sel = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_CEC_FRO_IM_CLK_CTRL_fro_div = BINARY(0,0,0,0, 0,0,0,1), + + /* HDMI Masks*/ + E_MASKREG_P00_VERSION_not_h = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_VERSION_not_s = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_FEATURE_N5 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_MAIN_CNTRL0_scaler = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_MAIN_CNTRL0_cehs = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_MAIN_CNTRL0_cecs = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_MAIN_CNTRL0_dehs = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_MAIN_CNTRL0_decs = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_MAIN_CNTRL0_sr = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_SR_REG_sr_i2c_ms = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_SR_REG_sr_audio = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_DDC_DISABLE_ddc_dis = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_CCLK_ON_cclk_ddc_on = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_I2C_MASTER_app_strt_lat = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_I2C_MASTER_dis_filt = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_I2C_MASTER_dis_mm = BINARY(0,0,0,0, 0,0,0,1), + +#ifdef TMFL_TDA19989 + E_MASKREG_FEAT_POWER_DOWN_spdif = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_FEAT_POWER_DOWN_otp = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_FEAT_POWER_DOWN_csc = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_FEAT_POWER_DOWN_prefilt = BINARY(0,0,0,0, 0,0,0,1), + E_MASKREG_FEAT_POWER_DOWN_all = BINARY(0,0,0,0, 1,1,1,1), +#endif + + E_MASKREG_P00_INT_FLAGS_0_r0 = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_0_pj = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_0_sha_1 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_0_bstatus = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_0_bcaps = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_INT_FLAGS_0_t0 = BINARY(0,0,0,0, 0,1,0,0), + /*E_MASKREG_P00_INT_FLAGS_0_hpd = BINARY(0,0,0,0, 0,0,1,0),*/ + E_MASKREG_P00_INT_FLAGS_0_encrypt = BINARY(0,0,0,0, 0,0,0,1), + + /*E_MASKREG_P00_INT_FLAGS_1_hpd_in = BINARY(1,0,0,0, 0,0,0,0),*/ + E_MASKREG_P00_INT_FLAGS_1_sw_int = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_1_sc_deil = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_1_sc_vid = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_INT_FLAGS_1_sc_out = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_INT_FLAGS_1_sc_in = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_INT_FLAGS_1_otp = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_INT_FLAGS_1_vs_rpt = BINARY(0,0,0,0, 0,0,0,1), + /*E_MASKREG_P00_INT_FLAGS_2_rx_sense = BINARY(0,0,0,0, 0,0,0,1),*/ + E_MASKREG_P00_INT_FLAGS_2_edid_blk_rd = BINARY(0,0,0,0, 0,0,1,0), + + /*E_MASKREG_P00_INT_FLAGS_3_rxs_fil = BINARY(0,0,0,0, 0,0,0,1),*/ + + E_MASKREG_P00_SW_INT_sw_int = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_ENA_ACLK_ena_aclk = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_GND_ACLK_gnd_aclk = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_ENA_VP_0_ena_vp7 = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_0_ena_vp6 = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_0_ena_vp5 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_0_ena_vp4 = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_ENA_VP_0_ena_vp3 = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_ENA_VP_0_ena_vp2 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_ENA_VP_0_ena_vp1 = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_ENA_VP_0_ena_vp0 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_ENA_VP_1_ena_vp15 = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_1_ena_vp14 = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_1_ena_vp13 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_1_ena_vp12 = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_ENA_VP_1_ena_vp11 = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_ENA_VP_1_ena_vp10 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_ENA_VP_1_ena_vp9 = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_ENA_VP_1_ena_vp8 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_ENA_VP_2_ena_vp23 = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_2_ena_vp22 = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_2_ena_vp21 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_ENA_VP_2_ena_vp20 = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_ENA_VP_2_ena_vp19 = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_ENA_VP_2_ena_vp18 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_ENA_VP_2_ena_vp17 = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_ENA_VP_2_ena_vp16 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_ENA_AP_ena_ap7 = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_AP_ena_ap6 = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_ENA_AP_ena_ap5 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_ENA_AP_ena_ap4 = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_ENA_AP_ena_ap3 = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_ENA_AP_ena_ap2 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_ENA_AP_ena_ap1 = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_ENA_AP_ena_ap0 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_VIP_CNTRL_0_mirr_a = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_0_swap_a = BINARY(0,1,1,1, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_0_mirr_b = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_VIP_CNTRL_0_swap_b = BINARY(0,0,0,0, 0,1,1,1), + + E_MASKREG_P00_VIP_CNTRL_1_mirr_c = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_1_swap_c = BINARY(0,1,1,1, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_1_mirr_d = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_VIP_CNTRL_1_swap_d = BINARY(0,0,0,0, 0,1,1,1), + + E_MASKREG_P00_VIP_CNTRL_2_mirr_e = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_2_swap_e = BINARY(0,1,1,1, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_2_mirr_f = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_VIP_CNTRL_2_swap_f = BINARY(0,0,0,0, 0,1,1,1), + +#ifdef TMFL_TDA19989 + E_MASKREG_P00_MUX_VP_VIP_OUT_red = BINARY(0,0,1,1, 0,0,0,0), + E_MASKREG_P00_MUX_VP_VIP_OUT_green = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P00_MUX_VP_VIP_OUT_blue = BINARY(0,0,0,0, 0,0,1,1), +#endif + + E_MASKREG_P00_VIP_CNTRL_3_edge = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_3_de_int = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_3_sp_sync = BINARY(0,0,1,1, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_3_emb = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_VIP_CNTRL_3_v_tgl = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_VIP_CNTRL_3_h_tgl = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_VIP_CNTRL_3_x_tgl = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_VIP_CNTRL_4_tst_pat = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_4_tst_656 = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_4_656_alt = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_4_ccir656 = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_VIP_CNTRL_4_blankit = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P00_VIP_CNTRL_4_blc = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P00_VIP_CNTRL_5_sp_cnt = BINARY(0,0,0,0, 0,1,1,0), + E_MASKREG_P00_VIP_CNTRL_5_ckcase = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_MAT_CONTRL_mat_bp = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_MAT_CONTRL_mat_sc = BINARY(0,0,0,0, 0,0,1,1), + +#ifdef TMFL_TDA19989 + E_MASKREG_P00_VIDFORMAT_3d = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_VIDFORMAT_3d_neg_vs = BINARY(0,1,0,0, 0,0,0,0), +#endif + E_MASKREG_P00_VIDFORMAT_vidformat = BINARY(0,0,0,1, 1,1,1,1), + + E_MASKREG_P00_TBG_CNTRL_0_sync_once = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_TBG_CNTRL_0_sync_mthd = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_TBG_CNTRL_0_frame_dis = BINARY(0,0,1,0, 0,0,0,0), + + E_MASKREG_P00_TBG_CNTRL_1_dwin_dis = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext = BINARY(0,0,1,1, 1,0,0,0), + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext_vs = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext_hs = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P00_TBG_CNTRL_1_vhx_ext_de = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_TBG_CNTRL_1_vh_tgl = BINARY(0,0,0,0, 0,1,1,1), + E_MASKREG_P00_TBG_CNTRL_1_vh_tgl_2 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_TBG_CNTRL_1_vh_tgl_1 = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_TBG_CNTRL_1_vh_tgl_0 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_I2C_TIMER_RI = BINARY(0,0,0,0, 1,1,1,1), + E_MASKREG_P00_I2C_TIMER_PJ = BINARY(1,1,1,1, 0,0,0,0), + + E_MASKREG_P00_HVF_CNTRL_0_sm = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P00_HVF_CNTRL_0_rwb = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_HVF_CNTRL_0_prefil = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P00_HVF_CNTRL_0_intpol = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P00_HVF_CNTRL_1_semi_planar = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_HVF_CNTRL_1_pad = BINARY(0,0,1,1, 0,0,0,0), + E_MASKREG_P00_HVF_CNTRL_1_vqr = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P00_HVF_CNTRL_1_yuvblk = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_HVF_CNTRL_1_for = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_TIMER_H_wd_clksel = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_TIMER_H_tim_h = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P00_DEBUG_PROBE_sel = BINARY(0,0,1,1, 0,0,0,0), + E_MASKREG_P00_DEBUG_PROBE_bypass = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P00_DEBUG_PROBE_vid_de = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_DEBUG_PROBE_di_de = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P00_DEBUG_PROBE_woo_en = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P00_I2S_FORMAT_i2s_format = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P00_I2S_FORMAT_i2s_data_size = BINARY(0,0,0,0, 1,1,0,0), + + E_MASKREG_P00_AIP_CLKSEL_dst_rate = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P00_AIP_CLKSEL_sel_aip_SHIFT = 3, + E_MASKREG_P00_AIP_CLKSEL_sel_aip = BINARY(0,0,1,1, 1,0,0,0), + E_MASKREG_P00_AIP_CLKSEL_sel_pol_clk = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P00_AIP_CLKSEL_sel_fs = BINARY(0,0,0,0, 0,0,1,1), + E_MASKREG_P01_SC_VIDFORMAT_lut_sel = BINARY(1,1,0,0, 0,0,0,0), + E_MASKREG_P01_SC_VIDFORMAT_vid_format_o = BINARY(0,0,1,1, 1,0,0,0), + E_MASKREG_P01_SC_VIDFORMAT_vid_format_i = BINARY(0,0,0,0, 0,1,1,1), + + E_MASKREG_P01_SC_CNTRL_phases_h = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P01_SC_CNTRL_il_out_on = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P01_SC_CNTRL_phases_v = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P01_SC_CNTRL_vs_on = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P01_SC_CNTRL_deil_on = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P01_VIDFORMAT_vidformat = BINARY(0,0,0,0, 0,1,1,1), + + E_MASKREG_P01_TBG_CNTRL_0_sync_once = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P01_TBG_CNTRL_0_sync_mthd = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P01_TBG_CNTRL_0_frame_dis = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P01_TBG_CNTRL_0_top_ext = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P01_TBG_CNTRL_0_de_ext = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P01_TBG_CNTRL_0_top_sel = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P01_TBG_CNTRL_0_top_tgl = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_PLL_SERIAL_1_srl_man_iz = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P02_PLL_SERIAL_1_srl_iz = BINARY(0,0,0,0, 0,1,1,0), + E_MASKREG_P02_PLL_SERIAL_1_srl_fdn = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_PLL_SERIAL_2_srl_pr = BINARY(1,1,1,1, 0,0,0,0), + E_MASKREG_P02_PLL_SERIAL_2_srl_nosc = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P02_PLL_SERIAL_3_srl_pxin_sel = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P02_PLL_SERIAL_3_srl_de = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P02_PLL_SERIAL_3_srl_ccir = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_SERIALIZER_srl_phase3 = BINARY(1,1,1,1, 0,0,0,0), + E_MASKREG_P02_SERIALIZER_srl_phase2 = BINARY(0,0,0,0, 1,1,1,1), + + E_MASKREG_P02_BUFFER_OUT_srl_force = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P02_BUFFER_OUT_srl_clk = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P02_PLL_SCG1_scg_fdn = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_PLL_SCG2_bypass_scg = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P02_PLL_SCG2_selpllclkin = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P02_PLL_SCG2_scg_nosc = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P02_VAI_PLL_pllde_hvp = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P02_VAI_PLL_pllscg_hvp = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P02_VAI_PLL_pllsrl_hvp = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P02_VAI_PLL_pllscg_lock = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P02_VAI_PLL_pllsrl_lock = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_AUDIO_DIV_audio_div = BINARY(0,0,0,0, 0,1,1,1), + + E_MASKREG_P02_TEST1_srldat = BINARY(1,1,0,0, 0,0,0,0), + E_MASKREG_P02_TEST1_tst_nosc = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P02_TEST1_tst_enahvp = BINARY(0,0,0,0, 0,0,0,1), + + //E_MASKREG_P02_TEST2_pwd1v8 = BINARY(0,0,0,0, 0,0,1,0), + //E_MASKREG_P02_TEST2_divtestoe = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_SEL_CLK_ena_sc_clk = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P02_SEL_CLK_sel_vrf_clk = BINARY(0,0,0,0, 0,1,1,0), + E_MASKREG_P02_SEL_CLK_sel_clk1 = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P02_BUFF_OUT2_force_dat2 = BINARY(0,0,1,1, 0,0,0,0), + E_MASKREG_P02_BUFF_OUT2_force_dat1 = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P02_BUFF_OUT2_force_dat0 = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P09_EDID_CTRL_edid_rd = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P11_AIP_CNTRL_0_rst_cts = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P11_AIP_CNTRL_0_acr_man = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P11_AIP_CNTRL_0_layout = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P11_AIP_CNTRL_0_swap = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P11_AIP_CNTRL_0_rst_fifo = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P11_CA_I2S_hbr_chstat_4 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P11_CA_I2S_ca_i2s = BINARY(0,0,0,1, 1,1,1,1), + + E_MASKREG_P11_GC_AVMUTE_set_mute = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P11_GC_AVMUTE_clr_mute = BINARY(0,0,0,0, 0,0,0,1), + E_MASKREG_P11_GC_AVMUTE_setclr_mute = BINARY(0,0,0,0, 0,0,1,1), + + E_MASKREG_P11_CTS_N_m_sel = BINARY(0,0,1,1, 0,0,0,0), + E_MASKREG_P11_CTS_N_k_sel = BINARY(0,0,0,0, 0,1,1,1), + + E_MASKREG_P11_ENC_CNTRL_ctl_code = BINARY(0,0,0,0, 1,1,0,0), + E_MASKREG_P11_ENC_CNTRL_rst_sel = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P11_ENC_CNTRL_rst_enc = BINARY(0,0,0,0, 0,0,0,1), + E_MASKREG_P11_DIP_FLAGS_force_null = BINARY(1,0,0,0, 0,0,0,0), + E_MASKREG_P11_DIP_FLAGS_null = BINARY(0,1,0,0, 0,0,0,0), + E_MASKREG_P11_DIP_FLAGS_acp = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P11_DIP_FLAGS_isrc2 = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P11_DIP_FLAGS_isrc1 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P11_DIP_FLAGS_gc = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P11_DIP_FLAGS_acr = BINARY(0,0,0,0, 0,0,0,1), + + E_MASKREG_P11_DIP_IF_FLAGS_if5 = BINARY(0,0,1,0, 0,0,0,0), + E_MASKREG_P11_DIP_IF_FLAGS_if4 = BINARY(0,0,0,1, 0,0,0,0), + E_MASKREG_P11_DIP_IF_FLAGS_if3 = BINARY(0,0,0,0, 1,0,0,0), + E_MASKREG_P11_DIP_IF_FLAGS_if2 = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P11_DIP_IF_FLAGS_if1 = BINARY(0,0,0,0, 0,0,1,0), + + E_MASKREG_P13_GMD_CONTROL_buf_sel = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P13_GMD_CONTROL_enable = BINARY(0,0,0,0, 0,0,0,1) +}; +#undef BINARY + +/** + * 3 enum for the video formats : + * - 1 used in the E_REG_P00_VIDFORMAT_W register + * - 1 for new format that are not prefetch + * - 1 for PC + */ +#define REGVFMT_INVALID 0xFF + +enum _eRegVfmt { + E_REGVFMT_640x480p_60Hz = 0, /* 1 */ + E_REGVFMT_720x480p_60Hz , /* 2/3 */ + E_REGVFMT_1280x720p_60Hz , /* 4 */ + E_REGVFMT_1920x1080i_60Hz , /* 5 */ + E_REGVFMT_720x480i_60Hz , /* 6/4 */ + E_REGVFMT_720x240p_60Hz , /*NT 8/9 */ + E_REGVFMT_1920x1080p_60Hz , /* 16 */ + E_REGVFMT_720x576p_50Hz , /* 17/18 */ + E_REGVFMT_1280x720p_50Hz , /* 19 */ + E_REGVFMT_1920x1080i_50Hz , /* 20 */ + E_REGVFMT_720x576i_50Hz , /* 21/22 */ + E_REGVFMT_720x288p_50Hz , /* 23/24 */ + E_REGVFMT_1920x1080p_50Hz , /* 31 */ +#ifdef TMFL_RGB_DDR_12BITS + E_REGVFMT_1920x1080p_24Hz , /* 32 */ + E_REGVFMT_1440x576p_50Hz , /* 29/30 */ + E_REGVFMT_1440x480p_60Hz , /* 14/15 */ + E_REGVFMT_2880x480p_60Hz , /* 35/36 */ + E_REGVFMT_2880x576p_50Hz , /* 37/38 */ + E_REGVFMT_2880x480i_60Hz , /* 10/11*/ + E_REGVFMT_2880x480i_60Hz_PR2, /* 10/11*/ + E_REGVFMT_2880x480i_60Hz_PR4, /* 10/11*/ + E_REGVFMT_2880x576i_50Hz , /* 25/26 */ + E_REGVFMT_2880x576i_50Hz_PR2, /* 25/26 */ + E_REGVFMT_720x480p_60Hz_FP , /* 2/3 FP */ + E_REGVFMT_1280x720p_60Hz_FP , /* 4 FP */ + E_REGVFMT_720x576p_50Hz_FP , /* 17/18 FP */ + E_REGVFMT_1280x720p_50Hz_FP , /* 19 FP */ + E_REGVFMT_1920x1080p_24Hz_FP, /* 32 FP */ + E_REGVFMT_1920x1080p_25Hz_FP, /* 33 FP */ + E_REGVFMT_1920x1080p_30Hz_FP, /* 34 FP */ + E_REGVFMT_1920x1080i_60Hz_FP, /* 5 FP */ + E_REGVFMT_1920x1080i_50Hz_FP, /* 20 FP */ +#endif + E_REGVFMT_MAX_PREFETCH , + E_REGVFMT_NUM_PREFETCH = E_REGVFMT_MAX_PREFETCH +}; + +enum _eRegVfmtExtra { +#ifndef TMFL_RGB_DDR_12BITS + E_REGVFMT_1920x1080p_24Hz = E_REGVFMT_MAX_PREFETCH, /* 32 */ + E_REGVFMT_1920x1080p_25Hz , /* 33 */ +#else + E_REGVFMT_1920x1080p_25Hz = E_REGVFMT_MAX_PREFETCH, +#endif + E_REGVFMT_1920x1080p_30Hz, /* 34 */ + E_REGVFMT_1280x720p_24Hz, /* 60 */ + E_REGVFMT_1280x720p_25Hz, /* 61 */ + E_REGVFMT_1280x720p_30Hz , /* 62 */ +#ifndef TMFL_RGB_DDR_12BITS + E_REGVFMT_1280x720p_60Hz_FP, + E_REGVFMT_1920x1080i_60Hz_FP, + E_REGVFMT_1280x720p_50Hz_FP, + E_REGVFMT_1920x1080i_50Hz_FP, + E_REGVFMT_1920x1080p_24Hz_FP, + E_REGVFMT_1920x1080p_25Hz_FP, + E_REGVFMT_1920x1080p_30Hz_FP, +#endif + E_REGVFMT_1280x720p_24Hz_FP, + E_REGVFMT_1280x720p_25Hz_FP, + E_REGVFMT_1280x720p_30Hz_FP, + E_REGVFMT_MAX_EXTRA , + E_REGVFMT_NUM_EXTRA = E_REGVFMT_MAX_EXTRA - E_REGVFMT_MAX_PREFETCH +}; + +#ifdef FORMAT_PC +enum _eRegVfmtPC { + E_REGVFMT_640x480p_72Hz = E_REGVFMT_MAX_EXTRA, + E_REGVFMT_640x480p_75Hz , + E_REGVFMT_640x480p_85Hz , + E_REGVFMT_800x600p_60Hz , + E_REGVFMT_800x600p_72Hz , + E_REGVFMT_800x600p_75Hz , + E_REGVFMT_800x600p_85Hz , + E_REGVFMT_1024x768p_60Hz , + E_REGVFMT_1024x768p_70Hz , + E_REGVFMT_1024x768p_75Hz , + E_REGVFMT_1280x768p_60Hz , + E_REGVFMT_1280x1024p_60Hz , + E_REGVFMT_1360x768p_60Hz , + E_REGVFMT_1400x1050p_60Hz , + E_REGVFMT_1600x1200p_60Hz , + E_REGVFMT_1280x1024p_85Hz , + E_REGVFMT_MAX_PC , + E_REGVFMT_NUM_PC = E_REGVFMT_MAX_PC - E_REGVFMT_MAX_EXTRA +}; +#define E_REGVFMT_MAX E_REGVFMT_MAX_PC +#else +#define E_REGVFMT_MAX E_REGVFMT_MAX_EXTRA +#endif /*FORMAT_PC*/ + +#define PREFETCH(fmt) ((fmt) < E_REGVFMT_MAX_PREFETCH) +#define EXTRA(fmt) (!PREFETCH(fmt)) +#define PCFORMAT(fmt) ((fmt) >= E_REGVFMT_MAX_EXTRA)/* PR1570 FIXED */ +#define BASE(fmt) (PREFETCH(fmt)?(fmt):(fmt)-E_REGVFMT_MAX_PREFETCH) + + +/** + * An enum for the video input formats used in the E_REG_P01_SC_VIDFORMAT_W + * register + */ +enum _eRegVfmtScIn +{ + E_REGVFMT_SCIN_480i_60Hz = 0, + E_REGVFMT_SCIN_576i_50Hz = 1, + E_REGVFMT_SCIN_480p_60Hz = 2, + E_REGVFMT_SCIN_576p_50Hz = 3, + E_REGVFMT_SCIN_720p_50Hz_60Hz = 4, + E_REGVFMT_SCIN_1080i_50Hz_60Hz = 5, + E_REGVFMT_SCIN_MAX = 5, + E_REGVFMT_SCIN_NUM = 6, + E_REGVFMT_SCIN_INVALID = 6 +}; + +/** + * An enum to list all supported pixel clock frequencies in kHz + */ +enum _ePixClk +{ + E_PIXCLK_25175 = 0, + E_PIXCLK_25200 = 1, + E_PIXCLK_27000 = 2, + E_PIXCLK_27027 = 3, + E_PIXCLK_54000 = 4, + E_PIXCLK_54054 = 5, + E_PIXCLK_59400 = 6, + E_PIXCLK_74175 = 7, + E_PIXCLK_74250 = 8, + E_PIXCLK_148350 = 9, + E_PIXCLK_148500 = 10, + E_PIXCLK_108000 = 11, + E_PIXCLK_108108 = 12, +#ifndef FORMAT_PC + E_PIXCLK_MAX = 12, + E_PIXCLK_INVALID = 13, + E_PIXCLK_NUM = 13 +#else /* FORMAT_PC */ + E_PIXCLK_31500 = 13, + E_PIXCLK_36000 = 14, + E_PIXCLK_40000 = 15, + E_PIXCLK_49500 = 16, + E_PIXCLK_50000 = 17, + E_PIXCLK_56250 = 18, + E_PIXCLK_65000 = 19, + E_PIXCLK_75000 = 20, + E_PIXCLK_78750 = 21, + E_PIXCLK_79500 = 22, + E_PIXCLK_85500 = 23, + E_PIXCLK_PC_108000 = 24, + E_PIXCLK_121750 = 25, + E_PIXCLK_162000 = 26, + E_PIXCLK_MAX = 26, + E_PIXCLK_INVALID = 27, + E_PIXCLK_NUM = 27 +#endif /* FORMAT_PC */ +}; + +/** + * An enum to list all device version codes supported by this driver. + * The values form a list, with non-zero version codes first in any order. + * The E_DEV_VERSION_END_LIST must be the last value in the list. + */ +enum _eDevVersion +{ + E_DEV_VERSION_N2 = 0x101, /**< TDA9989 n2 */ + E_DEV_VERSION_TDA19989 = 0x201, /**< TDA19989 */ + E_DEV_VERSION_TDA19989_N2 = 0x202, /**< TDA19989 N2 */ + E_DEV_VERSION_TDA19988 = 0x301, /**< TDA19988 */ + E_DEV_VERSION_LIST_END = 0x00, + E_DEV_VERSION_LIST_NUM = 5 /**< Number of items in list */ +}; + +/** + * An enum to list all CEA Data Block Tag Codes we may find in EDID. + */ +enum _eCeaBlockTags +{ + E_CEA_RESERVED_0 = 0x00, + E_CEA_AUDIO_BLOCK = 0x01, + E_CEA_VIDEO_BLOCK = 0x02, + E_CEA_VSDB = 0x03, + E_CEA_SPEAKER_ALLOC = 0x04, + E_CEA_VESA_DTC = 0x05, + E_CEA_RESERVED_6 = 0x06, + E_CEA_EXTENDED = 0x07 +}; + +/** + * An enum to list all CEA Data Block Extended Tag Codes we may find in EDID. + */ +enum _eCeaExtendedBlockTags +{ + EXT_CEA_MISC_VIDEO_FIELDS = 0x00, + EXT_CEA_VS_VIDEO_DB = 0x01, + EXT_CEA_COLORIMETRY_DB = 0x05, + EXT_CEA_MISC_AUDIO_FIELDS = 0x10, + EXT_CEA_VS_AUDIO_DB = 0x11 +}; + +/** A typedef for colourspace values */ +typedef enum +{ + HDMITX_CS_RGB_FULL = 0, /**< RGB Full (PC) */ + HDMITX_CS_RGB_LIMITED = 1, /**< RGB Limited (TV) */ + HDMITX_CS_YUV_ITU_BT601 = 2, /**< YUV ITUBT601 (SDTV) */ + HDMITX_CS_YUV_ITU_BT709 = 3, /**< YUV ITUBT709 (HDTV) */ + HDMITX_CS_NUM = 4 /**< Number Cspaces we support */ +} tmbslTDA9989Colourspace_t; + +/** Matrix register block size */ +#define MATRIX_PRESET_SIZE 31 + +/** Matrix register block size */ +#define MATRIX_PRESET_QTY 12 + +/** The enum that vectors us into the MatrixPreset table */ +enum _eMatrixPresetIndex +{ + E_MATRIX_RGBF_2_RGBL = 0, + E_MATRIX_RGBF_2_BT601 = 1, + E_MATRIX_RGBF_2_BT709 = 2, + E_MATRIX_RGBL_2_RGBF = 3, + E_MATRIX_RGBL_2_BT601 = 4, + E_MATRIX_RGBL_2_BT709 = 5, + E_MATRIX_BT601_2_RGBF = 6, + E_MATRIX_BT601_2_RGBL = 7, + E_MATRIX_BT601_2_BT709 = 8, + E_MATRIX_BT709_2_RGBF = 9, + E_MATRIX_BT709_2_RGBL = 10, + E_MATRIX_BT709_2_BT601 = 11 +}; + +/** EDID i2c address */ +#define DDC_EDID_ADDRESS 0xA0 + +/** EDID alternate i2c address */ +#define DDC_EDID_ADDRESS_ALT 0xA2 + +/** EDID Segment Pointer address */ +#define DDC_SGMT_PTR_ADDRESS 0x60 + +/** EDID DTD block descriptor size */ +#define EDID_DTD_BLK_SIZE 0x12 + +/** number of detailed timing descriptor stored in pDis */ +#define NUMBER_DTD_STORED 10 + +/** MUX_AP audio selection values */ +#define MUX_AP_SELECT_I2S 0xE4 +#define MUX_AP_SELECT_SPDIF 0x27 + +#define TDA19989_MUX_AP_SELECT_I2S 0x64 +#define TDA19989_MUX_AP_SELECT_SPDIF 0x24 + +/** VSWING default value */ +#define HDMI_TX_VSWING_VALUE 0x09 + + +/** + * \brief A structure type to form arrays that hold a series of registers and + * values + */ +typedef struct _tmHdmiTxRegVal_t +{ + UInt16 Reg; + UInt8 Val; +} tmHdmiTxRegVal_t; + +/** + * \brief A structure type to form arrays that hold a series of registers, + * bitfield masks and bitfield values + */ +typedef struct _tmHdmiTxRegMaskVal_t +{ + UInt16 Reg; + UInt8 Mask; + UInt8 Val; +} tmHdmiTxRegMaskVal_t; + +/** + * \brief A function pointer type to call a function and return a result + */ +typedef tmErrorCode_t (FUNC_PTR * ptmHdmiTxFunc_t) (tmUnitSelect_t txUnit); + +/** + * \brief The structure of a TM998x object, one per device unit + **************************************************************************** + ** Copy changes to kTestDisNames tab in "HDMI Driver - Register List.xls" ** + **************************************************************************** + */ + +typedef struct _tmHdmiTxobject_t +{ + /** Component State */ + tmbslTDA9989State_t state; + + /** Count of events ignored by setState() */ + UInt8 nIgnoredEvents; + + /** Device unit number */ + tmUnitSelect_t txUnit; + + /** Device I2C slave address */ + UInt8 uHwAddress; + + /** System function to write to the I2C driver */ + ptmbslHdmiTxSysFunc_t sysFuncWrite; + + /** System function to read from the I2C driver */ + ptmbslHdmiTxSysFunc_t sysFuncRead; + + /** System function to read EDID blocks via the I2C driver */ + ptmbslHdmiTxSysFuncEdid_t sysFuncEdidRead; + + /** System function to run a timer */ + ptmbslHdmiTxSysFuncTimer_t sysFuncTimer; + + /** Array of registered interrupt handler callback functions */ + ptmbslHdmiTxCallback_t funcIntCallbacks[HDMITX_CALLBACK_INT_NUM]; + + /** Flags to store disable or enable of interrupts */ + UInt16 InterruptsEnable; /* At moment used only for VS Interrupt */ + + /** Device version(s) supported by this component */ + UInt16 uSupportedVersions[E_DEV_VERSION_LIST_NUM]; + + /** Device version read from register, with features flags masked out */ + UInt16 uDeviceVersion; + + /** Device features flags read from version register */ + UInt8 uDeviceFeatures; + + /** The device's power state */ + tmbslHdmiTxPowerState_t ePowerState; + + /*=== E D I D ===*/ + + /** EDID Use alternative i2c address flag */ + Bool bEdidAlternateAddr; + + /** The sink type set by the user (may or may not match EdidSinkType) */ + tmbslHdmiTxSinkType_t sinkType; + + /** EDID Sink Type for receiver */ + tmbslHdmiTxSinkType_t EdidSinkType; + + /** EDID AI_Support from HDMI VSDB */ + Bool EdidSinkAi; + + /** EDID CEA flags from extension block */ + UInt8 EdidCeaFlags; + + /** EDID CEA flags from colorimetry block */ + UInt8 EdidCeaXVYCCFlags; + + /** EDID latency information */ + tmbslHdmiTxEdidLatency_t EdidLatency; + + /** EDID 3D data structure */ + tmbslHdmiTxEdidExtraVsdbData_t EdidExtraVsdbData; + + /** EDID Read Status */ + UInt8 EdidStatus; + + /** NB DTD stored in EdidDTD */ + UInt8 NbDTDStored; + + /** EDID Detailed Timing Descriptor */ + tmbslHdmiTxEdidDtd_t EdidDTD[NUMBER_DTD_STORED]; + + /** EDID First Moniteur descriptor */ + tmbslHdmiTxEdidFirstMD_t EdidFirstMonitorDescriptor; + + /** EDID Second Moniteur descriptor */ + tmbslHdmiTxEdidSecondMD_t EdidSecondMonitorDescriptor; + + /** EDID Other Moniteur descriptor */ + tmbslHdmiTxEdidOtherMD_t EdidOtherMonitorDescriptor; + + /** EDID supported Short Video Descriptors */ + UInt8 EdidVFmts[HDMI_TX_SVD_MAX_CNT]; + + /** Counter for supported short video descriptors */ + UInt8 EdidSvdCnt; + + /** EDID supported Short Audio Descriptors */ + tmbslHdmiTxEdidSad_t EdidAFmts[HDMI_TX_SAD_MAX_CNT]; + + /** Counter for supported short audio descriptors */ + UInt8 EdidSadCnt; + + /** EDID block workspace */ + UInt8 EdidBlock[EDID_BLOCK_SIZE]; + + /** EDID Block Count */ + UInt8 EdidBlockCnt; + + /** CEC Source Address read from EDID as "A.B.C.D" nibbles */ + UInt16 EdidSourceAddress; + + /** EDID block number which is reading */ + UInt8 EdidBlockRequested; + + /** EDID read on going*/ + Bool EdidReadStarted; + + /** Parameter for return edid block requested by application */ + tmbslHdmiTxEdidToApp_t EdidToApp; + + /** EDID Basic Display Parameters */ + tmbslHdmiTxEdidBDParam_t EDIDBasicDisplayParam; + +#ifdef TMFL_HDCP_SUPPORT + /*=== H D C P === */ + + Bool HDCPIgnoreEncrypt; + + /** Configured DDC I2C slave address */ + UInt8 HdcpSlaveAddress; + + /** Configured mode of our transmitter device */ + tmbslHdmiTxHdcpTxMode_t HdcpTxMode; + + /** Configured HDCP options */ + tmbslHdmiTxHdcpOptions_t HdcpOptions; + + /** BCAPS read from sink */ + UInt8 HdcpBcaps; + + /** BSTATUS read from sink */ + UInt16 HdcpBstatus; + + /** Device value generated for Ri=Ri' comparison */ + UInt16 HdcpRi; + + /** Device HDCP FSM state */ + UInt8 HdcpFsmState; + + /** Device failure state that caused T0 interrupt */ + UInt8 HdcpT0FailState; + + /** Otp Seed key from user*/ + UInt16 HdcpSeed; + + /* Key Selection Vector for transmitter */ + UInt8 HdcpAksv[HDMITX_KSV_BYTES_PER_DEVICE]; + + /** Local callback scheduled to be called after HdcpFuncRemainingMs */ + ptmHdmiTxFunc_t HdcpFuncScheduled; + + /** Period in ms after which to call HdcpFuncScheduled; 0=disabled */ + UInt16 HdcpFuncRemainingMs; + + /** Configured period in ms after which to do HDCP check */ + UInt16 HdcpCheckIntervalMs; + + /** Period in ms until next HDCP check */ + UInt16 HdcpCheckRemainingMs; + + /** Number of the HDCP check since HDCP was started; 0=disabled */ + UInt8 HdcpCheckNum; + + /** Configured number of HDCP checks to do after HDCP is started */ + UInt8 HdcpChecksToDo; +#endif /* TMFL_HDCP_SUPPORT */ + + /*=== V I D E O ===*/ + + /** Current EIA/CEA video input format */ + tmbslHdmiTxVidFmt_t vinFmt; + + /** Current EIA/CEA video output format */ + tmbslHdmiTxVidFmt_t voutFmt; + + /** Current pix Rate*/ + tmbslHdmiTxPixRate_t pixRate; + + /** Video input mode */ + tmbslHdmiTxVinMode_t vinMode; + + /** Video output mode */ + tmbslHdmiTxVoutMode_t voutMode; + + /** Vertical output frequency */ + tmbslHdmiTxVfreq_t voutFreq; + + /** Current scaler mode */ + tmbslHdmiTxScaMode_t scaMode; + + /** Current upsampler mode */ + tmbslHdmiTxUpsampleMode_t upsampleMode; + + /** Current pixel repetition count */ + UInt8 pixelRepeatCount; + + /** Status of hot plug detect pin last read at interrupt */ + tmbslHdmiTxHotPlug_t hotPlugStatus; + + /** Status of rx sense detect pin last read at interrupt */ + tmbslHdmiTxRxSense_t rxSenseStatus; + + /** Current register page */ + UInt8 curRegPage; + + /** Shadow copies of write-only registers with bitfields */ + UInt8 shadowReg[E_SNUM]; + + /** TRUE: Blue screen is the previous test pattern ; FALSE: is not */ + Bool prevFilterPattern; + + /** TRUE: last screen is test pattern ; FALSE: is not */ + Bool prevPattern; + + /** TRUE: Unit has been initialized; FALSE: not initialized */ + Bool bInitialized; + + tmbslHdmiTxVQR_t dviVqr; + + /** TRUE: 3D Frame Packing video is ongoing */ + Bool h3dFpOn; + +} tmHdmiTxobject_t; + +/** + * \The structure of registers for video format , + * used by PC_formats and chip_unknown formats + */ + +typedef struct _tmHdmiTxVidReg_t +{ + UInt16 nPix; + UInt16 nLine; + UInt8 VsLineStart; + UInt16 VsPixStart; + UInt8 VsLineEnd; + UInt16 VsPixEnd; + UInt16 HsStart; + UInt16 HsEnd; + UInt8 ActiveVideoStart; + UInt16 ActiveVideoEnd; + UInt16 DeStart; + UInt16 DeEnd; + UInt16 ActiveSpaceStart; + UInt16 ActiveSpaceEnd; +} tmHdmiTxVidReg_t; + + +/*============================================================================*/ +/* EXTERN DATA DEFINITION */ +/*============================================================================*/ + +#include "tmbslTDA9989_local_otp.h" + +extern RAM_DAT tmHdmiTxobject_t gHdmiTxInstance[HDMITX_UNITS_MAX]; +extern CONST_DAT UInt8 kPageIndexToPage[E_PAGE_NUM]; + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +tmErrorCode_t checkUnitSetDis (tmUnitSelect_t txUnit, + tmHdmiTxobject_t **ppDis); +tmErrorCode_t getHwRegisters (tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 *pData, UInt16 lenData); +tmErrorCode_t getHwRegister (tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 *pRegValue); +tmErrorCode_t setHwRegisters (tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 *pData, UInt16 lenData); +tmErrorCode_t setHwRegisterMsbLsb (tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt16 regWord); + +tmErrorCode_t setHwRegister_main (tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 regValue); +tmErrorCode_t setHwRegisterField (tmHdmiTxobject_t *pDis, + UInt16 regShadPageAddr, + UInt8 fieldMask, UInt8 fieldValue); +tmErrorCode_t setHwRegisterFieldTable(tmHdmiTxobject_t *pDis, + const tmHdmiTxRegMaskVal_t *pTable); +tmErrorCode_t getCECHwRegister(tmHdmiTxobject_t *pDis, + UInt16 regAddr, + UInt8 *pRegValue); +tmErrorCode_t setCECHwRegister(tmHdmiTxobject_t *pDis, + UInt16 regAddr, + UInt8 regValue); + +tmErrorCode_t lmemcpy (void *pTable1, + const void *pTable2, + UInt Size); +tmErrorCode_t lmemset (void *pTable1, + const UInt8 value, + UInt Size); + + +#ifdef __cplusplus +} +#endif + +#endif /* TMBSLTDA9989_LOCAL_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local_otp.h b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local_otp.h new file mode 100755 index 0000000000000..a5d2717ed0254 --- /dev/null +++ b/drivers/video/nxp/comps/tmbslTDA9989/src/tmbslTDA9989_local_otp.h @@ -0,0 +1,54 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmbslTDA9989_local_otp.h + * + * \version %version: 1 % + * +*/ + +#ifndef TMBSLTDA9989_LOCAL_OTP_H +#define TMBSLTDA9989_LOCAL_OTP_H + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +#define BINARY(d7,d6,d5,d4,d3,d2,d1,d0) \ + (((d7)<<7)|((d6)<<6)|((d5)<<5)|((d4)<<4)|((d3)<<3)|((d2)<<2)|((d1)<<1)|(d0)) + +enum _eRegOtp { +#ifdef TMFL_HDCP_SUPPORT + E_REG_P12_CTRL_W = SPA(E_SP12_CTRL , E_PAGE_12, 0x40), +#ifdef BCAPS_REPEATER + E_REG_P12_BCAPS_W = SPA(E_SP12_BCAPS , E_PAGE_12, 0x49), +#else + E_REG_P12_BCAPS_W = SPA(E_SNONE , E_PAGE_12, 0x49), +#endif /* BCAPS_REPEATER */ +#endif + E_REG_P12_TX0_RW = SPA(E_SNONE , E_PAGE_12, 0x97), + E_REG_P12_TX3_RW = SPA(E_SNONE , E_PAGE_12, 0x9A), +#ifdef TMFL_HDCP_OPTIMIZED_POWER + E_REG_P12_TX4_RW = SPA(E_SNONE , E_PAGE_12, 0x9B), +#endif + E_REG_P12_TX33_RW = SPA(E_SNONE , E_PAGE_12, 0xB8), +}; + +enum _eMaskRegOtp +{ + E_MASKREG_P12_TX33_hdmi = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P12_TX0_sr_hdcp = BINARY(0,0,0,0, 0,0,0,1), +#ifdef TMFL_HDCP_OPTIMIZED_POWER + E_MASKREG_P12_TX4_pd_rg = BINARY(0,0,0,0, 0,1,0,0), + E_MASKREG_P12_TX4_pd_ram = BINARY(0,0,0,0, 0,0,1,0), + E_MASKREG_P12_TX4_pd_hdcp = BINARY(0,0,0,0, 0,0,0,1), + E_MASKREG_P12_TX4_pd_all = BINARY(0,0,0,0, 0,1,1,1), +#endif +}; + +#endif /* TMBSLTDA9989_LOCAL_OTP_H */ diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_IW.h b/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_IW.h new file mode 100755 index 0000000000000..fea74bcf2740a --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_IW.h @@ -0,0 +1,305 @@ +/** + * Copyright (C) 2007 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiCEC_IW.h + * + * \version $Revision: 1 $ + * + * \date $Date: $ + * + * \brief devlib driver component API for the CEC messages + * + * \section refs Reference Documents + * + * \section info Change Information + * + * \verbatim + + $History: tmdlHdmiCEC_IW.h $ + * + \endverbatim + * +*/ + +#ifndef TMDLHDMICEC_IW_H +#define TMDLHDMICEC_IW_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#else +#ifdef TMFL_OS_WINDOWS +#define _WIN32_WINNT 0x0500 +#include "windows.h" +#else +#include "RTL.h" +#endif +#endif + +#include "tmNxTypes.h" +#include "tmdlHdmiCEC_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif +/*============================================================================*/ +/* TYPE DEFINITIONS */ +/*============================================================================*/ +typedef void (*tmdlHdmiTxIWFuncPtr_t) (void); +typedef UInt8 tmdlHdmiTxIWTaskHandle_t; +typedef UInt8 tmdlHdmiTxIWQueueHandle_t; +#ifdef TMFL_OS_WINDOWS +typedef HANDLE tmdlHdmiTxIWSemHandle_t; +#else +typedef UInt8 tmdlHdmiTxIWSemHandle_t; +#endif + +/** + * \brief Enum listing all available devices for enable/disable interrupts + */ +typedef enum +{ + TMDL_HDMI_IW_RX_1, + TMDL_HDMI_IW_RX_2, + TMDL_HDMI_IW_TX_1, + TMDL_HDMI_IW_TX_2, + TMDL_HDMI_IW_CEC_1, + TMDL_HDMI_IW_CEC_2 +} tmdlHdmiIWDeviceInterrupt_t; + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/** + \brief This function creates a task and allocates all the necessary + resources. Note that creating a task do not start it automatically, + an explicit call to IWTaskStart must be made. + + \param pFunc Pointer to the function that will be executed in the task context. + \param Priority Priority of the task. The minimum priority is 0, the maximum is 255. + \param StackSize Size of the stack to allocate for this task. + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMIRX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWTaskCreate(tmdlHdmiTxIWFuncPtr_t pFunc,UInt8 priority, UInt16 stackSize, tmdlHdmiTxIWTaskHandle_t *pHandle); + +/*============================================================================*/ + +/** + \brief This function destroys an existing task and frees resources used by it. + + \param Handle Handle of the task to be destroyed, as returned by IWTaskCreate. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWTaskDestroy(tmdlHdmiTxIWTaskHandle_t handle); + +/*============================================================================*/ + +/** + \brief This function start an existing task. + + \param Handle Handle of the task to be started. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_ALREADY_STARTED: the function is already started + - TMDL_ERR_DLHDMIRX_NOT_STARTED: the function is not started + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWTaskStart(tmdlHdmiTxIWTaskHandle_t handle); + +/*============================================================================*/ + +/** + \brief This function blocks the current task for the specified amount time. This is a passive wait. + + \param Duration Duration of the task blocking in milliseconds. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_NO_RESOURCES: the resource is not available + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWWait(UInt16 duration); + +/*============================================================================*/ + +/** + \brief This function creates a message queue. + + \param QueueSize Maximum number of messages in the message queue. + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMIRX_NO_RESOURCES: the resource is not available + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueCreate(UInt8 queueSize, tmdlHdmiTxIWQueueHandle_t *pHandle); + +/*============================================================================*/ + +/** + \brief This function destroys an existing message queue. + + \param Handle Handle of the queue to be destroyed. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMIRX_RESOURCE_NOT_OWNED: the caller does not own + the resource + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueDestroy(tmdlHdmiTxIWQueueHandle_t handle); + +/*============================================================================*/ + +/** + \brief This function sends a message into the specified message queue. + + \param Handle Handle of the queue that will receive the message. + \param Message Message to be sent. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMIRX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMIRX_FULL: the queue is full + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueSend(tmdlHdmiTxIWQueueHandle_t handle, UInt8 message); + +/*============================================================================*/ + +/** + \brief This function reads a message from the specified message queue. + + \param Handle Handle of the queue from which to read the message. + \param pMessage Pointer to the message buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMIRX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMIRX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueReceive(tmdlHdmiTxIWQueueHandle_t handle, UInt8 *pMessage); + +/*============================================================================*/ + +/** + \brief This function creates a semaphore. + + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMIRX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreCreate(tmdlHdmiTxIWSemHandle_t *pHandle); + +/*============================================================================*/ + +/** + \brief This function destroys an existing semaphore. + + \param Handle Handle of the semaphore to be destroyed. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreDestroy(tmdlHdmiTxIWSemHandle_t handle); + +/*============================================================================*/ + +/** + \brief This function acquires the specified semaphore. + + \param Handle Handle of the semaphore to be acquired. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreP(tmdlHdmiTxIWSemHandle_t handle); + +/*============================================================================*/ + +/** + \brief This function releases the specified semaphore. + + \param Handle Handle of the semaphore to be released. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMIRX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreV(tmdlHdmiTxIWSemHandle_t handle); + +/****************************************************************************** + \brief This function disables the interrupts for a specific device. + + \param + + \return The call result: + - TM_OK: the call was successful + +******************************************************************************/ +void tmdlHdmiTxIWDisableInterrupts(tmdlHdmiIWDeviceInterrupt_t device); + +/****************************************************************************** + \brief This function enables the interrupts for a specific device. + + \param + + \return The call result: + - TM_OK: the call was successful + +******************************************************************************/ +void tmdlHdmiTxIWEnableInterrupts(tmdlHdmiIWDeviceInterrupt_t device); + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMICEC_IW_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_Linux.c b/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_Linux.c new file mode 100755 index 0000000000000..be4453e91ab3f --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_Linux.c @@ -0,0 +1,436 @@ +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ +#include +#include +#include +#include +#include +#include + +#include "tmdlHdmiCEC_IW.h" +#include "tmNxTypes.h" +#include "tmdlHdmiCEC.h" +#include "tmdlHdmiCEC_cfg.h" + +struct i2c_client *GetThisI2cClient(void); +unsigned char my_i2c_data[255]; + +/*============================================================================*/ +/* MACROS */ +/*============================================================================*/ +#define RETIF(cond, rslt) if ((cond)){return (rslt);} +#define I2C_M_WR 0 + +/*============================================================================*/ +/* FUNCTIONS DECLARATIONS */ +/*============================================================================*/ + + +tmErrorCode_t I2cReadFunction(tmdlHdmiCecSysArgs_t *pSysArgs); +tmErrorCode_t I2cWriteFunction(tmdlHdmiCecSysArgs_t *pSysArgs); + + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ + + +#define COMMAND_TASK_PRIORITY_0 250 +#define COMMAND_TASK_STACKSIZE_0 128 +#define COMMAND_TASK_QUEUESIZE_0 8 + +/* I2C adress of the unit */ +#ifdef TMFL_TDA9996 + #define UNIT_I2C_ADDRESS_0 0x60 /* I2C Address of TDA9950 */ +#else + #define UNIT_I2C_ADDRESS_0 0x34 /* I2C Address of TDA9950 */ +#endif + + + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + + +tmdlHdmiCecCapabilities_t CeccapabilitiesList = {TMDL_HDMICEC_DEVICE_UNKNOWN, CEC_VERSION_1_3a}; + +tmdlHdmiCecDriverConfigTable_t CecdriverConfigTable[MAX_UNITS] = { + { + COMMAND_TASK_PRIORITY_0, + COMMAND_TASK_STACKSIZE_0, + COMMAND_TASK_QUEUESIZE_0, + UNIT_I2C_ADDRESS_0, + I2cReadFunction, + I2cWriteFunction, + &CeccapabilitiesList + } +}; + + +int blockwrite_reg(struct i2c_client *client, + u8 reg, u16 alength, u8 *val, u16 *out_len) +{ + int err = 0,i,initiator,receiver; + struct i2c_msg msg[1]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = alength+1; + msg->buf = my_i2c_data; + + msg->buf[0] = reg; + for (i=0; ibuf[i+1] = val[i]; +/* printk(KERN_INFO "buf[%d]=%d val[%d]=%d\n",i+1,msg->buf[i+1],i,val[i]); */ + } + + err = i2c_transfer(client->adapter, msg, 1); + udelay(50); + + if (reg==7) { + /* CEC message */ + extern char *cec_opcode(int op); + initiator = (msg->buf[3] >> 4) & 0x0f; + receiver = msg->buf[3] & 0x0f; +/* printk(KERN_INFO "reg:%d alength:%d \n",reg, alength); */ + if (alength==3) { + printk(KERN_INFO "hdmicec:polling:[%x--->%x] \n", initiator,receiver); + } + else { + printk(KERN_INFO "hdmicec:Tx:[%x--->%x] %s %02x%02x%02x%02x\n", \ + initiator,receiver,cec_opcode(msg->buf[4]),msg->buf[4],msg->buf[5],msg->buf[6],msg->buf[7]); + } + } +/* dev_dbg(&client->dev, "<%s> i2c Block write at 0x%x, " */ +/* "*val=%d flags=%d byte[%d] err=%d\n", */ +/* __func__, data[0], data[1], msg->flags, i, err); */ + return (err < 0?err:0); + +#if 0 + int err = 0, i; + struct i2c_msg msg[1]; + u8 data[2]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 2; + msg->buf = data; + + /* high byte goes out first */ + data[0] = reg >> 8; + + for (i = 0; i < alength - 1; i++) { + data[1] = val[i]; + err = i2c_transfer(client->adapter, msg, 1); + udelay(50); + dev_dbg(&client->dev, "<%s> i2c Block write at 0x%x, " + "*val=%d flags=%d byte[%d] err=%d\n", + __func__, data[0], data[1], msg->flags, i, err); + if (err < 0) + break; + } + /* set the number of bytes written*/ + *out_len = i; + + if (err < 0) { + dev_err(&client->dev, "<%s> ERROR: i2c Block Write at 0x%x, " + "*val=%d flags=%d bytes written=%d " + "err=%d\n", + __func__, data[0], data[1], msg->flags, i, err); + return err; + } + return 0; +#endif +} + +int blockread_reg(struct i2c_client *client, u16 data_length, + u8 reg, u16 alength, u8 *val, u16 *out_len) +{ + int err = 0; + struct i2c_msg msg[1]; + u8 data[2]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 1; + msg->buf = data; + data[0] = reg; /* High byte goes out first */ + err = i2c_transfer(client->adapter, msg, 1); + if (err<0) goto BLOCK_READ_OUPS; + + msg->flags = I2C_M_RD; + msg->len = alength; + msg->buf = val; + err = i2c_transfer(client->adapter, msg, 1); + if (err<0) goto BLOCK_READ_OUPS; + +/* printk(KERN_INFO "DBG blockread_reg addr:%x len:%d buf:%02x%02x%02x%02x\n",msg->addr,msg->len,\ */ +/* msg->buf[0],msg->buf[1],msg->buf[2],msg->buf[3]); */ + + return 0; + + BLOCK_READ_OUPS: +/* printk(KERN_INFO "DBG blockread_reg addr:%x len:%d ERROR\n",msg->addr,msg->len); */ + dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, " + "*val=%d flags=%d bytes err=%d\n", + __func__, reg, *val, msg->flags, err); + return err; + +#if 0 + int err = 0, i; + struct i2c_msg msg[1]; + u8 data[2]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 1; + msg->buf = data; + + /* High byte goes out first */ + data[0] = reg; + + for (i = 0; i < alength; i++) { + err = i2c_transfer(client->adapter, msg, 1); + dev_dbg(&client->dev, "<%s> i2c Block Read1 at 0x%x, " + "*val=%d flags=%d err=%d\n", + __func__, data[0], data[1], msg->flags, err); + if (err >= 0) { + mdelay(3); + msg->flags = I2C_M_RD; + msg->len = data_length; + err = i2c_transfer(client->adapter, msg, 1); + } else + break; + if (err >= 0) { + val[i] = 0; + /* High byte comes first */ + if (data_length == 1) + val[i] = data[0]; + else if (data_length == 2) + val[i] = data[1] + (data[0] << 8); + dev_dbg(&client->dev, "<%s> i2c Block Read2 at 0x%x, " + "*val=%d flags=%d byte=%d " + "err=%d\n", + __func__, reg, val[i], msg->flags, i, err); + } else + break; + } + *out_len = i; + dev_info(&client->dev, "<%s> i2c Block Read at 0x%x, bytes read = %d\n", + __func__, reg, *out_len); + + if (err < 0) { + dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, " + "*val=%d flags=%d bytes read=%d err=%d\n", + __func__, reg, *val, msg->flags, i, err); + return err; + } + return 0; +#endif +} + + +int write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err = 0; + struct i2c_msg msg[1]; + u8 data[2]; + int retries = 0; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + retry: + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 2; + msg->buf = data; + + data[0] = reg; + data[1] = val; + + err = i2c_transfer(client->adapter, msg, 1); + dev_dbg(&client->dev, "<%s> i2c write at=%x " + "val=%x flags=%d err=%d\n", + __func__, data[0], data[1], msg->flags, err); + udelay(50); + +/* printk(KERN_INFO "DBG write_reg addr:%x reg:%d data:%x %s\n",msg->addr,reg,val,(err<0?"ERROR":"")); */ + if (err >= 0) + return 0; + + dev_err(&client->dev, "<%s> ERROR: i2c write at=%x " + "val=%x flags=%d err=%d\n", + __func__, data[0], data[1], msg->flags, err); + if (retries <= 5) { + dev_info(&client->dev, "Retrying I2C... %d\n", retries); + retries++; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(20)); + goto retry; + } + + return err; +} + +int read_reg(struct i2c_client *client, u16 data_length, u8 reg, u8 *val) +{ + int err = 0; + struct i2c_msg msg[1]; + u8 data[2]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 1; + msg->buf = data; + + data[0] = reg; + err = i2c_transfer(client->adapter, msg, 1); + dev_dbg(&client->dev, "<%s> i2c Read1 reg=%x val=%d " + "flags=%d err=%d\n", + __func__, reg, data[1], msg->flags, err); + + if (err >= 0) { + mdelay(3); + msg->flags = I2C_M_RD; + msg->len = data_length; + err = i2c_transfer(client->adapter, msg, 1); + } + + if (err >= 0) { + *val = 0; + if (data_length == 1) + *val = data[0]; + else if (data_length == 2) + *val = data[1] + (data[0] << 8); + dev_dbg(&client->dev, "<%s> i2c Read2 at 0x%x, *val=%d " + "flags=%d err=%d\n", + __func__, reg, *val, msg->flags, err); + return 0; + } + + dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, " + "*val=%d flags=%d err=%d\n", + __func__, reg, *val, msg->flags, err); + return err; +} + + +tmErrorCode_t I2cReadFunction (tmdlHdmiCecSysArgs_t *pSysArgs) +{ + tmErrorCode_t errCode = TM_OK; + u16 outLenght=0; + struct i2c_client *client=GetThisI2cClient(); + u32 client_main_addr=client->addr; + + /* DevLib needs address control, so let it be */ + client->addr=pSysArgs->slaveAddr; + + if (pSysArgs->lenData == 1) { + /* single byte */ + errCode = read_reg(GetThisI2cClient(),1,pSysArgs->firstRegister,pSysArgs->pData); + } + else { + /* block */ + errCode = blockread_reg(GetThisI2cClient(),1, \ + pSysArgs->firstRegister, \ + pSysArgs->lenData, \ + pSysArgs->pData, &outLenght); + } + + /* restore default client address */ + client->addr=client_main_addr; + + return errCode; +} + + +tmErrorCode_t I2cWriteFunction(tmdlHdmiCecSysArgs_t *pSysArgs) +{ + + tmErrorCode_t errCode = TM_OK; + u16 outLenght=0; + struct i2c_client *client=GetThisI2cClient(); + u32 client_main_addr=client->addr; + + /* DevLib needs address control, so let it be */ + client->addr=pSysArgs->slaveAddr; + + if (pSysArgs->lenData == 1) { + /* single byte */ + errCode = write_reg(GetThisI2cClient(),pSysArgs->firstRegister,*pSysArgs->pData); + } + else { + /* block */ + errCode = blockwrite_reg(GetThisI2cClient(), \ + pSysArgs->firstRegister, \ + pSysArgs->lenData, \ + pSysArgs->pData,&outLenght); + } + + /* restore default client address */ + client->addr=client_main_addr; + + return errCode; + +} + +tmErrorCode_t tmdlHdmiTxIWWait +( + UInt16 duration +) +{ + + mdelay((unsigned long)duration); + + return(TM_OK); +} + +tmErrorCode_t tmdlHdmiCecCfgGetConfig +( + tmUnitSelect_t unit, + tmdlHdmiCecDriverConfigTable_t *pConfig +) +{ + /* check if unit number is in range */ + RETIF((unit < 0) || (unit >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER) + + /* check if pointer is Null */ + RETIF(pConfig == Null, TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + *pConfig = CecdriverConfigTable[unit]; + + return(TM_OK); +}; +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_cfg.h b/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_cfg.h new file mode 100755 index 0000000000000..36dae3c409068 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/cfg/tmdlHdmiCEC_cfg.h @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiCEC_cfg.h + * + * \version $Revision: 1 $ + * + * \date $Date: $ + * + * \brief devlib driver component API for the CEC messages + * + * \section refs Reference Documents + * + * \section info Change Information + * + * \verbatim + * + $History: tmdlHdmiCEC_cfg.h + * + * + \endverbatim + * +*/ +/****************************************************************************** +****************************************************************************** +* THIS FILE MUST NOT BE MODIFIED BY CUSTOMER * +****************************************************************************** +*****************************************************************************/ + +#ifndef TMDLHDMICEC_CFG_H +#define TMDLHDMICEC_CFG_H + +#include "tmNxTypes.h" +#include "tmdlHdmiCEC_Types.h" +#include "tmdlHdmiCEC_Functions.h" +#ifdef __cplusplus +extern "C" { +#endif + +/* Number of HW units supported by SW driver */ +#define MAX_UNITS 1 + + +#ifndef TMFL_CEC_AVAILABLE +typedef struct _tmbslHdmiTxSysArgs_t +{ + UInt8 slaveAddr; + UInt8 firstRegister; + UInt8 lenData; + UInt8 *pData; +} tmbslHdmiTxSysArgs_t; +#endif + + + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ +typedef struct +{ + UInt8 commandTaskPriority; + UInt8 commandTaskStackSize; + UInt8 commandTaskQueueSize; + UInt8 i2cAddress; + ptmdlHdmiCecSysFunc_t i2cReadFunction; + ptmdlHdmiCecSysFunc_t i2cWriteFunction; + tmdlHdmiCecCapabilities_t *pCapabilitiesList; +} tmdlHdmiCecDriverConfigTable_t; + +/*============================================================================*/ +/* FUNCTIONS DECLARATIONS */ +/*============================================================================*/ + +/** + \brief This function allows to the main driver to retrieve its + configuration parameters. + + \param pConfig Pointer to the config structure + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiCecCfgGetConfig +( + tmUnitSelect_t unit, + tmdlHdmiCecDriverConfigTable_t *pConfig +); + + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMICEC_CFG_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/docs/02_sw_req_an/tmdlHdmiCEC_API.zip b/drivers/video/nxp/comps/tmdlHdmiCEC/docs/02_sw_req_an/tmdlHdmiCEC_API.zip new file mode 100755 index 0000000000000000000000000000000000000000..0e96788c87aec8afb3a0753fe2ce8f6a6673791e GIT binary patch literal 148480 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
NP$+9#IO!BAe)>f&VnZU(VJnd7q+7 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%0Du;;sZuzjQjSP$GIa(4 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 + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Physical address of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecActiveSource +( + tmInstance_t Instance, + UInt16 PhysicalAddress +); + +//========================================================================== +/*! + \brief This message is used to indicate the supported CEC version in response + to a + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress\n + Address of message receiver. \n + + \param tmdlHdmiCECVersion_t CECVersion \n + Supported CEC Version.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVersion +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECVersion_t CECVersion +); + +//========================================================================== +/*! + \brief This message is used to clear an Analogue timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearAnalogueTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +); + + +//========================================================================== +/*! + \brief This message is used to clear a digital timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearDigitalTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification +); + +//========================================================================== +/*! + \brief This message is used to clear a digital timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPlug_t ExternalPlug \n + indicates external plug number (1 to 255 )on the recording device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearExternalTimerWithExternalPlug +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPlug_t ExternalPlug +); + +//========================================================================== +/*! + \brief This message is used to clear a digital timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Defines the path between the TV an a device-thus giving it a physical + address within the cluster.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearExternalTimerWithPhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress +); + +//========================================================================== +/*! + \brief This message is used to conrol a device's media functions + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDecControlMode_t DeckControlMode \n + Used in message \n + + \note The "Skip Forward / Wind" and "Skip Reverse / Rewind" values are + used for example in a DVD as next xhapter and previous chapter and + in a VCR as wind and rewind. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDeckControl +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDecControlMode_t DeckControlMode +); + +//========================================================================== +/*! + \brief This message is used to provide a deck's status to the initiator + of the message + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDecInfo_t DeckInfo \n + Information on the device's current status \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDeckStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDecInfo_t DeckInfo +); + +//========================================================================== +/*! + \brief This message report the vendor ID of this device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt32 VendorID \n + Indentifier for a specific Vendor \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDeviceVendorID +( + tmInstance_t Instance, + UInt32 VendorID +); + +//========================================================================== +/*! + \brief This message is used as a reponse to indicate that the device does + not support the requested message type, or that it cannot execute it + at the present time. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECFeatureOpcode_t FeatureOpcode \n + Opcode of the aborted message. \n + + \param tmdlHdmiCECAbortReason_t AbortReason \n + The reason why message cannot respond. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecFeatureAbort +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECFeatureOpcode_t FeatureOpcode, + tmdlHdmiCECAbortReason_t AbortReason +); + +//========================================================================== +/*! + \brief This message is used by a device to enquire which version of CEC + the target supports + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetCecVersion +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is sent by a device capable of character generation + (for OSD and Menus) to a TV in order to discover the currently selected + Menu Language. Also used by a TV during installation to dicover the + currently set menu language of other devices. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetMenuLanguage +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is requests an amplifier to send its volume and mute status + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveAudioStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to request the status of a device regardless + of whether or not it is the current active source. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECStatusRequest_t StatusRequest \n + Allows the initiator to request the status once or on all future state + change. Or to cancel a previous ["On"] request. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveDeckStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECStatusRequest_t StatusRequest +); + +//========================================================================== +/*! + \brief This message is used to determine the current power status of a + target device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveDevicePowerStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is request the vendor ID from a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveDeviceVendorID +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to request preferred OSD name of a device + for use in menus associated with that device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveOsdName +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is a request to a device to return its physical Address + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGivePhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message request the status of the system audio mode + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveSystemAudioModeStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to request the status of a tuner device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECStatusRequest_t StatusRequest \n + Allows the initiator to request the status once or on all future state + change. Or to cancel a previous ["On"] request. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveTunerDeviceStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECStatusRequest_t StatusRequest +); + +//========================================================================== +/*! + \brief This message sent by a source device to the TV whenever it enters + the active state + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receivers. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecImageViewOn +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used by the currently active source to inform the + TV that it has no video to be presented to the user, or is going + into standby as the result of a lcoal user command on the device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress, \n + Address of message receiver. \n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Physical Address of the device. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecInactiveSource +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress +); + +//========================================================================== +/*! + \brief This message request from the TV for a device to show/remove a + menu or to query if a device is currently showing a menu + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECMenuRequestType_t MenuRequestType \n + Indicates if the menu request is to activate or deactivate the + devices menu or simply query the devices menu status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecMenuRequest +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECMenuRequestType_t MenuRequestType +); + +//========================================================================== +/*! + \brief This message is used to indicate to the TV that the device is + showing/has removed a menu and requets the remote control keys to + be passed though + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECMenuState_t MenuState \n + Indicates if the device is in the 'Device Menu Active' state or + 'Device Menu Inactive' state. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecMenuStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECMenuState_t MenuState +); + +//========================================================================== +/*! + \brief This message is used to control the playback behaviour of a source + device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECPlayMode_t PlayMode \n + In which mode to play media. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecPlay +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECPlayMode_t PlayMode +); + +//========================================================================== +/*! + \brief This message is used by any device for device discovery - similar to + ping in other protocols + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecPollingMessage +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message request a device to stop a recording + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOff +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message attempt to record analogue source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnAnalogueService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +); + +//========================================================================== +/*! + \brief This message attempt to record digital source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnDigitalService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification +); + +//========================================================================== +/*! + \brief This message attempt to record an external physical address source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Defines the path between the TV an a device-thus giving it a physical + address within the cluster.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnExternalPhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress +); + +//========================================================================== +/*! + \brief This message attempt to record an external plug source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECExternalPlug_t ExternalPlug \n + indicates external plug number (1 to 255 )on the recording device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnExternalPlug +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECExternalPlug_t ExternalPlug +); + +//========================================================================== +/*! + \brief This message attempt to record an external plug source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnOwnSource +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used by a recording device to inform the initiator + of the message about its status. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECRecordStatusInfo_t RecordStatusInfo \n + The recording status of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECRecordStatusInfo_t RecordStatusInfo +); + +//========================================================================== +/*! + \brief This message request by the recording device to record the presently + displayed source. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordTvScreen +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message report an amplifier's volume and mute. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECAudioStatus_t AudioStatus \n + Volume and mute status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportAudioStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + ptmdlHdmiCECAudioStatus_t pAudioStatus +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportShortAudioDescriptor( ) + \brief This message Report Audio Capability. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt32 ShortAudioDecriptor \n + Audio Descriptor. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportShortAudioDescriptor +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt32 ShortAudioDecriptor +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestShortAudioDescriptor( ) + \brief This message Request Audio Capability. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 AudioFormatID \n + + \param UInt8 AudioFormatCode \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestShortAudioDescriptor +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 AudioFormatID, + UInt8 AudioFormatCode + +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecIniateARC( ) + \brief This message Used by an ARC RX device to activate the + ARC functionality in an ARC TX device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecIniateARC +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportArcInitiated( ) + \brief This message Used by an ARC TX device to indicate that + its ARC functionality has been activated + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportArcInitiated +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportArcTerminated( ) + \brief This message Used by an ARC TX device to indicate that its ARC functionality + has been deactivated. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportArcTerminated +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestArcInitiation( ) + \brief This message Used by an ARC TX device to request an ARC RX device to + activate the ARC functionality in the ARC TX device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestArcInitiation +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestArcTerminiation( ) + \brief Used by an ARC TX device to request an ARC RX device to deactivate + the ARC functionality in the ARC TX device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestArcTerminiation +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTerminateARC( ) + \brief Used by an ARC TX device to request an ARC RX device to deactivate + the ARC functionality in the ARC TX device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTerminateARC +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to inform all other devices of the mapping + between physical and logical address of the initiator. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Device physical address within the cluster. \n + + \param tmdlHdmiCECDeviceType_t DeviceType \n + Type of the device (TV, Playback, tuner,...). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportPhysicalAddress +( + tmInstance_t Instance, + UInt16 PhysicalAddress, + tmdlHdmiCECDeviceType_t DeviceType +); + +//========================================================================== +/*! + \brief This message is used to inform a requesting device of the current + power status. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECPowerStatus_t PowerStatus \n + Current power status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportPowerStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECPowerStatus_t PowerStatus +); + +//========================================================================== +/*! + \brief This message is used by a new device to discover the status of + the system. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestActiveSource +( + tmInstance_t Instance +); + +//========================================================================== +/*! + \brief This message is sent by a CEC switch when it is manually switched to + inform all other devices on the network that the active route below + the switch has changed. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 OriginalAddress \n + Previous address that the switch was switched to. \n + + \param UInt16 NewAddress \n + The new address it has been moved to. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRoutingChange +( + tmInstance_t Instance, + UInt16 OriginalAddress, + UInt16 NewAddress +); + +//========================================================================== +/*! + \brief This message is sent by a CEC switch to indicate the active route + below the switch. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + The current active route to the sink in the CEC switch. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRoutingInformation +( + tmInstance_t Instance, + UInt16 PhysicalAddress +); + +//========================================================================== +/*! + \brief This message select directly an analogue TV Service. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSelectAnalogueService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +); + +//========================================================================== +/*! + \brief This message select directly a digital TV, Radio or Data Broadcast + Service. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSelectDigitalService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + ptmdlHdmiCECDigitalServiceIdentification_t pServiceIdentification +); + +//========================================================================== +/*! + \brief This message is used to set asingle timer block on an analogue + recording device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetAnalogueTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +); + +//========================================================================== +/*! + \brief This message is used to control audio rate from Source device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECAudioRate_t AudioRate \n + The audio rate requested. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetAudioRate +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECAudioRate_t AudioRate +); + +//========================================================================== +/*! + \brief This message is used to set a digital timer block on a digital + recording device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetDigitalTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification +); + +//========================================================================== +/*! + \brief This message is used to set a single timer block to record from an + external device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPlug_t ExternalPlug \n + indicates external plug number (1 to 255 )on the recording device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetExternalTimerWithExternalPlug +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPlug_t ExternalPlug +); + +//========================================================================== +/*! + \brief This message is used to set a single timer block to record from an + external device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Defines the path between the TV an a device-thus giving it a physical + address within the cluster.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetExternalTimerWithPhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress +); + +//========================================================================== +/*! + \brief This message is used by a TV or another device to indicate the menu + Language. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param const char *pLanguage \n + Pointer on the user's menu language choice. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetMenuLanguage +( + tmInstance_t Instance, + const char *pLanguage +); + +//========================================================================== +/*! + \brief This message is used to set the preferred OSD name of a device + for use in manus associated with that device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param const char *pOsdName \n + Pointer on the preferred name of the device. \n + + \param UInt8 OsdNameLength \n + Length of Osd Name String. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetOsdName +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + const char *pOsdName, + UInt8 OsdNameLength +); + +//========================================================================== +/*! + \brief This message is used to send a test message to output on a TV. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDisplayControl_t DisplayControl \n + Display timing. \n + + \param const char *pOsdString \n + Pointer on the Text to display. \n + + \param UInt8 OsdStringLength \n + Length of Osd String. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetOsdString +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDisplayControl_t DisplayControl, + const char *pOsdString, + UInt8 OsdStringLength +); + +//========================================================================== +/*! + \brief This message is used by a TV to request a streaming path from + the specified physical address. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Physical address of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetStreamPath +( + tmInstance_t Instance, + UInt16 PhysicalAddress +); + +//========================================================================== +/*! + \brief This message turn the system audio Mode ON or OFF. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus \n + Specifies if the system audio mode is ON or OFF.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetSystemAudioMode +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus +); + +//========================================================================== +/*! + \brief This message is used to set the name of a program associated + with a timer block.Sent directly after sending a + or message. The name + is then associated with that timer block. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param const char *pProgramTitleString \n + Pointer on the program title. \n + + \param UInt8 ProgramTitleLength \n + Length of Program Title String. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetTimerProgramTitle +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + const char *pProgramTitleString, + UInt8 ProgramTitleLength +); + +//========================================================================== +/*! + \brief This message switches one or all devices into standby mode.Can be + be used as a broadcast message o be addressed to a specific device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecStandby +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief A device implementing System Audio Control and which has volume + control RC button(eg TV or STB) request to use System Audio Mode + to the amplifier. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Physical address of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSystemAudioModeRequest +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt16 PhysicalAddress +); + +//========================================================================== +/*! + \brief Reports the current status of the System Audio Mode. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus \n + Current system audio mode.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSystemAudioModeStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus +); + +//========================================================================== +/*! + \brief This message as , but should also remove any text, + menus and PIP windows from the TV's display + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTextViewOn +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to give the status of a , + or message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECTimerClearedStatusData_t TimerClearedStatusData \n + Indicates if the timer was cleared successfully. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTimerClearedStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECTimerClearedStatusData_t TimerClearedStatusData +); + +//========================================================================== +/*! + \brief This message is used to send timer status to the initiator of a + message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECTimerStatusData_t *pTimerStatusData \n + Pointer on the Timer status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTimerStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECTimerStatusData_t *pTimerStatusData +); + +//========================================================================== +/*! + \brief This message is used by a tuner device to provide its status to the + initiator of the message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECRecordingFlag_t RecordingFlag \n + Indicates if the tuner is being used as a source of a recording. \n + + \param tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo \n + Indicates if the the device is currently deplaying its tuner or not. \n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerDeviceStatusAnalogue +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECRecordingFlag_t RecordingFlag, + tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +); + +//========================================================================== +/*! + \brief This message is used by a tuner device to provide its status to the + initiator of the message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECRecordingFlag_t RecordingFlag \n + Indicates if the tuner is being used as a source of a recording. \n + + \param tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo \n + Indicates if the the device is currently deplaying its tuner or not. \n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerDeviceStatusDigital +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECRecordingFlag_t RecordingFlag, + tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo, + ptmdlHdmiCECDigitalServiceIdentification_t pServiceIdentification +); + +//========================================================================== +/*! + \brief This message is used to tune to next lowest service in a tuner's + service list.Can be used for PIP. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerStepDecrement +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to tune to next highest service in a tuner's + service list.Can be used for PIP. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerStepIncrement +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECUserRemoteControlCommand_t UICommand \n + Relevant UI command issued by user. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressed +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECUserRemoteControlCommand_t UICommand +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECPlayMode_t PlayMode \n + In which mode to play media. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedPlay +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECPlayMode_t PlayMode +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 SelectAudioInput \n + Number of the Audio Input (Audio input number between 1 and 255). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedSelectAudioInput +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 SelectAudioInput +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 SelectAVInput \n + Number of the A/V Input (A/V input number between 1 and 255). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedSelectAVInput +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 SelectAVInput +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 SelectMedia \n + Number of Media (Media number between 1 and 255). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedSelectMedia +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 SelectMedia +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECChannelIdentifier_t *pChannelIdentifier \n + Pointer to the structure of Major and Minor Channel number + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedTune +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECChannelIdentifier_t *pChannelIdentifier +); + +//========================================================================== +/*! + \brief This message is used to indicate that the user released a remote button + The last one indicated by the Message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlReleased +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief This message is allows vendor specific commands to be sent between + two devices. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 *pVendorSpecificData \n + Pointer to the Vendor Specific datas + + \param UInt8 VendorSpecificDataLength \n + Length of VendorSpecificData. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorCommand +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 *pVendorSpecificData, + UInt8 VendorSpecificDataLength +); + +//========================================================================== +/*! + \brief This message is allows vendor specific commands to be sent between + two devices or broadcast. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt32 VendorID \n + Indentifier for a specific Vendor \n + + \param UInt8 *pVendorSpecificData \n + Pointer to the Vendor Specific datas + + \param UInt8 VendorSpecificDataLength \n + Length of VendorSpecificData. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorCommandWithID +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt32 VendorID, + UInt8 *pVendorSpecificData, + UInt8 VendorSpecificDataLength +); + +//========================================================================== +/*! + \brief This message indicates that a remote control button has been depressed. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 *pVendorSpecificRcCode \n + Pointer to the Vendor Specific remote control code. + its recommended t keep this to a minimum size. + The maximum length shall not exceed 14 data blocks to avoid saturating bus + + \param UInt8 VendorSpecificRcCodeLength \n + Length of VendorSpecificRcCode. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorRemoteButtonDown +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 *pVendorSpecificRcCode, + UInt8 VendorSpecificRcCodeLength +); + +//========================================================================== +/*! + \brief This message indicates that a remote control button (the last button + pressed indicated by the message) has + been released. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorRemoteButtonUp +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +); + +//========================================================================== +/*! + \brief Get the software version of the driver. + This function is synchronous. + This function is ISR friendly. + + \param pSWVersion Pointer to the version structure + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetSWVersion +( + tmSWVersion_t *pSWVersion +); + +//========================================================================== +/*! + \brief Get the number of available CEC devices in the system. + A unit directly represents a physical device. + This function is synchronous. + This function is ISR friendly. + + \param pUnitCount Pointer to the number of available units. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetNumberOfUnits +( + UInt32 *pUnitCount +); + +//========================================================================== +/*! + \brief Get the capabilities of unit 0. Capabilities are stored into a + dedicated structure. + This function is synchronous. + This function is not ISR friendly. + + \param pCapabilities Pointer to the capabilities structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetCapabilities +( + tmdlHdmiCecCapabilities_t *pCapabilities +); + +//========================================================================== +/*! + \brief Get the capabilities of a specific unit. Capabilities are stored + into a dedicated structure + This function is synchronous. + This function is not ISR friendly. + + \param unit Unit to be probed. + \param pCapabilities Pointer to the capabilities structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetCapabilitiesM +( + tmUnitSelect_t unit, + tmdlHdmiCecCapabilities_t *pCapabilities +); + +//========================================================================== +/*! + \brief Open unit 0 of CEC driver and provides the instance number to + the caller. Note that one unit of CEC represents one physical + CEC device and that only one instance per unit can be opened. + This function is synchronous. + This function is not ISR friendly. + + \param pInstance Pointer to the variable that will receive the instance + identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMICEC_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_NO_RESOURCES: the resource is not available +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecOpen +( + tmInstance_t *pInstance +); + +//========================================================================== +/*! + \brief Open a specific unit of CEC driver and provides the instance + number to the caller. Note that one unit of CEC represents one + physical CEC device and that only one instance per unit can be + opened. + This function is synchronous. + This function is not ISR friendly. + + \param pInstance Pointer to the structure that will receive the instance + identifier. + \param unit Unit number to be opened. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMICEC_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_NO_RESOURCES: the resource is not available +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecOpenM +( + tmInstance_t *pInstance, + tmUnitSelect_t unit +); + +//========================================================================== +/*! + \brief Close an instance of CEC driver. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClose +( + tmInstance_t instance +); + +//========================================================================== +/*! + \brief Set the power state of an instance of the CEC device. ON + state corresponds to a fully supplied, up and running device. Other + modes correspond to the powerdown state of the device. + This function is synchronous. + This function is not ISR friendly. + + + \param instance Instance identifier. + \param powerState Power state to set. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetPowerState +( + tmInstance_t instance, + tmPowerState_t powerState +); + +//========================================================================== +/*! + \brief Get the power state of an instance of the CEC device. ON + state corresponds to a fully supplied, up and running device. Other + modes correspond to the powerdown state of the device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pPowerState Pointer to the power state. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetPowerState +( + tmInstance_t instance, + tmPowerState_t *pPowerState +); + +//========================================================================== +/*! + \brief Set the configuration of instance attributes. This function is + required by DVP architecture rules but actually does nothing in this + driver + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecInstanceConfig +( + tmInstance_t instance +); + +//========================================================================== +/*! + \brief Setup the instance with its configuration parameters. This function + allows basic instance configuration like Logical Address or device + state. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure containing all setup parameters + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecInstanceSetup +( + tmInstance_t instance, + ptmdlHdmiCecInstanceSetup_t pSetupInfo +); + +//========================================================================== +/*! + \brief Get instance setup parameters. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure that will receive setup + parameters + This function is synchronous. + This function is not ISR friendly. + + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetInstanceSetup +( + tmInstance_t instance, + ptmdlHdmiCecInstanceSetup_t pSetupInfo +); + +//========================================================================== +/*! + \brief Make device library handle an incoming interrupt. This function is + used by application to tell the device library that the hardware + sent an interrupt. It can also be used to poll the interrupt status + of the device if the interrupt line is not physically connected to + the CPU. + This function is synchronous. + This function is ISR friendly. + + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_FULL: the queue is full +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecHandleInterrupt +( + tmInstance_t instance +); + +//========================================================================== +/*! + \brief Register event callbacks. Only one callback is registered through + this API. This callback will received the type of event that + occured throug a dedicated parameter and will be called as many + times as there is pending events. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pCallback Pointer to the callback function that will handle events + from the devlib. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_INVALID_STATE: the state is invalid for + the function +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRegisterCallbacks +( + tmInstance_t instance, + ptmdlHdmiCecCallbackFunc_t pkCallback +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetLogicalAddress( ) + \brief Set Device Logical Address + + \param instance Instance identifier. + \param LogicalAddress Logical Address value. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetLogicalAddress +( + tmInstance_t instance, + tmdlHdmiCECLogicalAddress_t LogicalAddress +); + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetRetry( ) + \brief Change the number of retransmission + + \param instance Instance identifier. + \param NbRetry Number of retry. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetRetry +( + tmInstance_t instance, + UInt8 NbRetry +); + + +//========================================================================== +/*! + \fn tmErrorCode_t getCecLastMessage( ) + \brief Return the Addresses and the Opcode of the last CEC + transmitted message + + \param pSaveMessage Pointer to the CEC Save Message + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t getCecLastMessage +( + tmdlHdmiCecSaveMessage_t *pSaveMessage +); + + +//========================================================================== +/*! + \brief This function allows enabling a specific event of devlib. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param event Event to enable + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecEnableEvent +( + tmInstance_t instance, + tmdlHdmiCecEvent_t event +); + +//========================================================================== +/*! + \brief This function allows disabling a specific event of devlib. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param event Event to disable + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDisableEvent +( + tmInstance_t instance, + tmdlHdmiCecEvent_t event +); + + +//========================================================================== +/*! + \brief This function enables calibration depending on CEC clock source + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param cecClockSource CEC clock source + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecEnableCalibration +( + tmInstance_t instance, + tmdlHdmiCecClockSource_t cecClockSource +); + + +//========================================================================== +/*! + \brief This function disable calibration depending on CEC clock source + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDisableCalibration( + tmInstance_t instance +); + +//========================================================================== +/*! + \brief This function allow to send a generic CEC message + This function has to be used when CEC messages are construct in + the middleware + + \param instance Instance identifier. + + \param *pData Pointer to the CEC data buffer + + \param lenData Lenght of I2C data buffer + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSendMessage( + + tmInstance_t instance, + UInt8 *pData, + UInt16 lenData +); + +unsigned char tmdlHdmiCecGetRegister(tmInstance_t instance, UInt32 offset); +tmErrorCode_t tmdlHdmiCecSetRegister(tmInstance_t instance,UInt32 offset,UInt32 value); + + + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMICEC_FUNCTIONS_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h b/drivers/video/nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h new file mode 100755 index 0000000000000..1f8e1cf265d29 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/inc/tmdlHdmiCEC_Types.h @@ -0,0 +1,1083 @@ +//============================================================================= +// Copyright (C) 2007 NXP N.V., All Rights Reserved. +// This source code and any compilation or derivative thereof is the proprietary +// information of NXP N.V. and is confidential in nature. Under no circumstances +// is this software to be exposed to or placed under an Open Source License of +// any type without the expressed written permission of NXP N.V. +//============================================================================= +/*! + \file tmdlHdmiCEC_Types.h + + \version 1.0 + + \date 04/07/2007 + + \brief This provides interfaces description of CEC messages. + + \section refs Reference Documents + TDA998X Driver - tmdlHdmiTx - SCS.doc + \note None. + + HISTORY : + \verbatim + Date Modified by CRPRNr TASKNr Maintenance description + -------------|-----------|-------|-------|----------------------------------- + 04/07/2007 | F.G | | | Creation. + -------------|-----------|-------|-------|----------------------------------- + \endverbatim +*/ +//========================================================================== + +#ifndef TMDLHDMICEC_TYPES_H +#define TMDLHDMICEC_TYPES_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmNxTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* DEFINES */ +/*============================================================================*/ + +/**< Error Codes */ +#define TMDL_ERR_DLHDMICEC_BASE CID_DL_HDMICEC +#define TMDL_ERR_DLHDMICEC_COMPATIBILITY (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_COMPATIBILITY) /**< SW Interface compatibility */ +#define TMDL_ERR_DLHDMICEC_MAJOR_VERSION (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_MAJOR_VERSION) /**< SW Major Version error */ +#define TMDL_ERR_DLHDMICEC_COMP_VERSION (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_COMP_VERSION) /**< SW component version error */ +#define TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_BAD_UNIT_NUMBER) /**< Invalid device unit number */ +#define TMDL_ERR_DLHDMICEC_BAD_INSTANCE (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_BAD_INSTANCE) /**< Bad input instance value */ +#define TMDL_ERR_DLHDMICEC_BAD_HANDLE (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_BAD_HANDLE) /**< Bad input handle */ +#define TMDL_ERR_DLHDMICEC_BAD_PARAMETER (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_BAD_PARAMETER) /**< Invalid input parameter */ +#define TMDL_ERR_DLHDMICEC_NO_RESOURCES (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_NO_RESOURCES) /**< Resource is not available */ +#define TMDL_ERR_DLHDMICEC_RESOURCE_OWNED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_RESOURCE_OWNED) /**< Resource is already in use */ +#define TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_RESOURCE_NOT_OWNED) /**< Caller does not own resource */ +#define TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_INCONSISTENT_PARAMS) /**< Inconsistent input params */ +#define TMDL_ERR_DLHDMICEC_NOT_INITIALIZED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_NOT_INITIALIZED) /**< Component is not initialized */ +#define TMDL_ERR_DLHDMICEC_NOT_SUPPORTED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_NOT_SUPPORTED) /**< Function is not supported */ +#define TMDL_ERR_DLHDMICEC_INIT_FAILED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_INIT_FAILED) /**< Initialization failed */ +#define TMDL_ERR_DLHDMICEC_BUSY (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_BUSY) /**< Component is busy */ +#define TMDL_ERR_DLHDMICEC_I2C_READ (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_READ) /**< Read error */ +#define TMDL_ERR_DLHDMICEC_I2C_WRITE (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_WRITE) /**< Write error */ +#define TMDL_ERR_DLHDMICEC_FULL (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_FULL) /**< Queue is full */ +#define TMDL_ERR_DLHDMICEC_NOT_STARTED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_NOT_STARTED) /**< Function is not started */ +#define TMDL_ERR_DLHDMICEC_ALREADY_STARTED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_ALREADY_STARTED) /**< Function is already started */ +#define TMDL_ERR_DLHDMICEC_ASSERTION (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_ASSERTION) /**< Assertion failure */ +#define TMDL_ERR_DLHDMICEC_INVALID_STATE (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_INVALID_STATE) /**< Invalid state for function */ +#define TMDL_ERR_DLHDMICEC_OPERATION_NOT_PERMITTED (TMDL_ERR_DLHDMICEC_BASE + TM_ERR_OPERATION_NOT_PERMITTED) /**< corresponds to posix EPERM */ + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +/*! + \enum tmdlHdmiCECAbortReason_t + \brief This enum indicates the reason for a response +*/ +typedef enum +{ + CEC_ABORT_UNKNOWN_OPCODE = 0, /*!< Unrecognized opcode */ + CEC_ABORT_INCORRECT_MODE = 1, /*!< Not in correct mode to respond */ + CEC_ABORT_NO_SOURCE = 2, /*!< cannot provide source */ + CEC_ABORT_INVALID_OPERAND = 3, /*!< Invalid operand */ + CEC_ABORT_REFUSED = 4, /*!< Refused */ + CEC_ABORT_UNABLE_TO_DETERMINE = 5 /*!< Unable to Determine */ +} tmdlHdmiCECAbortReason_t; + +/*! + \enum tmdlHdmiCECAnalogueBroadcastType_t + \brief This enum indicates the analogue broadcast type +*/ +typedef enum +{ + CEC_BROADCAST_TYPE_CABLE = 0x00, /*!< Cable */ + CEC_BROADCAST_TYPE_SATELLITE = 0x01, /*!< Satellite*/ + CEC_BROADCAST_TYPE_TERRESTRIAL = 0x02 /*!< Terrestrial */ +} tmdlHdmiCECAnalogueBroadcastType_t; + +/*! + \enum _tmdlHdmiCECAnalogueFrequency + \brief This enum specify the min and max frequency used by an analogue tuner +*/ +enum _tmdlHdmiCECAnalogueFrequency +{ + CEC_ANALOG_FREQ_MIN = 0x0000, /*!< Min frequency used by analogue tuner */ + CEC_ANALOG_FREQ_MAX = 0xFFFF /*!< Max frequency used by analogue tuner */ +}; + +/*! + \enum _tmdlHdmiCECAsciiDigit + \brief This enum represent the min and max of a printable digit character +*/ +enum _tmdlHdmiCECAsciiDigit +{ + CEC_ASCII_DIGIT_MIN = 0x30, /*!< Min of a printable digit character */ + CEC_ASCII_DIGIT_MAX = 0x39 /*!< Max of a printable digit character */ +}; + +/*! + \enum _tmdlHdmiCECAscii + \brief This enum represent the min and max of a printable character +*/ +enum _tmbsHdmiCECAscii +{ + CEC_ASCII_CHARACTER_MIN = 0x20, /*!< Min of a printable character */ + CEC_ASCII_CHARACTER_MAX = 0x7E /*!< Max of a printable character */ +}; + +/*! + \enum _tmdlHdmiCECAudioFormatCode + \brief This enum represent the min and max of a Audio Format Code is defined + in CEA-861-D for CEA Short Audio Descriptor +*/ +enum _tmdlHdmiCECAudioFormatCode +{ + CEC_AUDIO_FORMAT_CODE_MIN = 0x01, /*!< Min of a Audio Format Code */ + CEC_AUDIO_FORMAT_CODE_MAX = 0x0F /*!< Max of a Audio Format Code */ +}; + +/*! + \enum tmdlHdmiCECAudioRate_t + \brief This enum indicates the audio range control +*/ +typedef enum +{ + CEC_AUDIO_RATE_OFF = 0, /*!< Rate Control off */ + CEC_AUDIO_RATE_WIDE_RANGE_STANDARD_RATE = 1, /*!< Standard rate : 100% rate */ + CEC_AUDIO_RATE_WIDE_RANGE_FAST_RATE = 2, /*!< Fast rate : Max 101% rate */ + CEC_AUDIO_RATE_WIDE_RANGE_SLOW_RATE = 3, /*!< Sloaw rate : 99% rate */ + CEC_AUDIO_RATE_NARROW_RANGE_STANDARD_RATE = 4, /*!< Standard rate : 100% rate */ + CEC_AUDIO_RATE_NARROW_RANGE_FAST_RATE = 5, /*!< Fast rate : Max 101% rate */ + CEC_AUDIO_RATE_NARROW_RANGE_SLOW_RATE = 6 /*!< Sloaw rate : 99% rate */ +} tmdlHdmiCECAudioRate_t; + +/*! + \enum tmdlHdmiCECAudioMute_t + \brief This enum indicates the audio current audio mute status +*/ +typedef enum +{ + CEC_AUDIO_MUTE_OFF = 0, /*!< Audio Mute off */ + CEC_AUDIO_MUTE_ON = 1 /*!< Audio Mute on */ +} tmdlHdmiCECAudioMute_t; + + +/*! + \struct tmdlHdmiCECAudioStatus_t + \brief This union indicates the current audio status of a device +*/ +typedef struct _tmdlHdmiCECAudioStatus_t +{ + tmdlHdmiCECAudioMute_t audioMuteStatus ; /*!< Audio Mute Status */ + UInt8 audioVolumeStatus ; /*!< Audio Volume Status */ +} tmdlHdmiCECAudioStatus_t, *ptmdlHdmiCECAudioStatus_t; + + +/*! + \enum tmdlHdmiCECBoolean_t + \brief This enum indicates a Flag +*/ +typedef enum +{ + CEC_FALSE = 0, /*!< False */ + CEC_TRUE = 1, /*!< True */ +} tmdlHdmiCECBoolean_t; + + +/*! + \enum tmdlHdmiCECBroadcastSystem_t + \brief This enum indicates information about the color system, the sound carrier and IF-frequency +*/ +typedef enum +{ /*!< Sound / Sound Modulation / Video Modulation / Vertical Frequency / Color sub-carier */ + CEC_BROADCAST_SYSTEM_PAL_BG = 0, /*!< 5.5MHZ / FM NEG 50HZ 4.43 MHZ */ + CEC_BROADCAST_SYSTEM_PAL_SECAM_L = 1, /*!< 6.5MHZ / AM POS 50HZ Fob 4.25MHz,For 4.406Mhz */ + CEC_BROADCAST_SYSTEM_PAL_M = 2, /*!< 4.5MHZ / FM NEG 60HZ 3.5756 MHZ */ + CEC_BROADCAST_SYSTEM_NTSC_M = 3, /*!< 4.5MHZ / FM NEG 60HZ 3.5795 MHZ */ + CEC_BROADCAST_SYSTEM_PAL_I = 4, /*!< 6.0MHZ / FM NEG 50HZ 4.43 MHZ */ + CEC_BROADCAST_SYSTEM_SECAM_DK = 5, /*!< 6.5MHZ / FM NEG 50HZ Fob 4.25MHz,For 4.406Mhz */ + CEC_BROADCAST_SYSTEM_SECAM_BG = 6, /*!< 5.5MHZ / FM NEG 50HZ Fob 4.25MHz,For 4.406Mhz */ + CEC_BROADCAST_SYSTEM_SECAM_L = 7, /*!< 6.5MHZ / AM POS 50HZ Fob 4.25MHz,For 4.406Mhz */ + CEC_BROADCAST_SYSTEM_PAL_DK = 8, /*!< 5.5MHZ / FM NEG 50HZ 4.43MHZ */ + CEC_BROADCAST_SYSTEM_FUTURE_USE = 9, /*!< Future Use */ + CEC_BROADCAST_SYSTEM_OTHER_SYSTEM = 31 /*!< Other System */ +} tmdlHdmiCECBroadcastSystem_t; + +/*! + \enum tmdlHdmiCECVersion_t + \brief This enum indicates the supported CEC version +*/ +typedef enum +{ + CEC_VERSION_Reserved = 0x00, /*!< CEC Reserved */ + CEC_VERSION_Reserved1 = 0x01, /*!< CEC Reserved */ + CEC_VERSION_Reserved2 = 0x02, /*!< CEC Reserved */ + CEC_VERSION_Reserved3 = 0x03, /*!< CEC Reserved */ + CEC_VERSION_1_3a = 0x04, /*!< CEC Version 1.3a */ + CEC_VERSION_1_4 = 0x05 /*!< CEC Version 1.4 */ +} tmdlHdmiCECVersion_t; + +/*! + \enum tmdlHdmiCECChanNumFormat_t + \brief This enum indicates the Channel Format +*/ +typedef enum +{ + CEC_FIRST_CHAN_NUMBER = 0x01, /*!< 1-part channel number */ + CEC_SECOND_CHAN_NUMBER = 0x02 /*!< 2-part channel number */ +} tmdlHdmiCECChanNumFormat_t; + +/*! + \struct tmdlHdmiCECChannelIdentifier_t + \brief This struct indicates a 1-part Logical or Virtual Channel Number or + a 2-part Major and Minor channel combination +*/ +typedef struct +{ + tmdlHdmiCECChanNumFormat_t ChanNumFormat ; /*!< Channel Format */ + UInt16 MajorChanNumber ; /*!< Major Channel Number (if channel is 2-part) */ + UInt16 MinorChanNumber ; /*!< 1-part Channel Number ,or a Minor Channel Number (if channel is 2-part) */ +} tmdlHdmiCECChannelIdentifier_t ; + +/*! + \enum tmdlHdmiCECDayOfMonth_t + \brief This enum indicates the day of the month +*/ +typedef enum +{ + CEC_FIRST_DAY_OF_MONTH = 1, /*!< First day of the month */ + CEC_LAST_DAY_OF_MONTH = 31 /*!< Last day of the month */ +} tmdlHdmiCECDayOfMonth_t; + +/*! + \enum tmdlHdmiCECDecControlMode_t + \brief This enum indicates command used for opcode +*/ +typedef enum +{ + CEC_DECK_CONTROL_WIND = 1, /*!< Skip Forward / Wind */ + CEC_DECK_CONTROL_REWIND = 2, /*!< Skip Reverse / Rewind */ + CEC_DECK_CONTROL_STOP = 3, /*!< Stop */ + CEC_DECK_CONTROL_EJECT = 4 /*!< Eject */ +} tmdlHdmiCECDecControlMode_t; + +/*! + \enum tmdlHdmiCECDecInfo_t + \brief This enum indicates the current status of a tape or disk deck +*/ +typedef enum +{ + CEC_DECK_INFO_PLAY = 0x11, /*!< Play */ + CEC_DECK_INFO_RECORD = 0x12, /*!< Record */ + CEC_DECK_INFO_PLAY_REVERSE = 0x13, /*!< Play Reverse */ + CEC_DECK_INFO_STILL = 0x14, /*!< Still */ + CEC_DECK_INFO_SLOW = 0x15, /*!< Slow */ + CEC_DECK_INFO_SLOW_REVERSE = 0x16, /*!< Slow Reverse */ + CEC_DECK_INFO_FAST_FORWARD = 0x17, /*!< Fast Forward */ + CEC_DECK_INFO_FAST_REVERSE = 0x18, /*!< Fast Reverse */ + CEC_DECK_INFO_NO_MEDIA = 0x19, /*!< No Media */ + CEC_DECK_INFO_STOP = 0x1A, /*!< Stop */ + CEC_DECK_INFO_WIND = 0x1B, /*!< Skip Forward / Wind */ + CEC_DECK_INFO_REWIND = 0x1C, /*!< Skip Reverse / Rewind */ + CEC_DECK_INFO_ID_SEARCH_FORWARD = 0x1D, /*!< Index Search Forward */ + CEC_DECK_INFO_ID_SEARCH_REVERSE = 0x1E, /*!< Index Search Forward */ + CEC_DECK_INFO_OTHER_STATUS = 0x1F /*!< Other Status */ +} tmdlHdmiCECDecInfo_t; + + +/*! + \enum tmdlHdmiCECDeviceType_t + \brief This enum indicates the device type +*/ +typedef enum +{ + CEC_DEVICE_TYPE_TV = 0, /*!< TV */ + CEC_DEVICE_TYPE_REC_DEVICE = 1, /*!< Recording Device */ + CEC_DEVICE_TYPE_RESERVED = 2, /*!< Reserved */ + CEC_DEVICE_TYPE_TUNER = 3, /*!< Tuner */ + CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4, /*!< PlayBack Device */ + CEC_DEVICE_TYPE_AUDIO_DEVICE = 5, /*!< Audio System */ + CEC_DEVICE_TYPE_PURE_CEC_SWITCTH = 6, /*!< Pure CEC Switch */ + CEC_DEVICE_TYPE_VIDEO_PROCESSOR = 7 /*!< Video Processor */ +} tmdlHdmiCECDeviceType_t; + +/*! + \enum tmdlHdmiCECServiceIdentMethod_t + \brief This enum indicates a Service Indentification Method +*/ +typedef enum +{ + CEC_SERVICE_DIGITAL = 0, /*!< Service identified by digital IDs */ + CEC_SERVICE_CHANNEL = 1 /*!< Service identified by channel */ +} tmdlHdmiCECServiceIdentMethod_t; + +/*! + \enum tmdlHdmiCECDigitalBroadcastSystem_t + \brief This enum indicates the Digital Broadcast System of required service +*/ +typedef enum +{ + CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_GENERIC = 0x01, /*!< ARIB generic */ + CEC_DIGITAL_BROADCAST_SYSTEM_ATSC_GENERIC = 0x02, /*!< ATSC generic */ + CEC_DIGITAL_BROADCAST_SYSTEM_DVB_GENERIC = 0x03, /*!< DVB generic */ + CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_BS = 0x08, /*!< ARIB-BS */ + CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_CS = 0x09, /*!< ARIB-CS */ + CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_T = 0x0A, /*!< ARIB-T */ + CEC_DIGITAL_BROADCAST_SYSTEM_CABLE = 0x10, /*!< Cable */ + CEC_DIGITAL_BROADCAST_SYSTEM_SATELLITE = 0x11, /*!< Satellite */ + CEC_DIGITAL_BROADCAST_SYSTEM_TERRESTRIAL = 0x12, /*!< Terrestrial */ + CEC_DIGITAL_BROADCAST_SYSTEM_DVB_C = 0x18, /*!< DVB-C */ + CEC_DIGITAL_BROADCAST_SYSTEM_DVB_S = 0x19, /*!< DVB-S */ + CEC_DIGITAL_BROADCAST_SYSTEM_DVB_S2 = 0x1A, /*!< DVB-S2 */ + CEC_DIGITAL_BROADCAST_SYSTEM_DVB_T = 0x1B /*!< DVB-T */ +} tmdlHdmiCECDigitalBroadcastSystem_t; + +/*! + \struct tmdlHdmiCECAribData_t + \brief This struct indicates the ARIB Data +*/ +typedef struct +{ + UInt16 TransportStreamID ; /*!< Tansport_stream_id of the transport stream carrying the required service */ + UInt16 ServiceID ; /*!< Service_ID of the required service */ + UInt16 OriginalNetworkID ; /*!< Original_network_ID of the network carrying the transport stream for the required service */ +} tmdlHdmiCECAribData_t ; + +/*! + \struct tmdlHdmiCECAtscData_t + \brief This struct indicates the ATSC Data +*/ +typedef struct +{ + UInt16 TransportStreamID ; /*!< Tansport_stream_id of the transport stream carrying the required service */ + UInt16 ProgramNumber ; /*!< Program Number of the required service */ + UInt16 Reserved ; /*!< Reserved */ +} tmdlHdmiCECAtscData_t ; + +/*! + \struct tmdlHdmiCECDvbData_t + \brief This struct indicates the DVB Data +*/ +typedef struct +{ + UInt16 TransportStreamID ; /*!< Tansport_stream_id of the transport stream carrying the required service */ + UInt16 ServiceID ; /*!< Service_ID of the required service */ + UInt16 OriginalNetworkID ; /*!< Original_network_ID of the network carrying the transport stream for the required service */ +} tmdlHdmiCECDvbData_t ; + +/*! + \struct tmdlHdmiCECChannelData_t + \brief This struct indicates the Channel Data +*/ +typedef struct +{ + tmdlHdmiCECChannelIdentifier_t ChannelIdentifier ; /*!< Logical or virtual channel number of a service */ + UInt16 Reserved ; /*!< Reserved */ +} tmdlHdmiCECChannelData_t ; + +/*! + \struct tmdlHdmiCECDigitalServiceIdentification_t + \brief This struct indicates the Digital Broadcast System + and the parameters to identify a specific service +*/ +typedef struct _tmdlHdmiCECDigitalServiceIdentification_t +{ + tmdlHdmiCECServiceIdentMethod_t ServiceIdentificationMethod ; /*!< See tmdlHdmiCECServiceIdentMethod_t */ + tmdlHdmiCECDigitalBroadcastSystem_t DigitalBroadcastSystem ; /*!< See tmdlHdmiCECDigitalBroadcastSystem_t */ + void *pServiceIdentification ; /*!< tmdlHdmiCECAribData_t or tmdlHdmiCECAtscData_t or tmdlHdmiCECDvbData_t or tmdlHdmiCECChannelData_t */ +}tmdlHdmiCECDigitalServiceIdentification_t, *ptmdlHdmiCECDigitalServiceIdentification_t; + +/*! + \enum tmdlHdmiCECDisplayControl_t + \brief This enum indicates the display mode for an on screen display message +*/ +typedef enum +{ + CEC_DISPLAY_CONTROL_DEFAULT_TIME = 0 , /*!< Display for default time */ + CEC_DISPLAY_CONTROL_UNTIL_CLEARED = 64 , /*!< Display until cleared */ + CEC_DISPLAY_CONTROL_CLEAR_PREVIOUS_MESSAGE = 128, /*!< Clear previous message */ + CEC_DISPLAY_CONTROL_RESERVED = 192 /*!< Clear previous message */ +} tmdlHdmiCECDisplayControl_t; + +/*! + \struct tmdlHdmiCECDuration_t + \brief This struct indicates a duration in BCD format +*/ +typedef struct +{ + UInt8 Hours ; /*!< Duration hours in bcd format between 0 and 99 */ + UInt8 Minute ; /*!< Duration minute in bcd format between 0 and 59 */ +} tmdlHdmiCECDuration_t ; + +/*! + \brief This typedef indicates physical adress of device that is to be used as the source of a recording +*/ +typedef UInt16 tmdlHdmiCECExternalPhysicalAddress_t ; + +/*! + \brief This typedef indicates external plug number (1 to 255 )on the recording device +*/ +typedef UInt8 tmdlHdmiCECExternalPlug_t; + +/*! + \enum tmdlHdmiCECExternalSourceSpecifier_t + \brief This enum indicates External source specifier +*/ +typedef enum +{ + CEC_EXTERNAL_PLUG = 4 , /*!< Display for default time */ + CEC_EXTERNAL_PHYSICAL_ADDRESS = 5 /*!< Display until cleared */ +} tmdlHdmiCECExternalSourceSpecifier_t; + +/*! + \brief This typedef indicates External Source is specified bey exeternal plug number on the recording device + or by the External physical Adress of the required source +*/ +typedef UInt8 ExternalSourceSpecifier; + + +/*! + \enum tmdlHdmiCECFeatureOpcode_t + \brief This enum defines command to be performed +*/ +typedef enum +{ + CEC_OPCODE_FEATURE_ABORT = 0x00, /*!< */ + CEC_OPCODE_IMAGE_VIEW_ON = 0x04, /*!< */ + CEC_OPCODE_TUNER_STEP_INCREMENT = 0x05, /*!< */ + CEC_OPCODE_TUNER_STEP_DECREMENT = 0x06, /*!< */ + CEC_OPCODE_TUNER_DEVICE_STATUS = 0x07, /*!< */ + CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS = 0x08, /*!< */ + CEC_OPCODE_RECORD_ON = 0x09, /*!< */ + CEC_OPCODE_RECORD_STATUS = 0x0A, /*!< */ + CEC_OPCODE_RECORD_OFF = 0x0B, /*!< */ + CEC_OPCODE_TEXT_VIEW_ON = 0x0D, /*!< */ + CEC_OPCODE_RECORD_TV_SCREEN = 0x0F, /*!< */ + CEC_OPCODE_GIVE_DECK_STATUS = 0x1A, /*!< */ + CEC_OPCODE_DECK_STATUS = 0x1B, /*!< */ + CEC_OPCODE_SET_MENU_LANGUAGE = 0x32, /*!< */ + CEC_OPCODE_CLEAR_ANALOGUE_TIMER = 0x33, /*!< */ + CEC_OPCODE_SET_ANALOGUE_TIMER = 0x34, /*!< */ + CEC_OPCODE_TIMER_STATUS = 0x35, /*!< */ + CEC_OPCODE_STANDBY = 0x36, /*!< */ + CEC_OPCODE_PLAY = 0x41, /*!< */ + CEC_OPCODE_DESCK_CONTROL = 0x42, /*!< */ + CEC_OPCODE_TIMER_CLEARED_STATUS = 0x43, /*!< */ + CEC_OPCODE_USER_CONTROL_PRESSED = 0x44, /*!< */ + CEC_OPCODE_USER_CONTROL_RELEASED = 0x45, /*!< */ + CEC_OPCODE_GIVE_OSD_NAME = 0x46, /*!< */ + CEC_OPCODE_SET_OSD_NAME = 0x47, /*!< */ + CEC_OPCODE_SET_OSD_STRING = 0x64, /*!< */ + CEC_OPCODE_SET_TIMER_PROGRAM_TITLE = 0x67, /*!< */ + CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST = 0x70, /*!< */ + CEC_OPCODE_GIVE_AUDIO_STATUS = 0x71, /*!< */ + CEC_OPCODE_SET_SYSTEM_AUDIO_MODE = 0x72, /*!< */ + CEC_OPCODE_REPORT_AUDIO_STATUS = 0x7A, /*!< */ + CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS = 0x7D, /*!< */ + CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS = 0x7E, /*!< */ + CEC_OPCODE_ROUTING_CHANGE = 0x80, /*!< */ + CEC_OPCODE_ROUTING_INFORMATION = 0x81, /*!< */ + CEC_OPCODE_ACTIVE_SOURCE = 0x82, /*!< */ + CEC_OPCODE_GIVE_PHYSICAL_ADDRESS = 0x83, /*!< */ + CEC_OPCODE_REPORT_PHYSICAL_ADDRESS = 0x84, /*!< */ + CEC_OPCODE_REQUEST_ACTIVE_SOURCE = 0x85, /*!< */ + CEC_OPCODE_SET_STREAM_PATH = 0x86, /*!< */ + CEC_OPCODE_DEVICE_VENDOR_ID = 0x87, /*!< */ + CEC_OPCODE_VENDOR_COMMAND = 0x89, /*!< */ + CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN = 0x8A, /*!< */ + CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP = 0x8B, /*!< */ + CEC_OPCODE_GIVE_DEVICE_VENDOR_ID = 0x8C, /*!< */ + CEC_OPCODE_MENU_REQUEST = 0x8D, /*!< */ + CEC_OPCODE_MENU_STATUS = 0x8E, /*!< */ + CEC_OPCODE_GIVE_DEVICE_POWER_STATUS = 0x8F, /*!< */ + CEC_OPCODE_REPORT_POWER_STATUS = 0x90, /*!< */ + CEC_OPCODE_GET_MENU_LANGUAGE = 0x91, /*!< */ + CEC_OPCODE_SET_ANALOGUE_SERVICE = 0x92, /*!< */ + CEC_OPCODE_SET_DIGITAL_SERVICE = 0x93, /*!< */ + CEC_OPCODE_SET_DIGITAL_TIMER = 0x97, /*!< */ + CEC_OPCODE_CLEAR_DIGITAL_TIMER = 0x99, /*!< */ + CEC_OPCODE_SET_AUDIO_RATE = 0x9A, /*!< */ + CEC_OPCODE_INACTIVE_SOURCE = 0x9D, /*!< */ + CEC_OPCODE_CEC_VERSION = 0x9E, /*!< */ + CEC_OPCODE_GET_CEC_VERSION = 0x9F, /*!< */ + CEC_OPCODE_VENDOR_COMMAND_WITH_ID = 0xA0, /*!< */ + CEC_OPCODE_CLEAR_EXTERNAL_TIMER = 0xA1, /*!< */ + CEC_OPCODE_SET_EXTERNAL_TIMER = 0xA2, /*!< */ + CEC_OPCODE_REPORT_SHORT_AUDIO_DESCRIPTOR = 0xA3, /*!< */ + CEC_OPCODE_REQUEST_SHORT_AUDIO_DESCRIPTOR = 0xA4, /*!< */ + CEC_OPCODE_INITATE_ARC = 0xC0, /*!< */ + CEC_OPCODE_REPORT_ARC_INITIATED = 0xC1, /*!< */ + CEC_OPCODE_REPORT_ARC_TERMINATED = 0xC2, /*!< */ + CEC_OPCODE_REPORT_ARC_INITIATION = 0xC3, /*!< */ + CEC_OPCODE_REPORT_ARC_TERMINATION = 0xC4, /*!< */ + CEC_OPCODE_TERMINATE_ARC = 0xC5, /*!< */ + CEC_OPCODE_ABORT_MESSAGE = 0xFF /*!< This message is reserved for testing*/ +} tmdlHdmiCECFeatureOpcode_t; + + +/*! + \enum tmdlHdmiCECMenuRequestType_t + \brief This enum specifies wether to activate or desactivate a devices menu or + simply query its current menu status +*/ +typedef enum +{ + CEC_MENU_TYPE_ACTIVATE = 0 , /*!< Activate */ + CEC_MENU_TYPE_DEACTIVATE = 1 , /*!< Deactivate */ + CEC_MENU_TYPE_QUERY = 2 /*!< Query */ +} tmdlHdmiCECMenuRequestType_t; + +/*! + \enum tmdlHdmiCECMenuState_t + \brief This enum pecifies state of the device menu +*/ +typedef enum +{ + CEC_MENU_STATE_ACTIVATE = 0 , /*!< Activate */ + CEC_MENU_STATE_DEACTIVATE = 1 /*!< Deactivate */ +} tmdlHdmiCECMenuState_t; + +/*! + \enum tmdlHdmiCECPlayMode_t + \brief This enum indicates in which mode to play media +*/ +typedef enum +{ + CEC_MODE_PLAY_FORWARD = 0x24 , + CEC_MODE_PLAY_REVERSE = 0x20 , + CEC_MODE_FAST_FORWARD_MIN_SPEED = 0x05 , + CEC_MODE_FAST_FORWARD_MEDIUM_SPEED = 0x06 , + CEC_MODE_FAST_FORWARD_MAX_SPEED = 0x07 , + CEC_MODE_FAST_REVERSE_MIN_SPEED = 0x09 , + CEC_MODE_FAST_REVERSE_MEDIUM_SPEED = 0x0A , + CEC_MODE_FAST_REVERSE_MAX_SPEED = 0x0B , + CEC_MODE_SLOW_FORWARD_MIN_SPEED = 0x15 , + CEC_MODE_SLOW_FORWARD_MEDIUM_SPEED = 0x16 , + CEC_MODE_SLOW_FORWARD_MAX_SPEED = 0x17 , + CEC_MODE_SLOW_REVERSE_MIN_SPEED = 0x19 , + CEC_MODE_SLOW_REVERSE_MEDIUM_SPEED = 0x1A , + CEC_MODE_SLOW_REVERSE_MAX_SPEED = 0x1B +} tmdlHdmiCECPlayMode_t; + +/*! + \enum tmdlHdmiCECPowerStatus_t + \brief This enum indicates the current power status of a device +*/ +typedef enum +{ + CEC_POWER_STATUS_ON = 0x00 , /*!< On */ + CEC_POWER_STATUS_STANDBY = 0x01 , /*!< Standby */ + CEC_POWER_STATUS_TRANSITION_STANDBY_TO_ON = 0x02 , /*!< In Transition Standby to On */ + CEC_POWER_STATUS_TRANSITION_ON_TO_STANDBY = 0x03 /*!< In Transition On to StandBy */ +} tmdlHdmiCECPowerStatus_t; + +/*! + \enum tmdlHdmiCECRecordSourceType_t + \brief This enum allows the record source to be specified for a recording +*/ +typedef enum +{ + CEC_RECORD_SOURCE_OWN_SOURCE = 1 , /*!< Own Source */ + CEC_RECORD_SOURCE_DIGITAL_SERVICE = 2 , /*!< Digital Service */ + CEC_RECORD_SOURCE_ANALOGUE_SERVICE = 3 , /*!< Analogue Service */ + CEC_RECORD_SOURCE_EXTERNAL_PLUG = 4 , /*!< External Plug */ + CEC_RECORD_SOURCE_EXTERNAL_PHYSICAL_ADDRESS = 5 /*!< External Physical Address */ +} tmdlHdmiCECRecordSourceType_t; + +/*! + \enum tmdlHdmiCECRecordStatusInfo_t + \brief This enum indicates the status of a recording +*/ +typedef enum +{ + CEC_RECORD_STATUS_INFO_RECORDING_CURRENTLY_SELECTED_SOURCE = 1 , /*!< */ + CEC_RECORD_STATUS_INFO_RECORDING_DIGITAL_SERVICE = 2 , /*!< */ + CEC_RECORD_STATUS_INFO_RECORDING_ANALOGUE_SERVCICE = 3 , /*!< */ + CEC_RECORD_STATUS_INFO_RECORDING_EXTERNAL_INPUT = 4 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_UNABLE_TO_RECORD_DIGITAL_SERVICE = 5 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_UNABLE_TO_RECORD_ANALOGUE_SERVICE = 6 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_UNABLE_TO_SELECT_REQUIRED_SERVICE = 7 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_INVALID_EXTERNAL_PLUG_NUMBER = 9 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 10 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_CA_SYSTEM_NOT_SUPPORTED = 11 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_NO_OR_INSUFFICIENT_CA_ENTITLEMENTS = 12 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_NOT_ALLOWED_TO_COPY_SOURCE = 13 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_NO_FURTHER_COPY_ALLOWED = 14 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_NO_MEDIA = 16 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_PLAYING = 17 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_ALREADY_RECORDING = 18 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_MEDIA_PROTECTED = 19 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_NO_SOURCE_SIGNAL = 20 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_MEDIA_PROBLEM = 21 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_NOT_ENOUGH_SPACE_AVAILABLE = 22 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_REC_PARENTAL_LOCK_ON = 23 , /*!< */ + CEC_RECORD_STATUS_INFO_RECORDING_TERMINATED_NORMALLY = 26 , /*!< */ + CEC_RECORD_STATUS_INFO_RECORDING_HAS_ALREADY_TERMINATED = 27 , /*!< */ + CEC_RECORD_STATUS_INFO_NO_RECORDING_OTHER_REASON = 31 /*!< */ +} tmdlHdmiCECRecordStatusInfo_t; + + +/*! + \enum tmdlHdmiCECRecordingSequence_t + \brief This enum indicates the status of a recording +*/ +typedef enum +{ + CEC_RECORDING_SEQUENCE_ONCE_ONLY = 0 , /*!< */ + CEC_RECORDING_SEQUENCE_SYNDAY = 1 , /*!< */ + CEC_RECORDING_SEQUENCE_MONDAY = 2 , /*!< */ + CEC_RECORDING_SEQUENCE_TUESDAY = 4 , /*!< */ + CEC_RECORDING_SEQUENCE_WEDNESDAY = 8 , /*!< */ + CEC_RECORDING_SEQUENCE_THURSDAY = 16, /*!< */ + CEC_RECORDING_SEQUENCE_FRIDAY = 32, /*!< */ + CEC_RECORDING_SEQUENCE_SATURDAY = 64 /*!< */ +} tmdlHdmiCECRecordingSequence_t; + +/*! + \enum tmdlHdmiCECStatusRequest_t + \brief This enum contains the status request mode which can be report once or + on all future state changes or reporting off. +*/ +typedef enum +{ + CEC_STATUS_REQUEST_ON = 1 , /*!< Status Request ON */ + CEC_STATUS_REQUEST_OFF = 2 , /*!< Status Request OFF */ + CEC_STATUS_REQUEST_ONCE = 3 /*!< Status Request ONCE */ +} tmdlHdmiCECStatusRequest_t; + +/*! + \enum tmdlHdmiCECSystemAudioStatus_t + \brief This enum indicates if the system audio Mode is On or Off +*/ +typedef enum +{ + CEC_SYSTEM_AUDIO_STATUS_OFF = 0 , /*!< Status Request OFF */ + CEC_SYSTEM_AUDIO_STATUS_ON = 1 /*!< Status Request ON */ +} tmdlHdmiCECSystemAudioStatus_t; + +/*! + \enum tmdlHdmiCECTimerClearedStatusData_t + \brief This enum indicates status in message +*/ +typedef enum +{ + CEC_TIMER_STATUS_TIMER_NOT_CLEARED_RECORDING = 0, /*!< */ + CEC_TIMER_STATUS_TIMER_NOT_CLEARED_NO_MATCHING = 1, /*!< */ + CEC_TIMER_STATUS_TIMER_NOT_CLEARED_NO_INFO_AVAILABLE = 2, /*!< */ + CEC_TIMER_STATUS_TIMER_NOT_TIMER_CLEARED = 128 /*!< */ +} tmdlHdmiCECTimerClearedStatusData_t; + + +/*! + \enum tmdlHdmiCECTimerOverlapWarning_t + \brief This enum indicates if there is another timer block already set which + overlaps with this new recording request +*/ +typedef enum +{ + CEC_TIMER_OVERLAP_WARNING_NO_OVERLAP = 0, /*!< No Overlap */ + CEC_TIMER_OVERLAP_WARNING_TIMER_BLOCKS_OVERLAP = 1 /*!< Timer blocks overlap */ +} tmdlHdmiCECTimerOverlapWarning_t; + +/*! + \enum tmdlHdmiCECMediaInfo_t + \brief This enum indicates if removable media is present and its write protect state +*/ +typedef enum +{ + CEC_MEDIA_INFO_MEDIA_PRESENT_AND_NOT_PROTECTED = 0, /*!< Media present and not protected */ + CEC_MEDIA_INFO_MEDIA_PRESENT_BUT_PROTECTED = 1, /*!< Media present but protected */ + CEC_MEDIA_INFO_MEDIA_NOT_PRESENT = 2, /*!< Media not present */ + CEC_MEDIA_INFO_FUTURE_USE = 3 /*!< Future use */ +} tmdlHdmiCECMediaInfo_t; + + +/*! + \enum tmdlHdmiCECProgrammedIndicator_t + \brief This enum indicates a selector for [Timer Programmed Info] +*/ +typedef enum +{ + CEC_PROGRAM_INDICATOR_NOT_PROGRAMMED = 0, /*!< */ + CEC_PROGRAM_INDICATOR_PROGRAMMED = 1 /*!< */ +} tmdlHdmiCECProgrammedIndicator_t; + +/*! + \enum tmdlHdmiCECProgrammedInfo_t + \brief This enum indicates any non-fatal issues with the programming request +*/ +typedef enum +{ + CEC_PROGRAM_INFO_ENOUGHT_SPACE_AVAILABLE_FOR_RECORDING = 8, /*!< */ + CEC_PROGRAM_INFO_NOT_ENOUGHT_SPACE_AVAILABLE_FOR_RECORDING = 9, /*!< */ + CEC_PROGRAM_INFO_NO_MEDIA_INFO_AVAILABLE = 10,/*!< */ + CEC_PROGRAM_INFO_MAY_NOT_BE_ENOUGH_SPACE_AVAILABLE = 11 /*!< */ +} tmdlHdmiCECProgrammedInfo_t; + + +/*! + \enum tmdlHdmiCECNotProgrammedErrorInfo_t + \brief This enum indicates reason for programming failure +*/ +typedef enum +{ + CEC_PROGRAM_ERROR_INFO_FUTURE_USE = 0, /*!< */ + CEC_PROGRAM_ERROR_INFO_NO_FREE_TIMER_AVAILABLE = 1, /*!< */ + CEC_PROGRAM_ERROR_INFO_DATE_OUT_OF_RANGE = 2, /*!< */ + CEC_PROGRAM_ERROR_INFO_RECORDING_SEQUENCE_ERROR = 3, /*!< */ + CEC_PROGRAM_ERROR_INFO_INVALID_EXTERNAL_PLUG_NUMBER = 4, /*!< */ + CEC_PROGRAM_ERROR_INFO_INVALID_EXTERNAL_PHYSICAL_ADDRESS = 5, /*!< */ + CEC_PROGRAM_ERROR_INFO_CA_SYSTEM_NOT_SUPPORTED = 6, /*!< */ + CEC_PROGRAM_ERROR_INFO_NO_OR_INSUFFICIENT_CA_ENTITLMENTS = 7, /*!< */ + CEC_PROGRAM_ERROR_INFO_DOES_NOT_SUPPORT_RESOLUTION = 8, /*!< Tuner or recorder does not support HD */ + CEC_PROGRAM_ERROR_INFO_PARENTAL_LOCK_ON = 9, /*!< */ + CEC_PROGRAM_ERROR_INFO_CLOCK_FAILURE = 10, /*!< */ + CEC_PROGRAM_ERROR_INFO_DUPLICATE_ALREADY_PROGRAMMED = 14 /*!< A timer block with identical details has already been programmed*/ +} tmdlHdmiCECNotProgrammedErrorInfo_t; + +/*! + \struct tmdlHdmiCECTimerProgrammedInfo_t + \brief This struct +*/ +typedef struct +{ + tmdlHdmiCECProgrammedIndicator_t SelectProgramInfo ; /*!< tmdlHdmiCECProgrammedIndicator_t */ + UInt8 ProgramInfo; /*!< tmdlHdmiCECProgrammedInfo_t or tmdlHdmiCECNotProgrammedErrorInfo_t*/ + UInt16 DurationAvailable ; /*!< Optional paramter : If [Programmed Info] is "Not enough space available" */ +} tmdlHdmiCECTimerProgrammedInfo_t ; /*!< If [Not Programmed Info] is "Duplicate : already programmed" */ + +/*! + \struct tmdlHdmiCECTimerStatusData_t + \brief This struct is used by recording device to respond to the initiator + of a message +*/ +typedef struct +{ + tmdlHdmiCECTimerOverlapWarning_t TimerOverlapWarning ; /*!< Indicates if there is another timer block already set which overlaps with this bew recording request*/ + tmdlHdmiCECMediaInfo_t MediaInfo ; /*!< Indicate if removable media is present and its write protect state */ + tmdlHdmiCECTimerProgrammedInfo_t TimerProgrammedInfo ; /*!< Give information about how and if the programming request has been done */ +} tmdlHdmiCECTimerStatusData_t ; + + +/*! + \enum tmdlHdmiCECRecordingFlag_t + \brief This enum indicates if the tuner is being used as a source of a recording +*/ +typedef enum +{ + CEC_RECORDING_FLAG_NOT_BEING_USED_FOR_RECORDING = 0, /*!< Not Being used for recording */ + CEC_RECORDING_FLAG_BEING_USED_FOR_RECORDING = 1 /*!< Being used for recording */ +} tmdlHdmiCECRecordingFlag_t; + +/*! + \enum tmdlHdmiCECTunerDisplayInfo_t + \brief This enum indicates if the device is currently displaying its tuner or not. + (it may for example be displaying an external source or media) +*/ +typedef enum +{ + CEC_TUNER_DISPLAY_MEDIA_DISPLAYING_DIGITAL_TUNER = 0, /*!< Displaying Digital Tuner */ + CEC_TUNER_DISPLAY_MEDIA_NOT_DISPLAYING_TUNER = 1, /*!< Not Displaying Tuner */ + CEC_TUNER_DISPLAY_MEDIA_DISPLAYING_ANALOGUE_TUNER = 2 /*!< Not Displaying Tuner */ +} tmdlHdmiCECTunerDisplayInfo_t; + +/*! + \enum tmdlHdmiCECUiBroadcastType_t + \brief This enum indicates type of broadcast +*/ +typedef enum +{ + CEC_UI_BROADCAST_TYPE_ALL_AVAILABLE = 0x00 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL_ANALOGUE_TOGGLE = 0x01 , /*!< */ + CEC_UI_BROADCAST_TYPE_ANALOGUE = 0x10 , /*!< */ + CEC_UI_BROADCAST_TYPE_ANALOGUE_TERRESTRIAL = 0x20 , /*!< */ + CEC_UI_BROADCAST_TYPE_ANALOGUE_CABLE = 0x30 , /*!< */ + CEC_UI_BROADCAST_TYPE_ANALOGUE_SATELLITE = 0x40 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL = 0x50 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL_TERRESTRIAL = 0x60 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL_CABLE = 0x70 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL_SATELLITE = 0x80 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL_COM_SATELLITE = 0x90 , /*!< */ + CEC_UI_BROADCAST_TYPE_DIGITAL_COM_SATELLITE_2 = 0x91 , /*!< */ + CEC_UI_BROADCAST_TYPE_IP = 0xA0 /*!< */ +} tmdlHdmiCECUiBroadcastType_t; + +/*! + \enum tmdlHdmiCECUiSoundPresentationControl_t + \brief This enum indicates the selected command +*/ +typedef enum +{ + CEC_UI_PRESENTATION_CONTROL_SOUND_MIX_DUAL_MONO = 0x20 , /*!< "Sound Mixing Mode (Dual Mono)" */ + CEC_UI_PRESENTATION_CONTROL_SOUND_MIX_KARAOKE = 0x30 , /*!< "Sound Mixing Mode (Karaoke)" */ + CEC_UI_PRESENTATION_CONTROL_SELECT_AUDIO_DOWNMIX = 0x80 , /*!< "Select Audio Downmix Mode" */ + CEC_UI_PRESENTATION_CONTROL_SELECT_AUDIO_REVERBERATION = 0x90 , /*!< "Select Audio Reverberation Processing Mode" */ + CEC_UI_PRESENTATION_CONTROL_SELECT_AUDIO_EQUALIZER = 0xA0 , /*!< "Select Audio Equalizer Mode" */ + CEC_UI_PRESENTATION_CONTROL_BASS_STEP_PLUS = 0xB1 , /*!< "bass step + " */ + CEC_UI_PRESENTATION_CONTROL_BASS_NEUTRAL_POSITION = 0xB2 , /*!< "bass neutral position" */ + CEC_UI_PRESENTATION_CONTROL_BASS_STEP_MINUS = 0xB3 , /*!< "bass step - " */ + CEC_UI_PRESENTATION_CONTROL_TREBLE_STEP_PLUS = 0xC1 , /*!< "Treble step + " */ + CEC_UI_PRESENTATION_CONTROL_TREBLE_NEUTRAL_POSITION = 0xC2 , /*!< "Treble neutral position" */ + CEC_UI_PRESENTATION_CONTROL_TREBLE_STEP_MINUS = 0xC3 /*!< "Treble step - " */ + +} tmdlHdmiCECUiSoundPresentationControl_t; + +/*! + \enum tmdlHdmiCECUserRemoteControlCommand_t + \brief This enum indicates the remote control button pressed +*/ +typedef enum +{ + CEC_REMOTE_BUTTON_SELECT = 0, + CEC_REMOTE_BUTTON_UP = 1, + CEC_REMOTE_BUTTON_DOWN = 2, + CEC_REMOTE_BUTTON_LEFT = 3, + CEC_REMOTE_BUTTON_RIGHT = 4, + CEC_REMOTE_BUTTON_RIGHT_UP = 5, + CEC_REMOTE_BUTTON_RIGHT_DOWN = 6, + CEC_REMOTE_BUTTON_LEFT_UP = 7, + CEC_REMOTE_BUTTON_LEFT_DOWN = 8, + CEC_REMOTE_BUTTON_ROOT_MENU = 9, + CEC_REMOTE_BUTTON_SETUP_MENU = 10, + CEC_REMOTE_BUTTON_CONTENTS_MENU = 11, + CEC_REMOTE_BUTTON_FAVORITE_MENU = 12, + CEC_REMOTE_BUTTON_EXIT = 13, + CEC_REMOTE_BUTTON_MEDIA_TOP_MENU = 16, + CEC_REMOTE_BUTTON_MEDIA_CONTEXT = 17, + CEC_REMOTE_BUTTON_NUMBER_ENTRY_MODE = 29, + CEC_REMOTE_BUTTON_NUMBER_11 = 30, + CEC_REMOTE_BUTTON_NUMBER_12 = 31, + CEC_REMOTE_BUTTON_NUMBER_0_OR_NUMBER_10 = 32, + CEC_REMOTE_BUTTON_NUMBER_1 = 33, + CEC_REMOTE_BUTTON_NUMBER_2 = 34, + CEC_REMOTE_BUTTON_NUMBER_3 = 35, + CEC_REMOTE_BUTTON_NUMBER_4 = 36, + CEC_REMOTE_BUTTON_NUMBER_5 = 37, + CEC_REMOTE_BUTTON_NUMBER_6 = 38, + CEC_REMOTE_BUTTON_NUMBER_7 = 39, + CEC_REMOTE_BUTTON_NUMBER_8 = 40, + CEC_REMOTE_BUTTON_NUMBER_9 = 41, + CEC_REMOTE_BUTTON_DOT = 42, + CEC_REMOTE_BUTTON_ENTER = 43, + CEC_REMOTE_BUTTON_CLEAR = 44, + CEC_REMOTE_BUTTON_NEXT_FAVORITE = 47, + CEC_REMOTE_BUTTON_CHANNEL_UP = 48, + CEC_REMOTE_BUTTON_CHANNEL_DOWN = 49, + CEC_REMOTE_BUTTON_PREVIOUS_CHANNEL = 50, + CEC_REMOTE_BUTTON_SOUND_SELECT = 51, + CEC_REMOTE_BUTTON_INPUT_SELECT = 52, + CEC_REMOTE_BUTTON_DISPLAY_INFORMATION = 53, + CEC_REMOTE_BUTTON_HELP = 54, + CEC_REMOTE_BUTTON_PAGE_UP = 55, + CEC_REMOTE_BUTTON_PAGE_DOWN = 56, + CEC_REMOTE_BUTTON_POWER = 64, + CEC_REMOTE_BUTTON_VOLUME_UP = 65, + CEC_REMOTE_BUTTON_VOLUME_DOWN = 66, + CEC_REMOTE_BUTTON_MUTE = 67, + CEC_REMOTE_BUTTON_PLAY = 68, + CEC_REMOTE_BUTTON_STOP = 69, + CEC_REMOTE_BUTTON_PAUSE = 70, + CEC_REMOTE_BUTTON_RECORD = 71, + CEC_REMOTE_BUTTON_REWIND = 72, + CEC_REMOTE_BUTTON_FAST_FORWARD = 73, + CEC_REMOTE_BUTTON_EJECT = 74, + CEC_REMOTE_BUTTON_FORWARD = 75, + CEC_REMOTE_BUTTON_BACKWARD = 76, + CEC_REMOTE_BUTTON_STOP_RECORD = 77, + CEC_REMOTE_BUTTON_PAUSE_RECORD = 78, + CEC_REMOTE_BUTTON_ANGLE = 80, + CEC_REMOTE_BUTTON_SUB_PICTURE = 81, + CEC_REMOTE_BUTTON_VIDEO_ON_DEMAND = 82, + CEC_REMOTE_BUTTON_ELECTRONIC_PROGRAM_GUIDE = 83, + CEC_REMOTE_BUTTON_TIMER_PROGRAMMING = 84, + CEC_REMOTE_BUTTON_INITIAL_CONFIGURATION = 85, + CEC_REMOTE_BUTTON_SELECT_BROADCAST_TYPE = 86, + CEC_REMOTE_BUTTON_SELECT_SOUND_PRESENTATION = 87, + CEC_REMOTE_BUTTON_PLAY_FUNCTION = 96, + CEC_REMOTE_BUTTON_PAUSE_PLAY_FUNCTION = 97, + CEC_REMOTE_BUTTON_RECORD_FUNCTION = 98, + CEC_REMOTE_BUTTON_PAUSE_RECORD_FUNCTION = 99, + CEC_REMOTE_BUTTON_STOP_FUNCTION = 100, + CEC_REMOTE_BUTTON_MUTE_FUNCTION = 101, + CEC_REMOTE_BUTTON_RESTORE_VOLUME_FUNCTION = 102, + CEC_REMOTE_BUTTON_TUNE_FUNCTION = 103, + CEC_REMOTE_BUTTON_SELECT_MEDIA_FUNCTION = 104, + CEC_REMOTE_BUTTON_SELECT_AV_INPUT_FUNCTION = 105, + CEC_REMOTE_BUTTON_SELECT_AUDIO_INPUT_FUNCTION = 106, + CEC_REMOTE_BUTTON_POWER_TOGGLE_FUNCTION = 107, + CEC_REMOTE_BUTTON_POWER_OFF_FUNCTION = 108, + CEC_REMOTE_BUTTON_POWER_ON_FUNCTION = 109, + CEC_REMOTE_BUTTON_F1_BLUE = 113, + CEC_REMOTE_BUTTON_F2_RED = 114, + CEC_REMOTE_BUTTON_F3_GREEN = 115, + CEC_REMOTE_BUTTON_F4_YELLOW = 116, + CEC_REMOTE_BUTTON_F5 = 117, + CEC_REMOTE_BUTTON_DATA = 118 +} tmdlHdmiCECUserRemoteControlCommand_t; + +/*! + \enum tmdlHdmiCECLogicalAddress_t + \brief This enum indicates the logical address of the a device +*/ +typedef enum +{ + CEC_LOGICAL_ADDRESS_TV = 0, /*!< TV */ + CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_1 = 1, /*!< Recording Device 1 */ + CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_2 = 2, /*!< Recording Device 1 */ + CEC_LOGICAL_ADDRESS_TUNER_1 = 3, /*!< Tuner 1 */ + CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_1 = 4, /*!< Playback Device 1 */ + CEC_LOGICAL_ADDRESS_AUDIO_SYSTEM = 5, /*!< Audio System */ + CEC_LOGICAL_ADDRESS_TUNER_2 = 6, /*!< Tuner 2 */ + CEC_LOGICAL_ADDRESS_TUNER_3 = 7, /*!< Tuner 3 */ + CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_2 = 8, /*!< Playback Device 2 */ + CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_3 = 9, /*!< Recording Device 3 */ + CEC_LOGICAL_ADDRESS_TUNER_4 = 10, /*!< Tuner 4 */ + CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_3 = 11, /*!< Playback Device 3 */ + CEC_LOGICAL_ADDRESS_RESERVED1 = 12, /*!< Reserved */ + CEC_LOGICAL_ADDRESS_RESERVED2 = 13, /*!< Reserved */ + CEC_LOGICAL_ADDRESS_SPECIFIC_USE = 14, /*!< Specific Use */ + CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST = 15 /*!< Unregistred/Broadcast */ +} tmdlHdmiCECLogicalAddress_t; + + +/*! + \enum tmdlHdmiCecEvent_t + \brief Enum listing all events that can be signalled to application + */ +typedef enum +{ + TMDL_HDMICEC_CALLBACK_MESSAGE_AVAILABLE = 0, /**< A message is available on CEC line */ + TMDL_HDMICEC_CALLBACK_STATUS = 1, /**< Status of CEC line */ +} tmdlHdmiCecEvent_t; + +/*! + \enum tmdlHdmiCecEventStatus_t + \brief Enum listing all available event status + */ +typedef enum +{ + TMDL_HDMICEC_EVENT_ENABLED, /*!< Event is enabled */ + TMDL_HDMICEC_EVENT_DISABLED /*!< Event is disabled */ +} tmdlHdmiCecEventStatus_t; + +/** + * \brief System function pointer type, to call user I2C read/write functions + * \param slaveAddr The I2C slave address + * \param firstRegister The first device register address to read or write + * \param lenData Length of data to read or write (i.e. no. of registers) + * \param pData Pointer to data to write, or to buffer to receive data + * \return The call result: + * - TM_OK: the call was successful + * - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing + * - TMBSL_ERR_HDMI_I2C_READ: failed when reading + */ +typedef struct +{ + UInt8 slaveAddr; + UInt8 firstRegister; + UInt8 lenData; + UInt8 *pData; +} tmdlHdmiCecSysArgs_t; +typedef tmErrorCode_t (*ptmdlHdmiCecSysFunc_t) (tmdlHdmiCecSysArgs_t *pSysArgs); + + +/*! + \brief Timer function pointer type, to call an application timer + \param Parameter ms: Delay in milliseconds required + */ +typedef Void (*ptmbslHdmiCecSysFuncTimer_t) (UInt16 ms); + +/*! + \brief Callback function pointer type, used to allow driver to callback + application when activity status is changing at input. + \param Event Identifier of the source event. + */ +typedef void (*ptmdlHdmiCecCallbackFunc_t) (tmdlHdmiCecEvent_t event, + UInt8 *pdata, + UInt8 size); + +/*! + \brief Enum listing all supported device versions + */ + typedef enum + { + TMDL_HDMICEC_DEVICE_UNKNOWN, /*!< HW device is unknown */ + TMDL_HDMICEC_DEVICE_TDA9950, /*!< HW device is a TDA9950 */ + TMDL_HDMICEC_DEVICE_TDA9989, /*!< HW device is a TDA9989 */ + } tmdlHdmiCecDeviceVersion_t; + + +/*! + \brief Enum listing possible CEC clock source + */ + typedef enum + { + TMDL_HDMICEC_CLOCK_XTAL, + TMDL_HDMICEC_CLOCK_FRO, + TMDL_HDMICEC_CLOCK_PCLK + } tmdlHdmiCecClockSource_t; + + +/** + * \brief Structure describing unit capabilities + */ +typedef struct +{ + tmdlHdmiCecDeviceVersion_t DeviceVersion; /*!< HW device version */ + tmdlHdmiCECVersion_t HdmiCecVersion; /*!< Supported HDMI CEC standard version */ +} tmdlHdmiCecCapabilities_t; + + +/*! + \struct tmdlHdmiCECInstanceSetup_t + \brief This struct is used to setup CEC driver by application + Application setup the device and state of the device. +*/ + +typedef struct _tmdlHdmiCecInstanceSetup_t +{ + tmdlHdmiCECLogicalAddress_t DeviceLogicalAddress; + tmdlHdmiCecClockSource_t cecClockSource; +// tmdlHdmiCECDeviceState_t DeviceState; +} tmdlHdmiCecInstanceSetup_t, *ptmdlHdmiCecInstanceSetup_t; + + +/** + * \brief The structure of a CEC Data Register Protocol +*/ +typedef struct +{ + UInt8 AddressByte; + Bool MessageTypePolling; /* Indicate if it's a poolling message "1" or a normal CEC message "0" */ + UInt8 Opcode; +}tmdlHdmiCecSaveMessage_t; + +typedef struct +{ + UInt8 FrameByteCount; + UInt8 AddressByte; + UInt8 DataBytes[15]; +}tmdlHdmiCecFrameFormat_t; + + + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMICEC_TYPES_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC.c b/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC.c new file mode 100755 index 0000000000000..859a7a72a2c9c --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC.c @@ -0,0 +1,7575 @@ +//============================================================================= +// Copyright (C) 2007 NXP N.V., All Rights Reserved. +// This source code and any compilation or derivative thereof is the proprietary +// information of NXP N.V. and is confidential in nature. Under no circumstances +// is this software to be exposed to or placed under an Open Source License of +// any type without the expressed written permission of NXP N.V. +//============================================================================= +/*! + \file tmdlHdmiCEC.c + + \version 1.0 + + \date 24/07/2007 + + \brief devlib driver component API for the CEC features. + + \section refs Reference Documents + TDA998X Driver - tmdlHdmiTx - SCS.doc + \note None. + + HISTORY : + \verbatim + Date Modified by CRPRNr TASKNr Maintenance description + -------------|-----------|-------|-------|----------------------------------- + 24/07/2007 | F.G | | | Creation. + -------------|-----------|-------|-------|----------------------------------- + \endverbatim +*/ +//========================================================================== + +/*============================================================================*/ +/* FILE CONFIGURATION */ +/*============================================================================*/ + + +/*============================================================================*/ +/* STANDARD INCLUDE FILES */ +/*============================================================================*/ + + +/*============================================================================*/ +/* PROJECT INCLUDE FILES */ +/*============================================================================*/ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#else +#include +#include +#endif +#include "tmdlHdmiCEC_IW.h" +#include "tmdlHdmiCEC_cfg.h" +#include "tmdlHdmiCEC.h" +#include "tmdlHdmiCEC_local.h" + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#define DV_DBG_PRINT printk +#else +#define DV_DBG_PRINT printf +#endif + +/*============================================================================*/ +/* TYPE DEFINITIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* PUBLIC VARIABLE DEFINITIONS */ +/*============================================================================*/ +tmdlHdmiCecUnitConfig_t UnitTable[MAX_UNITS] = { + {0,CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST,False, TMDL_HDMICEC_DEVICE_TDA9950, CEC_STATE_NOT_INITIALIZED, 0} +}; + +tmdlHdmiCecDriverConfigTable_t gtmdlHdmiCecDriverConfigTable[MAX_UNITS]; + +tmdlHdmiCecSaveMessage_t gtmdlHdmiCecDriverSaveMessage; + + +/*============================================================================*/ +/* STATIC CONSTANT DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* STATIC VARIABLE DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* STATIC FUNCTION DECLARATIONS */ +/*============================================================================*/ + + +/*============================================================================*/ +/* FUNCTIONS */ +/*============================================================================*/ + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGetSWVersion( ) + \brief Get the software version of the driver. + + \param pSWVersion Pointer to the version structure + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetSWVersion +( + tmSWVersion_t *pSWVersion +) +{ + /* check that input pointer is not NULL */ + RETIF(pSWVersion == Null, TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + /* copy SW version */ + pSWVersion->compatibilityNr = VERSION_COMPATIBILITY; + pSWVersion->majorVersionNr = VERSION_MAJOR; + pSWVersion->minorVersionNr = VERSION_MINOR; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGetNumberOfUnits( ) + \brief Get the number of available CEC devices in the system. + A unit directly represents a physical device. + + \param pUnitCount Pointer to the number of available units. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetNumberOfUnits +( + UInt32 *pUnitCount +) +{ + /* check that input pointer is not NULL */ + RETIF(pUnitCount == Null, TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + /* copy the maximum number of units */ + *pUnitCount = MAX_UNITS; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGetInstanceSetup( ) + \brief Get instance setup parameters. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure that will receive setup + parameters + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetInstanceSetup +( + tmInstance_t instance, + ptmdlHdmiCecInstanceSetup_t pSetupInfo +) +{ + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check that input pointer is not NULL */ + RETIF(pSetupInfo == Null, TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pSetupInfo->DeviceLogicalAddress = UnitTable[instance].DeviceLogicalAddress; + + + return(TM_OK); +} + +//========================= ================================================= +/*! + \fn tmErrorCode_t tmdlHdmiCecHandleInterrupt( ) + \brief Make device library handle an incoming interrupt. This function is + used by application to tell the device library that the hardware + sent an interrupt. It can also be used to poll the interrupt status + of the device if the interrupt line is not physically connected to + the CPU. + This function is synchronous. + This function is ISR friendly. + + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_FULL: the queue is full +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecHandleInterrupt +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + unsigned char I2c_ReadBuffer[19] ; /* I2C Read data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCecUnitConfig_t *pCecObject; /* Pointer to Cec Object */ + tmdlHdmiCecFrameFormat_t ReadFrame; + tmdlHdmiCecSaveMessage_t LastSendMessage; + int i; + + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + pCecObject = &UnitTable[instance]; + +#ifdef TMFL_TDA9989 + //Check if pending CEC interruption + errCode = getCecHwRegisters(pDis, E_REG_CEC_INT, I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + if ((I2c_ReadBuffer[0] & CEC_INT_MASK) == 0x00) + { + //No CEC interruption pending. + return TM_OK; + } +#endif + + errCode = getCecHwRegisters(pDis, E_REG_CDR0,I2c_ReadBuffer,19); + RETIF(errCode != TM_OK, errCode) + + /*Fill Frame structure with read data*/ + + /* Case of Receiving CECData.cnf*/ + /*Inform Success or reason of failure of CEC message sending*/ + if (I2c_ReadBuffer[1]== 0x01) + { + /* Get Infos of last message send */ + getCecLastMessage(&LastSendMessage); + + if (LastSendMessage.MessageTypePolling) + { + ReadFrame.FrameByteCount = I2c_ReadBuffer[0]; + ReadFrame.AddressByte = LastSendMessage.AddressByte; + ReadFrame.DataBytes[0]= I2c_ReadBuffer[2]; + } + else + { + ReadFrame.FrameByteCount = I2c_ReadBuffer[0]+1; + ReadFrame.AddressByte = LastSendMessage.AddressByte; + ReadFrame.DataBytes[0]= I2c_ReadBuffer[2]; + ReadFrame.DataBytes[1]= LastSendMessage.Opcode; + } + + pCecObject->MessageCallback(TMDL_HDMICEC_CALLBACK_STATUS + , (Void *) &ReadFrame, ReadFrame.FrameByteCount); + } + + /* Case of Receiving CECData.ind*/ + /*Give receive data from CEC bus*/ + if (I2c_ReadBuffer[1]== 0x81) + { + ReadFrame.FrameByteCount = I2c_ReadBuffer[0]; + ReadFrame.AddressByte = I2c_ReadBuffer[2]; + for (i=0; i<15; i++) + { + ReadFrame.DataBytes[i] = I2c_ReadBuffer[i+3]; + } + + pCecObject->MessageCallback(TMDL_HDMICEC_CALLBACK_MESSAGE_AVAILABLE + , (Void *) &ReadFrame, ReadFrame.FrameByteCount); + } + + return(TM_OK); + +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecOpen( ) + \brief Open unit 0 of CEC and provides the instance number to + the caller. Note that one unit of CEC represents one physical + CEC device and that only one instance per unit can be opened. + + \param pInstance Pointer to the variable that will receive the instance + identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMICEC_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMICEC_INVALID_STATE: the state is invalid for + the function +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecOpen +( + tmInstance_t *pInstance +) +{ + /* directly call OpenM function for unit 0 and return the result */ + return(tmdlHdmiCecOpenM(pInstance, (tmUnitSelect_t)0)); +} + + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecOpenM( ) + \brief Open a specific unit of CEC driver and provides the instance + number to the caller. Note that one unit of CEC represents one + physical CEC device and that only one instance per unit can be + opened. This function switches driver's state machine to + "initialized" state. + + \param pInstance Pointer to the structure that will receive the instance + identifier. + \param unit Unit number to be opened. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMICEC_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMICEC_INVALID_STATE: the state is invalid for + the function + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecOpenM +( + tmInstance_t *pInstance, + tmUnitSelect_t unit +) +{ + + /* check if unit number is in range */ + RETIF((unit < 0) || (unit >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER) + + /* check if Instance pointer is Null */ + RETIF(pInstance == Null, TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + /* check if unit is already instanciated */ + RETIF(UnitTable[unit].opened == True, TMDL_ERR_DLHDMICEC_RESOURCE_OWNED) + + /* Ckeck the state */ + RETIF(UnitTable[unit].state != CEC_STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + /* instanciate unit and return corresponding instance number */ + /* Since HW unit are only instanciable once, instance = unit */ + UnitTable[unit].opened = True; + UnitTable[unit].MessageCallback = Null; + /* Give a logical Address to Device */ + UnitTable[unit].DeviceLogicalAddress = CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + + /* Recover the configuration of the device library */ + RETIF(tmdlHdmiCecCfgGetConfig(unit, >mdlHdmiCecDriverConfigTable[unit])!= TM_OK, TMDL_ERR_DLHDMICEC_INIT_FAILED) + + *pInstance = (tmInstance_t)unit; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecClose( ) + \brief Close an instance of CEC driver. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClose +( + tmInstance_t instance +) +{ + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* close instance */ + UnitTable[instance].opened = False; + UnitTable[instance].state = CEC_STATE_NOT_INITIALIZED; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecInstanceConfig( ) + \brief Set the configuration of instance attributes. This function is + required by DVP architecture rules but actually does nothing in this + driver + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecInstanceConfig +( + tmInstance_t instance +) +{ + if (instance); + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecInstanceSetup( ) + \brief Setup the instance with its configuration parameters. This function + allows basic instance configuration for CEC Stack Processor. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure containing all setup parameters + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecInstanceSetup +( + tmInstance_t instance, + tmdlHdmiCecInstanceSetup_t *pSetupInfo +) +{ + tmErrorCode_t errCode; + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ +#ifdef TMFL_TDA9989 + unsigned char I2c_ReadBuffer[1]; +#endif + + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check that input pointer is not NULL */ + RETIF(pSetupInfo == Null, TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* Ckeck the state */ + RETIF(UnitTable[instance].state != CEC_STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + /* Wait for 250 ms */ + RETIF( (errCode = tmdlHdmiTxIWWait(500) ) != TM_OK, errCode) + +#ifdef TMFL_TDA9989 + /* Enable CEC Stack Processor */ + errCode = getCecHwRegisters(pDis, E_REG_CDR0,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + errCode = getCecHwRegisters(pDis, E_REG_ENAMODS,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + I2c_ReadBuffer[0] |= DEFAULT_ENAMODS; + + errCode = setCecHwRegister(pDis, E_REG_ENAMODS, I2c_ReadBuffer[0]); + if (errCode != TM_OK) + { + //TODO WA still needed? + errCode = setCecHwRegister(pDis, E_REG_ENAMODS, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + } + + RETIF( (errCode = tmdlHdmiTxIWWait(TDA9950_RESET_DELAY_MS) ) != TM_OK, errCode) + + /* Select CEC clock source and divider value */ + + if (pSetupInfo->cecClockSource == TMDL_HDMICEC_CLOCK_XTAL) + { + errCode = getCecHwRegisters(pDis, E_REG_CEC_CLK,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + I2c_ReadBuffer[0] &= CEC_CLK_SEL; + errCode = setCecHwRegister(pDis, E_REG_CEC_CLK, I2c_ReadBuffer[0]); + } + + RETIF( (errCode = tmdlHdmiTxIWWait(TDA9950_RESET_DELAY_MS) ) != TM_OK, errCode) + + //TODO WA to avoid spurious interrupts + errCode = getCecHwRegisters(pDis, E_REG_CDR0,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) +#endif + + + /* Reset CEC Stack Processor */ + errCode = setCecHwRegister(pDis, E_REG_CCR, 0x80); + RETIF(errCode != TM_OK, errCode) + + + /* Wait for 250 ms */ + RETIF( (errCode = tmdlHdmiTxIWWait(TDA9950_RESET_DELAY_MS) ) != TM_OK, errCode) + + /* Configure Stack Processor (Retry = 5)*/ + errCode = setCecHwRegister(pDis, E_REG_CCONR, 0x05); + RETIF(errCode != TM_OK, errCode) + + + UnitTable[instance].DeviceLogicalAddress = pSetupInfo->DeviceLogicalAddress; + + + /* CEC Control register */ + errCode = setCecHwRegisterMsbLsb(pDis, E_REG_ACKH, 0x1 << (UnitTable[instance].DeviceLogicalAddress)); + RETIF(errCode != TM_OK, errCode) + + + /* CEC Stack Processor enable*/ + errCode = setCecHwRegister(pDis, E_REG_CCR, 0x40); + RETIF(errCode != TM_OK, errCode) + + + /* switch instance to its new state */ + UnitTable[instance].state = CEC_STATE_CONFIGURED; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRegisterCallback( ) + \brief Register event callbacks. Three types of callbacks can be + registered : input activity related callback, data related + callback (infoframes, packets, etc.) and general information + callback. A null pointer means that no callback are registered. + + \param instance Instance identifier. + \param MessageCallback Pointer to the callback function that will + handle message related events. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_INVALID_STATE: the state is invalid for + the function + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRegisterCallbacks +( + tmInstance_t instance, + ptmdlHdmiCecCallbackFunc_t MessageCallback +) +{ + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + /* store callback pointers */ + UnitTable[instance].MessageCallback = MessageCallback; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetLogicalAddress( ) + \brief Set Device Logical Address + + \param instance Instance identifier. + \param LogicalAddress Logical address value. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetLogicalAddress +( + tmInstance_t instance, + tmdlHdmiCECLogicalAddress_t LogicalAddress +) +{ + tmErrorCode_t errCode; + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* Ckeck the state */ + RETIF(UnitTable[instance].state != CEC_STATE_CONFIGURED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + UnitTable[instance].DeviceLogicalAddress = LogicalAddress; + + errCode = setCecHwRegisterMsbLsb(pDis, E_REG_ACKH, 0x1 << (UnitTable[instance].DeviceLogicalAddress)); + RETIF(errCode != TM_OK, errCode) + + return(TM_OK); +} + + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetRetry( ) + \brief Change the number of retransmission + + \param instance Instance identifier. + \param NbRetry Number of retry. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetRetry +( + tmInstance_t instance, + UInt8 NbRetry +) +{ + tmErrorCode_t errCode; + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* Ckeck the state */ + RETIF(UnitTable[instance].state != CEC_STATE_CONFIGURED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + /* Configure Retry register */ + errCode = setCecHwRegister(pDis, E_REG_CCONR, NbRetry); + RETIF(errCode != TM_OK, errCode) + + return(TM_OK); +} + + +//========================================================================== +/*! + \fn tmErrorCode_t getCecLastMessage( ) + \brief Return the Addresses and the Opcode of the last CEC + transmitted message + + \param pSaveMessage Pointer to the CEC Save Message + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t getCecLastMessage +( + tmdlHdmiCecSaveMessage_t *pSaveMessage +) +{ + /* copy Last CEC message datas */ + pSaveMessage->AddressByte = gtmdlHdmiCecDriverSaveMessage.AddressByte; + pSaveMessage->MessageTypePolling = gtmdlHdmiCecDriverSaveMessage.MessageTypePolling; + pSaveMessage->Opcode = gtmdlHdmiCecDriverSaveMessage.Opcode; + + return(TM_OK); +} + + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecImageViewOn( ) + \brief This message sent by a source device to the TV whenever it enters + the active state + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receivers. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecImageViewOn +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C Write data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + //RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Image View On command */ + + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_IMAGE_VIEW_ON ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecInactiveSource( ) + \brief This message is used by the currently active source to inform the + TV that it has no video to be presented to the user, or is going + into standby as the result of a lcoal user command on the device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress, \n + Address of message receiver. \n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Physical Address of the device. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecInactiveSource +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + //======To do : make a prepare message function with parameter + /* Inactive source command */ + I2c_Buffer[0] = 0x06; + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_INACTIVE_SOURCE ; /* Inactive Source*/ + I2c_Buffer[4] = (unsigned char)(PhysicalAddress >> 8); /* MsByte of Physical Address */ + I2c_Buffer[5] = (unsigned char)PhysicalAddress; /* LsByte of Physical Address */ + + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecActiveSource() + \brief This message is used by a new source to indicate that it has started + to transmit a stream OR used in reponse to a + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Physical address of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecActiveSource +( + tmInstance_t Instance, + UInt16 PhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Active Source command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_ACTIVE_SOURCE ; /* Active source */ + I2c_Buffer[4] = (unsigned char)(PhysicalAddress >> 8); /* MsByte of Physical Address */ + I2c_Buffer[5] = (unsigned char)PhysicalAddress; /* LsByte of Physical Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecVersion() + \brief This message is used to indicate the supported CEC version in response + to a + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress\n + Address of message receiver. \n + + \param tmdlHdmiCECVersion_t CECVersion \n + Supported CEC Version.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVersion +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECVersion_t CECVersion +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* CEC Version command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_CEC_VERSION ; /* CECVersion*/ + I2c_Buffer[4] = CECVersion; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecClearAnalogueTimer( ) + \brief This message is used to clear an Analogue timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearAnalogueTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[15] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Clear Analogue Timer command */ + I2c_Buffer[0] = 0x0f; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_CLEAR_ANALOGUE_TIMER ; + I2c_Buffer[4] = DayOfMonth; /*Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /*Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /*Start Time*/ + I2c_Buffer[7] = (UInt8)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /*Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /*Duration minute*/ + I2c_Buffer[10] = RecordingSequence; /*Recording Sequence*/ + I2c_Buffer[11] = AnalogueBroadcastType; /*Analogue Broadcast Type*/ + I2c_Buffer[12] = (unsigned char)(AnalogueFrequency >> 8); /*Analogue Frequency*/ + I2c_Buffer[13] = (unsigned char)AnalogueFrequency; + I2c_Buffer[14] = BroadcastSystem; /*BroadcastSystem*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,15); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecClearDigitalTimer( ) + \brief This message is used to clear a digital timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearDigitalTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[18] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCECAribData_t *pARIB_Pointer; + tmdlHdmiCECAtscData_t *pATSC_Pointer; + tmdlHdmiCECDvbData_t *pDVB_Pointer; + + unsigned char Regval; /* Local variable*/ + + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + + //======To do : make a prepare message function with parameter + /* Clear Digital Timer command */ + I2c_Buffer[0] = 0x12; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_CLEAR_DIGITAL_TIMER ; + I2c_Buffer[4] = DayOfMonth; /*Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /*Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /*Start Time*/ + I2c_Buffer[7] = (UInt8)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /*Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /*Durantion Minute*/ + I2c_Buffer[10] = RecordingSequence; /*Recording Sequence*/ + + /* Digital service Identification*/ + /*Merge Service Method and Digital Broadcast System in the same Byte*/ + Regval = (unsigned char)(pServiceIdentification->ServiceIdentificationMethod & 0x01); /*bit 7 is Service Method*/ + Regval = Regval << 7; + Regval |= (unsigned char)(pServiceIdentification->DigitalBroadcastSystem & 0x7F); /*bits 6 to 0 are Digital Broadcast*/ + I2c_Buffer[11] = Regval; + + + /*Case of a ARIB Generic*/ + if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_GENERIC) + { + pARIB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[12] = (unsigned char)(pARIB_Pointer->TransportStreamID >> 8); + I2c_Buffer[13] = (unsigned char)pARIB_Pointer->TransportStreamID; + I2c_Buffer[14] = (unsigned char)(pARIB_Pointer->ServiceID >> 8); + I2c_Buffer[15] = (unsigned char)pARIB_Pointer->ServiceID; + I2c_Buffer[16] = (unsigned char)(pARIB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[17] = (unsigned char)pARIB_Pointer->OriginalNetworkID; + + } + /*Case of a ATSC Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ATSC_GENERIC) + { + pATSC_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[12] = (unsigned char)(pATSC_Pointer->TransportStreamID >> 8); + I2c_Buffer[13] = (unsigned char)pATSC_Pointer->TransportStreamID; + I2c_Buffer[14] = (unsigned char)(pATSC_Pointer->ProgramNumber >> 8); + I2c_Buffer[15] = (unsigned char)pATSC_Pointer->ProgramNumber; + I2c_Buffer[16] = (unsigned char)(pATSC_Pointer->Reserved >> 8); + I2c_Buffer[17] = (unsigned char)pATSC_Pointer->Reserved; + } + /*Case of a DVB Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_DVB_GENERIC) + { + pDVB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[12] = (unsigned char)(pDVB_Pointer->TransportStreamID >> 8); + I2c_Buffer[13] = (unsigned char)pDVB_Pointer->TransportStreamID; + I2c_Buffer[14] = (unsigned char)(pDVB_Pointer->ServiceID >> 8); + I2c_Buffer[15] = (unsigned char)pDVB_Pointer->ServiceID; + I2c_Buffer[16] = (unsigned char)(pDVB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[17] = (unsigned char)pDVB_Pointer->OriginalNetworkID; + } + /*other cases, Buffer are empty*/ + else + { + I2c_Buffer[12] = 0xFF; + I2c_Buffer[13] = 0xFF; + I2c_Buffer[14] = 0xFF; + I2c_Buffer[15] = 0xFF; + I2c_Buffer[16] = 0xFF; + I2c_Buffer[17] = 0xFF; + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,18); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecClearExternalTimerWithExternalPlug( ) + \brief This message is used to clear a digital timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPlug_t ExternalPlug \n + indicates external plug number (1 to 255 )on the recording device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearExternalTimerWithExternalPlug +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPlug_t ExternalPlug +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[13] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + // RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Clear External Timer with External Plug Command*/ + I2c_Buffer[0] = 0x0D; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_CLEAR_EXTERNAL_TIMER ; + I2c_Buffer[4] = DayOfMonth; /*Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /*Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /*Start Time*/ + I2c_Buffer[7] = (unsigned char)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /*Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /*Duration minute*/ + I2c_Buffer[10] = RecordingSequence; /*Recording Sequence*/ + I2c_Buffer[11] = CEC_EXTERNAL_PLUG; /*External Source Specifier = External Plug */ + I2c_Buffer[12] = ExternalPlug; /*External Plug*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,13); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecClearExternalTimerWithPhysicalAddress( ) + \brief This message is used to clear a digital timer block of a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Defines the path between the TV an a device-thus giving it a physical + address within the cluster.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecClearExternalTimerWithPhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[14] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Clear External Timer with Physical Address Command */ + I2c_Buffer[0] = 0x0E; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_CLEAR_EXTERNAL_TIMER ; /*Clear External Timer*/ + I2c_Buffer[4] = DayOfMonth; /*Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /*Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /*Start Time*/ + I2c_Buffer[7] = (unsigned char)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /*Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /*Duration Minute*/ + I2c_Buffer[10] = RecordingSequence; /*Recording Sequence*/ + I2c_Buffer[11] = CEC_EXTERNAL_PHYSICAL_ADDRESS; /*External Source Specifier = External Address*/ + I2c_Buffer[12] = (unsigned char)(ExternalPhysicalAddress >> 8); /*External Address*/ + I2c_Buffer[13] = (unsigned char)ExternalPhysicalAddress; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,14); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTextViewOn( ) + \brief This message as , but should also remove any text, + menus and PIP windows from the TV's display + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTextViewOn +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to Instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if Instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Text View On command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TEXT_VIEW_ON ; /* Text View On */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTimerClearedStatus( ) + \brief This message is used to give the status of a , + or message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECTimerClearedStatusData_t TimerClearedStatusData \n + Indicates if the timer was cleared successfully. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTimerClearedStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECTimerClearedStatusData_t TimerClearedStatusData +) +{ + + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Timer Clear Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TIMER_CLEARED_STATUS; /* System Audio Status*/ + I2c_Buffer[4] = TimerClearedStatusData; /* Timer Cleared Status*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTimerStatus( ) + \brief This message is used to send timer status to the initiator of a + message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECTimerStatusData_t *pTimerStatusData \n + Pointer on the Timer status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTimerStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECTimerStatusData_t *pTimerStatusData +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[7] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCECTimerProgrammedInfo_t *pTimerProgInfo; + unsigned char Regval; + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Timer Status command */ + I2c_Buffer[0] = 0x07; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TIMER_CLEARED_STATUS; /* System Audio Status*/ + /* First Byte Building */ + Regval = ((unsigned char)(pTimerStatusData->TimerOverlapWarning)& 0x01) << 7 ; // bit 7 for Timer Overlap Warning + Regval |= ((unsigned char)(pTimerStatusData->MediaInfo)& 0x03) << 5; // bit 6 to 5 for Media Info + + pTimerProgInfo = &(pTimerStatusData->TimerProgrammedInfo); + Regval |= ((unsigned char)(pTimerProgInfo->SelectProgramInfo)& 0x01)<< 4; // bit 4 for Timer Programed Indicator + Regval |= (unsigned char)(pTimerProgInfo->ProgramInfo)& 0x0F; // bit 3 to 0 for Program Information + I2c_Buffer[4] = Regval; + + /* 2 Duration Available Bytes Building */ + /* Duration Available is only filled in the the both following conditions*/ + if((pTimerProgInfo->SelectProgramInfo == CEC_PROGRAM_INDICATOR_NOT_PROGRAMMED)&&(pTimerProgInfo->ProgramInfo == CEC_PROGRAM_ERROR_INFO_DUPLICATE_ALREADY_PROGRAMMED)) + { + I2c_Buffer[5] = (unsigned char)(pTimerProgInfo->DurationAvailable >> 8); + I2c_Buffer[6] = (unsigned char)pTimerProgInfo->DurationAvailable; + } + else if((pTimerProgInfo->SelectProgramInfo == CEC_PROGRAM_INDICATOR_PROGRAMMED)&&(pTimerProgInfo->ProgramInfo == CEC_PROGRAM_INFO_NOT_ENOUGHT_SPACE_AVAILABLE_FOR_RECORDING)) + { + I2c_Buffer[5] = (unsigned char)(pTimerProgInfo->DurationAvailable >> 8); + I2c_Buffer[6] = (unsigned char)pTimerProgInfo->DurationAvailable; + } + /*Else, 2 bytes of Duration Available are filled with 0xFF*/ + else + { + I2c_Buffer[5] = 0xFF; + I2c_Buffer[6] = 0xFF; + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTunerDeviceStatusAnalogue( ) + \brief This message is used by a tuner device to provide its status to the + initiator of the message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECRecordingFlag_t RecordingFlag \n + Indicates if the tuner is being used as a source of a recording. \n + + \param tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo \n + Indicates if the the device is currently deplaying its tuner or not. \n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerDeviceStatusAnalogue +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECRecordingFlag_t RecordingFlag, + tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem + ) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[9] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + unsigned char Regval; /*Local Variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Select Aanalogue Service command */ + I2c_Buffer[0] = 0x09; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TUNER_DEVICE_STATUS ; /* Tuner Device Status*/ + /* Build First Byte*/ + Regval = ((unsigned char)RecordingFlag & 0X01)<< 7; /*bit 7 is Recording Flag */ + Regval |= (unsigned char)TunerDisplayInfo & 0X7F; /*bit 6 to 0 are Tuner display Info*/ + I2c_Buffer[4] = Regval; + + I2c_Buffer[5] = AnalogueBroadcastType; /*Analogue Broadcast System type*/ + I2c_Buffer[6] = (unsigned char)(AnalogueFrequency >> 8); /*Analogue Frequency*/ + I2c_Buffer[7] = (unsigned char)AnalogueFrequency; + I2c_Buffer[8] = BroadcastSystem; /*Broadcast System*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,9); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTunerDeviceStatusDigital( ) + \brief This message is used by a tuner device to provide its status to the + initiator of the message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECRecordingFlag_t RecordingFlag \n + Indicates if the tuner is being used as a source of a recording. \n + + \param tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo \n + Indicates if the the device is currently deplaying its tuner or not. \n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerDeviceStatusDigital +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECRecordingFlag_t RecordingFlag, + tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo, + ptmdlHdmiCECDigitalServiceIdentification_t pServiceIdentification +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[12] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCECAribData_t *pARIB_Pointer; + tmdlHdmiCECAtscData_t *pATSC_Pointer; + tmdlHdmiCECDvbData_t *pDVB_Pointer; + + unsigned char Regval; /* Local variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record On Digital Service command */ + I2c_Buffer[0] = 0x0C; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TUNER_DEVICE_STATUS ; /* Tuner Device Status*/ + + /* Merge Recording Flag With Tuner Display Info*/ + Regval = ((unsigned char)RecordingFlag & 0X01)<< 7; /* bit 7 is Recording Flag*/ + Regval |= (unsigned char)TunerDisplayInfo & 0X7F; /* bit 6 to 0 are Tuner display Info*/ + I2c_Buffer[4] = Regval; + + /* Digital service Identification*/ + /*Merge Service Method and Digital Broadcast System in the same Byte*/ + Regval = (unsigned char)(pServiceIdentification->ServiceIdentificationMethod & 0x01) << 7; /* bit 7 is Service Method*/ + Regval |= (unsigned char)(pServiceIdentification->DigitalBroadcastSystem & 0x7F); /* bits 6 to 0 are Digital Broadcast*/ + I2c_Buffer[5] = Regval; + + /*Case of a ARIB Generic*/ + if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_GENERIC) + { + pARIB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[6] = (unsigned char)(pARIB_Pointer->TransportStreamID >> 8); + I2c_Buffer[7] = (unsigned char)pARIB_Pointer->TransportStreamID; + I2c_Buffer[8] = (unsigned char)(pARIB_Pointer->ServiceID >> 8); + I2c_Buffer[9] = (unsigned char)pARIB_Pointer->ServiceID; + I2c_Buffer[10] = (unsigned char)(pARIB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[11] = (unsigned char)pARIB_Pointer->OriginalNetworkID; + } + /*Case of a ATSC Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ATSC_GENERIC) + { + pATSC_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[6] = (unsigned char)(pATSC_Pointer->TransportStreamID >> 8); + I2c_Buffer[7] = (unsigned char)pATSC_Pointer->TransportStreamID; + I2c_Buffer[8] = (unsigned char)(pATSC_Pointer->ProgramNumber >> 8); + I2c_Buffer[9] = (unsigned char)pATSC_Pointer->ProgramNumber; + I2c_Buffer[10] = (unsigned char)(pATSC_Pointer->Reserved >> 8); + I2c_Buffer[11] = (unsigned char)pATSC_Pointer->Reserved; + } + /*Case of a DVB Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_DVB_GENERIC) + { + pDVB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[6] = (unsigned char)(pDVB_Pointer->TransportStreamID >> 8); + I2c_Buffer[7] = (unsigned char)pDVB_Pointer->TransportStreamID; + I2c_Buffer[8] = (unsigned char)(pDVB_Pointer->ServiceID >> 8); + I2c_Buffer[9] = (unsigned char)pDVB_Pointer->ServiceID; + I2c_Buffer[10] = (unsigned char)(pDVB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[11] = (unsigned char)pDVB_Pointer->OriginalNetworkID; + } + /*other cases, Buffer are empty*/ + else + { + I2c_Buffer[6] = 0xFF; + I2c_Buffer[7] = 0xFF; + I2c_Buffer[8] = 0xFF; + I2c_Buffer[9] = 0xFF; + I2c_Buffer[10] = 0xFF; + I2c_Buffer[11] = 0xFF; + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,12); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestActiveSource( ) + \brief This message is used by a new device to discover the status of + the system. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_Instance: the Instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestActiveSource +( + tmInstance_t Instance +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* IRequest Active Source command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_REQUEST_ACTIVE_SOURCE ; /* Request Active Source */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRoutingChange( ) + \brief This message is sent by a CEC switch when it is manually switched to + inform all other devices on the network that the active route below + the switch has changed. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 OriginalAddress \n + Previous address that the switch was switched to. \n + + \param UInt16 NewAddress \n + The new address it has been moved to. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRoutingChange +( + tmInstance_t Instance, + UInt16 OriginalAddress, + UInt16 NewAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[8] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Routing Change command */ + I2c_Buffer[0] = 0x08; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_ROUTING_CHANGE ; /* Routing Change */ + I2c_Buffer[4] = (unsigned char)(OriginalAddress >> 8); /* MsByte of Original Address*/ + I2c_Buffer[5] = (unsigned char)OriginalAddress; /* LsByte of Original Address */ + I2c_Buffer[6] = (unsigned char)(NewAddress >> 8); /* MsByte of New Address */ + I2c_Buffer[7] = (unsigned char)NewAddress; /* LsByte of New Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,8); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRoutingInformation( ) + \brief This message is sent by a CEC switch to indicate the active route + below the switch. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + The current active route to the sink in the CEC switch. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRoutingInformation +( + tmInstance_t Instance, + UInt16 PhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Routing Information command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_ROUTING_INFORMATION ; /* Routing Information */ + I2c_Buffer[4] = (unsigned char)(PhysicalAddress >> 8); /* MsByte of Physical Address*/ + I2c_Buffer[5] = (unsigned char)PhysicalAddress; /* LsByte of Physical Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSelectAnalogueService( ) + \brief This message select directly an analogue TV Service. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSelectAnalogueService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[8] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Select Aanalogue Service command */ + I2c_Buffer[0] = 0x08; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_ANALOGUE_SERVICE ; /* Select Analogue Service*/ + I2c_Buffer[4] = AnalogueBroadcastType; + I2c_Buffer[5] = (unsigned char)(AnalogueFrequency >> 8); + I2c_Buffer[6] = (unsigned char)AnalogueFrequency; + I2c_Buffer[7] = BroadcastSystem; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,8); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetStreamPath( ) + \brief This message is used by a TV to request a streaming path from + the specified physical address. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Physical address of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetStreamPath +( + tmInstance_t Instance, + UInt16 PhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set Stream Path command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_STREAM_PATH ; /* Set Stream Path */ + I2c_Buffer[4] = (unsigned char)(PhysicalAddress >> 8); /* MsByte of Physical Address*/ + I2c_Buffer[5] = (unsigned char)PhysicalAddress; /* LsByte of Physical Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + //========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetSystemAudioMode( ) + \brief This message turn the system audio Mode ON or OFF. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus \n + Specifies if the system audio mode is ON or OFF.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetSystemAudioMode +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set System Audio Mode Command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_SYSTEM_AUDIO_MODE ; /* Set System Audio Mode*/ + I2c_Buffer[4] = SystemAudioStatus; /*System Audio Status*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetTimerProgramTitle( ) + \brief This message is used to set the name of a program associated + with a timer block.Sent directly after sending a + or message. The name + is then associated with that timer block. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param const char *pProgramTitleString \n + Pointer on the program title. \n + + \param UInt8 ProgramTitleLength \n + Length of Program Title String. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetTimerProgramTitle +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + const char *pProgramTitleString, + UInt8 ProgramTitleLength +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Set Timer Program Title */ + MessLength = ProgramTitleLength+4; /* Calculate Message length*/ + + I2c_Buffer[0] = (unsigned char)MessLength; + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_TIMER_PROGRAM_TITLE ; /* Set Timer Program Title*/ + + for(loci = 0; loci <= ProgramTitleLength ; loci++) + { + I2c_Buffer[(loci+4)] = pProgramTitleString[loci]; /* Fill Table with Program Title characters*/ + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,(MessLength)); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecStandby( ) + \brief This message switches one or all devices into standby mode.Can be + be used as a broadcast message o be addressed to a specific device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecStandby +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Standby command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_STANDBY ; /* Standby */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSystemAudioModeRequest( ) + \brief A device implementing System Audio Control and which has volume + control RC button(eg TV or STB) request to use System Audio Mode + to the amplifier. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Physical address of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSystemAudioModeRequest +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt16 PhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* System Audio Mode Request command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST ; /* System Audio Mode Request*/ + I2c_Buffer[4] = (unsigned char)(PhysicalAddress >> 8); /* MsByte of Physical Address */ + I2c_Buffer[5] = (unsigned char)PhysicalAddress; /* LsByte of Physical Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSystemAudioModeStatus( ) + \brief Reports the current status of the System Audio Mode. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus \n + Current system audio mode.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSystemAudioModeStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECSystemAudioStatus_t SystemAudioStatus +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* System Audio Mode Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS ; /* System Audio Mode Status*/ + I2c_Buffer[4] = SystemAudioStatus; /* System Audio Status*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveTunerDeviceStatus( ) + \brief This message is used to request the status of a tuner device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECStatusRequest_t StatusRequest \n + Allows the initiator to request the status once or on all future state + change. Or to cancel a previous ["On"] request. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveTunerDeviceStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECStatusRequest_t StatusRequest +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* System Audio Mode Request command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS ; /* Give Tuner Device Status*/ + I2c_Buffer[4] = (unsigned char)StatusRequest; /* Status Request */ + + errCode = setCecHwRegisters(pDis,E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordTvScreen( ) + \brief This message request by the recording device to record the presently + displayed source. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordTvScreen +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record TV Sreen command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_TV_SCREEN ; /* Record TV screen */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportAudioStatus( ) + \brief This message report an amplifier's volume and mute. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECAudioStatus_t AudioStatus \n + Volume and mute status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportAudioStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + ptmdlHdmiCECAudioStatus_t pAudioStatus +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char Regval; /*Local Variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Report Audio Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_AUDIO_STATUS ; /* Report Audio Statust*/ + Regval = (((unsigned char)pAudioStatus -> audioMuteStatus) & 0x01 )<< 7; /* bit 7 Mute Status*/ + Regval |= ((unsigned char)pAudioStatus -> audioVolumeStatus) & 0x7F; /* bit 6 to 0 Volum Status*/ + I2c_Buffer[4] = Regval; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportShortAudioDescriptor( ) + \brief This message Report Audio Capability. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt32 ShortAudioDecriptor \n + Audio Descriptor. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportShortAudioDescriptor +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt32 ShortAudioDecriptor +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[7] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x07; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_SHORT_AUDIO_DESCRIPTOR ; /* Report Audio Capability*/ + I2c_Buffer[4] = (unsigned char)(ShortAudioDecriptor >> 16); /* MSByte of ShortAudioDecriptor*/ + I2c_Buffer[5] = (unsigned char)(ShortAudioDecriptor >> 8); + I2c_Buffer[6] = (unsigned char)ShortAudioDecriptor; /* LSByte of ShortAudioDecriptor*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestShortAudioDescriptor( ) + \brief This message Request Audio Capability. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 AudioFormatID \n + + \param UInt8 AudioFormatCode \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestShortAudioDescriptor +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 AudioFormatID, + UInt8 AudioFormatCode + +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char Regval; /*Local Variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REQUEST_SHORT_AUDIO_DESCRIPTOR ; /* Request Audio Capability*/ + Regval = (((unsigned char)AudioFormatCode) & 0x3F )<< 2; /* bit 3 to 7 AudioFormatCode*/ + Regval |= ((unsigned char)AudioFormatID) & 0x03; /* bit 1 to 0 AudioFormatID*/ + I2c_Buffer[4] = Regval; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecIniateARC( ) + \brief This message Used by an ARC RX device to activate the + ARC functionality in an ARC TX device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecIniateARC +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_INITATE_ARC ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportArcInitiated( ) + \brief This message Used by an ARC TX device to indicate that + its ARC functionality has been activated + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportArcInitiated +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_ARC_INITIATED ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportArcTerminated( ) + \brief This message Used by an ARC TX device to indicate that its ARC functionality + has been deactivated. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportArcTerminated +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_ARC_TERMINATED ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestArcInitiation( ) + \brief This message Used by an ARC TX device to request an ARC RX device to + activate the ARC functionality in the ARC TX device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestArcInitiation +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_ARC_INITIATION ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRequestArcTerminiation( ) + \brief Used by an ARC TX device to request an ARC RX device to deactivate + the ARC functionality in the ARC TX device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRequestArcTerminiation +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_ARC_TERMINATION ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTerminateARC( ) + \brief Used by an ARC TX device to request an ARC RX device to deactivate + the ARC functionality in the ARC TX device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTerminateARC +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Report Short Audio Decriptor */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TERMINATE_ARC ; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGivePhysicalAddress( ) + \brief This message is a request to a device to return its physical Address + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGivePhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give physical Address command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_PHYSICAL_ADDRESS ; /* Give Physical Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveSystemAudioModeStatus( ) + \brief This message request the status of the system audio mode + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveSystemAudioModeStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give System Audio Mode Status command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS ; /* Give System Audio Mode Status*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGetMenuLanguage( ) + \brief This message is sent by a device capable of character generation + (for OSD and Menus) to a TV in order to discover the currently selected + Menu Language. Also used by a TV during installation to dicover the + currently set menu language of other devices. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetMenuLanguage +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Get Menu Language command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GET_MENU_LANGUAGE ; /* Get Menu Address */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveAudioStatus( ) + \brief This message is requests an amplifier to send its volume and mute status + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveAudioStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give Audio Mode Status command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_AUDIO_STATUS ; /* Message Abort*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecPollingMessage( ) + \brief This message is used by any device for device discovery - similar to + ping in other protocols + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecPollingMessage +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[3] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Polling Message command */ + I2c_Buffer[0] = 0x03; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,3); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 1; + gtmdlHdmiCecDriverSaveMessage.Opcode = 0; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordStatus( ) + \brief This message is used by a recording device to inform the initiator + of the message about its status. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECRecordStatusInfo_t RecordStatusInfo \n + The recording status of the device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECRecordStatusInfo_t RecordStatusInfo +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_STATUS ; /* Record Status */ + I2c_Buffer[4] = RecordStatusInfo; /* Record Status */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordOff( ) + \brief This message request a device to stop a recording + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOff +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record Off command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_OFF ; /* Record Off */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordOnAnalogueService( ) + \brief This message attempt to record analogue source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnAnalogueService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[9] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Record On Analogue Device command */ + I2c_Buffer[0] = 0x09; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_ON ; /*Record On*/ + + I2c_Buffer[4] = CEC_RECORD_SOURCE_ANALOGUE_SERVICE; /*RecordSourceType = CEC_RECORD_SOURCE_ANALOGUE_SERVICE*/ + I2c_Buffer[5] = AnalogueBroadcastType; /*Analogue Brodcast Type*/ + I2c_Buffer[6] = (unsigned char)(AnalogueFrequency >> 8); /*Analogue Frequency*/ + I2c_Buffer[7] = (unsigned char)AnalogueFrequency; + I2c_Buffer[8] = BroadcastSystem; /*Brodcast System*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,9); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordOnDigitalService( ) + \brief This message attempt to record digital source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnDigitalService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[12] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCECAribData_t *pARIB_Pointer; + tmdlHdmiCECAtscData_t *pATSC_Pointer; + tmdlHdmiCECDvbData_t *pDVB_Pointer; + + unsigned char Regval; /* Local variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record On Digital Service command */ + I2c_Buffer[0] = 0x0C; /* Param number = 10*/ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_ON ; /* Record On Digital Service*/ + + I2c_Buffer[4] = CEC_RECORD_SOURCE_DIGITAL_SERVICE; /* RecordSourceType = CEC_RECORD_SOURCE_DIGITAL_SERVICE */ + + /* Digital Service Identification*/ + /*Merge Service Method and Digital Broadcast System in the same Byte*/ + Regval = (unsigned char)(pServiceIdentification->ServiceIdentificationMethod & 0x01); /*bit 7 is Service Method*/ + Regval = Regval << 7; + Regval |= (unsigned char)(pServiceIdentification->DigitalBroadcastSystem & 0x7F); /*bits 6 to 0 are Digital Broadcast*/ + I2c_Buffer[5] = Regval; + + /*Case of a ARIB Generic*/ + if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_GENERIC) + { + pARIB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[6] = (unsigned char)(pARIB_Pointer->TransportStreamID >> 8); + I2c_Buffer[7] = (unsigned char)pARIB_Pointer->TransportStreamID; + I2c_Buffer[8] = (unsigned char)(pARIB_Pointer->ServiceID >> 8); + I2c_Buffer[9] = (unsigned char)pARIB_Pointer->ServiceID; + I2c_Buffer[10] = (unsigned char)(pARIB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[11] = (unsigned char)pARIB_Pointer->OriginalNetworkID; + } + /*Case of a ATSC Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ATSC_GENERIC) + { + pATSC_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[6] = (unsigned char)(pATSC_Pointer->TransportStreamID >> 8); + I2c_Buffer[7] = (unsigned char)pATSC_Pointer->TransportStreamID; + I2c_Buffer[8] = (unsigned char)(pATSC_Pointer->ProgramNumber >> 8); + I2c_Buffer[9] = (unsigned char)pATSC_Pointer->ProgramNumber; + I2c_Buffer[10] = (unsigned char)(pATSC_Pointer->Reserved >> 8); + I2c_Buffer[11] = (unsigned char)pATSC_Pointer->Reserved; + } + /*Case of a DVB Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_DVB_GENERIC) + { + pDVB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[6] = (unsigned char)(pDVB_Pointer->TransportStreamID >> 8); + I2c_Buffer[7] = (unsigned char)pDVB_Pointer->TransportStreamID; + I2c_Buffer[8] = (unsigned char)(pDVB_Pointer->ServiceID >> 8); + I2c_Buffer[9] = (unsigned char)pDVB_Pointer->ServiceID; + I2c_Buffer[10] = (unsigned char)(pDVB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[11] = (unsigned char)pDVB_Pointer->OriginalNetworkID; + } + /*other cases, Buffer are empty*/ + else + { + I2c_Buffer[6] = 0xFF; + I2c_Buffer[7] = 0xFF; + I2c_Buffer[8] = 0xFF; + I2c_Buffer[9] = 0xFF; + I2c_Buffer[10] = 0xFF; + I2c_Buffer[11] = 0xFF; + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,12); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordOnExternalPhysicalAddress( ) + \brief This message attempt to record an external physical address source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Defines the path between the TV an a device-thus giving it a physical + address within the cluster.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnExternalPhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[7] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record On External Physial Address command */ + I2c_Buffer[0] = 0x07; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_ON ; /*Record On*/ + I2c_Buffer[4] = CEC_RECORD_SOURCE_EXTERNAL_PHYSICAL_ADDRESS; /*RecordSourceType = CEC_RECORD_SOURCE_EXTERNAL_PHYSICAL_ADDRESS*/ + I2c_Buffer[5] = (unsigned char)(ExternalPhysicalAddress >> 8); /*External Physical Address*/ + I2c_Buffer[6] = (unsigned char)ExternalPhysicalAddress; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordOnExternalPlug( ) + \brief This message attempt to record an external plug source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param tmdlHdmiCECExternalPlug_t ExternalPlug \n + indicates external plug number (1 to 255 )on the recording device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnExternalPlug +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECExternalPlug_t ExternalPlug +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record On External Plug command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_ON ; /* Record On*/ + + I2c_Buffer[4] = CEC_RECORD_SOURCE_EXTERNAL_PLUG; /* RecordSourceType = CEC_RECORD_SOURCE_EXTERNAL_PLUG*/ + I2c_Buffer[5] = ExternalPlug; /*External Plug*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecRecordOnOwnSource( ) + \brief This message attempt to record an external plug source + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecRecordOnOwnSource +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Record On Own Source command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_RECORD_ON ; /* Record On*/ + + I2c_Buffer[4] = CEC_RECORD_SOURCE_OWN_SOURCE; /* RecordSourceType = CEC_RECORD_SOURCE_OWN_SOURCE*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportPhysicalAddress( ) + \brief This message is used to inform all other devices of the mapping + between physical and logical address of the initiator. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt16 PhysicalAddress \n + Device physical address within the cluster. \n + + \param tmdlHdmiCECDeviceType_t DeviceType \n + Type of the device (TV, Playback, tuner,...). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportPhysicalAddress +( + tmInstance_t Instance, + UInt16 PhysicalAddress, + tmdlHdmiCECDeviceType_t DeviceType +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[7] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Report Physical Address command */ + I2c_Buffer[0] = 0x07; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_PHYSICAL_ADDRESS ; /* Report Physical Address */ + I2c_Buffer[4] = (unsigned char)(PhysicalAddress >> 8); /* MsByte of Physical Address*/ + I2c_Buffer[5] = (unsigned char)PhysicalAddress; /* LsByte of Physical Address */ + + I2c_Buffer[6] = DeviceType ; /* Device Type*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetMenuLanguage( ) + \brief This message is used by a TV or another device to indicate the menu + Language. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param const char *pLanguage \n + Pointer on the user's menu language choice. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetMenuLanguage +( + tmInstance_t Instance, + const char *pLanguage +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[7] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + // RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set Menu Language command */ + I2c_Buffer[0] = 0x07; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_MENU_LANGUAGE ; /* Set Menu Language*/ + I2c_Buffer[4] = pLanguage[0]; /* First Tocken*/ + I2c_Buffer[5] = pLanguage[1]; + I2c_Buffer[6] = pLanguage[2]; /* Last Tocken*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecDeckControl() + \brief This message is used to conrol a device's media functions + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDecControlMode_t DeckControlMode \n + Used in message \n + + \note The "Skip Forward / Wind" and "Skip Reverse / Rewind" values are + used for example in a DVD as next xhapter and previous chapter and + in a VCR as wind and rewind. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDeckControl +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDecControlMode_t DeckControlMode +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if Instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to Instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if Instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Deck Control command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_DESCK_CONTROL; /* Deck Control Mode*/ + I2c_Buffer[4] = DeckControlMode; /* Deck Control Value*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecDeckStatus() + \brief This message is used to provide a deck's status to the initiator + of the message + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDecInfo_t DeckInfo \n + Information on the device's current status \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDeckStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDecInfo_t DeckInfo +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Deck Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_DECK_STATUS; /* Deck Status*/ + I2c_Buffer[4] = DeckInfo; /* Deck Status Mode Information*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveDeckStatus( ) + \brief This message is used to request the status of a device regardless + of whether or not it is the current active source. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECStatusRequest_t StatusRequest \n + Allows the initiator to request the status once or on all future state + change. Or to cancel a previous ["On"] request. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveDeckStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECStatusRequest_t StatusRequest +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if Instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give Deck Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_DECK_STATUS; /* Give Deck Status*/ + I2c_Buffer[4] = StatusRequest; /* Deck Status Request Information*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecPlay( ) + \brief This message is used to control the playback behaviour of a source + device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECPlayMode_t PlayMode \n + In which mode to play media. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecPlay +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECPlayMode_t PlayMode +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Play command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_PLAY; /* Play*/ + I2c_Buffer[4] = (unsigned char)PlayMode; /* Play Mode Information Information*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSelectDigitalService( ) + \brief This message select directly a digital TV, Radio or Data Broadcast + Service. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSelectDigitalService +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + ptmdlHdmiCECDigitalServiceIdentification_t pServiceIdentification +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[11] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCECAribData_t *pARIB_Pointer; + tmdlHdmiCECAtscData_t *pATSC_Pointer; + tmdlHdmiCECDvbData_t *pDVB_Pointer; + + unsigned char Regval; /*Local Variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Select Digital Service command */ + I2c_Buffer[0] = 0x0B; /* Param number = 10*/ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_DIGITAL_SERVICE ; /* Select Digital Service*/ + + /*Merge Service Method and Digital Broadcast System in the same Byte*/ + Regval = (unsigned char)(pServiceIdentification->ServiceIdentificationMethod & 0x01); /* Load the 1 bit of Service Method*/ + Regval = Regval << 7; + Regval |= (unsigned char)(pServiceIdentification->DigitalBroadcastSystem & 0x7F); /*Merge with the 7 bits of Digital Broadcast*/ + I2c_Buffer[4] = Regval; + + /*Case of a ARIB Generic*/ + if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_GENERIC) + { + pARIB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[5] = (unsigned char)(pARIB_Pointer->TransportStreamID >> 8); /* Service Identification */ + I2c_Buffer[6] = (unsigned char)pARIB_Pointer->TransportStreamID; + I2c_Buffer[7] = (unsigned char)(pARIB_Pointer->ServiceID >> 8); + I2c_Buffer[8] = (unsigned char)pARIB_Pointer->ServiceID; + I2c_Buffer[9] = (unsigned char)(pARIB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[10] = (unsigned char)pARIB_Pointer->OriginalNetworkID; + } + /*Case of a ATSC Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ATSC_GENERIC) + { + pATSC_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[5] = (unsigned char)(pATSC_Pointer->TransportStreamID >> 8); /* Service Identification */ + I2c_Buffer[6] = (unsigned char)pATSC_Pointer->TransportStreamID; + I2c_Buffer[7] = (unsigned char)(pATSC_Pointer->ProgramNumber >> 8); + I2c_Buffer[8] = (unsigned char)pATSC_Pointer->ProgramNumber; + I2c_Buffer[9] = (unsigned char)(pATSC_Pointer->Reserved >> 8); + I2c_Buffer[10] = (unsigned char)pATSC_Pointer->Reserved; + } + /*Case of a DVB Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_DVB_GENERIC) + { + pDVB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[5] = (unsigned char)(pDVB_Pointer->TransportStreamID >> 8); /* Service Identification */ + I2c_Buffer[6] = (unsigned char)pDVB_Pointer->TransportStreamID; + I2c_Buffer[7] = (unsigned char)(pDVB_Pointer->ServiceID >> 8); + I2c_Buffer[8] = (unsigned char)pDVB_Pointer->ServiceID; + I2c_Buffer[9] = (unsigned char)(pDVB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[10] = (unsigned char)pDVB_Pointer->OriginalNetworkID; + } + /*other cases, Buffer are empty*/ + else + { + I2c_Buffer[5] = 0xFF; /* Service Identification */ + I2c_Buffer[6] = 0xFF; + I2c_Buffer[7] = 0xFF; + I2c_Buffer[8] = 0xFF; + I2c_Buffer[9] = 0xFF; + I2c_Buffer[10] = 0xFF; + } + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,11); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetAnalogueTimer( ) + \brief This message is used to set asingle timer block on an analogue + recording device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType \n + "Cable,Sattellite,Terrestrial".\n + + \param UInt16 AnalogueFrequency \n + Specify frequency used by analogue tuner (0x0000<=N<=0xFFFF).\n + + \param tmdlHdmiCECBroadcastSystem_t BroadcastSystem \n + Specify information about the colour system, the sound carrier and + the IF-frequency.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetAnalogueTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType, + UInt16 AnalogueFrequency, + tmdlHdmiCECBroadcastSystem_t BroadcastSystem +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[15] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set Analogue Timer command */ + I2c_Buffer[0] = 0x0F; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_ANALOGUE_TIMER ; /* Message Abort*/ + I2c_Buffer[4] = DayOfMonth; + I2c_Buffer[5] = MonthOfYear; + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); + I2c_Buffer[7] = (unsigned char)StartTime; + I2c_Buffer[8] = pDuration -> Hours; + I2c_Buffer[9] = pDuration -> Minute; + I2c_Buffer[10] = RecordingSequence; + I2c_Buffer[11] = AnalogueBroadcastType; + I2c_Buffer[12] = (unsigned char)(AnalogueFrequency >> 8); + I2c_Buffer[13] = (unsigned char)AnalogueFrequency; + I2c_Buffer[14] = BroadcastSystem; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,15); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetAudioRate( ) + \brief This message is used to control audio rate from Source device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECAudioRate_t AudioRate \n + The audio rate requested. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetAudioRate +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECAudioRate_t AudioRate +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set Audio Rate command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_AUDIO_RATE ; /* Set Audio Rate */ + I2c_Buffer[4] = AudioRate; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetDigitalTimer( ) + \brief This message is used to set a digital timer block on a digital + recording device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress \n + Address of message receiver. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification \n + Pointer to the structure Digital Service Identification + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetDigitalTimer +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECDigitalServiceIdentification_t *pServiceIdentification +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[18] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + tmdlHdmiCECAribData_t *pARIB_Pointer; + tmdlHdmiCECAtscData_t *pATSC_Pointer; + tmdlHdmiCECDvbData_t *pDVB_Pointer; + + unsigned char Regval; /* Local variable*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set Digital Timer command */ + I2c_Buffer[0] = 0x12; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_DIGITAL_TIMER ; /* Set Digital Timer*/ + I2c_Buffer[4] = DayOfMonth; /* Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /* Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /* Start Time*/ + I2c_Buffer[7] = (unsigned char)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /* Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /* Duration Minute*/ + I2c_Buffer[10] = RecordingSequence; /*Recording Sequence*/ + + /* Digital service Identification*/ + /*Merge Service Method and Digital Broadcast System in the same Byte*/ + Regval = (unsigned char)(pServiceIdentification->ServiceIdentificationMethod & 0x01); /*bit 7 is Service Method*/ + Regval = Regval << 7; + Regval |= (unsigned char)(pServiceIdentification->DigitalBroadcastSystem & 0x7F); /*bits 6 to 0 are Digital Broadcast*/ + I2c_Buffer[11] = Regval; + + /*Case of a ARIB Generic*/ + if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ARIB_GENERIC) + { + pARIB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[12] = (unsigned char)(pARIB_Pointer->TransportStreamID >> 8); + I2c_Buffer[13] = (unsigned char)pARIB_Pointer->TransportStreamID; + I2c_Buffer[14] = (unsigned char)(pARIB_Pointer->ServiceID >> 8); + I2c_Buffer[15] = (unsigned char)pARIB_Pointer->ServiceID; + I2c_Buffer[16] = (unsigned char)(pARIB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[17] = (unsigned char)pARIB_Pointer->OriginalNetworkID; + } + /*Case of a ATSC Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_ATSC_GENERIC) + { + pATSC_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[12] = (unsigned char)(pATSC_Pointer->TransportStreamID >> 8); + I2c_Buffer[13] = (unsigned char)pATSC_Pointer->TransportStreamID; + I2c_Buffer[14] = (unsigned char)(pATSC_Pointer->ProgramNumber >> 8); + I2c_Buffer[15] = (unsigned char)pATSC_Pointer->ProgramNumber; + I2c_Buffer[16] = (unsigned char)(pATSC_Pointer->Reserved >> 8); + I2c_Buffer[17] = (unsigned char)pATSC_Pointer->Reserved; + } + /*Case of a DVB Generic*/ + else if(pServiceIdentification->DigitalBroadcastSystem == CEC_DIGITAL_BROADCAST_SYSTEM_DVB_GENERIC) + { + pDVB_Pointer = pServiceIdentification->pServiceIdentification; + + I2c_Buffer[12] = (unsigned char)(pDVB_Pointer->TransportStreamID >> 8); + I2c_Buffer[13] = (unsigned char)pDVB_Pointer->TransportStreamID; + I2c_Buffer[14] = (unsigned char)(pDVB_Pointer->ServiceID >> 8); + I2c_Buffer[15] = (unsigned char)pDVB_Pointer->ServiceID; + I2c_Buffer[16] = (unsigned char)(pDVB_Pointer->OriginalNetworkID >> 8); + I2c_Buffer[17] = (unsigned char)pDVB_Pointer->OriginalNetworkID; + } + /*other cases, Buffer are empty*/ + else + { + I2c_Buffer[12] = 0xFF; + I2c_Buffer[13] = 0xFF; + I2c_Buffer[14] = 0xFF; + I2c_Buffer[15] = 0xFF; + I2c_Buffer[16] = 0xFF; + I2c_Buffer[17] = 0xFF; + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,18); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetExternalTimerWithExternalPlug( ) + \brief This message is used to set a single timer block to record from an + external device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPlug_t ExternalPlug \n + indicates external plug number (1 to 255 )on the recording device.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetExternalTimerWithExternalPlug +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPlug_t ExternalPlug +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[13] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set External Timer With External Plug command */ + I2c_Buffer[0] = 0x0D; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_EXTERNAL_TIMER ; /*SetDigital Timer*/ + + I2c_Buffer[4] = DayOfMonth; /*Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /*Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /*Start Time*/ + I2c_Buffer[7] = (unsigned char)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /*Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /*Duration Minute*/ + I2c_Buffer[10] = RecordingSequence; /*Recording Sequence*/ + I2c_Buffer[11] = CEC_EXTERNAL_PLUG; /*External Source Specifier = External Plug */ + I2c_Buffer[12] = ExternalPlug; /*External Plug*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,13); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetExternalTimerWithPhysicalAddress( ) + \brief This message is used to set a single timer block to record from an + external device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 DayOfMonth \n + Day of the month.\n + + \param UInt8 MonthOfYear \n + Month of the year.\n + + \param UInt16 StartTime \n + Start time for a timer based recording.\n + + \param UInt16 Duration \n + Pointer to the structure tmdlHdmiCECDuration_t in BCD format.\n + + \param UInt8 Recording Sequence \n + Indicates if recording is repeated and, if so, on which day + For repeated recording the recording sequence value is the + bitwise OR of the days when recordings are required + Shall be set to 0x00 when recording is not repeated.\n + + \param tmdlHdmiCECExternalPhysicalAddress_t PhysicalAddress \n + Defines the path between the TV an a device-thus giving it a physical + address within the cluster.\n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetExternalTimerWithPhysicalAddress +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 DayOfMonth, + UInt8 MonthOfYear, + UInt16 StartTime, + tmdlHdmiCECDuration_t *pDuration, + UInt8 RecordingSequence, + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[14] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set external Timer With External Physical Address command */ + I2c_Buffer[0] = 0x0E; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_EXTERNAL_TIMER ; /* SetDigital Timer*/ + + I2c_Buffer[4] = DayOfMonth; /* Day of Month*/ + I2c_Buffer[5] = MonthOfYear; /* Month of Year*/ + I2c_Buffer[6] = (unsigned char)(StartTime >> 8); /* Start Time*/ + I2c_Buffer[7] = (unsigned char)StartTime; + I2c_Buffer[8] = pDuration -> Hours; /* Duration Hours*/ + I2c_Buffer[9] = pDuration -> Minute; /* Duration Minute*/ + I2c_Buffer[10] = RecordingSequence; /* Recording Sequence*/ + I2c_Buffer[11] = CEC_EXTERNAL_PHYSICAL_ADDRESS; /*External Source Specifier = External Address*/ + I2c_Buffer[12] = (unsigned char)(ExternalPhysicalAddress >> 8); /*External Address*/ + I2c_Buffer[13] = (unsigned char) ExternalPhysicalAddress; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,14); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTunerStepDecrement( ) + \brief This message is used to tune to next lowest service in a tuner's + service list.Can be used for PIP. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerStepDecrement +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Tuner Step Decrement command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TUNER_STEP_DECREMENT ; /* Tuner Step Decrement*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecTunerStepIncrement( ) + \brief This message is used to tune to next highest service in a tuner's + service list.Can be used for PIP. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecTunerStepIncrement +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Tuner Step Increment command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_TUNER_STEP_INCREMENT ; /* Tuner Step Increment*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecDeviceVendorID() + \brief This message report the vendor ID of this device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt32 VendorID \n + Indentifier for a specific Vendor \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecDeviceVendorID +( + tmInstance_t Instance, + UInt32 VendorID +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[7] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Device Vendor ID command */ + I2c_Buffer[0] = 0x07; /* Param number in case of Vendor ID is 32 Bytes*/ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= 0x0F; /* Broadcast*/ + + I2c_Buffer[3] = CEC_OPCODE_DEVICE_VENDOR_ID ; /* Device Vendor ID opcode = 0x87*/ + I2c_Buffer[4] = (unsigned char)(VendorID >> 16); /* MSByte of Vendor ID*/ + I2c_Buffer[5] = (unsigned char)(VendorID >> 8); + I2c_Buffer[6] = (unsigned char)VendorID; /* LSByte of Vendor ID*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,7); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveDeviceVendorID( ) + \brief This message is request the vendor ID from a device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveDeviceVendorID +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give Device Vendor ID command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_DEVICE_VENDOR_ID ; /* Give Device Vendor*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecVendorCommand( ) + \brief This message is allows vendor specific commands to be sent between + two devices. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 *pVendorSpecificData \n + Pointer to the Vendor Specific datas + + \param UInt8 VendorSpecificDataLength \n + Length of VendorSpecificData. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorCommand +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 *pVendorSpecificData, + UInt8 VendorSpecificDataLength +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Vendor Command command */ + MessLength = VendorSpecificDataLength + 4; /* Calculate Message length*/ + + I2c_Buffer[0] = MessLength; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_VENDOR_COMMAND ; /* Vendor Command*/ + + for(loci = 0; loci <= VendorSpecificDataLength ; loci++) + { + I2c_Buffer[(loci+7)] = pVendorSpecificData[loci]; /* Fill Table with vendorSpecific Data characters*/ + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,MessLength); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecVendorCommandWithID( ) + \brief This message is allows vendor specific commands to be sent between + two devices or broadcast. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt32 VendorID \n + Indentifier for a specific Vendor \n + + \param UInt8 *pVendorSpecificData \n + Pointer to the Vendor Specific datas + + \param UInt8 VendorSpecificDataLength \n + Length of VendorSpecificData. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorCommandWithID +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt32 VendorID, + UInt8 *pVendorSpecificData, + UInt8 VendorSpecificDataLength +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Vendor Command With ID command */ + MessLength = VendorSpecificDataLength + 7; /* Calculate Message length*/ + + I2c_Buffer[0] = MessLength; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_VENDOR_COMMAND_WITH_ID ; /* Vendor Command*/ + I2c_Buffer[4] = (unsigned char)(VendorID >> 16); /* MSByte of Vendor ID*/ + I2c_Buffer[5] = (unsigned char)(VendorID >> 8); + I2c_Buffer[6] = (unsigned char)VendorID; /* LSByte of Vendor ID*/ + + for(loci = 0; loci <= VendorSpecificDataLength ; loci++) + { + I2c_Buffer[(loci+7)] = pVendorSpecificData[loci]; /* Fill Table with vendorSpecific Data characters*/ + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,MessLength); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecVendorRemoteButtonDown( ) + \brief This message indicates that a remote control button has been depressed. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 *pVendorSpecificRcCode \n + Pointer to the Vendor Specific remote control code. + its recommended t keep this to a minimum size. + The maximum length shall not exceed 14 data blocks to avoid saturating bus + + \param UInt8 VendorSpecificRcCodeLength \n + Length of VendorSpecificRcCode. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorRemoteButtonDown +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 *pVendorSpecificRcCode, + UInt8 VendorSpecificRcCodeLength +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + /* Vendor Remote Button Down command */ + MessLength = VendorSpecificRcCodeLength + 4; /* Calculate Message length*/ + + I2c_Buffer[0] = MessLength; /* Message Length */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN ; /* Vendor Remote Button Down Opcode*/ + /*Vendor Specific RC code Parameter*/ + for(loci = 0; loci <= VendorSpecificRcCodeLength ; loci++) + { + I2c_Buffer[(loci+4)] = pVendorSpecificRcCode[loci]; /* Fill Table with Vendor Specific RC Code data*/ + } + /*Send message Via I2C*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,MessLength); + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecVendorRemoteButtonUp( ) + \brief This message indicates that a remote control button (the last button + pressed indicated by the message) has + been released. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecVendorRemoteButtonUp +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Vendor Remote Button Up command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP ; /* Vendor Remote Button Up*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetOsdString( ) + \brief This message is used to send a test message to output on a TV. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECDisplayControl_t DisplayControl \n + Display timing. \n + + \param const char *pOsdString \n + Pointer on the Text to display. \n + + \param UInt8 OsdStringLength \n + Length of Osd String. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetOsdString +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECDisplayControl_t DisplayControl, + const char *pOsdString, + UInt8 OsdStringLength +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set OSD String command */ + + MessLength = OsdStringLength+5; /* Calculate Message length*/ + + I2c_Buffer[0] = (unsigned char)MessLength; + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_OSD_STRING ; /* Set Osd String*/ + I2c_Buffer[4] = DisplayControl; /*Display Control*/ + for(loci = 0; loci <= OsdStringLength ; loci++) + { + I2c_Buffer[(loci+5)] = pOsdString[loci]; /* Fill Table with OSD Name characters*/ + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,(MessLength)); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveOsdName( ) + \brief This message is used to request preferred OSD name of a device + for use in menus associated with that device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveOsdName +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give OSD Name command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_OSD_NAME ; /* Give OSD Name*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetOsdName( ) + \brief This message is used to set the preferred OSD name of a device + for use in manus associated with that device. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param const char *pOsdName \n + Pointer on the preferred name of the device. \n + + \param UInt8 OsdNameLength \n + Length of Osd Name String. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetOsdName +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + const char *pOsdName, + UInt8 OsdNameLength +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Set OSD Name command */ + + MessLength = OsdNameLength+4; /* Calculate Message length*/ + + I2c_Buffer[0] = (unsigned char)MessLength; + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_SET_OSD_NAME ; /* Set Osd Name*/ + for(loci = 0; loci <= OsdNameLength ; loci++) + { + I2c_Buffer[(loci+4)] = pOsdName[loci]; /* Fill Table with OSD Name characters*/ + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,(MessLength)); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecMenuRequest( ) + \brief This message request from the TV for a device to show/remove a + menu or to query if a device is currently showing a menu + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECMenuRequestType_t MenuRequestType \n + Indicates if the menu request is to activate or deactivate the + devices menu or simply query the devices menu status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecMenuRequest +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECMenuRequestType_t MenuRequestType +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Menu Request command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_MENU_REQUEST ; /* Menu Request*/ + I2c_Buffer[4] = MenuRequestType; /*Menu Request Type */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecMenuStatus( ) + \brief This message is used to indicate to the TV that the device is + showing/has removed a menu and requets the remote control keys to + be passed though + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECMenuState_t MenuState \n + Indicates if the device is in the 'Device Menu Active' state or + 'Device Menu Inactive' state. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecMenuStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECMenuState_t MenuState +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Menu Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_MENU_STATUS; /* Menu Status*/ + I2c_Buffer[4] = MenuState; /* Menu State*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlPressed( ) + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECUserRemoteControlCommand_t UICommand \n + Relevant UI command issued by user. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressed +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECUserRemoteControlCommand_t UICommand +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Pressed command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_PRESSED; /* User Control pressed*/ + I2c_Buffer[4] = UICommand; /* UI Command*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlPressedPlay( ) + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECPlayMode_t PlayMode \n + In which mode to play media. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedPlay +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECPlayMode_t PlayMode +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Presses Play command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_PRESSED; /* User Control Pressed*/ + + I2c_Buffer[4] = CEC_REMOTE_BUTTON_PLAY_FUNCTION; /* UI Command = CEC_REMOTE_BUTTON_PLAY_FUNCTION */ + I2c_Buffer[5] = PlayMode; /* Play Mode*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlPressedSelectAudioInput( ) + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 SelectAudioInput \n + Number of the Audio Input (Audio input number between 1 and 255). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedSelectAudioInput +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 SelectAudioInput +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Pressed Select Audio Input command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_PRESSED; /* User Control Pressed*/ + + I2c_Buffer[4] = CEC_REMOTE_BUTTON_SELECT_AUDIO_INPUT_FUNCTION; /* UI Command = CEC_REMOTE_BUTTON_SELECT_AUDIO_INPUT_FUNCTION*/ + I2c_Buffer[5] = SelectAudioInput; /* UI Function Select Audio mode*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlPressedSelectAVInput( ) + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 SelectAVInput \n + Number of the A/V Input (A/V input number between 1 and 255). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedSelectAVInput +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 SelectAVInput +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Pressed Select AV Input command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_PRESSED; /* User Control Pressed*/ + + I2c_Buffer[4] = CEC_REMOTE_BUTTON_SELECT_AV_INPUT_FUNCTION; /* UI Command = CEC_REMOTE_BUTTON_SELECT_AV_INPUT_FUNCTION */ + I2c_Buffer[5] = SelectAVInput; /* UI Function Select A/V Input*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlPressedSelectMedia( ) + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 SelectMedia \n + Number of Media (Media number between 1 and 255). \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedSelectMedia +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + UInt8 SelectMedia +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Pressed Select Media command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_PRESSED; /* User Control Pressed*/ + + I2c_Buffer[4] = CEC_REMOTE_BUTTON_SELECT_MEDIA_FUNCTION; /* UI Command = CEC_REMOTE_BUTTON_SELECT_MEDIA_FUNCTION*/ + I2c_Buffer[5] = SelectMedia; /* UI Function Media*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlPressedTune( ) + \brief This message is used to indicate that the user pressed a remote button + or switched from one remote control button to another. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECChannelIdentifier_t *pChannelIdentifier \n + Pointer to the structure of Major and Minor Channel number + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlPressedTune +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECChannelIdentifier_t *pChannelIdentifier +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[10] ; /* I2C data buffer */ + UInt16 Regval16 ; /* Local variable used for conversion*/ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Pressed Tune command */ + I2c_Buffer[0] = 0x0A; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_PRESSED; /* User Control Pressed Opcode*/ + + I2c_Buffer[4] = CEC_REMOTE_BUTTON_TUNE_FUNCTION; /* UI Command = CEC_REMOTE_BUTTON_TUNE_FUNCTION*/ + + /* Merge 6 bits of ChanNum with 10 bits of Major channel*/ + Regval16 = (UInt16)(pChannelIdentifier->ChanNumFormat & 0x003F); // Save the 6 lsbits + Regval16 = Regval16 << 10; + Regval16 |= (UInt16)(pChannelIdentifier->MajorChanNumber & 0x03FF); + + /* Load the 4 information bytes of Channel ID*/ + I2c_Buffer[5] = (unsigned char)(Regval16 >> 8); + I2c_Buffer[6] = (unsigned char)Regval16; + I2c_Buffer[7] = (unsigned char)(pChannelIdentifier->MinorChanNumber >> 8); + I2c_Buffer[8] = (unsigned char)pChannelIdentifier->MinorChanNumber; + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,9); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecUserControlReleased( ) + \brief This message is used to indicate that the user released a remote button + The last one indicated by the Message. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecUserControlReleased +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* User Control Released command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_USER_CONTROL_RELEASED ; /* User Control Released */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGiveDevicePowerStatus( ) + \brief This message is used to determine the current power status of a + target device + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGiveDevicePowerStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Give Device power Status Power Status command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GIVE_DEVICE_POWER_STATUS ; /* Give Device Power Status */ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecReportPowerStatus( ) + \brief This message is used to inform a requesting device of the current + power status. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECPowerStatus_t PowerStatus \n + Current power status. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecReportPowerStatus +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECPowerStatus_t PowerStatus +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[5] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Report Power Status command */ + I2c_Buffer[0] = 0x05; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_REPORT_POWER_STATUS ; /* Report Power Status*/ + I2c_Buffer[4] = PowerStatus; /* Power Status*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,5); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecFeatureAbort() + \brief This message is used as a reponse to indicate that the device does + not support the requested message type, or that it cannot execute it + at the present time. + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param tmdlHdmiCECFeatureOpcode_t FeatureOpcode \n + Opcode of the aborted message. \n + + \param tmdlHdmiCECAbortReason_t AbortReason \n + The reason why message cannot respond. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecFeatureAbort +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress, + tmdlHdmiCECFeatureOpcode_t FeatureOpcode, + tmdlHdmiCECAbortReason_t AbortReason +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[6] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Feature Abort command */ + I2c_Buffer[0] = 0x06; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_FEATURE_ABORT ; /* Feature Abort*/ + I2c_Buffer[4] = FeatureOpcode; /* Feature Opcode*/ + I2c_Buffer[5] = AbortReason; /* Abort Reason*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,6); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGetCecVersion( ) + \brief This message is used by a device to enquire which version of CEC + the target supports + + \param tmInstance_t Instance \n + Instance identifier. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetCecVersion +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* Get CEC Version command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_GET_CEC_VERSION ; /* Get CEC Version*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecAbortMessage( ) + \brief This message is reserved for testing purposes + + \param tmInstance_t Instance \n + Instance identifier. \n + + \param UInt8 ReceiverLogicalAddress\n + Address of message receiver. \n + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecAbortMessage +( + tmInstance_t Instance, + UInt8 ReceiverLogicalAddress +) +{ + tmErrorCode_t errCode; + unsigned char I2c_Buffer[4] ; /* I2C data buffer */ + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((Instance < 0) || (Instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[Instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if instance state is correct */ + //RETIF(UnitTable[Instance].state != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[Instance]; + + //======To do : make a prepare message function with parameter + /* CEC Abort Message command */ + I2c_Buffer[0] = 0x04; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[Instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= ReceiverLogicalAddress & 0x0F; /* Receiver logical Address*/ + + I2c_Buffer[3] = CEC_OPCODE_ABORT_MESSAGE ; /* Message Abort*/ + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,4); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = I2c_Buffer[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = I2c_Buffer[3]; + + return(TM_OK); +} + +//Non Functional function used to provide easy way to access register + +//========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecGetRegister( ) + \brief Setup the instance with its configuration parameters. This function + allows basic instance configuration for CEC Stack Processor. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure containing all setup parameters + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +unsigned char tmdlHdmiCecGetRegister +( + tmInstance_t instance, + UInt32 offset +) +{ + tmErrorCode_t errCode; + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + unsigned char I2c_ReadBuffer[1]; + + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), 0xFF) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, 0xFF) + + /* Ckeck the state */ + //RETIF(UnitTable[instance].state != CEC_STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + errCode = getCecHwRegisters(pDis, (UInt8) offset,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, 0xff) + + return(I2c_ReadBuffer[0]); +} + +//QB 10 Jan ========================================================================== +/*! + \fn tmErrorCode_t tmdlHdmiCecSetRegister( ) + \brief Setup the instance with its configuration parameters. This function + allows basic instance configuration for CEC Stack Processor. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure containing all setup parameters + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetRegister +( + tmInstance_t instance, + UInt32 offset, + UInt32 value +) +{ + tmErrorCode_t errCode; + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* Ckeck the state */ + //RETIF(UnitTable[instance].state != CEC_STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMICEC_INVALID_STATE) + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + errCode = setCecHwRegister(pDis, (UInt8) offset,(UInt8)value); + RETIF(errCode != TM_OK, errCode) + + return(TM_OK); +} + + + +//========================================================================== +/*! + \brief Set the power state of an instance of the CEC device. ON + state corresponds to a fully supplied, up and running device. Other + modes correspond to the powerdown state of the device. + This function is synchronous. + This function is not ISR friendly. + + + \param instance Instance identifier. + \param powerState Power state to set. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSetPowerState +( + tmInstance_t instance, + tmPowerState_t powerState +) +{ + tmErrorCode_t errCode = TM_OK; + +#ifdef TMFL_TDA9989 + unsigned char I2c_ReadBuffer[1]; + + tmdlHdmiCecDriverConfigTable_t *pDis; + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + if (powerState == tmPowerOn) { + + errCode = getCecHwRegisters(pDis, E_REG_ENAMODS,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + I2c_ReadBuffer[0] |= DEFAULT_ENAMODS; + + errCode = setCecHwRegister(pDis, E_REG_ENAMODS, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + + + } + else if (powerState == tmPowerStandby) { + + errCode = getCecHwRegisters(pDis, E_REG_ENAMODS,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + I2c_ReadBuffer[0] &= ~(DEFAULT_ENAMODS); + + errCode = setCecHwRegister(pDis, E_REG_ENAMODS, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + + UnitTable[instance].state = CEC_STATE_NOT_INITIALIZED; + + } + else { + return TMDL_ERR_DLHDMICEC_BAD_PARAMETER; + } + +#endif /* TMFL_TDA9989 */ + + return errCode; +} + + +//========================================================================== +/*! + \brief Get the power state of an instance of the CEC device. ON + state corresponds to a fully supplied, up and running device. Other + modes correspond to the powerdown state of the device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pPowerState Pointer to the power state. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecGetPowerState +( + tmInstance_t instance, + tmPowerState_t *pPowerState +) +{ + tmErrorCode_t errCode = TM_OK; + +#ifdef TMFL_TDA9989 + + unsigned char I2c_ReadBuffer[1]; + + tmdlHdmiCecDriverConfigTable_t *pDis; + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + if (pPowerState == NULL) return TMDL_ERR_DLHDMICEC_BAD_PARAMETER; + + + errCode = getCecHwRegisters(pDis, E_REG_ENAMODS,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + + if ((I2c_ReadBuffer[0] & DEFAULT_ENAMODS) == DEFAULT_ENAMODS) { + *pPowerState = tmPowerOn; + } + else { + *pPowerState = tmPowerStandby; + } + + +#endif /* TMFL_TDA9989 */ + + return errCode; + +} + +//========================================================================== +/*! + \brief This function allow to send a generic CEC message + This function has to be used when CEC messages are construct in + the middleware + + \param instance Instance identifier. + + \param *pData Pointer to the CEC data buffer + + \param lenData Lenght of I2C data buffer + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent +*/ +//========================================================================== +tmErrorCode_t tmdlHdmiCecSendMessage( + + tmInstance_t instance, + UInt8 *pData, + UInt16 lenData +) +{ + + tmErrorCode_t errCode = TM_OK; + +#ifdef TMFL_TDA9989 + + unsigned char I2c_Buffer[19] ; /* I2C data buffer */ + unsigned char Loci; /* Local increment variable*/ + unsigned char MessLength; /* Local Message length*/ + + tmdlHdmiCecDriverConfigTable_t *pDis; /* Pointer to Device Instance Structure */ + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* check if unit corresponding to instance is opened */ + RETIF(UnitTable[instance].opened == False, TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED) + + /* check if CEC message is not too long */ + RETIF((lenData > 16), TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS) + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + /* Calculate Internal Message length*/ + MessLength = (lenData-1)+3; /* real data is less ReceiverLogical address */ + + I2c_Buffer[0] = MessLength; /* Param number */ + + I2c_Buffer[1] = 0x00; /* Request CEC data */ + + /*Build Initiator and Reciever Logical Address Byte*/ + I2c_Buffer[2] = (unsigned char)(UnitTable[instance].DeviceLogicalAddress) & 0x0F; /*Initiator logical Address*/ + I2c_Buffer[2] = I2c_Buffer[2] << 4; + I2c_Buffer[2] |= pData[0] & 0x0F; + + for(Loci = 0; Loci <= lenData ; Loci++) + { + I2c_Buffer[(Loci+3)] = pData[(Loci+1)]; /* Fill Table with Data from middleware, Data begin at position 1*/ + } + + errCode = setCecHwRegisters(pDis, E_REG_CDR0, I2c_Buffer,MessLength); /* CEC Data register */ + RETIF(errCode != TM_OK, errCode) + + /* Save Datas of the CEC message send */ + gtmdlHdmiCecDriverSaveMessage.AddressByte = pData[2]; + gtmdlHdmiCecDriverSaveMessage.MessageTypePolling = 0; + gtmdlHdmiCecDriverSaveMessage.Opcode = pData[3]; + +#endif /* TMFL_TDA9989 */ + + return errCode; + +} + + + +//========================================================================== +//========================================================================== +tmErrorCode_t tmdlHdmiCecEnableCalibration(tmInstance_t instance,tmdlHdmiCecClockSource_t cecClockSource) +{ + tmErrorCode_t errCode = TM_OK; + +#ifdef TMFL_TDA9989 + + unsigned char I2c_ReadBuffer[1]; + tmdlHdmiCecDriverConfigTable_t *pDis; + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* CLOCK SOURCE is FRO */ + if (cecClockSource == TMDL_HDMICEC_CLOCK_FRO) { + + + + /* cf PR1795 set desired frequency to 12 Mhz*/ + + tmdlHdmiCecSetRegister(instance, 0xF3, 0xC0); + + RETIF(errCode != TM_OK, errCode) + + tmdlHdmiCecSetRegister(instance, 0xF4, 0xD4); + + RETIF(errCode != TM_OK, errCode) + + /* set calibration in automatic mode */ + errCode = getCecHwRegisters(pDis, E_REG_CEC_DES_FREQ2,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + I2c_ReadBuffer[0] &= CEC_AUTOMATIC_CALIBRATION_MSK; + errCode = setCecHwRegister(pDis, E_REG_CEC_DES_FREQ2, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + + + /* select FRO clock mode, osc_freq shall be also set to one */ + I2c_ReadBuffer[0] = CEC_SELECT_FRO_CLOCK_SOURCE; + errCode = setCecHwRegister(pDis, E_REG_CEC_CLK, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + + + /* Enable cec_clk AND FRO */ + errCode = getCecHwRegisters(pDis, E_REG_ENAMODS,I2c_ReadBuffer,1); + RETIF(errCode != TM_OK, errCode) + I2c_ReadBuffer[0] |= CEC_ENABLE_CEC_CLK_MSK; + I2c_ReadBuffer[0] &= CEC_ENABLE_FRO_MSK; + errCode = setCecHwRegister(pDis, E_REG_ENAMODS, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + + /* Enable calibration */ + I2c_ReadBuffer[0] = CEC_ENABLE_CALIBRATION; + errCode = setCecHwRegister(pDis, E_REG_CEC_CAL_XOSC_CTRL1, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + + } /* CLOCK SOURCE is FRO */ + +#endif /* TMFL_TDA9989 */ + + return errCode; +} + + +//========================================================================== +//========================================================================== +tmErrorCode_t tmdlHdmiCecDisableCalibration(tmInstance_t instance) +{ + tmErrorCode_t errCode = TM_OK; + +#ifdef TMFL_TDA9989 + + unsigned char I2c_ReadBuffer[1]; + tmdlHdmiCecDriverConfigTable_t *pDis; + + pDis = >mdlHdmiCecDriverConfigTable[instance]; + + /* check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMICEC_BAD_INSTANCE) + + /* Disable calibration */ + I2c_ReadBuffer[0] = CEC_DISABLE_CALIBRATION; + errCode = setCecHwRegister(pDis, E_REG_CEC_CAL_XOSC_CTRL1, I2c_ReadBuffer[0]); + RETIF(errCode != TM_OK, errCode) + +#endif /* TMFL_TDA9989 */ + + return errCode; +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.c b/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.c new file mode 100755 index 0000000000000..9455ee7e0fd90 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.c @@ -0,0 +1,280 @@ +/** + * Copyright (C) 2006 Koninklijke Philips Electronics N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of Koninklijke Philips Electronics N.V. and is confidential in + * nature. Under no circumstances is this software to be exposed to or placed + * under an Open Source License of any type without the expressed written + * permission of Koninklijke Philips Electronics N.V. + * + * \file tmdlHdmiCEC_local.c + * + * \version $Revision: $ + * + * \date $Date: $ + * + * \brief dev lib driver component for the CEC messages + * + * \section refs Reference Documents + * \section info Change Information + * + * \verbatim + $History: tmdlHdmiCEC_local.c $ + * + \endverbatim + * +*/ + +/*============================================================================*/ +/* FILE CONFIGURATION */ +/*============================================================================*/ + +/* Defining this symbol on the compiler command line excludes some API checks */ +/* #define NO_RETIF_BADPARAM */ + +/*============================================================================*/ +/* STANDARD INCLUDE FILES */ +/*============================================================================*/ + + +/*============================================================================*/ +/* PROJECT INCLUDE FILES */ +/*============================================================================*/ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#else +#include +#endif +#include "tmdlHdmiCEC.h" +#include "tmdlHdmiCEC_local.h" + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* TYPE DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* PUBLIC VARIABLE DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* STATIC VARIABLE DECLARATIONS */ +/*============================================================================*/ + +/** + * Lookup table to map an 8-bit mask to a number of left shifts + * needed to shift a value starting at bit 0 onto the mask. + * Indexed by mask 0-255. For example, mask 0x00 and 0x01 need + * no shift, mask 0x02 needs one shift, mask 0x03 needs no shift, + * mask 0x04 needs 2 shifts, etc. + * Rows were formatted by "HDMI Driver - Register List.xls" and pasted here + */ +static CONST_DAT UInt8 kMaskToShift[256] = +{/* Mask index: */ + /*x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ + 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 0x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 1x */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 2x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 3x */ + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 4x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 5x */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 6x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 7x */ + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 8x */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* 9x */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Ax */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Bx */ + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Cx */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Dx */ + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, /* Ex */ + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 /* Fx */ +}; + +/*============================================================================*/ +/* STATIC FUNCTION DECLARATIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* PUBLIC FUNCTION DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* getCecHwRegisters */ +/*============================================================================*/ +tmErrorCode_t +getCecHwRegisters +( + tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 *pData, + UInt16 lenData + ) +{ + tmErrorCode_t err; /* Error code */ + tmdlHdmiCecSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Get I2C register range - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = (UInt8)lenData; + sysArgs.pData = pData; + err = pDis->i2cReadFunction(&sysArgs); + return (err == TM_OK) ? TM_OK : TMDL_ERR_DLHDMICEC_I2C_READ; +} + +/*============================================================================*/ +/* getCecHwRegister */ +/*============================================================================*/ +tmErrorCode_t +getCecHwRegister +( + tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 *pRegValue +) +{ + tmErrorCode_t err; /* Error code */ + tmdlHdmiCecSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Get I2C register - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = pRegValue; + err = pDis->i2cReadFunction(&sysArgs); + return (err == TM_OK) ? TM_OK : TMDL_ERR_DLHDMICEC_I2C_READ; + +} + +/*============================================================================*/ +/* setCecHwRegisters */ +/*============================================================================*/ +tmErrorCode_t +setCecHwRegisters +( + tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 *pData, + UInt16 lenData + ) +{ + tmErrorCode_t err; /* Error code */ + tmdlHdmiCecSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Write to I2C register range - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = (UInt8)lenData; + sysArgs.pData = pData; + err = pDis->i2cWriteFunction(&sysArgs); + return (err == TM_OK) ? TM_OK : TMDL_ERR_DLHDMICEC_I2C_WRITE; +} + +/*============================================================================*/ +/* setCecHwRegisterMsbLsb */ +/*============================================================================*/ +tmErrorCode_t +setCecHwRegisterMsbLsb +( + tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt16 regWord +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 msbLsb[2]; /* The bytes from regWord */ + tmdlHdmiCecSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Unpack regWord bytes, MSB first */ + msbLsb[0] = (UInt8)(regWord >> 8); + msbLsb[1] = (UInt8)(regWord & 0xFF); + + /* Write to I2C - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 2; + sysArgs.pData = &msbLsb[0]; + err = pDis->i2cWriteFunction(&sysArgs); + return (err == TM_OK) ? TM_OK : TMDL_ERR_DLHDMICEC_I2C_WRITE; +} + +/*============================================================================*/ +/* setCecHwRegister */ +/*============================================================================*/ +tmErrorCode_t +setCecHwRegister +( + tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 regValue +) +{ + tmErrorCode_t err; /* Error code */ + tmdlHdmiCecSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Write to I2C - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + err = pDis->i2cWriteFunction(&sysArgs); + return (err == TM_OK) ? TM_OK : TMDL_ERR_DLHDMICEC_I2C_WRITE; +} + +/*============================================================================*/ +/* setCecHwRegisterField */ +/*============================================================================*/ +tmErrorCode_t +setCecHwRegisterField +( + tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 fieldMask, + UInt8 fieldValue +) +{ + tmErrorCode_t err; /* Error code */ + UInt8 regValue; /* The register's current value */ + tmdlHdmiCecSysArgs_t sysArgs; /* Arguments passed to system function */ + + /* Read I2C register value. + * All bitfield registers are either shadowed or can be read. + */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + err = pDis->i2cReadFunction(&sysArgs); + RETIF(err != TM_OK, TMDL_ERR_DLHDMICEC_I2C_READ) + + /* Reset register bits that are set in the mask */ + regValue = regValue & (UInt8)(~fieldMask); + + /* Shift the field value left to align its bits with the mask */ + fieldValue <<= kMaskToShift[fieldMask]; + + /* Reset shifted field bits that are not set in the mask */ + fieldValue &= fieldMask; + + /* Set the shifted bitfield */ + regValue |= fieldValue; + + /* Write to I2C - all non-OK results are errors */ + sysArgs.slaveAddr = pDis->i2cAddress; + sysArgs.firstRegister = regAddr; + sysArgs.lenData = 1; + sysArgs.pData = ®Value; + err = pDis->i2cWriteFunction(&sysArgs); + return (err == TM_OK) ? TM_OK : TMDL_ERR_DLHDMICEC_I2C_WRITE; +} + + +/*============================================================================*/ +/* STATIC FUNCTION DEFINTIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.h b/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.h new file mode 100755 index 0000000000000..ae83e151b33ab --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiCEC/src/tmdlHdmiCEC_local.h @@ -0,0 +1,221 @@ +//============================================================================= +// Copyright (C) 2007 NXP N.V., All Rights Reserved. +// This source code and any compilation or derivative thereof is the proprietary +// information of NXP N.V. and is confidential in nature. Under no circumstances +// is this software to be exposed to or placed under an Open Source License of +// any type without the expressed written permission of NXP N.V. +//============================================================================= +/*! + \file tmdlHdmiCEC_local.h + + \version 1.0 + + \date 24/07/2007 + + \brief devlib driver component API for the CEC messages. + + \section refs Reference Documents + TDA998X Driver - tmdlHdmiTx - SCS.doc + \note None. + + HISTORY : + \verbatim + Date Modified by CRPRNr TASKNr Maintenance description + -------------|-----------|-------|-------|----------------------------------- + 24/07/2007 | F.G | | | Creation. + -------------|-----------|-------|-------|----------------------------------- + \endverbatim +*/ +//========================================================================== + +#ifndef TMDLHDMICEC_LOCAL_H +#define TMDLHDMICEC_LOCAL_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ +//#include "tmdlHdmiCEC_IW.h" +#include "tmdlHdmiCEC_cfg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + +/* Version of the SW driver */ +#define VERSION_COMPATIBILITY 0 +#define VERSION_MAJOR 1 +#define VERSION_MINOR 4 + +/** + * A macro to check a condition and if true return a result + */ +#define RETIF(cond, rslt) if ((cond)){return (rslt);} + +/** + * A macro to check a condition and if true return + * TMBSL_ERR_HDMI_BAD_PARAMETER. + * To save code space, it can be compiled out by defining NO_RETIF_BADPARAM on + * the compiler command line. + */ +#ifdef NO_RETIF_BADPARAM +#define RETIF_BADPARAM(cond) +#else +#define RETIF_BADPARAM(cond) if ((cond)){return TMBSL_ERR_HDMI_BAD_PARAMETER;} +#endif + +/** + * A macro to check the result of a register API and if not TM_OK to return it. + * To save code space, it can be compiled out by defining NO_RETIF_REG_FAIL on + * the compiler command line. + */ +#ifdef NO_RETIF_REG_FAIL +#define RETIF_REG_FAIL(result) +#else +#define RETIF_REG_FAIL(result) if ((result) != TM_OK){return (result);} +#endif + +#define TDA9950_RESET_DELAY_MS 250 + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +#ifdef TMFL_TDA9989 + +#define E_REG_ENAMODS 0xFF +#define E_REG_CEC_CLK 0xF6 +#define E_REG_CEC_INT 0xEE +#define E_REG_COMBI_INT 0xEC +#define DEFAULT_ENAMODS 0x81 +#define CEC_CLK_SEL 0xE6 +#define CEC_INT_MASK 0x01 + +#define E_REG_CEC_CAL_XOSC_CTRL1 0xF2 +#define E_REG_CEC_DES_FREQ2 0xF5 + + +#define CEC_AUTOMATIC_CALIBRATION_MSK 0x7F +#define CEC_SELECT_FRO_CLOCK_SOURCE 0x11 +#define CEC_ENABLE_CEC_CLK_MSK 0x80 +#define CEC_ENABLE_FRO_MSK 0xBF +#define CEC_ENABLE_CALIBRATION 0x01 +#define CEC_DISABLE_CALIBRATION 0x00 + + +#endif /* TMFL_TDA9989 */ + +/*! + \enum CEC Stack Processor Regsiters + \brief The CSP is controlled via a series of registers +*/ + +enum _eReg +{ + E_REG_APR = 0x00, /*!< Address Pointer Regsiter (Write) */ + E_REG_CSR = 0x00, /*!< CSP Status Register (Read) */ + E_REG_CER = 0x01, /*!< CSP Error Register (Read) */ + E_REG_CVR = 0x02, /*!< CSP Version Register(Read) */ + E_REG_CCR = 0x03, /*!< CSP Control Register (Read/Write) */ + E_REG_ACKH = 0x04, /*!< CEC Address ACK High Register (Read/Write) */ + E_REG_ACKL = 0x05, /*!< CEC Address ACK Low Register (Read/Write) */ + E_REG_CCONR = 0x06, /*!< CEC Config Register (Read/Write) */ + E_REG_CDR0 = 0x07, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR1 = 0x08, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR2 = 0x09, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR3 = 0x0A, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR4 = 0x0B, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR5 = 0x0C, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR6 = 0x0D, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR7 = 0x0E, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR8 = 0x0F, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR9 = 0x10, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR10 = 0x11, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR11 = 0x12, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR12 = 0x13, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR13 = 0x14, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR14 = 0x15, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR15 = 0x16, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR16 = 0x17, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR17 = 0x18, /*!< CEC Data Register (Read/Write) */ + E_REG_CDR18 = 0x19 /*!< CEC Data Register (Read/Write) */ +}; + + +/* possible states of the state driver */ +typedef enum +{ + CEC_STATE_NOT_INITIALIZED, /**< Driver is not initialized */ + CEC_STATE_UNLOCKED , /**< Driver is not locked */ + CEC_STATE_LOCKED, /**< Driver is locked */ + CEC_STATE_CONFIGURED /**< Driver is configured */ +} tmdlHdmiCecDriverState_t; + +/** + * \brief The structure of a CEC object, one per device unit +*/ +typedef struct +{ + tmInstance_t instance; + tmdlHdmiCECLogicalAddress_t DeviceLogicalAddress; + Bool opened; /**< is unit instanciated ? */ + tmdlHdmiCecDeviceVersion_t deviceVersion; /**< Version of the HW device */ + tmdlHdmiCecDriverState_t state; /**< Current state of the driver */ + ptmdlHdmiCecCallbackFunc_t MessageCallback; /**< Message callback */ +}tmdlHdmiCecUnitConfig_t; + + +/** + * \brief States of CEC Status +*/ +#define CEC_MSG_SUCCESS 0x00 /*Message transmisson Succeed*/ +#define CEC_CSP_OFF_STATE 0x80 /*CSP in Off State*/ +#define CEC_BAD_REQ_SERVICE 0x81 /*Bad .req service*/ +#define CEC_MSG_FAIL_UNABLE_TO_ACCESS 0x82 /*Message transmisson failed: Unable to access CEC line*/ +#define CEC_MSG_FAIL_ARBITRATION_ERROR 0x83 /*Message transmisson failed: Arbitration error*/ +#define CEC_MSG_FAIL_BIT_TIMMING_ERROR 0x84 /*Message transmisson failed: Bit timming error*/ +#define CEC_MSG_FAIL_DEST_NOT_ACK 0x85 /*Message transmisson failed: Destination Address not aknowledged*/ +#define CEC_MSG_FAIL_DATA_NOT_ACK 0x86 /*Message transmisson failed: Databyte not acknowledged*/ + + +/*============================================================================*/ +/* EXTERN DATA DEFINITION */ +/*============================================================================*/ + +extern tmdlHdmiCecDriverConfigTable_t gtmdlHdmiCecDriverConfigTable[MAX_UNITS]; + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +tmErrorCode_t getCecHwRegisters (tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 *pData, UInt16 lenData); +tmErrorCode_t getCecHwRegister (tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 *pRegValue); +tmErrorCode_t setCecHwRegisters (tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 *pData, UInt16 lenData); +tmErrorCode_t setCecHwRegisterMsbLsb (tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt16 regWord); +tmErrorCode_t setCecHwRegister (tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 regValue); +tmErrorCode_t setCecHwRegisterField (tmdlHdmiCecDriverConfigTable_t *pDis, + UInt8 regAddr, + UInt8 fieldMask, UInt8 fieldValue); + + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMI_CEC_LOCAL_H */ +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c new file mode 100755 index 0000000000000..35f4b7e1b40b6 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c @@ -0,0 +1,570 @@ +/** + * Copyright (C) 2009 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_LinuxCfg.c + * + * \version Revision: 1 + * + * \date Date: 25/03/11 11:00 + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * + * \section info Change Information + * + * \verbatim + + History: tmdlHdmiTx_LinuxCfg.c + * + * ***************** Version 2 ***************** + * User: V. Vrignaud Date: March 25th, 2011 + * + * ***************** Version 1 ***************** + * User: A. Lepine Date: October 1st, 2009 + * initial version + * + + \endverbatim + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +/*============================================================================*/ +/* MACRO */ +/*============================================================================*/ +/* macro for quick error handling */ +#define RETIF(cond, rslt) if ((cond)){return (rslt);} +#define I2C_M_WR 0 + +/*============================================================================*/ +/* STATIC FUNCTION DECLARATIONS */ +/*============================================================================*/ +tmErrorCode_t TxI2cReadFunction(tmbslHdmiTxSysArgs_t *pSysArgs); +tmErrorCode_t TxI2cWriteFunction(tmbslHdmiTxSysArgs_t *pSysArgs); + +/****************************************************************************** + ****************************************************************************** + * THIS PART CAN BE MODIFIED BY CUSTOMER * + ****************************************************************************** + *****************************************************************************/ +struct i2c_client *GetThisI2cClient(void); +unsigned char my_i2c_data[255]; + +/* The following includes are used by I2C access function. If */ +/* you need to rewrite these functions for your own SW infrastructure, then */ +/* it can be removed */ +# include +# include +# include +# include +# include +# include + +#include + +#include +#include +#include +#include + +/* I2C adress of the unit */ +/* Put there the I2C slave adress of the Tx transmitter IC */ +#define UNIT_I2C_ADDRESS_0 0x70 + +/* Intel CE 4100 I2C bus number */ +/* Put there the number of I2C bus handling the Rx transmitter IC */ +#define I2C_BUS_NUMBER_0 0 // initial:0 + +/* I2C Number of bytes in the data buffer. */ +#define SUB_ADDR_BYTE_COUNT_0 1 + +/* Priority of the command task */ +/* Command task is an internal task that handles incoming event from the IC */ +/* put there a value that will ensure a response time of ~20ms in your system */ +#define COMMAND_TASK_PRIORITY_0 250 +#define COMMAND_TASK_PRIORITY_1 250 + +/* Priority of the hdcp check tasks */ +/* HDCP task is an internal task that handles periodical HDCP processing */ +/* put there a value that will ensure a response time of ~20ms in your system */ +#define HDCP_CHECK_TASK_PRIORITY_0 250 + +/* Stack size of the command tasks */ +/* This value depends of the type of CPU used, and also from the length of */ +/* the customer callbacks. Increase this value if you are making a lot of */ +/* processing (function calls & local variables) and that you experience */ +/* stack overflows */ +#define COMMAND_TASK_STACKSIZE_0 128 +#define COMMAND_TASK_STACKSIZE_1 128 + +/* stack size of the hdcp check tasks */ +/* This value depends of the type of CPU used, default value should be enough */ +/* for all configuration */ +#define HDCP_CHECK_TASK_STACKSIZE_0 128 + +/* Size of the message queues for command tasks */ +/* This value defines the size of the message queue used to link the */ +/* the tmdlHdmiTxHandleInterrupt function and the command task. The default */ +/* value below should fit any configuration */ +#define COMMAND_TASK_QUEUESIZE_0 128 +#define COMMAND_TASK_QUEUESIZE_1 128 + +/* HDCP key seed */ +/* HDCP key are stored encrypted into the IC, this value allows the IC to */ +/* decrypt them. This value is provided to the customer by NXP customer */ +/* support team. */ +#define KEY_SEED 0x1234 + +/* Video port configuration for YUV444 input */ +/* You can specify in this table how are connected video ports in case of */ +/* YUV444 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignal444 videoPortMapping_YUV444[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID444_BU_0_TO_3, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID444_BU_4_TO_7, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VID444_GY_0_TO_3, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID444_GY_4_TO_7, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VID444_VR_0_TO_3, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID444_VR_4_TO_7 /* Signals connected to VPC[4..7] */ + } +}; + +/* Video port configuration for RGB444 input */ +/* You can specify in this table how are connected video ports in case of */ +/* RGB444 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignal444 videoPortMapping_RGB444[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID444_GY_0_TO_3, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID444_GY_4_TO_7, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VID444_BU_0_TO_3, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID444_BU_4_TO_7, /* Signals connected to VPC[4..7] */ + TMDL_HDMITX_VID444_VR_0_TO_3, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID444_VR_4_TO_7 /* Signals connected to VPB[4..7] */ + } +}; + +/* Video port configuration for YUV422 input */ +/* You can specify in this table how are connected video ports in case of */ +/* YUV422 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignal422 videoPortMapping_YUV422[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID422_Y_4_TO_7, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID422_Y_8_TO_11, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VID422_UV_4_TO_7, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID422_UV_8_TO_11, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VID422_NOT_CONNECTED, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID422_NOT_CONNECTED /* Signals connected to VPC[4..7] */ + } +}; + +/* Video port configuration for CCIR656 input */ +/* You can specify in this table how are connected video ports in case of */ +/* CCIR656 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignalCCIR656 videoPortMapping_CCIR656[MAX_UNITS][6] = { + { + TMDL_HDMITX_VIDCCIR_4_TO_7, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VIDCCIR_8_TO_11, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED /* Signals connected to VPC[4..7] */ + } +}; + +/* + * + * Linux wrapping starts here............................... + * + */ +/* + * Write a bloc to a register in Tx device. + */ +int blockwrite_reg(struct i2c_client *client, u8 reg, u16 alength, u8 *val) +{ + int err = 0; + int i; + struct i2c_msg msg[1]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = alength+1; + msg->buf = my_i2c_data; + + msg->buf[0] = reg; + for (i=1; i<=alength; i++) msg->buf[i] = (*val++); + + err = i2c_transfer(client->adapter, msg, 1); + udelay(50); + + +/* printk(KERN_INFO "DBG blockwrite_reg addr:%x reg:%d data:%x %s\n",msg->addr,reg,val,(err<0?"ERROR":"")); */ + +/* dev_dbg(&client->dev, "<%s> i2c Block write at 0x%x, " */ +/* "*val=%d flags=%d byte[%d] err=%d\n", */ +/* __func__, data[0], data[1], msg->flags, i, err); */ + + return (err < 0?err:0); +} + +/* + * Read a bloc to a register in Tx device. + */ +int blockread_reg(struct i2c_client *client, u8 reg, u16 alength, u8 *val) +{ + int err = 0; + struct i2c_msg msg[1]; + u8 data[2]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 1; + msg->buf = data; + data[0] = reg; /* High byte goes out first */ + err = i2c_transfer(client->adapter, msg, 1); +/* printk(KERN_INFO "DBG blockread_reg #1 addr:%x len:%d buf:%02x%02x%02x%02x %s\n",msg->addr,msg->len,\ */ +/* msg->buf[0],msg->buf[1],msg->buf[2],msg->buf[3],(err<0?"ERROR":"")); */ + if (err<0) goto BLOCK_READ_OUPS; + + msg->flags = I2C_M_RD; + msg->len = alength; + msg->buf = val; + err = i2c_transfer(client->adapter, msg, 1); +/* printk(KERN_INFO "DBG blockread_reg #2 addr:%x len:%d buf:%02x%02x%02x%02x %s\n",msg->addr,msg->len,\ */ +/* msg->buf[0],msg->buf[1],msg->buf[2],msg->buf[3],(err<0?"ERROR":"")); */ + + if (err<0) goto BLOCK_READ_OUPS; + + return 0; + + BLOCK_READ_OUPS: + dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, " + "*val=%d flags=%d bytes err=%d\n", + __func__, reg, *val, msg->flags, err); + + return err; +} + +/* + * Write a byte to a register in Tx device. + */ +int write_reg(struct i2c_client *client, u8 reg, u8 val) +{ + int err = 0; + struct i2c_msg msg[1]; + u8 data[2]; + int retries = 0; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + retry: + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 2; + msg->buf = data; + + data[0] = reg; + data[1] = val; + + err = i2c_transfer(client->adapter, msg, 1); + dev_dbg(&client->dev, "<%s> i2c write at=%x " + "val=%x flags=%d err=%d\n", + __func__, data[0], data[1], msg->flags, err); + udelay(50); + +/* printk(KERN_INFO "DBG write_reg addr:%x reg:%d data:%x %s\n",msg->addr,reg,val,(err<0?"ERROR":"")); */ + + if (err >= 0) + return 0; + + dev_err(&client->dev, "<%s> ERROR: i2c write at=%x " + "val=%x flags=%d err=%d\n", + __func__, data[0], data[1], msg->flags, err); + if (retries <= 5) { + dev_info(&client->dev, "Retrying I2C... %d\n", retries); + retries++; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(msecs_to_jiffies(20)); + goto retry; + } + + return err; +} + +/* + * Read a byte from a register in Tx device. + */ +int read_reg(struct i2c_client *client, u16 data_length, u8 reg, u8 *val) +{ + int err = 0; + struct i2c_msg msg[1]; + u8 data[2]; + + if (!client->adapter) { + dev_err(&client->dev, "<%s> ERROR: No HDMI Device\n", __func__); + return -ENODEV; + } + + msg->addr = client->addr; + msg->flags = I2C_M_WR; + msg->len = 1; + msg->buf = data; + + data[0] = reg; + err = i2c_transfer(client->adapter, msg, 1); + dev_dbg(&client->dev, "<%s> i2c Read1 reg=%x val=%d " + "flags=%d err=%d\n", + __func__, reg, data[1], msg->flags, err); + + if (err >= 0) { + mdelay(3); + msg->flags = I2C_M_RD; + msg->len = data_length; + err = i2c_transfer(client->adapter, msg, 1); + } + + if (err >= 0) { + *val = 0; + if (data_length == 1) + *val = data[0]; + else if (data_length == 2) + *val = data[1] + (data[0] << 8); + dev_dbg(&client->dev, "<%s> i2c Read2 at 0x%x, *val=%d " + "flags=%d err=%d\n", + __func__, reg, *val, msg->flags, err); + return 0; + } + + dev_err(&client->dev, "<%s> ERROR: i2c Read at 0x%x, " + "*val=%d flags=%d err=%d\n", + __func__, reg, *val, msg->flags, err); + + return err; +} +/* + * + * Linux wrapping end............................... + * + */ + +/* The following function must be rewritten by the customer to fit its own */ +/* SW infrastructure. This function allows reading through I2C bus. */ +/* tmbslHdmiTxSysArgs_t definition is located into tmbslHdmiTx_type.h file. */ +tmErrorCode_t TxI2cReadFunction(tmbslHdmiTxSysArgs_t *pSysArgs) +{ + tmErrorCode_t errCode = TM_OK; + struct i2c_client *client=GetThisI2cClient(); + u32 client_main_addr=client->addr; + + /* DevLib needs address control, so let it be */ + client->addr=pSysArgs->slaveAddr; + + if (pSysArgs->lenData == 1) { + /* single byte */ + errCode = read_reg(GetThisI2cClient(),1,pSysArgs->firstRegister,pSysArgs->pData); + } + else { + /* block */ + errCode = blockread_reg(GetThisI2cClient(), \ + pSysArgs->firstRegister, \ + pSysArgs->lenData, \ + pSysArgs->pData); + } + + /* restore default client address */ + client->addr=client_main_addr; + + return errCode; +} + +/* The following function must be rewritten by the customer to fit its own */ +/* SW infrastructure. This function allows writing through I2C bus. */ +/* tmbslHdmiTxSysArgs_t definition is located into tmbslHdmiTx_type.h file. */ +tmErrorCode_t TxI2cWriteFunction(tmbslHdmiTxSysArgs_t *pSysArgs) +{ + tmErrorCode_t errCode = TM_OK; + struct i2c_client *client=GetThisI2cClient(); + u32 client_main_addr=client->addr; + + /* DevLib needs address control, so let it be */ + client->addr=pSysArgs->slaveAddr; + + if (pSysArgs->lenData == 1) { + /* single byte */ + errCode = write_reg(GetThisI2cClient(),pSysArgs->firstRegister,*pSysArgs->pData); + } + else { + /* block */ + errCode = blockwrite_reg(GetThisI2cClient(), \ + pSysArgs->firstRegister, \ + pSysArgs->lenData, \ + pSysArgs->pData); + } + + /* restore default client address */ + client->addr=client_main_addr; + + return errCode; +} + + +/****************************************************************************** + \brief This function blocks the current task for the specified amount time. + This is a passive wait. + + \param Duration Duration of the task blocking in milliseconds. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWWait +( + UInt16 duration +) +{ + mdelay((unsigned long)duration); + + return(TM_OK); +} + +/****************************************************************************** + \brief This function creates a semaphore. + + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreCreate +( + tmdlHdmiTxIWSemHandle_t *pHandle +) +{ + struct semaphore * mutex; + + /* check that input pointer is not NULL */ + RETIF(pHandle == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + mutex = (struct semaphore *)kmalloc(sizeof(struct semaphore),GFP_KERNEL); + if (!mutex) { + printk(KERN_ERR "malloc failed in %s\n",__func__); + return TMDL_ERR_DLHDMITX_NO_RESOURCES; + } + + sema_init(mutex, 1); + *pHandle = (tmdlHdmiTxIWSemHandle_t)mutex; + + RETIF(pHandle == NULL, TMDL_ERR_DLHDMITX_NO_RESOURCES) + + return(TM_OK); +} + +/****************************************************************************** + \brief This function destroys an existing semaphore. + + \param Handle Handle of the semaphore to be destroyed. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreDestroy +( + tmdlHdmiTxIWSemHandle_t handle +) +{ + RETIF(handle == False, TMDL_ERR_DLHDMITX_BAD_HANDLE); + + if (atomic_read((atomic_t*)&((struct semaphore *)handle)->count) < 1) { + printk(KERN_ERR "release catched semaphore"); + } + + kfree((void*)handle); + + return(TM_OK); +} + +/****************************************************************************** + \brief This function acquires the specified semaphore. + + \param Handle Handle of the semaphore to be acquired. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreP +( + tmdlHdmiTxIWSemHandle_t handle +) +{ + down((struct semaphore *)handle); + + return(TM_OK); +} + +/****************************************************************************** + \brief This function releases the specified semaphore. + + \param Handle Handle of the semaphore to be released. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreV +( + tmdlHdmiTxIWSemHandle_t handle +) +{ + up((struct semaphore *)handle); + + return(TM_OK); +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_cfg.c b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_cfg.c new file mode 100755 index 0000000000000..79fd636769320 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_cfg.c @@ -0,0 +1,624 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_cfg.c + * + * \version Revision: 1 + * + * \date Date: 25/03/11 11:00 + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * + * \section info Change Information + * + * \verbatim + + History: tmdlHdmiTx_cfg.c + * + * ***************** Version 2 ***************** + * User: V. Vrignaud Date: March 25th, 2011 + * + * ***************** Version 1 ***************** + * User: J. Lamotte Date: 08/08/07 Time: 11:00 + * initial version + * + + \endverbatim + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmdlHdmiTx_IW.h" +#include "tmdlHdmiTx.h" +#include "tmdlHdmiTx_cfg.h" + +#ifdef TMFL_CEC_AVAILABLE +#include "tmdlHdmiCEC_functions.h" +#define CEC_UNIT_I2C_ADDRESS_0 0x34 +#define CEC_UNIT_I2C_ADDRESS_1 0x34 +#endif + +//#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#ifdef TMFL_CFG_ZOOMII // OMAP Zoom II +# include "tmdlHdmiTx_Linux_cfg.c" +#elif TMFL_CFG_INTELCE4100 // Intel CE 4100 +# include "tmdlHdmiTx_IntelCE4100_cfg.c" +#elif TMFL_OS_WINDOWS // Windows demo application +# include "tmdlHdmiTx_Win_cfg.c" +#else // Section to be modified by customer - Default configuration for NXP evalkit + +/*============================================================================*/ +/* MACRO */ +/*============================================================================*/ + +/*============================================================================*/ +/* STATIC FUNCTION DECLARATIONS */ +/*============================================================================*/ +tmErrorCode_t TxI2cReadFunction(tmbslHdmiTxSysArgs_t *pSysArgs); +tmErrorCode_t TxI2cWriteFunction(tmbslHdmiTxSysArgs_t *pSysArgs); + +/****************************************************************************** + ****************************************************************************** + * THIS PART CAN BE MODIFIED BY CUSTOMER * + ****************************************************************************** + *****************************************************************************/ +/* The following includes are used by I2C access function for ARM7. If */ +/* you need to rewrite these functions for your own SW infrastructure, then */ +/* it can be removed */ +#include "I2C.h" +#include + +/* I2C adress of the unit */ +/* Put there the I2C slave adress of the Tx transmitter IC */ +#define UNIT_I2C_ADDRESS_0 0x70 + +/* Priority of the command task */ +/* Command task is an internal task that handles incoming event from the IC */ +/* put there a value that will ensure a response time of ~20ms in your system */ +#define COMMAND_TASK_PRIORITY_0 250 +#define COMMAND_TASK_PRIORITY_1 250 + +/* Priority of the hdcp check tasks */ +/* HDCP task is an internal task that handles periodical HDCP processing */ +/* put there a value that will ensure a response time of ~20ms in your system */ +#define HDCP_CHECK_TASK_PRIORITY_0 250 + +/* Stack size of the command tasks */ +/* This value depends of the type of CPU used, and also from the length of */ +/* the customer callbacks. Increase this value if you are making a lot of */ +/* processing (function calls & local variables) and that you experience */ +/* stack overflows */ +#define COMMAND_TASK_STACKSIZE_0 128 +#define COMMAND_TASK_STACKSIZE_1 128 + +/* stack size of the hdcp check tasks */ +/* This value depends of the type of CPU used, default value should be enough */ +/* for all configuration */ +#define HDCP_CHECK_TASK_STACKSIZE_0 128 + +/* Size of the message queues for command tasks */ +/* This value defines the size of the message queue used to link the */ +/* the tmdlHdmiTxHandleInterrupt function and the command task. The default */ +/* value below should fit any configuration */ +#define COMMAND_TASK_QUEUESIZE_0 128 +#define COMMAND_TASK_QUEUESIZE_1 128 + +/* HDCP key seed */ +/* HDCP key are stored encrypted into the IC, this value allows the IC to */ +/* decrypt them. This value is provided to the customer by NXP customer */ +/* support team. */ +#define KEY_SEED 0x1234 + +/* Video port configuration for YUV444 input */ +/* You can specify in this table how are connected video ports in case of */ +/* YUV444 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignal444 videoPortMapping_YUV444[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID444_GY_0_TO_3, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID444_GY_4_TO_7, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VID444_BU_0_TO_3, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID444_BU_4_TO_7, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VID444_VR_0_TO_3, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID444_VR_4_TO_7 /* Signals connected to VPC[4..7] */ + } +}; + +/* Video port configuration for RGB444 input */ +/* You can specify in this table how are connected video ports in case of */ +/* RGB444 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignal444 videoPortMapping_RGB444[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID444_GY_0_TO_3, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID444_GY_4_TO_7, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VID444_BU_0_TO_3, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID444_BU_4_TO_7, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VID444_VR_0_TO_3, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID444_VR_4_TO_7 /* Signals connected to VPC[4..7] */ + } +}; + +/* Video port configuration for YUV422 input */ +/* You can specify in this table how are connected video ports in case of */ +/* YUV422 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignal422 videoPortMapping_YUV422[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID422_NOT_CONNECTED, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID422_NOT_CONNECTED, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VID422_UV_4_TO_7, /* Signals connected to VPC[4..7] */ + TMDL_HDMITX_VID422_UV_8_TO_11, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID422_Y_4_TO_7, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID422_Y_8_TO_11 /* Signals connected to VPA[4..7] */ + } +}; + +/* Video port configuration for CCIR656 input */ +/* You can specify in this table how are connected video ports in case of */ +/* CCIR656 input signal. Each line of the array corresponds to a quartet of */ +/* pins of one video port (see comment on the left to identify them). Just */ +/* change the enum to specify which signal you connected to it. See file */ +/* tmdlHdmiTx_cfg.h to get the list of possible values */ +const tmdlHdmiTxCfgVideoSignalCCIR656 videoPortMapping_CCIR656[MAX_UNITS][6] = { + { + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED, /* Signals connected to VPC[4..7] */ + TMDL_HDMITX_VIDCCIR_4_TO_7, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VIDCCIR_8_TO_11 /* Signals connected to VPA[0..3] */ + } +}; + +/* The following function must be rewritten by the customer to fit its own */ +/* SW infrastructure. This function allows reading through I2C bus. */ +/* tmbslHdmiTxSysArgs_t definition is located into tmbslHdmiTx_type.h file. */ +tmErrorCode_t TxI2cReadFunction(tmbslHdmiTxSysArgs_t *pSysArgs) +{ + tmErrorCode_t errCode = TM_OK; + + if (pSysArgs->slaveAddr == 0x70) + { + errCode = i2cRead(reg_TDA998X, (tmbslHdmiSysArgs_t *) pSysArgs); + } + else if (pSysArgs->slaveAddr == 0x34) + { + errCode = i2cRead(reg_TDA9989_CEC, (tmbslHdmiSysArgs_t *) pSysArgs); + } + else + { + errCode = ~TM_OK; + } + + return errCode; +} + +/* The following function must be rewritten by the customer to fit its own */ +/* SW infrastructure. This function allows writing through I2C bus. */ +/* tmbslHdmiTxSysArgs_t definition is located into tmbslHdmiTx_type.h file. */ +tmErrorCode_t TxI2cWriteFunction(tmbslHdmiTxSysArgs_t *pSysArgs) +{ + tmErrorCode_t errCode = TM_OK; + + if (pSysArgs->slaveAddr == 0x70) + { + errCode = i2cWrite(reg_TDA998X, (tmbslHdmiSysArgs_t *) pSysArgs); + + } + else if (pSysArgs->slaveAddr == 0x34) + { + errCode = i2cWrite(reg_TDA9989_CEC, (tmbslHdmiSysArgs_t *) pSysArgs); + } + else + { + errCode = ~TM_OK; + } + + return errCode; +} + +#endif + +#ifdef TMFL_RGB_DDR_12BITS + +/* Video port configuration for RGB 24 bits input received with only 12 bits */ +/* using the double data rate */ +/* + The main difference between RGB12 bits and CCIR 656 formats is that for the new format + RGB888 the“Green� data is separated on rising and on falling edge. This is in principle + no problem only the result is that the colors RGB will be swabbed. + After the Video Input Processing (VIP) module there will be a multiplexer structure + implemented which can swab all colors and combinations. + + Extra information on request + + P:\Partages\BCT_TV_FE\Product_Development\Project folders\TDA19988 \ + 14_Design\Video_pipe_Schematic_RGB888.pdf + + but ok, let's give it a try... + + In DDR, VIP input latches on failing and raising clock edge, + so VIP internal input is doubled from 24 to 48 bits + + VIP input ------>[ T ]---[ T ]--------------------> VIP internal input + /24 | | ° /24 | /48 + | | | | + | pclk----------- | + | | | + | ° | + ------>[ T ]------------------ + /24 + + But in the 24 VIP input, only 12 bits are used : + + ------------------------------------------------------------------- + | | | | | | | + | Vpc[7:4] | Vpc[3:0] | Vpb[7:4] | Vpb[3:0] | Vpa[7:4] | Vpa[3:0] | + | | | ........ | | ........ | ........ | + ------------------------------------------------------------------- + ^ ^ ^ + | | | + | | | + location of valid data ------------------------------------- + + So we get first RGB 12 bits on bits 24 to 47 of VIP internal input + and second RGB 12 bits on bits 0 to 23 of VIP internal input + + 1)first edge (failing) R[7:4] R[3:0] G[7:4] + | | | + | | | + V V V + --------------------------------------------------------------------.. + | | | | | | | + | 47...44 | 43...40 | 39...36 | 35...32 | 31...28 | 27...24 | + | | | | | | | + --------------------------------------------------------------------.. + + 2)2nd edge (raising) G[3:0] B[7:3] B[3:0] + | | | + | | | + V V V +..------------------------------------------------------------------- + | | | | | | | + | 23...20 | 19...16 | 15...12 | 11...8 | 7...4 | 3...0 | + | | | | | | | +..------------------------------------------------------------------- + + + + + + + After port swaping, internal video bus goes back from 48 to 24 bits + + VIP internal ------------>[ swap ]-------[ T ]----------> + /48 | | /24 + | | + i2c_swap_a/f ------ pclk --- + + ------------------------------------------------------------------- + | | | | | | | + | 23...20 | 19...16 | 15...12 | 11...8 | 7...4 | 3...0 | + | | | | | | | + ------------------------------------------------------------------- + R[7:4] R[3:0] G[7:4] G[3:0] B[7:3] B[3:0] + + Here is the swapping code : + +IF i2c_swap_a = "000" THEN vp_alt_d2(11 downto 8) <= vp_alt_i_r(23 downto 20); vp_alt_d2(23 downto 20) <= vp_alt_i_r(47 downto 44); +ELSIF i2c_swap_a = "001" THEN vp_alt_d2(11 downto 8) <= vp_alt_i_r(19 downto 16); vp_alt_d2(23 downto 20) <= vp_alt_i_r(43 downto 40); +ELSIF i2c_swap_a = "010" THEN vp_alt_d2(11 downto 8) <= vp_alt_i_r(15 downto 12); vp_alt_d2(23 downto 20) <= vp_alt_i_r(39 downto 36); +ELSIF i2c_swap_a = "011" THEN vp_alt_d2(11 downto 8) <= vp_alt_i_r(11 downto 8 ); vp_alt_d2(23 downto 20) <= vp_alt_i_r(35 downto 32); +ELSIF i2c_swap_a = "100" THEN vp_alt_d2(11 downto 8) <= vp_alt_i_r( 7 downto 4 ); vp_alt_d2(23 downto 20) <= vp_alt_i_r(31 downto 28); +ELSE vp_alt_d2(11 downto 8) <= vp_alt_i_r( 3 downto 0 ); vp_alt_d2(23 downto 20) <= vp_alt_i_r(27 downto 24); END IF; + +IF i2c_swap_b = "000" THEN vp_alt_d2( 7 downto 4) <= vp_alt_i_r(23 downto 20); vp_alt_d2(19 downto 16) <= vp_alt_i_r(47 downto 44); +ELSIF i2c_swap_b = "001" THEN vp_alt_d2( 7 downto 4) <= vp_alt_i_r(19 downto 16); vp_alt_d2(19 downto 16) <= vp_alt_i_r(43 downto 40); +ELSIF i2c_swap_b = "010" THEN vp_alt_d2( 7 downto 4) <= vp_alt_i_r(15 downto 12); vp_alt_d2(19 downto 16) <= vp_alt_i_r(39 downto 36); +ELSIF i2c_swap_b = "011" THEN vp_alt_d2( 7 downto 4) <= vp_alt_i_r(11 downto 8 ); vp_alt_d2(19 downto 16) <= vp_alt_i_r(35 downto 32); +ELSIF i2c_swap_b = "100" THEN vp_alt_d2( 7 downto 4) <= vp_alt_i_r( 7 downto 4 ); vp_alt_d2(19 downto 16) <= vp_alt_i_r(31 downto 28); +ELSE vp_alt_d2( 7 downto 4) <= vp_alt_i_r( 3 downto 0 ); vp_alt_d2(19 downto 16) <= vp_alt_i_r(27 downto 24); END IF; + +IF i2c_swap_c = "000" THEN vp_alt_d2( 3 downto 0) <= vp_alt_i_r(23 downto 20); vp_alt_d2(15 downto 12) <= vp_alt_i_r(47 downto 44); +ELSIF i2c_swap_c = "001" THEN vp_alt_d2( 3 downto 0) <= vp_alt_i_r(19 downto 16); vp_alt_d2(15 downto 12) <= vp_alt_i_r(43 downto 40); +ELSIF i2c_swap_c = "010" THEN vp_alt_d2( 3 downto 0) <= vp_alt_i_r(15 downto 12); vp_alt_d2(15 downto 12) <= vp_alt_i_r(39 downto 36); +ELSIF i2c_swap_c = "011" THEN vp_alt_d2( 3 downto 0) <= vp_alt_i_r(11 downto 8 ); vp_alt_d2(15 downto 12) <= vp_alt_i_r(35 downto 32); +ELSIF i2c_swap_c = "100" THEN vp_alt_d2( 3 downto 0) <= vp_alt_i_r( 7 downto 4 ); vp_alt_d2(15 downto 12) <= vp_alt_i_r(31 downto 28); +ELSE vp_alt_d2( 3 downto 0) <= vp_alt_i_r( 3 downto 0 ); vp_alt_d2(15 downto 12) <= vp_alt_i_r(27 downto 24); END IF; + + in case of RGB DDR 12 bits, we get : + . i2c_swap_a = "010" + . i2c_swap_b = "011" + . i2c_swap_c > "100" + + ;) + +*/ + +const tmdlHdmiTxCfgVideoSignal_RGB_DDR_12bits VideoPortMapping_RGB_DDR_12bits[MAX_UNITS][6] = { + { + TMDL_HDMITX_VID_B_0_3_G_4_7, /* Signals connected to VPA[0..3] */ + TMDL_HDMITX_VID_DDR_NOT_CONNECTED, /* Signals connected to VPA[4..7] */ + TMDL_HDMITX_VID_B_4_7_R_0_3, /* Signals connected to VPB[0..3] */ + TMDL_HDMITX_VID_G_0_3_R_4_7, /* Signals connected to VPB[4..7] */ + TMDL_HDMITX_VID_DDR_NOT_CONNECTED, /* Signals connected to VPC[0..3] */ + TMDL_HDMITX_VID_DDR_NOT_CONNECTED /* Signals connected to VPC[4..7] */ + } +}; + +/* + + Then VIP targeted order is not RGB but BGR + so we use a new register for TDA19988 MUX_VP_VIP_OUT + with VIP_OUTPUT_RGB_GBR as defined in cfg.h file + + ------------------------------------------------------------------- + | | | | | | | + | 23...20 | 19...16 | 15...12 | 11...8 | 7...4 | 3...0 | + | | | | | | | + ------------------------------------------------------------------- + R[7:4] R[3:0] G[7:4] G[3:0] B[7:3] B[3:0] + - . . + - . . + - . . + - . . + . - . + . - . + . - . + . - + . . - + . . - + . . - + + G[7:4] G[3:0] B[7:4] B[3:0] R[7:3] R[3:0] + +*/ + +const UInt8 VideoPortMux_RGB_DDR_12bits[MAX_UNITS] = { + VIP_MUX_R_R | VIP_MUX_G_G | VIP_MUX_B_B +}; + +const UInt8 VideoPortNoMux[MAX_UNITS] = { + VIP_MUX_G_B | VIP_MUX_B_R | VIP_MUX_R_G +}; + +#endif /* TMFL_RGB_DDR_12BITS */ + +/* Audio port configuration for SPDIF */ +/* Here you can specify the audio port routing configuration for SPDIF input. */ +/* enableAudioPortSPDIF and groundAudioPortSPDIF should be filled with a */ +/* value build as follows : each bit represent an audio port, LSB is port 0. */ +/* enableAudioClockPortSPDIF and groundAudioClockPortSPDIF can be configured */ +/* with the corresponding enums (See file tmdlHdmiTx_cfg.h for more details). */ +UInt8 enableAudioPortSPDIF[MAX_UNITS] = {0x02}; +UInt8 enableAudioClockPortSPDIF[MAX_UNITS] = {DISABLE_AUDIO_CLOCK_PORT}; +UInt8 groundAudioPortSPDIF[MAX_UNITS] = {0xFD}; +UInt8 groundAudioClockPortSPDIF[MAX_UNITS] = {ENABLE_AUDIO_CLOCK_PORT_PULLDOWN}; + +/* Audio port configuration for I2S */ +/* Here you can specify the audio port routing configuration for SPDIF input. */ +/* enableAudioPortI2S and groundAudioPortI2S should be filled with a */ +/* value build as follows : each bit represent an audio port, LSB is port 0. */ +/* enableAudioClockPortI2S and groundAudioClockPortI2S can be configured */ +/* with the corresponding enums (See file tmdlHdmiTx_cfg.h for more details). */ +UInt8 enableAudioPortI2S[MAX_UNITS] = {0x03}; +UInt8 enableAudioPortI2S8C[MAX_UNITS] = {0x1f}; +UInt8 enableAudioClockPortI2S[MAX_UNITS] = {ENABLE_AUDIO_CLOCK_PORT}; +UInt8 groundAudioPortI2S[MAX_UNITS] = {0xfc}; +UInt8 groundAudioPortI2S8C[MAX_UNITS] = {0xe0}; +UInt8 groundAudioClockPortI2S[MAX_UNITS] = {DISABLE_AUDIO_CLOCK_PORT_PULLDOWN}; + +/* Audio port configuration for OBA */ +/* Here you can specify the audio port routing configuration for SPDIF input. */ +/* enableAudioPortOBA and groundAudioPortOBA should be filled with a */ +/* value build as follows : each bit represent an audio port, LSB is port 0. */ +/* enableAudioClockPortOBA and groundAudioClockPortOBA can be configured */ +/* with the corresponding enums (See file tmdlHdmiTx_cfg.h for more details). */ +UInt8 enableAudioPortOBA[MAX_UNITS] = {0xFF}; +UInt8 enableAudioClockPortOBA[MAX_UNITS] = {ENABLE_AUDIO_CLOCK_PORT}; +UInt8 groundAudioPortOBA[MAX_UNITS] = {0x00}; +UInt8 groundAudioClockPortOBA[MAX_UNITS] = {DISABLE_AUDIO_CLOCK_PORT_PULLDOWN}; + +/* Audio port configuration for DST */ +/* Here you can specify the audio port routing configuration for SPDIF input. */ +/* enableAudioPortDST and groundAudioPortDST should be filled with a */ +/* value build as follows : each bit represent an audio port, LSB is port 0. */ +/* enableAudioClockPortDST and groundAudioClockPortDST can be configured */ +/* with the corresponding enums (See file tmdlHdmiTx_cfg.h for more details). */ +UInt8 enableAudioPortDST[MAX_UNITS] = {0xFF}; +UInt8 enableAudioClockPortDST[MAX_UNITS] = {ENABLE_AUDIO_CLOCK_PORT}; +UInt8 groundAudioPortDST[MAX_UNITS] = {0x00}; +UInt8 groundAudioClockPortDST[MAX_UNITS] = {DISABLE_AUDIO_CLOCK_PORT_PULLDOWN}; + +/* Audio port configuration for HBR */ +/* Here you can specify the audio port routing configuration for SPDIF input. */ +/* enableAudioPortHBR and groundAudioPortHBR should be filled with a */ +/* value build as follows : each bit represent an audio port, LSB is port 0. */ +/* enableAudioClockPortHBR and groundAudioClockPortHBR can be configured */ +/* with the corresponding enums (See file tmdlHdmiTx_cfg.h for more details). */ +UInt8 enableAudioPortHBR[MAX_UNITS] = {0x1f}; +UInt8 enableAudioClockPortHBR[MAX_UNITS] = {ENABLE_AUDIO_CLOCK_PORT}; +UInt8 groundAudioPortHBR[MAX_UNITS] = {0xe0}; +UInt8 groundAudioClockPortHBR[MAX_UNITS] = {DISABLE_AUDIO_CLOCK_PORT_PULLDOWN}; + +/***************************************************************************** +****************************************************************************** +* THIS PART MUST NOT BE MODIFIED BY CUSTOMER * +****************************************************************************** +*****************************************************************************/ + +/* DO NOT MODIFY, those tables are filled dynamically by */ +/* dlHdmiTxGenerateCfgVideoPortTables API */ +UInt8 mirrorTableCCIR656[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 swapTableCCIR656[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 enableVideoPortCCIR656[MAX_UNITS][3] = {{0x00, 0x00, 0x00}}; +UInt8 groundVideoPortCCIR656[MAX_UNITS][3] = {{0xFF, 0xFF, 0xFF}}; +UInt8 mirrorTableYUV422[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 swapTableYUV422[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 enableVideoPortYUV422[MAX_UNITS][3] = {{0x00, 0x00, 0x00}}; +UInt8 groundVideoPortYUV422[MAX_UNITS][3] = {{0xFF, 0xFF, 0xFF}}; +UInt8 mirrorTableYUV444[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 swapTableYUV444[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 enableVideoPortYUV444[MAX_UNITS][3] = {{0x00, 0x00, 0x00}}; +UInt8 groundVideoPortYUV444[MAX_UNITS][3] = {{0xFF, 0xFF, 0xFF}}; +UInt8 mirrorTableRGB444[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 swapTableRGB444[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 enableVideoPortRGB444[MAX_UNITS][3] = {{0x00, 0x00, 0x00}}; +UInt8 groundVideoPortRGB444[MAX_UNITS][3] = {{0xFF, 0xFF, 0xFF}}; +#ifdef TMFL_RGB_DDR_12BITS +UInt8 mirrorTableRGB_DDR_12bits[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 swapTableRGB_DDR_12bits[MAX_UNITS][6] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +UInt8 enableVideoPortRGB_DDR_12bits[MAX_UNITS][3] = {{0x00, 0x00, 0x00}}; +UInt8 groundVideoPortRGB_DDR_12bits[MAX_UNITS][3] = {{0xFF, 0xFF, 0xFF}}; +UInt8 NoMux[MAX_UNITS] = {0x00}; +UInt8 Mux_RGB_DDR_12bits[MAX_UNITS] = {0x00}; +#endif + +/* DO NOT MODIFY, this table is used for transmission of the configuration to */ +/* the core driver */ +tmdlHdmiTxDriverConfigTable_t driverConfigTableTx[MAX_UNITS] = { + { + COMMAND_TASK_PRIORITY_0, + COMMAND_TASK_STACKSIZE_0, + COMMAND_TASK_QUEUESIZE_0, + HDCP_CHECK_TASK_PRIORITY_0, + HDCP_CHECK_TASK_STACKSIZE_0, + UNIT_I2C_ADDRESS_0, + TxI2cReadFunction, + TxI2cWriteFunction, + Null, /* filled dynamically, do not modify */ + &mirrorTableCCIR656[0][0], /* filled dynamically, do not modify */ + &swapTableCCIR656[0][0], /* filled dynamically, do not modify */ + &enableVideoPortCCIR656[0][0], /* filled dynamically, do not modify */ + &groundVideoPortCCIR656[0][0], /* filled dynamically, do not modify */ + &mirrorTableYUV422[0][0], /* filled dynamically, do not modify */ + &swapTableYUV422[0][0], /* filled dynamically, do not modify */ + &enableVideoPortYUV422[0][0], /* filled dynamically, do not modify */ + &groundVideoPortYUV422[0][0], /* filled dynamically, do not modify */ + &mirrorTableYUV444[0][0], /* filled dynamically, do not modify */ + &swapTableYUV444[0][0], /* filled dynamically, do not modify */ + &enableVideoPortYUV444[0][0], /* filled dynamically, do not modify */ + &groundVideoPortYUV444[0][0], /* filled dynamically, do not modify */ + &mirrorTableRGB444[0][0], /* filled dynamically, do not modify */ + &swapTableRGB444[0][0], /* filled dynamically, do not modify */ + &enableVideoPortRGB444[0][0], /* filled dynamically, do not modify */ + &groundVideoPortRGB444[0][0], /* filled dynamically, do not modify */ +#ifdef TMFL_RGB_DDR_12BITS + &mirrorTableRGB_DDR_12bits[0][0], + &swapTableRGB_DDR_12bits[0][0], + &NoMux[0], + &Mux_RGB_DDR_12bits[0], + &enableVideoPortRGB_DDR_12bits[0][0], + &groundVideoPortRGB_DDR_12bits[0][0], +#endif + &enableAudioPortSPDIF[0], + &groundAudioPortSPDIF[0], + &enableAudioClockPortSPDIF[0], + &groundAudioClockPortSPDIF[0], + &enableAudioPortI2S[0], + &groundAudioPortI2S[0], + &enableAudioPortI2S8C[0], + &groundAudioPortI2S8C[0], + &enableAudioClockPortI2S[0], + &groundAudioClockPortI2S[0], + &enableAudioPortOBA[0], + &groundAudioPortOBA[0], + &enableAudioClockPortOBA[0], + &groundAudioClockPortOBA[0], + &enableAudioPortDST[0], + &groundAudioPortDST[0], + &enableAudioClockPortDST[0], + &groundAudioClockPortDST[0], + &enableAudioPortHBR[0], + &groundAudioPortHBR[0], + &enableAudioClockPortHBR[0], + &groundAudioClockPortHBR[0], + KEY_SEED, + TMDL_HDMITX_PATTERN_BLUE, + 1 /* DE signal is available */ + } + }; + +#ifdef TMFL_CEC_AVAILABLE + +tmdlHdmiCecCapabilities_t CeccapabilitiesList = {TMDL_HDMICEC_DEVICE_UNKNOWN, CEC_VERSION_1_3a}; + +/** + * \brief Configuration Tables. This table can be modified by the customer + to choose its prefered configuration + */ + +tmdlHdmiCecDriverConfigTable_t CecdriverConfigTable[MAX_UNITS] = { + { + COMMAND_TASK_PRIORITY_0, + COMMAND_TASK_STACKSIZE_0, + COMMAND_TASK_QUEUESIZE_0, + CEC_UNIT_I2C_ADDRESS_0, + TxI2cReadFunction, + TxI2cWriteFunction, + &CeccapabilitiesList + } +}; + + +/****************************************************************************** +****************************************************************************** +* THIS PART MUST NOT BE MODIFIED BY CUSTOMER * +****************************************************************************** +*****************************************************************************/ + +/** + \brief This function allows to the main driver to retrieve its + configuration parameters. + + \param pConfig Pointer to the config structure + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiCecCfgGetConfig +( + tmUnitSelect_t unit, + tmdlHdmiCecDriverConfigTable_t *pConfig +) +{ + /* check if unit number is in range */ + if((unit < 0) || (unit >= MAX_UNITS)) + return TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER; + + /* check if pointer is Null */ + if(pConfig == Null) + return TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS; + + *pConfig = CecdriverConfigTable[unit]; + + return TM_OK; +} + +#endif + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_IW.h b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_IW.h new file mode 100755 index 0000000000000..95fd008110e6d --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_IW.h @@ -0,0 +1,290 @@ +/** + * Copyright (C) 2007 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_IW.h + * + * \version $Revision: 1 $ + * + * \date $Date: 07/08/07 16:00 $ + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * TDA998x Driver - FRS.doc, + * TDA998x Driver - tmdlHdmiTx - SCS.doc + * + * \section info Change Information + * + * \verbatim + + $History: tmdlHdmiTx_IW.h $ + * + * ***************** Version 1 ***************** + * User: J. Lamotte Date: 07/08/07 Time: 16:00 + * Updated in $/Source/tmdlHdmiTx/inc + * initial version + * + + \endverbatim + * +*/ + +#ifndef TMDLHDMITX_IW_H +#define TMDLHDMITX_IW_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#ifdef TMFL_OS_WINDOWS +#define _WIN32_WINNT 0x0500 +#include "windows.h" +#endif + +#include "tmNxTypes.h" +#include "tmdlHdmiTx_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* TYPE DEFINITIONS */ +/*============================================================================*/ +typedef void (*tmdlHdmiTxIWFuncPtr_t) (void); +typedef UInt8 tmdlHdmiTxIWTaskHandle_t; +typedef UInt8 tmdlHdmiTxIWQueueHandle_t; +#ifdef TMFL_OS_WINDOWS +typedef HANDLE tmdlHdmiTxIWSemHandle_t; +#else +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +typedef unsigned long tmdlHdmiTxIWSemHandle_t; +#else +typedef UInt8 tmdlHdmiTxIWSemHandle_t; +#endif +#endif + +/** + * \brief Enum listing all available devices for enable/disable interrupts + */ +typedef enum +{ + TMDL_HDMI_IW_RX_1, + TMDL_HDMI_IW_RX_2, + TMDL_HDMI_IW_TX_1, + TMDL_HDMI_IW_TX_2, + TMDL_HDMI_IW_CEC_1, + TMDL_HDMI_IW_CEC_2 +} tmdlHdmiIWDeviceInterrupt_t; + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/****************************************************************************** + \brief This function creates a task and allocates all the necessary + resources. Note that creating a task do not start it automatically, + an explicit call to tmdlHdmiTxIWTaskStart must be made. + + \param pFunc Pointer to the function that will be executed in the task context. + \param Priority Priority of the task. The minimum priority is 0, the maximum is 255. + \param StackSize Size of the stack to allocate for this task. + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWTaskCreate(tmdlHdmiTxIWFuncPtr_t pFunc,UInt8 priority, UInt16 stackSize, tmdlHdmiTxIWTaskHandle_t *pHandle); + +/****************************************************************************** + \brief This function destroys an existing task and frees resources used by it. + + \param Handle Handle of the task to be destroyed, as returned by tmdlHdmiTxIWTaskCreate. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWTaskDestroy(tmdlHdmiTxIWTaskHandle_t handle); + +/****************************************************************************** + \brief This function start an existing task. + + \param Handle Handle of the task to be started. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_ALREADY_STARTED: the function is already started + - TMDL_ERR_DLHDMITX_NOT_STARTED: the function is not started + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWTaskStart(tmdlHdmiTxIWTaskHandle_t handle); + +/****************************************************************************** + \brief This function blocks the current task for the specified amount time. This is a passive wait. + + \param Duration Duration of the task blocking in milliseconds. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWWait(UInt16 duration); + +/****************************************************************************** + \brief This function creates a message queue. + + \param QueueSize Maximum number of messages in the message queue. + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueCreate(UInt8 queueSize, tmdlHdmiTxIWQueueHandle_t *pHandle); + +/****************************************************************************** + \brief This function destroys an existing message queue. + + \param Handle Handle of the queue to be destroyed. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueDestroy(tmdlHdmiTxIWQueueHandle_t handle); + +/****************************************************************************** + \brief This function sends a message into the specified message queue. + + \param Handle Handle of the queue that will receive the message. + \param Message Message to be sent. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_FULL: the queue is full + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueSend(tmdlHdmiTxIWQueueHandle_t handle, UInt8 message); + +/****************************************************************************** + \brief This function reads a message from the specified message queue. + + \param Handle Handle of the queue from which to read the message. + \param pMessage Pointer to the message buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWQueueReceive(tmdlHdmiTxIWQueueHandle_t handle, UInt8 *pMessage); + +/****************************************************************************** + \brief This function creates a semaphore. + + \param pHandle Pointer to the handle buffer. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreCreate(tmdlHdmiTxIWSemHandle_t *pHandle); + +/****************************************************************************** + \brief This function destroys an existing semaphore. + + \param Handle Handle of the semaphore to be destroyed. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreDestroy(tmdlHdmiTxIWSemHandle_t handle); + +/****************************************************************************** + \brief This function acquires the specified semaphore. + + \param Handle Handle of the semaphore to be acquired. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreP(tmdlHdmiTxIWSemHandle_t handle); + +/****************************************************************************** + \brief This function releases the specified semaphore. + + \param Handle Handle of the semaphore to be released. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxIWSemaphoreV(tmdlHdmiTxIWSemHandle_t handle); + +/****************************************************************************** + \brief This function disables the interrupts for a specific device. + + \param + + \return The call result: + - TM_OK: the call was successful + +******************************************************************************/ +void tmdlHdmiTxIWDisableInterrupts(tmdlHdmiIWDeviceInterrupt_t device); + +/****************************************************************************** + \brief This function enables the interrupts for a specific device. + + \param + + \return The call result: + - TM_OK: the call was successful + +******************************************************************************/ +void tmdlHdmiTxIWEnableInterrupts(tmdlHdmiIWDeviceInterrupt_t device); + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMITX_IW_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_cfg.h b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_cfg.h new file mode 100755 index 0000000000000..da2f18110efce --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/cfg/tmdlHdmiTx_cfg.h @@ -0,0 +1,298 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_cfg.h + * + * \version $Revision: 1 $ + * + * \date $Date: 08/08/07 11:00 $ + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * + * \section info Change Information + * + * \verbatim + + $History: tmbslHdmiTx_cfg.h $ + * + * ***************** Version 1 ***************** + * User: J. Lamotte Date: 08/08/07 Time: 11:00 + * initial version + * + + \endverbatim + * +*/ + +/*****************************************************************************/ +/*****************************************************************************/ +/* THIS FILE MUST NOT BE MODIFIED BY CUSTOMER */ +/* Customer specific configuration is set in tmdlHdmiTx_cfg.c file */ +/*****************************************************************************/ +/*****************************************************************************/ + +#ifndef TMDLHDMITX_CFG_H +#define TMDLHDMITX_CFG_H + +#include "tmNxTypes.h" +#include "tmbslHdmiTx_types.h" +#include "tmdlHdmiTx_Types.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + +/** + * \brief Video signals that can be input to video ports in RGB/YUV 4:4:4 mode + */ +typedef enum +{ + TMDL_HDMITX_VID444_GY_4_TO_7 = 0x00, /**< Video signal G/Y, bits 4 to 7 */ + TMDL_HDMITX_VID444_GY_0_TO_3 = 0x01, /**< Video signal G/Y, bits 0 to 3 */ + TMDL_HDMITX_VID444_BU_4_TO_7 = 0x02, /**< Video signal B/U, bits 4 to 7 */ + TMDL_HDMITX_VID444_BU_0_TO_3 = 0x03, /**< Video signal B/U, bits 0 to 3 */ + TMDL_HDMITX_VID444_VR_4_TO_7 = 0x04, /**< Video signal V/R, bits 4 to 7 */ + TMDL_HDMITX_VID444_VR_0_TO_3 = 0x05, /**< Video signal V/R, bits 0 to 3 */ + TMDL_HDMITX_VID444_GY_7_TO_4 = 0x80, /**< Video signal G/Y, bits 7 to 4 (mirrored) */ + TMDL_HDMITX_VID444_GY_3_TO_0 = 0x81, /**< Video signal G/Y, bits 3 to 0 (mirrored) */ + TMDL_HDMITX_VID444_BU_7_TO_4 = 0x82, /**< Video signal B/U, bits 7 to 4 (mirrored) */ + TMDL_HDMITX_VID444_BU_3_TO_0 = 0x83, /**< Video signal B/U, bits 3 to 0 (mirrored) */ + TMDL_HDMITX_VID444_VR_7_TO_4 = 0x84, /**< Video signal V/R, bits 7 to 4 (mirrored) */ + TMDL_HDMITX_VID444_VR_3_TO_0 = 0x85, /**< Video signal V/R, bits 3 to 0 (mirrored) */ + TMDL_HDMITX_VID444_NOT_CONNECTED = 0x100 /**< No signal connected */ +} tmdlHdmiTxCfgVideoSignal444; + +/** + * \brief Video signals that can be input to video ports in semi-planar YUV 4:2:2 mode + */ +typedef enum +{ + TMDL_HDMITX_VID422_Y_8_TO_11 = 0x00, /**< Video signal G/Y, bits 8 to 11 */ + TMDL_HDMITX_VID422_Y_4_TO_7 = 0x01, /**< Video signal G/Y, bits 4 to 7 */ + TMDL_HDMITX_VID422_Y_0_TO_3 = 0x02, /**< Video signal G/Y, bits 0 to 3 */ + TMDL_HDMITX_VID422_UV_8_TO_11 = 0x03, /**< Video signal B/U, bits 8 to 11 */ + TMDL_HDMITX_VID422_UV_4_TO_7 = 0x04, /**< Video signal B/U, bits 4 to 7 */ + TMDL_HDMITX_VID422_UV_0_TO_3 = 0x05, /**< Video signal B/U, bits 0 to 3 */ + TMDL_HDMITX_VID422_Y_11_TO_8 = 0x80, /**< Video signal G/Y, bits 11 to 8 (mirrored) */ + TMDL_HDMITX_VID422_Y_7_TO_4 = 0x81, /**< Video signal G/Y, bits 7 to 4 (mirrored) */ + TMDL_HDMITX_VID422_Y_3_TO_0 = 0x82, /**< Video signal G/Y, bits 3 to 0 (mirrored) */ + TMDL_HDMITX_VID422_UV_11_TO_8 = 0x83, /**< Video signal B/U, bits 11 to 8 (mirrored) */ + TMDL_HDMITX_VID422_UV_7_TO_4 = 0x84, /**< Video signal B/U, bits 7 to 4 (mirrored) */ + TMDL_HDMITX_VID422_UV_3_TO_0 = 0x85, /**< Video signal B/U, bits 3 to 0 (mirrored) */ + TMDL_HDMITX_VID422_NOT_CONNECTED = 0x100 /**< No signal connected */ +} tmdlHdmiTxCfgVideoSignal422; + +/** + * \brief Video signals that can be input to video ports in semi-planar CCIR 656 mode + */ +typedef enum +{ + TMDL_HDMITX_VIDCCIR_8_TO_11 = 0x00, /**< Video signal CCIR, bits 8 to 11 */ + TMDL_HDMITX_VIDCCIR_4_TO_7 = 0x01, /**< Video signal CCIR, bits 4 to 7 */ + TMDL_HDMITX_VIDCCIR_0_TO_3 = 0x02, /**< Video signal CCIR, bits 0 to 3 */ + TMDL_HDMITX_VIDCCIR_11_TO_8 = 0x80, /**< Video signal CCIR, bits 11 to 8 (mirrored) */ + TMDL_HDMITX_VIDCCIR_7_TO_4 = 0x81, /**< Video signal CCIR, bits 7 to 4 (mirrored) */ + TMDL_HDMITX_VIDCCIR_3_TO_0 = 0x82, /**< Video signal CCIR, bits 3 to 0 (mirrored) */ + TMDL_HDMITX_VIDCCIR_NOT_CONNECTED = 0x100 /**< No signal connected */ +} tmdlHdmiTxCfgVideoSignalCCIR656; + +#ifdef TMFL_RGB_DDR_12BITS +/** + * \brief Video signals that can be input to video ports in semi-planar CCIR 656 mode + */ +typedef enum +{ + TMDL_HDMITX_VID_B_0_3_G_4_7 = 0x00, /**< Video signal blue 0 to 3 then green 4 to 7 */ + TMDL_HDMITX_VID_B_4_7_R_0_3 = 0x01, /**< Video signal blue 4 to 7 then red 0 to 3 */ + TMDL_HDMITX_VID_G_0_3_R_4_7 = 0x02, /**< Video signal green 0 to 3 then red 4 to 7 */ + TMDL_HDMITX_VID_DDR_NOT_CONNECTED = 0x100 /**< No signal connected */ +} tmdlHdmiTxCfgVideoSignal_RGB_DDR_12bits; + +/** + * \brief Video signals can be mux each others using register 0x27 (MUX_VP_MIX_OUT) + * Whatch out that VIP output shall be GBR: green on [23:16], blue on [15:8] and red in [7:0] + * this is done by default for all video mode but RGB_DDR_12bits where some extra mux is needed + */ +typedef enum +{ + VIP_MUX_R_B = 0x00, /**< internal vp_r = vp blue */ + VIP_MUX_R_G = 0x10, /**< internal vp_r = vp green */ + VIP_MUX_R_R = 0x20, /**< internal vp_r = vp red */ + VIP_MUX_G_B = 0x00, /**< internal vp_g = vp blue */ + VIP_MUX_G_G = 0x04, /**< internal vp_g = vp green */ + VIP_MUX_G_R = 0x08, /**< internal vp_g = vp red */ + VIP_MUX_B_B = 0x00, /**< internal vp_b = vp blue */ + VIP_MUX_B_G = 0x01, /**< internal vp_b = vp green */ + VIP_MUX_B_R = 0x02, /**< internal vp_b = vp red */ +} tmdlHdmiTxCfgVideoSignal_VIP_OUTPUT_MUX; +#endif + +/* Audio port configuration, bitn = 1 to enable port n, = 0 to disable port n */ +#define ENABLE_ALL_AUDIO_PORT 0xFF +/* Audio clock port configuration */ +#define ENABLE_AUDIO_CLOCK_PORT 1 +#define DISABLE_AUDIO_CLOCK_PORT 0 +/* Audio port configuration, bitn = 1 to pulldown port n*/ +#define DISABLE_ALL_AUDIO_PORT_PULLDOWN 0x00 +/* Audio clock port pulldown configuration */ +#define ENABLE_AUDIO_CLOCK_PORT_PULLDOWN 1 +#define DISABLE_AUDIO_CLOCK_PORT_PULLDOWN 0 + +/** + * \brief Structure defining a video mode + */ +typedef struct _tmdlHdmiTxCfgResolution_t { + tmdlHdmiTxVidFmt_t resolutionID; + UInt16 width; + UInt16 height; + Bool interlaced; + tmdlHdmiTxVfreq_t vfrequency; + tmdlHdmiTxPictAspectRatio_t aspectRatio; +} tmdlHdmiTxCfgResolution_t, *ptmdlHdmiTxCfgResolution_t; + +/** + * \brief Structure gathering all configuration parameters + */ +typedef struct +{ + UInt8 commandTaskPriority; + UInt8 commandTaskStackSize; + UInt8 commandTaskQueueSize; + UInt8 hdcpTaskPriority; + UInt8 hdcpTaskStackSize; + UInt8 i2cAddress; + ptmbslHdmiTxSysFunc_t i2cReadFunction; + ptmbslHdmiTxSysFunc_t i2cWriteFunction; + ptmdlHdmiTxCfgResolution_t pResolutionInfo; + UInt8 *pMirrorTableCCIR656; + UInt8 *pSwapTableCCIR656; + UInt8 *pEnableVideoPortCCIR656; + UInt8 *pGroundVideoPortCCIR656; + UInt8 *pMirrorTableYUV422; + UInt8 *pSwapTableYUV422; + UInt8 *pEnableVideoPortYUV422; + UInt8 *pGroundVideoPortYUV422; + UInt8 *pMirrorTableYUV444; + UInt8 *pSwapTableYUV444; + UInt8 *pEnableVideoPortYUV444; + UInt8 *pGroundVideoPortYUV444; + UInt8 *pMirrorTableRGB444; + UInt8 *pSwapTableRGB444; + UInt8 *pEnableVideoPortRGB444; + UInt8 *pGroundVideoPortRGB444; +#ifdef TMFL_RGB_DDR_12BITS + UInt8 *pMirrorTableRGB_DDR_12bits; + UInt8 *pSwapTableRGB_DDR_12bits; + UInt8 *pNoMux; + UInt8 *pMux_RGB_DDR_12bits; + UInt8 *pEnableVideoPortRGB_DDR_12bits; + UInt8 *pGroundVideoPortRGB_DDR_12bits; +#endif + UInt8 *pEnableAudioPortSPDIF; + UInt8 *pGroundAudioPortSPDIF; + UInt8 *pEnableAudioClockPortSPDIF; + UInt8 *pGroundAudioClockPortSPDIF; + UInt8 *pEnableAudioPortI2S; + UInt8 *pGroundAudioPortI2S; + UInt8 *pEnableAudioPortI2S8C; + UInt8 *pGroundAudioPortI2S8C; + UInt8 *pEnableAudioClockPortI2S; + UInt8 *pGroundAudioClockPortI2S; + UInt8 *pEnableAudioPortOBA; + UInt8 *pGroundAudioPortOBA; + UInt8 *pEnableAudioClockPortOBA; + UInt8 *pGroundAudioClockPortOBA; + UInt8 *pEnableAudioPortDST; + UInt8 *pGroundAudioPortDST; + UInt8 *pEnableAudioClockPortDST; + UInt8 *pGroundAudioClockPortDST; + UInt8 *pEnableAudioPortHBR; + UInt8 *pGroundAudioPortHBR; + UInt8 *pEnableAudioClockPortHBR; + UInt8 *pGroundAudioClockPortHBR; + UInt16 keySeed; + tmdlHdmiTxTestPattern_t pattern; + UInt8 dataEnableSignalAvailable; /* 0 DE is NOT available, 1 DE is there */ +} tmdlHdmiTxDriverConfigTable_t; + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ + +/* Number of HW units supported by SW driver */ +#define MAX_UNITS 1 + +#ifdef TMFL_OS_WINDOWS /* OS Windows */ +extern tmdlHdmiTxCfgVideoSignalCCIR656 videoPortMapping_CCIR656[MAX_UNITS][6]; +extern tmdlHdmiTxCfgVideoSignal422 videoPortMapping_YUV422[MAX_UNITS][6]; +extern tmdlHdmiTxCfgVideoSignal444 videoPortMapping_YUV444[MAX_UNITS][6]; +extern tmdlHdmiTxCfgVideoSignal444 videoPortMapping_RGB444[MAX_UNITS][6]; +#ifdef TMFL_RGB_DDR_12BITS +extern tmdlHdmiTxCfgVideoSignal_RGB_DDR_12bits VideoPortMapping_RGB_DDR_12bits[MAX_UNITS][6]; +extern UInt8 VideoPortMux_RGB_DDR_12bits[MAX_UNITS]; +extern UInt8 VideoPortNoMux[MAX_UNITS]; +#endif +#else /* TMFL_OS_WINDOWS */ +extern const tmdlHdmiTxCfgVideoSignalCCIR656 videoPortMapping_CCIR656[MAX_UNITS][6]; +extern const tmdlHdmiTxCfgVideoSignal422 videoPortMapping_YUV422[MAX_UNITS][6]; +extern const tmdlHdmiTxCfgVideoSignal444 videoPortMapping_YUV444[MAX_UNITS][6]; +extern const tmdlHdmiTxCfgVideoSignal444 videoPortMapping_RGB444[MAX_UNITS][6]; +#ifdef TMFL_RGB_DDR_12BITS +extern const tmdlHdmiTxCfgVideoSignal_RGB_DDR_12bits VideoPortMapping_RGB_DDR_12bits[MAX_UNITS][6]; +extern const UInt8 VideoPortMux_RGB_DDR_12bits[MAX_UNITS]; +extern const UInt8 VideoPortNoMux[MAX_UNITS]; +#endif +#endif /* TMFL_OS_WINDOWS */ + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ +extern tmdlHdmiTxDriverConfigTable_t driverConfigTableTx[MAX_UNITS]; + + +/*============================================================================*/ +/* FUNCTIONS DECLARATIONS */ +/*============================================================================*/ +#ifdef TMFL_CEC_AVAILABLE + +#include "tmdlHdmiCEC_Types.h" + +typedef struct +{ + UInt8 commandTaskPriority; + UInt8 commandTaskStackSize; + UInt8 commandTaskQueueSize; + UInt8 i2cAddress; + ptmdlHdmiCecSysFunc_t i2cReadFunction; + ptmdlHdmiCecSysFunc_t i2cWriteFunction; + tmdlHdmiCecCapabilities_t *pCapabilitiesList; +} tmdlHdmiCecDriverConfigTable_t; + +tmErrorCode_t tmdlHdmiCecCfgGetConfig +( + tmUnitSelect_t unit, + tmdlHdmiCecDriverConfigTable_t *pConfig +); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMITX_CFG_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/docs/02_sw_req_an/tmdlHdmiTx_API.zip b/drivers/video/nxp/comps/tmdlHdmiTx/docs/02_sw_req_an/tmdlHdmiTx_API.zip new file mode 100755 index 0000000000000000000000000000000000000000..e4eebeb934798ab9e68af4b1e52f105e10827bb9 GIT binary patch literal 131083 zcmeFZQYAtDf+o%5T*)HciYq8Y~}?fAfeSnfW0~j3GjR77tgv z$AcOV%yTm|KyOtv^DXE-r(aR4rj_}Ieojoc&^8o^3x>`4b_Vij8ALfJ^^#6l zE7_@A*)@+3S2jcMg%?C^&xe+O?M-($mVWQonx|Ah*sWbNfc8=&79Lxq*-Y4B1?DLI zDO*`)FmdXBtPG_6nqtE9OZ#RF8*>o$(U^gZqk{S7!j91-E)bPWbJQGrEzomhbL8v~ z9OJ|S!Pe;vxvZNS-DB-nSuiYe*FIT(pp1y{{*^z8ZzLrg*3O!383-03VJtr`3NGqE zrH9NDwhVnp8t7D9at5Up;LdyeQyk5J9mrhJUzEN%H}#^af_~0V{M1VT{Z6LGbK;z! zSpDmf+(y4U#MbSo)jOqIO2wwpnPnttQD0s8V*uHsRy&K(8}2iNc$ zh{0$szi)}6COTqq9TLt58(B&u&Yl{e3T;;>wg1jMFtFHz`eIFko-OV;p!JK2drI8= zw5d#(cSOvu*0opQ7PfOLffH$p89N3nf}zZGF@jj?V5EZ8lpalnQM|w4D|fn>^b!YQ z)~S5oDce6ro=b*UY-u}2G@a(cCRzaaBmzfvw?6tT?tO5a6@=U&qaWc^jp5UgIV~Z3ZNlo|qw&z;giM(6y%b|lC?ctD-Le*c zZ%|xn9@gK_h;-d>HV7smTiZ@2VC!h&YQdC}lCEcfI%Oc}o6%h|B1hdA9{gMv0+}L1 zDiVF2R3jDtCc@_sk{5itv}J<6#kG|O1C#hfxh@mUUw+((Nx&`=SwYrva|6RqWWYNW zo+of@)~1z}4||xo%%k9Ic+#L$(O=L@z)~GWqeu=v_*sZ{ z>+b=1N6kNw+=NPbHq@q!jCc!pfmGEO=QR5;HyJB}o(_Qe-A$sV2v>JX;Negn8L%Ov z7O+(?$?a9m0NXrUBJK3a`Ps-;0zK5VdTpiGn5`wj8f@(-EitRr5tzBGNnd1!7VNoq zl2&O(d7BMt?I|vAkuc@r&XsV6Ejkhf*u3DsmM{&1i(RU;N5nGi+ViDbFnExGf#YOL zVDnGr+myE}D>nLL5teQz0elvpPPSQZRKb5{mL;op?KTPPvz5Yt#`*3sYiG-OJcszG zjY8vwnJH9iXvuF*7%uHUQOyJ8z)XbO0TW&wPr`XuA3145Fz@dW)9Ls8B=6TVBN zH|~`6C$2RL`ZZ`Rur6bOpiPA0P_;{Eyb`Y-NNAuPxgH7hF( zJZsu3)vl&+^5_Vnd1I~Ld&UZe6#Z=SN$Q}MO(9Xr;J*07U6$@Em=-D6JSz8PmtiZjA7R))J(OWEr$OvLLI`s zLvgw+EosR`Eund5$77KpJUdKN{1McnvE9j^?cMPXhkGv{JHD|RLcF8BvtT+^7!~&p zL$#}gy9BlM>v8c1@m6S(ePx@kD>6dn)?0`7Wv4M}PQ%=_u{rT(uaZ;vdLiQV! zYN4Hj&cWjO)N63y!_&~?lawxW9q40Ve*2b6wq<0d!IgHQryEI?l zo}&BhS<_Mg3EZ=z3{UB&oUu=UU)A``4v*06)ra*pmq11?kXJ}mdEe@tq<>hs98rzE zLK6;j1ZS48Oc^*JjA^ZNYE)k4seaSKVc$njz7e>6%~<~s+)LxGLWt@^qQg`5&CnFp zq?2tux$^TZ$46wr5ttH#gmojsfU^1HkX-}OGIC-+F zqAztW!-MgF(M9AIWh|-wa|q=}7>mlm8dBxiZ?z)|ty6|2%hrrB4iLvFyck{ijGkbuxW7hSq$_5Pq{XYSy-vEQEz1fGGB(Bo3p!TcD?F* z5;fD>IRNS$)_K@q6(A&6FAG?~>tP&4%vWTAX!S)+UODKvP$M4X$F|_UF#}g_KES=Z z)^)|;Vc!#G=9`GVk=p9DQ8!Po&$Ep|FH%i9BJ9fK1=1c<-5LF44=aHlg<>?$YBUbgztNK5j*PF z9$MAeEB>^qzRzzJn7BYX;b2W?n2pwpFUv()W}@k#8jitkk&S(+pi%L%+)2Dswt=9r2n?(N6i(Phs%A~qMb;5Q3FydsYa>^Yvti|G>v zkR=l5^N5>#`iPEZ4vtKp(~JSmf$ZS@)9p7KlAJn=b|bCG7t_+c7sW z{AuDyZ|-bk{V!7;vKS%wK|)y2o34QdN1H$Xdkhw<(Ar6&yCQ#lvK-eFT#FK{)e1=x zquKOsMQBRGC;d*vC)Z*z*f&<7?;f%XQa|O|_pmriwXbzirb)S&eCJEDbtcx*!_Zz z#N(}|pok&!4G93v z-3=j*pbJ*i%5EJ9Fx{_d3UKc1TDY3FOsUWtedD2kfY1^z)b)NDFE$$`Xf7~X^6m86 zy4tx8f$A)$#7rcNP|68Rk2OO0#+qHJuJNcudx^0P3ohj@MfTp&{U2GZvO)wH0yqHB z_?Q00eKoT+u(mU^qc^iK{g?N3I_XXWB@Ad(1e-A;mE2*-pLH0O3`|;N0&&X}EK!h> zE;z6nwN)sAx@R>0q%oEn21z-FRw3voyD+#ANN%Rabu&lzG%x2xzS)k2-L+|LSLLP? z#rCmFcl$-xNoVXQ#{0+DXV1-h*Gsiy=LCC;Co1_c$lt3|{3LqWO^60Qjc7?x28X;R z(x``-e~4nyEyyc%H(n=ZdVt&@bc~E#wM9@r%A_tV;}wuj*q0!=gdmPADJa|;j!b2U z=2K6MFAK5nKP8Gti5L_ExsCCh#@r>T_(yO75jtf5&K>xKG(u#TFu25+mCT6{k#-*x zYKSSY;ROh?9~x0!iWwo0P^uG?P_M+3NqI6#nLsiu2{zP_86tsI)XB)MDcq39M2b)f zSxgBtP>L5RYDAG)NGX|e9CkCkQ;c~Yi9(g`<=0t9(ma2FJFA`V=dY?W|P2%51_ zNrpJ#2Ui~Hd;_f@;-Lbmm=dYc$QUyv&a>UK5bLxnWMJO|uiWC7d(Twiyg4daGA3P} zZu~D=&I~b!0#GVL%wsS@z#=mWF=QYy^8GzLWehPDX+%8ec#s8PrXI=$(~vYG1*{9B z$fN-#|24cs)3uq1N&Mq~cSnDTQmsW7HqC3b8H9=R8(RII;N zL=lkK9O4fl2a})e=<=hC*$3{KSHXLvu_%-4`wsr3R8Z{5pin|}Q^0}oq()jm=?NLP z2;VQL)Tw`VFiRV_VtKL^fZJ#V<3~6nCDQnDWt=d;~S}aqmI1oZ`32+hU0;Ms< zX0ULCE??hYrCrHkgc?uHmCM!Zh^Qs0|19^;c}W%ijx9I3DDCXYF4MVB-DyjDPptH9 z$S*0(uP-}`cQ$jrD^@*0H>u_2=JfLRsya~L{4-nbWPrdrO1<6Y8qA5CX{jmDQ$Ahm zPPg&{U7A|OwvxtSvbeEC0v}C!u$S&N$5-Maefd=0rRUFx#gRgub@$i4qJB~$S8knzQ)UOq188L3%K!eFM|5}PGwUm zicW4aKyT4L*L%f>Q1HjvO^Lj~i|lmLmd29+!JjM!){k6jw9jSn7Y#q_axI-##of=7Aj$`pStafdTmCs?TUq5ZEeR_r~Z>mTJ8Qn z@fu85eGj3^;$&3?!+KVJ?l_hBCZAoZFAmqP$1?JT`tm-xY~OBSJqGz`pr>r* z;zU`&E96vPujqcP4Jp(9K$Ev&==8aMU7gF5=T}5a{odFSaPH;5jRJN$W=|<7I*2VD z3W9sWR z5UgF-O){NN^&oHSGD5N5Do~LJ;@knPp|ZhV+4f|4Ju$y9!R_->WpRw@;k&+|%rpNT z7WH1L5R~~eE83~veDm>OD>9Q4aMB|;p3b-F$Z^s+o8va>qpiwWvhinn{$Z4bg9rTV zMF(7knkE*__dB&>%K^{pYoL5qjVm+kxe#mpH$$b9m6gxT=2lB@*Ie0{mFm%~UVU|_ z!IOHnqMY5tb5FLmRhzAE^-#f#1Kkw2J`;EN1=jL!qn8fL#i?mn_x`B#*0sn*bvx@k z&4^wyK1%+p%^iKetIuNkN$Hcrz6jH0^lmwo+qFRXLYJ6}9(VriMedi&UlaU!R<=~R zD<5xXZDqX+`j?(}(omlromabjuQwnE@0PIF*0W)uIfZmYTkh9x8gPv?rW4U5Yo9Y| zR%$){(G{uPu~pO(v%QZA9g5mBAuONeBT<%lj#uFp@M9lG<934?#hv%A7+oyur(@%p zen(-Yao=x&@^?w!!2fIfZ6%RO)dm9q$Z!DwjDL|c{4KZ88#_7u%fNDlrK51c{+jUx zEn{v+CA~0tc2us&Sw0j{agos^!QrqTuG>MH%sk|`V>T*pG?HM6bQ_52#JzoJcL+ z>h-Xl&}9Ni^99xIea;WQjUO+DS>$o`D=tZlQWU4zeFyKTX+`)z;mraCv``=jId-xg zC2w0fVw_vxfVvln*QU{2j3J#nCRn3|Er-b}Uqendx{15}Dc zVP@q(7ZuyhU!jR^ck5cSIN&SDM>6%*S}71NLA?9qR5L-KOQTYZ0p8D)7UyJf zS@FLf>iO_>*BX%gEIFzz$;M46wT=AO$w;&q3mm0Z>7`cODMuq;>1-@q_sH=x1V8z@ zl&rIhkl<++W!-IUrKJQmuXut3)&?5f9M#mjVw8fv@rdqiG+9X>Hi*f)6oQ8!AXsG}k*mJ=M~>iku{y?yPRS5LEQJILM#1w!zEqmIomjHOu>FrjV_c+* zEmO4x8_nVj)m4Mk;aM<|#iCeRBhlh3yg*C9EQQj&nJM3&|MyV8l-!BAX zjkKK}feX{@<<5u&6im&YWd_MAsEt4tV=#Hd#r|Au{?p=m9R0e*)WK2o{S@m;M=2oi z1mjsB#1J>Vf8&yvXaVEctN$FEZBh+Y0m<$_7|=83zDEm2qcs1hur@=FPs%vy9C1k@ zv?*SEk$nvR;M3heGxzU3|GEzTuYB}Bah=n@uZRC@O{o9E+y8}z|6a}iSyul?VLn3@kB}G& z0ATz}1ph|O--5b_nTajEy{*|lgUA0Y)W@i6sG@`;!%1=wDvJsuvHOQ+iYE|vlVXYq z!%&jtV-hVkN>j|l)EN^q@m-WZ?yo=4r@Xms17`Va(<&6w2zwr?086(wJ%ck!-l zzD&qBa60Az{*b^X#%IV6F5@JeL&Iv0A9{$&fbz4z*ifNc_HzVpm(+7@ww869B_Y+H z!+ivH`4!$KODRPiXnXnhIa%1QqUd8S!q2+jRIMl&O^dHJ_1qWGHU87{>L=GZM^%}G z$JgogB83Lk1rXw$B_Oqr*u*`<9J<|a(izo$K@qQ{b!PlgxuwSTr;Y1k58TTIVojT* zQE5P(H|7TS4N@aB>Z#TdX1g?KUrJ~{k3GVX2k^GWr;Pi*Hux#HV^x#m=nFexrwGG( zmeyj;t}mPuhkl^K&CaG?s_?NQjQ$x=>gva{@z{1S${K<;dG#@iUV?1*ek&Xv>bGT5 z;1~)47_?|@X>wE(#!{Sjn&vDmcp*WaB6%?IoSogv%zNEK33D$?S!9M^cA8oA2SRTI z_QyWhwvHN{JSo<5&1f;C=5`pK!-!QAMQr9x1a3>0=TzgTw+sutM>R$F1hUfIu`;*7 zc4aR{#-={f$=hXc3KxQ9SG&sfS6W|pFs&DDkv8=t8*mqD0WFpuiF?-PVzFCE1Z+bI!IdK~vbguY!OC8fJ|9(($dr;Y)`S`0x*u`nE{_>wGZO3>q*0;utqbS))c)Wc?(*?b>%B+-x% z;3CYRK2L(oi0~dNWk$8Tg@e7^bROr`8*e%YQUs#Pk8@nIR(+ldpz7@SJX~%6-f5f~ z;LQyK@1iG$%XUq@wz|Cr8NHHB3={^0$SKgnsm3r;H>Vkr{vyjPf~IIUjwZIBI+P9v zXM4-oX{hVBRK&gIa<6)ABz7Dx_-xa(c9j3J>H3h}l=b+tKTzoT`r{{nf>M~u`Ad1) zl9qjB-LZ}m%RQRm$h=DNw}0WQ%e?(N{@ebO0%3F6mWZa|^dROe$K|ebJ@U_SDJ-6; zkHY*{OG3LP<4=1Y4+bl5kJm9O%f~Am^;7+84d2csjO*B=%~F&?9F=E@IGWY@Ukt&R zi_(zHI)%9(RbC@{5~ z?#w(^mW7XF;FQDe>+Z^k;0z!EJmnHhpHja28w4iTS6sZqN!q0gN6x=CHfzVP(Bg>2 z$@28=pxuY43z@r^)+ab+u$oLTIFhxua1JSp?OX`?EV=~f`Ufvdv^2^3Bk_~6r#)`k1foum2WVfa= z?KUmXjoDi}J}Tp!DHX{3D;lqFwnu0>hq+@~)AOQzh4w#}&{D`{r^ou@;caGL!3W9o zND%3e{G0hMJRFBMMbGG@EOOzZX6>rVtM$FOsI#`6Z$|~#@UfV1h*;(lo5^OtLE7eF z;3ZMnULv3L=ofgH`SewFCkxUk#LSwkt;k*4XZ$y;LrSj*BA5nhueK)k$+Bp5?=xt? zH#E(NhL-V)Lg!j}Jn?5^esy<$$a^~xL{Qd3_j(__2kzIJ6t45qf699HAHWO!+7DKl zpfTW7L4(M@)U~`}_|S^{p->brWmwPQD(P2%fB)k5MRm6&!O!Db@J?N=rFrFD>A$2D znRTZ#?6~{(i$?MdUG(Dm3bE>2g8vO%h&cGl06Bw8Z$%Sht0P(6QhFd2s4DFO*&=(H`}%|2;ONxIA|Rt6=kE1W>^#769|2i=f^Rjmq@g)*(S{uOkhWZW{c{U zXYr2DtMk15ZUFjsFZG2QJ#bY(O91*8xKsp6Vxc8&@-J*$i2f(iWJXq1xLg|iHbGat zHjBHL4yzbM?`w2r|9U>%CL-j4r~^#B&+Ij1*jF=eds1D&D*Z1IDp{Qadqj<$jOL29 zH1v_CaWc2=bB?RJcYrgqHS(Q)T?#1oB^d}(y9Ps{sgC>sKRE=R*1}Un`DcB`%xV0C z>Xa;n~Oe_AM^lNXp=&2wPUF-ebeOrnbuQ24Nc^kPCO{ki>azu(GC7s#7J!U_i_Ww}wNH4tyWX1v)iKlSo z%mxjFMCsAgySg|kHBaW3-oI&t$F8Hf?I<-^nM-#jfIJ~AVJxF%vnltSuzZxDUU_6* zeRYYMsu7JLXDw6tM7PaV>a!hj8^4|Lm%Okttw@==iS-#*l%%#iE9>ZGvF5gi6Zdm$ zrD61(UQ8)=e7_`qeP87&vKZjp6X z{lA#rAnD4`oBCb*Ed4+Q*K+I2Tkhq)5dI6O|0C!6??4^*-{f58{~fLW&xGqgX#GEE z{Xb~^KWP0wX#M{WwEkb<_`i4S{v9~}pDnxp>8t)3W5mgfdT~p@c#`Gu(17U;{IQwKL0bm#Hen_Z!#kKoY0h{uD5Qcrb1_m zRs{Q3mo*`Gkx=ByRdKsodQFxX?A&pKxvHJ=o0xjXo=go>c?p!gf&RKoi24zKR;;1v zccMHP=>`e)DpZEUH15Xs#6%i~b99-vSthNH6jPz!|EK98%O8YiT3DMn z{d)shR+F>aV1(^{(Xa<@(XpmjmDpGVhX%D_t`hV=W`_;2W@=H?njkHfd%lp+aY!u zz-Xi@aOFFy|KhMatWpu-=Ju+N@!IWr@-Wr5ZSu8;;P( z8s`r3=(Qc0xzop6*?4Dp;P4*j4#u=rF4WR?tXS6*-fgmXq1;zGf2jq~=y_T+ZOr;m zDMe@;RVP!mod?wpTuS};pwzK>Xu?09C7`<`q8NqJ20il+B1TCEvoHQ-42`g`qNo`G zgLo=UlZF@Zu=GHTDsfJggTZ$R|Ac3&*;5!;QCdIf?4@lterc_=#Z=HovJGOU-ZEq} z*SY}tvE8AP6S)J}bZQnx#=1$N71Z>Ib5#gY4-To{wF>_8x_^1;43~8GgnFE6wIZn? z+)?Ks`}h@jbYL;a1&H<{Dh^U=1eDvbPBkvPXs zXO*ADEa=zx7w^^=-gTlJQm@=N}Kg+F73y!N51wU|8 zAmfd03X#|ry4g1}H6RVzz_q1jW+Vt^k`x%FL&pj9{p0;r;Q{bS|1 zAFG*DBB^~g|0wVGuy-nP7PD^ib2zwz z`Teuw^m*yP_E^suIl-3B}2*S3L! zN~0l+<;AeWg?ocPaSaZF1vaVtJOU7~b^)ysa(P0N@y*H&j{Vhc*7*aWj)P=0%ieP1%fbB!)pB5dzTaY02|G2he`q3A_ zeSIvP^+`;WlV*xD?(}I^allOUUwP`i&^dEcqV8jt4M6}KN+)A$eKX?EH#h4E&Yxvo zY4=kMaBjwfJ=q}l*?HI83*_4p@9CNcb>;AqXZGc!PAW2xsoAIwnX@*J(Rx9kT$weJG2f!R>@MBmZUS7=CZ0*+f_|1N`;YVn z3zH6*gm#2$(T8IiFoT&M=z*L{SU2k!(~b{>YX{`XU~{hO-Wmtsu1gb^O9Q<>F11ce z-cE#juo>AyV-W91wn(ym_})Rd$3DQ<^ltaLyvV%3bt$N{u?0cfmKQjNglR2rRIc!_ zY$%ewiy$cx@(z5<33;d5w$cz4Bv#k87L4E~7J%6o)XUO~(PJ%(+E%2SJ*7vF3Y*TR zZeA7oix=nbGDRt-C!m@Hpok37ZywCc>;emu-!UeW^Rj+y8b9MOs(Bbm54}Z5TF$u0 z1D$eXKzGA;woUSq5xJ&zI}2`{Fv3UNPG z1;3MGu2%AqHyKIhW)?>~(4!MqvsCO&gcwwDw+-X3Te05;A9caDS64;Hq1qUy(_>mB z2!x?f!?UF+0(Wx{za3e>IR#~a=LQ{Z%n68jb_5^Hb%R{90$b}_594a!^$m?ar8aR2 zpQDSXd1o{%0A1+hyj*+z{PX7rT-t$xO1jj5n(2(Ly41z94qa7%8A2p_8l`xyCeSv3 z>5ZZTJT&2chTFfAV$n6j3Ny{?yzlV2CJJLG>-?kNZK`%?9)42~b)up}8)?Q#+j>iv z3V;E%2LrwM`Ki3T80nn5B74JCF@ z75>ugc*$sB(#F%r!A0N;kaV^j#$&z)&$N|Sr%;kdeagWlK|Gl-X*o3fR{K`wkyZ_#u|NZyB8=&92CF~D2RU3f? zsS2c&&kX42HDIJBFtJutmJ(Jk%l=bL5&XCVOZ*GtV=mbSGUdw3*E~m2r?+BviJ}SR zpt1elDG97_urzK7FisVtjr8EJ=VrhUo>F@ZRm%25Tm+t> zPwCmHY>YL0`T7p)x?bdNsRCzmblW$mBFVDXi1-61Z8=$0QW{QbqLFxzWdwVDf8=ni zkr=NTOUc?_p##O0uodR|=H^~obmyTWEEf6!ZhetMNWKuBXNl=c=9TUkGkvl7hJtQd z2~NiA!WT(*^87EHbKyvCnR3N<@if_i2OkYn$(57=_TFm{HwZsD8YV5Wy}^=bvA
7!Z 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 Z$B3xmOMs0uyfrX_o`51`gm>`P{a?^2+|mF5 literal 0 HcmV?d00001 diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/docs/14_user_doc/TRANSMITTER_TDA998X_SW_UM_Devlib.pdf b/drivers/video/nxp/comps/tmdlHdmiTx/docs/14_user_doc/TRANSMITTER_TDA998X_SW_UM_Devlib.pdf new file mode 100755 index 0000000000000000000000000000000000000000..510913334135870bdd9370ea2156a3af7e8780a8 GIT binary patch literal 610544 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 z zySCdYp75p5QV~X(I_mJ#XQAV~(7ZqtSXk~YA7HQVcHD6?>>Ht$&6Ns5!H%MwpWW(mnLq_;3C&e^ zFS$-5YX2ccPjY1^(03OLnzNkt;$1v5U@W&k3cK2Tj#-)i%u>+b$7MBT7K3(YQ~4hmLx-RE zC>zv)ogq=m&xQjNlt}fFZtEf#>fq>03ChmTBUw%ylHr^rq+wO0CAp|#K-&E9Q>2CA zlREm!YLt_WMir)t0TLTkL8nV%=v{d}yM_5&8fdE%{}rbNv+%U`2qllgAyCg-luFf` zvh5m+f+g<}+EMX&=j0F-Eu;T|#O3{P&uX|DQPITR%vMk(;+_5(`yT~|rX!T_K)TpV zY<~(YrG5MvPLXf;;I?0y7bp`Oe}Xpn)8`F{lrSsDK)YtyvORtz>#3AE;1hGEaib?9NF7hhD2F}com(Tc+lwFPLuPB+Kp{4uX%;#)4|g( zMl|L7I`HbrYdkmX(QjP()LZ(%&*62apev$1uAzrvu?>*&O52(VU7J4g>i_%Vsut_W z+Nr#4pg^&Tto_eB)w#=5 z=XI-bq1CqHyu-^B?O4 zCsh1HWAneF(f-!oCui;o<_xHoptGE1X z?Ts=^krFXyhZ@q64Rl-CN>fkVM$I$Wlm>liS+2%}BVPyWmZkUgpU3NFCTlWh6(LjS zA#okOg^^yMU*I5hZgaRiA-McnZ6KpML zGkwG>=OT<3qfp494XD<{xeo-Y*K?UrlpN>jzXcGCA{;rapm?i57?~|tv=Zwk>>=uT zceHVYt!lz#e`zTpRNoY*cUu#vZvCnCH}CCfr_1JcgQF*yUg*&tiHS+Pa}8F-C@T6pC^xZ8H|OcxX^$LFY278z z6M_-@CCY1LCAMvwyk;$qu$Kc2+b6^(91{aG(;l^vXo^dwQA%_%rhOj z{vO;+wTDG-tyy$LT;szlW3!Mhl=4#IbF_<8GIC&lwXf_K6vpJzsAuGQVmy(R0jo&L zq!(75t?Wviaav&mVS=F!V2&)`Y@R~by))wO*jQ34iW_D|qfhR5D}J`fsm|pk6H?*m z!@mMDBH2jANcp}HkE(%^%TZ8;Y7A&-#;O}&x)=>91_15z8`$mVdhi0CG#4=JQS;dM z?-k~UO#J5iQO^F@8#IvHOQ4Rr$%QI?rVXj&rI66-)iT>-W;tn#fDqG4qmj|-jdq7u z0xTn`m6%@&va)mJtH6gtqmG16uH0{(s}8H~WmVXmOa*DJ>t}KhB%~X9CFM)>PK#NU znU{^b$~xIWQt7U^Kp>Of=Njs%Av9NM}T80gYoI4!5ta*xAx<<1Z=Nm*`x+FVSO4 zZ??pRGiYRmdE@>(+Z9tAG+3;YC+}xdJ-uzq)Q{RnRBKO63&&>^KCV%(GWhB8@=KMkX( z{o+jP%0sa8#Lz=ECn>Mee!nDnpB>Eb>5m16hVpBNcigBiBwa|#lWy)I43?_{t0GaF zU}$J|23hyqBtJV0Icp7-xAGVA!w|QAca{6Sb{{iRbP5!{Ud#q9S;Q+XY{ImZe1+!8 zIrk8`qgMV=TJ1O+h^Qq2i@@-xx*bL5PvSs&MRSEY1rV;M7datq5^4l#>#}b4f0@A- z0|w*-F`Ut~PbCAd(9F$BKd`XO;(+sl{%s-SEr#OS9|8g_lYj!4ry9qVgt6Gzs~Zdi zGn5u36~SQOT#La85LPn=frDP!lLMp@V`%?eby-(oH#0j+b1#=w53u1NY_z1gIg8f}D9a00X!rvb-D?&7DcP�ur!R;zEEe=_v^wHTI5DS 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 !w+fqkGKSL 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 Xl+HHsMalJ^|Z1udU)c&WFU>?=*#7J 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ȁgmR4-I#2iuw2^H3k5n7U)kC&m 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%0Awt*t`h29v-RlOBtYhQ^R3~A45vWh7Z|Kd< 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

D1m6OnoPfUu^< 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 EH{2!8L;wH) literal 0 HcmV?d00001 diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx.h b/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx.h new file mode 100755 index 0000000000000..babc34a96c088 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx.h @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2007 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx.h + * + * \version $Revision: 1 $ + * + * \date $Date: 02/08/07 08:32 $ + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * HDMI Tx Driver - tmdlHdmiTx - SCS.doc + * + * \section info Change Information + * + * \verbatim + + $History: tmdlHdmiTx.h $ + * + * ***************** Version 13 ***************** + * User: Demoment Date: 02/08/07 Time: 08:32 + * Updated in $/Source/tmdlHdmiTx/inc + * initial version + * + + \endverbatim + * +*/ + +#ifndef TMDLHDMITX_H +#define TMDLHDMITX_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ +#include "tmNxCompId.h" +#include "tmdlHdmiTx_Types.h" +#include "tmdlHdmiTx_Functions.h" + + +#endif /* TMDLHDMITX_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Functions.h b/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Functions.h new file mode 100755 index 0000000000000..f8664eaeccaf8 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Functions.h @@ -0,0 +1,1806 @@ +/** + * Copyright (C) 2007 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_Functions.h + * + * \version $Revision: 1 $ + * + * \date $Date: 02/08/07 8:32 $ + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * HDMI Tx Driver - tmdlHdmiTx - SCS.doc + * + * \section info Change Information + * + * \verbatim + + $History: tmdlHdmiTx_Functions.h $ + * + * ***************** Version 1 ***************** + * User: Demoment Date: 02/08/07 Time: 8:32 + * Updated in $/Source/tmdlHdmiTx/inc + * initial version + * + + \endverbatim + * +*/ + +#ifndef TMDLHDMITX_FUNCTIONS_H +#define TMDLHDMITX_FUNCTIONS_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmNxTypes.h" +#include "tmdlHdmiTx_Types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* EXTERN FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/*****************************************************************************/ +/** + \brief Get the software version of the driver. + + \param pSWVersion Pointer to the version structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetSWVersion +( + tmSWVersion_t *pSWVersion +); + +/*****************************************************************************/ +/** + \brief Get the number of available HDMI transmitters devices in the system. + A unit directly represents a physical device. + + \param pUnitCount Pointer to the number of available units. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetNumberOfUnits +( + UInt32 *pUnitCount +); + +/*****************************************************************************/ +/** + \brief Get the capabilities of unit 0. Capabilities are stored into a + dedicated structure and are directly read from the HW device. + + \param pCapabilities Pointer to the capabilities structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetCapabilities +( + tmdlHdmiTxCapabilities_t *pCapabilities +); + +/*****************************************************************************/ +/** + \brief Get the capabilities of a specific unit. Capabilities are stored + into a dedicated structure and are directly read from the HW + device. + + \param unit Unit to be probed. + \param pCapabilities Pointer to the capabilities structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetCapabilitiesM +( + tmUnitSelect_t unit, + tmdlHdmiTxCapabilities_t *pCapabilities +); + +/*****************************************************************************/ +/** + \brief Open unit 0 of HdmiTx driver and provides the instance number to + the caller. Note that one unit of HdmiTx represents one physical + HDMI transmitter and that only one instance per unit can be opened. + + \param pInstance Pointer to the variable that will receive the instance + identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the transmitter instance is not initialised + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: the unit is not initialized + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_INIT_FAILED: the unit instance is already + initialised + - TMBSL_ERR_HDMI_COMPATIBILITY: the driver is not compatiable + with the internal device version code + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxOpen +( + tmInstance_t *pInstance +); + +/*****************************************************************************/ +/** + \brief Open a specific unit of HdmiTx driver and provides the instance + number to the caller. Note that one unit of HdmiTx represents one + physical HDMI transmitter and that only one instance per unit can be + opened. This function switches driver's state machine to + "initialized" state. + + \param pInstance Pointer to the structure that will receive the instance + identifier. + \param unit Unit number to be opened. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the transmitter instance is not initialised + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: the unit is not initialized + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_INIT_FAILED: the unit instance is already + initialised + - TMBSL_ERR_HDMI_COMPATIBILITY: the driver is not compatiable + with the internal device version code + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxOpenM +( + tmInstance_t *pInstance, + tmUnitSelect_t unit +); + +/*****************************************************************************/ +/** + \brief Close an instance of HdmiTx driver. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxClose +( + tmInstance_t instance +); + +/*****************************************************************************/ +/** + \brief Set the power state of an instance of the HDMI transmitter. + + \param instance Instance identifier. + \param powerState Power state to set. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetPowerState +( + tmInstance_t instance, + tmPowerState_t powerState +); + +/*****************************************************************************/ +/** + \brief Get the power state of an instance of the HDMI transmitter. + + \param instance Instance identifier. + \param pPowerState Pointer to the power state. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetPowerState +( + tmInstance_t instance, + tmPowerState_t *pPowerState +); + +/*****************************************************************************/ +/** + \brief Set the configuration of instance attributes. This function is + required by DVP architecture rules but actually does nothing in this + driver + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxInstanceConfig +( + tmInstance_t instance +); + +/*****************************************************************************/ +/** + \brief Setup the instance with its configuration parameters. This function + allows basic instance configuration like enabling HDCP, choosing + HDCP encryption mode or enabling HDCP repeater mode. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure containing all setup parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxInstanceSetup +( + tmInstance_t instance, + tmdlHdmiTxInstanceSetupInfo_t *pSetupInfo +); + +/*****************************************************************************/ +/** + \brief Get instance setup parameters. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure that will receive setup + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetInstanceSetup +( + tmInstance_t instance, + tmdlHdmiTxInstanceSetupInfo_t *pSetupInfo +); + +/*****************************************************************************/ +/** + \brief Make device library handle an incoming interrupt. This function is + used by application to tell the device library that the hardware + sent an interrupt. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_FULL: the queue is full + + ******************************************************************************/ +tmErrorCode_t tmdlHdmiTxHandleInterrupt +( + tmInstance_t instance +); + +/*****************************************************************************/ +/** + \brief Register event callbacks. Only one callback is registered through + this API. This callback will received the type of event that + occured throug a dedicated parameter and will be called as many + times as there is pending events. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pCallback Pointer to the callback function that will handle events + from the devlib. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxRegisterCallbacks +( + tmInstance_t instance, + ptmdlHdmiTxCallback_t pCallback +); + +/*****************************************************************************/ +/** + \brief This function allows enabling a specific event. By default, all + events are disabled, except input lock. + + \param instance Instance identifier. + \param event Event to enable. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxEnableEvent +( + tmInstance_t instance, + tmdlHdmiTxEvent_t event +); + +/*****************************************************************************/ +/** + \brief This function allows disabling a specific event. By default, all + events are disabled, except input lock. + + \param instance Instance identifier. + \param event Event to disable. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxDisableEvent +( + tmInstance_t instance, + tmdlHdmiTxEvent_t event +); + +/*****************************************************************************/ +/** + \brief Get specifications of a given video format. Application can use + this function to retreives all specifications (frequencies, + resolution, etc.) of a given IA/CEA 861-D video format. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param resolutionID ID of the resolution to retrieve specs from. + \param pResolutionSpecs Pointer to the structure receiving specs. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN: the resolution is unknown + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetVideoFormatSpecs +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t resolutionID, + tmdlHdmiTxVidFmtSpecs_t *pResolutionSpecs +); + +/*****************************************************************************/ +/** + \brief Configures all input and output parameters : format, modes, rates, + etc. This is the main configuration function of the driver. Here + are transmitted all crucial input and output parameters of the + device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param videoInputConfig Configuration of the input video. + \param videoOutputConfig Configuration of the output video. + \param audioInputConfig Configuration of the input audio. + \param sinkType Type of sink connected to the output of the Tx. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetInputOutput +( + tmInstance_t instance, + tmdlHdmiTxVideoInConfig_t videoInputConfig, + tmdlHdmiTxVideoOutConfig_t videoOutputConfig, + tmdlHdmiTxAudioInConfig_t audioInputConfig, + tmdlHdmiTxSinkType_t sinkType +); + +/*****************************************************************************/ +/** + \brief Configures audio input parameters : format, rate, etc. + This function is similar to tmdlHdmiTxSetInputOutput except that + video is not reconfigured. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param audioInputConfig Configuration of the input audio. + \param sinkType Type of sink connected to the output of the Tx. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetAudioInput +( + tmInstance_t instance, + tmdlHdmiTxAudioInConfig_t audioInputConfig, + tmdlHdmiTxSinkType_t sinkType +); + +/*****************************************************************************/ +/** + \brief Defines the content of AVI infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pAviIfData Pointer to the structure containing AVI infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetVideoInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxAviIfData_t *pAviIfData +); + +/*****************************************************************************/ +/** + \brief Defines the content of AUD infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pAudIfData Pointer to the structure containing AUD infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetAudioInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxAudIfData_t *pAudIfData +); + +/*****************************************************************************/ +/** + \brief Defines the content of the audio content protection packet to be + sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pAcpPktData Pointer to the structure containing ACP infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetACPPacket +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxAcpPktData_t *pAcpPktData +); + +/*****************************************************************************/ +/** + \brief Defines the content of the General Control packet to be sent by Tx + device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pGcpPktData Pointer to the structure containing GCP packet parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetGeneralControlPacket +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxGcpPktData_t *pGcpPktData +); + +/*****************************************************************************/ +/** + \brief Defines the content of ISRC1 packet to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pIsrc1PktData Pointer to the structure containing GCP packet parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetISRC1Packet +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxIsrc1PktData_t *pIsrc1PktData +); + +/*****************************************************************************/ +/** + \brief Defines the content of ISRC2 packet to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pIsrc2PktData Pointer to the structure containing GCP packet parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetISRC2Packet +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxIsrc2PktData_t *pIsrc2PktData +); + +/*****************************************************************************/ +/** + \brief Defines the content of MPS infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pMpsIfData Pointer to the structure containing MPS infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetMPSInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxMpsIfData_t *pMpsIfData +); + +/*****************************************************************************/ +/** + \brief Defines the content of SPD infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pSpdIfData Pointer to the structure containing SPD infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetSpdInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxSpdIfData_t *pSpdIfData +); + +/*****************************************************************************/ +/** + \brief Defines the content of VS infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pVsIfData Pointer to the structure containing VS infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetVsInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxVsPktData_t *pVsIfData +); + +/*****************************************************************************/ +/** + \brief Enables/disables NULL packet sending (only used for debug purpose). + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable packet insertion. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxDebugSetNullPacket +( + tmInstance_t instance, + Bool enable +); + +/*****************************************************************************/ +/** + \brief Send one single NULL packet (only used for debug purpose). + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxDebugSetSingleNullPacket +( + tmInstance_t instance +); + +/*****************************************************************************/ +/** + \brief Set the audio output mute status. This function can be used to mute + audio output, without muting video. This can be typically used when + reconfiguring the audio HW after a sample rate change. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param muteStatus Mute status (True/False). + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetAudioMute +( + tmInstance_t instance, + Bool audioMute +); + +/*****************************************************************************/ +/** + \brief Reset audio CTS. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxResetAudioCts +( + tmInstance_t instance +); + +/*****************************************************************************/ +/** + \brief Retrieve EDID Status from driver. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pEdidStatus Pointer to the array that will receive the EDID Status. + \param pEdidBlkCount Pointer to the integer that will receive the number of + read EDID block. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidStatus +( + tmInstance_t instance, + tmdlHdmiTxEdidStatus_t *pEdidStatus, + UInt8 *pEdidBlkCount +); + +/*****************************************************************************/ +/** + \brief Retrieves audio descriptors from receiver's EDID. This function + parses the EDID of Tx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + + \param instance Instance identifier. + \param pAudioDescs Pointer to the array that will receive audio + descriptors. + \param maxAudioDescs Size of the array. + \param pWrittenAudioDescs Pointer to the integer that will receive the actual + number of written descriptors. + \param pAudioFlags Pointer to the byte to receive Audio Capabilities Flags. + This byte is filled as such: + b7 is the Basic audio bit from CEA Extension Version 3. + If this bit is set to 1 this means that the sink handles "Basic audio" i.e. + two channel L-PCM audio at sample rates of 32kHz, 44.1kHz, and 48kHz. + b6 is the Supports_AI bit from the VSDB + This bit set to 1 if the sink supports at least one function that uses + information carried by the ACP, ISRC1, or ISRC2 packets. + b5-b0 0 + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidAudioCaps +( + tmInstance_t instance, + tmdlHdmiTxEdidAudioDesc_t *pAudioDescs, + UInt maxAudioDescs, + UInt *pWrittenAudioDescs, + UInt8 *pAudioFlags +); + +/*****************************************************************************/ +/** + \brief Retrieves supported video formats (short descriptors) from + receiver's EDID. This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pVideoDesc Pointer to the structure that will receive short + video descriptors. + \param maxVideoFormats Size of the array. + \param pWrittenVideoFormats Pointer to the integer that will receive the actual + number of written descriptors. + \param pVideoFlags Pointer to the byte to receive Video Capability Flags. + b7: underscan supported + b6: YCbCr 4:4:4 supported + b5: YCbCr 4:2:2 supported + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidVideoCaps +( + tmInstance_t instance, + tmdlHdmiTxShortVidDesc_t *pVideoDesc, + UInt maxVideoFormats, + UInt *pWrittenVideoFormats, + UInt8 *pVideoFlags +); + +/*****************************************************************************/ +/** + \brief Retrieves supported video formats (short descriptors) from + receiver's EDID. This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pNativeVideoFormat Pointer to the array that will receive video + timing descriptor. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidVideoPreferred +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pNativeVideoFormat +); + +/*****************************************************************************/ +/** + \brief Retrieves the sink type from receiver's EDID (HDMI or DVI). This + function parses the EDID of Rx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pSinkType Pointer to the array that will receive sink type. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: bad transmitter unit number + - TMDL_ERR_DLHDMITX_NOT_INITIALIZED: the transmitter is not initialized + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidSinkType +( + tmInstance_t instance, + tmdlHdmiTxSinkType_t *pSinkType +); + +/*****************************************************************************/ +/** + \brief Retrieves source address from receivers's EDID. This + function parses the EDID of Rx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pSourceAddress Pointer to the integer that will receive the EDID source + address. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidSourceAddress +( + tmInstance_t instance, + UInt16 *pSourceAddress +); + + + +/*****************************************************************************/ +/** + \brief Retreives KSV list received by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pKsv Pointer to the array that will receive the KSV list. + \param maxKsv Maximum number of KSV that the array can store. + \param pWrittenKsv Actual number of KSV written into the array. + \param pDepth Connection tree depth. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetKsvList +( + tmInstance_t instance, + UInt8 *pKsv, + UInt8 maxKsv, + UInt8 *pWrittenKsv, + UInt8 *pDepth, + Bool *pMaxCascExd, + Bool *pMaxDevsExd +); +#ifdef HDMI_TX_REPEATER_ISR_MODE +/****************************************************************************** + \brief Retreives HDCP depth received by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pDepth Connection tree depth returned with KSV list. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetDepth( + tmInstance_t instance, + UInt8 *pDepth +); + +/****************************************************************************** + \brief Generate SHA_1 interrupt if not occured. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGeneSHA_1_IT +( + tmInstance_t instance +); +#endif /* HDMI_TX_REPEATER_ISR_MODE */ +/*****************************************************************************/ +/** + \brief Enable/Disable HDCP encryption. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param hdcpEnable HDCP On/Off (true = On, False = Off). + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN: the resolution is unknown + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetHdcp +( + tmInstance_t instance, + Bool hdcpEnable +); + +/*****************************************************************************/ +/** + \brief Get the driver HDCP state. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pHdcpCheckState Pointer to the integer that will receive the HDCP check state. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetHdcpState +( + tmInstance_t instance, + tmdlHdmiTxHdcpCheck_t *pHdcpCheckState +); + +/*****************************************************************************/ +/** + \brief Check the result of an HDCP encryption attempt, called at + intervals (set by timeSinceLastCall) after tmdlHdmiTxSetHdcp(true). + This API must be used only in case of No Operating System. if OS, + this is manage internally of this device library. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param timeSinceLastCall Time passed in milliseconds since last call, + must be shorter than 600 ms. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxHdcpCheck +( + tmInstance_t instance, + UInt16 timeSinceLastCall +); + +/*****************************************************************************/ +/** + \brief This function loads a gamut metadata packet into the HW. HW will + actually send it at the beginning of next VS, during the vertical + blanking. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable gamut metadata packet insertion. + \param pGamutData Pointer to the structure containing gamut metadata + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetGamutPacket +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxGamutData_t *pGamutData +); + +/*****************************************************************************/ +/** + \brief This function set the extended colorimetry with one of the following + extended colorimetries(bits EC2-0): xvYCC601, xvYCC709, sYCC601, + AdobeYCC601, AdobeRGB. When the parameter extendedColorimetry is + xvYCC601 or xvYCC70, this function calls the API tmdlHdmiTxSetGamutPacket + to send Gamut Packet Data that does not exist for all other types of + extended colorimetries for which pointer pGamutData can be set to NULL. + This function also allows to set YCC Quantization Range (YQ1-0) + + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/Disable extended colorimetry. + \param extendedColorimetry value of the extended colorimetry (bits EC2 EC1 EC0). + \param yccQR YCC quantisation range + \param pGamutData Pointer to the structure containing gamut metadata + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter was out of range + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetExtendedColorimetry +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxExtColorimetry_t extendedColorimetry, + tmdlHdmiTxYCCQR_t yccQR, + tmdlHdmiTxGamutData_t *pGamutData +); + +/*****************************************************************************/ +/** + \brief Retrieves supported detailled video descriptors from + receiver's EDID. This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pDTDescriptors Pointer to the array that will receive detailled + timing descriptors. + \param maxDTDesc Size of the array. + \param pWrittenDesc Pointer to the integer that will receive the actual + number of written descriptors. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidDetailledTimingDescriptors +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + UInt8 maxDTDesc, + UInt8 *pWrittenDTDesc +); + +/*****************************************************************************/ +/** + \brief Retrieves supported monitor descriptor from receiver's EDID. + This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pEdidFirstMD Pointer to the array that will receive the first monitor + descriptors. + \param pEdidSecondMD Pointer to the array that will receive the second monitor + descriptors. + \param pEdidOtherMD Pointer to the array that will receive the other monitor + descriptors. + \param maxOtherMD Size of the array. + \param pWrittenOtherMD Pointer to the integer that will receive the actual + number of written descriptors. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidMonitorDescriptors +( + tmInstance_t instance, + tmdlHdmiTxEdidFirstMD_t *pEdidFirstMD, + tmdlHdmiTxEdidSecondMD_t *pEdidSecondMD, + tmdlHdmiTxEdidOtherMD_t *pEdidOtherMD, + UInt8 maxOtherMD, + UInt8 *pWrittenOtherMD +); + +/*****************************************************************************/ +/** + \brief Retrieves TV picture ratio from receiver's EDID. + This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pEdidTvPictureRatio Pointer to the variable that will receive TV picture ratio + value. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidTVPictureRatio +( + tmInstance_t instance, + tmdlHdmiTxPictAspectRatio_t *pEdidTvPictureRatio +); + +/****************************************************************************** + \brief This function set the revocation list use for HDCP + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param listPtr Pointer on revocation list provide by application. + \param length length of revocation list. + + \return The call result: + - TM_OK: the call was successful, however RX keys have + not been checked with provided revocation list + because they are not available. + - TMDL_DLHDMITX_HDCP_SECURE: the call was successful, RX keys are secure + - TMDL_DLHDMITX_HDCP_NOT_SECURE: the call was successful, RX keys are NOT secure + - TMDL_ERR_DLHDMITX_INVALID_STATE: we are a repeater + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + + +******************************************************************************/ + +tmErrorCode_t tmdlHdmiTxSetHDCPRevocationList( + tmInstance_t instance, + void *listPtr, + UInt32 length +); + + +/*****************************************************************************/ +/** + \brief Retreives current HDCP link status. This function is typically used + when an "HDCP INACTIVE" event is received to know why HDCP + is INACTIVE. + + \param instance Instance identifier. + \param pHdcpStatus Pointer to the enum describing the status. + \param pRawStatus Pointer to the byte with the raw error code from HW. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMITX_NOT_INITIALIZED: the transmitter is not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetHdcpFailStatus +( + tmInstance_t instance, + tmdlHdmiTxHdcpStatus_t *pHdcpStatus, + UInt8 *pRawStatus +); + + +/*****************************************************************************/ +/** + \brief Retrieves latency information from receiver's EDID. + This function is synchronous. + This function is not ISR friendly. + + + \param instance Instance identifier. + \param pLatency Pointer to the data structure that receive latency + information. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidLatencyInfo +( + tmInstance_t instance, + tmdlHdmiTxEdidLatency_t *pLatency +); + + +/****************************************************************************** + \brief Retrieves additional data from receiver's EDID VSDB. This function + parses the EDID of Rx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pExtraVsdbData Pointer to the structure of additional VSDB data + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidExtraVsdbData +( + tmInstance_t instance, + tmdlHdmiTxEdidExtraVsdbData_t **pExtraVsdbData +); + + +/****************************************************************************** + \brief This function set the B... screen + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful, however RX keys have + not been checked with provided revocation list + because they are not available. + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + + +******************************************************************************/ + +tmErrorCode_t tmdlHdmiTxSetBScreen( + tmInstance_t instance, + tmdlHdmiTxTestPattern_t pattern +); + +/****************************************************************************** + \brief This function set the Remove B.... screen + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful, however RX keys have + not been checked with provided revocation list + because they are not available. + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + + +******************************************************************************/ + +tmErrorCode_t tmdlHdmiTxRemoveBScreen( + tmInstance_t instance +); + +/****************************************************************************** + \brief This function Convert DTD to CEA + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pDTDescriptors Pointer on one DTD + \return The call result: + - CEA code + + +******************************************************************************/ +tmdlHdmiTxVidFmt_t tmdlHdmiTxConvertDTDtoCEA +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors +); + + +/*****************************************************************************/ +/** + \brief Retrieve HPD status from driver. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pHPDStatus Pointer to the variable that will receive the HPD Status. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetHPDStatus +( + tmInstance_t instance, + tmdlHdmiTxHotPlug_t * pHPDStatus +); + + +/*****************************************************************************/ +/** + \brief Retrieve RXSense status from driver. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pRXSenseStatus Pointer to the variable that will receive the RXSense Status. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetRXSenseStatus +( + tmInstance_t instance, + tmdlHdmiTxRxSense_t * pRXSenseStatus +); + + +/****************************************************************************** + \brief Mute or unmute the TMDS outputs. + + \param instance Instance identifier. + \param muteTmdsOut Mute or unmute indication. + + \return NA. + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxTmdsSetOutputsMute +( + tmInstance_t instance, + Bool muteTmdsOut +); + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMITX_FUNCTIONS_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h b/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h new file mode 100755 index 0000000000000..db98a7c2f528c --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h @@ -0,0 +1,1066 @@ +/** + * Copyright (C) 2007 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_Types.h + * + * \version $Revision: 1 $ + * + * \date $Date: 02/08/07 08:32 $ + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * HDMI Tx Driver - tmdlHdmiTx - SCS.doc + * + * \section info Change Information + * + * \verbatim + + $History: tmdlHdmiTx_Types.h $ + * + * ***************** Version 1 ***************** + * User: Demoment Date: 02/08/07 Time: 08:32 + * Updated in $/Source/tmdlHdmiTx/inc + * initial version + + \endverbatim + * +*/ + +#ifndef TMDLHDMITX_TYPES_H +#define TMDLHDMITX_TYPES_H + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ + +#include "tmNxTypes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + +/*============================================================================*/ +/* DEFINES */ +/*============================================================================*/ + +/**< Error Codes */ +#define TMDL_ERR_DLHDMITX_BASE CID_DL_HDMITX +#define TMDL_ERR_DLHDMITX_COMP (TMDL_ERR_DLHDMITX_BASE | TM_ERR_COMP_UNIQUE_START) + +#define TMDL_ERR_DLHDMITX_COMPATIBILITY (TMDL_ERR_DLHDMITX_BASE + TM_ERR_COMPATIBILITY) /**< SW Interface compatibility */ +#define TMDL_ERR_DLHDMITX_MAJOR_VERSION (TMDL_ERR_DLHDMITX_BASE + TM_ERR_MAJOR_VERSION) /**< SW Major Version error */ +#define TMDL_ERR_DLHDMITX_COMP_VERSION (TMDL_ERR_DLHDMITX_BASE + TM_ERR_COMP_VERSION) /**< SW component version error */ +#define TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER (TMDL_ERR_DLHDMITX_BASE + TM_ERR_BAD_UNIT_NUMBER) /**< Invalid device unit number */ +#define TMDL_ERR_DLHDMITX_BAD_INSTANCE (TMDL_ERR_DLHDMITX_BASE + TM_ERR_BAD_INSTANCE) /**< Bad input instance value */ +#define TMDL_ERR_DLHDMITX_BAD_HANDLE (TMDL_ERR_DLHDMITX_BASE + TM_ERR_BAD_HANDLE) /**< Bad input handle */ +#define TMDL_ERR_DLHDMITX_BAD_PARAMETER (TMDL_ERR_DLHDMITX_BASE + TM_ERR_BAD_PARAMETER) /**< Invalid input parameter */ +#define TMDL_ERR_DLHDMITX_NO_RESOURCES (TMDL_ERR_DLHDMITX_BASE + TM_ERR_NO_RESOURCES) /**< Resource is not available */ +#define TMDL_ERR_DLHDMITX_RESOURCE_OWNED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_RESOURCE_OWNED) /**< Resource is already in use */ +#define TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_RESOURCE_NOT_OWNED) /**< Caller does not own resource */ +#define TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS (TMDL_ERR_DLHDMITX_BASE + TM_ERR_INCONSISTENT_PARAMS) /**< Inconsistent input params */ +#define TMDL_ERR_DLHDMITX_NOT_INITIALIZED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_NOT_INITIALIZED) /**< Component is not initialized */ +#define TMDL_ERR_DLHDMITX_NOT_SUPPORTED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_NOT_SUPPORTED) /**< Function is not supported */ +#define TMDL_ERR_DLHDMITX_INIT_FAILED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_INIT_FAILED) /**< Initialization failed */ +#define TMDL_ERR_DLHDMITX_BUSY (TMDL_ERR_DLHDMITX_BASE + TM_ERR_BUSY) /**< Component is busy */ +#define TMDL_ERR_DLHDMITX_I2C_READ (TMDL_ERR_DLHDMITX_BASE + TM_ERR_READ) /**< Read error */ +#define TMDL_ERR_DLHDMITX_I2C_WRITE (TMDL_ERR_DLHDMITX_BASE + TM_ERR_WRITE) /**< Write error */ +#define TMDL_ERR_DLHDMITX_FULL (TMDL_ERR_DLHDMITX_BASE + TM_ERR_FULL) /**< Queue is full */ +#define TMDL_ERR_DLHDMITX_NOT_STARTED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_NOT_STARTED) /**< Function is not started */ +#define TMDL_ERR_DLHDMITX_ALREADY_STARTED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_ALREADY_STARTED) /**< Function is already started */ +#define TMDL_ERR_DLHDMITX_ASSERTION (TMDL_ERR_DLHDMITX_BASE + TM_ERR_ASSERTION) /**< Assertion failure */ +#define TMDL_ERR_DLHDMITX_INVALID_STATE (TMDL_ERR_DLHDMITX_BASE + TM_ERR_INVALID_STATE) /**< Invalid state for function */ +#define TMDL_ERR_DLHDMITX_OPERATION_NOT_PERMITTED (TMDL_ERR_DLHDMITX_BASE + TM_ERR_OPERATION_NOT_PERMITTED) /**< Corresponds to posix EPERM */ +#define TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN (TMDL_ERR_DLHDMITX_BASE + TM_ERR_BAD_FORMAT) /**< Bad format */ + +#define TMDL_DLHDMITX_HDCP_SECURE (TMDL_ERR_DLHDMITX_COMP + 0x0001) /**< Revocation list is secure */ +#define TMDL_DLHDMITX_HDCP_NOT_SECURE (TMDL_ERR_DLHDMITX_COMP + 0x0002) /**< Revocation list is NOT secure */ + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ + +/** + * \brief Enum listing all events that can be signalled to application + */ +typedef enum +{ + TMDL_HDMITX_HDCP_ACTIVE = 0, /**< HDCP encryption status switched to active */ + TMDL_HDMITX_HDCP_INACTIVE = 1, /**< HDCP encryption status switched to inactive */ + TMDL_HDMITX_HPD_ACTIVE = 2, /**< Hotplug status switched to active */ + TMDL_HDMITX_HPD_INACTIVE = 3, /**< Hotplug status switched to inactive */ + TMDL_HDMITX_RX_KEYS_RECEIVED = 4, /**< Receiver(s) key(s) received */ + TMDL_HDMITX_RX_DEVICE_ACTIVE = 5, /**< Rx device is connected and active */ + TMDL_HDMITX_RX_DEVICE_INACTIVE = 6, /**< Rx device is connected but inactive (standby) */ + TMDL_HDMITX_EDID_RECEIVED = 7, /**< EDID has been received */ + TMDL_HDMITX_VS_RPT_RECEIVED = 8, /**< VS interrupt has been received */ +#ifdef HDMI_TX_REPEATER_ISR_MODE + TMDL_HDMITX_B_STATUS = 9, /**< TX received BStatus */ +#endif /* HDMI_TX_REPEATER_ISR_MODE */ + TMDL_HDMITX_DEBUG_EVENT_1 = 10 /**< This is a debug event */ +} tmdlHdmiTxEvent_t; + +/** + * \brief Enum listing all available event status + */ +typedef enum +{ + TMDL_HDMITX_EVENT_ENABLED, /**< Event is enabled */ + TMDL_HDMITX_EVENT_DISABLED /**< Event is disabled */ +} tmdlHdmiTxEventStatus_t; + +/** + * \brief Callback function pointer type, used to allow driver to callback + application when activity status is changing at input. + * \param Event Identifier of the source event. + */ +typedef void (*ptmdlHdmiTxCallback_t) (tmdlHdmiTxEvent_t event); + +/** + * \brief Enum listing all supported device versions + */ + typedef enum + { + TMDL_HDMITX_DEVICE_UNKNOWN, /**< HW device is unknown */ + TMDL_HDMITX_DEVICE_TDA9984, /**< HW device is IC TDA9984 */ + TMDL_HDMITX_DEVICE_TDA9989, /**< HW device is IC TDA9989 */ + TMDL_HDMITX_DEVICE_TDA9981, /**< HW device is IC TDA9981 */ + TMDL_HDMITX_DEVICE_TDA9983, /**< HW device is IC TDA9983 */ + TMDL_HDMITX_DEVICE_TDA19989, /**< HW device is IC TDA19989 */ + TMDL_HDMITX_DEVICE_TDA19988 /**< ok, u got it, it's a TDA19988 */ + } tmdlHdmiTxDeviceVersion_t; + +/** + * \brief Enum defining the supported HDMI standard version + */ +typedef enum +{ + TMDL_HDMITX_HDMI_VERSION_UNKNOWN, /**< Unknown */ + TMDL_HDMITX_HDMI_VERSION_1_1, /**< HDMI 1.1 */ + TMDL_HDMITX_HDMI_VERSION_1_2a, /**< HDMI 1.2a */ + TMDL_HDMITX_HDMI_VERSION_1_3a /**< HDMI 1.3 */ +} tmdlHdmiTxHdmiVersion_t; + +/** + * \brief Enum listing all color depth (8 bits/color, 10 bits/color, etc.) + */ +typedef enum +{ + TMDL_HDMITX_COLORDEPTH_24 = 0, /**< 8 bits per color */ + TMDL_HDMITX_COLORDEPTH_30 = 1, /**< 10 bits per color */ + TMDL_HDMITX_COLORDEPTH_36 = 2, /**< 12 bits per color */ + TMDL_HDMITX_COLORDEPTH_48 = 3 /**< 16 bits per color */ +} tmdlHdmiTxColorDepth_t; + +/** + * \brief Enum defining the EDID Status + */ +typedef enum +{ + TMDL_HDMITX_EDID_READ = 0, /**< All blocks read OK */ + TMDL_HDMITX_EDID_READ_INCOMPLETE = 1, /**< All blocks read OK but buffer too small to return all of them */ + TMDL_HDMITX_EDID_ERROR_CHK_BLOCK_0 = 2, /**< Block 0 checksum error */ + TMDL_HDMITX_EDID_ERROR_CHK = 3, /**< Block 0 OK, checksum error in one or more other blocks */ + TMDL_HDMITX_EDID_NOT_READ = 4, /**< EDID not read */ + TMDL_HDMITX_EDID_STATUS_INVALID = 5 /**< Invalid */ +} tmdlHdmiTxEdidStatus_t; + +/** + * \brief Structure defining the supported audio packets + */ +typedef struct +{ + Bool HBR; /**< High Bitrate Audio packet */ + Bool DST; /**< Direct Stream Transport audio packet */ + Bool oneBitAudio; /**< One Bit Audio sample packet */ +} tmdlHdmiTxAudioPacket_t; + +/** + * \brief Enum listing all possible audio input formats + */ +typedef enum +{ + TMDL_HDMITX_AFMT_SPDIF = 0, /**< SPDIF */ + TMDL_HDMITX_AFMT_I2S = 1, /**< I2S */ + TMDL_HDMITX_AFMT_OBA = 2, /**< One bit audio / DSD */ + TMDL_HDMITX_AFMT_DST = 3, /**< DST */ + TMDL_HDMITX_AFMT_HBR = 4 /**< HBR */ +} tmdlHdmiTxAudioFormat_t; + +/** + * \brief Enum listing all possible audio input sample rates + */ +typedef enum +{ + TMDL_HDMITX_AFS_32K = 0, /**< 32kHz */ + TMDL_HDMITX_AFS_44K = 1, /**< 44.1kHz */ + TMDL_HDMITX_AFS_48K = 2, /**< 48kHz */ + TMDL_HDMITX_AFS_88K = 3, /**< 88.2kHz */ + TMDL_HDMITX_AFS_96K = 4, /**< 96kHz */ + TMDL_HDMITX_AFS_176K = 5, /**< 176.4kHz */ + TMDL_HDMITX_AFS_192K = 6 /**< 192kHz */ +} tmdlHdmiTxAudioRate_t; + +/** + * \brief Enum listing all possible audio input sample rates + */ +typedef enum +{ + TMDL_HDMITX_I2SQ_16BITS = 16, /**< 16 bits */ + TMDL_HDMITX_I2SQ_32BITS = 32, /**< 32 bits */ + TMDL_HDMITX_I2SQ_OTHERS = 0 /**< for SPDIF and DSD */ +} tmdlHdmiTxAudioI2SQualifier_t; + +/** + * \brief Enum listing all possible audio I2S formats + */ +typedef enum +{ + TMDL_HDMITX_I2SFOR_PHILIPS_L = 0, /**< Philips like format */ + TMDL_HDMITX_I2SFOR_OTH_L = 2, /**< Other non Philips left justified */ + TMDL_HDMITX_I2SFOR_OTH_R = 3, /**< Other non Philips right justified */ + TMDL_HDMITX_I2SFOR_INVALID = 4 /**< Invalid format */ +} tmdlHdmiTxAudioI2SFormat_t; + +/** + * \brief Enum listing all possible DST data transfer rates + */ +typedef enum +{ + TMDL_HDMITX_DSTRATE_SINGLE = 0, /**< Single transfer rate */ + TMDL_HDMITX_DSTRATE_DOUBLE = 1 /**< Double data rate */ +} tmdlHdmiTxDstRate_t; + +/** + * \brief Structure describing unit capabilities + */ +typedef struct +{ + tmdlHdmiTxDeviceVersion_t deviceVersion; /**< HW device version */ + tmdlHdmiTxHdmiVersion_t hdmiVersion; /**< Supported HDMI standard version */ + tmdlHdmiTxAudioPacket_t audioPacket; /**< Supported audio packets */ + tmdlHdmiTxColorDepth_t colorDepth; /**< Supported color depth */ + Bool hdcp; /**< Supported Hdcp encryption (True/False) */ + Bool scaler; /**< Supported scaler (True/False) */ +} tmdlHdmiTxCapabilities_t; + +/** + * \brief Structure gathering all instance setup parameters + */ +typedef struct +{ + Bool simplayHd; /**< Enable simplayHD support */ + Bool repeaterEnable; /**< Enable repeater mode */ + UInt8 *pEdidBuffer; /**< Pointer to raw EDID data */ + UInt32 edidBufferSize; /**< Size of buffer for raw EDID data */ +} tmdlHdmiTxInstanceSetupInfo_t; + +/** + * \brief Enum listing all IA/CEA 861-D video formats + */ +typedef enum +{ + TMDL_HDMITX_VFMT_NULL = 0, /**< Not a valid format... */ + TMDL_HDMITX_VFMT_NO_CHANGE = 0, /**< ...or no change required */ + TMDL_HDMITX_VFMT_MIN = 1, /**< Lowest valid format */ + TMDL_HDMITX_VFMT_TV_MIN = 1, /**< Lowest valid TV format */ + TMDL_HDMITX_VFMT_01_640x480p_60Hz = 1, /**< Format 01 640 x 480p 60Hz */ + TMDL_HDMITX_VFMT_02_720x480p_60Hz = 2, /**< Format 02 720 x 480p 60Hz */ + TMDL_HDMITX_VFMT_03_720x480p_60Hz = 3, /**< Format 03 720 x 480p 60Hz */ + TMDL_HDMITX_VFMT_04_1280x720p_60Hz = 4, /**< Format 04 1280 x 720p 60Hz */ + TMDL_HDMITX_VFMT_05_1920x1080i_60Hz = 5, /**< Format 05 1920 x 1080i 60Hz */ + TMDL_HDMITX_VFMT_06_720x480i_60Hz = 6, /**< Format 06 720 x 480i 60Hz */ + TMDL_HDMITX_VFMT_07_720x480i_60Hz = 7, /**< Format 07 720 x 480i 60Hz */ + TMDL_HDMITX_VFMT_08_720x240p_60Hz = 8, /**< Format 08 720 x 240p 60Hz */ + TMDL_HDMITX_VFMT_09_720x240p_60Hz = 9, /**< Format 09 720 x 240p 60Hz */ + TMDL_HDMITX_VFMT_10_720x480i_60Hz = 10, /**< Format 10 720 x 480i 60Hz */ + TMDL_HDMITX_VFMT_11_720x480i_60Hz = 11, /**< Format 11 720 x 480i 60Hz */ + TMDL_HDMITX_VFMT_12_720x240p_60Hz = 12, /**< Format 12 720 x 240p 60Hz */ + TMDL_HDMITX_VFMT_13_720x240p_60Hz = 13, /**< Format 13 720 x 240p 60Hz */ + TMDL_HDMITX_VFMT_14_1440x480p_60Hz = 14, /**< Format 14 1440 x 480p 60Hz */ + TMDL_HDMITX_VFMT_15_1440x480p_60Hz = 15, /**< Format 15 1440 x 480p 60Hz */ + TMDL_HDMITX_VFMT_16_1920x1080p_60Hz = 16, /**< Format 16 1920 x 1080p 60Hz */ + TMDL_HDMITX_VFMT_17_720x576p_50Hz = 17, /**< Format 17 720 x 576p 50Hz */ + TMDL_HDMITX_VFMT_18_720x576p_50Hz = 18, /**< Format 18 720 x 576p 50Hz */ + TMDL_HDMITX_VFMT_19_1280x720p_50Hz = 19, /**< Format 19 1280 x 720p 50Hz */ + TMDL_HDMITX_VFMT_20_1920x1080i_50Hz = 20, /**< Format 20 1920 x 1080i 50Hz */ + TMDL_HDMITX_VFMT_21_720x576i_50Hz = 21, /**< Format 21 720 x 576i 50Hz */ + TMDL_HDMITX_VFMT_22_720x576i_50Hz = 22, /**< Format 22 720 x 576i 50Hz */ + TMDL_HDMITX_VFMT_23_720x288p_50Hz = 23, /**< Format 23 720 x 288p 50Hz */ + TMDL_HDMITX_VFMT_24_720x288p_50Hz = 24, /**< Format 24 720 x 288p 50Hz */ + TMDL_HDMITX_VFMT_25_720x576i_50Hz = 25, /**< Format 25 720 x 576i 50Hz */ + TMDL_HDMITX_VFMT_26_720x576i_50Hz = 26, /**< Format 26 720 x 576i 50Hz */ + TMDL_HDMITX_VFMT_27_720x288p_50Hz = 27, /**< Format 27 720 x 288p 50Hz */ + TMDL_HDMITX_VFMT_28_720x288p_50Hz = 28, /**< Format 28 720 x 288p 50Hz */ + TMDL_HDMITX_VFMT_29_1440x576p_50Hz = 29, /**< Format 29 1440 x 576p 50Hz */ + TMDL_HDMITX_VFMT_30_1440x576p_50Hz = 30, /**< Format 30 1440 x 576p 50Hz */ + TMDL_HDMITX_VFMT_31_1920x1080p_50Hz = 31, /**< Format 31 1920 x 1080p 50Hz */ + TMDL_HDMITX_VFMT_32_1920x1080p_24Hz = 32, /**< Format 32 1920 x 1080p 24Hz */ + TMDL_HDMITX_VFMT_33_1920x1080p_25Hz = 33, /**< Format 33 1920 x 1080p 25Hz */ + TMDL_HDMITX_VFMT_34_1920x1080p_30Hz = 34, /**< Format 34 1920 x 1080p 30Hz */ + TMDL_HDMITX_VFMT_35_2880x480p_60Hz = 35, /**< Format 35 2880 x 480p 60Hz 4:3 */ + TMDL_HDMITX_VFMT_36_2880x480p_60Hz = 36, /**< Format 36 2880 x 480p 60Hz 16:9 */ + TMDL_HDMITX_VFMT_37_2880x576p_50Hz = 37, /**< Format 37 2880 x 576p 50Hz 4:3 */ + TMDL_HDMITX_VFMT_38_2880x576p_50Hz = 38, /**< Format 38 2880 x 576p 50Hz 16:9 */ + + TMDL_HDMITX_VFMT_INDEX_60_1280x720p_24Hz = 39,/**< Index of HDMITX_VFMT_60_1280x720p_24Hz */ + TMDL_HDMITX_VFMT_60_1280x720p_24Hz = 60, /**< Format 60 1280 x 720p 23.97/24Hz 16:9 */ + TMDL_HDMITX_VFMT_61_1280x720p_25Hz = 61, /**< Format 61 1280 x 720p 25Hz 16:9 */ + TMDL_HDMITX_VFMT_62_1280x720p_30Hz = 62, /**< Format 60 1280 x 720p 29.97/30Hz 16:9 */ + + TMDL_HDMITX_VFMT_TV_MAX = 62, /**< Highest valid TV format */ + TMDL_HDMITX_VFMT_TV_NO_REG_MIN = 32, /**< Lowest TV format without prefetched table */ + TMDL_HDMITX_VFMT_TV_NUM = 42, /**< Number of TV formats & null */ + + TMDL_HDMITX_VFMT_PC_MIN = 128, /**< Lowest valid PC format */ + TMDL_HDMITX_VFMT_PC_640x480p_60Hz = 128, /**< PC format 128 */ + TMDL_HDMITX_VFMT_PC_800x600p_60Hz = 129, /**< PC format 129 */ + TMDL_HDMITX_VFMT_PC_1152x960p_60Hz = 130, /**< PC format 130 */ + TMDL_HDMITX_VFMT_PC_1024x768p_60Hz = 131, /**< PC format 131 */ + TMDL_HDMITX_VFMT_PC_1280x768p_60Hz = 132, /**< PC format 132 */ + TMDL_HDMITX_VFMT_PC_1280x1024p_60Hz = 133, /**< PC format 133 */ + TMDL_HDMITX_VFMT_PC_1360x768p_60Hz = 134, /**< PC format 134 */ + TMDL_HDMITX_VFMT_PC_1400x1050p_60Hz = 135, /**< PC format 135 */ + TMDL_HDMITX_VFMT_PC_1600x1200p_60Hz = 136, /**< PC format 136 */ + TMDL_HDMITX_VFMT_PC_1024x768p_70Hz = 137, /**< PC format 137 */ + TMDL_HDMITX_VFMT_PC_640x480p_72Hz = 138, /**< PC format 138 */ + TMDL_HDMITX_VFMT_PC_800x600p_72Hz = 139, /**< PC format 139 */ + TMDL_HDMITX_VFMT_PC_640x480p_75Hz = 140, /**< PC format 140 */ + TMDL_HDMITX_VFMT_PC_1024x768p_75Hz = 141, /**< PC format 141 */ + TMDL_HDMITX_VFMT_PC_800x600p_75Hz = 142, /**< PC format 142 */ + TMDL_HDMITX_VFMT_PC_1024x864p_75Hz = 143, /**< PC format 143 */ + TMDL_HDMITX_VFMT_PC_1280x1024p_75Hz = 144, /**< PC format 144 */ + TMDL_HDMITX_VFMT_PC_640x350p_85Hz = 145, /**< PC format 145 */ + TMDL_HDMITX_VFMT_PC_640x400p_85Hz = 146, /**< PC format 146 */ + TMDL_HDMITX_VFMT_PC_720x400p_85Hz = 147, /**< PC format 147 */ + TMDL_HDMITX_VFMT_PC_640x480p_85Hz = 148, /**< PC format 148 */ + TMDL_HDMITX_VFMT_PC_800x600p_85Hz = 149, /**< PC format 149 */ + TMDL_HDMITX_VFMT_PC_1024x768p_85Hz = 150, /**< PC format 150 */ + TMDL_HDMITX_VFMT_PC_1152x864p_85Hz = 151, /**< PC format 151 */ + TMDL_HDMITX_VFMT_PC_1280x960p_85Hz = 152, /**< PC format 152 */ + TMDL_HDMITX_VFMT_PC_1280x1024p_85Hz = 153, /**< PC format 153 */ + TMDL_HDMITX_VFMT_PC_1024x768i_87Hz = 154, /**< PC format 154 */ + TMDL_HDMITX_VFMT_PC_MAX = 154, /**< Highest valid PC format */ + TMDL_HDMITX_VFMT_PC_NUM = (TMDL_HDMITX_VFMT_PC_MAX-TMDL_HDMITX_VFMT_PC_MIN+1) /**< Number of PC formats */ +} tmdlHdmiTxVidFmt_t; + +/** + * \brief Structure defining the EDID short video descriptor + */ +typedef struct +{ + tmdlHdmiTxVidFmt_t videoFormat; /**< Video format as defined by EIA/CEA 861-D */ + Bool nativeVideoFormat; /**< True if format is the preferred video format */ +} tmdlHdmiTxShortVidDesc_t; + +/** + * \brief Enum listing all picture aspect ratio (H:V) (4:3, 16:9) + */ +typedef enum +{ + TMDL_HDMITX_P_ASPECT_RATIO_UNDEFINED = 0, /**< Undefined picture aspect ratio */ + TMDL_HDMITX_P_ASPECT_RATIO_6_5 = 1, /**< 6:5 picture aspect ratio (PAR) */ + TMDL_HDMITX_P_ASPECT_RATIO_5_4 = 2, /**< 5:4 PAR */ + TMDL_HDMITX_P_ASPECT_RATIO_4_3 = 3, /**< 4:3 PAR */ + TMDL_HDMITX_P_ASPECT_RATIO_16_10 = 4, /**< 16:10 PAR */ + TMDL_HDMITX_P_ASPECT_RATIO_5_3 = 5, /**< 5:3 PAR */ + TMDL_HDMITX_P_ASPECT_RATIO_16_9 = 6, /**< 16:9 PAR */ + TMDL_HDMITX_P_ASPECT_RATIO_9_5 = 7 /**< 9:5 PAR */ +} tmdlHdmiTxPictAspectRatio_t; + +/** + * \brief Enum listing all vertical frequency + */ +typedef enum +{ + TMDL_HDMITX_VFREQ_24Hz = 0, /**< 24Hz */ + TMDL_HDMITX_VFREQ_25Hz = 1, /**< 25Hz */ + TMDL_HDMITX_VFREQ_30Hz = 2, /**< 30Hz */ + TMDL_HDMITX_VFREQ_50Hz = 3, /**< 50Hz */ + TMDL_HDMITX_VFREQ_59Hz = 4, /**< 59.94Hz */ + TMDL_HDMITX_VFREQ_60Hz = 5, /**< 60Hz */ +#ifndef FORMAT_PC + TMDL_HDMITX_VFREQ_INVALID = 6, /**< Invalid */ + TMDL_HDMITX_VFREQ_NUM = 6 /**< No. of values */ +#else /* FORMAT_PC */ + TMDL_HDMITX_VFREQ_70Hz = 6, /**< 70Hz */ + TMDL_HDMITX_VFREQ_72Hz = 7, /**< 72Hz */ + TMDL_HDMITX_VFREQ_75Hz = 8, /**< 75Hz */ + TMDL_HDMITX_VFREQ_85Hz = 9, /**< 85Hz */ + TMDL_HDMITX_VFREQ_87Hz = 10, /**< 87Hz */ + TMDL_HDMITX_VFREQ_INVALID = 11, /**< Invalid */ + TMDL_HDMITX_VFREQ_NUM = 11 /**< No. of values */ +#endif /* FORMAT_PC */ +} tmdlHdmiTxVfreq_t; + +/** + * \brief Structure storing specifications of a video resolution + */ +typedef struct +{ + UInt16 width; /**< Width of the frame in pixels */ + UInt16 height; /**< Height of the frame in pixels */ + Bool interlaced; /**< Interlaced mode (True/False) */ + tmdlHdmiTxVfreq_t vfrequency; /**< Vertical frequency in Hz */ + tmdlHdmiTxPictAspectRatio_t aspectRatio; /**< Picture aspect ratio (H:V) */ +} tmdlHdmiTxVidFmtSpecs_t; + +/** + * \brief Enum listing all video input modes (CCIR, RGB, etc.) + */ +typedef enum +{ + TMDL_HDMITX_VINMODE_CCIR656 = 0, /**< CCIR656 */ + TMDL_HDMITX_VINMODE_RGB444, /**< RGB444 */ + TMDL_HDMITX_VINMODE_YUV444, /**< YUV444 */ + TMDL_HDMITX_VINMODE_YUV422, /**< YUV422 */ +#ifdef TMFL_RGB_DDR_12BITS + TMDL_HDMITX_VINMODE_RGB_DDR_12BITS, /**< RGB24 bits on a 12 bits bus using double data rate clocking */ +#endif + TMDL_HDMITX_VINMODE_NO_CHANGE , /**< No change */ + TMDL_HDMITX_VINMODE_INVALID /**< Invalid */ +} tmdlHdmiTxVinMode_t; + +/** + * \brief Enum listing all possible sync sources + */ +typedef enum +{ + TMDL_HDMITX_SYNCSRC_EMBEDDED = 0, /**< Embedded sync */ + TMDL_HDMITX_SYNCSRC_EXT_VREF = 1, /**< External sync Vref, Href, Fref */ + TMDL_HDMITX_SYNCSRC_EXT_VS = 2 /**< External sync Vs, Hs */ +} tmdlHdmiTxSyncSource_t; + +/** + * \brief Enum listing all output pixel rate (Single, Double, etc.) + */ +typedef enum +{ + TMDL_HDMITX_PIXRATE_DOUBLE = 0, /**< Double pixel rate */ + TMDL_HDMITX_PIXRATE_SINGLE = 1, /**< Single pixel rate */ + TMDL_HDMITX_PIXRATE_SINGLE_REPEATED = 2 /**< Single pixel repeated */ +} tmdlHdmiTxPixRate_t; + +/** + * \brief Enum listing the supported transmission formats of 3D video data + */ +typedef enum +{ + TMDL_HDMITX_3D_NONE = 0, /**< 3D video data not present */ + TMDL_HDMITX_3D_FRAME_PACKING = 1, /**< 3D video data Frame Packing structure */ + TMDL_HDMITX_3D_TOP_AND_BOTTOM = 2, /**< 3D video data Top and Bottom structure */ + TMDL_HDMITX_3D_SIDE_BY_SIDE_HALF = 3, /**< 3D video data Side by Side Half structure */ + TMDL_HDMITX_3D_INVALID = 4 /**< Invalid */ +} tmdlHdmiTx3DStructure_t; + +/** + * \brief Structure defining the video input configuration + */ +typedef struct +{ + tmdlHdmiTxVidFmt_t format; /**< Video format as defined by EIA/CEA 861-D */ + tmdlHdmiTxVinMode_t mode; /**< Video mode (CCIR, RGB, YUV, etc.) */ + tmdlHdmiTxSyncSource_t syncSource; /**< Sync source type */ + tmdlHdmiTxPixRate_t pixelRate; /**< Pixel rate */ + tmdlHdmiTx3DStructure_t structure3D; /**< 3D structure as defined in HDMI1.4a */ +} tmdlHdmiTxVideoInConfig_t; + +/** + * \brief Enum listing all video output modes (YUV, RGB, etc.) + */ +typedef enum +{ + TMDL_HDMITX_VOUTMODE_RGB444 = 0, /**< RGB444 */ + TMDL_HDMITX_VOUTMODE_YUV422 = 1, /**< YUV422 */ + TMDL_HDMITX_VOUTMODE_YUV444 = 2 /**< YUV444 */ +} tmdlHdmiTxVoutMode_t; + +/** + * \brief Enum defining possible quantization range + */ +typedef enum +{ + TMDL_HDMITX_VQR_DEFAULT = 0, /* Follow HDMI spec. */ + TMDL_HDMITX_RGB_FULL = 1, /* Force RGB FULL , DVI only */ + TMDL_HDMITX_RGB_LIMITED = 2 /* Force RGB LIMITED , DVI only */ +} tmdlHdmiTxVQR_t; + + +/** + * \brief Enum defining possible YCC Quantization Range + */ +typedef enum +{ + TMDL_HDMITX_YQR_LIMITED = 0, /* LIMITED range */ + TMDL_HDMITX_YQR_FULL = 1, /* FULL range */ + TMDL_HDMITX_YQR_INVALID = 2 /* Invalid range */ +} tmdlHdmiTxYCCQR_t; + + +/** + * \brief Structure defining the video output configuration + */ +typedef struct +{ + tmdlHdmiTxVidFmt_t format; /**< Video format as defined by EIA/CEA 861-D */ + tmdlHdmiTxVoutMode_t mode; /**< Video mode (CCIR, RGB, YUV, etc.) */ + tmdlHdmiTxColorDepth_t colorDepth; /**< Color depth */ + tmdlHdmiTxVQR_t dviVqr; /**< VQR applied in DVI mode */ +} tmdlHdmiTxVideoOutConfig_t; + + +typedef enum +{ + TMDL_HDMITX_AUDIO_DATA_PCM = 0, /**< Main data field represents linear PCM samples. */ + TMDL_HDMITX_AUDIO_DATA_OTHER = 1, /**< Main data field used for purposes other purposes. */ + TMDL_HDMITX_AUDIO_DATA_INVALID = 2 /**< Invalid value */ +} tmdlHdmiTxAudioData_t; + + +typedef enum +{ + TMDL_HDMITX_CSCOPYRIGHT_PROTECTED = 0, /**< Copyright protected */ + TMDL_HDMITX_CSCOPYRIGHT_UNPROTECTED = 1, /**< Not copyright protected */ + TMDL_HDMITX_CSCOPYRIGHT_INVALID = 2 /**< Invalid value */ +} tmdlHdmiTxCScopyright_t; + +typedef enum +{ + TMDL_HDMITX_CSFI_PCM_2CHAN_NO_PRE = 0, /**< PCM 2 channels without pre-emphasis or NON Linear PCM */ + TMDL_HDMITX_CSFI_PCM_2CHAN_PRE = 1, /**< PCM 2 channels with 50us/15us pre-emphasis */ + TMDL_HDMITX_CSFI_PCM_2CHAN_PRE_RSVD1 = 2, /**< PCM Reserved for 2 channels with pre-emphasis */ + TMDL_HDMITX_CSFI_PCM_2CHAN_PRE_RSVD2 = 3, /**< PCM Reserved for 2 channels with pre-emphasis */ + TMDL_HDMITX_CSFI_INVALID = 4 /**< Invalid value */ +} tmdlHdmiTxCSformatInfo_t; + + +typedef enum +{ + TMDL_HDMITX_CSCLK_LEVEL_II = 0, /**< Level II */ + TMDL_HDMITX_CSCLK_LEVEL_I = 1, /**< Level I */ + TMDL_HDMITX_CSCLK_LEVEL_III = 2, /**< Level III */ + TMDL_HDMITX_CSCLK_NOT_MATCHED = 3, /**< Not matched to sample freq. */ + TMDL_HDMITX_CSCLK_INVALID = 4 /**< Invalid */ +} tmdlHdmiTxCSclkAcc_t; + + +typedef enum +{ + TMDL_HDMITX_CSMAX_LENGTH_20 = 0, /**< Max word length is 20 bits */ + TMDL_HDMITX_CSMAX_LENGTH_24 = 1, /**< Max word length is 24 bits */ + TMDL_HDMITX_CSMAX_INVALID = 2 /**< Invalid value */ +} tmdlHdmiTxCSmaxWordLength_t; + + + +typedef enum +{ + TMDL_HDMITX_CSWORD_DEFAULT = 0, /**< Word length is not indicated */ + TMDL_HDMITX_CSWORD_20_OF_24 = 1, /**< Sample length is 20 bits out of max 24 possible */ + TMDL_HDMITX_CSWORD_16_OF_20 = 1, /**< Sample length is 16 bits out of max 20 possible */ + TMDL_HDMITX_CSWORD_22_OF_24 = 2, /**< Sample length is 22 bits out of max 24 possible */ + TMDL_HDMITX_CSWORD_18_OF_20 = 2, /**< Sample length is 18 bits out of max 20 possible */ + TMDL_HDMITX_CSWORD_RESVD = 3, /**< Reserved - shall not be used */ + TMDL_HDMITX_CSWORD_23_OF_24 = 4, /**< Sample length is 23 bits out of max 24 possible */ + TMDL_HDMITX_CSWORD_19_OF_20 = 4, /**< Sample length is 19 bits out of max 20 possible */ + TMDL_HDMITX_CSWORD_24_OF_24 = 5, /**< Sample length is 24 bits out of max 24 possible */ + TMDL_HDMITX_CSWORD_20_OF_20 = 5, /**< Sample length is 20 bits out of max 20 possible */ + TMDL_HDMITX_CSWORD_21_OF_24 = 6, /**< Sample length is 21 bits out of max 24 possible */ + TMDL_HDMITX_CSWORD_17_OF_20 = 6, /**< Sample length is 17 bits out of max 20 possible */ + TMDL_HDMITX_CSWORD_INVALID = 7 /**< Invalid */ +} tmdlHdmiTxCSwordLength_t; + + +typedef enum +{ + TMDL_HDMITX_CSOFREQ_NOT_INDICATED = 0, /**< Not Indicated */ + TMDL_HDMITX_CSOFREQ_192k = 1, /**< 192kHz */ + TMDL_HDMITX_CSOFREQ_12k = 2, /**< 12kHz */ + TMDL_HDMITX_CSOFREQ_176_4k = 3, /**< 176.4kHz */ + TMDL_HDMITX_CSOFREQ_RSVD1 = 4, /**< Reserved */ + TMDL_HDMITX_CSOFREQ_96k = 5, /**< 96kHz */ + TMDL_HDMITX_CSOFREQ_8k = 6, /**< 8kHz */ + TMDL_HDMITX_CSOFREQ_88_2k = 7, /**< 88.2kHz */ + TMDL_HDMITX_CSOFREQ_16k = 8, /**< 16kHz */ + TMDL_HDMITX_CSOFREQ_24k = 9, /**< 24kHz */ + TMDL_HDMITX_CSOFREQ_11_025k = 10, /**< 11.025kHz */ + TMDL_HDMITX_CSOFREQ_22_05k = 11, /**< 22.05kHz */ + TMDL_HDMITX_CSOFREQ_32k = 12, /**< 32kHz */ + TMDL_HDMITX_CSOFREQ_48k = 13, /**< 48kHz */ + TMDL_HDMITX_CSOFREQ_RSVD2 = 14, /**< Reserved */ + TMDL_HDMITX_CSOFREQ_44_1k = 15, /**< 44.1kHz */ + TMDL_HDMITX_CSAFS_INVALID = 16 /**< Invalid value */ +} tmdlHdmiTxCSorigAfs_t; + + + +typedef struct +{ + tmdlHdmiTxAudioData_t PcmIdentification; + tmdlHdmiTxCScopyright_t CopyrightInfo; + tmdlHdmiTxCSformatInfo_t FormatInfo; + UInt8 categoryCode; + tmdlHdmiTxCSclkAcc_t clockAccuracy; + tmdlHdmiTxCSmaxWordLength_t maxWordLength; + tmdlHdmiTxCSwordLength_t wordLength; + tmdlHdmiTxCSorigAfs_t origSampleFreq; +} tmdlHdmiTxAudioInChannelStatus; + + +/** + * \brief Structure defining the audio input configuration + */ +typedef struct +{ + tmdlHdmiTxAudioFormat_t format; /**< Audio format (I2S, SPDIF, etc.) */ + tmdlHdmiTxAudioRate_t rate; /**< Audio sampling rate */ + tmdlHdmiTxAudioI2SFormat_t i2sFormat; /**< I2S format of the audio input */ + tmdlHdmiTxAudioI2SQualifier_t i2sQualifier; /**< I2S qualifier of the audio input (8,16,32 bits) */ + tmdlHdmiTxDstRate_t dstRate; /**< DST data transfer rate */ + UInt8 channelAllocation; /**< Ref to CEA-861D p85 */ + tmdlHdmiTxAudioInChannelStatus channelStatus; /**< Ref to IEC 60958-3 */ +} tmdlHdmiTxAudioInConfig_t; + +/** + * \brief Enum listing all the type of sunk + */ +typedef enum +{ + TMDL_HDMITX_SINK_DVI = 0, /**< DVI */ + TMDL_HDMITX_SINK_HDMI = 1, /**< HDMI */ + TMDL_HDMITX_SINK_EDID = 2 /**< As currently defined in EDID */ +} tmdlHdmiTxSinkType_t; + +/** + * \brief Structure defining the content of a gamut packet + */ +typedef struct +{ + Bool nextField; /**< Gamut relevant for field following packet insertion */ + UInt8 GBD_Profile; /**< Profile of the gamut packet : 0 = P0, 1 = P1 */ + UInt8 affectedGamutSeqNum; /**< Gamut sequence number of the field that have to be affected by this gamut packet */ + Bool noCurrentGBD; /**< Current field not using specific gamut */ + UInt8 currentGamutSeqNum; /**< Gamut sequence number of the current field */ + UInt8 packetSequence; /**< Sequence of the packet inside a multiple packet gamut */ + UInt8 payload[28]; /**< Payload of the gamut packet */ +} tmdlHdmiTxGamutData_t; + +/** + * \brief Type defining the content of a generic packet + */ +typedef UInt8 tmdlHdmiTxGenericPacket[28]; + +/** + * \brief Structure defining the content of an ACP packet + */ +typedef struct +{ + UInt8 acpType; + UInt8 acpData[28]; +} tmdlHdmiTxAcpPktData_t; + +/** + * \brief Structure defining the content of an AVI infoframe + */ +typedef struct +{ + UInt8 colorIndicator; /**< RGB or YCbCr indicator. See CEA-861-B table 8 for details */ + UInt8 activeInfoPresent; /**< Active information present. Indicates if activeFormatAspectRatio field is valid */ + UInt8 barInformationDataValid; /**< Bar information data valid */ + UInt8 scanInformation; /**< Scan information. See CEA-861-B table 8 for details */ + UInt8 colorimetry; /**< Colorimetry. See CEA-861-B table 9 for details */ + UInt8 pictureAspectRatio; /**< Picture aspect ratio. See CEA-861-B table 9 for details */ + UInt8 activeFormatAspectRatio; /**< Active Format aspect ratio. See CEA-861-B table 10 and Annex H for details */ + UInt8 nonUniformPictureScaling; /**< Non-uniform picture scaling. See CEA-861-B table 11 for details */ + UInt8 videoFormatIdentificationCode; /**< Video format indentification code. See CEA-861-B section 6.3 for details */ + UInt8 pixelRepetitionFactor; /**< Pixel repetition factor. See CEA-861-B table 11 for details */ + UInt16 lineNumberEndTopBar; + UInt16 lineNumberStartBottomBar; + UInt16 lineNumberEndLeftBar; + UInt16 lineNumberStartRightBar; +} tmdlHdmiTxAviIfData_t; + +/** + * \brief Structure defining the content of an ACP packet + */ +typedef struct +{ + Bool avMute; +} tmdlHdmiTxGcpPktData_t; + +/** + * \brief Structure defining the content of an AUD infoframe + */ +typedef struct +{ + UInt8 codingType; /**< Coding type (always set to zero) */ + UInt8 channelCount; /**< Channel count. See CEA-861-B table 17 for details */ + UInt8 samplefrequency; /**< Sample frequency. See CEA-861-B table 18 for details */ + UInt8 sampleSize; /**< Sample frequency. See CEA-861-B table 18 for details */ + UInt8 channelAllocation; /**< Channel allocation. See CEA-861-B section 6.3.2 for details */ + Bool downmixInhibit; /**< Downmix inhibit. See CEA-861-B section 6.3.2 for details */ + UInt8 levelShiftValue; /**< level shift value for downmixing. See CEA-861-B section 6.3.2 and table 23 for details */ +} tmdlHdmiTxAudIfData_t; + +/** + * \brief Structure defining the content of an ISRC1 packet + */ +typedef struct +{ + Bool isrcCont; /**< ISRC packet continued in next packet */ + Bool isrcValid; /**< Set to one when ISRCStatus and UPC_EAN_ISRC_xx are valid */ + UInt8 isrcStatus; /**< ISRC status */ + UInt8 UPC_EAN_ISRC[16]; /**< ISRC packet data */ +} tmdlHdmiTxIsrc1PktData_t; + +/** + * \brief Structure defining the content of an ISRC2 packet + */ +typedef struct +{ + UInt8 UPC_EAN_ISRC[16]; /**< ISRC packet data */ +} tmdlHdmiTxIsrc2PktData_t; + +/** + * \brief Structure defining the content of an MPS infoframe + */ +typedef struct +{ + UInt32 bitRate; /**< MPEG bit rate in Hz */ + UInt32 frameType; /**< MPEG frame type */ + Bool fieldRepeat; /**< 0: new field, 1:repeated field */ +} tmdlHdmiTxMpsIfData_t; + +/** + * \brief Structure defining the content of an SPD infoframe + */ +typedef struct +{ + UInt8 vendorName[8]; /**< Vendor name */ + UInt8 productDesc[16]; /**< Product Description */ + UInt32 sourceDevInfo; /**< Source Device Info */ +} tmdlHdmiTxSpdIfData_t; + + +/** + * \brief Structure defining the content of a VS infoframe packet according to HDMI 1.4a standard + */ + +/* HDMI version */ +#define TMDL_HDMITX_VERSION 0x01 + +/* HDMI video format [3bits] */ +#define TMDL_HDMITX_VIDEO_FORMAT_SHIFT 5 +#define TMDL_HDMITX_FORMAT_EXTENDED (0x01 << TMDL_HDMITX_VIDEO_FORMAT_SHIFT) +#define TMDL_HDMITX_3D (0x02 << TMDL_HDMITX_VIDEO_FORMAT_SHIFT) + +/* IEEE registration identifier (0x000C03) with least significant byte first */ +#define TMDL_HDMITX_HDMI_IEEE_BYTE0 0x03 +#define TMDL_HDMITX_HDMI_IEEE_BYTE1 0x0C +#define TMDL_HDMITX_HDMI_IEEE_BYTE2 0x00 + +/* 3D structure [4bits] */ +#define TMDL_HDMITX_3D_STRUCTURE_SHIFT 4 +#define TMDL_HDMITX_FRAME_PACKING (0x00 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_FIELD_ALTERNATIVE (0x01 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_LINE_ALTERNATIVE (0x02 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_SIDE_BY_SIDE_FULL (0x03 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_L_DEPTH (0x04 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_L_DEPTH_GFX (0x05 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_TOP_AND_BOTTOM (0x06 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) +#define TMDL_HDMITX_SIDE_BY_SIDE_HALF (0x08 << TMDL_HDMITX_3D_STRUCTURE_SHIFT) + +/* 3D EXT Data [4bits] */ +#define TMDL_HDMITX_3D_EXT_DATA_SHIFT 4 +#define TMDL_HDMITX_HORIZONTAL_SUB (0x00 << TMDL_HDMITX_3D_EXT_DATA_SHIFT) /* Horizontal sub-sampling */ +#define TMDL_HDMITX_QUINCUNX_OLOR (0x04 << TMDL_HDMITX_3D_EXT_DATA_SHIFT) /* Odd/Left picture, Odd/Right picture */ +#define TMDL_HDMITX_QUINCUNX_OLER (0x05 << TMDL_HDMITX_3D_EXT_DATA_SHIFT) /* Odd/Left picture, Even/Right picture */ +#define TMDL_HDMITX_QUINCUNX_ELOR (0x06 << TMDL_HDMITX_3D_EXT_DATA_SHIFT) /* Even/Left picture, Odd/Right picture */ +#define TMDL_HDMITX_QUINCUNX_ELER (0x07 << TMDL_HDMITX_3D_EXT_DATA_SHIFT) /* Even/Left picture, Even/Right picture */ + +/* 3D Meta field */ +#define TMDL_HDMITX_3D_META_TYPE_SHIFT 5 +#define TMDL_HDMITX_3D_META_PRESENT (0x01 << 3) +#define TMDL_HDMITX_3D_META_PARALLAX (0x00 << TMDL_HDMITX_3D_META_TYPE_SHIFT) + +#define TMDL_HDMITX_VS_PKT_DATA_LEN 27 +typedef struct +{ + UInt8 version; + /* + Packet Byte # 7 6 5 4 3 2 1 0 + + PB1 24bit IEEE Registration Identifier (0x000C03) + PB2 ( least significant byte first ) + PB3 + PB4 (HDMI_Video_Format ) (0) (0) (0) (0) (0) + PB5 (3D_Structure ) +Meta (0) (0) (0) + PB6 (3D_Ext_Data ) (0) (0) (0) (0) + PB7 (3D_Metadata_type ) (3D_Metadata_Length (= N)) + PB8 (3D_Metadata_1 ) + ... ... + PB [7+N] (3D_Metadata_N ) + PB[8+N]~[Nv] (Reserved (0) ) + */ + UInt8 vsData[TMDL_HDMITX_VS_PKT_DATA_LEN]; + +} tmdlHdmiTxVsPktData_t; + +/** + * \brief Structure defining the additional Edid VSDB data according to HDMI 1.4a standard + */ +typedef struct +{ + UInt8 maxTmdsClock; /* maximum supported TMDS clock */ + UInt8 cnc0; /* content type Graphics (text) */ + UInt8 cnc1; /* content type Photo */ + UInt8 cnc2; /* content type Cinema */ + UInt8 cnc3; /* content type Game */ + UInt8 hdmiVideoPresent; /* additional video format */ + UInt8 h3DPresent; /* 3D support by the HDMI Sink */ + UInt8 h3DMultiPresent; /* 3D multi strctures present */ + UInt8 imageSize; /* additional info for the values in the image size area */ + UInt8 hdmi3DLen; /* total length of 3D video formats */ + UInt8 hdmiVicLen; /* total length of extended video formats */ + UInt8 ext3DData[21]; /* max_len-10, ie: 31-10=21 */ +} tmdlHdmiTxEdidExtraVsdbData_t; + +/** + * \brief Structure defining the Edid audio descriptor + */ +typedef struct +{ + UInt8 format; /* EIA/CEA861 mode */ + UInt8 channels; /* number of channels */ + UInt8 supportedFreqs; /* bitmask of supported frequencies */ + UInt8 supportedRes; /* bitmask of supported resolutions (LPCM only) */ + UInt8 maxBitrate; /* Maximum bitrate divided by 8KHz (compressed formats only) */ +} tmdlHdmiTxEdidAudioDesc_t; + +/** + * \brief Structure defining detailed timings of a video format + */ +typedef struct +{ + UInt16 pixelClock; /**< Pixel Clock/10 000 */ + UInt16 hActivePixels; /**< Horizontal Active Pixels */ + UInt16 hBlankPixels; /**< Horizontal Blanking Pixels */ + UInt16 vActiveLines; /**< Vertical Active Lines */ + UInt16 vBlankLines; /**< Vertical Blanking Lines */ + UInt16 hSyncOffset; /**< Horizontal Sync Offset */ + UInt16 hSyncWidth; /**< Horiz. Sync Pulse Width */ + UInt16 vSyncOffset; /**< Vertical Sync Offset */ + UInt16 vSyncWidth; /**< Vertical Sync Pulse Width */ + UInt16 hImageSize; /**< Horizontal Image Size */ + UInt16 vImageSize; /**< Vertical Image Size */ + UInt16 hBorderPixels; /**< Horizontal Border */ + UInt16 vBorderPixels; /**< Vertical Border */ + UInt8 flags; /**< Interlace/sync info */ +} tmdlHdmiTxEdidVideoTimings_t; + +/** size descriptor block of monitor descriptor */ +#define EDID_MONITOR_DESCRIPTOR_SIZE 13 + +/** + * \brief Structure defining the first monitor descriptor + */ +typedef struct +{ + Bool descRecord; /**< True when parameters of struct are available */ + UInt8 monitorName[EDID_MONITOR_DESCRIPTOR_SIZE]; /**< Monitor Name */ +} tmdlHdmiTxEdidFirstMD_t; + +/** + * \brief Structure defining the second monitor descriptor + */ +typedef struct +{ + Bool descRecord; /**< True when parameters of struct are available */ + UInt8 minVerticalRate; /**< Min vertical rate in Hz */ + UInt8 maxVerticalRate; /**< Max vertical rate in Hz */ + UInt8 minHorizontalRate; /**< Min horizontal rate in Hz */ + UInt8 maxHorizontalRate; /**< Max horizontal rate in Hz */ + UInt8 maxSupportedPixelClk; /**< Max suuported pixel clock rate in MHz */ +} tmdlHdmiTxEdidSecondMD_t; + +/** + * \brief Structure defining the other monitor descriptor + */ +typedef struct +{ + Bool descRecord; /**< True when parameters of struct are available */ + UInt8 otherDescriptor[EDID_MONITOR_DESCRIPTOR_SIZE]; /**< Other monitor Descriptor */ +} tmdlHdmiTxEdidOtherMD_t; + +/** + * \brief Test pattern types + */ +typedef enum +{ + TMDL_HDMITX_PATTERN_OFF = 0, /**< Insert test pattern */ + TMDL_HDMITX_PATTERN_CBAR4 = 1, /**< Insert 4-bar colour bar */ + TMDL_HDMITX_PATTERN_CBAR8 = 2, /**< Insert 8-bar colour bar */ + TMDL_HDMITX_PATTERN_BLUE = 3, /**< Insert Blue screen */ + TMDL_HDMITX_PATTERN_BLACK = 4, /**< Insert Black screen */ + TMDL_HDMITX_PATTERN_INVALID = 5 /**< Invalid pattern */ +} tmdlHdmiTxTestPattern_t; + +/** + * \brief Enum listing all hdcp state + */ +typedef enum +{ + TMDL_HDMITX_HDCP_CHECK_NOT_STARTED = 0, /**< Check not started */ + TMDL_HDMITX_HDCP_CHECK_IN_PROGRESS = 1, /**< No failures, more to do */ + TMDL_HDMITX_HDCP_CHECK_PASS = 2, /**< Final check has passed */ + TMDL_HDMITX_HDCP_CHECK_FAIL_FIRST = 3, /**< First check failure code */ + TMDL_HDMITX_HDCP_CHECK_FAIL_DRIVER_STATE = 3, /**< Driver not AUTHENTICATED */ + TMDL_HDMITX_HDCP_CHECK_FAIL_DEVICE_T0 = 4, /**< A T0 interrupt occurred */ + TMDL_HDMITX_HDCP_CHECK_FAIL_DEVICE_RI = 5, /**< Device RI changed */ + TMDL_HDMITX_HDCP_CHECK_FAIL_DEVICE_FSM = 6, /**< Device FSM not 10h */ + TMDL_HDMITX_HDCP_CHECK_NUM = 7 /**< Number of check results */ +}tmdlHdmiTxHdcpCheck_t; + +/** + * \brief Enum listing all hdcp option flags + */ +typedef enum +{ + TMDL_HDMITX_HDCP_OPTION_FORCE_PJ_IGNORED = 0x01, /* Not set: obey PJ result */ + TMDL_HDMITX_HDCP_OPTION_FORCE_SLOW_DDC = 0x02, /* Not set: obey BCAPS setting */ + TMDL_HDMITX_HDCP_OPTION_FORCE_NO_1_1 = 0x04, /* Not set: obey BCAPS setting */ + TMDL_HDMITX_HDCP_OPTION_FORCE_REPEATER = 0x08, /* Not set: obey BCAPS setting */ + TMDL_HDMITX_HDCP_OPTION_FORCE_NO_REPEATER = 0x10, /* Not set: obey BCAPS setting */ + TMDL_HDMITX_HDCP_OPTION_FORCE_V_EQU_VBAR = 0x20, /* Not set: obey V=V' result */ + TMDL_HDMITX_HDCP_OPTION_FORCE_VSLOW_DDC = 0x40, /* Set: 50kHz DDC */ + TMDL_HDMITX_HDCP_OPTION_DEFAULT = 0x00, /* All the above Not Set vals */ + TMDL_HDMITX_HDCP_OPTION_MASK = 0x7F, /* Only these bits are allowed */ + TMDL_HDMITX_HDCP_OPTION_MASK_BAD = 0x80 /* These bits are not allowed */ +}tmdlHdmiTxHdcpOptions_t; + +#ifndef NO_HDCP +/** KSV list sizes */ +typedef enum +{ + TMDL_HDMITX_KSV_LIST_MAX_DEVICES = 128, + TMDL_HDMITX_KSV_BYTES_PER_DEVICE = 5 +} tmdlHdmiTxHdcpHandleSHA_1; + +/** + * \brief Structure defining information about hdcp + */ +typedef struct +{ + tmdlHdmiTxHdcpCheck_t hdcpCheckState; /* Hdcp check state */ + UInt8 hdcpErrorState; /* Error State when T0 occured */ + Bool bKsvSecure; /* BKSV is secured */ + UInt8 hdcpBksv[TMDL_HDMITX_KSV_BYTES_PER_DEVICE]; /* BKSV read from B sink */ + UInt8 hdcpKsvList[TMDL_HDMITX_KSV_BYTES_PER_DEVICE * + TMDL_HDMITX_KSV_LIST_MAX_DEVICES]; /* KSV list read from B sink during + SHA-1 interrupt */ + UInt8 hdcpKsvDevices; /* Number of devices read from + B sink during SHA-1 interrupt */ + UInt8 hdcpDeviceDepth; /* Connection tree depth */ + Bool hdcpMaxCascExceeded; + Bool hdcpMaxDevsExceeded; +} tmdlHdmiTxHdcpInfo_t; +#endif /* NO_HDCP */ + +/** + * \brief Enum defining possible HDCP + */ +typedef enum +{ + TMDL_HDMITX_HDCP_OK = 0, + TMDL_HDMITX_HDCP_BKSV_RCV_FAIL, /* Source does not receive Sink BKsv */ + TMDL_HDMITX_HDCP_BKSV_CHECK_FAIL, /* BKsv does not contain 20 zeros and 20 ones */ + TMDL_HDMITX_HDCP_BCAPS_RCV_FAIL, /* Source does not receive Sink Bcaps */ + TMDL_HDMITX_HDCP_AKSV_SEND_FAIL, /* Source does not send AKsv */ + TMDL_HDMITX_HDCP_R0_RCV_FAIL, /* Source does not receive R'0 */ + TMDL_HDMITX_HDCP_R0_CHECK_FAIL, /* R0 = R'0 check fail */ + TMDL_HDMITX_HDCP_BKSV_NOT_SECURE, + TMDL_HDMITX_HDCP_RI_RCV_FAIL, /* Source does not receive R'i */ + TMDL_HDMITX_HDCP_RPT_RI_RCV_FAIL, /* Source does not receive R'i repeater mode */ + TMDL_HDMITX_HDCP_RI_CHECK_FAIL, /* RI = R'I check fail */ + TMDL_HDMITX_HDCP_RPT_RI_CHECK_FAIL, /* RI = R'I check fail repeater mode */ + TMDL_HDMITX_HDCP_RPT_BCAPS_RCV_FAIL, /* Source does not receive Sink Bcaps repeater mode */ + TMDL_HDMITX_HDCP_RPT_BCAPS_READY_TIMEOUT, + TMDL_HDMITX_HDCP_RPT_V_RCV_FAIL, /* Source does not receive V'*/ + TMDL_HDMITX_HDCP_RPT_BSTATUS_RCV_FAIL, /* Source does not receive BSTATUS repeater mode */ + TMDL_HDMITX_HDCP_RPT_KSVLIST_RCV_FAIL, /* Source does not receive Ksv list in repeater mode */ + TMDL_HDMITX_HDCP_RPT_KSVLIST_NOT_SECURE, + TMDL_HDMITX_HDCP_UNKNOWN_STATUS + +}tmdlHdmiTxHdcpStatus_t; + + +/** + * \brief EDID information about sink latency + */ +typedef struct +{ + Bool latency_available; + Bool Ilatency_available; + UInt8 Edidvideo_latency; + UInt8 Edidaudio_latency; + UInt8 EdidIvideo_latency; + UInt8 EdidIaudio_latency; + +} tmdlHdmiTxEdidLatency_t; + + +/** + * \brief Enum defining possible HotPlug status + */ +typedef enum +{ + TMDL_HDMITX_HOTPLUG_INACTIVE = 0, /**< Hotplug inactive */ + TMDL_HDMITX_HOTPLUG_ACTIVE = 1, /**< Hotplug active */ + TMDL_HDMITX_HOTPLUG_INVALID = 2 /**< Invalid Hotplug */ +} tmdlHdmiTxHotPlug_t; + + +/** + * \brief Enum defining possible RxSense status + */ +typedef enum +{ + TMDL_HDMITX_RX_SENSE_INACTIVE = 0, /**< RxSense inactive */ + TMDL_HDMITX_RX_SENSE_ACTIVE = 1, /**< RxSense active */ + TMDL_HDMITX_RX_SENSE_INVALID = 2 /**< Invalid RxSense */ +} tmdlHdmiTxRxSense_t; + + +/** + * \brief Enum listing all the types of extented colorimetries + */ +typedef enum +{ + TMDL_HDMITX_EXT_COLORIMETRY_XVYCC601 = 0, + TMDL_HDMITX_EXT_COLORIMETRY_XVYCC709 = 1, + TMDL_HDMITX_EXT_COLORIMETRY_SYCC601 = 2, + TMDL_HDMITX_EXT_COLORIMETRY_ADOBEYCC601 = 3, + TMDL_HDMITX_EXT_COLORIMETRY_ADOBERGB = 4, + TMDL_HDMITX_EXT_COLORIMETRY_INVALID = 5 +} tmdlHdmiTxExtColorimetry_t; + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMITX_TYPES_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ + diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx.c b/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx.c new file mode 100755 index 0000000000000..7c556f5141597 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx.c @@ -0,0 +1,7166 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx.c + * + * \version Revision: 1 + * + * \date Date: 10/08/07 10:00 + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * + * \section info Change Information + * + * \verbatim + + History: tmdlHdmiTx.c + * + * ***************** Version 1 ***************** + * User: J. Lamotte Date: 10/08/07 Time: 10:00 + * Updated in $/Source/tmdlHdmiTx/inc + * initial version + + \endverbatim + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ +#include "tmdlHdmiTx_IW.h" +#include "tmdlHdmiTx.h" +#include "tmdlHdmiTx_local.h" +#include "tmdlHdmiTx_cfg.h" +#include "tmbslHdmiTx_funcMapping.h" + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + +/* Macro to avoid compilation warnings */ +#ifdef TMFL_OS_WINDOWS +#define DUMMY_ACCESS(x) x +#else +#define DUMMY_ACCESS(x) +#endif + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ + + + +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/* Prototypes of internal functions */ +/* Task functions */ +#ifndef TMFL_NO_RTOS +static void CommandTaskUnit0(void); +static void HdcpTaskUnit0(void); +#endif /* TMFL_NO_RTOS */ + +/* Interrupt callback functions */ +static void dlHdmiTxHandleENCRYPT(tmInstance_t instance); +static void dlHdmiTxHandleHPD(tmInstance_t instance); +static void dlHdmiTxHandleT0(tmInstance_t instance); +static void dlHdmiTxHandleBCAPS(tmInstance_t instance); +static void dlHdmiTxHandleBSTATUS(tmInstance_t instance); +static void dlHdmiTxHandleSHA_1(tmInstance_t instance); +static void dlHdmiTxHandlePJ(tmInstance_t instance); +static void dlHdmiTxHandleR0(tmInstance_t instance); +static void dlHdmiTxHandleSW_INT(tmInstance_t instance); +static void dlHdmiTxHandleRX_SENSE(tmInstance_t instance); +static void dlHdmiTxHandleEDID_READ(tmInstance_t instance); +static void dlHdmiTxHandleVS_RPT(tmInstance_t instance); + +/* Devlib internal color bar management functions */ +#ifndef NO_HDCP +static void dlHdmiTxCheckColorBar(tmInstance_t instance); +static void dlHdmiTxCheckHdcpColorBar(tmInstance_t instance); +#endif + +#ifndef NO_HDCP +static void dlHdmiTxFindHdcpSeed(tmInstance_t instance); +#endif /* NO_HDCP */ + +/* Set the state machine of device library */ +static void dlHdmiTxSetState +( + tmInstance_t instance, + tmdlHdmiTxDriverState_t state +); + +/* Get the event status (enable or disable) in order to known + if event should be signaled */ +static tmdlHdmiTxEventStatus_t dlHdmiTxGetEventStatus +( + tmInstance_t instance, + tmdlHdmiTxEvent_t event +); + +/* Use by tmdlHdmiTxSetInputOutput in scaler mode */ +static Bool dlHdmiTxGetReflineRefpix +( + tmdlHdmiTxVidFmt_t vinFmt, + tmdlHdmiTxVinMode_t vinMode, + tmdlHdmiTxVidFmt_t voutFmt, + UInt8 syncIn, + tmdlHdmiTxPixRate_t pixRate, + UInt16 *pRefPix, + UInt16 *pRefLine, + UInt16 *pScRefPix, + UInt16 *pScRefLine, + Bool *pbVerified +); + +/* Use by tmdlHdmiTxSetInputOutput to set AVI infoframe */ +static tmErrorCode_t dlHdmiTxSetVideoInfoframe +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t voutFmt, + tmdlHdmiTxVoutMode_t voutMode +); + +/* Use to set AVI infoframe with raw data */ +static tmErrorCode_t dlHdmiTxSetRawVideoInfoframe +( + tmInstance_t instance, + tmdlHdmiTxAviIfData_t *pContentVif, + Bool enable +); + +/* Calculate Checksum for info frame */ +static UInt8 +dlHdmiTxcalculateCheksumIF +( + tmbslHdmiTxPktRawAvi_t *pData /* Pointer to checksum data */ +); + +/* IMPORTANT: The 3 functions define below should not be declared in static + in order to allow applicative API to call them. Those functions are not + in tmdlHdmiTx_Functions.h but are in tmdlHdmiTxCore.def */ + +/* Get the device library state */ +tmdlHdmiTxDriverState_t dlHdmiTxGetState(tmInstance_t instance); + +/* Set pattern ON (Blue screen or color bar) */ +tmErrorCode_t dlHdmiTxSetTestPatternOn +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t voutFmt, + tmdlHdmiTxVoutMode_t voutMode, + tmdlHdmiTxTestPattern_t pattern +); + +/* Set pattern OFF */ +tmErrorCode_t dlHdmiTxSetTestPatternOff +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t voutFmt, + tmdlHdmiTxVoutMode_t voutMode +); + +/* Get DTD from BSL */ +static tmErrorCode_t dlHdmiTxEdidGetDTD +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + UInt8 maxDTDesc, + UInt8 *pWrittenDTDesc +); + +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_640HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors +); + +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_720HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio +); + +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_1280HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors +); + +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_1920HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + Bool formatInterlaced +); + +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_1440HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio, + Bool formatInterlaced +); + +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_2880HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio, + Bool formatInterlaced +); + +static tmdlHdmiTxPictAspectRatio_t dlHdmiTxCalcAspectRatio ( + UInt16 HImageSize, + UInt16 VImageSize +); + +#ifndef NO_HDCP +static void dlHdmiTxCheckHdcpBksv +( + tmInstance_t instance, + UInt8 * pHdcpBksvTested, + Bool * pbBksvSecure, + Bool bBigEndian +); +#endif + +/* Calculate table index according to video format value */ +static tmdlHdmiTxVidFmt_t dlHdmiTxCalcVidFmtIndex(tmdlHdmiTxVidFmt_t vidFmt); + +extern tmErrorCode_t tmbslDebugWriteFakeRegPage( tmUnitSelect_t txUnit ); + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + +tmdlHdmiTxIWSemHandle_t dlHdmiTxItSemaphore[MAX_UNITS]; + +/* Unit configuration structure (device library system configuration) */ +unitConfig_t unitTableTx[MAX_UNITS] = +{ + { + False, + False, + (tmdlHdmiTxHdcpOptions_t) HDCP_OPT_DEFAULT, + False, + False, + TMDL_HDMITX_DEVICE_UNKNOWN, + 0, + 0, + (tmdlHdmiTxIWTaskHandle_t) 0, + (tmdlHdmiTxIWQueueHandle_t) 0, + (tmdlHdmiTxIWTaskHandle_t) 0, + STATE_NOT_INITIALIZED, + (ptmdlHdmiTxCallback_t) 0, + {Null, 0,}, + } +}; + +#ifndef TMFL_NO_RTOS + +tmdlHdmiTxIWFuncPtr_t commandTaskTableTx[MAX_UNITS] = { + CommandTaskUnit0 + }; + +tmdlHdmiTxIWFuncPtr_t hdcpTaskTableTx[MAX_UNITS] = { + HdcpTaskUnit0 + }; + +#endif /* TMFL_NO_RTOS */ + +tmbslHdmiTxCallbackList_t callbackFuncTableTx; + +/* Device library configuration structure completed by dlHdmiTxGetConfig with + informations contained in config file */ +tmdlHdmiTxDriverConfigTable_t gtmdlHdmiTxDriverConfigTable[MAX_UNITS] = { + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0, 0, 0, 0, 0, 0, 0, TMDL_HDMITX_PATTERN_OFF,0}, +}; + +/* Video info (see instanceStatusInfoTx) */ +tmdlHdmiTxVideoInfo_t videoInfoListTx = { + False, + {TMDL_HDMITX_VFMT_03_720x480p_60Hz, TMDL_HDMITX_VINMODE_YUV422, TMDL_HDMITX_SYNCSRC_EXT_VS, TMDL_HDMITX_PIXRATE_SINGLE, TMDL_HDMITX_3D_NONE}, + {TMDL_HDMITX_VFMT_03_720x480p_60Hz, TMDL_HDMITX_VOUTMODE_YUV422, TMDL_HDMITX_COLORDEPTH_24,TMDL_HDMITX_VQR_DEFAULT} +}; + +/* Audio info (see instanceStatusInfoTx) */ +tmdlHdmiTxAudioInfo_t audioInfoListTx = { + False, + {TMDL_HDMITX_AFMT_SPDIF, TMDL_HDMITX_AFS_48K,TMDL_HDMITX_I2SFOR_PHILIPS_L,TMDL_HDMITX_I2SQ_16BITS,TMDL_HDMITX_DSTRATE_SINGLE,0x00} +}; + +/* Event state (see instanceStatusInfoTx) */ +tmdlHdmiTxEventState_t eventStateListTx[EVENT_NB] = { + {TMDL_HDMITX_HDCP_ACTIVE, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_HDCP_INACTIVE, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_HPD_ACTIVE, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_HPD_INACTIVE, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_RX_KEYS_RECEIVED, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_RX_DEVICE_ACTIVE, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_RX_DEVICE_INACTIVE, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_EDID_RECEIVED, TMDL_HDMITX_EVENT_DISABLED}, + {TMDL_HDMITX_VS_RPT_RECEIVED, TMDL_HDMITX_EVENT_DISABLED} +#ifdef HDMI_TX_REPEATER_ISR_MODE + ,{TMDL_HDMITX_B_STATUS, TMDL_HDMITX_EVENT_DISABLED} +#endif /* HDMI_TX_REPEATER_ISR_MODE */ +}; + +/* Color bars state (see instanceStatusInfoTx) */ +tmdlHdmiTxColBarState_t colorBarStateTx = { + False, + True, + True, + False, + False, + True, + False +}; + +tmdlHdmiTxGamutState_t gamutStateTx = { + False, + 0, + TMDL_HDMITX_EXT_COLORIMETRY_XVYCC601, + False, + TMDL_HDMITX_YQR_LIMITED +}; + + +/* Instance status (save the actual configuration) */ +instanceStatus_t instanceStatusInfoTx[MAX_UNITS] = { + {(ptmdlHdmiTxVideoInfo_t) &videoInfoListTx, + (ptmdlHdmiTxAudioInfo_t) &audioInfoListTx, + (ptmdlHdmiTxEventState_t) eventStateListTx, + (ptmdlHdmiTxColBarState_t) &colorBarStateTx, + (ptmdlHdmiTxGamutState_t) &gamutStateTx } +}; + +/* HDCP seed table, arranged as pairs of 16-bit integers: lookup value, seed value. + * If no table is programmed and if KEY_SEED in config file is null, HDCP will be disabled */ +#define SEED_TABLE_LEN 10 +static const UInt16 kSeedTable[SEED_TABLE_LEN][2] = { + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0} +}; + +#ifndef NO_HDCP +tmdlHdmiTxHdcpInfo_t hdcpInfoListTx[MAX_UNITS]; +#endif /* NO_HDCP */ + + +static Bool gI2CDebugAccessesEnabled = True; /* For debug purpose only, used to manage underlying I2C accessed */ + +#ifdef HDMI_TX_REPEATER_ISR_MODE +static Bool gIgnoreNextSha1 = False; +#endif /*HDMI_TX_REPEATER_ISR_MODE*/ + +/*============================================================================*/ +/* FUNCTIONS */ +/*============================================================================*/ + +/****************************************************************************** + \brief Get the software version of the driver. + + \param pSWVersion Pointer to the version structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetSWVersion +( + tmSWVersion_t *pSWVersion +) +{ + /* Check if SWVersion pointer is Null */ + RETIF(pSWVersion == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Copy SW version */ + pSWVersion->compatibilityNr = VERSION_COMPATIBILITY; + pSWVersion->majorVersionNr = VERSION_MAJOR; + pSWVersion->minorVersionNr = VERSION_MINOR; + + return TM_OK; +} + +/****************************************************************************** + \brief Get the number of available HDMI transmitters devices in the system. + A unit directly represents a physical device. + + \param pUnitCount Pointer to the number of available units. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetNumberOfUnits +( + UInt32 *pUnitCount +) +{ + /* Check if UnitCount pointer is Null */ + RETIF(pUnitCount == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Copy the maximum number of units */ + *pUnitCount = MAX_UNITS; + + return TM_OK; +} + +/****************************************************************************** + \brief Get the capabilities of unit 0. Capabilities are stored into a + dedicated structure and are directly read from the HW device. + + \param pCapabilities Pointer to the capabilities structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetCapabilities +( + tmdlHdmiTxCapabilities_t *pCapabilities +) +{ + /* Directly call GetCapabilitiesM function for unit 0 and return the result */ + return(tmdlHdmiTxGetCapabilitiesM((tmUnitSelect_t)0, pCapabilities)); +} + +/****************************************************************************** + \brief Get the capabilities of a specific unit. Capabilities are stored + into a dedicated structure and are directly read from the HW + device. + + \param unit Unit to be probed. + \param pCapabilities Pointer to the capabilities structure. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetCapabilitiesM +( + tmUnitSelect_t unit, + tmdlHdmiTxCapabilities_t *pCapabilities +) +{ + tmErrorCode_t errCode = TM_OK; + Bool featureSupported; + + /* Check if unit number is in range */ + RETIF((unit < 0) || (unit >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER) + + /* Check if Capalities pointer is Null */ + RETIF(pCapabilities == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Device version */ + pCapabilities->deviceVersion = unitTableTx[unit].deviceVersion ; + + /* Retrieve the capabilities from the BSL layer */ + + /* HDCP support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_HDCP, &featureSupported) ) != TM_OK, errCode) + + pCapabilities->hdcp = featureSupported; + + /* Scaler support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_SCALER, &featureSupported) ) != TM_OK, errCode) + + pCapabilities->scaler = featureSupported; + + /* Audio HBR support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_AUDIO_HBR, &featureSupported) ) != TM_OK, errCode) + + pCapabilities->audioPacket.HBR = featureSupported; + + /* Audio OBA support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_AUDIO_OBA, &featureSupported) ) != TM_OK, errCode) + + pCapabilities->audioPacket.oneBitAudio = featureSupported; + + /* Audio DST support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_AUDIO_DST, &featureSupported) ) != TM_OK, errCode) + + pCapabilities->audioPacket.DST = featureSupported; + + /* HDMI version 1.1 support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_HDMI_1_1, &featureSupported) ) != TM_OK, errCode) + + if (featureSupported) + { + pCapabilities->hdmiVersion = TMDL_HDMITX_HDMI_VERSION_1_1; + } + + /* HDMI version 1.2A support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_HDMI_1_2A, &featureSupported) ) != TM_OK, errCode) + + if (featureSupported) + { + pCapabilities->hdmiVersion = TMDL_HDMITX_HDMI_VERSION_1_2a; + } + + /* HDMI version 1.3 support */ + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_HDMI_1_3A, &featureSupported) ) != TM_OK, errCode) + + if (featureSupported) + { + pCapabilities->hdmiVersion = TMDL_HDMITX_HDMI_VERSION_1_3a; + } + + /* Deep Color support */ + /* By default */ + pCapabilities->colorDepth = TMDL_HDMITX_COLORDEPTH_24; + + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_DEEP_COLOR_30, &featureSupported) ) != TM_OK, errCode) + + if (featureSupported) + { + pCapabilities->colorDepth = TMDL_HDMITX_COLORDEPTH_30; + } + + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_DEEP_COLOR_36, &featureSupported) ) != TM_OK, errCode) + + if (featureSupported) + { + pCapabilities->colorDepth = TMDL_HDMITX_COLORDEPTH_36; + } + + RETIF( (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_DEEP_COLOR_48, &featureSupported) ) != TM_OK, errCode) + + if (featureSupported) + { + pCapabilities->colorDepth = TMDL_HDMITX_COLORDEPTH_48; + } + + return errCode; +} + +/****************************************************************************** + \brief Open unit 0 of HdmiTx driver and provides the instance number to + the caller. Note that one unit of HdmiTx represents one physical + HDMI transmitter and that only one instance per unit can be opened. + + \param pInstance Pointer to the variable that will receive the instance + identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the transmitter instance is not initialised + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: the unit is not initialized + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_INIT_FAILED: the unit instance is already + initialised + - TMBSL_ERR_HDMI_COMPATIBILITY: the driver is not compatiable + with the internal device version code + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxOpen +( + tmInstance_t *pInstance +) +{ + /* Directly call OpenM function for unit 0 and return the result */ + return(tmdlHdmiTxOpenM(pInstance, (tmUnitSelect_t)0)); +} + +/****************************************************************************** + \brief Open a specific unit of HdmiTx driver and provides the instance + number to the caller. Note that one unit of HdmiTx represents one + physical HDMI transmitter and that only one instance per unit can be + opened. This function switches driver's state machine to + "initialized" state. + + \param pInstance Pointer to the structure that will receive the instance + identifier. + \param unit Unit number to be opened. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the transmitter instance is not initialised + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_OWNED: the resource is already in use + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_INIT_FAILED: the unit instance is already + initialised or something wrong happened at lower level. + - TMDL_ERR_DLHDMITX_NO_RESOURCES: the resource is not available + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: the unit is not initialized + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter is invalid or out + of range + - TMBSL_ERR_HDMI_INIT_FAILED: the unit instance is already + initialised + - TMBSL_ERR_HDMI_COMPATIBILITY: the driver is not compatiable + with the internal device version code + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxOpenM +( + tmInstance_t *pInstance, + tmUnitSelect_t unit +) +{ + tmErrorCode_t errCode; + tmErrorCode_t errCodeSem; + UInt16 i; + UInt8 deviceVersion; + Bool featureSupported; + + /* Check if unit number is in range */ + RETIF((unit < 0) || (unit >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER) + + /* Check if Instance pointer is Null */ + RETIF(pInstance == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Create the semaphore to protect variables modified under interruption */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreCreate(&dlHdmiTxItSemaphore[unit]) ) != TM_OK, errCode) + + /* Take the sempahore */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[unit]) ) != TM_OK, errCodeSem) + + /* Check if unit is already instanciated */ + RETIF_SEM(dlHdmiTxItSemaphore[unit], + unitTableTx[unit].opened == True, TMDL_ERR_DLHDMITX_RESOURCE_OWNED) + + /* Check the state */ + RETIF_SEM(dlHdmiTxItSemaphore[unit], + dlHdmiTxGetState(unit) != STATE_NOT_INITIALIZED, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Instanciate unit and return corresponding instance number */ + /* Since HW unit are only instanciable once, instance = unit */ + unitTableTx[unit].opened = True; + unitTableTx[unit].hdcpEnable = False; + unitTableTx[unit].repeaterEnable = False; + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_UNKNOWN; + unitTableTx[unit].simplayHd = False; + unitTableTx[unit].pCallback = Null; + unitTableTx[unit].revocationList.pList = Null; + unitTableTx[unit].revocationList.length = 0; + + /* Recover the configuration of the device library */ + RETIF_SEM(dlHdmiTxItSemaphore[unit], + dlHdmiTxGetConfig(unit, >mdlHdmiTxDriverConfigTable[unit])!= TM_OK, TMDL_ERR_DLHDMITX_INIT_FAILED) + +#ifndef TMFL_NO_RTOS + + /* Create message queue associated to this instance/unit */ + RETIF_SEM(dlHdmiTxItSemaphore[unit], + tmdlHdmiTxIWQueueCreate(gtmdlHdmiTxDriverConfigTable[unit].commandTaskQueueSize, + &(unitTableTx[unit].queueHandle)) != TM_OK, TMDL_ERR_DLHDMITX_NO_RESOURCES) + + /* Create the command task associated to this instance/unit */ + RETIF_SEM(dlHdmiTxItSemaphore[unit], + tmdlHdmiTxIWTaskCreate(commandTaskTableTx[unit], + gtmdlHdmiTxDriverConfigTable[unit].commandTaskPriority, + gtmdlHdmiTxDriverConfigTable[unit].commandTaskStackSize, + &(unitTableTx[unit].commandTaskHandle)) != TM_OK, TMDL_ERR_DLHDMITX_NO_RESOURCES) + + RETIF_SEM(dlHdmiTxItSemaphore[unit], + tmdlHdmiTxIWTaskStart(unitTableTx[unit].commandTaskHandle) != TM_OK, TMDL_ERR_DLHDMITX_NO_RESOURCES) + + /* Create the hdcp check task associated to this instance/unit */ +#ifndef NO_HDCP + RETIF_SEM(dlHdmiTxItSemaphore[unit], + tmdlHdmiTxIWTaskCreate(hdcpTaskTableTx[unit], + gtmdlHdmiTxDriverConfigTable[unit].hdcpTaskPriority, + gtmdlHdmiTxDriverConfigTable[unit].hdcpTaskStackSize, + &(unitTableTx[unit].hdcpTaskHandle)) != TM_OK, TMDL_ERR_DLHDMITX_NO_RESOURCES) +#endif /* NO_HDCP */ + +#endif /* TMFL_NO_RTOS */ + + *pInstance = (tmInstance_t)unit; + +#ifndef NO_HDCP + hdcpInfoListTx[unit].bKsvSecure = False; + hdcpInfoListTx[unit].hdcpKsvDevices = 0; + for(i=0; idisableColorBarOnR0 = False; + instanceStatusInfoTx[unit].pColBarState->hdcpColbarChange = False; + instanceStatusInfoTx[unit].pColBarState->hdcpEncryptOrT0 = True; + instanceStatusInfoTx[unit].pColBarState->hdcpSecureOrT0 = False; + instanceStatusInfoTx[unit].pColBarState->inOutFirstSetDone = False; + instanceStatusInfoTx[unit].pColBarState->colorBarOn = False; + instanceStatusInfoTx[unit].pColBarState->changeColorBarNow = False; + + instanceStatusInfoTx[unit].pGamutState->gamutOn = False; + instanceStatusInfoTx[unit].pGamutState->gamutBufNum = 0; /* use buffer 0 by default */ + instanceStatusInfoTx[unit].pGamutState->wideGamutColorSpace = TMDL_HDMITX_EXT_COLORIMETRY_XVYCC601; + instanceStatusInfoTx[unit].pGamutState->extColOn = False; + instanceStatusInfoTx[unit].pGamutState->yccQR = TMDL_HDMITX_YQR_LIMITED; + + + instanceStatusInfoTx[unit].pAudioInfo->audioMuteState = False; /* Initially audio is not muted */ + + + + /* The funcCallback is not the same between BSL, so fill it dynamically */ + for(i=0; ivideoInConfig.format, + (tmbslHdmiTxPixRate_t)instanceStatusInfoTx[unit].pVideoInfo->videoInConfig.pixelRate); + if (errCode != TM_OK) + { + /* Init failed */ + tmbslHdmiTxDeinit(unit); + + /* Release the sempahore */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[unit]) ) != TM_OK, errCodeSem) + + return errCode; + } + else + { + /* Init passed, continue */ + + /* Start by forcing the TMDS ouputs off */ + errCode = tmbslHdmiTxTmdsSetOutputs(unit, + HDMITX_TMDSOUT_FORCED0); + RETIF_SEM(dlHdmiTxItSemaphore[unit], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[unit], + (errCode = tmbslHdmiTxHwGetCapabilities(unit, + HDMITX_FEATURE_HW_HDCP, &featureSupported) ) != TM_OK, errCode) + +#ifndef NO_HDCP + if (featureSupported == True) + { + dlHdmiTxFindHdcpSeed(unit); + } +#endif /* NO_HDCP */ + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + tmbslHdmiTxHdcpPowerDown(unit,True); +#endif + /* Retrieve the hardware device version from the BSL layer */ + RETIF_SEM(dlHdmiTxItSemaphore[unit], + (errCode = tmbslHdmiTxHwGetVersion(unit,&deviceVersion) ) \ + != TM_OK, errCode); + + /* Store the hardware device version in the global variable */ + switch (deviceVersion) + { + case BSLHDMITX_TDA9984: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_TDA9984; + break; + + case BSLHDMITX_TDA9989: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_TDA9989; + break; + + case BSLHDMITX_TDA9981: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_TDA9981; + break; + + case BSLHDMITX_TDA9983: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_TDA9983; + break; + + case BSLHDMITX_TDA19989: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_TDA19989; + break; + + case BSLHDMITX_TDA19988: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_TDA19988; + break; + + default: + unitTableTx[unit].deviceVersion = TMDL_HDMITX_DEVICE_UNKNOWN; + break; + } + } + + +#ifndef TMFL_NO_RTOS + /* Start HDCP check task */ + +#ifndef NO_HDCP + RETIF_SEM(dlHdmiTxItSemaphore[unit], + tmdlHdmiTxIWTaskStart(unitTableTx[unit].hdcpTaskHandle) != TM_OK, TMDL_ERR_DLHDMITX_NO_RESOURCES) +#endif /* NO_HDCP */ + +#endif /* TMFL_NO_RTOS */ + + + /* Set the state machine to initialized */ + dlHdmiTxSetState(unit, STATE_INITIALIZED); + + /* Release the sempahore */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[unit]) ) != TM_OK, errCodeSem) + + return TM_OK; +} + +/****************************************************************************** + \brief Close an instance of HdmiTx driver. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxClose +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode = TM_OK; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check if unit corresponding to instance is opened */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + unitTableTx[instance].opened == False, TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED) + + /* Close instance */ + unitTableTx[instance].opened = False; + + /* Set the state machine */ + dlHdmiTxSetState(instance, STATE_NOT_INITIALIZED); + + /* Destroy resources allocated for this instance/unit */ + +#ifndef TMFL_NO_RTOS + +#ifndef NO_HDCP + tmdlHdmiTxIWTaskDestroy(unitTableTx[instance].hdcpTaskHandle); +#endif /* NO_HDCP */ + + tmdlHdmiTxIWTaskDestroy(unitTableTx[instance].commandTaskHandle); + tmdlHdmiTxIWQueueDestroy(unitTableTx[instance].queueHandle); + +#endif /* TMFL_NO_RTOS */ + + /* Reset an instance of an HDMI transmitter */ + tmbslHdmiTxDeinit(instance); + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Close the handle to the semaphore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreDestroy(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Set the power state of an instance of the HDMI transmitter. + + \param instance Instance identifier. + \param powerState Power state to set. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetPowerState +( + tmInstance_t instance, + tmPowerState_t powerState +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxHotPlug_t hpdStatus; /* HPD status */ + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (unitTableTx[instance].deviceVersion == TMDL_HDMITX_DEVICE_TDA9984) + { + if (powerState == tmPowerSuspend) + { + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; + } + } + + + + + /* Switch off HDCP */ + if ( ((powerState == tmPowerOff) && (unitTableTx[instance].hdcpEnable == True)) + || ((powerState == tmPowerStandby) && (unitTableTx[instance].hdcpEnable == True)) + || ((powerState == tmPowerSuspend) && (unitTableTx[instance].hdcpEnable == True)) + ) + { + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + /* Switch off HDCP */ + RETIF( (errCode = tmdlHdmiTxSetHdcp(instance, False) ) != TM_OK, errCode) + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + } + + + /* TDA9989, TDA19989 and TDA19988 only */ + if ( (unitTableTx[instance].deviceVersion == TMDL_HDMITX_DEVICE_TDA9989) + || + (unitTableTx[instance].deviceVersion == TMDL_HDMITX_DEVICE_TDA19989) + || + (unitTableTx[instance].deviceVersion == TMDL_HDMITX_DEVICE_TDA19988)) + + { + if ((powerState != tmPowerOn) && (powerState != tmPowerSuspend)) { + dlHdmiTxSetState(instance, STATE_INITIALIZED); + } + + if ((powerState == tmPowerOn) && (unitTableTx[instance].simplayHd == True)) { + + instanceStatusInfoTx[0].pColBarState->disableColorBarOnR0 = False; + instanceStatusInfoTx[0].pColBarState->hdcpColbarChange = False; + instanceStatusInfoTx[0].pColBarState->hdcpEncryptOrT0 = True; + instanceStatusInfoTx[0].pColBarState->hdcpSecureOrT0 = False; + instanceStatusInfoTx[0].pColBarState->inOutFirstSetDone = False; + instanceStatusInfoTx[0].pColBarState->colorBarOn = True; + instanceStatusInfoTx[0].pColBarState->changeColorBarNow = True; + + } + + } + + /* Set the power state of the transmitter */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPowerSetState(instance, + powerState) ) != TM_OK, errCode) + + /* Get Hot Plug status */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHotPlugGetStatus(instance, + &hpdStatus,False) ) != TM_OK, errCode) + + if (powerState == tmPowerOn) + { + if ((hpdStatus == HDMITX_HOTPLUG_ACTIVE) && (dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE)) + { + /* Yes: Wait for DDC line to settle before reading EDID */ + tmbslHdmiTxSysTimerWait(instance, + 500); /* ms */ + + /* Request EDID read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidRequestBlockData(instance, + unitTableTx[instance].pEdidBuffer, (Int)((unitTableTx[instance].edidBufferSize) >> 7), + (Int)(unitTableTx[instance].edidBufferSize)) ) != TM_OK, errCode) + } + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Get the power state of an instance of the HDMI transmitter. + + \param instance Instance identifier. + \param pPowerState Pointer to the power state. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetPowerState +( + tmInstance_t instance, + tmPowerState_t *pPowerState +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if PowerState pointer is Null */ + RETIF(pPowerState == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Get the power state of the transmitter */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPowerGetState(instance, + pPowerState) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Set the configuration of instance attributes. This function is + required by DVP architecture rules but actually does nothing in this + driver. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxInstanceConfig +( + tmInstance_t instance +) +{ + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + return TM_OK; +} + +/****************************************************************************** + \brief Setup the instance with its configuration parameters. This function + allows basic instance configuration like enabling HDCP, choosing + HDCP encryption mode or enabling HDCP repeater mode. + + \param instance Instance identifier. + \param pSetupInfo Pointer to the structure containing all setup parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxInstanceSetup +( + tmInstance_t instance, + tmdlHdmiTxInstanceSetupInfo_t *pSetupInfo +) +{ + tmErrorCode_t errCode; +#ifndef NO_HDCP + UInt16 i; +#endif + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if SetupInfo pointer is NULL */ + RETIF(pSetupInfo == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check if unit corresponding to instance is opened */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + unitTableTx[instance].opened == False, TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED) + + /* Check the state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_INITIALIZED, TMDL_ERR_DLHDMITX_INVALID_STATE) + + unitTableTx[instance].repeaterEnable = pSetupInfo->repeaterEnable; + unitTableTx[instance].simplayHd = pSetupInfo->simplayHd; + unitTableTx[instance].pEdidBuffer = pSetupInfo->pEdidBuffer; + unitTableTx[instance].edidBufferSize = pSetupInfo->edidBufferSize; + +#ifndef NO_HDCP + /* Reset HDCP DevLib data */ + hdcpInfoListTx[instance].hdcpCheckState = TMDL_HDMITX_HDCP_CHECK_NOT_STARTED; + hdcpInfoListTx[instance].hdcpErrorState = 0; + hdcpInfoListTx[instance].hdcpKsvDevices = 0; + hdcpInfoListTx[instance].bKsvSecure = False; + for(i=0; i= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if SetupInfo pointer is NULL */ + RETIF(pSetupInfo == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check if unit corresponding to instance is opened */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + unitTableTx[instance].opened == False, TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED) + + pSetupInfo->simplayHd = unitTableTx[instance].simplayHd; + pSetupInfo->repeaterEnable = unitTableTx[instance].repeaterEnable; + /* JL, TODO */ + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Make device library handle an incoming interrupt. This function is + used by application to tell the device library that the hardware + sent an interrupt. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_FULL: the queue is full + + ******************************************************************************/ +tmErrorCode_t tmdlHdmiTxHandleInterrupt +( + tmInstance_t instance +) +{ +#ifndef TMFL_NO_RTOS + tmErrorCode_t errCode; + UInt8 message = 0; +#else + tmErrorCode_t err = TM_OK; +#endif /* TMFL_NO_RTOS */ + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + +#ifndef TMFL_NO_RTOS + RETIF( (errCode = tmdlHdmiTxIWQueueSend(unitTableTx[instance].queueHandle, message)) != TM_OK, errCode) + + /* Disable interrupts for Tx until the callbacks have been done by the command task */ + switch(instance) + { + case INSTANCE_0: + tmdlHdmiTxIWDisableInterrupts(TMDL_HDMI_IW_TX_1); + break; + case INSTANCE_1: + tmdlHdmiTxIWDisableInterrupts(TMDL_HDMI_IW_TX_2); + break; + default: + return TMDL_ERR_DLHDMITX_BAD_INSTANCE; + } +#else + + /* Clear T0 flag before polling for interrupts */ + instanceStatusInfoTx[0].pColBarState->hdcpSecureOrT0 = False; + + if (gI2CDebugAccessesEnabled == True) + { + + err = tmbslHdmiTxHwHandleInterrupt(0); + + if ((err == TMBSL_ERR_HDMI_I2C_WRITE) || (err == TMBSL_ERR_HDMI_I2C_READ)) + { + + unitTableTx[0].pCallback(TMDL_HDMITX_DEBUG_EVENT_1); + } + + }/* (gI2CDebugAccessesEnabled == True) */ + + +#endif /* TMFL_NO_RTOS */ + + return TM_OK; +} + +/****************************************************************************** + \brief Register event callbacks. Only one callback is registered through + this API. This callback will received the type of event that + occured throug a dedicated parameter and will be called as many + times as there is pending events. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pCallback Pointer to the callback function that will handle events + from the devlib. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED: the caller does not own + the resource + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxRegisterCallbacks +( + tmInstance_t instance, + ptmdlHdmiTxCallback_t pCallback +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check if unit corresponding to instance is opened */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + unitTableTx[instance].opened == False, TMDL_ERR_DLHDMITX_RESOURCE_NOT_OWNED) + + /* Check if instance state is correct */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_INITIALIZED, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Store callback pointers */ + unitTableTx[instance].pCallback = pCallback; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief This function allows enabling a specific event. By default, all + events are disabled, except input lock. + + \param instance Instance identifier. + \param event Event to enable. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxEnableEvent +( + tmInstance_t instance, + tmdlHdmiTxEvent_t event +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if the event exists */ + RETIF_BADPARAM(event >= EVENT_NB) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Protect the access to this ressource */ + instanceStatusInfoTx[instance].pEventState[event].status = TMDL_HDMITX_EVENT_ENABLED; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief This function allows disabling a specific event. By default, all + events are disabled, except input lock. + + \param instance Instance identifier. + \param event Event to disable. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxDisableEvent +( + tmInstance_t instance, + tmdlHdmiTxEvent_t event +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if the event exists */ + RETIF_BADPARAM(event >= EVENT_NB) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Protect the access to this ressource */ + instanceStatusInfoTx[instance].pEventState[event].status = TMDL_HDMITX_EVENT_DISABLED; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Get specifications of a given video format. Application can use + this function to retreives all specifications (frequencies, + resolution, etc.) of a given IA/CEA 861-D video format. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param resolutionID ID of the resolution to retrieve specs from. + \param pResolutionSpecs Pointer to the structure receiving specs. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN: the resolution is unknown + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetVideoFormatSpecs +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t resolutionID, + tmdlHdmiTxVidFmtSpecs_t *pResolutionSpecs +) +{ + UInt8 i; + Bool find = False; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if ResolutionSpecs pointer is Null */ + RETIF(pResolutionSpecs == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + for (i = 0; i < RESOLUTION_NB; i++) + { + if(resolutionID == gtmdlHdmiTxDriverConfigTable[instance].pResolutionInfo[i].resolutionID) + { + find = True; + pResolutionSpecs->height = gtmdlHdmiTxDriverConfigTable[instance].pResolutionInfo[i].height; + pResolutionSpecs->width = gtmdlHdmiTxDriverConfigTable[instance].pResolutionInfo[i].width; + pResolutionSpecs->interlaced = gtmdlHdmiTxDriverConfigTable[instance].pResolutionInfo[i].interlaced; + pResolutionSpecs->vfrequency = gtmdlHdmiTxDriverConfigTable[instance].pResolutionInfo[i].vfrequency; + pResolutionSpecs->aspectRatio = gtmdlHdmiTxDriverConfigTable[instance].pResolutionInfo[i].aspectRatio; + + /* Transformation of 2D-interlaced formats into 3DFP-progressif formats */ + if((instanceStatusInfoTx[instance].pVideoInfo->videoInConfig.structure3D == TMDL_HDMITX_3D_FRAME_PACKING) + && pResolutionSpecs->interlaced && ((resolutionID == TMDL_HDMITX_VFMT_20_1920x1080i_50Hz) + || (resolutionID == TMDL_HDMITX_VFMT_05_1920x1080i_60Hz))) + { + pResolutionSpecs->interlaced = False; + if(pResolutionSpecs->vfrequency == TMDL_HDMITX_VFREQ_50Hz) + { + pResolutionSpecs->vfrequency = TMDL_HDMITX_VFREQ_25Hz; + } + else if((pResolutionSpecs->vfrequency == TMDL_HDMITX_VFREQ_60Hz) || (pResolutionSpecs->vfrequency == TMDL_HDMITX_VFREQ_59Hz)) + { + pResolutionSpecs->vfrequency = TMDL_HDMITX_VFREQ_30Hz; + } + } + + break; + } + } + + /* Resolution not found in table */ + RETIF(find == False, TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN) + + return TM_OK; +} + +/****************************************************************************** + \brief Configures all input and output parameters : format, modes, rates, + etc. This is the main configuration function of the driver. Here + are transmitted all crucial input and output parameters of the + device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param videoInputConfig Configuration of the input video. + \param videoOutputConfig Configuration of the output video. + \param audioInputConfig Configuration of the input audio. + \param sinkType Type of sink connected to the output of the Tx. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetInputOutput +( + tmInstance_t instance, + tmdlHdmiTxVideoInConfig_t videoInputConfig, + tmdlHdmiTxVideoOutConfig_t videoOutputConfig, + tmdlHdmiTxAudioInConfig_t audioInputConfig, + tmdlHdmiTxSinkType_t sinkType +) +{ + tmErrorCode_t errCode; + UInt8 pixRepeat; /* Pixel repetition */ + tmbslHdmiTxVoutDbits_t pathBits; /* Data path bit width */ + tmbslHdmiTxPixEdge_t pixelEdge; /* Pixel sampling edge */ + tmbslHdmiTxVsMeth_t syncMethod; /* Sync method */ + tmbslHdmiTxPixTogl_t toggle; /* Toggling */ + UInt8 syncIn; /* Embedded or external */ + tmbslHdmiTxPixSubpkt_t spSync; /* Subpacket sync */ + tmbslHdmiTxBlnkSrc_t blankit; /* Blanking */ + tmbslHdmiTxPixRate_t pixRateSingleDouble; /* HDMITX_PIXRATE_SINGLE */ + UInt16 uRefPix; /* REFPIX for output */ + UInt16 uRefLine; /* REFLINE for output */ + UInt16 uScRefPix=0; /* REFPIX for scaler */ + UInt16 uScRefLine=0; /* REFLINE for scaler */ + Bool bVerified; /* Scaler setting verified */ + tmbslHdmiTxTopSel_t topSel; /* Adjustment for interlaced output */ + tmbslHdmiTxHPhases_t phasesH; /* Horizontal phase */ + tmbslHdmiTxVsOnce_t once; /* Line/pixel counters sync */ + tmbslHdmiTxScaMode_t scalerMode; /* Current scaler mode */ + Bool OBASupported; /* OBA supported or not */ + Bool DSTSupported; /* DST supported or not */ + Bool HBRSupported; /* HBR supporeted or not */ + + UInt8 *pSwapTable = Null; /* Initialized after (depend on video mode used) */ + UInt8 *pMirrorTable = Null; /* Initialized after (depend on video mode used) */ +#ifdef TMFL_RGB_DDR_12BITS + UInt8 *pMux = Null; /* Initialized after (depend on video mode used) */ +#endif + UInt8 *pEnaVideoPortTable = Null; /* Initialized after (depend on video mode used) */ + UInt8 *pGndVideoPortTable = Null; /* Initialized after (depend on video mode used) */ + tmdlHdmiTxVidFmt_t vinFmtIndex; /* index in table kVfmtToShortFmt_TV */ + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Update the instance status information */ + instanceStatusInfoTx[instance].pVideoInfo->videoInConfig.format = videoInputConfig.format; + instanceStatusInfoTx[instance].pVideoInfo->videoInConfig.mode = videoInputConfig.mode; + instanceStatusInfoTx[instance].pVideoInfo->videoInConfig.syncSource = videoInputConfig.syncSource; + instanceStatusInfoTx[instance].pVideoInfo->videoInConfig.pixelRate = videoInputConfig.pixelRate; + instanceStatusInfoTx[instance].pVideoInfo->videoInConfig.structure3D = videoInputConfig.structure3D; + + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format = videoOutputConfig.format; + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode = videoOutputConfig.mode; + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.colorDepth = videoOutputConfig.colorDepth; + + /* TODO */ + /*instanceStatusInfoTx[instance].pVideoInfo->videoMuteState = */ + + /* Audio OBA support */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_AUDIO_OBA, &OBASupported) ) != TM_OK, errCode) + + /* Audio DST support */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_AUDIO_DST, &DSTSupported) ) != TM_OK, errCode) + + /* Audio HBR support */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_AUDIO_HBR, &HBRSupported) ) != TM_OK, errCode) + + /* Test if audio input format is supported */ + if ( ((audioInputConfig.format == TMDL_HDMITX_AFMT_OBA) && (OBASupported == False)) || + ((audioInputConfig.format == TMDL_HDMITX_AFMT_DST) && (DSTSupported == False)) || + ((audioInputConfig.format == TMDL_HDMITX_AFMT_HBR) && (HBRSupported == False)) ) + { + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; + } + + instanceStatusInfoTx[instance].pAudioInfo->audioInCfg.format = audioInputConfig.format; + instanceStatusInfoTx[instance].pAudioInfo->audioInCfg.i2sFormat = audioInputConfig.i2sFormat; + instanceStatusInfoTx[instance].pAudioInfo->audioInCfg.i2sQualifier = audioInputConfig.i2sQualifier; + instanceStatusInfoTx[instance].pAudioInfo->audioInCfg.rate = audioInputConfig.rate; + instanceStatusInfoTx[instance].pAudioInfo->audioInCfg.channelAllocation = audioInputConfig.channelAllocation; + + + if (sinkType == TMDL_HDMITX_SINK_EDID) + { + /* Change sink type with the currently defined in EDID */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetSinkType(instance, + (tmbslHdmiTxSinkType_t *)&sinkType) ) != TM_OK, errCode) + } + + /* forbid format with pixel repetition in DVI */ + if (sinkType == TMDL_HDMITX_SINK_DVI) + { + if(((videoOutputConfig.format >= TMDL_HDMITX_VFMT_06_720x480i_60Hz) && (videoOutputConfig.format <= TMDL_HDMITX_VFMT_15_1440x480p_60Hz)) + || ((videoOutputConfig.format >= TMDL_HDMITX_VFMT_21_720x576i_50Hz) && (videoOutputConfig.format <= TMDL_HDMITX_VFMT_30_1440x576p_50Hz)) + || ((videoOutputConfig.format >= TMDL_HDMITX_VFMT_35_2880x480p_60Hz)&& (videoOutputConfig.format <= TMDL_HDMITX_VFMT_38_2880x576p_50Hz)) + ) + { + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_BAD_PARAMETER; + } + } + + /* Set color depth according to output config, transmitter termination is disable */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxSetColorDepth(instance, + (tmbslHdmiTxColorDepth)(videoOutputConfig.colorDepth), False) ) != TM_OK, errCode) + + /* Set the TMDS outputs to a forced state */ + errCode = tmbslHdmiTxTmdsSetOutputs(instance, + HDMITX_TMDSOUT_FORCED0); + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode) + + /* Fine-tune the TMDS serializer */ + errCode = tmbslHdmiTxTmdsSetSerializer(instance, + 4, 8); + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode) + + /* Set video output configuration */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoOutSetConfig(instance, + (tmbslHdmiTxSinkType_t)sinkType, (tmbslHdmiTxVoutMode_t)videoOutputConfig.mode, HDMITX_VOUT_PREFIL_OFF, + HDMITX_VOUT_YUV_BLNK_16, HDMITX_VOUT_QRANGE_FS) ) != TM_OK, errCode) + + /* Set default config */ + pixRepeat = HDMITX_PIXREP_DEFAULT; + pathBits = HDMITX_VOUT_DBITS_12; + pixelEdge = HDMITX_PIXEDGE_CLK_POS; + syncMethod = HDMITX_VSMETH_V_H; + toggle = HDMITX_PIXTOGL_ENABLE; + + /* Set sync details */ + if (videoInputConfig.syncSource == TMDL_HDMITX_SYNCSRC_EMBEDDED) + { + /* Embedded sync */ + syncIn = EMB; + spSync = HDMITX_PIXSUBPKT_SYNC_HEMB; + blankit = HDMITX_BLNKSRC_VS_HEMB_VEMB; + syncMethod = HDMITX_VSMETH_V_XDE; + } + else + { + /* External sync */ + syncIn = EXT; + + + if (gtmdlHdmiTxDriverConfigTable[instance].dataEnableSignalAvailable == 1) + { + /* DE is available */ + spSync = HDMITX_PIXSUBPKT_SYNC_DE; + } + else + { + /* DE is NOT available */ + spSync = HDMITX_PIXSUBPKT_SYNC_HS; + } + + + + blankit = HDMITX_BLNKSRC_NOT_DE; + } + + +#ifdef TMFL_RGB_DDR_12BITS + /* by default, mux is not used */ + pMux = >mdlHdmiTxDriverConfigTable[instance].pNoMux[0]; +#endif + + /* Port swap table */ + switch(videoInputConfig.mode) + { + case TMDL_HDMITX_VINMODE_CCIR656: + pathBits = HDMITX_VOUT_DBITS_8; + pixelEdge = HDMITX_PIXEDGE_CLK_NEG; + pSwapTable = gtmdlHdmiTxDriverConfigTable[instance].pSwapTableCCIR656; + pMirrorTable = gtmdlHdmiTxDriverConfigTable[instance].pMirrorTableCCIR656; +#ifdef TMFL_RGB_DDR_12BITS + pMux = >mdlHdmiTxDriverConfigTable[instance].pMux_RGB_DDR_12bits[0]; +#endif + pEnaVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pEnableVideoPortCCIR656; + pGndVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pGroundVideoPortCCIR656; + break; + + case TMDL_HDMITX_VINMODE_RGB444: + pSwapTable = gtmdlHdmiTxDriverConfigTable[instance].pSwapTableRGB444; + pMirrorTable = gtmdlHdmiTxDriverConfigTable[instance].pMirrorTableRGB444; + pEnaVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pEnableVideoPortRGB444; + pGndVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pGroundVideoPortRGB444; + break; + + case TMDL_HDMITX_VINMODE_YUV444: + pSwapTable = gtmdlHdmiTxDriverConfigTable[instance].pSwapTableYUV444; + pMirrorTable = gtmdlHdmiTxDriverConfigTable[instance].pMirrorTableYUV444; + pEnaVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pEnableVideoPortYUV444; + pGndVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pGroundVideoPortYUV444; + break; + + case TMDL_HDMITX_VINMODE_YUV422: + pSwapTable = gtmdlHdmiTxDriverConfigTable[instance].pSwapTableYUV422; + pMirrorTable = gtmdlHdmiTxDriverConfigTable[instance].pMirrorTableYUV422; +#ifdef TMFL_RGB_DDR_12BITS + pMux = >mdlHdmiTxDriverConfigTable[instance].pMux_RGB_DDR_12bits[0]; +#endif + pEnaVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pEnableVideoPortYUV422; + pGndVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pGroundVideoPortYUV422; + break; + +#ifdef TMFL_RGB_DDR_12BITS + case TMDL_HDMITX_VINMODE_RGB_DDR_12BITS: + pSwapTable = gtmdlHdmiTxDriverConfigTable[instance].pSwapTableRGB_DDR_12bits; + pMirrorTable = gtmdlHdmiTxDriverConfigTable[instance].pMirrorTableRGB_DDR_12bits; + pMux = >mdlHdmiTxDriverConfigTable[instance].pMux_RGB_DDR_12bits[0]; + pEnaVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pEnableVideoPortRGB_DDR_12bits; + pGndVideoPortTable = gtmdlHdmiTxDriverConfigTable[instance].pGroundVideoPortRGB_DDR_12bits; + break; +#endif + default: + break; + } + + /* Set the audio and video input port configuration */ + errCode = tmbslHdmiTxSetVideoPortConfig(instance, pEnaVideoPortTable, pGndVideoPortTable); + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode); + +#ifdef TMFL_RGB_DDR_12BITS + errCode = tmbslHdmiTxVideoInSetMapping(instance, pSwapTable, pMirrorTable, pMux); +#else + errCode = tmbslHdmiTxVideoInSetMapping(instance, pSwapTable, pMirrorTable); +#endif + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode); + + /* Set fine image position */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoInSetFine(instance, spSync, HDMITX_PIXTOGL_NO_ACTION) ) != TM_OK, errCode); + + /* Set input blanking */ + errCode = tmbslHdmiTxVideoInSetBlanking(instance, blankit, HDMITX_BLNKCODE_ALL_0); + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode); + + /* Configure video input options and control the upsampler */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoInSetConfig(instance, + (tmbslHdmiTxVinMode_t)videoInputConfig.mode, (tmbslHdmiTxVidFmt_t)videoOutputConfig.format, + (tmbslHdmiTx3DStructure_t)videoInputConfig.structure3D, pixelEdge, + (tmbslHdmiTxPixRate_t)videoInputConfig.pixelRate, HDMITX_UPSAMPLE_AUTO) ) != TM_OK, errCode); + + + /* Set input ouput - may give NOT_SUPPORTED error */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoSetInOut(instance, (tmbslHdmiTxVidFmt_t)videoInputConfig.format, + (tmbslHdmiTx3DStructure_t)videoInputConfig.structure3D, + HDMITX_SCAMODE_AUTO, (tmbslHdmiTxVidFmt_t)videoOutputConfig.format, + pixRepeat, HDMITX_MATMODE_AUTO, pathBits, (tmbslHdmiTxVQR_t) videoOutputConfig.dviVqr) ) != TM_OK, errCode); + + + /* Only set audio for HDMI, not DVI */ + if (sinkType == TMDL_HDMITX_SINK_HDMI) + { + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + /* Set audio parameters */ + RETIF( (errCode = tmdlHdmiTxSetAudioInput(instance, audioInputConfig, sinkType) ) != TM_OK, errCode) + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + } + + /* Output fine adjustment */ + pixRateSingleDouble = (tmbslHdmiTxPixRate_t)videoInputConfig.pixelRate; + if (videoInputConfig.pixelRate == HDMITX_PIXRATE_SINGLE_REPEATED) + { + pixRateSingleDouble = HDMITX_PIXRATE_SINGLE; + } + + + if ((videoInputConfig.structure3D != HDMITX_3D_FRAME_PACKING) && + dlHdmiTxGetReflineRefpix(videoInputConfig.format, videoInputConfig.mode, videoOutputConfig.format, + syncIn, (tmdlHdmiTxPixRate_t)pixRateSingleDouble, &uRefPix, &uRefLine, + &uScRefPix, &uScRefLine, &bVerified) > 0) + { + /* From 720p50/60 or 1080i50/60 up-scaling to 1080p50/60, when external sync, + toggleV, toggleH and toggleX need to be set to 0 */ + if (syncIn == EXT) + { + switch (videoInputConfig.format) + { + case TMDL_HDMITX_VFMT_04_1280x720p_60Hz: + case TMDL_HDMITX_VFMT_19_1280x720p_50Hz: + case TMDL_HDMITX_VFMT_05_1920x1080i_60Hz: + case TMDL_HDMITX_VFMT_20_1920x1080i_50Hz: + if ( (videoOutputConfig.format == TMDL_HDMITX_VFMT_16_1920x1080p_60Hz) + || (videoOutputConfig.format == TMDL_HDMITX_VFMT_31_1920x1080p_50Hz) ) + { + toggle = HDMITX_PIXTOGL_NO_ACTION; + } + break; + default: + toggle = HDMITX_PIXTOGL_ENABLE; + break; + } + } + + /* Combination found in table for scaler: configure input manually */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoInSetSyncManual(instance, + (tmbslHdmiTxSyncSource_t)videoInputConfig.syncSource, syncMethod, toggle, toggle, toggle, uRefPix, uRefLine) ) != TM_OK, errCode) + } + else + { + /* Not found so assume non-scaler and auto-configure input */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoInSetSyncAuto(instance, + (tmbslHdmiTxSyncSource_t)videoInputConfig.syncSource, (tmbslHdmiTxVidFmt_t)videoInputConfig.format, + (tmbslHdmiTxVinMode_t)videoInputConfig.mode, (tmbslHdmiTx3DStructure_t)videoInputConfig.structure3D)) != TM_OK, errCode) + } + + /* Only set infoframes for HDMI, not DVI */ + if (sinkType == TMDL_HDMITX_SINK_HDMI) + { + /* Set avi infoframe */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = dlHdmiTxSetVideoInfoframe(instance, videoOutputConfig.format, videoOutputConfig.mode) ) != TM_OK, + errCode) + } + + errCode = tmbslHdmiTxScalerGetMode(instance, + &scalerMode); + + /* Ignore scaler TMBSL_ERR_HDMI_NOT_SUPPORTED error */ + if ((errCode == TM_OK) && (scalerMode == HDMITX_SCAMODE_ON)) + { + /* Enable scaler mode */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxScalerInDisable(instance, + False) ) != TM_OK, errCode) + + /* Correction to interlace */ + topSel = HDMITX_TOPSEL_INTERNAL; + if ((videoOutputConfig.format == TMDL_HDMITX_VFMT_05_1920x1080i_60Hz) + || (videoOutputConfig.format == TMDL_HDMITX_VFMT_20_1920x1080i_50Hz)) + { + /* video input format is range-checked by tmbslHdmiTxVideoSetInOut above */ + vinFmtIndex = dlHdmiTxCalcVidFmtIndex(videoInputConfig.format); + if ((kVfmtToShortFmt_TV[vinFmtIndex] == TV_480p_60Hz) + || (kVfmtToShortFmt_TV[vinFmtIndex] == TV_576p_50Hz)) + { + /* Correct for 1080i output for p->i conversion only */ + topSel = HDMITX_TOPSEL_VRF; + } + } + + /* Set scaler field positions */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxScalerSetFieldOrder(instance, + HDMITX_INTEXT_NO_CHANGE, HDMITX_INTEXT_NO_CHANGE, topSel, HDMITX_TOPTGL_NO_CHANGE) ) != TM_OK, errCode) + + /* Scaler fine adjustment */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxScalerSetFine(instance, + uScRefPix, uScRefLine) ) != TM_OK, errCode) + + if ((videoOutputConfig.format == TMDL_HDMITX_VFMT_16_1920x1080p_60Hz) + || (videoOutputConfig.format == TMDL_HDMITX_VFMT_31_1920x1080p_50Hz)) + { + phasesH = HDMITX_H_PHASES_16; + } + else + { + phasesH = HDMITX_H_PHASES_15; + } + + /* Set scaler phase */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxScalerSetPhase(instance, + phasesH) ) != TM_OK, errCode) + + /* Set scaler latency */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxScalerSetLatency(instance, + 0x22) ) != TM_OK, errCode) + + /* Set scaler synchronisation option */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxScalerSetSync(instance, + syncMethod, HDMITX_VSONCE_EACH_FRAME) ) != TM_OK, errCode) + + /* With scaler, use Only Once setting for tmbslHdmiTxVideoOutSetSync */ + once = HDMITX_VSONCE_ONCE; + } + else + { + once = HDMITX_VSONCE_EACH_FRAME; + } + + /* Set video synchronisation */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxVideoOutSetSync(instance, + HDMITX_VSSRC_INTERNAL, HDMITX_VSSRC_INTERNAL, HDMITX_VSSRC_INTERNAL, + HDMITX_VSTGL_TABLE, once) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + instanceStatusInfoTx[instance].pColBarState->inOutFirstSetDone = True; + + /* Test if pattern is already on */ + if (instanceStatusInfoTx[instance].pColBarState->colorBarOn == True) + { + /* If pattern is On, apply new settings */ + instanceStatusInfoTx[instance].pColBarState->changeColorBarNow = True; + } + + return TM_OK; +} + +/*****************************************************************************/ +/** + \brief Configures audio input parameters : format, rate, etc. + This function is similar to tmdlHdmiTxSetInputOutput except that + video is not reconfigured. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param audioInputConfig Configuration of the input audio. + \param sinkType Type of sink connected to the output of the Tx. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetAudioInput +( + tmInstance_t instance, + tmdlHdmiTxAudioInConfig_t audioInputConfig, + tmdlHdmiTxSinkType_t sinkType +) +{ + tmErrorCode_t errCode; + tmdlHdmiTxVidFmtSpecs_t resolutionSpecs; /* Used to convert video format to video frequency */ + UInt8 layout; /* 0 or 1 */ + UInt8 aifChannelCountCode = 0; /* audio info frame channels */ + tmbslHdmiTxVfreq_t vOutFreq; /* Vertical output frequency */ + tmbslHdmiTxctsRef_t ctsRef; /* CTS ref source */ + UInt16 uCtsX; /* CtsX value */ + tmbslHdmiTxPktAif_t pktAif; /* Audio infoframe packet */ + Bool OBASupported; /* OBA supported or not */ + Bool DSTSupported; /* DST supported or not */ + Bool HBRSupported; /* HBR supporeted or not */ + UInt8 *pEnaAudioPortCfg; + UInt8 *pGndAudioPortCfg; + UInt8 *pEnaAudioClockPortCfg; + UInt8 *pGndAudioClockPortCfg; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the semaphore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Audio OBA support */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_AUDIO_OBA, &OBASupported) ) != TM_OK, errCode) + + /* Audio DST support */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_AUDIO_DST, &DSTSupported) ) != TM_OK, errCode) + + /* Audio HBR support */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_AUDIO_HBR, &HBRSupported) ) != TM_OK, errCode) + + /* Test if audio input format is supported */ + if ( ((audioInputConfig.format == TMDL_HDMITX_AFMT_OBA) && (OBASupported == False)) || + ((audioInputConfig.format == TMDL_HDMITX_AFMT_DST) && (DSTSupported == False)) || + ((audioInputConfig.format == TMDL_HDMITX_AFMT_HBR) && (HBRSupported == False)) ) + { + /* Release the semaphore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; + } + + if (sinkType == TMDL_HDMITX_SINK_EDID) + { + /* Change sink type with the currently defined in EDID */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetSinkType(instance, + (tmbslHdmiTxSinkType_t *)&sinkType) ) != TM_OK, errCode) + } + + if (sinkType == TMDL_HDMITX_SINK_HDMI) + { + /* Set audio layout */ + layout = 1; + if (audioInputConfig.channelAllocation == 0x00) { + layout = 0; + } + aifChannelCountCode = kChanAllocChanNum[audioInputConfig.channelAllocation] - 1; + + /* Port audio configuration */ + switch(audioInputConfig.format) + { + case TMDL_HDMITX_AFMT_SPDIF: + pEnaAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioPortSPDIF; + pGndAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioPortSPDIF; + pEnaAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioClockPortSPDIF; + pGndAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioClockPortSPDIF; + break; + + case TMDL_HDMITX_AFMT_I2S: + pEnaAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioClockPortI2S; + pGndAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioClockPortI2S; + + if(audioInputConfig.channelAllocation >= 1 ) /* For Multi channels */ + { + pEnaAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioPortI2S8C; + pGndAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioPortI2S8C; + } + else + { + pEnaAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioPortI2S; + pGndAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioPortI2S; + } + break; + + case TMDL_HDMITX_AFMT_OBA: + pEnaAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioPortOBA; + pGndAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioPortOBA; + pEnaAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioClockPortOBA; + pGndAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioClockPortOBA; + break; + + case TMDL_HDMITX_AFMT_DST: + pEnaAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioPortDST; + pGndAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioPortDST; + pEnaAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioClockPortDST; + pGndAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioClockPortDST; + break; + + case TMDL_HDMITX_AFMT_HBR: + pEnaAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioPortHBR; + pGndAudioPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioPortHBR; + pEnaAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pEnableAudioClockPortHBR; + pGndAudioClockPortCfg = gtmdlHdmiTxDriverConfigTable[instance].pGroundAudioClockPortHBR; + break; + + default: + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_BAD_PARAMETER; + } + + errCode = tmbslHdmiTxSetAudioPortConfig(instance, + pEnaAudioPortCfg, pGndAudioPortCfg); + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode) + + errCode = tmbslHdmiTxSetAudioClockPortConfig(instance, + pEnaAudioClockPortCfg, pGndAudioClockPortCfg); + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode != TM_OK) && (errCode != TMBSL_ERR_HDMI_NOT_SUPPORTED), errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioInSetConfig(instance, + (tmbslHdmiTxaFmt_t)audioInputConfig.format, (tmbslHdmiTxI2sFor_t)audioInputConfig.i2sFormat, + audioInputConfig.channelAllocation, HDMITX_CHAN_NO_CHANGE, HDMITX_CLKPOLDSD_NO_CHANGE, HDMITX_SWAPDSD_NO_CHANGE, + layout, HDMITX_LATENCY_CURRENT, (tmbslHdmiTxDstRate_t)audioInputConfig.dstRate) ) != TM_OK, errCode) + + /* Find output vertical frequency from output format */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmdlHdmiTxGetVideoFormatSpecs(instance, instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + &resolutionSpecs) ) != TM_OK, errCode) + vOutFreq = (tmbslHdmiTxVfreq_t)resolutionSpecs.vfrequency; + + if ((audioInputConfig.format == TMDL_HDMITX_AFMT_SPDIF) + || (audioInputConfig.format == TMDL_HDMITX_AFMT_OBA)) + { + ctsRef = HDMITX_CTSREF_FS64SPDIF; + uCtsX = HDMITX_CTSX_64; + } + else /* I2S */ + { + ctsRef = HDMITX_CTSREF_ACLK; + if (audioInputConfig.i2sQualifier == TMDL_HDMITX_I2SQ_32BITS) + { + uCtsX = HDMITX_CTSX_64; + } + else + { + uCtsX = HDMITX_CTSX_32; + } + } + + /* Set the Clock Time Stamp generator in HDMI mode only */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioInSetCts(instance, + ctsRef, (tmbslHdmiTxafs_t)audioInputConfig.rate, (tmbslHdmiTxVidFmt_t)instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + vOutFreq, HDMITX_CTS_AUTO, uCtsX, HDMITX_CTSK_USE_CTSX, HDMITX_CTSMTS_USE_CTSX, + (tmbslHdmiTxDstRate_t)audioInputConfig.dstRate) ) != TM_OK, errCode) + + /* Set Channel Status registers + No need to call tmbslTDA9984AudioOutSetChanStatusMapping, since default Byte 2 + values of "Do not take into account" are adequate */ + + + if (audioInputConfig.format != TMDL_HDMITX_AFMT_SPDIF) /* channel status automatically copied from SPDIF*/ + { + + if (audioInputConfig.format != TMDL_HDMITX_AFMT_HBR) { + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioOutSetChanStatus(instance, + (tmbslHdmiTxAudioData_t)audioInputConfig.channelStatus.PcmIdentification, + (tmbslHdmiTxCSformatInfo_t)audioInputConfig.channelStatus.FormatInfo, + (tmbslHdmiTxCScopyright_t)audioInputConfig.channelStatus.CopyrightInfo, + audioInputConfig.channelStatus.categoryCode, + (tmbslHdmiTxafs_t)audioInputConfig.rate, + (tmbslHdmiTxCSclkAcc_t)audioInputConfig.channelStatus.clockAccuracy, + (tmbslHdmiTxCSmaxWordLength_t)audioInputConfig.channelStatus.maxWordLength, + (tmbslHdmiTxCSwordLength_t)audioInputConfig.channelStatus.wordLength, + (tmbslHdmiTxCSorigAfs_t)audioInputConfig.channelStatus.origSampleFreq))!= TM_OK, errCode) + } + else { + + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioOutSetChanStatus(instance, + (tmbslHdmiTxAudioData_t)audioInputConfig.channelStatus.PcmIdentification, + (tmbslHdmiTxCSformatInfo_t)audioInputConfig.channelStatus.FormatInfo, + (tmbslHdmiTxCScopyright_t)audioInputConfig.channelStatus.CopyrightInfo, + audioInputConfig.channelStatus.categoryCode, + HDMITX_AFS_768K, + (tmbslHdmiTxCSclkAcc_t)audioInputConfig.channelStatus.clockAccuracy, + (tmbslHdmiTxCSmaxWordLength_t)audioInputConfig.channelStatus.maxWordLength, + (tmbslHdmiTxCSwordLength_t)audioInputConfig.channelStatus.wordLength, + (tmbslHdmiTxCSorigAfs_t)audioInputConfig.channelStatus.origSampleFreq))!= TM_OK, errCode) + + + } + + } + + + /* Set reset_fifo to 1 */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioOutSetMute(instance, + HDMITX_AMUTE_ON) ) != TM_OK, errCode) + + /* UN Mute audio only if previously not muted */ + if (instanceStatusInfoTx[instance].pAudioInfo->audioMuteState == False) { + + /* Wait for 20 ms */ + RETIF_SEM(dlHdmiTxItSemaphore[instance],(errCode = tmdlHdmiTxIWWait(20) ) != TM_OK, errCode) + /* Set reset_fifo to 0 */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioOutSetMute(instance, + HDMITX_AMUTE_OFF) ) != TM_OK, errCode) + + } + + + /* Set audio infoframe */ + pktAif.ChannelCount = aifChannelCountCode; + pktAif.CodingType = 0; /* refer to stream header */ + pktAif.SampleSize = 0; /* refer to stream header */ + pktAif.ChannelAlloc = audioInputConfig.channelAllocation; + pktAif.LevelShift = 0; /* 0dB level shift */ + pktAif.DownMixInhibit = 0; /* down-mix stereo permitted */ + pktAif.SampleFreq = AIF_SF_REFER_TO_STREAM_HEADER; /* refer to stream header */ + + /* SampleFreq parameter need to be set for OBA and DST audio stream */ + if ( (audioInputConfig.format == TMDL_HDMITX_AFMT_OBA) || + (audioInputConfig.format == TMDL_HDMITX_AFMT_DST) ) + { + switch (audioInputConfig.rate) + { + case TMDL_HDMITX_AFS_32K: + pktAif.SampleFreq = AIF_SF_32K; /* see table 18 of CEA-861 */ + break; + case TMDL_HDMITX_AFS_44K: + pktAif.SampleFreq = AIF_SF_44K; + break; + case TMDL_HDMITX_AFS_48K: + pktAif.SampleFreq = AIF_SF_48K; + break; + case TMDL_HDMITX_AFS_88K: + pktAif.SampleFreq = AIF_SF_88K; + break; + case TMDL_HDMITX_AFS_96K: + pktAif.SampleFreq = AIF_SF_96K; + break; + case TMDL_HDMITX_AFS_176K: + pktAif.SampleFreq = AIF_SF_176K; + break; + case TMDL_HDMITX_AFS_192K: + pktAif.SampleFreq = AIF_SF_192K; + break; + default: + pktAif.SampleFreq = AIF_SF_REFER_TO_STREAM_HEADER; /* refer to stream header */ + break; + } + } + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetAudioInfoframe(instance, + &pktAif, True) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of AVI infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pAviIfData Pointer to the structure containing AVI infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetVideoInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxAviIfData_t *pAviIfData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if AviIfData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pAviIfData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + errCode = dlHdmiTxSetRawVideoInfoframe(instance, pAviIfData, enable); + } + else + { + errCode = dlHdmiTxSetRawVideoInfoframe(instance, Null, enable); + } + + /* Ignore infoframe interlock in DVI mode */ + if (errCode == TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + { + errCode = TM_OK; + } + + RETIF_SEM(dlHdmiTxItSemaphore[instance], errCode != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of AUD infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pAudIfData Pointer to the structure containing AUD infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetAudioInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxAudIfData_t *pAudIfData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if AudIfData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pAudIfData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetAudioInfoframe(instance, + (tmbslHdmiTxPktAif_t *)pAudIfData, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetAudioInfoframe(instance, + Null, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of the audio content protection packet to be + sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pAcpPktData Pointer to the structure containing ACP infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetACPPacket +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxAcpPktData_t *pAcpPktData +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxPkt_t pkt; + UInt8 i; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if AcpPktData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pAcpPktData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + switch (pAcpPktData->acpType) + { + /* Make sure bytes reserved are 0 */ + case 0 : /* Generic audio */ + for (i=0; i<28; i++) { pkt.dataByte[i] = 0; } + break; + + case 1 : /* IEC 60958 identified audio */ + for (i=0; i<28; i++) { pkt.dataByte[i] = 0; } + break; + + case 2 : /* DVD Audio */ + for (i=0; i<2; i++) { pkt.dataByte[i] = pAcpPktData->acpData[i]; } + for (i=2; i<28; i++) { pkt.dataByte[i] = 0; } + break; + + case 3 : /* SuperAudio CD */ + for (i=0; i<17; i++) { pkt.dataByte[i] = pAcpPktData->acpData[i]; } + for (i=17; i<28; i++) { pkt.dataByte[i] = 0; } + break; + + default : + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + return TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS; + } + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetAcp(instance, + &pkt, 28, pAcpPktData->acpType, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetAcp(instance, + Null, 0, 0, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of the General Control packet to be sent by Tx + device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pGcpPktData Pointer to the structure containing GCP packet parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetGeneralControlPacket +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxGcpPktData_t *pGcpPktData +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxaMute_t aMute; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if GcpPktData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pGcpPktData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + if(pGcpPktData->avMute == False) + { + aMute = HDMITX_AMUTE_OFF; + } + else + { + aMute = HDMITX_AMUTE_ON; + } + + /* Set contents of general control packet & enable/disable packet insertion */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetGeneralCntrl(instance, + &aMute, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetGeneralCntrl(instance, + Null, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of ISRC1 packet to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pIsrc1PktData Pointer to the structure containing GCP packet parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetISRC1Packet +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxIsrc1PktData_t *pIsrc1PktData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if Isrc1PktData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pIsrc1PktData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetIsrc1(instance, + (tmbslHdmiTxPkt_t *)pIsrc1PktData->UPC_EAN_ISRC, 16, pIsrc1PktData->isrcCont, + pIsrc1PktData->isrcValid, pIsrc1PktData->isrcStatus, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetIsrc1(instance, + Null, 0, 0, 0, 0, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of ISRC2 packet to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pIsrc2PktData Pointer to the structure containing GCP packet parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetISRC2Packet +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxIsrc2PktData_t *pIsrc2PktData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if Isrc1PktData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pIsrc2PktData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetIsrc2(instance, + (tmbslHdmiTxPkt_t *)pIsrc2PktData->UPC_EAN_ISRC, 16, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetIsrc2(instance, + Null, 0, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of MPS infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pMpsIfData Pointer to the structure containing MPS infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetMPSInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxMpsIfData_t *pMpsIfData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if MpsIfData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pMpsIfData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetMpegInfoframe(instance, + (tmbslHdmiTxPktMpeg_t *)pMpsIfData, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetMpegInfoframe(instance, + Null, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of SPD infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pSpdIfData Pointer to the structure containing SPD infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetSpdInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxSpdIfData_t *pSpdIfData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if SpdIfData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pSpdIfData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetSpdInfoframe(instance, + (tmbslHdmiTxPktSpd_t *)pSpdIfData, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetSpdInfoframe(instance, + Null, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Defines the content of VS infoframe to be sent by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable infoframe insertion. + \param pVsIfData Pointer to the structure containing VS infoframe + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetVsInfoframe +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxVsPktData_t *pVsIfData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + if (enable == True) + { + /* Check if VsIfData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pVsIfData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetVsInfoframe(instance, + (tmbslHdmiTxPkt_t *)pVsIfData->vsData, HDMITX_PKT_DATA_BYTE_CNT-1, pVsIfData->version, enable) ) != TM_OK, errCode) + } + else + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetVsInfoframe(instance, + Null, 0, pVsIfData->version, enable) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Enables/disables NULL packet sending (only used for debug purpose). + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable packet insertion. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxDebugSetNullPacket +( + tmInstance_t instance, + Bool enable +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetNullInsert(instance, + enable) ) != TM_OK, errCode) + + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Send one single NULL packet (only used for debug purpose). + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxDebugSetSingleNullPacket +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSetNullSingle(instance) ) + != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Set the audio output mute status. This function can be used to mute + audio output, without muting video. This can be typically used when + reconfiguring the audio HW after a sample rate change. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param muteStatus Mute status (True/False). + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetAudioMute +( + tmInstance_t instance, + Bool audioMute +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Mute or Un-mute the audio output */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioOutSetMute(instance, + (tmbslHdmiTxaMute_t)audioMute) ) != TM_OK, errCode) + + /* Store current audio mute status */ + instanceStatusInfoTx[instance].pAudioInfo->audioMuteState = audioMute; + + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Reset audio CTS. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxResetAudioCts +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Reset the audio Clock Time Stamp generator */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxAudioInResetCts(instance) + ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Retrieve EDID Status from driver. + This function is synchronous. + This function is ISR friendly. + + \param instance Instance identifier. + \param pEdidStatus Pointer to the array that will receive the EDID Status. + \param pEdidBlkCount Pointer to the integer that will receive the number of + read EDID block. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidStatus +( + tmInstance_t instance, + tmdlHdmiTxEdidStatus_t *pEdidStatus, + UInt8 *pEdidBlkCount +) +{ + tmErrorCode_t errCode; + UInt8 edidStatus; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if EdidStatus and pReadBytesNumber pointers are Null */ + RETIF(pEdidStatus == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pEdidBlkCount == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Get the EDID status from BSL driver */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetStatus(instance, + (UInt8 *)&edidStatus) ) != TM_OK, errCode) + + if (edidStatus >= TMDL_HDMITX_EDID_STATUS_INVALID) + { + *pEdidStatus = TMDL_HDMITX_EDID_STATUS_INVALID; + } + else + { + *pEdidStatus = (tmdlHdmiTxEdidStatus_t)edidStatus; + } + + if ((*pEdidStatus == TMDL_HDMITX_EDID_READ) || + (*pEdidStatus == TMDL_HDMITX_EDID_ERROR_CHK)) + { + /* Get the read EDID block number from BSL driver */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetBlockCount(instance, + pEdidBlkCount) ) != TM_OK, errCode) + } + + if (errCode != TM_OK) + { + /* Error during read EDID, number of read block is 0 */ + *pEdidBlkCount = 0; + + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + + return errCode; + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Retrieves audio descriptors from receiver's EDID. This function + parses the EDID of Tx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + + \param instance Instance identifier. + \param pAudioDescs Pointer to the array that will receive audio + descriptors. + \param maxAudioDescs Size of the array. + \param pWrittenAudioDescs Pointer to the integer that will receive the actual + number of written descriptors. + \param pAudioFlags Pointer to the byte to receive Audio Capabilities Flags. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidAudioCaps +( + tmInstance_t instance, + tmdlHdmiTxEdidAudioDesc_t *pAudioDescs, + UInt maxAudioDescs, + UInt *pWrittenAudioDescs, + UInt8 *pAudioFlags +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxEdidSad_t edidSad[HDMI_TX_SAD_MAX_CNT]; + UInt i; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if AudioDescs, WrittenAudioDescs and AudioFlags pointers are Null */ + RETIF(pAudioDescs == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pWrittenAudioDescs == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pAudioFlags == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Get video capabilities from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetAudioCapabilities(instance, + edidSad, maxAudioDescs, pWrittenAudioDescs, pAudioFlags) ) != TM_OK, errCode) + + for (i=0; i<*pWrittenAudioDescs; i++) + { + pAudioDescs[i].format = (edidSad[i].ModeChans & 0x78) >> 3; /* Bits[6:3]: EIA/CEA861 mode */ + pAudioDescs[i].channels = edidSad[i].ModeChans & 0x07; /* Bits[2:0]: channels */ + pAudioDescs[i].supportedFreqs = edidSad[i].Freqs; /* Supported frequencies */ + + if (pAudioDescs[i].format == 1) /* LPCM format */ + { + pAudioDescs[i].supportedRes = edidSad[i].Byte3 & 0x07; + pAudioDescs[i].maxBitrate = 0x00; + } + else if ( (pAudioDescs[i].format >= 2) && /* Compressed format */ + (pAudioDescs[i].format <= 8) ) + { + pAudioDescs[i].supportedRes = 0x00; + pAudioDescs[i].maxBitrate = edidSad[i].Byte3; + } + else + { + pAudioDescs[i].supportedRes = 0x00; + pAudioDescs[i].maxBitrate = 0x00; + } + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Retrieves supported video formats (short descriptors) from + receiver's EDID. This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pVideoDesc Pointer to the structure that will receive short + video descriptors. + \param maxVideoFormats Size of the array. + \param pWrittenVideoFormats Pointer to the integer that will receive the actual + number of written descriptors. + \param pVideoFlags Pointer to the byte to receive Video Capability Flags. + b7: underscan supported + b6: YCbCr 4:4:4 supported + b5: YCbCr 4:2:2 supported + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidVideoCaps +( + tmInstance_t instance, + tmdlHdmiTxShortVidDesc_t *pVideoDesc, + UInt maxVideoFormats, + UInt *pWrittenVideoFormats, + UInt8 *pVideoFlags +) +{ + tmErrorCode_t errCode; + UInt8 edidVFmtsBuffer[HDMI_TX_SVD_MAX_CNT]; + tmdlHdmiTxEdidVideoTimings_t edidDTDBuffer[NUMBER_DTD_STORED]; + UInt8 i; + UInt8 writtenDTD = 0; + UInt8 dtdCounter = 0; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if Videoformats, WrittenVideoFormats and VideoFlags pointers are Null */ + RETIF(pVideoDesc == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pWrittenVideoFormats == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pVideoFlags == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(maxVideoFormats == 0, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Get video capabilities from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetVideoCapabilities(instance, + edidVFmtsBuffer, HDMI_TX_SVD_MAX_CNT, pWrittenVideoFormats, pVideoFlags) ) != TM_OK, errCode) + + /* Get detailled descriptors from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = dlHdmiTxEdidGetDTD(instance, edidDTDBuffer, NUMBER_DTD_STORED, &writtenDTD) ) != TM_OK, errCode) + + dtdCounter = 0; + if (writtenDTD > 0) + { + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Write first DTD in first position of table video desc */ + pVideoDesc[0].videoFormat = tmdlHdmiTxConvertDTDtoCEA(instance, &(edidDTDBuffer[dtdCounter])); + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + dtdCounter++; + + pVideoDesc[0].nativeVideoFormat = False; + } + + /* Start with i = 1 keep the first position for the first DTD */ + for (i = dtdCounter; i< maxVideoFormats ; i++) + { + if ((i < (HDMI_TX_SVD_MAX_CNT + dtdCounter)) && (i < ((*pWrittenVideoFormats) + dtdCounter))) + { + /* Store SVD */ + pVideoDesc[i].videoFormat = (tmdlHdmiTxVidFmt_t)((Int)edidVFmtsBuffer[i - dtdCounter] & 0x7F); + /* if bit 7 is true, it means that is a preferred video format */ + if ((edidVFmtsBuffer[i - dtdCounter] & 0x80) == 0x80) + { + pVideoDesc[i].nativeVideoFormat = True; + } + else + { + pVideoDesc[i].nativeVideoFormat = False; + } + } + else + { + if ((dtdCounter < NUMBER_DTD_STORED) && (dtdCounter < writtenDTD)) + { + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + /* Store DTD except first DTD */ + pVideoDesc[i].videoFormat = tmdlHdmiTxConvertDTDtoCEA(instance, &(edidDTDBuffer[dtdCounter])); + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + dtdCounter++; + + pVideoDesc[i].nativeVideoFormat = False; + } + else + { + /* VGA is always supported */ + pVideoDesc[i].videoFormat = TMDL_HDMITX_VFMT_01_640x480p_60Hz; + pVideoDesc[i].nativeVideoFormat = False; + /* Last format supported exit from loop for */ + break; + } + } + } + + *pWrittenVideoFormats = *pWrittenVideoFormats + dtdCounter + 1; /* + 1 for VGA format */ + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Retrieves supported video formats (short descriptors) from + receiver's EDID. This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pNativeVideoFormat Pointer to the array that will receive video + timing descriptor. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidVideoPreferred +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pNativeVideoFormat +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if NativeVideoFormat pointer is Null */ + RETIF(pNativeVideoFormat == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Get preferred video format from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetVideoPreferred(instance, + (tmbslHdmiTxEdidDtd_t *)pNativeVideoFormat) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/*****************************************************************************/ +/** + \brief Retrieves supported detailled video descriptors from + receiver's EDID. This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pDTDescriptors Pointer to the array that will receive detailled + timing descriptors. + \param maxDTDesc Size of the array. + \param pWrittenDesc Pointer to the integer that will receive the actual + number of written descriptors. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidDetailledTimingDescriptors +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + UInt8 maxDTDesc, + UInt8 *pWrittenDTDesc +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if DTDescriptors, WrittenDTDesc pointers are Null */ + RETIF(pDTDescriptors == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pWrittenDTDesc == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Get detailled descriptors from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = dlHdmiTxEdidGetDTD(instance, pDTDescriptors, maxDTDesc, pWrittenDTDesc) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/*****************************************************************************/ +/** + \brief Retrieves supported monitor descriptor from receiver's EDID. + This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pEdidFirstMD Pointer to the array that will receive the first monitor + descriptors. + \param pEdidSecondMD Pointer to the array that will receive the second monitor + descriptors. + \param pEdidOtherMD Pointer to the array that will receive the other monitor + descriptors. + \param maxOtherMD Size of the array. + \param pWrittenOtherMD Pointer to the integer that will receive the actual + number of written descriptors. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidMonitorDescriptors +( + tmInstance_t instance, + tmdlHdmiTxEdidFirstMD_t *pEdidFirstMD, + tmdlHdmiTxEdidSecondMD_t *pEdidSecondMD, + tmdlHdmiTxEdidOtherMD_t *pEdidOtherMD, + UInt8 maxOtherMD, + UInt8 *pWrittenOtherMD +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if DTDescriptors, WrittenDTDesc pointers are Null */ + RETIF(pEdidFirstMD == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pEdidSecondMD == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pEdidOtherMD == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Get monitor descriptors from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetMonitorDescriptors(instance, + (tmbslHdmiTxEdidFirstMD_t *)pEdidFirstMD, (tmbslHdmiTxEdidSecondMD_t *)pEdidSecondMD, + (tmbslHdmiTxEdidOtherMD_t *)pEdidOtherMD, maxOtherMD, pWrittenOtherMD) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/*****************************************************************************/ +/** + \brief Retrieves TV picture ratio from receiver's EDID. + This function parses the EDID of Rx device to get + the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pEdidTvPictureRatio Pointer to the array that will receive the TV picture + ratio. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidTVPictureRatio +( + tmInstance_t instance, + tmdlHdmiTxPictAspectRatio_t *pEdidTvPictureRatio +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxEdidBDParam_t edidBDParam; + UInt16 horizontalSize; + UInt16 verticalSize; + tmbslHdmiTxEdidDtd_t edidDTDBuffer; + UInt8 writtenDTD = 0; + Bool bDataAvailable = False; /* Data available in EDID for calcul TV picture ratio */ + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if DTDescriptors, WrittenDTDesc pointers are Null */ + RETIF(pEdidTvPictureRatio == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Get Basic Display Parameter from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetBasicDisplayParam(instance, + &edidBDParam) ) != TM_OK, errCode) + + horizontalSize = (UInt16)edidBDParam.uMaxHorizontalSize; + verticalSize = (UInt16)edidBDParam.uMaxVerticalSize; + + if ((horizontalSize == 0) && (verticalSize == 0)) + { + /* Get Basic Display Parameter from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetDetailedTimingDescriptors + (instance, &edidDTDBuffer, 1, &writtenDTD) ) != TM_OK, errCode); + + if (writtenDTD == 1) + { + horizontalSize = edidDTDBuffer.uHImageSize; + verticalSize = edidDTDBuffer.uVImageSize; + bDataAvailable = True; + } + else + { + *pEdidTvPictureRatio = TMDL_HDMITX_P_ASPECT_RATIO_UNDEFINED; + } + } + else + { + bDataAvailable = True; + } + + if (bDataAvailable == True) + { + *pEdidTvPictureRatio = dlHdmiTxCalcAspectRatio(horizontalSize, verticalSize); + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; + + +} + +/****************************************************************************** + \brief Retrieves the sink type from receiver's EDID (HDMI or DVI). This + function parses the EDID of Rx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pSinkType Pointer to the array that will receive sink type. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidSinkType +( + tmInstance_t instance, + tmdlHdmiTxSinkType_t *pSinkType +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if SinkType pointer is Null */ + RETIF(pSinkType == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Read the source address from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetSinkType(instance, + (tmbslHdmiTxSinkType_t *)pSinkType) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Retrieves source address from receivers's EDID. This + function parses the EDID of Rx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pSourceAddress Pointer to the integer that will receive the EDID source + address. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidSourceAddress +( + tmInstance_t instance, + UInt16 *pSourceAddress +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if SourceAddress pointer is Null */ + RETIF(pSourceAddress == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Read the source address from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetSourceAddress(instance, + pSourceAddress) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief Retreives KSV list received by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pKsv Pointer to the array that will receive the KSV list. + \param maxKsv Maximum number of KSV that the array can store. + \param pWrittenKsv Actual number of KSV written into the array. + \param pDepth Connection tree depth returned with KSV list. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetKsvList +( + tmInstance_t instance, + UInt8 *pKsv, + UInt8 maxKsv, + UInt8 *pWrittenKsv, + UInt8 *pDepth, + Bool *pMaxCascExd, + Bool *pMaxDevsExd +) +{ + tmErrorCode_t errCode; +#ifndef NO_HDCP + UInt16 i,j; +#endif + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if pDepth, Ksv and WrittenKsv pointers are Null */ + RETIF(pKsv == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pWrittenKsv == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pDepth == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pMaxCascExd == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pMaxDevsExd == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Maximum Ksv is HDMITX_KSV_LIST_MAX_DEVICES, 128 devices */ + RETIF_BADPARAM(maxKsv > HDMITX_KSV_LIST_MAX_DEVICES) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Make sure that *pWrittenKsv is 0 */ + *pWrittenKsv = 0; + + /* Make sure that *pDepth is 0 */ + *pDepth = 0; + +#ifndef NO_HDCP + + *pMaxCascExd = hdcpInfoListTx[instance].hdcpMaxCascExceeded; + *pMaxDevsExd = hdcpInfoListTx[instance].hdcpMaxDevsExceeded; + + + /* Copy the bKsv */ + if (maxKsv) { + + for (j=0; j<5 ;j++) { + pKsv[j] = hdcpInfoListTx[instance].hdcpBksv[4-j]; + } + *pWrittenKsv = *pWrittenKsv + 1; + + } /* maxKsv */ + + + /* Copy the Ksv list */ + for (i=1; i <= hdcpInfoListTx[instance].hdcpKsvDevices; i++) + { + if (i < maxKsv) + { + for (j=0; j<5 ;j++) + { + pKsv[(5*i)+j] = hdcpInfoListTx[instance].hdcpKsvList[(5*(i-1))+j]; + } + *pWrittenKsv = *pWrittenKsv + 1; + } + } + + *pDepth = hdcpInfoListTx[instance].hdcpDeviceDepth; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +#else + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; +#endif /* NO_HDCP */ +} +#ifdef HDMI_TX_REPEATER_ISR_MODE +/****************************************************************************** + \brief Retreives HDCP depth received by Tx device. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pDepth Connection tree depth returned with KSV list. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetDepth +( + tmInstance_t instance, + UInt8 *pDepth +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if pDepth, is Null */ + RETIF(pDepth == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Make sure that *pDepth is 0 */ + *pDepth = 0; + +#ifndef NO_HDCP + + + *pDepth = hdcpInfoListTx[instance].hdcpDeviceDepth; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +#else + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief Generate SHA_1 interrupt if not occured. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGeneSHA_1_IT +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + dlHdmiTxHandleSHA_1(instance); + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} +#endif /* HDMI_TX_REPEATER_ISR_MODE */ +/****************************************************************************** + \brief Enable/Disable HDCP encryption. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param hdcpEnable HDCP On/Off (true = On, False = Off). + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN: the resolution is unknown + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetHdcp +( + tmInstance_t instance, + Bool hdcpEnable +) +{ + tmErrorCode_t errCode; +#ifndef NO_HDCP + tmdlHdmiTxVidFmtSpecs_t resolutionSpecs; + tmbslHdmiTxVfreq_t voutFreq; + tmbslHdmiTxVidFmt_t voutFmt; + tmbslHdmiTxHdcpTxMode_t txMode; + tmbslHdmiTxHdcpOptions_t options; + UInt8 slaveAddress; + UInt16 i; +#endif + tmbslHdmiTxRxSense_t rxSenseStatus; /* Rx Sense status */ + tmbslHdmiTxHotPlug_t hpdStatus; /* HPD status */ + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Hdcp is not supported if keySeed is null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + gtmdlHdmiTxDriverConfigTable[instance].keySeed == HDCP_SEED_NULL, TMDL_ERR_DLHDMITX_NOT_SUPPORTED) + + /* Read rxSenseStatus and hpdStatus to authorize HDCP only if active */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxRxSenseGetStatus(instance, + &rxSenseStatus,False) ) != TM_OK, errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHotPlugGetStatus(instance, + &hpdStatus,False) ) != TM_OK, errCode) + +#ifndef NO_HDCP + if (hdcpEnable == True) /* HDCP ON */ + { + if ( (rxSenseStatus == HDMITX_RX_SENSE_ACTIVE) && (hpdStatus == HDMITX_HOTPLUG_ACTIVE) ) + { + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + tmbslHdmiTxHdcpPowerDown(instance,False); +#endif + /* Reset HDCP DevLib data to ensure that new values are used */ + hdcpInfoListTx[instance].hdcpCheckState = TMDL_HDMITX_HDCP_CHECK_IN_PROGRESS; + hdcpInfoListTx[instance].hdcpErrorState = 0; + hdcpInfoListTx[instance].hdcpKsvDevices = 0; + hdcpInfoListTx[instance].bKsvSecure = True; + for(i=0; ivideoOutConfig.format; + + /* Find output vertical frequency from output format */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmdlHdmiTxGetVideoFormatSpecs(instance, (tmdlHdmiTxVidFmt_t)voutFmt, &resolutionSpecs) ) != TM_OK, errCode) + voutFreq = (tmbslHdmiTxVfreq_t)resolutionSpecs.vfrequency; + + /* Configure HDCP */ + + /* HDCP DDC Slave address */ + slaveAddress = HDMITX_HDCP_SLAVE_PRIMARY; + + /* Top level or repeater HDCP mode */ + if (unitTableTx[instance].repeaterEnable == True) + { + txMode = HDMITX_HDCP_TXMODE_REPEATER; + } + else + { + txMode = HDMITX_HDCP_TXMODE_TOP_LEVEL; + } + + instanceStatusInfoTx[instance].pColBarState->changeColorBarNow = True; + instanceStatusInfoTx[instance].pColBarState->colorBarOn = True; + dlHdmiTxCheckColorBar(instance); + + /* HDCP options */ + options = (tmbslHdmiTxHdcpOptions_t)unitTableTx[instance].hdcpOptions; + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHdcpConfigure(instance, + slaveAddress, txMode, options, HDCP_CHECK_INTERVAL_MS, HDCP_NUM_CHECKS) ) != TM_OK, errCode) + + /* Start HDCP */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHdcpInit(instance, + voutFmt, voutFreq) ) != TM_OK, errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHdcpRun(instance) + ) != TM_OK, errCode) + + unitTableTx[instance].hdcpEnable = True; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return errCode; + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_INVALID_STATE; + } + else /* HDCP OFF */ + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHdcpStop(instance) + ) != TM_OK, errCode) + + unitTableTx[instance].hdcpEnable = False; + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_HDCP_INACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_HDCP_INACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode); + +#ifdef TMFL_HDCP_OPTIMIZED_POWER + tmbslHdmiTxHdcpPowerDown(instance,True); +#endif + return TM_OK; + } +#else + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief Get the driver HDCP state. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pHdcpCheckState Pointer to the integer that will receive the HDCP check state. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetHdcpState +( + tmInstance_t instance, + tmdlHdmiTxHdcpCheck_t *pHdcpCheckState +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check if HdcpCheckState pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pHdcpCheckState == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + +#ifndef NO_HDCP + /* Result of tmbslHdmiTxHdcpCheck */ + *pHdcpCheckState = hdcpInfoListTx[instance].hdcpCheckState; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +#else + *pHdcpCheckState = TMDL_HDMITX_HDCP_CHECK_NOT_STARTED; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief Check the result of an HDCP encryption attempt, called at + intervals (set by timeSinceLastCall) after tmdlHdmiTxSetHdcp(true). + This API must be used only in case of No Operating System. if OS, + this is manage internally of this device library. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param timeSinceLastCall Time passed in milliseconds since last call, + must be shorter than 600 ms. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_NOT_SUPPORTED: device does not support HDCP + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_READ: failed when reading the I2C bus + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing the I2C bus + - TMBSL_ERR_HDMI_NOT_SUPPORTED: device does not support HDCP + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxHdcpCheck +( + tmInstance_t instance, + UInt16 timeSinceLastCall +) +{ + tmErrorCode_t errCode; + Bool featureSupported; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHwGetCapabilities(instance, + HDMITX_FEATURE_HW_HDCP, &featureSupported) ) != TM_OK, errCode) + +#ifndef NO_HDCP + dlHdmiTxCheckColorBar(instance); + dlHdmiTxCheckHdcpColorBar(instance); + + if (featureSupported == True) + { + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxHdcpCheck(instance, + timeSinceLastCall, (tmbslHdmiTxHdcpCheck_t *)&(hdcpInfoListTx[instance].hdcpCheckState)) ) != TM_OK, errCode) + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +#else + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TMDL_ERR_DLHDMITX_NOT_SUPPORTED; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief This function loads a gamut metadata packet into the HW. HW will + actually send it at the beginning of next VS, during the vertical + blanking. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/disable gamut metadata packet insertion. + \param pGamutData Pointer to the structure containing gamut metadata + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetGamutPacket +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxGamutData_t *pGamutData +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxPktGamut_t pkt; + UInt8 i; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + if (enable == True) + { + /* Check if GamutData pointer is Null */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], pGamutData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Fill data */ + pkt.HB[0] = 0x0A; + + pkt.HB[1] = 0x00; + pkt.HB[1] = (UInt8)(pkt.HB[1] | ((pGamutData->nextField & 0x01) << 7)); + pkt.HB[1] |= (pGamutData->GBD_Profile & 0x07) << 4; + pkt.HB[1] |= (pGamutData->affectedGamutSeqNum & 0x0F); + + pkt.HB[2] = 0x00; + pkt.HB[2] = (UInt8)(pkt.HB[2] | ((pGamutData->noCurrentGBD & 0x01) << 7)); + pkt.HB[2] |= (pGamutData->packetSequence & 0x03) << 4; + pkt.HB[2] |= (pGamutData->currentGamutSeqNum & 0x0F); + + for(i=0; i<28; i++) + { + pkt.PB[i] = pGamutData->payload[i]; + } + + /* Store GBD color space */ + if ( ((pGamutData->payload[0]) & 0x03) == 2 ) + { + instanceStatusInfoTx[instance].pGamutState->wideGamutColorSpace = TMDL_HDMITX_EXT_COLORIMETRY_XVYCC709; + } + else + { + instanceStatusInfoTx[instance].pGamutState->wideGamutColorSpace = TMDL_HDMITX_EXT_COLORIMETRY_XVYCC601; + } + + /* Fill Gamut metadata packet */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktFillGamut(instance, + &pkt, instanceStatusInfoTx[instance].pGamutState->gamutBufNum) ) != TM_OK, errCode) + + /* Enable Gamut metadata transmission */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSendGamut(instance, + instanceStatusInfoTx[instance].pGamutState->gamutBufNum, enable) ) != TM_OK, errCode) + + /* Use next buffer for next time */ + if (instanceStatusInfoTx[instance].pGamutState->gamutBufNum == 0) + { + instanceStatusInfoTx[instance].pGamutState->gamutBufNum = 1; + } + else + { + instanceStatusInfoTx[instance].pGamutState->gamutBufNum = 0; + } + } + else + { + /* Disable Gamut metadata transmission */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxPktSendGamut(instance, + 0, enable) ) != TM_OK, errCode) + } + + /* Store gamut status */ + instanceStatusInfoTx[instance].pGamutState->gamutOn = enable; + if(enable) instanceStatusInfoTx[instance].pGamutState->extColOn = False; + + /* Set avi infoframe */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = dlHdmiTxSetVideoInfoframe(instance, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief This function set the extended colorimetry with one of the following + extended colorimetries(bits EC2-0): xvYCC601, xvYCC709, sYCC601, + AdobeYCC601, AdobeRGB. When the parameter extendedColorimetry is + xvYCC601 or xvYCC70, this function calls the API tmdlHdmiTxSetGamutPacket + to send Gamut Packet Data that does not exist for all other types of + extended colorimetries for which pointer pGamutData can be set to NULL. + This function also allows to set YCC Quantization Range (YQ1-0) + + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param enable Enable/Disable extended colorimetry. + \param extendedColorimetry value of the extended colorimetry (bits EC2 EC1 EC0). + \param yccQR YCC quantisation range + \param pGamutData Pointer to the structure containing gamut metadata + parameters. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter was out of range + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxSetExtendedColorimetry +( + tmInstance_t instance, + Bool enable, + tmdlHdmiTxExtColorimetry_t extendedColorimetry, + tmdlHdmiTxYCCQR_t yccQR, + tmdlHdmiTxGamutData_t *pGamutData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check if extendedColorimetry & yccQR values are in the correct range */ + if(enable) // no need to check them for disable handling + { + RETIF(extendedColorimetry >= TMDL_HDMITX_EXT_COLORIMETRY_INVALID, TMDL_ERR_DLHDMITX_BAD_PARAMETER) + RETIF(yccQR >= TMDL_HDMITX_YQR_INVALID, TMDL_ERR_DLHDMITX_BAD_PARAMETER) + } + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Store YCC quantisation range value for later AVI InfoFrame insertion */ + if(enable) instanceStatusInfoTx[instance].pGamutState->yccQR = yccQR; + + /* Extended colorimetries that need to send Gamut Packet Data */ + if( ( (enable == True) && ( (extendedColorimetry == TMDL_HDMITX_EXT_COLORIMETRY_XVYCC601) || + (extendedColorimetry == TMDL_HDMITX_EXT_COLORIMETRY_XVYCC709) ) ) + || + ( (enable == False) && (instanceStatusInfoTx[instance].pGamutState->gamutOn == True) ) ) + { + /* can not have two different types of extended colorimeties enabled in the same time */ + if(enable) instanceStatusInfoTx[instance].pGamutState->extColOn = False; + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Call the API that handles Gamut MetaData */ + RETIF( (errCode = tmdlHdmiTxSetGamutPacket(instance, enable, pGamutData) ) != TM_OK, errCode) + + return TM_OK; + } + + /* Extended colorimetries that do not need to send Gamut Packet Data */ + if (instanceStatusInfoTx[instance].pGamutState->gamutOn == True) + { + /* Disable Gamut metadata transmission */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], (errCode = tmbslHdmiTxPktSendGamut(instance, 0, False) ) != TM_OK, errCode) + + instanceStatusInfoTx[instance].pGamutState->gamutOn = False; + } + + /* Store the extended colorimetry that does not need sending Gamut Packet Data */ + if(enable) instanceStatusInfoTx[instance].pGamutState->wideGamutColorSpace = extendedColorimetry; + instanceStatusInfoTx[instance].pGamutState->extColOn = enable; + + /* Set avi infoframe */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = dlHdmiTxSetVideoInfoframe(instance, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief This function set the revocation list use for HDCP + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param listPtr Pointer on revocation list provide by application. + \param length length of revocation list. + + \return The call result: + - TM_OK: the call was successful, however RX keys have + not been checked with provided revocation list + because they are not available. + - TMDL_DLHDMITX_HDCP_SECURE: the call was successful, RX keys are secure + - TMDL_DLHDMITX_HDCP_NOT_SECURE: the call was successful, RX keys are NOT secure + - TMDL_ERR_DLHDMITX_INVALID_STATE: we are a repeater + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ + +tmErrorCode_t tmdlHdmiTxSetHDCPRevocationList( + tmInstance_t instance, + void *listPtr, + UInt32 length +) +{ + tmErrorCode_t errCode = TM_OK; +#ifndef NO_HDCP + tmErrorCode_t errCodeSem = TM_OK; + UInt8 aCounter = 0; + UInt8 indexKSVList = 0; + UInt8 i; + Bool bIsSecure = True; +#endif + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check parameters */ + RETIF((listPtr == Null) || (length == 0), TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + +#ifndef NO_HDCP + /* --------------------- */ + /* Take the semaphore */ + /* --------------------- */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + /* Register revocation list */ + unitTableTx[instance].revocationList.pList = (UInt8 *)listPtr; + unitTableTx[instance].revocationList.length = length; + + /* Look if hdcpBksv is filled in */ + for (i=0; i= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* --------------------- */ + /* Take the semaphore */ + /* --------------------- */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + gtmdlHdmiTxDriverConfigTable[instance].pattern = pattern; + + /* Set service mode colour bar on/off (also used as HDCP logo pattern) */ + (void)dlHdmiTxSetTestPatternOn(instance, instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode, + gtmdlHdmiTxDriverConfigTable[instance].pattern); + + /* --------------------------- */ + /* Release the sempahore */ + /* --------------------------- */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + return errCode; + +} + +/****************************************************************************** + \brief This function set the Remove B.... screen + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + + \return The call result: + - TM_OK: the call was successful, however RX keys have + not been checked with provided revocation list + because they are not available. + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + + +******************************************************************************/ + +tmErrorCode_t tmdlHdmiTxRemoveBScreen( + tmInstance_t instance +) +{ + + tmErrorCode_t errCodeSem = TM_OK; + tmErrorCode_t errCode = TM_OK; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* --------------------- */ + /* Take the semaphore */ + /* --------------------- */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + /* Restore last output format and mode */ + (void)dlHdmiTxSetTestPatternOff(instance, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode); + + /* --------------------------- */ + /* Release the sempahore */ + /* --------------------------- */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + return errCode; + +} + +/****************************************************************************** + \brief tmdlHdmiTxConvertDTDtoCEA . + + \param DTDescriptors DTD to convert. + + \return NA. + +******************************************************************************/ +tmdlHdmiTxVidFmt_t tmdlHdmiTxConvertDTDtoCEA +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors +) +{ + + tmdlHdmiTxVidFmt_t codeCEA; + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio; + Bool formatInterlaced; + + /* --------------------- */ + /* Take the semaphore */ + /* --------------------- */ + tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + + formatInterlaced = False; + + if ((pDTDescriptors->flags) & 0x80) + { + formatInterlaced = True; + } + + pictureAspectRatio = dlHdmiTxCalcAspectRatio (pDTDescriptors->hImageSize, pDTDescriptors->vImageSize); + + switch (pDTDescriptors->hActivePixels) + { + case 640: + codeCEA = dlHdmiTxConvertDTDtoCEA_640HAP(pDTDescriptors); + break; + + case 720: + codeCEA = dlHdmiTxConvertDTDtoCEA_720HAP(pDTDescriptors, pictureAspectRatio); + break; + + case 1280: + codeCEA = dlHdmiTxConvertDTDtoCEA_1280HAP(pDTDescriptors); + break; + + case 1920: + codeCEA = dlHdmiTxConvertDTDtoCEA_1920HAP(pDTDescriptors, formatInterlaced); + break; + + case 1440: + codeCEA = dlHdmiTxConvertDTDtoCEA_1440HAP(pDTDescriptors, pictureAspectRatio, formatInterlaced); + break; + + case 2880: + codeCEA = dlHdmiTxConvertDTDtoCEA_2880HAP(pDTDescriptors, pictureAspectRatio, formatInterlaced); + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + /* --------------------------- */ + /* Release the sempahore */ + /* --------------------------- */ + tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + + return codeCEA; + +} + +/*============================================================================*/ +/* INTERNAL FUNCTION */ +/*============================================================================*/ + +/****************************************************************************** + \brief Get the REFPIX and REFLINE for output and scaler + for the current settings. + + \param vinFmt Video input format. + \param vinMode Video input mode. + \param voutFmt Video output format. + \param syncIn Type of synchro (ext or emb). + \param pixRate Video pixel rate. + \param pRefPix RefPix for output. + \param pRefLine RefLine for output. + \param pScRefPix RefPix for scaler. + \param pScRefLine RefLine for scaler. + \param pbVerified Pointer to the boolean that will receive the fact that + this scaler setting was verified. + + \return True (Found) or False (Not found). + +******************************************************************************/ +static Bool dlHdmiTxGetReflineRefpix +( + tmdlHdmiTxVidFmt_t vinFmt, + tmdlHdmiTxVinMode_t vinMode, + tmdlHdmiTxVidFmt_t voutFmt, + UInt8 syncIn, + tmdlHdmiTxPixRate_t pixRate, + UInt16 *pRefPix, + UInt16 *pRefLine, + UInt16 *pScRefPix, + UInt16 *pScRefLine, + Bool *pbVerified +) +{ + UInt8 shortVinFmt; + UInt8 shortVoutFmt; + int i; + Bool bFound; + tmdlHdmiTxVidFmt_t vinFmtIndex, voutFmtIndex; + + /* Search for all values to match in table, until table end is reached + * when both refPix values are zero */ + *pRefPix = 0; + *pRefLine = 0; + *pScRefPix = 0; + *pScRefLine = 0; + + /* If match is not found in table, we can assume a verified non-scaler + * combination */ + *pbVerified = 1; + bFound = False; + + if ((voutFmt < TMDL_HDMITX_VFMT_TV_NO_REG_MIN) + || ((voutFmt >= HDMITX_VFMT_35_2880x480p_60Hz) && (voutFmt <= HDMITX_VFMT_38_2880x576p_50Hz))) + { + vinFmtIndex = dlHdmiTxCalcVidFmtIndex(vinFmt); + voutFmtIndex = dlHdmiTxCalcVidFmtIndex(voutFmt); + shortVinFmt = kVfmtToShortFmt_TV[vinFmtIndex]; + shortVoutFmt = kVfmtToShortFmt_TV[voutFmtIndex]; + + for (i = 0; kRefpixRefline[i].shortVinFmt != TV_INVALID; i++) + { + if ((kRefpixRefline[i].shortVinFmt == shortVinFmt) + && (UNPKMODE(kRefpixRefline[i].modeRateSyncVerf) == vinMode) + && (kRefpixRefline[i].shortVoutFmt == shortVoutFmt) + && (UNPKRATE(kRefpixRefline[i].modeRateSyncVerf) == pixRate) + && (UNPKSYNC(kRefpixRefline[i].modeRateSyncVerf) == syncIn)) + { + *pRefPix = kRefpixRefline[i].refPix; + *pRefLine = kRefpixRefline[i].refLine; + *pScRefPix = kRefpixRefline[i].scRefPix; + *pScRefLine = kRefpixRefline[i].scRefLine; + *pbVerified = UNPKVERF(kRefpixRefline[i].modeRateSyncVerf); + bFound = True; + break; + } + } + } + + return bFound; +} + +/****************************************************************************** + \brief Set the video infoframe. + + \param instance Instance identifier. + \param voutFmt Video output format. + \param voutMode Video output mode. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +static tmErrorCode_t dlHdmiTxSetVideoInfoframe +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t voutFmt, + tmdlHdmiTxVoutMode_t voutMode +) +{ + tmErrorCode_t errCode; + tmdlHdmiTxAviIfData_t contentVif; + tmdlHdmiTxVidFmt_t voutFmtIndex; + + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + contentVif.colorIndicator = voutMode; /* 3rd api_set_avi_infoframe param */ + contentVif.activeInfoPresent = 0; + contentVif.barInformationDataValid = 0; + contentVif.scanInformation = 0; + + voutFmtIndex = dlHdmiTxCalcVidFmtIndex(voutFmt); + contentVif.pictureAspectRatio = kVfmtToAspect_TV[voutFmtIndex]; + + contentVif.activeFormatAspectRatio = 8; + contentVif.nonUniformPictureScaling = 0; + +#ifdef FORMAT_PC + if (voutFmt >= TMDL_HDMITX_VFMT_PC_MIN) + { + if (voutFmt == TMDL_HDMITX_VFMT_PC_640x480p_60Hz) + { + contentVif.videoFormatIdentificationCode = (tmbslHdmiTxVidFmt_t)TMDL_HDMITX_VFMT_01_640x480p_60Hz; + } + else + { + /* Format PC not Valid in EIA861b */ + contentVif.videoFormatIdentificationCode = (tmbslHdmiTxVidFmt_t)TMDL_HDMITX_VFMT_NULL; + } + } + else + { +#endif /* FORMAT_PC */ + + contentVif.videoFormatIdentificationCode = (tmbslHdmiTxVidFmt_t)voutFmt; + +#ifdef FORMAT_PC + } +#endif /* FORMAT_PC */ + + + if (((voutFmt >= TMDL_HDMITX_VFMT_06_720x480i_60Hz) && (voutFmt <= TMDL_HDMITX_VFMT_09_720x240p_60Hz)) + || ((voutFmt >= TMDL_HDMITX_VFMT_21_720x576i_50Hz) && (voutFmt <= TMDL_HDMITX_VFMT_24_720x288p_50Hz))) + { + /* Force pixel repeat for formats where it's mandatory (Pixel Frequency < 20 Mpix/s)*/ + contentVif.pixelRepetitionFactor = 1; + } + else if((voutFmt == TMDL_HDMITX_VFMT_10_720x480i_60Hz) || (voutFmt == TMDL_HDMITX_VFMT_11_720x480i_60Hz) || + (voutFmt == TMDL_HDMITX_VFMT_25_720x576i_50Hz) || (voutFmt == TMDL_HDMITX_VFMT_26_720x576i_50Hz) ) + { + contentVif.pixelRepetitionFactor = HDMITX_PIXREP_3; // pixel sent 1 or 10 times, here 4 times + } + else if((voutFmt == TMDL_HDMITX_VFMT_14_1440x480p_60Hz) || (voutFmt == TMDL_HDMITX_VFMT_15_1440x480p_60Hz) || + (voutFmt == TMDL_HDMITX_VFMT_29_1440x576p_50Hz) || (voutFmt == TMDL_HDMITX_VFMT_30_1440x576p_50Hz)) + { + contentVif.pixelRepetitionFactor = HDMITX_PIXREP_1; // pixel sent 1 or 2 times, here 2 times + } + else if((voutFmt >= TMDL_HDMITX_VFMT_35_2880x480p_60Hz) && (voutFmt <= TMDL_HDMITX_VFMT_38_2880x576p_50Hz)) + { + contentVif.pixelRepetitionFactor = HDMITX_PIXREP_3; + } + else /* Default to no repeat for all other formats */ + { + contentVif.pixelRepetitionFactor = HDMITX_PIXREP_NONE; + } + + if ((instanceStatusInfoTx[instance].pGamutState->gamutOn == True) || + (instanceStatusInfoTx[instance].pGamutState->extColOn == True)) + { + contentVif.colorimetry = (UInt8)TMDL_HDMITX_COLORIMETRY_EXTENDED; + } + else + { + switch (voutFmt) + { + case TMDL_HDMITX_VFMT_04_1280x720p_60Hz: + case TMDL_HDMITX_VFMT_05_1920x1080i_60Hz: + case TMDL_HDMITX_VFMT_16_1920x1080p_60Hz: + case TMDL_HDMITX_VFMT_19_1280x720p_50Hz: + case TMDL_HDMITX_VFMT_20_1920x1080i_50Hz: + case TMDL_HDMITX_VFMT_31_1920x1080p_50Hz: + contentVif.colorimetry = (UInt8)TMDL_HDMITX_COLORIMETRY_ITU709; + break; + + default: + contentVif.colorimetry = (UInt8)TMDL_HDMITX_COLORIMETRY_ITU601; + break; + } + } + + contentVif.lineNumberEndTopBar = 0; + contentVif.lineNumberStartBottomBar = 0; + contentVif.lineNumberEndLeftBar = 0; + contentVif.lineNumberStartRightBar = 0; + + errCode = dlHdmiTxSetRawVideoInfoframe(instance, &contentVif, True); + + /* Ignore infoframe interlock in DVI mode */ + if (errCode == TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED) + { + errCode = TM_OK; + } + + return errCode; +} + +/****************************************************************************** + \brief Set the video infoframe. + + \param instance Instance identifier. + \param voutFmt Video output format. + \param voutMode Video output mode. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + - TMBSL_ERR_HDMI_I2C_READ: failed when reading to the I2C bus + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_OPERATION_NOT_PERMITTED: not allowed in DVI mode + +******************************************************************************/ +static tmErrorCode_t dlHdmiTxSetRawVideoInfoframe +( + tmInstance_t instance, + tmdlHdmiTxAviIfData_t *pContentVif, + Bool enable +) +{ + + tmErrorCode_t errCode; + tmbslHdmiTxPktRawAvi_t PktInfoFrame; + UInt8 i; + + if(pContentVif != Null) + { + + for(i=0; icolorIndicator& 0x03) << 5) | /* Y1-0, B1-0,S1-0 */ + ((pContentVif->barInformationDataValid& 0x03) << 2) | + (pContentVif->scanInformation & 0x03); + if(pContentVif->activeInfoPresent == True) + { + PktInfoFrame.PB[1] += 0x10; /* A0 bit */ + } + + PktInfoFrame.PB[2] = ((pContentVif->colorimetry & 0x03) << 6) | /* C1-0, M1-0, R3-0 */ + ((pContentVif->pictureAspectRatio & 0x03) << 4) | + (pContentVif->activeFormatAspectRatio & 0x0F); + + PktInfoFrame.PB[3] = (pContentVif->nonUniformPictureScaling & 0x03); /* SC1-0 */ /* [HDMI 1.2] */ + + /* Q1-0 = 00 => RGB Quantization Range depends on video format (CEA-861) */ + /* Limited Range for all video formats except PC formats which requires Full Range */ + + if (pContentVif->colorimetry == TMDL_HDMITX_COLORIMETRY_EXTENDED) + { + PktInfoFrame.PB[3] = (( ((UInt8)instanceStatusInfoTx[instance].pGamutState->wideGamutColorSpace) & 0x07) <<4) + | PktInfoFrame.PB[3]; + } + + /* Bit ITC = 0 => No Content Type ; Bit ITC = 1 => Content Type (see CN1-0) */ + /* Today ITC = 0 => No Content Type */ + + PktInfoFrame.PB[4] = (pContentVif->videoFormatIdentificationCode & 0x7F); /* VIC6-0 */ + + PktInfoFrame.PB[5] = (pContentVif->pixelRepetitionFactor & 0x0F); /* PR3-0 */ + + /* CN1-0 => Content Type */ + /* Today CN1-0 = 00 => No Data */ + + /* YQ1-0 => YCC Quantization Range, only managed for those extended colorimetries */ + if (pContentVif->colorimetry == TMDL_HDMITX_COLORIMETRY_EXTENDED) + { + PktInfoFrame.PB[5] |= ( ((UInt8)instanceStatusInfoTx[instance].pGamutState->yccQR) & 0x03) << 6; + } + PktInfoFrame.PB[6] = (UInt8)(pContentVif->lineNumberEndTopBar & 0x00FF); + PktInfoFrame.PB[7] = (UInt8)((pContentVif->lineNumberEndTopBar & 0xFF00) >> 8); + PktInfoFrame.PB[8] = (UInt8)(pContentVif->lineNumberStartBottomBar & 0x00FF); + PktInfoFrame.PB[9] = (UInt8)((pContentVif->lineNumberStartBottomBar & 0xFF00) >> 8); + PktInfoFrame.PB[10] = (UInt8)(pContentVif->lineNumberEndLeftBar & 0x00FF); + PktInfoFrame.PB[11] = (UInt8)((pContentVif->lineNumberEndLeftBar & 0xFF00) >> 8); + PktInfoFrame.PB[12] = (UInt8)(pContentVif->lineNumberStartRightBar & 0x00FF); + PktInfoFrame.PB[13] = (UInt8)((pContentVif->lineNumberStartRightBar & 0xFF00) >> 8); + + /* Calculate checksum - this is worked out on "Length" bytes of the + * packet, the checksum (which we've preset to zero), and the three + * header bytes. + */ + PktInfoFrame.PB[0] = dlHdmiTxcalculateCheksumIF(&PktInfoFrame); + + errCode = tmbslHdmiTxPktSetRawVideoInfoframe(instance, + &PktInfoFrame, enable); + } + else + { + errCode = tmbslHdmiTxPktSetVideoInfoframe(instance, + Null, enable); + } + + return errCode; + +} + +/*============================================================================*/ +/* calculateChecksum - returns the byte needed to yield a checksum of zero */ +/*============================================================================*/ +static UInt8 +dlHdmiTxcalculateCheksumIF +( + tmbslHdmiTxPktRawAvi_t *pData /* Pointer to checksum data */ +) +{ + UInt8 checksum = 0; /* Working checksum calculation */ + UInt8 result = 0; /* Value to be returned */ + UInt8 numBytes = 0; + Int i; + + if(pData != Null) + { + + numBytes = sizeof(pData->HB); + + for (i = 0; i < numBytes; i++) + { + checksum = checksum + pData->HB[i]; + } + + numBytes = sizeof(pData->PB); + + for (i = 0; i < numBytes; i++) + { + checksum = checksum + pData->PB[i]; + } + + result = (UInt8)((255 - checksum) + 1); + } + return result; /* returns 0 in the case of null ptr or 0 bytes */ +} + +/****************************************************************************** + \brief Set colourbar test pattern on with RGB infoframe + + \param instance Instance identifier. + \param voutFmt Video output format. + \param voutMode Video output mode. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + +******************************************************************************/ +tmErrorCode_t dlHdmiTxSetTestPatternOn +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t voutFmt, + tmdlHdmiTxVoutMode_t voutMode, + tmdlHdmiTxTestPattern_t pattern +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + RETIF( (errCode = tmbslHdmiTxTestSetPattern(instance, + (tmbslHdmiTxTestPattern_t)pattern) ) != TM_OK, errCode) + + if (pattern > TMDL_HDMITX_PATTERN_CBAR8) + { + RETIF( (errCode = dlHdmiTxSetVideoInfoframe(instance, voutFmt, voutMode) ) != TM_OK, errCode) + } + else + { + /* For TMDL_HDMITX_PATTERN_CBAR8 and TMDL_HDMITX_PATTERN_CBAR4, video mode in infoframe should be RGB */ + RETIF( (errCode = dlHdmiTxSetVideoInfoframe(instance, voutFmt, TMDL_HDMITX_VOUTMODE_RGB444) ) != TM_OK, errCode) + } + return TM_OK; +} + +/****************************************************************************** + \brief Set colourbar test pattern off with previous infoframe + + \param instance Instance identifier. + \param voutFmt Video output format. + \param voutMode Video output mode. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + - TMBSL_ERR_HDMI_I2C_WRITE: failed when writing to the I2C bus + +******************************************************************************/ +tmErrorCode_t dlHdmiTxSetTestPatternOff +( + tmInstance_t instance, + tmdlHdmiTxVidFmt_t voutFmt, + tmdlHdmiTxVoutMode_t voutMode +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + RETIF( (errCode = tmbslHdmiTxTestSetPattern(instance, + (tmbslHdmiTxTestPattern_t)TMDL_HDMITX_PATTERN_OFF) ) != TM_OK, errCode) + + /* Restore video infoframe */ + RETIF( (errCode = dlHdmiTxSetVideoInfoframe(instance, voutFmt, voutMode) ) != TM_OK, errCode) + + return TM_OK; +} + +/****************************************************************************** + \brief HDCP ENCRYPT interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleENCRYPT +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + + tmbslHdmiTxHdcpHandleENCRYPT(instance); + + if (instanceStatusInfoTx[instance].pColBarState->disableColorBarOnR0 == False) + { + instanceStatusInfoTx[instance].pColBarState->hdcpColbarChange = False; + instanceStatusInfoTx[instance].pColBarState->hdcpEncryptOrT0 = True; + } + instanceStatusInfoTx[instance].pColBarState->disableColorBarOnR0 = False; +#else + (void)instance; /* Remove compiler warning */ +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief HPD interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleHPD +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxHotPlug_t hpdStatus; /* HPD status */ + tmPowerState_t powerState; /* Power state of transmitter */ + + hpdStatus = HDMITX_HOTPLUG_INVALID; + + /* Get Hot Plug status */ + errCode = tmbslHdmiTxHotPlugGetStatus(instance, + &hpdStatus,False); + + if (errCode != TM_OK) return; + + /* Get the power state of the transmitter */ + errCode = tmbslHdmiTxPowerGetState(instance, + &powerState); + + if (errCode != TM_OK) return; + + /* Has hot plug changed to Active? */ + if (hpdStatus == HDMITX_HOTPLUG_ACTIVE) + { + /* Set state machine to Plugged */ + dlHdmiTxSetState(instance, STATE_PLUGGED); + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_HPD_ACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_HPD_ACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + if (powerState == tmPowerOn) + { + /* Yes: Wait for DDC line to settle before reading EDID */ + tmbslHdmiTxSysTimerWait(instance, + 500); /* ms */ + + /* Request EDID read */ + errCode = tmbslHdmiTxEdidRequestBlockData(instance, + unitTableTx[instance].pEdidBuffer, (Int)((unitTableTx[instance].edidBufferSize) >> 7), + (Int)(unitTableTx[instance].edidBufferSize)); + + if (errCode != TM_OK) return; + } + } + else + { +#ifndef NO_HDCP + if (unitTableTx[instance].hdcpEnable == True) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + /* Switch off HDCP */ + (void)tmdlHdmiTxSetHdcp(instance, False); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } +#endif /* NO_HDCP */ + + /* Set state machine to Unplugged */ + dlHdmiTxSetState(instance, STATE_UNPLUGGED); + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_HPD_INACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_HPD_INACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + } +} + +/****************************************************************************** + \brief T0 interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleT0 +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + tmErrorCode_t errCode; + + errCode = tmbslHdmiTxHdcpHandleT0(instance); + + if (errCode != TM_OK) return; + + tmbslHdmiTxHdcpGetT0FailState(instance, + &(hdcpInfoListTx[instance].hdcpErrorState)); + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_HDCP_INACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_HDCP_INACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + instanceStatusInfoTx[instance].pColBarState->hdcpColbarChange = False; + instanceStatusInfoTx[instance].pColBarState->hdcpEncryptOrT0 = True; + instanceStatusInfoTx[instance].pColBarState->hdcpSecureOrT0 = True; +#else + (void)instance; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief BCAPS interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleBCAPS +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + Bool bCheckRequired; + tmErrorCode_t errCode; + + /* Handle BCAPS interrupt immediately */ + errCode = tmbslHdmiTxHdcpHandleBCAPS(instance); + + if (errCode != TM_OK) return; + + /* Wait for TDA9984 to read BKSV from B device */ + tmbslHdmiTxSysTimerWait(instance, 10); + + /* Handle BKSV read */ + errCode = tmbslHdmiTxHdcpHandleBKSV(instance, + hdcpInfoListTx[instance].hdcpBksv, &bCheckRequired); + + if (errCode != TM_OK) return; + + if (bCheckRequired) + { + /* check HdcpBksv against a revocation list */ + dlHdmiTxCheckHdcpBksv (instance, hdcpInfoListTx[instance].hdcpBksv,&(hdcpInfoListTx[instance].bKsvSecure), True); + } + else + { + /* Result is always secure if no check required */ + hdcpInfoListTx[instance].bKsvSecure = True; + } + + /* Handle BKSV result */ + errCode = tmbslHdmiTxHdcpHandleBKSVResult(instance, + hdcpInfoListTx[instance].bKsvSecure); + + if (errCode != TM_OK) return; + + +#else + (void)instance; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief BSTATUS interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleBSTATUS +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + UInt16 bstatus = 0; + + tmbslHdmiTxHdcpHandleBSTATUS(instance, + &bstatus); + +#ifdef HDMI_TX_REPEATER_ISR_MODE + gIgnoreNextSha1 = False; +#endif /*HDMI_TX_REPEATER_ISR_MODE*/ + + if (((bstatus & HDMITX_HDCP_BSTATUS_MAX_CASCADE_EXCEEDED) > 0) + || ((bstatus & HDMITX_HDCP_BSTATUS_MAX_DEVS_EXCEEDED) > 0)) + { + + hdcpInfoListTx[instance].hdcpDeviceDepth = (UInt8)((bstatus & HDMITX_HDCP_BSTATUS_CASCADE_DEPTH)>>8); + + /* The KsvList length is limited by the smaller of the list array + * length and the number of devices returned in BSTATUS */ + hdcpInfoListTx[instance].hdcpKsvDevices = + (UInt8)(bstatus & HDMITX_HDCP_BSTATUS_DEVICE_COUNT); + + if (HDMITX_KSV_LIST_MAX_DEVICES < hdcpInfoListTx[instance].hdcpKsvDevices) + { + hdcpInfoListTx[instance].hdcpKsvDevices = HDMITX_KSV_LIST_MAX_DEVICES; + } + + if ((bstatus & HDMITX_HDCP_BSTATUS_MAX_CASCADE_EXCEEDED) > 0) + { + hdcpInfoListTx[instance].hdcpMaxCascExceeded = True; + } + + if ((bstatus & HDMITX_HDCP_BSTATUS_MAX_DEVS_EXCEEDED) > 0) + { + hdcpInfoListTx[instance].hdcpMaxDevsExceeded = True; + } + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_RX_KEYS_RECEIVED) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_RX_KEYS_RECEIVED); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + } + else + { + +#ifdef HDMI_TX_REPEATER_ISR_MODE + /* Call SHA_1 otherwise this ISR is missed */ + hdcpInfoListTx[instance].hdcpDeviceDepth = (UInt8)((bstatus & HDMITX_HDCP_BSTATUS_CASCADE_DEPTH)>>8); + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_B_STATUS) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_B_STATUS); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + +#endif /* HDMI_TX_REPEATER_ISR_MODE */ + } + + +#else + (void)instance; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief SHA_1 interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleSHA_1 +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + tmErrorCode_t errCode; + UInt8 indexKSVList; + +#ifdef HDMI_TX_REPEATER_ISR_MODE + if (gIgnoreNextSha1 == False) + { + gIgnoreNextSha1 = True; +#endif /*HDMI_TX_REPEATER_ISR_MODE*/ + + errCode = tmbslHdmiTxHdcpHandleSHA_1(instance, + HDMITX_KSV_LIST_MAX_DEVICES, hdcpInfoListTx[instance].hdcpKsvList, + &(hdcpInfoListTx[instance].hdcpKsvDevices),&(hdcpInfoListTx[instance].hdcpDeviceDepth)); + if (errCode != TM_OK) return; + + /* Top level or repeater HDCP mode */ + if (unitTableTx[instance].repeaterEnable == False) + { + /* check HdcpKsvList against revocation list */ + + indexKSVList = 0; + while (( indexKSVList < TMDL_HDMITX_KSV_LIST_MAX_DEVICES ) && + ( indexKSVList < hdcpInfoListTx[instance].hdcpKsvDevices ) && + (hdcpInfoListTx[instance].bKsvSecure == True) + ) + { + dlHdmiTxCheckHdcpBksv (instance, + &(hdcpInfoListTx[instance].hdcpKsvList[indexKSVList * TMDL_HDMITX_KSV_BYTES_PER_DEVICE]), + &(hdcpInfoListTx[instance].bKsvSecure), + False); + indexKSVList++; + } + } + else + { + hdcpInfoListTx[instance].bKsvSecure = True; + } + + /* Handle SHA_1 result */ + errCode = tmbslHdmiTxHdcpHandleSHA_1Result(instance, + hdcpInfoListTx[instance].bKsvSecure); + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_RX_KEYS_RECEIVED) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_RX_KEYS_RECEIVED); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + if (!hdcpInfoListTx[instance].bKsvSecure) + { + instanceStatusInfoTx[instance].pColBarState->changeColorBarNow = True; + instanceStatusInfoTx[instance].pColBarState->colorBarOn = True; + dlHdmiTxCheckColorBar(instance); + } +#ifdef HDMI_TX_REPEATER_ISR_MODE + } +#endif /*HDMI_TX_REPEATER_ISR_MODE*/ + + +#else + (void)instance; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief PJ interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandlePJ +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + tmbslHdmiTxHdcpHandlePJ(instance); +#else + (void)instance; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief R0 interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleR0 +( + tmInstance_t instance +) +{ +#ifndef NO_HDCP + tmErrorCode_t errCode; + tmbslHdmiTxSinkCategory_t category; + + + + if (hdcpInfoListTx[instance].bKsvSecure == True) + { + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_HDCP_ACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_HDCP_ACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + instanceStatusInfoTx[instance].pColBarState->hdcpSecureOrT0 = False; + } + + + errCode = tmbslHdmiTxHdcpGetSinkCategory(instance, + &category); + if (errCode != TM_OK) return; + + if (category == HDMITX_SINK_CAT_NOT_REPEATER) + { + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_RX_KEYS_RECEIVED) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_RX_KEYS_RECEIVED); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + } + + instanceStatusInfoTx[instance].pColBarState->disableColorBarOnR0 = True; + instanceStatusInfoTx[instance].pColBarState->hdcpColbarChange = True; +#else + (void)instance; +#endif /* NO_HDCP */ +} + +/****************************************************************************** + \brief SW_INT interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleSW_INT +( + tmInstance_t instance +) +{ + DUMMY_ACCESS(instance); +} + +/****************************************************************************** + \brief RX_SENSE interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleRX_SENSE +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + tmbslHdmiTxRxSense_t rxSenseStatus; /* Rx Sense status */ + tmbslHdmiTxHotPlug_t hpdStatus; /* HPD status */ + + errCode = tmbslHdmiTxRxSenseGetStatus(instance, + &rxSenseStatus,False); + + if (errCode != TM_OK) return; + + errCode = tmbslHdmiTxHotPlugGetStatus(instance, + &hpdStatus,False); + + if (errCode != TM_OK) return; + +// if (hpdStatus == HDMITX_HOTPLUG_ACTIVE) +// { + if (rxSenseStatus == HDMITX_RX_SENSE_ACTIVE) + { + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_RX_DEVICE_ACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_RX_DEVICE_ACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + } + else if (rxSenseStatus == HDMITX_RX_SENSE_INACTIVE) + { + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_RX_DEVICE_INACTIVE) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_RX_DEVICE_INACTIVE); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + +#ifndef NO_HDCP + if (unitTableTx[instance].hdcpEnable == True) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + /* Switch off HDCP */ + (void)tmdlHdmiTxSetHdcp(instance, False); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } +#endif /* NO_HDCP */ + } +// } +} + +/****************************************************************************** + \brief EDID_READ interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleEDID_READ +( + tmInstance_t instance +) +{ + tmErrorCode_t errCode; + UInt8 edidStatus = TMDL_HDMITX_EDID_NOT_READ; + + /* Get the edid status and read the connected device's EDID */ + + /* Get Edid status */ + errCode = tmbslHdmiTxEdidGetStatus(instance, + &edidStatus); + + if (errCode != TM_OK) + { + /* Set state machine to Plugged */ + dlHdmiTxSetState(instance, STATE_PLUGGED); + return; + } + + /* Has hot plug changed to Active? */ + if ((edidStatus == TMDL_HDMITX_EDID_READ) || + (edidStatus == TMDL_HDMITX_EDID_ERROR_CHK)) + { + /* Set state machine to EDID available */ + dlHdmiTxSetState(instance, STATE_EDID_AVAILABLE); + } + else + { + /* Set state machine to Plugged */ + dlHdmiTxSetState(instance, STATE_PLUGGED); + } + + + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_EDID_RECEIVED) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_EDID_RECEIVED); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } + + +} + +/****************************************************************************** + \brief VS_RPT interrupt callback. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxHandleVS_RPT +( + tmInstance_t instance +) +{ + if (dlHdmiTxGetEventStatus(instance, TMDL_HDMITX_VS_RPT_RECEIVED) == TMDL_HDMITX_EVENT_ENABLED) + { + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]); + unitTableTx[instance].pCallback(TMDL_HDMITX_VS_RPT_RECEIVED); + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]); + } +} + +/****************************************************************************** + \brief dlHdmiTxConvertDTDtoCEA_640HAP . + + \param pDTDescriptors DTD to convert. + pictureAspectRatio aspect ratio of DTD + formatInterlaced DTD Interlaced or progressif + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_640HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors +) +{ + tmdlHdmiTxVidFmt_t codeCEA; + + switch (pDTDescriptors->vActiveLines) + { + case 480: + codeCEA = TMDL_HDMITX_VFMT_01_640x480p_60Hz; + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + return codeCEA; + +} + +/****************************************************************************** + \brief dlHdmiTxConvertDTDtoCEA_720HAP . + + \param pDTDescriptors DTD to convert. + pictureAspectRatio aspect ratio of DTD + formatInterlaced DTD Interlaced or progressif + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_720HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio +) +{ + tmdlHdmiTxVidFmt_t codeCEA; + + switch (pDTDescriptors->vActiveLines) + { + case 480: + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_02_720x480p_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_03_720x480p_60Hz; + } + break; + + case 576: + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_17_720x576p_50Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_18_720x576p_50Hz; + } + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + return codeCEA; + +} +/****************************************************************************** + \brief dlHdmiTxConvertDTDtoCEA_1280HAP . + + \param pDTDescriptors DTD to convert. + pictureAspectRatio aspect ratio of DTD + formatInterlaced DTD Interlaced or progressif + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_1280HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors +) +{ + tmdlHdmiTxVidFmt_t codeCEA; + + switch (pDTDescriptors->vActiveLines) + { + case 720: + switch (pDTDescriptors->hBlankPixels) + { + case 370: + codeCEA = TMDL_HDMITX_VFMT_04_1280x720p_60Hz; + break; + + case 700: + codeCEA = TMDL_HDMITX_VFMT_19_1280x720p_50Hz; + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + + return codeCEA; +} + +/****************************************************************************** + \brief dlHdmiTxConvertDTDtoCEA_1920HAP . + + \param pDTDescriptors DTD to convert. + pictureAspectRatio aspect ratio of DTD + formatInterlaced DTD Interlaced or progressif + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_1920HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + Bool formatInterlaced + +) +{ + tmdlHdmiTxVidFmt_t codeCEA; + + switch (pDTDescriptors->hBlankPixels) + { + case 280: + if (formatInterlaced) + { + codeCEA = TMDL_HDMITX_VFMT_05_1920x1080i_60Hz; + } + else + { + if ( pDTDescriptors->pixelClock == 14850 ) + { + codeCEA = TMDL_HDMITX_VFMT_16_1920x1080p_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_34_1920x1080p_30Hz; + } + } + break; + + case 720: + if (formatInterlaced) + { + codeCEA = TMDL_HDMITX_VFMT_20_1920x1080i_50Hz; + } + else + { + switch (pDTDescriptors->pixelClock) + { + case 14850: + codeCEA = TMDL_HDMITX_VFMT_31_1920x1080p_50Hz; + break; + + case 7425: + codeCEA = TMDL_HDMITX_VFMT_33_1920x1080p_25Hz; + break; + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + } + break; + + case 830: + codeCEA = TMDL_HDMITX_VFMT_32_1920x1080p_24Hz; + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + + return codeCEA; +} + +/****************************************************************************** + \brief dlHdmiTxConvertDTDtoCEA_1440HAP . + + \param pDTDescriptors DTD to convert. + pictureAspectRatio aspect ratio of DTD + formatInterlaced DTD Interlaced or progressif + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_1440HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio, + Bool formatInterlaced + +) +{ + tmdlHdmiTxVidFmt_t codeCEA; + + switch (pDTDescriptors->vActiveLines) + { + case 240: + if (formatInterlaced) + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_06_720x480i_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_07_720x480i_60Hz; + } + } + else + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_08_720x240p_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_09_720x240p_60Hz; + } + } + break; + + case 288: + if (formatInterlaced) + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_21_720x576i_50Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_22_720x576i_50Hz; + } + } + else + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_23_720x288p_50Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_24_720x288p_50Hz; + } + } + break; + + case 480: + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_14_1440x480p_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_15_1440x480p_60Hz; + } + break; + + case 576: + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_29_1440x576p_50Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_30_1440x576p_50Hz; + } + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + return codeCEA; +} + +/****************************************************************************** + \brief dlHdmiTxConvertDTDtoCEA_2880HAP . + + \param pDTDescriptors DTD to convert. + pictureAspectRatio aspect ratio of DTD + formatInterlaced DTD Interlaced or progressif + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxConvertDTDtoCEA_2880HAP +( + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio, + Bool formatInterlaced +) +{ + tmdlHdmiTxVidFmt_t codeCEA; + + switch (pDTDescriptors->vActiveLines) + { + case 240: + if (formatInterlaced) + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_10_720x480i_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_11_720x480i_60Hz; + } + } + else + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_12_720x240p_60Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_13_720x240p_60Hz; + } + } + break; + + case 288: + if (formatInterlaced) + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_25_720x576i_50Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_26_720x576i_50Hz; + } + } + else + { + if (pictureAspectRatio == TMDL_HDMITX_P_ASPECT_RATIO_4_3) + { + codeCEA = TMDL_HDMITX_VFMT_27_720x288p_50Hz; + } + else + { + codeCEA = TMDL_HDMITX_VFMT_28_720x288p_50Hz; + } + } + break; + + default: + /* Not a valid format */ + codeCEA = TMDL_HDMITX_VFMT_NULL; + break; + } + + return codeCEA; +} + +/****************************************************************************** + \brief EdidGetDTD . + + \param . + + \return NA. + +******************************************************************************/ +tmErrorCode_t dlHdmiTxEdidGetDTD +( + tmInstance_t instance, + tmdlHdmiTxEdidVideoTimings_t *pDTDescriptors, + UInt8 maxDTDesc, + UInt8 *pWrittenDTDesc +) +{ + tmErrorCode_t errCode; + + /* Check the current state */ + RETIF( dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + /* Get detailled descriptors from EDID, return TMDL_ERR_DLHDMITX_NO_RESOURCES if EDID are not read */ + RETIF((errCode = tmbslHdmiTxEdidGetDetailedTimingDescriptors( + instance, (tmbslHdmiTxEdidDtd_t *)pDTDescriptors, maxDTDesc, pWrittenDTDesc) ) != TM_OK, errCode); + + return TM_OK; +} + + +/****************************************************************************** + \brief Command processing task, dedicated to unit/instance 0. + + \param NA. + + \return NA. + +******************************************************************************/ + +#ifndef TMFL_NO_RTOS +static void CommandTaskUnit0() +{ + UInt8 command; + Bool loop = True; /* Just to avoid compiler warning */ + tmErrorCode_t err = TM_OK; + + while(loop) + { + tmdlHdmiTxIWQueueReceive(unitTableTx[0].queueHandle, &command); + + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[0]); + + /* Clear T0 flag before polling for interrupts */ + instanceStatusInfoTx[0].pColBarState->hdcpSecureOrT0 = False; + + if (gI2CDebugAccessesEnabled == True) + { + + err = tmbslHdmiTxHwHandleInterrupt(0); + + if ((err == TMBSL_ERR_HDMI_I2C_WRITE) || (err == TMBSL_ERR_HDMI_I2C_READ)) + { + + unitTableTx[0].pCallback(TMDL_HDMITX_DEBUG_EVENT_1); + } + + }/* (gI2CDebugAccessesEnabled == True) */ + + /* Enable interrupts for Tx (interrupts are disabled in the HandleInterrupt function) */ + tmdlHdmiTxIWEnableInterrupts(TMDL_HDMI_IW_TX_1); + + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[0]); + }; +} +#endif /* TMFL_NO_RTOS */ + +/****************************************************************************** + \brief Hdcp check task, dedicated to unit/instance 0. + + \param NA. + + \return NA. + +******************************************************************************/ +#ifndef TMFL_NO_RTOS +static void HdcpTaskUnit0() +{ + Bool loop = True; /* Just to avoid compiler warning */ + Bool featureSupported; + + tmbslHdmiTxHwGetCapabilities(0, + HDMITX_FEATURE_HW_HDCP, &featureSupported); + +#ifndef NO_HDCP + while(loop) + { + (void)tmdlHdmiTxIWWait(35); + + /* Take the sempahore */ + (void)tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[0]); + + if (gI2CDebugAccessesEnabled == True) + { + + dlHdmiTxCheckColorBar(0); + dlHdmiTxCheckHdcpColorBar(0); + + if (featureSupported == True) + { + tmbslHdmiTxHdcpCheck(0,35, (tmbslHdmiTxHdcpCheck_t *)&(hdcpInfoListTx[0].hdcpCheckState)); + } + + } /* gI2CDebugAccessesEnabled == True*/ + + /* Release the sempahore */ + (void)tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[0]); + }; +#else + (void)loop; +#endif /* NO_HDCP */ +} +#endif /* TMFL_NO_RTOS */ + +#ifndef NO_HDCP +/****************************************************************************** + \brief Check hdcp state to manage color bar. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxCheckHdcpColorBar +( + tmInstance_t instance +) +{ + /* Use HDCP check result to control HDCP colour bars */ + if ( (instanceStatusInfoTx[instance].pColBarState->disableColorBarOnR0 == True) + && (instanceStatusInfoTx[instance].pColBarState->hdcpColbarChange == True) + && (instanceStatusInfoTx[instance].pColBarState->hdcpSecureOrT0 == False) ) + { + /* Remove test pattern once if Authenticated with no error interrupts */ + if (instanceStatusInfoTx[instance].pColBarState->colorBarOn != False) + { + instanceStatusInfoTx[instance].pColBarState->colorBarOn = False; + instanceStatusInfoTx[instance].pColBarState->changeColorBarNow = True; + + if (unitTableTx[instance].simplayHd == True) { + + /* Mute or Un-mute the audio output */ + tmbslHdmiTxAudioOutSetMute(instance,(tmbslHdmiTxaMute_t)HDMITX_AMUTE_OFF); + + /* Store current audio mute status */ + instanceStatusInfoTx[instance].pAudioInfo->audioMuteState = False; + } + + + } + /* Reset state flags */ + instanceStatusInfoTx[instance].pColBarState->hdcpColbarChange = False; + instanceStatusInfoTx[instance].pColBarState->hdcpSecureOrT0 = True; + +#ifdef TMFL_TDA19989 + instanceStatusInfoTx[instance].pColBarState->disableColorBarOnR0 = False; +#endif /* TMFL_TDA19989 */ + + + + } + + if ( (instanceStatusInfoTx[instance].pColBarState->hdcpEncryptOrT0 == True) + && (instanceStatusInfoTx[instance].pColBarState->inOutFirstSetDone == True)) + { + /* Set test pattern once if not Authenticated, to mask HDCP failure */ + if (instanceStatusInfoTx[instance].pColBarState->colorBarOn != True) + { + instanceStatusInfoTx[instance].pColBarState->colorBarOn = True; + instanceStatusInfoTx[instance].pColBarState->changeColorBarNow = True; + + if (unitTableTx[instance].simplayHd == True) { + + /* Mute or Un-mute the audio output */ + tmbslHdmiTxAudioOutSetMute(instance,(tmbslHdmiTxaMute_t)HDMITX_AMUTE_ON); + + /* Store current audio mute status */ + instanceStatusInfoTx[instance].pAudioInfo->audioMuteState = True; + } + + } + /* Reset state flag */ + instanceStatusInfoTx[instance].pColBarState->hdcpEncryptOrT0 = False; + } +} +#endif + +#ifndef NO_HDCP +/****************************************************************************** + \brief Show color bars or restore the last video format. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxCheckColorBar +( + tmInstance_t instance +) +{ + if ( (instanceStatusInfoTx[instance].pColBarState->inOutFirstSetDone == True) + && (instanceStatusInfoTx[instance].pColBarState->changeColorBarNow == True) ) + { + instanceStatusInfoTx[instance].pColBarState->changeColorBarNow = False; + + if (unitTableTx[instance].simplayHd == True) + { + if (instanceStatusInfoTx[instance].pColBarState->colorBarOn == True) + { + /* Set service mode colour bar on/off (also used as HDCP logo pattern) */ + (void)dlHdmiTxSetTestPatternOn(instance, instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode, + gtmdlHdmiTxDriverConfigTable[instance].pattern); + } + else + { + /* Restore last output format and mode */ + (void)dlHdmiTxSetTestPatternOff(instance, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.format, + instanceStatusInfoTx[instance].pVideoInfo->videoOutConfig.mode); + } + } + } +} +#endif + +#ifndef NO_HDCP +/****************************************************************************** + \brief Get hdcp seed. + + \param instance Instance identifier. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxFindHdcpSeed +( + tmInstance_t instance +) +{ +#if HDCP_SEED_DEFAULT == HDCP_SEED_NULL + UInt8 otp[3]; +#endif + + /* If no seed is coded in this file then find it somewhere else */ +#if HDCP_SEED_DEFAULT == HDCP_SEED_NULL + /* See if a seed table has been programmed in flash */ + if (kSeedTable[0][0] != 0xFFFF) + { + /* Read OTP LSB at address 0x00 and try to match in flash table */ + if ( (tmbslHdmiTxHdcpGetOtp(instance, + 0x00, otp)) == TM_OK) + { + int i; + for (i = 0; i < SEED_TABLE_LEN; i++) + { + if (kSeedTable[i][0] == otp[2]) /* OTP_DATA_LSB */ + { + /* Found seed! */ + gtmdlHdmiTxDriverConfigTable[instance].keySeed = kSeedTable[i][1]; + break; + } + } + } + } +#endif /* HDCP_SEED_DEFAULT != HDCP_SEED_NULL */ + + /* Initialise the TDA9984 HDCP keys */ + if (gtmdlHdmiTxDriverConfigTable[instance].keySeed != HDCP_SEED_NULL) + { + /* Initialise the HDMI Transmitter HDCP keys */ + tmbslHdmiTxHdcpDownloadKeys(instance, + gtmdlHdmiTxDriverConfigTable[instance].keySeed, HDMITX_HDCP_DECRYPT_ENABLE); + } +} +#endif /* NO_HDCP */ + +/****************************************************************************** + \brief Set the state of the state machine. + + \param instance Instance identifier. + \param state State of the state machine. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxSetState +( + tmInstance_t instance, + tmdlHdmiTxDriverState_t state +) +{ + /* Set the state */ + unitTableTx[instance].state = state; +} + +/****************************************************************************** + \brief Get the state of the state machine. + + \param instance Instance identifier. + + \return tmdlHdmiTxDriverState_t Current State of the state machine. + +******************************************************************************/ +tmdlHdmiTxDriverState_t dlHdmiTxGetState +( + tmInstance_t instance +) +{ + tmdlHdmiTxDriverState_t state; + + /* Get the state */ + state = unitTableTx[instance].state; + + return (state); +} + +/****************************************************************************** + \brief Get the state of the event (enabled or disabled). + + \param instance Instance identifier. + \param event Event to give the state. + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxEventStatus_t dlHdmiTxGetEventStatus +( + tmInstance_t instance, + tmdlHdmiTxEvent_t event +) +{ + tmdlHdmiTxEventStatus_t eventStatus; + + /* Get the event status */ + eventStatus = instanceStatusInfoTx[instance].pEventState[event].status; + + return (eventStatus); +} + +/****************************************************************************** + \brief Caculation of aspect ratio. + + \param HImageSize Horizontal image size. + \param VImageSize Vertical image size. + + \return NA. + +******************************************************************************/ +static tmdlHdmiTxPictAspectRatio_t dlHdmiTxCalcAspectRatio ( + UInt16 HImageSize, + UInt16 VImageSize +) +{ + tmdlHdmiTxPictAspectRatio_t pictureAspectRatio; + UInt16 calcPictureAspectRatio; + + /* Define picture Aspect Ratio */ + /* 16/9 = 1.77777 so the result approach is 2 */ + /* 4/3 = 1.33333 so the result approach is 1 */ + /* operation : */ + /* ImageSize + (vImageSize/2) */ + /* -------------------------- > vImageSize ->True 16/9 False 4/3 */ + /* 2 */ + + calcPictureAspectRatio = ((UInt16)(HImageSize + ((VImageSize)>>1)))>>1; + + if(calcPictureAspectRatio > VImageSize) + { + pictureAspectRatio = TMDL_HDMITX_P_ASPECT_RATIO_16_9; + } + else + { + pictureAspectRatio = TMDL_HDMITX_P_ASPECT_RATIO_4_3; + } + + return pictureAspectRatio; + +} + +#ifndef NO_HDCP +/****************************************************************************** + \brief dlHdmiTxCheckHdcpBksv . + + \param pHdcpBksvTested ksv To test. + \param pbBksvSecure Test result. + \param bBigEndian ksv provide by hardware are in little or big endian. + + \return NA. + +******************************************************************************/ +static void dlHdmiTxCheckHdcpBksv +( + tmInstance_t instance, + UInt8 * pHdcpBksvTested, + Bool * pbBksvSecure, + Bool bBigEndian +) +{ + + UInt32 NbInRevocationList; + + NbInRevocationList = 0; + + /* CBE: force secure, otherwise we will not look at anything */ + *pbBksvSecure = True; + + if ((unitTableTx[instance].revocationList.pList != Null) && (unitTableTx[instance].revocationList.length > 0)) + { + while ((*pbBksvSecure == True) && (NbInRevocationList < unitTableTx[instance].revocationList.length)) + { + if (bBigEndian) + { + if ((pHdcpBksvTested[0] == unitTableTx[instance].revocationList.pList[NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE]) + && + (pHdcpBksvTested[1] == unitTableTx[instance].revocationList.pList[1 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + && + (pHdcpBksvTested[2] == unitTableTx[instance].revocationList.pList[2 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + && + (pHdcpBksvTested[3] == unitTableTx[instance].revocationList.pList[3 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + && + (pHdcpBksvTested[4] == unitTableTx[instance].revocationList.pList[4 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + ) + { + *pbBksvSecure = False; + } + } + else + { + if ((pHdcpBksvTested[4] == unitTableTx[instance].revocationList.pList[NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE]) + && + (pHdcpBksvTested[3] == unitTableTx[instance].revocationList.pList[1 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + && + (pHdcpBksvTested[2] == unitTableTx[instance].revocationList.pList[2 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + && + (pHdcpBksvTested[1] == unitTableTx[instance].revocationList.pList[3 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + && + (pHdcpBksvTested[0] == unitTableTx[instance].revocationList.pList[4 + (NbInRevocationList * HDMITX_KSV_BYTES_PER_DEVICE)]) + ) + { + *pbBksvSecure = False; + } + } + NbInRevocationList++; + } + + } + + +} +#endif + +/****************************************************************************** + \brief dlHdmiTxCalcVidFmtIndex. + + \param vidFmt video format. + + \return table index. + +******************************************************************************/ +static tmdlHdmiTxVidFmt_t dlHdmiTxCalcVidFmtIndex(tmdlHdmiTxVidFmt_t vidFmt) +{ + tmdlHdmiTxVidFmt_t vidFmtIndex = vidFmt; + + /* Hanlde VIC or table index discontinuity */ + if((vidFmt >= TMDL_HDMITX_VFMT_60_1280x720p_24Hz) && (vidFmt <= TMDL_HDMITX_VFMT_62_1280x720p_30Hz)) + { + vidFmtIndex = (tmdlHdmiTxVidFmt_t)(TMDL_HDMITX_VFMT_INDEX_60_1280x720p_24Hz + (vidFmt - TMDL_HDMITX_VFMT_60_1280x720p_24Hz)); + } +#ifdef FORMAT_PC + else if (vidFmt >= TMDL_HDMITX_VFMT_PC_MIN) + { + vidFmtIndex = (tmdlHdmiTxVidFmt_t)(TMDL_HDMITX_VFMT_TV_NUM + (vidFmt - TMDL_HDMITX_VFMT_PC_MIN)); + } +#endif /* FORMAT_PC */ + return(vidFmtIndex); +} + + +tmErrorCode_t tmdlHdmiTxDebugEnableI2CAccesses ( tmInstance_t instance, + Bool enableI2C) +{ + tmErrorCode_t errCode = TM_OK; + + /* Check if instance number is in range */ + if( (instance < 0) || (instance >= MAX_UNITS) ) + { + errCode = TMDL_ERR_DLHDMITX_BAD_INSTANCE; + return errCode; + } + + if (enableI2C == True) + { + errCode = tmbslDebugWriteFakeRegPage(instance); + gI2CDebugAccessesEnabled = True; + } + else + { + gI2CDebugAccessesEnabled = False; + } + + + return errCode; + +} /* tmdlHdmiTxDebugManageI2CAccesses */ + +/*****************************************************************************/ +/** + \brief Retreives current HDCP link status. This function is typically used + when an "HDCP INACTIVE" event is received to know why HDCP + is INACTIVE. + + \param instance Instance identifier. + \param pHdcpStatus Pointer to the enum describing the status. + \param pRawStatus Pointer to the byte with the raw error code from HW. + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_BAD_HANDLE: the handle number is wrong + - TMDL_ERR_DLHDMITX_BAD_PARAMETER: a parameter is invalid or out + of range + - TMDL_ERR_DLHDMITX_NOT_INITIALIZED: the transmitter is not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetHdcpFailStatus +( + tmInstance_t instance, + tmdlHdmiTxHdcpStatus_t *pHdcpStatus, + UInt8 *pRawStatus +) +{ + tmErrorCode_t errCode = TM_OK; + +#ifndef NO_HDCP + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + RETIF(pHdcpStatus == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + RETIF(pRawStatus == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + *pRawStatus = hdcpInfoListTx[instance].hdcpErrorState; + + switch (hdcpInfoListTx[instance].hdcpErrorState) + { + + case 0: + *pHdcpStatus = TMDL_HDMITX_HDCP_OK; + break; + + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + *pHdcpStatus = TMDL_HDMITX_HDCP_BKSV_RCV_FAIL; + break; + + case 0x08: + *pHdcpStatus = TMDL_HDMITX_HDCP_BKSV_CHECK_FAIL; + break; + + case 0x0C: + *pHdcpStatus = TMDL_HDMITX_HDCP_BCAPS_RCV_FAIL; + break; + + case 0x0F: + case 0x10: + case 0x11: + *pHdcpStatus = TMDL_HDMITX_HDCP_AKSV_SEND_FAIL; + break; + + case 0x23: + case 0x24: + case 0x25: + *pHdcpStatus = TMDL_HDMITX_HDCP_R0_RCV_FAIL; + break; + + case 0x26: + *pHdcpStatus = TMDL_HDMITX_HDCP_R0_CHECK_FAIL; + break; + + case 0x27: + *pHdcpStatus = TMDL_HDMITX_HDCP_BKSV_NOT_SECURE; + break; + + case 0x2B: + case 0x2C: + case 0x2D: + *pHdcpStatus = TMDL_HDMITX_HDCP_RI_RCV_FAIL; + break; + + case 0x77: + case 0x78: + case 0x79: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_RI_RCV_FAIL; + break; + + case 0x2E: + *pHdcpStatus = TMDL_HDMITX_HDCP_RI_CHECK_FAIL; + break; + + case 0x7A: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_RI_CHECK_FAIL; + break; + + case 0x66: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_BCAPS_RCV_FAIL; + break; + + case 0x67: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_BCAPS_READY_TIMEOUT; + break; + + case 0x6A: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_V_RCV_FAIL; + break; + + case 0x6C: + case 0x6D: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_BSTATUS_RCV_FAIL; + break; + + case 0x6F: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_KSVLIST_RCV_FAIL; + break; + + case 0x74: + *pHdcpStatus = TMDL_HDMITX_HDCP_RPT_KSVLIST_NOT_SECURE; + break; + + default: + *pHdcpStatus = TMDL_HDMITX_HDCP_UNKNOWN_STATUS; + break; + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + +#else + (void)instance; /* Remove compiler warning */ +#endif /* NO_HDCP */ + + return errCode; +} + + +tmErrorCode_t tmdlHdmiTxGetEdidLatencyInfo +( + tmInstance_t instance, + tmdlHdmiTxEdidLatency_t *pLatency +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check pointer is Null */ + RETIF( pLatency == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetLatencyInfo(instance, (tmbslHdmiTxEdidLatency_t *) pLatency) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} /* tmdlHdmiTxGetEdidLatencyInfo */ + +/****************************************************************************** + \brief Retrieves additional data from receiver's EDID VSDB. This function + parses the EDID of Rx device to get the relevant data. + This function is synchronous. + This function is not ISR friendly. + + \param instance Instance identifier. + \param pExtraVsdbData Pointer to the structure of additional VSDB data + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_INSTANCE: the instance number is wrong or + out of range + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + - TMDL_ERR_DLHDMITX_INVALID_STATE: the state is invalid for + the function + - TMBSL_ERR_HDMI_BAD_PARAMETER: a parameter was out of range + - TMBSL_ERR_HDMI_BAD_UNIT_NUMBER: bad transmitter unit number + - TMBSL_ERR_HDMI_RESOURCE_NOT_AVAILABLE : EDID not read + - TMBSL_ERR_HDMI_NOT_INITIALIZED: transmitter not initialized + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxGetEdidExtraVsdbData +( + tmInstance_t instance, + tmdlHdmiTxEdidExtraVsdbData_t **pExtraVsdbData +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + /* Check pointer is Null */ + RETIF(pExtraVsdbData == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Check the current state */ + RETIF_SEM(dlHdmiTxItSemaphore[instance], + dlHdmiTxGetState(instance) != STATE_EDID_AVAILABLE, TMDL_ERR_DLHDMITX_INVALID_STATE) + + RETIF_SEM(dlHdmiTxItSemaphore[instance], + (errCode = tmbslHdmiTxEdidGetExtraVsdbData(instance, (tmbslHdmiTxEdidExtraVsdbData_t **)pExtraVsdbData) ) != TM_OK, errCode) + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; +} /* tmdlHdmiTxGetEdidExtraVsdbData */ + + +tmErrorCode_t tmdlHdmiTxGetHPDStatus +( + tmInstance_t instance, + tmdlHdmiTxHotPlug_t * pHPDStatus +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + RETIF( pHPDStatus== Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Get the HPD status from BSL driver */ + errCode = tmbslHdmiTxHotPlugGetStatus(instance,(tmbslHdmiTxHotPlug_t *)pHPDStatus,True); + + if (errCode == TM_OK) { + /* do nothing */ + } + else { + *pHPDStatus = TMDL_HDMITX_HOTPLUG_INVALID; + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; + +} /* tmdlHdmiTxGetHPDStatus */ + + + +tmErrorCode_t tmdlHdmiTxGetRXSenseStatus +( + tmInstance_t instance, + tmdlHdmiTxRxSense_t * pRXSenseStatus +) +{ + tmErrorCode_t errCode; + + /* Check if instance number is in range */ + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + RETIF( pRXSenseStatus== Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + + /* Take the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + /* Get the RXS sense status from BSL driver */ + errCode = tmbslHdmiTxRxSenseGetStatus(instance,( tmbslHdmiTxRxSense_t*)pRXSenseStatus,True); + + if (errCode == TM_OK) { + /* do nothing */ + } + else { + *pRXSenseStatus = TMDL_HDMITX_RX_SENSE_INVALID; + } + + /* Release the sempahore */ + RETIF( (errCode = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCode) + + return TM_OK; + +} /* tmdlHdmiTxGetRXSenseStatus */ + + +/****************************************************************************** + \brief Mute or unmute the TMDS outputs. + + \param instance Instance identifier. + \param muteTmdsOut Mute or unmute indication. + + \return NA. + +******************************************************************************/ +tmErrorCode_t tmdlHdmiTxTmdsSetOutputsMute +( + tmInstance_t instance, + Bool muteTmdsOut +) +{ + tmErrorCode_t errCode; + tmErrorCode_t errCodeSem; + tmbslHdmiTxTmdsOut_t tmdsOut; + + RETIF((instance < 0) || (instance >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_INSTANCE) + + if (muteTmdsOut) + tmdsOut = HDMITX_TMDSOUT_FORCED0; // forced 0 outputs + else + tmdsOut = HDMITX_TMDSOUT_NORMAL; // normal outputs + + /* Take the sempahore */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreP(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + errCode = tmbslHdmiTxTmdsSetOutputs (instance, tmdsOut); + + /* Release the sempahore */ + RETIF( (errCodeSem = tmdlHdmiTxIWSemaphoreV(dlHdmiTxItSemaphore[instance]) ) != TM_OK, errCodeSem) + + + return errCode; +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.c b/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.c new file mode 100755 index 0000000000000..2ddae86bec2b8 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.c @@ -0,0 +1,342 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_local.c + * + * \version Revision: 1 + * + * \date Date: 21/02/08 + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * + * \section info Change Information + * + * \verbatim + + History: tmdlHdmiTx_local.c + * + * ***************** Version 1 ***************** + * User: G. Burnouf Date: 21/02/08 + * Updated in $/Source/tmdlHdmiTx/src + * initial version + + \endverbatim + * +*/ + +/*============================================================================*/ +/* INCLUDE FILES */ +/*============================================================================*/ +#include "tmdlHdmiTx_local.h" +#include "tmdlHdmiTx_cfg.h" +#include "tmdlHdmiTx.h" + +/*============================================================================*/ +/* TYPES DECLARATIONS */ +/*============================================================================*/ + +typedef struct _dlHdmiTxResolution_t { + tmdlHdmiTxVidFmt_t resolutionID; + UInt16 width; + UInt16 height; + Bool interlaced; + tmdlHdmiTxVfreq_t vfrequency; + tmdlHdmiTxPictAspectRatio_t aspectRatio; +} dlHdmiTxResolution_t, *pdlHdmiTxResolution_t; + + +/*============================================================================*/ +/* CONSTANTS DECLARATIONS */ +/*============================================================================*/ +/* macro for quick error handling */ +#ifndef RETIF +#define RETIF(cond, rslt) if ((cond)){return (rslt);} +#endif + +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + +/******************************************************************************/ +/* DO NOT MODIFY */ +/******************************************************************************/ + +static void dlHdmiTxGenerateVideoPortTables +( + tmUnitSelect_t unit, + tmdlHdmiTxDriverConfigTable_t *pConfig +); + + +/*============================================================================*/ +/* VARIABLES DECLARATIONS */ +/*============================================================================*/ + +/** + * \brief List of the resolution to be detected by the device library + */ + +#ifdef TMFL_OS_WINDOWS /* OS Windows */ +dlHdmiTxResolution_t resolutionInfoTx[RESOLUTION_NB] = { +#else /* OS ARM7 */ +const dlHdmiTxResolution_t resolutionInfoTx[RESOLUTION_NB] = { +#endif /* endif TMFL_OS_WINDOWS */ + /* TV Formats */ + /* 60 HZ */ + {TMDL_HDMITX_VFMT_01_640x480p_60Hz, 640, 480, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_02_720x480p_60Hz, 720, 480, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_03_720x480p_60Hz, 720, 480, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_04_1280x720p_60Hz, 1280, 720, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_05_1920x1080i_60Hz, 1920, 1080, True, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_06_720x480i_60Hz, 720, 480, True, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_07_720x480i_60Hz, 720, 480, True, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_08_720x240p_60Hz, 720, 240, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_09_720x240p_60Hz, 720, 240, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_10_720x480i_60Hz, 720, 480, True, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_11_720x480i_60Hz, 720, 480, True, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_12_720x240p_60Hz, 720, 240, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_13_720x240p_60Hz, 720, 240, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_14_1440x480p_60Hz, 1440, 480, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_15_1440x480p_60Hz, 1440, 480, False, TMDL_HDMITX_VFREQ_59Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_16_1920x1080p_60Hz, 1920, 1080, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_35_2880x480p_60Hz, 2880, 480, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_36_2880x480p_60Hz, 2880, 480, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + + /* 50 HZ */ + {TMDL_HDMITX_VFMT_17_720x576p_50Hz, 720, 576, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_18_720x576p_50Hz, 720, 576, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_19_1280x720p_50Hz, 1280, 720, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_20_1920x1080i_50Hz, 1920, 1080, True, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_21_720x576i_50Hz, 720, 576, True, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_22_720x576i_50Hz, 720, 576, True, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_23_720x288p_50Hz, 720, 288, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_24_720x288p_50Hz, 720, 288, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_25_720x576i_50Hz, 720, 576, True, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_26_720x576i_50Hz, 720, 576, True, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_27_720x288p_50Hz, 720, 288, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_28_720x288p_50Hz, 720, 288, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_29_1440x576p_50Hz, 1440, 576, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_30_1440x576p_50Hz, 1440, 576, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_31_1920x1080p_50Hz, 1920, 1080, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_37_2880x576p_50Hz, 2880, 576, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_38_2880x576p_50Hz, 2880, 576, False, TMDL_HDMITX_VFREQ_50Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + + /* Low Tv */ + {TMDL_HDMITX_VFMT_32_1920x1080p_24Hz, 1920, 1080, False, TMDL_HDMITX_VFREQ_24Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_33_1920x1080p_25Hz, 1920, 1080, False, TMDL_HDMITX_VFREQ_25Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_34_1920x1080p_30Hz, 1920, 1080, False, TMDL_HDMITX_VFREQ_30Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_60_1280x720p_24Hz, 1280, 720, False, TMDL_HDMITX_VFREQ_24Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_61_1280x720p_25Hz, 1280, 720, False, TMDL_HDMITX_VFREQ_25Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_62_1280x720p_30Hz, 1280, 720, False, TMDL_HDMITX_VFREQ_30Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9} + +#ifdef FORMAT_PC + /* PC Formats */ + /* 60 HZ */ + ,{TMDL_HDMITX_VFMT_PC_640x480p_60Hz, 640, 480, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_800x600p_60Hz, 800, 600, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1152x960p_60Hz, 1152, 960, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_6_5}, + {TMDL_HDMITX_VFMT_PC_1024x768p_60Hz, 1024, 768, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1280x768p_60Hz, 1280, 768, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_5_3}, + {TMDL_HDMITX_VFMT_PC_1280x1024p_60Hz, 1280, 1024, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_5_4}, + {TMDL_HDMITX_VFMT_PC_1360x768p_60Hz, 1360, 768, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_9}, + {TMDL_HDMITX_VFMT_PC_1400x1050p_60Hz, 1400, 1050, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1600x1200p_60Hz, 1600, 1200, False, TMDL_HDMITX_VFREQ_60Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + /* 70 HZ */ + {TMDL_HDMITX_VFMT_PC_1024x768p_70Hz, 1024, 768, False, TMDL_HDMITX_VFREQ_70Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + /* 72 HZ */ + {TMDL_HDMITX_VFMT_PC_640x480p_72Hz, 640, 480, False, TMDL_HDMITX_VFREQ_72Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_800x600p_72Hz, 800, 600, False, TMDL_HDMITX_VFREQ_72Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + /* 75 HZ */ + {TMDL_HDMITX_VFMT_PC_640x480p_75Hz, 640, 480, False, TMDL_HDMITX_VFREQ_75Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1024x768p_75Hz, 1024, 768, False, TMDL_HDMITX_VFREQ_75Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_800x600p_75Hz, 800, 600, False, TMDL_HDMITX_VFREQ_75Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1024x864p_75Hz, 1024, 864, False, TMDL_HDMITX_VFREQ_75Hz, TMDL_HDMITX_P_ASPECT_RATIO_UNDEFINED}, + {TMDL_HDMITX_VFMT_PC_1280x1024p_75Hz, 1280, 1024, False, TMDL_HDMITX_VFREQ_75Hz, TMDL_HDMITX_P_ASPECT_RATIO_5_4}, + /* 85 HZ */ + {TMDL_HDMITX_VFMT_PC_640x350p_85Hz, 640, 350, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_UNDEFINED}, + {TMDL_HDMITX_VFMT_PC_640x400p_85Hz, 640, 400, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_16_10}, + {TMDL_HDMITX_VFMT_PC_720x400p_85Hz, 720, 400, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_9_5}, + {TMDL_HDMITX_VFMT_PC_640x480p_85Hz, 640, 480, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_800x600p_85Hz, 800, 600, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1024x768p_85Hz, 1024, 768, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1152x864p_85Hz, 1152, 864, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1280x960p_85Hz, 1280, 960, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3}, + {TMDL_HDMITX_VFMT_PC_1280x1024p_85Hz, 1280, 1024, False, TMDL_HDMITX_VFREQ_85Hz, TMDL_HDMITX_P_ASPECT_RATIO_5_4}, + /* 87 HZ */ + {TMDL_HDMITX_VFMT_PC_1024x768i_87Hz, 1024, 768, True, TMDL_HDMITX_VFREQ_87Hz, TMDL_HDMITX_P_ASPECT_RATIO_4_3} +#endif /* FORMAT_PC */ +}; + + +/*============================================================================*/ +/* FUNCTION */ +/*============================================================================*/ + +/******************************************************************************/ +/* DO NOT MODIFY */ +/****************************************************************************** + \brief This function allows to the main driver to retrieve its + configuration parameters. + + \param pConfig Pointer to the config structure + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t dlHdmiTxGetConfig +( + tmUnitSelect_t unit, + tmdlHdmiTxDriverConfigTable_t *pConfig +) +{ + /* Check if unit number is in range */ + RETIF((unit < 0) || (unit >= MAX_UNITS), TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER) + + /* Check if pointer is Null */ + RETIF(pConfig == Null, TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS) + + *pConfig = driverConfigTableTx[unit]; + + /* Done here because of const declaration of tables in ARM7 case */ + pConfig->pResolutionInfo = (ptmdlHdmiTxCfgResolution_t)resolutionInfoTx; + + /* Generate swap and mirror tables in function of video port mapping tables */ + dlHdmiTxGenerateVideoPortTables(unit, pConfig); + + return TM_OK; +} + + +/*============================================================================*/ +/* INTERNAL FUNCTION */ +/*============================================================================*/ +/******************************************************************************/ +/* DO NOT MODIFY */ +/******************************************************************************/ +static void dlHdmiTxGenerateVideoPortTables +( + tmUnitSelect_t unit, + tmdlHdmiTxDriverConfigTable_t *pConfig +) +{ + UInt8 i; + + for (i=0; i<6; i++) + { + /* CCIR656 */ + if (videoPortMapping_CCIR656[unit][i] != TMDL_HDMITX_VIDCCIR_NOT_CONNECTED) + { + pConfig->pSwapTableCCIR656[videoPortMapping_CCIR656[unit][i] & 0x07F] = 5-i; + pConfig->pMirrorTableCCIR656[videoPortMapping_CCIR656[unit][i] & 0x07F] = (UInt8)(videoPortMapping_CCIR656[unit][i] >> 7); + /* Enable port and disable ground port */ + if (((5-i) % 2) == 0) + { + pConfig->pEnableVideoPortCCIR656[i/2] |= 0x0F; + pConfig->pGroundVideoPortCCIR656[i/2] = (UInt8)(pConfig->pGroundVideoPortCCIR656[i/2] & 0xF0); + } + else + { + pConfig->pEnableVideoPortCCIR656[i/2] = (UInt8)(pConfig->pEnableVideoPortCCIR656[i/2] | 0xF0); + pConfig->pGroundVideoPortCCIR656[i/2] &= 0x0F; + } + } + + /* YUV422 */ + if (videoPortMapping_YUV422[unit][i] != TMDL_HDMITX_VID422_NOT_CONNECTED) + { + pConfig->pSwapTableYUV422[videoPortMapping_YUV422[unit][i] & 0x07F] = 5-i; + pConfig->pMirrorTableYUV422[videoPortMapping_YUV422[unit][i] & 0x07F] = (UInt8)(videoPortMapping_YUV422[unit][i] >> 7); + /* Enable port and disable ground port */ + if (((5-i) % 2) == 0) + { + pConfig->pEnableVideoPortYUV422[i/2] |= 0x0F; + pConfig->pGroundVideoPortYUV422[i/2] = (UInt8)(pConfig->pGroundVideoPortYUV422[i/2] & 0xF0); + } + else + { + pConfig->pEnableVideoPortYUV422[i/2] = (UInt8)(pConfig->pEnableVideoPortYUV422[i/2] | 0xF0); + pConfig->pGroundVideoPortYUV422[i/2] &= 0x0F; + } + } + + /* YUV444 */ + if (videoPortMapping_YUV444[unit][i] != TMDL_HDMITX_VID444_NOT_CONNECTED) + { + pConfig->pSwapTableYUV444[videoPortMapping_YUV444[unit][i] & 0x07F] = 5-i; + pConfig->pMirrorTableYUV444[videoPortMapping_YUV444[unit][i] & 0x07F] = (UInt8)(videoPortMapping_YUV444[unit][i] >> 7); + /* Enable port and disable ground port */ + if (((5-i) % 2) == 0) + { + pConfig->pEnableVideoPortYUV444[i/2] |= 0x0F; + pConfig->pGroundVideoPortYUV444[i/2] = (UInt8)(pConfig->pGroundVideoPortYUV444[i/2] & 0xF0); + } + else + { + pConfig->pEnableVideoPortYUV444[i/2] = (UInt8)(pConfig->pEnableVideoPortYUV444[i/2] | 0xF0); + pConfig->pGroundVideoPortYUV444[i/2] &= 0x0F; + } + } + + /* RGB444 */ + if (videoPortMapping_RGB444[unit][i] != TMDL_HDMITX_VID444_NOT_CONNECTED) + { + pConfig->pSwapTableRGB444[videoPortMapping_RGB444[unit][i] & 0x07F] = 5-i; + pConfig->pMirrorTableRGB444[videoPortMapping_RGB444[unit][i] & 0x07F] = (UInt8)(videoPortMapping_RGB444[unit][i] >> 7); + /* Enable port and disable ground port */ + if (((5-i) % 2) == 0) + { + pConfig->pEnableVideoPortRGB444[i/2] |= 0x0F; + pConfig->pGroundVideoPortRGB444[i/2] = (UInt8)(pConfig->pGroundVideoPortRGB444[i/2] & 0xF0); + } + else + { + pConfig->pEnableVideoPortRGB444[i/2] = (UInt8)(pConfig->pEnableVideoPortRGB444[i/2] | 0xF0); + pConfig->pGroundVideoPortRGB444[i/2] &= 0x0F; + } + } + + +#ifdef TMFL_RGB_DDR_12BITS + /* RGB DDR 12bits */ + if (VideoPortMapping_RGB_DDR_12bits[unit][i] != TMDL_HDMITX_VID_DDR_NOT_CONNECTED) + { + pConfig->pSwapTableRGB_DDR_12bits[VideoPortMapping_RGB_DDR_12bits[unit][i] & 0x07F] = 5-i; + pConfig->pMirrorTableRGB_DDR_12bits[VideoPortMapping_RGB_DDR_12bits[unit][i] & 0x07F] = (UInt8)(VideoPortMapping_RGB_DDR_12bits[unit][i] >> 7); + /* Enable port and disable ground port */ + if (((5-i) % 2) == 0) + { + pConfig->pEnableVideoPortRGB_DDR_12bits[i/2] |= 0x0F; + pConfig->pGroundVideoPortRGB_DDR_12bits[i/2] = (UInt8)(pConfig->pGroundVideoPortRGB_DDR_12bits[i/2] & 0xF0); + } + else + { + pConfig->pEnableVideoPortRGB_DDR_12bits[i/2] = (UInt8)(pConfig->pEnableVideoPortRGB_DDR_12bits[i/2] | 0xF0); + pConfig->pGroundVideoPortRGB_DDR_12bits[i/2] &= 0x0F; + } + } +#endif + } + +#ifdef TMFL_RGB_DDR_12BITS + /* VIP internal mux for RGB DDR */ + pConfig->pNoMux = (UInt8*)&VideoPortNoMux[unit]; + pConfig->pMux_RGB_DDR_12bits = (UInt8*)&VideoPortMux_RGB_DDR_12bits[unit]; +#endif + +} + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.h b/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.h new file mode 100755 index 0000000000000..ccda7bf1e4b45 --- /dev/null +++ b/drivers/video/nxp/comps/tmdlHdmiTx/src/tmdlHdmiTx_local.h @@ -0,0 +1,702 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * \file tmdlHdmiTx_local.h + * + * \version $Revision: 1 $ + * + * \date $Date: 02/08/07 08:32 $ + * + * \brief devlib driver component API for the TDA998x HDMI Transmitters + * + * \section refs Reference Documents + * HDMI Tx Driver - FRS.doc, + * + * \section info Change Information + * + * \verbatim + + $History: tmdlHdmiTx_local.h $ + * + * ***************** Version 13 ***************** + * User: J. Lamotte Date: 02/08/07 Time: 08:32 + * Updated in $/Source/tmdlHdmiTx/inc + * initial version + * + + \endverbatim + * +*/ + +#ifndef TMDLHDMITX_LOCAL_H +#define TMDLHDMITX_LOCAL_H + +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#include +#endif + +#include "tmdlHdmiTx_IW.h" +#include "tmNxTypes.h" +#include "tmdlHdmiTx_Types.h" +#include "tmdlHdmiTx_cfg.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*============================================================================*/ +/* MACRO DEFINITIONS */ +/*============================================================================*/ + +/* Version of the SW driver */ +#define VERSION_COMPATIBILITY 0 +#define VERSION_MAJOR 5 +#define VERSION_MINOR 3 + +/* Invalid HDCP seed */ +#define HDCP_SEED_NULL 0 + +/* A default seed value may be defined here, or set to HDCP_SEED_NULL. + * If HDCP_SEED_NULL, a table of seeds may instead be programmed separately + * into flash at the location of kSeedTable, below */ +#define HDCP_SEED_DEFAULT HDCP_SEED_NULL + +/* Default SHA-1 test handling */ +#define HDCP_OPT_DEFAULT ( TMDL_HDMITX_HDCP_OPTION_FORCE_PJ_IGNORED \ + | TMDL_HDMITX_HDCP_OPTION_FORCE_VSLOW_DDC \ + | TMDL_HDMITX_HDCP_OPTION_FORCE_NO_1_1 ) + +/** + * A macro to check a condition and if true return a result + */ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#define RETIF(cond, rslt) if ((cond)){ \ + printk(KERN_INFO "%s %d\n",__func__,__LINE__); \ + return (rslt);} +#else +#define RETIF(cond, rslt) if ((cond)){return (rslt);} +#endif + +/** + * A macro to check a condition and if true return + * TMDL_ERR_DLHDMITX_BAD_PARAMETER. + * To save code space, it can be compiled out by defining NO_RETIF_BADPARAM on + * the compiler command line. + */ +#ifdef NO_RETIF_BADPARAM +#define RETIF_BADPARAM(cond) +#else +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#define RETIF_BADPARAM(cond) if ((cond)){ \ + printk(KERN_INFO "%s %d\n",__func__,__LINE__); \ + return TMDL_ERR_DLHDMITX_BAD_PARAMETER;} +#else +#define RETIF_BADPARAM(cond) if ((cond)){return TMDL_ERR_DLHDMITX_BAD_PARAMETER;} +#endif +#endif + +/** + * A macro to check a condition and if true, release the semaphore describe by handle and return a result + */ +#ifdef TMFL_LINUX_OS_KERNEL_DRIVER +#define RETIF_SEM(handle, cond, rslt) if ((cond)){ \ + tmdlHdmiTxIWSemaphoreV(handle); \ + printk(KERN_INFO "%s %d\n",__func__,__LINE__); \ + return (rslt);} +#else +#define RETIF_SEM(handle, cond, rslt) if ((cond)){tmdlHdmiTxIWSemaphoreV(handle); return (rslt);} +#endif + + /* Resolution supported */ +#ifndef FORMAT_PC +#define RESOLUTION_NB 41 +#else +#define RESOLUTION_NB 68 +#endif /* FORMAT_PC */ + +/* Instance number */ +#define INSTANCE_0 0 +#define INSTANCE_1 1 + +#ifdef HDMI_TX_REPEATER_ISR_MODE +/* Number of event */ +#define EVENT_NB 10 +#else /* HDMI_TX_REPEATER_ISR_MODE */ +/* Number of event */ +#define EVENT_NB 9 +#endif /* HDMI_TX_REPEATER_ISR_MODE */ + +/* Size of a KSV is five bytes */ +#define KSV_SIZE 5 + +/* Arbitrary short TV format values */ +#define TV_INVALID 0 +#define TV_VGA_60Hz 1 +#define TV_240p_60Hz 2 +#define TV_480p_60Hz 3 +#define TV_480i_60Hz 4 +#define TV_720p_60Hz 5 +#define TV_1080p_60Hz 6 +#define TV_1080i_60Hz 7 +#define TV_288p_50Hz 8 +#define TV_576p_50Hz 9 +#define TV_576i_50Hz 10 +#define TV_720p_50Hz 11 +#define TV_1080p_50Hz 12 +#define TV_1080i_50Hz 13 + +/* Shorthands for vinMode values in tmbslTDA9984.h */ +#define iINVALID TMDL_HDMITX_VINMODE_INVALID +#define iCCIR656 TMDL_HDMITX_VINMODE_CCIR656 +#define iRGB444 TMDL_HDMITX_VINMODE_RGB444 +#define iYUV444 TMDL_HDMITX_VINMODE_YUV444 +#define iYUV422 TMDL_HDMITX_VINMODE_YUV422 + +/* Shorthands for input sync */ +#define EMB 1 +#define EXT 0 + +/* Shorthands for single/double pixel rate in tmbslTDA9984.h */ +#define SINGLE TMDL_HDMITX_PIXRATE_SINGLE +#define DOUBLE TMDL_HDMITX_PIXRATE_DOUBLE + +/* Shorthands for sampling frequency in tmdlHdmiTxSetAudioInput API */ +#define AIF_SF_REFER_TO_STREAM_HEADER 0 +#define AIF_SF_32K 1 +#define AIF_SF_44K 2 +#define AIF_SF_48K 3 +#define AIF_SF_88K 4 +#define AIF_SF_96K 5 +#define AIF_SF_176K 6 +#define AIF_SF_192K 7 + +/* HDCP check interval in milliseconds */ +#define HDCP_CHECK_INTERVAL_MS 2500 + +/* Number of HDCP checks to carry out after HDCP is started */ +#define HDCP_NUM_CHECKS 5 + +#define TMDL_HDMITX_CHANNELALLOC_LUT_SIZE 32 + + +static CONST_DAT UInt8 kChanAllocChanNum[TMDL_HDMITX_CHANNELALLOC_LUT_SIZE] = \ +{2,3,3,4,3,4,4,5,4,5,5,6,5,6,6,7,6,7,7,8,4,5,5,6,5,6,6,7,6,7,7,8 }; + + +/** + * Lookup table to convert from EIA/CEA TV video format to + * aspect ratio used in video infoframe: + * Aspect ratio 1=4:3, 2=16:9 + */ +#ifndef FORMAT_PC +static CONST_DAT UInt8 kVfmtToAspect_TV[TMDL_HDMITX_VFMT_TV_NUM] = +#else /* FORMAT_PC */ +static CONST_DAT UInt8 kVfmtToAspect_TV[TMDL_HDMITX_VFMT_TV_NUM + TMDL_HDMITX_VFMT_PC_NUM] = +#endif /* FORMAT_PC */ +{ + 0, /* HDMITX_VFMT_NULL */ + 1, /* HDMITX_VFMT_01_640x480p_60Hz */ + 1, /* HDMITX_VFMT_02_720x480p_60Hz */ + 2, /* HDMITX_VFMT_03_720x480p_60Hz */ + 2, /* HDMITX_VFMT_04_1280x720p_60Hz */ + 2, /* HDMITX_VFMT_05_1920x1080i_60Hz */ + 1, /* HDMITX_VFMT_06_720x480i_60Hz */ + 2, /* HDMITX_VFMT_07_720x480i_60Hz */ + 1, /* HDMITX_VFMT_08_720x240p_60Hz */ + 2, /* HDMITX_VFMT_09_720x240p_60Hz */ + 1, /* HDMITX_VFMT_10_720x480i_60Hz */ + 2, /* HDMITX_VFMT_11_720x480i_60Hz */ + 1, /* HDMITX_VFMT_12_720x240p_60Hz */ + 2, /* HDMITX_VFMT_13_720x240p_60Hz */ + 1, /* HDMITX_VFMT_14_1440x480p_60Hz */ + 2, /* HDMITX_VFMT_15_1440x480p_60Hz */ + 2, /* HDMITX_VFMT_16_1920x1080p_60Hz */ + 1, /* HDMITX_VFMT_17_720x576p_50Hz */ + 2, /* HDMITX_VFMT_18_720x576p_50Hz */ + 2, /* HDMITX_VFMT_19_1280x720p_50Hz */ + 2, /* HDMITX_VFMT_20_1920x1080i_50Hz */ + 1, /* HDMITX_VFMT_21_720x576i_50Hz */ + 2, /* HDMITX_VFMT_22_720x576i_50Hz */ + 1, /* HDMITX_VFMT_23_720x288p_50Hz */ + 2, /* HDMITX_VFMT_24_720x288p_50Hz */ + 1, /* HDMITX_VFMT_25_720x576i_50Hz */ + 2, /* HDMITX_VFMT_26_720x576i_50Hz */ + 1, /* HDMITX_VFMT_27_720x288p_50Hz */ + 2, /* HDMITX_VFMT_28_720x288p_50Hz */ + 1, /* HDMITX_VFMT_29_1440x576p_50Hz */ + 2, /* HDMITX_VFMT_30_1440x576p_50Hz */ + 2, /* HDMITX_VFMT_31_1920x1080p_50Hz */ + 2, /* HDMITX_VFMT_32_1920x1080p_24Hz */ + 2, /* HDMITX_VFMT_33_1920x1080p_25Hz */ + 2, /* HDMITX_VFMT_34_1920x1080p_30Hz */ + + 1, /* TMDL_HDMITX_VFMT_35_2880x480p_60Hz */ + 2, /* TMDL_HDMITX_VFMT_36_2880x480p_60Hz */ + 1, /* TMDL_HDMITX_VFMT_37_2880x576p_50Hz */ + 2, /* TMDL_HDMITX_VFMT_38_2880x576p_50Hz */ + + 2, /* TMDL_HDMITX_VFMT_60_1280x720p_24HZ */ + 2, /* TMDL_HDMITX_VFMT_61_1280_720p_25HZ */ + 2 /* TMDL_HDMITX_VFMT_62_1280_720p_30HZ */ + +#ifdef FORMAT_PC + ,1, /* HDMITX_VFMT_PC_640x480p_60Hz */ + 1, /* HDMITX_VFMT_PC_800x600p_60Hz */ + 1, /* HDMITX_VFMT_PC_1152x960p_60Hz */ + 1, /* HDMITX_VFMT_PC_1024x768p_60Hz */ + 1, /* HDMITX_VFMT_PC_1280x768p_60Hz */ + 1, /* HDMITX_VFMT_PC_1280x1024p_60Hz */ + 1, /* HDMITX_VFMT_PC_1360x768p_60Hz */ + 1, /* HDMITX_VFMT_PC_1400x1050p_60Hz */ + 1, /* HDMITX_VFMT_PC_1600x1200p_60Hz */ + 1, /* HDMITX_VFMT_PC_1024x768p_70Hz */ + 1, /* HDMITX_VFMT_PC_640x480p_72Hz */ + 1, /* HDMITX_VFMT_PC_800x600p_72Hz */ + 1, /* HDMITX_VFMT_PC_640x480p_75Hz */ + 1, /* HDMITX_VFMT_PC_1024x768p_75Hz */ + 1, /* HDMITX_VFMT_PC_800x600p_75Hz */ + 1, /* HDMITX_VFMT_PC_1024x864p_75Hz */ + 1, /* HDMITX_VFMT_PC_1280x1024p_75Hz */ + 1, /* HDMITX_VFMT_PC_640x350p_85Hz */ + 1, /* HDMITX_VFMT_PC_640x400p_85Hz */ + 1, /* HDMITX_VFMT_PC_720x400p_85Hz */ + 1, /* HDMITX_VFMT_PC_640x480p_85Hz */ + 1, /* HDMITX_VFMT_PC_800x600p_85Hz */ + 1, /* HDMITX_VFMT_PC_1024x768p_85Hz */ + 1, /* HDMITX_VFMT_PC_1152x864p_85Hz */ + 1, /* HDMITX_VFMT_PC_1280x960p_85Hz */ + 1, /* HDMITX_VFMT_PC_1280x1024p_85Hz */ + 1 /* HDMITX_VFMT_PC_1024x768i_87Hz */ +#endif /* FORMAT_PC */ +}; + +/** + * Lookup table to convert from EIA/CEA TV video format to + * the short format of resolution/interlace/frequency + */ +static CONST_DAT UInt8 kVfmtToShortFmt_TV[TMDL_HDMITX_VFMT_TV_NUM] = +{ + TV_INVALID, /* HDMITX_VFMT_NULL */ + TV_VGA_60Hz, /* HDMITX_VFMT_01_640x480p_60Hz */ + TV_480p_60Hz, /* HDMITX_VFMT_02_720x480p_60Hz */ + TV_480p_60Hz, /* HDMITX_VFMT_03_720x480p_60Hz */ + TV_720p_60Hz, /* HDMITX_VFMT_04_1280x720p_60Hz */ + TV_1080i_60Hz, /* HDMITX_VFMT_05_1920x1080i_60Hz */ + TV_480i_60Hz, /* HDMITX_VFMT_06_720x480i_60Hz */ + TV_480i_60Hz, /* HDMITX_VFMT_07_720x480i_60Hz */ + TV_240p_60Hz, /* HDMITX_VFMT_08_720x240p_60Hz */ + TV_240p_60Hz, /* HDMITX_VFMT_09_720x240p_60Hz */ + TV_480i_60Hz, /* HDMITX_VFMT_10_720x480i_60Hz */ + TV_480i_60Hz, /* HDMITX_VFMT_11_720x480i_60Hz */ + TV_240p_60Hz, /* HDMITX_VFMT_12_720x240p_60Hz */ + TV_240p_60Hz, /* HDMITX_VFMT_13_720x240p_60Hz */ + TV_480p_60Hz, /* HDMITX_VFMT_14_1440x480p_60Hz */ + TV_480p_60Hz, /* HDMITX_VFMT_15_1440x480p_60Hz */ + TV_1080p_60Hz, /* HDMITX_VFMT_16_1920x1080p_60Hz */ + TV_576p_50Hz, /* HDMITX_VFMT_17_720x576p_50Hz */ + TV_576p_50Hz, /* HDMITX_VFMT_18_720x576p_50Hz */ + TV_720p_50Hz, /* HDMITX_VFMT_19_1280x720p_50Hz */ + TV_1080i_50Hz, /* HDMITX_VFMT_20_1920x1080i_50Hz */ + TV_576i_50Hz, /* HDMITX_VFMT_21_720x576i_50Hz */ + TV_576i_50Hz, /* HDMITX_VFMT_22_720x576i_50Hz */ + TV_288p_50Hz, /* HDMITX_VFMT_23_720x288p_50Hz */ + TV_288p_50Hz, /* HDMITX_VFMT_24_720x288p_50Hz */ + TV_576i_50Hz, /* HDMITX_VFMT_25_720x576i_50Hz */ + TV_576i_50Hz, /* HDMITX_VFMT_26_720x576i_50Hz */ + TV_288p_50Hz, /* HDMITX_VFMT_27_720x288p_50Hz */ + TV_288p_50Hz, /* HDMITX_VFMT_28_720x288p_50Hz */ + TV_576p_50Hz, /* HDMITX_VFMT_29_1440x576p_50Hz */ + TV_576p_50Hz, /* HDMITX_VFMT_30_1440x576p_50Hz */ + TV_1080p_50Hz, /* HDMITX_VFMT_31_1920x1080p_50Hz */ + TV_INVALID, /* HDMITX_VFMT_NULL */ + TV_INVALID, /* HDMITX_VFMT_NULL */ + TV_INVALID, /* HDMITX_VFMT_NULL */ + TV_480p_60Hz, /* HDMITX_VFMT_35_2880x480p_60Hz */ + TV_480p_60Hz, /* HDMITX_VFMT_36_2880x480p_60Hz */ + TV_576p_50Hz, /* HDMITX_VFMT_37_2880x576p_50Hz */ + TV_576p_50Hz, /* HDMITX_VFMT_38_2880x576p_50Hz */ + TV_INVALID, /* HDMITX_VFMT_NULL */ + TV_INVALID, /* HDMITX_VFMT_NULL */ + TV_INVALID /* HDMITX_VFMT_NULL */ +}; + +/** + * Macro to pack vinMode(0-5), pixRate(0-1), syncIn(0-1) and bVerified(0-1) + * into a byte + */ +#define PKBYTE(mode,rate,sync,verf) (((rate)<<7)|((sync)<<6)|((verf)<<5)|((mode)&0x1F)) + +/** + * Macros to unpack vinMode(0-5), pixRate(0-1), syncIn(0-1) and bVerified(0-1) + * from a byte + */ +#define UNPKRATE(byte) (((byte)>>7)&1) +#define UNPKSYNC(byte) (((byte)>>6)&1) +#define UNPKVERF(byte) (((byte)>>5)&1) +#define UNPKMODE(byte) ((byte)&0x1F) + +/** + * Lookup table to match main video settings and look up sets of + * Refpix and Refline values + */ +static CONST_DAT struct +{ + /* Values to match */ + UInt8 modeRateSyncVerf; /* Packed vinMode, pixRate, syncIn, bVerified */ + UInt8 shortVinFmt; + UInt8 shortVoutFmt; + /* Values to look up */ + UInt16 refPix; /* Output values */ + UInt16 refLine; + UInt16 scRefPix; /* Scaler values */ + UInt16 scRefLine; +} kRefpixRefline [] = +{ + /*************************************************************/ + /** Rows formatted in "Refpix_Refline.xls" and pasted here **/ + /** DO NOT DELETE ANY ROWS, to keep all scaler combinations **/ + /*************************************************************/ + /* mode_____Rate___Sync_Verf shortVinFmt shortVoutFmt refPix refLine scRefPix scRefLine Test ID */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480i_60Hz, TV_480p_60Hz, 0x08b, 0x024, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480i_60Hz, TV_720p_60Hz, 0x08b, 0x012, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480i_60Hz, TV_1080i_60Hz, 0x08b, 0x00e, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480i_60Hz, TV_1080p_60Hz, 0x08b, 0x021, 0x078, 0x017}, /* */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480p_60Hz, TV_720p_60Hz, 0x08b, 0x017, 0x078, 0x02c}, /* VID_F_01 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480p_60Hz, TV_1080i_60Hz, 0x08b, 0x013, 0x078, 0x02c}, /* VID_F_01 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_480p_60Hz, TV_1080p_60Hz, 0x08b, 0x027, 0x07A, 0x02c}, /* */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576i_50Hz, TV_576p_50Hz, 0x091, 0x026, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576i_50Hz, TV_720p_50Hz, 0x091, 0x013, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576i_50Hz, TV_1080i_50Hz, 0x091, 0x00f, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576i_50Hz, TV_1080p_50Hz, 0x091, 0x022, 0x085, 0x018}, /* */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576p_50Hz, TV_720p_50Hz, 0x091, 0x019, 0x085, 0x02e}, /* VID_F_06 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576p_50Hz, TV_1080i_50Hz, 0x091, 0x014, 0x085, 0x02e}, /* VID_F_06 */ + {PKBYTE(iCCIR656,SINGLE,EMB, 1), TV_576p_50Hz, TV_1080p_50Hz, 0x091, 0x028, 0x087, 0x02e}, /* */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480i_60Hz, TV_480p_60Hz, 0x014, 0x20d, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480i_60Hz, TV_720p_60Hz, 0x014, 0x2cb, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480i_60Hz, TV_1080i_60Hz, 0x014, 0x44c, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480i_60Hz, TV_1080p_60Hz, 0x014, 0x436, 0x359, 0x004}, /* */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480p_60Hz, TV_720p_60Hz, 0x011, 0x2d3, 0x358, 0x007}, /* VID_F_01 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480p_60Hz, TV_1080i_60Hz, 0x011, 0x452, 0x358, 0x007}, /* VID_F_01 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_480p_60Hz, TV_1080p_60Hz, 0x011, 0x43e, 0x358, 0x007}, /* */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576i_50Hz, TV_576p_50Hz, 0x00d, 0x26b, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576i_50Hz, TV_720p_50Hz, 0x00d, 0x2cb, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576i_50Hz, TV_1080i_50Hz, 0x00d, 0x44b, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576i_50Hz, TV_1080p_50Hz, 0x00d, 0x435, 0x35f, 0x001}, /* */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576p_50Hz, TV_720p_50Hz, 0x00d, 0x2d1, 0x35f, 0x001}, /* VID_F_06 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576p_50Hz, TV_1080i_50Hz, 0x00d, 0x451, 0x35f, 0x001}, /* VID_F_06 */ + {PKBYTE(iCCIR656,SINGLE,EXT, 1), TV_576p_50Hz, TV_1080p_50Hz, 0x00d, 0x43d, 0x35f, 0x001}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480i_60Hz, TV_480p_60Hz, 0x08b, 0x024, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480i_60Hz, TV_720p_60Hz, 0x08b, 0x012, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480i_60Hz, TV_1080i_60Hz, 0x08b, 0x00e, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480i_60Hz, TV_1080p_60Hz, 0x08b, 0x021, 0x078, 0x017}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480p_60Hz, TV_720p_60Hz, 0x08b, 0x017, 0x078, 0x02c}, /* VID_F_01 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480p_60Hz, TV_1080i_60Hz, 0x08b, 0x013, 0x078, 0x02c}, /* VID_F_01 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_480p_60Hz, TV_1080p_60Hz, 0x08b, 0x027, 0x07A, 0x02c}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576i_50Hz, TV_576p_50Hz, 0x091, 0x026, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576i_50Hz, TV_720p_50Hz, 0x091, 0x013, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576i_50Hz, TV_1080i_50Hz, 0x091, 0x00f, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576i_50Hz, TV_1080p_50Hz, 0x091, 0x022, 0x085, 0x018}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576p_50Hz, TV_720p_50Hz, 0x091, 0x019, 0x085, 0x02e}, /* VID_F_06 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576p_50Hz, TV_1080i_50Hz, 0x091, 0x014, 0x085, 0x02e}, /* VID_F_06 */ + {PKBYTE(iCCIR656,DOUBLE,EMB, 1), TV_576p_50Hz, TV_1080p_50Hz, 0x091, 0x028, 0x087, 0x02e}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480i_60Hz, TV_480p_60Hz, 0x014, 0x20d, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480i_60Hz, TV_720p_60Hz, 0x014, 0x2cb, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480i_60Hz, TV_1080i_60Hz, 0x014, 0x44c, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480i_60Hz, TV_1080p_60Hz, 0x014, 0x436, 0x359, 0x004}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480p_60Hz, TV_720p_60Hz, 0x011, 0x2d3, 0x358, 0x007}, /* VID_F_01 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480p_60Hz, TV_1080i_60Hz, 0x011, 0x452, 0x358, 0x007}, /* VID_F_01 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_480p_60Hz, TV_1080p_60Hz, 0x011, 0x43e, 0x358, 0x007}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576i_50Hz, TV_576p_50Hz, 0x00d, 0x26b, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576i_50Hz, TV_720p_50Hz, 0x00d, 0x2cb, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576i_50Hz, TV_1080i_50Hz, 0x00d, 0x44b, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576i_50Hz, TV_1080p_50Hz, 0x00d, 0x435, 0x35f, 0x001}, /* */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576p_50Hz, TV_720p_50Hz, 0x00d, 0x2d1, 0x35f, 0x001}, /* VID_F_06 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576p_50Hz, TV_1080i_50Hz, 0x00d, 0x451, 0x35f, 0x001}, /* VID_F_06 */ + {PKBYTE(iCCIR656,DOUBLE,EXT, 1), TV_576p_50Hz, TV_1080p_50Hz, 0x00d, 0x43d, 0x35f, 0x001}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480i_60Hz, TV_480p_60Hz, 0x08d, 0x028, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480i_60Hz, TV_720p_60Hz, 0x08d, 0x014, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480i_60Hz, TV_1080i_60Hz, 0x08d, 0x010, 0x078, 0x017}, /* VID_F_04 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480i_60Hz, TV_1080p_60Hz, 0x08d, 0x021, 0x078, 0x017}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480p_60Hz, TV_720p_60Hz, 0x08d, 0x017, 0x078, 0x02c}, /* VID_F_01 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480p_60Hz, TV_1080i_60Hz, 0x08d, 0x014, 0x078, 0x02c}, /* VID_F_01 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_480p_60Hz, TV_1080p_60Hz, 0x08d, 0x027, 0x07C, 0x02c}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576i_50Hz, TV_576p_50Hz, 0x093, 0x02a, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576i_50Hz, TV_720p_50Hz, 0x093, 0x013, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576i_50Hz, TV_1080i_50Hz, 0x093, 0x00e, 0x085, 0x018}, /* VID_F_09 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576i_50Hz, TV_1080p_50Hz, 0x093, 0x022, 0x085, 0x018}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576p_50Hz, TV_720p_50Hz, 0x093, 0x019, 0x085, 0x02e}, /* VID_F_06 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576p_50Hz, TV_1080i_50Hz, 0x093, 0x014, 0x085, 0x02e}, /* VID_F_06 */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_576p_50Hz, TV_1080p_50Hz, 0x093, 0x028, 0x089, 0x02e}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_720p_50Hz, TV_1080p_50Hz, 0x2bf, 0x024, 0x105, 0x019}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_720p_60Hz, TV_1080p_60Hz, 0x175, 0x024, 0x105, 0x019}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_1080i_50Hz, TV_1080p_50Hz, 0x2d3, 0x023, 0x0c3, 0x014}, /* */ + {PKBYTE(iYUV422, SINGLE,EMB, 1), TV_1080i_60Hz, TV_1080p_60Hz, 0x11b, 0x023, 0x0c3, 0x014}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480i_60Hz, TV_480p_60Hz, 0x016, 0x20d, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480i_60Hz, TV_720p_60Hz, 0x016, 0x2cb, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480i_60Hz, TV_1080i_60Hz, 0x016, 0x44c, 0x359, 0x004}, /* VID_F_04 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480i_60Hz, TV_1080p_60Hz, 0x016, 0x436, 0x359, 0x004}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480p_60Hz, TV_720p_60Hz, 0x013, 0x2d3, 0x358, 0x007}, /* VID_F_01 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480p_60Hz, TV_1080i_60Hz, 0x013, 0x452, 0x358, 0x007}, /* VID_F_01 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_480p_60Hz, TV_1080p_60Hz, 0x013, 0x43e, 0x358, 0x007}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576i_50Hz, TV_576p_50Hz, 0x00f, 0x26b, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576i_50Hz, TV_720p_50Hz, 0x00f, 0x2cb, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576i_50Hz, TV_1080i_50Hz, 0x00f, 0x44b, 0x35f, 0x001}, /* VID_F_09 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576i_50Hz, TV_1080p_50Hz, 0x00f, 0x435, 0x35f, 0x001}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576p_50Hz, TV_720p_50Hz, 0x00f, 0x2d1, 0x35f, 0x001}, /* VID_F_06 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576p_50Hz, TV_1080i_50Hz, 0x00f, 0x451, 0x35f, 0x001}, /* VID_F_06 */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_576p_50Hz, TV_1080p_50Hz, 0x00f, 0x43d, 0x35f, 0x001}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_720p_50Hz, TV_1080p_50Hz, 0x1bb, 0x463, 0x7bb, 0x000}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_720p_60Hz, TV_1080p_60Hz, 0x071, 0x463, 0x671, 0x000}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_1080i_50Hz, TV_1080p_50Hz, 0x213, 0x460, 0xa4f, 0x000}, /* */ + {PKBYTE(iYUV422, SINGLE,EXT, 1), TV_1080i_60Hz, TV_1080p_60Hz, 0x05b, 0x460, 0x897, 0x000}, /* */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV422, DOUBLE,EMB, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV422, DOUBLE,EXT, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, SINGLE,EMB, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, SINGLE,EXT, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, DOUBLE,EMB, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iYUV444, DOUBLE,EXT, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, SINGLE,EMB, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_480p_60Hz, TV_VGA_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, SINGLE,EXT, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, DOUBLE,EMB, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_480i_60Hz, TV_480p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_480i_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_480i_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_04 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_480p_60Hz, TV_720p_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_480p_60Hz, TV_1080i_60Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_01 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_576i_50Hz, TV_576p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_576i_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_576i_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_09 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_576p_50Hz, TV_720p_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iRGB444, DOUBLE,EXT, 0), TV_576p_50Hz, TV_1080i_50Hz, 0x000, 0x000, 0x000, 0x000}, /* VID_F_06 */ + {PKBYTE(iINVALID,DOUBLE,EMB, 0), TV_INVALID, TV_INVALID, 0x000, 0x000, 0x000, 0x000} /* EndTable */ +}; + + +/*============================================================================*/ +/* ENUM OR TYPE DEFINITIONS */ +/*============================================================================*/ +/* Enum listing all the type of colorimetry */ +typedef enum +{ + TMDL_HDMITX_COLORIMETRY_NO_DATA = 0, + TMDL_HDMITX_COLORIMETRY_ITU601 = 1, + TMDL_HDMITX_COLORIMETRY_ITU709 = 2, + TMDL_HDMITX_COLORIMETRY_EXTENDED = 3 +} tmdlHdmiTxColorimetry_t; + +/* Possible states of the state machine */ +typedef enum +{ + STATE_NOT_INITIALIZED, /**< Driver is not initialized */ + STATE_INITIALIZED, /**< Driver is initialized */ + STATE_UNPLUGGED, /**< Receiver device not connected */ + STATE_PLUGGED, /**< Receiver device connected, clock lock */ + STATE_EDID_AVAILABLE /**< Managed to read receiver's EDID */ +} tmdlHdmiTxDriverState_t; + +/* revocation list structure */ +typedef struct +{ + UInt8* pList; + UInt32 length; +} revocationList_t; + + +/* unit configuration structure */ +typedef struct +{ + Bool opened; /**< Is unit instanciated ? */ + Bool hdcpEnable; /**< Is HDCP enabled ? */ + tmdlHdmiTxHdcpOptions_t hdcpOptions; /**< HDCP options */ + Bool repeaterEnable; /**< Is repeater enabled ? */ + Bool simplayHd; /**< Enable simplayHD support */ + tmdlHdmiTxDeviceVersion_t deviceVersion; /**< Version of the HW device */ + UInt8 *pEdidBuffer; /**< Pointer to raw EDID data */ + UInt32 edidBufferSize; /**< Size of buffer for raw EDID data */ + tmdlHdmiTxIWTaskHandle_t commandTaskHandle; /**< Handle of the command task associated to this unit */ + tmdlHdmiTxIWQueueHandle_t queueHandle; /**< Handle of the message queue associated to this unit */ + tmdlHdmiTxIWTaskHandle_t hdcpTaskHandle; /**< Handle of the hdcp check task associated to this unit */ + tmdlHdmiTxDriverState_t state; /**< Current state of the driver */ + ptmdlHdmiTxCallback_t pCallback; /**< Data callback */ + revocationList_t revocationList; /**< Revolation List */ +} unitConfig_t; + + +/* Instance status */ + +/* Video information structure */ +typedef struct _tmdlHdmiTxVideoInfo_t +{ + Bool videoMuteState; /* Video mute state: on/off */ + tmdlHdmiTxVideoInConfig_t videoInConfig; /* Video input configuration */ + tmdlHdmiTxVideoOutConfig_t videoOutConfig; /* Video output configuration */ +} tmdlHdmiTxVideoInfo_t, *ptmdlHdmiTxVideoInfo_t; + +/* Audio information structure */ +typedef struct _tmdlHdmiTxAudioInfo_t +{ + Bool audioMuteState; /* Audio mute state: on/off */ + tmdlHdmiTxAudioInConfig_t audioInCfg; /* Audio input configuration */ +} tmdlHdmiTxAudioInfo_t, *ptmdlHdmiTxAudioInfo_t; + +/* Event state structure */ +typedef struct _tmdlHdmiTxEventState_t +{ + tmdlHdmiTxEvent_t event; /* Event */ + tmdlHdmiTxEventStatus_t status; /* Event status: enabled or disabled */ +} tmdlHdmiTxEventState_t, *ptmdlHdmiTxEventState_t; + +/* Color bars state structure */ +typedef struct _tmdlHdmiTxColBarState_t +{ + Bool disableColorBarOnR0; /* To be able to disable colorBar on R0*/ + Bool hdcpColbarChange; /* Used to auto-reset colour bars */ + Bool hdcpEncryptOrT0; /* True when ENCRYPT or T0 interrupt */ + Bool hdcpSecureOrT0; /* True when BKSV secure or T0 */ + Bool inOutFirstSetDone; /* API tmdlHdmiTxSetInputOutput call at least one time*/ + Bool colorBarOn; + Bool changeColorBarNow; +} tmdlHdmiTxColBarState_t, *ptmdlHdmiTxColBarState_t; + +/* Gamut state structure */ +typedef struct _tmdlHdmiTxGamutState_t +{ + Bool gamutOn; /* Gamut status : able or disable */ + UInt8 gamutBufNum; /* Numero of the buffer used for Gamut metadata (0 or 1) */ + tmdlHdmiTxExtColorimetry_t wideGamutColorSpace; /* Store extended colorimetry */ + Bool extColOn; /* extended colorimetry status : enabled or disabled */ + tmdlHdmiTxYCCQR_t yccQR; /* Store YCC quantisation range */ +} tmdlHdmiTxGamutState_t, *ptmdlHdmiTxGamutState_t; + + +/* instance status structure */ +typedef struct +{ + ptmdlHdmiTxVideoInfo_t pVideoInfo; /* Video information: current mode and format... */ + ptmdlHdmiTxAudioInfo_t pAudioInfo; /* Audio information: current mode and format... */ + ptmdlHdmiTxEventState_t pEventState; /* Event state: enabled or disabled */ + ptmdlHdmiTxColBarState_t pColBarState; /* Color bars state */ + ptmdlHdmiTxGamutState_t pGamutState; /* Gamut state */ +} instanceStatus_t; + +/*============================================================================*/ +/* FUNCTION PROTOTYPES */ +/*============================================================================*/ + + +/****************************************************************************** + \brief This function allows to the main driver to retrieve its + configuration parameters. + + \param pConfig Pointer to the config structure + + \return The call result: + - TM_OK: the call was successful + - TMDL_ERR_DLHDMITX_BAD_UNIT_NUMBER: the unit number is wrong or + the receiver instance is not initialised + - TMDL_ERR_DLHDMITX_INCONSISTENT_PARAMS: an input parameter is + inconsistent + +******************************************************************************/ +tmErrorCode_t dlHdmiTxGetConfig +( + tmUnitSelect_t unit, + tmdlHdmiTxDriverConfigTable_t *pConfig +); + + +#ifdef __cplusplus +} +#endif + +#endif /* TMDLHDMITX_LOCAL_H */ + +/*============================================================================*/ +/* END OF FILE */ +/*============================================================================*/ diff --git a/drivers/video/nxp/inc/tmFlags.h b/drivers/video/nxp/inc/tmFlags.h new file mode 100755 index 0000000000000..def2b06b87466 --- /dev/null +++ b/drivers/video/nxp/inc/tmFlags.h @@ -0,0 +1,237 @@ +/* MoReUse 2002-09-13 Continuus Version 2 */ +/* */ +/* Changes: made ansi compliant */ +/*-------------------------------------------------------------------------- */ + /* (C) Copyright 2002 Koninklijke Philips Electronics N.V., All Rights Reserved*/ + /* */ + /* This source code and any compilation or derivative thereof is the sole */ + /* property of Philips Corporation and is provided pursuant to a Software */ + /* License Agreement. This code is the proprietary information of */ + /* Philips Corporation and is confidential in nature. Its use and */ + /* dissemination by any party other than Philips Corporation is strictly */ + /* limited by the confidential information provisions of the Agreement */ + /* referenced above. */ + /*------------------------------------------------------------------------- */ + /* FILENAME: tmFlags.h */ + /* */ + /* DESCRIPTION: Platform dependent build flags (typically generated by the */ + /* SDE build process if it doesn't already exist). */ + /* */ + /* DOCUMENT REF: DVP Build Process Specification */ + /* */ + /* NOTES: This file defines the TMFL_xxx build flags configuration. */ + /* It does not include specific component diversity flags that */ + /* are defined in the component makefiles (e.g., TMFL_SCOPE */ + /* defined in BSL board files) */ + /* */ + /* This file is based on SDE Version 1.2 generated output. */ + /*------------------------------------------------------------------------- */ + /* */ + #ifndef TM_FLAGS_H + #define TM_FLAGS_H + +/* Configurable build flags */ +/* NOTE: The following flags are configurable (typically generated by SDE */ +/* based on _TMXXX build environment variables). See individual flags */ +/* for comments about the settings and consistency requirements. */ + +/* TMFL_BUILD_VERSION: .. as decimal digits. This */ +/* number is product/release dependent and not standardized as of now. */ +/*#define TMFL_BUILD_VERSION 00.01.00*/ + +/* RIDE tool does not support . in define value */ +/* TMFL_BUILD_VERSION is not used to specify neither TDA9975_SW version not TDA9983_SW version */ +#define TMFL_BUILD_VERSION 00 + +/* TMFL_CPU: CPU type/model numbers: (TMFL_CPU_TYPE_XXX | TMFL_CPU_MODEL_XXX). */ +/* Example: (TMFL_CPU_TYPE_X86 | TMFL_CPU_MODEL_I486) or (TMFL_CPU_I486) for */ +/* an x86 i486 CPU. */ + #define TMFL_CPU (TMFL_CPU_TYPE_X86 | TMFL_CPU_MODEL_I486) + +/* TMFL_ENDIAN: CPU endianness: */ + #define TMFL_ENDIAN (TMFL_ENDIAN_LITTLE) + +/* TMFL_OS: Operating system type/version where the version number should be */ +/* included if defined: (TMFL_OS_[VVV]). Example: TMFL_OS_PSOS250 */ +/* indicates that the target OS is pSOS Version 2.50. */ + #define TMFL_OS (TMFL_OS_NULLOS) + +/* TMFL_CPU_IS_XXX: These are boolean flags that reflects the CPU type and */ +/* must be consistent with the TMFL_CPU setting (i.e., if TMFL_CPU = */ +/* TMFL_CPU_I486, then TMFL_CPU_IS_X86 = 1) and all other TMFL_CPU_IS_XXX */ +/* flags are 0. */ + #define TMFL_CPU_IS_X86 1 + #define TMFL_CPU_IS_MIPS 0 + #define TMFL_CPU_IS_HP 0 + #define TMFL_CPU_IS_TM 0 + #define TMFL_CPU_IS_ARM 0 + #define TMFL_CPU_IS_REAL 0 + +/* TMFL_OS_IS_XXX: These are boolean flags that reflects the OS type and */ +/* must be consistent with the TMFL_OS setting (i.e., if TMFL_OS = */ +/* TMFL_OS_PSOS250, then TMFL_OS_IS_PSOS = 1) and all other TMFL_OS_IS_XXX */ +/* flags are 0. */ + #define TMFL_OS_IS_BTM 0 + #define TMFL_OS_IS_CE 0 + #define TMFL_OS_IS_NT 0 + #define TMFL_OS_IS_PSOS 0 + #define TMFL_OS_IS_NULLOS 1 + #define TMFL_OS_IS_ECOS 0 + #define TMFL_OS_IS_VXWORKS 0 + #define TMFL_OS_IS_MTOS 0 + + +/* Non-configurable constants */ +/* NOTE: These values do not change and should not be modified ! */ + #define TMFL_CPU_TYPE_MASK 0xffff0000 + #define TMFL_CPU_TYPE_X86 0x00010000 + #define TMFL_CPU_TYPE_MIPS 0x00020000 + #define TMFL_CPU_TYPE_TM 0x00030000 + #define TMFL_CPU_TYPE_HP 0x00040000 + #define TMFL_CPU_TYPE_ARM 0x00050000 + #define TMFL_CPU_TYPE_REAL 0x00060000 + #define TMFL_CPU_MODEL_MASK 0x0000ffff + #define TMFL_CPU_MODEL_I486 0x00000001 + #define TMFL_CPU_MODEL_R3940 0x00000002 + #define TMFL_CPU_MODEL_R4300 0x00000003 + #define TMFL_CPU_MODEL_TM1100 0x00000004 + #define TMFL_CPU_MODEL_TM1300 0x00000005 + #define TMFL_CPU_MODEL_TM32 0x00000006 + #define TMFL_CPU_MODEL_HP 0x00000007 + #define TMFL_CPU_MODEL_R4640 0x00000008 + #define TMFL_CPU_MODEL_ARM7 0x00000009 + #define TMFL_CPU_MODEL_ARM920T 0x0000000a + #define TMFL_CPU_MODEL_ARM940T 0x0000000b + #define TMFL_CPU_MODEL_ARM10 0x0000000c + #define TMFL_CPU_MODEL_STRONGARM 0x0000000d + #define TMFL_CPU_MODEL_RD24120 0x0000000e + #define TMFL_CPU_MODEL_ARM926EJS 0x0000000f + #define TMFL_CPU_MODEL_ARM946 0x00000010 + #define TMFL_CPU_MODEL_R1910 0x00000011 + #define TMFL_CPU_MODEL_R4450 0x00000012 + #define TMFL_CPU_MODEL_TM3260 0x00000013 + #define TMFL_ENDIAN_BIG 1 + #define TMFL_ENDIAN_LITTLE 0 + #define TMFL_OS_MASK 0xff000000 + #define TMFL_OS_VERSION_MASK 0x00ffffff + #define TMFL_OS_BTM 0x00000000 + #define TMFL_OS_CE 0x01000000 + #define TMFL_OS_CE212 0x01020102 + #define TMFL_OS_CE300 0x01030000 + #define TMFL_OS_NT 0x02000000 + #define TMFL_OS_NT4 0x02040000 + #define TMFL_OS_PSOS 0x03000000 + #define TMFL_OS_PSOS250 0x03020500 + #define TMFL_OS_PSOS200 0x03020000 + #define TMFL_OS_NULLOS 0x04000000 + #define TMFL_OS_ECOS 0x05000000 + #define TMFL_OS_VXWORKS 0x06000000 + #define TMFL_OS_MTOS 0x07000000 + #define TMFL_SCOPE_SP 0 + #define TMFL_SCOPE_MP 1 + #define TMFL_REL_ASSERT 0x00000002 + #define TMFL_REL_DEBUG 0x00000001 + #define TMFL_REL_RETAIL 0x00000000 + #define TMFL_CPU_I486 0x00010001 + #define TMFL_CPU_R3940 0x00020002 + #define TMFL_CPU_R4300 0x00020003 + #define TMFL_CPU_TM1100 0x00030004 + #define TMFL_CPU_TM1300 0x00030005 + #define TMFL_CPU_TM32 0x00030006 + #define TMFL_CPU_HP 0x00040007 + #define TMFL_CPU_R4640 0x00020008 + #define TMFL_CPU_ARM7 0x00050009 + #define TMFL_CPU_ARM920T 0x0005000a + #define TMFL_CPU_ARM940T 0x0005000b + #define TMFL_CPU_ARM10 0x0005000c + #define TMFL_CPU_STRONGARM 0x0005000d + #define TMFL_CPU_RD24120 0x0006000e + #define TMFL_CPU_ARM926EJS 0x0005000f + #define TMFL_CPU_ARM946 0x00050010 + #define TMFL_CPU_R1910 0x00020011 + #define TMFL_CPU_R4450 0x00020012 + #define TMFL_CPU_TM3260 0x00030013 + #define TMFL_MODE_KERNEL 1 + #define TMFL_MODE_USER 0 + +/******************************************************************************/ +/* Components features defines */ +/******************************************************************************/ +#ifdef TMFL_TDA19988 +# ifndef TMFL_TDA19989 +# define TMFL_TDA19989 +# endif /* TMFL_TDA19989 */ +# define TMFL_RGB_DDR_12BITS +# define TMFL_HDCP_OPTIMIZED_POWER +#endif /* TMFL_TDA19988 */ + +#ifdef TMFL_TDA19989 +# ifndef TMFL_TDA9989 +# define TMFL_TDA9989 +# define SUPPORT_3D_FP +# endif /* TMFL_TDA9989 */ +#endif /* TMFL_TDA19989 */ +/******************************************************************************/ +/* Preprocessor checks for invalid settings (if file is manually modified) */ +/******************************************************************************/ +/* */ + +/* Check if TMFL_CPU flag changed from its default setting. */ +#if (TMFL_CPU == (TMFL_CPU_TYPE_MASK | TMFL_CPU_MODEL_MASK)) +#error ERROR: TMFL_CPU must be set (TMFL_CPU_TYPE_XXX | TMFL_CPU_MODEL_XXX) ! +#endif + +/* Check if TMFL_ENDIAN flag setting is valid. */ +#if ((TMFL_ENDIAN != TMFL_ENDIAN_BIG) && (TMFL_ENDIAN != TMFL_ENDIAN_LITTLE)) +#error ERROR: TMFL_ENDIAN must be set to a valid TMFL_ENDIAN_XXX value ! +#endif + +/* Check if TMFL_OS flag changed from its default setting. */ +#if (TMFL_OS == (TMFL_OS_MASK | TMFL_OS_VERSION_MASK)) +#error ERROR: TMFL_OS must be set to a valid value (TMFL_OS_[]) ! +#endif + +/* The TMFL_CPU_IS_XXX is a Boolean; one and only one flag can be true (=1). */ +#if ((TMFL_CPU_IS_X86 + TMFL_CPU_IS_MIPS + TMFL_CPU_IS_TM + TMFL_CPU_IS_HP + TMFL_CPU_IS_ARM + TMFL_CPU_IS_REAL) != 1) +#error ERROR: One or more TMFL_CPU_IS_XXX values are incorrect or missing ! +#endif + +/* TMFL_CPU and TMFL_CPU_IS_XXX must be consistent */ +#if (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_X86) && (TMFL_CPU_IS_X86 != 1)) +#error ERROR: Inconsistent TMFL_CPU and TMFL_CPU_IS_X86 settings ! +#elif (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_MIPS) && (TMFL_CPU_IS_MIPS != 1)) +#error ERROR: Inconsistent TMFL_CPU and TMFL_CPU_IS_MIPS settings ! +#elif (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_TM) && (TMFL_CPU_IS_TM != 1)) +#error ERROR: Inconsistent TMFL_CPU and TMFL_CPU_IS_TM settings ! +#elif (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_HP) && (TMFL_CPU_IS_HP != 1)) +#error ERROR: Inconsistent TMFL_CPU and TMFL_CPU_IS_HP settings ! +#elif (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_ARM) && (TMFL_CPU_IS_ARM != 1)) +#error ERROR: Inconsistent TMFL_CPU and TMFL_CPU_IS_ARM settings ! +#elif (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_REAL) && (TMFL_CPU_IS_REAL != 1)) +#error ERROR: Inconsistent TMFL_CPU and TMFL_CPU_IS_REAL settings ! +#endif /* (((TMFL_CPU & TMFL_CPU_TYPE_MASK) == TMFL_CPU_TYPE_X86) && ... */ + +/* The TMFL_OS_IS_XXX is a Boolean; one and only one flag can be true (=1). */ +#if ((TMFL_OS_IS_BTM + TMFL_OS_IS_CE + TMFL_OS_IS_NT + TMFL_OS_IS_PSOS + TMFL_OS_IS_NULLOS + TMFL_OS_IS_ECOS + TMFL_OS_IS_VXWORKS + TMFL_OS_IS_MTOS) != 1) +#error ERROR: One or more TMFL_OS_IS_XXX values are incorrect or missing ! +#endif + +#if (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_BTM) && (TMFL_OS_IS_BTM != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_BTM settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_CE) && (TMFL_OS_IS_CE != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_CE settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_NT) && (TMFL_OS_IS_NT != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_NT settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_PSOS) && (TMFL_OS_IS_PSOS != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_PSOS settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_NULLOS) && (TMFL_OS_IS_NULLOS != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_NULLOS settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_ECOS) && (TMFL_OS_IS_ECOS != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_ECOS settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_VXWORKS) && (TMFL_OS_IS_VXWORKS != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_VXWORKS settings ! +#elif (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_MTOS) && (TMFL_OS_IS_MTOS != 1)) +#error ERROR: Inconsistent TMFL_OS and TMFL_OS_IS_MTOS settings ! +#endif /* (((TMFL_OS & TMFL_OS_MASK) == TMFL_OS_XX) && (TMFL_OS_IS_XX != 1)) */ + +#endif /* TM_FLAGS_H */ diff --git a/drivers/video/nxp/inc/tmNxCompId.h b/drivers/video/nxp/inc/tmNxCompId.h new file mode 100755 index 0000000000000..8943359231f06 --- /dev/null +++ b/drivers/video/nxp/inc/tmNxCompId.h @@ -0,0 +1,1743 @@ +/* -------------------------------------------------------------------------- */ +/* (C) Copyright 2000-2005 Koninklijke Philips Electronics N.V., */ +/* All rights reserved */ +/* */ +/* This source code and any compilation or derivative thereof is the */ +/* proprietary information of Konlinklijke Philips Electronics N.V. and is */ +/* Confidential in nature. */ +/* Under no circumstances is this software to be exposed to or placed under an*/ +/* Open Source License of any type without the expressed written permission of*/ +/* Koninklijke Philips Electronics N.V. */ +/* -------------------------------------------------------------------------- */ +/* */ +/* MoReUse - 2005-10-24 Version 118 */ +/* */ +/* Added: */ +/* CID_AACPENC */ +/* */ +/* */ +/* Changed: */ +/* */ +/* */ +/* */ +/* Removed: */ +/* */ +/* */ +/* */ +/* General Error Codes Added */ +/* */ +/* -------------------------------------------------------------------------- */ +/* FILE NAME: tmNxCompId.h */ +/* */ +/* DESCRIPTION: This header file identifies the standard component */ +/* identifiers (CIDs) and interface identifiers (IID) for */ +/* Nexperia platforms. */ +/* The objective of these identifiers is to enable unique */ +/* identification of software components and interfaces. */ +/* In addition, standard status values are also defined to make */ +/* determination of typical error cases much easier. */ +/* */ +/* Functional errors are not real errors in the sense of */ +/* unexpected behaviour but are part of the normal communication*/ +/* between a client an a server component. They are linked to */ +/* an interface, rather than to a component. All implementations*/ +/* of an interface must have the same behaviour with respect to */ +/* functional errors. Functional erros are all positive */ +/* One global functional error is defined: TM_OK 0x00000000 */ +/* */ +/* Non-functional errors (all negative numbers) indicate */ +/* unexpected behaviour. They are linked to concrete component */ +/* implementations */ +/* */ +/* NOTE: The current implementation is different from the prev. */ +/* component identifier implementation, based on classes, */ +/* types and layers. However, the new system is backward */ +/* compatitible with the old implementation. */ +/* */ +/* tmNxCompId.h defines a number of general error codes that can*/ +/* be used by all components. These error codes are concatenated*/ +/* to the CID or IID value in the local component headerfile of */ +/* the component that wants to (re-)use this general error code */ +/* General error codes can be used for both functional and */ +/* non-functional errors. They should only be used if they */ +/* semantically fully match (if not, defined a new component or */ +/* interface specific error code. */ +/* */ +/* General Rules: */ +/* A return value has a length of 32 bits. At the binary level, */ +/* 1 bit indicates the component or interface flag; 16 bits are */ +/* used for the actual component id (CID) or interface id (IID) */ +/* and 12 bits for the return status. */ +/* The component/interface flag is bit 31. */ +/* Bits 30--28 are all 0. */ +/* The component/interface id occupies bits 27--12. */ +/* The return status occupies bits 11--0. */ +/* */ +/* +--------+-----+-------+-----------+ */ +/* | flag:1 | 0:3 | id:16 | status:12 | */ +/* +--------+-----+-------+-----------+ */ +/* */ +/* Format of interface ids: */ +/* */ +/* +-----+-----+--------+-----------+ */ +/* | 0:1 | 0:3 | iid:16 | status:12 | */ +/* +-----+-----+--------+-----------+ */ +/* */ +/* Format of component ids: */ +/* */ +/* +-----+-----+--------+-----------+ */ +/* | 1:1 | 0:3 | cid:16 | status:12 | */ +/* +-----+-----+--------+-----------+ */ +/* */ +/* At the macro level, we use the prefix "CID_" for component */ +/* ids (previous version "CID_COMP_") and "IID_" for interface */ +/* ids. */ +/* */ +/* Each component id will be used by only one component; each */ +/* component will have its own component id. */ +/* Each interface id will be used by only one interface; each */ +/* interface will have its own interface id. */ +/* */ +/* In order to avoid problems when promoting a UNIQUE interface */ +/* to a SEPARATE interface, the ranges for CIDs and IIDS must */ +/* not overlap. */ +/* */ +/* Component names and component ids have to be registered */ +/* together; the same applies for interface names and ids. */ +/* */ +/* NOTE about Compatibility */ +/* In the previous implementation the first four bits were */ +/* reserved for class, and there were separate fields for */ +/* type and tag, like this: */ +/* */ +/* +---------+--------+-------+---------+-----------+ */ +/* | class:4 | type:4 | tag:8 | layer:4 | status:12 | */ +/* +---------+--------+-------+---------+-----------+ */ +/* */ +/* The values 0 or 8 are not valid classes, and this fact */ +/* can be used to distinguish a new-style IID (class == 0), */ +/* a new-style CID (class == 8), and an old-style CID */ +/* (otherwise). */ +/* */ +/* NOTE about error codes */ +/* The general error codes use the range 0x001 to 0x7FF. */ +/* The component specific error codes are defined in the */ +/* local component header file and can use 0x800 to 0xFFF. */ +/* TM_OK has the value 0x00000000. */ +/* The proposed error code ranges (general and specific) are */ +/* the same for functional and non-functional errors. */ +/* */ +/* The previously defined ranges for external customers, */ +/* assert errors and fatal errors have been dropped. */ +/* The previously defined range for general errors started */ +/* at 0x000 instead of 0x001 */ +/* */ +/* DOCUMENT REF: Nexperia/MoReUse Naming Conventions */ +/* */ +/* -------------------------------------------------------------------------- */ + +#ifndef TMNXCOMPID_H +#define TMNXCOMPID_H + +/* -------------------------------------------------------------------------- */ +/* */ +/* Standard include files: */ +/* */ +/* -------------------------------------------------------------------------- */ +#include "tmNxTypes.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* -------------------------------------------------------------------------- */ +/* */ +/* Types and defines: */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* */ +/* TM_OK is the 32 bit global status value used by all Nexperia components */ +/* to indicate successful function/operation status. If a non-zero value is*/ +/* returned as status, it should use the component ID formats defined. */ +/* */ +/* -------------------------------------------------------------------------- */ +#define TM_OK 0U /* Global success return status */ + +/* -------------------------------------------------------------------------- */ +/* */ +/* General Defines */ +/* */ +/* -------------------------------------------------------------------------- */ +#define CID_IID_FLAG_BITSHIFT 31 +#define CID_ID_BITSHIFT 12 +#define IID_ID_BITSHIFT 12 + +#define CID_FLAG (0x1U << CID_IID_FLAG_BITSHIFT) +#define IID_FLAG (0x0U << CID_IID_FLAG_BITSHIFT) + +#define CID_ID(number) ((number) << CID_ID_BITSHIFT) +#define CID_ID_BITMASK (0x7FFFFU << CID_ID_BITSHIFT) + +#define IID_ID(number) ((number) << IID_ID_BITSHIFT) +#define IID_ID_BITMASK (0x7FFFFU << IID_ID_BITSHIFT) + +/* -------------------------------------------------------------------------- */ +/* */ +/* Definition of the interface IDs */ +/* */ +/* -------------------------------------------------------------------------- */ +#define IID_IENUMUNKNOWN (IID_ID(0x001U) | IID_FLAG) +#define IID_IBIND (IID_ID(0x002U) | IID_FLAG) +#define IID_IBINDINFO (IID_ID(0x003U) | IID_FLAG) +#define IID_IMEM (IID_ID(0x004U) | IID_FLAG) +#define IID_IUNKNOWN (IID_ID(0x005U) | IID_FLAG) +#define IID_IIC (IID_ID(0x006U) | IID_FLAG) +#define IID_ACHAN (IID_ID(0x007U) | IID_FLAG) +#define IID_AFEAT (IID_ID(0x008U) | IID_FLAG) +#define IID_AMIX (IID_ID(0x009U) | IID_FLAG) +#define IID_ANAADEC (IID_ID(0x00aU) | IID_FLAG) +#define IID_ANAVENC (IID_ID(0x00bU) | IID_FLAG) +#define IID_ANAVENCRYPT (IID_ID(0x00cU) | IID_FLAG) +#define IID_ANAVDEC (IID_ID(0x00dU) | IID_FLAG) +#define IID_BBARDETEXT (IID_ID(0x00eU) | IID_FLAG) +#define IID_BLEVELDETEXT (IID_ID(0x00fU) | IID_FLAG) +#define IID_BLEVELMODEXT (IID_ID(0x010U) | IID_FLAG) +#define IID_BSLSPDI (IID_ID(0x011U) | IID_FLAG) +#define IID_BSLSPDO (IID_ID(0x012U) | IID_FLAG) +#define IID_BSL_AI (IID_ID(0x013U) | IID_FLAG) +#define IID_BSL_AO (IID_ID(0x014U) | IID_FLAG) +#define IID_BSL_AVI (IID_ID(0X015U) | IID_FLAG) +#define IID_BSL_AVO (IID_ID(0x016U) | IID_FLAG) +#define IID_BSL_EEPROM (IID_ID(0X017U) | IID_FLAG) +#define IID_BSL_IDE (IID_ID(0X018U) | IID_FLAG) +#define IID_BSL_NANDFLASH (IID_ID(0X019U) | IID_FLAG) +#define IID_BSL_NORFLASH (IID_ID(0X01aU) | IID_FLAG) +#define IID_BSL_PARPORT (IID_ID(0X01bU) | IID_FLAG) +#define IID_BSL_RTC (IID_ID(0X01cU) | IID_FLAG) +#define IID_COLENH (IID_ID(0x01dU) | IID_FLAG) +#define IID_COLENHEXT (IID_ID(0x01eU) | IID_FLAG) +#define IID_CONNMGR (IID_ID(0x01fU) | IID_FLAG) +#define IID_CRT (IID_ID(0x020U) | IID_FLAG) +#define IID_CTI (IID_ID(0X021U) | IID_FLAG) +#define IID_CTIEXT (IID_ID(0X022U) | IID_FLAG) +#define IID_DIGADEC (IID_ID(0X023U) | IID_FLAG) +#define IID_DIGVDEC (IID_ID(0X024U) | IID_FLAG) +#define IID_DMX (IID_ID(0X025U) | IID_FLAG) +#define IID_DNR (IID_ID(0X026U) | IID_FLAG) +#define IID_DNREXT (IID_ID(0X027U) | IID_FLAG) +#define IID_DVBSUBTDEC (IID_ID(0X028U) | IID_FLAG) +#define IID_FATERR (IID_ID(0X029U) | IID_FLAG) +#define IID_FREND (IID_ID(0X02aU) | IID_FLAG) +#define IID_GAMMAEXT (IID_ID(0X02bU) | IID_FLAG) +#define IID_HISTOMEASEXT (IID_ID(0X02cU) | IID_FLAG) +#define IID_HISTOMODEXT (IID_ID(0X02dU) | IID_FLAG) +#define IID_MML (IID_ID(0X02eU) | IID_FLAG) +#define IID_NOISEESTEXT (IID_ID(0X02fU) | IID_FLAG) +#define IID_OSAL (IID_ID(0X030U) | IID_FLAG) +#define IID_PIPSTORE (IID_ID(0X031U) | IID_FLAG) +#define IID_SCANRATECONV (IID_ID(0X032U) | IID_FLAG) +#define IID_SCANRATECONVEXT (IID_ID(0X033U) | IID_FLAG) +#define IID_SHARPENH (IID_ID(0X034U) | IID_FLAG) +#define IID_SHARPENHEXT (IID_ID(0X035U) | IID_FLAG) +#define IID_SHARPMEASEXT (IID_ID(0X036U) | IID_FLAG) +#define IID_SPDIFIN (IID_ID(0X037U) | IID_FLAG) +#define IID_SPDIFOUT (IID_ID(0X038U) | IID_FLAG) +#define IID_SPEAKER (IID_ID(0X039U) | IID_FLAG) +#define IID_STCDEC (IID_ID(0X03aU) | IID_FLAG) +#define IID_STREAMINJ (IID_ID(0X03bU) | IID_FLAG) +#define IID_SYNCTAG (IID_ID(0X03cU) | IID_FLAG) +#define IID_TSSACOM (IID_ID(0X03dU) | IID_FLAG) +#define IID_TXTDEC (IID_ID(0X03eU) | IID_FLAG) +#define IID_UTILCRYPT (IID_ID(0X03fU) | IID_FLAG) +#define IID_UVBWDETEXT (IID_ID(0X040U) | IID_FLAG) +#define IID_VBIINSERT (IID_ID(0X041U) | IID_FLAG) +#define IID_VBISLICE (IID_ID(0X042U) | IID_FLAG) +#define IID_VDCC (IID_ID(0X043U) | IID_FLAG) +#define IID_VDSTSCAN (IID_ID(0X044U) | IID_FLAG) +#define IID_VFEAT (IID_ID(0X045U) | IID_FLAG) +#define IID_VMIX (IID_ID(0X046U) | IID_FLAG) +#define IID_VSCALEEXT (IID_ID(0X047U) | IID_FLAG) +#define IID_VSRCPROP (IID_ID(0X048U) | IID_FLAG) +#define IID_VSRCSCANPROP (IID_ID(0X049U) | IID_FLAG) +#define IID_GENI2C (IID_ID(0X04aU) | IID_FLAG) +#define IID_PLFINSTVIN (IID_ID(0X04bU) | IID_FLAG) +#define IID_PLFINSTAIN (IID_ID(0X04cU) | IID_FLAG) +#define IID_PLFINSTAOUT (IID_ID(0X04dU) | IID_FLAG) +#define IID_PLFINSTGFX (IID_ID(0X04eU) | IID_FLAG) +#define IID_CONNMGRATV (IID_ID(0X04fU) | IID_FLAG) +#define IID_IAMALIVE (IID_ID(0X050U) | IID_FLAG) +#define IID_BBARDET (IID_ID(0X051U) | IID_FLAG) +#define IID_CONTRRESEXT (IID_ID(0X052U) | IID_FLAG) +#define IID_NOISEMEAS (IID_ID(0X053U) | IID_FLAG) +#define IID_SHARPMEAS (IID_ID(0X054U) | IID_FLAG) +#define IID_HISTOMOD (IID_ID(0X055U) | IID_FLAG) +#define IID_ANTIAGING (IID_ID(0X056U) | IID_FLAG) +#define IID_AMBIENTLEVEL (IID_ID(0X057U) | IID_FLAG) +#define IID_HAD_DRV_IIC (IID_ID(0X058U) | IID_FLAG) +#define IID_HAD_DRV_GPIO (IID_ID(0X059U) | IID_FLAG) +#define IID_HAD_DRV_CSM (IID_ID(0X05aU) | IID_FLAG) +#define IID_DRIVERHAL (IID_ID(0X05bU) | IID_FLAG) +#define IID_MUTISTR (IID_ID(0X05cU) | IID_FLAG) +#define IID_MUTIVEC (IID_ID(0X05dU) | IID_FLAG) +#define IID_MUTISTRX (IID_ID(0X05eU) | IID_FLAG) +#define IID_MUTICMD (IID_ID(0X05fU) | IID_FLAG) +#define IID_TASK_CONDITION (IID_ID(0X060U) | IID_FLAG) +#define IID_PACKET_POOL (IID_ID(0X061U) | IID_FLAG) +#define IID_PACKET_QUEUE (IID_ID(0X062U) | IID_FLAG) +#define IID_UDSDCD (IID_ID(0X063U) | IID_FLAG) +#define IID_DCSS_RL (IID_ID(0X064U) | IID_FLAG) +#define IID_DCSS_DD (IID_ID(0X065U) | IID_FLAG) +#define IID_DCSS_GD (IID_ID(0X066U) | IID_FLAG) +#define IID_DCSS_RSC (IID_ID(0X067U) | IID_FLAG) +#define IID_DCSS_P (IID_ID(0X068U) | IID_FLAG) +#define IID_DCSS (IID_ID(0X069U) | IID_FLAG) +#define IID_CC_BURST_CUTTING_AREA (IID_ID(0X06aU) | IID_FLAG) +#define IID_CC_CONFIGURATION (IID_ID(0X06bU) | IID_FLAG) +#define IID_CC_CONTROL (IID_ID(0X06cU) | IID_FLAG) +#define IID_CC_DEBUG (IID_ID(0X06dU) | IID_FLAG) +#define IID_CC_DECODER (IID_ID(0X06eU) | IID_FLAG) +#define IID_CC_ENCODER (IID_ID(0X06fU) | IID_FLAG) +#define IID_CC_HF_PROCESSING (IID_ID(0X070U) | IID_FLAG) +#define IID_CC_INTERFACE (IID_ID(0X071U) | IID_FLAG) +#define IID_CC_NATLAB (IID_ID(0X072U) | IID_FLAG) +#define IID_CC_PIC (IID_ID(0X073U) | IID_FLAG) +#define IID_CC_WOBBLE (IID_ID(0X074U) | IID_FLAG) +#define IID_CC_REGISTERMAP (IID_ID(0X075U) | IID_FLAG) +#define IID_CC_WOBBLE_REG (IID_ID(0X076U) | IID_FLAG) +#define IID_CC_PIC_REG (IID_ID(0X077U) | IID_FLAG) +#define IID_CC_NATLAB_REG (IID_ID(0X078U) | IID_FLAG) +#define IID_CC_INTERFACE_REG (IID_ID(0X079U) | IID_FLAG) +#define IID_CC_HF_PROCESSING_REG (IID_ID(0X07aU) | IID_FLAG) +#define IID_CC_ENCODER_REG (IID_ID(0X07bU) | IID_FLAG) +#define IID_CC_DECODER_REG (IID_ID(0X07cU) | IID_FLAG) +#define IID_CC_DEBUG_REG (IID_ID(0X07dU) | IID_FLAG) +#define IID_CC_CONTROL_REG (IID_ID(0X07eU) | IID_FLAG) +#define IID_CC_CONFIGURATION_REG (IID_ID(0X07fU) | IID_FLAG) +#define IID_CC_BURST_CUTTING_AREA_REG (IID_ID(0X080U) | IID_FLAG) +#define IID_CC_PHYSICAL_VALUES (IID_ID(0X081U) | IID_FLAG) +#define IID_CC_GENERAL_SETTINGS (IID_ID(0X082U) | IID_FLAG) +#define IID_CC_COEFFICIENTS (IID_ID(0X083U) | IID_FLAG) +#define IID_REMOTE_CONTROL (IID_ID(0X084U) | IID_FLAG) +#define IID_TUNER (IID_ID(0X085U) | IID_FLAG) +#define IID_MUTITST (IID_ID(0X086U) | IID_FLAG) +#define IID_CHIP_CONTEXT (IID_ID(0X087U) | IID_FLAG) +#define IID_API (IID_ID(0X088U) | IID_FLAG) +#define IID_CHANDEC (IID_ID(0X089U) | IID_FLAG) +#define IID_TUNING (IID_ID(0X08aU) | IID_FLAG) +#define IID_TUNINGAFC (IID_ID(0X08bU) | IID_FLAG) +#define IID_TUNINGAFCNTF (IID_ID(0X08cU) | IID_FLAG) +#define IID_TUNINGCHAN (IID_ID(0X08dU) | IID_FLAG) +#define IID_TUNINGSEARCHNTF (IID_ID(0X08eU) | IID_FLAG) +#define IID_ID3EXTR (IID_ID(0X08fU) | IID_FLAG) +#define IID_ANAAVDEM (IID_ID(0X090U) | IID_FLAG) +#define IID_ANAAVDEMNTF (IID_ID(0X091U) | IID_FLAG) +#define IID_CCEXTR (IID_ID(0X092U) | IID_FLAG) +#define IID_CHANDECDVBC (IID_ID(0X093U) | IID_FLAG) +#define IID_CHANDECDVBS (IID_ID(0X094U) | IID_FLAG) +#define IID_CHANDECDVBT (IID_ID(0X095U) | IID_FLAG) +#define IID_CHANDECNTF (IID_ID(0X096U) | IID_FLAG) +#define IID_OOB (IID_ID(0X097U) | IID_FLAG) +#define IID_RFAMP (IID_ID(0X098U) | IID_FLAG) +#define IID_SIGSTRENGTH (IID_ID(0X099U) | IID_FLAG) +#define IID_SIGSTRENGTHNTF (IID_ID(0X09aU) | IID_FLAG) +#define IID_IMAGEDEC (IID_ID(0X09bU) | IID_FLAG) +#define IID_TUNINGSEARCH (IID_ID(0X09cU) | IID_FLAG) +#define IID_PINOBJECTS (IID_ID(0X09dU) | IID_FLAG) +#define IID_URLSRC (IID_ID(0X09eU) | IID_FLAG) +#define IID_OSDKERNELAPP (IID_ID(0X09fU) | IID_FLAG) +#define IID_OSDKERNELMEM (IID_ID(0X0a0U) | IID_FLAG) +#define IID_OSDKERNELOSD (IID_ID(0X0a1U) | IID_FLAG) +#define IID_OSDKERNELOSDCONTROL (IID_ID(0X0a2U) | IID_FLAG) +#define IID_RTC (IID_ID(0X0a3U) | IID_FLAG) +#define IID_FS (IID_ID(0X0a4U) | IID_FLAG) +#define IID_BE (IID_ID(0X0a5U) | IID_FLAG) +#define IID_CD_LIB (IID_ID(0X0a6U) | IID_FLAG) +#define IID_DB (IID_ID(0X0a7U) | IID_FLAG) +#define IID_AVIN (IID_ID(0X0a8U) | IID_FLAG) +#define IID_AVOUT (IID_ID(0X0a9U) | IID_FLAG) +#define IID_INT (IID_ID(0X0aaU) | IID_FLAG) +#define IID_EVT (IID_ID(0X0abU) | IID_FLAG) +#define IID_DMA (IID_ID(0X0acU) | IID_FLAG) +#define IID_CLK (IID_ID(0X0adU) | IID_FLAG) +#define IID_VMIXBORDERPAINTER (IID_ID(0X0aeU) | IID_FLAG) +#define IID_CPROCTVFLOW (IID_ID(0X0afU) | IID_FLAG) +#define IID_VTRANTIAGING (IID_ID(0X0b0U) | IID_FLAG) +#define IID_VTRFADE (IID_ID(0X0b1U) | IID_FLAG) +#define IID_VTRSCALE (IID_ID(0X0b2U) | IID_FLAG) +#define IID_VTRSTROBE (IID_ID(0X0b3U) | IID_FLAG) +#define IID_HDMIIN (IID_ID(0X0b4U) | IID_FLAG) +#define IID_ACHANSEL (IID_ID(0X0b5U) | IID_FLAG) +#define IID_SSP (IID_ID(0X0b6U) | IID_FLAG) +#define IID_CONNMGR_STILL (IID_ID(0X0b7U) | IID_FLAG) +#define IID_CONNMGR_AUDIO (IID_ID(0X0b8U) | IID_FLAG) +#define IID_CONNMGR_MPEG2PS (IID_ID(0X0b9U) | IID_FLAG) +#define IID_SPI_SD (IID_ID(0X0baU) | IID_FLAG) +#define IID_DECODERHALCST (IID_ID(0X0bbU) | IID_FLAG) +#define IID_SOD (IID_ID(0X0bcU) | IID_FLAG) +#define IID_DCSS_AA (IID_ID(0X0bdU) | IID_FLAG) +#define IID_DCSS_AVI (IID_ID(0X0beU) | IID_FLAG) +#define IID_DCSS_BC (IID_ID(0X0bfU) | IID_FLAG) +#define IID_DCSS_CLUT (IID_ID(0X0c0U) | IID_FLAG) +#define IID_DCSS_COL (IID_ID(0X0c1U) | IID_FLAG) +#define IID_DCSS_DFC (IID_ID(0X0c2U) | IID_FLAG) +#define IID_DCSS_DOC (IID_ID(0X0c3U) | IID_FLAG) +#define IID_DCSS_GIO (IID_ID(0X0c4U) | IID_FLAG) +#define IID_DCSS_ISD (IID_ID(0X0c5U) | IID_FLAG) +#define IID_DCSS_KBI (IID_ID(0X0c6U) | IID_FLAG) +#define IID_DCSS_OSD (IID_ID(0X0c7U) | IID_FLAG) +#define IID_DCSS_PIF (IID_ID(0X0c8U) | IID_FLAG) +#define IID_DCSS_PVI (IID_ID(0X0c9U) | IID_FLAG) +#define IID_DCSS_SIS (IID_ID(0X0caU) | IID_FLAG) +#define IID_DCSS_TIG (IID_ID(0X0cbU) | IID_FLAG) +#define IID_DCSS_USC (IID_ID(0X0ccU) | IID_FLAG) +#define IID_DCSS_VCR (IID_ID(0X0cdU) | IID_FLAG) +#define IID_CONNMGR_MP4RTP_PLAYER (IID_ID(0X0ceU) | IID_FLAG) +#define IID_CONNMGR_AVIMP4_PLAYER (IID_ID(0X0cfU) | IID_FLAG) +#define IID_VDECANAEXT2 (IID_ID(0X0d0U) | IID_FLAG) +#define IID_STBCOMMON (IID_ID(0X0d1U) | IID_FLAG) +#define IID_AVSYNCCTRL (IID_ID(0X0d2U) | IID_FLAG) +#define IID_PRIVNETSCHEMECONFIG (IID_ID(0X0d3U) | IID_FLAG) +#define IID_SHAREDVARIABLE (IID_ID(0X0d4U) | IID_FLAG) +#define IID_NETSCHEMECONFIG (IID_ID(0X0d5U) | IID_FLAG) +#define IID_AVSYNCTRICK (IID_ID(0X0d6U) | IID_FLAG) +#define IID_SETINTF (IID_ID(0X0d7U) | IID_FLAG) +#define IID_URLDMXMONITOR (IID_ID(0X0d8U) | IID_FLAG) +#define IID_VDECMONITOR (IID_ID(0X0d9U) | IID_FLAG) +#define IID_STBVIDEOTYPES (IID_ID(0X0daU) | IID_FLAG) + +#define IID_RESERVED (CID_ID(0x7fffU) | CID_FLAG) +/* ************************************************************************** */ +/* Interface Id's reserved for external organizations */ +/* */ +/* None */ +/* */ +/* ************************************************************************** */ + +/* -------------------------------------------------------------------------- */ +/* */ +/* Definition of the component IDs */ +/* */ +/* -------------------------------------------------------------------------- */ +#define CID_MPMP1_GRINDER (CID_ID(0x8001U) | CID_FLAG) +#define CID_MUSB_GRINDER (CID_ID(0x8002U) | CID_FLAG) +#define CID_UOTGPFL (CID_ID(0x8003U) | CID_FLAG) +#define CID_CHIPBUILDER_GRINDER (CID_ID(0x8004U) | CID_FLAG) + +#define CID_AANALYZER (CID_ID(0x8009U) | CID_FLAG) +#define CID_ADEC_AAC4 (CID_ID(0x800aU) | CID_FLAG) +#define CID_ADEC_ATV (CID_ID(0x800bU) | CID_FLAG) +#define CID_ADEC_CELP4 (CID_ID(0x800cU) | CID_FLAG) +#define CID_ADEC_CORE (CID_ID(0x800dU) | CID_FLAG) +#define CID_ADEC_MP3PRO (CID_ID(0x800eU) | CID_FLAG) +#define CID_ADEC_PL2 (CID_ID(0x800fU) | CID_FLAG) +#define CID_ADEC_STB (CID_ID(0x8010U) | CID_FLAG) +#define CID_ADEEMPH (CID_ID(0x8011U) | CID_FLAG) +#define CID_AENCAAC4 (CID_ID(0x8012U) | CID_FLAG) +#define CID_AREND_AO_MUX (CID_ID(0x8013U) | CID_FLAG) +#define CID_ASP_IIRZ2 (CID_ID(0x8014U) | CID_FLAG) +#define CID_ASRC (CID_ID(0x8015U) | CID_FLAG) +#define CID_ASYS_CORE (CID_ID(0x8016U) | CID_FLAG) +#define CID_ATV_PLF_BASIC (CID_ID(0x8017U) | CID_FLAG) +#define CID_ATV_STUBS (CID_ID(0x8018U) | CID_FLAG) +#define CID_AVI_READ_DIVX (CID_ID(0x8019U) | CID_FLAG) +#define CID_BOOTINFO (CID_ID(0x801aU) | CID_FLAG) +#define CID_BROWSE_EIS (CID_ID(0x801bU) | CID_FLAG) +#define CID_BSL_7113 (CID_ID(0x801cU) | CID_FLAG) +#define CID_BSL_7113QT (CID_ID(0x801dU) | CID_FLAG) +#define CID_BSL_7114 (CID_ID(0x801eU) | CID_FLAG) +#define CID_BSL_7118 (CID_ID(0x801fU) | CID_FLAG) +#define CID_BSL_ANABEL (CID_ID(0x8020U) | CID_FLAG) +#define CID_BSL_ANABELQT (CID_ID(0x8021U) | CID_FLAG) +#define CID_BSL_AVIP (CID_ID(0x8022U) | CID_FLAG) +#define CID_BSL_BOARDS (CID_ID(0x8023U) | CID_FLAG) +#define CID_BSL_CORE (CID_ID(0x8024U) | CID_FLAG) +#define CID_BSL_DENC (CID_ID(0x8025U) | CID_FLAG) +#define CID_BSL_EEPROM_ATMEL (CID_ID(0x8026U) | CID_FLAG) +#define CID_BSL_IDEXIO (CID_ID(0x8027U) | CID_FLAG) +#define CID_BSL_NANDSAMSUNG (CID_ID(0x8028U) | CID_FLAG) +#define CID_BSL_NORINTEL (CID_ID(0x8029U) | CID_FLAG) +#define CID_BSL_RTCPCF8563 (CID_ID(0x802aU) | CID_FLAG) +#define CID_BSL_UART_HWAPI (CID_ID(0x802bU) | CID_FLAG) +#define CID_BSL_UDA1344 (CID_ID(0x802cU) | CID_FLAG) +#define CID_BT_1500 (CID_ID(0x802dU) | CID_FLAG) +#define CID_BT_API (CID_ID(0x802eU) | CID_FLAG) +#define CID_BT_CORE (CID_ID(0x802fU) | CID_FLAG) +#define CID_BT_CPU (CID_ID(0x8030U) | CID_FLAG) +#define CID_BT_MIPS (CID_ID(0x8031U) | CID_FLAG) +#define CID_BT_TRIMEDIA (CID_ID(0x8032U) | CID_FLAG) +#define CID_BT_V2PCI (CID_ID(0x8033U) | CID_FLAG) +#define CID_BT_VPCI (CID_ID(0x8034U) | CID_FLAG) +#define CID_BT_VSTB (CID_ID(0x8035U) | CID_FLAG) +#define CID_BUFFEREDREAD (CID_ID(0x8036U) | CID_FLAG) +#define CID_CONN_MGRAUDSYSSTB (CID_ID(0x8037U) | CID_FLAG) +#define CID_DEMUXMPEGTS_SW (CID_ID(0x8038U) | CID_FLAG) +#define CID_DIG_ADEC_AUDSYS_STB (CID_ID(0x8039U) | CID_FLAG) +#define CID_DL_AI (CID_ID(0x803aU) | CID_FLAG) +#define CID_DL_AICP (CID_ID(0x803bU) | CID_FLAG) +#define CID_DL_AO (CID_ID(0x803cU) | CID_FLAG) +#define CID_DL_AVFS (CID_ID(0x803dU) | CID_FLAG) +#define CID_DL_CLOCK (CID_ID(0x803eU) | CID_FLAG) +#define CID_DL_DFS (CID_ID(0x803fU) | CID_FLAG) +#define CID_DL_DISKSCHED (CID_ID(0x8040U) | CID_FLAG) +#define CID_DL_DMA (CID_ID(0x8041U) | CID_FLAG) +#define CID_DL_ETH_IP3902 (CID_ID(0x8042U) | CID_FLAG) +#define CID_DL_GPIO (CID_ID(0x8043U) | CID_FLAG) +#define CID_DL_I2C (CID_ID(0x8044U) | CID_FLAG) +#define CID_DL_IDE (CID_ID(0x8045U) | CID_FLAG) +#define CID_DL_IDESTUB (CID_ID(0x8046U) | CID_FLAG) +#define CID_DL_IIC (CID_ID(0x8047U) | CID_FLAG) +#define CID_DL_IR (CID_ID(0x8048U) | CID_FLAG) +#define CID_DL_MBS (CID_ID(0x8049U) | CID_FLAG) +#define CID_DL_MBS2 (CID_ID(0x804aU) | CID_FLAG) +#define CID_DL_NANDFLASH (CID_ID(0x804bU) | CID_FLAG) +#define CID_DL_NORFLASH (CID_ID(0x804cU) | CID_FLAG) +#define CID_DL_PCI (CID_ID(0x804dU) | CID_FLAG) +#define CID_DL_PROCESSOR (CID_ID(0x804eU) | CID_FLAG) +#define CID_DL_QTNR (CID_ID(0x804fU) | CID_FLAG) +#define CID_DL_QVCP (CID_ID(0x8050U) | CID_FLAG) +#define CID_DL_SEM (CID_ID(0x8051U) | CID_FLAG) +#define CID_DL_SPDI (CID_ID(0x8052U) | CID_FLAG) +#define CID_DL_SPDO (CID_ID(0x8053U) | CID_FLAG) +#define CID_DL_TIMER (CID_ID(0x8054U) | CID_FLAG) +#define CID_DL_TSDMA (CID_ID(0x8055U) | CID_FLAG) +#define CID_DL_TSIO (CID_ID(0x8056U) | CID_FLAG) +#define CID_DL_UDMA (CID_ID(0x8057U) | CID_FLAG) +#define CID_DL_VID_MEAS (CID_ID(0x8058U) | CID_FLAG) +#define CID_DL_VIP (CID_ID(0x8059U) | CID_FLAG) +#define CID_DL_VMPG (CID_ID(0x805aU) | CID_FLAG) +#define CID_DL_XIO (CID_ID(0x805bU) | CID_FLAG) +#define CID_DRAWTEXT (CID_ID(0x805cU) | CID_FLAG) +#define CID_DVPDEBUG (CID_ID(0x805dU) | CID_FLAG) +#define CID_FATALERROR (CID_ID(0x805eU) | CID_FLAG) +#define CID_FATALERROR_VT (CID_ID(0x805fU) | CID_FLAG) +#define CID_FREADAVPROP (CID_ID(0x8060U) | CID_FLAG) +#define CID_FWRITEAVPROP (CID_ID(0x8061U) | CID_FLAG) +#define CID_HELP (CID_ID(0x8062U) | CID_FLAG) +#define CID_HTTP_IO_DRIVER (CID_ID(0x8063U) | CID_FLAG) +#define CID_HW_AICP (CID_ID(0x8064U) | CID_FLAG) +#define CID_HW_CLOCK (CID_ID(0x8065U) | CID_FLAG) +#define CID_HW_DMA (CID_ID(0x8066U) | CID_FLAG) +#define CID_HW_DRAW (CID_ID(0x8067U) | CID_FLAG) +#define CID_HW_DRAWCOMMON (CID_ID(0x8068U) | CID_FLAG) +#define CID_HW_DRAWDE (CID_ID(0x8069U) | CID_FLAG) +#define CID_HW_DRAWREF (CID_ID(0x806aU) | CID_FLAG) +#define CID_HW_DRAWSHARED (CID_ID(0x806bU) | CID_FLAG) +#define CID_HW_DRAWTMH (CID_ID(0x806cU) | CID_FLAG) +#define CID_HW_DRAWTMT (CID_ID(0x806dU) | CID_FLAG) +#define CID_HW_DRAWTMTH (CID_ID(0x806eU) | CID_FLAG) +#define CID_HW_DSP (CID_ID(0x806fU) | CID_FLAG) +#define CID_HW_ETH_IP3902 (CID_ID(0x8070U) | CID_FLAG) +#define CID_HW_GIC (CID_ID(0x8071U) | CID_FLAG) +#define CID_HW_GPIO (CID_ID(0x8072U) | CID_FLAG) +#define CID_HW_I2C (CID_ID(0x8073U) | CID_FLAG) +#define CID_HW_IIC (CID_ID(0x8074U) | CID_FLAG) +#define CID_HW_MBS (CID_ID(0x8075U) | CID_FLAG) +#define CID_HW_MMIARB (CID_ID(0x8076U) | CID_FLAG) +#define CID_HW_MMIARB1010 (CID_ID(0x8077U) | CID_FLAG) +#define CID_HW_PCI (CID_ID(0x8078U) | CID_FLAG) +#define CID_HW_PIC (CID_ID(0x8079U) | CID_FLAG) +#define CID_HW_SMC (CID_ID(0x807aU) | CID_FLAG) +#define CID_HW_TSDMA (CID_ID(0x807bU) | CID_FLAG) +#define CID_HW_UART (CID_ID(0x807cU) | CID_FLAG) +#define CID_HW_UDMA (CID_ID(0x807dU) | CID_FLAG) +#define CID_HW_VIP (CID_ID(0x807eU) | CID_FLAG) +#define CID_HW_VMSP (CID_ID(0x807fU) | CID_FLAG) +#define CID_HW_XIO (CID_ID(0x8080U) | CID_FLAG) +#define CID_INFRA_MISC (CID_ID(0x8081U) | CID_FLAG) +#define CID_INTERRUPT (CID_ID(0x8082U) | CID_FLAG) +#define CID_IPC_DT (CID_ID(0x8083U) | CID_FLAG) +#define CID_IPC_READ (CID_ID(0x8084U) | CID_FLAG) +#define CID_IPC_RPC (CID_ID(0x8085U) | CID_FLAG) +#define CID_IPC_WRITE (CID_ID(0x8086U) | CID_FLAG) +#define CID_LIBLOAD_TM (CID_ID(0x8087U) | CID_FLAG) +#define CID_MEMDBG (CID_ID(0x8088U) | CID_FLAG) +#define CID_MENU (CID_ID(0x8089U) | CID_FLAG) +#define CID_MP4READ (CID_ID(0x808aU) | CID_FLAG) +#define CID_MPEGCOLORBAR (CID_ID(0x808bU) | CID_FLAG) +#define CID_NETSTACK_FUSION (CID_ID(0x808cU) | CID_FLAG) +#define CID_NETSTACK_TARGET_TCP (CID_ID(0x808dU) | CID_FLAG) +#define CID_NETSTACK_UPNP_ALLEGRO (CID_ID(0x808dU) | CID_FLAG) +#define CID_NETSTACK_UPNP_INTEL (CID_ID(0x808eU) | CID_FLAG) +#define CID_NETWORKREAD (CID_ID(0x8090U) | CID_FLAG) +#define CID_NM_COMMON (CID_ID(0x8091U) | CID_FLAG) +#define CID_NM_DEI (CID_ID(0x8092U) | CID_FLAG) +#define CID_NM_EST (CID_ID(0x8093U) | CID_FLAG) +#define CID_NM_QFD (CID_ID(0x8094U) | CID_FLAG) +#define CID_NM_UPC (CID_ID(0x8095U) | CID_FLAG) +#define CID_NM_UPC_SPIDER (CID_ID(0x8096U) | CID_FLAG) +#define CID_OS (CID_ID(0x8097U) | CID_FLAG) +#define CID_PROBE (CID_ID(0x8098U) | CID_FLAG) +#define CID_PSIUTIL (CID_ID(0x8099U) | CID_FLAG) +#define CID_REALNETWORKS_ENGINE (CID_ID(0x809aU) | CID_FLAG) +#define CID_SCAN_RATE_CONV_VSYS_TV (CID_ID(0x809bU) | CID_FLAG) +#define CID_SPOSAL (CID_ID(0x809cU) | CID_FLAG) +#define CID_TIMEDOCTOR (CID_ID(0x809dU) | CID_FLAG) +#define CID_TSA_CLOCK (CID_ID(0x809eU) | CID_FLAG) + +#define CID_TST_AVETC_SINK (CID_ID(0x80a0U) | CID_FLAG) +#define CID_TST_DEMUX (CID_ID(0x80a1U) | CID_FLAG) +#define CID_TST_DEMUX_FOR_MUX (CID_ID(0x80a2U) | CID_FLAG) +#define CID_TST_SPTS_SINK (CID_ID(0x80a3U) | CID_FLAG) +#define CID_TTI_UTIL (CID_ID(0x80a4U) | CID_FLAG) +#define CID_UART (CID_ID(0x80a5U) | CID_FLAG) +#define CID_UPCONV100MC (CID_ID(0x80a6U) | CID_FLAG) +#define CID_UTILCPIREC (CID_ID(0x80a7U) | CID_FLAG) +#define CID_UTILCRYPTRIJNDAEL (CID_ID(0x80a8U) | CID_FLAG) +#define CID_VATV (CID_ID(0x80a9U) | CID_FLAG) +#define CID_VATV_TR (CID_ID(0x80aaU) | CID_FLAG) +#define CID_VBI_INSERT_VSYS_TV (CID_ID(0x80abU) | CID_FLAG) +#define CID_VCAP_VIP2 (CID_ID(0x80acU) | CID_FLAG) +#define CID_VDEC_BMP (CID_ID(0x80adU) | CID_FLAG) +#define CID_VDEC_DIVX (CID_ID(0x80aeU) | CID_FLAG) +#define CID_VDEC_GIF (CID_ID(0x80afU) | CID_FLAG) +#define CID_VDEC_JPEG (CID_ID(0x80b0U) | CID_FLAG) +#define CID_VDEC_JPEG2K (CID_ID(0x80b1U) | CID_FLAG) +#define CID_VDEC_MP (CID_ID(0x80b2U) | CID_FLAG) +#define CID_VDECMPEG4 (CID_ID(0x80b3U) | CID_FLAG) +#define CID_VENC_MPEG4 (CID_ID(0x80b4U) | CID_FLAG) +#define CID_VENCMJPEG (CID_ID(0x80b5U) | CID_FLAG) +#define CID_VENCMPEG2 (CID_ID(0x80b6U) | CID_FLAG) +#define CID_VIDEOUTIL (CID_ID(0x80b7U) | CID_FLAG) +#define CID_VPACK (CID_ID(0x80b8U) | CID_FLAG) +#define CID_VPIP_REC_PLAY (CID_ID(0x80b9U) | CID_FLAG) +#define CID_VPOST_ICP (CID_ID(0x80baU) | CID_FLAG) +#define CID_VREND_VCP (CID_ID(0x80bbU) | CID_FLAG) +#define CID_VRENDVO (CID_ID(0x80bcU) | CID_FLAG) +#define CID_VSCHED (CID_ID(0x80bdU) | CID_FLAG) +#define CID_VTBLBASE (CID_ID(0x80beU) | CID_FLAG) +#define CID_VTRANS_MBS2 (CID_ID(0x80bfU) | CID_FLAG) +#define CID_VTRANS_QTNR (CID_ID(0x80c0U) | CID_FLAG) +#define CID_VXWORKS_BSP (CID_ID(0x80c1U) | CID_FLAG) +#define CID_WREAD (CID_ID(0x80c2U) | CID_FLAG) +#define CID_CONNMGR_ATV (CID_ID(0x80c3U) | CID_FLAG) +#define CID_DL_VPK (CID_ID(0x80c4U) | CID_FLAG) +#define CID_VTRANS_VPK (CID_ID(0x80c5U) | CID_FLAG) +#define CID_DL_VIP2 (CID_ID(0x80c6U) | CID_FLAG) +#define CID_VX_GEN_UART (CID_ID(0x80c7U) | CID_FLAG) +#define CID_VX_GPIO (CID_ID(0x80c8U) | CID_FLAG) +#define CID_VX_GEN_TIMER (CID_ID(0x80c9U) | CID_FLAG) +#define CID_M4VENC_DIS (CID_ID(0x80caU) | CID_FLAG) +#define CID_VENC_ANA (CID_ID(0x80cbU) | CID_FLAG) +#define CID_BSL_VENC_ANA (CID_ID(0x80ccU) | CID_FLAG) +#define CID_BSL_VENC_ANA_EXT (CID_ID(0x80cdU) | CID_FLAG) +#define CID_BSL_VENC_ANAVBI_EXT (CID_ID(0x80ceU) | CID_FLAG) +#define CID_CMDX (CID_ID(0x80cfU) | CID_FLAG) +#define CID_LL_GPIO (CID_ID(0x80d0U) | CID_FLAG) +#define CID_LL_KEYPAD (CID_ID(0x80d1U) | CID_FLAG) +#define CID_LL_TIMER (CID_ID(0x80d2U) | CID_FLAG) +#define CID_LL_SPI (CID_ID(0x80d3U) | CID_FLAG) +#define CID_LL_UART (CID_ID(0x80d4U) | CID_FLAG) +#define CID_LL_I2C (CID_ID(0x80d5U) | CID_FLAG) +#define CID_LL_TR (CID_ID(0x80d6U) | CID_FLAG) +#define CID_HW_KEYPAD (CID_ID(0x80d7U) | CID_FLAG) +#define CID_HW_TIMER (CID_ID(0x80d8U) | CID_FLAG) +#define CID_HW_SPI (CID_ID(0x80d9U) | CID_FLAG) +#define CID_HW_VATV_IOSYNC (CID_ID(0x80daU) | CID_FLAG) +#define CID_DL_VO (CID_ID(0x80dbU) | CID_FLAG) +#define CID_DL_LVDS (CID_ID(0x80dcU) | CID_FLAG) +#define CID_HW_DDR2031 (CID_ID(0x80ddU) | CID_FLAG) +#define CID_BSL_PHY (CID_ID(0x80deU) | CID_FLAG) +#define CID_ETH_TTCP (CID_ID(0x80dfU) | CID_FLAG) +#define CID_CDIGADEC_MP3PRO (CID_ID(0x80e0U) | CID_FLAG) +#define CID_CID3EXTR (CID_ID(0x80e1U) | CID_FLAG) +#define CID_IMAGEDEC_JPEG (CID_ID(0x80e2U) | CID_FLAG) +#define CID_CURLSRC_MP3PRO (CID_ID(0x80e3U) | CID_FLAG) +#define CID_CURLSRC_IMAGEDEC (CID_ID(0x80e4U) | CID_FLAG) +#define CID_DVP_MAIN (CID_ID(0x80e5U) | CID_FLAG) +#define CID_TMMAN32 (CID_ID(0x80e6U) | CID_FLAG) +#define CID_TMMAN_CRT (CID_ID(0x80e7U) | CID_FLAG) +#define CID_UHS_HAL_PCI (CID_ID(0x80e8U) | CID_FLAG) +#define CID_UHS_OSAL_VXWORKS (CID_ID(0x80e9U) | CID_FLAG) +#define CID_UHS_OSAL_PSOS (CID_ID(0x80eaU) | CID_FLAG) +#define CID_UHS_USBD (CID_ID(0x80ebU) | CID_FLAG) +#define CID_UHS_RBC (CID_ID(0x80ecU) | CID_FLAG) +#define CID_UHS_UFI (CID_ID(0x80edU) | CID_FLAG) +#define CID_UHS_SCSI (CID_ID(0x80eeU) | CID_FLAG) +#define CID_UHS_PRINTER (CID_ID(0x80efU) | CID_FLAG) +#define CID_UHS_MOUSE (CID_ID(0x80f0U) | CID_FLAG) +#define CID_UHS_KEYBOARD (CID_ID(0x80f1U) | CID_FLAG) +#define CID_UHS_HUB (CID_ID(0x80f2U) | CID_FLAG) +#define CID_UHS_HCD_1561 (CID_ID(0x80f3U) | CID_FLAG) +#define CID_CLEANUP (CID_ID(0x80f4U) | CID_FLAG) +#define CID_ALLOCATOR (CID_ID(0x80f5U) | CID_FLAG) +#define CID_TCS_CORE_LIBDEV (CID_ID(0x80f6U) | CID_FLAG) +#define CID_VDI_VDO_ROUTER (CID_ID(0x80f7U) | CID_FLAG) +#define CID_CONNMGR_ATSC (CID_ID(0x80f8U) | CID_FLAG) +#define CID_ASPDIF (CID_ID(0x80f9U) | CID_FLAG) +#define CID_APLL (CID_ID(0x80faU) | CID_FLAG) +#define CID_ATVPLFINSTVIN (CID_ID(0x80fbU) | CID_FLAG) +#define CID_ATV_PLF (CID_ID(0x80fcU) | CID_FLAG) +#define CID_DL_WATCHDOG (CID_ID(0x80fdU) | CID_FLAG) +#define CID_WMT_NET_READER (CID_ID(0x80feU) | CID_FLAG) +#define CID_DL_FGPO (CID_ID(0x80ffU) | CID_FLAG) +#define CID_DL_FGPI (CID_ID(0x8100U) | CID_FLAG) +#define CID_WMT_DECODER (CID_ID(0x8101U) | CID_FLAG) +#define CID_HAD_DRV_IIC (CID_ID(0x8102U) | CID_FLAG) +#define CID_HAD_DRV_GPIO (CID_ID(0x8103U) | CID_FLAG) +#define CID_HAD_GLOBAL (CID_ID(0x8104U) | CID_FLAG) +#define CID_HAD_SMM (CID_ID(0x8105U) | CID_FLAG) +#define CID_HAD_DRV_CSM (CID_ID(0x8106U) | CID_FLAG) +#define CID_CARACASWDOG (CID_ID(0x8107U) | CID_FLAG) +#define CID_CARACASADC (CID_ID(0x8108U) | CID_FLAG) +#define CID_CARACASDMA (CID_ID(0x8109U) | CID_FLAG) +#define CID_CARACASFLASHCTRL (CID_ID(0x810aU) | CID_FLAG) +#define CID_CARACASGPTIMER (CID_ID(0x810bU) | CID_FLAG) +#define CID_CARACASGPIO (CID_ID(0x810cU) | CID_FLAG) +#define CID_CARACASI2CMO (CID_ID(0x810dU) | CID_FLAG) +#define CID_CARACASI2CMS (CID_ID(0x810eU) | CID_FLAG) +#define CID_CARACASRTC (CID_ID(0x810fU) | CID_FLAG) +#define CID_CARACASSPI (CID_ID(0x8110U) | CID_FLAG) +#define CID_CARACASTIMER (CID_ID(0x8111U) | CID_FLAG) +#define CID_CARACASUART (CID_ID(0x8112U) | CID_FLAG) +#define CID_TSSA40 (CID_ID(0x8113U) | CID_FLAG) +#define CID_PACKET_POOL (CID_ID(0x8114U) | CID_FLAG) +#define CID_TSSA15_WRAPPER (CID_ID(0x8115U) | CID_FLAG) +#define CID_TASK_SYNC (CID_ID(0x8116U) | CID_FLAG) +#define CID_TASK_CONDITION (CID_ID(0x8117U) | CID_FLAG) +#define CID_PACKET_QUEUE (CID_ID(0x8118U) | CID_FLAG) +#define CID_CONNECTION_TOOLKIT (CID_ID(0x8119U) | CID_FLAG) +#define CID_TSSA16 (CID_ID(0x811aU) | CID_FLAG) +#define CID_UDSDFU (CID_ID(0x811bU) | CID_FLAG) +#define CID_BTH (CID_ID(0x811cU) | CID_FLAG) +#define CID_DCDIP9021 (CID_ID(0x811dU) | CID_FLAG) +#define CID_DCDIP3501V1X (CID_ID(0x811eU) | CID_FLAG) +#define CID_ISP1581 (CID_ID(0x811fU) | CID_FLAG) +#define CID_DCSS_TV (CID_ID(0x8120U) | CID_FLAG) +#define CID_DCSS_MON (CID_ID(0x8121U) | CID_FLAG) +#define CID_DCSS_RSC_PC (CID_ID(0x8122U) | CID_FLAG) +#define CID_DCSS_RSC_INT (CID_ID(0x8123U) | CID_FLAG) +#define CID_DCSS_RSC_EXT (CID_ID(0x8124U) | CID_FLAG) +#define CID_DCSS_LIT (CID_ID(0x8125U) | CID_FLAG) +#define CID_DCSS_LIT_C (CID_ID(0x8126U) | CID_FLAG) +#define CID_DCSS_45A (CID_ID(0x8127U) | CID_FLAG) +#define CID_UDSCORE (CID_ID(0x8128U) | CID_FLAG) +#define CID_HW_AUDIO7135 (CID_ID(0x8129U) | CID_FLAG) +#define CID_DL_AUDIO3X (CID_ID(0x812aU) | CID_FLAG) +#define CID_REGACC (CID_ID(0x812bU) | CID_FLAG) +#define CID_HW_MJPEG (CID_ID(0x812cU) | CID_FLAG) +#define CID_ISP1582 (CID_ID(0x812dU) | CID_FLAG) +#define CID_MUTI (CID_ID(0x812eU) | CID_FLAG) +#define CID_CHANNEL_DECODER_ENCODER (CID_ID(0x812fU) | CID_FLAG) +#define CID_RESMGR (CID_ID(0x8130U) | CID_FLAG) +#define CID_WIDGET (CID_ID(0x8131U) | CID_FLAG) +#define CID_FB (CID_ID(0x8132U) | CID_FLAG) +#define CID_GFX (CID_ID(0x8133U) | CID_FLAG) +#define CID_HPS_DISPATCHER (CID_ID(0x8134U) | CID_FLAG) +#define CID_DL_PLXGPIO (CID_ID(0x8135U) | CID_FLAG) +#define CID_HW_PLXGPIO (CID_ID(0x8136U) | CID_FLAG) +#define CID_DL_PLXPHI (CID_ID(0x8137U) | CID_FLAG) +#define CID_HW_PLXPHI_EVALUATOR (CID_ID(0x8138U) | CID_FLAG) +#define CID_DL_SCALER (CID_ID(0x8139U) | CID_FLAG) +#define CID_EFM (CID_ID(0x813aU) | CID_FLAG) +#define CID_HW_TUNER_FM1236MK3 (CID_ID(0x813bU) | CID_FLAG) +#define CID_HW_TUNER_FM1216MK3 (CID_ID(0x813cU) | CID_FLAG) +#define CID_HW_TUNER_FM1216MK2 (CID_ID(0x813dU) | CID_FLAG) +#define CID_ANALOG_CHANNEL_TABLE (CID_ID(0x813eU) | CID_FLAG) +#define CID_TUNER_CONTROL (CID_ID(0x813fU) | CID_FLAG) +#define CID_DL_UIMS (CID_ID(0x8140U) | CID_FLAG) +#define CID_DL_RCTRANSMITTER (CID_ID(0x8141U) | CID_FLAG) +#define CID_HW_CST_RCRECEIVER (CID_ID(0x8142U) | CID_FLAG) +#define CID_HW_CST_RCTRANSMITTER (CID_ID(0x8143U) | CID_FLAG) +#define CID_DCDIP3506 (CID_ID(0x8144U) | CID_FLAG) +#define CID_DCDIP3501V2X (CID_ID(0x8145U) | CID_FLAG) +#define CID_MTV_COORD (CID_ID(0x8146U) | CID_FLAG) +#define CID_MTV_IMG_ROT_CTRL (CID_ID(0x8147U) | CID_FLAG) +#define CID_TFE_TRACE (CID_ID(0x8148U) | CID_FLAG) +#define CID_TMCAL_SERVER (CID_ID(0x8149U) | CID_FLAG) +#define CID_BOOT_LOADER (CID_ID(0x814aU) | CID_FLAG) +#define CID_TD_SAVE_DATA (CID_ID(0x814bU) | CID_FLAG) +#define CID_TFE_TRACE_PROCESS_DATA (CID_ID(0x814cU) | CID_FLAG) +#define CID_VIDEOCTRL (CID_ID(0x814dU) | CID_FLAG) +#define CID_BOOT (CID_ID(0x814eU) | CID_FLAG) +#define CID_EVENT (CID_ID(0x814fU) | CID_FLAG) +#define CID_USERINPUT (CID_ID(0x8150U) | CID_FLAG) +#define CID_BSL_TUNER (CID_ID(0x8151U) | CID_FLAG) +#define CID_P5KIIC (CID_ID(0x8152U) | CID_FLAG) +#define CID_HW_PMANSECURITY (CID_ID(0x8153U) | CID_FLAG) +#define CID_DRM_DIVX (CID_ID(0x8154U) | CID_FLAG) +#define CID_TMHWVIDEODEC7136 (CID_ID(0x8155U) | CID_FLAG) +#define CID_TMDLVIDEODEC (CID_ID(0x8156U) | CID_FLAG) +#define CID_OSD_KERNEL (CID_ID(0x8157U) | CID_FLAG) +#define CID_HW_DCSNETWORK (CID_ID(0x8158U) | CID_FLAG) +#define CID_DL_RCRECEIVER (CID_ID(0x8159U) | CID_FLAG) +#define CID_INT (CID_ID(0x815aU) | CID_FLAG) +#define CID_RTC (CID_ID(0x815bU) | CID_FLAG) +#define CID_TIMER (CID_ID(0x815cU) | CID_FLAG) +#define CID_IPC (CID_ID(0x815dU) | CID_FLAG) +#define CID_P5KTELETEXT (CID_ID(0x815eU) | CID_FLAG) +#define CID_P5KAUDIOVIDEO (CID_ID(0x815fU) | CID_FLAG) +#define CID_P5KCONFIG (CID_ID(0x8160U) | CID_FLAG) +#define CID_HW_CST_TRANSPSTREAMIN (CID_ID(0x8161U) | CID_FLAG) +#define CID_HOMER_KERNEL (CID_ID(0x8162U) | CID_FLAG) +#define CID_HOMER_DRIVER (CID_ID(0x8163U) | CID_FLAG) +#define CID_CD_FILE_SYSTEM (CID_ID(0x8164U) | CID_FLAG) +#define CID_COBALT_APP (CID_ID(0x8165U) | CID_FLAG) +#define CID_COBALT_UI (CID_ID(0x8166U) | CID_FLAG) +#define CID_CD_SERVO (CID_ID(0x8167U) | CID_FLAG) +#define CID_CD_UTILS (CID_ID(0x8168U) | CID_FLAG) +#define CID_COBALT_SYSTEM (CID_ID(0x8169U) | CID_FLAG) +#define CID_CDSLIM (CID_ID(0x816aU) | CID_FLAG) +#define CID_CD_DATABASE (CID_ID(0x816bU) | CID_FLAG) +#define CID_CANAVENC (CID_ID(0x816cU) | CID_FLAG) +#define CID_CANTIAGING (CID_ID(0x816dU) | CID_FLAG) +#define CID_CAUTOPICTCTRL (CID_ID(0x816eU) | CID_FLAG) +#define CID_CBBARCTRL (CID_ID(0x816fU) | CID_FLAG) +#define CID_CBBARDET (CID_ID(0x8170U) | CID_FLAG) +#define CID_CBBARDETEXT (CID_ID(0x8171U) | CID_FLAG) +#define CID_CBLEVELDETEXT (CID_ID(0x8172U) | CID_FLAG) +#define CID_CCOLENH (CID_ID(0x8173U) | CID_FLAG) +#define CID_CCOLENHEXT (CID_ID(0x8174U) | CID_FLAG) +#define CID_CCONTRESEXT (CID_ID(0x8175U) | CID_FLAG) +#define CID_CCTI (CID_ID(0x8176U) | CID_FLAG) +#define CID_CCTIEXT (CID_ID(0x8177U) | CID_FLAG) +#define CID_CDNR (CID_ID(0x8178U) | CID_FLAG) +#define CID_CDNREXT (CID_ID(0x8179U) | CID_FLAG) +#define CID_CGAMMAEXT (CID_ID(0x817aU) | CID_FLAG) +#define CID_CHISTOMEASEXT (CID_ID(0x817bU) | CID_FLAG) +#define CID_CHISTOMOD (CID_ID(0x817cU) | CID_FLAG) +#define CID_CHISTOMODEXT (CID_ID(0x817dU) | CID_FLAG) +#define CID_CMBSXRAY (CID_ID(0x817eU) | CID_FLAG) +#define CID_CNOISE (CID_ID(0x817fU) | CID_FLAG) +#define CID_CNOISEESTEXT (CID_ID(0x8180U) | CID_FLAG) +#define CID_CPFSPD (CID_ID(0x8181U) | CID_FLAG) +#define CID_CQVCPXRAY (CID_ID(0x8182U) | CID_FLAG) +#define CID_CSCANRATECONV (CID_ID(0x8183U) | CID_FLAG) +#define CID_CSCANRATECONVEXT (CID_ID(0x8184U) | CID_FLAG) +#define CID_CSHARPENH (CID_ID(0x8185U) | CID_FLAG) +#define CID_CSHARPENHEXT (CID_ID(0x8186U) | CID_FLAG) +#define CID_CSHARPMEAS (CID_ID(0x8187U) | CID_FLAG) +#define CID_CSHARPMEASEXT (CID_ID(0x8188U) | CID_FLAG) +#define CID_CSYNCTAG (CID_ID(0x8189U) | CID_FLAG) +#define CID_CUVBWDETEXT (CID_ID(0x818aU) | CID_FLAG) +#define CID_CVBISLICE (CID_ID(0x818bU) | CID_FLAG) +#define CID_CVFEAT (CID_ID(0x818cU) | CID_FLAG) +#define CID_CVFEAT2 (CID_ID(0x818dU) | CID_FLAG) +#define CID_CVIPXRAY (CID_ID(0x818eU) | CID_FLAG) +#define CID_CVIPXRAYDITHER (CID_ID(0x818fU) | CID_FLAG) +#define CID_CVMIX (CID_ID(0x8190U) | CID_FLAG) +#define CID_CVTRSCALEEXT (CID_ID(0x8191U) | CID_FLAG) +#define CID_CVTRANTIAGING (CID_ID(0x8192U) | CID_FLAG) +#define CID_CVTRFADEVCP (CID_ID(0x8193U) | CID_FLAG) +#define CID_CVTRSCALEMBSVCP (CID_ID(0x8194U) | CID_FLAG) +#define CID_CVTRSTROBEMBS (CID_ID(0x8195U) | CID_FLAG) +#define CID_NM_UTILS (CID_ID(0x8196U) | CID_FLAG) +#define CID_VSEQSCHEDENGINE (CID_ID(0x8197U) | CID_FLAG) +#define CID_VCPSCHEDENGINE (CID_ID(0x8198U) | CID_FLAG) +#define CID_VGENTEST (CID_ID(0x8199U) | CID_FLAG) +#define CID_VMENU (CID_ID(0x819aU) | CID_FLAG) +#define CID_VPROCCOMMON (CID_ID(0x819bU) | CID_FLAG) +#define CID_VPROCTV (CID_ID(0x819cU) | CID_FLAG) +#define CID_VPROCTV505E (CID_ID(0x819dU) | CID_FLAG) +#define CID_SCHEDENGINE (CID_ID(0x819eU) | CID_FLAG) +#define CID_VSLNMCOMMON (CID_ID(0x819fU) | CID_FLAG) +#define CID_VSLVCAPVIP (CID_ID(0x81a0U) | CID_FLAG) +#define CID_VSLVCAPVIPVBI (CID_ID(0x81a1U) | CID_FLAG) +#define CID_VSLVINCONVERT (CID_ID(0x81a2U) | CID_FLAG) +#define CID_VSLIOSYNC (CID_ID(0x81a3U) | CID_FLAG) +#define CID_VSLVRENDVCP (CID_ID(0x81a4U) | CID_FLAG) +#define CID_VSLVRENDVCPVBI (CID_ID(0x81a5U) | CID_FLAG) +#define CID_VSLSYNCTAG (CID_ID(0x81a6U) | CID_FLAG) +#define CID_VSLVTRANSMBS (CID_ID(0x81a7U) | CID_FLAG) +#define CID_VSLVTRANSNM (CID_ID(0x81a8U) | CID_FLAG) +#define CID_VSLVTRANSQTNR (CID_ID(0x81a9U) | CID_FLAG) +#define CID_VSLVTRANSSWTNR (CID_ID(0x81aaU) | CID_FLAG) +#define CID_VTRANSSWTNR (CID_ID(0x81abU) | CID_FLAG) +#define CID_LL_DMA (CID_ID(0x81acU) | CID_FLAG) +#define CID_BSL_PNX8550 (CID_ID(0x81adU) | CID_FLAG) +#define CID_BSL_PNX1500 (CID_ID(0x81aeU) | CID_FLAG) +#define CID_BSL_NULL (CID_ID(0x81afU) | CID_FLAG) +#define CID_BSL_PNX2015 (CID_ID(0x81b0U) | CID_FLAG) +#define CID_HW_SCALER7136 (CID_ID(0x81b1U) | CID_FLAG) +#define CID_SPI_IP3409 (CID_ID(0x81b2U) | CID_FLAG) +#define CID_SPI_3409 (CID_ID(0x81b3U) | CID_FLAG) +#define CID_SPISD_3409 (CID_ID(0x81b4U) | CID_FLAG) +#define CID_CONNMGRMP4RTPPLAYER (CID_ID(0x81b5U) | CID_FLAG) +#define CID_DL_NANDFLASH2 (CID_ID(0x81b6U) | CID_FLAG) +#define CID_HW_HOSTIF (CID_ID(0x81b7U) | CID_FLAG) +#define CID_LL_HOSTIF (CID_ID(0x81b8U) | CID_FLAG) +#define CID_LL_MJPEG (CID_ID(0x81b9U) | CID_FLAG) +#define CID_HW_SENSORIF (CID_ID(0x81baU) | CID_FLAG) +#define CID_LL_SENSORIF (CID_ID(0x81bbU) | CID_FLAG) +#define CID_HW_ECSP (CID_ID(0x81bcU) | CID_FLAG) +#define CID_LL_ECSP (CID_ID(0x81bdU) | CID_FLAG) +#define CID_HW_DOWNSCALER (CID_ID(0x81beU) | CID_FLAG) +#define CID_LL_DOWNSCALER (CID_ID(0x81bfU) | CID_FLAG) +#define CID_HW_UPSCALER (CID_ID(0x81c0U) | CID_FLAG) +#define CID_LL_UPSCALER (CID_ID(0x81c1U) | CID_FLAG) +#define CID_HW_JITTEREX (CID_ID(0x81c2U) | CID_FLAG) +#define CID_LL_JITTEREX (CID_ID(0x81c3U) | CID_FLAG) +#define CID_HW_NOISERED (CID_ID(0x81c4U) | CID_FLAG) +#define CID_LL_NOISERED (CID_ID(0x81c5U) | CID_FLAG) +#define CID_HW_JPEGENCODER (CID_ID(0x81c6U) | CID_FLAG) +#define CID_LL_JPEGENCODER (CID_ID(0x81c7U) | CID_FLAG) +#define CID_HW_FLASHLIGHT (CID_ID(0x81c8U) | CID_FLAG) +#define CID_LL_FLASHLIGHT (CID_ID(0x81c9U) | CID_FLAG) +#define CID_HW_TVCONVERTER (CID_ID(0x81caU) | CID_FLAG) +#define CID_LL_TVCONVERTER (CID_ID(0x81cbU) | CID_FLAG) +#define CID_HW_DVDOMATRIX (CID_ID(0x81ccU) | CID_FLAG) +#define CID_LL_DVDOMATRIX (CID_ID(0x81cdU) | CID_FLAG) +#define CID_HW_CLCD (CID_ID(0x81ceU) | CID_FLAG) +#define CID_LL_CLCD (CID_ID(0x81cfU) | CID_FLAG) +#define CID_HW_VDE (CID_ID(0x81d0U) | CID_FLAG) +#define CID_LL_VDE (CID_ID(0x81d1U) | CID_FLAG) +#define CID_HW_MCSPI (CID_ID(0x81d2U) | CID_FLAG) +#define CID_LL_MCSPI (CID_ID(0x81d3U) | CID_FLAG) +#define CID_HW_PWM (CID_ID(0x81d4U) | CID_FLAG) +#define CID_LL_PWM (CID_ID(0x81d5U) | CID_FLAG) +#define CID_OSAL_NXM (CID_ID(0x81d6U) | CID_FLAG) +#define CID_MEMPROF (CID_ID(0x81d7U) | CID_FLAG) +#define CID_ALCONSTRETCH (CID_ID(0x81d8U) | CID_FLAG) +#define CID_AUTOFOCUS (CID_ID(0x81d9U) | CID_FLAG) +#define CID_LL_DVDO2DTL (CID_ID(0x81daU) | CID_FLAG) +#define CID_HW_DVDO2DTL (CID_ID(0x81dbU) | CID_FLAG) +#define CID_LL_DTL2DVDO (CID_ID(0x81dcU) | CID_FLAG) +#define CID_HW_DTL2DVDO (CID_ID(0x81ddU) | CID_FLAG) +#define CID_LL_COLORMATRIX (CID_ID(0x81deU) | CID_FLAG) +#define CID_HW_COLORMATRIX (CID_ID(0x81dfU) | CID_FLAG) +#define CID_UHSPDIFOUT_ASYSATV (CID_ID(0x81e0U) | CID_FLAG) +#define CID_DL_NANDFLASH1 (CID_ID(0x81e1U) | CID_FLAG) +#define CID_NANDBOOTFFS (CID_ID(0x81e2U) | CID_FLAG) +#define CID_CONNMGR_APROCTV (CID_ID(0x81e3U) | CID_FLAG) +#define CID_CONNMGRSTILLPLAYER (CID_ID(0x81e4U) | CID_FLAG) +#define CID_CONNMGRAUDIOPLAYER (CID_ID(0x81e5U) | CID_FLAG) +#define CID_DCDIP9028 (CID_ID(0x81e6U) | CID_FLAG) +#define CID_CURLSRC_AUDIO (CID_ID(0x81e7U) | CID_FLAG) +#define CID_CONNMGRAVIMP4PLAYER (CID_ID(0x81e8U) | CID_FLAG) +#define CID_AUDIOVIDEOSYNC (CID_ID(0x81e9U) | CID_FLAG) +#define CID_PACKETLIST (CID_ID(0x81eaU) | CID_FLAG) +#define CID_ASYNCSINK (CID_ID(0x81ebU) | CID_FLAG) +#define CID_VSYNCSINK (CID_ID(0x81ecU) | CID_FLAG) +#define CID_XSYNCSINK (CID_ID(0x81edU) | CID_FLAG) +#define CID_PCIEXP (CID_ID(0x81eeU) | CID_FLAG) +#define CID_SOD_KERNEL (CID_ID(0x81efU) | CID_FLAG) +#define CID_SOD_EMULATE (CID_ID(0x81f0U) | CID_FLAG) +#define CID_SOD_MGR (CID_ID(0x81f1U) | CID_FLAG) +#define CID_NANDPARTTABLE (CID_ID(0x81f2U) | CID_FLAG) +#define CID_HW_AUDIO7136 (CID_ID(0x81f3U) | CID_FLAG) +#define CID_SPI3409 (CID_ID(0x81f4U) | CID_FLAG) +#define CID_DCSS_MATH (CID_ID(0x81f5U) | CID_FLAG) +#define CID_DCSS_LIT_CSD (CID_ID(0x81f6U) | CID_FLAG) +#define CID_DCSS_LIT_M (CID_ID(0x81f7U) | CID_FLAG) +#define CID_ADT (CID_ID(0x81f8U) | CID_FLAG) +#define CID_ACS (CID_ID(0x81f9U) | CID_FLAG) +#define CID_ACB (CID_ID(0x81faU) | CID_FLAG) +#define CID_ACL (CID_ID(0x81fbU) | CID_FLAG) +#define CID_AVEPP (CID_ID(0x81fcU) | CID_FLAG) +#define CID_UDSSIC (CID_ID(0x81fdU) | CID_FLAG) +#define CID_PROXYI2C (CID_ID(0x81feU) | CID_FLAG) +#define CID_PL081DMA (CID_ID(0x81feU) | CID_FLAG) +#define CID_DD_CPIPE (CID_ID(0x81ffU) | CID_FLAG) +#define CID_DD_MBVP (CID_ID(0x8200U) | CID_FLAG) +#define CID_CARENDAOUT (CID_ID(0x8201U) | CID_FLAG) +#define CID_CADIGAIN (CID_ID(0x8202U) | CID_FLAG) +#define CID_CONNMGR_TV506E (CID_ID(0x8203U) | CID_FLAG) +#define CID_ASYNCHANDLER (CID_ID(0x8204U) | CID_FLAG) +#define CID_COMP_M4VENCPSC (CID_ID(0x8205U) | CID_FLAG) +#define CID_CONNMGRNETSCHEMECONFIG (CID_ID(0x8206U) | CID_FLAG) +#define CID_CARACASSPIAHB (CID_ID(0x8207U) | CID_FLAG) +#define CID_COMP_ADECLPCM (CID_ID(0x8208U) | CID_FLAG) +#define CID_CDIGADEC_MULTISTD (CID_ID(0x8209U) | CID_FLAG) +#define CID_ADB (CID_ID(0x820aU) | CID_FLAG) +#define CID_ADR (CID_ID(0x820bU) | CID_FLAG) +#define CID_AGN (CID_ID(0x820cU) | CID_FLAG) +#define CID_ANT (CID_ID(0x820dU) | CID_FLAG) +#define CID_APP (CID_ID(0x820eU) | CID_FLAG) +#define CID_ASC (CID_ID(0x820fU) | CID_FLAG) +#define CID_ASM (CID_ID(0x8210U) | CID_FLAG) +#define CID_ASS (CID_ID(0x8211U) | CID_FLAG) +#define CID_ATP (CID_ID(0x8212U) | CID_FLAG) +#define CID_VDEC_MJPEG (CID_ID(0x8213U) | CID_FLAG) +#define CID_MOV_READ (CID_ID(0x8214U) | CID_FLAG) +#define CID_EWIFI (CID_ID(0x8215U) | CID_FLAG) +#define CID_SCR (CID_ID(0x8216U) | CID_FLAG) +#define CID_AEPP (CID_ID(0x8217U) | CID_FLAG) +#define CID_VEPP (CID_ID(0x8218U) | CID_FLAG) +#define CID_MP3ENC (CID_ID(0x8219U) | CID_FLAG) +#define CID_TDFLOADER (CID_ID(0x821aU) | CID_FLAG) +#define CID_VIOSYNC (CID_ID(0x821bU) | CID_FLAG) +#define CID_STBDP (CID_ID(0x821cU) | CID_FLAG) +#define CID_STBEVENT (CID_ID(0x821dU) | CID_FLAG) +#define CID_STBFB (CID_ID(0x821eU) | CID_FLAG) +#define CID_STBDEMUX (CID_ID(0x821fU) | CID_FLAG) +#define CID_STBFILE (CID_ID(0x8220U) | CID_FLAG) +#define CID_STBGPIO (CID_ID(0x8221U) | CID_FLAG) +#define CID_STBI2C (CID_ID(0x8222U) | CID_FLAG) +#define CID_STBMMIOBUS (CID_ID(0x8223U) | CID_FLAG) +#define CID_STBPROC (CID_ID(0x8224U) | CID_FLAG) +#define CID_STBROOT (CID_ID(0x8225U) | CID_FLAG) +#define CID_STBRPC (CID_ID(0x8226U) | CID_FLAG) +#define CID_STBRTC (CID_ID(0x8227U) | CID_FLAG) +#define CID_STBTMLOAD (CID_ID(0x8228U) | CID_FLAG) +#define CID_STBSTREAMINGSYSTEM (CID_ID(0x8229U) | CID_FLAG) +#define CID_STBVIDEOSCALER (CID_ID(0x822aU) | CID_FLAG) +#define CID_STBANALOGBACKEND (CID_ID(0x822bU) | CID_FLAG) +#define CID_STBVIDEORENDERER (CID_ID(0x822cU) | CID_FLAG) +#define CID_DRV_MMU (CID_ID(0x822dU) | CID_FLAG) +#define CID_COMP_AINJECTOR (CID_ID(0x822eU) | CID_FLAG) +#define CID_VDEC_ANA (CID_ID(0x822fU) | CID_FLAG) +#define CID_STBAC3AUD (CID_ID(0x8230U) | CID_FLAG) +#define CID_STBAUDIO (CID_ID(0x8231U) | CID_FLAG) +#define CID_PHMODARM11WRAPPER (CID_ID(0x8232U) | CID_FLAG) +#define CID_GPIO_IP4004 (CID_ID(0x8233U) | CID_FLAG) +#define CID_TMCADIGSPDIFIN (CID_ID(0x8234U) | CID_FLAG) +#define CID_TMCARENDSPDIFOUT (CID_ID(0x8235U) | CID_FLAG) +#define CID_TMCPLFINSTAIN (CID_ID(0x8236U) | CID_FLAG) +#define CID_TMCPLFINSTAOUT (CID_ID(0x8237U) | CID_FLAG) +#define CID_TMCSPDIFIN (CID_ID(0x8238U) | CID_FLAG) +#define CID_TMCSPDIFOUT (CID_ID(0x8239U) | CID_FLAG) +#define CID_BSL_HDMIRX (CID_ID(0x823aU) | CID_FLAG) +#define CID_AACPENC (CID_ID(0x823bU) | CID_FLAG) +#define CID_DL_HDMIRX (CID_ID(0x823cU) | CID_FLAG) +#define CID_APP_HDMIRX (CID_ID(0x823dU) | CID_FLAG) +#define CID_INFRA_HDMI (CID_ID(0x823eU) | CID_FLAG) +#define CID_DL_HDMICEC (CID_ID(0x823fU) | CID_FLAG) +#define CID_BSL_HDMITX (CID_ID(0x8240U) | CID_FLAG) +#define CID_DL_HDMITX (CID_ID(0x8241U) | CID_FLAG) +#define CID_APP_HDMITX (CID_ID(0x8242U) | CID_FLAG) + +/*define CID_UART (CID_ID(0x80a5U) | CID_FLAG) already defined*/ +#define CID_CHIP (CID_ID(0x815bU) | CID_FLAG) + +#define CID_RESERVED (CID_ID(0xff80U) | CID_FLAG) +/* ************************************************************************** */ +/* Component Id's reserved for external organizations */ +/* */ +/* 0xff80 thru 0xffbf */ +/* Range of component ID's is reserved for the use of parties outside of */ +/* Philips that wish to use component ID's privately. */ +/* If a component is going to be exchanged in the 'PS Ecosystem', then a */ +/* public component ID should be registered with MoReUse. */ +/* */ +/* Range to be used by CE Television Systems */ +/* 0xffc0 thru 0xffff */ +/* */ +/* ************************************************************************** */ + +/* -------------------------------------------------------------------------- */ +/* */ +/* Component ID types are defined as unsigned 32 bit integers (UInt32) */ +/* Interface ID types are defined as unsigned 32 bit integers (UInt32) */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* */ +/* Obsolete Component ID values */ +/* */ +/* -------------------------------------------------------------------------- */ + +/* -------------------------------------------------------------------------- */ +/* Component Class definitions (bits 31:28, 4 bits) */ +/* NOTE: A class of 0x0 must not be defined to ensure that the overall 32 bit */ +/* component ID/status combination is always non-0 (no TM_OK conflict). */ +/* -------------------------------------------------------------------------- */ +#define CID_CLASS_BITSHIFT 28 +#define CID_CLASS_BITMASK (0xFU << CID_CLASS_BITSHIFT) +#define CID_GET_CLASS(compId) ((compId & CID_CLASS_BITMASK) >> CID_CLASS_BITSHIFT) + +#define CID_CLASS_NONE (0x1U << CID_CLASS_BITSHIFT) +#define CID_CLASS_VIDEO (0x2U << CID_CLASS_BITSHIFT) +#define CID_CLASS_AUDIO (0x3U << CID_CLASS_BITSHIFT) +#define CID_CLASS_GRAPHICS (0x4U << CID_CLASS_BITSHIFT) +#define CID_CLASS_BUS (0x5U << CID_CLASS_BITSHIFT) +#define CID_CLASS_INFRASTR (0x6U << CID_CLASS_BITSHIFT) + +#define CID_CLASS_CUSTOMER (0xFU << CID_CLASS_BITSHIFT) + +/* -------------------------------------------------------------------------- */ +/* Component Type definitions (bits 27:24, 4 bits) */ +/* -------------------------------------------------------------------------- */ +#define CID_TYPE_BITSHIFT 24 +#define CID_TYPE_BITMASK (0xFU << CID_TYPE_BITSHIFT) +#define CID_GET_TYPE(compId) ((compId & CID_TYPE_BITMASK) >> CID_TYPE_BITSHIFT) + +#define CID_TYPE_NONE (0x0U << CID_TYPE_BITSHIFT) +#define CID_TYPE_SOURCE (0x1U << CID_TYPE_BITSHIFT) +#define CID_TYPE_SINK (0x2U << CID_TYPE_BITSHIFT) +#define CID_TYPE_ENCODER (0x3U << CID_TYPE_BITSHIFT) +#define CID_TYPE_DECODER (0x4U << CID_TYPE_BITSHIFT) +#define CID_TYPE_MUX (0x5U << CID_TYPE_BITSHIFT) +#define CID_TYPE_DEMUX (0x6U << CID_TYPE_BITSHIFT) +#define CID_TYPE_DIGITIZER (0x7U << CID_TYPE_BITSHIFT) +#define CID_TYPE_RENDERER (0x8U << CID_TYPE_BITSHIFT) +#define CID_TYPE_FILTER (0x9U << CID_TYPE_BITSHIFT) +#define CID_TYPE_CONTROL (0xAU << CID_TYPE_BITSHIFT) +#define CID_TYPE_DATABASE (0xBU << CID_TYPE_BITSHIFT) +#define CID_TYPE_SUBSYSTEM (0xCU << CID_TYPE_BITSHIFT) +#define CID_TYPE_CUSTOMER (0xFU << CID_TYPE_BITSHIFT) + +/* -------------------------------------------------------------------------- */ +/* Component Tag definitions (bits 23:16, 8 bits) */ +/* NOTE: Component tags are defined in groups, dependent on the class and */ +/* type. */ +/* -------------------------------------------------------------------------- */ +#define CID_TAG_BITSHIFT 16 +#define CID_TAG_BITMASK (0xFFU << CID_TAG_BITSHIFT) + +#define CID_TAG_NONE (0x00U << CID_TAG_BITSHIFT) + +#define CID_TAG_CUSTOMER (0xE0U << CID_TAG_BITSHIFT) + +#define TAG(number) ((number) << CID_TAG_BITSHIFT) + +/* -------------------------------------------------------------------------- */ +/* General Component Layer definitions (bits 15:12, 4 bits) */ +/* -------------------------------------------------------------------------- */ +#define CID_LAYER_BITSHIFT 12 +#define CID_LAYER_BITMASK (0xF << CID_LAYER_BITSHIFT) +#define CID_GET_LAYER(compId) ((compId & CID_LAYER_BITMASK) >> CID_LAYER_BITSHIFT) + +#define CID_LAYER_NONE (0x0U << CID_LAYER_BITSHIFT) +#define CID_LAYER_BTM (0x1U << CID_LAYER_BITSHIFT) +#define CID_LAYER_HWAPI (0x2U << CID_LAYER_BITSHIFT) +#define CID_LAYER_BSL (0x3U << CID_LAYER_BITSHIFT) +#define CID_LAYER_DEVLIB (0x4U << CID_LAYER_BITSHIFT) +#define CID_LAYER_TMAL (0x5U << CID_LAYER_BITSHIFT) +#define CID_LAYER_TMOL (0x6U << CID_LAYER_BITSHIFT) +#define CID_LAYER_TMNL (0xEU << CID_LAYER_BITSHIFT) + +/* -------------------------------------------------------------------------- */ +/* "new" i.e. after 2002-01-31 layer definitions */ +/* "New" Component Layers depend on the component type and class */ +/* So we can have an identical layer value for each type/class combination */ +/* In order not to break existing code that assumes that layers are unique, */ +/* we start new layers at 0x7 */ +/* -------------------------------------------------------------------------- */ + +/*------------------ CTYP_BUS_NOTYPE dependent layer definitions -------------*/ +#define CID_LAYER_UDS (0x7U << CID_LAYER_BITSHIFT) /* USB Device Stack */ +#define CID_LAYER_UHS (0x8U << CID_LAYER_BITSHIFT) /* USB Host stack */ +#define CID_LAYER_UOTG (0x9U << CID_LAYER_BITSHIFT) /* USB OTG stack */ + +#define CID_LAYER_CUSTOMER (0xFU << CID_LAYER_BITSHIFT) /* Customer Defined */ + +/* -------------------------------------------------------------------------- */ +/* Component Identifier definitions (bits 31:12, 20 bits) */ +/* NOTE: These DVP platform component identifiers are designed to be unique */ +/* within the system. The component identifier encompasses the class */ +/* (CID_CLASS_XXX), type (CID_TYPE_XXX), tag, and layer (CID_LAYER_XXX) */ +/* fields to form the unique component identifier. This allows any */ +/* error/progress status value to be identified as to its original */ +/* source, whether or not the source component s header file is present.*/ +/* The standard error/progress status definitions should be used */ +/* whenever possible to ease status interpretation. No layer */ +/* information is defined at this point; it should be ORed into the API */ +/* status values defined in the APIs header file. */ +/* -------------------------------------------------------------------------- */ +#if (CID_LAYER_NONE != 0) +#error ERROR: DVP component identifiers require the layer type 'NONE' = 0 ! +#endif + +/* -------------------------------------------------------------------------- */ +/* Classless Types/Components (don t fit into other class categories) */ +/* -------------------------------------------------------------------------- */ +#define CTYP_NOCLASS_NOTYPE (CID_CLASS_NONE | CID_TYPE_NONE) +#define CTYP_NOCLASS_SOURCE (CID_CLASS_NONE | CID_TYPE_SOURCE) +#define CTYP_NOCLASS_SINK (CID_CLASS_NONE | CID_TYPE_SINK) +#define CTYP_NOCLASS_MUX (CID_CLASS_NONE | CID_TYPE_MUX) +#define CTYP_NOCLASS_DEMUX (CID_CLASS_NONE | CID_TYPE_DEMUX) +#define CTYP_NOCLASS_FILTER (CID_CLASS_NONE | CID_TYPE_FILTER) +#define CTYP_NOCLASS_CONTROL (CID_CLASS_NONE | CID_TYPE_CONTROL) +#define CTYP_NOCLASS_DATABASE (CID_CLASS_NONE | CID_TYPE_DATABASE) +#define CTYP_NOCLASS_SUBSYS (CID_CLASS_NONE | CID_TYPE_SUBSYSTEM) + +#define CID_COMP_CLOCK (TAG(0x01U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_DMA (TAG(0x02U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_PIC (TAG(0x03U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_NORFLASH (TAG(0x04U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_NANDFLASH (TAG(0x05U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_GPIO (TAG(0x06U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_SMARTCARD (TAG(0x07U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_UDMA (TAG(0x08U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_DSP (TAG(0x09U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_TIMER (TAG(0x0AU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_TSDMA (TAG(0x0BU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_MMIARB (TAG(0x0CU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_EEPROM (TAG(0x0DU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_PARPORT (TAG(0x0EU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_VSS (TAG(0x0FU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_TSIO (TAG(0x10U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_DBG (TAG(0x11U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_TTE (TAG(0x12U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_AVPROP (TAG(0x13U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_SERIAL_RAM (TAG(0x14U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_SMARTMEDIA (TAG(0x15U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_COMPACT_FLASH (TAG(0x16U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_CI (TAG(0x17U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_INT_ALARM (TAG(0x18U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_TASK_ALARM (TAG(0x19U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_XDMA (TAG(0x1AU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_ICC (TAG(0x1BU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_CONNMGR (TAG(0x1CU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_CONNMGRVSYSTV (TAG(0x1DU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_VBISLICERVSYSTV (TAG(0x1EU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_VMIXVSYSTV (TAG(0x1FU) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_NTF (TAG(0x20U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_NTY CID_COMP_NTF /* legacy */ +#define CID_COMP_FATERR (TAG(0x21U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_DVBTDEMOD (TAG(0x22U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_HYBRIDTUNER (TAG(0x23U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_VLD (TAG(0x24U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_GIC (TAG(0x25U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_WEB (TAG(0x26U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_ANAEPGDB (TAG(0x27U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_HWSEM (TAG(0x28U) | CTYP_NOCLASS_NOTYPE) +#define CID_COMP_MMON (TAG(0x29U) | CTYP_NOCLASS_NOTYPE) + +#define CID_COMP_FREAD (TAG(0x01U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_CDRREAD (TAG(0x02U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_VSB (TAG(0x03U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_ANALOGTVTUNER (TAG(0x04U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_TPINMPEG2 (TAG(0x05U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_DREAD (TAG(0x06U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_TREAD (TAG(0x07U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_RTC (TAG(0x08U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_TOUCHC (TAG(0x09U) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_KEYPAD (TAG(0x0AU) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_ADC (TAG(0x0BU) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_READLIST (TAG(0x0CU) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_FROMDISK (TAG(0x0DU) | CTYP_NOCLASS_SOURCE) +#define CID_COMP_SOURCE (TAG(0x0EU) | CTYP_NOCLASS_SOURCE) + +#define CID_COMP_FWRITE (TAG(0x01U) | CTYP_NOCLASS_SINK) +#define CID_COMP_CDWRITE (TAG(0x02U) | CTYP_NOCLASS_SINK) +#define CID_COMP_CHARLCD (TAG(0x03U) | CTYP_NOCLASS_SINK) +#define CID_COMP_PWM (TAG(0x04U) | CTYP_NOCLASS_SINK) +#define CID_COMP_DAC (TAG(0x05U) | CTYP_NOCLASS_SINK) +#define CID_COMP_TSDMAINJECTOR (TAG(0x06U) | CTYP_NOCLASS_SINK) +#define CID_COMP_TODISK (TAG(0x07U) | CTYP_NOCLASS_SINK) + +#define CID_COMP_MUXMPEGPS (TAG(0x01U) | CTYP_NOCLASS_MUX) +#define CID_COMP_MUXMPEG (TAG(0x02U) | CTYP_NOCLASS_MUX) + +#define CID_COMP_DEMUXMPEGTS (TAG(0x01U) | CTYP_NOCLASS_DEMUX) +#define CID_COMP_DEMUXMPEGPS (TAG(0x02U) | CTYP_NOCLASS_DEMUX) +#define CID_COMP_DEMUXDV (TAG(0x03U) | CTYP_NOCLASS_DEMUX) + +#define CID_COMP_COPYIO (TAG(0x01U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_COPYINPLACE (TAG(0x02U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_UART (TAG(0x03U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_SSI (TAG(0x04U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_MODEMV34 (TAG(0x05U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_MODEMV42 (TAG(0x06U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_HTMLPARSER (TAG(0x07U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_VMSP (TAG(0x08U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_X (TAG(0x09U) | CTYP_NOCLASS_FILTER) +#define CID_COMP_TXTSUBTDECEBU (TAG(0x0AU) | CTYP_NOCLASS_FILTER) +#define CID_COMP_CPI (TAG(0x0BU) | CTYP_NOCLASS_FILTER) +#define CID_COMP_TRICK (TAG(0x0CU) | CTYP_NOCLASS_FILTER) +#define CID_COMP_FWRITEFREAD (TAG(0x0DU) | CTYP_NOCLASS_FILTER) + +#define CID_COMP_REMCTL5 (TAG(0x01U) | CTYP_NOCLASS_CONTROL) +#define CID_COMP_INFRARED (TAG(0x02U) | CTYP_NOCLASS_CONTROL) + +#define CID_COMP_PSIP (TAG(0x01U) | CTYP_NOCLASS_DATABASE) +#define CID_COMP_IDE (TAG(0x02U) | CTYP_NOCLASS_DATABASE) +#define CID_COMP_DISKSCHED (TAG(0x03U) | CTYP_NOCLASS_DATABASE) +#define CID_COMP_AVFS (TAG(0x04U) | CTYP_NOCLASS_DATABASE) +#define CID_COMP_MDB (TAG(0x05U) | CTYP_NOCLASS_DATABASE) +#define CID_COMP_ATAPI_CMDS (TAG(0x06U) | CTYP_NOCLASS_DATABASE) + +#define CID_COMP_IRDMMPEG (TAG(0x01U) | CTYP_NOCLASS_SUBSYS) +#define CID_COMP_STORSYS (TAG(0x02U) | CTYP_NOCLASS_SUBSYS) +#define CID_COMP_PMU (TAG(0x03U) | CTYP_NOCLASS_SUBSYS) + +/* -------------------------------------------------------------------------- */ +/* Video Class Types/Components (video types handle video/graphics data) */ +/* -------------------------------------------------------------------------- */ +#define CTYP_VIDEO_SINK (CID_CLASS_VIDEO | CID_TYPE_SINK) +#define CTYP_VIDEO_SOURCE (CID_CLASS_VIDEO | CID_TYPE_SOURCE) +#define CTYP_VIDEO_ENCODER (CID_CLASS_VIDEO | CID_TYPE_ENCODER) +#define CTYP_VIDEO_DECODER (CID_CLASS_VIDEO | CID_TYPE_DECODER) +#define CTYP_VIDEO_DIGITIZER (CID_CLASS_VIDEO | CID_TYPE_DIGITIZER) +#define CTYP_VIDEO_RENDERER (CID_CLASS_VIDEO | CID_TYPE_RENDERER) +#define CTYP_VIDEO_FILTER (CID_CLASS_VIDEO | CID_TYPE_FILTER) +#define CTYP_VIDEO_SUBSYS (CID_CLASS_VIDEO | CID_TYPE_SUBSYSTEM) + +#define CID_COMP_LCD (TAG(0x01U) | CTYP_VIDEO_SINK) + +#define CID_COMP_VCAPVI (TAG(0x01U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_VIP (TAG(0x02U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_VI (TAG(0x03U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_VSLICER (TAG(0x04U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_FBREAD (TAG(0x05U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_QVI (TAG(0x06U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_CAMERA (TAG(0x07U) | CTYP_VIDEO_SOURCE) +#define CID_COMP_CAM_SENSOR (TAG(0x08U) | CTYP_VIDEO_SOURCE) + +#define CID_COMP_VENCM1 (TAG(0x01U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_VENCM2 (TAG(0x02U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_VENCMJ (TAG(0x03U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_VENCH263 (TAG(0x04U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_VENCH261 (TAG(0x05U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_M4VENC (TAG(0x06U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_M4VENCME (TAG(0x07U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_M4VENCTC (TAG(0x08U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_M4VENCBSG (TAG(0x09U) | CTYP_VIDEO_ENCODER) +#define CID_COMP_M4VENCJPEG (TAG(0x0AU) | CTYP_VIDEO_ENCODER) + +#define CID_COMP_VDECM1 (TAG(0x01U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECM2 (TAG(0x02U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECMPEG (TAG(0x03U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECMJ (TAG(0x04U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECSUBPICSVCD (TAG(0x05U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECH263 (TAG(0x06U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECH261 (TAG(0x07U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDEC (TAG(0x08U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECSUBPICDVD (TAG(0x09U) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECSUBPICBMPDVD (TAG(0x0AU) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECSUBPICRENDDVD (TAG(0x0BU) | CTYP_VIDEO_DECODER) +#define CID_COMP_M4PP (TAG(0x0CU) | CTYP_VIDEO_DECODER) +#define CID_COMP_M4MC (TAG(0x0DU) | CTYP_VIDEO_DECODER) +#define CID_COMP_M4CSC (TAG(0x0EU) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECTXT (TAG(0x0FU) | CTYP_VIDEO_DECODER) +#define CID_COMP_VDECDV (TAG(0x10U) | CTYP_VIDEO_DECODER) +#define CID_COMP_BACKANIM (TAG(0x11U) | CTYP_VIDEO_DECODER) + +#define CID_COMP_VDIG (TAG(0x01U) | CTYP_VIDEO_DIGITIZER) +#define CID_COMP_VDIGVIRAW (TAG(0x02U) | CTYP_VIDEO_DIGITIZER) +#define CID_COMP_VDIG_EXT (TAG(0x03U) | CTYP_VIDEO_DIGITIZER) +#define CID_COMP_VDIG_VBI (TAG(0x04U) | CTYP_VIDEO_DIGITIZER) +#define CID_COMP_VDIG_EXT_VBI (TAG(0x05U) | CTYP_VIDEO_DIGITIZER) + +#define CID_COMP_VREND (TAG(0x01U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_HDVO (TAG(0x02U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VRENDGFXVO (TAG(0x03U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_AICP (TAG(0x04U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VRENDVORAW (TAG(0x05U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VO (TAG(0x06U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VRENDVOICP (TAG(0x07U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VMIX (TAG(0x08U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_QVCP (TAG(0x09U) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VREND_EXT (TAG(0x0AU) | CTYP_VIDEO_RENDERER) +#define CID_COMP_VENCANA (TAG(0x0BU) | CTYP_VIDEO_RENDERER) +#define CID_COMP_QVO (TAG(0x0CU) | CTYP_VIDEO_RENDERER) + +#define CID_COMP_MBS (TAG(0x01U) | CTYP_VIDEO_FILTER) +#define CID_COMP_VTRANS (TAG(0x02U) | CTYP_VIDEO_FILTER) +#define CID_COMP_QNM (TAG(0x03U) | CTYP_VIDEO_FILTER) +#define CID_COMP_ICP (TAG(0x04U) | CTYP_VIDEO_FILTER) +#define CID_COMP_VTRANSNM (TAG(0x05U) | CTYP_VIDEO_FILTER) +#define CID_COMP_QFD (TAG(0x06U) | CTYP_VIDEO_FILTER) +#define CID_COMP_VTRANSDVD (TAG(0x07U) | CTYP_VIDEO_FILTER) +#define CID_COMP_VTRANSCRYSTAL (TAG(0x08U) | CTYP_VIDEO_FILTER) +#define CID_COMP_VTRANSUD (TAG(0x09U) | CTYP_VIDEO_FILTER) +/*#define CID_COMP_QTNR (TAG(0x0AU) | CTYP_VIDEO_FILTER) Removed v17: Replaced with CID_VTRANS_QTNR */ + +#define CID_COMP_VSYSMT3 (TAG(0x01U) | CTYP_VIDEO_SUBSYS) +#define CID_COMP_VSYSSTB (TAG(0x01U) | CTYP_VIDEO_SUBSYS) +#define CID_COMP_DVDVIDSYS (TAG(0x02U) | CTYP_VIDEO_SUBSYS) +#define CID_COMP_VDECUD (TAG(0x03U) | CTYP_VIDEO_SUBSYS) +#define CID_COMP_VIDSYS (TAG(0x04U) | CTYP_VIDEO_SUBSYS) +#define CID_COMP_VSYSTV (TAG(0x05U) | CTYP_VIDEO_SUBSYS) + +/* -------------------------------------------------------------------------- */ +/* Audio Class Types/Components (audio types primarily handle audio data) */ +/* -------------------------------------------------------------------------- */ +#define CTYP_AUDIO_NOTYPE (CID_CLASS_AUDIO | CID_TYPE_NONE) +#define CTYP_AUDIO_SINK (CID_CLASS_AUDIO | CID_TYPE_SINK) +#define CTYP_AUDIO_SOURCE (CID_CLASS_AUDIO | CID_TYPE_SOURCE) +#define CTYP_AUDIO_ENCODER (CID_CLASS_AUDIO | CID_TYPE_ENCODER) +#define CTYP_AUDIO_DECODER (CID_CLASS_AUDIO | CID_TYPE_DECODER) +#define CTYP_AUDIO_DIGITIZER (CID_CLASS_AUDIO | CID_TYPE_DIGITIZER) +#define CTYP_AUDIO_RENDERER (CID_CLASS_AUDIO | CID_TYPE_RENDERER) +#define CTYP_AUDIO_FILTER (CID_CLASS_AUDIO | CID_TYPE_FILTER) +#define CTYP_AUDIO_SUBSYS (CID_CLASS_AUDIO | CID_TYPE_SUBSYSTEM) + +#define CID_COMP_CODEC (TAG(0x01U) | CTYP_AUDIO_NOTYPE) + +#define CID_COMP_SDAC (TAG(0x01U) | CTYP_AUDIO_SINK) + +#define CID_COMP_ADIGAI (TAG(0x01U) | CTYP_AUDIO_DIGITIZER) +#define CID_COMP_ADIGSPDIF (TAG(0x02U) | CTYP_AUDIO_DIGITIZER) + +#define CID_COMP_ARENDAO (TAG(0x01U) | CTYP_AUDIO_RENDERER) +#define CID_COMP_ARENDSPDIF (TAG(0x02U) | CTYP_AUDIO_RENDERER) + +#define CID_COMP_NOISESEQ (TAG(0x03U) | CTYP_AUDIO_SOURCE) + +#define CID_COMP_AENCAC3 (TAG(0x01U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AENCMPEG1 (TAG(0x02U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AENCAAC (TAG(0x03U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AENCG723 (TAG(0x04U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AENCG728 (TAG(0x05U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AENCWMA (TAG(0x06U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AVENCMPEG (TAG(0x07U) | CTYP_AUDIO_ENCODER) +#define CID_COMP_AENCMP3 (TAG(0x08U) | CTYP_AUDIO_ENCODER) + +#define CID_COMP_ADECPROLOGIC (TAG(0x01U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECAC3 (TAG(0x02U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECMPEG1 (TAG(0x03U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECMP3 (TAG(0x04U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECAAC (TAG(0x05U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECG723 (TAG(0x06U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECG728 (TAG(0x07U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECWMA (TAG(0x08U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECTHRU (TAG(0x09U) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADEC (TAG(0x0AU) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECPCM (TAG(0x0BU) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECDV (TAG(0x0CU) | CTYP_AUDIO_DECODER) +#define CID_COMP_ADECDTS (TAG(0x0DU) | CTYP_AUDIO_DECODER) + +#define CID_COMP_ASPLIB (TAG(0x01U) | CTYP_AUDIO_FILTER) +#define CID_COMP_IIR (TAG(0x02U) | CTYP_AUDIO_FILTER) +#define CID_COMP_ASPEQ2 (TAG(0x03U) | CTYP_AUDIO_FILTER) +#define CID_COMP_ASPEQ5 (TAG(0x04U) | CTYP_AUDIO_FILTER) +#define CID_COMP_ASPBASSREDIR (TAG(0x05U) | CTYP_AUDIO_FILTER) +#define CID_COMP_ASPLAT2 (TAG(0x06U) | CTYP_AUDIO_FILTER) +#define CID_COMP_ASPPLUGIN (TAG(0x07U) | CTYP_AUDIO_FILTER) +#define CID_COMP_AMIXDTV (TAG(0x08U) | CTYP_AUDIO_FILTER) +#define CID_COMP_AMIXSIMPLE (TAG(0x09U) | CTYP_AUDIO_FILTER) +#define CID_COMP_AMIXSTB (TAG(0x0AU) | CTYP_AUDIO_FILTER) +#define CID_COMP_ASPEQ (TAG(0x0BU) | CTYP_AUDIO_FILTER) +#define CID_COMP_ATESTSIG (TAG(0x0CU) | CTYP_AUDIO_FILTER) +#define CID_COMP_APROC (TAG(0x0DU) | CTYP_AUDIO_FILTER) + +#define CID_COMP_AUDSUBSYS (TAG(0x01U) | CTYP_AUDIO_SUBSYS) +#define CID_COMP_AUDSYSSTB (TAG(0x02U) | CTYP_AUDIO_SUBSYS) +#define CID_COMP_AUDSYSDVD (TAG(0x03U) | CTYP_AUDIO_SUBSYS) +#define CID_COMP_MMC (TAG(0x04U) | CTYP_AUDIO_SUBSYS) +#define CID_COMP_COMP_MMC CID_COMP_MMC /* legacy */ +#define CID_COMP_ASYSATV (TAG(0x05U) | CTYP_AUDIO_SUBSYS) + +/* -------------------------------------------------------------------------- */ +/* Graphics Class Types/Components */ +/* -------------------------------------------------------------------------- */ +#define CTYP_GRAPHICS_RENDERER (CID_CLASS_GRAPHICS | CID_TYPE_SINK) + +#define CID_COMP_WM (TAG(0x01U) | CTYP_GRAPHICS_RENDERER) +#define CID_COMP_WIDGET (TAG(0x02U) | CTYP_GRAPHICS_RENDERER) +#define CID_COMP_OM (TAG(0x03U) | CTYP_GRAPHICS_RENDERER) +#define CID_COMP_HTMLRENDER (TAG(0x04U) | CTYP_GRAPHICS_RENDERER) +#define CID_COMP_VRENDEIA708 (TAG(0x05U) | CTYP_GRAPHICS_RENDERER) +#define CID_COMP_VRENDEIA608 (TAG(0x06U) | CTYP_GRAPHICS_RENDERER) + +#define CTYP_GRAPHICS_DRAW (CID_CLASS_GRAPHICS | CID_TYPE_NONE) + +#define CID_COMP_DRAW (TAG(0x10U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_DRAW_UT (TAG(0x11U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_DRAW_DE (TAG(0x12U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_DRAW_REF (TAG(0x13U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_DRAW_TMH (TAG(0x14U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_DRAW_TMT (TAG(0x15U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_DRAW_TMTH (TAG(0x16U) | CTYP_GRAPHICS_DRAW) + +#define CID_COMP_3D (TAG(0x30U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_JAWT (TAG(0x31U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_JINPUT (TAG(0x32U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_LWM (TAG(0x33U) | CTYP_GRAPHICS_DRAW) +#define CID_COMP_2D (TAG(0x34U) | CTYP_GRAPHICS_DRAW) + +/* -------------------------------------------------------------------------- */ +/* Bus Class Types/Components (busses connect hardware components together) */ +/* -------------------------------------------------------------------------- */ +#define CTYP_BUS_NOTYPE (CID_CLASS_BUS | CID_TYPE_NONE) + +#define CID_COMP_XIO (TAG(0x01U) | CTYP_BUS_NOTYPE) +#define CID_COMP_IIC (TAG(0x02U) | CTYP_BUS_NOTYPE) +#define CID_COMP_PCI (TAG(0x03U) | CTYP_BUS_NOTYPE) +#define CID_COMP_P1394 (TAG(0x04U) | CTYP_BUS_NOTYPE) +#define CID_COMP_ENET (TAG(0x05U) | CTYP_BUS_NOTYPE) +#define CID_COMP_ATA (TAG(0x06U) | CTYP_BUS_NOTYPE) +#define CID_COMP_CAN (TAG(0x07U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UCGDMA (TAG(0x08U) | CTYP_BUS_NOTYPE) +#define CID_COMP_I2S (TAG(0x09U) | CTYP_BUS_NOTYPE) +#define CID_COMP_SPI (TAG(0x0AU) | CTYP_BUS_NOTYPE) +#define CID_COMP_PCM (TAG(0x0BU) | CTYP_BUS_NOTYPE) +#define CID_COMP_L3 (TAG(0x0CU) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSPFL (TAG(0x0DU) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSRSL (TAG(0x0EU) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSMSBOT (TAG(0x0FU) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSMSCBI (TAG(0x10U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSAUDIO (TAG(0x11U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSHID (TAG(0x12U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSCDC (TAG(0x13U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSPRINTER (TAG(0x14U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSSCSI (TAG(0x15U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSMODEM (TAG(0x16U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UDSETHERNET (TAG(0x17U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UHSPFL (TAG(0x18U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UHSMS (TAG(0x19U) | CTYP_BUS_NOTYPE) +#define CID_COMP_UHSAUDIO (TAG(0x1AU) | CTYP_BUS_NOTYPE) +#define CID_COMP_UHSSCSI (TAG(0x1BU) | CTYP_BUS_NOTYPE) + +/* -------------------------------------------------------------------------- */ +/* Infrastructure Class Types/Components */ +/* -------------------------------------------------------------------------- */ +#define CTYP_INFRASTR_NOTYPE (CID_CLASS_INFRASTR | CID_TYPE_NONE) +#define CTYP_INFRASTR_DATABASE (CID_CLASS_INFRASTR | CID_TYPE_DATABASE) + +#define CID_COMP_OSAL (TAG(0x01U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_MML (TAG(0x02U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_TSSA_DEFAULTS (TAG(0x03U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_RPC (TAG(0x04U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_THI (TAG(0x05U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_REGISTRY (TAG(0x06U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_TMMAN (TAG(0x07U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_LDT (TAG(0x08U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_CPUCONN (TAG(0x09U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_COMMQUE (TAG(0x0AU) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_BSLMGR (TAG(0x0BU) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_CR (TAG(0x0CU) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_NODE (TAG(0x0DU) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_COM (TAG(0x0EU) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_UTIL (TAG(0x0FU) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_SGLIST (TAG(0x10U) | CTYP_INFRASTR_NOTYPE) +#define CID_COMP_ARITH (TAG(0x11U) | CTYP_INFRASTR_NOTYPE) + +#define CID_COMP_MULTIFS (TAG(0x01U) | CTYP_INFRASTR_DATABASE) +#define CID_COMP_SFS (TAG(0x02U) | CTYP_INFRASTR_DATABASE) + +/* -------------------------------------------------------------------------- */ +/* Component Standard Error/Progress Status definitions (bits 11:0, 12 bits) */ +/* NOTE: These status codes are ORed with the component identifier to create */ +/* component unique 32 bit status values. The component status values */ +/* should be defined in the header files where the APIs are defined. */ +/* -------------------------------------------------------------------------- */ +#define CID_ERR_BITMASK 0xFFFU +#define CID_ERR_BITSHIFT 0 +#define CID_GET_ERROR(compId) ((compId & CID_ERR_BITMASK) >> CID_ERR_BITSHIFT) + +#define TM_ERR_COMPATIBILITY 0x001U /* SW Interface compatibility */ +#define TM_ERR_MAJOR_VERSION 0x002U /* SW Major Version error */ +#define TM_ERR_COMP_VERSION 0x003U /* SW component version error */ +#define TM_ERR_BAD_MODULE_ID 0x004U /* SW - HW module ID error */ +#define TM_ERR_BAD_UNIT_NUMBER 0x005U /* Invalid device unit number */ +#define TM_ERR_BAD_INSTANCE 0x006U /* Bad input instance value */ +#define TM_ERR_BAD_HANDLE 0x007U /* Bad input handle */ +#define TM_ERR_BAD_INDEX 0x008U /* Bad input index */ +#define TM_ERR_BAD_PARAMETER 0x009U /* Invalid input parameter */ +#define TM_ERR_NO_INSTANCES 0x00AU /* No instances available */ +#define TM_ERR_NO_COMPONENT 0x00BU /* Component is not present */ +#define TM_ERR_NO_RESOURCES 0x00CU /* Resource is not available */ +#define TM_ERR_INSTANCE_IN_USE 0x00DU /* Instance is already in use */ +#define TM_ERR_RESOURCE_OWNED 0x00EU /* Resource is already in use */ +#define TM_ERR_RESOURCE_NOT_OWNED 0x00FU /* Caller does not own resource */ +#define TM_ERR_INCONSISTENT_PARAMS 0x010U /* Inconsistent input params */ +#define TM_ERR_NOT_INITIALIZED 0x011U /* Component is not initialized */ +#define TM_ERR_NOT_ENABLED 0x012U /* Component is not enabled */ +#define TM_ERR_NOT_SUPPORTED 0x013U /* Function is not supported */ +#define TM_ERR_INIT_FAILED 0x014U /* Initialization failed */ +#define TM_ERR_BUSY 0x015U /* Component is busy */ +#define TM_ERR_NOT_BUSY 0x016U /* Component is not busy */ +#define TM_ERR_READ 0x017U /* Read error */ +#define TM_ERR_WRITE 0x018U /* Write error */ +#define TM_ERR_ERASE 0x019U /* Erase error */ +#define TM_ERR_LOCK 0x01AU /* Lock error */ +#define TM_ERR_UNLOCK 0x01BU /* Unlock error */ +#define TM_ERR_OUT_OF_MEMORY 0x01CU /* Memory allocation failed */ +#define TM_ERR_BAD_VIRT_ADDRESS 0x01DU /* Bad virtual address */ +#define TM_ERR_BAD_PHYS_ADDRESS 0x01EU /* Bad physical address */ +#define TM_ERR_TIMEOUT 0x01FU /* Timeout error */ +#define TM_ERR_OVERFLOW 0x020U /* Data overflow/overrun error */ +#define TM_ERR_FULL 0x021U /* Queue (etc.) is full */ +#define TM_ERR_EMPTY 0x022U /* Queue (etc.) is empty */ +#define TM_ERR_NOT_STARTED 0x023U /* Streaming function failed */ +#define TM_ERR_ALREADY_STARTED 0x024U /* Start function failed */ +#define TM_ERR_NOT_STOPPED 0x025U /* Non-streaming function failed*/ +#define TM_ERR_ALREADY_STOPPED 0x026U /* Stop function failed */ +#define TM_ERR_ALREADY_SETUP 0x027U /* Setup function failed */ +#define TM_ERR_NULL_PARAMETER 0x028U /* Null input parameter */ +#define TM_ERR_NULL_DATAINFUNC 0x029U /* Null data input function */ +#define TM_ERR_NULL_DATAOUTFUNC 0x02AU /* Null data output function */ +#define TM_ERR_NULL_CONTROLFUNC 0x02BU /* Null control function */ +#define TM_ERR_NULL_COMPLETIONFUNC 0x02CU /* Null completion function */ +#define TM_ERR_NULL_PROGRESSFUNC 0x02DU /* Null progress function */ +#define TM_ERR_NULL_ERRORFUNC 0x02EU /* Null error handler function */ +#define TM_ERR_NULL_MEMALLOCFUNC 0x02FU /* Null memory alloc function */ +#define TM_ERR_NULL_MEMFREEFUNC 0x030U /* Null memory free function */ +#define TM_ERR_NULL_CONFIGFUNC 0x031U /* Null configuration function */ +#define TM_ERR_NULL_PARENT 0x032U /* Null parent data */ +#define TM_ERR_NULL_IODESC 0x033U /* Null in/out descriptor */ +#define TM_ERR_NULL_CTRLDESC 0x034U /* Null control descriptor */ +#define TM_ERR_UNSUPPORTED_DATACLASS 0x035U /* Unsupported data class */ +#define TM_ERR_UNSUPPORTED_DATATYPE 0x036U /* Unsupported data type */ +#define TM_ERR_UNSUPPORTED_DATASUBTYPE 0x037U /* Unsupported data subtype */ +#define TM_ERR_FORMAT 0x038U /* Invalid/unsupported format */ +#define TM_ERR_INPUT_DESC_FLAGS 0x039U /* Bad input descriptor flags */ +#define TM_ERR_OUTPUT_DESC_FLAGS 0x03AU /* Bad output descriptor flags */ +#define TM_ERR_CAP_REQUIRED 0x03BU /* Capabilities required ??? */ +#define TM_ERR_BAD_TMALFUNC_TABLE 0x03CU /* Bad TMAL function table */ +#define TM_ERR_INVALID_CHANNEL_ID 0x03DU /* Invalid channel identifier */ +#define TM_ERR_INVALID_COMMAND 0x03EU /* Invalid command/request */ +#define TM_ERR_STREAM_MODE_CONFUSION 0x03FU /* Stream mode config conflict */ +#define TM_ERR_UNDERRUN 0x040U /* Data underflow/underrun */ +#define TM_ERR_EMPTY_PACKET_RECVD 0x041U /* Empty data packet received */ +#define TM_ERR_OTHER_DATAINOUT_ERR 0x042U /* Other data input/output err */ +#define TM_ERR_STOP_REQUESTED 0x043U /* Stop in progress */ +#define TM_ERR_ASSERTION 0x049U /* Assertion failure */ +#define TM_ERR_HIGHWAY_BANDWIDTH 0x04AU /* Highway bandwidth bus error */ +#define TM_ERR_HW_RESET_FAILED 0x04BU /* Hardware reset failed */ +#define TM_ERR_BAD_FLAGS 0x04DU /* Bad flags */ +#define TM_ERR_BAD_PRIORITY 0x04EU /* Bad priority */ +#define TM_ERR_BAD_REFERENCE_COUNT 0x04FU /* Bad reference count */ +#define TM_ERR_BAD_SETUP 0x050U /* Bad setup */ +#define TM_ERR_BAD_STACK_SIZE 0x051U /* Bad stack size */ +#define TM_ERR_BAD_TEE 0x052U /* Bad tee */ +#define TM_ERR_IN_PLACE 0x053U /* In place */ +#define TM_ERR_NOT_CACHE_ALIGNED 0x054U /* Not cache aligned */ +#define TM_ERR_NO_ROOT_TEE 0x055U /* No root tee */ +#define TM_ERR_NO_TEE_ALLOWED 0x056U /* No tee allowed */ +#define TM_ERR_NO_TEE_EMPTY_PACKET 0x057U /* No tee empty packet */ +#define TM_ERR_NULL_PACKET 0x059U /* Null packet */ +#define TM_ERR_FORMAT_FREED 0x05AU /* Format freed */ +#define TM_ERR_FORMAT_INTERNAL 0x05BU /* Format internal */ +#define TM_ERR_BAD_FORMAT 0x05CU /* Bad format */ +#define TM_ERR_FORMAT_NEGOTIATE_DATACLASS 0x05DU /* Format negotiate class */ +#define TM_ERR_FORMAT_NEGOTIATE_DATATYPE 0x05EU /* Format negotiate type */ +#define TM_ERR_FORMAT_NEGOTIATE_DATASUBTYPE 0x05FU /* Format negotiate subtype */ +#define TM_ERR_FORMAT_NEGOTIATE_DESCRIPTION 0x060U /* Format negotiate desc */ +#define TM_ERR_NULL_FORMAT 0x061U /* Null format */ +#define TM_ERR_FORMAT_REFERENCE_COUNT 0x062U /* Format reference count */ +#define TM_ERR_FORMAT_NOT_UNIQUE 0x063U /* Format not unique */ +#define TM_NEW_FORMAT 0x064U /* New format (not an error) */ +#define TM_ERR_FORMAT_NEGOTIATE_EXTENSION 0x065U /* Format negotiate extension */ +#define TM_ERR_INVALID_STATE 0x066U /* Invalid state for function */ +#define TM_ERR_NULL_CONNECTION 0x067U /* No connection to this pin */ +#define TM_ERR_OPERATION_NOT_PERMITTED 0x068U /* corresponds to posix EPERM */ +#define TM_ERR_NOT_CLOCKED 0x069U /* Power down - clocked off */ + + +#define PH_ERR_COMPATIBILITY 0x001U /* SW Interface compatibility */ +#define PH_ERR_MAJOR_VERSION 0x002U /* SW Major Version error */ +#define PH_ERR_COMP_VERSION 0x003U /* SW component version error */ +#define PH_ERR_BAD_MODULE_ID 0x004U /* SW - HW module ID error */ +#define PH_ERR_BAD_UNIT_NUMBER 0x005U /* Invalid device unit number */ +#define PH_ERR_BAD_INSTANCE 0x006U /* Bad input instance value */ +#define PH_ERR_BAD_HANDLE 0x007U /* Bad input handle */ +#define PH_ERR_BAD_INDEX 0x008U /* Bad input index */ +#define PH_ERR_BAD_PARAMETER 0x009U /* Invalid input parameter */ +#define PH_ERR_NO_INSTANCES 0x00AU /* No instances available */ +#define PH_ERR_NO_COMPONENT 0x00BU /* Component is not present */ +#define PH_ERR_NO_RESOURCES 0x00CU /* Resource is not available */ +#define PH_ERR_INSTANCE_IN_USE 0x00DU /* Instance is already in use */ +#define PH_ERR_RESOURCE_OWNED 0x00EU /* Resource is already in use */ +#define PH_ERR_RESOURCE_NOT_OWNED 0x00FU /* Caller does not own resource */ +#define PH_ERR_INCONSISTENT_PARAMS 0x010U /* Inconsistent input params */ +#define PH_ERR_NOT_INITIALIZED 0x011U /* Component is not initialized */ +#define PH_ERR_NOT_ENABLED 0x012U /* Component is not enabled */ +#define PH_ERR_NOT_SUPPORTED 0x013U /* Function is not supported */ +#define PH_ERR_INIT_FAILED 0x014U /* Initialization failed */ +#define PH_ERR_BUSY 0x015U /* Component is busy */ +#define PH_ERR_NOT_BUSY 0x016U /* Component is not busy */ +#define PH_ERR_READ 0x017U /* Read error */ +#define PH_ERR_WRITE 0x018U /* Write error */ +#define PH_ERR_ERASE 0x019U /* Erase error */ +#define PH_ERR_LOCK 0x01AU /* Lock error */ +#define PH_ERR_UNLOCK 0x01BU /* Unlock error */ +#define PH_ERR_OUT_OF_MEMORY 0x01CU /* Memory allocation failed */ +#define PH_ERR_BAD_VIRT_ADDRESS 0x01DU /* Bad virtual address */ +#define PH_ERR_BAD_PHYS_ADDRESS 0x01EU /* Bad physical address */ +#define PH_ERR_TIMEOUT 0x01FU /* Timeout error */ +#define PH_ERR_OVERFLOW 0x020U /* Data overflow/overrun error */ +#define PH_ERR_FULL 0x021U /* Queue (etc.) is full */ +#define PH_ERR_EMPTY 0x022U /* Queue (etc.) is empty */ +#define PH_ERR_NOT_STARTED 0x023U /* Streaming function failed */ +#define PH_ERR_ALREADY_STARTED 0x024U /* Start function failed */ +#define PH_ERR_NOT_STOPPED 0x025U /* Non-streaming function failed*/ +#define PH_ERR_ALREADY_STOPPED 0x026U /* Stop function failed */ +#define PH_ERR_ALREADY_SETUP 0x027U /* Setup function failed */ +#define PH_ERR_NULL_PARAMETER 0x028U /* Null input parameter */ +#define PH_ERR_NULL_DATAINFUNC 0x029U /* Null data input function */ +#define PH_ERR_NULL_DATAOUTFUNC 0x02AU /* Null data output function */ +#define PH_ERR_NULL_CONTROLFUNC 0x02BU /* Null control function */ +#define PH_ERR_NULL_COMPLETIONFUNC 0x02CU /* Null completion function */ +#define PH_ERR_NULL_PROGRESSFUNC 0x02DU /* Null progress function */ +#define PH_ERR_NULL_ERRORFUNC 0x02EU /* Null error handler function */ +#define PH_ERR_NULL_MEMALLOCFUNC 0x02FU /* Null memory alloc function */ +#define PH_ERR_NULL_MEMFREEFUNC 0x030U /* Null memory free function */ +#define PH_ERR_NULL_CONFIGFUNC 0x031U /* Null configuration function */ +#define PH_ERR_NULL_PARENT 0x032U /* Null parent data */ +#define PH_ERR_NULL_IODESC 0x033U /* Null in/out descriptor */ +#define PH_ERR_NULL_CTRLDESC 0x034U /* Null control descriptor */ +#define PH_ERR_UNSUPPORTED_DATACLASS 0x035U /* Unsupported data class */ +#define PH_ERR_UNSUPPORTED_DATATYPE 0x036U /* Unsupported data type */ +#define PH_ERR_UNSUPPORTED_DATASUBTYPE 0x037U /* Unsupported data subtype */ +#define PH_ERR_FORMAT 0x038U /* Invalid/unsupported format */ +#define PH_ERR_INPUT_DESC_FLAGS 0x039U /* Bad input descriptor flags */ +#define PH_ERR_OUTPUT_DESC_FLAGS 0x03AU /* Bad output descriptor flags */ +#define PH_ERR_CAP_REQUIRED 0x03BU /* Capabilities required ??? */ +#define PH_ERR_BAD_TMALFUNC_TABLE 0x03CU /* Bad TMAL function table */ +#define PH_ERR_INVALID_CHANNEL_ID 0x03DU /* Invalid channel identifier */ +#define PH_ERR_INVALID_COMMAND 0x03EU /* Invalid command/request */ +#define PH_ERR_STREAM_MODE_CONFUSION 0x03FU /* Stream mode config conflict */ +#define PH_ERR_UNDERRUN 0x040U /* Data underflow/underrun */ +#define PH_ERR_EMPTY_PACKET_RECVD 0x041U /* Empty data packet received */ +#define PH_ERR_OTHER_DATAINOUT_ERR 0x042U /* Other data input/output err */ +#define PH_ERR_STOP_REQUESTED 0x043U /* Stop in progress */ +#define PH_ERR_ASSERTION 0x049U /* Assertion failure */ +#define PH_ERR_HIGHWAY_BANDWIDTH 0x04AU /* Highway bandwidth bus error */ +#define PH_ERR_HW_RESET_FAILED 0x04BU /* Hardware reset failed */ +#define PH_ERR_BAD_FLAGS 0x04DU /* Bad flags */ +#define PH_ERR_BAD_PRIORITY 0x04EU /* Bad priority */ +#define PH_ERR_BAD_REFERENCE_COUNT 0x04FU /* Bad reference count */ +#define PH_ERR_BAD_SETUP 0x050U /* Bad setup */ +#define PH_ERR_BAD_STACK_SIZE 0x051U /* Bad stack size */ +#define PH_ERR_BAD_TEE 0x052U /* Bad tee */ +#define PH_ERR_IN_PLACE 0x053U /* In place */ +#define PH_ERR_NOT_CACHE_ALIGNED 0x054U /* Not cache aligned */ +#define PH_ERR_NO_ROOT_TEE 0x055U /* No root tee */ +#define PH_ERR_NO_TEE_ALLOWED 0x056U /* No tee allowed */ +#define PH_ERR_NO_TEE_EMPTY_PACKET 0x057U /* No tee empty packet */ +#define PH_ERR_NULL_PACKET 0x059U /* Null packet */ +#define PH_ERR_FORMAT_FREED 0x05AU /* Format freed */ +#define PH_ERR_FORMAT_INTERNAL 0x05BU /* Format internal */ +#define PH_ERR_BAD_FORMAT 0x05CU /* Bad format */ +#define PH_ERR_FORMAT_NEGOTIATE_DATACLASS 0x05DU /* Format negotiate class */ +#define PH_ERR_FORMAT_NEGOTIATE_DATATYPE 0x05EU /* Format negotiate type */ +#define PH_ERR_FORMAT_NEGOTIATE_DATASUBTYPE 0x05FU /* Format negotiate subtype */ +#define PH_ERR_FORMAT_NEGOTIATE_DESCRIPTION 0x060U /* Format negotiate desc */ +#define PH_ERR_NULL_FORMAT 0x061U /* Null format */ +#define PH_ERR_FORMAT_REFERENCE_COUNT 0x062U /* Format reference count */ +#define PH_ERR_FORMAT_NOT_UNIQUE 0x063U /* Format not unique */ +#define PH_NEW_FORMAT 0x064U /* New format (not an error) */ +#define PH_ERR_FORMAT_NEGOTIATE_EXTENSION 0x065U /* Format negotiate extension */ +#define PH_ERR_INVALID_STATE 0x066U /* Invalid state for function */ +#define PH_ERR_NULL_CONNECTION 0x067U /* No connection to this pin */ +#define PH_ERR_OPERATION_NOT_PERMITTED 0x068U /* corresponds to posix EPERM */ +#define PH_ERR_NOT_CLOCKED 0x069U /* Power down - clocked off */ + +/* Add new standard error/progress status codes here */ + +#define TM_ERR_COMP_UNIQUE_START 0x800U /* 0x800-0xBFF: Component unique */ +#define PH_ERR_COMP_UNIQUE_START 0x800U /* 0x800-0xBFF: Component unique */ +#define TM_ERR_CUSTOMER_START 0xC00U /* 0xC00-0xDFF: Customer defined */ +#define PH_ERR_CUSTOMER_START 0xC00U /* 0xC00-0xDFF: Customer defined */ + +/* Legacy and withdrawn error codes */ +#define TM_ERR_FORMAT_NEGOTIATE_SUBCLASS TM_ERR_FORMAT_NEGOTIATE_DATACLASS +#define TM_ERR_NEW_FORMAT TM_NEW_FORMAT +#define TM_ERR_PAUSE_PIN_REQUESTED TM_ERR_STOP_REQUESTED +#define TM_ERR_PIN_ALREADY_STARTED TM_ERR_ALREADY_STARTED +#define TM_ERR_PIN_ALREADY_STOPPED TM_ERR_ALREADY_STOPPED +#define TM_ERR_PIN_NOT_STARTED TM_ERR_NOT_STARTED +#define TM_ERR_PIN_NOT_STOPPED TM_ERR_NOT_STOPPED +#define TM_ERR_PIN_PAUSED TM_ERR_NOT_STARTED + +/* -------------------------------------------------------------------------- */ +/* Standard assert error code start offset */ +/* NOTE: These ranges are FOR LEGACY CODE ONLY and must not be used in new */ +/* components */ +/* -------------------------------------------------------------------------- */ +#define TM_ERR_ASSERT_START 0xE00U /* 0xE00-0xEFF: Assert failures */ +#define TM_ERR_ASSERT_LAST 0xEFFU /* Last assert error range value */ +#define CID_IS_ASSERT_ERROR(compId) ((CID_GET_ERROR(compId) >= TM_ERR_ASSERT_START) && (CID_GET_ERROR(compId) <= TM_ERR_ASSERT_LAST)) + +/* -------------------------------------------------------------------------- */ +/* Standard fatal error code start offset */ +/* NOTE: These ranges are FOR LEGACY CODE ONLY and must not be used in new */ +/* components */ +/* -------------------------------------------------------------------------- */ + +#define TM_ERR_FATAL_START 0xF00U /* 0xF00-0xFFF: Fatal failures */ +#define TM_ERR_FATAL_LAST 0xFFFU /* Last fatal error range value */ +#define CID_IS_FATAL_ERROR(compId) ((CID_GET_ERROR(compId) >= TM_ERR_FATAL_START) && (CID_GET_ERROR(compId) <= TM_ERR_FATAL_LAST)) + +#ifdef __cplusplus +} +#endif + +#endif /* TMNXCOMPID_H ----------------- */ diff --git a/drivers/video/nxp/inc/tmNxTypes.h b/drivers/video/nxp/inc/tmNxTypes.h new file mode 100755 index 0000000000000..5645d28c52218 --- /dev/null +++ b/drivers/video/nxp/inc/tmNxTypes.h @@ -0,0 +1,366 @@ +/*==========================================================================*/ +/* (Copyright (C) 2003 Koninklijke Philips Electronics N.V. */ +/* All rights reserved. */ +/* This source code and any compilation or derivative thereof is the */ +/* proprietary information of Koninklijke Philips Electronics N.V. */ +/* and is confidential in nature. */ +/* Under no circumstances is this software to be exposed to or placed */ +/* under an Open Source License of any type without the expressed */ +/* written permission of Koninklijke Philips Electronics N.V. */ +/*==========================================================================*/ +/* + * Copyright (C) 2000,2001 + * Koninklijke Philips Electronics N.V. + * All Rights Reserved. + * + * Copyright (C) 2000,2001 TriMedia Technologies, Inc. + * All Rights Reserved. + * + *############################################################ + * + * Module name : tmNxTypes.h %version: 7 % + * + * Last Update : %date_modified: Tue Jul 8 18:08:00 2003 % + * + * Description: TriMedia/MIPS global type definitions. + * + * Document Ref: DVP Software Coding Guidelines Specification + * DVP/MoReUse Naming Conventions specification + * DVP Software Versioning Specification + * DVP Device Library Architecture Specification + * DVP Board Support Library Architecture Specification + * DVP Hardware API Architecture Specification + * + * + *############################################################ + */ + +#ifndef TMNXTYPES_H +#define TMNXTYPES_H + +//----------------------------------------------------------------------------- +// Standard include files: +//----------------------------------------------------------------------------- +// + +//----------------------------------------------------------------------------- +// Project include files: +//----------------------------------------------------------------------------- +// +#include "tmFlags.h" // DVP common build control flags + +#ifdef __cplusplus +extern "C" +{ +#endif + +//----------------------------------------------------------------------------- +// Types and defines: +//----------------------------------------------------------------------------- +// + +/*Under the TCS, may have been included by our client. In + order to avoid errors, we take account of this possibility, but in order to + support environments where the TCS is not available, we do not include the + file by name.*/ + +#ifndef _TMtypes_h +#define _TMtypes_h + +#define False 0 +#define True 1 + +#ifdef __cplusplus +#define Null 0 +#else +#define Null ((Void *) 0) +#endif + +// +// Standard Types +// +typedef signed char Int8; // 8 bit signed integer +typedef signed short Int16; // 16 bit signed integer +typedef signed long Int32; // 32 bit signed integer +typedef unsigned char UInt8; // 8 bit unsigned integer +typedef unsigned short UInt16; // 16 bit unsigned integer +typedef unsigned long UInt32; // 32 bit unsigned integer +typedef float Float; // 32 bit floating point +typedef unsigned int Bool; // Boolean (True/False) +typedef char Char; // character, character array ptr +typedef int Int; // machine-natural integer +typedef unsigned int UInt; // machine-natural unsigned integer +typedef char *String; // Null terminated 8 bit char str + +//----------------------------------------------------------------------------- +// Legacy TM Types/Structures (Not necessarily DVP Coding Guideline compliant) +// NOTE: For DVP Coding Gudeline compliant code, do not use these types. +// +typedef char *Address; // Ready for address-arithmetic +typedef char const *ConstAddress; +typedef unsigned char Byte; // Raw byte +typedef float Float32; // Single-precision float +typedef double Float64; // Double-precision float +typedef void *Pointer; // Pointer to anonymous object +typedef void const *ConstPointer; +typedef char const *ConstString; + +typedef Int Endian; +#define BigEndian 0 +#define LittleEndian 1 + +typedef struct tmVersion +{ + UInt8 majorVersion; + UInt8 minorVersion; + UInt16 buildVersion; +} tmVersion_t, *ptmVersion_t; +#endif /*ndef _TMtypes_h*/ + +/*Define DVP types that are not TCS types.*/ +/* +** ===== Updated from SDE2/2.3_Beta/sde_template/inc/tmNxTypes.h ===== +** +** NOTE: IBits32/UBits32 types are defined for use with 32 bit bitfields. +** This is done because ANSI/ISO compliant compilers require bitfields +** to be of type "int" else a large number of compiler warnings will +** result. To avoid the risks associated with redefining Int32/UInt32 +** to type "int" instead of type "long" (which are the same size on 32 +** bit CPUs) separate 32bit signed/unsigned bitfield types are defined. +*/ +typedef signed int IBits32; /* 32 bit signed integer bitfields */ +typedef unsigned int UBits32; /* 32 bit unsigned integer bitfields */ +typedef IBits32 *pIBits32; /* 32 bit signed integer bitfield ptr */ +typedef UBits32 *pUBits32; /* 32 bit unsigned integer bitfield ptr */ + +typedef Int8 *pInt8; // 8 bit signed integer +typedef Int16 *pInt16; // 16 bit signed integer +typedef Int32 *pInt32; // 32 bit signed integer +typedef UInt8 *pUInt8; // 8 bit unsigned integer +typedef UInt16 *pUInt16; // 16 bit unsigned integer +typedef UInt32 *pUInt32; // 32 bit unsigned integer +typedef void Void, *pVoid; // Void (typeless) +typedef Float *pFloat; // 32 bit floating point +typedef double Double, *pDouble; // 32/64 bit floating point +typedef Bool *pBool; // Boolean (True/False) +typedef Char *pChar; // character, character array ptr +typedef Int *pInt; // machine-natural integer +typedef UInt *pUInt; // machine-natural unsigned integer +typedef String *pString; // Null terminated 8 bit char str, + +/*Assume that 64-bit integers are supported natively by C99 compilers and Visual + C version 6.00 and higher. More discrimination in this area may be added + here as necessary.*/ +#if defined __STDC_VERSION__ && __STDC_VERSION__ > 199409L +/*This can be enabled only when all explicit references to the hi and lo + structure members are eliminated from client code.*/ +#define TMFL_NATIVE_INT64 1 +typedef signed long long int Int64, *pInt64; // 64-bit integer +typedef unsigned long long int UInt64, *pUInt64; // 64-bit bitmask +// #elif defined _MSC_VER && _MSC_VER >= 1200 +// /*This can be enabled only when all explicit references to the hi and lo +// structure members are eliminated from client code.*/ +// #define TMFL_NATIVE_INT64 1 +// typedef signed __int64 Int64, *pInt64; // 64-bit integer +// typedef unsigned __int64 UInt64, *pUInt64; // 64-bit bitmask +#else /*!(defined __STDC_VERSION__ && __STDC_VERSION__ > 199409L)*/ +#define TMFL_NATIVE_INT64 0 +typedef + struct + { + /*Get the correct endianness (this has no impact on any other part of + the system, but may make memory dumps easier to understand).*/ +#if TMFL_ENDIAN == TMFL_ENDIAN_BIG + Int32 hi; UInt32 lo; +#else + UInt32 lo; Int32 hi; +#endif + } + Int64, *pInt64; // 64-bit integer +typedef + struct + { +#if TMFL_ENDIAN == TMFL_ENDIAN_BIG + UInt32 hi; UInt32 lo; +#else + UInt32 lo; UInt32 hi; +#endif + } + UInt64, *pUInt64; // 64-bit bitmask +#endif /*defined __STDC_VERSION__ && __STDC_VERSION__ > 199409L*/ + +// Maximum length of device name in all BSP and capability structures +#define HAL_DEVICE_NAME_LENGTH 16 + +typedef UInt32 tmErrorCode_t; +typedef UInt32 tmProgressCode_t; + +/* timestamp definition */ +typedef UInt64 tmTimeStamp_t, *ptmTimeStamp_t; + +//for backwards compatibility with the older tmTimeStamp_t definition +#define ticks lo +#define hiTicks hi + +typedef union tmColor3 // 3 byte color structure +{ + UBits32 u32; +#if (TMFL_ENDIAN == TMFL_ENDIAN_BIG) + struct { + UBits32 : 8; + UBits32 red : 8; + UBits32 green : 8; + UBits32 blue : 8; + } rgb; + struct { + UBits32 : 8; + UBits32 y : 8; + UBits32 u : 8; + UBits32 v : 8; + } yuv; + struct { + UBits32 : 8; + UBits32 u : 8; + UBits32 m : 8; + UBits32 l : 8; + } uml; +#else + struct { + UBits32 blue : 8; + UBits32 green : 8; + UBits32 red : 8; + UBits32 : 8; + } rgb; + struct { + UBits32 v : 8; + UBits32 u : 8; + UBits32 y : 8; + UBits32 : 8; + } yuv; + struct { + UBits32 l : 8; + UBits32 m : 8; + UBits32 u : 8; + UBits32 : 8; + } uml; +#endif +} tmColor3_t, *ptmColor3_t; + +typedef union tmColor4 // 4 byte color structure +{ + UBits32 u32; +#if (TMFL_ENDIAN == TMFL_ENDIAN_BIG) + struct { + UBits32 alpha : 8; + UBits32 red : 8; + UBits32 green : 8; + UBits32 blue : 8; + } argb; + struct { + UBits32 alpha : 8; + UBits32 y : 8; + UBits32 u : 8; + UBits32 v : 8; + } ayuv; + struct { + UBits32 alpha : 8; + UBits32 u : 8; + UBits32 m : 8; + UBits32 l : 8; + } auml; +#else + struct { + UBits32 blue : 8; + UBits32 green : 8; + UBits32 red : 8; + UBits32 alpha : 8; + } argb; + struct { + UBits32 v : 8; + UBits32 u : 8; + UBits32 y : 8; + UBits32 alpha : 8; + } ayuv; + struct { + UBits32 l : 8; + UBits32 m : 8; + UBits32 u : 8; + UBits32 alpha : 8; + } auml; +#endif +} tmColor4_t, *ptmColor4_t; + +//----------------------------------------------------------------------------- +// Hardware device power states +// +typedef enum tmPowerState +{ + tmPowerOn, // Device powered on (D0 state) + tmPowerStandby, // Device power standby (D1 state) + tmPowerSuspend, // Device power suspended (D2 state) + tmPowerOff // Device powered off (D3 state) + +} tmPowerState_t, *ptmPowerState_t; + +//----------------------------------------------------------------------------- +// Software Version Structure +// +typedef struct tmSWVersion +{ + UInt32 compatibilityNr; // Interface compatibility number + UInt32 majorVersionNr; // Interface major version number + UInt32 minorVersionNr; // Interface minor version number + +} tmSWVersion_t, *ptmSWVersion_t; + +/*Under the TCS, may have been included by our client. In + order to avoid errors, we take account of this possibility, but in order to + support environments where the TCS is not available, we do not include the + file by name.*/ +#ifndef _TMBOARDDEF_H_ +#define _TMBOARDDEF_H_ + +//----------------------------------------------------------------------------- +// HW Unit Selection +// +typedef Int tmUnitSelect_t, *ptmUnitSelect_t; + +#define tmUnitNone (-1) +#define tmUnit0 0 +#define tmUnit1 1 +#define tmUnit2 2 +#define tmUnit3 3 +#define tmUnit4 4 + +/*+compatibility*/ +#define unitSelect_t tmUnitSelect_t +#define unit0 tmUnit0 +#define unit1 tmUnit1 +#define unit2 tmUnit2 +#define unit3 tmUnit3 +#define unit4 tmUnit4 +#define DEVICE_NAME_LENGTH HAL_DEVICE_NAME_LENGTH +/*-compatibility*/ + +#endif /*ndef _TMBOARDDEF_H_ */ + +//----------------------------------------------------------------------------- +// Instance handle +// +typedef Int tmInstance_t, *ptmInstance_t; + +// Callback function declaration +typedef Void (*ptmCallback_t) (UInt32 events, Void *pData, UInt32 userData); +#define tmCallback_t ptmCallback_t /*compatibility*/ + +// Kernel debugging function declaration +#ifdef TMFL_CFG_INTELCE4100 +#define KERN_INFO void +#define printk(fmt, args...) printf(fmt, ## args) +#endif + +#ifdef __cplusplus +} +#endif + +#endif //ndef TMNXTYPES_H diff --git a/drivers/video/nxp/linux_hdmi_release_note.txt b/drivers/video/nxp/linux_hdmi_release_note.txt new file mode 100755 index 0000000000000..afbce97880f62 --- /dev/null +++ b/drivers/video/nxp/linux_hdmi_release_note.txt @@ -0,0 +1,417 @@ +Release note: + +------------------------------- + HDMI Tx modules for TDA998x + by + NXP Semiconductors BV +------------------------------- + +--------------------------------- + /!\ WARNING /!\ +If you want to use the HDMI driver from the user space (easier for non-Linux-expert, but needs to have an I2C driver available +from the user space), PLEASE DON'T USE THE LINUX DELIVERY. USE THE BASIC DELIVERY INSTEAD, and refer to the install_DL.txt note. +An exemple of application is available in HdmiTx\sde2\comps\tmdlHdmiTx\tst\tmdlHdmiTx_ExampleApplication\src folder. +--------------------------------- + +The release note gives all necessary detail for installation in Linux +kernel and application tunning. Installation is Linux typical and does +not require any HDMI background. A default video and audio setting is +defined in hdmi_tx_init function. It can be changed at will. +There is no porting to do, it is already provided in module. And the +classical HDMI DevLib is embedded in it. But the UserManual is still +usefull for customers who like to optimise the module according to +their needs. If so, feedback is welcome. ;) +Customers who like to drive the module from userland can do it using +IOCTL. IOCTL maps the classical HDMI API. Using the WAIT_FRAME IOCTL, +userland can catch HDMI events like Hot Plug Detect, RxSens or EDID. + +So the two main functions the customer needs to take care are : +- hdmi_tx_init : to setup the default HDMI settings. These settings can be + overwritten using the TDA_SET_INPUT_OUTPUT_CMD IOCTL +- eventCallbackTx : to fetch HDMI events from userland OR add more + automatic behavior in the module itself. For example basic EDID check + after reading EDID from the sink. + +For customers who like to understand how the HDMI stack works, please +read the TRANSMITTER_TDA998X_SW_UM_Devlib.pdf user manuel. You learn that: +1- this module is a 3 levels stack +2- HDMI core driver API in defined in comps/tmdlHdmiTx/inc + +HDCP is delivered in a proprietary module to avoid GPL license constraints. +For customer that uses HDCP, don't forget to get additional stuff from NXP + +For OMAP architecture, a DSS plugin is provided. So to activate +HDMI (switch DSS to HDMI output) just prompt on target: +echo "3" > /sys/power/vdd2_lock +echo "1" > /sys/devices/platform/omapdss/display2/enabled +And desactivate : +echo "0" > /sys/devices/platform/omapdss/display2/enabled + +------------------------------- + ^ ^ +/!\ CAUTION /!\ +--- --- + +This release note and it's FAQ below covers every known questions from customers +up to now. Thank you for reading it carefully. If you modify the driver, we would +appreciate to gain from your update. So any feedback is welcome. + +------------------------------- + +- Contains : + . HdmiTx Linux module + . HdmiCec linux module + . HDCP linux module (on request only) + . test_hdmi/demo_tda test application + . TRANSMITTER_TDA998X_SW_UM_Devlib.pdf for HDMI TX API + . HDMI_CEC_User_Manual.pdf for HDMI CEC API + . this release note + +- Features : + . HDMI transmiter + . Hot Plug Detection + . HDCP (on request only) + . Customer Electronics Control (v1.4) + . 3D video format, including frame packing + +- Target : + . OMAP3430-ZOOMII (http://omappedia.org/wiki/Android_Getting_Started) + +- OS : + . Linux Kernel 2.6.29, Android RLS25.12 + +- Directory : + . driver/video/hdmi + . driver/video/hdcp (only if hdcp is delivered) + +- Compilation tool : + . arm-2007q3-51-arm-none-linux-gnueabi-i686-pc-linux-gnu + +------------------------------- + +- Release : + * V1.3.0: 2011, 4th May by Vincent Vrignaud + . HDMI1565 improved HDCP robustness in show_video function + * V1.2: 2010, 22th Oct by Andre Lepine + . TDA19988 support + * V1.1: 2010, 15th Oct by Andre Lepine + . TDA9983 version (only) has been produced in pure Linux style + * V1.03: 2010, 26th Augut by Andre Lepine + . USER_SET_INPUT_OUPUT + . use suspend mode for event catching when DSS HDMI panel is off (hdmi_disable(1)) + . prevent IOCTL from updating power mode when used by DSS HDMI panel + * V1.02: 2010, 22th Jully by Andre Lepine + . SetHdcp with IOCTL + * V1.01: 2010, 15th Jully by Andre Lepine + . copy_from_user EDID IOCTL + . hdcp_onoff rework + . SimplayHD feature + . kernel i2c_client + . start implementing sysfs_attrs : first is resolution + * V1.0: 2010, 1st Jully by Andre Lepine + . ATC compliancy + . BCaps polling during 5s when CCLK is not devided by 2 + . It HPD+RxSens rebound (several changes before SW polling) + . EDID used for video mode switch (HDMI, DVI) + . blue screen before the HDCP authentification is passed + . TDA reset when removing Linux module + . hdcp_fail_status not used in TDA9981 + * V0.964: 2010, 25th may by Andre Lepine + . Check incoming REQUEST_ACTIVE_SOURCE is a broadcast + * V0.963: 2010, 21th may by Andre Lepine + . External HDCP module validation + * V0.963: 2010, 18th may by Andre Lepine + . External HDCP module validation + * V0.962: 2010, 11th may by Andre Lepine + . Clean up + * V0.961: 2010, 4th may by Andre Lepine + . Put image_view_on under compilation flag because it is not suitable for + "only hdmi with videoplay" usecase + . DEVICE_VENDOR_ID boradcast after logical address retrival + . Allow CEC_OPCODE_VENDOR_COMMAND and CEC_OPCODE_DEVICE_VENDOR_ID (not send FEATURE ABORTED) + * V0.96: 2010, 16th april by Andre Lepine + . Accept HDCP support using the proprietary module nwolc.ko + * V0.95: 2010, 23th march by Andre Lepine + . Add TDA9981 driver + * V0.94: 2010, 19th march by Andre Lepine + . Merge TDA19989, TDA9984 and TDA9983 drivers + * V0.92: 2010, 11th march by Andre Lepine + . Clean-up + . DSS pixclock inversion + * V0.91: 2010, 18th february by Andre Lepine + . porting for TDA9983 + * V0.9: 2010, 2nd february by Andre Lepine + . Change directory structure + . Update NXP DevLib + . CEC & HDP event handeling fix + * V0.8: 2010, 18 january by Andre Lepine + . Pure IRQ (remove IRQ flag for polling with timer) + . Merge with last HdmiTx and HdmiCec version + . Cec initialization and power state + . Check argument of IOCTL and use -EFAULT when inconsistant + * V0.7: 2010, 11 january by Andre Lepine + . Automatic CEC answering for following opcodes : + > GIVE_PHYSICAL_ADDRESS + > GET_CEC_VERSION + > GIVE_OSD_NAME + > GIVE_DEVICE_VENDOR_ID + > REQUEST_ACTIVE_SOURCE + > GIVE_DEVICE_POWER_STATUS + > STANDBY + > SET_STREAM_PATH + > ROUTING_CHANGE + > ABORT_MESSAGE + . Automatic logical address negociation + . HdmiCec gets EDID physical address and HDMI status from HdmiTx + +------------------------------- + +- Installation : + + * On host: + . mkdir $KERNEL_MODULES + . cp nxp-TDA1998X-linux-hdmi-cec-(hdcp)-L###-DL##-BSL##.tar.cvfj $KERNEL_MODULES/. + . cd $KERNEL_MODULES + . tar xvfj nxp-TDA1998X-linux-hdmi-cec-(hdcp)-L###-DL##-BSL##.tar.cvfj + . update LINUX_DIR in hdmi/MakeModules with your kernel directory path + . select your TDA target in Makefile : for example TDA_TX := TDA19988 !!! CAUTION, don't forget this !!! + . select your platform in Makefile : for example TDA_PLATFORM := ZOOMII + . cd hdmi + . make -f MakeModules clean (optional for the first time) + . make -f MakeModules (then you get hdmitx.ko and hdmicecc.ko modules) + . make -f MakeModules uptx (or any download mean that does not use adb) + . make -f MakeModules upcec (or any download mean that does not use adb) (19988/89 only) + . cd hdcp (for 19988/89 and 9984 only) + . update the KEY_SEED value in comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c + . make -f MakeModules (then you get nwolc.ko module) + . make -f MakeModules up (or any download mean that does not use adb) + * Application (optional), better use your own, this one is just a sample + . cd test + . make clean (optional for the first time) + . make + . make upload (or any download mean that does not use adb) + * On target: + . insmod hdmitx.ko verbose=1 (remove verbose to make the module silent) + . insmod hdmicec.ko verbose=1 device=4 (remove verbose to make the module silent) + . insmod nwolc.ko (only for HDCP) + * On TV + . connect TV to target + +- Usage : + + . hdmitx module parameters used with insmod : + > verbose: Make the driver verbose + > major: The major number of the device mapper + . hdmicec module parameters used with insmod : + > verbose: Make the driver verbose + > major: The major number of the device mapper + > device: Device type can be 0:tv, 1:rec 3:tuner 4:mediaplayer, 5:audio + > addr: Physical address (until EDID received) + . modules handles automaticaly HPD, EDID and following CEC messaging : + device connectivity and addressing, routing, standby, OSD name, + vendor name features. + . tda_demo test application show how to take control of the two modules + from userland and catch CEC messages + BUT HDMI MODULES CAN RUN WITHOUT IT + . HDCP feature is only supported if nwolc module is installed, you can + add it or remove it dynamically using insmod nwolc.ko and rmmod nwolk. + +- FAQ : + + . "Can I modify file tda998x.c ?" + YES ! It's only a kind of "application" sample of the core driver below. + Feel free to customize it at will ! + + . "Can I modify files in comps directoty ?" + NO ! Core driver bug shall be discussed with NXP otherwise you may break down + some patches and introduce regressions + + . "this->driver.i2c_client not allocated" : + 1) Declare your I2C bus usage in arch/arm/mach-omap2/board-zoom2.c as follow : + | static struct i2c_board_info __initdata zoom2_i2c_bus3_info[] = { + | {I2C_BOARD_INFO(TX_NAME, TDA998X_I2C_SLAVEADDRESS),}, + | {I2C_BOARD_INFO(CEC_NAME, TDA99XCEC_I2C_SLAVEADDRESS),}, + | }; + 2) Check the TDA target in Makefile : for example TDA_TX := TDA9984 + + . "Video format and plan are strange..." : + Check tda.setio.videoout/in in hdmi_tx_init() function of tda998x.c + + . "The resolution is not the one I want" : + Update or create your own omap_video_timings structure and change + the video resolution of this->tda.setio.video_out.format in hdmi_tx_init() + + . "I want 720p@60Hz" : + 1- Line 860: Uncomment> /* this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_04_1280x720p_60Hz; */ + 2- Line 862: Comment> this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_02_720x480p_60Hz; + 3- Line 1051: Replace> video_720x480at60Hz_panel_timings with video_1280x720at60Hz_panel_timings + + . "RGB colors are swapped, for example I see RBG instead of RGB" : (for TDA9984 and TDA19989 only) + Modify the videoPortMapping_RGB444 video port mapping in comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c. + + . "YUV signals are swapped, for example I see UVY instead of YUV" : (for TDA9984 and TDA19989 only) + Modify the videoPortMapping_YUV444/YUV422 video port mapping in comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c. + + . "I2C or SPDIF audio does not work, signals are swapped" : (for TDA9984 and TDA19989 only) + Modify the enableAudioPortI2S/SPDIF audio port mapping in comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c. + + . "Where can I find all video format definition ?": + in hdmi/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h + + . "Where can I find all audio format definition ?": + in hdmi/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h + + . "Where can I find all HDMI types definition ?": + in hdmi/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h + + . "Where can I find all power management types definition ?": + in hdmi/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Types.h + + . "Where can I find all HDMI Tx API definition ?": + in hdmi/comps/tmdlHdmiTx/inc/tmdlHdmiTx_Functions.h + + . "Where can I find all HDMI CEC types definition ?": + in hdmi/comps/tmdlHdmiCec/inc/tmdlHdmiCec_Types.h + + . "Where can I find all HDMI CEC API definition ?": + in hdmi/comps/tmdlHdmiCec/inc/tmdlHdmiCec_Functions.h + + . "I would like to get debug message": + Install the module with debug messages > insmod hdmitx.ko verbose=1 + + . "I would like to see the EDID of the TV": + Install the module with debug messages > insmod hdmitx.ko verbose=1 + + . "On the TV display some pixel are flickering": + Check the OMAP DSS setup and update the dssdev->panel.config parameters + + . "CEC send Samsung vendor ID": + Yes, otherwise you cannot use Samsung devices... replace is by your own + + . "I don't use OMAP": + This module contains an OMAP Display SubSystem plugin that automatically + drives video output of OMAP (video input of TDA). If you don't have OMAP + remove the ANDROID_DSS (or add your PLATFORM flag in Makefile) and do + the video bus configuration at your convience. Anyhow, any other usefull + plugin is welcome... So please feedback ;) + + . "How to install HDMI module ?": + See installation chapter above. + + . "HDCP is not supported": + Ask NXP to deliver you the proprietary HDCP module + + . "HDCP module does not work": + Ask NXP to provide you your customer seed number... + + . "How can I control the HDMI with my apps ?": + Use open("/dev/hdmitx") to get access to HdmiTx module. + Then use ioctl as described in tda998x_ioctl.h. + + . "How can I control CEC with my apps ?": + Use open("/dev/hdmicec") to get access to HdmiCec module. + Then use ioctl as described in tda998x_ioctl.h. + + . "How can my application get the HDMI event ?": + Create a dedicated incoming event thread in your apps and use ioctl WAIT_EVENT + + . "Is is mandatory to create an incoming event thread in my apps ?": + No if you don't care. + + . "Did I need to create some apps to make HDMI running ?": + No, you can modify hdmi_tx_init according to your needs and install the + modules in your init.rc. Hdmi will run automatically. + + . "HDCP device is not authenticated": + Check your personnal customer ROMCODE and update accordingly your KEY_SEED value + in comps/tmdlHdmiTx/cfg/TDA9989/tmdlHdmiTx_Linux_cfg.c + + . "Where can I get the the KEY_SEED value for HDCP": + Ask direcly NXP technical software support + + . "How can I get PC video format like 600x480" + Watch out the "features on demand" part of Makefile + + . "I don't get any interrupt wired nor IRQ on my board" + Remove the IRQ flag for timer based polling of interrupt + + . "I want to use HDCP" + 1) Add the nwolc.ko module (or ask it to NXP) + 2) Add TDA_HDCP := TMFL_HDCP_SUPPORT flag + 3) set your KEY_SEED number in tmdlHdmiTx_Linux_cfg.c file + + . "HDCP does not work" + Ask you key seed to NXP + + . "got unexpected TMDS activity between EDID reading and SetInputOuput" + use USER_SET_INPUT_OUTPUT flag + + . "I don't want the module to automatically setup TMDS but from userland instead" + use USER_SET_INPUT_OUTPUT flag + + . "I2S audio does not work, N value is not good" + Check the audio frequence in hdmi_tx_init or using IOCTL TDA_SET_AUDIO_INPUT_CMD + For example, N=6144 at 48KHz, but N=6272 at 44.1Khz + + . "I2S audio does not work, CTS value is not good" + Check the audio I2S format in hdmi_tx_init or using IOCTL TDA_SET_AUDIO_INPUT_CMD + CTS is automatically computed by the TDA accordingly to the audio input + so accordingly to the upstream settings (like an OMAP ;) + For example, I2S 16 bits or 32 bits do not produce the same CTS value + + . "How can I change the audio settings ?" + Put your own settings in setio.audio_in structure. For example : + this->tda.setio.audio_in.format = TMDL_HDMITX_AFMT_I2S; + this->tda.setio.audio_in.rate = TMDL_HDMITX_AFS_44K; + this->tda.setio.audio_in.i2sFormat = TMDL_HDMITX_I2SFOR_PHILIPS_L; + this->tda.setio.audio_in.i2sQualifier = TMDL_HDMITX_I2SQ_16BITS; + this->tda.setio.audio_in.dstRate = TMDL_HDMITX_DSTRATE_SINGLE; /* not relevant here */ + this->tda.setio.audio_in.channelAllocation = 0; /* audio channel allocation L+R (Ref to CEA-861D p85) */ + + . "When shall I set audio ?" + Default (at module startup) is in hdmi_tx_init + At will using IOCTL TDA_SET_AUDIO_INPUT_CMD + +- Restriction : + + . Remove IRQ flag in Makefile for timer based polling + . Add ZOOMII_PATCH to reverse clock edge in ZOOMII + . add TWL4030_HACK to get keypad handle and inject CEC::USER_CONTROL events + . omap_dss_driver might not be supported by kernel, then hdmi_enable + and hdmi_disable should be triggered by any other kernel means or + replaced by direct call from application using: + --> ioctl(my_fd,TDA_IOCTL_SET_POWER,[tmPowerOn|tmPowerStandby]); + . HDCP can be switch off dynamically with TDA_IOCTL_SET_HDCP but not hw engine, + stop it by removing nwolc.ko module + +- License : + + . hdmitx and hdmicec modules are free software; you can redistribute + it and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, using version 2 of the License. + These modules are distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + . nwolc module source code and any compilation or derivative thereof is + the proprietary information of NXP N.V. and is confidential in nature. + Under no circumstances is this software to be exposed to or placed under + an Open Source License of any type without the expressed written permission + of NXP N.V. + +- DV : + + . How to create a DV : + -> update tda998xversion.h and set PATCH_LEVEL to 0 + -> update linux_hdmi_release_note.txt + $>cd driver/video/hdmi + $>make -f MakeModules clean + $>cd .. + $>tar cvfj $DV_FOLDER/linux-hdmi-nxp-modules.vXYZ.tar.cvfj hdmi + +----------------------------------- + +- Feedback : vincent.vrignaud@nxp.com - + +----------------------------------- + diff --git a/drivers/video/nxp/tda998x.c b/drivers/video/nxp/tda998x.c new file mode 100755 index 0000000000000..b01b2b0c31268 --- /dev/null +++ b/drivers/video/nxp/tda998x.c @@ -0,0 +1,2307 @@ +/*****************************************************************************/ +/* Copyright (c) 2009 NXP Semiconductors BV */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, using version 2 of the License. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */ +/* USA. */ +/* */ +/*****************************************************************************/ + +#define _tx_c_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// #include + +/* HDMI DevLib */ +#include "tmNxCompId.h" +#include "tmdlHdmiTx_Types.h" +#include "tmdlHdmiTx_Functions.h" + +/* local */ +#include "tda998x_version.h" +#include "tda998x.h" +#include "tda998x_ioctl.h" + +#ifdef I2C_DBG +#include "tmbslHdmiTx_types.h" +#include "tmbslTDA9989_local.h" +#endif + +#ifdef ANDROID_DSS +/* DSS hack */ +#endif + +/* + * + * DEFINITION + * ---------- + * LEVEL 0 + * + */ + +#define FRAME_PACKING 200 +#define NO_FP(x) ((x) % FRAME_PACKING) +#define IS_FP(x) ((x) > FRAME_PACKING) +#define WITH_FP(x) ((x) + FRAME_PACKING * (this->tda.setio.video_in.structure3D == TMDL_HDMITX_3D_FRAME_PACKING)) +/* + * Global + */ + +tda_instance our_instance; +static struct cdev our_cdev, *this_cdev=&our_cdev; +#ifdef ANDROID_DSS +static struct omap_video_timings video_640x480at60Hz_panel_timings = { + .x_res = 640, + .y_res = 480, + .pixel_clock = 25175, + .hfp = 16, + .hsw = 96, + .hbp = 48, + .vfp = 10, + .vsw = 2, + .vbp = 33, +}; +static struct omap_video_timings video_640x480at72Hz_panel_timings = { + .x_res = 640, + .y_res = 480, + .pixel_clock = 31500, + .hfp = 24, + .hsw = 40, + .hbp = 128, + .vfp = 9, + .vsw = 3, + .vbp = 28, +}; +static struct omap_video_timings video_720x480at60Hz_panel_timings = { + .x_res = 720, + .y_res = 480, + .pixel_clock = 27027, + .hfp = 16, + .hbp = 60, + .hsw = 62, + .vfp = 9, + .vbp = 30, + .vsw = 6, +}; +static struct omap_video_timings video_1280x720at50Hz_panel_timings = { + .x_res = 1280, + .y_res = 720, + .pixel_clock = 74250, +#ifdef ZOOMII_PATCH + .hfp = 400, + .hbp = 260, +#else + .hfp = 440, + .hbp = 220, +#endif + .hsw = 40, + .vfp = 5, + .vbp = 20, + .vsw = 5, +}; +static struct omap_video_timings video_1280x720at60Hz_panel_timings = { + .x_res = 1280, + .y_res = 720, + .pixel_clock = 74250, +#ifdef ZOOMII_PATCH + .hfp = 70, + .hbp = 260, +#else + .hfp = 110, + .hbp = 220, +#endif + .hsw = 40, + .vfp = 5, + .vbp = 20, + .vsw = 5, +}; +static struct omap_video_timings video_1920x1080at50Hz_panel_timings = { + .x_res = 1920, + .y_res = 1080, + .pixel_clock = 148500, /* 2640 x 1125 x 50 /2 */ +#ifdef ZOOMII_PATCH + .hfp = 488, + .hbp = 188, +#else + .hfp = 528, + .hbp = 148, +#endif + .hsw = 44, + .vfp = 4, + .vbp = 36, + .vsw = 5, +}; +static struct omap_video_timings video_800x480at60Hz_panel_timings = { + /* .x_res = 800 /\* 1280 *\/, */ + /* .y_res = 480 /\* 720 *\/, */ + /* .pixel_clock = 21800 /\* 21800 23800 25700 *\/, */ + .x_res = 800, + .y_res = 480, + .pixel_clock = 21800, + .hfp = 6, + .hsw = 1, + .hbp = 4, + .vfp = 3, + .vsw = 1, + .vbp = 4, +}; + +#endif + +/* #define HDCP_TEST 1 */ +#ifdef HDCP_TEST +/* TEST */ +int test = 0; +#endif + +/* + * Module params + */ + +static int param_verbose=0,param_major=0,param_minor=0; +module_param_named(verbose,param_verbose,int,S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(verbose, "Make the driver verbose"); +module_param_named(major, param_major, int, S_IRUGO); +MODULE_PARM_DESC(major, "The major number of the device mapper"); + +/* + * + * TOOLBOX + * ------- + * LEVEL 1 + * + * - i2c read/write + * - chip Id check + * - i2c client info + * + */ + +/* + * Get main and unique I2C Client driver handle + */ +struct i2c_client *GetThisI2cClient(void) +{ + tda_instance *this=&our_instance; + return this->driver.i2c_client; +} + +/* + * error handling + */ +char *hdmi_tx_err_string(int err) +{ + switch (err & 0x0FFF) + { + case TM_ERR_COMPATIBILITY: {return "SW Interface compatibility";break;} + case TM_ERR_MAJOR_VERSION: {return "SW Major Version error";break;} + case TM_ERR_COMP_VERSION: {return "SW component version error";break;} + case TM_ERR_BAD_UNIT_NUMBER: {return "Invalid device unit number";break;} + case TM_ERR_BAD_INSTANCE: {return "Bad input instance value ";break;} + case TM_ERR_BAD_HANDLE: {return "Bad input handle";break;} + case TM_ERR_BAD_PARAMETER: {return "Invalid input parameter";break;} + case TM_ERR_NO_RESOURCES: {return "Resource is not available ";break;} + case TM_ERR_RESOURCE_OWNED: {return "Resource is already in use";break;} + case TM_ERR_RESOURCE_NOT_OWNED: {return "Caller does not own resource";break;} + case TM_ERR_INCONSISTENT_PARAMS: {return "Inconsistent input params";break;} + case TM_ERR_NOT_INITIALIZED: {return "Component is not initialised";break;} + case TM_ERR_NOT_SUPPORTED: {return "Function is not supported";break;} + case TM_ERR_INIT_FAILED: {return "Initialization failed";break;} + case TM_ERR_BUSY: {return "Component is busy";break;} + case TMDL_ERR_DLHDMITX_I2C_READ: {return "Read error";break;} + case TMDL_ERR_DLHDMITX_I2C_WRITE: {return "Write error";break;} + case TM_ERR_FULL: {return "Queue is full";break;} + case TM_ERR_NOT_STARTED: {return "Function is not started";break;} + case TM_ERR_ALREADY_STARTED: {return "Function is already starte";break;} + case TM_ERR_ASSERTION: {return "Assertion failure";break;} + case TM_ERR_INVALID_STATE: {return "Invalid state for function";break;} + case TM_ERR_OPERATION_NOT_PERMITTED: {return "Corresponds to posix EPERM";break;} + case TMDL_ERR_DLHDMITX_RESOLUTION_UNKNOWN: {return "Bad format";break;} + case TM_OK: {return "OK";break;} + default : {printk(KERN_INFO "(err:%x) ",err);return "unknown";break;} + } +} + +static char *tda_spy_event(int event) +{ + switch (event) + { + case TMDL_HDMITX_HDCP_ACTIVE: {return "HDCP active";break;} + case TMDL_HDMITX_HDCP_INACTIVE: {return "HDCP inactive";break;} + case TMDL_HDMITX_HPD_ACTIVE: {return "HPD active";break;} + case TMDL_HDMITX_HPD_INACTIVE: {return "HPD inactive";break;} + case TMDL_HDMITX_RX_KEYS_RECEIVED: {return "Rx keys received";break;} + case TMDL_HDMITX_RX_DEVICE_ACTIVE: {return "Rx device active";break;} + case TMDL_HDMITX_RX_DEVICE_INACTIVE: {return "Rx device inactive";break;} + case TMDL_HDMITX_EDID_RECEIVED: {return "EDID received";break;} + case TMDL_HDMITX_VS_RPT_RECEIVED: {return "VS interrupt has been received";break;} + /* case TMDL_HDMITX_B_STATUS: {return "TX received BStatus";break;} */ +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + case TMDL_HDMITX_DEBUG_EVENT_1: {return "DEBUG_EVENT_1";break;} +#endif + default : {return "Unkonwn event";break;} + } +} +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) +static char *tda_spy_hsdc_fail_status(int fail) +{ + switch (fail) + { + case TMDL_HDMITX_HDCP_OK: {return "ok";break;} + case TMDL_HDMITX_HDCP_BKSV_RCV_FAIL: {return "Source does not receive Sink BKsv ";break;} + case TMDL_HDMITX_HDCP_BKSV_CHECK_FAIL: {return "BKsv does not contain 20 zeros and 20 ones";break;} + case TMDL_HDMITX_HDCP_BCAPS_RCV_FAIL: {return "Source does not receive Sink Bcaps";break;} + case TMDL_HDMITX_HDCP_AKSV_SEND_FAIL: {return "Source does not send AKsv";break;} + case TMDL_HDMITX_HDCP_R0_RCV_FAIL: {return "Source does not receive R'0";break;} + case TMDL_HDMITX_HDCP_R0_CHECK_FAIL: {return "R0 = R'0 check fail";break;} + case TMDL_HDMITX_HDCP_BKSV_NOT_SECURE: {return "bksv not secure";break;} + case TMDL_HDMITX_HDCP_RI_RCV_FAIL: {return "Source does not receive R'i";break;} + case TMDL_HDMITX_HDCP_RPT_RI_RCV_FAIL: {return "Source does not receive R'i repeater mode";break;} + case TMDL_HDMITX_HDCP_RI_CHECK_FAIL: {return "RI = R'I check fail";break;} + case TMDL_HDMITX_HDCP_RPT_RI_CHECK_FAIL: {return "RI = R'I check fail repeater mode";break;} + case TMDL_HDMITX_HDCP_RPT_BCAPS_RCV_FAIL: {return "Source does not receive Sink Bcaps repeater mode";break;} + case TMDL_HDMITX_HDCP_RPT_BCAPS_READY_TIMEOUT: {return "bcaps ready timeout";break;} + case TMDL_HDMITX_HDCP_RPT_V_RCV_FAIL: {return "Source does not receive V";break;} + case TMDL_HDMITX_HDCP_RPT_BSTATUS_RCV_FAIL: {return "Source does not receive BSTATUS repeater mode";break;} + case TMDL_HDMITX_HDCP_RPT_KSVLIST_RCV_FAIL: {return "Source does not receive Ksv list in repeater mode";break;} + case TMDL_HDMITX_HDCP_RPT_KSVLIST_NOT_SECURE: {return "ksvlist not secure";break;} + default: {return "";break;} + } +} + +static char *tda_spy_hdcp_status(int status) +{ + switch (status) + { + case TMDL_HDMITX_HDCP_CHECK_NOT_STARTED: {return "Check not started";break;} + case TMDL_HDMITX_HDCP_CHECK_IN_PROGRESS: {return "No failures, more to do";break;} + case TMDL_HDMITX_HDCP_CHECK_PASS: {return "Final check has passed";break;} + case TMDL_HDMITX_HDCP_CHECK_FAIL_FIRST: {return "First check failure code\nDriver not AUTHENTICATED";break;} + case TMDL_HDMITX_HDCP_CHECK_FAIL_DEVICE_T0: {return "A T0 interrupt occurred";break;} + case TMDL_HDMITX_HDCP_CHECK_FAIL_DEVICE_RI: {return "Device RI changed";break;} + case TMDL_HDMITX_HDCP_CHECK_FAIL_DEVICE_FSM: {return "Device FSM not 10h";break;} + default : {return "Unknown hdcp status";break;} + } + +} +#endif + +static char *tda_spy_sink(int sink) +{ + switch (sink) + { + case TMDL_HDMITX_SINK_DVI: {return "DVI";break;} + case TMDL_HDMITX_SINK_HDMI: {return "HDMI";break;} + case TMDL_HDMITX_SINK_EDID: {return "As currently defined in EDID";break;} + default : {return "Unkonwn sink";break;} + } +} + +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) +static char *tda_spy_aspect_ratio(int ar) +{ + switch (ar) + { + case TMDL_HDMITX_P_ASPECT_RATIO_UNDEFINED: {return "Undefined picture aspect rati";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_6_5: {return "6:5 picture aspect ratio (PAR";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_5_4: {return "5:4 PA";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_4_3: {return "4:3 PA";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_16_10: {return "16:10 PA";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_5_3: {return "5:3 PA";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_16_9: {return "16:9 PA";break;} + case TMDL_HDMITX_P_ASPECT_RATIO_9_5: {return "9:5 PA";break;} + default : {return "Unknown aspect ratio";break;} + } +} + +#if 0 /* no more used */ +static char *tda_spy_edid_status(int status) +{ + switch (status) + { + case TMDL_HDMITX_EDID_READ: {return "All blocks read";break;} + case TMDL_HDMITX_EDID_READ_INCOMPLETE: {return "All blocks read OK but buffer too small to return all of the";break;} + case TMDL_HDMITX_EDID_ERROR_CHK_BLOCK_0: {return "Block 0 checksum erro";break;} + case TMDL_HDMITX_EDID_ERROR_CHK: {return "Block 0 OK, checksum error in one or more other block";break;} + case TMDL_HDMITX_EDID_NOT_READ: {return "EDID not read";break;} + case TMDL_HDMITX_EDID_STATUS_INVALID: {return "Invalid ";break;} + default : {return "Unknown edid status";break;} + } +} +#endif + +static char *tda_spy_vfmt(int fmt) +{ + switch (fmt) + { + case TMDL_HDMITX_VFMT_NULL: {return "NOT a valid format...";break;} + case TMDL_HDMITX_VFMT_01_640x480p_60Hz: {return "vic 01: 640x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_02_720x480p_60Hz: {return "vic 02: 720x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_03_720x480p_60Hz: {return "vic 03: 720x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_04_1280x720p_60Hz: {return "vic 04: 1280x720p 60Hz";break;} + case TMDL_HDMITX_VFMT_05_1920x1080i_60Hz: {return "vic 05: 1920x1080i 60Hz";break;} + case TMDL_HDMITX_VFMT_06_720x480i_60Hz: {return "vic 06: 720x480i 60Hz";break;} + case TMDL_HDMITX_VFMT_07_720x480i_60Hz: {return "vic 07: 720x480i 60Hz";break;} + case TMDL_HDMITX_VFMT_08_720x240p_60Hz: {return "vic 08: 720x240p 60Hz";break;} + case TMDL_HDMITX_VFMT_09_720x240p_60Hz: {return "vic 09: 720x240p 60Hz";break;} + case TMDL_HDMITX_VFMT_10_720x480i_60Hz: {return "vic 10: 720x480i 60Hz";break;} + case TMDL_HDMITX_VFMT_11_720x480i_60Hz: {return "vic 11: 720x480i 60Hz";break;} + case TMDL_HDMITX_VFMT_12_720x240p_60Hz: {return "vic 12: 720x240p 60Hz";break;} + case TMDL_HDMITX_VFMT_13_720x240p_60Hz: {return "vic 13: 720x240p 60Hz";break;} + case TMDL_HDMITX_VFMT_14_1440x480p_60Hz: {return "vic 14: 1440x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_15_1440x480p_60Hz: {return "vic 15: 1440x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_16_1920x1080p_60Hz: {return "vic 16: 1920x1080p 60Hz";break;} + case TMDL_HDMITX_VFMT_17_720x576p_50Hz: {return "vic 17: 720x576p 50Hz";break;} + case TMDL_HDMITX_VFMT_18_720x576p_50Hz: {return "vic 18: 720x576p 50Hz";break;} + case TMDL_HDMITX_VFMT_19_1280x720p_50Hz: {return "vic 19: 1280x720p 50Hz";break;} + case TMDL_HDMITX_VFMT_20_1920x1080i_50Hz: {return "vic 20: 1920x1080i 50Hz";break;} + case TMDL_HDMITX_VFMT_21_720x576i_50Hz: {return "vic 21: 720x576i 50Hz";break;} + case TMDL_HDMITX_VFMT_22_720x576i_50Hz: {return "vic 22: 720x576i 50Hz";break;} + case TMDL_HDMITX_VFMT_23_720x288p_50Hz: {return "vic 23: 720x288p 50Hz";break;} + case TMDL_HDMITX_VFMT_24_720x288p_50Hz: {return "vic 24: 720x288p 50Hz";break;} + case TMDL_HDMITX_VFMT_25_720x576i_50Hz: {return "vic 25: 720x576i 50Hz";break;} + case TMDL_HDMITX_VFMT_26_720x576i_50Hz: {return "vic 26: 720x576i 50Hz";break;} + case TMDL_HDMITX_VFMT_27_720x288p_50Hz: {return "vic 27: 720x288p 50Hz";break;} + case TMDL_HDMITX_VFMT_28_720x288p_50Hz: {return "vic 28: 720x288p 50Hz";break;} + case TMDL_HDMITX_VFMT_29_1440x576p_50Hz: {return "vic 29: 1440x576p 50Hz";break;} + case TMDL_HDMITX_VFMT_30_1440x576p_50Hz: {return "vic 30: 1440x576p 50Hz";break;} + case TMDL_HDMITX_VFMT_31_1920x1080p_50Hz: {return "vic 31: 1920x1080p 50Hz";break;} + case TMDL_HDMITX_VFMT_32_1920x1080p_24Hz: {return "vic 32: 1920x1080p 24Hz";break;} + case TMDL_HDMITX_VFMT_33_1920x1080p_25Hz: {return "vic 33: 1920x1080p 25Hz";break;} + case TMDL_HDMITX_VFMT_34_1920x1080p_30Hz: {return "vic 34: 1920x1080p 30Hz";break;} + case TMDL_HDMITX_VFMT_35_2880x480p_60Hz: {return "vic 3: 2880x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_36_2880x480p_60Hz: {return "vic 3: 2880x480p 60Hz";break;} + case TMDL_HDMITX_VFMT_37_2880x576p_50Hz: {return "vic 3: 2880x576p 50Hz";break;} + case TMDL_HDMITX_VFMT_38_2880x576p_50Hz: {return "vic 3: 2880x576p 50Hz";break;} + case TMDL_HDMITX_VFMT_60_1280x720p_24Hz: {return "vic 60: 1280x720p 24Hz";break;} + case TMDL_HDMITX_VFMT_61_1280x720p_25Hz: {return "vic 61: 1280x720p 25Hz";break;} + case TMDL_HDMITX_VFMT_62_1280x720p_30Hz: {return "vic 62: 1280x720p 30Hz";break;} + case TMDL_HDMITX_VFMT_PC_800x600p_60Hz: {return "PC 129";break;} + case TMDL_HDMITX_VFMT_PC_1152x960p_60Hz: {return "PC 130";break;} + case TMDL_HDMITX_VFMT_PC_1024x768p_60Hz: {return "PC 131";break;} + case TMDL_HDMITX_VFMT_PC_1280x768p_60Hz: {return "PC 132";break;} + case TMDL_HDMITX_VFMT_PC_1280x1024p_60Hz: {return "PC 133";break;} + case TMDL_HDMITX_VFMT_PC_1360x768p_60Hz: {return "PC 134";break;} + case TMDL_HDMITX_VFMT_PC_1400x1050p_60Hz: {return "PC 135";break;} + case TMDL_HDMITX_VFMT_PC_1600x1200p_60Hz: {return "PC 136";break;} + case TMDL_HDMITX_VFMT_PC_1024x768p_70Hz: {return "PC 137";break;} + case TMDL_HDMITX_VFMT_PC_640x480p_72Hz: {return "PC 138";break;} + case TMDL_HDMITX_VFMT_PC_800x600p_72Hz: {return "PC 139";break;} + case TMDL_HDMITX_VFMT_PC_640x480p_75Hz: {return "PC 140";break;} + case TMDL_HDMITX_VFMT_PC_1024x768p_75Hz: {return "PC 141";break;} + case TMDL_HDMITX_VFMT_PC_800x600p_75Hz: {return "PC 142";break;} + case TMDL_HDMITX_VFMT_PC_1024x864p_75Hz: {return "PC 143";break;} + case TMDL_HDMITX_VFMT_PC_1280x1024p_75Hz: {return "PC 144";break;} + case TMDL_HDMITX_VFMT_PC_640x350p_85Hz: {return "PC 145";break;} + case TMDL_HDMITX_VFMT_PC_640x400p_85Hz: {return "PC 146";break;} + case TMDL_HDMITX_VFMT_PC_720x400p_85Hz: {return "PC 147";break;} + case TMDL_HDMITX_VFMT_PC_640x480p_85Hz: {return "PC 148";break;} + case TMDL_HDMITX_VFMT_PC_800x600p_85Hz: {return "PC 149";break;} + case TMDL_HDMITX_VFMT_PC_1024x768p_85Hz: {return "PC 150";break;} + case TMDL_HDMITX_VFMT_PC_1152x864p_85Hz: {return "PC 151";break;} + case TMDL_HDMITX_VFMT_PC_1280x960p_85Hz: {return "PC 152";break;} + case TMDL_HDMITX_VFMT_PC_1280x1024p_85Hz: {return "PC 153";break;} + case TMDL_HDMITX_VFMT_PC_1024x768i_87Hz: {return "PC 154";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_02_720x480p_60Hz: {return "vic 02: 720x480p 60Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_17_720x576p_50Hz: {return "vic 17: 720x576p 50Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_60_1280x720p_24Hz: {return "vic 60: 1280x720p 24Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_61_1280x720p_25Hz: {return "vic 61: 1280x720p 25Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_62_1280x720p_30Hz: {return "vic 62: 1280x720p 30Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_19_1280x720p_50Hz: {return "vic 19: 1280x720p 50Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_04_1280x720p_60Hz: {return "vic 04: 1280x720p 60Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_32_1920x1080p_24Hz: {return "vic 32: 1920x1080p 24Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_33_1920x1080p_25Hz: {return "vic 33: 1920x1080p 25Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_34_1920x1080p_30Hz: {return "vic 34: 1920x1080p 30Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_31_1920x1080p_50Hz: {return "vic 31: 1920x1080p 50Hz frame packing";break;} + case FRAME_PACKING + TMDL_HDMITX_VFMT_16_1920x1080p_60Hz: {return "vic 16: 1920x1080p 60Hz frame packing";break;} + default : {return "unknown video format";break;} + } +} +#endif + +static char *tda_spy_audio_fmt(int fmt) +{ + switch (fmt) + { + case TMDL_HDMITX_AFMT_SPDIF: {return "SPDIF";break;} + case TMDL_HDMITX_AFMT_I2S: {return "I2S";break;} + case TMDL_HDMITX_AFMT_OBA: {return "OBA";break;} + case TMDL_HDMITX_AFMT_DST: {return "DST";break;} + case TMDL_HDMITX_AFMT_HBR: {return "HBR";break;} + default : {return "Unknown audio format";break;} + } +} + +static char *tda_spy_audio_freq(int freq) +{ + switch (freq) + { + case TMDL_HDMITX_AFS_32K: {return "32k";break;} + case TMDL_HDMITX_AFS_44K: {return "44k";break;} + case TMDL_HDMITX_AFS_48K: {return "48k";break;} + case TMDL_HDMITX_AFS_88K: {return "88k";break;} + case TMDL_HDMITX_AFS_96K: {return "96k";break;} + case TMDL_HDMITX_AFS_176K: {return "176k";break;} + case TMDL_HDMITX_AFS_192K: {return "192k";break;} + default : {return "Unknown audio freq";break;} + } +} + +static char *tda_spy_audio_i2c(int bits) +{ + switch (bits) + { + case TMDL_HDMITX_I2SQ_16BITS: {return "16 bits";break;} + case TMDL_HDMITX_I2SQ_32BITS: {return "32 bits";break;} + default : {return "Unknown audio i2c sampling";break;} + } +} + +static char *tda_spy_audio_i2c4(int align) +{ + switch (align) + { + case TMDL_HDMITX_I2SFOR_PHILIPS_L: {return "Philips Left";break;} + case TMDL_HDMITX_I2SFOR_OTH_L: {return "other left";break;} + case TMDL_HDMITX_I2SFOR_OTH_R: {return "other right";break;} + default : {return "Unknown audio I2C alignement";break;} + } +} + +static void tda_spy_audio(tmdlHdmiTxAudioInConfig_t *audio) +{ + printk(KERN_INFO "hdmitx audio input\n format:%d(%s) rate:%d(%s) i2c_format:%d(%s) i2c_qualif:%d(%s) dst_rate:%d channel:%d\n", \ + audio->format, \ + tda_spy_audio_fmt(audio->format), \ + audio->rate, \ + tda_spy_audio_freq(audio->rate), \ + audio->i2sFormat, \ + tda_spy_audio_i2c4(audio->i2sFormat), \ + audio->i2sQualifier, \ + tda_spy_audio_i2c(audio->i2sQualifier), \ + audio->dstRate, \ + audio->channelAllocation); + } + + +static char *tda_ioctl(int io) +{ + switch (io) + { + case TDA_VERBOSE_ON_CMD: {return "TDA_VERBOSE_ON_CMD";break;} + case TDA_VERBOSE_OFF_CMD: {return "TDA_VERBOSE_OFF_CMD";break;} + case TDA_BYEBYE_CMD: {return "TDA_BYEBYE_CMD";break;} + case TDA_GET_SW_VERSION_CMD: {return "TDA_GET_SW_VERSION_CMD";break;} + case TDA_SET_POWER_CMD: {return "TDA_SET_POWER_CMD";break;} + case TDA_GET_POWER_CMD: {return "TDA_GET_POWER_CMD";break;} + case TDA_SETUP_CMD: {return "TDA_SETUP_CMD";break;} + case TDA_GET_SETUP_CMD: {return "TDA_GET_SETUP_CMD";break;} + case TDA_WAIT_EVENT_CMD: {return "TDA_WAIT_EVENT_CMD";break;} + case TDA_ENABLE_EVENT_CMD: {return "TDA_ENABLE_EVENT_CMD";break;} + case TDA_DISABLE_EVENT_CMD: {return "TDA_DISABLE_EVENT_CMD";break;} + case TDA_GET_VIDEO_SPEC_CMD: {return "TDA_GET_VIDEO_SPEC_CMD";break;} + case TDA_SET_INPUT_OUTPUT_CMD: {return "TDA_SET_INPUT_OUTPUT_CMD";break;} + case TDA_SET_AUDIO_INPUT_CMD: {return "TDA_SET_AUDIO_INPUT_CMD";break;} + case TDA_SET_VIDEO_INFOFRAME_CMD: {return "TDA_SET_VIDEO_INFOFRAME_CMD";break;} + case TDA_SET_AUDIO_INFOFRAME_CMD: {return "TDA_SET_AUDIO_INFOFRAME_CMD";break;} + case TDA_SET_ACP_CMD: {return "TDA_SET_ACP_CMD";break;} + case TDA_SET_GCP_CMD: {return "TDA_SET_GCP_CMD";break;} + case TDA_SET_ISRC1_CMD: {return "TDA_SET_ISRC1_CMD";break;} + case TDA_SET_ISRC2_CMD: {return "TDA_SET_ISRC2_CMD";break;} + case TDA_SET_MPS_INFOFRAME_CMD: {return "TDA_SET_MPS_INFOFRAME_CMD";break;} + case TDA_SET_SPD_INFOFRAME_CMD: {return "TDA_SET_SPD_INFOFRAME_CMD";break;} + case TDA_SET_VS_INFOFRAME_CMD: {return "TDA_SET_VS_INFOFRAME_CMD";break;} + case TDA_SET_AUDIO_MUTE_CMD: {return "TDA_SET_AUDIO_MUTE_CMD";break;} + case TDA_RESET_AUDIO_CTS_CMD: {return "TDA_RESET_AUDIO_CTS_CMD";break;} + case TDA_GET_EDID_STATUS_CMD: {return "TDA_GET_EDID_STATUS_CMD";break;} + case TDA_GET_EDID_AUDIO_CAPS_CMD: {return "TDA_GET_EDID_AUDIO_CAPS_CMD";break;} + case TDA_GET_EDID_VIDEO_CAPS_CMD: {return "TDA_GET_EDID_VIDEO_CAPS_CMD";break;} + case TDA_GET_EDID_VIDEO_PREF_CMD: {return "TDA_GET_EDID_VIDEO_PREF_CMD";break;} + case TDA_GET_EDID_SINK_TYPE_CMD: {return "TDA_GET_EDID_SINK_TYPE_CMD";break;} + case TDA_GET_EDID_SOURCE_ADDRESS_CMD: {return "TDA_GET_EDID_SOURCE_ADDRESS_CMD";break;} + case TDA_SET_GAMMUT_CMD: {return "TDA_SET_GAMMUT_CMD";break;} + case TDA_GET_EDID_DTD_CMD: {return "TDA_GET_EDID_DTD_CMD";break;} + case TDA_GET_EDID_MD_CMD: {return "TDA_GET_EDID_MD_CMD";break;} + case TDA_GET_EDID_TV_ASPECT_RATIO_CMD: {return "TDA_GET_EDID_TV_ASPECT_RATIO_CMD";break;} + case TDA_GET_EDID_LATENCY_CMD: {return "TDA_GET_EDID_LATENCY_CMD";break;} + case TDA_GET_HPD_STATUS_CMD: {return "TDA_GET_HPD_STATUS_CMD";break;} + default : {return "unknown";break;} + } + + +} + +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) +/* + * + */ +static int tda_spy(int verbose) +{ + tda_instance *this=&our_instance; + int i,err=0; + + if (!verbose) { + return err; + } + + printk(KERN_INFO "\n\n"); + this->tda.edid_video_caps.max=EXAMPLE_MAX_SVD; + TRY(tmdlHdmiTxGetEdidVideoCaps(this->tda.instance, \ + this->tda.edid_video_caps.desc, \ + this->tda.edid_video_caps.max, \ + &this->tda.edid_video_caps.written, \ + &this->tda.edid_video_caps.flags)); + printk(KERN_INFO "written:%d\n",this->tda.edid_video_caps.written); + printk(KERN_INFO "flags:0X%x\n",this->tda.edid_video_caps.flags); + if (this->tda.edid_video_caps.written > this->tda.edid_video_caps.max) { + printk(KERN_ERR "get %d video caps but was waiting for %d\n", \ + this->tda.edid_video_caps.written, \ + this->tda.edid_video_caps.max); + this->tda.edid_video_caps.written = this->tda.edid_video_caps.max; + } + for(i=0; itda.edid_video_caps.written;i++) { + printk(KERN_INFO "videoFormat: %s\n",tda_spy_vfmt(this->tda.edid_video_caps.desc[i].videoFormat)); + printk(KERN_INFO "nativeVideoFormat:%s\n",(this->tda.edid_video_caps.desc[i].nativeVideoFormat?"yes":"no")); + } + + printk(KERN_INFO "\n\n"); + TRY(tmdlHdmiTxGetEdidVideoPreferred(this->tda.instance, \ + &this->tda.edid_video_timings)); + printk(KERN_INFO "Pixel Clock/10 000:%d\n",this->tda.edid_video_timings.pixelClock); + printk(KERN_INFO "Horizontal Active Pixels:%d\n",this->tda.edid_video_timings.hActivePixels); + printk(KERN_INFO "Horizontal Blanking Pixels:%d\n",this->tda.edid_video_timings.hBlankPixels); + printk(KERN_INFO "Vertical Active Lines:%d\n",this->tda.edid_video_timings.vActiveLines); + printk(KERN_INFO "Vertical Blanking Lines:%d\n",this->tda.edid_video_timings.vBlankLines); + printk(KERN_INFO "Horizontal Sync Offset:%d\n",this->tda.edid_video_timings.hSyncOffset); + printk(KERN_INFO "Horiz. Sync Pulse Width:%d\n",this->tda.edid_video_timings.hSyncWidth); + printk(KERN_INFO "Vertical Sync Offset:%d\n",this->tda.edid_video_timings.vSyncOffset); + printk(KERN_INFO "Vertical Sync Pulse Width:%d\n",this->tda.edid_video_timings.vSyncWidth); + printk(KERN_INFO "Horizontal Image Size:%d\n",this->tda.edid_video_timings.hImageSize); + printk(KERN_INFO "Vertical Image Size:%d\n",this->tda.edid_video_timings.vImageSize); + printk(KERN_INFO "Horizontal Border:%d\n",this->tda.edid_video_timings.hBorderPixels); + printk(KERN_INFO "Vertical Border:%d\n",this->tda.edid_video_timings.vBorderPixels); + printk(KERN_INFO "Interlace/sync info:%x\n",this->tda.edid_video_timings.flags); + + printk(KERN_INFO "\n\n"); + TRY(tmdlHdmiTxGetEdidSinkType(this->tda.instance, \ + &this->tda.setio.sink)); + printk(KERN_INFO "%s\n",tda_spy_sink(this->tda.setio.sink)); + printk(KERN_INFO "\n\n"); + TRY(tmdlHdmiTxGetEdidSourceAddress(this->tda.instance, \ + &this->tda.src_address)); + printk(KERN_INFO "%x\n",this->tda.src_address); + printk(KERN_INFO "\n\n"); + this->tda.edid_dtd.max=EXAMPLE_MAX_SVD; + TRY(tmdlHdmiTxGetEdidDetailledTimingDescriptors(this->tda.instance, \ + this->tda.edid_dtd.desc, \ + this->tda.edid_dtd.max, \ + &this->tda.edid_dtd.written)); + printk(KERN_INFO "Interlace/sync info:%x\n",this->tda.edid_dtd.desc[i].flags); + printk(KERN_INFO "written:%d\n",this->tda.edid_dtd.written); + if (this->tda.edid_dtd.written > this->tda.edid_dtd.max) { + printk(KERN_ERR "get %d video caps but was waiting for %d\n", \ + this->tda.edid_dtd.written, \ + this->tda.edid_dtd.max); + this->tda.edid_dtd.written = this->tda.edid_dtd.max; + } + for(i=0; itda.edid_dtd.written;i++) { + printk(KERN_INFO "Pixel Clock/10 000:%d\n",this->tda.edid_dtd.desc[i].pixelClock); + printk(KERN_INFO "Horizontal Active Pixels:%d\n",this->tda.edid_dtd.desc[i].hActivePixels); + printk(KERN_INFO "Horizontal Blanking Pixels:%d\n",this->tda.edid_dtd.desc[i].hBlankPixels); + printk(KERN_INFO "Vertical Active Lines:%d\n",this->tda.edid_dtd.desc[i].vActiveLines); + printk(KERN_INFO "Vertical Blanking Lines:%d\n",this->tda.edid_dtd.desc[i].vBlankLines); + printk(KERN_INFO "Horizontal Sync Offset:%d\n",this->tda.edid_dtd.desc[i].hSyncOffset); + printk(KERN_INFO "Horiz. Sync Pulse Width:%d\n",this->tda.edid_dtd.desc[i].hSyncWidth); + printk(KERN_INFO "Vertical Sync Offset:%d\n",this->tda.edid_dtd.desc[i].vSyncOffset); + printk(KERN_INFO "Vertical Sync Pulse Width:%d\n",this->tda.edid_dtd.desc[i].vSyncWidth); + printk(KERN_INFO "Horizontal Image Size:%d\n",this->tda.edid_dtd.desc[i].hImageSize); + printk(KERN_INFO "Vertical Image Size:%d\n",this->tda.edid_dtd.desc[i].vImageSize); + printk(KERN_INFO "Horizontal Border:%d\n",this->tda.edid_dtd.desc[i].hBorderPixels); + printk(KERN_INFO "Vertical Border:%d\n",this->tda.edid_dtd.desc[i].vBorderPixels); + } + + printk(KERN_INFO "\n\n"); + this->tda.edid_md.max=EXAMPLE_MAX_SVD; + TRY(tmdlHdmiTxGetEdidMonitorDescriptors(this->tda.instance, \ + this->tda.edid_md.desc1, \ + this->tda.edid_md.desc2, \ + this->tda.edid_md.other, \ + this->tda.edid_md.max, \ + &this->tda.edid_md.written)); + printk(KERN_INFO "written:%d\n",this->tda.edid_md.written); + if (this->tda.edid_md.written > this->tda.edid_md.max) { + printk(KERN_ERR "get %d video caps but was waiting for %d\n", \ + this->tda.edid_md.written, \ + this->tda.edid_md.max); + this->tda.edid_md.written = this->tda.edid_md.max; + } + for(i=0; itda.edid_md.written;i++) { + if (this->tda.edid_md.desc1[i].descRecord) { + this->tda.edid_md.desc1[i].monitorName[EDID_MONITOR_DESCRIPTOR_SIZE-1]=0; + printk(KERN_INFO "Monitor name:%s\n",this->tda.edid_md.desc1[i].monitorName); + } + if (this->tda.edid_md.desc1[i].descRecord) { + printk(KERN_INFO "Min vertical rate in Hz:%d\n",this->tda.edid_md.desc2[i].minVerticalRate); + printk(KERN_INFO "Max vertical rate in Hz:%d\n",this->tda.edid_md.desc2[i].maxVerticalRate); + printk(KERN_INFO "Min horizontal rate in Hz:%d\n",this->tda.edid_md.desc2[i].minHorizontalRate); + printk(KERN_INFO "Max horizontal rate in Hz:%d\n",this->tda.edid_md.desc2[i].maxHorizontalRate); + printk(KERN_INFO "Max supported pixel clock rate in MHz:%d\n",this->tda.edid_md.desc2[i].maxSupportedPixelClk); + } + } + + printk(KERN_INFO "\n\n"); + TRY(tmdlHdmiTxGetEdidTVPictureRatio(this->tda.instance, \ + &this->tda.edid_tv_aspect_ratio)); + printk(KERN_INFO "%s\n",tda_spy_aspect_ratio(this->tda.edid_tv_aspect_ratio)); + + printk(KERN_INFO "\n\n"); + TRY(tmdlHdmiTxGetEdidLatencyInfo(this->tda.instance, \ + &this->tda.edid_latency)); + if (this->tda.edid_latency.latency_available) { + printk(KERN_INFO "Edid video:%d\n",this->tda.edid_latency.Edidvideo_latency); + printk(KERN_INFO "Edid audio:%d\n",this->tda.edid_latency.Edidaudio_latency); + } + if (this->tda.edid_latency.Ilatency_available) { + printk(KERN_INFO "Edid Ivideo:%d\n",this->tda.edid_latency.EdidIvideo_latency); + printk(KERN_INFO "Edid Iaudio:%d\n",this->tda.edid_latency.EdidIaudio_latency); + } + TRY_DONE: + return err; +} +#endif + +/* + * + * PROCESSING + * ---------- + * LEVEL 2 + * + * - + * + */ + +/* + * On HDCP + */ +void hdcp_on(tda_instance *this) { + + int err=0; + + if (this->tda.hdcp_status != HDCP_IS_NOT_INSTALLED) { /* check HDCP is installed ... */ + if (this->tda.hdcp_enable) { /* ... but requested ! */ + TRY(tmdlHdmiTxSetHdcp(this->tda.instance,True)); /* switch if on */ +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + /* hide video content until HDCP authentification is finished */ + if (!this->tda.setup.simplayHd) { + TRY(tmdlHdmiTxSetBScreen(this->tda.instance,TMDL_HDMITX_PATTERN_BLUE)); + } +#endif + } + } + TRY_DONE: + (void)0; +} + +/* + * Off HDCP + */ +void hdcp_off(tda_instance *this) { + + int err=0; + + if (this->tda.hdcp_status != HDCP_IS_NOT_INSTALLED) { /* check HDCP is installed ... */ + + if (this->tda.hdcp_enable) { /* but no more requested */ + TRY(tmdlHdmiTxSetHdcp(this->tda.instance,False)); /* switch if off */ + } + } + TRY_DONE: + (void)0; +} + +/* + * Run video + */ +void show_video(tda_instance *this) { + + int err=0; + + if (this->tda.rx_device_active) { /* check RxSens */ + if (this->tda.hot_plug_detect == TMDL_HDMITX_HOTPLUG_ACTIVE) { /* should be useless, but legacy... */ + if (this->tda.power == tmPowerOn) { /* check CEC or DSS didn't switch it off */ + if (this->tda.src_address != 0xFFFF) { /* check EDID has been received */ + hdcp_off(this); + TRY(tmdlHdmiTxSetInputOutput(this->tda.instance, \ + this->tda.setio.video_in, \ + this->tda.setio.video_out, \ + this->tda.setio.audio_in, \ + this->tda.setio.sink)); + hdcp_on(this); + /* + Mind that SetInputOutput disable the blue color matrix settings of tmdlHdmiTxSetBScreen ... + so put tmdlHdmiTxSetBScreen (or hdcp_on) always after + */ + } + } + } + } + + TRY_DONE: + (void)0; +} + +/* + * TDA interrupt polling + */ +static void interrupt_polling(struct work_struct *dummy) +{ + tda_instance *this=&our_instance; + int err=0; + + /* Tx part */ + TRY(tmdlHdmiTxHandleInterrupt(this->tda.instance)); + + /* CEC part */ + if (this->driver.cec_callback) this->driver.cec_callback(dummy); + + /* FIX : IT anti debounce */ + TRY(tmdlHdmiTxHandleInterrupt(this->tda.instance)); + + TRY_DONE: + + /* setup next polling */ +#ifndef IRQ + mod_timer(&this->driver.no_irq_timer,jiffies + ( CHECK_EVERY_XX_MS * HZ / 1000 )); +#endif + + (void)0; +} + +/* + * TDA interrupt polling + */ +static void hdcp_check(struct work_struct *dummy) +{ + int err=0; + tda_instance *this=&our_instance; + tmdlHdmiTxHdcpCheck_t hdcp_status; + + down(&this->driver.sem); + + if (this->tda.hdcp_status == HDCP_IS_NOT_INSTALLED) goto TRY_DONE; + + TRY(tmdlHdmiTxHdcpCheck(this->tda.instance,HDCP_CHECK_EVERY_MS)); + TRY(tmdlHdmiTxGetHdcpState(this->tda.instance, &hdcp_status)); +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + if (this->tda.hdcp_status != hdcp_status) { + LOG(KERN_INFO,"HDCP status:%s\n",tda_spy_hdcp_status(hdcp_status)); + this->tda.hdcp_status = hdcp_status; + } +#endif +#ifdef HDCP_TEST + /* TEST */ + if (test++>500) { + test=0; + this->tda.hdcp_enable=1-this->tda.hdcp_enable; + printk("TEST hdcp:%d\n",this->tda.hdcp_enable); + if (this->tda.rx_device_active) { /* check RxSens */ + if (this->tda.hot_plug_detect == TMDL_HDMITX_HOTPLUG_ACTIVE) { /* should be useless, but legacy... */ + if (this->tda.power == tmPowerOn) { /* check CEC didn't switch it off */ + if (this->tda.src_address != 0xFFFF) { /* check EDID has been received */ + hdcp_off(this); + hdcp_on(this); + } + } + } + } + } +#endif + + TRY_DONE: + + /* setup next polling */ + mod_timer(&this->driver.hdcp_check,jiffies + ( HDCP_CHECK_EVERY_MS * HZ / 1000 )); + + up(&this->driver.sem); +} + +void register_cec_interrupt(cec_callback_t fct) +{ + tda_instance *this=&our_instance; + + this->driver.cec_callback = fct; +} +EXPORT_SYMBOL(register_cec_interrupt); + +void unregister_cec_interrupt(void) +{ + tda_instance *this=&our_instance; + + this->driver.cec_callback = NULL; +} +EXPORT_SYMBOL(unregister_cec_interrupt); + +static DECLARE_WORK(wq_irq, interrupt_polling); +void polling_timeout(unsigned long arg) +{ + /* derefered because ATOMIC context of timer does not support I2C_transfert */ + schedule_work(&wq_irq); +} + +static DECLARE_WORK(wq_hdcp, hdcp_check); +void hdcp_check_timeout(unsigned long arg) +{ + /* derefered because ATOMIC context of timer does not support I2C_transfert */ + schedule_work(&wq_hdcp); +} + +#ifdef IRQ +/* + * TDA irq + */ +static irqreturn_t tda_irq(int irq, void *_udc) +{ + + /* do it now */ + schedule_work(&wq_irq); + + return IRQ_HANDLED; +} +#endif + +/* + * TDA callback + */ +static void eventCallbackTx(tmdlHdmiTxEvent_t event) +{ + tda_instance *this=&our_instance; + int err=0; + unsigned short new_addr; +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + tda_hdcp_fail hdcp_fail; +#endif + + this->tda.event=event; + if (TMDL_HDMITX_HDCP_INACTIVE != event) { + printk(KERN_INFO "hdmi %s\n",tda_spy_event(event)); + } + + switch (event) { + case TMDL_HDMITX_EDID_RECEIVED: + TRY(tmdlHdmiTxGetEdidSourceAddress(this->tda.instance, \ + &new_addr)); + LOG(KERN_INFO,"phy.@:%x\n",new_addr); + /* if (this->tda.src_address == new_addr) { */ + /* break; */ + /* } */ + this->tda.src_address = new_addr; +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + tda_spy(this->param.verbose>1); +#endif + /* + Customer may add stuff to analyse EDID (see tda_spy()) + and select automatically some video/audio settings. + By default, let go on with next case and activate + default video/audio settings with tmdlHdmiTxSetInputOutput() + */ + + TRY(tmdlHdmiTxGetEdidSinkType(this->tda.instance, \ + &this->tda.setio.sink)); + if (TMDL_HDMITX_SINK_HDMI != this->tda.setio.sink) { + printk(KERN_INFO "/!\\ CAUTION /!\\ sink is not HDMI but %s\n",tda_spy_sink(this->tda.setio.sink)); + } + + msleep(100); + /* + /!\ WARNING /! \ + the core driver does not send any HPD nor RXSENS when HDMI was plugged after at boot time + and only EDID_RECEIVED is send, so rx_device_active shall be forced now. + Do not skip the next case nor add any break here please + */ + case TMDL_HDMITX_RX_DEVICE_ACTIVE: /* TV is ready to receive */ + this->tda.rx_device_active = 1; + show_video(this); + break; + case TMDL_HDMITX_RX_DEVICE_INACTIVE: /* TV is ignoring the source */ + this->tda.rx_device_active = 0; + break; + case TMDL_HDMITX_HPD_ACTIVE: /* HDMI is so funny u can get RxSens without being plugged !!! */ + this->tda.hot_plug_detect = TMDL_HDMITX_HOTPLUG_ACTIVE; + show_video(this); + break; + case TMDL_HDMITX_HPD_INACTIVE: /* unplug */ + this->tda.hot_plug_detect = TMDL_HDMITX_HOTPLUG_INACTIVE; + this->tda.src_address = 0xFFFF; + break; +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + case TMDL_HDMITX_HDCP_INACTIVE: /* HDCP drops off */ + tmdlHdmiTxGetHdcpFailStatus(this->tda.instance, \ + &hdcp_fail, \ + &this->tda.hdcp_raw_status); + if (this->tda.hdcp_fail != hdcp_fail) { + if (this->tda.hdcp_fail) { + LOG(KERN_INFO,"%s (%d)\n",tda_spy_hsdc_fail_status(this->tda.hdcp_fail),this->tda.hdcp_raw_status); + } + this->tda.hdcp_fail = hdcp_fail; + tmdlHdmiTxSetBScreen(this->tda.instance,TMDL_HDMITX_PATTERN_BLUE); + } + break; + case TMDL_HDMITX_RX_KEYS_RECEIVED: /* end of HDCP authentification */ + if (!this->tda.setup.simplayHd) { + tmdlHdmiTxRemoveBScreen(this->tda.instance); + } + break; +#endif + default: + break; + } + + this->driver.poll_done=true; + wake_up_interruptible(&this->driver.wait); + + TRY_DONE: + (void)0; +} + +/* + * hdmi Tx init + */ +static int hdmi_tx_init(tda_instance *this) +{ + int err=0; + + LOG(KERN_INFO,"called\n"); + + + /*Initialize HDMI Transmiter*/ + TRY(tmdlHdmiTxOpen(&this->tda.instance)); + /* Register the HDMI TX events callbacks */ + TRY(tmdlHdmiTxRegisterCallbacks(this->tda.instance,(ptmdlHdmiTxCallback_t)eventCallbackTx)); + /* EnableEvent, all by default */ + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_HDCP_ACTIVE)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_HDCP_INACTIVE)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_HPD_ACTIVE)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_HPD_INACTIVE)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_RX_KEYS_RECEIVED)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_RX_DEVICE_ACTIVE)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_RX_DEVICE_INACTIVE)); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,TMDL_HDMITX_EDID_RECEIVED)); + + /* Size of the application EDID buffer */ + this->tda.setup.edidBufferSize=EDID_BLOCK_COUNT * EDID_BLOCK_SIZE; + /* Buffer to store the application EDID data */ + this->tda.setup.pEdidBuffer=this->tda.raw_edid; + /* To Enable/disable repeater feature, nor relevant here */ + this->tda.setup.repeaterEnable=false; + /* To enable/disable simplayHD feature: blue screen when not authenticated */ +#ifdef SIMPLAYHD + this->tda.setup.simplayHd=(this->tda.hdcp_enable?true:false); +#else + this->tda.setup.simplayHd=false; +#endif + + /* Provides HDMI TX instance configuration */ + TRY(tmdlHdmiTxInstanceSetup(this->tda.instance,&this->tda.setup)); + /* Get IC version */ + TRY(tmdlHdmiTxGetCapabilities(&this->tda.capabilities)); + + /* Main settings */ + this->tda.setio.video_out.mode = TMDL_HDMITX_VOUTMODE_RGB444; + this->tda.setio.video_out.colorDepth = TMDL_HDMITX_COLORDEPTH_24; +#ifdef TMFL_TDA19989 + this->tda.setio.video_out.dviVqr = TMDL_HDMITX_VQR_DEFAULT; /* Use HDMI rules for DVI output */ +#endif + /* this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_31_1920x1080p_50Hz; */ + /* this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_PC_640x480p_60Hz; */ + /* this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_PC_640x480p_72Hz; */ + // this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_04_1280x720p_60Hz; + /* this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_19_1280x720p_50Hz; */ + this->tda.setio.video_out.format = TMDL_HDMITX_VFMT_02_720x480p_60Hz; + + this->tda.setio.video_in.mode = TMDL_HDMITX_VINMODE_RGB444; + /* this->tda.setio.video_in.mode = TMDL_HDMITX_VINMODE_CCIR656; */ + /* this->tda.setio.video_in.mode = TMDL_HDMITX_VINMODE_YUV422; */ + this->tda.setio.video_in.format = this->tda.setio.video_out.format; + this->tda.setio.video_in.pixelRate = TMDL_HDMITX_PIXRATE_SINGLE; + this->tda.setio.video_in.syncSource = TMDL_HDMITX_SYNCSRC_EXT_VS; /* we use HS,VS as synchronisation source */ + + this->tda.setio.audio_in.format = TMDL_HDMITX_AFMT_I2S; /* audio I2S is coming in */ + this->tda.setio.audio_in.rate = TMDL_HDMITX_AFS_48K; /* audio sampling rate */ + this->tda.setio.audio_in.i2sFormat = TMDL_HDMITX_I2SFOR_PHILIPS_L; /* I2S format of the audio input */ + this->tda.setio.audio_in.i2sQualifier = TMDL_HDMITX_I2SQ_32BITS; /* we use a 32 bits bus */ + this->tda.setio.audio_in.dstRate = TMDL_HDMITX_DSTRATE_SINGLE; /* not relevant here */ + this->tda.setio.audio_in.channelAllocation = 0; /* audio channel allocation (Ref to CEA-861D p85) */ + /* set default channel status */ + this->tda.setio.audio_in.channelStatus.PcmIdentification = TMDL_HDMITX_AUDIO_DATA_PCM; + this->tda.setio.audio_in.channelStatus.CopyrightInfo = TMDL_HDMITX_CSCOPYRIGHT_PROTECTED; + this->tda.setio.audio_in.channelStatus.FormatInfo = TMDL_HDMITX_CSFI_PCM_2CHAN_NO_PRE; + this->tda.setio.audio_in.channelStatus.categoryCode = 0x00; + this->tda.setio.audio_in.channelStatus.clockAccuracy = TMDL_HDMITX_CSCLK_LEVEL_II; + this->tda.setio.audio_in.channelStatus.maxWordLength = TMDL_HDMITX_CSMAX_LENGTH_20; + this->tda.setio.audio_in.channelStatus.wordLength = TMDL_HDMITX_CSWORD_DEFAULT; + this->tda.setio.audio_in.channelStatus.origSampleFreq = TMDL_HDMITX_CSOFREQ_NOT_INDICATED; + + + this->tda.setio.sink = TMDL_HDMITX_SINK_HDMI; /* skip edid reading */ + /* this->tda.src_address = 0x1000; /\* debug *\/ */ + this->tda.src_address = NO_PHY_ADDR; /* it's unref */ + + TRY_DONE: + return err; +} + +void reset_hdmi(int hdcp_module) +{ + tda_instance *this=&our_instance; + int err=0; + + down(&this->driver.sem); + + /* PATCH because of SetPowerState that calls SetHdcp that has just been removed by nwolc :( */ + if (hdcp_module==2) { + tmdlHdmiTxSetHdcp(this->tda.instance,0); + goto TRY_DONE; + } + + TRY(tmdlHdmiTxSetPowerState(this->tda.instance,tmPowerStandby)); + tmdlHdmiTxClose(this->tda.instance); + + /* reset */ + this->tda.hdcp_enable = (hdcp_module?1:0); + hdmi_tx_init(this); + /* recover previous power state */ + TRY(tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power)); + tmdlHdmiTxGetHPDStatus(this->tda.instance,&this->tda.hot_plug_detect); /* check if activ for timer */ +#ifndef USER_SET_INPUT_OUTPUT + show_video(this); +#endif + + /* wake up or shut down hdcp checking */ + if (hdcp_module) { + this->driver.hdcp_check.expires = jiffies + ( HDCP_CHECK_EVERY_MS * HZ / 1000 ); + add_timer(&this->driver.hdcp_check); + this->tda.hdcp_status = TMDL_HDMITX_HDCP_CHECK_NOT_STARTED; +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + tmdlHdmiTxSetBScreen(this->tda.instance,TMDL_HDMITX_PATTERN_BLUE); +#endif + } + else { + del_timer(&this->driver.hdcp_check); + this->tda.hdcp_status = HDCP_IS_NOT_INSTALLED; + } + + TRY_DONE: + up(&this->driver.sem); +} +EXPORT_SYMBOL(reset_hdmi); + +/* + * + */ +short edid_phy_addr(void) +{ + tda_instance *this=&our_instance; + + return this->tda.src_address; +} +EXPORT_SYMBOL(edid_phy_addr); + +/* + * + */ +tda_power get_hdmi_status(void) +{ + tda_instance *this=&our_instance; + + return this->tda.power; +} +EXPORT_SYMBOL(get_hdmi_status); + +/* + * + */ +tda_power get_hpd_status(void) +{ + tda_instance *this=&our_instance; + + return (this->tda.hot_plug_detect == TMDL_HDMITX_HOTPLUG_ACTIVE); +} +EXPORT_SYMBOL(get_hpd_status); + +/* + * + */ +int edid_received(void) +{ + tda_instance *this=&our_instance; + + return (this->tda.event == TMDL_HDMITX_EDID_RECEIVED); +} +EXPORT_SYMBOL(edid_received); + +/* + * + */ +int hdmi_enable(void) +{ + tda_instance *this=&our_instance; + int err=0; + + LOG(KERN_INFO,"called\n"); + + down(&this->driver.sem); + + this->driver.omap_dss_hdmi_panel = true; + + this->tda.power = tmPowerOn; + TRY(tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power)); + if (err==TM_ERR_NO_RESOURCES) { + LOG(KERN_INFO,"Busy...\n"); + TRY(tmdlHdmiTxHandleInterrupt(this->tda.instance)); + TRY(tmdlHdmiTxHandleInterrupt(this->tda.instance)); + TRY(tmdlHdmiTxHandleInterrupt(this->tda.instance)); + } + tmdlHdmiTxGetHPDStatus(this->tda.instance,&this->tda.hot_plug_detect); + show_video(this); + + TRY_DONE: + up(&this->driver.sem); + return err; +} +EXPORT_SYMBOL(hdmi_enable); + +/* + * + */ +int hdmi_disable(int event_tracking) +{ + tda_instance *this=&our_instance; + int err=0; + + LOG(KERN_INFO,"called\n"); + + down(&this->driver.sem); + this->tda.power = (event_tracking?tmPowerSuspend:tmPowerStandby); + TRY(tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power)); + + TRY_DONE: + this->driver.omap_dss_hdmi_panel = false; + up(&this->driver.sem); + return err; +} +EXPORT_SYMBOL(hdmi_disable); + +/* + * + * ENTRY POINTS + * ------------ + * LEVEL 3 + * + * - + * + */ + +#ifdef ANDROID_DSS +/* + * DSS driver :: probe + */ +static int hdmi_panel_probe(struct omap_dss_device *dssdev) +{ + tda_instance *this=&our_instance; + + LOG(KERN_INFO," called\n"); + + /* OMAP_DSS_LCD_IVS = 1<<0, */ + /* OMAP_DSS_LCD_IHS = 1<<1, */ + /* OMAP_DSS_LCD_IPC = 1<<2, */ + /* OMAP_DSS_LCD_IEO = 1<<3, */ + /* OMAP_DSS_LCD_RF = 1<<4, */ + /* OMAP_DSS_LCD_ONOFF = 1<<5, */ + /* OMAP_DSS_LCD_TFT = 1<<20, */ + + dssdev->panel.config = OMAP_DSS_LCD_ONOFF | OMAP_DSS_LCD_IPC | \ + OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS; + dssdev->panel.timings = video_1280x720at50Hz_panel_timings; + (void)video_1280x720at60Hz_panel_timings; + (void)video_720x480at60Hz_panel_timings; + (void)video_1280x720at50Hz_panel_timings; + (void)video_800x480at60Hz_panel_timings; + (void)video_1280x720at50Hz_panel_timings; + (void)video_1920x1080at50Hz_panel_timings; + (void)video_640x480at72Hz_panel_timings; + (void)video_640x480at60Hz_panel_timings; + + return 0; +} + +/* + * DSS driver :: enable + */ +static void hdmi_panel_remove(struct omap_dss_device *dssdev) +{ +} + +/* + * DSS driver :: enable + */ +static int hdmi_panel_enable(struct omap_dss_device *dssdev) +{ + int r = 0; + + if (dssdev->platform_enable) + r = dssdev->platform_enable(dssdev); + + if (r) + goto ERROR0; + + r = hdmi_enable(); + if (r) + goto ERROR0; + /* wait couple of vsyncs until enabling the LCD */ + msleep(50); + + return 0; + ERROR0: + return r; +} + +/* + * DSS driver :: disable + */ +static void hdmi_panel_disable(struct omap_dss_device *dssdev) +{ + hdmi_disable(1); /* keep HPD int actif */ + + /* wait couple of vsyncs until enabling the hdmi */ + msleep(50); + + if (dssdev->platform_disable) + dssdev->platform_disable(dssdev); +} + +/* + * DSS driver :: suspend + */ +static int hdmi_panel_suspend(struct omap_dss_device *dssdev) +{ + hdmi_panel_disable(dssdev); + return 0; +} + +/* + * DSS driver :: resume + */ +static int hdmi_panel_resume(struct omap_dss_device *dssdev) +{ + return hdmi_panel_enable(dssdev); +} + +/* + * DSS driver (frontend with omapzoom) + * ----------------------------------- + */ +static struct omap_dss_driver hdmi_driver = { + .probe = hdmi_panel_probe, + .remove = hdmi_panel_remove, + .enable = hdmi_panel_enable, + .disable = hdmi_panel_disable, + .suspend = hdmi_panel_suspend, + .resume = hdmi_panel_resume, + .driver = { + .name = "hdmi_panel", + .owner = THIS_MODULE, + } +}; +#endif + +/* + * ioctl driver :: opening + */ + +static int this_cdev_open(struct inode *pInode, struct file *pFile) +{ + tda_instance *this; + int minor=iminor(pInode); + + if(minor >= MAX_MINOR) { + printk(KERN_ERR "hdmitx:%s:only one tda can be open\n",__func__); + return -EINVAL; + } + + if ((pFile->private_data != NULL) && (pFile->private_data != &our_instance)) { + printk(KERN_ERR "hdmitx:%s:pFile missmatch\n",__func__); + } + this = pFile->private_data = &our_instance; + down(&this->driver.sem); + + LOG(KERN_INFO,"major:%d minor:%d user:%d\n", imajor(pInode), iminor(pInode), this->driver.user_counter); + + if ((this->driver.user_counter++) && (this->driver.minor == minor)) { + /* init already done */ + up(&this->driver.sem); + return 0; + } + this->driver.minor = minor; + + + up(&this->driver.sem); + return 0; +} + +/* + * ioctl driver :: ioctl + */ +static int this_cdev_ioctl(struct inode *pInode, struct file *pFile, unsigned int cmd, unsigned long arg) +{ + tda_instance* this = pFile->private_data; + int err=0; + + LOG(KERN_INFO,":%s\n",tda_ioctl(_IOC_NR(cmd))); + + BUG_ON(this->driver.minor!=iminor(pInode)); + if (_IOC_TYPE(cmd) != TDA_IOCTL_BASE) { + printk(KERN_INFO "hdmitx:%s:unknown ioctl type: %x\n",__func__,_IOC_TYPE(cmd)); + return -ENOIOCTLCMD; + } + + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)) || !arg; + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)) || !arg; + if (err) { + printk(KERN_ERR "hdmitx:%s:argument access denied (check address vs value)\n",__func__); + printk(KERN_ERR "_IOC_DIR:%d arg:%lx\n",_IOC_DIR(cmd),arg); + return -EFAULT; + } + + down(&this->driver.sem); + + /* Check DevLib consistancy here */ + + switch ( _IOC_NR(cmd) ) + { + case TDA_VERBOSE_ON_CMD: + { + this->param.verbose=1; + printk(KERN_INFO "hdmitx:verbose on\n"); + break; + } + + case TDA_VERBOSE_OFF_CMD: + { + printk(KERN_INFO "hdmitx:verbose off\n"); + this->param.verbose=0; + break; + } + + case TDA_BYEBYE_CMD: + { + LOG(KERN_INFO,"release event handeling request\n"); + this->tda.event=RELEASE; + this->driver.poll_done = true; + wake_up_interruptible(&this->driver.wait); + break; + } + + case TDA_GET_SW_VERSION_CMD: + { + TRY(tmdlHdmiTxGetSWVersion(&this->tda.version)); + BUG_ON(copy_to_user((tda_version*)arg,&this->tda.version,sizeof(tda_version)) != 0); + break; + } + + case TDA_SET_POWER_CMD: + { + if (this->driver.omap_dss_hdmi_panel) { + /* DSS uses HDMI panel => do not switch the power through the ioctl, this will be done be DSS */ + } + else { + BUG_ON(copy_from_user(&this->tda.power,(tda_power*)arg,sizeof(tda_power)) != 0); + TRY(tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power)); + } + break; + } + + case TDA_GET_POWER_CMD: + { + TRY(tmdlHdmiTxGetPowerState(this->tda.instance, \ + &this->tda.power)); + BUG_ON(copy_to_user((tda_power*)arg,&this->tda.power,sizeof(tda_power)) != 0); + break; + } + + case TDA_SETUP_CMD: + { + BUG_ON(copy_from_user(&this->tda.setup,(tda_setup_info*)arg,sizeof(tda_setup_info)) != 0); + TRY(tmdlHdmiTxInstanceSetup(this->tda.instance, \ + &this->tda.setup)); + break; + } + + case TDA_GET_SETUP_CMD: + { + TRY(tmdlHdmiTxGetInstanceSetup(this->tda.instance, \ + &this->tda.setup)); + BUG_ON(copy_to_user((tda_setup*)arg,&this->tda.setup,sizeof(tda_setup)) != 0); + break; + } + + case TDA_WAIT_EVENT_CMD: + { + this->driver.poll_done = false; + up(&this->driver.sem); + if (wait_event_interruptible(this->driver.wait,this->driver.poll_done)) return -ERESTARTSYS; + down(&this->driver.sem); + BUG_ON(copy_to_user((tda_event*)arg,&this->tda.event,sizeof(tda_event)) != 0); + break; + } + + case TDA_ENABLE_EVENT_CMD: + { + tmdlHdmiTxEvent_t event; + BUG_ON(copy_from_user(&event,(tmdlHdmiTxEvent_t*)arg,sizeof(tmdlHdmiTxEvent_t)) != 0); + TRY(tmdlHdmiTxEnableEvent(this->tda.instance,event)); + break; + } + + case TDA_DISABLE_EVENT_CMD: + { + tmdlHdmiTxEvent_t event; + BUG_ON(copy_from_user(&event,(tmdlHdmiTxEvent_t*)arg,sizeof(tmdlHdmiTxEvent_t)) != 0); + TRY(tmdlHdmiTxDisableEvent(this->tda.instance,event)); + break; + } + + case TDA_GET_VIDEO_SPEC_CMD: + { + BUG_ON(copy_from_user(&this->tda.video_fmt,(tda_video_format*)arg,sizeof(tda_video_format)) != 0); + TRY(tmdlHdmiTxGetVideoFormatSpecs(this->tda.instance, \ + this->tda.video_fmt.id, \ + &this->tda.video_fmt.spec)); + BUG_ON(copy_to_user((tda_video_format*)arg,&this->tda.video_fmt,sizeof(tda_video_format)) != 0); + break; + } + + case TDA_SET_INPUT_OUTPUT_CMD: + { + BUG_ON(copy_from_user(&this->tda.setio,(tda_set_in_out*)arg,sizeof(tda_set_in_out)) != 0); + + /* TRY(tmdlHdmiTxSetInputOutput(this->tda.instance, \ */ + /* this->tda.setio.video_in, \ */ + /* this->tda.setio.video_out, \ */ + /* this->tda.setio.audio_in, \ */ + /* this->tda.setio.sink)); */ + break; + } + + case TDA_SET_AUDIO_INPUT_CMD: + { + BUG_ON(copy_from_user(&this->tda.setio.audio_in,(tda_set_audio_in*)arg,sizeof(tda_set_audio_in)) != 0); + TRY(tmdlHdmiTxSetAudioInput(this->tda.instance, \ + this->tda.setio.audio_in, \ + this->tda.setio.sink)); + break; + } + + case TDA_SET_VIDEO_INFOFRAME_CMD: + { + BUG_ON(copy_from_user(&this->tda.video_infoframe,(tda_video_infoframe*)arg,sizeof(tda_video_infoframe)) != 0); + TRY(tmdlHdmiTxSetVideoInfoframe(this->tda.instance, \ + this->tda.video_infoframe.enable, \ + &this->tda.video_infoframe.data)); + break; + } + + case TDA_SET_AUDIO_INFOFRAME_CMD: + { + BUG_ON(copy_from_user(&this->tda.audio_infoframe,(tda_audio_infoframe*)arg,sizeof(tda_audio_infoframe)) != 0); + TRY(tmdlHdmiTxSetAudioInfoframe(this->tda.instance, \ + this->tda.audio_infoframe.enable, \ + &this->tda.audio_infoframe.data)); + break; + } + + case TDA_SET_ACP_CMD: + { + BUG_ON(copy_from_user(&this->tda.acp,(tda_acp*)arg,sizeof(tda_acp)) != 0); + TRY(tmdlHdmiTxSetACPPacket(this->tda.instance, \ + this->tda.acp.enable, \ + &this->tda.acp.data)); + break; + } + + case TDA_SET_GCP_CMD: + { + BUG_ON(copy_from_user(&this->tda.gcp,(tda_gcp*)arg,sizeof(tda_gcp)) != 0); + TRY(tmdlHdmiTxSetGeneralControlPacket(this->tda.instance, \ + this->tda.gcp.enable, \ + &this->tda.gcp.data)); + break; + } + + case TDA_SET_ISRC1_CMD: + { + BUG_ON(copy_from_user(&this->tda.isrc1,(tda_isrc1*)arg,sizeof(tda_isrc1)) != 0); + TRY(tmdlHdmiTxSetISRC1Packet(this->tda.instance, \ + this->tda.isrc1.enable, \ + &this->tda.isrc1.data)); + break; + } + + case TDA_SET_MPS_INFOFRAME_CMD: + { + BUG_ON(copy_from_user(&this->tda.mps_infoframe,(tda_mps_infoframe*)arg,sizeof(tda_mps_infoframe)) != 0); + TRY(tmdlHdmiTxSetMPSInfoframe(this->tda.instance, \ + this->tda.mps_infoframe.enable, \ + &this->tda.mps_infoframe.data)); + break; + } + + case TDA_SET_SPD_INFOFRAME_CMD: + { + BUG_ON(copy_from_user(&this->tda.spd_infoframe,(tda_spd_infoframe*)arg,sizeof(tda_spd_infoframe)) != 0); + TRY(tmdlHdmiTxSetSpdInfoframe(this->tda.instance, \ + this->tda.spd_infoframe.enable, \ + &this->tda.spd_infoframe.data)); + break; + } + + case TDA_SET_VS_INFOFRAME_CMD: + { + BUG_ON(copy_from_user(&this->tda.vs_infoframe,(tda_vs_infoframe*)arg,sizeof(tda_vs_infoframe)) != 0); + TRY(tmdlHdmiTxSetVsInfoframe(this->tda.instance, \ + this->tda.vs_infoframe.enable, \ + &this->tda.vs_infoframe.data)); + break; + } + + case TDA_SET_AUDIO_MUTE_CMD: + { + BUG_ON(copy_from_user(&this->tda.audio_mute,(bool*)arg,sizeof(bool)) != 0); + TRY(tmdlHdmiTxSetAudioMute(this->tda.instance, \ + this->tda.audio_mute)); + break; + } + + case TDA_RESET_AUDIO_CTS_CMD: + { + TRY(tmdlHdmiTxResetAudioCts(this->tda.instance)); + break; + } + + case TDA_GET_EDID_STATUS_CMD: + { + TRY(tmdlHdmiTxGetEdidStatus(this->tda.instance, \ + &this->tda.edid.status, \ + &this->tda.edid.block_count)); + BUG_ON(copy_to_user((tda_edid*)arg,&this->tda.edid,sizeof(tda_edid)) != 0); + break; + } + + case TDA_GET_EDID_AUDIO_CAPS_CMD: + { + BUG_ON(copy_from_user(&this->tda.edid_audio_caps,(tda_edid_audio_caps*)arg,sizeof(tda_edid_audio_caps)) != 0); + TRY(tmdlHdmiTxGetEdidAudioCaps(this->tda.instance, \ + this->tda.edid_audio_caps.desc, \ + this->tda.edid_audio_caps.max, \ + &this->tda.edid_audio_caps.written, \ + &this->tda.edid_audio_caps.flags)); + BUG_ON(copy_to_user((tda_edid_audio_caps*)arg,&this->tda.edid_audio_caps,sizeof(tda_edid_audio_caps)) != 0); + break; + } + + case TDA_GET_EDID_VIDEO_CAPS_CMD: + { + BUG_ON(copy_from_user(&this->tda.edid_video_caps,(tda_edid_video_caps*)arg,sizeof(tda_edid_video_caps)) != 0); + TRY(tmdlHdmiTxGetEdidVideoCaps(this->tda.instance, \ + this->tda.edid_video_caps.desc, \ + this->tda.edid_video_caps.max, \ + &this->tda.edid_video_caps.written, \ + &this->tda.edid_video_caps.flags)); + BUG_ON(copy_to_user((tda_edid_video_caps*)arg,&this->tda.edid_video_caps,sizeof(tda_edid_video_caps)) != 0); + break; + } + + case TDA_GET_EDID_VIDEO_PREF_CMD: + { + TRY(tmdlHdmiTxGetEdidVideoPreferred(this->tda.instance, \ + &this->tda.edid_video_timings)); + BUG_ON(copy_to_user((tda_edid_video_timings*)arg,&this->tda.edid_video_timings,sizeof(tda_edid_video_timings)) != 0); + break; + } + + case TDA_GET_EDID_SINK_TYPE_CMD: + { + TRY(tmdlHdmiTxGetEdidSinkType(this->tda.instance, \ + &this->tda.setio.sink)); + BUG_ON(copy_to_user((tda_sink*)arg,&this->tda.setio.sink,sizeof(tda_sink)) != 0); + break; + } + + case TDA_GET_EDID_SOURCE_ADDRESS_CMD: + { + TRY(tmdlHdmiTxGetEdidSourceAddress(this->tda.instance, \ + &this->tda.src_address)); + BUG_ON(copy_to_user((unsigned short*)arg,&this->tda.src_address,sizeof(unsigned short)) != 0); + break; + } + + case TDA_SET_GAMMUT_CMD: + { + BUG_ON(copy_from_user(&this->tda.gammut,(tda_gammut*)arg,sizeof(tda_gammut)) != 0); + TRY(tmdlHdmiTxSetGamutPacket(this->tda.instance, \ + this->tda.gammut.enable, \ + &this->tda.gammut.data)); + break; + } + + case TDA_GET_EDID_DTD_CMD: + { + BUG_ON(copy_from_user(&this->tda.edid_dtd,(tda_edid_dtd*)arg,sizeof(tda_edid_dtd)) != 0); + TRY(tmdlHdmiTxGetEdidDetailledTimingDescriptors(this->tda.instance, \ + this->tda.edid_dtd.desc, \ + this->tda.edid_dtd.max, \ + &this->tda.edid_dtd.written)); + BUG_ON(copy_to_user((tda_edid_dtd*)arg,&this->tda.edid_dtd,sizeof(tda_edid_dtd)) != 0); + break; + } + +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + case TDA_GET_EDID_MD_CMD: + { + BUG_ON(copy_from_user(&this->tda.edid_md,(tda_edid_md*)arg,sizeof(tda_edid_md)) != 0); + TRY(tmdlHdmiTxGetEdidMonitorDescriptors(this->tda.instance, \ + this->tda.edid_md.desc1, \ + this->tda.edid_md.desc2, \ + this->tda.edid_md.other, \ + this->tda.edid_md.max, \ + &this->tda.edid_md.written)); + BUG_ON(copy_to_user((tda_edid_md*)arg,&this->tda.edid_md,sizeof(tda_edid_md)) != 0); + break; + } + + case TDA_GET_EDID_TV_ASPECT_RATIO_CMD: + { + TRY(tmdlHdmiTxGetEdidTVPictureRatio(this->tda.instance, \ + &this->tda.edid_tv_aspect_ratio)); + BUG_ON(copy_to_user((tda_edid_tv_aspect_ratio*)arg,&this->tda.edid_tv_aspect_ratio,sizeof(tda_edid_tv_aspect_ratio)) != 0); + break; + } + + case TDA_GET_EDID_LATENCY_CMD: + { + TRY(tmdlHdmiTxGetEdidLatencyInfo(this->tda.instance, \ + &this->tda.edid_latency)); + BUG_ON(copy_to_user((tda_edid_latency*)arg,&this->tda.edid_latency,sizeof(tda_edid_latency)) != 0); + break; + } + + case TDA_SET_HDCP_CMD: + { + BUG_ON(copy_from_user(&this->tda.hdcp_enable,(bool*)arg,sizeof(bool)) != 0); + break; + } + + case TDA_GET_HPD_STATUS_CMD: + { + tmdlHdmiTxGetHPDStatus(this->tda.instance,&this->tda.hot_plug_detect); + BUG_ON(copy_to_user((tmdlHdmiTxHotPlug_t*)arg,&this->tda.hot_plug_detect,sizeof(tmdlHdmiTxHotPlug_t)) != 0); + break; + } + case TDA_GET_HDCP_STATUS_CMD: + { + BUG_ON(copy_to_user((tda_edid_latency*)arg,&this->tda.hdcp_status,sizeof(tda_hdcp_status)) != 0); + break; + } +#endif + + default: + { + /* unrecognized ioctl */ + printk(KERN_INFO "hdmitx:%s:unknown ioctl number: %x\n",__func__,cmd); + up(&this->driver.sem); + return -ENOIOCTLCMD; + } + } + + TRY_DONE: + up(&this->driver.sem); + return err; +} + +/* + * ioctl driver :: releasing + */ +static int this_cdev_release(struct inode *pInode, struct file *pFile) +{ + tda_instance* this = pFile->private_data; + int minor = iminor(pInode); + + LOG(KERN_INFO,"called\n"); + + if(minor >= MAX_MINOR) { + LOG(KERN_ERR,"minor too big!\n"); + return -EINVAL; + } + + BUG_ON(this->driver.minor!=iminor(pInode)); + down(&this->driver.sem); + + this->driver.user_counter--; + if(this->driver.user_counter == 0) { + pFile->private_data = NULL; + } + else { + LOG(KERN_INFO,"Still %d users pending\n",this->driver.user_counter); + } + + up(&this->driver.sem); + return 0; +} + +/* + * I2C client :: creation + */ +static int this_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + tda_instance *this=&our_instance; + int err=0; + + printk(KERN_ERR "i2c probe called.....\n"); + + LOG(KERN_INFO,"called\n"); + + /* + I2C setup + */ + if (this->driver.i2c_client) { + dev_err(&this->driver.i2c_client->dev, "<%s> HDMI Device already created \n", + __func__); + return -ENODEV; + } + + this->driver.i2c_client = client; + i2c_set_clientdata(client, this); + + /* I2C ok, then let's startup TDA */ + err = hdmi_tx_init(this); + if (err) goto i2c_out; + this->tda.hdcp_enable = 0; + /* Standby the HDMI TX instance : this is mandatory for TDA boot up sequence, do not change it */ + this->tda.power = tmPowerStandby; /* power start sequence phase 1, see phase 2 */ + tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power); + /* update HPD */ + tmdlHdmiTxGetHPDStatus(this->tda.instance,&this->tda.hot_plug_detect); + +#ifdef ANDROID_DSS + /* probe DSS */ + err = omap_dss_register_driver(&hdmi_driver); +#endif + if (err) goto i2c_tx_out; + + /* prepare event */ + this->driver.poll_done = true; /* currently idle */ + init_waitqueue_head(&this->driver.wait); + +#ifdef IRQ + if (client->irq > 0) { + this->driver.gpio = irq_to_gpio(client->irq); + } else { + this->driver.gpio = TDA_IRQ_CALIB; + } + + /* FRO calibration */ + err=gpio_request(this->driver.gpio, "tda998x calibration"); + if (err < 0) { + printk(KERN_ERR "hdmitx:%s:cannot use GPIO %d, err:%d\n",__func__, this->driver.gpio,err); + goto i2c_out; + } + /* turn GPIO into IRQ */ + gpio_direction_input(this->driver.gpio); + msleep(1); + + err=request_irq(gpio_to_irq(this->driver.gpio), tda_irq, + IRQF_TRIGGER_FALLING|IRQF_DISABLED, "TDA IRQ", this); + if (err <0) { + printk(KERN_ERR "hdmitx:%s:Cannot request irq, err:%d\n",__func__,err); + gpio_free(this->driver.gpio); + goto i2c_out; + } +#else + init_timer(&this->driver.no_irq_timer); + this->driver.no_irq_timer.function=polling_timeout; + this->driver.no_irq_timer.data=0; + this->driver.no_irq_timer.expires = jiffies + HZ; /* start polling in one sec */ + add_timer(&this->driver.no_irq_timer); +#endif + + /* setup hdcp check timer */ + init_timer(&this->driver.hdcp_check); + this->driver.hdcp_check.function=hdcp_check_timeout; + this->driver.hdcp_check.data=0; + + tmdlHdmiTxGetSWVersion(&this->tda.version); + printk(KERN_INFO "HDMI TX SW Version:%lu.%lu compatibility:%lu\n", \ + this->tda.version.majorVersionNr,\ + this->tda.version.minorVersionNr,\ + this->tda.version.compatibilityNr); + return 0; + + i2c_tx_out: + LOG(KERN_INFO,"tmdlHdmiTx closed\n"); + /* close DevLib */ + err=tmdlHdmiTxClose(this->tda.instance); + + i2c_out: + LOG(KERN_INFO,"this->driver.i2c_client removed\n"); + this->driver.i2c_client = NULL; + + return err; +} + +/* + * I2C client :: destroy + */ +static int this_i2c_remove(struct i2c_client *client) +{ + tda_instance *this=&our_instance; + int err=0; + + LOG(KERN_INFO,"called\n"); + +#ifdef ANDROID_DSS + /* unplug DSS */ + omap_dss_unregister_driver(&hdmi_driver); +#endif + + /* close DevLib */ + err=tmdlHdmiTxClose(this->tda.instance); + + if (!client->adapter) { + dev_err(&this->driver.i2c_client->dev, "<%s> No HDMI Device \n", + __func__); + return -ENODEV; + } + this->driver.i2c_client = NULL; + + return err; +} + +/* + * I2C client driver (backend) + * ----------------- + */ +static const struct i2c_device_id this_i2c_id[] = { + { TX_NAME, 0 }, + { }, +}; + +MODULE_DEVICE_TABLE(i2c, this_i2c_id); + +static struct i2c_driver this_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = TX_NAME, + }, + .probe = this_i2c_probe, + .remove = this_i2c_remove, + .id_table = this_i2c_id, +}; + +/* + * ioctl driver (userland frontend) + * ------------ + */ +static struct file_operations this_cdev_fops = { + owner: THIS_MODULE, + open: this_cdev_open, + release: this_cdev_release, +// ioctl: this_cdev_ioctl, +}; + +/* + * sysfs_attrs + * ----------- + */ + +static ssize_t reso_show(struct device *dev,struct device_attribute *attr, char *buf) +{ + tda_instance *this=&our_instance; + + return sprintf(buf,"format video %d ( %s )\n", \ + this->tda.setio.video_in.format, \ + tda_spy_vfmt(this->tda.setio.video_in.format)); +} + +static ssize_t reso_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + tda_instance *this=&our_instance; + int resolution=0; + + sscanf(buf,"%d",&resolution); + if (resolution != WITH_FP(this->tda.setio.video_in.format)) { + LOG(KERN_INFO,"sys_attr new video format\n from %d:( %s )\n to %d:( %s )\n", \ + this->tda.setio.video_in.format, \ + tda_spy_vfmt(this->tda.setio.video_in.format), \ + resolution, \ + tda_spy_vfmt(resolution)); + this->tda.setio.video_out.format = NO_FP(resolution); + this->tda.setio.video_in.format = this->tda.setio.video_out.format; + this->tda.setio.video_in.structure3D = (IS_FP(resolution)?TMDL_HDMITX_3D_FRAME_PACKING:TMDL_HDMITX_3D_NONE); + + if (resolution == 0) { + this->tda.power = tmPowerStandby; + tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power); + } else { + this->tda.power = tmPowerOn; + tmdlHdmiTxSetPowerState(this->tda.instance,this->tda.power); + show_video(this); + } + } + return 0; +} + + +static ssize_t audio_show(struct device *dev,struct device_attribute *attr, char *buf) +{ + tda_instance *this=&our_instance; + printk("Audio Show\n"); + + tda_spy_audio(&this->tda.setio.audio_in); + return sprintf(buf,"audio format %d - %d - %d - %d - %d - %d\n", \ + this->tda.setio.audio_in.format, \ + this->tda.setio.audio_in.rate, \ + this->tda.setio.audio_in.i2sFormat, \ + this->tda.setio.audio_in.i2sQualifier, \ + this->tda.setio.audio_in.dstRate, \ + this->tda.setio.audio_in.channelAllocation); +} + +static ssize_t audio_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + tda_instance *this=&our_instance; + char desc_format[]="%d - %d - %d - %d - %d - %d\n"; + tda_audio_in audio; + + /* + Example: + + adb shell "echo '1 - 1 - 0 - 32 - 0 -' >/sys/hdmitx/audio" + + with : + + TMDL_HDMITX_AFMT_I2S, + TMDL_HDMITX_AFS_44K, + TMDL_HDMITX_I2SFOR_PHILIPS_L, + TMDL_HDMITX_I2SQ_32BITS, + TMDL_HDMITX_DSTRATE_SINGLE, + channel:0 + */ + + memcpy(&audio,&this->tda.setio.audio_in,sizeof(audio)); + sscanf(buf,desc_format, \ + &audio.format, \ + &audio.rate, \ + &audio.i2sFormat, \ + &audio.i2sQualifier, \ + &audio.dstRate, \ + &audio.channelAllocation); + + if (memcmp(&this->tda.setio.audio_in,&audio,sizeof(audio))) { + tda_spy_audio(&this->tda.setio.audio_in); + memcpy(&this->tda.setio.audio_in,&audio,sizeof(audio)); + tmdlHdmiTxSetAudioInput(this->tda.instance, \ + this->tda.setio.audio_in, \ + this->tda.setio.sink); + } + return 0; +} + +#ifdef I2C_DBG +static ssize_t i2cR_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + /* + adb shell "echo '2 1' >/sys/hdmitx/i2cR" + ... read page 0x02 address 0x01 + */ + tda_instance *this=&our_instance; + tmHdmiTxobject_t *p; + tmErrorCode_t err; + unsigned int address; + unsigned int value,page; + char desc_format[]="%x %x\n"; + + err = checkUnitSetDis(this->tda.instance, &p); + sscanf(buf,desc_format,&page,&address); + err = getHwRegister(p, SPA(E_SNONE,page,address), (unsigned char *)&value); + printk("i2c read %x @ page:%x address:%x\n",value,page,address); + return 0; +} + +static ssize_t i2cW_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + /* + adb shell "echo '2 1 0x03 2' >/sys/hdmitx/i2cW" + ... write 0x02 page 0x02 address 0x01 using mask 0x03 + */ + + tda_instance *this=&our_instance; + tmHdmiTxobject_t *p; + tmErrorCode_t err; + unsigned int page,address,mask,value; + char desc_format[]="%x %x %x %x\n"; + + err = checkUnitSetDis(this->tda.instance, &p); + sscanf(buf,desc_format,&page,&address,&mask,&value); + err = setHwRegisterField(p,SPA(E_SNONE,page,address),mask,value); + printk("i2c write %x @ page:%x address:%x mask:%x\n",value,page,address,mask); + return 0; +} +#endif + +static DEVICE_ATTR(resolution, S_IRUGO|S_IWUSR, reso_show, reso_store); +static DEVICE_ATTR(audio, S_IRUGO|S_IWUSR, audio_show, audio_store); +#ifdef I2C_DBG +static DEVICE_ATTR(i2cW, S_IRUGO|S_IWUSR, NULL, i2cW_store); +static DEVICE_ATTR(i2cR, S_IRUGO|S_IWUSR, NULL, i2cR_store); +#endif +static struct device_attribute *display_sysfs_attrs[] = { + &dev_attr_resolution, + &dev_attr_audio, +#ifdef I2C_DBG + &dev_attr_i2cW, + &dev_attr_i2cR, +#endif + NULL +}; + +static int comm_init(void) +{ + tda_instance *this=&our_instance; + int retval=0; + int i=0; + struct device_attribute *attr; + + while ((attr = display_sysfs_attrs[i++]) != NULL) { + retval=device_create_file (this->driver.dev,attr); + if (retval != 0) { + goto out_create_file; + } + } + /* create display sysfs links */ + retval = sysfs_create_link(NULL,&(this->driver.dev->kobj),HDMITX_NAME); + if (retval != 0) + goto out_create_link; + return retval; + + out_create_link: + sysfs_remove_link(NULL, HDMITX_NAME); + out_create_file: + while ((attr = display_sysfs_attrs[i++]) != NULL) { + device_remove_file (this->driver.dev,attr); + } + return retval; +} + +static void comm_exit(void) +{ + tda_instance *this=&our_instance; + int i=0; + struct device_attribute *attr; + while ((attr = display_sysfs_attrs[i++]) != NULL) { + device_remove_file (this->driver.dev,attr); + } + sysfs_remove_link(NULL, HDMITX_NAME); +} + +/* + * Module :: start up + */ +static int __init tx_init(void) +{ + tda_instance *this=&our_instance; + dev_t dev=0; + int err=0; + + /* + general device context + */ + memset(this,0,sizeof(tda_instance)); + this->param.verbose = param_verbose; + this->param.major = param_major; + this->param.minor = param_minor; + + /* Hello word */ + printk(KERN_INFO "%s(%s) %d.%d.%d compiled: %s %s %s\n", HDMITX_NAME, TDA_NAME, + TDA_VERSION_MAJOR, + TDA_VERSION_MINOR, + TDA_VERSION_PATCHLEVEL, + __DATE__, __TIME__, TDA_VERSION_EXTRA); + if (this->param.verbose) LOG(KERN_INFO,".verbose mode\n"); + + /* + plug I2C (backend : Hw interfacing) + */ + err = i2c_add_driver(&this_i2c_driver); + if (err < 0) { + printk(KERN_ERR "Driver registration failed\n"); + return -ENODEV; + } + + if (this->driver.i2c_client == NULL) { + printk(KERN_ERR "this->driver.i2c_client not allocated\n"); + /* unregister i2c */ + err = -ENODEV; + goto init_out; + } + + /* + cdev init (userland frontend) + */ + + /* arbitray range of device numbers */ + if (this->param.major) { + /* user force major number @ insmod */ + dev = MKDEV(this->param.major, this->param.minor); + err = register_chrdev_region(dev,MAX_MINOR,HDMITX_NAME); + if (err) { + printk(KERN_ERR "unable to register %s, dev=%d %s\n",HDMITX_NAME,dev,ERR_TO_STR(err)); + goto init_out; + } + } else { + /* fully dynamic major number */ + err = alloc_chrdev_region(&dev, this->param.minor, MAX_MINOR,HDMITX_NAME); + if (err) { + printk(KERN_ERR "unable to alloc chrdev region for %s, dev=%d %s\n",HDMITX_NAME,dev,ERR_TO_STR(err)); + goto init_out; + } + this->param.major = MAJOR(dev); + this->param.minor = MINOR(dev); + /* create_dev("/dev/hdmitx",dev); */ + LOG(KERN_INFO,"/dev/hdmitx created major:%d minor:%d\n",this->param.major, this->param.minor); + } + + cdev_init(this_cdev, &this_cdev_fops); + this_cdev->owner = THIS_MODULE; + + this->driver.class = class_create(THIS_MODULE, HDMITX_NAME); + if (IS_ERR(this->driver.class)) { + printk(KERN_INFO "Error creating mmap device class.\n"); + err =-EIO; + goto init_out; + } + this->driver.dev=device_create(this->driver.class, NULL /* parent */, dev, NULL, HDMITX_NAME); + + this->driver.devno = dev; + err = cdev_add(this_cdev, this->driver.devno, MAX_MINOR); + if (err){ + printk(KERN_INFO "unable to add device for %s, ipp_driver.devno=%d %s\n",HDMITX_NAME,this->driver.devno,ERR_TO_STR(err)); + device_destroy(this->driver.class,this->driver.devno); + class_destroy(this->driver.class); + unregister_chrdev_region(this->driver.devno, MAX_MINOR); + goto init_out; + } + + /* + general device context + */ + sema_init(&this->driver.sem, 1); + + /* + /!\ WARNING /! \ + the startup power sequence SHALL BE standby AND THEN suspend (core driver legacy...) + this is the only way to get the TDA idle but with active HDP and RxSens interrupt listening + */ + hdmi_disable(1); /* power start sequence phase 2 */ + + /* + /!\ WARNING /! \ + if HDMI is plugged, the core driver will send HDP nor RXSENS event when beeing powered on ! + So the Android HDMI service shall start by asking the HDP status using the IOCTL GET_HPD_STATUS + */ + tmdlHdmiTxGetHPDStatus(this->tda.instance, + &this->tda.hot_plug_detect); /* power start sequence phase 3 */ + + /* sysfs_attrs */ + comm_init(); + hdmi_enable(); + return 0; + + init_out: + i2c_del_driver(&this_i2c_driver); + return err; +} + +/* + * Module :: shut down + */ +static void __exit tx_exit(void) +{ + tda_instance *this=&our_instance; + + LOG(KERN_INFO,"called\n"); + +#ifdef IRQ + free_irq(gpio_to_irq(this->driver.gpio), this); + gpio_free(this->driver.gpio); +#else + del_timer(&this->driver.no_irq_timer); +#endif + + del_timer(&this->driver.hdcp_check); + + /* sysfs_attrs */ + comm_exit(); + + /* unregister cdevice */ + cdev_del(this_cdev); + unregister_chrdev_region(this->driver.devno, MAX_MINOR); + + /* unregister device */ + device_destroy(this->driver.class,this->driver.devno); + class_destroy(this->driver.class); + + /* unregister i2c */ + i2c_del_driver(&this_i2c_driver); +} + + +/* + * Module + * ------ + */ +late_initcall(tx_init); +// module_init(tx_init); +module_exit(tx_exit); + +/* + * Disclamer + * --------- + */ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andre Lepine "); +MODULE_DESCRIPTION(HDMITX_NAME " driver"); diff --git a/drivers/video/nxp/tda998x.h b/drivers/video/nxp/tda998x.h new file mode 100755 index 0000000000000..a6cfa4309d1b3 --- /dev/null +++ b/drivers/video/nxp/tda998x.h @@ -0,0 +1,143 @@ +/*****************************************************************************/ +/* Copyright (c) 2009 NXP Semiconductors BV */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, using version 2 of the License. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */ +/* USA. */ +/* */ +/*****************************************************************************/ + +#ifndef __tx_h__ +#define __tx_h__ + +#include "tda998x_ioctl.h" + +#define HDMITX_NAME "hdmitx" + +#define POLLING_WQ_NAME "TDA_POLLING" +#define HDCP_CHECK_EVERY_MS 35 +#define CHECK_EVERY_XX_MS 200 +#define OMAP_LCD_GPIO 8 + +#define TDA_MAJOR 234 /* old-style interval of device numbers */ +#define MAX_MINOR 1 /* 1 minor but 2 access : 1 more for pooling */ + + +/* common I2C define with kernel */ +/* should be the same as arch/arm/mach-omap2/board-zoom2.c */ +#define TX_NAME "tda998X" +#define TDA998X_I2C_SLAVEADDRESS 0x70 + +#define TDA_IRQ_CALIB 107 + +#define EDID_BLOCK_COUNT 4 +#define EDID_BLOCK_SIZE 128 +#define MAX_EDID_TRIAL 5 +#define NO_PHY_ADDR 0xFFFF + +#define HDCP_IS_NOT_INSTALLED TMDL_HDMITX_HDCP_CHECK_NUM /* ugly is bad ! */ + +#define LOG(type,fmt,args...) {if (this->param.verbose) {printk(type HDMITX_NAME":%s:" fmt, __func__, ## args);}} +/* not found the kernel "strerror" one! If someone knows, please replace it */ +#define ERR_TO_STR(e)((e == -ENODATA)?"ENODATA, no data available":\ + (e == -ENOMEM)? "ENOMEM, no memory available":\ + (e == -EINVAL)? "EINVAL, invalid argument":\ + (e == -EIO)? "EIO, input/output error":\ + (e == -ETIMEDOUT)? "ETIMEOUT, timeout has expired":\ + (e == -EBUSY)? "EBUSY, device or resource busy":\ + (e == -ENOENT)? "ENOENT, no such file or directory":\ + (e == -EACCES)? "EACCES, permission denied":\ + (e == 0)? "":\ + "!UNKNOWN!") + +#define TRY(fct) { \ + err=(fct); \ + if (err) { \ + printk(KERN_ERR "%s returned in %s line %d\n",hdmi_tx_err_string(err),__func__,__LINE__); \ + goto TRY_DONE; \ + } \ + } + +typedef void (*cec_callback_t)(struct work_struct *dummy); + +typedef struct { + /* module params */ + struct { + int verbose; + int major; + int minor; + } param; + /* driver */ + struct { + struct class *class; + struct device *dev; + int devno; + struct i2c_client *i2c_client; + struct semaphore sem; + int user_counter; + int minor; + wait_queue_head_t wait; + bool poll_done; +#ifndef IRQ + struct timer_list no_irq_timer; +#endif + struct timer_list hdcp_check; + cec_callback_t cec_callback; + bool omap_dss_hdmi_panel; + int gpio; + } driver; + /* HDMI */ + struct { + int instance; + tda_version version; + tda_setup setup; + tda_power power; + tmdlHdmiTxHotPlug_t hot_plug_detect; + bool rx_device_active; + tda_video_format video_fmt; + tda_set_in_out setio; + bool audio_mute; + tda_video_infoframe video_infoframe; + tda_audio_infoframe audio_infoframe; + tda_acp acp; + tda_gcp gcp; + tda_isrc1 isrc1; + tda_isrc2 isrc2; + tda_gammut gammut; + tda_mps_infoframe mps_infoframe; + tda_spd_infoframe spd_infoframe; + tda_vs_infoframe vs_infoframe; + tda_edid edid; + tda_edid_dtd edid_dtd; + tda_edid_md edid_md; + tda_edid_audio_caps edid_audio_caps; + tda_edid_video_caps edid_video_caps; + tda_edid_video_timings edid_video_timings; + tda_edid_tv_aspect_ratio edid_tv_aspect_ratio; +#ifdef TMFL_TDA19989 + tda_edid_latency edid_latency; +#endif + unsigned short src_address; + unsigned char raw_edid[EDID_BLOCK_COUNT*EDID_BLOCK_SIZE]; + tda_capabilities capabilities; + tda_event event; + tda_hdcp_status hdcp_status; + bool hdcp_enable; +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) + tda_hdcp_fail hdcp_fail; +#endif + unsigned char hdcp_raw_status; + } tda; +} tda_instance; + +#endif /* __tx_h__ */ diff --git a/drivers/video/nxp/tda998x_cec.c b/drivers/video/nxp/tda998x_cec.c new file mode 100755 index 0000000000000..25144e0248ffb --- /dev/null +++ b/drivers/video/nxp/tda998x_cec.c @@ -0,0 +1,2157 @@ +/*****************************************************************************/ +/* Copyright (c) 2009 NXP Semiconductors BV */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, using version 2 of the License. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */ +/* USA. */ +/* */ +/*****************************************************************************/ + +#define _cec_c_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* HDMI DevLib */ +#include "tmNxCompId.h" +#include "tmdlHdmiCEC.h" +#include "tmdlHdmiCEC_local.h" + +/* local */ +#include "tda998x_version.h" +#include "tda998x_cec.h" +#include "tda998x_ioctl.h" + +#include +#include +#include +#include + + +/* + * + * DEFINITION + * ---------- + * LEVEL 0 + * + */ + +/* + * Global + */ + +MODULE_DEVICE_TABLE(i2c, this_i2c_id); +static const struct i2c_device_id this_i2c_id[] = { + { CEC_NAME, 0 }, + { }, +}; +cec_instance our_instance; +static struct cdev our_cdev, *this_cdev=&our_cdev; + +#ifdef TWL4030_HACK +/* AL : hack to bypass keypad */ +struct input_dev *gkp_input; +extern struct input_dev *get_twm4030_input(void); +#endif + +/* + * Dependancies to HdmiTx module + */ + +extern void register_cec_interrupt(cec_callback_t fct); +extern void unregister_cec_interrupt(void); +extern short edid_phy_addr(void); +extern int hdmi_enable(void); +extern int hdmi_disable(int event_tracking); +extern cec_power get_hdmi_status(void); +extern cec_power get_hpd_status(void); +extern int edid_received(void); + +/* + * Module params + */ + +static int param_verbose=0,param_major=0,param_minor=0,param_device=4,param_addr=0xFFFF; +module_param_named(verbose,param_verbose,int,S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(verbose, "Make the driver verbose"); +module_param_named(major, param_major, int, S_IRUGO); +MODULE_PARM_DESC(major, "The major number of the device mapper"); +module_param_named(device, param_device, int, S_IRUGO); +MODULE_PARM_DESC(device, "Device type can be 0:tv, 1:rec 3:tuner 4:mediaplayer, 5:audio"); +module_param_named(addr, param_addr, int, S_IRUGO); +MODULE_PARM_DESC(addr, "Physical address (until EDID received)"); + +/* + * + * TOOLBOX + * ------- + * LEVEL 1 + * + * - i2c read/write + * - chip Id check + * - i2c client info + * + */ + + +/* + * Get main and unique I2C Client driver handle + */ +struct i2c_client *GetThisI2cClient(void) +{ + cec_instance *this=&our_instance; + return this->driver.i2c_client; +} + +/* + * error handling + */ +static char *hdmi_cec_err_string(int err) +{ + switch (err) + { + case TMDL_ERR_DLHDMICEC_COMPATIBILITY: {return "SW Interface compatibility";break;} + case TMDL_ERR_DLHDMICEC_MAJOR_VERSION: {return "SW Major Version error";break;} + case TMDL_ERR_DLHDMICEC_COMP_VERSION: {return "SW component version error";break;} + case TMDL_ERR_DLHDMICEC_BAD_UNIT_NUMBER: {return "Invalid device unit number";break;} + case TMDL_ERR_DLHDMICEC_BAD_INSTANCE: {return "Bad input instance value ";break;} + case TMDL_ERR_DLHDMICEC_BAD_HANDLE: {return "Bad input handle";break;} + case TMDL_ERR_DLHDMICEC_BAD_PARAMETER: {return "Invalid input parameter";break;} + case TMDL_ERR_DLHDMICEC_NO_RESOURCES: {return "Resource is not available ";break;} + case TMDL_ERR_DLHDMICEC_RESOURCE_OWNED: {return "Resource is already in use";break;} + case TMDL_ERR_DLHDMICEC_RESOURCE_NOT_OWNED: {return "Caller does not own resource";break;} + case TMDL_ERR_DLHDMICEC_INCONSISTENT_PARAMS: {return "Inconsistent input params";break;} + case TMDL_ERR_DLHDMICEC_NOT_INITIALIZED: {return "Component is not initializ";break;} + case TMDL_ERR_DLHDMICEC_NOT_SUPPORTED: {return "Function is not supported";break;} + case TMDL_ERR_DLHDMICEC_INIT_FAILED: {return "Initialization failed";break;} + case TMDL_ERR_DLHDMICEC_BUSY: {return "Component is busy";break;} + case TMDL_ERR_DLHDMICEC_I2C_READ: {return "Read error";break;} + case TMDL_ERR_DLHDMICEC_I2C_WRITE: {return "Write error";break;} + case TMDL_ERR_DLHDMICEC_FULL: {return "Queue is full";break;} + case TMDL_ERR_DLHDMICEC_NOT_STARTED: {return "Function is not started";break;} + case TMDL_ERR_DLHDMICEC_ALREADY_STARTED: {return "Function is already starte";break;} + case TMDL_ERR_DLHDMICEC_ASSERTION: {return "Assertion failure";break;} + case TMDL_ERR_DLHDMICEC_INVALID_STATE: {return "Invalid state for function";break;} + case TMDL_ERR_DLHDMICEC_OPERATION_NOT_PERMITTED: {return "Corresponds to posix EPERM";break;} + default : {return "Unexpected error";break;} + } +} + +char *cec_opcode(int op) +{ + switch (op) + { + case CEC_OPCODE_FEATURE_ABORT: {return "CEC_OPCODE_FEATURE_ABORT";break;} + case CEC_OPCODE_IMAGE_VIEW_ON: {return "CEC_OPCODE_IMAGE_VIEW_ON";break;} + case CEC_OPCODE_TUNER_STEP_INCREMENT: {return "CEC_OPCODE_TUNER_STEP_INCREMENT";break;} + case CEC_OPCODE_TUNER_STEP_DECREMENT: {return "CEC_OPCODE_TUNER_STEP_DECREMENT";break;} + case CEC_OPCODE_TUNER_DEVICE_STATUS: {return "CEC_OPCODE_TUNER_DEVICE_STATUS";break;} + case CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS: {return "CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS";break;} + case CEC_OPCODE_RECORD_ON: {return "CEC_OPCODE_RECORD_ON";break;} + case CEC_OPCODE_RECORD_STATUS: {return "CEC_OPCODE_RECORD_STATUS";break;} + case CEC_OPCODE_RECORD_OFF: {return "CEC_OPCODE_RECORD_OFF";break;} + case CEC_OPCODE_TEXT_VIEW_ON: {return "CEC_OPCODE_TEXT_VIEW_ON";break;} + case CEC_OPCODE_RECORD_TV_SCREEN: {return "CEC_OPCODE_RECORD_TV_SCREEN";break;} + case CEC_OPCODE_GIVE_DECK_STATUS: {return "CEC_OPCODE_GIVE_DECK_STATUS";break;} + case CEC_OPCODE_DECK_STATUS: {return "CEC_OPCODE_DECK_STATUS";break;} + case CEC_OPCODE_SET_MENU_LANGUAGE: {return "CEC_OPCODE_SET_MENU_LANGUAGE";break;} + case CEC_OPCODE_CLEAR_ANALOGUE_TIMER: {return "CEC_OPCODE_CLEAR_ANALOGUE_TIMER";break;} + case CEC_OPCODE_SET_ANALOGUE_TIMER: {return "CEC_OPCODE_SET_ANALOGUE_TIMER";break;} + case CEC_OPCODE_TIMER_STATUS: {return "CEC_OPCODE_TIMER_STATUS";break;} + case CEC_OPCODE_STANDBY: {return "CEC_OPCODE_STANDBY";break;} + case CEC_OPCODE_PLAY: {return "CEC_OPCODE_PLAY";break;} +/* case CEC_OPCODE_DECK_CONTROL: {return "CEC_OPCODE_DECK_CONTROL";break;} */ + case CEC_OPCODE_TIMER_CLEARED_STATUS: {return "CEC_OPCODE_TIMER_CLEARED_STATUS";break;} + case CEC_OPCODE_USER_CONTROL_PRESSED: {return "CEC_OPCODE_USER_CONTROL_PRESSED";break;} + case CEC_OPCODE_USER_CONTROL_RELEASED: {return "CEC_OPCODE_USER_CONTROL_RELEASED";break;} + case CEC_OPCODE_GIVE_OSD_NAME: {return "CEC_OPCODE_GIVE_OSD_NAME";break;} + case CEC_OPCODE_SET_OSD_NAME: {return "CEC_OPCODE_SET_OSD_NAME";break;} + case CEC_OPCODE_SET_OSD_STRING: {return "CEC_OPCODE_SET_OSD_STRING";break;} + case CEC_OPCODE_SET_TIMER_PROGRAM_TITLE: {return "CEC_OPCODE_SET_TIMER_PROGRAM_TITLE";break;} + case CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST: {return "CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST";break;} + case CEC_OPCODE_GIVE_AUDIO_STATUS: {return "CEC_OPCODE_GIVE_AUDIO_STATUS";break;} + case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE: {return "CEC_OPCODE_SET_SYSTEM_AUDIO_MODE";break;} + case CEC_OPCODE_REPORT_AUDIO_STATUS: {return "CEC_OPCODE_REPORT_AUDIO_STATUS";break;} + case CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS: {return "CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS";break;} + case CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS: {return "CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS";break;} + case CEC_OPCODE_ROUTING_CHANGE: {return "CEC_OPCODE_ROUTING_CHANGE";break;} + case CEC_OPCODE_ROUTING_INFORMATION: {return "CEC_OPCODE_ROUTING_INFORMATION";break;} + case CEC_OPCODE_ACTIVE_SOURCE: {return "CEC_OPCODE_ACTIVE_SOURCE";break;} + case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS: {return "CEC_OPCODE_GIVE_PHYSICAL_ADDRESS";break;} + case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS: {return "CEC_OPCODE_REPORT_PHYSICAL_ADDRESS";break;} + case CEC_OPCODE_REQUEST_ACTIVE_SOURCE: {return "CEC_OPCODE_REQUEST_ACTIVE_SOURCE";break;} + case CEC_OPCODE_SET_STREAM_PATH: {return "CEC_OPCODE_SET_STREAM_PATH";break;} + case CEC_OPCODE_DEVICE_VENDOR_ID: {return "CEC_OPCODE_DEVICE_VENDOR_ID";break;} + case CEC_OPCODE_VENDOR_COMMAND: {return "CEC_OPCODE_VENDOR_COMMAND";break;} + case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN: {return "CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN";break;} + case CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP: {return "CEC_OPCODE_VENDOR_REMOTE_BUTTON_UP";break;} + case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID: {return "CEC_OPCODE_GIVE_DEVICE_VENDOR_ID";break;} + case CEC_OPCODE_MENU_REQUEST: {return "CEC_OPCODE_MENU_REQUEST";break;} + case CEC_OPCODE_MENU_STATUS: {return "CEC_OPCODE_MENU_STATUS";break;} + case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS: {return "CEC_OPCODE_GIVE_DEVICE_POWER_STATUS";break;} + case CEC_OPCODE_REPORT_POWER_STATUS: {return "CEC_OPCODE_REPORT_POWER_STATUS";break;} + case CEC_OPCODE_GET_MENU_LANGUAGE: {return "CEC_OPCODE_GET_MENU_LANGUAGE";break;} + case CEC_OPCODE_SET_ANALOGUE_SERVICE: {return "CEC_OPCODE_SET_ANALOGUE_SERVICE";break;} + case CEC_OPCODE_SET_DIGITAL_SERVICE: {return "CEC_OPCODE_SET_DIGITAL_SERVICE";break;} + case CEC_OPCODE_SET_DIGITAL_TIMER: {return "CEC_OPCODE_SET_DIGITAL_TIMER";break;} + case CEC_OPCODE_CLEAR_DIGITAL_TIMER: {return "CEC_OPCODE_CLEAR_DIGITAL_TIMER";break;} + case CEC_OPCODE_SET_AUDIO_RATE: {return "CEC_OPCODE_SET_AUDIO_RATE";break;} + case CEC_OPCODE_INACTIVE_SOURCE: {return "CEC_OPCODE_INACTIVE_SOURCE";break;} + case CEC_OPCODE_CEC_VERSION: {return "CEC_OPCODE_CEC_VERSION";break;} + case CEC_OPCODE_GET_CEC_VERSION: {return "CEC_OPCODE_GET_CEC_VERSION";break;} + case CEC_OPCODE_VENDOR_COMMAND_WITH_ID: {return "CEC_OPCODE_VENDOR_COMMAND_WITH_ID";break;} + case CEC_OPCODE_CLEAR_EXTERNAL_TIMER: {return "CEC_OPCODE_CLEAR_EXTERNAL_TIMER";break;} + case CEC_OPCODE_SET_EXTERNAL_TIMER: {return "CEC_OPCODE_SET_EXTERNAL_TIMER";break;} + case CEC_OPCODE_ABORT_MESSAGE: {return "CEC_OPCODE_ABORT_MESSAGE";break;} + default : {return "unknown";break;} + } +} + + +static char *cec_ioctl(int io) +{ + switch (io) + { + case CEC_VERBOSE_ON_CMD: {return "CEC_VERBOSE_ON_CMD";break;} + case CEC_VERBOSE_OFF_CMD: {return "CEC_VERBOSE_OFF_CMD";break;} + case CEC_BYEBYE_CMD: {return "CEC_BYEBYE_CMD";break;} + case CEC_IOCTL_RX_ADDR_CMD: {return "CEC_IOCTL_RX_ADDR_CMD";break;} + case CEC_IOCTL_PHY_ADDR_CMD: {return "CEC_IOCTL_PHY_ADDR_CMD";break;} + case CEC_IOCTL_WAIT_FRAME_CMD: {return "CEC_IOCTL_WAIT_FRAME_CMD";break;} + case CEC_IOCTL_ABORT_MSG_CMD: {return "CEC_IOCTL_ABORT_MSG_CMD";break;} + case CEC_IOCTL_ACTIVE_SRC_CMD: {return "CEC_IOCTL_ACTIVE_SRC_CMD";break;} + case CEC_IOCTL_VERSION_CMD: {return "CEC_IOCTL_VERSION_CMD";break;} + case CEC_IOCTL_CLEAR_ANALOGUE_TIMER_CMD: {return "CEC_IOCTL_CLEAR_ANALOGUE_TIMER_CMD";break;} + case CEC_IOCTL_CLEAR_DIGITAL_TIMER_CMD: {return "CEC_IOCTL_CLEAR_DIGITAL_TIMER_CMD";break;} + case CEC_IOCTL_CLEAR_EXT_TIMER_WITH_EXT_PLUG_CMD: {return "CEC_IOCTL_CLEAR_EXT_TIMER_WITH_EXT_PLUG_CMD";break;} + case CEC_IOCTL_CLEAR_EXT_TIMER_WITH_PHY_ADDR_CMD: {return "CEC_IOCTL_CLEAR_EXT_TIMER_WITH_PHY_ADDR_CMD";break;} + case CEC_IOCTL_DECK_CTRL_CMD: {return "CEC_IOCTL_DECK_CTRL_CMD";break;} + case CEC_IOCTL_DECK_STATUS_CMD: {return "CEC_IOCTL_DECK_STATUS_CMD";break;} + case CEC_IOCTL_DEVICE_VENDOR_ID_CMD: {return "CEC_IOCTL_DEVICE_VENDOR_ID_CMD";break;} + case CEC_IOCTL_FEATURE_ABORT_CMD: {return "CEC_IOCTL_FEATURE_ABORT_CMD";break;} + case CEC_IOCTL_GET_CEC_VERSION_CMD: {return "CEC_IOCTL_GET_CEC_VERSION_CMD";break;} + case CEC_IOCTL_GET_MENU_LANGUAGE_CMD: {return "CEC_IOCTL_GET_MENU_LANGUAGE_CMD";break;} + case CEC_IOCTL_GIVE_AUDIO_STATUS_CMD: {return "CEC_IOCTL_GIVE_AUDIO_STATUS_CMD";break;} + case CEC_IOCTL_GIVE_DECK_STATUS_CMD: {return "CEC_IOCTL_GIVE_DECK_STATUS_CMD";break;} + case CEC_IOCTL_GIVE_DEVICE_POWER_STATUS_CMD: {return "CEC_IOCTL_GIVE_DEVICE_POWER_STATUS_CMD";break;} + case CEC_IOCTL_GIVE_DEVICE_VENDOR_ID_CMD: {return "CEC_IOCTL_GIVE_DEVICE_VENDOR_ID_CMD";break;} + case CEC_IOCTL_GIVE_OSD_NAME_CMD: {return "CEC_IOCTL_GIVE_OSD_NAME_CMD";break;} + case CEC_IOCTL_GIVE_PHY_ADDR_CMD: {return "CEC_IOCTL_GIVE_PHY_ADDR_CMD";break;} + case CEC_IOCTL_GIVE_SYS_AUDIO_MODE_STATUS_CMD: {return "CEC_IOCTL_GIVE_SYS_AUDIO_MODE_STATUS_CMD";break;} + case CEC_IOCTL_GIVE_TUNER_DEVICE_STATUS_CMD: {return "CEC_IOCTL_GIVE_TUNER_DEVICE_STATUS_CMD";break;} + case CEC_IOCTL_IMAGE_VIEW_ON_CMD: {return "CEC_IOCTL_IMAGE_VIEW_ON_CMD";break;} + case CEC_IOCTL_INACTIVE_SRC_CMD: {return "CEC_IOCTL_INACTIVE_SRC_CMD";break;} + case CEC_IOCTL_MENU_REQUEST_CMD: {return "CEC_IOCTL_MENU_REQUEST_CMD";break;} + case CEC_IOCTL_MENU_STATUS_CMD: {return "CEC_IOCTL_MENU_STATUS_CMD";break;} + case CEC_IOCTL_PLAY_CMD: {return "CEC_IOCTL_PLAY_CMD";break;} + case CEC_IOCTL_POLLING_MSG_CMD: {return "CEC_IOCTL_POLLING_MSG_CMD";break;} + case CEC_IOCTL_REC_OFF_CMD: {return "CEC_IOCTL_REC_OFF_CMD";break;} + case CEC_IOCTL_REC_ON_ANALOGUE_SERVICE_CMD: {return "CEC_IOCTL_REC_ON_ANALOGUE_SERVICE_CMD";break;} + case CEC_IOCTL_REC_ON_DIGITAL_SERVICE_CMD: {return "CEC_IOCTL_REC_ON_DIGITAL_SERVICE_CMD";break;} + case CEC_IOCTL_REC_ON_EXT_PHY_ADDR_CMD: {return "CEC_IOCTL_REC_ON_EXT_PHY_ADDR_CMD";break;} + case CEC_IOCTL_REC_ON_EXT_PLUG_CMD: {return "CEC_IOCTL_REC_ON_EXT_PLUG_CMD";break;} + case CEC_IOCTL_REC_ON_OWN_SRC_CMD: {return "CEC_IOCTL_REC_ON_OWN_SRC_CMD";break;} + case CEC_IOCTL_REC_STATUS_CMD: {return "CEC_IOCTL_REC_STATUS_CMD";break;} + case CEC_IOCTL_REC_TV_SCREEN_CMD: {return "CEC_IOCTL_REC_TV_SCREEN_CMD";break;} + case CEC_IOCTL_REPORT_AUDIO_STATUS_CMD: {return "CEC_IOCTL_REPORT_AUDIO_STATUS_CMD";break;} + case CEC_IOCTL_REPORT_PHY_ADDR_CMD: {return "CEC_IOCTL_REPORT_PHY_ADDR_CMD";break;} + case CEC_IOCTL_REPORT_POWER_STATUS_CMD: {return "CEC_IOCTL_REPORT_POWER_STATUS_CMD";break;} + case CEC_IOCTL_REQUEST_ACTIVE_SRC_CMD: {return "CEC_IOCTL_REQUEST_ACTIVE_SRC_CMD";break;} + case CEC_IOCTL_ROUTING_CHANGE_CMD: {return "CEC_IOCTL_ROUTING_CHANGE_CMD";break;} + case CEC_IOCTL_ROUTING_INFORMATION_CMD: {return "CEC_IOCTL_ROUTING_INFORMATION_CMD";break;} + case CEC_IOCTL_SELECT_ANALOGUE_SERVICE_CMD: {return "CEC_IOCTL_SELECT_ANALOGUE_SERVICE_CMD";break;} + case CEC_IOCTL_SELECT_DIGITAL_SERVICE_CMD: {return "CEC_IOCTL_SELECT_DIGITAL_SERVICE_CMD";break;} + case CEC_IOCTL_SET_ANALOGUE_TIMER_CMD: {return "CEC_IOCTL_SET_ANALOGUE_TIMER_CMD";break;} + case CEC_IOCTL_SET_AUDIO_RATE_CMD: {return "CEC_IOCTL_SET_AUDIO_RATE_CMD";break;} + case CEC_IOCTL_SET_DIGITAL_TIMER_CMD: {return "CEC_IOCTL_SET_DIGITAL_TIMER_CMD";break;} + case CEC_IOCTL_SET_EXT_TIMER_WITH_EXT_PLUG_CMD: {return "CEC_IOCTL_SET_EXT_TIMER_WITH_EXT_PLUG_CMD";break;} + case CEC_IOCTL_SET_EXT_TIMER_WITH_PHY_ADDR_CMD: {return "CEC_IOCTL_SET_EXT_TIMER_WITH_PHY_ADDR_CMD";break;} + case CEC_IOCTL_SET_MENU_LANGUAGE_CMD: {return "CEC_IOCTL_SET_MENU_LANGUAGE_CMD";break;} + case CEC_IOCTL_SET_OSD_NAME_CMD: {return "CEC_IOCTL_SET_OSD_NAME_CMD";break;} + case CEC_IOCTL_SET_OSD_STRING_CMD: {return "CEC_IOCTL_SET_OSD_STRING_CMD";break;} + case CEC_IOCTL_SET_STREAM_PATH_CMD: {return "CEC_IOCTL_SET_STREAM_PATH_CMD";break;} + case CEC_IOCTL_SET_SYS_AUDIO_MODE_CMD: {return "CEC_IOCTL_SET_SYS_AUDIO_MODE_CMD";break;} + case CEC_IOCTL_SET_TIMER_PROGRAM_TITLE_CMD: {return "CEC_IOCTL_SET_TIMER_PROGRAM_TITLE_CMD";break;} + case CEC_IOCTL_STANDBY_CMD: {return "CEC_IOCTL_STANDBY_CMD";break;} + case CEC_IOCTL_SYS_AUDIO_MODE_REQUEST_CMD: {return "CEC_IOCTL_SYS_AUDIO_MODE_REQUEST_CMD";break;} + case CEC_IOCTL_SYS_AUDIO_MODE_STATUS_CMD: {return "CEC_IOCTL_SYS_AUDIO_MODE_STATUS_CMD";break;} + case CEC_IOCTL_TEXT_VIEW_ON_CMD: {return "CEC_IOCTL_TEXT_VIEW_ON_CMD";break;} + case CEC_IOCTL_TIMER_CLEARED_STATUS_CMD: {return "CEC_IOCTL_TIMER_CLEARED_STATUS_CMD";break;} + case CEC_IOCTL_TIMER_STATUS_CMD: {return "CEC_IOCTL_TIMER_STATUS_CMD";break;} + case CEC_IOCTL_TUNER_DEVICE_STATUS_ANALOGUE_CMD: {return "CEC_IOCTL_TUNER_DEVICE_STATUS_ANALOGUE_CMD";break;} + case CEC_IOCTL_TUNER_DEVICE_STATUS_DIGITAL_CMD: {return "CEC_IOCTL_TUNER_DEVICE_STATUS_DIGITAL_CMD";break;} + case CEC_IOCTL_TUNER_STEP_DECREMENT_CMD: {return "CEC_IOCTL_TUNER_STEP_DECREMENT_CMD";break;} + case CEC_IOCTL_TUNER_STEP_INCREMENT_CMD: {return "CEC_IOCTL_TUNER_STEP_INCREMENT_CMD";break;} + case CEC_IOCTL_USER_CTRL_CMD: {return "CEC_IOCTL_USER_CTRL_CMD";break;} + case CEC_IOCTL_USER_CTRL_PLAY_CMD: {return "CEC_IOCTL_USER_CTRL_PLAY_CMD";break;} + case CEC_IOCTL_USER_CTRL_SELECT_AUDIOINPUT_CMD: {return "CEC_IOCTL_USER_CTRL_SELECT_AUDIOINPUT_CMD";break;} + case CEC_IOCTL_USER_CTRL_SELECT_AVINPUT_CMD: {return "CEC_IOCTL_USER_CTRL_SELECT_AVINPUT_CMD";break;} + case CEC_IOCTL_USER_CTRL_SELECT_MEDIA_CMD: {return "CEC_IOCTL_USER_CTRL_SELECT_MEDIA_CMD";break;} + case CEC_IOCTL_USER_CTRL_TUNE_CMD: {return "CEC_IOCTL_USER_CTRL_TUNE_CMD";break;} + case CEC_IOCTL_USER_CTRL_RELEASED_CMD: {return "CEC_IOCTL_USER_CTRL_RELEASED_CMD";break;} + case CEC_IOCTL_VENDOR_COMMAND_CMD: {return "CEC_IOCTL_VENDOR_COMMAND_CMD";break;} + case CEC_IOCTL_VENDOR_COMMAND_WITH_ID_CMD: {return "CEC_IOCTL_VENDOR_COMMAND_WITH_ID_CMD";break;} + case CEC_IOCTL_VENDOR_REMOTE_BUTTON_DOWN_CMD: {return "CEC_IOCTL_VENDOR_REMOTE_BUTTON_DOWN_CMD";break;} + case CEC_IOCTL_VENDOR_REMOTE_BUTTON_UP_CMD: {return "CEC_IOCTL_VENDOR_REMOTE_BUTTON_UP_CMD";break;} + case CEC_IOCTL_GET_SW_VERSION_CMD: {return "CEC_IOCTL_GET_SW_VERSION_CMD";break;} + case CEC_IOCTL_SET_POWER_STATE_CMD: {return "CEC_IOCTL_SET_POWER_STATE_CMD";break;} + case CEC_IOCTL_GET_POWER_STATE_CMD: {return "CEC_IOCTL_GET_POWER_STATE_CMD";break;} + case CEC_IOCTL_INSTANCE_CONFIG_CMD: {return "CEC_IOCTL_INSTANCE_CONFIG_CMD";break;} + case CEC_IOCTL_INSTANCE_SETUP_CMD: {return "CEC_IOCTL_INSTANCE_SETUP_CMD";break;} + case CEC_IOCTL_GET_INSTANCE_SETUP_CMD: {return "CEC_IOCTL_GET_INSTANCE_SETUP_CMD";break;} + case CEC_IOCTL_ENABLE_EVENT_CMD: {return "CEC_IOCTL_ENABLE_EVENT_CMD";break;} + case CEC_IOCTL_DISABLE_EVENT_CMD: {return "CEC_IOCTL_DISABLE_EVENT_CMD";break;} + case CEC_IOCTL_ENABLE_CALIBRATION_CMD: {return "CEC_IOCTL_ENABLE_CALIBRATION_CMD";break;} + case CEC_IOCTL_DISABLE_CALIBRATION_CMD: {return "CEC_IOCTL_DISABLE_CALIBRATION_CMD";break;} + case CEC_IOCTL_SEND_MSG_CMD: {return "CEC_IOCTL_SEND_MSG_CMD";break;} + case CEC_IOCTL_SET_REGISTER_CMD: {return "CEC_IOCTL_SET_REGISTER_CMD";break;} + default : {return "unknown";break;} + } +} + + +static char *cec_rxstatus(int s) +{ + switch (s) + { + case CEC_MSG_SUCCESS :{return "success";break;} + case CEC_MSG_FAIL_DATA_NOT_ACK :{return "data not ack";break;} + case CEC_CSP_OFF_STATE :{return "CSP off";break;} + case CEC_BAD_REQ_SERVICE :{return "bad Req";break;} + case CEC_MSG_FAIL_UNABLE_TO_ACCESS :{return "CEC line error";break;} + case CEC_MSG_FAIL_ARBITRATION_ERROR :{return "arb error";break;} + case CEC_MSG_FAIL_BIT_TIMMING_ERROR :{return "bit error";break;} + case CEC_MSG_FAIL_DEST_NOT_ACK :{return "destination not ack";break;} + default : {return "unknown";break;} + } +} + + +static unsigned char get_next_logical_addr(cec_device_type device,unsigned char la) +{ + switch (device) { + case CEC_DEVICE_TYPE_TV: + switch (la) { + case CEC_LOGICAL_ADDRESS_TV: + return CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + default: + return CEC_LOGICAL_ADDRESS_TV; + } + case CEC_DEVICE_TYPE_REC_DEVICE: + switch (la) { + case CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_1: + return CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_2; + case CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_2: + return CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_3; + case CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_3: + return CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + default: + return CEC_LOGICAL_ADDRESS_RECORDING_DEVICE_1; + } + case CEC_DEVICE_TYPE_TUNER: + switch (la) { + case CEC_LOGICAL_ADDRESS_TUNER_1: + return CEC_LOGICAL_ADDRESS_TUNER_2; + case CEC_LOGICAL_ADDRESS_TUNER_2: + return CEC_LOGICAL_ADDRESS_TUNER_3; + case CEC_LOGICAL_ADDRESS_TUNER_3: + return CEC_LOGICAL_ADDRESS_TUNER_4; + case CEC_LOGICAL_ADDRESS_TUNER_4: + return CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + default: + return CEC_LOGICAL_ADDRESS_TUNER_1; + } + case CEC_DEVICE_TYPE_PLAYBACK_DEVICE: + switch (la) { + case CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_1: + return CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_2; + case CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_2: + return CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_3; + case CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_3: + return CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + default: + return CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_1; + } + case CEC_DEVICE_TYPE_AUDIO_DEVICE: + switch (la) { + case CEC_LOGICAL_ADDRESS_AUDIO_SYSTEM: + return CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + default: + return CEC_LOGICAL_ADDRESS_AUDIO_SYSTEM; + } + default: + return CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + } +} + +static int device_type(int type) +{ + printk(KERN_INFO "hdmicec declared as a "); + switch (type) { + case CEC_DEVICE_TYPE_TV: + printk("TV"); + break; + case CEC_DEVICE_TYPE_REC_DEVICE: + printk("record"); + break; + case CEC_DEVICE_TYPE_TUNER: + printk("tuner"); + break; + case CEC_DEVICE_TYPE_PLAYBACK_DEVICE: + printk("playback"); + break; + case CEC_DEVICE_TYPE_AUDIO_DEVICE: + printk("audio"); + break; + default: + printk("default (playback)"); + type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE; + break; + } + printk(" device type\n"); + return type; +} + + +/* + * + * PROCESSING + * ---------- + * LEVEL 2 + * + */ + + +/* + * CEC Power On + */ +static void cec_on(cec_instance *this) +{ + int err; + struct task_struct *tsk = current; + + // disable_irq(gpio_to_irq(TDA_IRQ_CALIB)); + + this->cec.power = tmPowerOn; + TRY(tmdlHdmiCecSetPowerState(this->cec.inst,this->cec.power)); + + /* turn GPIO into calib pulse generator */ + gpio_direction_output(TDA_IRQ_CALIB,0); /* output (1 means try-state or high) */ + __gpio_set_value(TDA_IRQ_CALIB,1); + this->cec.clock = TMDL_HDMICEC_CLOCK_FRO; + TRY(tmdlHdmiCecEnableCalibration(this->cec.inst,this->cec.clock)); + msleep(10); + set_current_state(TASK_UNINTERRUPTIBLE); + + /* CAUTION : TDA needs a real 10ms pulse */ + cpu_relax(); + spin_lock_irq(&tsk->sighand->siglock); + __gpio_set_value(TDA_IRQ_CALIB,0); + __udelay(10000); + __gpio_set_value(TDA_IRQ_CALIB,1); + spin_unlock_irq(&tsk->sighand->siglock); + + msleep(10); + TRY(tmdlHdmiCecDisableCalibration(this->cec.inst)); + + /* setup */ + TRY(tmdlHdmiCecGetInstanceSetup(this->cec.inst,&this->cec.setup)); + this->cec.setup.DeviceLogicalAddress = this->cec.rx_addr; + this->cec.clock = TMDL_HDMICEC_CLOCK_FRO; + this->cec.setup.cecClockSource = this->cec.clock; + TRY(tmdlHdmiCecInstanceSetup(this->cec.inst,&this->cec.setup)); + + /* turn GPIO into IRQ */ + gpio_direction_input(TDA_IRQ_CALIB); + // enable_irq(gpio_to_irq(TDA_IRQ_CALIB)); + + LOG(KERN_INFO,"standby --> on\n"); + + TRY_DONE: + (void)0; +} + +/* + * CEC Power Off + */ +static void cec_standby(cec_instance *this) +{ + int err; + + this->cec.power = tmPowerStandby; + TRY(tmdlHdmiCecSetPowerState(this->cec.inst,this->cec.power)); + + LOG(KERN_INFO,"on --> standby\n"); + + TRY_DONE: + (void)0; +} + +/* + * CEC interrupt polling + */ +static void cec_interrupt(struct work_struct *dummy) +{ + cec_instance *this=&our_instance; + unsigned short new_phy_addr=edid_phy_addr(); + int err=0; + + LOG(KERN_INFO,"%s called\n",__func__); + + /* switch on/off CEC */ + if (!get_hpd_status() && \ + (this->cec.power == tmPowerOn)) { + this->cec.source_status = CEC_POWER_STATUS_STANDBY; +/* TRY(tmdlHdmiCecInactiveSource(this->cec.inst, \ */ +/* this->cec.initiator, \ */ +/* this->cec.phy_addr)); */ + cec_standby(this); + } + else if (get_hpd_status() && \ + (this->cec.power == tmPowerStandby)) { + /* send active msg when hdmi has been abled */ + cec_on(this); + } + /* new phy addr means new EDID, mean HPD ! */ + else if ((this->cec.phy_addr != new_phy_addr) && \ + (this->cec.source_status == CEC_POWER_STATUS_ON)) { + LOG(KERN_INFO,"New physical address %02x\n",new_phy_addr); + this->cec.phy_addr = new_phy_addr; + if (this->cec.phy_addr != 0xFFFF) { + this->cec.rx_addr = get_next_logical_addr(this->cec.device_type,CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST); + TRY(tmdlHdmiCecPollingMessage(this->cec.inst,this->cec.rx_addr)); + } + else { + this->cec.rx_addr = CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + } + } +#ifdef GUI_OVER_HDMI + else if (edid_received()) { /* Check me */ + if (this->cec.source_status == CEC_POWER_STATUS_STANDBY) { + /* only for GFX on HDMI, do not use if only video playback on HDMI */ + TRY(tmdlHdmiCecImageViewOn(this->cec.inst,this->cec.initiator)); + TRY(tmdlHdmiCecHandleInterrupt(this->cec.inst)); + msleep(200); + TRY(tmdlHdmiCecActiveSource(this->cec.inst,this->cec.phy_addr)); + this->cec.source_status = CEC_POWER_STATUS_ON; + } + } +#endif + +#if 0 + if (this->cec.phy_addr != 0xFFFF) { + + /* claim source status */ + if ((get_hdmi_status() == tmPowerStandby) && \ + (this->cec.source_status == CEC_POWER_STATUS_ON)) { + /* send inactive msg when hdmi has been disabled */ + this->cec.source_status = CEC_POWER_STATUS_STANDBY; + TRY(tmdlHdmiCecInactiveSource(this->cec.inst, \ + this->cec.initiator, \ + this->cec.phy_addr)); + } + else if ((get_hdmi_status() == tmPowerOn) && \ + (this->cec.source_status == CEC_POWER_STATUS_STANDBY)) { + /* send active msg when hdmi has been abled */ + this->cec.source_status = CEC_POWER_STATUS_ON; + TRY(tmdlHdmiCecActiveSource(this->cec.inst, \ + this->cec.phy_addr)); + } +/* printk(KERN_INFO "DBG phd_status:%s cec.power:%s\n", \ */ +/* get_hpd_status()?"Active":"Inactive", \ */ +/* (this->cec.power==tmPowerOn)?"On":"Standby"); */ + } +#endif + + /* internal handeling */ + TRY(tmdlHdmiCecHandleInterrupt(this->cec.inst)); + + TRY_DONE: + + /* setup next tick */ + if (!this->driver.deinit_req) { + /* setup next polling */ +#ifndef IRQ +/* this->driver.timer.expires = jiffies + ( CHECK_EVERY_XX_MS * HZ / 1000 ); */ +/* add_timer(&this->driver.timer); */ + mod_timer(&this->driver.timer,jiffies + ( CHECK_EVERY_XX_MS * HZ / 1000 )); +#endif + } + else { + this->driver.deinit_req++; + wake_up_interruptible(&this->driver.wait); + } +} + +#ifndef IRQ +static DECLARE_WORK(wq_name, cec_interrupt); + +void polling_timeout(unsigned long arg) +{ + +#if 0 + /* fake frame for equipement-less testing */ + + cec_instance *this=&our_instance; + + if (this->driver.timer.data++>1000) { + printk(KERN_INFO "Fake Rx message\n"); + this->driver.timer.data=0; + + this->cec.frame.count = 4; + this->cec.frame.addr = 4; /* 0-->4 (TV-->MediaPlayer1) */ + this->cec.frame.data[0]=0x46; /* opcode: "GiveOsd" */ + this->cec.frame.service = CEC_RX_DONE; + + this->driver.poll_done = true; + wake_up_interruptible(&this->driver.wait); + } +#endif + + /* derefered because ATOMIC context of timer does not support I2C_transfert */ + schedule_work(&wq_name); + +} +#endif + +#ifndef IRQ +/* + * TDA irq + */ +static irqreturn_t tda_irq(int irq, void *_udc) +{ + cec_instance *this=&our_instance; + /* printk(KERN_INFO "DBG caught irq:%d\n",irq); */ + + /* do it now */ + mod_timer(&this->driver.timer,jiffies); + + return IRQ_HANDLED; +} +#endif + +#ifdef TWL4030_HACK +/* + * User Control + */ +static void user_control(int key, int press) +{ + input_report_key(gkp_input, key, press); + input_sync(gkp_input); + msleep(20); + input_report_key(gkp_input, key, 0); + input_sync(gkp_input); +} +#endif + +/* + * CEC callback + */ +static void eventCallbackCEC(tmdlHdmiCecEvent_t event, unsigned char *data, unsigned char length) +{ + int err=0; + cec_instance *this=&our_instance; + int opcode; + int initiator,receiver; + + if (event == TMDL_HDMICEC_CALLBACK_MESSAGE_AVAILABLE) { + + this->cec.frame.count = length; + this->cec.frame.addr = data[1]; /* .AddressByte */ + initiator = (this->cec.frame.addr >> 4) & 0x0F; + this->cec.initiator = initiator; + receiver = this->cec.frame.addr & 0x0F; + memcpy(&this->cec.frame.data,&data[2],length-2); /* .DataBytes[], length - siezof(length,addr,ack) */ + opcode=this->cec.frame.data[0]; + printk(KERN_INFO "hdmicec:Rx:[%x--->%x] %s length:%d addr:%d %02x%02x%02x%02x\n",initiator,receiver,cec_opcode(opcode), \ + length,data[1], + this->cec.frame.data[0], \ + this->cec.frame.data[1], \ + this->cec.frame.data[2], \ + this->cec.frame.data[3]); + this->cec.frame.service = CEC_RX_DONE; + + msleep(20); + + /* automatic answering */ + switch (opcode) { + case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS: + TRY(tmdlHdmiCecReportPhysicalAddress(this->cec.inst, \ + this->cec.phy_addr, \ + this->cec.device_type)); + break; + case CEC_OPCODE_GET_CEC_VERSION: + TRY(tmdlHdmiCecVersion(this->cec.inst, \ + this->cec.initiator, \ + this->cec.version)); + break; + case CEC_OPCODE_GIVE_OSD_NAME: + TRY(tmdlHdmiCecSetOsdName(this->cec.inst, \ + this->cec.initiator, \ + this->cec.osd_name.data, \ + this->cec.osd_name.length)); + break; + case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID: + TRY(tmdlHdmiCecDeviceVendorID(this->cec.inst, \ + this->cec.vendor_id)); + break; + case CEC_OPCODE_REQUEST_ACTIVE_SOURCE: + if (this->cec.source_status == CEC_POWER_STATUS_ON) { + if (this->cec.initiator != 0x0F) { + if (receiver == 0x0F) { + TRY(tmdlHdmiCecActiveSource(this->cec.inst,this->cec.phy_addr)); + } + } + } + break; + case CEC_OPCODE_ACTIVE_SOURCE: + if (this->cec.source_status == CEC_POWER_STATUS_ON) { + this->cec.source_status = CEC_POWER_STATUS_STANDBY; + hdmi_disable(1); + this->cec.power = tmPowerOn; + TRY(tmdlHdmiCecSetPowerState(this->cec.inst,this->cec.power)); /* keeps CEC alive */ + } + break; + case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS: + TRY(tmdlHdmiCecReportPowerStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.source_status)); + break; + case CEC_OPCODE_STANDBY: + /* mind recording device can only be stopped by appli */ + if (this->cec.device_type != CEC_DEVICE_TYPE_REC_DEVICE) { + this->cec.source_status = CEC_POWER_STATUS_STANDBY; + hdmi_disable(1); + this->cec.power = tmPowerOn; + TRY(tmdlHdmiCecSetPowerState(this->cec.inst,this->cec.power)); /* keeps CEC alive */ + } + break; + case CEC_OPCODE_ROUTING_INFORMATION: + case CEC_OPCODE_SET_STREAM_PATH: + /* wake-up if called */ + if (this->cec.phy_addr == (((int)this->cec.frame.data[1] << 8) + this->cec.frame.data[2])) { + if (this->cec.source_status != CEC_POWER_STATUS_ON) { + this->cec.source_status = CEC_POWER_STATUS_ON; + hdmi_enable(); + } + TRY(tmdlHdmiCecActiveSource(this->cec.inst,this->cec.phy_addr)); + } + break; +/* case /\* NEW DECK ??? *\/ */ + case CEC_OPCODE_ROUTING_CHANGE: + /* wake-up if called */ + if (this->cec.phy_addr == (((int)this->cec.frame.data[3] << 8) + this->cec.frame.data[4])) { + if (this->cec.source_status != CEC_POWER_STATUS_ON) { + this->cec.source_status = CEC_POWER_STATUS_ON; + hdmi_enable(); + } + TRY(tmdlHdmiCecActiveSource(this->cec.inst,this->cec.phy_addr)); + } + break; + case CEC_OPCODE_ABORT_MESSAGE: + if (this->cec.phy_addr == (((int)this->cec.frame.data[3] << 8) + this->cec.frame.data[4])) { + TRY(tmdlHdmiCecFeatureAbort(this->cec.inst, \ + this->cec.initiator, \ + this->cec.feature_abort.FeatureOpcode, \ + this->cec.feature_abort.AbortReason)); + } + break; + case CEC_OPCODE_MENU_REQUEST: +#ifdef TWL4030_HACK + this->cec.menu_status = CEC_MENU_STATE_ACTIVATE; + TRY(tmdlHdmiCecMenuStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.menu_status)); + break; +#endif + case CEC_OPCODE_USER_CONTROL_PRESSED: + switch (this->cec.frame.data[1]) { +#ifdef TWL4030_HACK /* AL : hack to bypass keypad */ + case CEC_REMOTE_BUTTON_SELECT: + user_control(353,64); + break; + case CEC_REMOTE_BUTTON_UP: + user_control(103,128); + break; + case CEC_REMOTE_BUTTON_DOWN: + user_control(108,128); + break; + case CEC_REMOTE_BUTTON_LEFT: + user_control(105,128); + break; + case CEC_REMOTE_BUTTON_RIGHT: + user_control(106,128); + break; + case CEC_REMOTE_BUTTON_EXIT: + user_control(14,8); + break; +#endif + case CEC_REMOTE_BUTTON_POWER: + this->cec.source_status = CEC_POWER_STATUS_ON; + hdmi_enable(); + break; + default: + this->cec.feature_abort.FeatureOpcode=opcode; + this->cec.feature_abort.AbortReason=CEC_ABORT_INVALID_OPERAND; + TRY(tmdlHdmiCecFeatureAbort(this->cec.inst, \ + this->cec.initiator, \ + this->cec.feature_abort.FeatureOpcode, \ + this->cec.feature_abort.AbortReason)); + break; + } + break; +#ifdef TWL4030_HACK + case CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN: + user_control(59,8); +#endif + break; + case CEC_OPCODE_FEATURE_ABORT: + /* stop any state machine transition */ + break; + case CEC_OPCODE_VENDOR_COMMAND: + case CEC_OPCODE_DEVICE_VENDOR_ID: + /* hopefully will be handle in userspace */ + break; + default: + if (receiver != 0x0F) { + this->cec.feature_abort.FeatureOpcode=opcode; + this->cec.feature_abort.AbortReason=CEC_ABORT_UNKNOWN_OPCODE; + TRY(tmdlHdmiCecFeatureAbort(this->cec.inst, \ + this->cec.initiator, \ + this->cec.feature_abort.FeatureOpcode, \ + this->cec.feature_abort.AbortReason)); + } + break; + } + this->driver.poll_done = true; + wake_up_interruptible(&this->driver.wait); + } + else if (event == TMDL_HDMICEC_CALLBACK_STATUS) { + + this->cec.frame.count = length; + this->cec.frame.addr = data[1]; /* .AddressByte */ + initiator = (this->cec.frame.addr >> 4) & 0x0F; + receiver = this->cec.frame.addr & 0x0F; + memcpy(&this->cec.frame.data,&data[2],length-2); /* .DataBytes[], length - siezof(length,addr) */ + opcode=this->cec.frame.data[0]; + this->cec.frame.service = CEC_TX_DONE; + + if (length==POLLING_LENGTH) { + if (opcode == CEC_MSG_FAIL_DEST_NOT_ACK) { + /* no echo means it's mine ! */ + TRY(tmdlHdmiCecSetLogicalAddress(this->cec.inst,this->cec.rx_addr)); + TRY(tmdlHdmiCecReportPhysicalAddress(this->cec.inst, \ + this->cec.phy_addr, \ + this->cec.device_type)); + /* DEVICE VENDOR ID sending after logicial address allocation according to spec 1.4 */ + TRY(tmdlHdmiCecDeviceVendorID(this->cec.inst, this->cec.vendor_id)); + } + else if (opcode == CEC_MSG_SUCCESS) { + /* try next one */ + this->cec.rx_addr=get_next_logical_addr(this->cec.device_type,this->cec.rx_addr); + if (this->cec.rx_addr != CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST) { + TRY(tmdlHdmiCecPollingMessage(this->cec.inst,this->cec.rx_addr)); + } + else { + /* no more room, keep and claim unregistred */ + TRY(tmdlHdmiCecSetLogicalAddress(this->cec.inst,this->cec.rx_addr)); + TRY(tmdlHdmiCecReportPhysicalAddress(this->cec.inst, \ + this->cec.phy_addr, \ + this->cec.device_type)); + } + } + else { + printk(KERN_INFO "ACK [%x--->%x] %s\n",initiator,receiver,cec_rxstatus(opcode)); + } + } + else { + if (CEC_MSG_SUCCESS != opcode) { + printk(KERN_INFO "ACK [%x--->%x] %s\n",initiator,receiver,cec_rxstatus(opcode)); + } + } + + this->driver.poll_done = true; + wake_up_interruptible(&this->driver.wait); + + } + else { + LOG(KERN_ERR,"Oups ! Callback got invalid event %d !\n",event); + } + + TRY_DONE: + (void)err; +} + +/* + * DevLib CEC opening + */ +static int hdmi_cec_init(cec_instance *this) +{ + int err=0; + + /* Real opening */ + TRY(tmdlHdmiCecOpen(&this->cec.inst)); + +/* this->cec.vendor_id = 0x006037; /\* NXP (IEEE OUI) *\/ */ +/* this->cec.vendor_id = 0x0000f0; /\* Samsung *\/ */ + this->cec.vendor_id = 0x00e091; /* LGE */ + +/* this->cec.version = CEC_VERSION_1_4; */ + this->cec.version = CEC_VERSION_1_3a; + this->cec.osd_name.data[0]=0x54; /* TDA19989 by default */ + this->cec.osd_name.data[1]=0x44; + this->cec.osd_name.data[2]=0x41; + this->cec.osd_name.data[3]=0x31; + this->cec.osd_name.data[4]=0x39; + this->cec.osd_name.data[5]=0x39; + this->cec.osd_name.data[6]=0x38; + this->cec.osd_name.data[7]=0x39; + this->cec.osd_name.length=8; + + TRY(tmdlHdmiCecRegisterCallbacks(this->cec.inst,eventCallbackCEC)); + + this->cec.phy_addr = param_addr; + this->cec.device_type = device_type(param_device); + + TRY_DONE: + return err; +} + + +/* + * + * ENTRY POINTS + * ------------ + * LEVEL 3 + * + * - + * + */ + + + +/* + * ioctl driver :: opening + */ + +static int this_cdev_open(struct inode *pInode, struct file *pFile) +{ + cec_instance *this; + int minor=iminor(pInode); + + if(minor >= MAX_MINOR) { + printk(KERN_ERR "hdmicec:%s:only one cec opening please\n",__func__); + return -EINVAL; + } + + if ((pFile->private_data != NULL) && (pFile->private_data != &our_instance)) { + printk(KERN_ERR "hdmicec:%s:pFile missmatch\n",__func__); + } + this = pFile->private_data = &our_instance; + down(&this->driver.sem); + + LOG(KERN_INFO,"major:%d minor:%d user:%d\n", imajor(pInode), iminor(pInode), this->driver.user_counter); + + if ((this->driver.user_counter++) && (this->driver.minor == minor)) { + /* init already done */ + up(&this->driver.sem); + return 0; + } + this->driver.minor = minor; + + + up(&this->driver.sem); + return 0; +} + +/* + * ioctl driver :: ioctl + */ +static int this_cdev_ioctl(struct inode *pInode, struct file *pFile, unsigned int cmd, unsigned long arg) +{ + cec_instance* this = pFile->private_data; + int err=0; + + LOG(KERN_INFO,":%s\n",cec_ioctl(_IOC_NR(cmd))); + + BUG_ON(this->driver.minor!=iminor(pInode)); + if (_IOC_TYPE(cmd) != CEC_IOCTL_BASE) { + printk(KERN_INFO "hdmicec:%s:unknown ioctl type: %x\n",__func__,_IOC_TYPE(cmd)); + return -ENOIOCTLCMD; + } + + if (_IOC_DIR(cmd) & _IOC_READ) + err = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)) || !arg; + else if (_IOC_DIR(cmd) & _IOC_WRITE) + err = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)) || !arg; + if (err) { + printk(KERN_ERR "hdmicec:%s:argument access denied (check address vs value)\n",__func__); + printk(KERN_ERR "_IOC_DIR:%d arg:%lx\n",_IOC_DIR(cmd),arg); + return -EFAULT; + } + + down(&this->driver.sem); + + /* Check DevLib consistancy here */ + + switch ( _IOC_NR(cmd) ) + { + case CEC_VERBOSE_ON_CMD: + { + printk(KERN_INFO "verbose on\n"); + this->param.verbose=1; + break; + } + + case CEC_VERBOSE_OFF_CMD: + { + printk(KERN_INFO "verbose off\n"); + this->param.verbose=0; + break; + } + + case CEC_BYEBYE_CMD: + { + LOG(KERN_INFO,"callback release request\n"); + this->cec.frame.service=CEC_RELEASE; + this->driver.poll_done = true; + wake_up_interruptible(&this->driver.wait); + break; + } + + /* + no param + */ + + case CEC_IOCTL_DISABLE_CALIBRATION_CMD: + { + TRY(tmdlHdmiCecDisableCalibration(this->cec.inst)); + break; + } + + case CEC_IOCTL_INSTANCE_CONFIG_CMD: + { + TRY(tmdlHdmiCecInstanceConfig(this->cec.inst)); + break; + } + + case CEC_IOCTL_REQUEST_ACTIVE_SRC_CMD: + { + TRY(tmdlHdmiCecRequestActiveSource(this->cec.inst)); + break; + } + + case CEC_IOCTL_ABORT_MSG_CMD: + { + TRY(tmdlHdmiCecAbortMessage(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GET_MENU_LANGUAGE_CMD: + { + TRY(tmdlHdmiCecGetMenuLanguage(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GIVE_AUDIO_STATUS_CMD: + { + TRY(tmdlHdmiCecGiveAudioStatus(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GIVE_DEVICE_POWER_STATUS_CMD: + { + TRY(tmdlHdmiCecGiveDevicePowerStatus(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GIVE_DEVICE_VENDOR_ID_CMD: + { + TRY(tmdlHdmiCecGiveDeviceVendorID(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GIVE_OSD_NAME_CMD: + { + TRY(tmdlHdmiCecGiveOsdName(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GIVE_PHY_ADDR_CMD: + { + TRY(tmdlHdmiCecGivePhysicalAddress(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_GIVE_SYS_AUDIO_MODE_STATUS_CMD: + { + TRY(tmdlHdmiCecGiveSystemAudioModeStatus(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_IMAGE_VIEW_ON_CMD: + { + TRY(tmdlHdmiCecImageViewOn(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_POLLING_MSG_CMD: + { + TRY(tmdlHdmiCecPollingMessage(this->cec.inst,this->cec.rx_addr)); + break; + } + + case CEC_IOCTL_REC_OFF_CMD: + { + TRY(tmdlHdmiCecRecordOff(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_REC_ON_OWN_SRC_CMD: + { + TRY(tmdlHdmiCecRecordOnOwnSource(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_REC_TV_SCREEN_CMD: + { + TRY(tmdlHdmiCecRecordTvScreen(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_STANDBY_CMD: + { + TRY(tmdlHdmiCecStandby(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_TEXT_VIEW_ON_CMD: + { + TRY(tmdlHdmiCecTextViewOn(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_TUNER_STEP_DECREMENT_CMD: + { + TRY(tmdlHdmiCecTunerStepDecrement(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_TUNER_STEP_INCREMENT_CMD: + { + TRY(tmdlHdmiCecTunerStepIncrement(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_USER_CTRL_RELEASED_CMD: + { + TRY(tmdlHdmiCecUserControlReleased(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_VENDOR_REMOTE_BUTTON_UP_CMD: + { + TRY(tmdlHdmiCecVendorRemoteButtonUp(this->cec.inst,this->cec.initiator)); + break; + } + + case CEC_IOCTL_ROUTING_INFORMATION_CMD: + { + TRY(tmdlHdmiCecRoutingInformation(this->cec.inst,this->cec.phy_addr)); + break; + } + + case CEC_IOCTL_SET_STREAM_PATH_CMD: + { + TRY(tmdlHdmiCecSetStreamPath(this->cec.inst,this->cec.phy_addr)); + break; + } + + case CEC_IOCTL_ACTIVE_SRC_CMD: + { + /* NEW first do a */ + /* NEW when switch by DSS and was inactive */ + TRY(tmdlHdmiCecActiveSource(this->cec.inst,this->cec.phy_addr)); + break; + } + + case CEC_IOCTL_SYS_AUDIO_MODE_REQUEST_CMD: + { + TRY(tmdlHdmiCecSystemAudioModeRequest(this->cec.inst, \ + this->cec.initiator, \ + this->cec.phy_addr)); + break; + } + + /* + 1 param + */ + + case CEC_IOCTL_RX_ADDR_CMD: + { + /* BUG_ON(copy_from_user(&this->cec.rx_addr,(unsigned char*)arg,sizeof(unsigned char)) != 0); */ + this->cec.rx_addr=arg; + TRY(tmdlHdmiCecSetLogicalAddress(this->cec.inst,this->cec.rx_addr)); + break; + } + + case CEC_IOCTL_PHY_ADDR_CMD: + { + BUG_ON(copy_from_user(&this->cec.phy_addr,(unsigned short*)arg,sizeof(unsigned short)) != 0); + break; + } + + case CEC_IOCTL_GET_CEC_VERSION_CMD: + { + BUG_ON(copy_from_user(&this->cec.version,(cec_version*)arg,sizeof(cec_version)) != 0); + TRY(tmdlHdmiCecGetCecVersion(this->cec.inst,this->cec.version)); + break; + } + + case CEC_IOCTL_GET_SW_VERSION_CMD: + { + TRY(tmdlHdmiCecGetSWVersion(&this->cec.sw_version)); + BUG_ON(copy_to_user((cec_sw_version*)arg,&this->cec.sw_version,sizeof(cec_sw_version)) != 0); + break; + } + + case CEC_IOCTL_SET_POWER_STATE_CMD: + { + /* NEW : log : please use DSS */ + BUG_ON(copy_from_user(&this->cec.power,(cec_power*)arg,sizeof(cec_power)) != 0); + TRY(tmdlHdmiCecSetPowerState(this->cec.inst,this->cec.power)); + break; + } + + case CEC_IOCTL_GET_POWER_STATE_CMD: + { + TRY(tmdlHdmiCecGetPowerState(this->cec.inst,&this->cec.power)); + BUG_ON(copy_to_user((cec_power*)arg,&this->cec.power,sizeof(cec_power)) != 0); + break; + } + + case CEC_IOCTL_INSTANCE_SETUP_CMD: + { + BUG_ON(copy_from_user(&this->cec.setup,(cec_setup*)arg,sizeof(cec_setup)) != 0); + TRY(tmdlHdmiCecInstanceSetup(this->cec.inst,&this->cec.setup)); + break; + } + + case CEC_IOCTL_GET_INSTANCE_SETUP_CMD: + { + TRY(tmdlHdmiCecGetInstanceSetup(this->cec.inst,&this->cec.setup)); + BUG_ON(copy_to_user((cec_setup*)arg,&this->cec.setup,sizeof(cec_setup)) != 0); + break; + } + + /* + case CEC_IOCTL_ENABLE_EVENT_CMD: + { + BUG_ON(copy_from_user(&this->cec.an_event,(cec_event*)arg,sizeof(cec_event)) != 0); + TRY(tmdlHdmiCecEnableEvent(this->cec.inst,this->cec.an_event)); + break; + } + + case CEC_IOCTL_DISABLE_EVENT_CMD: + { + BUG_ON(copy_from_user(&this->cec.an_event,(cec_event*)arg,sizeof(cec_event)) != 0); + TRY(tmdlHdmiCecDisableEvent(this->cec.inst,this->cec.an_event)); + break; + } + */ + + case CEC_IOCTL_SET_MENU_LANGUAGE_CMD: + { + BUG_ON(copy_from_user(&this->cec.clock,(cec_string*)arg,sizeof(cec_string)) != 0); + TRY(tmdlHdmiCecSetMenuLanguage(this->cec.inst,this->cec.string.data)); + break; + } + + case CEC_IOCTL_ENABLE_CALIBRATION_CMD: + { + BUG_ON(copy_from_user(&this->cec.clock,(cec_clock*)arg,sizeof(cec_clock)) != 0); + TRY(tmdlHdmiCecEnableCalibration(this->cec.inst,this->cec.clock)); + break; + } + + /* + >1 param + */ + + case CEC_IOCTL_WAIT_FRAME_CMD: + { + this->cec.frame.service = CEC_WAITING; + this->driver.poll_done = false; + up(&this->driver.sem); + if (wait_event_interruptible(this->driver.wait,this->driver.poll_done)) return -ERESTARTSYS; + down(&this->driver.sem); + BUG_ON(copy_to_user((cec_frame*)arg,&this->cec.frame,sizeof(cec_frame)) != 0); + break; + } + + case CEC_IOCTL_VERSION_CMD: + { + BUG_ON(copy_from_user(&this->cec.version,(cec_version*)arg,sizeof(cec_version)) != 0); + TRY(tmdlHdmiCecVersion(this->cec.inst, \ + this->cec.initiator, \ + this->cec.version)); + break; + } + + case CEC_IOCTL_CLEAR_ANALOGUE_TIMER_CMD: + { + BUG_ON(copy_from_user(&this->cec.analog_timer,(cec_analogue_timer*)arg,sizeof(cec_analogue_timer)) != 0); + TRY(tmdlHdmiCecClearAnalogueTimer(this->cec.inst, \ + this->cec.initiator, \ + this->cec.analog_timer.DayOfMonth, \ + this->cec.analog_timer.MonthOfYear, \ + this->cec.analog_timer.StartTime, \ + &this->cec.analog_timer.Duration, \ + this->cec.analog_timer.RecordingSequence, \ + this->cec.analog_timer.AnalogueBroadcastType, \ + this->cec.analog_timer.AnalogueFrequency, \ + this->cec.analog_timer.BroadcastSystem)); + break; + } + + case CEC_IOCTL_CLEAR_DIGITAL_TIMER_CMD: + { + BUG_ON(copy_from_user(&this->cec.digital_timer,(cec_digital_timer*)arg,sizeof(cec_digital_timer)) != 0); + TRY(tmdlHdmiCecClearDigitalTimer(this->cec.inst, \ + this->cec.initiator, \ + this->cec.digital_timer.DayOfMonth, \ + this->cec.digital_timer.MonthOfYear, \ + this->cec.digital_timer.StartTime, \ + &this->cec.digital_timer.Duration, \ + this->cec.digital_timer.RecordingSequence, \ + &this->cec.digital_timer.ServiceIdentification)); + break; + } + + case CEC_IOCTL_CLEAR_EXT_TIMER_WITH_EXT_PLUG_CMD: + { + BUG_ON(copy_from_user(&this->cec.etwep,(cec_ext_timer_with_ext_plug*)arg,sizeof(cec_ext_timer_with_ext_plug)) != 0); + TRY(tmdlHdmiCecClearExternalTimerWithExternalPlug(this->cec.inst, \ + this->cec.initiator, \ + this->cec.etwep.DayOfMonth, \ + this->cec.etwep.MonthOfYear, \ + this->cec.etwep.StartTime, \ + &this->cec.etwep.Duration, \ + this->cec.etwep.RecordingSequence, \ + this->cec.etwep.ExternalPlug)); + break; + } + + case CEC_IOCTL_CLEAR_EXT_TIMER_WITH_PHY_ADDR_CMD: + { + BUG_ON(copy_from_user(&this->cec.etwpa,(cec_ext_timer_with_phy_addr*)arg,sizeof(cec_ext_timer_with_phy_addr)) != 0); + TRY(tmdlHdmiCecClearExternalTimerWithPhysicalAddress(this->cec.inst, \ + this->cec.initiator, \ + this->cec.etwpa.DayOfMonth, \ + this->cec.etwpa.MonthOfYear, \ + this->cec.etwpa.StartTime, \ + &this->cec.etwpa.Duration, \ + this->cec.etwpa.RecordingSequence, \ + this->cec.etwpa.ExternalPhysicalAddress)); + break; + } + + case CEC_IOCTL_DECK_CTRL_CMD: + { + BUG_ON(copy_from_user(&this->cec.deck_ctrl,(cec_deck_ctrl*)arg,sizeof(cec_deck_ctrl)) != 0); + TRY(tmdlHdmiCecDeckControl(this->cec.inst, \ + this->cec.initiator, \ + this->cec.deck_ctrl)); + break; + } + + case CEC_IOCTL_DECK_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.deck_status,(cec_deck_status*)arg,sizeof(cec_deck_status)) != 0); + TRY(tmdlHdmiCecDeckStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.deck_status)); + break; + } + + case CEC_IOCTL_DEVICE_VENDOR_ID_CMD: + { + BUG_ON(copy_from_user(&this->cec.vendor_id,(unsigned long*)arg,sizeof(unsigned long)) != 0); + TRY(tmdlHdmiCecDeviceVendorID(this->cec.inst, \ + this->cec.vendor_id)); + break; + } + + case CEC_IOCTL_FEATURE_ABORT_CMD: + { + BUG_ON(copy_from_user(&this->cec.feature_abort,(cec_feature_abort*)arg,sizeof(cec_feature_abort)) != 0); + TRY(tmdlHdmiCecFeatureAbort(this->cec.inst, \ + this->cec.initiator, \ + this->cec.feature_abort.FeatureOpcode, \ + this->cec.feature_abort.AbortReason)); + break; + } + + case CEC_IOCTL_GIVE_DECK_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.satus_request,(cec_status_request*)arg,sizeof(cec_status_request)) != 0); + TRY(tmdlHdmiCecGiveDeckStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.satus_request)); + break; + } + + case CEC_IOCTL_GIVE_TUNER_DEVICE_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.satus_request,(cec_status_request*)arg,sizeof(cec_status_request*)) != 0); + TRY(tmdlHdmiCecGiveTunerDeviceStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.satus_request)); + break; + } + + case CEC_IOCTL_INACTIVE_SRC_CMD: + { + /* NEW first stand by video */ + /* NEW when hdmi_disable and was active */ + TRY(tmdlHdmiCecInactiveSource(this->cec.inst, \ + this->cec.initiator, \ + this->cec.phy_addr)); + break; + } + + case CEC_IOCTL_MENU_REQUEST_CMD: + { + BUG_ON(copy_from_user(&this->cec.menu_request,(cec_menu_request*)arg,sizeof(cec_menu_request)) != 0); + TRY(tmdlHdmiCecMenuRequest(this->cec.inst, \ + this->cec.initiator, \ + this->cec.menu_request)); + break; + } + + case CEC_IOCTL_MENU_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.menu_status,(cec_menu_status*)arg,sizeof(cec_menu_status)) != 0); + TRY(tmdlHdmiCecMenuStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.menu_status)); + break; + } + + case CEC_IOCTL_PLAY_CMD: + { + BUG_ON(copy_from_user(&this->cec.play,(cec_play*)arg,sizeof(cec_play)) != 0); + TRY(tmdlHdmiCecPlay(this->cec.inst, \ + this->cec.initiator, \ + this->cec.play)); + break; + } + + case CEC_IOCTL_REC_ON_ANALOGUE_SERVICE_CMD: + { + BUG_ON(copy_from_user(&this->cec.analog_service,(cec_analogue_service*)arg,sizeof(cec_analogue_service)) != 0); + TRY(tmdlHdmiCecRecordOnAnalogueService(this->cec.inst, \ + this->cec.initiator, \ + this->cec.analog_service.AnalogueBroadcastType, \ + this->cec.analog_service.AnalogueFrequency, \ + this->cec.analog_service.BroadcastSystem)); + break; + } + + case CEC_IOCTL_REC_ON_DIGITAL_SERVICE_CMD: + { + BUG_ON(copy_from_user(&this->cec.digital_service,(cec_digital_service*)arg,sizeof(cec_digital_service)) != 0); + TRY(tmdlHdmiCecRecordOnDigitalService(this->cec.inst, \ + this->cec.initiator, \ + &this->cec.digital_service)); + break; + } + + case CEC_IOCTL_REC_ON_EXT_PHY_ADDR_CMD: + { + TRY(tmdlHdmiCecRecordOnExternalPhysicalAddress(this->cec.inst, \ + this->cec.initiator, \ + this->cec.phy_addr)); + break; + } + + case CEC_IOCTL_REC_ON_EXT_PLUG_CMD: + { + BUG_ON(copy_from_user(&this->cec.ext_plug,(cec_ext_plug*)arg,sizeof(cec_ext_plug)) != 0); + TRY(tmdlHdmiCecRecordOnExternalPlug(this->cec.inst, \ + this->cec.initiator, \ + this->cec.ext_plug)); + break; + } + + case CEC_IOCTL_REC_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.rec_status,(cec_rec_status*)arg,sizeof(cec_rec_status)) != 0); + TRY(tmdlHdmiCecRecordStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.rec_status)); + break; + } + + case CEC_IOCTL_REPORT_AUDIO_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.audio_status,(cec_audio_status*)arg,sizeof(cec_audio_status)) != 0); + TRY(tmdlHdmiCecReportAudioStatus(this->cec.inst, \ + this->cec.initiator, \ + &this->cec.audio_status)); + break; + } + + case CEC_IOCTL_REPORT_PHY_ADDR_CMD: + { + BUG_ON(copy_from_user(&this->cec.device_type,(cec_device_type*)arg,sizeof(cec_device_type)) != 0); + TRY(tmdlHdmiCecReportPhysicalAddress(this->cec.inst, \ + this->cec.phy_addr, \ + this->cec.device_type)); + break; + } + + case CEC_IOCTL_REPORT_POWER_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.source_status,(cec_power_status*)arg,sizeof(cec_power_status)) != 0); + TRY(tmdlHdmiCecReportPowerStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.source_status)); + break; + } + + case CEC_IOCTL_SELECT_ANALOGUE_SERVICE_CMD: + { + BUG_ON(copy_from_user(&this->cec.analog_service,(cec_analogue_service*)arg,sizeof(cec_analogue_service)) != 0); + TRY(tmdlHdmiCecSelectAnalogueService(this->cec.inst, \ + this->cec.initiator, \ + this->cec.analog_service.AnalogueBroadcastType, \ + this->cec.analog_service.AnalogueFrequency, \ + this->cec.analog_service.BroadcastSystem)); + break; + } + + case CEC_IOCTL_SELECT_DIGITAL_SERVICE_CMD: + { + BUG_ON(copy_from_user(&this->cec.digital_service,(cec_digital_service*)arg,sizeof(cec_digital_service)) != 0); + TRY(tmdlHdmiCecSelectDigitalService(this->cec.inst, \ + this->cec.initiator, \ + &this->cec.digital_service)); + break; + } + + case CEC_IOCTL_SET_ANALOGUE_TIMER_CMD: + { + BUG_ON(copy_from_user(&this->cec.analog_timer,(cec_analogue_timer*)arg,sizeof(cec_analogue_timer)) != 0); + TRY(tmdlHdmiCecSetAnalogueTimer(this->cec.inst, \ + this->cec.initiator, \ + this->cec.analog_timer.DayOfMonth, \ + this->cec.analog_timer.MonthOfYear, \ + this->cec.analog_timer.StartTime, \ + &this->cec.analog_timer.Duration, \ + this->cec.analog_timer.RecordingSequence, \ + this->cec.analog_timer.AnalogueBroadcastType, \ + this->cec.analog_timer.AnalogueFrequency, \ + this->cec.analog_timer.BroadcastSystem)); + break; + } + + case CEC_IOCTL_SET_AUDIO_RATE_CMD: + { + BUG_ON(copy_from_user(&this->cec.audio_rate,(cec_audio_rate*)arg,sizeof(cec_audio_rate)) != 0); + TRY(tmdlHdmiCecSetAudioRate(this->cec.inst, \ + this->cec.initiator, \ + this->cec.audio_rate)); + break; + } + + case CEC_IOCTL_SET_DIGITAL_TIMER_CMD: + { + BUG_ON(copy_from_user(&this->cec.digital_timer,(cec_digital_timer*)arg,sizeof(cec_digital_timer)) != 0); + TRY(tmdlHdmiCecSetDigitalTimer(this->cec.inst, \ + this->cec.initiator, \ + this->cec.digital_timer.DayOfMonth, \ + this->cec.digital_timer.MonthOfYear, \ + this->cec.digital_timer.StartTime, \ + &this->cec.digital_timer.Duration, \ + this->cec.digital_timer.RecordingSequence, \ + &this->cec.digital_timer.ServiceIdentification)); + break; + } + + case CEC_IOCTL_SET_EXT_TIMER_WITH_EXT_PLUG_CMD: + { + BUG_ON(copy_from_user(&this->cec.etwep,(cec_ext_timer_with_ext_plug*)arg,sizeof(cec_ext_timer_with_ext_plug)) != 0); + TRY(tmdlHdmiCecSetExternalTimerWithExternalPlug(this->cec.inst, \ + this->cec.initiator, \ + this->cec.etwep.DayOfMonth, \ + this->cec.etwep.MonthOfYear, \ + this->cec.etwep.StartTime, \ + &this->cec.etwep.Duration, \ + this->cec.etwep.RecordingSequence, \ + this->cec.etwep.ExternalPlug)); + break; + } + + case CEC_IOCTL_SET_EXT_TIMER_WITH_PHY_ADDR_CMD: + { + BUG_ON(copy_from_user(&this->cec.etwpa,(cec_ext_timer_with_phy_addr*)arg,sizeof(cec_ext_timer_with_phy_addr)) != 0); + TRY(tmdlHdmiCecSetExternalTimerWithPhysicalAddress(this->cec.inst, \ + this->cec.initiator, \ + this->cec.etwpa.DayOfMonth, \ + this->cec.etwpa.MonthOfYear, \ + this->cec.etwpa.StartTime, \ + &this->cec.etwpa.Duration, \ + this->cec.etwpa.RecordingSequence, \ + this->cec.etwpa.ExternalPhysicalAddress)); + break; + } + + case CEC_IOCTL_SET_SYS_AUDIO_MODE_CMD: + { + BUG_ON(copy_from_user(&this->cec.sys_audio_status,(cec_sys_audio_status*)arg,sizeof(cec_sys_audio_status)) != 0); + TRY(tmdlHdmiCecSetSystemAudioMode(this->cec.inst, \ + this->cec.initiator, \ + this->cec.sys_audio_status)); + break; + } + + case CEC_IOCTL_SYS_AUDIO_MODE_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.sys_audio_status,(cec_sys_audio_status*)arg,sizeof(cec_sys_audio_status)) != 0); + TRY(tmdlHdmiCecSystemAudioModeStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.sys_audio_status)); + break; + } + + case CEC_IOCTL_TIMER_CLEARED_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.timer_cleared_status,(cec_timer_cleared_status*)arg,sizeof(cec_timer_cleared_status)) != 0); + TRY(tmdlHdmiCecTimerClearedStatus(this->cec.inst, \ + this->cec.initiator, \ + this->cec.timer_cleared_status)); + break; + } + + case CEC_IOCTL_TIMER_STATUS_CMD: + { + BUG_ON(copy_from_user(&this->cec.timer_status,(cec_timer_status*)arg,sizeof(cec_timer_status)) != 0); + TRY(tmdlHdmiCecTimerStatus(this->cec.inst, \ + this->cec.initiator, \ + &this->cec.timer_status)); + break; + } + + case CEC_IOCTL_TUNER_DEVICE_STATUS_ANALOGUE_CMD: + { + BUG_ON(copy_from_user(&this->cec.tdsa,(cec_tuner_device_status_analogue*)arg,sizeof(cec_tuner_device_status_analogue)) != 0); + TRY(tmdlHdmiCecTunerDeviceStatusAnalogue(this->cec.inst, \ + this->cec.initiator, \ + this->cec.tdsa.RecordingFlag, \ + this->cec.tdsa.TunerDisplayInfo, \ + this->cec.tdsa.AnalogueBroadcastType, \ + this->cec.tdsa.AnalogueFrequency, \ + this->cec.tdsa.BroadcastSystem)); + break; + } + + case CEC_IOCTL_TUNER_DEVICE_STATUS_DIGITAL_CMD: + { + BUG_ON(copy_from_user(&this->cec.tdsd,(cec_tuner_device_status_digital*)arg,sizeof(cec_tuner_device_status_digital)) != 0); + TRY(tmdlHdmiCecTunerDeviceStatusDigital(this->cec.inst, \ + this->cec.initiator, \ + this->cec.tdsd.RecordingFlag, \ + this->cec.tdsd.TunerDisplayInfo, \ + &this->cec.tdsd.ServiceIdentification)); + break; + } + + case CEC_IOCTL_USER_CTRL_CMD: + { + BUG_ON(copy_from_user(&this->cec.user_ctrl,(cec_user_ctrl*)arg,sizeof(cec_user_ctrl)) != 0); + TRY(tmdlHdmiCecUserControlPressed(this->cec.inst, \ + this->cec.initiator, \ + this->cec.user_ctrl)); + break; + } + + case CEC_IOCTL_USER_CTRL_PLAY_CMD: + { + BUG_ON(copy_from_user(&this->cec.play,(cec_play*)arg,sizeof(cec_play)) != 0); + TRY(tmdlHdmiCecUserControlPressedPlay(this->cec.inst, \ + this->cec.initiator, \ + this->cec.play)); + break; + } + + case CEC_IOCTL_USER_CTRL_SELECT_AUDIOINPUT_CMD: + { + BUG_ON(copy_from_user(&this->cec.select,(unsigned char*)arg,sizeof(unsigned char)) != 0); + TRY(tmdlHdmiCecUserControlPressedSelectAudioInput(this->cec.inst, \ + this->cec.initiator, \ + this->cec.select)); + break; + } + + case CEC_IOCTL_USER_CTRL_SELECT_AVINPUT_CMD: + { + BUG_ON(copy_from_user(&this->cec.select,(unsigned char*)arg,sizeof(unsigned char)) != 0); + TRY(tmdlHdmiCecUserControlPressedSelectAVInput(this->cec.inst, \ + this->cec.initiator, \ + this->cec.select)); + break; + } + + case CEC_IOCTL_USER_CTRL_SELECT_MEDIA_CMD: + { + BUG_ON(copy_from_user(&this->cec.select,(unsigned char*)arg,sizeof(unsigned char)) != 0); + TRY(tmdlHdmiCecUserControlPressedSelectMedia(this->cec.inst, \ + this->cec.initiator, \ + this->cec.select)); + break; + } + + case CEC_IOCTL_USER_CTRL_TUNE_CMD: + { + BUG_ON(copy_from_user(&this->cec.user_ctrl_tune,(cec_user_ctrl_tune*)arg,sizeof(cec_user_ctrl_tune)) != 0); + TRY(tmdlHdmiCecUserControlPressedTune(this->cec.inst, \ + this->cec.initiator, \ + &this->cec.user_ctrl_tune)); + break; + } + + case CEC_IOCTL_SET_OSD_NAME_CMD: + { + BUG_ON(copy_from_user(&this->cec.osd_name,(cec_string*)arg,sizeof(cec_string)) != 0); + TRY(tmdlHdmiCecSetOsdName(this->cec.inst, \ + this->cec.initiator, \ + this->cec.osd_name.data, \ + this->cec.osd_name.length)); + break; + } + + case CEC_IOCTL_SET_OSD_STRING_CMD: + { + BUG_ON(copy_from_user(&this->cec.osd_string,(cec_osd_string*)arg,sizeof(cec_osd_string)) != 0); + TRY(tmdlHdmiCecSetOsdString(this->cec.inst, \ + this->cec.initiator, \ + this->cec.osd_string.DisplayControl, \ + this->cec.osd_string.data, \ + this->cec.osd_string.length)); + break; + } + + case CEC_IOCTL_SET_TIMER_PROGRAM_TITLE_CMD: + { + BUG_ON(copy_from_user(&this->cec.string,(cec_string*)arg,sizeof(cec_string)) != 0); + TRY(tmdlHdmiCecSetTimerProgramTitle(this->cec.inst, \ + this->cec.initiator, \ + this->cec.string.data, \ + this->cec.string.length)); + break; + } + + case CEC_IOCTL_VENDOR_COMMAND_CMD: + { + BUG_ON(copy_from_user(&this->cec.string,(cec_string*)arg,sizeof(cec_string)) != 0); + TRY(tmdlHdmiCecVendorCommand(this->cec.inst, \ + this->cec.initiator, \ + this->cec.string.data, \ + this->cec.string.length)); + break; + } + + case CEC_IOCTL_VENDOR_REMOTE_BUTTON_DOWN_CMD: + { + BUG_ON(copy_from_user(&this->cec.string,(cec_string*)arg,sizeof(cec_string)) != 0); + TRY(tmdlHdmiCecVendorRemoteButtonDown(this->cec.inst, \ + this->cec.initiator, \ + this->cec.string.data, \ + this->cec.string.length)); + break; + } + + case CEC_IOCTL_VENDOR_COMMAND_WITH_ID_CMD: + { + BUG_ON(copy_from_user(&this->cec.vcwi,(cec_vendor_command_with_id*)arg,sizeof(cec_vendor_command_with_id)) != 0); + TRY(tmdlHdmiCecVendorCommandWithID(this->cec.inst, \ + this->cec.initiator, \ + this->cec.vcwi.VendorID, \ + this->cec.vcwi.cmd.data, \ + this->cec.vcwi.cmd.length)); + break; + } + + /* case : */ + /* { */ + /* BUG_ON(copy_from_user(&this->cec.,(*)arg,sizeof()) != 0); */ + /* TRY((this->cec.inst, \ */ + /* this->cec., \ */ + /* &this->cec.)); */ + /* break; */ + /* } */ + + default: + { + /* unrecognized ioctl */ + printk(KERN_INFO " unknown ioctl %x\n",cmd); + up(&this->driver.sem); + return -ENOIOCTLCMD; + } + } + + TRY_DONE: + up(&this->driver.sem); + return err; +} + +/* + * ioctl driver :: releasing + */ +static int this_cdev_release(struct inode *pInode, struct file *pFile) +{ + cec_instance* this = pFile->private_data; + int minor = iminor(pInode); + + LOG(KERN_INFO,"called\n"); + + if(minor >= MAX_MINOR) { + return -EINVAL; + } + + BUG_ON(this->driver.minor!=iminor(pInode)); + down(&this->driver.sem); + + this->driver.user_counter--; + if(this->driver.user_counter == 0) { + pFile->private_data = NULL; + } + else { + LOG(KERN_INFO,"Still %d user pending\n",this->driver.user_counter); + } + + up(&this->driver.sem); + return 0; +} + +/* + * I2C client :: creation + */ +static int __devinit this_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + cec_instance *this=&our_instance; + int err=0; + + LOG(KERN_INFO,"called\n"); + + /* + I2C setup + */ + if (this->driver.i2c_client) { + dev_err(&this->driver.i2c_client->dev, "<%s> CEC Device already created \n", + __func__); + return -ENODEV; + } + + this->driver.i2c_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); + if (!this->driver.i2c_client) { + return -ENOMEM; + } + memset(this->driver.i2c_client, 0, sizeof(struct i2c_client)); + + strncpy(this->driver.i2c_client->name, CEC_NAME, I2C_NAME_SIZE); + this->driver.i2c_client->addr = TDA99XCEC_I2C_SLAVEADDRESS; + this->driver.i2c_client->adapter = client->adapter; + + i2c_set_clientdata(client, this->driver.i2c_client); + + tmdlHdmiCecGetSWVersion(&this->cec.sw_version); + LOG(KERN_INFO,"HDMI CEC SW Version:%lu.%lu compatibility:%lu\n", \ + this->cec.sw_version.majorVersionNr,\ + this->cec.sw_version.minorVersionNr,\ + this->cec.sw_version.compatibilityNr); + + /* I2C ok, then let's startup CEC */ + + /* prepare event */ + this->driver.poll_done = true; /* currently idle */ + init_waitqueue_head(&this->driver.wait); +#ifndef IRQ + init_timer(&this->driver.timer); /* do it before request_irq */ + this->driver.timer.function=polling_timeout; + this->driver.timer.data=0; + this->driver.timer.expires = jiffies + HZ; /* start polling in one sec */ + add_timer(&this->driver.timer); +#else + register_cec_interrupt((cec_callback_t)cec_interrupt); +#endif + +#ifndef IRQ + /* FRO calibration */ + err=gpio_request(TDA_IRQ_CALIB,"tda19989 calibration"); + if (err < 0) { + printk(KERN_ERR "hdmicec:%s:cannot use GPIO 107\n",__func__); + goto i2c_out; + } + /* turn GPIO into IRQ + gpio_direction_input(TDA_IRQ_CALIB); + msleep(1); + if (request_irq(gpio_to_irq(TDA_IRQ_CALIB), \ + tda_irq, IRQF_TRIGGER_FALLING|IRQF_DISABLED, "TDA IRQ", NULL)) { + printk(KERN_ERR "hdmicec:%s:Cannot request irq, err:%d\n",__func__,err); + gpio_free(TDA_IRQ_CALIB); + goto i2c_out; + } + */ +#endif + + err = hdmi_cec_init(this); + if (err) goto i2c_out; + this->cec.rx_addr=CEC_LOGICAL_ADDRESS_UNREGISTRED_BROADCAST; + + if (get_hpd_status()) { + cec_on(this); + // disable_irq(gpio_to_irq(TDA_IRQ_CALIB)); + cec_interrupt(NULL); /* initiate polling */ + // enable_irq(gpio_to_irq(TDA_IRQ_CALIB)); + } + else { + cec_standby(this); + } + + return 0; + + i2c_out: + LOG(KERN_INFO,"HDMICEC eject: this->driver.i2c_client removed\n"); + tmdlHdmiCecClose(this->cec.inst); + kfree(this->driver.i2c_client); + this->driver.i2c_client = NULL; + + return err; +} + +/* + * I2C client :: destroy + */ +static int this_i2c_remove(struct i2c_client *client) +{ + cec_instance *this=&our_instance; + int err=0; + + LOG(KERN_INFO,"called\n"); + + err=tmdlHdmiCecClose(this->cec.inst); + + if (!client->adapter) { + dev_err(&this->driver.i2c_client->dev, "<%s> No CEC Device \n", + __func__); + return -ENODEV; + } + kfree(this->driver.i2c_client); + this->driver.i2c_client = NULL; + + return err; +} + +/* + * I2C client driver (backend) + * ----------------- + */ +static struct i2c_driver this_i2c_driver = { + .driver = { + .owner = THIS_MODULE, + .name = CEC_NAME, + }, + .probe = this_i2c_probe, + .remove = this_i2c_remove, + .id_table = this_i2c_id, +}; + +/* + * ioctl driver (userland frontend) + * ------------ + */ +static struct file_operations this_cdev_fops = { + owner: THIS_MODULE, + open: this_cdev_open, + release: this_cdev_release, +// ioctl: this_cdev_ioctl, +}; + +/* + * Module :: start up + */ +static int __init cec_init(void) +{ + cec_instance *this=&our_instance; + dev_t dev=0; + int err=0; + + /* + general device context + */ + memset(this,0,sizeof(cec_instance)); + this->param.verbose = param_verbose; + this->param.major = param_major; + this->param.minor = param_minor; + + /* Hello word */ + printk(KERN_INFO "%s(%s) %d.%d.%d compiled: %s %s %s\n", HDMICEC_NAME, TDA_NAME, TDA_VERSION_MAJOR, + TDA_VERSION_MINOR, TDA_VERSION_PATCHLEVEL, __DATE__, __TIME__, TDA_VERSION_EXTRA); + if (this->param.verbose) LOG(KERN_INFO,".verbose mode\n"); + + /* + plug I2C (backend : Hw interfacing) + */ + err = i2c_add_driver(&this_i2c_driver); + if (err < 0) { + printk(KERN_ERR "Driver registration failed\n"); + return -ENODEV; + } + + if (this->driver.i2c_client == NULL) { + printk(KERN_ERR "this->driver.i2c_client not allocated\n"); + err = -ENODEV; + goto init_out; + } + + /* + cdev init (userland frontend) + */ + + /* arbitray range of device numbers */ + if (this->param.major) { + /* user force major number @ insmod */ + dev = MKDEV(this->param.major, this->param.minor); + err = register_chrdev_region(dev,MAX_MINOR,HDMICEC_NAME); + if (err) { + printk(KERN_ERR "unable to register %s, dev=%d %s\n",HDMICEC_NAME,dev,ERR_TO_STR(err)); + goto init_out; + } + } else { + /* fully dynamic major number */ + err = alloc_chrdev_region(&dev, this->param.minor, MAX_MINOR,HDMICEC_NAME); + if (err) { + printk(KERN_ERR "unable to alloc chrdev region for %s, dev=%d %s\n",HDMICEC_NAME,dev,ERR_TO_STR(err)); + goto init_out; + } + this->param.major = MAJOR(dev); + } + + cdev_init(this_cdev, &this_cdev_fops); + this_cdev->owner = THIS_MODULE; + + this->driver.class = class_create(THIS_MODULE, HDMICEC_NAME); + if (IS_ERR(this->driver.class)) { + printk(KERN_INFO "Error creating mmap device class.\n"); + err =-EIO; + goto init_out; + } + this->driver.dev = device_create(this->driver.class, NULL, dev, NULL, HDMICEC_NAME); + + this->driver.devno = dev; + err = cdev_add(this_cdev, this->driver.devno, MAX_MINOR); + if (err){ + printk(KERN_INFO "unable to add device for %s, ipp_driver.devno=%d %s\n",HDMICEC_NAME,this->driver.devno,ERR_TO_STR(err)); + device_destroy(this->driver.class,this->driver.devno); + class_destroy(this->driver.class); + unregister_chrdev_region(this->driver.devno, MAX_MINOR); + goto init_out; + } + +#ifdef TWL4030_HACK + /* AL : hack to bypass keypad */ + gkp_input = get_twm4030_input(); +#endif + + /* + general device context + */ + sema_init(&this->driver.sem, 1); + this->driver.deinit_req=0; + + return 0; + + init_out: + i2c_del_driver(&this_i2c_driver); + return err; +} + +/* + * Module :: shut down + */ +static void __exit cec_exit(void) +{ + cec_instance *this=&our_instance; + + LOG(KERN_INFO,"called\n"); + +#ifndef IRQ + // free_irq(gpio_to_irq(TDA_IRQ_CALIB), NULL); +#endif + + unregister_cec_interrupt(); + this->driver.deinit_req=1; +#ifndef IRQ + if (wait_event_interruptible(this->driver.wait,this->driver.deinit_req>1)) { + /* oups... just wait... */ + msleep(CHECK_EVERY_XX_MS*20); + } +#endif + +#ifndef IRQ + /* release GPIO */ + gpio_free(TDA_IRQ_CALIB); +#endif + + /* unregister cdevice */ + cdev_del(this_cdev); + unregister_chrdev_region(this->driver.devno, MAX_MINOR); + + /* unregister device */ + device_destroy(this->driver.class,this->driver.devno); + class_destroy(this->driver.class); + + /* unregister i2c */ + i2c_del_driver(&this_i2c_driver); + +} + + +/* + * Module + * ------ + */ +/* late_initcall(cec_init); */ +module_init(cec_init); +module_exit(cec_exit); + +/* + * Disclamer + * --------- + */ +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Andre Lepine "); +MODULE_DESCRIPTION(HDMICEC_NAME " driver"); + diff --git a/drivers/video/nxp/tda998x_cec.h b/drivers/video/nxp/tda998x_cec.h new file mode 100755 index 0000000000000..a3819121edd37 --- /dev/null +++ b/drivers/video/nxp/tda998x_cec.h @@ -0,0 +1,140 @@ +/*****************************************************************************/ +/* Copyright (c) 2009 NXP Semiconductors BV */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, using version 2 of the License. */ +/* */ +/* This program is distributed in the hope that it will be useful, */ +/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ +/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ +/* GNU General Public License for more details. */ +/* */ +/* You should have received a copy of the GNU General Public License */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 */ +/* USA. */ +/* */ +/*****************************************************************************/ + +#ifndef __cec_h__ +#define __cec_h__ + +#include "tda998x_ioctl.h" + +#define HDMICEC_NAME "hdmicec" + +#define CEC_MAJOR 234 /* old-style interval of device numbers */ +#define MAX_MINOR 1 /* 1 minor but 2 access : 1 more for pooling */ + +/* common I2C define with kernel */ +/* should be the same as arch/arm/mach-omap2/board-zoom2.c */ +#define CEC_NAME "tda99Xcec" +#define TDA99XCEC_I2C_SLAVEADDRESS 0x34 + +#define TDA_IRQ_CALIB 107 +#define POLLING_LENGTH 3 + +#define EDID_BLOCK_COUNT 4 +#define EDID_BLOCK_SIZE 128 + +#ifdef GPL +#define CHECK_EVERY_XX_MS 500 /* ms */ +#else +#define CHECK_EVERY_XX_MS 10 /* ms */ +#endif + +#define LOG(type,fmt,args...) {if (this->param.verbose) {printk(type HDMICEC_NAME":%s:" fmt, __func__, ## args);}} +/* not found the kernel "strerror" one! If someone knows, please replace it */ +#define ERR_TO_STR(e)((e == -ENODATA)?"ENODATA, no data available":\ + (e == -ENOMEM)? "ENOMEM, no memory available":\ + (e == -EINVAL)? "EINVAL, invalid argument":\ + (e == -EIO)? "EIO, input/output error":\ + (e == -ETIMEDOUT)? "ETIMEOUT, timeout has expired":\ + (e == -EBUSY)? "EBUSY, device or resource busy":\ + (e == -ENOENT)? "ENOENT, no such file or directory":\ + (e == -EACCES)? "EACCES, permission denied":\ + (e == 0)? "":\ + "!UNKNOWN!") + +#define TRY(fct) { \ + err=(fct); \ + if (err) { \ + printk(KERN_ERR "%s? in %s line %d\n",hdmi_cec_err_string(err),__func__,__LINE__); \ + goto TRY_DONE; \ + } \ + } + +typedef void (*cec_callback_t) (struct work_struct *dummy); + +typedef struct { + /* module params */ + struct { + int verbose; + int major; + int minor; + } param; + /* driver */ + struct { + struct class *class; + struct device *dev; + int devno; + struct i2c_client *i2c_client; + struct semaphore sem; + int user_counter; + int minor; + wait_queue_head_t wait; + bool poll_done; + int deinit_req; + struct timer_list timer; + } driver; + /* cec */ + struct { + int inst; + unsigned char rx_addr; + unsigned short phy_addr; + unsigned char initiator; + cec_version version; + cec_sw_version sw_version; + cec_power power; + cec_setup setup; + cec_clock clock; + cec_analogue_timer analog_timer; + cec_digital_timer digital_timer; + cec_ext_timer_with_ext_plug etwep; + cec_ext_timer_with_phy_addr etwpa; + cec_deck_ctrl deck_ctrl; + cec_deck_status deck_status; + unsigned long vendor_id; + cec_feature_abort feature_abort; + cec_status_request satus_request; + cec_menu_request menu_request; + cec_menu_status menu_status; + cec_play play; + cec_analogue_service analog_service; + cec_digital_service digital_service; + cec_ext_plug ext_plug; + cec_rec_status rec_status; + cec_audio_status audio_status; + cec_device_type device_type; + cec_power_status source_status; + cec_audio_rate audio_rate; + cec_sys_audio_status sys_audio_status; + cec_timer_cleared_status timer_cleared_status; + cec_timer_status timer_status; + cec_tuner_device_status_analogue tdsa; + cec_tuner_device_status_digital tdsd; + cec_user_ctrl user_ctrl; + unsigned char select; + cec_user_ctrl_tune user_ctrl_tune; + cec_frame frame; + bool byebye; + cec_string string; + cec_string osd_name; + cec_osd_string osd_string; + cec_vendor_command_with_id vcwi; + } cec; +} cec_instance; + +#endif /* __cec_h__ */ + diff --git a/drivers/video/nxp/tda998x_ioctl.h b/drivers/video/nxp/tda998x_ioctl.h new file mode 100755 index 0000000000000..192615bc1a84b --- /dev/null +++ b/drivers/video/nxp/tda998x_ioctl.h @@ -0,0 +1,1123 @@ +/** + * Copyright (C) 2006 NXP N.V., All Rights Reserved. + * This source code and any compilation or derivative thereof is the proprietary + * information of NXP N.V. and is confidential in nature. Under no circumstances + * is this software to be exposed to or placed under an Open Source License of + * any type without the expressed written permission of NXP N.V. + * + * Version Revision: 1.0 + * + * Date Date: 27/10/09 + * + * Brief API for the TDA1998x HDMI Transmitters + * + **/ + +#include + +#ifndef __tx_ioctl__ +#define __tx_ioctl__ + +#ifdef __tx_h__ + +#define TRANS_TYPE 1 + +#if TRANS_TYPE + +#define EXAMPLE_MAX_SVD 30 + +/* + trans-type +*/ +typedef tmSWVersion_t tda_version; +typedef tmPowerState_t tda_power; +typedef tmdlHdmiTxInstanceSetupInfo_t tda_setup; +typedef tmdlHdmiTxCapabilities_t tda_capabilities; +typedef tmdlHdmiTxVideoOutConfig_t tda_video_out; +typedef tmdlHdmiTxVideoInConfig_t tda_video_in; +typedef tmdlHdmiTxSinkType_t tda_sink; +typedef tmdlHdmiTxAudioInConfig_t tda_audio_in; +typedef tmdlHdmiTxEdidAudioDesc_t tda_edid_audio_desc; +typedef tmdlHdmiTxShortVidDesc_t tda_edid_video_desc; +typedef tmdlHdmiTxEvent_t tda_event; +typedef tmdlHdmiTxInstanceSetupInfo_t tda_setup_info; +typedef tmdlHdmiTxEdidVideoTimings_t tda_edid_video_timings; +typedef tmdlHdmiTxPictAspectRatio_t tda_edid_tv_aspect_ratio; +typedef tmdlHdmiTxHdcpCheck_t tda_hdcp_status; +#if defined (TMFL_TDA19989) || defined (TMFL_TDA9984) +typedef tmdlHdmiTxHdcpStatus_t tda_hdcp_fail; +#endif +#ifdef TMFL_TDA19989 +typedef tmdlHdmiTxEdidLatency_t tda_edid_latency; +#endif + +typedef struct { + Bool enable; + tmdlHdmiTxGamutData_t data; +} tda_gammut; + +typedef struct { + Bool enable; + tmdlHdmiTxVsPktData_t data; +} tda_vs_infoframe; + +typedef struct { + Bool enable; + tmdlHdmiTxSpdIfData_t data; +} tda_spd_infoframe; + +typedef struct { + Bool enable; + tmdlHdmiTxMpsIfData_t data; +} tda_mps_infoframe; + +typedef struct { + Bool enable; + tmdlHdmiTxIsrc1PktData_t data; +} tda_isrc1; + +typedef struct { + Bool enable; + tmdlHdmiTxIsrc2PktData_t data; +} tda_isrc2; + +typedef struct { + Bool enable; + tmdlHdmiTxAcpPktData_t data; +} tda_acp; + +typedef struct { + Bool enable; + tmdlHdmiTxGcpPktData_t data; +} tda_gcp; + +typedef struct { + Bool enable; + tmdlHdmiTxAviIfData_t data; +} tda_video_infoframe; + +typedef struct { + Bool enable; + tmdlHdmiTxAudIfData_t data; +} tda_audio_infoframe; + +typedef struct { + tmdlHdmiTxVidFmt_t id; + tmdlHdmiTxVidFmtSpecs_t spec; +} tda_video_format; + +typedef struct { + tda_video_in video_in; + tda_video_out video_out; + tda_audio_in audio_in; /* Mind tda_set_audio_in if you change this */ + tda_sink sink; /* Mind tda_set_audio_in if you change this */ +} tda_set_in_out; + +typedef struct { + tda_audio_in audio_in; + tda_sink sink; +} tda_set_audio_in; + +typedef struct { + tda_edid_audio_desc desc[EXAMPLE_MAX_SVD]; + unsigned int max; + unsigned int written; + unsigned char flags; +} tda_edid_audio_caps; + +typedef struct { + tda_edid_video_desc desc[EXAMPLE_MAX_SVD]; + unsigned int max; + unsigned int written; + unsigned char flags; +} tda_edid_video_caps; + +typedef struct { + tmdlHdmiTxEdidStatus_t status; + unsigned char block_count; +} tda_edid; + +typedef struct { + tmdlHdmiTxEdidVideoTimings_t desc[EXAMPLE_MAX_SVD]; + unsigned char max; + unsigned char written; +} tda_edid_dtd; + +typedef struct { + tmdlHdmiTxEdidFirstMD_t desc1[EXAMPLE_MAX_SVD]; + tmdlHdmiTxEdidSecondMD_t desc2[EXAMPLE_MAX_SVD]; + tmdlHdmiTxEdidOtherMD_t other[EXAMPLE_MAX_SVD]; + unsigned char max; + unsigned char written; +} tda_edid_md; + +#else + +#error do not compiled this ! + +typedef enum +{ + TDA_HDCP_ACTIVE = 0, /**< HDCP encryption status switched to active */ + TDA_HDCP_INACTIVE = 1, /**< HDCP encryption status switched to inactive */ + TDA_HPD_ACTIVE = 2, /**< Hotplug status switched to active */ + TDA_HPD_INACTIVE = 3, /**< Hotplug status switched to inactive */ + TDA_RX_KEYS_RECEIVED = 4, /**< Receiver(s) key(s) received */ + TDA_RX_DEVICE_ACTIVE = 5, /**< Rx device is connected and active */ + TDA_RX_DEVICE_INACTIVE = 6, /**< Rx device is connected but inactive (standby) */ + TDA_EDID_RECEIVED = 7, /**< EDID has been received */ + TDA_VS_RPT_RECEIVED = 8, /**< VS interrupt has been received */ +#ifdef HDMI_TX_REPEATER_ISR_MODE + TDA_B_STATUS = 9, /**< TX received BStatus */ +#endif /* HDMI_TX_REPEATER_ISR_MODE */ + TDA_DEBUG_EVENT_1 = 10 /**< This is a debug event */ +} tda_event; + +typedef struct { + unsigned char format; /* EIA/CEA861 mode */ + unsigned char channels; /* number of channels */ + unsigned char supportedFreqs; /* bitmask of supported frequencies */ + unsigned char supportedRes; /* bitmask of supported resolutions (LPCM only) */ + unsigned char maxBitrate; /* Maximum bitrate divided by 8KHz (compressed formats only) */ +} tda_edid_audio_desc; + +typedef enum { + TDA_EDID_READ = 0, /**< All blocks read OK */ + TDA_EDID_READ_INCOMPLETE = 1, /**< All blocks read OK but buffer too small to return all of them */ + TDA_EDID_ERROR_CHK_BLOCK_0 = 2, /**< Block 0 checksum error */ + TDA_EDID_ERROR_CHK = 3, /**< Block 0 OK, checksum error in one or more other blocks */ + TDA_EDID_NOT_READ = 4, /**< EDID not read */ + TDA_EDID_STATUS_INVALID = 5 /**< Invalid */ +} tda_edid_status; + +typedef struct { + int HBR; /**< High Bitrate Audio packet */ + int DST; /**< Direct Stream Transport audio packet */ + int oneBitAudio; /**< One Bit Audio sample packet */ +} tda_audio_packet; + +typedef enum { + TDA_AFMT_SPDIF = 0, /**< SPDIF */ + TDA_AFMT_I2S = 1, /**< I2S */ + TDA_AFMT_OBA = 2, /**< One bit audio / DSD */ + TDA_AFMT_DST = 3, /**< DST */ + TDA_AFMT_HBR = 4 /**< HBR */ +} tda_audio_format; + +typedef enum { + TDA_AFS_32K = 0, /**< 32kHz */ + TDA_AFS_44K = 1, /**< 44.1kHz */ + TDA_AFS_48K = 2, /**< 48kHz */ + TDA_AFS_88K = 3, /**< 88.2kHz */ + TDA_AFS_96K = 4, /**< 96kHz */ + TDA_AFS_176K = 5, /**< 176.4kHz */ + TDA_AFS_192K = 6 /**< 192kHz */ +} tda_audio_rate; + +typedef enum { + TDA_I2SQ_16BITS = 16, /**< 16 bits */ + TDA_I2SQ_32BITS = 32, /**< 32 bits */ + TDA_I2SQ_OTHERS = 0 /**< for SPDIF and DSD */ +} tda_audio_I2S_qualifier; + +typedef enum { + TDA_I2SFOR_PHILIPS_L = 0, /**< Philips like format */ + TDA_I2SFOR_OTH_L = 2, /**< Other non Philips left justified */ + TDA_I2SFOR_OTH_R = 3, /**< Other non Philips right justified */ + TDA_I2SFOR_INVALID = 4 /**< Invalid format */ +} tda_audio_I2S_format; + +typedef enum { + TDA_DSTRATE_SINGLE = 0, /**< Single transfer rate */ + TDA_DSTRATE_DOUBLE = 1 /**< Double data rate */ +} tda_dst_rate; + +typedef struct { + int simplayHd; /**< Enable simplayHD support */ + int repeaterEnable; /**< Enable repeater mode */ + unsigned char *pEdidBuffer; /**< Pointer to raw EDID data */ + unsigned long edidBufferSize; /**< Size of buffer for raw EDID data */ +} tda_instance_setup_info; + +typedef enum { + TDA_VFMT_NULL = 0, /**< Not a valid format... */ + TDA_VFMT_NO_CHANGE = 0, /**< ...or no change required */ + TDA_VFMT_MIN = 1, /**< Lowest valid format */ + TDA_VFMT_TV_MIN = 1, /**< Lowest valid TV format */ + TDA_VFMT_01_640x480p_60Hz = 1, /**< Format 01 640 x 480p 60Hz */ + TDA_VFMT_02_720x480p_60Hz = 2, /**< Format 02 720 x 480p 60Hz */ + TDA_VFMT_03_720x480p_60Hz = 3, /**< Format 03 720 x 480p 60Hz */ + TDA_VFMT_04_1280x720p_60Hz = 4, /**< Format 04 1280 x 720p 60Hz */ + TDA_VFMT_05_1920x1080i_60Hz = 5, /**< Format 05 1920 x 1080i 60Hz */ + TDA_VFMT_06_720x480i_60Hz = 6, /**< Format 06 720 x 480i 60Hz */ + TDA_VFMT_07_720x480i_60Hz = 7, /**< Format 07 720 x 480i 60Hz */ + TDA_VFMT_08_720x240p_60Hz = 8, /**< Format 08 720 x 240p 60Hz */ + TDA_VFMT_09_720x240p_60Hz = 9, /**< Format 09 720 x 240p 60Hz */ + TDA_VFMT_10_720x480i_60Hz = 10, /**< Format 10 720 x 480i 60Hz */ + TDA_VFMT_11_720x480i_60Hz = 11, /**< Format 11 720 x 480i 60Hz */ + TDA_VFMT_12_720x240p_60Hz = 12, /**< Format 12 720 x 240p 60Hz */ + TDA_VFMT_13_720x240p_60Hz = 13, /**< Format 13 720 x 240p 60Hz */ + TDA_VFMT_14_1440x480p_60Hz = 14, /**< Format 14 1440 x 480p 60Hz */ + TDA_VFMT_15_1440x480p_60Hz = 15, /**< Format 15 1440 x 480p 60Hz */ + TDA_VFMT_16_1920x1080p_60Hz = 16, /**< Format 16 1920 x 1080p 60Hz */ + TDA_VFMT_17_720x576p_50Hz = 17, /**< Format 17 720 x 576p 50Hz */ + TDA_VFMT_18_720x576p_50Hz = 18, /**< Format 18 720 x 576p 50Hz */ + TDA_VFMT_19_1280x720p_50Hz = 19, /**< Format 19 1280 x 720p 50Hz */ + TDA_VFMT_20_1920x1080i_50Hz = 20, /**< Format 20 1920 x 1080i 50Hz */ + TDA_VFMT_21_720x576i_50Hz = 21, /**< Format 21 720 x 576i 50Hz */ + TDA_VFMT_22_720x576i_50Hz = 22, /**< Format 22 720 x 576i 50Hz */ + TDA_VFMT_23_720x288p_50Hz = 23, /**< Format 23 720 x 288p 50Hz */ + TDA_VFMT_24_720x288p_50Hz = 24, /**< Format 24 720 x 288p 50Hz */ + TDA_VFMT_25_720x576i_50Hz = 25, /**< Format 25 720 x 576i 50Hz */ + TDA_VFMT_26_720x576i_50Hz = 26, /**< Format 26 720 x 576i 50Hz */ + TDA_VFMT_27_720x288p_50Hz = 27, /**< Format 27 720 x 288p 50Hz */ + TDA_VFMT_28_720x288p_50Hz = 28, /**< Format 28 720 x 288p 50Hz */ + TDA_VFMT_29_1440x576p_50Hz = 29, /**< Format 29 1440 x 576p 50Hz */ + TDA_VFMT_30_1440x576p_50Hz = 30, /**< Format 30 1440 x 576p 50Hz */ + TDA_VFMT_31_1920x1080p_50Hz = 31, /**< Format 31 1920 x 1080p 50Hz */ + TDA_VFMT_32_1920x1080p_24Hz = 32, /**< Format 32 1920 x 1080p 24Hz */ + TDA_VFMT_33_1920x1080p_25Hz = 33, /**< Format 33 1920 x 1080p 25Hz */ + TDA_VFMT_34_1920x1080p_30Hz = 34, /**< Format 34 1920 x 1080p 30Hz */ + TDA_VFMT_TV_MAX = 34, /**< Highest valid TV format */ + TDA_VFMT_TV_NO_REG_MIN = 32, /**< Lowest TV format without prefetched table */ + TDA_VFMT_TV_NUM = 35, /**< Number of TV formats & null */ + TDA_VFMT_PC_MIN = 128, /**< Lowest valid PC format */ + TDA_VFMT_PC_640x480p_60Hz = 128, /**< PC format 128 */ + TDA_VFMT_PC_800x600p_60Hz = 129, /**< PC format 129 */ + TDA_VFMT_PC_1152x960p_60Hz = 130, /**< PC format 130 */ + TDA_VFMT_PC_1024x768p_60Hz = 131, /**< PC format 131 */ + TDA_VFMT_PC_1280x768p_60Hz = 132, /**< PC format 132 */ + TDA_VFMT_PC_1280x1024p_60Hz = 133, /**< PC format 133 */ + TDA_VFMT_PC_1360x768p_60Hz = 134, /**< PC format 134 */ + TDA_VFMT_PC_1400x1050p_60Hz = 135, /**< PC format 135 */ + TDA_VFMT_PC_1600x1200p_60Hz = 136, /**< PC format 136 */ + TDA_VFMT_PC_1024x768p_70Hz = 137, /**< PC format 137 */ + TDA_VFMT_PC_640x480p_72Hz = 138, /**< PC format 138 */ + TDA_VFMT_PC_800x600p_72Hz = 139, /**< PC format 139 */ + TDA_VFMT_PC_640x480p_75Hz = 140, /**< PC format 140 */ + TDA_VFMT_PC_1024x768p_75Hz = 141, /**< PC format 141 */ + TDA_VFMT_PC_800x600p_75Hz = 142, /**< PC format 142 */ + TDA_VFMT_PC_1024x864p_75Hz = 143, /**< PC format 143 */ + TDA_VFMT_PC_1280x1024p_75Hz = 144, /**< PC format 144 */ + TDA_VFMT_PC_640x350p_85Hz = 145, /**< PC format 145 */ + TDA_VFMT_PC_640x400p_85Hz = 146, /**< PC format 146 */ + TDA_VFMT_PC_720x400p_85Hz = 147, /**< PC format 147 */ + TDA_VFMT_PC_640x480p_85Hz = 148, /**< PC format 148 */ + TDA_VFMT_PC_800x600p_85Hz = 149, /**< PC format 149 */ + TDA_VFMT_PC_1024x768p_85Hz = 150, /**< PC format 150 */ + TDA_VFMT_PC_1152x864p_85Hz = 151, /**< PC format 151 */ + TDA_VFMT_PC_1280x960p_85Hz = 152, /**< PC format 152 */ + TDA_VFMT_PC_1280x1024p_85Hz = 153, /**< PC format 153 */ + TDA_VFMT_PC_1024x768i_87Hz = 154, /**< PC format 154 */ + TDA_VFMT_PC_MAX = 154, /**< Highest valid PC format */ + TDA_VFMT_PC_NUM = (1+154-128) /**< Number of PC formats */ +} tda_video_fmt_id; + +typedef struct { + tda_video_fmt_id videoFormat; /**< Video format as defined by EIA/CEA 861-D */ + int nativeVideoFormat; /**< True if format is the preferred video format */ +} tda_edid_video_desc; + +typedef struct { + tda_video_fmt_id videoFormat; /**< Video format as defined by EIA/CEA 861-D */ + int nativeVideoFormat; /**< True if format is the preferred video format */ +} tda_short_video_desc; + +typedef enum { + TDA_P_ASPECT_RATIO_UNDEFINED = 0, /**< Undefined picture aspect ratio */ + TDA_P_ASPECT_RATIO_6_5 = 1, /**< 6:5 picture aspect ratio (PAR) */ + TDA_P_ASPECT_RATIO_5_4 = 2, /**< 5:4 PAR */ + TDA_P_ASPECT_RATIO_4_3 = 3, /**< 4:3 PAR */ + TDA_P_ASPECT_RATIO_16_10 = 4, /**< 16:10 PAR */ + TDA_P_ASPECT_RATIO_5_3 = 5, /**< 5:3 PAR */ + TDA_P_ASPECT_RATIO_16_9 = 6, /**< 16:9 PAR */ + TDA_P_ASPECT_RATIO_9_5 = 7 /**< 9:5 PAR */ +} tda_pict_aspect_ratio; + +typedef enum { + TDA_VFREQ_24Hz = 0, /**< 24Hz */ + TDA_VFREQ_25Hz = 1, /**< 25Hz */ + TDA_VFREQ_30Hz = 2, /**< 30Hz */ + TDA_VFREQ_50Hz = 3, /**< 50Hz */ + TDA_VFREQ_59Hz = 4, /**< 59.94Hz */ + TDA_VFREQ_60Hz = 5, /**< 60Hz */ + TDA_VFREQ_70Hz = 6, /**< 70Hz */ + TDA_VFREQ_72Hz = 7, /**< 72Hz */ + TDA_VFREQ_75Hz = 8, /**< 75Hz */ + TDA_VFREQ_85Hz = 9, /**< 85Hz */ + TDA_VFREQ_87Hz = 10, /**< 87Hz */ + TDA_VFREQ_INVALID = 11, /**< Invalid */ + TDA_VFREQ_NUM = 11 /**< No. of values */ +} tda_vfreq; + +typedef struct { + unsigned short width; /**< Width of the frame in pixels */ + unsigned short height; /**< Height of the frame in pixels */ + int interlaced; /**< Interlaced mode (True/False) */ + tda_vfreq vfrequency; /**< Vertical frequency in Hz */ + tda_pict_aspect_ratio aspectRatio; /**< Picture aspect ratio (H:V) */ +} tda_video_fmt_specs; + +typedef enum { + TDA_VINMODE_CCIR656 = 0, /**< CCIR656 */ + TDA_VINMODE_RGB444 = 1, /**< RGB444 */ + TDA_VINMODE_YUV444 = 2, /**< YUV444 */ + TDA_VINMODE_YUV422 = 3, /**< YUV422 */ + TDA_VINMODE_NO_CHANGE = 4, /**< No change */ + TDA_VINMODE_INVALID = 5 /**< Invalid */ +} tda_vinmode; + +typedef enum { + TDA_SYNCSRC_EMBEDDED = 0, /**< Embedded sync */ + TDA_SYNCSRC_EXT_VREF = 1, /**< External sync Vref, Href, Fref */ + TDA_SYNCSRC_EXT_VS = 2 /**< External sync Vs, Hs */ +} tda_sync_source; + +typedef enum { + TDA_PIXRATE_DOUBLE = 0, /**< Double pixel rate */ + TDA_PIXRATE_SINGLE = 1, /**< Single pixel rate */ + TDA_PIXRATE_SINGLE_REPEATED = 2 /**< Single pixel repeated */ +} tda_pix_rate; + +typedef struct { + tda_video_fmt_id format; /**< Video format as defined by EIA/CEA 861-D */ + tda_vinmode mode; /**< Video mode (CCIR, RGB, YUV, etc.) */ + tda_sync_source syncSource; /**< Sync source type */ + tda_pix_rate pixelRate; /**< Pixel rate */ +} tda_video_in; + +typedef enum { + TDA_VOUTMODE_RGB444 = 0, /**< RGB444 */ + TDA_VOUTMODE_YUV422 = 1, /**< YUV422 */ + TDA_VOUTMODE_YUV444 = 2 /**< YUV444 */ +} tda_vout_mode; + +typedef enum { + TDA_VQR_DEFAULT = 0, /* Follow HDMI spec. */ + TDA_RGB_FULL = 1, /* Force RGB FULL , DVI only */ + TDA_RGB_LIMITED = 2 /* Force RGB LIMITED , DVI only */ +} tda_vqr; + +typedef enum { + TDA_COLORDEPTH_24 = 0, /**< 8 bits per color */ + TDA_COLORDEPTH_30 = 1, /**< 10 bits per color */ + TDA_COLORDEPTH_36 = 2, /**< 12 bits per color */ + TDA_COLORDEPTH_48 = 3 /**< 16 bits per color */ +} tda_color_depth; + +typedef struct { + tda_video_fmt_id format; /**< Video format as defined by EIA/CEA 861-D */ + tda_vout_mode mode; /**< Video mode (CCIR, RGB, YUV, etc.) */ + tda_color_depth colorDepth; /**< Color depth */ + tda_vqr dviVqr; /**< VQR applied in DVI mode */ +} tda_video_out; + +typedef struct { + tda_audio_format format; /**< Audio format (I2S, SPDIF, etc.) */ + tda_audio_rate rate; /**< Audio sampling rate */ + tda_audio_I2S_format i2sFormat; /**< I2S format of the audio input */ + tda_audio_I2S_qualifier i2sQualifier; /**< I2S qualifier of the audio input (8,16,32 bits) */ + tda_dst_rate dstRate; /**< DST data transfer rate */ + unsigned char channelAllocation; /**< Ref to CEA-861D p85 */ +} tda_audio_in; + +typedef enum { + TDA_SINK_DVI = 0, /**< DVI */ + TDA_SINK_HDMI = 1, /**< HDMI */ + TDA_SINK_EDID = 2 /**< As currently defined in EDID */ +} tda_sink; + + typedef enum { + TDA_DEVICE_UNKNOWN, /**< HW device is unknown */ + TDA_DEVICE_TDA9984, /**< HW device is IC TDA9984 */ + TDA_DEVICE_TDA9989, /**< HW device is IC TDA9989 */ + TDA_DEVICE_TDA9981, /**< HW device is IC TDA9981 */ + TDA_DEVICE_TDA9983, /**< HW device is IC TDA9983 */ + TDA_DEVICE_TDA19989 /**< HW device is IC TDA19989 */ + } tda_device_version; + +typedef enum { + TDA_HDMI_VERSION_UNKNOWN, /**< Unknown */ + TDA_HDMI_VERSION_1_1, /**< HDMI 1.1 */ + TDA_HDMI_VERSION_1_2a, /**< HDMI 1.2a */ + TDA_HDMI_VERSION_1_3a /**< HDMI 1.3 */ +} tda_hdmi_version; + +typedef struct { + int HBR; /**< High Bitrate Audio packet */ + int DST; /**< Direct Stream Transport audio packet */ + int oneBitAudio; /**< One Bit Audio sample packet */ +} tda_audio_packet; + +typedef enum { + TDA_COLORDEPTH_24 = 0, /**< 8 bits per color */ + TDA_COLORDEPTH_30 = 1, /**< 10 bits per color */ + TDA_COLORDEPTH_36 = 2, /**< 12 bits per color */ + TDA_COLORDEPTH_48 = 3 /**< 16 bits per color */ +} tda_color_depth; + +typedef struct { + tda_device_version deviceVersion; /**< HW device version */ + tda_hdmi_version hdmiVersion; /**< Supported HDMI standard version */ + tda_audio_packet audioPacket; /**< Supported audio packets */ + tda_color_depth colorDepth; /**< Supported color depth */ + int hdcp; /**< Supported Hdcp encryption (True/False) */ + int scaler; /**< Supported scaler (True/False) */ +} tda_capabilities; + +typedef struct { + unsigned long compatibilityNr; // Interface compatibility number + unsigned long majorVersionNr; // Interface major version number + unsigned long minorVersionNr; // Interface minor version number +} tda_version; + +typedef enum +{ + PowerOn, // Device powered on (D0 state) + PowerStandby, // Device power standby (D1 state) + PowerSuspend, // Device power suspended (D2 state) + PowerOff // Device powered off (D3 state) +} tda_powerXXX; + +typedef struct { + unsigned int simplayHd; /**< Enable simplayHD support */ + unsigned int repeaterEnable; /**< Enable repeater mode */ + unsigned char *pEdidBuffer; /**< Pointer to raw EDID data */ + unsigned long edidBufferSize; /**< Size of buffer for raw EDID data */ +} tda_setup; + +typedef struct { + tda_video_fmt_id id; + tda_video_fmt_specs spec; +} tda_video_format; + +typedef struct { + tda_video_in video_in; + tda_video_out video_out; + tda_audio_in audio_in; +} tda_set_in_out; + +typedef struct { + tda_edid_audio_desc desc; + unsigned int max; + unsigned int written; + unsigned char flags; +} tda_edid_audio_caps; + +typedef struct { + tda_edid_video_desc desc; + unsigned int max; + unsigned int written; + unsigned char flags; +} tda_edid_video_caps; + +typedef struct { + tda_edid_status status; + unsigned char block_count; +} tda_edid; + +#endif + +#define TDA_IOCTL_BASE 0x40 +#define RELEASE 0xFF + +enum { + /* driver specific */ + TDA_VERBOSE_ON_CMD = 0, + TDA_VERBOSE_OFF_CMD, + TDA_BYEBYE_CMD, + /* HDMI Tx */ + TDA_GET_SW_VERSION_CMD, + TDA_SET_POWER_CMD, + TDA_GET_POWER_CMD, + TDA_SETUP_CMD, + TDA_GET_SETUP_CMD, + TDA_WAIT_EVENT_CMD, + TDA_ENABLE_EVENT_CMD, + TDA_DISABLE_EVENT_CMD, + TDA_GET_VIDEO_SPEC_CMD, + TDA_SET_INPUT_OUTPUT_CMD, + TDA_SET_AUDIO_INPUT_CMD, + TDA_SET_VIDEO_INFOFRAME_CMD, + TDA_SET_AUDIO_INFOFRAME_CMD, + TDA_SET_ACP_CMD, + TDA_SET_GCP_CMD, + TDA_SET_ISRC1_CMD, + TDA_SET_ISRC2_CMD, + TDA_SET_MPS_INFOFRAME_CMD, + TDA_SET_SPD_INFOFRAME_CMD, + TDA_SET_VS_INFOFRAME_CMD, + TDA_SET_AUDIO_MUTE_CMD, + TDA_RESET_AUDIO_CTS_CMD, + TDA_GET_EDID_STATUS_CMD, + TDA_GET_EDID_AUDIO_CAPS_CMD, + TDA_GET_EDID_VIDEO_CAPS_CMD, + TDA_GET_EDID_VIDEO_PREF_CMD, + TDA_GET_EDID_SINK_TYPE_CMD, + TDA_GET_EDID_SOURCE_ADDRESS_CMD, + TDA_SET_GAMMUT_CMD, + TDA_GET_EDID_DTD_CMD, + TDA_GET_EDID_MD_CMD, + TDA_GET_EDID_TV_ASPECT_RATIO_CMD, + TDA_GET_EDID_LATENCY_CMD, + TDA_SET_HDCP_CMD, + TDA_GET_HDCP_STATUS_CMD, + TDA_GET_HPD_STATUS_CMD, +}; + + +/* driver specific */ +#define TDA_IOCTL_VERBOSE_ON _IO(TDA_IOCTL_BASE, TDA_VERBOSE_ON_CMD) +#define TDA_IOCTL_VERBOSE_OFF _IO(TDA_IOCTL_BASE, TDA_VERBOSE_OFF_CMD) +#define TDA_IOCTL_BYEBYE _IO(TDA_IOCTL_BASE, TDA_BYEBYE_CMD) +/* HDMI Tx */ +#define TDA_IOCTL_GET_SW_VERSION _IOWR(TDA_IOCTL_BASE, TDA_GET_SW_VERSION_CMD,tda_version) +#define TDA_IOCTL_SET_POWER _IOWR(TDA_IOCTL_BASE, TDA_SET_POWER_CMD,tda_power) +#define TDA_IOCTL_GET_POWER _IOWR(TDA_IOCTL_BASE, TDA_GET_POWER_CMD,tda_power) +#define TDA_IOCTL_SETUP _IOWR(TDA_IOCTL_BASE, TDA_SETUP_CMD,tda_setup_info) +#define TDA_IOCTL_GET_SETUP _IOWR(TDA_IOCTL_BASE, TDA_GET_SETUP_CMD,tda_setup_info) +#define TDA_IOCTL_WAIT_EVENT _IOWR(TDA_IOCTL_BASE, TDA_WAIT_EVENT_CMD,tda_event) +#define TDA_IOCTL_ENABLE_EVENT _IOWR(TDA_IOCTL_BASE, TDA_ENABLE_EVENT_CMD,tda_event) +#define TDA_IOCTL_DISABLE_EVENT _IOWR(TDA_IOCTL_BASE, TDA_DISABLE_EVENT_CMD,tda_event) +#define TDA_IOCTL_GET_VIDEO_SPEC _IOWR(TDA_IOCTL_BASE, TDA_GET_VIDEO_SPEC_CMD,tda_video_format) +#define TDA_IOCTL_SET_INPUT_OUTPUT _IOWR(TDA_IOCTL_BASE, TDA_SET_INPUT_OUTPUT_CMD,tda_set_in_out) +#define TDA_IOCTL_SET_AUDIO_INPUT _IOWR(TDA_IOCTL_BASE, TDA_SET_AUDIO_INPUT_CMD,tda_audio_in) +#define TDA_IOCTL_SET_VIDEO_INFOFRAME _IOWR(TDA_IOCTL_BASE, TDA_SET_VIDEO_INFOFRAME_CMD,tda_video_infoframe) +#define TDA_IOCTL_SET_AUDIO_INFOFRAME _IOWR(TDA_IOCTL_BASE, TDA_SET_AUDIO_INFOFRAME_CMD,tda_audio_infoframe) +#define TDA_IOCTL_SET_ACP _IOWR(TDA_IOCTL_BASE, TDA_SET_ACP_CMD,tda_acp) +#define TDA_IOCTL_SET_GCP _IOWR(TDA_IOCTL_BASE, TDA_SET_GCP_CMD,tda_gcp) +#define TDA_IOCTL_SET_ISRC1 _IOWR(TDA_IOCTL_BASE, TDA_SET_ISRC1_CMD,tda_isrc1) +#define TDA_IOCTL_SET_ISRC2 _IOWR(TDA_IOCTL_BASE, TDA_SET_ISRC2_CMD,tda_isrc2) +#define TDA_IOCTL_SET_MPS_INFOFRAME _IOWR(TDA_IOCTL_BASE, TDA_SET_MPS_INFOFRAME_CMD,tda_mps_infoframe) +#define TDA_IOCTL_SET_SPD_INFOFRAME _IOWR(TDA_IOCTL_BASE, TDA_SET_SPD_INFOFRAME_CMD,tda_spd_infoframe) +#define TDA_IOCTL_SET_VS_INFOFRAME _IOWR(TDA_IOCTL_BASE, TDA_SET_VS_INFOFRAME_CMD,tda_vs_infoframe) +#define TDA_IOCTL_SET_AUDIO_MUTE _IOWR(TDA_IOCTL_BASE, TDA_SET_AUDIO_MUTE_CMD,bool) +#define TDA_IOCTL_RESET_AUDIO_CTS _IO(TDA_IOCTL_BASE, TDA_RESET_AUDIO_CTS_CMD) +#define TDA_IOCTL_GET_EDID_STATUS _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_STATUS_CMD,tda_edid) +#define TDA_IOCTL_GET_EDID_AUDIO_CAPS _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_AUDIO_CAPS_CMD,tda_edid_audio_caps) +#define TDA_IOCTL_GET_EDID_VIDEO_CAPS _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_VIDEO_CAPS_CMD,tda_edid_video_caps) +#define TDA_IOCTL_GET_EDID_VIDEO_PREF _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_VIDEO_PREF_CMD,tda_edid_video_timings) +#define TDA_IOCTL_GET_EDID_SINK_TYPE _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_SINK_TYPE_CMD,tda_sink) +#define TDA_IOCTL_GET_EDID_SOURCE_ADDRESS _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_SOURCE_ADDRESS_CMD,unsigned short) +#define TDA_IOCTL_SET_GAMMUT _IOWR(TDA_IOCTL_BASE, TDA_SET_GAMMUT_CMD,tda_gammut) +#define TDA_IOCTL_GET_EDID_DTD _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_DTD_CMD,tda_edid_dtd) +#define TDA_IOCTL_GET_EDID_MD _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_MD_CMD,tda_edid_md) +#define TDA_IOCTL_GET_EDID_TV_ASPECT_RATIO _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_TV_ASPECT_RATIO_CMD,tda_edid_tv_aspect_ratio) +#define TDA_IOCTL_GET_HPD_STATUS _IOWR(TDA_IOCTL_BASE, TDA_GET_HPD_STATUS_CMD, tmdlHdmiTxHotPlug_t) +#ifdef TMFL_TDA19989 +#define TDA_IOCTL_GET_EDID_LATENCY _IOWR(TDA_IOCTL_BASE, TDA_GET_EDID_LATENCY_CMD,tda_edid_latency) +#define TDA_IOCTL_SET_HDCP _IOWR(TDA_IOCTL_BASE, TDA_SET_HDCP_CMD,bool) +#define TDA_IOCTL_GET_HDCP_STATUS _IOWR(TDA_IOCTL_BASE, TDA_GET_HDCP_STATUS_CMD,tda_hdcp_status) +#endif + + +/* --- Full list --- */ + +/* legend: */ +/* ------- */ +/* [ ] : not supported */ +/* [x] : IOCTL */ +/* [i] : open, init... */ + +/* [x] tmdlHdmiTxGetSWVersion */ +/* [ ] tmdlHdmiTxGetNumberOfUnits */ +/* [i] tmdlHdmiTxGetCapabilities */ +/* [ ] tmdlHdmiTxGetCapabilitiesM */ +/* [i] tmdlHdmiTxOpen */ +/* [ ] tmdlHdmiTxOpenM */ +/* [i] tmdlHdmiTxClose */ +/* [x] tmdlHdmiTxSetPowerState */ +/* [x] tmdlHdmiTxGetPowerState */ +/* [ ] tmdlHdmiTxInstanceConfig */ +/* [xi] tmdlHdmiTxInstanceSetup */ +/* [x] tmdlHdmiTxGetInstanceSetup */ +/* [x] tmdlHdmiTxHandleInterrupt see IOCTL_WAIT_EVENT */ +/* [i] tmdlHdmiTxRegisterCallbacks */ +/* [x] tmdlHdmiTxEnableEvent */ +/* [x] tmdlHdmiTxDisableEvent */ +/* [x] tmdlHdmiTxGetVideoFormatSpecs */ +/* [x] tmdlHdmiTxSetInputOutput */ +/* [x] tmdlHdmiTxSetAudioInput */ +/* [x] tmdlHdmiTxSetVideoInfoframe */ +/* [x] tmdlHdmiTxSetAudioInfoframe */ +/* [x] tmdlHdmiTxSetACPPacket */ +/* [x] tmdlHdmiTxSetGeneralControlPacket */ +/* [x] tmdlHdmiTxSetISRC1Packet */ +/* [x] tmdlHdmiTxSetISRC2Packet */ +/* [x] tmdlHdmiTxSetMPSInfoframe */ +/* [x] tmdlHdmiTxSetSpdInfoframe */ +/* [x] tmdlHdmiTxSetVsInfoframe */ +/* [ ] tmdlHdmiTxDebugSetNullPacket */ +/* [ ] tmdlHdmiTxDebugSetSingleNullPacket */ +/* [x] tmdlHdmiTxSetAudioMute */ +/* [x] tmdlHdmiTxResetAudioCts */ +/* [x] tmdlHdmiTxGetEdidStatus */ +/* [x] tmdlHdmiTxGetEdidAudioCaps */ +/* [x] tmdlHdmiTxGetEdidVideoCaps */ +/* [x] tmdlHdmiTxGetEdidVideoPreferred */ +/* [x] tmdlHdmiTxGetEdidSinkType */ +/* [x] tmdlHdmiTxGetEdidSourceAddress */ +/* [ ] tmdlHdmiTxGetKsvList */ +/* [ ] tmdlHdmiTxGetDepth */ +/* [ ] tmdlHdmiTxGeneSHA_1_IT */ +/* [ ] tmdlHdmiTxSetHdcp */ +/* [ ] tmdlHdmiTxGetHdcpState */ +/* [ ] tmdlHdmiTxHdcpCheck */ +/* [x] tmdlHdmiTxSetGamutPacket */ +/* [x] tmdlHdmiTxGetEdidDetailledTimingDescriptors */ +/* [x] tmdlHdmiTxGetEdidMonitorDescriptors */ +/* [x] tmdlHdmiTxGetEdidTVPictureRatio */ +/* [ ] tmdlHdmiTxSetHDCPRevocationList */ +/* [ ] tmdlHdmiTxGetHdcpFailStatus */ +/* [x] tmdlHdmiTxGetEdidLatencyInfo */ +/* [ ] tmdlHdmiTxSetBScreen */ +/* [ ] tmdlHdmiTxRemoveBScreen */ + + +#endif /* __tx_h__ */ +#endif /* __tx_ioctl__ */ + +#ifndef __cec_ioctl__ +#define __cec_ioctl__ + +#ifdef __cec_h__ + +typedef struct { + UInt8 DayOfMonth; + UInt8 MonthOfYear; + UInt16 StartTime; + tmdlHdmiCECDuration_t Duration; + UInt8 RecordingSequence; + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType; + UInt16 AnalogueFrequency; + tmdlHdmiCECBroadcastSystem_t BroadcastSystem; +} cec_analogue_timer; + +typedef struct { + UInt8 DayOfMonth; + UInt8 MonthOfYear; + UInt16 StartTime; + tmdlHdmiCECDuration_t Duration; + UInt8 RecordingSequence; + tmdlHdmiCECDigitalServiceIdentification_t ServiceIdentification; +} cec_digital_timer; + +typedef struct { + UInt8 DayOfMonth; + UInt8 MonthOfYear; + UInt16 StartTime; + tmdlHdmiCECDuration_t Duration; + UInt8 RecordingSequence; + tmdlHdmiCECExternalPlug_t ExternalPlug; +} cec_ext_timer_with_ext_plug; + +typedef struct { + UInt8 DayOfMonth; + UInt8 MonthOfYear; + UInt16 StartTime; + tmdlHdmiCECDuration_t Duration; + UInt8 RecordingSequence; + tmdlHdmiCECExternalPhysicalAddress_t ExternalPhysicalAddress; +} cec_ext_timer_with_phy_addr; + +typedef struct { + tmdlHdmiCECFeatureOpcode_t FeatureOpcode; + tmdlHdmiCECAbortReason_t AbortReason; +} cec_feature_abort; + +typedef struct { + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType; + UInt16 AnalogueFrequency; + tmdlHdmiCECBroadcastSystem_t BroadcastSystem; +} cec_analogue_service; + +typedef struct { + UInt16 OriginalAddress; + UInt16 NewAddress; +} cec_routing_change; + +typedef struct { + char data[15]; + unsigned char length; +} cec_string; + +typedef struct { + tmdlHdmiCECDisplayControl_t DisplayControl; + char data[15]; + unsigned char length; +} cec_osd_string; + +typedef struct { + tmdlHdmiCECRecordingFlag_t RecordingFlag; + tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo; + tmdlHdmiCECAnalogueBroadcastType_t AnalogueBroadcastType; + UInt16 AnalogueFrequency; + tmdlHdmiCECBroadcastSystem_t BroadcastSystem; +} cec_tuner_device_status_analogue; + +typedef struct { + tmdlHdmiCECRecordingFlag_t RecordingFlag; + tmdlHdmiCECTunerDisplayInfo_t TunerDisplayInfo; + tmdlHdmiCECDigitalServiceIdentification_t ServiceIdentification; +} cec_tuner_device_status_digital; + +typedef struct { + unsigned long VendorID; + cec_string cmd; +} cec_vendor_command_with_id; + +/* + typedef struct { + UInt8 *pData; + UInt16 lenData; + } cec_send_msg; +*/ + +typedef struct +{ + unsigned char count; + unsigned char service; + unsigned char addr; + unsigned char data[15]; +} cec_frame; +/* typedef tmdlHdmiCecFrameFormat_t cec_frame; */ + +typedef tmSWVersion_t cec_sw_version; +typedef tmPowerState_t cec_power; +typedef tmdlHdmiCecInstanceSetup_t cec_setup; +typedef tmdlHdmiCecEvent_t cec_event; +typedef tmdlHdmiCecClockSource_t cec_clock; +typedef tmdlHdmiCECSystemAudioStatus_t cec_sys_audio_status; +typedef tmdlHdmiCECAudioRate_t cec_audio_rate; +typedef tmdlHdmiCECDigitalServiceIdentification_t cec_digital_service; +typedef tmdlHdmiCECVersion_t cec_version; +typedef tmdlHdmiCECDecControlMode_t cec_deck_ctrl; +typedef tmdlHdmiCECDecInfo_t cec_deck_status; +typedef tmdlHdmiCECStatusRequest_t cec_status_request; +typedef tmdlHdmiCECMenuRequestType_t cec_menu_request; +typedef tmdlHdmiCECMenuState_t cec_menu_status; +typedef tmdlHdmiCECPlayMode_t cec_play; +typedef tmdlHdmiCECExternalPlug_t cec_ext_plug; +typedef tmdlHdmiCECRecordStatusInfo_t cec_rec_status; +typedef tmdlHdmiCECAudioStatus_t cec_audio_status; +typedef tmdlHdmiCECPowerStatus_t cec_power_status; +typedef tmdlHdmiCECTimerClearedStatusData_t cec_timer_cleared_status; +typedef tmdlHdmiCECTimerStatusData_t cec_timer_status; +typedef tmdlHdmiCECUserRemoteControlCommand_t cec_user_ctrl; +typedef tmdlHdmiCECChannelIdentifier_t cec_user_ctrl_tune; +typedef tmdlHdmiCECDeviceType_t cec_device_type; + +#define CEC_IOCTL_BASE 0x40 + +/* service */ +enum { + CEC_WAITING = 0x80, + CEC_RELEASE, + CEC_RX_DONE, + CEC_TX_DONE +}; + +enum { + /* driver specific */ + CEC_VERBOSE_ON_CMD = 0, + CEC_VERBOSE_OFF_CMD, + CEC_BYEBYE_CMD, + + /* CEC */ + CEC_IOCTL_RX_ADDR_CMD, /* receiver logical address selector */ + CEC_IOCTL_PHY_ADDR_CMD, /* physical address selector */ + CEC_IOCTL_WAIT_FRAME_CMD, + CEC_IOCTL_ABORT_MSG_CMD, + CEC_IOCTL_ACTIVE_SRC_CMD, + CEC_IOCTL_VERSION_CMD, + CEC_IOCTL_CLEAR_ANALOGUE_TIMER_CMD, + CEC_IOCTL_CLEAR_DIGITAL_TIMER_CMD, + CEC_IOCTL_CLEAR_EXT_TIMER_WITH_EXT_PLUG_CMD, + CEC_IOCTL_CLEAR_EXT_TIMER_WITH_PHY_ADDR_CMD, + CEC_IOCTL_DECK_CTRL_CMD, + CEC_IOCTL_DECK_STATUS_CMD, + CEC_IOCTL_DEVICE_VENDOR_ID_CMD, + CEC_IOCTL_FEATURE_ABORT_CMD, + CEC_IOCTL_GET_CEC_VERSION_CMD, + CEC_IOCTL_GET_MENU_LANGUAGE_CMD, + CEC_IOCTL_GIVE_AUDIO_STATUS_CMD, + CEC_IOCTL_GIVE_DECK_STATUS_CMD, + CEC_IOCTL_GIVE_DEVICE_POWER_STATUS_CMD, + CEC_IOCTL_GIVE_DEVICE_VENDOR_ID_CMD, + CEC_IOCTL_GIVE_OSD_NAME_CMD, + CEC_IOCTL_GIVE_PHY_ADDR_CMD, + CEC_IOCTL_GIVE_SYS_AUDIO_MODE_STATUS_CMD, + CEC_IOCTL_GIVE_TUNER_DEVICE_STATUS_CMD, + CEC_IOCTL_IMAGE_VIEW_ON_CMD, + CEC_IOCTL_INACTIVE_SRC_CMD, + CEC_IOCTL_MENU_REQUEST_CMD, + CEC_IOCTL_MENU_STATUS_CMD, + CEC_IOCTL_PLAY_CMD, + CEC_IOCTL_POLLING_MSG_CMD, + CEC_IOCTL_REC_OFF_CMD, + CEC_IOCTL_REC_ON_ANALOGUE_SERVICE_CMD, + CEC_IOCTL_REC_ON_DIGITAL_SERVICE_CMD, + CEC_IOCTL_REC_ON_EXT_PHY_ADDR_CMD, + CEC_IOCTL_REC_ON_EXT_PLUG_CMD, + CEC_IOCTL_REC_ON_OWN_SRC_CMD, + CEC_IOCTL_REC_STATUS_CMD, + CEC_IOCTL_REC_TV_SCREEN_CMD, + CEC_IOCTL_REPORT_AUDIO_STATUS_CMD, + CEC_IOCTL_REPORT_PHY_ADDR_CMD, + CEC_IOCTL_REPORT_POWER_STATUS_CMD, + CEC_IOCTL_REQUEST_ACTIVE_SRC_CMD, + CEC_IOCTL_ROUTING_CHANGE_CMD, + CEC_IOCTL_ROUTING_INFORMATION_CMD, + CEC_IOCTL_SELECT_ANALOGUE_SERVICE_CMD, + CEC_IOCTL_SELECT_DIGITAL_SERVICE_CMD, + CEC_IOCTL_SET_ANALOGUE_TIMER_CMD, + CEC_IOCTL_SET_AUDIO_RATE_CMD, + CEC_IOCTL_SET_DIGITAL_TIMER_CMD, + CEC_IOCTL_SET_EXT_TIMER_WITH_EXT_PLUG_CMD, + CEC_IOCTL_SET_EXT_TIMER_WITH_PHY_ADDR_CMD, + CEC_IOCTL_SET_MENU_LANGUAGE_CMD, + CEC_IOCTL_SET_OSD_NAME_CMD, + CEC_IOCTL_SET_OSD_STRING_CMD, + CEC_IOCTL_SET_STREAM_PATH_CMD, + CEC_IOCTL_SET_SYS_AUDIO_MODE_CMD, + CEC_IOCTL_SET_TIMER_PROGRAM_TITLE_CMD, + CEC_IOCTL_STANDBY_CMD, + CEC_IOCTL_SYS_AUDIO_MODE_REQUEST_CMD, + CEC_IOCTL_SYS_AUDIO_MODE_STATUS_CMD, + CEC_IOCTL_TEXT_VIEW_ON_CMD, + CEC_IOCTL_TIMER_CLEARED_STATUS_CMD, + CEC_IOCTL_TIMER_STATUS_CMD, + CEC_IOCTL_TUNER_DEVICE_STATUS_ANALOGUE_CMD, + CEC_IOCTL_TUNER_DEVICE_STATUS_DIGITAL_CMD, + CEC_IOCTL_TUNER_STEP_DECREMENT_CMD, + CEC_IOCTL_TUNER_STEP_INCREMENT_CMD, + CEC_IOCTL_USER_CTRL_CMD, + CEC_IOCTL_USER_CTRL_PLAY_CMD, + CEC_IOCTL_USER_CTRL_SELECT_AUDIOINPUT_CMD, + CEC_IOCTL_USER_CTRL_SELECT_AVINPUT_CMD, + CEC_IOCTL_USER_CTRL_SELECT_MEDIA_CMD, + CEC_IOCTL_USER_CTRL_TUNE_CMD, + CEC_IOCTL_USER_CTRL_RELEASED_CMD, + CEC_IOCTL_VENDOR_COMMAND_CMD, + CEC_IOCTL_VENDOR_COMMAND_WITH_ID_CMD, + CEC_IOCTL_VENDOR_REMOTE_BUTTON_DOWN_CMD, + CEC_IOCTL_VENDOR_REMOTE_BUTTON_UP_CMD, + CEC_IOCTL_GET_SW_VERSION_CMD, + CEC_IOCTL_SET_POWER_STATE_CMD, + CEC_IOCTL_GET_POWER_STATE_CMD, + CEC_IOCTL_INSTANCE_CONFIG_CMD, + CEC_IOCTL_INSTANCE_SETUP_CMD, + CEC_IOCTL_GET_INSTANCE_SETUP_CMD, + CEC_IOCTL_ENABLE_EVENT_CMD, + CEC_IOCTL_DISABLE_EVENT_CMD, + CEC_IOCTL_ENABLE_CALIBRATION_CMD, + CEC_IOCTL_DISABLE_CALIBRATION_CMD, + CEC_IOCTL_SEND_MSG_CMD, + CEC_IOCTL_SET_REGISTER_CMD +}; + + +/* driver specific */ +#define CEC_IOCTL_VERBOSE_ON _IO(CEC_IOCTL_BASE, CEC_VERBOSE_ON_CMD) +#define CEC_IOCTL_VERBOSE_OFF _IO(CEC_IOCTL_BASE, CEC_VERBOSE_OFF_CMD) +#define CEC_IOCTL_BYEBYE _IO(CEC_IOCTL_BASE, CEC_BYEBYE_CMD) + +/* CEC */ +#define CEC_IOCTL_RX_ADDR _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_RX_ADDR_CMD,unsigned char) +#define CEC_IOCTL_PHY_ADDR _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_PHY_ADDR_CMD,unsigned short) +#define CEC_IOCTL_WAIT_FRAME _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_WAIT_FRAME_CMD,cec_frame) +#define CEC_IOCTL_ABORT_MSG _IO(CEC_IOCTL_BASE,CEC_IOCTL_ABORT_MSG_CMD) +#define CEC_IOCTL_ACTIVE_SRC _IO(CEC_IOCTL_BASE,CEC_IOCTL_ACTIVE_SRC_CMD) +#define CEC_IOCTL_VERSION _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_VERSION_CMD,cec_version) +#define CEC_IOCTL_CLEAR_ANALOGUE_TIMER _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_CLEAR_ANALOGUE_TIMER_CMD,cec_analogue_timer) +#define CEC_IOCTL_CLEAR_DIGITAL_TIMER _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_CLEAR_DIGITAL_TIMER_CMD,cec_digital_timer) +#define CEC_IOCTL_CLEAR_EXT_TIMER_WITH_EXT_PLUG _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_CLEAR_EXT_TIMER_WITH_EXT_PLUG_CMD,cec_ext_timer_with_ext_plug) +#define CEC_IOCTL_CLEAR_EXT_TIMER_WITH_PHY_ADDR _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_CLEAR_EXT_TIMER_WITH_PHY_ADDR_CMD,cec_ext_timer_with_phy_addr) +#define CEC_IOCTL_DECK_CTRL _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_DECK_CTRL_CMD,cec_deck_ctrl) +#define CEC_IOCTL_DECK_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_DECK_STATUS_CMD,cec_deck_status) +#define CEC_IOCTL_DEVICE_VENDOR_ID _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_DEVICE_VENDOR_ID_CMD,unsigned long) +#define CEC_IOCTL_FEATURE_ABORT _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_FEATURE_ABORT_CMD,cec_feature_abort) +#define CEC_IOCTL_GET_CEC_VERSION _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_GET_CEC_VERSION_CMD,unsigned char) +#define CEC_IOCTL_GET_MENU_LANGUAGE _IO(CEC_IOCTL_BASE,CEC_IOCTL_GET_MENU_LANGUAGE_CMD) +#define CEC_IOCTL_GIVE_AUDIO_STATUS _IO(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_AUDIO_STATUS_CMD) +#define CEC_IOCTL_GIVE_DECK_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_DECK_STATUS_CMD,cec_status_request) +#define CEC_IOCTL_GIVE_DEVICE_POWER_STATUS _IO(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_DEVICE_POWER_STATUS_CMD) +#define CEC_IOCTL_GIVE_DEVICE_VENDOR_ID _IO(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_DEVICE_VENDOR_ID_CMD) +#define CEC_IOCTL_GIVE_OSD_NAME _IO(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_OSD_NAME_CMD) +#define CEC_IOCTL_GIVE_PHY_ADDR _IO(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_PHY_ADDR_CMD) +#define CEC_IOCTL_GIVE_SYS_AUDIO_MODE_STATUS _IO(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_SYS_AUDIO_MODE_STATUS_CMD) +#define CEC_IOCTL_GIVE_TUNER_DEVICE_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_GIVE_TUNER_DEVICE_STATUS_CMD,cec_status_request) +#define CEC_IOCTL_IMAGE_VIEW_ON _IO(CEC_IOCTL_BASE,CEC_IOCTL_IMAGE_VIEW_ON_CMD) +#define CEC_IOCTL_INACTIVE_SRC _IO(CEC_IOCTL_BASE,CEC_IOCTL_INACTIVE_SRC_CMD) +#define CEC_IOCTL_MENU_REQUEST _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_MENU_REQUEST_CMD,cec_menu_request) +#define CEC_IOCTL_MENU_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_MENU_STATUS_CMD,cec_menu_status) +#define CEC_IOCTL_PLAY _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_PLAY_CMD,cec_play) +#define CEC_IOCTL_POLLING_MSG _IO(CEC_IOCTL_BASE,CEC_IOCTL_POLLING_MSG_CMD) +#define CEC_IOCTL_REC_OFF _IO(CEC_IOCTL_BASE,CEC_IOCTL_REC_OFF_CMD) +#define CEC_IOCTL_REC_ON_ANALOGUE_SERVICE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REC_ON_ANALOGUE_SERVICE_CMD,cec_analogue_service) +#define CEC_IOCTL_REC_ON_DIGITAL_SERVICE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REC_ON_DIGITAL_SERVICE_CMD,cec_digital_service) +#define CEC_IOCTL_REC_ON_EXT_PHY_ADDR _IO(CEC_IOCTL_BASE,CEC_IOCTL_REC_ON_EXT_PHY_ADDR_CMD) +#define CEC_IOCTL_REC_ON_EXT_PLUG _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REC_ON_EXT_PLUG_CMD,cec_ext_plug) +#define CEC_IOCTL_REC_ON_OWN_SRC _IO(CEC_IOCTL_BASE,CEC_IOCTL_REC_ON_OWN_SRC_CMD) +#define CEC_IOCTL_REC_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REC_STATUS_CMD,cec_rec_status) +#define CEC_IOCTL_REC_TV_SCREEN _IO(CEC_IOCTL_BASE,CEC_IOCTL_REC_TV_SCREEN_CMD) +#define CEC_IOCTL_REPORT_AUDIO_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REPORT_AUDIO_STATUS_CMD,cec_audio_status) +#define CEC_IOCTL_REPORT_PHY_ADDR _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REPORT_PHY_ADDR_CMD,cec_device_type) +#define CEC_IOCTL_REPORT_POWER_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_REPORT_POWER_STATUS_CMD,cec_power_status) +#define CEC_IOCTL_REQUEST_ACTIVE_SRC _IO(CEC_IOCTL_BASE,CEC_IOCTL_REQUEST_ACTIVE_SRC_CMD) +#define CEC_IOCTL_ROUTING_CHANGE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_ROUTING_CHANGE_CMD,cec_routing_change) +#define CEC_IOCTL_ROUTING_INFORMATION _IO(CEC_IOCTL_BASE,CEC_IOCTL_ROUTING_INFORMATION_CMD) +#define CEC_IOCTL_SELECT_ANALOGUE_SERVICE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SELECT_ANALOGUE_SERVICE_CMD,cec_analogue_service) +#define CEC_IOCTL_SELECT_DIGITAL_SERVICE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SELECT_DIGITAL_SERVICE_CMD,cec_digital_service) +#define CEC_IOCTL_SET_ANALOGUE_TIMER _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_ANALOGUE_TIMER_CMD,cec_analogue_timer) +#define CEC_IOCTL_SET_AUDIO_RATE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_AUDIO_RATE_CMD,cec_audio_rate) +#define CEC_IOCTL_SET_DIGITAL_TIMER _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_DIGITAL_TIMER_CMD,cec_digital_timer) +#define CEC_IOCTL_SET_EXT_TIMER_WITH_EXT_PLUG _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_EXT_TIMER_WITH_EXT_PLUG_CMD,cec_ext_timer_with_ext_plug) +#define CEC_IOCTL_SET_EXT_TIMER_WITH_PHY_ADDR _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_EXT_TIMER_WITH_PHY_ADDR_CMD,cec_ext_timer_with_phy_addr) +#define CEC_IOCTL_SET_MENU_LANGUAGE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_MENU_LANGUAGE_CMD,cec_string) +#define CEC_IOCTL_SET_OSD_NAME _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_OSD_NAME_CMD,cec_string) +#define CEC_IOCTL_SET_OSD_STRING _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_OSD_STRING_CMD,cec_osd_string) +#define CEC_IOCTL_SET_STREAM_PATH _IO(CEC_IOCTL_BASE,CEC_IOCTL_SET_STREAM_PATH_CMD) +#define CEC_IOCTL_SET_SYS_AUDIO_MODE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_SYS_AUDIO_MODE_CMD,cec_sys_audio_status) +#define CEC_IOCTL_SET_TIMER_PROGRAM_TITLE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_TIMER_PROGRAM_TITLE_CMD,cec_string) +#define CEC_IOCTL_STANDBY _IO(CEC_IOCTL_BASE,CEC_IOCTL_STANDBY_CMD) +#define CEC_IOCTL_SYS_AUDIO_MODE_REQUEST _IO(CEC_IOCTL_BASE,CEC_IOCTL_SYS_AUDIO_MODE_REQUEST_CMD) +#define CEC_IOCTL_SYS_AUDIO_MODE_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SYS_AUDIO_MODE_STATUS_CMD,cec_sys_audio_status) +#define CEC_IOCTL_TEXT_VIEW_ON _IO(CEC_IOCTL_BASE,CEC_IOCTL_TEXT_VIEW_ON_CMD) +#define CEC_IOCTL_TIMER_CLEARED_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_TIMER_CLEARED_STATUS_CMD,cec_timer_cleared_status) +#define CEC_IOCTL_TIMER_STATUS _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_TIMER_STATUS_CMD,cec_timer_status) +#define CEC_IOCTL_TUNER_DEVICE_STATUS_ANALOGUE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_TUNER_DEVICE_STATUS_ANALOGUE_CMD,cec_tuner_device_status_analogue) +#define CEC_IOCTL_TUNER_DEVICE_STATUS_DIGITAL _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_TUNER_DEVICE_STATUS_DIGITAL_CMD,cec_tuner_device_status_digital) +#define CEC_IOCTL_TUNER_STEP_DECREMENT _IO(CEC_IOCTL_BASE,CEC_IOCTL_TUNER_STEP_DECREMENT_CMD) +#define CEC_IOCTL_TUNER_STEP_INCREMENT _IO(CEC_IOCTL_BASE,CEC_IOCTL_TUNER_STEP_INCREMENT_CMD) +#define CEC_IOCTL_USER_CTRL_PRESSED _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_CMD,cec_user_ctrl) +#define CEC_IOCTL_USER_CTRL_PLAY _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_PLAY_CMD,cec_play) +#define CEC_IOCTL_USER_CTRL_SELECT_AUDIOINPUT _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_SELECT_AUDIOINPUT_CMD,unsigned char) +#define CEC_IOCTL_USER_CTRL_SELECT_AVINPUT _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_SELECT_AVINPUT_CMD,unsigned char) +#define CEC_IOCTL_USER_CTRL_SELECT_MEDIA _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_SELECT_MEDIA_CMD,unsigned char) +#define CEC_IOCTL_USER_CTRL_TUNE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_TUNE_CMD,cec_user_ctrl_tune) +#define CEC_IOCTL_USER_CTRL_RELEASED _IO(CEC_IOCTL_BASE,CEC_IOCTL_USER_CTRL_RELEASED_CMD) +#define CEC_IOCTL_VENDOR_COMMAND _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_VENDOR_COMMAND_CMD,cec_string) +#define CEC_IOCTL_VENDOR_COMMAND_WITH_ID _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_VENDOR_COMMAND_WITH_ID_CMD,cec_vendor_command_with_id) +#define CEC_IOCTL_VENDOR_REMOTE_BUTTON_DOWN _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_VENDOR_REMOTE_BUTTON_DOWN_CMD,cec_string) +#define CEC_IOCTL_VENDOR_REMOTE_BUTTON_UP _IO(CEC_IOCTL_BASE,CEC_IOCTL_VENDOR_REMOTE_BUTTON_UP_CMD) +#define CEC_IOCTL_GET_SW_VERSION _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_GET_SW_VERSION_CMD,cec_sw_version) +#define CEC_IOCTL_SET_POWER_STATE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SET_POWER_STATE_CMD,cec_power) +#define CEC_IOCTL_GET_POWER_STATE _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_GET_POWER_STATE_CMD,cec_power) +#define CEC_IOCTL_INSTANCE_CONFIG _IO(CEC_IOCTL_BASE,CEC_IOCTL_INSTANCE_CONFIG_CMD) +#define CEC_IOCTL_INSTANCE_SETUP _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_INSTANCE_SETUP_CMD,cec_setup) +#define CEC_IOCTL_GET_INSTANCE_SETUP _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_GET_INSTANCE_SETUP_CMD,cec_setup) +#define CEC_IOCTL_ENABLE_EVENT _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_ENABLE_EVENT_CMD,cec_event) +#define CEC_IOCTL_DISABLE_EVENT _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_DISABLE_EVENT_CMD,cec_event) +#define CEC_IOCTL_ENABLE_CALIBRATION _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_ENABLE_CALIBRATION_CMD,cec_clock) +#define CEC_IOCTL_DISABLE_CALIBRATION _IO(CEC_IOCTL_BASE,CEC_IOCTL_DISABLE_CALIBRATION_CMD) +//#define CEC_IOCTL_SEND_MSG _IOWR(CEC_IOCTL_BASE,CEC_IOCTL_SEND_MSG_CMD,cec_send_msg) + +/* --- Full list --- */ + +/* legend: */ +/* ------- */ +/* [ ] : not supported */ +/* [x] : IOCTL */ +/* [i] : open, init... */ + +/* [ ] tmdlHdmiCecAbortMessage */ +/* [ ] tmdlHdmiCecActiveSource */ +/* [ ] tmdlHdmiCecVersion */ +/* [ ] tmdlHdmiCecClearAnalogueTimer */ +/* [ ] tmdlHdmiCecClearDigitalTimer */ +/* [ ] tmdlHdmiCecClearExternalTimerWithExternalPlug */ +/* [ ] tmdlHdmiCecClearExternalTimerWithPhysicalAddress */ +/* [ ] tmdlHdmiCecDeckControl */ +/* [ ] tmdlHdmiCecDeckStatus */ +/* [ ] tmdlHdmiCecDeviceVendorID */ +/* [ ] tmdlHdmiCecFeatureAbort */ +/* [ ] tmdlHdmiCecGetCecVersion */ +/* [ ] tmdlHdmiCecGetMenuLanguage */ +/* [ ] tmdlHdmiCecGiveAudioStatus */ +/* [ ] tmdlHdmiCecGiveDeckStatus */ +/* [ ] tmdlHdmiCecGiveDevicePowerStatus */ +/* [ ] tmdlHdmiCecGiveDeviceVendorID */ +/* [ ] tmdlHdmiCecGiveOsdName */ +/* [ ] tmdlHdmiCecGivePhysicalAddress */ +/* [ ] tmdlHdmiCecGiveSystemAudioModeStatus */ +/* [ ] tmdlHdmiCecGiveTunerDeviceStatus */ +/* [ ] tmdlHdmiCecImageViewOn */ +/* [ ] tmdlHdmiCecInactiveSource */ +/* [ ] tmdlHdmiCecMenuRequest */ +/* [ ] tmdlHdmiCecMenuStatus */ +/* [ ] tmdlHdmiCecPlay */ +/* [ ] tmdlHdmiCecPollingMessage */ +/* [ ] tmdlHdmiCecRecordOff */ +/* [ ] tmdlHdmiCecRecordOnAnalogueService */ +/* [ ] tmdlHdmiCecRecordOnDigitalService */ +/* [ ] tmdlHdmiCecRecordOnExternalPhysicalAddress */ +/* [ ] tmdlHdmiCecRecordOnExternalPlug */ +/* [ ] tmdlHdmiCecRecordOnOwnSource */ +/* [ ] tmdlHdmiCecRecordStatus */ +/* [ ] tmdlHdmiCecRecordTvScreen */ +/* [ ] tmdlHdmiCecReportAudioStatus */ +/* [ ] tmdlHdmiCecReportPhysicalAddress */ +/* [ ] tmdlHdmiCecReportPowerStatus */ +/* [ ] tmdlHdmiCecRequestActiveSource */ +/* [ ] tmdlHdmiCecRoutingChange */ +/* [ ] tmdlHdmiCecRoutingInformation */ +/* [ ] tmdlHdmiCecSelectAnalogueService */ +/* [ ] tmdlHdmiCecSelectDigitalService */ +/* [ ] tmdlHdmiCecSetAnalogueTimer */ +/* [ ] tmdlHdmiCecSetAudioRate */ +/* [ ] tmdlHdmiCecSetDigitalTimer */ +/* [ ] tmdlHdmiCecSetExternalTimerWithExternalPlug */ +/* [ ] tmdlHdmiCecSetExternalTimerWithPhysicalAddress */ +/* [ ] tmdlHdmiCecSetMenuLanguage */ +/* [ ] tmdlHdmiCecSetOsdName */ +/* [ ] tmdlHdmiCecSetOsdString */ +/* [ ] tmdlHdmiCecSetStreamPath */ +/* [ ] tmdlHdmiCecSetSystemAudioMode */ +/* [ ] tmdlHdmiCecSetTimerProgramTitle */ +/* [ ] tmdlHdmiCecStandby */ +/* [ ] tmdlHdmiCecSystemAudioModeRequest */ +/* [ ] tmdlHdmiCecSystemAudioModeStatus */ +/* [ ] tmdlHdmiCecTextViewOn */ +/* [ ] tmdlHdmiCecTimerClearedStatus */ +/* [ ] tmdlHdmiCecTimerStatus */ +/* [ ] tmdlHdmiCecTunerDeviceStatusAnalogue */ +/* [ ] tmdlHdmiCecTunerDeviceStatusDigital */ +/* [ ] tmdlHdmiCecTunerStepDecrement */ +/* [ ] tmdlHdmiCecTunerStepIncrement */ +/* [ ] tmdlHdmiCecUserControlPressed */ +/* [ ] tmdlHdmiCecUserControlPressedPlay */ +/* [ ] tmdlHdmiCecUserControlPressedSelectAudioInput */ +/* [ ] tmdlHdmiCecUserControlPressedSelectAVInput */ +/* [ ] tmdlHdmiCecUserControlPressedSelectMedia */ +/* [ ] tmdlHdmiCecUserControlPressedTune */ +/* [ ] tmdlHdmiCecUserControlReleased */ +/* [ ] tmdlHdmiCecVendorCommand */ +/* [ ] tmdlHdmiCecVendorCommandWithID */ +/* [ ] tmdlHdmiCecVendorRemoteButtonDown */ +/* [ ] tmdlHdmiCecVendorRemoteButtonUp */ +/* [ ] tmdlHdmiCecGetSWVersion */ +/* [ ] tmdlHdmiCecGetNumberOfUnits */ +/* [ ] tmdlHdmiCecGetCapabilities */ +/* [ ] tmdlHdmiCecGetCapabilitiesM */ +/* [ ] tmdlHdmiCecOpen */ +/* [ ] tmdlHdmiCecOpenM */ +/* [ ] tmdlHdmiCecClose */ +/* [ ] tmdlHdmiCecSetPowerState */ +/* [ ] tmdlHdmiCecGetPowerState */ +/* [ ] tmdlHdmiCecInstanceConfig */ +/* [ ] tmdlHdmiCecInstanceSetup */ +/* [ ] tmdlHdmiCecGetInstanceSetup */ +/* [ ] tmdlHdmiCecHandleInterrupt */ +/* [ ] tmdlHdmiCecRegisterCallbacks */ +/* [ ] tmdlHdmiCecSetAutoAnswer */ +/* [ ] tmdlHdmiCecSetLogicalAddress */ +/* [ ] tmdlHdmiCecEnableEvent */ +/* [ ] tmdlHdmiCecDisableEvent */ +/* [ ] tmdlHdmiCecEnableCalibration */ +/* [ ] tmdlHdmiCecDisableCalibration */ +/* [ ] tmdlHdmiCecSendMessage */ +/* [ ] tmdlHdmiCecSetRegister */ + + +#endif /* __cec_h__ */ +#endif /* __cec_ioctl__ */ diff --git a/drivers/video/nxp/tda998x_version.h b/drivers/video/nxp/tda998x_version.h new file mode 100755 index 0000000000000..11233e0a0f363 --- /dev/null +++ b/drivers/video/nxp/tda998x_version.h @@ -0,0 +1,17 @@ +#ifndef __tda_version__ +#define __tda_version__ + +/* version */ +#define TDA_VERSION_MAJOR 1 +#define TDA_VERSION_MINOR 3 +#define TDA_VERSION_PATCHLEVEL 0 +#define TDA_VERSION_EXTRA "-ioctl (2009-10-15)" + +/* TDA TX chip list */ +#define TDA19989 "tda19989" +#define TDA19988 "tda19989" +#define TDA9984 "tda9984" +#define TDA9983 "tda9983" +#define TDA9981 "tda9981" + +#endif diff --git a/drivers/video/nxp/test/Makefile b/drivers/video/nxp/test/Makefile new file mode 100755 index 0000000000000..def296049938c --- /dev/null +++ b/drivers/video/nxp/test/Makefile @@ -0,0 +1,28 @@ +PACKAGE_NAME=DEMO_TDA + +RULES:=compile +# ROOT=/home/vadmin/dev/hdmi/omapzoom/nxp-modules +ROOT=.. +INC=-I${ROOT} -I${ROOT}/inc -I${ROOT}/comps -I${ROOT}/comps/inc -I${ROOT}/comps/tmdlHdmiTx/inc -I${ROOT}/comps/tmdlHdmiCEC/inc + +EXTRA_CFLAGS += -DFUNC_PTR=" " -DCONST_DAT="const " -DRAM_DAT=" " +CFLAGS= ${INC} +# LDFLAGS= -lpthread +ACC=agcc +# ACC=arm-none-linux-gnueabi-gcc + +BINARIES=demo_tda + +all: $(RULES) + +clean: + @echo "\t-----> $(PACKAGE_NAME):$@" + @rm -f $(BINARIES) *.o + +compile: + $(ACC) $(CFLAGS) $(LDFLAGS) demo_tda.c -o demo_tda + +upload: + adb shell rm demo_tda + adb push demo_tda demo_tda + adb shell ./demo_tda diff --git a/drivers/video/nxp/test/demo_tda.c b/drivers/video/nxp/test/demo_tda.c new file mode 100755 index 0000000000000..e6bec2ade080a --- /dev/null +++ b/drivers/video/nxp/test/demo_tda.c @@ -0,0 +1,758 @@ +/* * + * Filename: tda_demo.c + * + * Description: bench and stress of CEC + * features for TDA19989 + */ +/* Created: 2009-10-20 + * + * Author: Andre Lepine + * Company: NXP Semiconductors Caen + * + */ +#define TDA_DEMO_VERSION "v0.1" + +/* linux */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tmdlHdmiTx_Types.h" +#include "tmdlHdmiCEC_Types.h" +#include "tda998x.h" +#include "tda998x_ioctl.h" +/* #include "tda998x_cec.h" */ + + +/* + * + * Definitions + * ----------- + * CHAPTER 0 + * + */ + +#define USERCHECK(x,y) {if (user_request & (x)) {y;}} +#define _MY_IOCTL(fd,prefix,io,param) {if (ioctl(fd,prefix##io, param) == -1) {oups("ioctl failed",prefix##io);}} +#define IO_CEC(io,param) _MY_IOCTL(cec,CEC_IOCTL_,io,param) +#define IO_TX(io,param) _MY_IOCTL(tx,TDA_IOCTL_,io,param) +#define IO_RX(io,param) _MY_IOCTL(rx,CEC_IOCTL_,io,param) +#define CEC_DEV "/dev/hdmicec" +#define TX_DEV "/dev/hdmitx" + +typedef struct { + unsigned char received; + unsigned char service; + unsigned char addr; + unsigned char data[15]; +} rx_frame; + +unsigned int user_request,user_wait; +const char cec_name[]=CEC_DEV; +const char tx_name[]=TX_DEV; +int rx=0,tx=0,cec=0; +pthread_t rx_thread; +unsigned short phy_addr; +cec_string osd_name = {{78,88,80},3}; /* NXP */ +tmdlHdmiCECDeviceType_t device_type = CEC_DEVICE_TYPE_PLAYBACK_DEVICE; + +/* + * + * Internals + * --------- + * CHAPTER 1 + * + */ + +char *cec_service(int service) +{ + switch (service) + { + case CEC_WAITING: {return "waiting";break;} + case CEC_RELEASE: {return "release";break;} + case CEC_RX_DONE: {return "new message";break;} + case CEC_TX_DONE: {return "one message sent";break;} + default : {return "unknown";break;} + } +} + +/* + * syntax for dumies + */ +void print_usage(char *exename) +{ + printf("Usage: %s [test_numer] [loop]\n",exename); + printf("0x001: driver open/close\n"); + printf("0x002: ...\n"); +} + +/* + * We did it ! + */ +void my_exit(int signum) { + + printf("bye\n"); + + /* + .last ioctl for releasing + .munmap if needed + .free + */ + + if (tx) close(tx); + if (cec) { + ioctl(cec,CEC_IOCTL_BYEBYE, NULL); + close(cec); + } + if (rx) close(rx); + + _exit(signum); +} + +/* + * Failure + */ +void oups(char *s,int io) { + + if (io) { + printf("%s (%d)\noups...\n",s,io); + } + else { + } + + /* + .specific ioctl for releasing + */ + + if (tx) close(tx); + if (cec) { + ioctl(cec,CEC_IOCTL_BYEBYE, NULL); + close(cec); + } + if (rx) close(rx); + + my_exit(EXIT_FAILURE); +} + + +/* + * + * Methods + * ------- + * CHAPTER 2 + * + */ + +/* + do some event control here... +*/ +void read_frame(cec_frame *frame) { + + unsigned char initiator, receiver; + int param1,param2,param3; + UInt32 vendor_ID; + UInt32 vendor_CmdID0, vendor_CmdID1, vendor_CmdID2; + char language[3] = {0x65,0x6e,0x67}; /* eng */ + tmdlHdmiCECAudioStatus_t audio; + tmdlHdmiCecInstanceSetup_t setup; + cec_feature_abort fa; + int i; + + printf("CEC module says:%s\n",cec_service(frame->service)); + + /*Give receive data from CEC bus*/ + if (frame->service == CEC_RX_DONE) { + + //initiator and receiver + initiator = (frame->addr >> 4) & 0x0f; + receiver = frame->addr & 0x0f; + printf("[%x]->[%x] data:%02x%02x%02x%02x...\n", \ + initiator, \ + receiver, \ + frame->data[0], \ + frame->data[1], \ + frame->data[2], \ + frame->data[3]); + + + // Particular case of Polling Message// + if (frame->count == 0x03) + { + } + else + { + switch(frame->data[0]) + { + // Standby + case CEC_OPCODE_STANDBY : +#ifdef CEC_PW_MGT + IO_TX(SET_POWER,tmPowerStandby); +#endif + break; + + // Set Menu Language + case CEC_OPCODE_GET_MENU_LANGUAGE : + IO_CEC(SET_MENU_LANGUAGE,language); + break; + + // Set Menu Language + case CEC_OPCODE_SET_MENU_LANGUAGE : + param1 = frame->data[1]; + param2 = frame->data[2]; + param3 = frame->data[3]; + printf(" \n", param1,param2,param3); + break; + + // Active Source + case CEC_OPCODE_ACTIVE_SOURCE : + param1 = ((int)frame->data[1] << 8) + frame->data[2]; + printf(" \n", param1); + break; + + // Inactive Source + case CEC_OPCODE_INACTIVE_SOURCE : + param1 = ((int)frame->data[1] << 8) + frame->data[2]; + printf(" \n", param1); + break; + + // CEC Version + case CEC_OPCODE_CEC_VERSION : + param1 = frame->data[1]; + printf(" \n", param1); + break; + + // Give OSD Name + case CEC_OPCODE_GIVE_OSD_NAME : + IO_CEC(SET_OSD_NAME,&osd_name); /* to be check FIXEME */ + break; + + // Give Device vendor_ ID + case CEC_OPCODE_GIVE_DEVICE_VENDOR_ID : + IO_CEC(DEVICE_VENDOR_ID,0x000800b7); + break; + + // Report Physical Address + case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS : + param1 = ((int)frame->data[1] << 8) + frame->data[2]; + param2 = frame->data[3]; + printf(" \n", param1, param2); + break; + + // Device vendor_ ID + case CEC_OPCODE_DEVICE_VENDOR_ID : + vendor_ID = ((int)frame->data[1] << 16) + \ + ((int)frame->data[2] << 8) + \ + frame->data[3]; + printf(" \n", vendor_ID); + break; + + case CEC_OPCODE_VENDOR_COMMAND_WITH_ID : + vendor_ID = ((int)frame->data[1] << 16) + \ + ((int)frame->data[2] << 8)+ \ + frame->data[3]; + vendor_CmdID0 = ((int)frame->data[4] << 24) + \ + ((int)frame->data[5] << 16)+ \ + ((int)frame->data[6] << 8)+ \ + frame->data[7]; + vendor_CmdID1 = ((int)frame->data[8] << 24) + \ + ((int)frame->data[9] << 16)+ \ + ((int)frame->data[10] << 8)+ \ + frame->data[11]; + vendor_CmdID2 = ((int)frame->data[12] << 16) + \ + ((int)frame->data[13] << 8)+ \ + frame->data[14]; + printf(" \n", vendor_ID, vendor_CmdID0, vendor_CmdID1, vendor_CmdID2); + break; + + // Menu Request + case CEC_OPCODE_MENU_REQUEST : + param1 = frame->data[1]; + printf("

\n", param1); + break; + + // Report Power Status + case CEC_OPCODE_REPORT_POWER_STATUS : + param1 =frame->data[1]; + printf(" \n", param1); + break; + + // Set OSD Name + case CEC_OPCODE_SET_OSD_NAME : + for(i=1; i <= (frame->count-4); i++) + printf("%c", frame->data[i]); + printf(" >\n "); + break; + + // Abort Message + case CEC_OPCODE_ABORT_MESSAGE : + fa.FeatureOpcode=CEC_OPCODE_ABORT_MESSAGE; + fa.AbortReason=CEC_ABORT_REFUSED; + printf("ABORT_MESSAGE received\n"); + IO_CEC(FEATURE_ABORT,&fa); + break; + + // Feature Abort + case CEC_OPCODE_FEATURE_ABORT : + printf("FEATURE_ABORT"); + param1 = frame->data[1]; + param2 = frame->data[2]; + printf(" \n", param1, param2); + break; + + // Routing Change + case CEC_OPCODE_ROUTING_CHANGE : + param1 = ((int)frame->data[1] << 8) + frame->data[2]; + param2 = frame->data[3]; + printf(" \n", param1, param2); + break; + + //Set Stream Path + case CEC_OPCODE_SET_STREAM_PATH : + param1 = ((int)frame->data[1] << 8) + frame->data[2]; + printf(" \n", param1); + if (param1 == phy_addr) { + /* IO_CEC(ACTIVE_SRC,0); Done my module itself */ + } + break; + + //Give Device Power Status + case CEC_OPCODE_GIVE_DEVICE_POWER_STATUS : + IO_CEC(REPORT_POWER_STATUS,CEC_POWER_STATUS_ON); + break; + + //Give Audio Status + case CEC_OPCODE_GIVE_AUDIO_STATUS : + audio.audioMuteSatus = CEC_AUDIO_MUTE_OFF; + audio.audioVolumeSatus = 15; + IO_CEC(REPORT_AUDIO_STATUS,&audio); + break; + + case CEC_OPCODE_PLAY: + switch (frame->data[1]) { + case CEC_MODE_PLAY_FORWARD: + IO_TX(SET_POWER,tmPowerOn); + break; + case CEC_MODE_PLAY_REVERSE: + break; + case CEC_MODE_FAST_FORWARD_MIN_SPEED: + break; + case CEC_MODE_FAST_FORWARD_MEDIUM_SPEED: + break; + case CEC_MODE_FAST_FORWARD_MAX_SPEED: + break; + case CEC_MODE_FAST_REVERSE_MIN_SPEED: + break; + case CEC_MODE_FAST_REVERSE_MEDIUM_SPEED: + break; + case CEC_MODE_FAST_REVERSE_MAX_SPEED: + break; + case CEC_MODE_SLOW_FORWARD_MIN_SPEED: + break; + case CEC_MODE_SLOW_FORWARD_MEDIUM_SPEED: + break; + case CEC_MODE_SLOW_FORWARD_MAX_SPEED: + break; + case CEC_MODE_SLOW_REVERSE_MIN_SPEED: + break; + case CEC_MODE_SLOW_REVERSE_MEDIUM_SPEED: + break; + case CEC_MODE_SLOW_REVERSE_MAX_SPEED: + break; + default: + fa.FeatureOpcode=frame->data[0]; + fa.AbortReason=CEC_ABORT_INVALID_OPERAND; + printf("Send feature abort::invalid operand in opcode play\n"); + IO_CEC(FEATURE_ABORT,&fa); + break; + } + break; + + case CEC_OPCODE_USER_CONTROL_PRESSED: + switch (frame->data[1]) { + case CEC_REMOTE_BUTTON_SELECT: + break; + case CEC_REMOTE_BUTTON_UP: + break; + case CEC_REMOTE_BUTTON_DOWN: + break; + case CEC_REMOTE_BUTTON_LEFT: + break; + case CEC_REMOTE_BUTTON_RIGHT: + break; + case CEC_REMOTE_BUTTON_RIGHT_UP: + break; + case CEC_REMOTE_BUTTON_RIGHT_DOWN: + break; + case CEC_REMOTE_BUTTON_LEFT_UP: + break; + case CEC_REMOTE_BUTTON_LEFT_DOWN: + break; + case CEC_REMOTE_BUTTON_ROOT_MENU: + break; + case CEC_REMOTE_BUTTON_SETUP_MENU: + break; + case CEC_REMOTE_BUTTON_CONTENTS_MENU: + break; + case CEC_REMOTE_BUTTON_FAVORITE_MENU: + break; + case CEC_REMOTE_BUTTON_EXIT: + break; + case CEC_REMOTE_BUTTON_NUMBER_0: + break; + case CEC_REMOTE_BUTTON_NUMBER_1: + break; + case CEC_REMOTE_BUTTON_NUMBER_2: + break; + case CEC_REMOTE_BUTTON_NUMBER_3: + break; + case CEC_REMOTE_BUTTON_NUMBER_4: + break; + case CEC_REMOTE_BUTTON_NUMBER_5: + break; + case CEC_REMOTE_BUTTON_NUMBER_6: + break; + case CEC_REMOTE_BUTTON_NUMBER_7: + break; + case CEC_REMOTE_BUTTON_NUMBER_8: + break; + case CEC_REMOTE_BUTTON_NUMBER_9: + break; + case CEC_REMOTE_BUTTON_DOT: + break; + case CEC_REMOTE_BUTTON_ENTER: + break; + case CEC_REMOTE_BUTTON_CLEAR: + break; + case CEC_REMOTE_BUTTON_NEXT_FAVORITE: + break; + case CEC_REMOTE_BUTTON_CHANNEL_UP: + break; + case CEC_REMOTE_BUTTON_CHANNEL_DOWN: + break; + case CEC_REMOTE_BUTTON_PREVIOUS_CHANNEL: + break; + case CEC_REMOTE_BUTTON_SOUND_SELECT: + break; + case CEC_REMOTE_BUTTON_INPUT_SELECT: + break; + case CEC_REMOTE_BUTTON_DISPLAY_INFORMATION: + break; + case CEC_REMOTE_BUTTON_HELP: + break; + case CEC_REMOTE_BUTTON_PAGE_UP: + break; + case CEC_REMOTE_BUTTON_PAGE_DOWN: + break; + case CEC_REMOTE_BUTTON_POWER: + break; + case CEC_REMOTE_BUTTON_VOLUME_UP: + break; + case CEC_REMOTE_BUTTON_VOLUME_DOWN: + break; + case CEC_REMOTE_BUTTON_MUTE: + break; + case CEC_REMOTE_BUTTON_PLAY: + break; + case CEC_REMOTE_BUTTON_STOP: + break; + case CEC_REMOTE_BUTTON_PAUSE: + break; + case CEC_REMOTE_BUTTON_RECORD: + break; + case CEC_REMOTE_BUTTON_REWIND: + break; + case CEC_REMOTE_BUTTON_FAST_FORWARD: + break; + case CEC_REMOTE_BUTTON_EJECT: + break; + case CEC_REMOTE_BUTTON_FORWARD: + break; + case CEC_REMOTE_BUTTON_BACKWARD: + break; + case CEC_REMOTE_BUTTON_STOP_RECORD: + break; + case CEC_REMOTE_BUTTON_PAUSE_RECORD: + break; + case CEC_REMOTE_BUTTON_ANGLE: + break; + case CEC_REMOTE_BUTTON_SUB_PICTURE: + break; + case CEC_REMOTE_BUTTON_VIDEO_ON_DEMAND: + break; + case CEC_REMOTE_BUTTON_ELECTRONIC_PROGRAM_GUIDE: + break; + case CEC_REMOTE_BUTTON_TIMER_PROGRAMMING: + break; + case CEC_REMOTE_BUTTON_INITIAL_CONFIGURATION: + break; + case CEC_REMOTE_BUTTON_PLAY_FUNCTION: + break; + case CEC_REMOTE_BUTTON_PAUSE_PLAY_FUNCTION: + break; + case CEC_REMOTE_BUTTON_RECORD_FUNCTION: + break; + case CEC_REMOTE_BUTTON_PAUSE_RECORD_FUNCTION: + break; + case CEC_REMOTE_BUTTON_STOP_FUNCTION: + break; + case CEC_REMOTE_BUTTON_MUTE_FUNCTION: + break; + case CEC_REMOTE_BUTTON_RESTORE_VOLUME_FUNCTION: + break; + case CEC_REMOTE_BUTTON_TUNE_FUNCTION: + break; + case CEC_REMOTE_BUTTON_SELECT_MEDIA_FUNCTION: + break; + case CEC_REMOTE_BUTTON_SELECT_AV_INPUT_FUNCTION: + break; + case CEC_REMOTE_BUTTON_SELECT_AUDIO_INPUT_FUNCTION: + break; + case CEC_REMOTE_BUTTON_POWER_TOGGLE_FUNCTION: + break; + case CEC_REMOTE_BUTTON_POWER_OFF_FUNCTION: + break; + case CEC_REMOTE_BUTTON_POWER_ON_FUNCTION: + break; + case CEC_REMOTE_BUTTON_F1_BLUE: + break; + case CEC_REMOTE_BUTTON_F2_RED: + break; + case CEC_REMOTE_BUTTON_F3_GREEN: + break; + case CEC_REMOTE_BUTTON_F4_YELLOW: + break; + case CEC_REMOTE_BUTTON_F5: + break; + case CEC_REMOTE_BUTTON_DATA: + break; + default: + fa.FeatureOpcode=frame->data[0]; + fa.AbortReason=CEC_ABORT_INVALID_OPERAND; + printf("Send feature abort::invalid operand in user control pressed\n"); + IO_CEC(FEATURE_ABORT,&fa); + break; + } + break; + + case CEC_OPCODE_DECK_CONTROL: + switch (frame->data[1]) { + case CEC_DECK_CONTROL_WIND: /*!< Skip Forward / Wind */ + break; + case CEC_DECK_CONTROL_REWIND: /*!< Skip Reverse / Rewind */ + break; + case CEC_DECK_CONTROL_STOP: /*!< Stop */ + break; + case CEC_DECK_CONTROL_EJECT: /*!< Eject */ + break; + default: + fa.FeatureOpcode=frame->data[0]; + fa.AbortReason=CEC_ABORT_INVALID_OPERAND; + printf("Send feature abort::invalid operand in deck control\n"); + IO_CEC(FEATURE_ABORT,&fa); + break; + } + break; + + case CEC_OPCODE_DECK_STATUS: + switch (frame->data[1]) { + case CEC_DECK_INFO_PLAY: /*!< Play */ + break; + case CEC_DECK_INFO_RECORD: /*!< Record */ + break; + case CEC_DECK_INFO_PLAY_REVERSE: /*!< Play Reverse */ + break; + case CEC_DECK_INFO_STILL: /*!< Still */ + break; + case CEC_DECK_INFO_SLOW: /*!< Slow */ + break; + case CEC_DECK_INFO_SLOW_REVERSE: /*!< Slow Reverse */ + break; + case CEC_DECK_INFO_FAST_FORWARD: /*!< Fast Forward */ + break; + case CEC_DECK_INFO_FAST_REVERSE: /*!< Fast Reverse */ + break; + case CEC_DECK_INFO_NO_MEDIA: /*!< No Media */ + break; + case CEC_DECK_INFO_STOP: /*!< Stop */ + break; + case CEC_DECK_INFO_WIND: /*!< Skip Forward / Wind */ + break; + case CEC_DECK_INFO_REWIND: /*!< Skip Reverse / Rewind */ + break; + case CEC_DECK_INFO_ID_SEARCH_FORWARD: /*!< Index Search Forward */ + break; + case CEC_DECK_INFO_ID_SEARCH_REVERSE: /*!< Index Search Forward */ + break; + case CEC_DECK_INFO_OTHER_STATUS: /*!< Other Status */ + break; + default: + fa.FeatureOpcode=frame->data[0]; + fa.AbortReason=CEC_ABORT_INVALID_OPERAND; + printf("Send feature abort::invalid operand in deck status\n"); + IO_CEC(FEATURE_ABORT,&fa); + break; + } + break; + + + case CEC_OPCODE_USER_CONTROL_RELEASED: + break; + + default: + fa.FeatureOpcode=frame->data[0]; + fa.AbortReason=CEC_ABORT_UNKNOWN_OPCODE; + printf("Send feature abort::unknown opcode\n"); + IO_CEC(FEATURE_ABORT,&fa); + break; + } + } + } + else if (frame->service == CEC_TX_DONE) { + /* ack */ + } +} + + +void *rx_main( void *ptr ) { + + cec_frame frame; + memset(&frame,0,sizeof(cec_frame)); + + printf("%s is alive\n",__func__); + + /* another cec for event */ + if ((rx = open(cec_name, O_RDWR)) == -1) { + perror(cec_name); + oups("can not open hdmicec driver\n",0); + } + + /* main loop */ + while(frame.service!=CEC_RELEASE) { + IO_RX(WAIT_FRAME,&frame); + read_frame(&frame); + } + + close(rx); + pthread_exit(0); + + return NULL; +} + +/* + * + * Bench + * --------- + * CHAPTER 3 + * + */ + +/* 0x001: driver open/close */ +void bench0001(void) { + + unsigned long /* tda_power */ power; + + printf("%s\n",__func__); + + + /* + * init + */ + + if ((tx = open(tx_name, O_RDWR)) == -1) { + perror(tx_name); + oups("can not open hdmicec driver (evt mgr)\n",0); + } + + printf("Power on device\n"); + power = tmPowerOn; + IO_TX(SET_POWER,&power); + + if ((cec = open(cec_name, O_RDWR)) == -1) { + perror(cec_name); + oups("can not open hdmicec driver\n",0); + } + + IO_CEC(RX_ADDR,CEC_LOGICAL_ADDRESS_PLAYBACK_DEVICE_1); + IO_CEC(POLLING_MSG,NULL); + + /* Create independent threads each of which will execute function */ + if (pthread_create( &rx_thread, NULL, rx_main, NULL)) { + oups("can not create rx_thread\n",0); + } + + /* + * idle + */ + + sleep(user_wait); + /* IO_CEC(ACTIVE_SRC,0); */ + /* IO_CEC(IMAGE_VIEW_ON,0); */ + + + /* + * deinit + */ + + /* stop rx_thread */ + printf("rx_thread release request\n"); + IO_CEC(BYEBYE,0); + pthread_join(rx_thread, NULL); + + /* bye bye */ + close(cec); + close(tx); +} + +/* 0x002: ... */ +void bench0002(void) { + + printf("%s\n",__func__); + +} + +/* + * + * Entry point + * ----------- + * CHAPTER 4 + * + */ + +int main(int argc, char *argv[]) { + + printf("tda_demo, %s, %s %s\n",TDA_DEMO_VERSION,__DATE__,__TIME__); + printf("any feedback welcome - andre.lepine@nxp.com\n"); + + user_wait = 3; + user_request=0xFFFF; + /* Check command line parameters and init framebuffer */ + if (argc > 1) user_request = strtol(argv[1],NULL,16); + if (argc > 2) user_wait = strtol(argv[2],NULL,16); + + printf("User request:%x user_wait:%d\n",user_request,user_wait); + + /* hook up our exit handler */ + signal(SIGINT|SIGTERM|SIGKILL|SIGQUIT, my_exit); + + /* + * BENCH + */ + printf("\nSW raster%s", \ + "\n---------\n"); + USERCHECK(0x01,bench0001()); + USERCHECK(0x02,bench0002()); + + /* + Exit with success + */ + print_usage(argv[0]); + raise(SIGTERM); + return 0; +}