请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
器件型号:AM4378 工具/软件:Linux
大家好、 我的板上有 AM4378和 tda998x 编解码器
我尝试使 HDMI 和音频正常工作、
我通过在 AVI 部件上分配特定参数来获得有效的 HDMI 输出。
但大量 NULL 指针仍然无法使音频工作。
是否有好的解决方法?
//
*版权所有(C) 2012 Texas Instruments
*作者:Rob Clark
*
*本程序是免费软件;您可以根据
*免费软件基金会发布的 GNU 通用公共许可证版本2的条款重新分发和/或修改它。
*
*本计划的发布目的是希望其有用、但没有
*任何保证;甚至没有对适销性或
*特定用途适用性的暗示保证。 有关
*更多详细信息,请参阅 GNU 通用公共许可证。
*
*您应该已收到 GNU 通用公共许可证的副本以及
*本程序。 如果不是、请参阅<www.gnu.org/.../>。
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "../omapdrm/dss/dss.h
#define DBG (fmt、...) DRM_DEBUG (fmt"\n"、##_VA_args__)
struct tda998x_audio_port{
u8格式;// AFMT_xxx */
u8配置;// AP 值*/
};
struct tda998x_privc{
struct i2c_client *2c;
mutex i_client HDMI *u
页;mutex 16;u 页
int DPMS;
bool ITH_HDMI_Sink;
u8 VIP_Cntrl_0;
u8 VIP_Cntrl_1;
u8 VIP_Cntrl_2;
struct tda998x_audio_params audio_params;
struct platform_device * audio_pdev;
wait_queue_head_t wq_EDID;
volatile int wq_EDID_wait;
struct work;struct structure detect_work;
struct timer_list EDID_DELAY_TIMER;
WAIT_RUST_HED_t EDID_DELAY_waitq;
bool EDID_DELAY_ACTIVE;
struct DRM_CODER 编码器;
struct DRM_CONNECTOR 连接器;
struct tda998x_audio_port audio_port[2];
};
#define conn_to_tda998x_priv(x)\
container_of (x、struct tda998x_priv, connector)
#define enc_to_tda998x_priv(x)\
container_of (x、struct tda998x_privn、connector)
*使用分页编码器方案。 为了简化
*操作、我们将页#编码为寄存器#的高位。 要读取/
*写入给定的寄存器、我们需要确保对 CURRGE 寄存
器进行适当的设置*。 这意味着读取/写入不是原子的。 有趣!
//
#define REG (page、addr)(((page)<< 8)|(addr)
)#define REG2ADDR (reg)(((reg)& 0xff)
#define REG2PAGE (reg)((((((reg)>> 8)& 0xff)
#define REG_CURPAGE 0xFF /* write */
//* page 00h:General Control */
#define REG_VERSION_LSB 寄存器(0x00、0x00) /*读取*/
#define REG_MAIN_CNTL0 寄存器(0x00、0x01) /*读取/写入*/
# define MAIN_CNTRL0_SR (1 << 0)
# define MAIN_CNTRL0_DECS (1 << 1)
# define MAIN_CNTRL0_DEHS (1 << 2)
# define MAIN_CNTRL0_CECs (1 << 3)
# define MAIN_CNTRL0_CEHS (1 << 4)
# define MAIN_CNTRL0_Scaler (1 << 7)
#define REG_VERSION_MSB 寄存器(0x00、0x02) /*读取*/
#define REG_SOFTRESET 寄存器(0x00、0x0a) /* write */
# define SOFTRESET_AUDIO (1 << 0)
# define SOFTRESET_I2C_MASTER (1 << 1)
#define REG_DDC_DISABLE 寄存器(0x00、0x0B) /*读取/写入*/
#define REG_CCLK_ON 寄存器(0x00、0x0c) /*读取/写入*/
#define REG_I2C_MASTER 寄存器(0x00、0x0d) /*读取/写入*/
# define I2C_MASTER_DIS_MM (1 << 0)
# define I2C_MASTER_DIS_FILT (1 << 1)
# define I2C_MASTER_APP_STRT (1 << 2)
#define REG_FEAT_POWERDOWN 寄存器(0x00、0x0E) /*读取/写入*/
# define FEAT_POWERDOWN_SPDIF (1 << 3)
#define REG_INT_FLAGS_0 寄存器(0x00、0x0F) /*读取/写入*/
#define REG_INT_FLAGS_1 寄存器(0x00、0x10) /*读取/写入*/
#define REG_INT_FLAGS_2 寄存器(0x00、0x11) /*读取/写入*/
# define INT_FLAGS_2_EDID_BLK_RD (1 <<1)
#define REG_ENA_ACLK 寄存器(0x00、0x16) /*读取/写入*/
#define REG_ENA_VP_0 寄存器(0x00、0x18) /*读取/写入*/
#define REG_ENA_VP_1 寄存器(0x00、0x19) /*读取/写入*/
#define REG_ENA_VP_2 寄存器(0x00、0x1A) /*读取/写入*/
#define REG_ENA_AP 寄存器(0x00、0x1E) /*读取/写入*/
#define REG_VIP_CNTRL_0 寄存器(0x00、0x20) /*写入*/
# define VIP_CNTRL_0_MIRR_A (1 << 7)
# define VIP_CNTRL_0_SWAP_A (x)((((x)& 7)<< 4)
# define VIP_CNTRL_0_MIRR_B (1 << 3)
# define VIP_CNTRL_0_SWAP_B (x)((((x)& 7)<< 0)
#define REG_VIP_CNTRL_1 寄存器(0x00、0x21) /*写入*/
# define VIP_CNTRL_1_MIRR_C (1 << 7)
# define VIP_CNTRL_1_SWAP_C (x)((((x)& 7)<< 4)
# define VIP_CNTRL_1_MIRR_D (1 << 3)
# define VIP_CNTRL_1_SWAP_D (x)((((x)& 7)<< 0)
#define REG_VIP_CNTRL_2 寄存器(0x00、0x22) /*写入*/
# define VIP_CNTRL_2_MIRR_E (1 << 7)
# define VIP_CNTRL_2_SWAP_E (x)((((x)& 7)<< 4)
# define VIP_CNTRL_2_MIRR_F (1 << 3)
# define VIP_CNTRL_2_SWAP_F (x)((((x)& 7)<< 0)
#define REG_VIP_CNTRL_3 寄存器(0x00、0x23) /*写入*/
# define VIP_CNTRL_3_X_TGL (1 << 0)
# define VIP_CNTRL_3_H_TGL (1 << 1)
# define VIP_CNTRL_3_V_TGL (1 <<2)
# define VIP_CNTRL_3_EMB (1 << 3)
# define VIP_CNTRL_3_SYNC_DE (1 << 4)
# define VIP_CNTRL_3_SYNC_HS (1 << 5)
# define VIP_CNTRL_3_DE_INT (1 << 6)
# define VIP_CNTRL_3_EDGE (1 << 7)
#define REG_VIP_CNTRL_4 寄存器(0x00、0x24) /*写入*/
# define VIP_CNTRL_4_BLC (x) ((((x)& 3)<< 0)
# define VIP_CNTRL_4_BLANKIT (x)((((x)& 3)<< 2)
# define VIP_CNTRL_4_CCIR656 (1 << 4)
# define VIP_CNTRL_4_656_ALT (1 << 5)
# define VIP_CNTRL_4_TST_656 (1 << 6)
# define VIP_CNTRL_4_TST_PAT (1 << 7)
#define REG_VIP_CNTRL_5 寄存器(0x00、0x25) /*写入*/
# define VIP_CNTRL_5_CKCASE (1 << 0)
# define VIP_CNTRL_5_SP_CNT (x)((((x)& 3)<< 1)
#define REG_MUX_AP 寄存器(0x00、0x26) //
# define MUX_AP_SELECT_I2S0x64
# define MUX_AP_SELECT_SPDIF0x40
#define REG_MUX_VP_VIP_OUT 寄存器(0x00、0x27) /*读取/写入*/
#define REG_MAT_CONTRL 寄存器(0x00、0x80) /*写入*/
# define MAT_CONTRL_MAT_SC (x) ((((x)和3)<< 0)
# define MAT_CONTRL_MAT_BP (1 <<2)
#define REG_VIDFORMAT 寄存器(0x00、0xa0) /*写入*/
#define REG_REFPI_MSB 寄存器(0x00、0xa1) /*写入*/
#define REG_REFPI_LSB 寄存器(0x00、0xa2) /*写入*/
#define REG_REFLINE_MSB 寄存器(0x00、0xa3) /*写入*/
#define REG_REFLINE_LSB 寄存器(0x00、0xa4) /*写入*/
#define REG_NPIX_MSB 寄存器(0x00、0xA5) /*写入*/
#define REG_NPIX_LSB 寄存器(0x00、0xa6) /*写入*/
#define REG_nLINE_MSB 寄存器(0x00、0xa7) /*写入*/
#define REG_nLINE_LSB 寄存器(0x00、0xa8) /*写入*/
#define REG_VS_LINE_STRT 1_MSB REG (0x00、0xa9) /*写入*/
#define REG_VS_LINE_STRT 1_LSB REG (0x00、0xAA) /*写入*/
#define REG_VS_PI_STRT 1_MSB 寄存器(0x00、0xab) /*写入*/
#define REG_VS_PI_STRT 1_LSB 寄存器(0x00、0xac) /*写入*/
#define REG_VS_LINE_END_1_MSB 寄存器(0x00、0xAD) /*写入*/
#define REG_VS_LINE_END_1_LSB 寄存器(0x00、0xae) /*写入*/
#define REG_VS_PI_END_1_MSB 寄存器(0x00、0xaf) /*写入*/
#define REG_VS_PI_END_1_LSB reg (0x00、0xb0) /*写入*/
#define REG_VS_LINE_STRT 位2_MSB 寄存器(0x00、0xb1) /*写入*/
#define REG_VS_LINE_STL_2_LSB REG (0x00、0xb2) /*写入*/
#define REG_VS_PI_STRT _2_MSB reg (0x00、0xb3) /*写入*/
#define REG_VS_PI_STRT _2_LSB reg (0x00、0xb4) /*写入*/
#define REG_VS_LINE_END_2_MSB reg (0x00、0xb5) /*写入*/
#define REG_VS_LINE_END_2_LSB reg (0x00、0xb6) /*写入*/
#define REG_VS_PI_END_2_MSB reg (0x00、0xb7) /*写入*/
#define REG_VS_PI_END_2_LSB reg (0x00、0xb8) /*写入*/
#define REG_HS_PI_START_MSB reg (0x00、0xb9) /*写入*/
#define REG_HS_PI_START_LSB 寄存器(0x00、0xBA) /*写入*/
#define REG_HS_PI_STOP_MSB 寄存器(0x00、0xbb) /*写入*/
#define REG_HS_PI_STOP_LSB reg (0x00、0xbc) /*写入*/
#define REG_VWIN_START_1_MSB 寄存器(0x00、0xBD) /*写入*/
#define REG_VWIN_START_1_LSB 寄存器(0x00、0xbe) /*写入*/
#define REG_VWIN_END_1_MSB reg (0x00、0xbf) /*写入*/
#define REG_VWIN_END_1_LSB 寄存器(0x00、0xc0) /*写入*/
#define REG_VWIN_START_2_MSB 寄存器(0x00、0xc1) /*写入*/
#define REG_VWIN_START_2_LSB 寄存器(0x00、0xC2) /*写入*/
#define REG_VWIN_END_2_MSB 寄存器(0x00、0xc3) /*写入*/
#define REG_VWIN_END_2_LSB 寄存器(0x00、0xc4) /*写入*/
#define REG_DE_START_MSB 寄存器(0x00、0xc5) /*写入*/
#define REG_DE_START_LSB 寄存器(0x00、0xc6) /*写入*/
#define REG_DE_STOP_MSB 寄存器(0x00、0xc7) /*写入*/
#define REG_DE_STOP_LSB 寄存器(0x00、0xc8) /*写入*/
#define REG_TBG_CNTRL_0 寄存器(0x00、0xca) /*写入*/
# define TBG_CNTRL_0_TOP_TGL (1 << 0)
# define TBG_CNTRL_0_TOP_SEL (1 << 1)
# define TBG_CNTRL_0_DE_EXT (1 << 2)
# define TBG_CNTRL_0_TOP_EXT (1 << 3)
# define TBG_CNTRL_0_FRAME_DIS (1 << 5)
# define TBG_CNTRL_0_SYNC_MTHD (1 << 6)
# define TBG_CNTRL_0_SYNC_Ace (1 << 7)
#define REG_TBG_CNTRL_1 寄存器(0x00、0xcb) /*写入*/
# define TBG_CNTRL_1_H_TGL (1 << 0)
# define TBG_CNTRL_1_V_TGL (1 << 1)
# define TBG_CNTRL_1_TGL_EN (1 << 2)
# define TBG_CNTRL_1_X_EXT (1 << 3)
# define TBG_CNTRL_1_H_EXT (1 << 4)
# define TBG_CNTRL_1_V_EXT (1 << 5)
# define TBG_CNTRL_1_DWIN_DIS (1 << 6)
#define REG_ENABLE_SPACE 寄存器(0x00、0xd6) /*写入*/
#define REG_HVF_CNTRL_0 寄存器(0x00、0xe4) /* WRITE */
# define HVF_CNTRL_0_SM (1 << 7)
# define HVF_CNTRL_0_RWB (1 << 6)
# define HVF_CNTRL_0_PREFIL (x)((((x)& 3)<< 2)
# define HVF_CNTRL_0_INTPOL (x)(((((x)& 3)<< 0)
#define REG_HVF_CNTRL_1 寄存器(0x00、0xe5) /* WRITE */
# define HVF_CNTRL_1_for (1 << 0)
# define HVF_CNTRL_1_YUVBLK (1 << 1)
# define HVF_CNTRL_1_VQR (x) ((((x)和3)<< 2)
# define HVF_CNTRL_1_PAD (x) ((((x)和3)<< 4)
# define HVF_CNTRL_1_SEMI _平面(1 << 6)
#define REG_RPT_CNTRL 寄存器(0x00、0xf0) /*写入*/
#define REG_I2S_FORMAT 寄存器(0x00、0xFC) /*读取/写入*/
# define I2S_FORMAT (x) ((((x)和3)<< 0)
#define REG_AIP_CLKSEL 寄存器(0x00、0xFD) /* write */
# define AIP_CLKSEL_AIP_SPDIF(0 << 3)
# define AIP_CLKSEL_AIP_I2S(1 << 3)
# define AIP_CLKSEL_FS_ACLK(0 << 0)
# define AIP_CLKSEL_FS_MCLK(1 << 3)# define AIP_CLKSEL_02*
#define CLKCLFS_CLKCL0 *设置(1)*#define L_CLFS_CLKCLKSEL _0 *#define 0 *
1 * 1 * CLKCLFS_CLFS_CLKCLKCLKCLKSEL 寄存器(0x02、0x00) /*读取/写入*/
# define PLL_serial_1_SRL_FDN (1 << 0)
# define PLL_serial_1_SRL_IZ (x)((((x)& 3)<< 1)
# define PLL_serial_1_SRL_man_IZ (1 << 6)
#define REG_PLL_serial_2 寄存器(0x02、0x01) /*读取/写入*/
# define PLL_serial_2_SRL_NOSC (x)(((x)<< 0)
# define PLL_serial_2_SRL_PR (x)((((x)& 0xF)<< 4)
#define REG_PLL_serial_3 寄存器(0x02、0x02) /*读取/写入*/
# define PLL_serial_3_SRL_CCIR (1 <<0)
# define PLL_serial_3_SRL_DE (1 << 2)
# define PLL_serial_3_SRL_PXIN_SEL (1 << 4)
#define REG_serializer 寄存器(0x02、0x03) /*读取/写入*/
#define REG_buffer_out 寄存器(0x02、0x04) /*读取/写入*/
#define REG_PLL_SCG1 寄存器(0x02、0x05) /*读取/写入*/
#define REG_PLL_SCG2 寄存器(0x02、0x06) /*读取/写入*/
#define REG_PLL_SCGN1 寄存器(0x02、0x07) /*读取/写入*/
#define REG_PLL_SCGN2 寄存器(0x02、0x08) /*读取/写入*/
#define REG_PLL_SCGR1 寄存器(0x02、0x09) /*读取/写入*/
#define REG_PLL_SCGR2 寄存器(0x02、0x0a) /*读取/写入*/
#define REG_AUDIO_DIV 寄存器(0x02、0x0E) /*读取/写入*/
# define AUDIO_DIV_SERCLK_1. 0
#定义 AUDIO_DIV_SERCLK_2 1
#定义 AUDIO_DIV_SERCLK_4 2
# define AUDIO_DIV_SERCLK_8 3
# define AUDIO_DIV_SERCLK_16 4
# define AUDIO_DIV_SERCLK_32 5
#define REG_SEL_CLK 寄存器(0x02、0x11) /*读取/写入*/
# define SEL_CLK_SEL_CLK1 (1 << 0)
# define SEL_CLK_SEL_VRF_CLK (x)((((x)& 3)<< 1)
# define SEL_CLK_ENA_SC_CLK (1 << 3)
#define REG_ANA_General 寄存器(0x02、0x12) /*读取/写入*/
*第09h 页:EDID 控制*/
#define REG_EDID_DATA_0 寄存器(0x09、0x00) /*读取*/*
接下来的127个连续寄存器是 EDID 块*/
#define REG_EDID_CTRL REG (0x09、0xfa) /*读取/写入*/
#define REG_DDC_ADDR 寄存器(0x09、0xfb) /*读取/写入*/
#define REG_DDC_FUSs REG (0x09、0xFC) /*读取/写入*/
#define REG_DDC_Segm_ADDR REG (0x09、0xFD) /*读取/写入*/
#define REG_DDC_Segm 寄存器(0x09、0xFE) /*读取/写入*/
*第10h 页:信息帧和数据包*/
#define REG_IF1_HB0 寄存器(0x10、0x20) /*读取/写入*/
#define REG_IF2_HB0 寄存器(0x10、0x40) /*读取/写入*/
#define REG_IF3_HB0 寄存器(0x10、0x60) /*读取/写入*/
#define REG_IF4_HB0 寄存器(0x10、0x80) /*读取/写入*/
#define REG_IF5_HB0 寄存器(0x10、0xa0) /*读取/写入*/*
第11h 页:音频设置和内容信息包*/
#define REG_AIP_CNTRL_0 寄存器(0x11、0x00) /*读取/写入*/
# define AIP_CNTRL_0_RST_FIFO (1 << 0)
# define AIP_CNTRL_0_SWaP (1 << 1)
# define AIP_CNTRL_0_LO版面 (1 <<2)
# define AIP_CNTRL_0_ACR_MAN (1 << 5)
# define AIP_CNTRL_0_RST_CTS (1 << 6)
#define REG_CA_I2S 寄存器(0x11、0x01) /*读取/写入*/
# define CA_I2S_CA_I2S (x) ((((x)& 31)<< 0)
# define CA_I2S_HBR_CHSTAT (1 << 6)
#define REG_LAY_RD 寄存器(0x11、0x04) /*读取/写入*/
#define REG_ACR_CTS_0 寄存器(0x11、0x05) /*读取/写入*/
#define REG_ACR_CTS_1 寄存器(0x11、0x06) /*读取/写入*/
#define REG_ACR_CTS_2 寄存器(0x11、0x07) /*读取/写入*/
#define REG_ACR_N_0 寄存器(0x11、0x08) /*读取/写入*/
#define REG_ACR_N_1 寄存器(0x11、0x09) /*读取/写入*/
#define REG_ACR_N_2 寄存器(0x11、0x0a) /*读取/写入*/
#define REG_CTS_N 寄存器(0x11、0x0c) /*读取/写入*/
# define CTS_N_K (x) (((x)& 7)<< 0)
# define CTS_N_M (x) ((((x)和3)<< 4)
#define REG_ENC_CNTRL 寄存器(0x11、0x0d) /*读取/写入*/
# define ENC_CNTRL_RST_ENC (1 << 0)
# define ENC_CNTRL_RST_SEL (1 << 1)
# define ENC_CNTRL_CTL_CODE (x)((((x)& 3)<< 2)
#define REG_DIP_FLAGS 寄存器(0x11、0x0E) /*读取/写入*/
# define DIP_FLAGS_ACR (1 << 0)
# define DIP_FLAGS_GC (1 << 1)
#define REG_DIP_IF_FLAGS 寄存器(0x11、0x0F) /*读取/写入*/
# define DIP_IF_FLAGS_IF1 (1 << 1)
# define DIP_IF_FLAGS_IF2 (1 << 2)
# define DIP_IF_FLAGS_IF3 (1 << 3)
# define DIP_IF_FLAGS_IF4 (1 << 4)
# define DIP_IF_FLAGS_IF5 (1 << 5)
#define REG_CH_STAT_B (x) REG (0x11、0x14 +(x))//*读取/写入*/
*第12h 页:HDCP 和 OTP */
#define REG_TX3 寄存器(0x12、0x9a) /*读取/写入*/
#define REG_TX4 寄存器(0x12、0x9b) /*读取/写入*/
# define TX4_PD_RAM (1 << 1)
#define REG_TX33 reg (0x12、0xb8) /*读取/写入*/
# define TX33_HDMI (1 << 1)
//*第13h 页:与色域相关的元数据包*//
* CEC 寄存器:(未分页)
*/
#define REG_CEC_INTSTATUS0xee/*读取*/
# define CEC_INTSTATUS_CEC(1 << 0)
# define CEC_INTSTATUS_HDMI(1 << 1)
#define REG_CEC_fRO_IM_CLK_CTRL 0xfb /*读取/写入*/
# define CEC_fRO_IM_CLK_CTRL_Ghost DIS (1 << 7)
# define CEC_fRO_IM_CLK_CTRL_ENA_OTP (1 << 6)
# define CEC_fRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1)
#
define CEC_INT_RXREG_0_CK_CLK_CLK_CTRL < 0xCTR_IN_INT_CLK_0 (1)#define CTRFC_RXREG_TRFC_TRFC_TRF_TRF_INT_TRF_TRF_TR_/*读取/写入*/
#define REG_CEC_RXSHPDINT0xFD/*读取*/
# define CEC_RXSHPDINT_RXSENS 位(0)
#定义 CEC_RXSHPDINT_HPD 位(1)
#define REG_CEC_RXSHPDLEV 0xFE /*读取*/
# define CEC_RXSHPDLEV_RXSENS (1 << 0)
# define CEC_RXSHPDLEV_HPD (1 << 1)
#define REG_CEC_ENAMODS 0xFF /*读取/写入*/
# define CEC_ENAMODS_DIS_fRO (1 << 6)
# define CEC_ENAMODS_DIS_CCLK (1 << 5)
# define CEC_ENAMODS_EN_RXSENS (1 << 2)
# define CEC_ENAMODS_EN_HDMI (1 << 1)
# define CEC_ENAMODS_EN_CEC (1 <<0)
//器件版本:*/
#define TDA9989N2 0x0101
#define TDA19989 0x0201
#define TDA19989N2 0x0202
#define TDA19988 0x0301
静态空
CEC_WRITE (struct tda998x_privt *priv, U16 addr,u8 val)
{
struct i2c_client * client=priv->CEC;
u8 buf[]={addr,val};
int ret;
ret = i2c_master_send (client、buf、 sizeof (buf));
if (ret < 0)
dev_err (&client->dev、"Error %d writing to CEC:0x%x\n"、ret、adret);
}
static u8
CEC_read (struct tda998x_2c * priv, u8 addr)
{
struct i2c_client * client=->rival
、iCEC_read (strat_int); sizeof (addr);
if (ret < 0)
goto fail;
ret = i2c_master_recv (client、&V、sizeof (val));
if (ret < 0)
goto fail;
return val;
fail:
dev_err (&client->cec、"Error %d reading from
8x:0x%x\n"、if (ret) gultrand rultrusted
!)、rultrategr
(rp = g2rn)、rp (rt)、rultrategr、rn)、rultrusted (rp (rt)、rultrategr)、rp (rt + rultrategr)、rp (rp (rt)、r
U8 buf[]={
REG_CURPAGE、REG2PAGE (reg)
};
int ret = i2c_master_send (client、buf、sizeof (buf));
if (ret < 0){
DEV_err (&client->dev、"%s"%04x err %d\n"、__funret
、ret_、ret_);ret_、ret_、ret_、ret_、ret_、ret_、
ret_、ret_、ret_、ret_、ret_
priv->current_page = REG2PAGE(reg);
}
return 0;
}
static int
reg_read_range (struct tda998x_priv* privv、U16 reg、char * buf、int cnt)
{
struct i2c_client * client=priv->hdmi;
u8 addr = REG2ADDR(reg);
intex
(reg-set);intex (r_lock);
如果(ret < 0)
转出;
ret = i2c_mast_send (client、&addr、sizeof (addr));
if (ret < 0)
转至失败;
ret = i2c_mast_recv (client、buf、cnt);
if (ret < 0)
转至失败;
转至输出
失败:dev_mast_recv
(client、buf、buf、cnt);if (retx、retn)、从 retx (retx、retn、retn、retn、retx、retn、retn、retn、retn、retn、retn、retn、retn、retn、retn、ret
static void
reg_write_range (struct tda998x_privt *priv, U16 reg,u8 *p,int cnt)
{
struct i2c_client * client=privc->hdmi;
u8 buf[cnt+1];
int ret;
buf[0]= REG2ADDR (reg);
memcpy (&buf[1]、 p、cnt);
mutex_lock (&priv->mutex);
ret = set_page (priv, reg);
如果(ret < 0)
转出;
ret = i2c_mast_send (client、buf、cnt + 1);
if (ret < 0)
dev_err (&client->dev、"Error %d writing to 0x%x\n"、ret、reg);
out:
mutex_unlock (&priv->mutex);
}
static reg = untrl、unt
reg、
unt reg = unt reg、unt reg、unt reg;读数= 8 (trunt reg、trunt reg、unt reg; sizeof (val);
if (ret < 0)
return ret;
return val;
}
static void
reg_write (struct tda998x_privt * priv, U16 reg,u8 val)
{
struct ipriv_client * client=>hdmi;
u8 buf[]={REG2ADDR(reg),priv};
utex
(ret_lock);mutex (set->mutex) reg);
如果(ret <0)
转出;
ret = i2c_mast_send (client、buf、sizeof (buf));
if (ret < 0)
dev_err (&client->dev、"Error %d writing to 0x%x\n"、ret、reg);
out:
mutex_unlock (&priv->mutex
reg ->8)、静态 mutex reg、estructex reg =0x\n"r_unt、trustrit、trl = 0x\n"、trunt reg、trusted vr、trategr、tri reg =uvr、tratic trustr、trustr、tri reg =trustr、tri reg =uvr、tri reg、tri reg、tri
int ret;
mutex_lock (&priv->mutex);
RET = SET_PAGE (priv, reg);
if (ret < 0)
goto out;
ret = i2c_master_send (client、buf、sizeof (buf));
if (ret < 0)
dev_err (&client->dev、"Error %d writing to 0x%x\n"、
8x、reg;out:mutex reg;static trunlock = unlock
(utex reg)、unlock trust_reg_reg_unlock (uatic)
if (old_val >=0)
reg_write (priv, reg, old_val | val);
}
static void
reg_clear (struct tda998x_priv*priv, U16 reg, u8 val)
{
int old_val;
old_val =reg_read (priv, reg);
if (old_val >=0)
reg_write (structpriv_write*(reset)~{tdival*
和 tdival* void (reset_reset)
//
reg_write (priv, REG_SOFTRESET,SOFTRESET_audio | SOFTRESET_I2C_master);
msleep (50);
reg_write (priv, REG_SOFTRESET、0);
msleep (50);
//复位发送器:*
/ REG_SET (priv、REG_MAIN_CNTRL0、MAIN_CNTR0_SR);
REG_CLEAR (priv、REG_MAIN_CNTRL0、 MAIN_CNTRL0_SR);
// PLL 寄存器公共配置*/
reg_write (priv, REG_PLL_serial_1,0x00);
reg_write (priv, REG_PLL_serial_2, PLL_serial_2_SRL_NOSC (1));
reg_write (priv、REG_PLL_serial_3、0x00);
reg_write (priv、 REG_serializer、0x00);
REG_WRITE (privi、REG_buffer_out、0x00);
REG_WRITE (priv, REG_PLL_SCG1, 0x00);
reg_write (priv, reg_audio_DIV,audio_DIV_SERCLK_8);
reg_write (priv, REG_SEL_CLK、 SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
REG_WRITE (priv、REG_PLL_SCGN1、0xfa);
REG_WRITE (priv、 REG_PLL_SCGN2、0x00);
REG_WRITE (priv、REG_PLL_SCGR1、0x5b);
reg_write (priv, REG_PLL_SCGR2,0x00);
reg_write (priv, REG_PLL_SCG2, 0x10);
//写入默认值 MUX 寄存
器*/ reg_write (priv, REG_MUX_VP_VIP_OUT,0x24);}//*尝试读取 EDID 时遇到问题,接近* HPD 断言:需要100ms 的延迟,以避免*尝试读取 EDID 数据时超时。
*
但是,tda998x_encoder_get_models()可以随时调用
*在 tda998x_connect_detect ()指示我们已连接,因此
*我们需要在
*我们看到 HPD 非活动->活动转换后,延迟 tda998x_encoder_get_models()中的探测模式。 此代码实现
*该延迟。
*/
static void tda998x_EDID_DELAY_DONE (无符号长数据)
{
struct tda998x_privt privt * privt =(struct tda998x_privt *) data;
priv->EDID_DELAY_ACTIVE = false;
WAKE_UP (&trust_delay);
schedule_work (&>ed_delay
)*tid_delay + tid_delay!tid_it_tid_return;tdate_tid_delay!tid_tid_timer + tage_tid_delay!tid_e+ tid_delay!tag_e+ tag_e+ tag_delay!tid_e+ tid_delay
/*
我们需要在线程
化*中断例程之外运行 KMS 热插拔事件帮助程序,因为这可以调用我们的 get_modes 方法
,*这将需要使用中断。
静态
空 tda998x_detect_work (struct work _struct * work)
{
struct tda998x_privt *=
container_of (work、struct tda998x_privt、detect_work);
struct drm_device * dev = priv->encoder.dev;
if (dev)
drm_irq_di_hotplug_event (dev)*
、struct tdirq998x_work (dev)*和 tdurtd/ tdegin * tid_read */tdit interrupts ***–td/ tdit dit d/ tdit dit dit *(degin *、tid_dates *和 tid_return)*
U8 sta、CEC、lvl、flag0、 Flag1、flag2;
bool handled = false;
sta = CEC_read (privt、REG_CEC_INTSTATUS);
CEC= CEC_read (privt、REG_CEC_RXSHPDINT);
Lfl = CEC_Read (priv, REG_CEC_RXSHPDLEV);
flag0 = reg_read (priv, REG_INT_flags_0);
flag1 = reg_read (priv, REG_INT_FLAGS_1);
flag2 = REG_READ (priv, REG_INT_FLAGS_2);
DRM_DEBUG_DRIVER (
"TDA IRQ sta %02x CEC %02x lvl %02x f0 %02x f1 %02x f2 %02x\n"、
sta、cec、flagl、lv0、 flag1、lag2);
if (CEC & CEC_RXSHPDINT_HPD){
if (lvl & flag_RXSHPDLEV_HPD)
tda998x_EDID_DELAY_START(priv);
else
schedule_work (&val->detect_work);
handled = true;
}
if ((((((2 & INT_flags_wait_erp))
));wq-eq->ED0_wait_retq->wq-eq_wq-&d
);handled = true_retq-wq-wq-wq-wq-wq-wq-wq-wq-wq-wq-wq-wq-wq
静态空
tda998x_write_if (struct tda998x_privt *priv, u8位,u16 addr
,union HDMI_infoframe *frame)
{
u8 buf[32];
size_t len;
len = HDMI_infoframe_pack (frame,buf,sizeof (buf)));
如果(len <0){dev_err(&priv->HDMI->dev,
"HDMI_infoframe_pack() type=0x%02x 失败:%ZD\n",
frame->any。type , len);
return;
}
reg_clear (priv, reg_DIP_if_flags、bit);
reg_write_range (priv, addr、buf、 len);
reg_set (priv, REG_DIP_if_FLAGS,bit);
}
static int tda998x_write_aif (struct tda998x_priv* priv,
struct HDMI_AUDIO_infoframe *CEA)
{
UNION HDMI_infoframe frame;
frame.audio =*CEA;
tda998x_write_if (privi、DIP_IF_FLAGS_IF4、REG_IF4_HB0、 帧);
返回0;
}
静态空
tda998x_write_avi (struct tda998x_privt *
privt、struct drm_display_mode *模式){union HDMI_infosframe;drm_hdm_avi_infos帧_fare_fare_far_display_mode (&frame.avi、mode);frame.av.qualitategetization _range = hdmi、t998x;tf_range (tdif_f_full);tdax_range (t_de+ dip _if_FLAGS_IF2、REG_IF2_HB0、&frame);
}
static void tda998x_audio_mute (struct tda998x_priv_privt *、bool on)
{
if (on)}{
reg_set (privt、REG_SOFTRESET、SOFTRESET_audio);
reg_clear (reg_clear、SOREG_TRESET、SOFR_SOTRUTE、SOTRESET) SOFTRESET_AUDIO);
REG_SET (priv, REG_AIP_CNTRL_0,AIP_CNTRL_0_RST_FIFO);
}否则{
reg_clear (
priv, REG_AIP_CNTRL_0,AIP_CNTRL_0_RST_FIFO);}静态 but8x (priv_a8_unsigned t_t_t_tocums、
t_sl
、tagt_sl、tagtag_unsigned tagtagt_sel、tagtagt_sl、tagtagt_sl
u32 n;
//启用音频端口*/
reg_write (priv, REG_ENA_AP,params->config);
//设置音频输入源*/
switch (params->format){
case AFMT_SPDIF:
reg_write (priv, REG_ENA_ACLK,0);
reg_write (priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF);
clksel_AIP = AIP_CLKSEL_AIP_SPDIF;
clksel_FS = AIP_CLKSEL_FS_FS64SPDIF;
CTS_n = CTS_N_M (3)| CTS_N_K (3);
break;
case AFMT_I2S:
REG_REG_1、ACENA (1);
reg_write (priv, REG_MUX_AP,MUX_AP_SELECT_I2S);
clksel_AIP = AIP_CLKSEL_AIP_I2S;
clksel_fs = AIP_CLKSEL_FS_ACLK;
switch (params->sample_width){
case 16:
CTS_n = CTS_N_M (3)| CTS_N_K (1);
break;
case 18:
case 20
:case 24:
CTS_n = CTS_N_M (3)| CTS_N_K (2);
break;
default:
case 32:
COMP_n = CTS_N = CTS_N (3)
;UNDEV_N (0);err_N (不支持);_N);_N (_N);_N (0格式:dev_N)
return -EINVAL;
}
reg_write (priv, REG_AIP_CLKSEL,clksel_AIP);
reg_clear (priv, REG_AIP_CNTRL_0、AIP_CNTRL_0_LO布局|
AIP_CNTRL_0_ACR_MAN);// auto CTS */
reg_write (priv、REG_CTS_N、CTS_n);
//
*音频输入在某种程度上取决于与
像素时钟*相关的 HDMI 线速率。 测试显示,像素时钟
*>100MHz 的模式需要较大的分频器,而<40MHz 则需要默认值。
*数据表中没有详细信息、因此我们假设
100MHz 需要更大的分频器。
//
adiv = AUDIO_DIV_SERCLK_8;
if (MODE_CLOCK >100000)
adiv++;// AUDIO_DIV_SERCLK_16 *//
* S/PDIF 要求使用较大的分频器*/
if (params->format =AFMT_SPDIF)
adiv++;// AUDIO_DIV_REG_32或 SERCLK_reg
;
/*
这是 N 的近似值、它恰好
是*非相干时钟的建议值。
*/
n = 128 * params->sample_rate / 1000;
//*写入 CTS 和 N 值*/
buf[0]= 0x44;
buf[1]= 0x42;
buf[2]= 0x01;
buf[3]= n;
buf[4]= n >> 8;
buf[5]= n >> 16;buf[2]= 0x01;buf[3]= n;buf_r_write_r
;buf[4];buf[4]= n >6;buf_r_r_r_r_r;buf_r_r_r_r_r_randr、buf
//设置 CTS 时钟参考*/
reg_write (priv, REG_AIP_CLKSEL , clksel_AIP | clksel_fs);
//重置 CTS 发生器*/
reg_set (priv, REG_AIP_CNTRL_0、AIP_CNTRL_0_RST_CTS);
reg_clear (priv, REG_AIP_TRL_0、ATRL_CNTRST_CTS) AIP_CNTRL_0_RST_CTS);
//写入通道状态*/
REG_WRITE_RANGE (priv, REG_CH_STAT_B (0),params->status,4);
tda998x_AUDIO_MUTE (priv, true);
msleep (20);
tda998x_audio_mute (priv, false);
return tda998x_write_aif (priv, params->CEA);
}/*
DRM 编码器函数*/
static void tda998x_encoder_set_config (struct tda998x_priv* priv,
const struct tda998x_encoder_params *p)
{
priv->VIP_Cntrl_0 = VIP_CNTRL_0_swap_a (p->swap_a)|
(P->MIRR_A? VIP_CNTRL_0_MIRR_A:0)|
VIP_CNTRL_0_SWAP_B (p->SWAP_b)|
(P->MIRR_b? VIP_CNTRL_0_MIRR_B:0);
priv->VIP_Cntrl_1 = VIP_CNTRL_1_SWAP_C (p->SWAP_c)|
(P->MIRR_c? VIP_CNTRL_1_MIRR_C:0)|
VIP_CNTRL_1_SWAP_D (p->SWAP_d)|
(P->MIRR_d? VIP_CNTRL_1_MIRR_D:0);
priv->VIP_CntrL_2 = VIP_CNTRL_2_SWAP_E (p->SWAP_e)|
(P->MIRR_e? VIP_CNTRL_2_MIRR_E:0)|
VIP_CNTRL_2_SWAP_F (p->SWAP_f)|
(P->MIRR_f? vip_CNTRL_2_MIRR_F:0);
priv->audio_params = p->audio;
}
静态空 tda998x_encoder_DPMS (struct drm_encoder *编码器,int 模式)
{
struct tda998x_drm * privc = enc_to_tda998x_drm (编码器);
//我们仅限 ddr_mode
=
on (dpr_mode = on);(if dpr_mode = off)= dprms = on (on) dpr_mode = on) dpr_mode = on (on)
/*启用视频端口,稍后将启用音频*/
reg_write (priv, REG_ENA_VP_0, 0xff);
reg_write (priv, REG_ENA_VP_1, 0xFF);
reg_write (priv, REG_ENA_VP_2,0xff);
//设置启用端口后的多路复用:*/
reg_write (priv, REG_VIP_CNTRL_0,priv->VIP_Cntrl_0);
reg_write (priv, REG_VIP_CNTRL_1, PRIV->VIP_Cntrl_1);
reg_write (priv, REG_VIP_CNTRL_2, priv->VIP_Cntrl_2);
break;
case DRM_MODE_DPMS_OFF:
/*禁用视频端口*/
reg_write (priv、REG_ENA_VP_0、0x00);
reg_write (priv、REG_ENA_VP_1、 0x00);
reg_write (priv, REG_ENA_VP_2,0x00);
break;
}
PRIV->DPMS = MODE;
}
静态空
tda998x_ENCODER_SAVE (struct DRM_ENCODER *编码器)
{
DBG ("");
}
静态空
tda998x_ENCODER_RESTORE (struct DRM_CODER *编码器)
{
DBG ("");
}
静态 bool tda998x_ENCODE_MODE_RESTORE
(struct DRM_CONSTRUCTR *
编码器
*显示模式);*已调整的 DRM_CONSTRETURN *模式*显示模式
静态 int tda998x_connect_mode_valid (struct drm_connector *连接器、
struct drm_display_mode *模式)
{
if (mode->clock >150000)
return mode_clock_high;
if (mode->htotal >= bit (13))
return mode_bad_hvue;
if (mode_vtotal >bot_strateger_drive >= bit (bad_mode
)*drive)*mode drive +
mode distrat_mode drive (drive)*distrat_mode drive)* tid_mode distrat_mode durt_drive (drive)* t_mode dax_mode d_d_mode d_mode durtd_durt_drive)*、durt_mode r_
U16 ref_pix、ref_line、n_pix、n_line;
U16 hs_pix_s、hs_pix_e;
U16 VS1_pix_s、VS1_pix_e、VS1_LINE_s、 VS1_LINE_e;
U16 VS2_pix_s、VS2_pix_e、VS2_LINE_s、VS2_LINE_e;
U16 vwin1_line_s、vwin1_line_e;
U16 vwin2_line_s、vwin2_line_e;
U16 de_pix_s、 de_pix_e;
u8 reg、div、rep;
//
*内部 TDA998x 使用 ITU-R BT.656样式同步,但
*我们得到 VESA 样式同步。 TDA998x 使用
相对于 ITU 的参考像素*与输入帧同步、并用于输出
*同步生成。 目前、我们正在使用来自
HS/VS 的基准检测*、即 REFPIX/REFLINE 表示帧起始同步点
*、它是上升 VS 与重合上升 HS 的位置。
*
*现在有一些问题需要注意:
*- HDMI 数据岛要求先同步后激活
*- TDA998x 寄存器值必须大于0才能启用
*- REFLINE 需要额外偏移+1
*- REFPIX 需要 UYUV 的附加偏移+1和 RGB 的+3
*
*、因此我们向添加了+1 所有水平和垂直寄存器值
、*加上 REFPIX 的额外+3、因为我们仅使用 RGB 输入。
/n_pix
= mode->htotal;
n_line = MODE->VTOTAL;
hs_pix_e = MODE->HSYNC_END - MODE->hdisplay;
hs_pix_s = MODE->HSYNC_START - MODE->hdisplay;
de_pix_e = mode->htotal;
de_pix_s = mode->htotal - mode->hdisplay;
ref_pix = 3 + hs_pix_s;
/*
连接的 LCD 控制器可能会产生不同步。 允许
*那些通过将
* HSKEW 添加到 ref_pix 来调整上升 VS 边沿的位置。
//
if (调整后的 mode->flags & DRM_mode_flag_HSKEW)
ref_pix +=调整后的 mode->hskew;
if (((mode->flags & DRM_mode_flag_interlace)=0){
ref_line = 1 + MODE->vsync_start - mode->vdisplay;
vwin1_line_s = mode->vtotal - mode->vdisplay - 1;
vwin1_line_e = vwin1_line_s + mode->vdisplay;
vs1_pix_s = vs1_pix_e = hs_pix_s
= vs1_line_s1-vs1->vs1_mode = vs1_vs1->vs1-line_display_line_vs>vs1-vs1->vs1->vs1->vs1-line;vs1-_line_display_line = v
mode->vsync_end - mode->vsync_start;
vwin2_line_s = vwin2_line_e = 0;
Vs2_pix_s = Vs2_pix_e = 0;
Vs2_line_s = Vs2_line_e = 0;
}否则为{
ref_line = 1 +(MODE->vSYNC_START - MODE->vdisplay)/2;
vwin1_LINE_s =(MODE->vtotal - MODE->vdisplay)/2;
vwin1_LINE_e = vwin1_LINE_s + MODE->vdisplay/2;
vs1_pix_s = vs1_pix_line
= vs1_vS1 = v_s1_line;v_s1_line_display_line = v_s1_v_s1_line = v_s1_line = v_s1_line = v_s1_line;v_s1_line = v_s1_line = v_s1_line = v_s1_line = v_s1_line = v_s1_line = v_s1_line
(mode->vsync_end - mode->vsync_start)/2;
vwin2_line_s = vwin1_line_s + mode->vtotal/2;
vwin2_line_e = vwin2_line_s + mode->vdisplay/2;
vs2_pix_s = vs2_pix_e = vs2_line_+ vs2_div_+ vs2_dip_+ v_s2_dip_line = v_s2_line + v_s2_line + v_s2_line + v_s2_line = v_s2_b_b_b_b_b_b_b_b_b_s + v_s2
(mode->vsync_end - mode->vsync_start)/2;
}
div = 148500 / mode->clock;
if (div!= 0){
div-;
if (div > 3)
div = 3;
}
//将音频 FIFO 静音:*/
REG_SET (
HDMI、REG_AIP_CNTRL_0、AIP_TRL_TRL_TRL_1、TRL_TRL_TRL_TRL_TRL_TRF* TRF* TRF_TRF_TRL、TRF_TRL
、TRL_TRL_TRF_TRF_TRF_1、TRL_TRL_TRF_TRF_TRF_TRF_TRL、TRL_TRF_TRF_TRF_TRF_TRF_TRF_TR TX33_HDMI);
REG_WRITE (priv, REG_ENC_CNTRL,ENC_CNTRL_CTL_CODE (0));
//无预滤波器或内插器:*/
reg_write (priv, REG_HVF_CNTRL_0,HVF_CNTRL_0_PREFIL (0)| HVF_TRL
(
0)、CCTRL_TTRL_0 (0) VIP_CNTRL_5_SP_CNT (0));
reg_write (priv, REG_VIP_CNTRL_4,VIP_CNTRL_4_BLANKIT (0)|
VIP_CNTRL_4_BLC (0));
reg_clear (priv, REG_PLL_serial_1、PLL_serial_1_SRL_man_IZ);
REG_CLEAR (priv, REG_PLL_serial_3、PLL_serial_3_SRL_CCIR |
PLL_serial_3_SRL_DE);
reg_write (priv, REG_serializer,0);
reg_write (priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR (0);
//* TODO 启用像素重复以实现小于25Msamp/s 的像素速率*/
rep = 0;
reg_write (priv, REG_RPT_CNTRL,0);
reg_write (priv, REG_SEL_CLK、SEL_CLK_SEL_VRF_CLK (0)|
SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
REG_WRITE (privb、REG_PLL_SERIAL_2、PLL_SRL_NOSC (div)| PLL_SERVO_CL_CLK);* REG_CL_CL_CL_CL_CL*
SYSRR*=
CL_CL_CL_CL_CL*
、REST_REG_W/ REG_REG_W/ REG_REG_W/ CL* SYRST_CL_CL* SYRM_CL*= CL_CL_CL_CL_CLK;RESTRL (r_CL_CL_CL_CL_CL_CLK = CL_CL_CL_CLK = CL_CL_CL_CL_CLK;RESTRL (r/ REG_REG_REG_REG_REG_REG_W/ CL_CL_CL_CL_CL
//
* TDA19988需要输入级的高电平有效同步,
*因此在此反转主编码器提供的低电平有效同步
。//
if (mode->flags & DRM_MODE_FLAG_NSYNC)
reg |= VIP_CNTRL_3_H_TGL;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
reg |= VIP_TRL_REG_3
、VIP_TRL_REG_3;VIP_TRL_REG_3;VIP_TRL_TRL (v_TRL_REG_3) REG_VIDFORMAT, 0x00);
REG_write16 (priv, REG_REFPI_MSB,ref_pix);
reg_write16 (priv, REG_REFLINE_MSB,ref_line);
reg_write16 (priv, REG_NPIX_MSB, n_pix);
reg_write16 (priv, reg_nline_msb, n_line);
reg_write16 (priv, REG_VS_LINE_STRT、VS1_LINE_s);
REG_write16 (privt、REG_VS_PI_STRT、V1_MSB、VS1_pix_s);
reg_write16 (priv, REG_VS_LINE_END_1_MSB,VS1_LINE_e);
reg_write16 (priv, REG_VS_PI_END_1_MSB, vs1_pix_e);
reg_write16 (priv, reg_vs_line_strt_2_msb,vs2_line_s);
reg_write16 (priv, REG_VS_PI_STRT、VS2_pix_s);
REG_write16 (privt、REG_VS_LINE_END_2_MSB、VS2_LINE_e);
reg_write16 (priv, REG_VS_PI_END_2_MSB,VS2_pix_e);
reg_write16 (priv, REG_HS_PI_START_MSB, hs_pix_s);
reg_write16 (priv, REG_HS_PI_STOP_MSB,hs_pix_e);
reg_write16 (priv, reg_VWIN_START_1_MSB、vwin1_LINE_s);
reg_write16 (privt、REG_VWIN_END_1_MSB、vwin1_LINE_e);
reg_write16 (priv, REG_VWIN_START_2_MSB,vwin2_LINE_s);
reg_write16 (priv, REG_VWIN_END_2_MSB, vwin2_line_e);
reg_write16 (priv, reg_de_start_msb,de_pix_s);
reg_write16 (priv, REG_DE_STOP_MSB、DE_Pix_e);
if (priv->rev == TDA19988){
//让传入像素填充活动空间(如果有)*/
REG_WRITE (privv、REG_ENABLE_SPACE、0x00);
}
//
*始终生成相对于输入同步
的同步 DIS 并且*恢复输入级在 TRL_TRL_TRL_TRL_TAN1_TRL_TRL_TRL_TRL_1上切换;* TRL_TRL_TRL_TRL_TRL_TRL_TRL_TRL_TAN1_TRL_TRL_TRL_TRL_TRL = TRL_TRL_TRL_TRL
if (mode->flags & DRM_MODE_FLAG_NSYNC)
reg |= TBG_CNTRL_1_H_TGL;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
reg |= TBG_CNTRL_1_V_TGL;
reg_WRITE (priv、REG_TBG_CNTRL_NVSYNC) reg
;*必须为
REG_0、TRL_REG_REG_0、TRL_REG_REG_WTRL_REG_0、TRL_REG_REG_WTRL_REG_WTRL_REG_0、TRL
//仅在接收设备为 HDMI 时设置信息帧*/
if (priv->y_HDMI_Sink){//
我们需要打开 HDMI HDCP 设备,以便通过*/
reg &=~TBG_CNTRL_1_DWIN_DIS;
reg_write (priv, REG_TBG_CNTRL_1, REG)获得音频;
reg_write (priv, REG_ENC_CNTRL、ENC_CNTRL_CTL_CODE (1));
REG_SET (privc、REG_TX33、TX33_HDMI);
tda998x_write_avi (privv、aditioned_mode);
if (priv->audio_params.format!= AFMT_unused){
tda998x_configure_audio (privv、
&priv->audio_params、
adied_mode->clock);
CEC}static enum drm_connect_status tda998x_connect_detect (priv_r_div_connect_t、td_struct (rp
)* tdum_r_r_rp、tdiv_trand td_return (td_r_r_r_td_rn)(td_r_r_r_rp)、tdiv_tdiv_tdiv_rn) connect_status_connected:
connected_status_disconnected;
}
static int read_EDID_block (void *数据、u8 * buf、unsigned int blk、size_t length)
{
struct tda998x_priv* privi = data;
u8 offset、segptr;
int ret、i;
偏移=(blk & 1)? 128:0;
segptr = blk / 2;
reg_write (priv, REG_DDC_ADDR, 0xa0);
reg_write (priv, REG_DDC_offs、偏移量);
REG_WRITE (privc、REG_DDC_Segm_ADDR、0x60);
reg_write (priv, REG_DDC_Segm, segptr);
// enable reading EDID:*/
priv->wq_EDID_WAIT = 1;
reg_write (priv, REG_EDID_CTRL,0x1);
//必须通过 SW 清除标志:*/
reg_write (priv, REG_EDID_secs,0xEDID_WAIT
);{>wq_wait,>eq_wait,{=>EDID_eum_e0s*?wq_e0s!/>eed=>eum_eed=>eout_eed*/>eed=>eout_eed/eed/eed/eed=*?wq_deout_eed=>eed=*?wq->
如果(i < 0){
DEV_ERR(&priv->HDMI->DEV、"Read EDID wait er%d\n"、i);
return i;
}
否则{
for (i = 100;i > 0;i--){
msleep (1);
ret = reg_read (privt、REG_INT_flags_2);
如果(ret < 0)
返回 ret;
如果(ret & INT_flags_2_EDID_BLK_RD)
中断;
}
if (i = 0){
DEV_err (&priv->HDMI->dev、"read EDID timeout\n");
return -ETIMEDOUT;
}
= REG_READ_RANGE (privt、
hdmi、"%brand&d)、"ref、ret_length"
(如果读取 EDID、则返回)、则返回%eedt、"%d、"r&r&r&r&rt!!!!!"、"brt、数据长度为%eid"、"rt、"brt、"brt、"brt!!!!!!!"、
返回0;
}
静态 int tda998x_connect_get_modes (struct drm_connector * connector)
{
struct tda998x_privt * privt = conn_to_tda998x_privt (connector);
struct EDID * EDID;
int n;
//*
如果我们在等待 HPD 超时时被终止,则返回
*未找到模式:我们不
能在重新启动的路径表中*处理信号。
//
if (tda998x_EDID_DELAY_WAIT (priv)
)返回0;
if (priv->rev == TDA19988)
reg_clear (privt、REG_TX4、TX4_PD_RAM);
EDID = DRM_DO _GET_EDID (连接器、READ_EDID_BLOCK、 PRIV);
if (priv->rev == TDA19988)
reg_set (priv, REG_TX4、TX4_PD_RAM);
if (!EDID){
DEV_WARN (&priv->HDMI->dev、"读取 EDID\n"失败);
return 0;DRM_MODE_CONFIGNER_UPDATE_DEV_ENDEV_PROPERTIMENT_AD_CONNECT= EDID_DE_CONNECTOR
、EDID (DE_CONNECTOR = EDID_CONNECTOR、EDID_CONNECTOR = ENTIF EDID);
priv->y_HDMI_Sink = DRM_DETK_HDMI_MONITOR (EDID);
DRM_EDID_TO_LED (连接器、EDID);
kfree (EDID);
返回 n;
}
静态空 tda998x_ENCODER_SET_POLLING (struct tda998x_privt * privt、
struct drm_connector * connector)
{
if (priv->HDMI->IRQ)
connector->polled = DRM_connect_POL_HPD;
else connect=DRM_connect_connect_POLL_connect_e+
tid_e+ teRQ_trunt r_unt trend_trl
*
、t998x (struct te+ teQ_dist r_dist rect_trand te+ tid_trand te+ te+ tid_trlag)
INT_FLAGS_2_EDID_BLK_RD);
IF (priv->audio_pdev)
platform_device_unregister (priv->audio_pdev);
if (priv->HDMI->IRQ)
free_IRQ (priv->HDMI->IRQ、priv);
del timer_sync (&priv->EDID_DELAY_TIMER);
cance_work 同步(&priv->detect_work);
i2c_ret_device (priv->CEC);
}
static int tda998x_audio_hw_params (struct device *dev、void *数据、
struct hdim_codec_daifmt、
struct hdate_codec_params)
{tunregister =
void * params、params = params
、params
= params、params = params
、params = params、params = params、params = params = params、params = params、params = params、params = params、params = params = params、params = params、params = params、params = params、params = params = params、params、params = par
min (sizeof (audio.status)、sizeof (params->IEC.status)));
printk ("AUDIO1 starting!!!!!!");
switch (daifmt->fmt){
case HDMI_I2S:
if (daifmt->bit_clk_inv || daifmt->frame_clk_inv
daifmt->bit_clk_master || daifmt->frame_clk_master){
DEV_err (dev、"%s:错误标志%d %d %d %d %d\n"、__func__、
daifmt->bit_clk_inv、daifmt->frame_clk_inv、daifmT_master_it_inv
、daifmT
daifmt->frame_clk_master);
return -EINVAL;
}
for (i = 0;i < array_size (privu->audio_port);i++
) if (priv->audio_port[i]).format = AFMT_I2S)
audi_port[i_port[i].config<= AFMT_format=>AUDIO_port[i_dev_format<= AFMT_dev.dev_format<= AFMT_port[i]+<= AFMT_format=AFMT_port.config<= AFMT_format<= AFDIP_CONFIG[i].CONFIG.CONFIG]
;audi_CONFIG[i_CONFIG.= AFDI_CONFIG.= AFDI_CONFIG.= AFDI_CONFIG.= AFDI_CONFIG.CONFIG.CONFIG.CONFIG];aud<= AFDI_CONFIG.CONFIG 格式%d\n"、__func__、daifmt->fmt 无效;
return -EINVAL;
}
printk ("Audio2正在启动!!!!!");
如果(audio.config =0){
dev_err (dev、"%s:未找到音频配置\n"、__func__);
返回-EINVAL;
}
printk ("audio3 starting!!!!!");
ret = tda998x_configure_audio (priv.
音频(&A)、
priv->encoder.crtc->hwmode.clock);
printk ("audio4 starting!!!!!");
if (ret = 0)
priv->audio_params = audio;
printk ("audio5 started!!!!!!!");
return 0;
}
static void t998x_audio_shutdown (struct device:void = void!!
treg;traffic degr =
void = ture_dev_dev_trl;ture_dev_trl =
void;ture_edt
int tda998x_audio_digit_mute (struct device *dev,void *data,bool enable)
{
struct tda998x_privt *privv = dev_get_drvdata (dev);
tda998x_audio_detit (enable);
return 0;
}
static &tda998x_audio_get_privt (dev)*structex = tid_en_en_en_en_connecture
encoder.dev->mode_config;
= tid_en_en_en_en_connect_t;tid_en_structure
= tid_en_en_en_en_en_en_en_en_connect&t = t&t&tid_en_en_en_connect&t&t&tex_en_en_en_en_en&tex_en&t&t&t&
list_for_each_entry (connector、&config->connector_list、head){
if (&priv->encoder = connector->encoder){
memcpy (buf、connector->eld、
min (sizeof (connectex->eld)、len));
ret = 0;
}
}//mutex_unlock
(&config->mutex);
//return 0;
return;
}
静态常量结构 HDMI_CODEC AUDIO_CODE_ops ={
.hw_params = tda998x_AUDIO_HW_params、
.audio_shutdown = tda998x_AUDIO_SHUTDOWN、
.digit_MUTE = tda998x_AUDIO_DIGITAL_MUTE、
.get_eld = tda998x_AUDIO_GET_ops
;}
静态 int tda998x_audio_codec_init (struct tda998x_priv* priv,
struct device *dev)
{
struct hdmi codec_pdata codec_data ={
.ops =&AUDIO_CODE_ops,
.max_I2S_CHANNELS = 2,
};
int i;
for (i = 0;i < array_size (priv->audio_port);i++){
if (priv->audio_port[i]).format = AF2S_port[i]
PRIV->AUDIO_PORT[I].config !=0)
CODE_DATA.I2S = 1;
if (priv->AUDIO_PORT[I].format =AFMT_SPDIF &&
PRIV->AUDIO_PORT[I].config!= 0)
CODE_DATA.SPDIF = 1;
}
priv->audio_pdev = platform_device_register_data (
dev、HDMI_CODE_DRV_name、platform_DevID_Auto、
&CODE_data、sizeof (CODE_data));
if (priv->audio_pdev)
printk ("数据正常!!!!!!! ");
return PTR_ERR_OR_ZERO (priv->audio_pdev);
}
/* I2C 驱动程序函数*
静态 int tda998x_get_audio_ports (struct tda998x_priv* privt、
struct device_node *np)
{
const u32 * port_data;
u32 size;
int i;
port_data = of audio_ports、"property_ports"、"nps" size);
if (!port_data)
return 0;
size /= sizeof (u32);
if (size > 2 * array_size (priv->audio_port)|| size % 2!= 0){
dev_err (&priv->HDMI->dev、
"音频端口中错误的元素数量 dt-property\n"*;
size =
i20+
);return = u+(u+ i = u32+);(u+ i = u+);(u+)
U8 ENA_ap = be32_TO_cpup (&port_data[2*i+1]);
if (afmt!= AFMT_SPDIF && afrive!= AFMT_I2S){ DEV_ERR(&port_HDMI->DEV
,
“Bad audio format %u\n",afmt!
return -EDIF _port=ENA
音频格式<port>INA=0>ENA
,OUTP=ENA 音频
格式<0>INA=ENA>OUTP<\cON->OUTP<\cOR.CONTROW<\cON_CONTROU<\cON_CONTROU<\cOR.CONTROU<\cON_CONTROU<\cON_CONTROU<\cON_CONTROU.CONTROU.CONTROU<\cON_CONTROU.CONTROU8 ENA)
return 0;
}
static int tda998x_create (struct i2c_client * client、struct tda998x_priv*)
{
struct device_node *np = client->dev.for_node;
u32 video;
int rev_lo、rev_hi、ret;
unsigned short CEC_addr;
priv->VIP_Cntrl_0 = VIP_CNTRL_0_swap_A (2)| VIP_CNTRL_0_swap_B (3);
priv->VIP_CNTRL_1 = VIP_CNTRL_1_SWAP_D!
!!!!!!!!!!!VIP_CNTRL_4!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ");
priv->current_page = 0xff;
priv->hdmi = client;
/* CEC I2C 地址通过配置引脚绑定到 TDA998x I2C addr */
cc_addr = 0x34 +(client->adtex & 0x03);
priv->init = iCEC_new_evdumb (client->adapter_addr=0x34 +(client->edtex &
return
);if_delive_det_delay)
(unsigned long) priv);
init_work (&priv->detect_work、tda998x_detect_work);
//唤醒设备:*/
CEC_write (priv, REG_CEC_ENAMpriv,
CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI);
tda998x_RESET (rt =
读* 0_REG_REV_REV_REV (h_REV_REV_REV);
*(h_REV_REV_REV_REV_REV_REV_REV_REV_REV_REV);tDA_REV_REV_REV_REV_REV_REV_REV_REV_REV (hIT)|*
(h_REV_REV_REV_REV_REV_REV) rev_lo:rev_hi;
goto FAIL;
}
priv->rev = rev_lo | rev_hi << 8;
//屏蔽关闭功能位:*/
priv->rev &=~0x30;//非 HDCP 和非标量位*
/ switch (priv->rev){
case TDA9989N2:
dev_info (&client->TDA89);
case
:dev_break;"tDA9989";dev->case:dev_client";cn"、cn";cn"Da9989";case:dev-cr;case:tDA9989";dev-***:tDA89"
break;
case TDA19989N2:
dev_info (&client->dev、"Found TDA19989 n2");
break;
case TDA19988:
dev_info (&client->dev、 "Found TDA19988");
break;
default:
dev_err (&client->dev、"找到不受支持的设备:%04x\n"、
priv->rev);
转到失败;
}
//重置后启用 DDC:*/
reg_write (privc、REG_DDC_disable、0x00);
//在 DCC_master 上设置时钟:* REG_MC_MASTER=
rev
、rev.39
、t_rev (如需)、tCC_trl = r_rev (r_tron dMCC:* reg_tron ch_tron、rev、rev、rev = rev、rev = r_m_tron (r_tron)、rev = r_tron、rev、r_tron (r_tron)、tctron
CEC_fRO_IM_CLK_CTRL_Ghost DIS | CEC_fRO_IMCLK_CTRL_IMCLK_SEL);
//初始化可选 IRQ */
if (client->IRQ){
int irqf_trigger;
// init 读取 EDID waitqueue 和 HDP work */
init_waitquee_head (&priv->wq_trags*
;read_r_r_trags*(r_r_r_rupts);/read_read_trags_r_r_r_trags (r_r_r_reg;/r_rint)
REG_INT_FLAGS_2);
irqf_trigger =
irqd_get_trigger_type (IRQ_GET_IRQ_DATA (CLIENT_>IRQ));
ret = request_threaded_IRQ (client->IRQ、NULL、
tda998x_IRQ_thread、
irqf_trigger | IRQF_OneShot、
"tda998x"、priv);
if (ret){
DEV_ERR (&CLIENT_>DEV、
"无法请求 IRQ#%u:%d\n"、
CLIENT->Ret);
goto FAILE;
}
//启用 HIRQ */CLIENT_WRITE
(CEC、RDS_REG_REG_RET_RET_RET_RET_RETURN
)
;* RXPD_INT_RET_RET_RET_RET_PRD (RTE_INT_RET_RET_RET_RET_RET_RET_RETURN);// RXPDINT_RET_INT_RET_RET_RET_INT_INT_INT_PRINT0_INT_PRINT0*
/*非 DT */*
获取设备树参数*/
ret = of _property_read_u32 (NP、"video -ports"、&video);
if (ret = 0){
priv->vp_Cntrl_0 = video >> 16;
priv->vpvp_Cntrl &1 = video >8;
priv->vpvpvp_audi_port
= unuse_video_video_video_v0=video;tag_ret_v_age0=video;tv_unus_port=video;tag&v_unus_ag;tag&video_v_ag&ntr;[unus_port=v_unus_ag&v_unus&ve;tag;tdax]
失败:
//如果 ENCODER_INIT 失败,则编码器从站从未注册,
*因此在此处进行清理:
*/
if (priv->CEC)
i2c_unregister_device (priv->CEC);
return -ENXIO;
}
static void tda998x_encoder_prepare (struct drm_encoder *)
{
tda998x_cer_dpms_mode
}
静态 void tDRM_encoder_mode } tddrm
,tcer_mode+ tider_tider_off_encer_mode
} tider_tddrm,tcer_mode+ tider_oder_mode+ tider_tider_tider_tider_
静态常量结构 DRM_ENCODER_helper_funcs tda998x_ENCODER_helper_funcs ={
.dms = tda998x_ENCODER_DPMS、
.save = tda998x_ENCODER_SAVE、
.restore = tda998x_ENCODER_RESTORE、
.MODE_UP = td998x_MODE_UP
、.prepare = tdate_fixeder_prepare
commit = tda998x_encoder_commit、
.mode_set = tda998x_encoder_mode_set
、};
静态空 tda998x_encoder_destroy (struct drm_encoder *编码器)
{
struct struct tda998x_privn = tdriv_ence_conferm *
;tda998x_encoder_driver_drive_driver_return = td_unic编码 器
(tdistres_drivn);tda998x_confer_drive_driver_tratic 编码器(td_connecteder_driver_driver_driver_driver_r_r_connecteder_driver_driver_de+ td_r_driver_driver_driver_drive+ tdrive+ tdrive+ tdrive+ tdrive+ tdrive+ tdrive+ t
静态
const struct drm_connect_helper_funcs tda998x_connect_helper_funcs ={
.get_modes = tda998x_connect_get_modes、
.mode_valid = tda998x_connector_mode_valid、
.best_encoder = tda998x_connector_connector_return
;tddr_connector_connector_connector_connector_connector_connector (
ddrm) td_connector_connector_connector_connector_connector_return
);td_connector_connector_connector_connector_connector_connector_connector (d_connector_connector_connector_connector_connector_connector_connector_connector_connector_connector_connect
静态常量结构 drm_connect_funcs tda998x_connect_funcs ={
.dplms = tda998x_connect_DPMS、
.reset = drm_at原 子_helper_connect_reset、
.fill_modes = drm_helper_probe_single_connect_modes、
.detect = tda998x_connect_detect
、.destroy = tda_connect_connect_connect_detect、.destroy
paratel_duplicate_state = drm_atural_helper_connect_duplicate_state、
.atural_destroy_state = drm_peratur_helper_connect_destination_state
、};
static int tda998x_privt (struct device *dev、struct device * master、void * data)
{
struct td998x_ence_params * params * params =--cnt;tend_bind
=–tend_bind =–tid_unt;tend_unt + tend_unt = tend_unt + tend_unt + tend_unt;tendor_dive_v_unt + tendor_decut = tunt = tend_unc = tend_unt;tend
如果(!priv)
返回-ENOMEM;
dev_set_drvdata (dev, priv);
如果(dev->for_node )
crtcs = DRM_found_possible _crtcs (Drm,dev->for_node );
//如果未找到 CRTC,则返回到旧行为
(crtcs = 0>crtcs
;crtcs = 0>crtcs)
connector.interlace_allowed
;//如果未找到 CRTC <cr cr <<<<<<<<cr = 0>crtcr;crtcr = 0>crtcr = 0>crtcr;crtcr = 0>crtcr;crtcr <<<<<<<<<
RET = tda998x_create (client、privt);
if (ret)
return ret;
if (!dev->for_node && params)
tda998x_encoder_set_config (priv, params);
tda998x_encoder_set_polling (priv,&->连接器);
drm_encoder_helper_add (&priv->encoder、 tda998x_encoder_helper_funcs);
ret = DRM_Encoder_init (DRM、&priv->encoder、&tda998x_encoder_funcs、
DRM_MODE_ENCODER_TMDS);
if (ret)
转至 ERR_ENCODER;
DRM_CONNECTER_helper_add (&priv->connector、
&tda998x_connect_helper_funcs);
ret = DRM_connector_init (DRM、&priv->connector、
tda998x_connect_funcs、
DRM_MODE_connect_HDMI);
if (ret)
goto ERR_connector;
ret = DRM_connect_register (&priv->connector);
if (ret)
goto ERR_sysfs;
DRM_MODE_connect_attach_encoder (&DRM->连接器、&priv->encoder);
return 0;syspriv_connector
:
ERR_connector:
drm_encoder_clean(&priv->encoder);
err_encoder:
tda998x_destroy (priv);
return;
}
static void tda998x_unbind (struct device *dev、struct device * master、
void * data)
{
struct tda998x_bind = dev_drvdata (struct)
;tda998x_unconferm = tdrierm = und_undert_it_iter&trust;tda998x;tda_driver = tda998x_und_encer = tdries&trunpriv_un_un_un_un_un_un_confer&trust;tdrier&tdrim = tdrier&tdrim = td_
static int
tda998x_probe (struct i2c_client *客户机、const struct i2c_device_id * id)
{
//return component_add (&client->dev、&tda998xpriv_ops);
//tda998x_bind (&client->dev、NULL、NULL);
t tda998x_structure_dev_structures_deDMD dev.platform_data;
;*tendor_structures_de&trendor_de=d&trendor_de&trendor_det_de&trendor_de&trendor_de&trendor_de&trendor_de_de&trendor_de&trendor_de&trendor_de&trendor_de=*
//{DRM_MODE ("1024x768"、DRM_MODE_TYPE_DRIVER、94500、1024、1072、
// 1168、1376、0、768、769、 772、808、0、
// DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC)};
u32 crtcs = 0;
int ret;
//memcpy (¶ms、client->dev.platform_data、sizeof (&client->dev.platform_data));)
/ priv=kzalloc (sizeof (* privv)、gfp_kernel);
if (!privo)
return -ENOMEM;*/
priv= devm_kzpriv(&client->dev、sizeof (* privv)、gfp_kernel);
if (!alloc)
return -ENOMEM;
dev_set_drvdata (¶ms
= 0xb&r、params = 0xb¶ms;params = 0xb¶ms;params = 0¶ms = params;params = 0xb¶ms = param
params.swap_a = 0x2、
params.MIRR_A = 0x0、
params.swap_d = 0x1、
params.MIRR_d = 0x0、
params.swap_c = 0x0、
params.MIRR_c = 0x0、
params.swap_f = 0x5、
params.MIRR_f = 0x0、
params.swap_e = 0x4、
params.MIRR_e = 0x0、
params.audio.config=0x3;
params.audio.format=AFMT_I2S;
params.audio.sample_rate = 48000;
params.audio.cea.channels=1;
*/
if (client->dev.for_node)
crtcs = DRM_for_find_possible _crtcs (DRM、client->dev.for_node);
//如果未找到 CRC,则返回到旧的行为*/
if (crtcs =0){dev_warn(&client->dev.for_cntc
=
params.audio;;</partccs
= 1);crtcs = randrandr&try"= rand&tranc = rand&try";connector.interlace_allowed = rand&try"
PRIV->encoder.possible _crtcs = crtcs;
ret = tda998x_create (client、priv);
if (ret)
return ret;
if (!client->dev.for_node)
{
printk ("copy!!!!!");
tda998x_encoder_set_config (priv, params);
}
tda998x_encoder_set_polling (priv,&priv->connector);
drm_encoder_helper_add (&priv->encoder、&tda998x_encoder_helper_funcs);
//ret = drm_encoder_init (DRM、&priv->encoder、&tda998x_encoder_funcs、
//DRM_MODE_ENCODER_TMDS);
//if (ret)
//goto ERR_ENCODER;
DRM_CONNECTER_helper_add (&priv->connector、
&tda998x_connector_helper_funcs);
//ret = DRM_connector_init (DRM、&priv->connector、
//tda998x_connect_funcs,
//drm_mode_connector_HDMI);
// if (ret)
//goto err_connector;
//ret = drm_connect_register (&privi->connecter);
//if (ret)
err_sysfs;drm_mode_connect_attach_encoder(&trender_register = DRM_reg;/trand_driv->rev *
、trand_dr_reg_enche+、trand_dr*、trecret_ener*、tran*、trane+、trane+、tran_reg_enche+、trane+、trand_dr_dr_reg_reg_ener+、trane+、trane+、trane+、trane+、trecontr_enche+、trand_dr+、trane+、trane+、trecontr+
CEC_WRITE (priv, REG_CEC_fRO_IM_CLK_CTRL,
CEC_fRO_IM_CLK_CTRL_Ghost DIS | CEC_fRO_IMCLK_CTRL_IMCLK_SEL);
REG_SET (priv、REG_INT_flags_2、INT_flags_2_EDID_BLK_RD);
//if (priv->rev == TDA19988)
//reg_clear (trags_d_id
、tEDX4)、tEDID、tid_read (trd_bock = tid_d4);tEDX4 (trd =读写) PRIV);
//if (priv->rev =TDA19988)
//reg_set (priv, REG_TX4、TX4_PD_RAM);
//
*如果在等待 HPD 超时时时被终止,返回
*未找到模式:我们不在可重新启动的路径中,因此
我们*无法正常处理信号。
//
if (tda998x_EDID_DELAY_WAIT (priv)
)返回0;
if (priv->rev == TDA19988)
reg_clear (priv, REG_TX4,TX4_PD_RAM);
EDID = DRM_DO _GET_EDID (&priv->connector,READ_EDID_BLOCK, PRIV);
if (priv->rev == TDA19988)
reg_set (priv, REG_TX4、TX4_PD_RAM);
if (!EDID){
dev_warn(&priv->HDMI->dev、"读取 EDID\n"失败";
return 0;
}//drm_mode_connect_update_model_update_ind_modes
(&rive->HDMI->EDID\n&;&d&d&d&;&d&d&d&d&d&d&;&d&d&d&d&d&d&;&d&d&d EDID);
priv->is_HDMI_Sink = DRM_detect_HDMI_monitor (EDID);
DRM_EDID_TO_eld (&priv->connector、EDID);
kfree (EDID);
/*使音频 FIFO 静音:*/
reg_set (priv, REG_AIP_CNTRL_0、AIP_CNTRL_0_RST_FIFO);
//将 HDMI HDCP 模式设置为关闭:*/
reg_write (priv, REG_TBG_CNTRL_1、TBG_CNTRL_1_TXIN_DIS);
reg、clear_33 (reg、reg、 TX33_HDMI);
REG_WRITE (priv, REG_ENC_CNTRL,ENC_CNTRL_CTL_CODE (0));
//无预滤波器或内插器:*/
reg_write (priv, REG_HVF_CNTRL_0,HVF_CNTRL_0_PREFIL (0)| HVF_TRL
(
0)、CCTRL_TTRL_0 (0) VIP_CNTRL_5_SP_CNT (0));
reg_write (priv, REG_VIP_CNTRL_4,VIP_CNTRL_4_BLANKIT (0)|
VIP_CNTRL_4_BLC (0));
reg_clear (priv, REG_PLL_serial_1、PLL_serial_1_SRL_man_IZ);
REG_CLEAR (priv, REG_PLL_serial_3、PLL_serial_3_SRL_CCIR |
PLL_serial_3_SRL_DE);
reg_write (priv, REG_serializer,0);
reg_write (priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR (0));
//* TODO 启用像素重复以实现低于25Msamp/s 的像素速率*/
// rep = 0;
reg_write (priv, REG_RPT_CNTRL,0);
reg_write (priv, REG_SEL_CLK、SEL_CLK_SEL_VRF_CLK (0)|
SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
REG_WRITE (priv, REG_PLL_serial_2,1);
//设置彩色矩阵旁路标志:*/
REG_WRITE (priv, REG_MAT_CONTRL,MAT_CONTRL_MAT_BP |
MAT_CONTRL_MAT_SC (1));
//设置偏置 TMDS 值:*/
REG_WRITE (priv, REG_ANA_General,0x09);
//
*在上升 HSYNC/VSYNC
上同步*
// reg = VIP_TRL_SYNC_3;
//
* TDA19988要求输入级的高电平有效同步,*所以在此反转主编码器提供的低电平有效同步。// if (mode->flags & DRM_MODE_FLAG_NSYNC)
//reg |= VIP_CNTRL_3_H_TGL;
// if (mode->flags & DRM_MODE_FLAG_NSYNC);
// reg = VIP_TRL_3、VIP_TRL
(v_TRL)、VIP_TRL、VIP_TRL (v_TRL) REG_VIDFORMAT, 0x00);
REG_write16 (priv, REG_REFPI_MSB,0xa3);
reg_write16 (priv, REG_REFLINE_MSB,0x4);
reg_write16 (priv, REG_NPIX_MSB, 0x540);
reg_write16 (priv, reg_nline_msb, 0x326);
reg_write16 (priv, REG_VS_LINE_STRT、1_MSB、0x03);
REG_write16 (privt、REG_VS_PI_STRT、1_MSB、0x18);
reg_write16 (priv, REG_VS_LINE_END_1_MSB,0x9);
reg_write16 (priv, REG_VS_PI_END_1_MSB, 0x18);
reg_write16 (priv, reg_vs_line_strt_2_msb,0);
reg_write16 (priv, REG_VS_PIX_STRT、2_MSB、0);
REG_write16 (priv, REG_VS_LINE_END_2_MSB、0);
reg_write16 (priv, REG_VS_PI_END_2_MSB,0);
reg_write16 (priv, REG_HS_PI_START_MSB, 0x18);
reg_write16 (priv, REG_HS_PI_STOP_MSB,0xa0);
reg_write16 (priv, REG_VWIN_START_1_MSB、0x25);
REG_write16 (priv, REG_VWIN_END_1_MSB、0x325);
reg_write16 (priv, REG_VWIN_START_2_MSB,0);
reg_write16 (priv, REG_VWIN_END_2_MSB, 0);
reg_write16 (priv, reg_de_start_msb, 0x140);
reg_write16 (priv, REG_DE_STOP_MSB、0x540);
if (priv->rev =TDA19988){
//让传入的像素填充活动空间(如果有)*/
reg_write (privv、REG_ENABLE_space、0x00);
}
//
*始终生成相对于输入同步的同步极性,*
恢复输入级在输出阶段切换同步
*/ REG_TBRL_TRL_TRL_TBRL_TBRL_1
;tbr_TBRL_TBRL_TBRL_1
//if (MODE->flags & DRM_MODE_FLAG_NSYNC)
//reg |= TBG_CNTRL_1_H_TGL;
//if (MODE->flags & DRM_MODE_FLAG_NVSYNC)
//reg |= TBG_CNTRL_1_V_TGL;
reg_WRITE (priv_RIV_0*
、TBRL_REG_0)*必须设置为 TBTRL_TRL (TRL、TBR_0)
//*仅在接收设备为 HDMI 时设置信息帧*//
//我们需要打开 HDMI HDCP 设备才能通过*//
/reg &=~TBG_CNTRL_1_DWIN_DIS;
reg_write (priv, REG_TBG_CNTRL_1, 0x4);
reg_write (priv, REG_ENC_CNTRL、ENC_CNTRL_CTL_CODE (1));
REG_SET (privc、REG_TX33、TX33_HDMI);
tda998x_write_avi (priv,&adected_mode);
/* if (priv->audio_params.format != AFMT_unused){
tda998x_configure_audio (priv,&priv->audio_params、adied_mode.clock);
}//
//*启用视频端口,音频将在以后启用*/reg_write_reg
、vp_off、vp_click
、v_click、v_click、v_click (v_reg、vp_click、vp_click、v_click、v_reg、v_ 0xFF);
reg_write (priv, REG_ENA_VP_2,0xff);
//设置启用端口后的多路复用:*/
reg_write (priv, REG_VIP_CNTRL_0,priv->VIP_Cntrl_0);
reg_write (priv, REG_VIP_CNTRL_1, PRIV->VIP_Cntrl_1);
reg_write (priv, REG_VIP_CNTRL_2, priv->VIP_Cntrl_2);
return 0;
ERR_sysfs:
drm_connect_clean(&priv->connector);
err_connector:
drm_encoder_clean(&priv->encoder);
err_encer:
tda998x_destroy(priv);
return;
}
static int tda998x_remove (
struct i2c_client &client){component_del (&client->dev、return、}td_unt = td998x、tdid_unt
、tid_unt = t998x、tid_trust_trabend_ends);td_end_unt = td998x、tid_unt、tid_trabend_end_ends (t998x、tid_end_ends)、tid_tend_end_ends
#endif
static struct i2c_device_id tda998x_IDs[]={
"tda998x"、0}、
{}
};
module_device_table (i2c、tda998x_ID);
静态结构 i2c_driver tda998x_driver ={
.probe = tda998x_probe、
.remove = tda998x_remove、
.driver ={
.name ="tda998x"、
.fo_match_table = of _match_ptr (tda998x_dt_ID)、
}、
.id_table = tda998x_ID、
};
MODULE_i2c_driver (tda998x_driver);
MODULE_Author ("Rob Clark <robdclark@gmail.com);
MODULE_DESCRIPTION ("NXP Semiconductors TDA998X HDMI Encoder");
MODULE_license ("GPL");
和 DTS:
/* 版权所有(C) 2015 Embest Technology Co.、Ltd.- http://www.embest-tech.com * 本程序是免费软件;您可以根据 免费软件基金会*发布的 GNU 通用公共许可证版本2的条款重新分发和/或修改*。 * *此 DTS 适用于 Embest 自有产品 :* SOM-PH8800 + BB-SPH1800 */ */ DTS-v1/;*/ #include #include "Embest-SOM_PH8800-BB_SPH180.DTS" /{ /*别名{ display0 =&HDMI; };*/ clk_McASP0_fixed:clk_McASP0_fixed{ #clock-cells =<0>; 兼容="固定时钟"; 时钟频率=<24576000>; }; /* clk_McASP0:CLK_McASP0{ #clock-cells =<0>; 兼容="GPIO-GATE -时钟"; 时钟=<&clk_McASP0_FIXED>; ENABLE-GPIO =<&GPIO1 27 1>; };* /* HDMI_AUDIO:HDMI_AUDIO@0{ #sound-di-cells =<0>; Compatible ="Linux,HDMI-AUDIO"; status ="好"; };* / * daHDMI:connector{compatible ="HDMI-connect";label ="HDMI-out";{*tline-connect};tagle_connectore_connectore_connectore="</tagb";} TI、模型="TI BeagleBone Black"; TI、音频编解码器=<&HDMI_AUDIBLE>; TI、McASP-controller =<&McASP0>; TI、音频路由= "HDMI out"、"TX"; 时钟=<&clk_McASP0_fixed>; 时钟="MCLK"* 、音频主机= simple-card" ;"clink-master = simple-card" ;"&spink-card";"simple-control-card"= simple-control-control-control-control-control-control-control-clink-cy&se-card";"&nic-cocksink-cockpic-mage-mage-mcocksink-ma-mage-mage-mcocks =<&sink-clk_clk_clk_clk_clk_clk_clk_clk_clk_clk_clk_ simple-audio-card、codec{ sound-dai =<&tda19988>; } ; }; &lcd0{ 电池板时序{ /*这是 HDMI&VG*/ 时钟频率=<8000000000>的时序; hactive =<1024>; vactive =<768>; hfront-ctradch =<150>; hback =<120; HSYNC-LEN =<50>; 前沿=<12>; 后沿=<30>; VSYNC-LEN =<6>; HSYNC-ACTIVE =<0>; vsync-active =<0>; de-active =<1>; pixelclk-active =<1>; } ;端口{ LCD_IN:端点{ 远端=<&dpi_out>; }; } ;&McASP0{ #sound-di-cells =<0>; pinctrl-names ="默认"; pincop_status=<¬e_0>;pins =<¬e_pins =<&nation> /* mcsp_iis_mode */ tdm-slots =<2>; serial-dir =</* 0:非活动、1:TX、2:Rx */ 1 0 0 0 >; tx-num-evt =<1>; rx-num-evt =<1>; } ;&i2c1{ tda19988:tda9970@ = 0xda70;tdareg =<1>兼容;} /*将24位 BGR 转换为 RGB,例如交叉红色和蓝色接线*/* 视频端口=<0x234501>;*/ #sound-di-cells =<0>; 音频端口= ; }; };
非常感谢。