433 lines
12 KiB
C
433 lines
12 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2017-2021, 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 __SECDP_H
|
|
#define __SECDP_H
|
|
|
|
#if IS_ENABLED(CONFIG_USB_TYPEC_MANAGER_NOTIFIER)
|
|
#include <linux/usb/typec/manager/usb_typec_manager_notifier.h>
|
|
#endif
|
|
#if IS_ENABLED(CONFIG_PDIC_NOTIFIER)
|
|
#include <linux/usb/typec/common/pdic_notifier.h>
|
|
#endif
|
|
#include <linux/secdp_logger.h>
|
|
#include <linux/pm_wakeup.h>
|
|
#include <linux/sched/clock.h>
|
|
|
|
/*#define MODEM_RF_INFO*/
|
|
#if defined(MODEM_RF_INFO) && IS_ENABLED(CONFIG_DEV_RIL_BRIDGE)
|
|
#include <linux/dev_ril_bridge.h>
|
|
|
|
struct rf_information {
|
|
u8 rat;
|
|
u32 band;
|
|
u32 arfcn;
|
|
} __packed;
|
|
#endif
|
|
|
|
#include "dp_hpd.h"
|
|
#include "dp_power.h"
|
|
#include "dp_panel.h"
|
|
#include "dp_catalog.h"
|
|
#include "dp_parser.h"
|
|
#include "dp_link.h"
|
|
#include "secdp_sysfs.h"
|
|
|
|
/*defined at kmodule/usb/typec/common/pdic_core.h*/
|
|
#define SAMSUNG_VENDOR_ID 0x04E8
|
|
|
|
#define DEXDOCK_PRODUCT_ID 0xA020 /* EE-MG950 DeX Station */
|
|
#define DEXPAD_PRODUCT_ID 0xA029 /* EE-M5100 DeX Pad */
|
|
#define DEXCABLE_PRODUCT_ID 0xA048 /* EE-I3100 DeX Cable */
|
|
#define HG950_PRODUCT_ID 0xA025 /* EE-HG950 HDMI Adapter */
|
|
#define MPA2_PRODUCT_ID 0xA027 /* EE-P5000 Multiport Adapter */
|
|
#define MPA3_PRODUCT_ID 0xA056 /* EE-P3200 Multiport Adapter */
|
|
#define MPA4_PRODUCT_ID 0xA066 /* EE-P5400 Multiport Adapter */
|
|
|
|
#define SECDP_ENUM_STR(x) #x
|
|
|
|
#define SECDP_USB_CONCURRENCY
|
|
#define SECDP_USE_WAKELOCK
|
|
#define SECDP_MAX_HBR2
|
|
/*#define SECDP_AUDIO_CTS*/
|
|
/*#define SECDP_HDCP_DISABLE*/
|
|
/*#define SECDP_TEST_HDCP2P2_REAUTH*/
|
|
/*#define NOT_SUPPORT_DEX_RES_CHANGE*/
|
|
#define REMOVE_YUV420_AT_PREFER
|
|
#define SYSFS_BW_CODE
|
|
|
|
#define DPCD_IEEE_OUI 0x500
|
|
#define DPCD_DEVID_STR 0x503
|
|
|
|
#define LEN_BRANCH_REV 3
|
|
#define DPCD_BRANCH_HW_REV 0x509
|
|
#define DPCD_BRANCH_SW_REV_MAJOR 0x50A
|
|
#define DPCD_BRANCH_SW_REV_MINOR 0x50B
|
|
|
|
#define MAX_CNT_LINK_STATUS_UPDATE 4
|
|
#define MAX_CNT_HDCP_RETRY 10
|
|
|
|
/* MST: max resolution, max refresh rate, max pclk */
|
|
#define MST_MAX_COLS 3840
|
|
#define MST_MAX_ROWS 2160
|
|
#define MST_MAX_FPS 30
|
|
#define MST_MAX_PCLK 300000
|
|
|
|
#define PDIC_DP_NOTI_REG_DELAY 1000
|
|
|
|
/* displayport self test */
|
|
#if defined(CONFIG_SECDP_DBG)
|
|
#define SECDP_SELF_TEST
|
|
#endif
|
|
|
|
#ifdef SECDP_SELF_TEST
|
|
#define ST_EDID_SIZE 256
|
|
#define ST_ARG_CNT 20
|
|
#define ST_TEST_EXIT 555
|
|
|
|
enum {
|
|
ST_CLEAR_CMD,
|
|
ST_LANE_CNT,
|
|
ST_LINK_RATE,
|
|
ST_CONNECTION_TEST,
|
|
ST_HDCP_TEST,
|
|
ST_PREEM_TUN,
|
|
ST_VOLTAGE_TUN,
|
|
ST_MAX,
|
|
};
|
|
|
|
struct secdp_sef_test_item {
|
|
char cmd_str[20];
|
|
int arg[ST_ARG_CNT];
|
|
int arg_cnt;
|
|
char arg_str[100];
|
|
bool enabled;
|
|
void (*clear)(void);
|
|
};
|
|
|
|
int secdp_self_test_status(int cmd);
|
|
void secdp_self_test_start_reconnect(struct secdp_sysfs *dp_sysfs, void (*func)(struct secdp_misc *sec));
|
|
void secdp_self_test_start_hdcp_test(struct secdp_sysfs *dp_sysfs, void (*func_on)(void),
|
|
void (*func_off)(void));
|
|
//void secdp_self_register_clear_func(int cmd, void (*func)(void));
|
|
int *secdp_self_test_get_arg(int cmd);
|
|
#endif/*SECDP_SELF_TEST*/
|
|
|
|
/* monitor aspect ratio */
|
|
enum mon_aspect_ratio_t {
|
|
MON_RATIO_NA = -1,
|
|
MON_RATIO_3_2,
|
|
MON_RATIO_4_3,
|
|
MON_RATIO_5_3,
|
|
MON_RATIO_5_4,
|
|
MON_RATIO_8_5,
|
|
MON_RATIO_10P5_9,
|
|
MON_RATIO_11_10,
|
|
MON_RATIO_16_9,
|
|
MON_RATIO_16_10,
|
|
MON_RATIO_21_9,
|
|
MON_RATIO_21_10,
|
|
MON_RATIO_32_9,
|
|
MON_RATIO_32_10,
|
|
};
|
|
|
|
static inline char *secdp_aspect_ratio_to_string(enum mon_aspect_ratio_t ratio)
|
|
{
|
|
switch (ratio) {
|
|
case MON_RATIO_3_2: return DP_ENUM_STR(MON_RATIO_3_2);
|
|
case MON_RATIO_4_3: return DP_ENUM_STR(MON_RATIO_4_3);
|
|
case MON_RATIO_5_3: return DP_ENUM_STR(MON_RATIO_5_3);
|
|
case MON_RATIO_5_4: return DP_ENUM_STR(MON_RATIO_5_4);
|
|
case MON_RATIO_8_5: return DP_ENUM_STR(MON_RATIO_8_5);
|
|
case MON_RATIO_10P5_9: return DP_ENUM_STR(MON_RATIO_10P5_9);
|
|
case MON_RATIO_11_10: return DP_ENUM_STR(MON_RATIO_11_10);
|
|
case MON_RATIO_16_9: return DP_ENUM_STR(MON_RATIO_16_9);
|
|
case MON_RATIO_16_10: return DP_ENUM_STR(MON_RATIO_16_10);
|
|
case MON_RATIO_21_9: return DP_ENUM_STR(MON_RATIO_21_9);
|
|
case MON_RATIO_21_10: return DP_ENUM_STR(MON_RATIO_21_10);
|
|
case MON_RATIO_32_9: return DP_ENUM_STR(MON_RATIO_32_9);
|
|
case MON_RATIO_32_10: return DP_ENUM_STR(MON_RATIO_32_10);
|
|
case MON_RATIO_NA: return DP_ENUM_STR(MON_RATIO_NA);
|
|
default: return "unknown";
|
|
}
|
|
}
|
|
|
|
/* adapter type : SST or MST */
|
|
enum secdp_adapter_t {
|
|
SECDP_ADT_UNKNOWN = -1,
|
|
SECDP_ADT_SST = 10,
|
|
SECDP_ADT_MST = 11,
|
|
};
|
|
|
|
/* dex supported resolutions */
|
|
enum dex_support_res_t {
|
|
DEX_RES_NOT_SUPPORT = 0,
|
|
DEX_RES_1600X900, /* HD+ */
|
|
DEX_RES_1920X1080, /* FHD */
|
|
DEX_RES_1920X1200, /* WUXGA */
|
|
DEX_RES_2560X1080, /* UW-UXGA */
|
|
DEX_RES_2560X1440, /* QHD */
|
|
DEX_RES_2560X1600, /* WQXGA */
|
|
DEX_RES_3440X1440, /* UW-QHD */
|
|
DEX_RES_END,
|
|
};
|
|
#define DEX_RES_DFT DEX_RES_1920X1080 /* DeX default timing */
|
|
#define DEX_DFT_COL 1920
|
|
#define DEX_DFT_ROW 1080
|
|
#define DEX_RES_MAX DEX_RES_3440X1440 /* DeX max timing */
|
|
#define DEX_MAX_COL 3440
|
|
#define DEX_MAX_ROW 1440
|
|
|
|
#define DEX_REFRESH_MIN 50
|
|
#define DEX_REFRESH_MAX 60
|
|
#define MIRROR_REFRESH_MIN 24
|
|
|
|
static inline char *secdp_dex_res_to_string(int res)
|
|
{
|
|
switch (res) {
|
|
case DEX_RES_NOT_SUPPORT:
|
|
return DP_ENUM_STR(DEX_RES_NOT_SUPPORT);
|
|
case DEX_RES_1600X900:
|
|
return DP_ENUM_STR(DEX_RES_1600X900);
|
|
case DEX_RES_1920X1080:
|
|
return DP_ENUM_STR(DEX_RES_1920X1080);
|
|
case DEX_RES_1920X1200:
|
|
return DP_ENUM_STR(DEX_RES_1920X1200);
|
|
case DEX_RES_2560X1080:
|
|
return DP_ENUM_STR(DEX_RES_2560X1080);
|
|
case DEX_RES_2560X1440:
|
|
return DP_ENUM_STR(DEX_RES_2560X1440);
|
|
case DEX_RES_2560X1600:
|
|
return DP_ENUM_STR(DEX_RES_2560X1600);
|
|
case DEX_RES_3440X1440:
|
|
return DP_ENUM_STR(DEX_RES_3440X1440);
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
enum DEX_STATUS {
|
|
DEX_DISABLED = 0,
|
|
DEX_ENABLED,
|
|
DEX_MODE_CHANGING,
|
|
};
|
|
|
|
/** redriver devices */
|
|
enum secdp_redrv_dev {
|
|
SECDP_REDRV_NONE = 0,
|
|
SECDP_REDRV_PTN36502, /* don't need AUX_SEL control */
|
|
SECDP_REDRV_PS5169, /* need AUX_SEL control */
|
|
};
|
|
|
|
static inline char *secdp_redrv_to_string(int res)
|
|
{
|
|
switch (res) {
|
|
case SECDP_REDRV_NONE:
|
|
return DP_ENUM_STR(SECDP_REDRV_NONE);
|
|
case SECDP_REDRV_PTN36502:
|
|
return DP_ENUM_STR(SECDP_REDRV_PTN36502);
|
|
case SECDP_REDRV_PS5169:
|
|
return DP_ENUM_STR(SECDP_REDRV_PS5169);
|
|
default:
|
|
return "unknown";
|
|
}
|
|
}
|
|
|
|
struct secdp_adapter {
|
|
uint ven_id;
|
|
uint prod_id;
|
|
char ieee_oui[4]; /* DPCD 500h ~ 502h */
|
|
char devid_str[7]; /* DPCD 503h ~ 508h */
|
|
char fw_ver[10]; /* firmware ver, 0:h/w, 1:s/w major, 2:s/w minor */
|
|
|
|
bool ss_genuine;
|
|
bool ss_legacy;
|
|
enum dex_support_res_t dex_type;
|
|
};
|
|
|
|
#define MON_NAME_LEN 14 /* monitor name length, max 13 chars + null */
|
|
|
|
#define MAX_NUM_HMD 32
|
|
#define DEX_TAG_HMD "HMD"
|
|
|
|
struct secdp_sink_dev {
|
|
uint ven_id; /* vendor id from PDIC */
|
|
uint prod_id; /* product id from PDIC */
|
|
char monitor_name[MON_NAME_LEN]; /* from EDID */
|
|
};
|
|
|
|
struct secdp_pdic_noti {
|
|
struct delayed_work reg_work;
|
|
struct notifier_block nb;
|
|
bool registered;
|
|
bool reset; /* true if PDIC or SSUSB get reset after DP connection */
|
|
};
|
|
|
|
struct secdp_prefer {
|
|
enum mon_aspect_ratio_t ratio;
|
|
|
|
bool exist; /* true if preferred resolution */
|
|
int hdisp; /* horizontal pixel of preferred resolution */
|
|
int vdisp; /* vertical pixel of preferred resolution */
|
|
int refresh; /* refresh rate of preferred resolution */
|
|
};
|
|
|
|
struct secdp_dex {
|
|
struct class *sysfs_class;
|
|
enum dex_support_res_t res; /* dex supported resolution */
|
|
|
|
enum DEX_STATUS prev; /* previously known as "dex_now" */
|
|
enum DEX_STATUS curr; /* previously known as "dex_en" */
|
|
int setting_ui; /* "dex_set", true if setting has Dex mode */
|
|
|
|
bool ignore_prefer_ratio; /* true if prefer ratio does not match to dex ratio */
|
|
bool adapter_check_skip;
|
|
|
|
/*
|
|
* 2 if resolution is changed during dex mode change.
|
|
* And once dex framework reads the dex_node_stauts using dex node,
|
|
* it's assigned to same value with curr.
|
|
*/
|
|
enum DEX_STATUS status; /* previously known as "dex_node_status" */
|
|
|
|
bool reconnecting; /* true if dex is under reconnecting */
|
|
};
|
|
|
|
struct secdp_display_timing {
|
|
u32 active_h;
|
|
u32 active_v;
|
|
u32 refresh_rate;
|
|
bool interlaced;
|
|
int clock; /* pixel clock, refer to "struct drm_display_mode" */
|
|
enum dex_support_res_t dex_res; /* dex supported resolution */
|
|
enum mon_aspect_ratio_t mon_ratio; /* monitor aspect ratio */
|
|
int supported; /* for unit test */
|
|
u64 total;
|
|
};
|
|
|
|
struct secdp_hmd {
|
|
struct secdp_sink_dev list[MAX_NUM_HMD]; /* supported HMD dev list */
|
|
struct mutex lock;
|
|
bool exist; /* true if connected sink is known HMD device */
|
|
};
|
|
|
|
struct secdp_hdcp {
|
|
struct delayed_work start_work;
|
|
int retry; /* count if dp link is unstable during hdcp */
|
|
};
|
|
|
|
struct secdp_hpd {
|
|
struct delayed_work noti_work;
|
|
bool noti_deferred;
|
|
atomic_t val; /* 1 if hpd high, 0 if hpd low" */
|
|
bool prev_evt;
|
|
};
|
|
|
|
struct secdp_debug {
|
|
bool prefer_check_skip;
|
|
};
|
|
|
|
struct secdp_misc {
|
|
struct delayed_work link_status_work;
|
|
struct delayed_work link_backoff_work;
|
|
bool backoff_start;
|
|
struct delayed_work poor_discon_work;
|
|
|
|
struct device *uevent_dev;
|
|
#ifdef MODEM_RF_INFO
|
|
struct rf_information rf_info;
|
|
struct notifier_block modem_rfinfo_nb;
|
|
#endif
|
|
|
|
bool extdisp_off;
|
|
bool cable_connected; /* previously known as "cable_connected_phy" */
|
|
bool link_conf; /* previously known as "sec_link_conf" */
|
|
struct secdp_hpd hpd;
|
|
int mode_cnt;
|
|
|
|
struct secdp_adapter adapter;
|
|
struct secdp_pdic_noti pdic_noti;
|
|
|
|
struct secdp_display_timing prf_timing; /* preferred timing */
|
|
struct secdp_display_timing mrr_timing; /* max "mirror" timing */
|
|
struct secdp_display_timing dex_timing; /* max "dex" timing */
|
|
|
|
struct secdp_prefer prefer;
|
|
struct secdp_hdcp hdcp;
|
|
struct secdp_debug debug;
|
|
struct secdp_sysfs *sysfs;
|
|
struct secdp_dex dex;
|
|
struct secdp_hmd hmd;
|
|
|
|
struct completion dp_off_comp;
|
|
struct completion dp_discon_comp;
|
|
bool dp_disconnecting;
|
|
bool lpm_booting;
|
|
|
|
struct mutex notify_lock;
|
|
struct mutex attention_lock;
|
|
struct mutex notifier_lock;
|
|
atomic_t noti_status;
|
|
|
|
struct notifier_block reboot_nb;
|
|
bool reboot; /* true if rebooted or shutdown */
|
|
|
|
#ifdef SECDP_USE_WAKELOCK
|
|
struct wakeup_source *ws;
|
|
#endif
|
|
#ifdef SECDP_SELF_TEST
|
|
struct delayed_work self_test_reconnect_work;
|
|
struct delayed_work self_test_hdcp_test_work;
|
|
|
|
void (*self_test_reconnect_cb)(struct secdp_misc *sec);
|
|
void (*self_test_hdcp_on_cb)(void);
|
|
void (*self_test_hdcp_off_cb)(void);
|
|
#endif
|
|
};
|
|
|
|
bool secdp_adapter_check_parade(struct secdp_misc *sec);
|
|
bool secdp_adapter_check_ps176(struct secdp_misc *sec);
|
|
bool secdp_adapter_check_ps176_legacy(struct secdp_misc *sec);
|
|
bool secdp_adapter_check_realtek(struct secdp_misc *sec);
|
|
|
|
bool secdp_get_lpm_mode(struct secdp_misc *sec);
|
|
int secdp_send_deferred_hpd_noti(struct secdp_misc *sec);
|
|
|
|
int secdp_pdic_noti_register_ex(struct secdp_misc *sec, bool retry);
|
|
bool secdp_phy_reset_check(void);
|
|
bool secdp_get_power_status(void);
|
|
bool secdp_get_cable_status(void);
|
|
bool secdp_get_hpd_irq_status(void);
|
|
int secdp_get_hpd_status(void);
|
|
struct drm_connector *secdp_get_connector(void);
|
|
|
|
bool secdp_get_reboot_status(void);
|
|
|
|
bool secdp_check_hmd_dev(struct secdp_misc *sec, const char *name_to_search);
|
|
int secdp_store_hmd_dev(struct secdp_misc *sec, char *buf, size_t len, int num);
|
|
|
|
void secdp_timing_init(struct secdp_misc *sec);
|
|
void secdp_extdisp_on(struct secdp_misc *sec);
|
|
void secdp_extdisp_off(struct secdp_misc *sec);
|
|
void secdp_reconnect(struct secdp_misc *sec);
|
|
bool secdp_check_reconnect(struct secdp_misc *sec);
|
|
|
|
void secdp_link_backoff_start(void);
|
|
void secdp_link_backoff_stop(void);
|
|
bool secdp_adapter_is_legacy(void);
|
|
|
|
bool secdp_panel_hdr_supported(void);
|
|
|
|
#endif/*__SECDP_H*/
|