From 1543e317f1da31b75942316931e8f491a8920811 Mon Sep 17 00:00:00 2001
From: hc <hc@nodka.com>
Date: Thu, 04 Jan 2024 10:08:02 +0000
Subject: [PATCH] disable FB
---
kernel/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 486 ++++++++++++++++++-----------------------------------
1 files changed, 169 insertions(+), 317 deletions(-)
diff --git a/kernel/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/kernel/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 7ea8132..e756d7c 100644
--- a/kernel/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/kernel/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1,13 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Analogix DP (Display port) core register interface driver.
*
* Copyright (C) 2012 Samsung Electronics Co., Ltd.
* Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
*/
#include <linux/delay.h>
@@ -18,14 +14,10 @@
#include <linux/phy/phy.h>
#include <drm/bridge/analogix_dp.h>
+#include <drm/drm_probe_helper.h>
#include "analogix_dp_core.h"
#include "analogix_dp_reg.h"
-
-#define COMMON_INT_MASK_1 0
-#define COMMON_INT_MASK_2 0
-#define COMMON_INT_MASK_3 0
-#define COMMON_INT_MASK_4 (HOTPLUG_CHG | HPD_LOST | PLUG)
static void analogix_dp_write(struct analogix_dp_device *dp, u32 reg, u32 val)
{
@@ -69,16 +61,13 @@
analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_1, reg);
}
-void analogix_dp_lane_swap(struct analogix_dp_device *dp, bool enable)
+static void analogix_dp_set_lane_map(struct analogix_dp_device *dp)
{
- u32 reg;
+ struct video_info *video_info = &dp->video_info;
+ u32 i, reg = 0;
- if (enable)
- reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
- LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
- else
- reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
- LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+ for (i = 0; i < video_info->max_lane_count; i++)
+ reg |= video_info->lane_map[i] << (2 * i);
analogix_dp_write(dp, ANALOGIX_DP_LANE_MAP, reg);
}
@@ -95,8 +84,7 @@
if (dp->plat_data && is_rockchip(dp->plat_data->dev_type)) {
reg = REF_CLK_24M;
- if (dp->plat_data->dev_type == RK3288_DP ||
- dp->plat_data->dev_type == RK3368_EDP)
+ if (dp->plat_data->dev_type == RK3288_DP)
reg ^= REF_CLK_MASK;
analogix_dp_write(dp, ANALOGIX_DP_PLL_REG_1, reg);
@@ -163,7 +151,7 @@
usleep_range(20, 30);
- analogix_dp_lane_swap(dp, 0);
+ analogix_dp_set_lane_map(dp);
analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_1, 0x0);
analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_2, 0x40);
@@ -172,9 +160,6 @@
analogix_dp_write(dp, ANALOGIX_DP_PKT_SEND_CTL, 0x0);
analogix_dp_write(dp, ANALOGIX_DP_HDCP_CTL, 0x0);
-
- analogix_dp_write(dp, ANALOGIX_DP_HPD_DEGLITCH_L, 0x5e);
- analogix_dp_write(dp, ANALOGIX_DP_HPD_DEGLITCH_H, 0x1a);
analogix_dp_write(dp, ANALOGIX_DP_LINK_DEBUG_CTL, 0x10);
@@ -196,17 +181,10 @@
void analogix_dp_config_interrupt(struct analogix_dp_device *dp)
{
- u32 reg;
-
/* 0: mask, 1: unmask */
- reg = COMMON_INT_MASK_1;
- analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_1, reg);
-
- reg = COMMON_INT_MASK_2;
- analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_2, reg);
-
- reg = COMMON_INT_MASK_3;
- analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_3, reg);
+ analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_1, 0);
+ analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_2, 0);
+ analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_3, 0);
if (dp->force_hpd || dp->hpd_gpiod)
analogix_dp_mute_hpd_interrupt(dp);
@@ -220,7 +198,7 @@
/* 0: mask, 1: unmask */
reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_MASK_4);
- reg &= ~COMMON_INT_MASK_4;
+ reg &= ~HOTPLUG_CHG;
analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA_MASK);
@@ -233,7 +211,8 @@
u32 reg;
/* 0: mask, 1: unmask */
- reg = COMMON_INT_MASK_4;
+ reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_MASK_4);
+ reg |= HOTPLUG_CHG;
analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_MASK_4, reg);
reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA_MASK);
@@ -424,7 +403,8 @@
if (dp->hpd_gpiod)
return;
- analogix_dp_clear_hotplug_interrupts(dp);
+ analogix_dp_write(dp, ANALOGIX_DP_HPD_DEGLITCH_H, 0xbb);
+ analogix_dp_write(dp, ANALOGIX_DP_HPD_DEGLITCH_L, 0x80);
reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
reg &= ~(F_HPD | HPD_CTRL);
@@ -440,23 +420,39 @@
analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
}
-enum dp_irq_type analogix_dp_get_irq_type(struct analogix_dp_device *dp)
+static void analogix_dp_handle_hpd_event(struct analogix_dp_device *dp)
{
+ bool changed = false;
u32 reg;
- /* Parse hotplug interrupt status register */
+ reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
+ if (reg & INT_HPD) {
+ analogix_dp_write(dp, ANALOGIX_DP_INT_STA, INT_HPD);
+
+ memset(&dp->compliance, 0, sizeof(dp->compliance));
+
+ analogix_dp_check_device_service_irq(dp);
+
+ if (dp->compliance.test_active &&
+ dp->compliance.test_type == DP_TEST_LINK_PHY_TEST_PATTERN) {
+ analogix_dp_phy_test(dp);
+ return;
+ }
+ }
+
reg = analogix_dp_read(dp, ANALOGIX_DP_COMMON_INT_STA_4);
+ if (reg & HOTPLUG_CHG) {
+ analogix_dp_write(dp, ANALOGIX_DP_COMMON_INT_STA_4, HOTPLUG_CHG);
+ changed = true;
+ }
- if (reg & PLUG)
- return DP_IRQ_TYPE_HP_CABLE_IN;
+ if (changed)
+ drm_helper_hpd_irq_event(dp->drm_dev);
+}
- if (reg & HPD_LOST)
- return DP_IRQ_TYPE_HP_CABLE_OUT;
-
- if (reg & HOTPLUG_CHG)
- return DP_IRQ_TYPE_HP_CHANGE;
-
- return DP_IRQ_TYPE_UNKNOWN;
+void analogix_dp_irq_handler(struct analogix_dp_device *dp)
+{
+ analogix_dp_handle_hpd_event(dp);
}
void analogix_dp_reset_aux(struct analogix_dp_device *dp)
@@ -531,99 +527,12 @@
analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
}
-int analogix_dp_start_aux_transaction(struct analogix_dp_device *dp)
-{
- int reg;
- int retval = 0;
- int timeout_loop = 0;
-
- /* Enable AUX CH operation */
- reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_CTL_2);
- reg |= AUX_EN;
- analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_2, reg);
-
- /* Is AUX CH command reply received? */
- reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
- while (!(reg & RPLY_RECEIV)) {
- timeout_loop++;
- if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
- dev_err(dp->dev, "AUX CH command reply failed!\n");
- return -ETIMEDOUT;
- }
- reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
- usleep_range(10, 11);
- }
-
- /* Clear interrupt source for AUX CH command reply */
- analogix_dp_write(dp, ANALOGIX_DP_INT_STA, RPLY_RECEIV);
-
- /* Clear interrupt source for AUX CH access error */
- reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
- if (reg & AUX_ERR) {
- analogix_dp_write(dp, ANALOGIX_DP_INT_STA, AUX_ERR);
- return -EREMOTEIO;
- }
-
- /* Check AUX CH error access status */
- reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_STA);
- if ((reg & AUX_STATUS_MASK) != 0) {
- dev_err(dp->dev, "AUX CH error happens: %d\n\n",
- reg & AUX_STATUS_MASK);
- return -EREMOTEIO;
- }
-
- return retval;
-}
-
-int analogix_dp_write_byte_to_dpcd(struct analogix_dp_device *dp,
- unsigned int reg_addr,
- unsigned char data)
-{
- u32 reg;
- int i;
- int retval;
-
- for (i = 0; i < 3; i++) {
- /* Clear AUX CH data buffer */
- reg = BUF_CLR;
- analogix_dp_write(dp, ANALOGIX_DP_BUFFER_DATA_CTL, reg);
-
- /* Select DPCD device address */
- reg = AUX_ADDR_7_0(reg_addr);
- analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_7_0, reg);
- reg = AUX_ADDR_15_8(reg_addr);
- analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_15_8, reg);
- reg = AUX_ADDR_19_16(reg_addr);
- analogix_dp_write(dp, ANALOGIX_DP_AUX_ADDR_19_16, reg);
-
- /* Write data buffer */
- reg = (unsigned int)data;
- analogix_dp_write(dp, ANALOGIX_DP_BUF_DATA_0, reg);
-
- /*
- * Set DisplayPort transaction and write 1 byte
- * If bit 3 is 1, DisplayPort transaction.
- * If Bit 3 is 0, I2C transaction.
- */
- reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
- analogix_dp_write(dp, ANALOGIX_DP_AUX_CH_CTL_1, reg);
-
- /* Start AUX transaction */
- retval = analogix_dp_start_aux_transaction(dp);
- if (retval == 0)
- break;
-
- dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
- }
-
- return retval;
-}
-
static void analogix_dp_ssc_enable(struct analogix_dp_device *dp)
{
u32 reg;
- writel(0x17, dp->reg_base + ANALOGIX_DP_SSC_REG);
+ /* 4500ppm */
+ writel(0x19, dp->reg_base + ANALOIGX_DP_SSC_REG);
/*
* To apply updated SSC parameters into SSC operation,
* firmware must disable and enable this bit.
@@ -658,17 +567,18 @@
analogix_dp_write(dp, ANALOGIX_DP_LINK_BW_SET, bwtype);
if (dp->phy) {
- union phy_configure_opts phy_cfg;
+ union phy_configure_opts phy_cfg = {0};
phy_cfg.dp.lanes = dp->link_train.lane_count;
- phy_cfg.dp.link_rate = drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
+ phy_cfg.dp.link_rate =
+ drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
phy_cfg.dp.ssc = analogix_dp_ssc_supported(dp);
phy_cfg.dp.set_lanes = false;
phy_cfg.dp.set_rate = true;
phy_cfg.dp.set_voltages = false;
ret = phy_configure(dp->phy, &phy_cfg);
if (ret && ret != -EOPNOTSUPP) {
- dev_err(dp->dev, "%s: phy_configure() failed: %d\n",
+ dev_err(dp->dev, "%s: phy_configure failed: %d\n",
__func__, ret);
return;
}
@@ -705,7 +615,7 @@
analogix_dp_write(dp, ANALOGIX_DP_LANE_COUNT_SET, reg);
if (dp->phy) {
- union phy_configure_opts phy_cfg;
+ union phy_configure_opts phy_cfg = {0};
phy_cfg.dp.lanes = dp->link_train.lane_count;
phy_cfg.dp.set_lanes = true;
@@ -728,86 +638,6 @@
*count = reg;
}
-struct swing_pre_emp_ctrl {
- u8 amp;
- u8 emp;
-};
-
-static const struct swing_pre_emp_ctrl swing_pre_emp_ctrl_rbr[4][4] = {
- /* voltage swing 0, pre-emphasis 0->3 */
- {
- { .amp = 0x50, .emp = 0x00 },
- { .amp = 0x6c, .emp = 0x28 },
- { .amp = 0x80, .emp = 0x60 },
- { .amp = 0xb0, .emp = 0xc4 },
- },
- /* voltage swing 1, pre-emphasis 0->3 */
- {
- { .amp = 0x78, .emp = 0x00 },
- { .amp = 0xa4, .emp = 0x50 },
- { .amp = 0xcc, .emp = 0xa6 },
- },
- /* voltage swing 2, pre-emphasis 0->3 */
- {
- { .amp = 0xa0, .emp = 0x00 },
- { .amp = 0xe4, .emp = 0x72 },
- },
- /* voltage swing 3, pre-emphasis 0->3 */
- {
- { .amp = 0xf0, .emp = 0x00 },
- },
-};
-
-static const struct swing_pre_emp_ctrl swing_pre_emp_ctrl_hbr[4][4] = {
- /* voltage swing 0, pre-emphasis 0->3 */
- {
- { .amp = 0x50, .emp = 0x00 },
- { .amp = 0x6c, .emp = 0x34 },
- { .amp = 0x80, .emp = 0x64 },
- { .amp = 0xb8, .emp = 0xdc },
- },
- /* voltage swing 1, pre-emphasis 0->3 */
- {
- { .amp = 0x78, .emp = 0x00 },
- { .amp = 0xa8, .emp = 0x58 },
- { .amp = 0xcc, .emp = 0xa8 },
- },
- /* voltage swing 2, pre-emphasis 0->3 */
- {
- { .amp = 0xa0, .emp = 0x00 },
- { .amp = 0xdd, .emp = 0x74 },
- },
- /* voltage swing 3, pre-emphasis 0->3 */
- {
- { .amp = 0xf0, .emp = 0x00 },
- },
-};
-
-static const struct swing_pre_emp_ctrl swing_pre_emp_ctrl_hbr2[4][4] = {
- /* voltage swing 0, pre-emphasis 0->3 */
- {
- { .amp = 0x64, .emp = 0x1c },
- { .amp = 0x90, .emp = 0x78 },
- { .amp = 0xc4, .emp = 0xe0 },
- { .amp = 0xa0, .emp = 0xa0 },
- },
- /* voltage swing 1, pre-emphasis 0->3 */
- {
- { .amp = 0x9c, .emp = 0x3c },
- { .amp = 0xe8, .emp = 0xd0 },
- { .amp = 0xb4, .emp = 0x78 },
- },
- /* voltage swing 2, pre-emphasis 0->3 */
- {
- { .amp = 0xe0, .emp = 0x68 },
- { .amp = 0xe8, .emp = 0xd0 },
- },
- /* voltage swing 3, pre-emphasis 0->3 */
- {
- { .amp = 0xf0, .emp = 0x00 },
- },
-};
-
void analogix_dp_set_lane_link_training(struct analogix_dp_device *dp)
{
u8 lane;
@@ -819,7 +649,7 @@
dp->link_train.training_lane[lane]);
if (dp->phy) {
- union phy_configure_opts phy_cfg;
+ union phy_configure_opts phy_cfg = {0};
for (lane = 0; lane < dp->link_train.lane_count; lane++) {
u8 training_lane = dp->link_train.training_lane[lane];
@@ -834,6 +664,8 @@
}
phy_cfg.dp.lanes = dp->link_train.lane_count;
+ phy_cfg.dp.link_rate =
+ drm_dp_bw_code_to_link_rate(dp->link_train.link_rate) / 100;
phy_cfg.dp.set_lanes = false;
phy_cfg.dp.set_rate = false;
phy_cfg.dp.set_voltages = true;
@@ -842,63 +674,6 @@
dev_err(dp->dev, "%s: phy_configure() failed: %d\n",
__func__, ret);
return;
- }
- } else {
- const struct swing_pre_emp_ctrl *ctrl;
-
- for (lane = 0; lane < dp->link_train.lane_count; lane++) {
- u8 training_lane = dp->link_train.training_lane[lane];
- u8 vs, pe;
- u32 reg;
-
- vs = (training_lane & DP_TRAIN_VOLTAGE_SWING_MASK) >>
- DP_TRAIN_VOLTAGE_SWING_SHIFT;
- pe = (training_lane & DP_TRAIN_PRE_EMPHASIS_MASK) >>
- DP_TRAIN_PRE_EMPHASIS_SHIFT;
-
- switch (dp->link_train.link_rate) {
- case DP_LINK_BW_1_62:
- ctrl = &swing_pre_emp_ctrl_rbr[vs][pe];
- break;
- case DP_LINK_BW_2_7:
- ctrl = &swing_pre_emp_ctrl_hbr[vs][pe];
- break;
- case DP_LINK_BW_5_4:
- default:
- ctrl = &swing_pre_emp_ctrl_hbr2[vs][pe];
- break;
- }
-
- switch (lane) {
- case 0:
- reg = analogix_dp_read(dp, ANALOGIX_DP_ANALOG_CTL_42);
- reg |= R_FORCE_CH0_AMP | R_FORCE_CH0_EMP;
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_42, reg);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_36, ctrl->amp);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_37, ctrl->emp);
- break;
- case 1:
- reg = analogix_dp_read(dp, ANALOGIX_DP_ANALOG_CTL_42);
- reg |= R_FORCE_CH1_AMP | R_FORCE_CH1_EMP;
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_42, reg);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_39, ctrl->amp);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_40, ctrl->emp);
- break;
- case 2:
- reg = analogix_dp_read(dp, ANALOGIX_DP_ANALOG_CTL_49);
- reg |= R_FORCE_CH2_AMP | R_FORCE_CH2_EMP;
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_49, reg);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_43, ctrl->amp);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_44, ctrl->emp);
- break;
- case 3:
- reg = analogix_dp_read(dp, ANALOGIX_DP_ANALOG_CTL_49);
- reg |= R_FORCE_CH3_AMP | R_FORCE_CH3_EMP;
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_49, reg);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_46, ctrl->amp);
- analogix_dp_write(dp, ANALOGIX_DP_ANALOG_CTL_47, ctrl->emp);
- break;
- }
}
}
}
@@ -925,6 +700,15 @@
}
}
+bool analogix_dp_get_enhanced_mode(struct analogix_dp_device *dp)
+{
+ u32 reg;
+
+ reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_4);
+
+ return !!(reg & ENHANCED);
+}
+
void analogix_dp_set_training_pattern(struct analogix_dp_device *dp,
enum pattern_set pattern)
{
@@ -949,6 +733,22 @@
break;
case TRAINING_PTN3:
reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN3;
+ analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
+ break;
+ case TEST_PATTERN_80BIT:
+ reg = 0x3e0f83e0;
+ analogix_dp_write(dp, ANALOGIX_DP_TEST_80B_PATTERN0, reg);
+ reg = 0x0f83e0f8;
+ analogix_dp_write(dp, ANALOGIX_DP_TEST_80B_PATTERN1, reg);
+ reg = 0x0000f83e;
+ analogix_dp_write(dp, ANALOGIX_DP_TEST_80B_PATTERN2, reg);
+ reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_80BIT;
+ analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
+ break;
+ case TEST_PATTERN_HBR2:
+ reg = 0xfb;
+ analogix_dp_write(dp, ANALOGIX_DP_TEST_HBR2_PATTERN, reg);
+ reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_HBR2;
analogix_dp_write(dp, ANALOGIX_DP_TRAINING_PTN_SET, reg);
break;
case DP_NONE:
@@ -990,8 +790,11 @@
reg = CHA_CRI(4) | CHA_CTRL;
analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_2, reg);
- reg = 0x0;
- analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
+ if (dp->video_info.force_stream_valid) {
+ reg = analogix_dp_read(dp, ANALOGIX_DP_SYS_CTL_3);
+ reg |= VALID_CTRL | F_VALID;
+ analogix_dp_write(dp, ANALOGIX_DP_SYS_CTL_3, reg);
+ }
reg = VID_HRES_TH(2) | VID_VRES_TH(0);
analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_8, reg);
@@ -1204,8 +1007,26 @@
return status;
}
+static void analogix_dp_reuse_spd(struct analogix_dp_device *dp)
+{
+ u32 reg, val;
+
+ switch (dp->plat_data->dev_type) {
+ case RK3588_EDP:
+ reg = ANALOGIX_DP_SPDIF_AUDIO_CTL_0;
+ break;
+ default:
+ reg = ANALOGIX_DP_VIDEO_CTL_3;
+ break;
+ }
+
+ val = analogix_dp_read(dp, reg);
+ val |= REUSE_SPD_EN;
+ analogix_dp_write(dp, reg, val);
+}
+
int analogix_dp_send_psr_spd(struct analogix_dp_device *dp,
- struct edp_vsc_psr *vsc, bool blocking)
+ struct dp_sdp *vsc, bool blocking)
{
unsigned int val;
int ret;
@@ -1233,13 +1054,16 @@
analogix_dp_write(dp, ANALOGIX_DP_SPD_PB3, 0x5D);
/* configure DB0 / DB1 values */
- analogix_dp_write(dp, ANALOGIX_DP_VSC_SHADOW_DB0, vsc->DB0);
- analogix_dp_write(dp, ANALOGIX_DP_VSC_SHADOW_DB1, vsc->DB1);
+ analogix_dp_write(dp, ANALOGIX_DP_VSC_SHADOW_DB0, vsc->db[0]);
+ analogix_dp_write(dp, ANALOGIX_DP_VSC_SHADOW_DB1, vsc->db[1]);
+
+ /* configure PB0 / PB1 values */
+ analogix_dp_write(dp, ANALOGIX_DP_VSC_SHADOW_PB0,
+ vsc->db[1] ? 0x8d : 0x00);
+ analogix_dp_write(dp, ANALOGIX_DP_VSC_SHADOW_PB1, 0x00);
/* set reuse spd inforframe */
- val = analogix_dp_read(dp, ANALOGIX_DP_VIDEO_CTL_3);
- val |= REUSE_SPD_EN;
- analogix_dp_write(dp, ANALOGIX_DP_VIDEO_CTL_3, val);
+ analogix_dp_reuse_spd(dp);
/* mark info frame update */
val = analogix_dp_read(dp, ANALOGIX_DP_PKT_SEND_CTL);
@@ -1254,11 +1078,21 @@
if (!blocking)
return 0;
+ /*
+ * db[1]!=0: entering PSR, wait for fully active remote frame buffer.
+ * db[1]==0: exiting PSR, wait for either
+ * (a) ACTIVE_RESYNC - the sink "must display the
+ * incoming active frames from the Source device with no visible
+ * glitches and/or artifacts", even though timings may still be
+ * re-synchronizing; or
+ * (b) INACTIVE - the transition is fully complete.
+ */
ret = readx_poll_timeout(analogix_dp_get_psr_status, dp, psr_status,
psr_status >= 0 &&
- ((vsc->DB1 && psr_status == DP_PSR_SINK_ACTIVE_RFB) ||
- (!vsc->DB1 && psr_status == DP_PSR_SINK_INACTIVE)), 1500,
- DP_TIMEOUT_PSR_LOOP_MS * 1000);
+ ((vsc->db[1] && psr_status == DP_PSR_SINK_ACTIVE_RFB) ||
+ (!vsc->db[1] && (psr_status == DP_PSR_SINK_ACTIVE_RESYNC ||
+ psr_status == DP_PSR_SINK_INACTIVE))),
+ 1500, DP_TIMEOUT_PSR_LOOP_MS * 1000);
if (ret) {
dev_warn(dp->dev, "Failed to apply PSR %d\n", ret);
return ret;
@@ -1266,31 +1100,46 @@
return 0;
}
-void analogix_dp_phy_power_on(struct analogix_dp_device *dp)
+int analogix_dp_phy_power_on(struct analogix_dp_device *dp)
{
- if (dp->phy_enabled)
- return;
+ int ret;
- phy_power_on(dp->phy);
+ ret = phy_set_mode(dp->phy, PHY_MODE_DP);
+ if (ret) {
+ dev_err(dp->dev, "phy_set_mode failed: %d\n", ret);
+ return ret;
+ }
- dp->phy_enabled = true;
+ ret = phy_power_on(dp->phy);
+ if (ret) {
+ dev_err(dp->dev, "phy_power_on failed: %d\n", ret);
+ return ret;
+ }
+
+ return ret;
}
void analogix_dp_phy_power_off(struct analogix_dp_device *dp)
{
- if (!dp->phy_enabled)
- return;
-
phy_power_off(dp->phy);
-
- dp->phy_enabled = false;
}
+
+enum {
+ AUX_STATUS_OK,
+ AUX_STATUS_NACK_ERROR,
+ AUX_STATUS_TIMEOUT_ERROR,
+ AUX_STATUS_UNKNOWN_ERROR,
+ AUX_STATUS_MUCH_DEFER_ERROR,
+ AUX_STATUS_TX_SHORT_ERROR,
+ AUX_STATUS_RX_SHORT_ERROR,
+ AUX_STATUS_NACK_WITHOUT_M_ERROR,
+ AUX_STATUS_I2C_NACK_ERROR
+};
ssize_t analogix_dp_transfer(struct analogix_dp_device *dp,
struct drm_dp_aux_msg *msg)
{
u32 reg;
- u32 status_reg;
u8 *buffer = msg->buffer;
unsigned int i;
int num_transferred = 0;
@@ -1299,12 +1148,6 @@
/* Buffer size of AUX CH is 16 bytes */
if (WARN_ON(msg->size > 16))
return -E2BIG;
-
- reg = analogix_dp_read(dp, ANALOGIX_DP_FUNC_EN_2);
- if (reg & AUX_FUNC_EN_N) {
- analogix_dp_phy_power_on(dp);
- analogix_dp_init_aux(dp);
- }
/* Clear AUX CH data buffer */
reg = BUF_CLR;
@@ -1383,18 +1226,19 @@
/* Clear interrupt source for AUX CH command reply */
analogix_dp_write(dp, ANALOGIX_DP_INT_STA, RPLY_RECEIV);
- /* Clear interrupt source for AUX CH access error */
- reg = analogix_dp_read(dp, ANALOGIX_DP_INT_STA);
- status_reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_STA);
- if ((reg & AUX_ERR) || (status_reg & AUX_STATUS_MASK)) {
- analogix_dp_write(dp, ANALOGIX_DP_INT_STA, AUX_ERR);
-
- dev_warn(dp->dev, "AUX CH error happened: %#x (%d)\n",
- status_reg & AUX_STATUS_MASK, !!(reg & AUX_ERR));
- goto aux_error;
- }
+ reg = analogix_dp_read(dp, ANALOGIX_DP_AUX_CH_STA);
+ if ((reg & AUX_STATUS_MASK) == AUX_STATUS_TIMEOUT_ERROR)
+ return -ETIMEDOUT;
if (msg->request & DP_AUX_I2C_READ) {
+ size_t buf_data_count;
+
+ reg = analogix_dp_read(dp, ANALOGIX_DP_BUFFER_DATA_CTL);
+ buf_data_count = BUF_DATA_COUNT(reg);
+
+ if (buf_data_count != msg->size)
+ return -EBUSY;
+
for (i = 0; i < msg->size; i++) {
reg = analogix_dp_read(dp, ANALOGIX_DP_BUF_DATA_0 +
4 * i);
@@ -1540,3 +1384,11 @@
reg |= AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N;
analogix_dp_write(dp, ANALOGIX_DP_FUNC_EN_1, reg);
}
+
+void analogix_dp_init(struct analogix_dp_device *dp)
+{
+ analogix_dp_init_interrupt(dp);
+ analogix_dp_config_interrupt(dp);
+ analogix_dp_init_hpd(dp);
+ analogix_dp_init_aux(dp);
+}
--
Gitblit v1.6.2