The DP AUX interrupt handling was a bit of a mess. * There were two functions (one for "native" transfers and one for "i2c" transfers) that were quite similar. It was hard to say how many of the differences between the two functions were on purpose and how many of them were just an accident of how they were coded. * Each function sometimes used "else if" to test for error bits and sometimes didn't and again it was hard to say if this was on purpose or just an accident. * The two functions wouldn't notice whether "unknown" bits were set. For instance, there seems to be a bit "DP_INTR_PLL_UNLOCKED" and if it was set there would be no indication. * The two functions wouldn't notice if more than one error was set. Let's fix this by being more consistent / explicit about what we're doing. By design this could cause different handling for AUX transfers, though I'm not actually aware of any bug fixed as a result of this patch (this patch was created because we simply noticed how odd the old code was by code inspection). Specific notes here: 1. In the old native transfer case if we got "done + wrong address" we'd ignore the "wrong address" (because of the "else if"). Now we won't. 2. In the old native transfer case if we got "done + timeout" we'd ignore the "timeout" (because of the "else if"). Now we won't. 3. In the old native transfer case we'd see "nack_defer" and translate it to the error number for "nack". This differed from the i2c transfer case where "nack_defer" was given the error number for "nack_defer". This 100% can't matter because the only user of this error number treats "nack defer" the same as "nack", so it's clear that the difference between the "native" and "i2c" was pointless here. 4. In the old i2c transfer case if we got "done" plus any error besides "nack" or "defer" then we'd ignore the error. Now we don't. 5. If there is more than one error signaled by the hardware it's possible that we'll report a different one than we used to. I don't know if this matters. If someone is aware of a case this matters we should document it and change the code to make it explicit. 6. One quirk we keep (I don't know if this is important) is that in the i2c transfer case if we see "done + defer" we report that as a "nack". That seemed too intentional in the old code to just drop. After this change we will add extra logging, including: * A warning if we see more than one error bit set. * A warning if we see an unexpected interrupt. * A warning if we get an AUX transfer interrupt when shouldn't. It actually turns out that as a result of this change then at boot we sometimes see an error: [drm:dp_aux_isr] *ERROR* Unexpected DP AUX IRQ 0x01000000 when not busy That means that, during init, we are seeing DP_INTR_PLL_UNLOCKED. For now I'm going to say that leaving this error reported in the logs is OK-ish and hopefully it will encourage someone to track down what's going on at init time. One last note here is that this change renames one of the interrupt bits. The bit named "i2c done" clearly was used for native transfers being done too, so I renamed it to indicate this. Signed-off-by: Douglas Anderson <dianders@chromium.org> Tested-by: Kuogee Hsieh <quic_khsieh@quicinc.com> Reviewed-by: Kuogee Hsieh <quic_khsieh@quicinc.com> Patchwork: https://patchwork.freedesktop.org/patch/520658/ Link: https://lore.kernel.org/r/20230126170745.v2.1.I90ffed3ddd21e818ae534f820cb4d6d8638859ab@changeid Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
143 lines
5.1 KiB
C
143 lines
5.1 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
|
*/
|
|
|
|
#ifndef _DP_CATALOG_H_
|
|
#define _DP_CATALOG_H_
|
|
|
|
#include <drm/drm_modes.h>
|
|
|
|
#include "dp_parser.h"
|
|
#include "disp/msm_disp_snapshot.h"
|
|
|
|
/* interrupts */
|
|
#define DP_INTR_HPD BIT(0)
|
|
#define DP_INTR_AUX_XFER_DONE BIT(3)
|
|
#define DP_INTR_WRONG_ADDR BIT(6)
|
|
#define DP_INTR_TIMEOUT BIT(9)
|
|
#define DP_INTR_NACK_DEFER BIT(12)
|
|
#define DP_INTR_WRONG_DATA_CNT BIT(15)
|
|
#define DP_INTR_I2C_NACK BIT(18)
|
|
#define DP_INTR_I2C_DEFER BIT(21)
|
|
#define DP_INTR_PLL_UNLOCKED BIT(24)
|
|
#define DP_INTR_AUX_ERROR BIT(27)
|
|
|
|
#define DP_INTR_READY_FOR_VIDEO BIT(0)
|
|
#define DP_INTR_IDLE_PATTERN_SENT BIT(3)
|
|
#define DP_INTR_FRAME_END BIT(6)
|
|
#define DP_INTR_CRC_UPDATED BIT(9)
|
|
|
|
#define DP_AUX_CFG_MAX_VALUE_CNT 3
|
|
|
|
/* PHY AUX config registers */
|
|
enum dp_phy_aux_config_type {
|
|
PHY_AUX_CFG0,
|
|
PHY_AUX_CFG1,
|
|
PHY_AUX_CFG2,
|
|
PHY_AUX_CFG3,
|
|
PHY_AUX_CFG4,
|
|
PHY_AUX_CFG5,
|
|
PHY_AUX_CFG6,
|
|
PHY_AUX_CFG7,
|
|
PHY_AUX_CFG8,
|
|
PHY_AUX_CFG9,
|
|
PHY_AUX_CFG_MAX,
|
|
};
|
|
|
|
enum dp_catalog_audio_sdp_type {
|
|
DP_AUDIO_SDP_STREAM,
|
|
DP_AUDIO_SDP_TIMESTAMP,
|
|
DP_AUDIO_SDP_INFOFRAME,
|
|
DP_AUDIO_SDP_COPYMANAGEMENT,
|
|
DP_AUDIO_SDP_ISRC,
|
|
DP_AUDIO_SDP_MAX,
|
|
};
|
|
|
|
enum dp_catalog_audio_header_type {
|
|
DP_AUDIO_SDP_HEADER_1,
|
|
DP_AUDIO_SDP_HEADER_2,
|
|
DP_AUDIO_SDP_HEADER_3,
|
|
DP_AUDIO_SDP_HEADER_MAX,
|
|
};
|
|
|
|
struct dp_catalog {
|
|
u32 aux_data;
|
|
u32 total;
|
|
u32 sync_start;
|
|
u32 width_blanking;
|
|
u32 dp_active;
|
|
enum dp_catalog_audio_sdp_type sdp_type;
|
|
enum dp_catalog_audio_header_type sdp_header;
|
|
u32 audio_data;
|
|
bool wide_bus_en;
|
|
};
|
|
|
|
/* Debug module */
|
|
void dp_catalog_snapshot(struct dp_catalog *dp_catalog, struct msm_disp_state *disp_state);
|
|
|
|
/* AUX APIs */
|
|
u32 dp_catalog_aux_read_data(struct dp_catalog *dp_catalog);
|
|
int dp_catalog_aux_write_data(struct dp_catalog *dp_catalog);
|
|
int dp_catalog_aux_write_trans(struct dp_catalog *dp_catalog);
|
|
int dp_catalog_aux_clear_trans(struct dp_catalog *dp_catalog, bool read);
|
|
int dp_catalog_aux_clear_hw_interrupts(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_aux_reset(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_aux_enable(struct dp_catalog *dp_catalog, bool enable);
|
|
void dp_catalog_aux_update_cfg(struct dp_catalog *dp_catalog);
|
|
int dp_catalog_aux_wait_for_hpd_connect_state(struct dp_catalog *dp_catalog);
|
|
u32 dp_catalog_aux_get_irq(struct dp_catalog *dp_catalog);
|
|
|
|
/* DP Controller APIs */
|
|
void dp_catalog_ctrl_state_ctrl(struct dp_catalog *dp_catalog, u32 state);
|
|
void dp_catalog_ctrl_config_ctrl(struct dp_catalog *dp_catalog, u32 config);
|
|
void dp_catalog_ctrl_lane_mapping(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog *dp_catalog, bool enable);
|
|
void dp_catalog_ctrl_psr_mainlink_enable(struct dp_catalog *dp_catalog, bool enable);
|
|
void dp_catalog_ctrl_config_misc(struct dp_catalog *dp_catalog, u32 cc, u32 tb);
|
|
void dp_catalog_ctrl_config_msa(struct dp_catalog *dp_catalog, u32 rate,
|
|
u32 stream_rate_khz, bool fixed_nvid);
|
|
int dp_catalog_ctrl_set_pattern_state_bit(struct dp_catalog *dp_catalog, u32 pattern);
|
|
u32 dp_catalog_hw_revision(const struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_reset(struct dp_catalog *dp_catalog);
|
|
bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_enable_irq(struct dp_catalog *dp_catalog, bool enable);
|
|
void dp_catalog_hpd_config_intr(struct dp_catalog *dp_catalog,
|
|
u32 intr_mask, bool en);
|
|
void dp_catalog_ctrl_hpd_config(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_config_psr(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_set_psr(struct dp_catalog *dp_catalog, bool enter);
|
|
u32 dp_catalog_link_is_connected(struct dp_catalog *dp_catalog);
|
|
u32 dp_catalog_hpd_get_intr_status(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_phy_reset(struct dp_catalog *dp_catalog);
|
|
int dp_catalog_ctrl_update_vx_px(struct dp_catalog *dp_catalog, u8 v_level,
|
|
u8 p_level);
|
|
int dp_catalog_ctrl_get_interrupt(struct dp_catalog *dp_catalog);
|
|
u32 dp_catalog_ctrl_read_psr_interrupt_status(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog *dp_catalog,
|
|
u32 dp_tu, u32 valid_boundary,
|
|
u32 valid_boundary2);
|
|
void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog *dp_catalog,
|
|
u32 pattern);
|
|
u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog *dp_catalog);
|
|
|
|
/* DP Panel APIs */
|
|
int dp_catalog_panel_timing_cfg(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_dump_regs(struct dp_catalog *dp_catalog);
|
|
void dp_catalog_panel_tpg_enable(struct dp_catalog *dp_catalog,
|
|
struct drm_display_mode *drm_mode);
|
|
void dp_catalog_panel_tpg_disable(struct dp_catalog *dp_catalog);
|
|
|
|
struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io);
|
|
|
|
/* DP Audio APIs */
|
|
void dp_catalog_audio_get_header(struct dp_catalog *catalog);
|
|
void dp_catalog_audio_set_header(struct dp_catalog *catalog);
|
|
void dp_catalog_audio_config_acr(struct dp_catalog *catalog);
|
|
void dp_catalog_audio_enable(struct dp_catalog *catalog);
|
|
void dp_catalog_audio_config_sdp(struct dp_catalog *catalog);
|
|
void dp_catalog_audio_init(struct dp_catalog *catalog);
|
|
void dp_catalog_audio_sfe_level(struct dp_catalog *catalog);
|
|
|
|
#endif /* _DP_CATALOG_H_ */
|