162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2012 Texas Instruments 462306a36Sopenharmony_ci * Author: Rob Clark <robdclark@gmail.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/component.h> 862306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 962306a36Sopenharmony_ci#include <linux/hdmi.h> 1062306a36Sopenharmony_ci#include <linux/i2c.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/platform_data/tda9950.h> 1362306a36Sopenharmony_ci#include <linux/irq.h> 1462306a36Sopenharmony_ci#include <sound/asoundef.h> 1562306a36Sopenharmony_ci#include <sound/hdmi-codec.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <drm/drm_atomic_helper.h> 1862306a36Sopenharmony_ci#include <drm/drm_bridge.h> 1962306a36Sopenharmony_ci#include <drm/drm_edid.h> 2062306a36Sopenharmony_ci#include <drm/drm_of.h> 2162306a36Sopenharmony_ci#include <drm/drm_print.h> 2262306a36Sopenharmony_ci#include <drm/drm_probe_helper.h> 2362306a36Sopenharmony_ci#include <drm/drm_simple_kms_helper.h> 2462306a36Sopenharmony_ci#include <drm/i2c/tda998x.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <media/cec-notifier.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#define DBG(fmt, ...) DRM_DEBUG(fmt"\n", ##__VA_ARGS__) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_cienum { 3162306a36Sopenharmony_ci AUDIO_ROUTE_I2S, 3262306a36Sopenharmony_ci AUDIO_ROUTE_SPDIF, 3362306a36Sopenharmony_ci AUDIO_ROUTE_NUM 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct tda998x_audio_route { 3762306a36Sopenharmony_ci u8 ena_aclk; 3862306a36Sopenharmony_ci u8 mux_ap; 3962306a36Sopenharmony_ci u8 aip_clksel; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct tda998x_audio_settings { 4362306a36Sopenharmony_ci const struct tda998x_audio_route *route; 4462306a36Sopenharmony_ci struct hdmi_audio_infoframe cea; 4562306a36Sopenharmony_ci unsigned int sample_rate; 4662306a36Sopenharmony_ci u8 status[5]; 4762306a36Sopenharmony_ci u8 ena_ap; 4862306a36Sopenharmony_ci u8 i2s_format; 4962306a36Sopenharmony_ci u8 cts_n; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct tda998x_priv { 5362306a36Sopenharmony_ci struct i2c_client *cec; 5462306a36Sopenharmony_ci struct i2c_client *hdmi; 5562306a36Sopenharmony_ci struct mutex mutex; 5662306a36Sopenharmony_ci u16 rev; 5762306a36Sopenharmony_ci u8 cec_addr; 5862306a36Sopenharmony_ci u8 current_page; 5962306a36Sopenharmony_ci bool is_on; 6062306a36Sopenharmony_ci bool supports_infoframes; 6162306a36Sopenharmony_ci bool sink_has_audio; 6262306a36Sopenharmony_ci enum hdmi_quantization_range rgb_quant_range; 6362306a36Sopenharmony_ci u8 vip_cntrl_0; 6462306a36Sopenharmony_ci u8 vip_cntrl_1; 6562306a36Sopenharmony_ci u8 vip_cntrl_2; 6662306a36Sopenharmony_ci unsigned long tmds_clock; 6762306a36Sopenharmony_ci struct tda998x_audio_settings audio; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci struct platform_device *audio_pdev; 7062306a36Sopenharmony_ci struct mutex audio_mutex; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci struct mutex edid_mutex; 7362306a36Sopenharmony_ci wait_queue_head_t wq_edid; 7462306a36Sopenharmony_ci volatile int wq_edid_wait; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci struct work_struct detect_work; 7762306a36Sopenharmony_ci struct timer_list edid_delay_timer; 7862306a36Sopenharmony_ci wait_queue_head_t edid_delay_waitq; 7962306a36Sopenharmony_ci bool edid_delay_active; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci struct drm_encoder encoder; 8262306a36Sopenharmony_ci struct drm_bridge bridge; 8362306a36Sopenharmony_ci struct drm_connector connector; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci u8 audio_port_enable[AUDIO_ROUTE_NUM]; 8662306a36Sopenharmony_ci struct tda9950_glue cec_glue; 8762306a36Sopenharmony_ci struct gpio_desc *calib; 8862306a36Sopenharmony_ci struct cec_notifier *cec_notify; 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define conn_to_tda998x_priv(x) \ 9262306a36Sopenharmony_ci container_of(x, struct tda998x_priv, connector) 9362306a36Sopenharmony_ci#define enc_to_tda998x_priv(x) \ 9462306a36Sopenharmony_ci container_of(x, struct tda998x_priv, encoder) 9562306a36Sopenharmony_ci#define bridge_to_tda998x_priv(x) \ 9662306a36Sopenharmony_ci container_of(x, struct tda998x_priv, bridge) 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* The TDA9988 series of devices use a paged register scheme.. to simplify 9962306a36Sopenharmony_ci * things we encode the page # in upper bits of the register #. To read/ 10062306a36Sopenharmony_ci * write a given register, we need to make sure CURPAGE register is set 10162306a36Sopenharmony_ci * appropriately. Which implies reads/writes are not atomic. Fun! 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci#define REG(page, addr) (((page) << 8) | (addr)) 10562306a36Sopenharmony_ci#define REG2ADDR(reg) ((reg) & 0xff) 10662306a36Sopenharmony_ci#define REG2PAGE(reg) (((reg) >> 8) & 0xff) 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci#define REG_CURPAGE 0xff /* write */ 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* Page 00h: General Control */ 11262306a36Sopenharmony_ci#define REG_VERSION_LSB REG(0x00, 0x00) /* read */ 11362306a36Sopenharmony_ci#define REG_MAIN_CNTRL0 REG(0x00, 0x01) /* read/write */ 11462306a36Sopenharmony_ci# define MAIN_CNTRL0_SR (1 << 0) 11562306a36Sopenharmony_ci# define MAIN_CNTRL0_DECS (1 << 1) 11662306a36Sopenharmony_ci# define MAIN_CNTRL0_DEHS (1 << 2) 11762306a36Sopenharmony_ci# define MAIN_CNTRL0_CECS (1 << 3) 11862306a36Sopenharmony_ci# define MAIN_CNTRL0_CEHS (1 << 4) 11962306a36Sopenharmony_ci# define MAIN_CNTRL0_SCALER (1 << 7) 12062306a36Sopenharmony_ci#define REG_VERSION_MSB REG(0x00, 0x02) /* read */ 12162306a36Sopenharmony_ci#define REG_SOFTRESET REG(0x00, 0x0a) /* write */ 12262306a36Sopenharmony_ci# define SOFTRESET_AUDIO (1 << 0) 12362306a36Sopenharmony_ci# define SOFTRESET_I2C_MASTER (1 << 1) 12462306a36Sopenharmony_ci#define REG_DDC_DISABLE REG(0x00, 0x0b) /* read/write */ 12562306a36Sopenharmony_ci#define REG_CCLK_ON REG(0x00, 0x0c) /* read/write */ 12662306a36Sopenharmony_ci#define REG_I2C_MASTER REG(0x00, 0x0d) /* read/write */ 12762306a36Sopenharmony_ci# define I2C_MASTER_DIS_MM (1 << 0) 12862306a36Sopenharmony_ci# define I2C_MASTER_DIS_FILT (1 << 1) 12962306a36Sopenharmony_ci# define I2C_MASTER_APP_STRT_LAT (1 << 2) 13062306a36Sopenharmony_ci#define REG_FEAT_POWERDOWN REG(0x00, 0x0e) /* read/write */ 13162306a36Sopenharmony_ci# define FEAT_POWERDOWN_PREFILT BIT(0) 13262306a36Sopenharmony_ci# define FEAT_POWERDOWN_CSC BIT(1) 13362306a36Sopenharmony_ci# define FEAT_POWERDOWN_SPDIF (1 << 3) 13462306a36Sopenharmony_ci#define REG_INT_FLAGS_0 REG(0x00, 0x0f) /* read/write */ 13562306a36Sopenharmony_ci#define REG_INT_FLAGS_1 REG(0x00, 0x10) /* read/write */ 13662306a36Sopenharmony_ci#define REG_INT_FLAGS_2 REG(0x00, 0x11) /* read/write */ 13762306a36Sopenharmony_ci# define INT_FLAGS_2_EDID_BLK_RD (1 << 1) 13862306a36Sopenharmony_ci#define REG_ENA_ACLK REG(0x00, 0x16) /* read/write */ 13962306a36Sopenharmony_ci#define REG_ENA_VP_0 REG(0x00, 0x18) /* read/write */ 14062306a36Sopenharmony_ci#define REG_ENA_VP_1 REG(0x00, 0x19) /* read/write */ 14162306a36Sopenharmony_ci#define REG_ENA_VP_2 REG(0x00, 0x1a) /* read/write */ 14262306a36Sopenharmony_ci#define REG_ENA_AP REG(0x00, 0x1e) /* read/write */ 14362306a36Sopenharmony_ci#define REG_VIP_CNTRL_0 REG(0x00, 0x20) /* write */ 14462306a36Sopenharmony_ci# define VIP_CNTRL_0_MIRR_A (1 << 7) 14562306a36Sopenharmony_ci# define VIP_CNTRL_0_SWAP_A(x) (((x) & 7) << 4) 14662306a36Sopenharmony_ci# define VIP_CNTRL_0_MIRR_B (1 << 3) 14762306a36Sopenharmony_ci# define VIP_CNTRL_0_SWAP_B(x) (((x) & 7) << 0) 14862306a36Sopenharmony_ci#define REG_VIP_CNTRL_1 REG(0x00, 0x21) /* write */ 14962306a36Sopenharmony_ci# define VIP_CNTRL_1_MIRR_C (1 << 7) 15062306a36Sopenharmony_ci# define VIP_CNTRL_1_SWAP_C(x) (((x) & 7) << 4) 15162306a36Sopenharmony_ci# define VIP_CNTRL_1_MIRR_D (1 << 3) 15262306a36Sopenharmony_ci# define VIP_CNTRL_1_SWAP_D(x) (((x) & 7) << 0) 15362306a36Sopenharmony_ci#define REG_VIP_CNTRL_2 REG(0x00, 0x22) /* write */ 15462306a36Sopenharmony_ci# define VIP_CNTRL_2_MIRR_E (1 << 7) 15562306a36Sopenharmony_ci# define VIP_CNTRL_2_SWAP_E(x) (((x) & 7) << 4) 15662306a36Sopenharmony_ci# define VIP_CNTRL_2_MIRR_F (1 << 3) 15762306a36Sopenharmony_ci# define VIP_CNTRL_2_SWAP_F(x) (((x) & 7) << 0) 15862306a36Sopenharmony_ci#define REG_VIP_CNTRL_3 REG(0x00, 0x23) /* write */ 15962306a36Sopenharmony_ci# define VIP_CNTRL_3_X_TGL (1 << 0) 16062306a36Sopenharmony_ci# define VIP_CNTRL_3_H_TGL (1 << 1) 16162306a36Sopenharmony_ci# define VIP_CNTRL_3_V_TGL (1 << 2) 16262306a36Sopenharmony_ci# define VIP_CNTRL_3_EMB (1 << 3) 16362306a36Sopenharmony_ci# define VIP_CNTRL_3_SYNC_DE (1 << 4) 16462306a36Sopenharmony_ci# define VIP_CNTRL_3_SYNC_HS (1 << 5) 16562306a36Sopenharmony_ci# define VIP_CNTRL_3_DE_INT (1 << 6) 16662306a36Sopenharmony_ci# define VIP_CNTRL_3_EDGE (1 << 7) 16762306a36Sopenharmony_ci#define REG_VIP_CNTRL_4 REG(0x00, 0x24) /* write */ 16862306a36Sopenharmony_ci# define VIP_CNTRL_4_BLC(x) (((x) & 3) << 0) 16962306a36Sopenharmony_ci# define VIP_CNTRL_4_BLANKIT(x) (((x) & 3) << 2) 17062306a36Sopenharmony_ci# define VIP_CNTRL_4_CCIR656 (1 << 4) 17162306a36Sopenharmony_ci# define VIP_CNTRL_4_656_ALT (1 << 5) 17262306a36Sopenharmony_ci# define VIP_CNTRL_4_TST_656 (1 << 6) 17362306a36Sopenharmony_ci# define VIP_CNTRL_4_TST_PAT (1 << 7) 17462306a36Sopenharmony_ci#define REG_VIP_CNTRL_5 REG(0x00, 0x25) /* write */ 17562306a36Sopenharmony_ci# define VIP_CNTRL_5_CKCASE (1 << 0) 17662306a36Sopenharmony_ci# define VIP_CNTRL_5_SP_CNT(x) (((x) & 3) << 1) 17762306a36Sopenharmony_ci#define REG_MUX_AP REG(0x00, 0x26) /* read/write */ 17862306a36Sopenharmony_ci# define MUX_AP_SELECT_I2S 0x64 17962306a36Sopenharmony_ci# define MUX_AP_SELECT_SPDIF 0x40 18062306a36Sopenharmony_ci#define REG_MUX_VP_VIP_OUT REG(0x00, 0x27) /* read/write */ 18162306a36Sopenharmony_ci#define REG_MAT_CONTRL REG(0x00, 0x80) /* write */ 18262306a36Sopenharmony_ci# define MAT_CONTRL_MAT_SC(x) (((x) & 3) << 0) 18362306a36Sopenharmony_ci# define MAT_CONTRL_MAT_BP (1 << 2) 18462306a36Sopenharmony_ci#define REG_VIDFORMAT REG(0x00, 0xa0) /* write */ 18562306a36Sopenharmony_ci#define REG_REFPIX_MSB REG(0x00, 0xa1) /* write */ 18662306a36Sopenharmony_ci#define REG_REFPIX_LSB REG(0x00, 0xa2) /* write */ 18762306a36Sopenharmony_ci#define REG_REFLINE_MSB REG(0x00, 0xa3) /* write */ 18862306a36Sopenharmony_ci#define REG_REFLINE_LSB REG(0x00, 0xa4) /* write */ 18962306a36Sopenharmony_ci#define REG_NPIX_MSB REG(0x00, 0xa5) /* write */ 19062306a36Sopenharmony_ci#define REG_NPIX_LSB REG(0x00, 0xa6) /* write */ 19162306a36Sopenharmony_ci#define REG_NLINE_MSB REG(0x00, 0xa7) /* write */ 19262306a36Sopenharmony_ci#define REG_NLINE_LSB REG(0x00, 0xa8) /* write */ 19362306a36Sopenharmony_ci#define REG_VS_LINE_STRT_1_MSB REG(0x00, 0xa9) /* write */ 19462306a36Sopenharmony_ci#define REG_VS_LINE_STRT_1_LSB REG(0x00, 0xaa) /* write */ 19562306a36Sopenharmony_ci#define REG_VS_PIX_STRT_1_MSB REG(0x00, 0xab) /* write */ 19662306a36Sopenharmony_ci#define REG_VS_PIX_STRT_1_LSB REG(0x00, 0xac) /* write */ 19762306a36Sopenharmony_ci#define REG_VS_LINE_END_1_MSB REG(0x00, 0xad) /* write */ 19862306a36Sopenharmony_ci#define REG_VS_LINE_END_1_LSB REG(0x00, 0xae) /* write */ 19962306a36Sopenharmony_ci#define REG_VS_PIX_END_1_MSB REG(0x00, 0xaf) /* write */ 20062306a36Sopenharmony_ci#define REG_VS_PIX_END_1_LSB REG(0x00, 0xb0) /* write */ 20162306a36Sopenharmony_ci#define REG_VS_LINE_STRT_2_MSB REG(0x00, 0xb1) /* write */ 20262306a36Sopenharmony_ci#define REG_VS_LINE_STRT_2_LSB REG(0x00, 0xb2) /* write */ 20362306a36Sopenharmony_ci#define REG_VS_PIX_STRT_2_MSB REG(0x00, 0xb3) /* write */ 20462306a36Sopenharmony_ci#define REG_VS_PIX_STRT_2_LSB REG(0x00, 0xb4) /* write */ 20562306a36Sopenharmony_ci#define REG_VS_LINE_END_2_MSB REG(0x00, 0xb5) /* write */ 20662306a36Sopenharmony_ci#define REG_VS_LINE_END_2_LSB REG(0x00, 0xb6) /* write */ 20762306a36Sopenharmony_ci#define REG_VS_PIX_END_2_MSB REG(0x00, 0xb7) /* write */ 20862306a36Sopenharmony_ci#define REG_VS_PIX_END_2_LSB REG(0x00, 0xb8) /* write */ 20962306a36Sopenharmony_ci#define REG_HS_PIX_START_MSB REG(0x00, 0xb9) /* write */ 21062306a36Sopenharmony_ci#define REG_HS_PIX_START_LSB REG(0x00, 0xba) /* write */ 21162306a36Sopenharmony_ci#define REG_HS_PIX_STOP_MSB REG(0x00, 0xbb) /* write */ 21262306a36Sopenharmony_ci#define REG_HS_PIX_STOP_LSB REG(0x00, 0xbc) /* write */ 21362306a36Sopenharmony_ci#define REG_VWIN_START_1_MSB REG(0x00, 0xbd) /* write */ 21462306a36Sopenharmony_ci#define REG_VWIN_START_1_LSB REG(0x00, 0xbe) /* write */ 21562306a36Sopenharmony_ci#define REG_VWIN_END_1_MSB REG(0x00, 0xbf) /* write */ 21662306a36Sopenharmony_ci#define REG_VWIN_END_1_LSB REG(0x00, 0xc0) /* write */ 21762306a36Sopenharmony_ci#define REG_VWIN_START_2_MSB REG(0x00, 0xc1) /* write */ 21862306a36Sopenharmony_ci#define REG_VWIN_START_2_LSB REG(0x00, 0xc2) /* write */ 21962306a36Sopenharmony_ci#define REG_VWIN_END_2_MSB REG(0x00, 0xc3) /* write */ 22062306a36Sopenharmony_ci#define REG_VWIN_END_2_LSB REG(0x00, 0xc4) /* write */ 22162306a36Sopenharmony_ci#define REG_DE_START_MSB REG(0x00, 0xc5) /* write */ 22262306a36Sopenharmony_ci#define REG_DE_START_LSB REG(0x00, 0xc6) /* write */ 22362306a36Sopenharmony_ci#define REG_DE_STOP_MSB REG(0x00, 0xc7) /* write */ 22462306a36Sopenharmony_ci#define REG_DE_STOP_LSB REG(0x00, 0xc8) /* write */ 22562306a36Sopenharmony_ci#define REG_TBG_CNTRL_0 REG(0x00, 0xca) /* write */ 22662306a36Sopenharmony_ci# define TBG_CNTRL_0_TOP_TGL (1 << 0) 22762306a36Sopenharmony_ci# define TBG_CNTRL_0_TOP_SEL (1 << 1) 22862306a36Sopenharmony_ci# define TBG_CNTRL_0_DE_EXT (1 << 2) 22962306a36Sopenharmony_ci# define TBG_CNTRL_0_TOP_EXT (1 << 3) 23062306a36Sopenharmony_ci# define TBG_CNTRL_0_FRAME_DIS (1 << 5) 23162306a36Sopenharmony_ci# define TBG_CNTRL_0_SYNC_MTHD (1 << 6) 23262306a36Sopenharmony_ci# define TBG_CNTRL_0_SYNC_ONCE (1 << 7) 23362306a36Sopenharmony_ci#define REG_TBG_CNTRL_1 REG(0x00, 0xcb) /* write */ 23462306a36Sopenharmony_ci# define TBG_CNTRL_1_H_TGL (1 << 0) 23562306a36Sopenharmony_ci# define TBG_CNTRL_1_V_TGL (1 << 1) 23662306a36Sopenharmony_ci# define TBG_CNTRL_1_TGL_EN (1 << 2) 23762306a36Sopenharmony_ci# define TBG_CNTRL_1_X_EXT (1 << 3) 23862306a36Sopenharmony_ci# define TBG_CNTRL_1_H_EXT (1 << 4) 23962306a36Sopenharmony_ci# define TBG_CNTRL_1_V_EXT (1 << 5) 24062306a36Sopenharmony_ci# define TBG_CNTRL_1_DWIN_DIS (1 << 6) 24162306a36Sopenharmony_ci#define REG_ENABLE_SPACE REG(0x00, 0xd6) /* write */ 24262306a36Sopenharmony_ci#define REG_HVF_CNTRL_0 REG(0x00, 0xe4) /* write */ 24362306a36Sopenharmony_ci# define HVF_CNTRL_0_SM (1 << 7) 24462306a36Sopenharmony_ci# define HVF_CNTRL_0_RWB (1 << 6) 24562306a36Sopenharmony_ci# define HVF_CNTRL_0_PREFIL(x) (((x) & 3) << 2) 24662306a36Sopenharmony_ci# define HVF_CNTRL_0_INTPOL(x) (((x) & 3) << 0) 24762306a36Sopenharmony_ci#define REG_HVF_CNTRL_1 REG(0x00, 0xe5) /* write */ 24862306a36Sopenharmony_ci# define HVF_CNTRL_1_FOR (1 << 0) 24962306a36Sopenharmony_ci# define HVF_CNTRL_1_YUVBLK (1 << 1) 25062306a36Sopenharmony_ci# define HVF_CNTRL_1_VQR(x) (((x) & 3) << 2) 25162306a36Sopenharmony_ci# define HVF_CNTRL_1_PAD(x) (((x) & 3) << 4) 25262306a36Sopenharmony_ci# define HVF_CNTRL_1_SEMI_PLANAR (1 << 6) 25362306a36Sopenharmony_ci#define REG_RPT_CNTRL REG(0x00, 0xf0) /* write */ 25462306a36Sopenharmony_ci# define RPT_CNTRL_REPEAT(x) ((x) & 15) 25562306a36Sopenharmony_ci#define REG_I2S_FORMAT REG(0x00, 0xfc) /* read/write */ 25662306a36Sopenharmony_ci# define I2S_FORMAT_PHILIPS (0 << 0) 25762306a36Sopenharmony_ci# define I2S_FORMAT_LEFT_J (2 << 0) 25862306a36Sopenharmony_ci# define I2S_FORMAT_RIGHT_J (3 << 0) 25962306a36Sopenharmony_ci#define REG_AIP_CLKSEL REG(0x00, 0xfd) /* write */ 26062306a36Sopenharmony_ci# define AIP_CLKSEL_AIP_SPDIF (0 << 3) 26162306a36Sopenharmony_ci# define AIP_CLKSEL_AIP_I2S (1 << 3) 26262306a36Sopenharmony_ci# define AIP_CLKSEL_FS_ACLK (0 << 0) 26362306a36Sopenharmony_ci# define AIP_CLKSEL_FS_MCLK (1 << 0) 26462306a36Sopenharmony_ci# define AIP_CLKSEL_FS_FS64SPDIF (2 << 0) 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci/* Page 02h: PLL settings */ 26762306a36Sopenharmony_ci#define REG_PLL_SERIAL_1 REG(0x02, 0x00) /* read/write */ 26862306a36Sopenharmony_ci# define PLL_SERIAL_1_SRL_FDN (1 << 0) 26962306a36Sopenharmony_ci# define PLL_SERIAL_1_SRL_IZ(x) (((x) & 3) << 1) 27062306a36Sopenharmony_ci# define PLL_SERIAL_1_SRL_MAN_IZ (1 << 6) 27162306a36Sopenharmony_ci#define REG_PLL_SERIAL_2 REG(0x02, 0x01) /* read/write */ 27262306a36Sopenharmony_ci# define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0) 27362306a36Sopenharmony_ci# define PLL_SERIAL_2_SRL_PR(x) (((x) & 0xf) << 4) 27462306a36Sopenharmony_ci#define REG_PLL_SERIAL_3 REG(0x02, 0x02) /* read/write */ 27562306a36Sopenharmony_ci# define PLL_SERIAL_3_SRL_CCIR (1 << 0) 27662306a36Sopenharmony_ci# define PLL_SERIAL_3_SRL_DE (1 << 2) 27762306a36Sopenharmony_ci# define PLL_SERIAL_3_SRL_PXIN_SEL (1 << 4) 27862306a36Sopenharmony_ci#define REG_SERIALIZER REG(0x02, 0x03) /* read/write */ 27962306a36Sopenharmony_ci#define REG_BUFFER_OUT REG(0x02, 0x04) /* read/write */ 28062306a36Sopenharmony_ci#define REG_PLL_SCG1 REG(0x02, 0x05) /* read/write */ 28162306a36Sopenharmony_ci#define REG_PLL_SCG2 REG(0x02, 0x06) /* read/write */ 28262306a36Sopenharmony_ci#define REG_PLL_SCGN1 REG(0x02, 0x07) /* read/write */ 28362306a36Sopenharmony_ci#define REG_PLL_SCGN2 REG(0x02, 0x08) /* read/write */ 28462306a36Sopenharmony_ci#define REG_PLL_SCGR1 REG(0x02, 0x09) /* read/write */ 28562306a36Sopenharmony_ci#define REG_PLL_SCGR2 REG(0x02, 0x0a) /* read/write */ 28662306a36Sopenharmony_ci#define REG_AUDIO_DIV REG(0x02, 0x0e) /* read/write */ 28762306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_1 0 28862306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_2 1 28962306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_4 2 29062306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_8 3 29162306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_16 4 29262306a36Sopenharmony_ci# define AUDIO_DIV_SERCLK_32 5 29362306a36Sopenharmony_ci#define REG_SEL_CLK REG(0x02, 0x11) /* read/write */ 29462306a36Sopenharmony_ci# define SEL_CLK_SEL_CLK1 (1 << 0) 29562306a36Sopenharmony_ci# define SEL_CLK_SEL_VRF_CLK(x) (((x) & 3) << 1) 29662306a36Sopenharmony_ci# define SEL_CLK_ENA_SC_CLK (1 << 3) 29762306a36Sopenharmony_ci#define REG_ANA_GENERAL REG(0x02, 0x12) /* read/write */ 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci/* Page 09h: EDID Control */ 30162306a36Sopenharmony_ci#define REG_EDID_DATA_0 REG(0x09, 0x00) /* read */ 30262306a36Sopenharmony_ci/* next 127 successive registers are the EDID block */ 30362306a36Sopenharmony_ci#define REG_EDID_CTRL REG(0x09, 0xfa) /* read/write */ 30462306a36Sopenharmony_ci#define REG_DDC_ADDR REG(0x09, 0xfb) /* read/write */ 30562306a36Sopenharmony_ci#define REG_DDC_OFFS REG(0x09, 0xfc) /* read/write */ 30662306a36Sopenharmony_ci#define REG_DDC_SEGM_ADDR REG(0x09, 0xfd) /* read/write */ 30762306a36Sopenharmony_ci#define REG_DDC_SEGM REG(0x09, 0xfe) /* read/write */ 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci/* Page 10h: information frames and packets */ 31162306a36Sopenharmony_ci#define REG_IF1_HB0 REG(0x10, 0x20) /* read/write */ 31262306a36Sopenharmony_ci#define REG_IF2_HB0 REG(0x10, 0x40) /* read/write */ 31362306a36Sopenharmony_ci#define REG_IF3_HB0 REG(0x10, 0x60) /* read/write */ 31462306a36Sopenharmony_ci#define REG_IF4_HB0 REG(0x10, 0x80) /* read/write */ 31562306a36Sopenharmony_ci#define REG_IF5_HB0 REG(0x10, 0xa0) /* read/write */ 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* Page 11h: audio settings and content info packets */ 31962306a36Sopenharmony_ci#define REG_AIP_CNTRL_0 REG(0x11, 0x00) /* read/write */ 32062306a36Sopenharmony_ci# define AIP_CNTRL_0_RST_FIFO (1 << 0) 32162306a36Sopenharmony_ci# define AIP_CNTRL_0_SWAP (1 << 1) 32262306a36Sopenharmony_ci# define AIP_CNTRL_0_LAYOUT (1 << 2) 32362306a36Sopenharmony_ci# define AIP_CNTRL_0_ACR_MAN (1 << 5) 32462306a36Sopenharmony_ci# define AIP_CNTRL_0_RST_CTS (1 << 6) 32562306a36Sopenharmony_ci#define REG_CA_I2S REG(0x11, 0x01) /* read/write */ 32662306a36Sopenharmony_ci# define CA_I2S_CA_I2S(x) (((x) & 31) << 0) 32762306a36Sopenharmony_ci# define CA_I2S_HBR_CHSTAT (1 << 6) 32862306a36Sopenharmony_ci#define REG_LATENCY_RD REG(0x11, 0x04) /* read/write */ 32962306a36Sopenharmony_ci#define REG_ACR_CTS_0 REG(0x11, 0x05) /* read/write */ 33062306a36Sopenharmony_ci#define REG_ACR_CTS_1 REG(0x11, 0x06) /* read/write */ 33162306a36Sopenharmony_ci#define REG_ACR_CTS_2 REG(0x11, 0x07) /* read/write */ 33262306a36Sopenharmony_ci#define REG_ACR_N_0 REG(0x11, 0x08) /* read/write */ 33362306a36Sopenharmony_ci#define REG_ACR_N_1 REG(0x11, 0x09) /* read/write */ 33462306a36Sopenharmony_ci#define REG_ACR_N_2 REG(0x11, 0x0a) /* read/write */ 33562306a36Sopenharmony_ci#define REG_CTS_N REG(0x11, 0x0c) /* read/write */ 33662306a36Sopenharmony_ci# define CTS_N_K(x) (((x) & 7) << 0) 33762306a36Sopenharmony_ci# define CTS_N_M(x) (((x) & 3) << 4) 33862306a36Sopenharmony_ci#define REG_ENC_CNTRL REG(0x11, 0x0d) /* read/write */ 33962306a36Sopenharmony_ci# define ENC_CNTRL_RST_ENC (1 << 0) 34062306a36Sopenharmony_ci# define ENC_CNTRL_RST_SEL (1 << 1) 34162306a36Sopenharmony_ci# define ENC_CNTRL_CTL_CODE(x) (((x) & 3) << 2) 34262306a36Sopenharmony_ci#define REG_DIP_FLAGS REG(0x11, 0x0e) /* read/write */ 34362306a36Sopenharmony_ci# define DIP_FLAGS_ACR (1 << 0) 34462306a36Sopenharmony_ci# define DIP_FLAGS_GC (1 << 1) 34562306a36Sopenharmony_ci#define REG_DIP_IF_FLAGS REG(0x11, 0x0f) /* read/write */ 34662306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF1 (1 << 1) 34762306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF2 (1 << 2) 34862306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF3 (1 << 3) 34962306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF4 (1 << 4) 35062306a36Sopenharmony_ci# define DIP_IF_FLAGS_IF5 (1 << 5) 35162306a36Sopenharmony_ci#define REG_CH_STAT_B(x) REG(0x11, 0x14 + (x)) /* read/write */ 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* Page 12h: HDCP and OTP */ 35562306a36Sopenharmony_ci#define REG_TX3 REG(0x12, 0x9a) /* read/write */ 35662306a36Sopenharmony_ci#define REG_TX4 REG(0x12, 0x9b) /* read/write */ 35762306a36Sopenharmony_ci# define TX4_PD_RAM (1 << 1) 35862306a36Sopenharmony_ci#define REG_TX33 REG(0x12, 0xb8) /* read/write */ 35962306a36Sopenharmony_ci# define TX33_HDMI (1 << 1) 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* Page 13h: Gamut related metadata packets */ 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/* CEC registers: (not paged) 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci#define REG_CEC_INTSTATUS 0xee /* read */ 36962306a36Sopenharmony_ci# define CEC_INTSTATUS_CEC (1 << 0) 37062306a36Sopenharmony_ci# define CEC_INTSTATUS_HDMI (1 << 1) 37162306a36Sopenharmony_ci#define REG_CEC_CAL_XOSC_CTRL1 0xf2 37262306a36Sopenharmony_ci# define CEC_CAL_XOSC_CTRL1_ENA_CAL BIT(0) 37362306a36Sopenharmony_ci#define REG_CEC_DES_FREQ2 0xf5 37462306a36Sopenharmony_ci# define CEC_DES_FREQ2_DIS_AUTOCAL BIT(7) 37562306a36Sopenharmony_ci#define REG_CEC_CLK 0xf6 37662306a36Sopenharmony_ci# define CEC_CLK_FRO 0x11 37762306a36Sopenharmony_ci#define REG_CEC_FRO_IM_CLK_CTRL 0xfb /* read/write */ 37862306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7) 37962306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_ENA_OTP (1 << 6) 38062306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1) 38162306a36Sopenharmony_ci# define CEC_FRO_IM_CLK_CTRL_FRO_DIV (1 << 0) 38262306a36Sopenharmony_ci#define REG_CEC_RXSHPDINTENA 0xfc /* read/write */ 38362306a36Sopenharmony_ci#define REG_CEC_RXSHPDINT 0xfd /* read */ 38462306a36Sopenharmony_ci# define CEC_RXSHPDINT_RXSENS BIT(0) 38562306a36Sopenharmony_ci# define CEC_RXSHPDINT_HPD BIT(1) 38662306a36Sopenharmony_ci#define REG_CEC_RXSHPDLEV 0xfe /* read */ 38762306a36Sopenharmony_ci# define CEC_RXSHPDLEV_RXSENS (1 << 0) 38862306a36Sopenharmony_ci# define CEC_RXSHPDLEV_HPD (1 << 1) 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci#define REG_CEC_ENAMODS 0xff /* read/write */ 39162306a36Sopenharmony_ci# define CEC_ENAMODS_EN_CEC_CLK (1 << 7) 39262306a36Sopenharmony_ci# define CEC_ENAMODS_DIS_FRO (1 << 6) 39362306a36Sopenharmony_ci# define CEC_ENAMODS_DIS_CCLK (1 << 5) 39462306a36Sopenharmony_ci# define CEC_ENAMODS_EN_RXSENS (1 << 2) 39562306a36Sopenharmony_ci# define CEC_ENAMODS_EN_HDMI (1 << 1) 39662306a36Sopenharmony_ci# define CEC_ENAMODS_EN_CEC (1 << 0) 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci/* Device versions: */ 40062306a36Sopenharmony_ci#define TDA9989N2 0x0101 40162306a36Sopenharmony_ci#define TDA19989 0x0201 40262306a36Sopenharmony_ci#define TDA19989N2 0x0202 40362306a36Sopenharmony_ci#define TDA19988 0x0301 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_cistatic void 40662306a36Sopenharmony_cicec_write(struct tda998x_priv *priv, u16 addr, u8 val) 40762306a36Sopenharmony_ci{ 40862306a36Sopenharmony_ci u8 buf[] = {addr, val}; 40962306a36Sopenharmony_ci struct i2c_msg msg = { 41062306a36Sopenharmony_ci .addr = priv->cec_addr, 41162306a36Sopenharmony_ci .len = 2, 41262306a36Sopenharmony_ci .buf = buf, 41362306a36Sopenharmony_ci }; 41462306a36Sopenharmony_ci int ret; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ret = i2c_transfer(priv->hdmi->adapter, &msg, 1); 41762306a36Sopenharmony_ci if (ret < 0) 41862306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "Error %d writing to cec:0x%x\n", 41962306a36Sopenharmony_ci ret, addr); 42062306a36Sopenharmony_ci} 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_cistatic u8 42362306a36Sopenharmony_cicec_read(struct tda998x_priv *priv, u8 addr) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci u8 val; 42662306a36Sopenharmony_ci struct i2c_msg msg[2] = { 42762306a36Sopenharmony_ci { 42862306a36Sopenharmony_ci .addr = priv->cec_addr, 42962306a36Sopenharmony_ci .len = 1, 43062306a36Sopenharmony_ci .buf = &addr, 43162306a36Sopenharmony_ci }, { 43262306a36Sopenharmony_ci .addr = priv->cec_addr, 43362306a36Sopenharmony_ci .flags = I2C_M_RD, 43462306a36Sopenharmony_ci .len = 1, 43562306a36Sopenharmony_ci .buf = &val, 43662306a36Sopenharmony_ci }, 43762306a36Sopenharmony_ci }; 43862306a36Sopenharmony_ci int ret; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci ret = i2c_transfer(priv->hdmi->adapter, msg, ARRAY_SIZE(msg)); 44162306a36Sopenharmony_ci if (ret < 0) { 44262306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "Error %d reading from cec:0x%x\n", 44362306a36Sopenharmony_ci ret, addr); 44462306a36Sopenharmony_ci val = 0; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return val; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void cec_enamods(struct tda998x_priv *priv, u8 mods, bool enable) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci int val = cec_read(priv, REG_CEC_ENAMODS); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (val < 0) 45562306a36Sopenharmony_ci return; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (enable) 45862306a36Sopenharmony_ci val |= mods; 45962306a36Sopenharmony_ci else 46062306a36Sopenharmony_ci val &= ~mods; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci cec_write(priv, REG_CEC_ENAMODS, val); 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic void tda998x_cec_set_calibration(struct tda998x_priv *priv, bool enable) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci if (enable) { 46862306a36Sopenharmony_ci u8 val; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci cec_write(priv, 0xf3, 0xc0); 47162306a36Sopenharmony_ci cec_write(priv, 0xf4, 0xd4); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* Enable automatic calibration mode */ 47462306a36Sopenharmony_ci val = cec_read(priv, REG_CEC_DES_FREQ2); 47562306a36Sopenharmony_ci val &= ~CEC_DES_FREQ2_DIS_AUTOCAL; 47662306a36Sopenharmony_ci cec_write(priv, REG_CEC_DES_FREQ2, val); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci /* Enable free running oscillator */ 47962306a36Sopenharmony_ci cec_write(priv, REG_CEC_CLK, CEC_CLK_FRO); 48062306a36Sopenharmony_ci cec_enamods(priv, CEC_ENAMODS_DIS_FRO, false); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci cec_write(priv, REG_CEC_CAL_XOSC_CTRL1, 48362306a36Sopenharmony_ci CEC_CAL_XOSC_CTRL1_ENA_CAL); 48462306a36Sopenharmony_ci } else { 48562306a36Sopenharmony_ci cec_write(priv, REG_CEC_CAL_XOSC_CTRL1, 0); 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci} 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci/* 49062306a36Sopenharmony_ci * Calibration for the internal oscillator: we need to set calibration mode, 49162306a36Sopenharmony_ci * and then pulse the IRQ line low for a 10ms ± 1% period. 49262306a36Sopenharmony_ci */ 49362306a36Sopenharmony_cistatic void tda998x_cec_calibration(struct tda998x_priv *priv) 49462306a36Sopenharmony_ci{ 49562306a36Sopenharmony_ci struct gpio_desc *calib = priv->calib; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci mutex_lock(&priv->edid_mutex); 49862306a36Sopenharmony_ci if (priv->hdmi->irq > 0) 49962306a36Sopenharmony_ci disable_irq(priv->hdmi->irq); 50062306a36Sopenharmony_ci gpiod_direction_output(calib, 1); 50162306a36Sopenharmony_ci tda998x_cec_set_calibration(priv, true); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci local_irq_disable(); 50462306a36Sopenharmony_ci gpiod_set_value(calib, 0); 50562306a36Sopenharmony_ci mdelay(10); 50662306a36Sopenharmony_ci gpiod_set_value(calib, 1); 50762306a36Sopenharmony_ci local_irq_enable(); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci tda998x_cec_set_calibration(priv, false); 51062306a36Sopenharmony_ci gpiod_direction_input(calib); 51162306a36Sopenharmony_ci if (priv->hdmi->irq > 0) 51262306a36Sopenharmony_ci enable_irq(priv->hdmi->irq); 51362306a36Sopenharmony_ci mutex_unlock(&priv->edid_mutex); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic int tda998x_cec_hook_init(void *data) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct tda998x_priv *priv = data; 51962306a36Sopenharmony_ci struct gpio_desc *calib; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci calib = gpiod_get(&priv->hdmi->dev, "nxp,calib", GPIOD_ASIS); 52262306a36Sopenharmony_ci if (IS_ERR(calib)) { 52362306a36Sopenharmony_ci dev_warn(&priv->hdmi->dev, "failed to get calibration gpio: %ld\n", 52462306a36Sopenharmony_ci PTR_ERR(calib)); 52562306a36Sopenharmony_ci return PTR_ERR(calib); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci priv->calib = calib; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return 0; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic void tda998x_cec_hook_exit(void *data) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci struct tda998x_priv *priv = data; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci gpiod_put(priv->calib); 53862306a36Sopenharmony_ci priv->calib = NULL; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int tda998x_cec_hook_open(void *data) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct tda998x_priv *priv = data; 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci cec_enamods(priv, CEC_ENAMODS_EN_CEC_CLK | CEC_ENAMODS_EN_CEC, true); 54662306a36Sopenharmony_ci tda998x_cec_calibration(priv); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci return 0; 54962306a36Sopenharmony_ci} 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_cistatic void tda998x_cec_hook_release(void *data) 55262306a36Sopenharmony_ci{ 55362306a36Sopenharmony_ci struct tda998x_priv *priv = data; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci cec_enamods(priv, CEC_ENAMODS_EN_CEC_CLK | CEC_ENAMODS_EN_CEC, false); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic int 55962306a36Sopenharmony_ciset_page(struct tda998x_priv *priv, u16 reg) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci if (REG2PAGE(reg) != priv->current_page) { 56262306a36Sopenharmony_ci struct i2c_client *client = priv->hdmi; 56362306a36Sopenharmony_ci u8 buf[] = { 56462306a36Sopenharmony_ci REG_CURPAGE, REG2PAGE(reg) 56562306a36Sopenharmony_ci }; 56662306a36Sopenharmony_ci int ret = i2c_master_send(client, buf, sizeof(buf)); 56762306a36Sopenharmony_ci if (ret < 0) { 56862306a36Sopenharmony_ci dev_err(&client->dev, "%s %04x err %d\n", __func__, 56962306a36Sopenharmony_ci reg, ret); 57062306a36Sopenharmony_ci return ret; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci priv->current_page = REG2PAGE(reg); 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci return 0; 57662306a36Sopenharmony_ci} 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_cistatic int 57962306a36Sopenharmony_cireg_read_range(struct tda998x_priv *priv, u16 reg, char *buf, int cnt) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci struct i2c_client *client = priv->hdmi; 58262306a36Sopenharmony_ci u8 addr = REG2ADDR(reg); 58362306a36Sopenharmony_ci int ret; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci mutex_lock(&priv->mutex); 58662306a36Sopenharmony_ci ret = set_page(priv, reg); 58762306a36Sopenharmony_ci if (ret < 0) 58862306a36Sopenharmony_ci goto out; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci ret = i2c_master_send(client, &addr, sizeof(addr)); 59162306a36Sopenharmony_ci if (ret < 0) 59262306a36Sopenharmony_ci goto fail; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci ret = i2c_master_recv(client, buf, cnt); 59562306a36Sopenharmony_ci if (ret < 0) 59662306a36Sopenharmony_ci goto fail; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci goto out; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_cifail: 60162306a36Sopenharmony_ci dev_err(&client->dev, "Error %d reading from 0x%x\n", ret, reg); 60262306a36Sopenharmony_ciout: 60362306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 60462306a36Sopenharmony_ci return ret; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci#define MAX_WRITE_RANGE_BUF 32 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_cistatic void 61062306a36Sopenharmony_cireg_write_range(struct tda998x_priv *priv, u16 reg, u8 *p, int cnt) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci struct i2c_client *client = priv->hdmi; 61362306a36Sopenharmony_ci /* This is the maximum size of the buffer passed in */ 61462306a36Sopenharmony_ci u8 buf[MAX_WRITE_RANGE_BUF + 1]; 61562306a36Sopenharmony_ci int ret; 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci if (cnt > MAX_WRITE_RANGE_BUF) { 61862306a36Sopenharmony_ci dev_err(&client->dev, "Fixed write buffer too small (%d)\n", 61962306a36Sopenharmony_ci MAX_WRITE_RANGE_BUF); 62062306a36Sopenharmony_ci return; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci buf[0] = REG2ADDR(reg); 62462306a36Sopenharmony_ci memcpy(&buf[1], p, cnt); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci mutex_lock(&priv->mutex); 62762306a36Sopenharmony_ci ret = set_page(priv, reg); 62862306a36Sopenharmony_ci if (ret < 0) 62962306a36Sopenharmony_ci goto out; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci ret = i2c_master_send(client, buf, cnt + 1); 63262306a36Sopenharmony_ci if (ret < 0) 63362306a36Sopenharmony_ci dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); 63462306a36Sopenharmony_ciout: 63562306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 63662306a36Sopenharmony_ci} 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_cistatic int 63962306a36Sopenharmony_cireg_read(struct tda998x_priv *priv, u16 reg) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci u8 val = 0; 64262306a36Sopenharmony_ci int ret; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci ret = reg_read_range(priv, reg, &val, sizeof(val)); 64562306a36Sopenharmony_ci if (ret < 0) 64662306a36Sopenharmony_ci return ret; 64762306a36Sopenharmony_ci return val; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic void 65162306a36Sopenharmony_cireg_write(struct tda998x_priv *priv, u16 reg, u8 val) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct i2c_client *client = priv->hdmi; 65462306a36Sopenharmony_ci u8 buf[] = {REG2ADDR(reg), val}; 65562306a36Sopenharmony_ci int ret; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci mutex_lock(&priv->mutex); 65862306a36Sopenharmony_ci ret = set_page(priv, reg); 65962306a36Sopenharmony_ci if (ret < 0) 66062306a36Sopenharmony_ci goto out; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci ret = i2c_master_send(client, buf, sizeof(buf)); 66362306a36Sopenharmony_ci if (ret < 0) 66462306a36Sopenharmony_ci dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); 66562306a36Sopenharmony_ciout: 66662306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_cistatic void 67062306a36Sopenharmony_cireg_write16(struct tda998x_priv *priv, u16 reg, u16 val) 67162306a36Sopenharmony_ci{ 67262306a36Sopenharmony_ci struct i2c_client *client = priv->hdmi; 67362306a36Sopenharmony_ci u8 buf[] = {REG2ADDR(reg), val >> 8, val}; 67462306a36Sopenharmony_ci int ret; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci mutex_lock(&priv->mutex); 67762306a36Sopenharmony_ci ret = set_page(priv, reg); 67862306a36Sopenharmony_ci if (ret < 0) 67962306a36Sopenharmony_ci goto out; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ret = i2c_master_send(client, buf, sizeof(buf)); 68262306a36Sopenharmony_ci if (ret < 0) 68362306a36Sopenharmony_ci dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg); 68462306a36Sopenharmony_ciout: 68562306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 68662306a36Sopenharmony_ci} 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic void 68962306a36Sopenharmony_cireg_set(struct tda998x_priv *priv, u16 reg, u8 val) 69062306a36Sopenharmony_ci{ 69162306a36Sopenharmony_ci int old_val; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci old_val = reg_read(priv, reg); 69462306a36Sopenharmony_ci if (old_val >= 0) 69562306a36Sopenharmony_ci reg_write(priv, reg, old_val | val); 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic void 69962306a36Sopenharmony_cireg_clear(struct tda998x_priv *priv, u16 reg, u8 val) 70062306a36Sopenharmony_ci{ 70162306a36Sopenharmony_ci int old_val; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci old_val = reg_read(priv, reg); 70462306a36Sopenharmony_ci if (old_val >= 0) 70562306a36Sopenharmony_ci reg_write(priv, reg, old_val & ~val); 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic void 70962306a36Sopenharmony_citda998x_reset(struct tda998x_priv *priv) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci /* reset audio and i2c master: */ 71262306a36Sopenharmony_ci reg_write(priv, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER); 71362306a36Sopenharmony_ci msleep(50); 71462306a36Sopenharmony_ci reg_write(priv, REG_SOFTRESET, 0); 71562306a36Sopenharmony_ci msleep(50); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci /* reset transmitter: */ 71862306a36Sopenharmony_ci reg_set(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR); 71962306a36Sopenharmony_ci reg_clear(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci /* PLL registers common configuration */ 72262306a36Sopenharmony_ci reg_write(priv, REG_PLL_SERIAL_1, 0x00); 72362306a36Sopenharmony_ci reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1)); 72462306a36Sopenharmony_ci reg_write(priv, REG_PLL_SERIAL_3, 0x00); 72562306a36Sopenharmony_ci reg_write(priv, REG_SERIALIZER, 0x00); 72662306a36Sopenharmony_ci reg_write(priv, REG_BUFFER_OUT, 0x00); 72762306a36Sopenharmony_ci reg_write(priv, REG_PLL_SCG1, 0x00); 72862306a36Sopenharmony_ci reg_write(priv, REG_AUDIO_DIV, AUDIO_DIV_SERCLK_8); 72962306a36Sopenharmony_ci reg_write(priv, REG_SEL_CLK, SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK); 73062306a36Sopenharmony_ci reg_write(priv, REG_PLL_SCGN1, 0xfa); 73162306a36Sopenharmony_ci reg_write(priv, REG_PLL_SCGN2, 0x00); 73262306a36Sopenharmony_ci reg_write(priv, REG_PLL_SCGR1, 0x5b); 73362306a36Sopenharmony_ci reg_write(priv, REG_PLL_SCGR2, 0x00); 73462306a36Sopenharmony_ci reg_write(priv, REG_PLL_SCG2, 0x10); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Write the default value MUX register */ 73762306a36Sopenharmony_ci reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci/* 74162306a36Sopenharmony_ci * The TDA998x has a problem when trying to read the EDID close to a 74262306a36Sopenharmony_ci * HPD assertion: it needs a delay of 100ms to avoid timing out while 74362306a36Sopenharmony_ci * trying to read EDID data. 74462306a36Sopenharmony_ci * 74562306a36Sopenharmony_ci * However, tda998x_connector_get_modes() may be called at any moment 74662306a36Sopenharmony_ci * after tda998x_connector_detect() indicates that we are connected, so 74762306a36Sopenharmony_ci * we need to delay probing modes in tda998x_connector_get_modes() after 74862306a36Sopenharmony_ci * we have seen a HPD inactive->active transition. This code implements 74962306a36Sopenharmony_ci * that delay. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_cistatic void tda998x_edid_delay_done(struct timer_list *t) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct tda998x_priv *priv = from_timer(priv, t, edid_delay_timer); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci priv->edid_delay_active = false; 75662306a36Sopenharmony_ci wake_up(&priv->edid_delay_waitq); 75762306a36Sopenharmony_ci schedule_work(&priv->detect_work); 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic void tda998x_edid_delay_start(struct tda998x_priv *priv) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci priv->edid_delay_active = true; 76362306a36Sopenharmony_ci mod_timer(&priv->edid_delay_timer, jiffies + HZ/10); 76462306a36Sopenharmony_ci} 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic int tda998x_edid_delay_wait(struct tda998x_priv *priv) 76762306a36Sopenharmony_ci{ 76862306a36Sopenharmony_ci return wait_event_killable(priv->edid_delay_waitq, !priv->edid_delay_active); 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/* 77262306a36Sopenharmony_ci * We need to run the KMS hotplug event helper outside of our threaded 77362306a36Sopenharmony_ci * interrupt routine as this can call back into our get_modes method, 77462306a36Sopenharmony_ci * which will want to make use of interrupts. 77562306a36Sopenharmony_ci */ 77662306a36Sopenharmony_cistatic void tda998x_detect_work(struct work_struct *work) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct tda998x_priv *priv = 77962306a36Sopenharmony_ci container_of(work, struct tda998x_priv, detect_work); 78062306a36Sopenharmony_ci struct drm_device *dev = priv->connector.dev; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci if (dev) 78362306a36Sopenharmony_ci drm_kms_helper_hotplug_event(dev); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/* 78762306a36Sopenharmony_ci * only 2 interrupts may occur: screen plug/unplug and EDID read 78862306a36Sopenharmony_ci */ 78962306a36Sopenharmony_cistatic irqreturn_t tda998x_irq_thread(int irq, void *data) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct tda998x_priv *priv = data; 79262306a36Sopenharmony_ci u8 sta, cec, lvl, flag0, flag1, flag2; 79362306a36Sopenharmony_ci bool handled = false; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci sta = cec_read(priv, REG_CEC_INTSTATUS); 79662306a36Sopenharmony_ci if (sta & CEC_INTSTATUS_HDMI) { 79762306a36Sopenharmony_ci cec = cec_read(priv, REG_CEC_RXSHPDINT); 79862306a36Sopenharmony_ci lvl = cec_read(priv, REG_CEC_RXSHPDLEV); 79962306a36Sopenharmony_ci flag0 = reg_read(priv, REG_INT_FLAGS_0); 80062306a36Sopenharmony_ci flag1 = reg_read(priv, REG_INT_FLAGS_1); 80162306a36Sopenharmony_ci flag2 = reg_read(priv, REG_INT_FLAGS_2); 80262306a36Sopenharmony_ci DRM_DEBUG_DRIVER( 80362306a36Sopenharmony_ci "tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n", 80462306a36Sopenharmony_ci sta, cec, lvl, flag0, flag1, flag2); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (cec & CEC_RXSHPDINT_HPD) { 80762306a36Sopenharmony_ci if (lvl & CEC_RXSHPDLEV_HPD) { 80862306a36Sopenharmony_ci tda998x_edid_delay_start(priv); 80962306a36Sopenharmony_ci } else { 81062306a36Sopenharmony_ci schedule_work(&priv->detect_work); 81162306a36Sopenharmony_ci cec_notifier_phys_addr_invalidate( 81262306a36Sopenharmony_ci priv->cec_notify); 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci handled = true; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) { 81962306a36Sopenharmony_ci priv->wq_edid_wait = 0; 82062306a36Sopenharmony_ci wake_up(&priv->wq_edid); 82162306a36Sopenharmony_ci handled = true; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci return IRQ_RETVAL(handled); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_cistatic void 82962306a36Sopenharmony_citda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, 83062306a36Sopenharmony_ci union hdmi_infoframe *frame) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci u8 buf[MAX_WRITE_RANGE_BUF]; 83362306a36Sopenharmony_ci ssize_t len; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); 83662306a36Sopenharmony_ci if (len < 0) { 83762306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, 83862306a36Sopenharmony_ci "hdmi_infoframe_pack() type=0x%02x failed: %zd\n", 83962306a36Sopenharmony_ci frame->any.type, len); 84062306a36Sopenharmony_ci return; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci reg_clear(priv, REG_DIP_IF_FLAGS, bit); 84462306a36Sopenharmony_ci reg_write_range(priv, addr, buf, len); 84562306a36Sopenharmony_ci reg_set(priv, REG_DIP_IF_FLAGS, bit); 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic void tda998x_write_aif(struct tda998x_priv *priv, 84962306a36Sopenharmony_ci const struct hdmi_audio_infoframe *cea) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci union hdmi_infoframe frame; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci frame.audio = *cea; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, &frame); 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic void 85962306a36Sopenharmony_citda998x_write_avi(struct tda998x_priv *priv, const struct drm_display_mode *mode) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci union hdmi_infoframe frame; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, 86462306a36Sopenharmony_ci &priv->connector, mode); 86562306a36Sopenharmony_ci frame.avi.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; 86662306a36Sopenharmony_ci drm_hdmi_avi_infoframe_quant_range(&frame.avi, &priv->connector, mode, 86762306a36Sopenharmony_ci priv->rgb_quant_range); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, &frame); 87062306a36Sopenharmony_ci} 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic void tda998x_write_vsi(struct tda998x_priv *priv, 87362306a36Sopenharmony_ci const struct drm_display_mode *mode) 87462306a36Sopenharmony_ci{ 87562306a36Sopenharmony_ci union hdmi_infoframe frame; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci if (drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi, 87862306a36Sopenharmony_ci &priv->connector, 87962306a36Sopenharmony_ci mode)) 88062306a36Sopenharmony_ci reg_clear(priv, REG_DIP_IF_FLAGS, DIP_IF_FLAGS_IF1); 88162306a36Sopenharmony_ci else 88262306a36Sopenharmony_ci tda998x_write_if(priv, DIP_IF_FLAGS_IF1, REG_IF1_HB0, &frame); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/* Audio support */ 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_cistatic const struct tda998x_audio_route tda998x_audio_route[AUDIO_ROUTE_NUM] = { 88862306a36Sopenharmony_ci [AUDIO_ROUTE_I2S] = { 88962306a36Sopenharmony_ci .ena_aclk = 1, 89062306a36Sopenharmony_ci .mux_ap = MUX_AP_SELECT_I2S, 89162306a36Sopenharmony_ci .aip_clksel = AIP_CLKSEL_AIP_I2S | AIP_CLKSEL_FS_ACLK, 89262306a36Sopenharmony_ci }, 89362306a36Sopenharmony_ci [AUDIO_ROUTE_SPDIF] = { 89462306a36Sopenharmony_ci .ena_aclk = 0, 89562306a36Sopenharmony_ci .mux_ap = MUX_AP_SELECT_SPDIF, 89662306a36Sopenharmony_ci .aip_clksel = AIP_CLKSEL_AIP_SPDIF | AIP_CLKSEL_FS_FS64SPDIF, 89762306a36Sopenharmony_ci }, 89862306a36Sopenharmony_ci}; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/* Configure the TDA998x audio data and clock routing. */ 90162306a36Sopenharmony_cistatic int tda998x_derive_routing(struct tda998x_priv *priv, 90262306a36Sopenharmony_ci struct tda998x_audio_settings *s, 90362306a36Sopenharmony_ci unsigned int route) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci s->route = &tda998x_audio_route[route]; 90662306a36Sopenharmony_ci s->ena_ap = priv->audio_port_enable[route]; 90762306a36Sopenharmony_ci if (s->ena_ap == 0) { 90862306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "no audio configuration found\n"); 90962306a36Sopenharmony_ci return -EINVAL; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci return 0; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci/* 91662306a36Sopenharmony_ci * The audio clock divisor register controls a divider producing Audio_Clk_Out 91762306a36Sopenharmony_ci * from SERclk by dividing it by 2^n where 0 <= n <= 5. We don't know what 91862306a36Sopenharmony_ci * Audio_Clk_Out or SERclk are. We guess SERclk is the same as TMDS clock. 91962306a36Sopenharmony_ci * 92062306a36Sopenharmony_ci * It seems that Audio_Clk_Out must be the smallest value that is greater 92162306a36Sopenharmony_ci * than 128*fs, otherwise audio does not function. There is some suggestion 92262306a36Sopenharmony_ci * that 126*fs is a better value. 92362306a36Sopenharmony_ci */ 92462306a36Sopenharmony_cistatic u8 tda998x_get_adiv(struct tda998x_priv *priv, unsigned int fs) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci unsigned long min_audio_clk = fs * 128; 92762306a36Sopenharmony_ci unsigned long ser_clk = priv->tmds_clock * 1000; 92862306a36Sopenharmony_ci u8 adiv; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci for (adiv = AUDIO_DIV_SERCLK_32; adiv != AUDIO_DIV_SERCLK_1; adiv--) 93162306a36Sopenharmony_ci if (ser_clk > min_audio_clk << adiv) 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci dev_dbg(&priv->hdmi->dev, 93562306a36Sopenharmony_ci "ser_clk=%luHz fs=%uHz min_aclk=%luHz adiv=%d\n", 93662306a36Sopenharmony_ci ser_clk, fs, min_audio_clk, adiv); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return adiv; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci/* 94262306a36Sopenharmony_ci * In auto-CTS mode, the TDA998x uses a "measured time stamp" counter to 94362306a36Sopenharmony_ci * generate the CTS value. It appears that the "measured time stamp" is 94462306a36Sopenharmony_ci * the number of TDMS clock cycles within a number of audio input clock 94562306a36Sopenharmony_ci * cycles defined by the k and N parameters defined below, in a similar 94662306a36Sopenharmony_ci * way to that which is set out in the CTS generation in the HDMI spec. 94762306a36Sopenharmony_ci * 94862306a36Sopenharmony_ci * tmdsclk ----> mts -> /m ---> CTS 94962306a36Sopenharmony_ci * ^ 95062306a36Sopenharmony_ci * sclk -> /k -> /N 95162306a36Sopenharmony_ci * 95262306a36Sopenharmony_ci * CTS = mts / m, where m is 2^M. 95362306a36Sopenharmony_ci * /k is a divider based on the K value below, K+1 for K < 4, or 8 for K >= 4 95462306a36Sopenharmony_ci * /N is a divider based on the HDMI specified N value. 95562306a36Sopenharmony_ci * 95662306a36Sopenharmony_ci * This produces the following equation: 95762306a36Sopenharmony_ci * CTS = tmds_clock * k * N / (sclk * m) 95862306a36Sopenharmony_ci * 95962306a36Sopenharmony_ci * When combined with the sink-side equation, and realising that sclk is 96062306a36Sopenharmony_ci * bclk_ratio * fs, we end up with: 96162306a36Sopenharmony_ci * k = m * bclk_ratio / 128. 96262306a36Sopenharmony_ci * 96362306a36Sopenharmony_ci * Note: S/PDIF always uses a bclk_ratio of 64. 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_cistatic int tda998x_derive_cts_n(struct tda998x_priv *priv, 96662306a36Sopenharmony_ci struct tda998x_audio_settings *settings, 96762306a36Sopenharmony_ci unsigned int ratio) 96862306a36Sopenharmony_ci{ 96962306a36Sopenharmony_ci switch (ratio) { 97062306a36Sopenharmony_ci case 16: 97162306a36Sopenharmony_ci settings->cts_n = CTS_N_M(3) | CTS_N_K(0); 97262306a36Sopenharmony_ci break; 97362306a36Sopenharmony_ci case 32: 97462306a36Sopenharmony_ci settings->cts_n = CTS_N_M(3) | CTS_N_K(1); 97562306a36Sopenharmony_ci break; 97662306a36Sopenharmony_ci case 48: 97762306a36Sopenharmony_ci settings->cts_n = CTS_N_M(3) | CTS_N_K(2); 97862306a36Sopenharmony_ci break; 97962306a36Sopenharmony_ci case 64: 98062306a36Sopenharmony_ci settings->cts_n = CTS_N_M(3) | CTS_N_K(3); 98162306a36Sopenharmony_ci break; 98262306a36Sopenharmony_ci case 128: 98362306a36Sopenharmony_ci settings->cts_n = CTS_N_M(0) | CTS_N_K(0); 98462306a36Sopenharmony_ci break; 98562306a36Sopenharmony_ci default: 98662306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "unsupported bclk ratio %ufs\n", 98762306a36Sopenharmony_ci ratio); 98862306a36Sopenharmony_ci return -EINVAL; 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci return 0; 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic void tda998x_audio_mute(struct tda998x_priv *priv, bool on) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci if (on) { 99662306a36Sopenharmony_ci reg_set(priv, REG_SOFTRESET, SOFTRESET_AUDIO); 99762306a36Sopenharmony_ci reg_clear(priv, REG_SOFTRESET, SOFTRESET_AUDIO); 99862306a36Sopenharmony_ci reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); 99962306a36Sopenharmony_ci } else { 100062306a36Sopenharmony_ci reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); 100162306a36Sopenharmony_ci } 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic void tda998x_configure_audio(struct tda998x_priv *priv) 100562306a36Sopenharmony_ci{ 100662306a36Sopenharmony_ci const struct tda998x_audio_settings *settings = &priv->audio; 100762306a36Sopenharmony_ci u8 buf[6], adiv; 100862306a36Sopenharmony_ci u32 n; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* If audio is not configured, there is nothing to do. */ 101162306a36Sopenharmony_ci if (settings->ena_ap == 0) 101262306a36Sopenharmony_ci return; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci adiv = tda998x_get_adiv(priv, settings->sample_rate); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci /* Enable audio ports */ 101762306a36Sopenharmony_ci reg_write(priv, REG_ENA_AP, settings->ena_ap); 101862306a36Sopenharmony_ci reg_write(priv, REG_ENA_ACLK, settings->route->ena_aclk); 101962306a36Sopenharmony_ci reg_write(priv, REG_MUX_AP, settings->route->mux_ap); 102062306a36Sopenharmony_ci reg_write(priv, REG_I2S_FORMAT, settings->i2s_format); 102162306a36Sopenharmony_ci reg_write(priv, REG_AIP_CLKSEL, settings->route->aip_clksel); 102262306a36Sopenharmony_ci reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | 102362306a36Sopenharmony_ci AIP_CNTRL_0_ACR_MAN); /* auto CTS */ 102462306a36Sopenharmony_ci reg_write(priv, REG_CTS_N, settings->cts_n); 102562306a36Sopenharmony_ci reg_write(priv, REG_AUDIO_DIV, adiv); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci /* 102862306a36Sopenharmony_ci * This is the approximate value of N, which happens to be 102962306a36Sopenharmony_ci * the recommended values for non-coherent clocks. 103062306a36Sopenharmony_ci */ 103162306a36Sopenharmony_ci n = 128 * settings->sample_rate / 1000; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci /* Write the CTS and N values */ 103462306a36Sopenharmony_ci buf[0] = 0x44; 103562306a36Sopenharmony_ci buf[1] = 0x42; 103662306a36Sopenharmony_ci buf[2] = 0x01; 103762306a36Sopenharmony_ci buf[3] = n; 103862306a36Sopenharmony_ci buf[4] = n >> 8; 103962306a36Sopenharmony_ci buf[5] = n >> 16; 104062306a36Sopenharmony_ci reg_write_range(priv, REG_ACR_CTS_0, buf, 6); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci /* Reset CTS generator */ 104362306a36Sopenharmony_ci reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); 104462306a36Sopenharmony_ci reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* Write the channel status 104762306a36Sopenharmony_ci * The REG_CH_STAT_B-registers skip IEC958 AES2 byte, because 104862306a36Sopenharmony_ci * there is a separate register for each I2S wire. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci buf[0] = settings->status[0]; 105162306a36Sopenharmony_ci buf[1] = settings->status[1]; 105262306a36Sopenharmony_ci buf[2] = settings->status[3]; 105362306a36Sopenharmony_ci buf[3] = settings->status[4]; 105462306a36Sopenharmony_ci reg_write_range(priv, REG_CH_STAT_B(0), buf, 4); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci tda998x_audio_mute(priv, true); 105762306a36Sopenharmony_ci msleep(20); 105862306a36Sopenharmony_ci tda998x_audio_mute(priv, false); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci tda998x_write_aif(priv, &settings->cea); 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic int tda998x_audio_hw_params(struct device *dev, void *data, 106462306a36Sopenharmony_ci struct hdmi_codec_daifmt *daifmt, 106562306a36Sopenharmony_ci struct hdmi_codec_params *params) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 106862306a36Sopenharmony_ci unsigned int bclk_ratio; 106962306a36Sopenharmony_ci bool spdif = daifmt->fmt == HDMI_SPDIF; 107062306a36Sopenharmony_ci int ret; 107162306a36Sopenharmony_ci struct tda998x_audio_settings audio = { 107262306a36Sopenharmony_ci .sample_rate = params->sample_rate, 107362306a36Sopenharmony_ci .cea = params->cea, 107462306a36Sopenharmony_ci }; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci memcpy(audio.status, params->iec.status, 107762306a36Sopenharmony_ci min(sizeof(audio.status), sizeof(params->iec.status))); 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci switch (daifmt->fmt) { 108062306a36Sopenharmony_ci case HDMI_I2S: 108162306a36Sopenharmony_ci audio.i2s_format = I2S_FORMAT_PHILIPS; 108262306a36Sopenharmony_ci break; 108362306a36Sopenharmony_ci case HDMI_LEFT_J: 108462306a36Sopenharmony_ci audio.i2s_format = I2S_FORMAT_LEFT_J; 108562306a36Sopenharmony_ci break; 108662306a36Sopenharmony_ci case HDMI_RIGHT_J: 108762306a36Sopenharmony_ci audio.i2s_format = I2S_FORMAT_RIGHT_J; 108862306a36Sopenharmony_ci break; 108962306a36Sopenharmony_ci case HDMI_SPDIF: 109062306a36Sopenharmony_ci audio.i2s_format = 0; 109162306a36Sopenharmony_ci break; 109262306a36Sopenharmony_ci default: 109362306a36Sopenharmony_ci dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt); 109462306a36Sopenharmony_ci return -EINVAL; 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (!spdif && 109862306a36Sopenharmony_ci (daifmt->bit_clk_inv || daifmt->frame_clk_inv || 109962306a36Sopenharmony_ci daifmt->bit_clk_provider || daifmt->frame_clk_provider)) { 110062306a36Sopenharmony_ci dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__, 110162306a36Sopenharmony_ci daifmt->bit_clk_inv, daifmt->frame_clk_inv, 110262306a36Sopenharmony_ci daifmt->bit_clk_provider, 110362306a36Sopenharmony_ci daifmt->frame_clk_provider); 110462306a36Sopenharmony_ci return -EINVAL; 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci ret = tda998x_derive_routing(priv, &audio, AUDIO_ROUTE_I2S + spdif); 110862306a36Sopenharmony_ci if (ret < 0) 110962306a36Sopenharmony_ci return ret; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci bclk_ratio = spdif ? 64 : params->sample_width * 2; 111262306a36Sopenharmony_ci ret = tda998x_derive_cts_n(priv, &audio, bclk_ratio); 111362306a36Sopenharmony_ci if (ret < 0) 111462306a36Sopenharmony_ci return ret; 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_ci mutex_lock(&priv->audio_mutex); 111762306a36Sopenharmony_ci priv->audio = audio; 111862306a36Sopenharmony_ci if (priv->supports_infoframes && priv->sink_has_audio) 111962306a36Sopenharmony_ci tda998x_configure_audio(priv); 112062306a36Sopenharmony_ci mutex_unlock(&priv->audio_mutex); 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci return 0; 112362306a36Sopenharmony_ci} 112462306a36Sopenharmony_ci 112562306a36Sopenharmony_cistatic void tda998x_audio_shutdown(struct device *dev, void *data) 112662306a36Sopenharmony_ci{ 112762306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci mutex_lock(&priv->audio_mutex); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci reg_write(priv, REG_ENA_AP, 0); 113262306a36Sopenharmony_ci priv->audio.ena_ap = 0; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci mutex_unlock(&priv->audio_mutex); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_cistatic int tda998x_audio_mute_stream(struct device *dev, void *data, 113862306a36Sopenharmony_ci bool enable, int direction) 113962306a36Sopenharmony_ci{ 114062306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci mutex_lock(&priv->audio_mutex); 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci tda998x_audio_mute(priv, enable); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci mutex_unlock(&priv->audio_mutex); 114762306a36Sopenharmony_ci return 0; 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic int tda998x_audio_get_eld(struct device *dev, void *data, 115162306a36Sopenharmony_ci uint8_t *buf, size_t len) 115262306a36Sopenharmony_ci{ 115362306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci mutex_lock(&priv->audio_mutex); 115662306a36Sopenharmony_ci memcpy(buf, priv->connector.eld, 115762306a36Sopenharmony_ci min(sizeof(priv->connector.eld), len)); 115862306a36Sopenharmony_ci mutex_unlock(&priv->audio_mutex); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci return 0; 116162306a36Sopenharmony_ci} 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_cistatic const struct hdmi_codec_ops audio_codec_ops = { 116462306a36Sopenharmony_ci .hw_params = tda998x_audio_hw_params, 116562306a36Sopenharmony_ci .audio_shutdown = tda998x_audio_shutdown, 116662306a36Sopenharmony_ci .mute_stream = tda998x_audio_mute_stream, 116762306a36Sopenharmony_ci .get_eld = tda998x_audio_get_eld, 116862306a36Sopenharmony_ci .no_capture_mute = 1, 116962306a36Sopenharmony_ci}; 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_cistatic int tda998x_audio_codec_init(struct tda998x_priv *priv, 117262306a36Sopenharmony_ci struct device *dev) 117362306a36Sopenharmony_ci{ 117462306a36Sopenharmony_ci struct hdmi_codec_pdata codec_data = { 117562306a36Sopenharmony_ci .ops = &audio_codec_ops, 117662306a36Sopenharmony_ci .max_i2s_channels = 2, 117762306a36Sopenharmony_ci .no_i2s_capture = 1, 117862306a36Sopenharmony_ci .no_spdif_capture = 1, 117962306a36Sopenharmony_ci }; 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_ci if (priv->audio_port_enable[AUDIO_ROUTE_I2S]) 118262306a36Sopenharmony_ci codec_data.i2s = 1; 118362306a36Sopenharmony_ci if (priv->audio_port_enable[AUDIO_ROUTE_SPDIF]) 118462306a36Sopenharmony_ci codec_data.spdif = 1; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci priv->audio_pdev = platform_device_register_data( 118762306a36Sopenharmony_ci dev, HDMI_CODEC_DRV_NAME, PLATFORM_DEVID_AUTO, 118862306a36Sopenharmony_ci &codec_data, sizeof(codec_data)); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci return PTR_ERR_OR_ZERO(priv->audio_pdev); 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci/* DRM connector functions */ 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic enum drm_connector_status 119662306a36Sopenharmony_citda998x_connector_detect(struct drm_connector *connector, bool force) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci struct tda998x_priv *priv = conn_to_tda998x_priv(connector); 119962306a36Sopenharmony_ci u8 val = cec_read(priv, REG_CEC_RXSHPDLEV); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected : 120262306a36Sopenharmony_ci connector_status_disconnected; 120362306a36Sopenharmony_ci} 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_cistatic void tda998x_connector_destroy(struct drm_connector *connector) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci drm_connector_cleanup(connector); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic const struct drm_connector_funcs tda998x_connector_funcs = { 121162306a36Sopenharmony_ci .reset = drm_atomic_helper_connector_reset, 121262306a36Sopenharmony_ci .fill_modes = drm_helper_probe_single_connector_modes, 121362306a36Sopenharmony_ci .detect = tda998x_connector_detect, 121462306a36Sopenharmony_ci .destroy = tda998x_connector_destroy, 121562306a36Sopenharmony_ci .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 121662306a36Sopenharmony_ci .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, 121762306a36Sopenharmony_ci}; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_cistatic int read_edid_block(void *data, u8 *buf, unsigned int blk, size_t length) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci struct tda998x_priv *priv = data; 122262306a36Sopenharmony_ci u8 offset, segptr; 122362306a36Sopenharmony_ci int ret, i; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci offset = (blk & 1) ? 128 : 0; 122662306a36Sopenharmony_ci segptr = blk / 2; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci mutex_lock(&priv->edid_mutex); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci reg_write(priv, REG_DDC_ADDR, 0xa0); 123162306a36Sopenharmony_ci reg_write(priv, REG_DDC_OFFS, offset); 123262306a36Sopenharmony_ci reg_write(priv, REG_DDC_SEGM_ADDR, 0x60); 123362306a36Sopenharmony_ci reg_write(priv, REG_DDC_SEGM, segptr); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci /* enable reading EDID: */ 123662306a36Sopenharmony_ci priv->wq_edid_wait = 1; 123762306a36Sopenharmony_ci reg_write(priv, REG_EDID_CTRL, 0x1); 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci /* flag must be cleared by sw: */ 124062306a36Sopenharmony_ci reg_write(priv, REG_EDID_CTRL, 0x0); 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci /* wait for block read to complete: */ 124362306a36Sopenharmony_ci if (priv->hdmi->irq) { 124462306a36Sopenharmony_ci i = wait_event_timeout(priv->wq_edid, 124562306a36Sopenharmony_ci !priv->wq_edid_wait, 124662306a36Sopenharmony_ci msecs_to_jiffies(100)); 124762306a36Sopenharmony_ci if (i < 0) { 124862306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "read edid wait err %d\n", i); 124962306a36Sopenharmony_ci ret = i; 125062306a36Sopenharmony_ci goto failed; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci } else { 125362306a36Sopenharmony_ci for (i = 100; i > 0; i--) { 125462306a36Sopenharmony_ci msleep(1); 125562306a36Sopenharmony_ci ret = reg_read(priv, REG_INT_FLAGS_2); 125662306a36Sopenharmony_ci if (ret < 0) 125762306a36Sopenharmony_ci goto failed; 125862306a36Sopenharmony_ci if (ret & INT_FLAGS_2_EDID_BLK_RD) 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci } 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (i == 0) { 126462306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "read edid timeout\n"); 126562306a36Sopenharmony_ci ret = -ETIMEDOUT; 126662306a36Sopenharmony_ci goto failed; 126762306a36Sopenharmony_ci } 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci ret = reg_read_range(priv, REG_EDID_DATA_0, buf, length); 127062306a36Sopenharmony_ci if (ret != length) { 127162306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n", 127262306a36Sopenharmony_ci blk, ret); 127362306a36Sopenharmony_ci goto failed; 127462306a36Sopenharmony_ci } 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci ret = 0; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci failed: 127962306a36Sopenharmony_ci mutex_unlock(&priv->edid_mutex); 128062306a36Sopenharmony_ci return ret; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int tda998x_connector_get_modes(struct drm_connector *connector) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct tda998x_priv *priv = conn_to_tda998x_priv(connector); 128662306a36Sopenharmony_ci struct edid *edid; 128762306a36Sopenharmony_ci int n; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci /* 129062306a36Sopenharmony_ci * If we get killed while waiting for the HPD timeout, return 129162306a36Sopenharmony_ci * no modes found: we are not in a restartable path, so we 129262306a36Sopenharmony_ci * can't handle signals gracefully. 129362306a36Sopenharmony_ci */ 129462306a36Sopenharmony_ci if (tda998x_edid_delay_wait(priv)) 129562306a36Sopenharmony_ci return 0; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (priv->rev == TDA19988) 129862306a36Sopenharmony_ci reg_clear(priv, REG_TX4, TX4_PD_RAM); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci edid = drm_do_get_edid(connector, read_edid_block, priv); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (priv->rev == TDA19988) 130362306a36Sopenharmony_ci reg_set(priv, REG_TX4, TX4_PD_RAM); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (!edid) { 130662306a36Sopenharmony_ci dev_warn(&priv->hdmi->dev, "failed to read EDID\n"); 130762306a36Sopenharmony_ci return 0; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci drm_connector_update_edid_property(connector, edid); 131162306a36Sopenharmony_ci cec_notifier_set_phys_addr_from_edid(priv->cec_notify, edid); 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci mutex_lock(&priv->audio_mutex); 131462306a36Sopenharmony_ci n = drm_add_edid_modes(connector, edid); 131562306a36Sopenharmony_ci priv->sink_has_audio = drm_detect_monitor_audio(edid); 131662306a36Sopenharmony_ci mutex_unlock(&priv->audio_mutex); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci kfree(edid); 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci return n; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic struct drm_encoder * 132462306a36Sopenharmony_citda998x_connector_best_encoder(struct drm_connector *connector) 132562306a36Sopenharmony_ci{ 132662306a36Sopenharmony_ci struct tda998x_priv *priv = conn_to_tda998x_priv(connector); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci return priv->bridge.encoder; 132962306a36Sopenharmony_ci} 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_cistatic 133262306a36Sopenharmony_ciconst struct drm_connector_helper_funcs tda998x_connector_helper_funcs = { 133362306a36Sopenharmony_ci .get_modes = tda998x_connector_get_modes, 133462306a36Sopenharmony_ci .best_encoder = tda998x_connector_best_encoder, 133562306a36Sopenharmony_ci}; 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_cistatic int tda998x_connector_init(struct tda998x_priv *priv, 133862306a36Sopenharmony_ci struct drm_device *drm) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct drm_connector *connector = &priv->connector; 134162306a36Sopenharmony_ci int ret; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci connector->interlace_allowed = 1; 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci if (priv->hdmi->irq) 134662306a36Sopenharmony_ci connector->polled = DRM_CONNECTOR_POLL_HPD; 134762306a36Sopenharmony_ci else 134862306a36Sopenharmony_ci connector->polled = DRM_CONNECTOR_POLL_CONNECT | 134962306a36Sopenharmony_ci DRM_CONNECTOR_POLL_DISCONNECT; 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci drm_connector_helper_add(connector, &tda998x_connector_helper_funcs); 135262306a36Sopenharmony_ci ret = drm_connector_init(drm, connector, &tda998x_connector_funcs, 135362306a36Sopenharmony_ci DRM_MODE_CONNECTOR_HDMIA); 135462306a36Sopenharmony_ci if (ret) 135562306a36Sopenharmony_ci return ret; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci drm_connector_attach_encoder(&priv->connector, 135862306a36Sopenharmony_ci priv->bridge.encoder); 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci return 0; 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci/* DRM bridge functions */ 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int tda998x_bridge_attach(struct drm_bridge *bridge, 136662306a36Sopenharmony_ci enum drm_bridge_attach_flags flags) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { 137162306a36Sopenharmony_ci DRM_ERROR("Fix bridge driver to make connector optional!"); 137262306a36Sopenharmony_ci return -EINVAL; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci return tda998x_connector_init(priv, bridge->dev); 137662306a36Sopenharmony_ci} 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_cistatic void tda998x_bridge_detach(struct drm_bridge *bridge) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci drm_connector_cleanup(&priv->connector); 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic enum drm_mode_status tda998x_bridge_mode_valid(struct drm_bridge *bridge, 138662306a36Sopenharmony_ci const struct drm_display_info *info, 138762306a36Sopenharmony_ci const struct drm_display_mode *mode) 138862306a36Sopenharmony_ci{ 138962306a36Sopenharmony_ci /* TDA19988 dotclock can go up to 165MHz */ 139062306a36Sopenharmony_ci struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci if (mode->clock > ((priv->rev == TDA19988) ? 165000 : 150000)) 139362306a36Sopenharmony_ci return MODE_CLOCK_HIGH; 139462306a36Sopenharmony_ci if (mode->htotal >= BIT(13)) 139562306a36Sopenharmony_ci return MODE_BAD_HVALUE; 139662306a36Sopenharmony_ci if (mode->vtotal >= BIT(11)) 139762306a36Sopenharmony_ci return MODE_BAD_VVALUE; 139862306a36Sopenharmony_ci return MODE_OK; 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_cistatic void tda998x_bridge_enable(struct drm_bridge *bridge) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (!priv->is_on) { 140662306a36Sopenharmony_ci /* enable video ports, audio will be enabled later */ 140762306a36Sopenharmony_ci reg_write(priv, REG_ENA_VP_0, 0xff); 140862306a36Sopenharmony_ci reg_write(priv, REG_ENA_VP_1, 0xff); 140962306a36Sopenharmony_ci reg_write(priv, REG_ENA_VP_2, 0xff); 141062306a36Sopenharmony_ci /* set muxing after enabling ports: */ 141162306a36Sopenharmony_ci reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0); 141262306a36Sopenharmony_ci reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1); 141362306a36Sopenharmony_ci reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci priv->is_on = true; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic void tda998x_bridge_disable(struct drm_bridge *bridge) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci if (priv->is_on) { 142462306a36Sopenharmony_ci /* disable video ports */ 142562306a36Sopenharmony_ci reg_write(priv, REG_ENA_VP_0, 0x00); 142662306a36Sopenharmony_ci reg_write(priv, REG_ENA_VP_1, 0x00); 142762306a36Sopenharmony_ci reg_write(priv, REG_ENA_VP_2, 0x00); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci priv->is_on = false; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci} 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_cistatic void tda998x_bridge_mode_set(struct drm_bridge *bridge, 143462306a36Sopenharmony_ci const struct drm_display_mode *mode, 143562306a36Sopenharmony_ci const struct drm_display_mode *adjusted_mode) 143662306a36Sopenharmony_ci{ 143762306a36Sopenharmony_ci struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge); 143862306a36Sopenharmony_ci unsigned long tmds_clock; 143962306a36Sopenharmony_ci u16 ref_pix, ref_line, n_pix, n_line; 144062306a36Sopenharmony_ci u16 hs_pix_s, hs_pix_e; 144162306a36Sopenharmony_ci u16 vs1_pix_s, vs1_pix_e, vs1_line_s, vs1_line_e; 144262306a36Sopenharmony_ci u16 vs2_pix_s, vs2_pix_e, vs2_line_s, vs2_line_e; 144362306a36Sopenharmony_ci u16 vwin1_line_s, vwin1_line_e; 144462306a36Sopenharmony_ci u16 vwin2_line_s, vwin2_line_e; 144562306a36Sopenharmony_ci u16 de_pix_s, de_pix_e; 144662306a36Sopenharmony_ci u8 reg, div, rep, sel_clk; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci /* 144962306a36Sopenharmony_ci * Since we are "computer" like, our source invariably produces 145062306a36Sopenharmony_ci * full-range RGB. If the monitor supports full-range, then use 145162306a36Sopenharmony_ci * it, otherwise reduce to limited-range. 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_ci priv->rgb_quant_range = 145462306a36Sopenharmony_ci priv->connector.display_info.rgb_quant_range_selectable ? 145562306a36Sopenharmony_ci HDMI_QUANTIZATION_RANGE_FULL : 145662306a36Sopenharmony_ci drm_default_rgb_quant_range(adjusted_mode); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci /* 145962306a36Sopenharmony_ci * Internally TDA998x is using ITU-R BT.656 style sync but 146062306a36Sopenharmony_ci * we get VESA style sync. TDA998x is using a reference pixel 146162306a36Sopenharmony_ci * relative to ITU to sync to the input frame and for output 146262306a36Sopenharmony_ci * sync generation. Currently, we are using reference detection 146362306a36Sopenharmony_ci * from HS/VS, i.e. REFPIX/REFLINE denote frame start sync point 146462306a36Sopenharmony_ci * which is position of rising VS with coincident rising HS. 146562306a36Sopenharmony_ci * 146662306a36Sopenharmony_ci * Now there is some issues to take care of: 146762306a36Sopenharmony_ci * - HDMI data islands require sync-before-active 146862306a36Sopenharmony_ci * - TDA998x register values must be > 0 to be enabled 146962306a36Sopenharmony_ci * - REFLINE needs an additional offset of +1 147062306a36Sopenharmony_ci * - REFPIX needs an addtional offset of +1 for UYUV and +3 for RGB 147162306a36Sopenharmony_ci * 147262306a36Sopenharmony_ci * So we add +1 to all horizontal and vertical register values, 147362306a36Sopenharmony_ci * plus an additional +3 for REFPIX as we are using RGB input only. 147462306a36Sopenharmony_ci */ 147562306a36Sopenharmony_ci n_pix = mode->htotal; 147662306a36Sopenharmony_ci n_line = mode->vtotal; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci hs_pix_e = mode->hsync_end - mode->hdisplay; 147962306a36Sopenharmony_ci hs_pix_s = mode->hsync_start - mode->hdisplay; 148062306a36Sopenharmony_ci de_pix_e = mode->htotal; 148162306a36Sopenharmony_ci de_pix_s = mode->htotal - mode->hdisplay; 148262306a36Sopenharmony_ci ref_pix = 3 + hs_pix_s; 148362306a36Sopenharmony_ci 148462306a36Sopenharmony_ci /* 148562306a36Sopenharmony_ci * Attached LCD controllers may generate broken sync. Allow 148662306a36Sopenharmony_ci * those to adjust the position of the rising VS edge by adding 148762306a36Sopenharmony_ci * HSKEW to ref_pix. 148862306a36Sopenharmony_ci */ 148962306a36Sopenharmony_ci if (adjusted_mode->flags & DRM_MODE_FLAG_HSKEW) 149062306a36Sopenharmony_ci ref_pix += adjusted_mode->hskew; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci if ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0) { 149362306a36Sopenharmony_ci ref_line = 1 + mode->vsync_start - mode->vdisplay; 149462306a36Sopenharmony_ci vwin1_line_s = mode->vtotal - mode->vdisplay - 1; 149562306a36Sopenharmony_ci vwin1_line_e = vwin1_line_s + mode->vdisplay; 149662306a36Sopenharmony_ci vs1_pix_s = vs1_pix_e = hs_pix_s; 149762306a36Sopenharmony_ci vs1_line_s = mode->vsync_start - mode->vdisplay; 149862306a36Sopenharmony_ci vs1_line_e = vs1_line_s + 149962306a36Sopenharmony_ci mode->vsync_end - mode->vsync_start; 150062306a36Sopenharmony_ci vwin2_line_s = vwin2_line_e = 0; 150162306a36Sopenharmony_ci vs2_pix_s = vs2_pix_e = 0; 150262306a36Sopenharmony_ci vs2_line_s = vs2_line_e = 0; 150362306a36Sopenharmony_ci } else { 150462306a36Sopenharmony_ci ref_line = 1 + (mode->vsync_start - mode->vdisplay)/2; 150562306a36Sopenharmony_ci vwin1_line_s = (mode->vtotal - mode->vdisplay)/2; 150662306a36Sopenharmony_ci vwin1_line_e = vwin1_line_s + mode->vdisplay/2; 150762306a36Sopenharmony_ci vs1_pix_s = vs1_pix_e = hs_pix_s; 150862306a36Sopenharmony_ci vs1_line_s = (mode->vsync_start - mode->vdisplay)/2; 150962306a36Sopenharmony_ci vs1_line_e = vs1_line_s + 151062306a36Sopenharmony_ci (mode->vsync_end - mode->vsync_start)/2; 151162306a36Sopenharmony_ci vwin2_line_s = vwin1_line_s + mode->vtotal/2; 151262306a36Sopenharmony_ci vwin2_line_e = vwin2_line_s + mode->vdisplay/2; 151362306a36Sopenharmony_ci vs2_pix_s = vs2_pix_e = hs_pix_s + mode->htotal/2; 151462306a36Sopenharmony_ci vs2_line_s = vs1_line_s + mode->vtotal/2 ; 151562306a36Sopenharmony_ci vs2_line_e = vs2_line_s + 151662306a36Sopenharmony_ci (mode->vsync_end - mode->vsync_start)/2; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci /* 152062306a36Sopenharmony_ci * Select pixel repeat depending on the double-clock flag 152162306a36Sopenharmony_ci * (which means we have to repeat each pixel once.) 152262306a36Sopenharmony_ci */ 152362306a36Sopenharmony_ci rep = mode->flags & DRM_MODE_FLAG_DBLCLK ? 1 : 0; 152462306a36Sopenharmony_ci sel_clk = SEL_CLK_ENA_SC_CLK | SEL_CLK_SEL_CLK1 | 152562306a36Sopenharmony_ci SEL_CLK_SEL_VRF_CLK(rep ? 2 : 0); 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci /* the TMDS clock is scaled up by the pixel repeat */ 152862306a36Sopenharmony_ci tmds_clock = mode->clock * (1 + rep); 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci /* 153162306a36Sopenharmony_ci * The divisor is power-of-2. The TDA9983B datasheet gives 153262306a36Sopenharmony_ci * this as ranges of Msample/s, which is 10x the TMDS clock: 153362306a36Sopenharmony_ci * 0 - 800 to 1500 Msample/s 153462306a36Sopenharmony_ci * 1 - 400 to 800 Msample/s 153562306a36Sopenharmony_ci * 2 - 200 to 400 Msample/s 153662306a36Sopenharmony_ci * 3 - as 2 above 153762306a36Sopenharmony_ci */ 153862306a36Sopenharmony_ci for (div = 0; div < 3; div++) 153962306a36Sopenharmony_ci if (80000 >> div <= tmds_clock) 154062306a36Sopenharmony_ci break; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci mutex_lock(&priv->audio_mutex); 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci priv->tmds_clock = tmds_clock; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci /* mute the audio FIFO: */ 154762306a36Sopenharmony_ci reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_ci /* set HDMI HDCP mode off: */ 155062306a36Sopenharmony_ci reg_write(priv, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS); 155162306a36Sopenharmony_ci reg_clear(priv, REG_TX33, TX33_HDMI); 155262306a36Sopenharmony_ci reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0)); 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci /* no pre-filter or interpolator: */ 155562306a36Sopenharmony_ci reg_write(priv, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) | 155662306a36Sopenharmony_ci HVF_CNTRL_0_INTPOL(0)); 155762306a36Sopenharmony_ci reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_PREFILT); 155862306a36Sopenharmony_ci reg_write(priv, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0)); 155962306a36Sopenharmony_ci reg_write(priv, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) | 156062306a36Sopenharmony_ci VIP_CNTRL_4_BLC(0)); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci reg_clear(priv, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ); 156362306a36Sopenharmony_ci reg_clear(priv, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR | 156462306a36Sopenharmony_ci PLL_SERIAL_3_SRL_DE); 156562306a36Sopenharmony_ci reg_write(priv, REG_SERIALIZER, 0); 156662306a36Sopenharmony_ci reg_write(priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0)); 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci reg_write(priv, REG_RPT_CNTRL, RPT_CNTRL_REPEAT(rep)); 156962306a36Sopenharmony_ci reg_write(priv, REG_SEL_CLK, sel_clk); 157062306a36Sopenharmony_ci reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) | 157162306a36Sopenharmony_ci PLL_SERIAL_2_SRL_PR(rep)); 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* set color matrix according to output rgb quant range */ 157462306a36Sopenharmony_ci if (priv->rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED) { 157562306a36Sopenharmony_ci static u8 tda998x_full_to_limited_range[] = { 157662306a36Sopenharmony_ci MAT_CONTRL_MAT_SC(2), 157762306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 157862306a36Sopenharmony_ci 0x03, 0x6f, 0x00, 0x00, 0x00, 0x00, 157962306a36Sopenharmony_ci 0x00, 0x00, 0x03, 0x6f, 0x00, 0x00, 158062306a36Sopenharmony_ci 0x00, 0x00, 0x00, 0x00, 0x03, 0x6f, 158162306a36Sopenharmony_ci 0x00, 0x40, 0x00, 0x40, 0x00, 0x40 158262306a36Sopenharmony_ci }; 158362306a36Sopenharmony_ci reg_clear(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC); 158462306a36Sopenharmony_ci reg_write_range(priv, REG_MAT_CONTRL, 158562306a36Sopenharmony_ci tda998x_full_to_limited_range, 158662306a36Sopenharmony_ci sizeof(tda998x_full_to_limited_range)); 158762306a36Sopenharmony_ci } else { 158862306a36Sopenharmony_ci reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP | 158962306a36Sopenharmony_ci MAT_CONTRL_MAT_SC(1)); 159062306a36Sopenharmony_ci reg_set(priv, REG_FEAT_POWERDOWN, FEAT_POWERDOWN_CSC); 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci /* set BIAS tmds value: */ 159462306a36Sopenharmony_ci reg_write(priv, REG_ANA_GENERAL, 0x09); 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci /* 159762306a36Sopenharmony_ci * Sync on rising HSYNC/VSYNC 159862306a36Sopenharmony_ci */ 159962306a36Sopenharmony_ci reg = VIP_CNTRL_3_SYNC_HS; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci /* 160262306a36Sopenharmony_ci * TDA19988 requires high-active sync at input stage, 160362306a36Sopenharmony_ci * so invert low-active sync provided by master encoder here 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NHSYNC) 160662306a36Sopenharmony_ci reg |= VIP_CNTRL_3_H_TGL; 160762306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NVSYNC) 160862306a36Sopenharmony_ci reg |= VIP_CNTRL_3_V_TGL; 160962306a36Sopenharmony_ci reg_write(priv, REG_VIP_CNTRL_3, reg); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci reg_write(priv, REG_VIDFORMAT, 0x00); 161262306a36Sopenharmony_ci reg_write16(priv, REG_REFPIX_MSB, ref_pix); 161362306a36Sopenharmony_ci reg_write16(priv, REG_REFLINE_MSB, ref_line); 161462306a36Sopenharmony_ci reg_write16(priv, REG_NPIX_MSB, n_pix); 161562306a36Sopenharmony_ci reg_write16(priv, REG_NLINE_MSB, n_line); 161662306a36Sopenharmony_ci reg_write16(priv, REG_VS_LINE_STRT_1_MSB, vs1_line_s); 161762306a36Sopenharmony_ci reg_write16(priv, REG_VS_PIX_STRT_1_MSB, vs1_pix_s); 161862306a36Sopenharmony_ci reg_write16(priv, REG_VS_LINE_END_1_MSB, vs1_line_e); 161962306a36Sopenharmony_ci reg_write16(priv, REG_VS_PIX_END_1_MSB, vs1_pix_e); 162062306a36Sopenharmony_ci reg_write16(priv, REG_VS_LINE_STRT_2_MSB, vs2_line_s); 162162306a36Sopenharmony_ci reg_write16(priv, REG_VS_PIX_STRT_2_MSB, vs2_pix_s); 162262306a36Sopenharmony_ci reg_write16(priv, REG_VS_LINE_END_2_MSB, vs2_line_e); 162362306a36Sopenharmony_ci reg_write16(priv, REG_VS_PIX_END_2_MSB, vs2_pix_e); 162462306a36Sopenharmony_ci reg_write16(priv, REG_HS_PIX_START_MSB, hs_pix_s); 162562306a36Sopenharmony_ci reg_write16(priv, REG_HS_PIX_STOP_MSB, hs_pix_e); 162662306a36Sopenharmony_ci reg_write16(priv, REG_VWIN_START_1_MSB, vwin1_line_s); 162762306a36Sopenharmony_ci reg_write16(priv, REG_VWIN_END_1_MSB, vwin1_line_e); 162862306a36Sopenharmony_ci reg_write16(priv, REG_VWIN_START_2_MSB, vwin2_line_s); 162962306a36Sopenharmony_ci reg_write16(priv, REG_VWIN_END_2_MSB, vwin2_line_e); 163062306a36Sopenharmony_ci reg_write16(priv, REG_DE_START_MSB, de_pix_s); 163162306a36Sopenharmony_ci reg_write16(priv, REG_DE_STOP_MSB, de_pix_e); 163262306a36Sopenharmony_ci 163362306a36Sopenharmony_ci if (priv->rev == TDA19988) { 163462306a36Sopenharmony_ci /* let incoming pixels fill the active space (if any) */ 163562306a36Sopenharmony_ci reg_write(priv, REG_ENABLE_SPACE, 0x00); 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci /* 163962306a36Sopenharmony_ci * Always generate sync polarity relative to input sync and 164062306a36Sopenharmony_ci * revert input stage toggled sync at output stage 164162306a36Sopenharmony_ci */ 164262306a36Sopenharmony_ci reg = TBG_CNTRL_1_DWIN_DIS | TBG_CNTRL_1_TGL_EN; 164362306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NHSYNC) 164462306a36Sopenharmony_ci reg |= TBG_CNTRL_1_H_TGL; 164562306a36Sopenharmony_ci if (mode->flags & DRM_MODE_FLAG_NVSYNC) 164662306a36Sopenharmony_ci reg |= TBG_CNTRL_1_V_TGL; 164762306a36Sopenharmony_ci reg_write(priv, REG_TBG_CNTRL_1, reg); 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_ci /* must be last register set: */ 165062306a36Sopenharmony_ci reg_write(priv, REG_TBG_CNTRL_0, 0); 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci /* CEA-861B section 6 says that: 165362306a36Sopenharmony_ci * CEA version 1 (CEA-861) has no support for infoframes. 165462306a36Sopenharmony_ci * CEA version 2 (CEA-861A) supports version 1 AVI infoframes, 165562306a36Sopenharmony_ci * and optional basic audio. 165662306a36Sopenharmony_ci * CEA version 3 (CEA-861B) supports version 1 and 2 AVI infoframes, 165762306a36Sopenharmony_ci * and optional digital audio, with audio infoframes. 165862306a36Sopenharmony_ci * 165962306a36Sopenharmony_ci * Since we only support generation of version 2 AVI infoframes, 166062306a36Sopenharmony_ci * ignore CEA version 2 and below (iow, behave as if we're a 166162306a36Sopenharmony_ci * CEA-861 source.) 166262306a36Sopenharmony_ci */ 166362306a36Sopenharmony_ci priv->supports_infoframes = priv->connector.display_info.cea_rev >= 3; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci if (priv->supports_infoframes) { 166662306a36Sopenharmony_ci /* We need to turn HDMI HDCP stuff on to get audio through */ 166762306a36Sopenharmony_ci reg &= ~TBG_CNTRL_1_DWIN_DIS; 166862306a36Sopenharmony_ci reg_write(priv, REG_TBG_CNTRL_1, reg); 166962306a36Sopenharmony_ci reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1)); 167062306a36Sopenharmony_ci reg_set(priv, REG_TX33, TX33_HDMI); 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci tda998x_write_avi(priv, adjusted_mode); 167362306a36Sopenharmony_ci tda998x_write_vsi(priv, adjusted_mode); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ci if (priv->sink_has_audio) 167662306a36Sopenharmony_ci tda998x_configure_audio(priv); 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_ci mutex_unlock(&priv->audio_mutex); 168062306a36Sopenharmony_ci} 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_cistatic const struct drm_bridge_funcs tda998x_bridge_funcs = { 168362306a36Sopenharmony_ci .attach = tda998x_bridge_attach, 168462306a36Sopenharmony_ci .detach = tda998x_bridge_detach, 168562306a36Sopenharmony_ci .mode_valid = tda998x_bridge_mode_valid, 168662306a36Sopenharmony_ci .disable = tda998x_bridge_disable, 168762306a36Sopenharmony_ci .mode_set = tda998x_bridge_mode_set, 168862306a36Sopenharmony_ci .enable = tda998x_bridge_enable, 168962306a36Sopenharmony_ci}; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci/* I2C driver functions */ 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic int tda998x_get_audio_ports(struct tda998x_priv *priv, 169462306a36Sopenharmony_ci struct device_node *np) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci const u32 *port_data; 169762306a36Sopenharmony_ci u32 size; 169862306a36Sopenharmony_ci int i; 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci port_data = of_get_property(np, "audio-ports", &size); 170162306a36Sopenharmony_ci if (!port_data) 170262306a36Sopenharmony_ci return 0; 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci size /= sizeof(u32); 170562306a36Sopenharmony_ci if (size > 2 * ARRAY_SIZE(priv->audio_port_enable) || size % 2 != 0) { 170662306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, 170762306a36Sopenharmony_ci "Bad number of elements in audio-ports dt-property\n"); 170862306a36Sopenharmony_ci return -EINVAL; 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ci size /= 2; 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci for (i = 0; i < size; i++) { 171462306a36Sopenharmony_ci unsigned int route; 171562306a36Sopenharmony_ci u8 afmt = be32_to_cpup(&port_data[2*i]); 171662306a36Sopenharmony_ci u8 ena_ap = be32_to_cpup(&port_data[2*i+1]); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci switch (afmt) { 171962306a36Sopenharmony_ci case AFMT_I2S: 172062306a36Sopenharmony_ci route = AUDIO_ROUTE_I2S; 172162306a36Sopenharmony_ci break; 172262306a36Sopenharmony_ci case AFMT_SPDIF: 172362306a36Sopenharmony_ci route = AUDIO_ROUTE_SPDIF; 172462306a36Sopenharmony_ci break; 172562306a36Sopenharmony_ci default: 172662306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, 172762306a36Sopenharmony_ci "Bad audio format %u\n", afmt); 172862306a36Sopenharmony_ci return -EINVAL; 172962306a36Sopenharmony_ci } 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci if (!ena_ap) { 173262306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, "invalid zero port config\n"); 173362306a36Sopenharmony_ci continue; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (priv->audio_port_enable[route]) { 173762306a36Sopenharmony_ci dev_err(&priv->hdmi->dev, 173862306a36Sopenharmony_ci "%s format already configured\n", 173962306a36Sopenharmony_ci route == AUDIO_ROUTE_SPDIF ? "SPDIF" : "I2S"); 174062306a36Sopenharmony_ci return -EINVAL; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci priv->audio_port_enable[route] = ena_ap; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci return 0; 174662306a36Sopenharmony_ci} 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_cistatic int tda998x_set_config(struct tda998x_priv *priv, 174962306a36Sopenharmony_ci const struct tda998x_encoder_params *p) 175062306a36Sopenharmony_ci{ 175162306a36Sopenharmony_ci priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(p->swap_a) | 175262306a36Sopenharmony_ci (p->mirr_a ? VIP_CNTRL_0_MIRR_A : 0) | 175362306a36Sopenharmony_ci VIP_CNTRL_0_SWAP_B(p->swap_b) | 175462306a36Sopenharmony_ci (p->mirr_b ? VIP_CNTRL_0_MIRR_B : 0); 175562306a36Sopenharmony_ci priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(p->swap_c) | 175662306a36Sopenharmony_ci (p->mirr_c ? VIP_CNTRL_1_MIRR_C : 0) | 175762306a36Sopenharmony_ci VIP_CNTRL_1_SWAP_D(p->swap_d) | 175862306a36Sopenharmony_ci (p->mirr_d ? VIP_CNTRL_1_MIRR_D : 0); 175962306a36Sopenharmony_ci priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(p->swap_e) | 176062306a36Sopenharmony_ci (p->mirr_e ? VIP_CNTRL_2_MIRR_E : 0) | 176162306a36Sopenharmony_ci VIP_CNTRL_2_SWAP_F(p->swap_f) | 176262306a36Sopenharmony_ci (p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0); 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci if (p->audio_params.format != AFMT_UNUSED) { 176562306a36Sopenharmony_ci unsigned int ratio, route; 176662306a36Sopenharmony_ci bool spdif = p->audio_params.format == AFMT_SPDIF; 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci route = AUDIO_ROUTE_I2S + spdif; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci priv->audio.route = &tda998x_audio_route[route]; 177162306a36Sopenharmony_ci priv->audio.cea = p->audio_params.cea; 177262306a36Sopenharmony_ci priv->audio.sample_rate = p->audio_params.sample_rate; 177362306a36Sopenharmony_ci memcpy(priv->audio.status, p->audio_params.status, 177462306a36Sopenharmony_ci min(sizeof(priv->audio.status), 177562306a36Sopenharmony_ci sizeof(p->audio_params.status))); 177662306a36Sopenharmony_ci priv->audio.ena_ap = p->audio_params.config; 177762306a36Sopenharmony_ci priv->audio.i2s_format = I2S_FORMAT_PHILIPS; 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci ratio = spdif ? 64 : p->audio_params.sample_width * 2; 178062306a36Sopenharmony_ci return tda998x_derive_cts_n(priv, &priv->audio, ratio); 178162306a36Sopenharmony_ci } 178262306a36Sopenharmony_ci 178362306a36Sopenharmony_ci return 0; 178462306a36Sopenharmony_ci} 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_cistatic void tda998x_destroy(struct device *dev) 178762306a36Sopenharmony_ci{ 178862306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 178962306a36Sopenharmony_ci 179062306a36Sopenharmony_ci drm_bridge_remove(&priv->bridge); 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci /* disable all IRQs and free the IRQ handler */ 179362306a36Sopenharmony_ci cec_write(priv, REG_CEC_RXSHPDINTENA, 0); 179462306a36Sopenharmony_ci reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci if (priv->audio_pdev) 179762306a36Sopenharmony_ci platform_device_unregister(priv->audio_pdev); 179862306a36Sopenharmony_ci 179962306a36Sopenharmony_ci if (priv->hdmi->irq) 180062306a36Sopenharmony_ci free_irq(priv->hdmi->irq, priv); 180162306a36Sopenharmony_ci 180262306a36Sopenharmony_ci del_timer_sync(&priv->edid_delay_timer); 180362306a36Sopenharmony_ci cancel_work_sync(&priv->detect_work); 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci i2c_unregister_device(priv->cec); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci cec_notifier_conn_unregister(priv->cec_notify); 180862306a36Sopenharmony_ci} 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_cistatic int tda998x_create(struct device *dev) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 181362306a36Sopenharmony_ci struct device_node *np = client->dev.of_node; 181462306a36Sopenharmony_ci struct i2c_board_info cec_info; 181562306a36Sopenharmony_ci struct tda998x_priv *priv; 181662306a36Sopenharmony_ci u32 video; 181762306a36Sopenharmony_ci int rev_lo, rev_hi, ret; 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 182062306a36Sopenharmony_ci if (!priv) 182162306a36Sopenharmony_ci return -ENOMEM; 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci dev_set_drvdata(dev, priv); 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci mutex_init(&priv->mutex); /* protect the page access */ 182662306a36Sopenharmony_ci mutex_init(&priv->audio_mutex); /* protect access from audio thread */ 182762306a36Sopenharmony_ci mutex_init(&priv->edid_mutex); 182862306a36Sopenharmony_ci INIT_LIST_HEAD(&priv->bridge.list); 182962306a36Sopenharmony_ci init_waitqueue_head(&priv->edid_delay_waitq); 183062306a36Sopenharmony_ci timer_setup(&priv->edid_delay_timer, tda998x_edid_delay_done, 0); 183162306a36Sopenharmony_ci INIT_WORK(&priv->detect_work, tda998x_detect_work); 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci priv->vip_cntrl_0 = VIP_CNTRL_0_SWAP_A(2) | VIP_CNTRL_0_SWAP_B(3); 183462306a36Sopenharmony_ci priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); 183562306a36Sopenharmony_ci priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci /* CEC I2C address bound to TDA998x I2C addr by configuration pins */ 183862306a36Sopenharmony_ci priv->cec_addr = 0x34 + (client->addr & 0x03); 183962306a36Sopenharmony_ci priv->current_page = 0xff; 184062306a36Sopenharmony_ci priv->hdmi = client; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* wake up the device: */ 184362306a36Sopenharmony_ci cec_write(priv, REG_CEC_ENAMODS, 184462306a36Sopenharmony_ci CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI); 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci tda998x_reset(priv); 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci /* read version: */ 184962306a36Sopenharmony_ci rev_lo = reg_read(priv, REG_VERSION_LSB); 185062306a36Sopenharmony_ci if (rev_lo < 0) { 185162306a36Sopenharmony_ci dev_err(dev, "failed to read version: %d\n", rev_lo); 185262306a36Sopenharmony_ci return rev_lo; 185362306a36Sopenharmony_ci } 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci rev_hi = reg_read(priv, REG_VERSION_MSB); 185662306a36Sopenharmony_ci if (rev_hi < 0) { 185762306a36Sopenharmony_ci dev_err(dev, "failed to read version: %d\n", rev_hi); 185862306a36Sopenharmony_ci return rev_hi; 185962306a36Sopenharmony_ci } 186062306a36Sopenharmony_ci 186162306a36Sopenharmony_ci priv->rev = rev_lo | rev_hi << 8; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci /* mask off feature bits: */ 186462306a36Sopenharmony_ci priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */ 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci switch (priv->rev) { 186762306a36Sopenharmony_ci case TDA9989N2: 186862306a36Sopenharmony_ci dev_info(dev, "found TDA9989 n2"); 186962306a36Sopenharmony_ci break; 187062306a36Sopenharmony_ci case TDA19989: 187162306a36Sopenharmony_ci dev_info(dev, "found TDA19989"); 187262306a36Sopenharmony_ci break; 187362306a36Sopenharmony_ci case TDA19989N2: 187462306a36Sopenharmony_ci dev_info(dev, "found TDA19989 n2"); 187562306a36Sopenharmony_ci break; 187662306a36Sopenharmony_ci case TDA19988: 187762306a36Sopenharmony_ci dev_info(dev, "found TDA19988"); 187862306a36Sopenharmony_ci break; 187962306a36Sopenharmony_ci default: 188062306a36Sopenharmony_ci dev_err(dev, "found unsupported device: %04x\n", priv->rev); 188162306a36Sopenharmony_ci return -ENXIO; 188262306a36Sopenharmony_ci } 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci /* after reset, enable DDC: */ 188562306a36Sopenharmony_ci reg_write(priv, REG_DDC_DISABLE, 0x00); 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci /* set clock on DDC channel: */ 188862306a36Sopenharmony_ci reg_write(priv, REG_TX3, 39); 188962306a36Sopenharmony_ci 189062306a36Sopenharmony_ci /* if necessary, disable multi-master: */ 189162306a36Sopenharmony_ci if (priv->rev == TDA19989) 189262306a36Sopenharmony_ci reg_set(priv, REG_I2C_MASTER, I2C_MASTER_DIS_MM); 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci cec_write(priv, REG_CEC_FRO_IM_CLK_CTRL, 189562306a36Sopenharmony_ci CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci /* ensure interrupts are disabled */ 189862306a36Sopenharmony_ci cec_write(priv, REG_CEC_RXSHPDINTENA, 0); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci /* clear pending interrupts */ 190162306a36Sopenharmony_ci cec_read(priv, REG_CEC_RXSHPDINT); 190262306a36Sopenharmony_ci reg_read(priv, REG_INT_FLAGS_0); 190362306a36Sopenharmony_ci reg_read(priv, REG_INT_FLAGS_1); 190462306a36Sopenharmony_ci reg_read(priv, REG_INT_FLAGS_2); 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_ci /* initialize the optional IRQ */ 190762306a36Sopenharmony_ci if (client->irq) { 190862306a36Sopenharmony_ci unsigned long irq_flags; 190962306a36Sopenharmony_ci 191062306a36Sopenharmony_ci /* init read EDID waitqueue and HDP work */ 191162306a36Sopenharmony_ci init_waitqueue_head(&priv->wq_edid); 191262306a36Sopenharmony_ci 191362306a36Sopenharmony_ci irq_flags = 191462306a36Sopenharmony_ci irqd_get_trigger_type(irq_get_irq_data(client->irq)); 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci priv->cec_glue.irq_flags = irq_flags; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci irq_flags |= IRQF_SHARED | IRQF_ONESHOT; 191962306a36Sopenharmony_ci ret = request_threaded_irq(client->irq, NULL, 192062306a36Sopenharmony_ci tda998x_irq_thread, irq_flags, 192162306a36Sopenharmony_ci "tda998x", priv); 192262306a36Sopenharmony_ci if (ret) { 192362306a36Sopenharmony_ci dev_err(dev, "failed to request IRQ#%u: %d\n", 192462306a36Sopenharmony_ci client->irq, ret); 192562306a36Sopenharmony_ci goto err_irq; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci /* enable HPD irq */ 192962306a36Sopenharmony_ci cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD); 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci priv->cec_notify = cec_notifier_conn_register(dev, NULL, NULL); 193362306a36Sopenharmony_ci if (!priv->cec_notify) { 193462306a36Sopenharmony_ci ret = -ENOMEM; 193562306a36Sopenharmony_ci goto fail; 193662306a36Sopenharmony_ci } 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci priv->cec_glue.parent = dev; 193962306a36Sopenharmony_ci priv->cec_glue.data = priv; 194062306a36Sopenharmony_ci priv->cec_glue.init = tda998x_cec_hook_init; 194162306a36Sopenharmony_ci priv->cec_glue.exit = tda998x_cec_hook_exit; 194262306a36Sopenharmony_ci priv->cec_glue.open = tda998x_cec_hook_open; 194362306a36Sopenharmony_ci priv->cec_glue.release = tda998x_cec_hook_release; 194462306a36Sopenharmony_ci 194562306a36Sopenharmony_ci /* 194662306a36Sopenharmony_ci * Some TDA998x are actually two I2C devices merged onto one piece 194762306a36Sopenharmony_ci * of silicon: TDA9989 and TDA19989 combine the HDMI transmitter 194862306a36Sopenharmony_ci * with a slightly modified TDA9950 CEC device. The CEC device 194962306a36Sopenharmony_ci * is at the TDA9950 address, with the address pins strapped across 195062306a36Sopenharmony_ci * to the TDA998x address pins. Hence, it always has the same 195162306a36Sopenharmony_ci * offset. 195262306a36Sopenharmony_ci */ 195362306a36Sopenharmony_ci memset(&cec_info, 0, sizeof(cec_info)); 195462306a36Sopenharmony_ci strscpy(cec_info.type, "tda9950", sizeof(cec_info.type)); 195562306a36Sopenharmony_ci cec_info.addr = priv->cec_addr; 195662306a36Sopenharmony_ci cec_info.platform_data = &priv->cec_glue; 195762306a36Sopenharmony_ci cec_info.irq = client->irq; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci priv->cec = i2c_new_client_device(client->adapter, &cec_info); 196062306a36Sopenharmony_ci if (IS_ERR(priv->cec)) { 196162306a36Sopenharmony_ci ret = PTR_ERR(priv->cec); 196262306a36Sopenharmony_ci goto fail; 196362306a36Sopenharmony_ci } 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* enable EDID read irq: */ 196662306a36Sopenharmony_ci reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD); 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci if (np) { 196962306a36Sopenharmony_ci /* get the device tree parameters */ 197062306a36Sopenharmony_ci ret = of_property_read_u32(np, "video-ports", &video); 197162306a36Sopenharmony_ci if (ret == 0) { 197262306a36Sopenharmony_ci priv->vip_cntrl_0 = video >> 16; 197362306a36Sopenharmony_ci priv->vip_cntrl_1 = video >> 8; 197462306a36Sopenharmony_ci priv->vip_cntrl_2 = video; 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci ret = tda998x_get_audio_ports(priv, np); 197862306a36Sopenharmony_ci if (ret) 197962306a36Sopenharmony_ci goto fail; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if (priv->audio_port_enable[AUDIO_ROUTE_I2S] || 198262306a36Sopenharmony_ci priv->audio_port_enable[AUDIO_ROUTE_SPDIF]) 198362306a36Sopenharmony_ci tda998x_audio_codec_init(priv, &client->dev); 198462306a36Sopenharmony_ci } else if (dev->platform_data) { 198562306a36Sopenharmony_ci ret = tda998x_set_config(priv, dev->platform_data); 198662306a36Sopenharmony_ci if (ret) 198762306a36Sopenharmony_ci goto fail; 198862306a36Sopenharmony_ci } 198962306a36Sopenharmony_ci 199062306a36Sopenharmony_ci priv->bridge.funcs = &tda998x_bridge_funcs; 199162306a36Sopenharmony_ci#ifdef CONFIG_OF 199262306a36Sopenharmony_ci priv->bridge.of_node = dev->of_node; 199362306a36Sopenharmony_ci#endif 199462306a36Sopenharmony_ci 199562306a36Sopenharmony_ci drm_bridge_add(&priv->bridge); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci return 0; 199862306a36Sopenharmony_ci 199962306a36Sopenharmony_cifail: 200062306a36Sopenharmony_ci tda998x_destroy(dev); 200162306a36Sopenharmony_cierr_irq: 200262306a36Sopenharmony_ci return ret; 200362306a36Sopenharmony_ci} 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci/* DRM encoder functions */ 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_cistatic int tda998x_encoder_init(struct device *dev, struct drm_device *drm) 200862306a36Sopenharmony_ci{ 200962306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 201062306a36Sopenharmony_ci u32 crtcs = 0; 201162306a36Sopenharmony_ci int ret; 201262306a36Sopenharmony_ci 201362306a36Sopenharmony_ci if (dev->of_node) 201462306a36Sopenharmony_ci crtcs = drm_of_find_possible_crtcs(drm, dev->of_node); 201562306a36Sopenharmony_ci 201662306a36Sopenharmony_ci /* If no CRTCs were found, fall back to our old behaviour */ 201762306a36Sopenharmony_ci if (crtcs == 0) { 201862306a36Sopenharmony_ci dev_warn(dev, "Falling back to first CRTC\n"); 201962306a36Sopenharmony_ci crtcs = 1 << 0; 202062306a36Sopenharmony_ci } 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci priv->encoder.possible_crtcs = crtcs; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci ret = drm_simple_encoder_init(drm, &priv->encoder, 202562306a36Sopenharmony_ci DRM_MODE_ENCODER_TMDS); 202662306a36Sopenharmony_ci if (ret) 202762306a36Sopenharmony_ci goto err_encoder; 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci ret = drm_bridge_attach(&priv->encoder, &priv->bridge, NULL, 0); 203062306a36Sopenharmony_ci if (ret) 203162306a36Sopenharmony_ci goto err_bridge; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_ci return 0; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_cierr_bridge: 203662306a36Sopenharmony_ci drm_encoder_cleanup(&priv->encoder); 203762306a36Sopenharmony_cierr_encoder: 203862306a36Sopenharmony_ci return ret; 203962306a36Sopenharmony_ci} 204062306a36Sopenharmony_ci 204162306a36Sopenharmony_cistatic int tda998x_bind(struct device *dev, struct device *master, void *data) 204262306a36Sopenharmony_ci{ 204362306a36Sopenharmony_ci struct drm_device *drm = data; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci return tda998x_encoder_init(dev, drm); 204662306a36Sopenharmony_ci} 204762306a36Sopenharmony_ci 204862306a36Sopenharmony_cistatic void tda998x_unbind(struct device *dev, struct device *master, 204962306a36Sopenharmony_ci void *data) 205062306a36Sopenharmony_ci{ 205162306a36Sopenharmony_ci struct tda998x_priv *priv = dev_get_drvdata(dev); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci drm_encoder_cleanup(&priv->encoder); 205462306a36Sopenharmony_ci} 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_cistatic const struct component_ops tda998x_ops = { 205762306a36Sopenharmony_ci .bind = tda998x_bind, 205862306a36Sopenharmony_ci .unbind = tda998x_unbind, 205962306a36Sopenharmony_ci}; 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_cistatic int 206262306a36Sopenharmony_citda998x_probe(struct i2c_client *client) 206362306a36Sopenharmony_ci{ 206462306a36Sopenharmony_ci int ret; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { 206762306a36Sopenharmony_ci dev_warn(&client->dev, "adapter does not support I2C\n"); 206862306a36Sopenharmony_ci return -EIO; 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci 207162306a36Sopenharmony_ci ret = tda998x_create(&client->dev); 207262306a36Sopenharmony_ci if (ret) 207362306a36Sopenharmony_ci return ret; 207462306a36Sopenharmony_ci 207562306a36Sopenharmony_ci ret = component_add(&client->dev, &tda998x_ops); 207662306a36Sopenharmony_ci if (ret) 207762306a36Sopenharmony_ci tda998x_destroy(&client->dev); 207862306a36Sopenharmony_ci return ret; 207962306a36Sopenharmony_ci} 208062306a36Sopenharmony_ci 208162306a36Sopenharmony_cistatic void tda998x_remove(struct i2c_client *client) 208262306a36Sopenharmony_ci{ 208362306a36Sopenharmony_ci component_del(&client->dev, &tda998x_ops); 208462306a36Sopenharmony_ci tda998x_destroy(&client->dev); 208562306a36Sopenharmony_ci} 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci#ifdef CONFIG_OF 208862306a36Sopenharmony_cistatic const struct of_device_id tda998x_dt_ids[] = { 208962306a36Sopenharmony_ci { .compatible = "nxp,tda998x", }, 209062306a36Sopenharmony_ci { } 209162306a36Sopenharmony_ci}; 209262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tda998x_dt_ids); 209362306a36Sopenharmony_ci#endif 209462306a36Sopenharmony_ci 209562306a36Sopenharmony_cistatic const struct i2c_device_id tda998x_ids[] = { 209662306a36Sopenharmony_ci { "tda998x", 0 }, 209762306a36Sopenharmony_ci { } 209862306a36Sopenharmony_ci}; 209962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, tda998x_ids); 210062306a36Sopenharmony_ci 210162306a36Sopenharmony_cistatic struct i2c_driver tda998x_driver = { 210262306a36Sopenharmony_ci .probe = tda998x_probe, 210362306a36Sopenharmony_ci .remove = tda998x_remove, 210462306a36Sopenharmony_ci .driver = { 210562306a36Sopenharmony_ci .name = "tda998x", 210662306a36Sopenharmony_ci .of_match_table = of_match_ptr(tda998x_dt_ids), 210762306a36Sopenharmony_ci }, 210862306a36Sopenharmony_ci .id_table = tda998x_ids, 210962306a36Sopenharmony_ci}; 211062306a36Sopenharmony_ci 211162306a36Sopenharmony_cimodule_i2c_driver(tda998x_driver); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ciMODULE_AUTHOR("Rob Clark <robdclark@gmail.com"); 211462306a36Sopenharmony_ciMODULE_DESCRIPTION("NXP Semiconductors TDA998X HDMI Encoder"); 211562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2116