From 08f87f769b595151be1afeff53e144f543faa614 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 06 Dec 2023 09:51:13 +0000 Subject: [PATCH] add dts config --- 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