replace common qcom sources with samsung ones
This commit is contained in:
@@ -43,6 +43,7 @@ enum dp_altmode_pin_assignment {
|
||||
DPAM_HPD_F,
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
static int dp_altmode_set_usb_dp_mode(struct dp_altmode_private *altmode)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -171,7 +172,7 @@ static int dp_altmode_notify(void *priv, void *data, size_t len)
|
||||
if (altmode->dp_altmode.base.multi_func)
|
||||
altmode->lanes = 2;
|
||||
|
||||
DP_DEBUG("Connected=%d, lanes=%d\n",altmode->connected,altmode->lanes);
|
||||
DP_DEBUG("Connected=%d, lanes=%d\n", altmode->connected, altmode->lanes);
|
||||
|
||||
switch (orientation) {
|
||||
case 0:
|
||||
@@ -228,6 +229,7 @@ static void dp_altmode_register(void *priv)
|
||||
else
|
||||
DP_DEBUG("success\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_altmode_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
{
|
||||
@@ -273,7 +275,9 @@ static int dp_altmode_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
|
||||
struct dp_hpd *dp_altmode_get(struct device *dev, struct dp_hpd_cb *cb)
|
||||
{
|
||||
#if !defined(CONFIG_SECDP)
|
||||
int rc = 0;
|
||||
#endif
|
||||
struct dp_altmode_private *altmode;
|
||||
struct dp_altmode *dp_altmode;
|
||||
|
||||
@@ -294,18 +298,22 @@ struct dp_hpd *dp_altmode_get(struct device *dev, struct dp_hpd_cb *cb)
|
||||
dp_altmode->base.simulate_connect = dp_altmode_simulate_connect;
|
||||
dp_altmode->base.simulate_attention = dp_altmode_simulate_attention;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
rc = altmode_register_notifier(dev, dp_altmode_register, altmode);
|
||||
if (rc < 0) {
|
||||
DP_ERR("altmode probe notifier registration failed: %d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_DEBUG("success\n");
|
||||
|
||||
return &dp_altmode->base;
|
||||
#if !defined(CONFIG_SECDP)
|
||||
error:
|
||||
kfree(altmode);
|
||||
return ERR_PTR(rc);
|
||||
#endif
|
||||
}
|
||||
|
||||
void dp_altmode_put(struct dp_hpd *dp_hpd)
|
||||
@@ -320,8 +328,10 @@ void dp_altmode_put(struct dp_hpd *dp_hpd)
|
||||
altmode = container_of(dp_altmode, struct dp_altmode_private,
|
||||
dp_altmode);
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
altmode_deregister_client(altmode->amclient);
|
||||
altmode_deregister_notifier(altmode->dev, altmode);
|
||||
#endif
|
||||
|
||||
kfree(altmode);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,20 @@
|
||||
#include "dp_panel.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
#include <linux/switch.h>
|
||||
|
||||
static struct switch_dev switch_secdp_audio = {
|
||||
.name = "ch_hdmi_audio",
|
||||
};
|
||||
#endif
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
struct dp_audio_private {
|
||||
struct platform_device *ext_pdev;
|
||||
struct platform_device *pdev;
|
||||
@@ -409,17 +423,16 @@ static int dp_audio_info_setup(struct platform_device *pdev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!audio->panel || !audio->panel->get_panel_on) {
|
||||
DP_ERR("invalid panel data\n");
|
||||
rc = -EINVAL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (audio->dp_audio.tui_active) {
|
||||
DP_DEBUG("TUI session active\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_save_item(BD_AUD_CH, params->num_of_channels);
|
||||
secdp_bigdata_save_item(BD_AUD_FREQ, params->sample_rate_hz);
|
||||
#endif
|
||||
|
||||
mutex_lock(&audio->ops_lock);
|
||||
|
||||
audio->channels = params->num_of_channels;
|
||||
@@ -443,6 +456,38 @@ static int dp_audio_info_setup(struct platform_device *pdev,
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
static void secdp_audio_use_one_sampling_freq(u8 *adb, int size)
|
||||
{
|
||||
const int one_adb_size = 3;
|
||||
int adb_count;
|
||||
|
||||
if (size <= 0)
|
||||
return;
|
||||
|
||||
adb_count = size / one_adb_size;
|
||||
while (adb_count > 0) {
|
||||
if (adb[1] & BIT(2))
|
||||
adb[1] = BIT(2); /* 48kHz */
|
||||
else if (adb[1] & BIT(1))
|
||||
adb[1] = BIT(1); /* 44.1kHz */
|
||||
else if (adb[1] & BIT(0))
|
||||
adb[1] = BIT(0); /* 32kHz */
|
||||
else if (adb[1] & BIT(3))
|
||||
adb[1] = BIT(3); /* 88kHz */
|
||||
else if (adb[1] & BIT(4))
|
||||
adb[1] = BIT(4); /* 96kHz */
|
||||
else if (adb[1] & BIT(5))
|
||||
adb[1] = BIT(5); /* 176kHz */
|
||||
else if (adb[1] & BIT(6))
|
||||
adb[1] = BIT(6); /* 192kHz */
|
||||
|
||||
adb += one_adb_size;
|
||||
adb_count--;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_audio_get_edid_blk(struct platform_device *pdev,
|
||||
struct msm_ext_disp_audio_edid_blk *blk)
|
||||
{
|
||||
@@ -469,8 +514,19 @@ static int dp_audio_get_edid_blk(struct platform_device *pdev,
|
||||
|
||||
edid = audio->panel->edid_ctrl;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_adapter_is_legacy(audio->pdev))
|
||||
secdp_audio_use_one_sampling_freq(edid->audio_data_block, edid->adb_size);
|
||||
#endif
|
||||
blk->audio_data_blk = edid->audio_data_block;
|
||||
blk->audio_data_blk_size = edid->adb_size;
|
||||
#if defined(CONFIG_SECDP)
|
||||
print_hex_dump(KERN_DEBUG, "AUDIO_BLK: ",
|
||||
DUMP_PREFIX_NONE, 16, 1, blk->audio_data_blk,
|
||||
blk->audio_data_blk_size, false);
|
||||
secdp_logger_hex_dump(blk->audio_data_blk, "AUDIO_BLK:",
|
||||
blk->audio_data_blk_size);
|
||||
#endif
|
||||
|
||||
blk->spk_alloc_data_blk = edid->spkr_alloc_data_block;
|
||||
blk->spk_alloc_data_blk_size = edid->sadb_size;
|
||||
@@ -518,11 +574,6 @@ static void dp_audio_teardown_done(struct platform_device *pdev)
|
||||
if (IS_ERR(audio))
|
||||
return;
|
||||
|
||||
if (!audio->panel || !audio->panel->get_panel_on) {
|
||||
DP_ERR("invalid panel data\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio->dp_audio.tui_active) {
|
||||
DP_DEBUG("TUI session active\n");
|
||||
return;
|
||||
@@ -605,6 +656,8 @@ static int dp_audio_register_ext_disp(struct dp_audio_private *audio)
|
||||
struct msm_ext_disp_init_data *ext;
|
||||
struct msm_ext_disp_audio_codec_ops *ops;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
ops = &ext->codec_ops;
|
||||
|
||||
@@ -692,6 +745,10 @@ end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
extern int secdp_get_audio_ch(void);
|
||||
#endif
|
||||
|
||||
static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -704,12 +761,26 @@ static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
|
||||
goto end;
|
||||
}
|
||||
|
||||
DP_INFO("audio stream %d is %s\n", ext->codec.stream_id,
|
||||
(state == EXT_DISPLAY_CABLE_CONNECT) ? "connected" : "disconnected");
|
||||
|
||||
reinit_completion(&audio->hpd_comp);
|
||||
rc = ext->intf_ops.audio_notify(audio->ext_pdev,
|
||||
&ext->codec, state);
|
||||
if (rc)
|
||||
goto end;
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
{
|
||||
if (!audio->dp_audio.has_mst) {
|
||||
int audio_ch = state ? secdp_get_audio_ch() : -1;
|
||||
|
||||
switch_set_state(&switch_secdp_audio, audio_ch);
|
||||
DP_INFO("secdp audio state:0x%x\n", audio_ch);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (atomic_read(&audio->acked))
|
||||
goto end;
|
||||
|
||||
@@ -773,6 +844,15 @@ static int dp_audio_on(struct dp_audio *dp_audio)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status(&audio->pdev->dev)) {
|
||||
DP_INFO("cable is out\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
dp_audio_register_ext_disp(audio);
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
@@ -804,6 +884,8 @@ static int dp_audio_off(struct dp_audio *dp_audio, bool skip_wait)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
audio = container_of(dp_audio, struct dp_audio_private, dp_audio);
|
||||
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
@@ -813,6 +895,13 @@ static int dp_audio_off(struct dp_audio *dp_audio, bool skip_wait)
|
||||
|
||||
ext = &audio->ext_audio_data;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!atomic_read(&audio->session_on)) {
|
||||
DP_INFO("dp audio already off\n");
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
work_pending = cancel_delayed_work_sync(&audio->notify_delayed_work);
|
||||
if (work_pending)
|
||||
DP_DEBUG("pending notification work completed\n");
|
||||
@@ -845,6 +934,43 @@ static void dp_audio_notify_work_fn(struct work_struct *work)
|
||||
dp_audio_notify(audio, EXT_DISPLAY_CABLE_CONNECT);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
int secdp_audio_register_switch(struct dp_audio *dp_audio)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (dp_audio->has_mst) {
|
||||
DP_INFO("skip switch register\n");
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = switch_dev_register(&switch_secdp_audio);
|
||||
if (rc) {
|
||||
DP_INFO("Failed to register secdp_audio switch %d\n", rc);
|
||||
rc = -ENODEV;
|
||||
goto end;
|
||||
}
|
||||
|
||||
DP_INFO("secdp_audio register success\n");
|
||||
end:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void secdp_audio_unregister_switch(struct dp_audio_private *audio)
|
||||
{
|
||||
struct dp_audio *dp_audio = &audio->dp_audio;
|
||||
|
||||
if (dp_audio->has_mst) {
|
||||
DP_DEBUG("skip switch unregister\n");
|
||||
return;
|
||||
}
|
||||
|
||||
switch_dev_unregister(&switch_secdp_audio);
|
||||
DP_INFO("secdp_audio unregister success\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_audio_create_notify_workqueue(struct dp_audio_private *audio)
|
||||
{
|
||||
audio->notify_workqueue = create_workqueue("sdm_dp_audio_notify");
|
||||
@@ -862,6 +988,10 @@ static void dp_audio_destroy_notify_workqueue(struct dp_audio_private *audio)
|
||||
{
|
||||
if (audio->notify_workqueue)
|
||||
destroy_workqueue(audio->notify_workqueue);
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
secdp_audio_unregister_switch(audio);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct dp_audio *dp_audio_get(struct platform_device *pdev,
|
||||
|
||||
@@ -22,6 +22,9 @@ struct dp_audio {
|
||||
u32 lane_count;
|
||||
u32 bw_code;
|
||||
bool tui_active;
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
bool has_mst;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* on()
|
||||
@@ -73,4 +76,9 @@ struct dp_audio *dp_audio_get(struct platform_device *pdev,
|
||||
* @dp_audio: an instance of dp_audio.
|
||||
*/
|
||||
void dp_audio_put(struct dp_audio *dp_audio);
|
||||
|
||||
#if defined(CONFIG_SECDP_SWITCH)
|
||||
int secdp_audio_register_switch(struct dp_audio *dp_audio);
|
||||
#endif
|
||||
|
||||
#endif /* _DP_AUDIO_H_ */
|
||||
|
||||
@@ -16,6 +16,12 @@
|
||||
#include "dp_aux.h"
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_AUX_ENUM_STR(x) #x
|
||||
#define DP_AUX_IPC_NUM_PAGES 10
|
||||
@@ -69,7 +75,11 @@ struct dp_aux_private {
|
||||
struct dp_aux dp_aux;
|
||||
struct dp_catalog_aux *catalog;
|
||||
struct dp_aux_cfg *cfg;
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct device_node *aux_switch_node;
|
||||
#else
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
struct mutex mutex;
|
||||
struct completion comp;
|
||||
struct drm_dp_aux drm_aux;
|
||||
@@ -104,9 +114,11 @@ static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
|
||||
int i, linelen, remaining = msg->size;
|
||||
const int rowsize = 16;
|
||||
u8 linebuf[64];
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct dp_aux_private *aux = container_of(drm_aux,
|
||||
struct dp_aux_private, drm_aux);
|
||||
struct dp_aux *dp_aux = &aux->dp_aux;
|
||||
#endif
|
||||
|
||||
snprintf(prefix, sizeof(prefix), "%s %s %4xh(%2zu): ",
|
||||
(msg->request & DP_AUX_I2C_MOT) ? "I2C" : "NAT",
|
||||
@@ -120,10 +132,12 @@ static void dp_aux_hex_dump(struct drm_dp_aux *drm_aux,
|
||||
hex_dump_to_buffer(msg->buffer + i, linelen, rowsize, 1,
|
||||
linebuf, sizeof(linebuf), false);
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
if (msg->size == 1 && msg->address == 0)
|
||||
DP_DEBUG_V("%s%s\n", prefix, linebuf);
|
||||
else
|
||||
DP_AUX_DEBUG(dp_aux, "%s%s\n", prefix, linebuf);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,6 +223,21 @@ static u32 dp_aux_write(struct dp_aux_private *aux,
|
||||
return len;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#define DDC_SEGMENT_ADDR 0x30
|
||||
|
||||
static bool secdp_check_seg_addr(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
if (msg->address == DDC_SEGMENT_ADDR &&
|
||||
!(msg->request & DP_AUX_I2C_READ) &&
|
||||
msg->size == 1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
|
||||
struct drm_dp_aux_msg *msg)
|
||||
{
|
||||
@@ -239,6 +268,15 @@ static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux,
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE) {
|
||||
ret = len;
|
||||
} else {
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_check_seg_addr(aux, msg)) {
|
||||
DP_AUX_ERR(dp_aux, "ignore %s during [%s]\n",
|
||||
dp_aux_get_error(aux->aux_error_num), prefix);
|
||||
aux->aux_error_num = DP_AUX_ERR_NONE;
|
||||
return msg->size;
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_AUX_WARN_RATELIMITED(dp_aux, "aux err [%s] during [%s]\n",
|
||||
dp_aux_get_error(aux->aux_error_num), prefix);
|
||||
ret = -EINVAL;
|
||||
@@ -298,6 +336,13 @@ static void dp_aux_native_handler(struct dp_aux_private *aux)
|
||||
aux->catalog->clear_hw_interrupts(aux->catalog);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE)
|
||||
secdp_bigdata_clr_error_cnt(ERR_AUX);
|
||||
else
|
||||
secdp_bigdata_inc_error_cnt(ERR_AUX);
|
||||
#endif
|
||||
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
@@ -327,6 +372,13 @@ static void dp_aux_i2c_handler(struct dp_aux_private *aux)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (aux->aux_error_num == DP_AUX_ERR_NONE)
|
||||
secdp_bigdata_clr_error_cnt(ERR_AUX);
|
||||
else
|
||||
secdp_bigdata_inc_error_cnt(ERR_AUX);
|
||||
#endif
|
||||
|
||||
complete(&aux->comp);
|
||||
}
|
||||
|
||||
@@ -361,6 +413,8 @@ static void dp_aux_reconfig(struct dp_aux *dp_aux)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
aux->catalog->update_aux_cfg(aux->catalog,
|
||||
@@ -377,6 +431,8 @@ static void dp_aux_abort_transaction(struct dp_aux *dp_aux, bool abort)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
atomic_set(&aux->aborted, abort);
|
||||
@@ -558,6 +614,20 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
|
||||
|
||||
ret = dp_aux_cmd_fifo_tx(aux, msg);
|
||||
if ((ret < 0) && !atomic_read(&aux->aborted)) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status(aux->dev) || !secdp_get_hpd_status(aux->dev)) {
|
||||
DP_INFO("hpd_low or cable_lost %ld\n", ret);
|
||||
/*
|
||||
* don't need to repeat aux.
|
||||
* exit loop in drm_dp_dpcd_access()
|
||||
*/
|
||||
msg->reply = aux->native ?
|
||||
DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
|
||||
ret = msg->size;
|
||||
aux->retry_cnt = 0;
|
||||
goto unlock_exit;
|
||||
}
|
||||
#endif
|
||||
aux->retry_cnt++;
|
||||
if (!(aux->retry_cnt % retry_count))
|
||||
aux->catalog->update_aux_cfg(aux->catalog,
|
||||
@@ -661,6 +731,8 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
if (aux->enabled)
|
||||
@@ -673,6 +745,8 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
|
||||
atomic_set(&aux->aborted, 0);
|
||||
aux->retry_cnt = 0;
|
||||
aux->enabled = true;
|
||||
|
||||
DP_LEAVE("\n");
|
||||
}
|
||||
|
||||
static void dp_aux_deinit(struct dp_aux *dp_aux)
|
||||
@@ -684,6 +758,8 @@ static void dp_aux_deinit(struct dp_aux *dp_aux)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
|
||||
|
||||
if (!aux->enabled)
|
||||
@@ -692,6 +768,8 @@ static void dp_aux_deinit(struct dp_aux *dp_aux)
|
||||
atomic_set(&aux->aborted, 1);
|
||||
aux->catalog->enable(aux->catalog, false);
|
||||
aux->enabled = false;
|
||||
|
||||
DP_LEAVE("\n");
|
||||
}
|
||||
|
||||
static int dp_aux_register(struct dp_aux *dp_aux, struct drm_device *drm_dev)
|
||||
@@ -724,6 +802,7 @@ static int dp_aux_register(struct dp_aux *dp_aux, struct drm_device *drm_dev)
|
||||
/* if bridge is defined, override transfer function */
|
||||
if (aux->aux_bridge && aux->aux_bridge->transfer)
|
||||
aux->drm_aux.transfer = dp_aux_bridge_transfer;
|
||||
|
||||
exit:
|
||||
return ret;
|
||||
}
|
||||
@@ -876,10 +955,17 @@ end:
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
|
||||
enum dp_aux_switch_type switch_type)
|
||||
#else
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
|
||||
enum dp_aux_switch_type switch_type, void *sec)
|
||||
#endif
|
||||
{
|
||||
int rc = 0;
|
||||
struct dp_aux_private *aux;
|
||||
@@ -891,6 +977,8 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
|
||||
if (!aux) {
|
||||
rc = -ENOMEM;
|
||||
@@ -904,7 +992,11 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
aux->dev = dev;
|
||||
aux->catalog = catalog;
|
||||
aux->cfg = parser->aux_cfg;
|
||||
#if !defined(CONFIG_SECDP)
|
||||
aux->aux_switch_node = aux_switch;
|
||||
#else
|
||||
aux->sec = (struct secdp_misc *)sec;
|
||||
#endif
|
||||
aux->aux_bridge = aux_bridge;
|
||||
dp_aux = &aux->dp_aux;
|
||||
aux->retry_cnt = 0;
|
||||
|
||||
@@ -68,10 +68,17 @@ struct dp_aux {
|
||||
int (*switch_unregister_notifier)(struct notifier_block *nb, struct device_node *node);
|
||||
};
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
|
||||
enum dp_aux_switch_type switch_type);
|
||||
#else
|
||||
struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
|
||||
struct dp_parser *parser, struct device_node *aux_switch,
|
||||
struct dp_aux_bridge *aux_bridge, void *ipc_log_context,
|
||||
enum dp_aux_switch_type switch_type, void *sec);
|
||||
#endif
|
||||
void dp_aux_put(struct dp_aux *aux);
|
||||
|
||||
#endif /*__DP_AUX_H_*/
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "dp_debug.h"
|
||||
#include "dp_link.h"
|
||||
#include "dp_lphw_hpd.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_GET_MSB(x) (x >> 8)
|
||||
#define DP_GET_LSB(x) (x & 0xff)
|
||||
@@ -41,24 +44,13 @@
|
||||
|
||||
#define DP_INTR_MASK2 (DP_INTERRUPT_STATUS2 << 2)
|
||||
|
||||
/**
|
||||
* FIFO errors should be enabled in development environment
|
||||
* to capture issues during internal testing.
|
||||
* In production environment, driver should ignore the errors
|
||||
* and let the black screen persist and end user should replug
|
||||
* to recover from this.
|
||||
*/
|
||||
|
||||
#define DP_INTERRUPT_STATUS3_DEV \
|
||||
#define DP_INTERRUPT_STATUS3 \
|
||||
(DP_INTR_SST_ML_FIFO_OVERFLOW | DP_INTR_MST0_ML_FIFO_OVERFLOW | \
|
||||
DP_INTR_MST1_ML_FIFO_OVERFLOW | DP_INTR_DP1_FRAME_END | DP_INTR_SDP0_COLLISION | \
|
||||
DP_INTR_SDP1_COLLISION)
|
||||
|
||||
#define DP_INTERRUPT_STATUS3_PROD \
|
||||
(DP_INTR_DP1_FRAME_END | DP_INTR_SDP0_COLLISION | DP_INTR_SDP1_COLLISION)
|
||||
|
||||
#define DP_INTR_MASK3_DEV (DP_INTERRUPT_STATUS3_DEV << 2)
|
||||
#define DP_INTR_MASK3_PROD (DP_INTERRUPT_STATUS3_PROD << 2)
|
||||
#define DP_INTR_MASK3 (DP_INTERRUPT_STATUS3 << 2)
|
||||
|
||||
#define DP_INTERRUPT_STATUS5 \
|
||||
(DP_INTR_MST_DP0_VCPF_SENT | DP_INTR_MST_DP1_VCPF_SENT)
|
||||
@@ -178,6 +170,11 @@ static u32 dp_read_hw(struct dp_catalog_private *catalog,
|
||||
{
|
||||
u32 data = 0;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_phy_reset_check(catalog->dev))
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
data = readl_relaxed(io_data->io.base + offset);
|
||||
|
||||
return data;
|
||||
@@ -186,6 +183,11 @@ static u32 dp_read_hw(struct dp_catalog_private *catalog,
|
||||
static void dp_write_hw(struct dp_catalog_private *catalog,
|
||||
struct dp_io_data *io_data, u32 offset, u32 data)
|
||||
{
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_phy_reset_check(catalog->dev))
|
||||
return;
|
||||
#endif
|
||||
|
||||
writel_relaxed(data, io_data->io.base + offset);
|
||||
}
|
||||
|
||||
@@ -302,7 +304,16 @@ static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read)
|
||||
|
||||
if (read) {
|
||||
data = dp_read(DP_AUX_TRANS_CTRL);
|
||||
#if defined(CONFIG_SECDP)
|
||||
/* Prevent_CXX Major defect - Invalid Assignment: The type size
|
||||
* of both side variables are different:
|
||||
* "data" is 4 ( unsigned int ) and "data & 0xfffffffffffffdffUL
|
||||
* " is 8 ( unsigned long )
|
||||
*/
|
||||
data &= ((u32)~BIT(9));
|
||||
#else
|
||||
data &= ~BIT(9);
|
||||
#endif
|
||||
dp_write(DP_AUX_TRANS_CTRL, data);
|
||||
} else {
|
||||
dp_write(DP_AUX_TRANS_CTRL, 0);
|
||||
@@ -326,6 +337,10 @@ static void dp_catalog_aux_clear_hw_interrupts(struct dp_catalog_aux *aux)
|
||||
io_data = catalog->io.dp_phy;
|
||||
|
||||
data = dp_read(DP_PHY_AUX_INTERRUPT_STATUS);
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (data)
|
||||
DP_DEBUG("PHY_AUX_INTERRUPT_STATUS=0x%08x\n", data);
|
||||
#endif
|
||||
|
||||
dp_write(DP_PHY_AUX_INTERRUPT_CLEAR, 0x1f);
|
||||
wmb(); /* make sure 0x1f is written before next write */
|
||||
@@ -404,6 +419,13 @@ static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux,
|
||||
|
||||
catalog = dp_catalog_get_priv(aux);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status(catalog->dev)) {
|
||||
DP_INFO("cable is out\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
io_data = catalog->io.dp_phy;
|
||||
|
||||
current_index = cfg[type].current_index;
|
||||
@@ -1098,6 +1120,8 @@ static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
catalog = dp_catalog_get_priv(ctrl);
|
||||
io_data = catalog->io.dp_link;
|
||||
|
||||
@@ -1199,6 +1223,8 @@ static void dp_catalog_panel_config_dto(struct dp_catalog_panel *panel,
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
catalog = dp_catalog_get_priv(panel);
|
||||
io_data = catalog->io.dp_link;
|
||||
|
||||
@@ -1275,6 +1301,8 @@ static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl,
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("en:%d\n", enable);
|
||||
|
||||
catalog = dp_catalog_get_priv(ctrl);
|
||||
io_data = catalog->io.dp_link;
|
||||
|
||||
@@ -1693,7 +1721,9 @@ static void dp_catalog_panel_dp_flush(struct dp_catalog_panel *panel,
|
||||
static void dp_catalog_panel_pps_flush(struct dp_catalog_panel *panel)
|
||||
{
|
||||
dp_catalog_panel_dp_flush(panel, DP_PPS_FLUSH);
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG("pps flush for stream:%d\n", panel->stream_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dp_catalog_panel_dhdr_flush(struct dp_catalog_panel *panel)
|
||||
@@ -1810,8 +1840,6 @@ end:
|
||||
static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl,
|
||||
bool enable)
|
||||
{
|
||||
u32 DP_INTR_MASK3 = DP_INTR_MASK3_PROD;
|
||||
u32 DP_INTERRUPT_STATUS3 = DP_INTERRUPT_STATUS3_PROD;
|
||||
struct dp_catalog_private *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
|
||||
@@ -1823,11 +1851,6 @@ static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl,
|
||||
catalog = dp_catalog_get_priv(ctrl);
|
||||
io_data = catalog->io.dp_ahb;
|
||||
|
||||
if (catalog->parser->fifo_error_enable) {
|
||||
DP_INTR_MASK3 = DP_INTR_MASK3_DEV;
|
||||
DP_INTERRUPT_STATUS3 = DP_INTERRUPT_STATUS3_DEV;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
dp_write(DP_INTR_STATUS, DP_INTR_MASK1);
|
||||
dp_write(DP_INTR_STATUS2, DP_INTR_MASK2);
|
||||
@@ -1856,8 +1879,7 @@ static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl,
|
||||
|
||||
static void dp_catalog_ctrl_get_interrupt(struct dp_catalog_ctrl *ctrl)
|
||||
{
|
||||
u32 ack = 0, DP_INTR_MASK3 = DP_INTR_MASK3_PROD;
|
||||
u32 DP_INTERRUPT_STATUS3 = DP_INTERRUPT_STATUS3_PROD;
|
||||
u32 ack = 0;
|
||||
struct dp_catalog_private *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
|
||||
@@ -1869,11 +1891,6 @@ static void dp_catalog_ctrl_get_interrupt(struct dp_catalog_ctrl *ctrl)
|
||||
catalog = dp_catalog_get_priv(ctrl);
|
||||
io_data = catalog->io.dp_ahb;
|
||||
|
||||
if (catalog->parser->fifo_error_enable) {
|
||||
DP_INTR_MASK3 = DP_INTR_MASK3_DEV;
|
||||
DP_INTERRUPT_STATUS3 = DP_INTERRUPT_STATUS3_DEV;
|
||||
}
|
||||
|
||||
ctrl->isr = dp_read(DP_INTR_STATUS2);
|
||||
ctrl->isr &= ~DP_INTR_MASK2;
|
||||
ack = ctrl->isr & DP_INTERRUPT_STATUS2;
|
||||
@@ -1980,6 +1997,22 @@ static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl,
|
||||
value1 = vm_pre_emphasis[v_level][p_level];
|
||||
}
|
||||
|
||||
#if defined(SECDP_SELF_TEST)
|
||||
if (secdp_self_test_status(ST_VOLTAGE_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_VOLTAGE_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[vx] value0: %02x => %02x\n", value0, val);
|
||||
value0 = val;
|
||||
}
|
||||
|
||||
if (secdp_self_test_status(ST_PREEM_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_PREEM_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[px] value0: %02x => %02x\n", value1, val);
|
||||
value1 = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* program default setting first */
|
||||
|
||||
io_data = catalog->io.dp_ln_tx0;
|
||||
@@ -3189,6 +3222,22 @@ struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_parser *parser)
|
||||
ctrl.valid_lt_params = false;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (parser->valid_preshoot_params) {
|
||||
ctrl.preshoot0_rbr_hbr = parser->preshoot0_rbr_hbr;
|
||||
ctrl.preshoot1_rbr_hbr = parser->preshoot1_rbr_hbr;
|
||||
ctrl.preshoot0_hbr2_3 = parser->preshoot0_hbr2_3;
|
||||
ctrl.preshoot1_hbr2_3 = parser->preshoot1_hbr2_3;
|
||||
ctrl.valid_preshoot_params = true;
|
||||
} else {
|
||||
ctrl.preshoot0_rbr_hbr = NULL;
|
||||
ctrl.preshoot1_rbr_hbr = NULL;
|
||||
ctrl.preshoot0_hbr2_3 = NULL;
|
||||
ctrl.preshoot1_hbr2_3 = NULL;
|
||||
ctrl.valid_preshoot_params = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
dp_catalog = &catalog->dp_catalog;
|
||||
dp_catalog->parser = parser;
|
||||
|
||||
|
||||
@@ -99,6 +99,14 @@ struct dp_catalog_ctrl {
|
||||
u8 *pre_emp_hbr_rbr;
|
||||
bool valid_lt_params;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
u8 *preshoot0_hbr2_3;
|
||||
u8 *preshoot1_hbr2_3;
|
||||
u8 *preshoot0_rbr_hbr;
|
||||
u8 *preshoot1_rbr_hbr;
|
||||
bool valid_preshoot_params;
|
||||
#endif
|
||||
|
||||
void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state);
|
||||
void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u8 ln_cnt);
|
||||
void (*lane_mapping)(struct dp_catalog_ctrl *ctrl, bool flipped,
|
||||
|
||||
@@ -12,6 +12,13 @@
|
||||
#include <linux/rational.h>
|
||||
#include <drm/drm_fixed.h>
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
#include "dp_parser.h"
|
||||
#endif
|
||||
|
||||
#define dp_catalog_get_priv_v420(x) ({ \
|
||||
struct dp_catalog *catalog; \
|
||||
catalog = container_of(x, struct dp_catalog, x); \
|
||||
@@ -52,6 +59,62 @@ struct dp_catalog_private_v420 {
|
||||
struct dp_catalog *dpc;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#define PRESHOOT_ADDR 0xE8
|
||||
|
||||
static void _secdp_catalog420_preshoot_adjust(
|
||||
struct dp_catalog_ctrl *ctrl, u32 version,
|
||||
u8 v_level, u8 p_level, bool high)
|
||||
{
|
||||
struct dp_catalog_private_v420 *catalog;
|
||||
struct dp_io_data *io_data;
|
||||
int i, idx;
|
||||
u8 value[DP_HW_PRESHOOT_MAX];
|
||||
|
||||
if (version < 0x10020003) {
|
||||
DP_ERR("version not matched %x\n", version);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ctrl->valid_preshoot_params) {
|
||||
//DP_ERR("invalid preshoot params\n");
|
||||
return;
|
||||
}
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(ctrl);
|
||||
idx = v_level * MAX_VOLTAGE_LEVELS + p_level;
|
||||
|
||||
if (high) {
|
||||
value[DP_HW_PRESHOOT_0] = ctrl->preshoot0_hbr2_3[idx];
|
||||
value[DP_HW_PRESHOOT_1] = ctrl->preshoot1_hbr2_3[idx];
|
||||
} else {
|
||||
value[DP_HW_PRESHOOT_0] = ctrl->preshoot0_rbr_hbr[idx];
|
||||
value[DP_HW_PRESHOOT_1] = ctrl->preshoot1_rbr_hbr[idx];
|
||||
}
|
||||
|
||||
for (i = 0; i < DP_HW_PRESHOOT_MAX; i++) {
|
||||
|
||||
if (i == DP_HW_PRESHOOT_0)
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
else if (i == DP_HW_PRESHOOT_1)
|
||||
io_data = catalog->io->dp_ln_tx1;
|
||||
else
|
||||
DP_ERR("cannot be here\n");
|
||||
|
||||
value[i] |= BIT(5);
|
||||
|
||||
/*
|
||||
* USB3_DP_PHY_DP_QSERDES_TX0_PRE_EMPH
|
||||
* USB3_DP_PHY_DP_QSERDES_TX1_PRE_EMPH
|
||||
*/
|
||||
dp_write(PRESHOOT_ADDR, value[i]);
|
||||
|
||||
DP_INFO("%s [%s] %02x\n", secdp_preshoot_to_string(i),
|
||||
(!high ? "low" : "high"), value[i]);
|
||||
}
|
||||
}
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux,
|
||||
struct dp_aux_cfg *cfg)
|
||||
{
|
||||
@@ -64,6 +127,8 @@ static void dp_catalog_aux_setup_v420(struct dp_catalog_aux *aux,
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
catalog = dp_catalog_get_priv_v420(aux);
|
||||
|
||||
io_data = catalog->io->dp_phy;
|
||||
@@ -248,6 +313,22 @@ static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
|
||||
value1 = vm_pre_emphasis[v_level][p_level];
|
||||
}
|
||||
|
||||
#if defined(SECDP_SELF_TEST)
|
||||
if (secdp_self_test_status(ST_VOLTAGE_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_VOLTAGE_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[vx] value0: 0x%02x => 0x%02x\n", value0, val);
|
||||
value0 = val;
|
||||
}
|
||||
|
||||
if (secdp_self_test_status(ST_PREEM_TUN) >= 0) {
|
||||
u8 val = secdp_self_test_get_arg(ST_PREEM_TUN)[v_level*4 + p_level];
|
||||
|
||||
DP_INFO("[px] value0: 0x%02x => 0x%02x\n", value1, val);
|
||||
value1 = val;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* program default setting first */
|
||||
io_data = catalog->io->dp_ln_tx0;
|
||||
dp_write(TXn_TX_DRV_LVL_V420, 0x2A);
|
||||
@@ -277,6 +358,10 @@ static void dp_catalog_ctrl_update_vx_px_v420(struct dp_catalog_ctrl *ctrl,
|
||||
DP_ERR("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n",
|
||||
v_level, value0, p_level, value1);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
_secdp_catalog420_preshoot_adjust(ctrl, version, v_level, p_level, high);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dp_catalog_ctrl_lane_pnswap_v420(struct dp_catalog_ctrl *ctrl,
|
||||
@@ -325,6 +410,8 @@ struct dp_catalog_sub *dp_catalog_get_v420(struct device *dev,
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
catalog_priv = devm_kzalloc(dev, sizeof(*catalog_priv), GFP_KERNEL);
|
||||
if (!catalog_priv)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
@@ -13,7 +13,12 @@
|
||||
#include "dp_ctrl.h"
|
||||
#include "dp_debug.h"
|
||||
#include "sde_dbg.h"
|
||||
#include "dp_panel_tu.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
|
||||
@@ -66,6 +71,10 @@ struct dp_ctrl_private {
|
||||
struct dp_parser *parser;
|
||||
struct dp_catalog_ctrl *catalog;
|
||||
struct dp_pll *pll;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
bool link_train_status;
|
||||
#endif
|
||||
|
||||
struct completion idle_comp;
|
||||
struct completion video_comp;
|
||||
@@ -134,6 +143,8 @@ static void dp_ctrl_push_idle(struct dp_ctrl_private *ctrl,
|
||||
if (!ctrl->power_on)
|
||||
return;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
if (!ctrl->mst_mode) {
|
||||
state = ST_PUSH_IDLE;
|
||||
goto trigger_idle;
|
||||
@@ -244,6 +255,11 @@ static void dp_ctrl_update_hw_vx_px(struct dp_ctrl_private *ctrl)
|
||||
ctrl->link->link_params.bw_code == DP_LINK_BW_8_1)
|
||||
high = true;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_redriver_linkinfo(ctrl->power, link->link_params.bw_code,
|
||||
link->phy_params.v_level, link->phy_params.p_level);
|
||||
#endif
|
||||
|
||||
ctrl->catalog->update_vx_px(ctrl->catalog,
|
||||
link->phy_params.v_level, link->phy_params.p_level, high);
|
||||
}
|
||||
@@ -449,6 +465,11 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
|
||||
|
||||
DP_DEBUG("new bw code=0x%x\n", ctrl->link->link_params.bw_code);
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
secdp_bigdata_save_item(BD_CUR_LINK_RATE,
|
||||
ctrl->link->link_params.bw_code);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -553,9 +574,26 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
|
||||
u8 const encoding = 0x1, downspread = 0x00;
|
||||
struct drm_dp_link link_info = {0};
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status(ctrl->dev) || !secdp_get_hpd_status(ctrl->dev)) {
|
||||
DP_INFO("cable is out\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
ctrl->link_train_status = false;
|
||||
#endif
|
||||
|
||||
ctrl->link->phy_params.p_level = 0;
|
||||
ctrl->link->phy_params.v_level = 0;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_check_hmd_dev(ctrl->sec, "PicoVR")) {
|
||||
DP_INFO("pico REAL Plus!\n");
|
||||
ctrl->link->phy_params.v_level = 2; /*800mV*/
|
||||
}
|
||||
#endif
|
||||
|
||||
link_info.num_lanes = ctrl->link->link_params.lane_count;
|
||||
link_info.rate = drm_dp_bw_code_to_link_rate(
|
||||
ctrl->link->link_params.bw_code);
|
||||
@@ -601,11 +639,22 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
|
||||
DP_INFO("link training #2 successful\n");
|
||||
|
||||
end:
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status(ctrl->dev) || !secdp_get_hpd_status(ctrl->dev)) {
|
||||
DP_INFO("cable is out <2>\n");
|
||||
return -EIO;
|
||||
}
|
||||
#endif
|
||||
|
||||
dp_ctrl_state_ctrl(ctrl, 0);
|
||||
/* Make sure to clear the current pattern before starting a new one */
|
||||
wmb();
|
||||
|
||||
dp_ctrl_clear_training_pattern(ctrl);
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!ret)
|
||||
ctrl->link_train_status = true;
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -613,6 +662,8 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
|
||||
goto end;
|
||||
|
||||
@@ -628,7 +679,10 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
|
||||
0x01);
|
||||
|
||||
ret = dp_ctrl_link_train(ctrl);
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (ret)
|
||||
secdp_bigdata_inc_error_cnt(ERR_LINK_TRAIN);
|
||||
#endif
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
@@ -694,6 +748,8 @@ static void dp_ctrl_disable_link_clock(struct dp_ctrl_private *ctrl)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl->power->clk_enable(ctrl->power, DP_LINK_PM, false);
|
||||
if (ctrl->pll->pll_unprepare) {
|
||||
rc = ctrl->pll->pll_unprepare(ctrl->pll);
|
||||
@@ -714,6 +770,15 @@ static void dp_ctrl_select_training_pattern(struct dp_ctrl_private *ctrl,
|
||||
else
|
||||
pattern = DP_TRAINING_PATTERN_2;
|
||||
|
||||
DP_INFO("+ pattern:%d, downgrade:%d\n", pattern, downgrade);
|
||||
|
||||
#ifdef SECDP_MAX_HBR2
|
||||
if (pattern == DP_TRAINING_PATTERN_4) {
|
||||
DP_INFO("TPS4 to TPS3\n");
|
||||
downgrade = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!downgrade)
|
||||
goto end;
|
||||
|
||||
@@ -728,6 +793,7 @@ static void dp_ctrl_select_training_pattern(struct dp_ctrl_private *ctrl,
|
||||
break;
|
||||
}
|
||||
end:
|
||||
DP_INFO("- pattern:%d\n", pattern);
|
||||
ctrl->training_2_pattern = pattern;
|
||||
}
|
||||
|
||||
@@ -739,6 +805,8 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow)
|
||||
struct dp_catalog_ctrl *catalog;
|
||||
struct dp_link_params *link_params;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
catalog = ctrl->catalog;
|
||||
link_params = &ctrl->link->link_params;
|
||||
|
||||
@@ -746,6 +814,13 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow)
|
||||
link_params->lane_count);
|
||||
|
||||
while (1) {
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!secdp_get_cable_status(ctrl->dev) || !secdp_get_hpd_status(ctrl->dev)) {
|
||||
DP_INFO("cable is out\n");
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
DP_DEBUG("bw_code=%d, lane_count=%d\n",
|
||||
link_params->bw_code, link_params->lane_count);
|
||||
|
||||
@@ -785,6 +860,14 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl, bool shallow)
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP) && !defined(SECDP_AUDIO_CTS)
|
||||
if ((ctrl->link->link_params.bw_code == DP_LINK_BW_1_62 && downgrade) ||
|
||||
!secdp_get_cable_status(ctrl->dev) || !secdp_get_hpd_status(ctrl->dev)) {
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!link_train_max_retries || atomic_read(&ctrl->aborted)) {
|
||||
dp_ctrl_disable_link_clock(ctrl);
|
||||
break;
|
||||
@@ -813,6 +896,8 @@ static int dp_ctrl_enable_stream_clocks(struct dp_ctrl_private *ctrl,
|
||||
enum dp_pm_type clk_type;
|
||||
char clk_name[32] = "";
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ret = ctrl->power->set_pixel_clk_parent(ctrl->power,
|
||||
dp_panel->stream_id);
|
||||
|
||||
@@ -850,6 +935,8 @@ static int dp_ctrl_disable_stream_clocks(struct dp_ctrl_private *ctrl,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
if (dp_panel->stream_id == DP_STREAM_0) {
|
||||
return ctrl->power->clk_enable(ctrl->power,
|
||||
DP_STREAM0_PM, false);
|
||||
@@ -873,6 +960,8 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
|
||||
ctrl->orientation = flip;
|
||||
@@ -904,6 +993,8 @@ static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
|
||||
ctrl->catalog->enable_irq(ctrl->catalog, false);
|
||||
@@ -982,6 +1073,8 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
|
||||
ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
|
||||
@@ -1104,13 +1197,105 @@ static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
|
||||
dp_link_get_phy_test_pattern(pattern_requested));
|
||||
}
|
||||
|
||||
static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl,
|
||||
struct dp_panel *panel, u32 *p_x_int, u32 *p_y_frac_enum)
|
||||
{
|
||||
u64 min_slot_cnt, max_slot_cnt;
|
||||
u64 raw_target_sc, target_sc_fixp;
|
||||
u64 ts_denom, ts_enum, ts_int;
|
||||
u64 pclk = panel->pinfo.pixel_clk_khz;
|
||||
u64 lclk = 0;
|
||||
u64 lanes = ctrl->link->link_params.lane_count;
|
||||
u64 bpp = panel->pinfo.bpp;
|
||||
u64 pbn = panel->pinfo.pbn_no_overhead; // before dsc/fec overhead
|
||||
u64 numerator, denominator, temp, temp1, temp2;
|
||||
u32 x_int = 0, y_frac_enum = 0;
|
||||
u64 target_strm_sym, ts_int_fixp, ts_frac_fixp, y_frac_enum_fixp;
|
||||
|
||||
lclk = drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code);
|
||||
if (panel->pinfo.comp_info.enabled)
|
||||
bpp = panel->pinfo.comp_info.tgt_bpp;
|
||||
|
||||
/* min_slot_cnt */
|
||||
numerator = pclk * bpp * 64 * 1000;
|
||||
denominator = lclk * lanes * 8 * 1000;
|
||||
min_slot_cnt = drm_fixp_from_fraction(numerator, denominator);
|
||||
|
||||
/* max_slot_cnt */
|
||||
numerator = pbn * 54 * 1000;
|
||||
denominator = lclk * lanes;
|
||||
max_slot_cnt = drm_fixp_from_fraction(numerator, denominator);
|
||||
|
||||
/* raw_target_sc */
|
||||
numerator = max_slot_cnt + min_slot_cnt;
|
||||
denominator = drm_fixp_from_fraction(2, 1);
|
||||
raw_target_sc = drm_fixp_div(numerator, denominator);
|
||||
|
||||
DP_DEBUG("raw_target_sc before overhead:0x%llx\n", raw_target_sc);
|
||||
DP_DEBUG("dsc_overhead_fp:0x%llx\n", panel->pinfo.dsc_overhead_fp);
|
||||
|
||||
/* apply fec and dsc overhead factor */
|
||||
if (panel->pinfo.dsc_overhead_fp)
|
||||
raw_target_sc = drm_fixp_mul(raw_target_sc,
|
||||
panel->pinfo.dsc_overhead_fp);
|
||||
|
||||
if (panel->fec_overhead_fp)
|
||||
raw_target_sc = drm_fixp_mul(raw_target_sc,
|
||||
panel->fec_overhead_fp);
|
||||
|
||||
DP_DEBUG("raw_target_sc after overhead:0x%llx\n", raw_target_sc);
|
||||
|
||||
/* target_sc */
|
||||
temp = drm_fixp_from_fraction(256 * lanes, 1);
|
||||
numerator = drm_fixp_mul(raw_target_sc, temp);
|
||||
denominator = drm_fixp_from_fraction(256 * lanes, 1);
|
||||
target_sc_fixp = drm_fixp_div(numerator, denominator);
|
||||
|
||||
ts_enum = 256 * lanes;
|
||||
ts_denom = drm_fixp_from_fraction(256 * lanes, 1);
|
||||
ts_int = drm_fixp2int(target_sc_fixp);
|
||||
|
||||
temp = drm_fixp2int_ceil(raw_target_sc);
|
||||
if (temp != ts_int) {
|
||||
temp = drm_fixp_from_fraction(ts_int, 1);
|
||||
temp1 = raw_target_sc - temp;
|
||||
temp2 = drm_fixp_mul(temp1, ts_denom);
|
||||
ts_enum = drm_fixp2int(temp2);
|
||||
}
|
||||
|
||||
/* target_strm_sym */
|
||||
ts_int_fixp = drm_fixp_from_fraction(ts_int, 1);
|
||||
ts_frac_fixp = drm_fixp_from_fraction(ts_enum, drm_fixp2int(ts_denom));
|
||||
temp = ts_int_fixp + ts_frac_fixp;
|
||||
temp1 = drm_fixp_from_fraction(lanes, 1);
|
||||
target_strm_sym = drm_fixp_mul(temp, temp1);
|
||||
|
||||
/* x_int */
|
||||
x_int = drm_fixp2int(target_strm_sym);
|
||||
|
||||
/* y_enum_frac */
|
||||
temp = drm_fixp_from_fraction(x_int, 1);
|
||||
temp1 = target_strm_sym - temp;
|
||||
temp2 = drm_fixp_from_fraction(256, 1);
|
||||
y_frac_enum_fixp = drm_fixp_mul(temp1, temp2);
|
||||
|
||||
temp1 = drm_fixp2int(y_frac_enum_fixp);
|
||||
temp2 = drm_fixp2int_ceil(y_frac_enum_fixp);
|
||||
|
||||
y_frac_enum = (u32)((temp1 == temp2) ? temp1 : temp1 + 1);
|
||||
|
||||
panel->mst_target_sc = raw_target_sc;
|
||||
*p_x_int = x_int;
|
||||
*p_y_frac_enum = y_frac_enum;
|
||||
|
||||
DP_DEBUG("x_int: %d, y_frac_enum: %d\n", x_int, y_frac_enum);
|
||||
}
|
||||
|
||||
static void dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl,
|
||||
struct dp_panel *panel)
|
||||
{
|
||||
u32 x_int, y_frac_enum;
|
||||
u32 x_int, y_frac_enum, lanes, bw_code;
|
||||
int i;
|
||||
struct dp_tu_mst_rg_in mst_rg_calc_in;
|
||||
struct dp_tu_mst_rg_out mst_rg_calc_out;
|
||||
|
||||
if (!ctrl->mst_mode)
|
||||
return;
|
||||
@@ -1124,21 +1309,10 @@ static void dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl,
|
||||
ctrl->mst_ch_info.slot_info[i].tot_slots);
|
||||
}
|
||||
|
||||
mst_rg_calc_in.lclk_khz = drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code);
|
||||
mst_rg_calc_in.pclk_khz = panel->pinfo.pixel_clk_khz;
|
||||
mst_rg_calc_in.nlanes = ctrl->link->link_params.lane_count;
|
||||
mst_rg_calc_in.src_bpp = panel->pinfo.bpp;
|
||||
mst_rg_calc_in.tgt_bpp = panel->pinfo.comp_info.tgt_bpp;
|
||||
mst_rg_calc_in.fec_en = panel->fec_overhead_fp ? 1 : 0;
|
||||
mst_rg_calc_in.dsc_en = panel->pinfo.comp_info.enabled ? 1 : 0;
|
||||
mst_rg_calc_in.fec_overhead_fp = panel->fec_overhead_fp;
|
||||
mst_rg_calc_in.dsc_overhead_fp = panel->pinfo.dsc_overhead_fp;
|
||||
mst_rg_calc_in.pbn = panel->pbn;
|
||||
lanes = ctrl->link->link_params.lane_count;
|
||||
bw_code = ctrl->link->link_params.bw_code;
|
||||
|
||||
dp_tu_mst_rg_calc(&mst_rg_calc_in, &mst_rg_calc_out);
|
||||
|
||||
x_int = mst_rg_calc_out.x_int;
|
||||
y_frac_enum = mst_rg_calc_out.y_frac_enum;
|
||||
dp_ctrl_mst_calculate_rg(ctrl, panel, &x_int, &y_frac_enum);
|
||||
|
||||
ctrl->catalog->update_rg(ctrl->catalog, panel->stream_id,
|
||||
x_int, y_frac_enum);
|
||||
@@ -1148,8 +1322,7 @@ static void dp_ctrl_mst_stream_setup(struct dp_ctrl_private *ctrl,
|
||||
panel->channel_start_slot, panel->channel_total_slots);
|
||||
|
||||
DP_MST_DEBUG("mst lane_cnt:%d, bw:%d, x_int:%d, y_frac:%d\n",
|
||||
ctrl->link->link_params.lane_count,
|
||||
ctrl->link->link_params.bw_code, x_int, y_frac_enum);
|
||||
lanes, bw_code, x_int, y_frac_enum);
|
||||
}
|
||||
|
||||
static void dp_ctrl_dsc_setup(struct dp_ctrl_private *ctrl, struct dp_panel *panel)
|
||||
@@ -1157,7 +1330,6 @@ static void dp_ctrl_dsc_setup(struct dp_ctrl_private *ctrl, struct dp_panel *pan
|
||||
int rlen;
|
||||
u32 dsc_enable;
|
||||
struct dp_panel_info *pinfo = &panel->pinfo;
|
||||
u8 dsc_status = 0;
|
||||
|
||||
if (!ctrl->fec_mode)
|
||||
return;
|
||||
@@ -1171,14 +1343,6 @@ static void dp_ctrl_dsc_setup(struct dp_ctrl_private *ctrl, struct dp_panel *pan
|
||||
if (ctrl->mst_mode && (panel->stream_id == DP_STREAM_1) && !dsc_enable)
|
||||
return;
|
||||
|
||||
if (dsc_enable && ctrl->mst_mode && (ctrl->stream_count > 1)) {
|
||||
drm_dp_dpcd_readb(ctrl->aux->drm_aux, DP_DSC_ENABLE, &dsc_status);
|
||||
|
||||
// Avoid writing DP_DSC_ENABLE if it is already enabled.
|
||||
if (dsc_status & DP_DECOMPRESSION_EN)
|
||||
return;
|
||||
}
|
||||
|
||||
rlen = drm_dp_dpcd_writeb(ctrl->aux->drm_aux, DP_DSC_ENABLE,
|
||||
dsc_enable);
|
||||
if (rlen < 1)
|
||||
@@ -1194,6 +1358,8 @@ static int dp_ctrl_stream_on(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
|
||||
if (!dp_ctrl || !panel)
|
||||
return -EINVAL;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
|
||||
if (!ctrl->power_on) {
|
||||
@@ -1256,6 +1422,8 @@ static void dp_ctrl_mst_stream_pre_off(struct dp_ctrl *dp_ctrl,
|
||||
if (!ctrl->mst_mode)
|
||||
return;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) {
|
||||
ctrl->catalog->channel_alloc(ctrl->catalog,
|
||||
i,
|
||||
@@ -1283,6 +1451,8 @@ static void dp_ctrl_stream_pre_off(struct dp_ctrl *dp_ctrl,
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
|
||||
dp_ctrl_push_idle(ctrl, panel->stream_id);
|
||||
@@ -1297,6 +1467,8 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
|
||||
if (!dp_ctrl || !panel)
|
||||
return;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
|
||||
if (!ctrl->power_on)
|
||||
@@ -1309,6 +1481,16 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)
|
||||
ctrl->stream_count--;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_get_link_train_status(struct dp_ctrl *dp_ctrl)
|
||||
{
|
||||
struct dp_ctrl_private *ctrl;
|
||||
|
||||
ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
|
||||
return ctrl->link_train_status;
|
||||
}
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
|
||||
bool fec_mode, bool dsc_mode, bool shallow)
|
||||
{
|
||||
@@ -1342,13 +1524,17 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool mst_mode,
|
||||
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) {
|
||||
DP_DEBUG("using phy test link parameters\n");
|
||||
} else {
|
||||
#if defined(CONFIG_SECDP) && defined(SECDP_OPTIMAL_LINK_RATE)
|
||||
if (!ctrl->panel->tbox && !ctrl->parser->mst_support)
|
||||
rate = secdp_gen_link_clk(ctrl->panel);
|
||||
#endif
|
||||
ctrl->link->link_params.bw_code =
|
||||
drm_dp_link_rate_to_bw_code(rate);
|
||||
ctrl->link->link_params.lane_count =
|
||||
ctrl->panel->link_info.num_lanes;
|
||||
}
|
||||
|
||||
DP_DEBUG("bw_code=%d, lane_count=%d\n",
|
||||
DP_INFO("bw_code=%d, lane_count=%d\n",
|
||||
ctrl->link->link_params.bw_code,
|
||||
ctrl->link->link_params.lane_count);
|
||||
|
||||
@@ -1375,6 +1561,8 @@ static void dp_ctrl_off(struct dp_ctrl *dp_ctrl)
|
||||
if (!ctrl->power_on)
|
||||
return;
|
||||
|
||||
DP_ENTER("power_on: %d\n", ctrl->power_on);
|
||||
|
||||
ctrl->catalog->fec_config(ctrl->catalog, false);
|
||||
dp_ctrl_configure_source_link_params(ctrl, false);
|
||||
dp_ctrl_state_ctrl(ctrl, 0);
|
||||
@@ -1500,6 +1688,9 @@ struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in)
|
||||
ctrl->aux = in->aux;
|
||||
ctrl->link = in->link;
|
||||
ctrl->catalog = in->catalog;
|
||||
#if defined(CONFIG_SECDP)
|
||||
ctrl->sec = in->sec;
|
||||
#endif
|
||||
ctrl->pll = in->pll;
|
||||
ctrl->dev = in->dev;
|
||||
ctrl->mst_mode = false;
|
||||
|
||||
@@ -46,9 +46,16 @@ struct dp_ctrl_in {
|
||||
struct dp_power *power;
|
||||
struct dp_catalog_ctrl *catalog;
|
||||
struct dp_pll *pll;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in);
|
||||
void dp_ctrl_put(struct dp_ctrl *dp_ctrl);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_get_link_train_status(struct dp_ctrl *dp_ctrl);
|
||||
#endif
|
||||
|
||||
#endif /* _DP_CTRL_H_ */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@@ -25,6 +25,9 @@
|
||||
#include "dp_hpd.h"
|
||||
#include "dp_mst_sim.h"
|
||||
#include "dp_mst_drm.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG_NAME "drm_dp"
|
||||
|
||||
@@ -163,6 +166,16 @@ static ssize_t dp_debug_write_edid(struct file *file,
|
||||
if (copy_from_user(buf, user_buff, size))
|
||||
goto bail;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!strncmp(buf, "reset", 5)) {
|
||||
DP_DEBUG("disable SIM_MODE_EDID\n");
|
||||
dp_debug_disable_sim_mode(debug, DP_SIM_MODE_EDID);
|
||||
kfree(buf);
|
||||
mutex_unlock(&debug->lock);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
edid_size = size / char_to_nib;
|
||||
buf_t = buf;
|
||||
size = edid_size;
|
||||
@@ -962,10 +975,8 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file,
|
||||
|
||||
/* Leave room for termination char */
|
||||
len = min_t(size_t, count, SZ_8 - 1);
|
||||
if (copy_from_user(buf, user_buff, len)) {
|
||||
mutex_unlock(&debug->lock);
|
||||
if (copy_from_user(buf, user_buff, len))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
@@ -2408,15 +2419,6 @@ static int dp_debug_init_configs(struct dp_debug_private *debug,
|
||||
|
||||
}
|
||||
|
||||
static int dp_debug_init_fifo_error(struct dp_debug_private *debug,
|
||||
struct dentry *dir)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
debugfs_create_bool("fifo_error_enable", 0644, dir, &debug->parser->fifo_error_enable);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int dp_debug_init(struct dp_debug *dp_debug)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -2491,10 +2493,6 @@ static int dp_debug_init(struct dp_debug *dp_debug)
|
||||
if (rc)
|
||||
goto error_remove_dir;
|
||||
|
||||
rc = dp_debug_init_fifo_error(debug, dir);
|
||||
if (rc)
|
||||
goto error_remove_dir;
|
||||
|
||||
return 0;
|
||||
|
||||
error_remove_dir:
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
DP_ERR_V(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
#define DP_DEBUG_V(fmt, ...) \
|
||||
do { \
|
||||
if (drm_debug_enabled(DRM_UT_KMS)) \
|
||||
@@ -80,6 +81,47 @@
|
||||
#define DP_ERR_RATELIMITED_V(fmt, ...) \
|
||||
pr_err_ratelimited("[drm:%s][msm-dp-err][%-4d]"fmt, __func__, \
|
||||
current->pid, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DP_DEBUG_V(fmt, ...) \
|
||||
do { \
|
||||
if (drm_debug_enabled(DRM_UT_KMS)) \
|
||||
DRM_DEBUG("[msm-dp-debug][%-4d]"fmt, current->pid, \
|
||||
##__VA_ARGS__); \
|
||||
else \
|
||||
pr_debug(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_INFO_V(fmt, ...) \
|
||||
do { \
|
||||
if (drm_debug_enabled(DRM_UT_KMS)) \
|
||||
DRM_INFO("[msm-dp-info][%-4d]"fmt, current->pid, \
|
||||
##__VA_ARGS__); \
|
||||
else \
|
||||
pr_info(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define DP_WARN_V(fmt, ...) pr_warn(fmt, ##__VA_ARGS__)
|
||||
#define DP_WARN_RATELIMITED_V(fmt, ...) pr_warn(fmt, ##__VA_ARGS__)
|
||||
#define DP_ERR_V(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
|
||||
#define DP_ERR_RATELIMITED_V(fmt, ...) pr_err(fmt, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
extern bool secdp_func_trace;
|
||||
#define DP_ENTER(fmt, ...) \
|
||||
do { \
|
||||
if (secdp_func_trace) \
|
||||
pr_debug("+++ " pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define DP_LEAVE(fmt, ...) \
|
||||
do { \
|
||||
if (secdp_func_trace) \
|
||||
pr_debug("--- " pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#else
|
||||
#define DP_ENTER(fmt, ...) do {} while (0)
|
||||
#define DP_LEAVE(fmt, ...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define DEFAULT_DISCONNECT_DELAY_MS 0
|
||||
#define MAX_DISCONNECT_DELAY_MS 10000
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -161,4 +161,11 @@ static inline int dp_display_mmrm_callback(struct mmrm_client_notifier_data *not
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_DRM_MSM_DP */
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_debug_set_ssc(struct secdp_misc *sec, bool onoff);
|
||||
bool secdp_debug_get_ssc(struct secdp_misc *sec);
|
||||
int secdp_show_hmd_dev(struct secdp_misc *sec, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
|
||||
#endif /* _DP_DISPLAY_H_ */
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include "dp_drm.h"
|
||||
#include "dp_mst_drm.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
|
||||
@@ -85,6 +88,8 @@ static void dp_bridge_pre_enable(struct drm_bridge *drm_bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
dp = bridge->display;
|
||||
|
||||
@@ -133,6 +138,8 @@ static void dp_bridge_enable(struct drm_bridge *drm_bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
@@ -163,6 +170,8 @@ static void dp_bridge_disable(struct drm_bridge *drm_bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
@@ -202,6 +211,8 @@ static void dp_bridge_post_disable(struct drm_bridge *drm_bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
bridge = to_dp_bridge(drm_bridge);
|
||||
if (!bridge->connector) {
|
||||
DP_ERR("Invalid connector\n");
|
||||
@@ -381,7 +392,7 @@ int dp_connector_set_colorspace(struct drm_connector *connector,
|
||||
|
||||
sde_conn = to_sde_connector(connector);
|
||||
if (!sde_conn->drv_panel) {
|
||||
pr_err("invalid dp panel\n");
|
||||
DP_ERR("invalid dp panel\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@@ -601,7 +612,12 @@ int dp_connector_atomic_check(struct drm_connector *connector,
|
||||
* to configure the new colorspace in HW
|
||||
*/
|
||||
if (c_state->colorspace != old_state->colorspace) {
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG("colorspace has been updated\n");
|
||||
#else
|
||||
DP_INFO("colorspace has been updated %d %d\n",
|
||||
old_state->colorspace, c_state->colorspace);
|
||||
#endif
|
||||
sde_conn->colorspace_updated = true;
|
||||
}
|
||||
|
||||
@@ -641,7 +657,7 @@ int dp_connector_get_modes(struct drm_connector *connector,
|
||||
*/
|
||||
rc = dp->get_modes(dp, sde_conn->drv_panel, dp_mode);
|
||||
if (!rc) {
|
||||
DP_WARN("failed to get DP sink modes, adding failsafe");
|
||||
DP_WARN("failed to get DP sink modes, adding failsafe\n");
|
||||
init_failsafe_mode(dp_mode);
|
||||
}
|
||||
if (dp_mode->timing.pixel_clk_khz) /* valid DP mode */
|
||||
|
||||
@@ -19,6 +19,9 @@
|
||||
#include <linux/of_gpio.h>
|
||||
#include "dp_gpio_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
struct dp_gpio_hpd_private {
|
||||
struct device *dev;
|
||||
@@ -40,6 +43,8 @@ static int dp_gpio_hpd_connect(struct dp_gpio_hpd_private *gpio_hpd, bool hpd)
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
gpio_hpd->base.hpd_high = hpd;
|
||||
gpio_hpd->base.alt_mode_cfg_done = hpd;
|
||||
gpio_hpd->base.hpd_irq = false;
|
||||
@@ -71,6 +76,8 @@ static int dp_gpio_hpd_attention(struct dp_gpio_hpd_private *gpio_hpd)
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
gpio_hpd->base.hpd_irq = true;
|
||||
|
||||
if (gpio_hpd->cb && gpio_hpd->cb->attention)
|
||||
@@ -127,6 +134,8 @@ static void dp_gpio_hpd_work(struct work_struct *work)
|
||||
struct dp_gpio_hpd_private, work);
|
||||
int ret;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
if (gpio_hpd->hpd) {
|
||||
devm_free_irq(gpio_hpd->dev,
|
||||
gpio_hpd->irq, gpio_hpd);
|
||||
@@ -162,6 +171,8 @@ static int dp_gpio_hpd_simulate_connect(struct dp_hpd *dp_hpd, bool hpd)
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
dp_gpio_hpd_connect(gpio_hpd, hpd);
|
||||
@@ -180,6 +191,8 @@ static int dp_gpio_hpd_simulate_attention(struct dp_hpd *dp_hpd, int vdo)
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
dp_gpio_hpd_attention(gpio_hpd);
|
||||
@@ -238,6 +251,8 @@ struct dp_hpd *dp_gpio_hpd_get(struct device *dev,
|
||||
goto error;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
gpio_hpd = devm_kzalloc(dev, sizeof(*gpio_hpd), GFP_KERNEL);
|
||||
if (!gpio_hpd) {
|
||||
rc = -ENOMEM;
|
||||
@@ -295,6 +310,8 @@ void dp_gpio_hpd_put(struct dp_hpd *dp_hpd)
|
||||
if (!dp_hpd)
|
||||
return;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
gpio_hpd = container_of(dp_hpd, struct dp_gpio_hpd_private, base);
|
||||
|
||||
gpio_free(gpio_hpd->gpio_cfg.gpio);
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
#include "sde_hdcp_2x.h"
|
||||
#include "dp_debug.h"
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
#include <linux/secdp_logger.h>
|
||||
#endif
|
||||
|
||||
#define DP_INTR_STATUS2 (0x00000024)
|
||||
#define DP_INTR_STATUS3 (0x00000028)
|
||||
#define dp_read(offset) readl_relaxed((offset))
|
||||
@@ -656,6 +660,10 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
|
||||
}
|
||||
|
||||
cp_irq = buf & BIT(2);
|
||||
#ifdef SECDP_TEST_HDCP2P2_REAUTH
|
||||
cp_irq = true;
|
||||
DP_DEBUG("[HDCP2P2_REAUTH_TEST]\n");
|
||||
#endif
|
||||
DP_DEBUG("cp_irq=0x%x\n", cp_irq);
|
||||
buf = 0;
|
||||
|
||||
@@ -668,6 +676,9 @@ static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl,
|
||||
goto error;
|
||||
}
|
||||
*rx_status = buf;
|
||||
#ifdef SECDP_TEST_HDCP2P2_REAUTH
|
||||
*rx_status = 0x8;
|
||||
#endif
|
||||
DP_DEBUG("rx_status=0x%x\n", *rx_status);
|
||||
}
|
||||
|
||||
@@ -795,6 +806,15 @@ static bool dp_hdcp2p2_supported(void *input)
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
{
|
||||
u32 i;
|
||||
|
||||
for (i = 0; i < DP_HDCP_RXCAPS_LENGTH; i++)
|
||||
DP_DEBUG("rxcaps[%d] 0x%x\n", i, buf[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
DP_DEBUG("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1);
|
||||
DP_DEBUG("VERSION=%d\n", buf[0]);
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "dp_lphw_hpd.h"
|
||||
#include "dp_debug.h"
|
||||
#include "dp_bridge_hpd.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
static void dp_hpd_host_init(struct dp_hpd *dp_hpd,
|
||||
struct dp_catalog_hpd *catalog)
|
||||
@@ -48,6 +51,8 @@ struct dp_hpd *dp_hpd_get(struct device *dev, struct dp_parser *parser,
|
||||
{
|
||||
struct dp_hpd *dp_hpd = NULL;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
if (aux_bridge && (aux_bridge->flag & DP_AUX_BRIDGE_HPD)) {
|
||||
dp_hpd = dp_bridge_hpd_get(dev, cb, aux_bridge);
|
||||
if (!IS_ERR(dp_hpd)) {
|
||||
@@ -100,6 +105,8 @@ void dp_hpd_put(struct dp_hpd *dp_hpd)
|
||||
if (!dp_hpd)
|
||||
return;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
switch (dp_hpd->type) {
|
||||
case DP_HPD_USBPD:
|
||||
dp_usbpd_put(dp_hpd);
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
#include "dp_link.h"
|
||||
#include "dp_panel.h"
|
||||
#include "dp_debug.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
#include <linux/secdp_bigdata.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum dynamic_range {
|
||||
DP_DYNAMIC_RANGE_RGB_VESA = 0x00,
|
||||
@@ -903,6 +909,12 @@ static void dp_link_parse_sink_status_field(struct dp_link_private *link)
|
||||
link->link_status);
|
||||
if (len < DP_LINK_STATUS_SIZE)
|
||||
DP_ERR("DP link status read failed\n");
|
||||
#if defined(CONFIG_SECDP)
|
||||
else
|
||||
DP_INFO("[202h-207h] %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
link->link_status[0], link->link_status[1], link->link_status[2],
|
||||
link->link_status[3], link->link_status[4], link->link_status[5]);
|
||||
#endif
|
||||
dp_link_parse_request(link);
|
||||
}
|
||||
|
||||
@@ -965,6 +977,8 @@ static int dp_link_psm_config(struct dp_link *dp_link,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DP_INFO("psm_config %d\n", enable);
|
||||
|
||||
link = container_of(dp_link, struct dp_link_private, dp_link);
|
||||
|
||||
if (enable)
|
||||
@@ -1268,6 +1282,106 @@ static void dp_link_reset_data(struct dp_link_private *link)
|
||||
link->dp_link.test_response = 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool secdp_get_poor_connection_status(struct dp_link *dp_link)
|
||||
{
|
||||
return dp_link->poor_connection;
|
||||
}
|
||||
|
||||
void secdp_clear_link_status_cnt(struct dp_link *dp_link)
|
||||
{
|
||||
dp_link->poor_connection = false;
|
||||
dp_link->status_update_cnt = 0;
|
||||
}
|
||||
|
||||
/** refer to dp_link_parse_sink_status_field() */
|
||||
void secdp_read_link_status(struct dp_link *dp_link)
|
||||
{
|
||||
struct dp_link_private *link;
|
||||
int len = 0;
|
||||
|
||||
if (!dp_link) {
|
||||
DP_ERR("invalid input\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
link = container_of(dp_link, struct dp_link_private, dp_link);
|
||||
if (!link) {
|
||||
DP_ERR("link is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
len = drm_dp_dpcd_read_link_status(link->aux->drm_aux,
|
||||
link->link_status);
|
||||
if (len < DP_LINK_STATUS_SIZE) {
|
||||
DP_ERR("DP link status read failed %d\n", len);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_INFO("[202h-207h] %02x-%02x-%02x-%02x-%02x-%02x\n",
|
||||
link->link_status[0], link->link_status[1], link->link_status[2],
|
||||
link->link_status[3], link->link_status[4], link->link_status[5]);
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @retval true if connection is stable
|
||||
* @retval false if connection is unstable(poor)
|
||||
*/
|
||||
bool secdp_check_link_stable(struct dp_link *dp_link)
|
||||
{
|
||||
bool stable = false;
|
||||
struct dp_link_private *link;
|
||||
|
||||
if (!dp_link) {
|
||||
DP_ERR("invalid input\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
link = container_of(dp_link, struct dp_link_private, dp_link);
|
||||
if (!link) {
|
||||
DP_ERR("link is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
|
||||
DP_INTERLANE_ALIGN_DONE)) {
|
||||
DP_ERR("[204h] interlane_align_done is zero!\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
stable = true;
|
||||
exit:
|
||||
if (stable)
|
||||
DP_DEBUG("DP connection is stable!\n");
|
||||
|
||||
#if defined(CONFIG_SECDP_BIGDATA)
|
||||
if (!stable)
|
||||
secdp_bigdata_inc_error_cnt(ERR_INF_IRQHPD);
|
||||
#endif
|
||||
return stable;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_show_link_param(struct dp_link *dp_link, char *buf)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
rc += scnprintf(buf + rc, PAGE_SIZE - rc,
|
||||
"v_level: %u\np_level: %u\nlane_cnt: %u\nbw_code: 0x%x\n",
|
||||
dp_link->phy_params.v_level,
|
||||
dp_link->phy_params.p_level,
|
||||
dp_link->link_params.lane_count,
|
||||
dp_link->link_params.bw_code);
|
||||
|
||||
return rc;
|
||||
}
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
/**
|
||||
* dp_link_process_request() - handle HPD IRQ transition to HIGH
|
||||
* @link: pointer to link module data
|
||||
@@ -1292,6 +1406,14 @@ static int dp_link_process_request(struct dp_link *dp_link)
|
||||
|
||||
dp_link_parse_sink_status_field(link);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (secdp_get_power_status(link->dev) && !secdp_check_link_stable(dp_link)) {
|
||||
dp_link->status_update_cnt++;
|
||||
DP_INFO("[link_request] status_update_cnt %d\n",
|
||||
dp_link->status_update_cnt);
|
||||
secdp_link_backoff_start();
|
||||
}
|
||||
#endif
|
||||
if (dp_link_is_test_edid_read(link)) {
|
||||
dp_link->sink_request |= DP_TEST_LINK_EDID_READ;
|
||||
goto exit;
|
||||
|
||||
@@ -148,6 +148,11 @@ struct dp_link {
|
||||
u32 sink_request;
|
||||
u32 test_response;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool poor_connection;
|
||||
int status_update_cnt;
|
||||
#endif
|
||||
|
||||
struct dp_link_sink_count sink_count;
|
||||
struct dp_link_test_video test_video;
|
||||
struct dp_link_test_audio test_audio;
|
||||
@@ -223,6 +228,9 @@ static inline u32 dp_link_bit_depth_to_bpp(u32 tbd)
|
||||
break;
|
||||
case DP_TEST_BIT_DEPTH_UNKNOWN:
|
||||
default:
|
||||
#if defined(CONFIG_SECDP)
|
||||
pr_debug("%s: tbd(%d)\n", __func__, tbd);
|
||||
#endif
|
||||
bpp = 0;
|
||||
}
|
||||
|
||||
@@ -245,4 +253,15 @@ struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux, u32 dp_core_
|
||||
*/
|
||||
void dp_link_put(struct dp_link *dp_link);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
void secdp_clear_link_status_cnt(struct dp_link *dp_link);
|
||||
void secdp_read_link_status(struct dp_link *dp_link);
|
||||
bool secdp_check_link_stable(struct dp_link *dp_link);
|
||||
bool secdp_get_poor_connection_status(struct dp_link *dp_link);
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
int secdp_show_link_param(struct dp_link *dp_link, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#endif /* _DP_LINK_H_ */
|
||||
|
||||
@@ -52,6 +52,9 @@
|
||||
#include "dp_drm.h"
|
||||
#include "dp_debug.h"
|
||||
#include "dp_parser.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include "secdp.h"
|
||||
#endif
|
||||
|
||||
#define DP_MST_DEBUG(fmt, ...) DP_DEBUG(fmt, ##__VA_ARGS__)
|
||||
#define DP_MST_INFO(fmt, ...) DP_INFO(fmt, ##__VA_ARGS__)
|
||||
@@ -61,7 +64,6 @@
|
||||
#define MAX_DP_MST_DRM_ENCODERS 2
|
||||
#define MAX_DP_MST_DRM_BRIDGES 2
|
||||
#define HPD_STRING_SIZE 30
|
||||
#define UPDATE_PAYLOAD_RETRY_CNT 3
|
||||
#define DP_MST_CONN_ID(bridge) ((bridge)->connector ? \
|
||||
(bridge)->connector->base.id : 0)
|
||||
|
||||
@@ -343,8 +345,10 @@ static int dp_mst_calc_pbn_mode(struct dp_display_mode *dp_mode)
|
||||
pbn = drm_fixp2int(pbn_fp);
|
||||
pinfo->pbn = pbn;
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_DEBUG_V("pbn before overhead:%d pbn final:%d, bpp:%d\n", pinfo->pbn_no_overhead, pbn,
|
||||
bpp);
|
||||
#endif
|
||||
|
||||
return pbn;
|
||||
}
|
||||
@@ -657,7 +661,7 @@ static int _dp_mst_bridge_pre_enable_part1(struct dp_mst_bridge *dp_bridge)
|
||||
struct drm_dp_mst_atomic_payload *payload;
|
||||
#endif
|
||||
bool ret;
|
||||
int pbn, slots, i;
|
||||
int pbn, slots;
|
||||
int rc = 0;
|
||||
|
||||
DP_MST_DEBUG_V("enter\n");
|
||||
@@ -690,18 +694,8 @@ static int _dp_mst_bridge_pre_enable_part1(struct dp_mst_bridge *dp_bridge)
|
||||
|
||||
drm_dp_mst_update_slots(mst_state, DP_CAP_ANSI_8B10B);
|
||||
|
||||
for (i = 0; i < UPDATE_PAYLOAD_RETRY_CNT; i++) {
|
||||
rc = mst->mst_fw_cbs->update_payload_part1(&mst->mst_mgr,
|
||||
mst_state, payload);
|
||||
if (rc && (i != UPDATE_PAYLOAD_RETRY_CNT-1)) {
|
||||
DP_WARN("payload allocation failure for conn:%d, retries:%d\n",
|
||||
DP_MST_CONN_ID(dp_bridge), i+1);
|
||||
msleep(100);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rc = mst->mst_fw_cbs->update_payload_part1(&mst->mst_mgr,
|
||||
mst_state, payload);
|
||||
if (rc) {
|
||||
DP_ERR("payload allocation failure for conn:%d\n", DP_MST_CONN_ID(dp_bridge));
|
||||
goto end;
|
||||
@@ -1258,6 +1252,9 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector,
|
||||
struct dp_display_mode *dp_mode = NULL;
|
||||
int rc = 0;
|
||||
struct edid *edid = NULL;
|
||||
#if defined(CONFIG_SECDP)
|
||||
u8 i;
|
||||
#endif
|
||||
|
||||
DP_MST_DEBUG_V("enter:\n");
|
||||
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, connector->base.id);
|
||||
@@ -1280,6 +1277,14 @@ static int dp_mst_connector_get_modes(struct drm_connector *connector,
|
||||
mutex_lock(&mst->edid_lock);
|
||||
c_conn->cached_edid = edid;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
for (i = 0; i <= edid->extensions; i++) {
|
||||
print_hex_dump(KERN_DEBUG, "EDID: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
edid + i, EDID_LENGTH, false);
|
||||
secdp_logger_hex_dump(edid + i, "EDID:", EDID_LENGTH);
|
||||
}
|
||||
#endif
|
||||
|
||||
duplicate_edid:
|
||||
|
||||
edid = drm_edid_duplicate(c_conn->cached_edid);
|
||||
@@ -1405,8 +1410,10 @@ int dp_mst_connector_get_mode_info(struct drm_connector *connector,
|
||||
rc = dp_connector_get_mode_info(connector, drm_mode, NULL, mode_info,
|
||||
display, avail_res);
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
DP_MST_DEBUG_V("mst connector:%d get mode info. rc:%d\n",
|
||||
connector->base.id, rc);
|
||||
#endif
|
||||
|
||||
DP_MST_DEBUG_V("exit:\n");
|
||||
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, connector->base.id);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,7 +14,6 @@
|
||||
#include "sde_edid_parser.h"
|
||||
#include "sde_connector.h"
|
||||
#include "msm_drv.h"
|
||||
#include "dp_panel_tu.h"
|
||||
|
||||
#define DP_RECEIVER_DSC_CAP_SIZE 15
|
||||
#define DP_RECEIVER_FEC_STATUS_SIZE 3
|
||||
@@ -94,6 +93,9 @@ struct dp_panel_in {
|
||||
struct drm_connector *connector;
|
||||
struct dp_panel *base_panel;
|
||||
struct dp_parser *parser;
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct secdp_misc *sec;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct dp_dsc_caps {
|
||||
@@ -132,6 +134,13 @@ struct dp_panel {
|
||||
u32 link_bw_code;
|
||||
u32 max_supported_bpp;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool tbox;
|
||||
u8 monitor_name[14]; /* max 13 chars + null */
|
||||
u32 dsp_type;
|
||||
struct dp_panel_info max_timing_info;
|
||||
#endif
|
||||
|
||||
/* By default, stream_id is assigned to DP_INVALID_STREAM.
|
||||
* Client sets the stream id value using set_stream_id interface.
|
||||
*/
|
||||
@@ -208,6 +217,21 @@ struct dp_panel {
|
||||
void (*set_lttpr_mode)(struct dp_panel *dp_panel, bool is_transparent);
|
||||
};
|
||||
|
||||
struct dp_tu_calc_input {
|
||||
u64 lclk; /* 162, 270, 540 and 810 */
|
||||
u64 pclk_khz; /* in KHz */
|
||||
u64 hactive; /* active h-width */
|
||||
u64 hporch; /* bp + fp + pulse */
|
||||
int nlanes; /* no.of.lanes */
|
||||
int bpp; /* bits */
|
||||
int pixel_enc; /* 444, 420, 422 */
|
||||
int dsc_en; /* dsc on/off */
|
||||
int async_en; /* async mode */
|
||||
int fec_en; /* fec */
|
||||
int compress_ratio; /* 2:1 = 200, 3:1 = 300, 3.75:1 = 375 */
|
||||
int num_of_dsc_slices; /* number of slices per line */
|
||||
};
|
||||
|
||||
struct dp_vc_tu_mapping_table {
|
||||
u32 vic;
|
||||
u8 lanes;
|
||||
@@ -251,5 +275,12 @@ static inline bool is_lane_count_valid(u32 lane_count)
|
||||
|
||||
struct dp_panel *dp_panel_get(struct dp_panel_in *in);
|
||||
void dp_panel_put(struct dp_panel *dp_panel);
|
||||
void dp_panel_get_dto_params(u32 pclk_factor, struct dp_dsc_dto_params *dsc_params);
|
||||
void dp_panel_calc_tu_test(struct dp_tu_calc_input *in,
|
||||
struct dp_vc_tu_mapping_table *tu_table);
|
||||
|
||||
#define SECDP_OPTIMAL_LINK_RATE /* use optimum link_rate, not max link_rate */
|
||||
#if defined(CONFIG_SECDP) && defined(SECDP_OPTIMAL_LINK_RATE)
|
||||
u32 secdp_gen_link_clk(struct dp_panel *dp_panel);
|
||||
#endif
|
||||
|
||||
#endif /* _DP_PANEL_H_ */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,98 +0,0 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2022-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DP_PANEL_TU_H_
|
||||
#define _DP_PANEL_TU_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct dp_tu_calc_input {
|
||||
u64 lclk; /* 162, 270, 540 and 810 MHz*/
|
||||
u64 pclk_khz; /* in KHz */
|
||||
u64 hactive; /* active h-width */
|
||||
u64 hporch; /* bp + fp + pulse */
|
||||
int nlanes; /* no.of.lanes */
|
||||
int bpp; /* bits */
|
||||
int pixel_enc; /* 444, 420, 422 */
|
||||
int dsc_en; /* dsc on/off */
|
||||
int async_en; /* async mode */
|
||||
int fec_en; /* fec */
|
||||
int compress_ratio; /* 2:1 = 200, 3:1 = 300, 3.75:1 = 375 */
|
||||
int num_of_dsc_slices; /* number of slices per line */
|
||||
s64 comp_bpp; /* compressed bpp = uncomp_bpp / compression_ratio */
|
||||
int ppc_div_factor; /* pass in ppc mode 2/4 */
|
||||
};
|
||||
|
||||
struct dp_tu_calc_output {
|
||||
u32 valid_boundary_link;
|
||||
u32 delay_start_link;
|
||||
bool boundary_moderation_en;
|
||||
u32 valid_lower_boundary_link;
|
||||
u32 upper_boundary_count;
|
||||
u32 lower_boundary_count;
|
||||
u32 tu_size_minus1;
|
||||
};
|
||||
|
||||
struct dp_tu_compression_info {
|
||||
u32 src_bpp;
|
||||
u32 tgt_bpp;
|
||||
u16 pic_width;
|
||||
int pclk_per_line;
|
||||
int ppc_div_factor;
|
||||
};
|
||||
|
||||
struct dp_tu_dhdr_info {
|
||||
u32 mdp_clk;
|
||||
u32 lclk;
|
||||
u32 pclk;
|
||||
u32 h_active;
|
||||
u32 nlanes;
|
||||
s64 mst_target_sc;
|
||||
bool mst_en;
|
||||
bool fec_en;
|
||||
};
|
||||
|
||||
struct dp_tu_mst_rg_in {
|
||||
u64 lclk_khz;
|
||||
u64 pclk_khz;
|
||||
u8 nlanes;
|
||||
u8 src_bpp;
|
||||
u8 tgt_bpp;
|
||||
bool fec_en;
|
||||
bool dsc_en;
|
||||
s64 fec_overhead_fp;
|
||||
s64 dsc_overhead_fp;
|
||||
u64 pbn;
|
||||
/*
|
||||
* margin_ovrd: SW control for handling margin
|
||||
* Only enabled when running 4k60fps displays on 2x MST stream
|
||||
*/
|
||||
bool margin_ovrd;
|
||||
};
|
||||
|
||||
struct dp_tu_mst_rg_out {
|
||||
u64 min_sc_fp;
|
||||
u64 max_sc_fp;
|
||||
u64 target_sc_fp;
|
||||
u64 ts_int;
|
||||
u32 x_int;
|
||||
u32 y_frac_enum;
|
||||
};
|
||||
|
||||
struct dp_dsc_dto_params {
|
||||
u32 tgt_bpp;
|
||||
u32 src_bpp;
|
||||
u32 num;
|
||||
u32 denom;
|
||||
};
|
||||
|
||||
void dp_tu_calculate(struct dp_tu_calc_input *in, struct dp_tu_calc_output *tu_table);
|
||||
u32 dp_tu_dsc_get_num_extra_pclk(u32 pclk_factor, struct dp_tu_compression_info *input);
|
||||
u32 dp_tu_dhdr_pkt_limit(struct dp_tu_dhdr_info *input);
|
||||
void dp_tu_mst_rg_calc(struct dp_tu_mst_rg_in *in, struct dp_tu_mst_rg_out *out);
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (c) 2021-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@@ -219,6 +219,42 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
enum secdp_phy_pre_emphasis_type {
|
||||
PHY_PRE_EMP0, /* 0 db */
|
||||
PHY_PRE_EMP1, /* 3.5 db */
|
||||
PHY_PRE_EMP2, /* 6.0 db */
|
||||
PHY_PRE_EMP3, /* 9.5 db */
|
||||
// MAX_PRE_EMP_LEVELS,
|
||||
};
|
||||
|
||||
enum secdp_phy_voltage_type {
|
||||
PHY_VOLTAGE_SWING0, /* 0.4 v */
|
||||
PHY_VOLTAGE_SWING1, /* 0.6 v */
|
||||
PHY_VOLTAGE_SWING2, /* 0.8 v */
|
||||
PHY_VOLTAGE_SWING3, /* 1.2 v, optional */
|
||||
MAX_VOLTAGE_LEVELS,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
enum secdp_ps5169_pre_emphasis_type {
|
||||
PHY_PS5169_EMP0, /* 0 db */
|
||||
PHY_PS5169_EMP1, /* 3.5 db */
|
||||
PHY_PS5169_EMP2, /* 6.0 db */
|
||||
PHY_PS5169_EMP3, /* 9.5 db */
|
||||
MAX_PS5169_EMP_LEVELS,
|
||||
};
|
||||
|
||||
enum secdp_PS5169_voltage_type {
|
||||
PHY_PS5169_SWING0, /* 0.4 v */
|
||||
PHY_PS5169_SWING1, /* 0.6 v */
|
||||
PHY_PS5169_SWING2, /* 0.8 v */
|
||||
PHY_PS5169_SWING3, /* 1.2 v, optional */
|
||||
MAX_PS5169_SWING_LEVELS,
|
||||
};
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
/**
|
||||
* struct dp_parser - DP parser's data exposed to clients
|
||||
*
|
||||
@@ -237,7 +273,6 @@ static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type)
|
||||
* @dsc_feature_enable: DSC feature enable status
|
||||
* @fec_feature_enable: FEC feature enable status
|
||||
* @dsc_continuous_pps: PPS sent every frame by HW
|
||||
* @fifo_error_enable : fifo error enable status
|
||||
* @has_widebus: widebus (2PPC) feature eanble status
|
||||
*@mst_fixed_port: mst port_num reserved for fixed topology
|
||||
* @qos_cpu_mask: CPU mask for QOS
|
||||
@@ -273,7 +308,6 @@ struct dp_parser {
|
||||
bool dsc_feature_enable;
|
||||
bool fec_feature_enable;
|
||||
bool dsc_continuous_pps;
|
||||
bool fifo_error_enable;
|
||||
bool has_widebus;
|
||||
bool has_4ppc_enabled;
|
||||
bool gpio_aux_switch;
|
||||
@@ -291,6 +325,35 @@ struct dp_parser {
|
||||
u8 *pre_emp_hbr_rbr;
|
||||
bool valid_lt_params;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
struct regulator *aux_pullup_vreg;
|
||||
bool cc_dir_inv; /* CC_DIR is inversed, e.g, T865 */
|
||||
bool aux_sel_inv; /* inverse control of AUX_SEL e.g, D2Xq hwid 01,02 */
|
||||
int use_redrv; /* ptn36502 needs NOT AUX switch SEL control */
|
||||
int dex_dft_res; /* DeX default resolution, e.g, HG950 */
|
||||
bool prefer_support; /* true if prefer resolution has high priority */
|
||||
bool mrr_fps_nolimit; /* true if mirroring refresh rate has no limit */
|
||||
bool rf_tx_backoff; /* true if it RF TX Backoff is supported, for SHELL-less type connector */
|
||||
bool mst_support; /* true if MST is supported */
|
||||
|
||||
u8 *preshoot0_hbr2_3;
|
||||
u8 *preshoot1_hbr2_3;
|
||||
u8 *preshoot0_rbr_hbr;
|
||||
u8 *preshoot1_rbr_hbr;
|
||||
bool valid_preshoot_params;
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
u8 ps5169_rbr_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_rbr_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr2_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr2_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr3_eq0[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
u8 ps5169_hbr3_eq1[MAX_PS5169_SWING_LEVELS][MAX_PS5169_EMP_LEVELS];
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
int (*parse)(struct dp_parser *parser);
|
||||
struct dp_io_data *(*get_io)(struct dp_parser *parser, char *name);
|
||||
void (*get_io_buf)(struct dp_parser *parser, char *name);
|
||||
@@ -331,4 +394,132 @@ struct dp_parser *dp_parser_get(struct platform_device *pdev);
|
||||
* @parser: pointer to the parser's data.
|
||||
*/
|
||||
void dp_parser_put(struct dp_parser *parser);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
enum secdp_hw_preshoot_t {
|
||||
DP_HW_PRESHOOT_0,
|
||||
DP_HW_PRESHOOT_1,
|
||||
DP_HW_PRESHOOT_MAX,
|
||||
};
|
||||
|
||||
static inline char *secdp_preshoot_to_string(int hw)
|
||||
{
|
||||
switch (hw) {
|
||||
case DP_HW_PRESHOOT_0:
|
||||
return DP_ENUM_STR(DP_HW_PRESHOOT_0);
|
||||
case DP_HW_PRESHOOT_1:
|
||||
return DP_ENUM_STR(DP_HW_PRESHOOT_1);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
enum secdp_ps5169_eq_t {
|
||||
DP_PS5169_EQ0,
|
||||
DP_PS5169_EQ1,
|
||||
DP_PS5169_EQ_MAX,
|
||||
};
|
||||
|
||||
enum secdp_ps5169_link_rate_t {
|
||||
DP_PS5169_RATE_RBR,
|
||||
DP_PS5169_RATE_HBR,
|
||||
DP_PS5169_RATE_HBR2,
|
||||
DP_PS5169_RATE_HBR3,
|
||||
DP_PS5169_RATE_MAX,
|
||||
};
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#if defined(CONFIG_SECDP_DBG)
|
||||
enum secdp_link_rate_t {
|
||||
DP_LR_NONE = 0x0,
|
||||
DP_LR_HBR_RBR = 0x1,
|
||||
DP_LR_HBR2_3 = 0x2,
|
||||
};
|
||||
|
||||
static inline char *secdp_link_rate_to_string(int lr)
|
||||
{
|
||||
switch (lr) {
|
||||
case DP_LR_HBR_RBR:
|
||||
return DP_ENUM_STR(DP_LR_HBR_RBR);
|
||||
case DP_LR_HBR2_3:
|
||||
return DP_ENUM_STR(DP_LR_HBR2_3);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
enum secdp_phy_param_t {
|
||||
DP_PARAM_NONE = 0x0,
|
||||
DP_PARAM_VX = 0x1, /* voltage swing */
|
||||
DP_PARAM_PX = 0x2, /* pre-emphasis */
|
||||
};
|
||||
|
||||
static inline char *secdp_phy_type_to_string(int param)
|
||||
{
|
||||
switch (param) {
|
||||
case DP_PARAM_VX:
|
||||
return DP_ENUM_STR(DP_PARAM_VX);
|
||||
case DP_PARAM_PX:
|
||||
return DP_ENUM_STR(DP_PARAM_PX);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
/* voltage swing, pre-emphasis */
|
||||
int secdp_parse_vxpx_show(struct dp_parser *parser, enum secdp_link_rate_t lr,
|
||||
enum secdp_phy_param_t vxpx, char *buf);
|
||||
int secdp_parse_vxpx_store(struct dp_parser *parser, enum secdp_link_rate_t lr,
|
||||
enum secdp_phy_param_t vxpx, char *buf);
|
||||
int secdp_show_phy_param(struct dp_parser *parser, char *buf);
|
||||
|
||||
int secdp_parse_preshoot_show(struct dp_parser *parser, enum secdp_link_rate_t lr,
|
||||
enum secdp_hw_preshoot_t prst, char *buf);
|
||||
int secdp_parse_preshoot_store(struct dp_parser *parser, enum secdp_link_rate_t lr,
|
||||
enum secdp_hw_preshoot_t prst, char *buf);
|
||||
int secdp_show_preshoot_param(struct dp_parser *parser, char *buf);
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
static inline char *secdp_ps5169_eq_to_string(int hw)
|
||||
{
|
||||
switch (hw) {
|
||||
case DP_PS5169_EQ0:
|
||||
return DP_ENUM_STR(DP_PS5169_EQ0);
|
||||
case DP_PS5169_EQ1:
|
||||
return DP_ENUM_STR(DP_PS5169_EQ1);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *secdp_ps5169_rate_to_string(int hw)
|
||||
{
|
||||
switch (hw) {
|
||||
case DP_PS5169_RATE_RBR:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_RBR);
|
||||
case DP_PS5169_RATE_HBR:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_HBR);
|
||||
case DP_PS5169_RATE_HBR2:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_HBR2);
|
||||
case DP_PS5169_RATE_HBR3:
|
||||
return DP_ENUM_STR(DP_PS5169_RATE_HBR3);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
int secdp_parse_ps5169_show(struct dp_parser *parser, enum secdp_ps5169_eq_t eq,
|
||||
enum secdp_ps5169_link_rate_t link_rate, char *buf);
|
||||
int secdp_parse_ps5169_store(struct dp_parser *parser, enum secdp_ps5169_eq_t eq,
|
||||
enum secdp_ps5169_link_rate_t link_rate, char *buf);
|
||||
int secdp_show_ps5169_param(struct dp_parser *parser, char *buf);
|
||||
#endif/*CONFIG_COMBO_REDRIVER_PS5169*/
|
||||
|
||||
/* AUX configuration */
|
||||
int secdp_aux_cfg_show(struct dp_parser *parser, char *buf);
|
||||
int secdp_aux_cfg_store(struct dp_parser *parser, char *buf);
|
||||
#endif/*CONFIG_SECDP_DBG*/
|
||||
|
||||
#endif
|
||||
|
||||
@@ -9,6 +9,10 @@
|
||||
#include <linux/of_platform.h>
|
||||
#include "dp_debug.h"
|
||||
#include "dp_pll.h"
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include <linux/secdp_logger.h>
|
||||
#endif
|
||||
|
||||
|
||||
struct dp_pll_ver_spec_info {
|
||||
u32 revision;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2021-2025, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2021-2024, Qualcomm Innovation Center, Inc. All rights reserved.
|
||||
* Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,28 @@
|
||||
#include "dp_debug.h"
|
||||
#include "dp_pll.h"
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/delay.h>
|
||||
#include "secdp.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)// && IS_ENABLED(CONFIG_IF_CB_MANAGER)
|
||||
#include <linux/usb/typec/manager/if_cb_manager.h>
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502)
|
||||
#include <linux/combo_redriver/ptn36502.h>
|
||||
#elif IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
#include <linux/combo_redriver/ps5169.h>
|
||||
#endif
|
||||
|
||||
#define DP_LINK_BW_RBR 0x06
|
||||
#define DP_LINK_BW_HBR 0x0a
|
||||
#define DP_LINK_BW_HBR2 0x14 /* 1.2 */
|
||||
#define DP_LINK_BW_HBR3 0x1e /* 1.4 */
|
||||
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#define DP_CLIENT_NAME_SIZE 20
|
||||
#define XO_CLK_KHZ 19200
|
||||
|
||||
@@ -39,8 +61,32 @@ struct dp_power_private {
|
||||
bool strm0_clks_parked;
|
||||
bool strm1_clks_parked;
|
||||
bool link_clks_parked;
|
||||
#if defined(CONFIG_SECDP)
|
||||
bool aux_pullup_on;
|
||||
struct mutex dp_clk_lock;
|
||||
#if IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
enum sbu_switch_status sbu_status;
|
||||
#endif
|
||||
|
||||
void (*redrv_onoff)(struct dp_power_private *power,
|
||||
bool enable, int lane);
|
||||
void (*redrv_aux_ctrl)(struct dp_power_private *power, int cross);
|
||||
void (*redrv_notify_linkinfo)(struct dp_power_private *power,
|
||||
u32 bw_code, u8 v_level, u8 p_level);
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
#define DP_ENUM_STR(x) #x
|
||||
|
||||
enum redriver_switch_t {
|
||||
REDRIVER_SWITCH_UNKNOWN = -1,
|
||||
REDRIVER_SWITCH_RESET = 0,
|
||||
REDRIVER_SWITCH_CROSS,
|
||||
REDRIVER_SWITCH_THROU,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int dp_power_regulator_init(struct dp_power_private *power)
|
||||
{
|
||||
int rc = 0, i = 0, j = 0;
|
||||
@@ -89,6 +135,86 @@ static void dp_power_regulator_deinit(struct dp_power_private *power)
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
/* factory use only
|
||||
* ref: qusb_phy_enable_power()
|
||||
*/
|
||||
static int secdp_aux_pullup_vreg_enable(struct dp_power_private *power, bool on)
|
||||
{
|
||||
struct regulator *aux_pu_vreg;
|
||||
int rc = 0;
|
||||
|
||||
if (!power || !power->parser) {
|
||||
DP_ERR("error! power is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
aux_pu_vreg = power->parser->aux_pullup_vreg;
|
||||
if (!aux_pu_vreg) {
|
||||
DP_ERR("error! vdda33 is null\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_ENTER("on:%d\n", on);
|
||||
|
||||
#define QUSB2PHY_3P3_VOL_MIN 3104000 /* uV */
|
||||
#define QUSB2PHY_3P3_VOL_MAX 3105000 /* uV */
|
||||
#define QUSB2PHY_3P3_HPM_LOAD 30000 /* uA */
|
||||
|
||||
if (on) {
|
||||
if (power->aux_pullup_on) {
|
||||
DP_INFO("already on\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = regulator_set_load(aux_pu_vreg, QUSB2PHY_3P3_HPM_LOAD);
|
||||
if (rc < 0) {
|
||||
DP_ERR("Unable to set HPM of vdda33:%d\n", rc);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = regulator_set_voltage(aux_pu_vreg, QUSB2PHY_3P3_VOL_MIN,
|
||||
QUSB2PHY_3P3_VOL_MAX);
|
||||
if (rc) {
|
||||
DP_ERR("Unable to set voltage for vdda33:%d\n", rc);
|
||||
goto put_vdda33_lpm;
|
||||
}
|
||||
|
||||
rc = regulator_enable(aux_pu_vreg);
|
||||
if (rc) {
|
||||
DP_ERR("Unable to enable vdda33:%d\n", rc);
|
||||
goto unset_vdd33;
|
||||
}
|
||||
|
||||
DP_INFO("[AUX_PU] on success\n");
|
||||
power->aux_pullup_on = true;
|
||||
} else {
|
||||
|
||||
rc = regulator_disable(aux_pu_vreg);
|
||||
if (rc)
|
||||
DP_ERR("Unable to disable vdda33:%d\n", rc);
|
||||
|
||||
unset_vdd33:
|
||||
rc = regulator_set_voltage(aux_pu_vreg, 0,
|
||||
QUSB2PHY_3P3_VOL_MAX);
|
||||
if (rc)
|
||||
DP_ERR("Unable to set 0 voltage for vdda33:%d\n", rc);
|
||||
|
||||
put_vdda33_lpm:
|
||||
rc = regulator_set_load(aux_pu_vreg, 0);
|
||||
if (!rc)
|
||||
DP_INFO("[AUX_PU] off success\n");
|
||||
else
|
||||
DP_ERR("Unable to set 0 HPM of vdda33:%d\n", rc);
|
||||
|
||||
power->aux_pullup_on = false;
|
||||
}
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void dp_power_phy_gdsc(struct dp_power *dp_power, bool on)
|
||||
{
|
||||
int rc = 0;
|
||||
@@ -96,6 +222,8 @@ static void dp_power_phy_gdsc(struct dp_power *dp_power, bool on)
|
||||
if (IS_ERR_OR_NULL(dp_power->dp_phy_gdsc))
|
||||
return;
|
||||
|
||||
DP_ENTER("on:%d\n", on);
|
||||
|
||||
if (on)
|
||||
rc = regulator_enable(dp_power->dp_phy_gdsc);
|
||||
else
|
||||
@@ -104,6 +232,8 @@ static void dp_power_phy_gdsc(struct dp_power *dp_power, bool on)
|
||||
if (rc)
|
||||
DP_ERR("Fail to %s dp_phy_gdsc regulator ret =%d\n",
|
||||
on ? "enable" : "disable", rc);
|
||||
|
||||
DP_LEAVE("rc:%d\n", rc);
|
||||
}
|
||||
|
||||
static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable)
|
||||
@@ -144,6 +274,11 @@ static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable)
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_aux_pullup_vreg_enable(power, enable);
|
||||
#endif
|
||||
|
||||
error:
|
||||
return rc;
|
||||
}
|
||||
@@ -154,11 +289,17 @@ static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
|
||||
struct pinctrl_state *pin_state;
|
||||
struct dp_parser *parser;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
parser = power->parser;
|
||||
|
||||
if (IS_ERR_OR_NULL(parser->pinctrl.pin))
|
||||
return 0;
|
||||
|
||||
DP_DEBUG("pinctrl:%d\n", active);
|
||||
|
||||
pin_state = active ? parser->pinctrl.state_active
|
||||
: parser->pinctrl.state_suspend;
|
||||
if (!IS_ERR_OR_NULL(pin_state)) {
|
||||
@@ -168,6 +309,8 @@ static int dp_power_pinctrl_set(struct dp_power_private *power, bool active)
|
||||
DP_ERR("can not set %s pins\n",
|
||||
active ? "dp_active"
|
||||
: "dp_sleep");
|
||||
else
|
||||
DP_DEBUG("%s success\n", active ? "dp_active" : "dp_sleep");
|
||||
} else {
|
||||
DP_ERR("invalid '%s' pinstate\n",
|
||||
active ? "dp_active"
|
||||
@@ -368,7 +511,11 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
{
|
||||
int rc = 0;
|
||||
struct dss_module_power *mp;
|
||||
#if defined(CONFIG_SECDP)
|
||||
static bool prev[DP_MAX_PM];
|
||||
|
||||
mutex_lock(&power->dp_clk_lock);
|
||||
#endif
|
||||
if (!power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
rc = -EINVAL;
|
||||
@@ -377,6 +524,13 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
|
||||
mp = &power->parser->mp[module];
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (prev[module] == enable) {
|
||||
DP_DEBUG("%d clk already %s\n", module, enable ? "enabled" : "disabled");
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (enable) {
|
||||
rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk);
|
||||
if (rc) {
|
||||
@@ -398,7 +552,14 @@ static int dp_power_clk_set_rate(struct dp_power_private *power,
|
||||
|
||||
dp_power_park_module(power, module);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
prev[module] = enable;
|
||||
#endif
|
||||
exit:
|
||||
#if defined(CONFIG_SECDP)
|
||||
mutex_unlock(&power->dp_clk_lock);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -530,6 +691,8 @@ static int dp_power_request_gpios(struct dp_power_private *power)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
dev = &power->pdev->dev;
|
||||
mp = &power->parser->mp[DP_CORE_PM];
|
||||
|
||||
@@ -541,11 +704,18 @@ static int dp_power_request_gpios(struct dp_power_private *power)
|
||||
if (rc) {
|
||||
DP_ERR("request %s gpio failed, rc=%d\n",
|
||||
gpio_names[i], rc);
|
||||
#if defined(CONFIG_SECDP)
|
||||
if (!strncmp(gpio_names[i], "usbplug_cc",
|
||||
strlen(gpio_names[i]))) {
|
||||
DP_ERR("keep going\n");
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DP_LEAVE("\n");
|
||||
return 0;
|
||||
error:
|
||||
for (i = 0; i < ARRAY_SIZE(gpio_names); i++) {
|
||||
@@ -562,6 +732,7 @@ static bool dp_power_find_gpio(const char *gpio1, const char *gpio2)
|
||||
return !!strnstr(gpio1, gpio2, strlen(gpio1));
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_SECDP)
|
||||
static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int i;
|
||||
@@ -587,10 +758,465 @@ static void dp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
config++;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int secdp_power_request_gpios(struct dp_power *dp_power)
|
||||
{
|
||||
int rc;
|
||||
struct dp_power_private *power;
|
||||
|
||||
if (!dp_power) {
|
||||
DP_ERR("invalid power data\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
rc = dp_power_request_gpios(power);
|
||||
|
||||
exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502) || IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
static inline char *secdp_redriver_switch_to_string(int event)
|
||||
{
|
||||
switch (event) {
|
||||
case REDRIVER_SWITCH_UNKNOWN:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_UNKNOWN);
|
||||
case REDRIVER_SWITCH_RESET:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_RESET);
|
||||
case REDRIVER_SWITCH_CROSS:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_CROSS);
|
||||
case REDRIVER_SWITCH_THROU:
|
||||
return DP_ENUM_STR(REDRIVER_SWITCH_THROU);
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502)
|
||||
static void secdp_ptn36502_aux_ctrl(struct dp_power_private *power, int cross)
|
||||
{
|
||||
DP_DEBUG("cross:%s\n", secdp_redriver_switch_to_string(cross));
|
||||
|
||||
switch (cross) {
|
||||
case REDRIVER_SWITCH_CROSS:
|
||||
ptn36502_config(AUX_CROSS_MODE, 0);
|
||||
break;
|
||||
case REDRIVER_SWITCH_THROU:
|
||||
ptn36502_config(AUX_THRU_MODE, 0);
|
||||
break;
|
||||
case REDRIVER_SWITCH_RESET:
|
||||
ptn36502_config(SAFE_STATE, 0);
|
||||
break;
|
||||
default:
|
||||
DP_INFO("unknown: %d\n", cross);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void secdp_ptn36502_onoff(struct dp_power_private *power, bool enable, int lane)
|
||||
{
|
||||
DP_DEBUG("en:%d, lane:%d\n", enable, lane);
|
||||
|
||||
if (enable) {
|
||||
int val = -1;
|
||||
|
||||
if (lane == 2)
|
||||
ptn36502_config(DP2_LANE_USB3_MODE, 1);
|
||||
else if (lane == 4)
|
||||
ptn36502_config(DP4_LANE_MODE, 1);
|
||||
else {
|
||||
DP_ERR("error! unknown lane: %d\n", lane);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
val = ptn36502_i2c_read(Chip_ID);
|
||||
DP_INFO("Chip_ID: 0x%x\n", val);
|
||||
val = ptn36502_i2c_read(Chip_Rev);
|
||||
DP_INFO("Chip_Rev: 0x%x\n", val);
|
||||
} else {
|
||||
ptn36502_config(SAFE_STATE, 0);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void secdp_ptn36502_notify_linkinfo(struct dp_power_private *power, u32 bw_code, u8 v_level, u8 p_level)
|
||||
{
|
||||
DP_ENTER("0x%x,%d,%d, do nothing!\n", bw_code, v_level, p_level);
|
||||
|
||||
//.TODO:
|
||||
}
|
||||
#elif IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
static void secdp_ps5169_aux_ctrl(struct dp_power_private *power, int cross)
|
||||
{
|
||||
/*
|
||||
* ps5169 does not support AUX switching function.
|
||||
* It needs to be done by AUX switch IC
|
||||
*/
|
||||
DP_ENTER("cross: %s, do nothing!\n",
|
||||
secdp_redriver_switch_to_string(cross));
|
||||
}
|
||||
|
||||
static void secdp_ps5169_onoff(struct dp_power_private *power, bool enable, int lane)
|
||||
{
|
||||
DP_DEBUG("en:%d, lane:%d\n", enable, lane);
|
||||
|
||||
if (enable) {
|
||||
if (lane == 2)
|
||||
ps5169_config(DP2_LANE_USB_MODE, 1);
|
||||
else if (lane == 4)
|
||||
ps5169_config(DP_ONLY_MODE, 1);
|
||||
else {
|
||||
DP_ERR("error! unknown lane: %d\n", lane);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_INFO("Chip_ID1: 0x%x, Chip_Rev1: 0x%x\n",
|
||||
ps5169_i2c_read(Chip_ID1), ps5169_i2c_read(Chip_Rev1));
|
||||
DP_INFO("Chip_ID2: 0x%x, Chip_Rev2: 0x%x\n",
|
||||
ps5169_i2c_read(Chip_ID2), ps5169_i2c_read(Chip_Rev2));
|
||||
} else {
|
||||
ps5169_config(CLEAR_STATE, 0);
|
||||
}
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
static void secdp_ps5169_notify_linkinfo(struct dp_power_private *power,
|
||||
u32 bw_code, u8 v_level, u8 p_level)
|
||||
{
|
||||
struct dp_parser *parser = power->parser;
|
||||
u8 eq0, eq1;
|
||||
|
||||
switch (bw_code) {
|
||||
case DP_LINK_BW_RBR:
|
||||
eq0 = parser->ps5169_rbr_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_rbr_eq1[v_level][p_level];
|
||||
break;
|
||||
case DP_LINK_BW_HBR:
|
||||
eq0 = parser->ps5169_hbr_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_hbr_eq1[v_level][p_level];
|
||||
break;
|
||||
case DP_LINK_BW_HBR2:
|
||||
eq0 = parser->ps5169_hbr2_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_hbr2_eq1[v_level][p_level];
|
||||
break;
|
||||
case DP_LINK_BW_HBR3:
|
||||
default:
|
||||
eq0 = parser->ps5169_hbr3_eq0[v_level][p_level];
|
||||
eq1 = parser->ps5169_hbr3_eq1[v_level][p_level];
|
||||
break;
|
||||
}
|
||||
|
||||
DP_DEBUG("bw:0x%x, v:%d, p:%d, eq0:0x%x, eq1:0x%x\n",
|
||||
bw_code, v_level, p_level, eq0, eq1);
|
||||
ps5169_notify_dplink(eq0, eq1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void secdp_redriver_onoff(struct dp_power *dp_power,
|
||||
bool enable, int lane)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
if (power && power->redrv_onoff)
|
||||
power->redrv_onoff(power, enable, lane);
|
||||
}
|
||||
|
||||
void secdp_redriver_linkinfo(struct dp_power *dp_power,
|
||||
u32 rate, u8 v_level, u8 p_level)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
if (power && power->redrv_notify_linkinfo)
|
||||
power->redrv_notify_linkinfo(power, rate, v_level, p_level);
|
||||
}
|
||||
|
||||
static void secdp_redriver_register(struct dp_power_private *power)
|
||||
{
|
||||
int use_redrv;
|
||||
|
||||
if (!power || !power->parser) {
|
||||
DP_ERR("invalid power!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
use_redrv = power->parser->use_redrv;
|
||||
DP_DEBUG("++ use_redrv(%d)\n", use_redrv);
|
||||
|
||||
if (!use_redrv) {
|
||||
DP_INFO("nothing registered!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_COMBO_REDRIVER_PTN36502)
|
||||
power->redrv_onoff = secdp_ptn36502_onoff;
|
||||
power->redrv_aux_ctrl = secdp_ptn36502_aux_ctrl;
|
||||
power->redrv_notify_linkinfo = secdp_ptn36502_notify_linkinfo;
|
||||
DP_INFO("ptn36502 API registered!\n");
|
||||
#elif IS_ENABLED(CONFIG_COMBO_REDRIVER_PS5169)
|
||||
power->redrv_onoff = secdp_ps5169_onoff;
|
||||
power->redrv_aux_ctrl = secdp_ps5169_aux_ctrl;
|
||||
power->redrv_notify_linkinfo = secdp_ps5169_notify_linkinfo;
|
||||
DP_INFO("ps5169 API registered!\n");
|
||||
#endif
|
||||
|
||||
end:
|
||||
return;
|
||||
}
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
/* turn on EDP_AUX switch
|
||||
* ===================================================
|
||||
* | usbplug-cc(dir) | orientation | flip | aux-sel |
|
||||
* ===================================================
|
||||
* | 0 | CC1 | false | 0 |
|
||||
* | 1 | CC2 | true | 1 |
|
||||
* ===================================================
|
||||
*/
|
||||
static void _secdp_power_set_gpio(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int i, rc = 0;
|
||||
/*int dir = (flip == false) ? 0 : 1;*/
|
||||
struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
|
||||
struct dss_gpio *config = mp->gpio_config;
|
||||
struct dp_parser *parser = power->parser;
|
||||
bool sel_val = false;
|
||||
|
||||
// DP_DEBUG("flip:%d, aux_inv:%d, redrv:%d\n",
|
||||
// flip, parser->aux_sel_inv, parser->use_redrv);
|
||||
|
||||
if (parser->aux_sel_inv)
|
||||
sel_val = true;
|
||||
|
||||
for (i = 0; i <= DP_GPIO_CMN_MAX; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-sel")) {
|
||||
if (parser->use_redrv == SECDP_REDRV_PTN36502) {
|
||||
rc = gpio_direction_output(config->gpio, 0);
|
||||
} else {
|
||||
/* SECDP_REDRV_PS5169 or SECDP_REDRV_NONE */
|
||||
bool val = (bool)gpio_get_value(config->gpio);
|
||||
|
||||
if ((!flip && (val == sel_val)) ||
|
||||
(flip && (val == !sel_val))) {
|
||||
DP_DEBUG("%s: already %d %d, skip\n",
|
||||
config->gpio_name, flip, val);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio,
|
||||
(!flip ? sel_val : !sel_val));
|
||||
}
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-sel] set %d (f:%d,i:%d,r:%d) %d\n",
|
||||
gpio_get_value(config->gpio),
|
||||
flip, parser->aux_sel_inv, parser->use_redrv, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
|
||||
usleep_range(100, 120);
|
||||
config = mp->gpio_config;
|
||||
for (i = 0; i <= DP_GPIO_CMN_MAX; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-en")) {
|
||||
if (!gpio_get_value(config->gpio)) {
|
||||
DP_DEBUG("%s: already enabled, skip\n",
|
||||
config->gpio_name);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio, 0);
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-en] set %d (f:%d,i:%d,r:%d) %d\n",
|
||||
gpio_get_value(config->gpio),
|
||||
flip, parser->aux_sel_inv, parser->use_redrv, rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
}
|
||||
|
||||
/* turn off EDP_AUX switch */
|
||||
static void _secdp_power_unset_gpio(struct dp_power_private *power)
|
||||
{
|
||||
int i, rc = 0;
|
||||
struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM];
|
||||
struct dss_gpio *config = mp->gpio_config;
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-en")) {
|
||||
if (gpio_get_value(config->gpio)) {
|
||||
DP_DEBUG("%s: already disabled, skip\n",
|
||||
config->gpio_name);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio, 1);
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-en] set %d, %d\n",
|
||||
gpio_get_value(config->gpio), rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
|
||||
config = mp->gpio_config;
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name, "aux-sel")) {
|
||||
if (!gpio_get_value(config->gpio)) {
|
||||
DP_DEBUG("%s: already 0, skip\n",
|
||||
config->gpio_name);
|
||||
break;
|
||||
}
|
||||
rc = gpio_direction_output(config->gpio, 0);
|
||||
usleep_range(100, 120);
|
||||
DP_INFO("[aux-sel] set %d, %d\n",
|
||||
gpio_get_value(config->gpio), rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
}
|
||||
#else/*CONFIG_SBU_SWITCH_CONTROL*/
|
||||
static void _secdp_sbu_switch_on(struct dp_power_private *power, bool flip)
|
||||
{
|
||||
int cc_sbu = !flip ? CLOSE_SBU_CC1_ACTIVE : CLOSE_SBU_CC2_ACTIVE;
|
||||
|
||||
if (power->sbu_status == cc_sbu)
|
||||
return;
|
||||
|
||||
usbpd_sbu_switch_control(cc_sbu);
|
||||
power->sbu_status = cc_sbu;
|
||||
}
|
||||
|
||||
static void _secdp_sbu_switch_off(struct dp_power_private *power)
|
||||
{
|
||||
if (power->sbu_status == OPEN_SBU)
|
||||
return;
|
||||
|
||||
usbpd_sbu_switch_control(OPEN_SBU);
|
||||
power->sbu_status = OPEN_SBU;
|
||||
}
|
||||
#endif
|
||||
|
||||
void secdp_power_set_gpio(struct dp_power *dp_power, bool flip)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
_secdp_power_set_gpio(power, flip);
|
||||
#else
|
||||
_secdp_sbu_switch_on(power, flip);
|
||||
#endif
|
||||
}
|
||||
|
||||
void secdp_power_unset_gpio(struct dp_power *dp_power)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SBU_SWITCH_CONTROL)
|
||||
_secdp_power_unset_gpio(power);
|
||||
#else
|
||||
_secdp_sbu_switch_off(power);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP_FACTORY_DPSWITCH_TEST)
|
||||
static void secdp_redriver_aux_ctrl(struct dp_power_private *power,
|
||||
int cross)
|
||||
{
|
||||
if (power && power->redrv_aux_ctrl)
|
||||
power->redrv_aux_ctrl(power, cross);
|
||||
}
|
||||
|
||||
/*
|
||||
* @aux_sel : 1 or 0
|
||||
*/
|
||||
void secdp_config_gpios_factory(struct dp_power *dp_power, int aux_sel, bool on)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
DP_DEBUG("sel:%d, on:%d\n", aux_sel, on);
|
||||
|
||||
if (on) {
|
||||
secdp_aux_pullup_vreg_enable(power, true);
|
||||
secdp_power_set_gpio(dp_power, aux_sel);
|
||||
|
||||
if (aux_sel == 1)
|
||||
secdp_redriver_aux_ctrl(power, REDRIVER_SWITCH_CROSS);
|
||||
else if (aux_sel == 0)
|
||||
secdp_redriver_aux_ctrl(power, REDRIVER_SWITCH_THROU);
|
||||
else
|
||||
DP_ERR("unknown <%d>\n", aux_sel);
|
||||
} else {
|
||||
secdp_redriver_aux_ctrl(power, REDRIVER_SWITCH_RESET);
|
||||
secdp_power_unset_gpio(dp_power);
|
||||
secdp_aux_pullup_vreg_enable(power, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
enum dp_hpd_plug_orientation secdp_get_plug_orientation(struct dp_power *dp_power)
|
||||
{
|
||||
struct dp_power_private *power;
|
||||
struct dp_parser *parser;
|
||||
struct dss_module_power *mp;
|
||||
struct dss_gpio *config;
|
||||
int i, dir;
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
parser = power->parser;
|
||||
mp = &power->parser->mp[DP_CORE_PM];
|
||||
config = mp->gpio_config;
|
||||
|
||||
for (i = 0; i < mp->num_gpio; i++) {
|
||||
if (gpio_is_valid(config->gpio)) {
|
||||
if (dp_power_find_gpio(config->gpio_name,
|
||||
"usbplug-cc")) {
|
||||
dir = gpio_get_value(config->gpio);
|
||||
if (parser->cc_dir_inv)
|
||||
dir = !dir;
|
||||
DP_INFO("cc_dir_inv:%d, orientation:%s\n",
|
||||
parser->cc_dir_inv, !dir ? "CC1" : "CC2");
|
||||
if (dir == 0)
|
||||
return ORIENTATION_CC1;
|
||||
else /* if (dir == 1) */
|
||||
return ORIENTATION_CC2;
|
||||
}
|
||||
}
|
||||
config++;
|
||||
}
|
||||
|
||||
/*cannot be here*/
|
||||
return ORIENTATION_NONE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
|
||||
bool enable)
|
||||
{
|
||||
#if !defined(CONFIG_SECDP)
|
||||
int rc = 0, i;
|
||||
struct dss_module_power *mp;
|
||||
struct dss_gpio *config;
|
||||
@@ -614,6 +1240,14 @@ static int dp_power_config_gpios(struct dp_power_private *power, bool flip,
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
struct dp_power *dp_power = &power->dp_power;
|
||||
|
||||
if (enable)
|
||||
secdp_power_set_gpio(dp_power, flip);
|
||||
else
|
||||
secdp_power_unset_gpio(dp_power);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -667,8 +1301,19 @@ static int dp_power_client_init(struct dp_power *dp_power,
|
||||
dp_power->phandle = phandle;
|
||||
dp_power->drm_dev = drm_dev;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
rc = dp_power_pinctrl_set(power, false);
|
||||
if (rc) {
|
||||
DP_ERR("failed to set pinctrl state\n");
|
||||
goto error_client;
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
error_client:
|
||||
dp_power_clk_init(power, false);
|
||||
#endif
|
||||
error_clk:
|
||||
dp_power_regulator_deinit(power);
|
||||
error_power:
|
||||
@@ -708,12 +1353,10 @@ static int dp_power_park_clocks(struct dp_power *dp_power)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (power->parser->has_mst) {
|
||||
rc = dp_power_park_module(power, DP_STREAM1_PM);
|
||||
if (rc) {
|
||||
DP_ERR("failed to park stream 1. err=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
rc = dp_power_park_module(power, DP_STREAM1_PM);
|
||||
if (rc) {
|
||||
DP_ERR("failed to park stream 1. err=%d\n", rc);
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = dp_power_park_module(power, DP_LINK_PM);
|
||||
@@ -808,6 +1451,8 @@ static int dp_power_init(struct dp_power *dp_power, bool flip)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
rc = dp_power_regulator_ctrl(power, true);
|
||||
@@ -865,6 +1510,8 @@ static int dp_power_deinit(struct dp_power *dp_power)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
DP_ENTER("\n");
|
||||
|
||||
power = container_of(dp_power, struct dp_power_private, dp_power);
|
||||
|
||||
if (power->link_clks_on)
|
||||
@@ -955,6 +1602,11 @@ struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll)
|
||||
DP_DEBUG("Optional GDSC regulator is missing\n");
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
secdp_redriver_register(power);
|
||||
mutex_init(&power->dp_clk_lock);
|
||||
#endif
|
||||
|
||||
return dp_power;
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
|
||||
@@ -68,4 +68,20 @@ struct dp_power *dp_power_get(struct dp_parser *parser, struct dp_pll *pll);
|
||||
* @power: pointer to the power module's data
|
||||
*/
|
||||
void dp_power_put(struct dp_power *power);
|
||||
|
||||
#if defined(CONFIG_SECDP)
|
||||
enum dp_hpd_plug_orientation secdp_get_plug_orientation(struct dp_power *dp_power);
|
||||
|
||||
int secdp_power_request_gpios(struct dp_power *dp_power);
|
||||
void secdp_power_set_gpio(struct dp_power *dp_power, bool flip);
|
||||
void secdp_power_unset_gpio(struct dp_power *dp_power);
|
||||
|
||||
#if defined(CONFIG_SECDP_FACTORY_DPSWITCH_TEST)
|
||||
void secdp_config_gpios_factory(struct dp_power *dp_power, int aux_sel, bool out_en);
|
||||
#endif
|
||||
|
||||
void secdp_redriver_onoff(struct dp_power *dp_power, bool enable, int lane);
|
||||
void secdp_redriver_linkinfo(struct dp_power *dp_power, u32 rate, u8 v_level, u8 p_level);
|
||||
#endif/*CONFIG_SECDP*/
|
||||
|
||||
#endif /* _DP_POWER_H_ */
|
||||
|
||||
430
qcom/opensource/display-drivers/msm/dp/secdp.h
Normal file
430
qcom/opensource/display-drivers/msm/dp/secdp.h
Normal file
@@ -0,0 +1,430 @@
|
||||
/* 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/device.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_10P5_9,
|
||||
MON_RATIO_11_10,
|
||||
MON_RATIO_16_9,
|
||||
MON_RATIO_16_10, /* same with 8:5 */
|
||||
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_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 */
|
||||
u32 fail_cnt;
|
||||
};
|
||||
|
||||
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 device *dev;
|
||||
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(struct device *dev);
|
||||
bool secdp_get_power_status(struct device *dev);
|
||||
bool secdp_get_cable_status(struct device *dev);
|
||||
int secdp_get_hpd_status(struct device *dev);
|
||||
struct drm_connector *secdp_get_connector(struct secdp_misc *sec);
|
||||
|
||||
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(struct platform_device *pdev);
|
||||
|
||||
bool secdp_panel_hdr_supported(void);
|
||||
|
||||
#endif/*__SECDP_H*/
|
||||
360
qcom/opensource/display-drivers/msm/dp/secdp_bigdata.c
Normal file
360
qcom/opensource/display-drivers/msm/dp/secdp_bigdata.c
Normal file
@@ -0,0 +1,360 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2021 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* DP bigdata
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/secdp_bigdata.h>
|
||||
|
||||
#define EDID_BUF_SIZE 512
|
||||
#define ERR_DATA_BUF_SIZE 1024
|
||||
#define COL_NAME_SIZE 20
|
||||
|
||||
enum DP_ITEM_TYPE {
|
||||
INT = 1,
|
||||
HEX = 2,
|
||||
STR = 4,
|
||||
CHR = 8,
|
||||
ERR = 16,
|
||||
};
|
||||
|
||||
enum DP_STATUS {
|
||||
STATUS_NO_CONNECTION,
|
||||
STATUS_CONNECTION,
|
||||
STATUS_ERROR_OCCURRED,
|
||||
};
|
||||
|
||||
struct bd_item_info {
|
||||
char name[COL_NAME_SIZE];
|
||||
char type;
|
||||
void *data;
|
||||
int str_max_len;
|
||||
};
|
||||
|
||||
struct bd_error_data {
|
||||
int limit;
|
||||
int count;
|
||||
};
|
||||
|
||||
static char err_data_buf[ERR_DATA_BUF_SIZE];
|
||||
static struct bd_item_info item_to_column[BD_ITEM_MAX];
|
||||
static enum DP_STATUS dp_status;
|
||||
|
||||
static void secdp_bigdata_save_data(void);
|
||||
static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...);
|
||||
static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit);
|
||||
static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val);
|
||||
static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val);
|
||||
static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val);
|
||||
static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val);
|
||||
|
||||
ssize_t _secdp_bigdata_show(const struct class *class,
|
||||
const struct class_attribute *attr, char *buf)
|
||||
{
|
||||
if (dp_status == STATUS_NO_CONNECTION)
|
||||
return 0;
|
||||
|
||||
return scnprintf(buf, ERR_DATA_BUF_SIZE, "%s", err_data_buf);
|
||||
}
|
||||
|
||||
ssize_t _secdp_bigdata_store(const struct class *class,
|
||||
const struct class_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
if ((buf[0] | 0x20) == 'c')
|
||||
dp_status = STATUS_NO_CONNECTION;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void secdp_bigdata_init(struct class *dp_class)
|
||||
{
|
||||
secdp_bigdata_init_item(BD_LINK_CONFIGURE, "LINK_CFG", CHR);
|
||||
secdp_bigdata_init_item(BD_ADAPTER_HWID, "ADT_HWID", HEX);
|
||||
secdp_bigdata_init_item(BD_ADAPTER_FWVER, "ADT_FWVER", HEX);
|
||||
secdp_bigdata_init_item(BD_ADAPTER_TYPE, "ADT_TYPE", STR, 20);
|
||||
secdp_bigdata_init_item(BD_MAX_LANE_COUNT, "MLANE_CNT", INT);
|
||||
secdp_bigdata_init_item(BD_MAX_LINK_RATE, "MLINK_RATE", INT);
|
||||
secdp_bigdata_init_item(BD_CUR_LANE_COUNT, "CLANE_CNT", INT);
|
||||
secdp_bigdata_init_item(BD_CUR_LINK_RATE, "CLINK_RATE", INT);
|
||||
secdp_bigdata_init_item(BD_HDCP_VER, "HDCP_VER", STR, 10);
|
||||
secdp_bigdata_init_item(BD_ORIENTATION, "ORIENTATION", STR, 10);
|
||||
secdp_bigdata_init_item(BD_RESOLUTION, "RESOLUTION", STR, 20);
|
||||
secdp_bigdata_init_item(BD_EDID, "EDID", STR, EDID_BUF_SIZE);
|
||||
secdp_bigdata_init_item(BD_ADT_VID, "ADT_VID", HEX);
|
||||
secdp_bigdata_init_item(BD_ADT_PID, "ADT_PID", HEX);
|
||||
secdp_bigdata_init_item(BD_DP_MODE, "DP_MODE", STR, 10);
|
||||
secdp_bigdata_init_item(BD_SINK_NAME, "SINK_NAME", STR, 14);
|
||||
secdp_bigdata_init_item(BD_AUD_CH, "AUD_CH", INT);
|
||||
secdp_bigdata_init_item(BD_AUD_FREQ, "AUD_FREQ", INT);
|
||||
secdp_bigdata_init_item(BD_AUD_BIT, "AUD_BIT", INT);
|
||||
|
||||
secdp_bigdata_init_error(ERR_AUX, "ERR_AUX", 3);
|
||||
secdp_bigdata_init_error(ERR_EDID, "ERR_EDID", 1);
|
||||
secdp_bigdata_init_error(ERR_HDCP_AUTH, "ERR_HDCP", 5);
|
||||
secdp_bigdata_init_error(ERR_LINK_TRAIN, "ERR_LT_TRAIN", 1);
|
||||
secdp_bigdata_init_error(ERR_INF_IRQHPD, "ERR_INF_IRQHPD", 10);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_init_item_str(enum DP_BD_ITEM_LIST item, char *val, int max_len)
|
||||
{
|
||||
kfree(item_to_column[item].data);
|
||||
|
||||
item_to_column[item].data = kzalloc(max_len + 1, GFP_KERNEL);
|
||||
if (!item_to_column[item].data)
|
||||
return;
|
||||
|
||||
item_to_column[item].str_max_len = max_len;
|
||||
strlcpy((char *)item_to_column[item].data, val, max_len + 1);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_init_item(enum DP_BD_ITEM_LIST item, char *col_name, enum DP_ITEM_TYPE type, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
va_start(vl, type);
|
||||
|
||||
strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
|
||||
item_to_column[item].type = type;
|
||||
|
||||
switch (type) {
|
||||
case INT:
|
||||
case HEX:
|
||||
secdp_bigdata_save_item_int(item, -1);
|
||||
break;
|
||||
case STR:
|
||||
secdp_bigdata_init_item_str(item, "X", (int)va_arg(vl, int));
|
||||
break;
|
||||
case CHR:
|
||||
secdp_bigdata_save_item_char(item, 'X');
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_init_error(enum DP_BD_ITEM_LIST item, char *col_name, int err_limit)
|
||||
{
|
||||
struct bd_error_data *err = kzalloc(sizeof(struct bd_error_data), GFP_KERNEL);
|
||||
|
||||
if (err)
|
||||
err->limit = err_limit;
|
||||
|
||||
strlcpy(item_to_column[item].name, col_name, COL_NAME_SIZE);
|
||||
item_to_column[item].type = ERR;
|
||||
item_to_column[item].data = err;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_int(enum DP_BD_ITEM_LIST item, int val)
|
||||
{
|
||||
if (!item_to_column[item].data) {
|
||||
item_to_column[item].data = kzalloc(sizeof(int), GFP_KERNEL);
|
||||
if (!item_to_column[item].data)
|
||||
return;
|
||||
}
|
||||
|
||||
*((int *)item_to_column[item].data) = val;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_hex(enum DP_BD_ITEM_LIST item, int val)
|
||||
{
|
||||
secdp_bigdata_save_item_int(item, val);
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_char(enum DP_BD_ITEM_LIST item, char val)
|
||||
{
|
||||
if (!item_to_column[item].data) {
|
||||
item_to_column[item].data = kzalloc(sizeof(char), GFP_KERNEL);
|
||||
if (!item_to_column[item].data)
|
||||
return;
|
||||
}
|
||||
|
||||
*((char *)item_to_column[item].data) = val;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_item_str(enum DP_BD_ITEM_LIST item, char *val)
|
||||
{
|
||||
if (!item_to_column[item].data || !val)
|
||||
return;
|
||||
|
||||
if (item == BD_EDID && val[0] != 'X') {
|
||||
int ret = 0;
|
||||
int i;
|
||||
int ext_blk_cnt = val[0x7e] ? 1 : 0;
|
||||
int edid_size = 128 * (ext_blk_cnt + 1);
|
||||
|
||||
for (i = 0; i < edid_size; i++) {
|
||||
ret += scnprintf(((char *)item_to_column[item].data) + ret,
|
||||
EDID_BUF_SIZE + 1 - ret, "%02x",
|
||||
val[i]);
|
||||
}
|
||||
|
||||
} else {
|
||||
strlcpy((char *)item_to_column[item].data, val,
|
||||
item_to_column[item].str_max_len + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void secdp_bigdata_save_item(enum DP_BD_ITEM_LIST item, ...)
|
||||
{
|
||||
va_list vl;
|
||||
|
||||
if (item >= BD_ITEM_MAX || item < 0)
|
||||
return;
|
||||
|
||||
va_start(vl, item);
|
||||
|
||||
switch (item_to_column[item].type) {
|
||||
case INT:
|
||||
secdp_bigdata_save_item_hex(item, (int)va_arg(vl, int));
|
||||
break;
|
||||
case HEX:
|
||||
secdp_bigdata_save_item_int(item, (int)va_arg(vl, int));
|
||||
break;
|
||||
case STR:
|
||||
secdp_bigdata_save_item_str(item, (char *)va_arg(vl, char *));
|
||||
break;
|
||||
case CHR:
|
||||
secdp_bigdata_save_item_char(item, (char)va_arg(vl, int));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void secdp_bigdata_inc_error_cnt(enum DP_BD_ITEM_LIST err)
|
||||
{
|
||||
if (err >= BD_ITEM_MAX || err < 0)
|
||||
return;
|
||||
|
||||
if (item_to_column[err].data && item_to_column[err].type == ERR)
|
||||
((struct bd_error_data *)item_to_column[err].data)->count++;
|
||||
}
|
||||
|
||||
void secdp_bigdata_clr_error_cnt(enum DP_BD_ITEM_LIST err)
|
||||
{
|
||||
if (err >= BD_ITEM_MAX || err < 0)
|
||||
return;
|
||||
|
||||
if (item_to_column[err].data && item_to_column[err].type == ERR)
|
||||
((struct bd_error_data *)item_to_column[err].data)->count = 0;
|
||||
}
|
||||
|
||||
static void secdp_bigdata_save_data(void)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
for (i = 0; i < BD_ITEM_MAX; i++) {
|
||||
switch (item_to_column[i].type) {
|
||||
case INT:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%d\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
*((int *)item_to_column[i].data) : -1);
|
||||
break;
|
||||
case HEX:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"0x%x\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
*((int *)item_to_column[i].data) : -1);
|
||||
break;
|
||||
case STR:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%s\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
(char *)item_to_column[i].data : "X");
|
||||
break;
|
||||
case CHR:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%c\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
*((char *)item_to_column[i].data) : 'X');
|
||||
break;
|
||||
case ERR:
|
||||
ret += scnprintf(err_data_buf + ret, ERR_DATA_BUF_SIZE - ret,
|
||||
"\"%s\":\"%d\",",
|
||||
item_to_column[i].name,
|
||||
(item_to_column[i].data != NULL) ?
|
||||
((struct bd_error_data *)item_to_column[i].data)->count : 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret > 0)
|
||||
err_data_buf[ret - 1] = '\n';
|
||||
}
|
||||
|
||||
static int secdp_bigdata_check_err(void)
|
||||
{
|
||||
int i;
|
||||
struct bd_error_data *e_data;
|
||||
|
||||
for (i = 0; i < BD_ITEM_MAX; i++) {
|
||||
if (item_to_column[i].type == ERR) {
|
||||
e_data = item_to_column[i].data;
|
||||
if (e_data != NULL && e_data->count >= e_data->limit)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void secdp_bigdata_connection(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (dp_status != STATUS_ERROR_OCCURRED)
|
||||
dp_status = STATUS_CONNECTION;
|
||||
|
||||
for (i = 0; i < BD_ITEM_MAX; i++) {
|
||||
switch (item_to_column[i].type) {
|
||||
case INT:
|
||||
case HEX:
|
||||
secdp_bigdata_save_item_int(i, -1);
|
||||
break;
|
||||
case STR:
|
||||
secdp_bigdata_save_item_str(i, "X");
|
||||
break;
|
||||
case CHR:
|
||||
secdp_bigdata_save_item_char(i, 'X');
|
||||
break;
|
||||
case ERR:
|
||||
secdp_bigdata_clr_error_cnt(i);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void secdp_bigdata_disconnection(void)
|
||||
{
|
||||
if (secdp_bigdata_check_err()) {
|
||||
dp_status = STATUS_ERROR_OCCURRED;
|
||||
secdp_bigdata_save_data();
|
||||
}
|
||||
|
||||
if (dp_status != STATUS_ERROR_OCCURRED)
|
||||
secdp_bigdata_save_data();
|
||||
|
||||
}
|
||||
266
qcom/opensource/display-drivers/msm/dp/secdp_logger.c
Normal file
266
qcom/opensource/display-drivers/msm/dp/secdp_logger.c
Normal file
@@ -0,0 +1,266 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copyright (c) 2017-2022 Samsung Electronics Co., Ltd.
|
||||
* http://www.samsung.com
|
||||
*
|
||||
* SECDP logger
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ktime.h>
|
||||
#if LINUX_VERSION_CODE > KERNEL_VERSION(4, 10, 0)
|
||||
#include <linux/sched/clock.h>
|
||||
#else
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/secdp_logger.h>
|
||||
|
||||
#include "secdp_unit_test.h"
|
||||
|
||||
#define BUF_SIZE SZ_64K
|
||||
#define MAX_STR_LEN 160
|
||||
#define PROC_FILE_NAME "dplog"
|
||||
#define LOG_PREFIX "secdp"
|
||||
|
||||
static char log_buf[BUF_SIZE];
|
||||
static unsigned int g_curpos;
|
||||
static int is_secdp_logger_init;
|
||||
static int is_buf_full;
|
||||
static int log_max_count = -1;
|
||||
static unsigned int max_mode_count;
|
||||
static struct mutex dplog_lock;
|
||||
static struct proc_dir_entry *g_entry;
|
||||
|
||||
static void dp_logger_print_date_time(void)
|
||||
{
|
||||
char tmp[64] = {0x0, };
|
||||
struct tm tm;
|
||||
struct timespec64 ts;
|
||||
unsigned long sec;
|
||||
|
||||
ktime_get_real_ts64(&ts);
|
||||
sec = ts.tv_sec - (sys_tz.tz_minuteswest * 60);
|
||||
time64_to_tm(sec, 0, &tm);
|
||||
snprintf(tmp, sizeof(tmp), "!@[%02d-%02d %02d:%02d:%02d.%03lu]",
|
||||
tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
ts.tv_nsec / 1000000);
|
||||
|
||||
secdp_logger_print("%s\n", tmp);
|
||||
}
|
||||
|
||||
/* set max log count, if count is -1, no limit */
|
||||
void secdp_logger_set_max_count(int count)
|
||||
{
|
||||
log_max_count = count;
|
||||
dp_logger_print_date_time();
|
||||
}
|
||||
|
||||
static void _secdp_logger_print(const char *fmt, va_list args)
|
||||
{
|
||||
int len;
|
||||
char buf[MAX_STR_LEN] = {0, };
|
||||
u64 time;
|
||||
unsigned long nsec;
|
||||
volatile unsigned int curpos;
|
||||
|
||||
mutex_lock(&dplog_lock);
|
||||
|
||||
time = local_clock();
|
||||
nsec = do_div(time, 1000000000);
|
||||
len = snprintf(buf, sizeof(buf), "[%5lu.%06ld] ",
|
||||
(unsigned long)time, nsec / 1000);
|
||||
|
||||
len += vsnprintf(buf + len, MAX_STR_LEN - len, fmt, args);
|
||||
if (len > MAX_STR_LEN)
|
||||
len = MAX_STR_LEN;
|
||||
|
||||
curpos = g_curpos;
|
||||
if (curpos + len >= BUF_SIZE) {
|
||||
g_curpos = curpos = 0;
|
||||
is_buf_full = 1;
|
||||
}
|
||||
memcpy(log_buf + curpos, buf, len);
|
||||
g_curpos += len;
|
||||
|
||||
mutex_unlock(&dplog_lock);
|
||||
}
|
||||
|
||||
void secdp_logger_print(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (!log_max_count)
|
||||
return;
|
||||
|
||||
if (log_max_count > 0)
|
||||
log_max_count--;
|
||||
|
||||
va_start(args, fmt);
|
||||
_secdp_logger_print(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* set max num of modes print */
|
||||
void secdp_logger_set_mode_max_count(unsigned int num)
|
||||
{
|
||||
max_mode_count = num + 1;
|
||||
}
|
||||
|
||||
void secdp_logger_dec_mode_count(void)
|
||||
{
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (max_mode_count > 0)
|
||||
max_mode_count--;
|
||||
}
|
||||
|
||||
void secdp_logger_print_mode(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (!max_mode_count)
|
||||
return;
|
||||
|
||||
va_start(args, fmt);
|
||||
_secdp_logger_print(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void secdp_logger_hex_dump(void *buf, void *pref, size_t size)
|
||||
{
|
||||
uint8_t *ptr = buf;
|
||||
size_t i;
|
||||
char tmp[128] = {0x0, };
|
||||
char *ptmp = tmp;
|
||||
int len;
|
||||
|
||||
if (!is_secdp_logger_init)
|
||||
return;
|
||||
|
||||
if (!log_max_count)
|
||||
return;
|
||||
|
||||
if (log_max_count > 0)
|
||||
log_max_count--;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
len = snprintf(ptmp, 4, "%02x ", *ptr++);
|
||||
ptmp = ptmp + len;
|
||||
if (((i+1)%16) == 0) {
|
||||
secdp_logger_print("%s%s\n", (char *)pref, tmp);
|
||||
ptmp = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
if (i % 16) {
|
||||
len = ptmp - tmp;
|
||||
tmp[len] = 0x0;
|
||||
secdp_logger_print("%s%s\n", (char *)pref, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t secdp_logger_read(struct file *file, char __user *buf,
|
||||
size_t len, loff_t *offset)
|
||||
{
|
||||
loff_t pos = *offset;
|
||||
ssize_t count;
|
||||
size_t size;
|
||||
volatile unsigned int curpos;
|
||||
|
||||
mutex_lock(&dplog_lock);
|
||||
|
||||
curpos = g_curpos;
|
||||
|
||||
if (is_buf_full || BUF_SIZE <= curpos)
|
||||
size = BUF_SIZE;
|
||||
else
|
||||
size = (size_t)curpos;
|
||||
|
||||
if (pos >= size) {
|
||||
count = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
count = min(len, size);
|
||||
|
||||
if ((pos + count) > size)
|
||||
count = size - pos;
|
||||
|
||||
if (copy_to_user(buf, log_buf + pos, count)) {
|
||||
count = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
*offset += count;
|
||||
end:
|
||||
mutex_unlock(&dplog_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
#if KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE
|
||||
static const struct proc_ops secdp_logger_ops = {
|
||||
.proc_read = secdp_logger_read,
|
||||
.proc_lseek = default_llseek,
|
||||
};
|
||||
#else
|
||||
static const struct file_operations secdp_logger_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = secdp_logger_read,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
#endif
|
||||
|
||||
int secdp_logger_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
|
||||
if (is_secdp_logger_init)
|
||||
return 0;
|
||||
|
||||
entry = proc_create(PROC_FILE_NAME, 0444, NULL, &secdp_logger_ops);
|
||||
if (!entry) {
|
||||
pr_err("%s: failed to create proc entry\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
proc_set_size(entry, BUF_SIZE);
|
||||
is_secdp_logger_init = 1;
|
||||
g_entry = entry;
|
||||
|
||||
mutex_init(&dplog_lock);
|
||||
secdp_logger_print("dp logger init ok\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void secdp_logger_deinit(void)
|
||||
{
|
||||
if (!g_entry)
|
||||
return;
|
||||
|
||||
proc_remove(g_entry);
|
||||
is_secdp_logger_init = 0;
|
||||
g_entry = NULL;
|
||||
|
||||
mutex_destroy(&dplog_lock);
|
||||
secdp_logger_print("dp logger deinit ok\n");
|
||||
}
|
||||
1824
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.c
Normal file
1824
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.c
Normal file
File diff suppressed because it is too large
Load Diff
51
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.h
Normal file
51
qcom/opensource/display-drivers/msm/dp/secdp_sysfs.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* 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_SYSFS_H
|
||||
#define __SECDP_SYSFS_H
|
||||
|
||||
#include "secdp.h"
|
||||
|
||||
struct secdp_sysfs_in {
|
||||
struct device *dev;
|
||||
struct dp_parser *parser;
|
||||
struct dp_ctrl *ctrl;
|
||||
struct dp_link *link;
|
||||
struct dp_panel *panel;
|
||||
struct dp_power *power;
|
||||
struct dp_catalog *catalog;
|
||||
struct secdp_misc *sec;
|
||||
};
|
||||
|
||||
struct secdp_sysfs {
|
||||
struct class dp_class;
|
||||
};
|
||||
|
||||
/**
|
||||
* secdp_sysfs_get() - get the functionalities of secdp sysfs module
|
||||
*
|
||||
*
|
||||
* return: a pointer to dp_link struct
|
||||
*/
|
||||
struct secdp_sysfs *secdp_sysfs_get(struct secdp_sysfs_in *in);
|
||||
|
||||
/**
|
||||
* secdp_sysfs_put() - releases the dp test module's resources
|
||||
*
|
||||
* @dp_link: an instance of dp_link module
|
||||
*
|
||||
*/
|
||||
void secdp_sysfs_put(struct device *dev, struct secdp_sysfs *dp_sysfs);
|
||||
|
||||
#endif /*__SECDP_SYSFS_H*/
|
||||
162
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.c
Normal file
162
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.c
Normal file
@@ -0,0 +1,162 @@
|
||||
// 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.
|
||||
*
|
||||
*/
|
||||
#include "dp_debug.h"
|
||||
#include "dp_display.h"
|
||||
#include "sde_edid_parser.h"
|
||||
#include "secdp.h"
|
||||
|
||||
static u8 g_test_edid[] = {
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x09, 0xD1, 0x54, 0x7F, 0x45, 0x54, 0x00, 0x00,
|
||||
0x14, 0x1B, 0x01, 0x03, 0x80, 0x46, 0x28, 0x78, 0x2E, 0xDF, 0x50, 0xA3, 0x54, 0x35, 0xB5, 0x26,
|
||||
0x0F, 0x50, 0x54, 0xA5, 0x6B, 0x80, 0xD1, 0xC0, 0x81, 0xC0, 0x81, 0x00, 0x81, 0x80, 0xA9, 0xC0,
|
||||
0xB3, 0x00, 0x01, 0x01, 0x01, 0x01, 0x51, 0xD0, 0x00, 0xA0, 0xF0, 0x70, 0x3E, 0x80, 0x30, 0x20,
|
||||
0x35, 0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x53, 0x35, 0x48,
|
||||
0x30, 0x31, 0x38, 0x39, 0x31, 0x53, 0x4C, 0x30, 0x0A, 0x20, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x18,
|
||||
0x4C, 0x1E, 0x8C, 0x3C, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0xFC,
|
||||
0x00, 0x42, 0x65, 0x6E, 0x51, 0x20, 0x53, 0x57, 0x33, 0x32, 0x30, 0x0A, 0x20, 0x20, 0x01, 0x42,
|
||||
0x02, 0x03, 0x45, 0xF1, 0x56, 0x61, 0x60, 0x5D, 0x5E, 0x5F, 0x10, 0x05, 0x04, 0x03, 0x02, 0x07,
|
||||
0x06, 0x0F, 0x1F, 0x20, 0x21, 0x22, 0x14, 0x13, 0x12, 0x16, 0x01, 0x23, 0x09, 0x07, 0x07, 0xE6,
|
||||
0x06, 0x05, 0x01, 0x60, 0x5A, 0x44, 0x6D, 0x03, 0x0C, 0x00, 0x10, 0x00, 0x38, 0x44, 0x20, 0x00,
|
||||
0x60, 0x01, 0x02, 0x03, 0x67, 0xD8, 0x5D, 0xC4, 0x01, 0x78, 0x80, 0x01, 0xE4, 0x0F, 0x03, 0x00,
|
||||
0x00, 0xE3, 0x05, 0xC3, 0x00, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40, 0x58, 0x2C, 0x45,
|
||||
0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1E, 0x56, 0x5E, 0x00, 0xA0, 0xA0, 0xA0, 0x29, 0x50, 0x30,
|
||||
0x20, 0x35, 0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1A, 0xF4, 0x51, 0x00, 0xA0, 0xF0, 0x70, 0x19,
|
||||
0x80, 0x30, 0x20, 0x35, 0x00, 0xBA, 0x89, 0x21, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0xAB,
|
||||
};
|
||||
|
||||
static struct secdp_display_timing g_parsed_res[] = {
|
||||
/* active_h, active_v, refresh_rate, interlaced */
|
||||
{0, 640, 480, 60, false}, /* 640x480 60hz */
|
||||
{0, 640, 480, 75, false}, /* 640x480 75hz */
|
||||
{0, 720, 400, 70, false}, /* 720x400 70hz */
|
||||
{0, 720, 480, 60, true}, /* 720x480i 60hz */
|
||||
{0, 720, 480, 60, false}, /* 720x480 60hz */
|
||||
|
||||
{0, 720, 576, 50, true}, /* 720x576i 50hz */
|
||||
{0, 720, 576, 50, false}, /* 720x576 50hz */
|
||||
{0, 800, 600, 60, false}, /* 800x600 60hz */
|
||||
{0, 800, 600, 75, false}, /* 800x600 75hz */
|
||||
{0, 832, 624, 75, false}, /* 832x624 75hz */
|
||||
|
||||
{0, 1024, 768, 60, false}, /* 1024x768 60hz */
|
||||
{0, 1024, 768, 75, false}, /* 1024x768 75hz */
|
||||
{0, 1152, 864, 75, false}, /* 1152x864 75hz */
|
||||
{0, 1280, 720, 50, false}, /* 1280x720 50hz */
|
||||
{0, 1280, 720, 60, false}, /* 1280x720 60hz */
|
||||
|
||||
{0, 1280, 800, 60, false}, /* 1280x800 60hz */
|
||||
{0, 1280, 1024, 60, false}, /* 1280x1024 60hz */
|
||||
{0, 1280, 1024, 75, false}, /* 1280x1024 75hz */
|
||||
{0, 1440, 480, 60, false}, /* 1440x480 60hz */
|
||||
{0, 1600, 900, 60, false}, /* 1600x900 60hz */
|
||||
|
||||
{0, 1680, 1050, 60, false}, /* 1680x1050 60hz */
|
||||
{0, 1920, 1080, 50, true}, /* 1920x1080i 50hz */
|
||||
{0, 1920, 1080, 60, true}, /* 1920x1080i 60hz */
|
||||
{0, 1920, 1080, 24, false}, /* 1920x1080 24hz */
|
||||
{0, 1920, 1080, 25, false}, /* 1920x1080 25hz */
|
||||
|
||||
{0, 1920, 1080, 30, false}, /* 1920x1080 30hz */
|
||||
{0, 1920, 1080, 50, false}, /* 1920x1080 50hz */
|
||||
{0, 1920, 1080, 60, false}, /* 1920x1080 60hz */
|
||||
{0, 2560, 1440, 60, false}, /* 2560x1440 60hz */
|
||||
{0, 3840, 2160, 24, false}, /* 3840x2160 24hz */
|
||||
|
||||
{0, 3840, 2160, 25, false}, /* 3840x2160 25hz */
|
||||
{0, 3840, 2160, 30, false}, /* 3840x2160 30hz */
|
||||
{0, 3840, 2160, 50, false}, /* 3840x2160 50hz */
|
||||
{0, 3840, 2160, 60, false}, /* 3840x2160 60hz */
|
||||
};
|
||||
|
||||
static void drm_mode_remove(struct drm_connector *connector,
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
list_del(&mode->head);
|
||||
drm_mode_destroy(connector->dev, mode);
|
||||
}
|
||||
|
||||
bool secdp_unit_test_edid_parse(struct secdp_misc *sec)
|
||||
{
|
||||
int rc, i, parsed_res_cnt = 0, table_size;
|
||||
bool ret = false;
|
||||
struct sde_edid_ctrl *edid_ctrl = NULL;
|
||||
struct drm_display_mode *mode, *t;
|
||||
struct drm_connector *connector;
|
||||
|
||||
connector = secdp_get_connector(sec);
|
||||
if (!connector) {
|
||||
DP_ERR("fail to get connector\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
table_size = ARRAY_SIZE(g_parsed_res);
|
||||
|
||||
edid_ctrl = sde_edid_init();
|
||||
if (!edid_ctrl) {
|
||||
DP_ERR("edid_ctrl alloc failed\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&connector->dev->mode_config.mutex);
|
||||
|
||||
edid_ctrl->edid = (struct edid *)g_test_edid;
|
||||
rc = _sde_edid_update_modes(connector, edid_ctrl);
|
||||
DP_INFO("_sde_edid_update_modes, rc: %d\n", rc);
|
||||
|
||||
/* init g_parsed_res */
|
||||
for (i = 0; i < table_size; i++)
|
||||
g_parsed_res[i].supported = false;
|
||||
|
||||
/* check resolutions */
|
||||
list_for_each_entry(mode, &connector->probed_modes, head) {
|
||||
DP_INFO("checking %s @ %d Hz..\n", mode->name, drm_mode_vrefresh(mode));
|
||||
for (i = 0; i < table_size; i++) {
|
||||
bool interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
|
||||
|
||||
if (g_parsed_res[i].active_h == mode->hdisplay &&
|
||||
g_parsed_res[i].active_v == mode->vdisplay &&
|
||||
g_parsed_res[i].refresh_rate == drm_mode_vrefresh(mode) &&
|
||||
g_parsed_res[i].interlaced == interlaced) {
|
||||
|
||||
/*all conditions are met, mark it as supported*/
|
||||
g_parsed_res[i].supported = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(mode, t, &connector->probed_modes, head)
|
||||
drm_mode_remove(connector, mode);
|
||||
|
||||
mutex_unlock(&connector->dev->mode_config.mutex);
|
||||
kfree(edid_ctrl);
|
||||
|
||||
/* count how many resolutions are marked as supported */
|
||||
for (i = 0; i < table_size; i++) {
|
||||
if (g_parsed_res[i].supported)
|
||||
parsed_res_cnt++;
|
||||
}
|
||||
|
||||
/* check if num of supported resolutions are found without errors */
|
||||
if (parsed_res_cnt != table_size) {
|
||||
DP_ERR("count is not matched! res_cnt: %d, table_size: %d\n",
|
||||
parsed_res_cnt, table_size);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
exit:
|
||||
DP_INFO("returns %s\n", ret ? "true" : "false");
|
||||
return ret;
|
||||
}
|
||||
22
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.h
Normal file
22
qcom/opensource/display-drivers/msm/dp/secdp_unit_test.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/* 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_UNIT_TEST_H
|
||||
#define __SECDP_UNIT_TEST_H
|
||||
|
||||
#include "secdp.h"
|
||||
|
||||
bool secdp_unit_test_edid_parse(struct secdp_misc *sec);
|
||||
|
||||
#endif/*__SECDP_UNIT_TEST_H*/
|
||||
Reference in New Issue
Block a user