Files
android_kernel_eebbk_sm6150/drivers/video/fbdev/msm/mdss_dp.h
T

1202 lines
29 KiB
C

/* Copyright (c) 2012-2014, 2016-2017, 2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef MDSS_DP_H
#define MDSS_DP_H
#include <linux/list.h>
#include <linux/mdss_io_util.h>
#include <linux/irqreturn.h>
#include <linux/pinctrl/consumer.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/usb/usbpd.h>
#include "mdss_hdmi_util.h"
#include "mdss_hdmi_edid.h"
#include "video/msm_hdmi_modes.h"
#include "mdss.h"
#include "mdss_panel.h"
#define dp_read(offset) readl_relaxed((offset))
#define dp_write(offset, data) writel_relaxed((data), (offset))
#define AUX_CMD_FIFO_LEN 144
#define AUX_CMD_MAX 16
#define AUX_CMD_I2C_MAX 128
#define AUX_CFG_LEN 10
#define EDP_PORT_MAX 1
#define EDP_SINK_CAP_LEN 16
/* 4 bits of aux command */
#define EDP_CMD_AUX_WRITE 0x8
#define EDP_CMD_AUX_READ 0x9
/* 4 bits of i2c command */
#define EDP_CMD_I2C_MOT 0x4 /* i2c middle of transaction */
#define EDP_CMD_I2C_WRITE 0x0
#define EDP_CMD_I2C_READ 0x1
#define EDP_CMD_I2C_STATUS 0x2 /* i2c write status request */
/* cmd reply: bit 0, 1 for aux */
#define EDP_AUX_ACK 0x0
#define EDP_AUX_NACK 0x1
#define EDP_AUX_DEFER 0x2
/* cmd reply: bit 2, 3 for i2c */
#define EDP_I2C_ACK 0x0
#define EDP_I2C_NACK 0x4
#define EDP_I2C_DEFER 0x8
#define EDP_CMD_TIMEOUT 400 /* us */
#define EDP_CMD_LEN 16
#define EDP_INTR_ACK_SHIFT 1
#define EDP_INTR_MASK_SHIFT 2
/* isr */
#define EDP_INTR_HPD BIT(0)
#define EDP_INTR_AUX_I2C_DONE BIT(3)
#define EDP_INTR_WRONG_ADDR BIT(6)
#define EDP_INTR_TIMEOUT BIT(9)
#define EDP_INTR_NACK_DEFER BIT(12)
#define EDP_INTR_WRONG_DATA_CNT BIT(15)
#define EDP_INTR_I2C_NACK BIT(18)
#define EDP_INTR_I2C_DEFER BIT(21)
#define EDP_INTR_PLL_UNLOCKED BIT(24)
#define EDP_INTR_PHY_AUX_ERR BIT(27)
#define EDP_INTR_STATUS1 \
(EDP_INTR_AUX_I2C_DONE| \
EDP_INTR_WRONG_ADDR | EDP_INTR_TIMEOUT | \
EDP_INTR_NACK_DEFER | EDP_INTR_WRONG_DATA_CNT | \
EDP_INTR_I2C_NACK | EDP_INTR_I2C_DEFER | \
EDP_INTR_PLL_UNLOCKED | EDP_INTR_PHY_AUX_ERR)
#define EDP_INTR_MASK1 (EDP_INTR_STATUS1 << 2)
#define EDP_INTR_READY_FOR_VIDEO BIT(0)
#define EDP_INTR_IDLE_PATTERNs_SENT BIT(3)
#define EDP_INTR_FRAME_END BIT(6)
#define EDP_INTR_CRC_UPDATED BIT(9)
#define EDP_INTR_STATUS2 \
(EDP_INTR_READY_FOR_VIDEO | EDP_INTR_IDLE_PATTERNs_SENT | \
EDP_INTR_FRAME_END | EDP_INTR_CRC_UPDATED)
#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2)
#define DP_ENUM_STR(x) #x
struct edp_buf {
char *start; /* buffer start addr */
char *end; /* buffer end addr */
int size; /* size of buffer */
char *data; /* data pointer */
int len; /* dara length */
char trans_num; /* transaction number */
char i2c; /* 1 == i2c cmd, 0 == native cmd */
bool no_send_addr;
bool no_send_stop;
};
/* USBPD-TypeC specific Macros */
#define VDM_VERSION 0x0
#define USB_C_DP_SID 0xFF01
enum dp_pm_type {
DP_CORE_PM,
DP_CTRL_PM,
DP_PHY_PM,
DP_MAX_PM
};
#define PIN_ASSIGN_A BIT(0)
#define PIN_ASSIGN_B BIT(1)
#define PIN_ASSIGN_C BIT(2)
#define PIN_ASSIGN_D BIT(3)
#define PIN_ASSIGN_E BIT(4)
#define PIN_ASSIGN_F BIT(5)
#define SVDM_HDR(svid, ver, mode, cmd_type, cmd) \
(((svid) << 16) | (1 << 15) | ((ver) << 13) \
| ((mode) << 8) | ((cmd_type) << 6) | (cmd))
/* DP specific VDM commands */
#define DP_VDM_STATUS 0x10
#define DP_VDM_CONFIGURE 0x11
enum dp_port_cap {
PORT_NONE = 0,
PORT_UFP_D,
PORT_DFP_D,
PORT_D_UFP_D,
};
struct usbpd_dp_capabilities {
u32 response;
enum dp_port_cap s_port;
bool receptacle_state;
u8 ulink_pin_config;
u8 dlink_pin_config;
};
struct usbpd_dp_status {
u32 response;
enum dp_port_cap c_port;
bool low_pow_st;
bool adaptor_dp_en;
bool multi_func;
bool switch_to_usb_config;
bool exit_dp_mode;
bool hpd_high;
bool hpd_irq;
};
enum dp_alt_mode_state {
UNKNOWN_STATE = 0,
ALT_MODE_INIT_STATE = BIT(0),
DISCOVER_MODES_DONE = BIT(1),
ENTER_MODE_DONE = BIT(2),
DP_STATUS_DONE = BIT(3),
DP_CONFIGURE_DONE = BIT(4),
};
struct dp_alt_mode {
struct usbpd_dp_capabilities dp_cap;
struct usbpd_dp_status dp_status;
u32 usbpd_dp_config;
enum dp_alt_mode_state current_state;
};
#define DPCD_ENHANCED_FRAME BIT(0)
#define DPCD_TPS3 BIT(1)
#define DPCD_MAX_DOWNSPREAD_0_5 BIT(2)
#define DPCD_NO_AUX_HANDSHAKE BIT(3)
#define DPCD_PORT_0_EDID_PRESENTED BIT(4)
#define DPCD_PORT_1_EDID_PRESENTED BIT(5)
/* event */
#define EV_EDP_AUX_SETUP BIT(0)
#define EV_EDID_READ BIT(1)
#define EV_DPCD_CAP_READ BIT(2)
#define EV_DPCD_STATUS_READ BIT(3)
#define EV_LINK_TRAIN BIT(4)
#define EV_IDLE_PATTERNS_SENT BIT(5)
#define EV_VIDEO_READY BIT(6)
#define EV_USBPD_DISCOVER_MODES BIT(7)
#define EV_USBPD_ENTER_MODE BIT(8)
#define EV_USBPD_DP_STATUS BIT(9)
#define EV_USBPD_DP_CONFIGURE BIT(10)
#define EV_USBPD_CC_PIN_POLARITY BIT(11)
#define EV_USBPD_EXIT_MODE BIT(12)
#define EV_USBPD_ATTENTION BIT(13)
/* dp state ctrl */
#define ST_TRAIN_PATTERN_1 BIT(0)
#define ST_TRAIN_PATTERN_2 BIT(1)
#define ST_TRAIN_PATTERN_3 BIT(2)
#define ST_TRAIN_PATTERN_4 BIT(3)
#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(4)
#define ST_PRBS7 BIT(5)
#define ST_CUSTOM_80_BIT_PATTERN BIT(6)
#define ST_SEND_VIDEO BIT(7)
#define ST_PUSH_IDLE BIT(8)
#define DP_LINK_RATE_162 6 /* 1.62G = 270M * 6 */
#define DP_LINK_RATE_270 10 /* 2.70G = 270M * 10 */
#define DP_LINK_RATE_540 20 /* 5.40G = 270M * 20 */
#define DP_LINK_RATE_MAX DP_LINK_RATE_540
#define DP_LINK_RATE_MULTIPLIER 27000000
#define DP_KHZ_TO_HZ 1000
#define DP_MAX_PIXEL_CLK_KHZ 675000
enum downstream_port_type {
DSP_TYPE_DP = 0x00,
DSP_TYPE_VGA,
DSP_TYPE_DVI_HDMI_DPPP,
DSP_TYPE_OTHER,
};
static inline char *mdss_dp_dsp_type_to_string(u32 dsp_type)
{
switch (dsp_type) {
case DSP_TYPE_DP:
return DP_ENUM_STR(DSP_TYPE_DP);
case DSP_TYPE_VGA:
return DP_ENUM_STR(DSP_TYPE_VGA);
case DSP_TYPE_DVI_HDMI_DPPP:
return DP_ENUM_STR(DSP_TYPE_DVI_HDMI_DPPP);
case DSP_TYPE_OTHER:
return DP_ENUM_STR(DSP_TYPE_OTHER);
default:
return "unknown";
}
}
struct downstream_port_config {
/* Byte 02205h */
bool dsp_present;
enum downstream_port_type dsp_type;
bool format_conversion;
bool detailed_cap_info_available;
/* Byte 02207h */
u32 dsp_count;
bool msa_timing_par_ignored;
bool oui_support;
};
#define DP_MAX_DS_PORT_COUNT 2
struct dpcd_cap {
char major;
char minor;
char max_lane_count;
char num_rx_port;
char i2c_speed_ctrl;
char scrambler_reset;
char enhanced_frame;
u32 max_link_rate; /* 162, 270 and 540 Mb, divided by 10 */
u32 flags;
u32 rx_port_buf_size[DP_MAX_DS_PORT_COUNT];
u32 training_read_interval;/* us */
struct downstream_port_config downstream_port;
};
struct dpcd_link_status {
char lane_01_status;
char lane_23_status;
char interlane_align_done;
char downstream_port_status_changed;
char link_status_updated;
char port_0_in_sync;
char port_1_in_sync;
char req_voltage_swing[4];
char req_pre_emphasis[4];
};
struct dpcd_test_request {
u32 test_requested;
u32 test_link_rate;
u32 test_lane_count;
u32 phy_test_pattern_sel;
u32 test_video_pattern;
u32 test_bit_depth;
u32 test_dyn_range;
u32 test_h_total;
u32 test_v_total;
u32 test_h_start;
u32 test_v_start;
u32 test_hsync_pol;
u32 test_hsync_width;
u32 test_vsync_pol;
u32 test_vsync_width;
u32 test_h_width;
u32 test_v_height;
u32 test_rr_d;
u32 test_rr_n;
u32 test_audio_sampling_rate;
u32 test_audio_channel_count;
u32 test_audio_pattern_type;
u32 test_audio_period_ch_1;
u32 test_audio_period_ch_2;
u32 test_audio_period_ch_3;
u32 test_audio_period_ch_4;
u32 test_audio_period_ch_5;
u32 test_audio_period_ch_6;
u32 test_audio_period_ch_7;
u32 test_audio_period_ch_8;
u32 response;
};
struct dpcd_sink_count {
u32 count;
bool cp_ready;
};
struct display_timing_desc {
u32 pclk;
u32 h_addressable; /* addressable + boder = active */
u32 h_border;
u32 h_blank; /* fporch + bporch + sync_pulse = blank */
u32 h_fporch;
u32 h_sync_pulse;
u32 v_addressable; /* addressable + boder = active */
u32 v_border;
u32 v_blank; /* fporch + bporch + sync_pulse = blank */
u32 v_fporch;
u32 v_sync_pulse;
u32 width_mm;
u32 height_mm;
u32 interlaced;
u32 stereo;
u32 sync_type;
u32 sync_separate;
u32 vsync_pol;
u32 hsync_pol;
};
#define EDID_DISPLAY_PORT_SUPPORT 0x05
struct edp_edid {
char id_name[4];
short id_product;
char version;
char revision;
char video_intf; /* dp == 0x5 */
char color_depth; /* 6, 8, 10, 12 and 14 bits */
char color_format; /* RGB 4:4:4, YCrCb 4:4:4, Ycrcb 4:2:2 */
char dpm; /* display power management */
char sync_digital; /* 1 = digital */
char sync_separate; /* 1 = separate */
char vsync_pol; /* 0 = negative, 1 = positive */
char hsync_pol; /* 0 = negative, 1 = positive */
char ext_block_cnt;
struct display_timing_desc timing[4];
};
struct dp_statistic {
u32 intr_hpd;
u32 intr_aux_i2c_done;
u32 intr_wrong_addr;
u32 intr_tout;
u32 intr_nack_defer;
u32 intr_wrong_data_cnt;
u32 intr_i2c_nack;
u32 intr_i2c_defer;
u32 intr_pll_unlock;
u32 intr_crc_update;
u32 intr_frame_end;
u32 intr_idle_pattern_sent;
u32 intr_ready_for_video;
u32 aux_i2c_tx;
u32 aux_i2c_rx;
u32 aux_native_tx;
u32 aux_native_rx;
};
enum dpcd_link_voltage_level {
DPCD_LINK_VOLTAGE_LEVEL_0 = 0,
DPCD_LINK_VOLTAGE_LEVEL_1 = 1,
DPCD_LINK_VOLTAGE_LEVEL_2 = 2,
DPCD_LINK_VOLTAGE_MAX = DPCD_LINK_VOLTAGE_LEVEL_2,
};
enum dpcd_link_preemaphasis_level {
DPCD_LINK_PRE_EMPHASIS_LEVEL_0 = 0,
DPCD_LINK_PRE_EMPHASIS_LEVEL_1 = 1,
DPCD_LINK_PRE_EMPHASIS_LEVEL_2 = 2,
DPCD_LINK_PRE_EMPHASIS_MAX = DPCD_LINK_PRE_EMPHASIS_LEVEL_2,
};
struct dp_pinctrl_res {
struct pinctrl *pinctrl;
struct pinctrl_state *state_active;
struct pinctrl_state *state_hpd_active;
struct pinctrl_state *state_suspend;
};
irqreturn_t dp_isr(int irq, void *ptr);
struct dp_hdcp {
void *data;
struct hdcp_ops *ops;
void *hdcp1;
void *hdcp2;
int enc_lvl;
bool auth_state;
bool hdcp1_present;
bool hdcp2_present;
bool feature_enabled;
};
struct mdss_dp_event {
struct mdss_dp_drv_pdata *dp;
u32 id;
};
#define MDSS_DP_EVENT_Q_MAX 4
struct mdss_dp_event_data {
wait_queue_head_t event_q;
u32 pndx;
u32 gndx;
struct mdss_dp_event event_list[MDSS_DP_EVENT_Q_MAX];
spinlock_t event_lock;
};
struct mdss_dp_crc_data {
bool en;
u32 r_cr;
u32 g_y;
u32 b_cb;
};
#define MDSS_DP_MAX_PHY_CFG_VALUE_CNT 3
struct mdss_dp_phy_cfg {
u32 cfg_cnt;
u32 current_index;
u32 offset;
u32 lut[MDSS_DP_MAX_PHY_CFG_VALUE_CNT];
};
/* PHY AUX config registers */
enum dp_phy_aux_config_type {
PHY_AUX_CFG0,
PHY_AUX_CFG1,
PHY_AUX_CFG2,
PHY_AUX_CFG3,
PHY_AUX_CFG4,
PHY_AUX_CFG5,
PHY_AUX_CFG6,
PHY_AUX_CFG7,
PHY_AUX_CFG8,
PHY_AUX_CFG9,
PHY_AUX_CFG_MAX,
};
static inline const char *mdss_dp_get_phy_aux_config_property(u32 cfg_type)
{
switch (cfg_type) {
case PHY_AUX_CFG0:
return "qcom,aux-cfg0-settings";
case PHY_AUX_CFG1:
return "qcom,aux-cfg1-settings";
case PHY_AUX_CFG2:
return "qcom,aux-cfg2-settings";
case PHY_AUX_CFG3:
return "qcom,aux-cfg3-settings";
case PHY_AUX_CFG4:
return "qcom,aux-cfg4-settings";
case PHY_AUX_CFG5:
return "qcom,aux-cfg5-settings";
case PHY_AUX_CFG6:
return "qcom,aux-cfg6-settings";
case PHY_AUX_CFG7:
return "qcom,aux-cfg7-settings";
case PHY_AUX_CFG8:
return "qcom,aux-cfg8-settings";
case PHY_AUX_CFG9:
return "qcom,aux-cfg9-settings";
default:
return "unknown";
}
}
static inline char *mdss_dp_phy_aux_config_type_to_string(u32 cfg_type)
{
switch (cfg_type) {
case PHY_AUX_CFG0:
return DP_ENUM_STR(PHY_AUX_CFG0);
case PHY_AUX_CFG1:
return DP_ENUM_STR(PHY_AUX_CFG1);
case PHY_AUX_CFG2:
return DP_ENUM_STR(PHY_AUX_CFG2);
case PHY_AUX_CFG3:
return DP_ENUM_STR(PHY_AUX_CFG3);
case PHY_AUX_CFG4:
return DP_ENUM_STR(PHY_AUX_CFG4);
case PHY_AUX_CFG5:
return DP_ENUM_STR(PHY_AUX_CFG5);
case PHY_AUX_CFG6:
return DP_ENUM_STR(PHY_AUX_CFG6);
case PHY_AUX_CFG7:
return DP_ENUM_STR(PHY_AUX_CFG7);
case PHY_AUX_CFG8:
return DP_ENUM_STR(PHY_AUX_CFG8);
case PHY_AUX_CFG9:
return DP_ENUM_STR(PHY_AUX_CFG9);
default:
return "unknown";
}
}
enum dp_aux_transaction {
DP_AUX_WRITE,
DP_AUX_READ
};
static inline char *mdss_dp_aux_transaction_to_string(u32 transaction)
{
switch (transaction) {
case DP_AUX_WRITE:
return DP_ENUM_STR(DP_AUX_WRITE);
case DP_AUX_READ:
return DP_ENUM_STR(DP_AUX_READ);
default:
return "unknown";
}
}
struct mdss_dp_drv_pdata {
/* device driver */
int (*on)(struct mdss_panel_data *pdata);
int (*off)(struct mdss_panel_data *pdata);
struct platform_device *pdev;
struct platform_device *ext_pdev;
struct usbpd *pd;
enum plug_orientation orientation;
struct dp_hdcp hdcp;
struct usbpd_svid_handler svid_handler;
struct dp_alt_mode alt_mode;
bool dp_initialized;
struct msm_ext_disp_init_data ext_audio_data;
struct mutex emutex;
int clk_cnt;
int cont_splash;
bool inited;
bool core_power;
bool core_clks_on;
bool link_clks_on;
bool power_on;
u32 suspend_vic;
bool hpd;
bool psm_enabled;
bool audio_test_req;
bool dpcd_read_required;
/* dp specific */
unsigned char *base;
struct dss_io_data ctrl_io;
struct dss_io_data phy_io;
struct dss_io_data tcsr_reg_io;
struct dss_io_data dp_cc_io;
struct dss_io_data qfprom_io;
struct dss_io_data hdcp_io;
u32 phy_reg_offset;
int base_size;
unsigned char *mmss_cc_base;
bool override_config;
u32 mask1;
u32 mask2;
struct mdss_dp_crc_data ctl_crc;
struct mdss_dp_crc_data sink_crc;
struct mdss_panel_data panel_data;
struct mdss_util_intf *mdss_util;
int dp_on_cnt;
int dp_off_cnt;
u32 pixel_rate; /* KHz */
u32 aux_rate;
char link_rate; /* X 27000000 for real rate */
char lane_cnt;
char train_link_rate; /* X 27000000 for real rate */
char train_lane_cnt;
u8 *edid_buf;
u32 edid_buf_size;
struct edp_edid edid;
struct dpcd_cap dpcd;
/* DP Pixel clock RCG and PLL parent */
struct clk *pixel_clk_rcg;
struct clk *pixel_parent;
struct clk *pixel_clk_two_div;
struct clk *pixel_clk_four_div;
/* regulators */
struct dss_module_power power_data[DP_MAX_PM];
struct dp_pinctrl_res pin_res;
int aux_sel_gpio;
int aux_sel_gpio_output;
int aux_en_gpio;
int usbplug_cc_gpio;
int hpd_gpio;
int clk_on;
/* hpd */
int gpio_panel_hpd;
enum of_gpio_flags hpd_flags;
int hpd_irq;
/* aux */
struct completion aux_comp;
struct completion idle_comp;
struct completion video_comp;
struct completion notification_comp;
struct mutex aux_mutex;
struct mutex train_mutex;
struct mutex attention_lock;
struct mutex hdcp_mutex;
bool cable_connected;
u32 s3d_mode;
u32 aux_cmd_busy;
u32 aux_cmd_i2c;
int aux_trans_num;
int aux_error_num;
u32 aux_ctrl_reg;
struct edp_buf txp;
struct edp_buf rxp;
char txbuf[256];
char rxbuf[256];
struct dpcd_link_status link_status;
char v_level;
char p_level;
/* transfer unit */
char tu_desired;
char valid_boundary;
char delay_start;
struct dp_statistic dp_stat;
bool hpd_irq_on;
u32 hpd_notification_status;
atomic_t notification_pending;
struct mdss_dp_event_data dp_event;
struct task_struct *ev_thread;
/* dt settings */
char l_map[4];
struct mdss_dp_phy_cfg aux_cfg[PHY_AUX_CFG_MAX];
struct workqueue_struct *workq;
struct delayed_work hdcp_cb_work;
spinlock_t lock;
/* struct switch_dev sdev; BALDEV */
struct kobject *kobj;
u32 max_pclk_khz;
u32 vic;
u32 new_vic;
u16 dpcd_version;
int fb_node;
int hdcp_status;
void *audio_data;
bool hpd_notify_state;
struct dpcd_test_request test_data;
struct dpcd_sink_count sink_count;
struct dpcd_sink_count prev_sink_count;
struct list_head attention_head;
};
enum dp_phy_lane_num {
DP_PHY_LN0 = 0,
DP_PHY_LN1 = 1,
DP_PHY_LN2 = 2,
DP_PHY_LN3 = 3,
DP_MAX_PHY_LN = 4,
};
enum dp_mainlink_lane_num {
DP_ML0 = 0,
DP_ML1 = 1,
DP_ML2 = 2,
DP_ML3 = 3,
};
enum dp_lane_count {
DP_LANE_COUNT_1 = 1,
DP_LANE_COUNT_2 = 2,
DP_LANE_COUNT_4 = 4,
};
enum audio_pattern_type {
AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00,
AUDIO_TEST_PATTERN_SAWTOOTH = 0x01,
};
static inline char *mdss_dp_get_audio_test_pattern(u32 pattern)
{
switch (pattern) {
case AUDIO_TEST_PATTERN_OPERATOR_DEFINED:
return DP_ENUM_STR(AUDIO_TEST_PATTERN_OPERATOR_DEFINED);
case AUDIO_TEST_PATTERN_SAWTOOTH:
return DP_ENUM_STR(AUDIO_TEST_PATTERN_SAWTOOTH);
default:
return "unknown";
}
}
enum audio_sample_rate {
AUDIO_SAMPLE_RATE_32_KHZ = 0x00,
AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01,
AUDIO_SAMPLE_RATE_48_KHZ = 0x02,
AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03,
AUDIO_SAMPLE_RATE_96_KHZ = 0x04,
AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05,
AUDIO_SAMPLE_RATE_192_KHZ = 0x06,
};
static inline char *mdss_dp_get_audio_sample_rate(u32 rate)
{
switch (rate) {
case AUDIO_SAMPLE_RATE_32_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_32_KHZ);
case AUDIO_SAMPLE_RATE_44_1_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_44_1_KHZ);
case AUDIO_SAMPLE_RATE_48_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_48_KHZ);
case AUDIO_SAMPLE_RATE_88_2_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_88_2_KHZ);
case AUDIO_SAMPLE_RATE_96_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_96_KHZ);
case AUDIO_SAMPLE_RATE_176_4_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_176_4_KHZ);
case AUDIO_SAMPLE_RATE_192_KHZ:
return DP_ENUM_STR(AUDIO_SAMPLE_RATE_192_KHZ);
default:
return "unknown";
}
}
enum phy_test_pattern {
PHY_TEST_PATTERN_NONE,
PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING,
PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT,
PHY_TEST_PATTERN_PRBS7,
PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN,
PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN,
};
static inline char *mdss_dp_get_phy_test_pattern(u32 phy_test_pattern_sel)
{
switch (phy_test_pattern_sel) {
case PHY_TEST_PATTERN_NONE:
return DP_ENUM_STR(PHY_TEST_PATTERN_NONE);
case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
return DP_ENUM_STR(PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING);
case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
return DP_ENUM_STR(PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT);
case PHY_TEST_PATTERN_PRBS7:
return DP_ENUM_STR(PHY_TEST_PATTERN_PRBS7);
case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
return DP_ENUM_STR(PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN);
case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
return DP_ENUM_STR(PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN);
default:
return "unknown";
}
}
static inline bool mdss_dp_is_phy_test_pattern_supported(
u32 phy_test_pattern_sel)
{
switch (phy_test_pattern_sel) {
case PHY_TEST_PATTERN_NONE:
case PHY_TEST_PATTERN_D10_2_NO_SCRAMBLING:
case PHY_TEST_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT:
case PHY_TEST_PATTERN_PRBS7:
case PHY_TEST_PATTERN_80_BIT_CUSTOM_PATTERN:
case PHY_TEST_PATTERN_HBR2_CTS_EYE_PATTERN:
return true;
default:
return false;
}
}
enum dp_aux_error {
EDP_AUX_ERR_NONE = 0,
EDP_AUX_ERR_ADDR = -1,
EDP_AUX_ERR_TOUT = -2,
EDP_AUX_ERR_NACK = -3,
EDP_AUX_ERR_DEFER = -4,
EDP_AUX_ERR_NACK_DEFER = -5,
EDP_AUX_ERR_PHY = -6,
};
static inline char *mdss_dp_get_aux_error(u32 aux_error)
{
switch (aux_error) {
case EDP_AUX_ERR_NONE:
return DP_ENUM_STR(EDP_AUX_ERR_NONE);
case EDP_AUX_ERR_ADDR:
return DP_ENUM_STR(EDP_AUX_ERR_ADDR);
case EDP_AUX_ERR_TOUT:
return DP_ENUM_STR(EDP_AUX_ERR_TOUT);
case EDP_AUX_ERR_NACK:
return DP_ENUM_STR(EDP_AUX_ERR_NACK);
case EDP_AUX_ERR_DEFER:
return DP_ENUM_STR(EDP_AUX_ERR_DEFER);
case EDP_AUX_ERR_NACK_DEFER:
return DP_ENUM_STR(EDP_AUX_ERR_NACK_DEFER);
default:
return "unknown";
}
}
enum test_response {
TEST_ACK = 0x1,
TEST_NACK = 0x2,
TEST_EDID_CHECKSUM_WRITE = 0x4,
};
static inline char *mdss_dp_get_test_response(u32 test_response)
{
switch (test_response) {
case TEST_NACK:
return DP_ENUM_STR(TEST_NACK);
case TEST_ACK:
return DP_ENUM_STR(TEST_ACK);
case TEST_EDID_CHECKSUM_WRITE:
return DP_ENUM_STR(TEST_EDID_CHECKSUM_WRITE);
default:
return "unknown";
}
}
enum test_type {
UNKNOWN_TEST = 0,
TEST_LINK_TRAINING = 0x1,
TEST_VIDEO_PATTERN = 0x2,
PHY_TEST_PATTERN = 0x8,
TEST_EDID_READ = 0x4,
TEST_AUDIO_PATTERN = 32,
TEST_AUDIO_DISABLED_VIDEO = 64,
};
static inline char *mdss_dp_get_test_name(u32 test_requested)
{
switch (test_requested) {
case TEST_LINK_TRAINING: return DP_ENUM_STR(TEST_LINK_TRAINING);
case TEST_VIDEO_PATTERN: return DP_ENUM_STR(TEST_VIDEO_PATTERN);
case PHY_TEST_PATTERN: return DP_ENUM_STR(PHY_TEST_PATTERN);
case TEST_EDID_READ: return DP_ENUM_STR(TEST_EDID_READ);
case TEST_AUDIO_PATTERN: return DP_ENUM_STR(TEST_AUDIO_PATTERN);
default: return "unknown";
}
}
static inline const char *__mdss_dp_pm_name(enum dp_pm_type module)
{
switch (module) {
case DP_CORE_PM: return "DP_CORE_PM";
case DP_CTRL_PM: return "DP_CTRL_PM";
case DP_PHY_PM: return "DP_PHY_PM";
default: return "???";
}
}
static inline const char *__mdss_dp_pm_supply_node_name(
enum dp_pm_type module)
{
switch (module) {
case DP_CORE_PM: return "qcom,core-supply-entries";
case DP_CTRL_PM: return "qcom,ctrl-supply-entries";
case DP_PHY_PM: return "qcom,phy-supply-entries";
default: return "???";
}
}
static inline char *mdss_dp_ev_event_to_string(int event)
{
switch (event) {
case EV_EDP_AUX_SETUP:
return DP_ENUM_STR(EV_EDP_AUX_SETUP);
case EV_EDID_READ:
return DP_ENUM_STR(EV_EDID_READ);
case EV_DPCD_CAP_READ:
return DP_ENUM_STR(EV_DPCD_CAP_READ);
case EV_DPCD_STATUS_READ:
return DP_ENUM_STR(EV_DPCD_STATUS_READ);
case EV_LINK_TRAIN:
return DP_ENUM_STR(EV_LINK_TRAIN);
case EV_IDLE_PATTERNS_SENT:
return DP_ENUM_STR(EV_IDLE_PATTERNS_SENT);
case EV_VIDEO_READY:
return DP_ENUM_STR(EV_VIDEO_READY);
case EV_USBPD_DISCOVER_MODES:
return DP_ENUM_STR(EV_USBPD_DISCOVER_MODES);
case EV_USBPD_ENTER_MODE:
return DP_ENUM_STR(EV_USBPD_ENTER_MODE);
case EV_USBPD_DP_STATUS:
return DP_ENUM_STR(EV_USBPD_DP_STATUS);
case EV_USBPD_DP_CONFIGURE:
return DP_ENUM_STR(EV_USBPD_DP_CONFIGURE);
case EV_USBPD_CC_PIN_POLARITY:
return DP_ENUM_STR(EV_USBPD_CC_PIN_POLARITY);
case EV_USBPD_EXIT_MODE:
return DP_ENUM_STR(EV_USBPD_EXIT_MODE);
case EV_USBPD_ATTENTION:
return DP_ENUM_STR(EV_USBPD_ATTENTION);
default:
return "unknown";
}
}
enum dynamic_range {
DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
DP_DYNAMIC_RANGE_RGB_CEA = 0x01,
DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF,
};
static inline char *mdss_dp_dynamic_range_to_string(u32 dr)
{
switch (dr) {
case DP_DYNAMIC_RANGE_RGB_VESA:
return DP_ENUM_STR(DP_DYNAMIC_RANGE_RGB_VESA);
case DP_DYNAMIC_RANGE_RGB_CEA:
return DP_ENUM_STR(DP_DYNAMIC_RANGE_RGB_CEA);
case DP_DYNAMIC_RANGE_UNKNOWN:
default:
return "unknown";
}
}
/**
* mdss_dp_is_dynamic_range_valid() - validates the dynamic range
* @bit_depth: the dynamic range value to be checked
*
* Returns true if the dynamic range value is supported.
*/
static inline bool mdss_dp_is_dynamic_range_valid(u32 dr)
{
switch (dr) {
case DP_DYNAMIC_RANGE_RGB_VESA:
case DP_DYNAMIC_RANGE_RGB_CEA:
return true;
default:
return false;
}
}
enum test_bit_depth {
DP_TEST_BIT_DEPTH_6 = 0x00,
DP_TEST_BIT_DEPTH_8 = 0x01,
DP_TEST_BIT_DEPTH_10 = 0x02,
DP_TEST_BIT_DEPTH_UNKNOWN = 0xFFFFFFFF,
};
static inline char *mdss_dp_test_bit_depth_to_string(u32 tbd)
{
switch (tbd) {
case DP_TEST_BIT_DEPTH_6:
return DP_ENUM_STR(DP_TEST_BIT_DEPTH_6);
case DP_TEST_BIT_DEPTH_8:
return DP_ENUM_STR(DP_TEST_BIT_DEPTH_8);
case DP_TEST_BIT_DEPTH_10:
return DP_ENUM_STR(DP_TEST_BIT_DEPTH_10);
case DP_TEST_BIT_DEPTH_UNKNOWN:
default:
return "unknown";
}
}
/**
* mdss_dp_is_test_bit_depth_valid() - validates the bit depth requested
* @bit_depth: bit depth requested by the sink
*
* Returns true if the requested bit depth is supported.
*/
static inline bool mdss_dp_is_test_bit_depth_valid(u32 tbd)
{
/* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */
switch (tbd) {
case DP_TEST_BIT_DEPTH_6:
case DP_TEST_BIT_DEPTH_8:
case DP_TEST_BIT_DEPTH_10:
return true;
default:
return false;
}
}
/**
* mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp
* @tbd: test bit depth
*
* Returns the bits per pixel (bpp) to be used corresponding to the
* git bit depth value. This function assumes that bit depth has
* already been validated.
*/
static inline u32 mdss_dp_test_bit_depth_to_bpp(enum test_bit_depth tbd)
{
u32 bpp;
/*
* Few simplistic rules and assumptions made here:
* 1. Bit depth is per color component
* 2. If bit depth is unknown return 0
* 3. Assume 3 color components
*/
switch (tbd) {
case DP_TEST_BIT_DEPTH_6:
bpp = 18;
break;
case DP_TEST_BIT_DEPTH_8:
bpp = 24;
break;
case DP_TEST_BIT_DEPTH_10:
bpp = 30;
break;
case DP_TEST_BIT_DEPTH_UNKNOWN:
default:
bpp = 0;
}
return bpp;
}
/**
* mdss_dp_bpp_to_test_bit_depth() - convert bpp to test bit depth
* &bpp: the bpp to be converted
*
* Return the bit depth per color component to used with the video
* test pattern data based on the bits per pixel value.
*/
static inline u32 mdss_dp_bpp_to_test_bit_depth(u32 bpp)
{
enum test_bit_depth tbd;
/*
* Few simplistic rules and assumptions made here:
* 1. Test bit depth is bit depth per color component
* 2. Assume 3 color components
*/
switch (bpp) {
case 18:
tbd = DP_TEST_BIT_DEPTH_6;
break;
case 24:
tbd = DP_TEST_BIT_DEPTH_8;
break;
case 30:
tbd = DP_TEST_BIT_DEPTH_10;
break;
default:
tbd = DP_TEST_BIT_DEPTH_UNKNOWN;
break;
}
return tbd;
}
enum test_video_pattern {
DP_TEST_VIDEO_PATTERN_NONE = 0x00,
DP_TEST_VIDEO_PATTERN_COLOR_RAMPS = 0x01,
DP_TEST_VIDEO_PATTERN_BW_VERT_LINES = 0x02,
DP_TEST_VIDEO_PATTERN_COLOR_SQUARE = 0x03,
};
static inline char *mdss_dp_test_video_pattern_to_string(u32 test_video_pattern)
{
switch (test_video_pattern) {
case DP_TEST_VIDEO_PATTERN_NONE:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_NONE);
case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_RAMPS);
case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_BW_VERT_LINES);
case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
return DP_ENUM_STR(DP_TEST_VIDEO_PATTERN_COLOR_SQUARE);
default:
return "unknown";
}
}
/**
* mdss_dp_is_test_video_pattern_valid() - validates the video pattern
* @pattern: video pattern requested by the sink
*
* Returns true if the requested video pattern is supported.
*/
static inline bool mdss_dp_is_test_video_pattern_valid(u32 pattern)
{
switch (pattern) {
case DP_TEST_VIDEO_PATTERN_NONE:
case DP_TEST_VIDEO_PATTERN_COLOR_RAMPS:
case DP_TEST_VIDEO_PATTERN_BW_VERT_LINES:
case DP_TEST_VIDEO_PATTERN_COLOR_SQUARE:
return true;
default:
return false;
}
}
enum notification_status {
NOTIFY_UNKNOWN,
NOTIFY_CONNECT,
NOTIFY_DISCONNECT,
NOTIFY_CONNECT_IRQ_HPD,
NOTIFY_DISCONNECT_IRQ_HPD,
};
static inline char const *mdss_dp_notification_status_to_string(
enum notification_status status)
{
switch (status) {
case NOTIFY_UNKNOWN:
return DP_ENUM_STR(NOTIFY_UNKNOWN);
case NOTIFY_CONNECT:
return DP_ENUM_STR(NOTIFY_CONNECT);
case NOTIFY_DISCONNECT:
return DP_ENUM_STR(NOTIFY_DISCONNECT);
case NOTIFY_CONNECT_IRQ_HPD:
return DP_ENUM_STR(NOTIFY_CONNECT_IRQ_HPD);
case NOTIFY_DISCONNECT_IRQ_HPD:
return DP_ENUM_STR(NOTIFY_DISCONNECT_IRQ_HPD);
default:
return "unknown";
}
}
static inline void mdss_dp_reset_frame_crc_data(struct mdss_dp_crc_data *crc)
{
if (!crc)
return;
crc->r_cr = 0;
crc->g_y = 0;
crc->b_cb = 0;
crc->en = false;
}
static inline bool mdss_dp_is_dsp_type_vga(struct mdss_dp_drv_pdata *dp)
{
return (dp->dpcd.downstream_port.dsp_present &&
(dp->dpcd.downstream_port.dsp_type == DSP_TYPE_VGA));
}
void mdss_dp_phy_initialize(struct mdss_dp_drv_pdata *dp);
int mdss_dp_dpcd_cap_read(struct mdss_dp_drv_pdata *dp);
int mdss_dp_dpcd_status_read(struct mdss_dp_drv_pdata *dp);
void mdss_dp_aux_parse_sink_status_field(struct mdss_dp_drv_pdata *dp);
int mdss_dp_edid_read(struct mdss_dp_drv_pdata *dp);
int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp);
void dp_aux_i2c_handler(struct mdss_dp_drv_pdata *dp, u32 isr);
void dp_aux_native_handler(struct mdss_dp_drv_pdata *dp, u32 isr);
void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep);
void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep);
void mdss_dp_lane_power_ctrl(struct mdss_dp_drv_pdata *ep, int up);
void mdss_dp_config_ctrl(struct mdss_dp_drv_pdata *ep);
char mdss_dp_gen_link_clk(struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_send_psm_request(struct mdss_dp_drv_pdata *dp, bool enable);
void mdss_dp_aux_send_test_response(struct mdss_dp_drv_pdata *ep);
void *mdss_dp_get_hdcp_data(struct device *dev);
int mdss_dp_hdcp2p2_init(struct mdss_dp_drv_pdata *dp_drv);
bool mdss_dp_aux_clock_recovery_done(struct mdss_dp_drv_pdata *ep);
bool mdss_dp_aux_channel_eq_done(struct mdss_dp_drv_pdata *ep);
bool mdss_dp_aux_is_link_rate_valid(u32 link_rate);
bool mdss_dp_aux_is_lane_count_valid(u32 lane_count);
int mdss_dp_aux_link_status_read(struct mdss_dp_drv_pdata *ep, int len);
void mdss_dp_aux_update_voltage_and_pre_emphasis_lvl(
struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_read_sink_frame_crc(struct mdss_dp_drv_pdata *dp);
int mdss_dp_aux_config_sink_frame_crc(struct mdss_dp_drv_pdata *dp,
bool enable);
int mdss_dp_aux_parse_vx_px(struct mdss_dp_drv_pdata *ep);
#endif /* MDSS_DP_H */