mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 02:01:18 -04:00
drm/msm/dp: move/inline ctrl register functions
Move CTRL-related functions to dp_ctrl.c, inlining one line wrappers during this process. The enable/disable functions have been split to the enable/disable or enter/exit pairs. The IRQ and HPD related functions are left in dp_catalog.c, pending later cleanup. Reviewed-by: Stephen Boyd <swboyd@chromium.org> Tested-by: Stephen Boyd <swboyd@chromium.org> # sc7180-trogdor Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> Patchwork: https://patchwork.freedesktop.org/patch/654328/ Link: https://lore.kernel.org/r/20250518-fd-dp-audio-fixup-v6-8-2f0ec3ec000d@oss.qualcomm.com
This commit is contained in:
committed by
Dmitry Baryshkov
parent
db3f715e88
commit
2b3d6611b2
@@ -18,8 +18,6 @@
|
||||
#define POLLING_SLEEP_US 1000
|
||||
#define POLLING_TIMEOUT_US 10000
|
||||
|
||||
#define SCRAMBLER_RESET_COUNT_VALUE 0xFC
|
||||
|
||||
#define DP_INTERRUPT_STATUS_ACK_SHIFT 1
|
||||
#define DP_INTERRUPT_STATUS_MASK_SHIFT 2
|
||||
|
||||
@@ -94,262 +92,6 @@ u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog)
|
||||
|
||||
}
|
||||
|
||||
/* controller related catalog functions */
|
||||
void msm_dp_catalog_ctrl_update_transfer_unit(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 msm_dp_tu, u32 valid_boundary,
|
||||
u32 valid_boundary2)
|
||||
{
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_VALID_BOUNDARY, valid_boundary);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TU, msm_dp_tu);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_VALID_BOUNDARY_2, valid_boundary2);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state)
|
||||
{
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL, state);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 cfg)
|
||||
{
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
struct msm_dp_catalog_private, msm_dp_catalog);
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", cfg);
|
||||
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_CONFIGURATION_CTRL, cfg);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
|
||||
u32 ln_mapping;
|
||||
|
||||
ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
|
||||
ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
|
||||
ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
|
||||
ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
|
||||
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING,
|
||||
ln_mapping);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog,
|
||||
bool enable)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
|
||||
if (enable)
|
||||
val |= DP_MAINLINK_CTRL_ENABLE;
|
||||
else
|
||||
val &= ~DP_MAINLINK_CTRL_ENABLE;
|
||||
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, val);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog,
|
||||
bool enable)
|
||||
{
|
||||
u32 mainlink_ctrl;
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
struct msm_dp_catalog_private, msm_dp_catalog);
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "enable=%d\n", enable);
|
||||
if (enable) {
|
||||
/*
|
||||
* To make sure link reg writes happens before other operation,
|
||||
* msm_dp_write_link() function uses writel()
|
||||
*/
|
||||
mainlink_ctrl = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
|
||||
mainlink_ctrl &= ~(DP_MAINLINK_CTRL_RESET |
|
||||
DP_MAINLINK_CTRL_ENABLE);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
|
||||
mainlink_ctrl |= DP_MAINLINK_CTRL_RESET;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
|
||||
mainlink_ctrl &= ~DP_MAINLINK_CTRL_RESET;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
|
||||
mainlink_ctrl |= (DP_MAINLINK_CTRL_ENABLE |
|
||||
DP_MAINLINK_FB_BOUNDARY_SEL);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
} else {
|
||||
mainlink_ctrl = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
}
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_config_misc(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 colorimetry_cfg,
|
||||
u32 test_bits_depth)
|
||||
{
|
||||
u32 misc_val;
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
struct msm_dp_catalog_private, msm_dp_catalog);
|
||||
|
||||
misc_val = msm_dp_read_link(msm_dp_catalog, REG_DP_MISC1_MISC0);
|
||||
|
||||
/* clear bpp bits */
|
||||
misc_val &= ~(0x07 << DP_MISC0_TEST_BITS_DEPTH_SHIFT);
|
||||
misc_val |= colorimetry_cfg << DP_MISC0_COLORIMETRY_CFG_SHIFT;
|
||||
misc_val |= test_bits_depth << DP_MISC0_TEST_BITS_DEPTH_SHIFT;
|
||||
/* Configure clock to synchronous mode */
|
||||
misc_val |= DP_MISC0_SYNCHRONOUS_CLK;
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "misc settings = 0x%x\n", misc_val);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MISC1_MISC0, misc_val);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
u32 mainlink_ctrl;
|
||||
|
||||
mainlink_ctrl = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
|
||||
if (msm_dp_catalog->hw_revision >= DP_HW_VERSION_1_2)
|
||||
mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
|
||||
else
|
||||
mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
|
||||
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_config_msa(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 rate, u32 stream_rate_khz,
|
||||
bool is_ycbcr_420)
|
||||
{
|
||||
u32 pixel_m, pixel_n;
|
||||
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
|
||||
u32 const nvid_fixed = DP_LINK_CONSTANT_N_VALUE;
|
||||
u32 const link_rate_hbr2 = 540000;
|
||||
u32 const link_rate_hbr3 = 810000;
|
||||
unsigned long den, num;
|
||||
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
struct msm_dp_catalog_private, msm_dp_catalog);
|
||||
|
||||
if (rate == link_rate_hbr3)
|
||||
pixel_div = 6;
|
||||
else if (rate == 162000 || rate == 270000)
|
||||
pixel_div = 2;
|
||||
else if (rate == link_rate_hbr2)
|
||||
pixel_div = 4;
|
||||
else
|
||||
DRM_ERROR("Invalid pixel mux divider\n");
|
||||
|
||||
dispcc_input_rate = (rate * 10) / pixel_div;
|
||||
|
||||
rational_best_approximation(dispcc_input_rate, stream_rate_khz,
|
||||
(unsigned long)(1 << 16) - 1,
|
||||
(unsigned long)(1 << 16) - 1, &den, &num);
|
||||
|
||||
den = ~(den - num);
|
||||
den = den & 0xFFFF;
|
||||
pixel_m = num;
|
||||
pixel_n = den;
|
||||
|
||||
mvid = (pixel_m & 0xFFFF) * 5;
|
||||
nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
|
||||
|
||||
if (nvid < nvid_fixed) {
|
||||
u32 temp;
|
||||
|
||||
temp = (nvid_fixed / nvid) * nvid;
|
||||
mvid = (nvid_fixed / nvid) * mvid;
|
||||
nvid = temp;
|
||||
}
|
||||
|
||||
if (is_ycbcr_420)
|
||||
mvid /= 2;
|
||||
|
||||
if (link_rate_hbr2 == rate)
|
||||
nvid *= 2;
|
||||
|
||||
if (link_rate_hbr3 == rate)
|
||||
nvid *= 3;
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_SOFTWARE_MVID, mvid);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_SOFTWARE_NVID, nvid);
|
||||
}
|
||||
|
||||
int msm_dp_catalog_ctrl_set_pattern_state_bit(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 state_bit)
|
||||
{
|
||||
int bit, ret;
|
||||
u32 data;
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
struct msm_dp_catalog_private, msm_dp_catalog);
|
||||
|
||||
bit = BIT(state_bit - 1);
|
||||
drm_dbg_dp(catalog->drm_dev, "hw: bit=%d train=%d\n", bit, state_bit);
|
||||
msm_dp_catalog_ctrl_state_ctrl(msm_dp_catalog, bit);
|
||||
|
||||
bit = BIT(state_bit - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT;
|
||||
|
||||
/* Poll for mainlink ready status */
|
||||
ret = readx_poll_timeout(readl, msm_dp_catalog->link_base +
|
||||
REG_DP_MAINLINK_READY,
|
||||
data, data & bit,
|
||||
POLLING_SLEEP_US, POLLING_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("set state_bit for link_train=%d failed\n", state_bit);
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* msm_dp_catalog_ctrl_reset() - reset DP controller
|
||||
*
|
||||
* @msm_dp_catalog: DP catalog structure
|
||||
*
|
||||
* return: void
|
||||
*
|
||||
* This function reset the DP controller
|
||||
*
|
||||
* NOTE: reset DP controller will also clear any pending HPD related interrupts
|
||||
*
|
||||
*/
|
||||
void msm_dp_catalog_ctrl_reset(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
u32 sw_reset;
|
||||
|
||||
sw_reset = msm_dp_read_ahb(msm_dp_catalog, REG_DP_SW_RESET);
|
||||
|
||||
sw_reset |= DP_SW_RESET;
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_SW_RESET, sw_reset);
|
||||
usleep_range(1000, 1100); /* h/w recommended delay */
|
||||
|
||||
sw_reset &= ~DP_SW_RESET;
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_SW_RESET, sw_reset);
|
||||
|
||||
if (!msm_dp_catalog->hw_revision)
|
||||
msm_dp_catalog->hw_revision = msm_dp_read_ahb(msm_dp_catalog, REG_DP_HW_VERSION);
|
||||
}
|
||||
|
||||
bool msm_dp_catalog_ctrl_mainlink_ready(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
/* Poll for mainlink ready status */
|
||||
ret = readl_poll_timeout(msm_dp_catalog->link_base +
|
||||
REG_DP_MAINLINK_READY,
|
||||
data, data & DP_MAINLINK_READY_FOR_VIDEO,
|
||||
POLLING_SLEEP_US, POLLING_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("mainlink not ready\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_enable_irq(struct msm_dp_catalog *msm_dp_catalog,
|
||||
bool enable)
|
||||
{
|
||||
@@ -402,43 +144,6 @@ void msm_dp_catalog_ctrl_hpd_disable(struct msm_dp_catalog *msm_dp_catalog)
|
||||
msm_dp_write_aux(msm_dp_catalog, REG_DP_DP_HPD_CTRL, 0);
|
||||
}
|
||||
|
||||
static void msm_dp_catalog_enable_sdp(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
/* trigger sdp */
|
||||
msm_dp_write_link(msm_dp_catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
|
||||
msm_dp_write_link(msm_dp_catalog, MMSS_DP_SDP_CFG3, 0x0);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_config_psr(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
u32 config;
|
||||
|
||||
/* enable PSR1 function */
|
||||
config = msm_dp_read_link(msm_dp_catalog, REG_PSR_CONFIG);
|
||||
config |= PSR1_SUPPORTED;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_PSR_CONFIG, config);
|
||||
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
|
||||
msm_dp_catalog_enable_sdp(msm_dp_catalog);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_set_psr(struct msm_dp_catalog *msm_dp_catalog, bool enter)
|
||||
{
|
||||
u32 cmd;
|
||||
|
||||
cmd = msm_dp_read_link(msm_dp_catalog, REG_PSR_CMD);
|
||||
|
||||
cmd &= ~(PSR_ENTER | PSR_EXIT);
|
||||
|
||||
if (enter)
|
||||
cmd |= PSR_ENTER;
|
||||
else
|
||||
cmd |= PSR_EXIT;
|
||||
|
||||
msm_dp_catalog_enable_sdp(msm_dp_catalog);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_PSR_CMD, cmd);
|
||||
}
|
||||
|
||||
u32 msm_dp_catalog_link_is_connected(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
@@ -484,6 +189,11 @@ u32 msm_dp_catalog_ctrl_read_psr_interrupt_status(struct msm_dp_catalog *msm_dp_
|
||||
return intr;
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_config_psr_interrupt(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_INTR_MASK4, DP_INTERRUPT_MASK4);
|
||||
}
|
||||
|
||||
int msm_dp_catalog_ctrl_get_interrupt(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
u32 intr, intr_ack;
|
||||
@@ -498,96 +208,6 @@ int msm_dp_catalog_ctrl_get_interrupt(struct msm_dp_catalog *msm_dp_catalog)
|
||||
return intr;
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_phy_reset(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_PHY_CTRL,
|
||||
DP_PHY_CTRL_SW_RESET | DP_PHY_CTRL_SW_RESET_PLL);
|
||||
usleep_range(1000, 1100); /* h/w recommended delay */
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_PHY_CTRL, 0x0);
|
||||
}
|
||||
|
||||
void msm_dp_catalog_ctrl_send_phy_pattern(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 pattern)
|
||||
{
|
||||
struct msm_dp_catalog_private *catalog = container_of(msm_dp_catalog,
|
||||
struct msm_dp_catalog_private, msm_dp_catalog);
|
||||
u32 value = 0x0;
|
||||
|
||||
/* Make sure to clear the current pattern before starting a new one */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL, 0x0);
|
||||
|
||||
drm_dbg_dp(catalog->drm_dev, "pattern: %#x\n", pattern);
|
||||
switch (pattern) {
|
||||
case DP_PHY_TEST_PATTERN_D10_2:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_TRAINING_PATTERN1);
|
||||
break;
|
||||
case DP_PHY_TEST_PATTERN_ERROR_COUNT:
|
||||
value &= ~(1 << 16);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
value |= SCRAMBLER_RESET_COUNT_VALUE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_LEVELS,
|
||||
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
|
||||
break;
|
||||
case DP_PHY_TEST_PATTERN_PRBS7:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_PRBS7);
|
||||
break;
|
||||
case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN);
|
||||
/* 00111110000011111000001111100000 */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0,
|
||||
0x3E0F83E0);
|
||||
/* 00001111100000111110000011111000 */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1,
|
||||
0x0F83E0F8);
|
||||
/* 1111100000111110 */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2,
|
||||
0x0000F83E);
|
||||
break;
|
||||
case DP_PHY_TEST_PATTERN_CP2520:
|
||||
value = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
value &= ~DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, value);
|
||||
|
||||
value = DP_HBR2_ERM_PATTERN;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
value |= SCRAMBLER_RESET_COUNT_VALUE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_LEVELS,
|
||||
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
|
||||
value = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
value |= DP_MAINLINK_CTRL_ENABLE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, value);
|
||||
break;
|
||||
case DP_PHY_TEST_PATTERN_SEL_MASK:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL,
|
||||
DP_MAINLINK_CTRL_ENABLE);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_TRAINING_PATTERN4);
|
||||
break;
|
||||
default:
|
||||
drm_dbg_dp(catalog->drm_dev,
|
||||
"No valid test pattern requested: %#x\n", pattern);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
u32 msm_dp_catalog_ctrl_read_phy_pattern(struct msm_dp_catalog *msm_dp_catalog)
|
||||
{
|
||||
return msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_READY);
|
||||
}
|
||||
|
||||
static void __iomem *msm_dp_ioremap(struct platform_device *pdev, int idx, size_t *len)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
|
||||
struct msm_dp_catalog {
|
||||
bool wide_bus_en;
|
||||
u32 hw_revision;
|
||||
|
||||
void __iomem *ahb_base;
|
||||
size_t ahb_len;
|
||||
@@ -117,36 +116,16 @@ void msm_dp_catalog_snapshot(struct msm_dp_catalog *msm_dp_catalog, struct msm_d
|
||||
u32 msm_dp_catalog_aux_get_irq(struct msm_dp_catalog *msm_dp_catalog);
|
||||
|
||||
/* DP Controller APIs */
|
||||
void msm_dp_catalog_ctrl_state_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 state);
|
||||
void msm_dp_catalog_ctrl_config_ctrl(struct msm_dp_catalog *msm_dp_catalog, u32 config);
|
||||
void msm_dp_catalog_ctrl_lane_mapping(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_mainlink_ctrl(struct msm_dp_catalog *msm_dp_catalog, bool enable);
|
||||
void msm_dp_catalog_ctrl_psr_mainlink_enable(struct msm_dp_catalog *msm_dp_catalog, bool enable);
|
||||
void msm_dp_catalog_setup_peripheral_flush(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_config_misc(struct msm_dp_catalog *msm_dp_catalog, u32 cc, u32 tb);
|
||||
void msm_dp_catalog_ctrl_config_msa(struct msm_dp_catalog *msm_dp_catalog, u32 rate,
|
||||
u32 stream_rate_khz, bool is_ycbcr_420);
|
||||
int msm_dp_catalog_ctrl_set_pattern_state_bit(struct msm_dp_catalog *msm_dp_catalog, u32 pattern);
|
||||
void msm_dp_catalog_ctrl_reset(struct msm_dp_catalog *msm_dp_catalog);
|
||||
bool msm_dp_catalog_ctrl_mainlink_ready(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_enable_irq(struct msm_dp_catalog *msm_dp_catalog, bool enable);
|
||||
void msm_dp_catalog_hpd_config_intr(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 intr_mask, bool en);
|
||||
void msm_dp_catalog_ctrl_hpd_enable(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_hpd_disable(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_config_psr(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_set_psr(struct msm_dp_catalog *msm_dp_catalog, bool enter);
|
||||
u32 msm_dp_catalog_link_is_connected(struct msm_dp_catalog *msm_dp_catalog);
|
||||
u32 msm_dp_catalog_hpd_get_intr_status(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_phy_reset(struct msm_dp_catalog *msm_dp_catalog);
|
||||
int msm_dp_catalog_ctrl_get_interrupt(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_config_psr_interrupt(struct msm_dp_catalog *msm_dp_catalog);
|
||||
u32 msm_dp_catalog_ctrl_read_psr_interrupt_status(struct msm_dp_catalog *msm_dp_catalog);
|
||||
void msm_dp_catalog_ctrl_update_transfer_unit(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 msm_dp_tu, u32 valid_boundary,
|
||||
u32 valid_boundary2);
|
||||
void msm_dp_catalog_ctrl_send_phy_pattern(struct msm_dp_catalog *msm_dp_catalog,
|
||||
u32 pattern);
|
||||
u32 msm_dp_catalog_ctrl_read_phy_pattern(struct msm_dp_catalog *msm_dp_catalog);
|
||||
|
||||
struct msm_dp_catalog *msm_dp_catalog_get(struct device *dev);
|
||||
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/phy/phy.h>
|
||||
#include <linux/phy/phy-dp.h>
|
||||
#include <linux/pm_opp.h>
|
||||
#include <linux/rational.h>
|
||||
#include <linux/string_choices.h>
|
||||
|
||||
#include <drm/display/drm_dp_helper.h>
|
||||
@@ -21,6 +23,9 @@
|
||||
#include "dp_ctrl.h"
|
||||
#include "dp_link.h"
|
||||
|
||||
#define POLLING_SLEEP_US 1000
|
||||
#define POLLING_TIMEOUT_US 10000
|
||||
|
||||
#define DP_KHZ_TO_HZ 1000
|
||||
#define IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES (30 * HZ / 1000) /* 30 ms */
|
||||
#define PSR_OPERATION_COMPLETION_TIMEOUT_JIFFIES (300 * HZ / 1000) /* 300 ms */
|
||||
@@ -95,6 +100,8 @@ struct msm_dp_ctrl_private {
|
||||
struct completion psr_op_comp;
|
||||
struct completion video_comp;
|
||||
|
||||
u32 hw_revision;
|
||||
|
||||
bool core_clks_on;
|
||||
bool link_clks_on;
|
||||
bool stream_clks_on;
|
||||
@@ -119,6 +126,118 @@ static int msm_dp_aux_link_configure(struct drm_dp_aux *aux,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* NOTE: resetting DP controller will also clear any pending HPD related interrupts
|
||||
*/
|
||||
static void msm_dp_ctrl_reset(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 sw_reset;
|
||||
|
||||
sw_reset = msm_dp_read_ahb(msm_dp_catalog, REG_DP_SW_RESET);
|
||||
|
||||
sw_reset |= DP_SW_RESET;
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_SW_RESET, sw_reset);
|
||||
usleep_range(1000, 1100); /* h/w recommended delay */
|
||||
|
||||
sw_reset &= ~DP_SW_RESET;
|
||||
msm_dp_write_ahb(msm_dp_catalog, REG_DP_SW_RESET, sw_reset);
|
||||
|
||||
if (!ctrl->hw_revision) {
|
||||
ctrl->hw_revision = msm_dp_read_ahb(msm_dp_catalog, REG_DP_HW_VERSION);
|
||||
ctrl->panel->hw_revision = ctrl->hw_revision;
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_psr_mainlink_enable(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 val;
|
||||
|
||||
val = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
val |= DP_MAINLINK_CTRL_ENABLE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, val);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_psr_mainlink_disable(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 val;
|
||||
|
||||
val = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
val &= ~DP_MAINLINK_CTRL_ENABLE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, val);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_mainlink_enable(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 mainlink_ctrl;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "enable\n");
|
||||
|
||||
mainlink_ctrl = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
|
||||
mainlink_ctrl &= ~(DP_MAINLINK_CTRL_RESET |
|
||||
DP_MAINLINK_CTRL_ENABLE);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
|
||||
mainlink_ctrl |= DP_MAINLINK_CTRL_RESET;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
|
||||
mainlink_ctrl &= ~DP_MAINLINK_CTRL_RESET;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
|
||||
mainlink_ctrl |= (DP_MAINLINK_CTRL_ENABLE |
|
||||
DP_MAINLINK_FB_BOUNDARY_SEL);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_mainlink_disable(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 mainlink_ctrl;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "disable\n");
|
||||
|
||||
mainlink_ctrl = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
mainlink_ctrl &= ~DP_MAINLINK_CTRL_ENABLE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
}
|
||||
|
||||
static void msm_dp_setup_peripheral_flush(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 mainlink_ctrl;
|
||||
|
||||
mainlink_ctrl = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
|
||||
if (ctrl->hw_revision >= DP_HW_VERSION_1_2)
|
||||
mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_SDE_PERIPH_UPDATE;
|
||||
else
|
||||
mainlink_ctrl |= DP_MAINLINK_FLUSH_MODE_UPDATE_SDP;
|
||||
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, mainlink_ctrl);
|
||||
}
|
||||
|
||||
static bool msm_dp_ctrl_mainlink_ready(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 data;
|
||||
int ret;
|
||||
|
||||
/* Poll for mainlink ready status */
|
||||
ret = readl_poll_timeout(msm_dp_catalog->link_base + REG_DP_MAINLINK_READY,
|
||||
data, data & DP_MAINLINK_READY_FOR_VIDEO,
|
||||
POLLING_SLEEP_US, POLLING_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("mainlink not ready\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
@@ -126,7 +245,7 @@ void msm_dp_ctrl_push_idle(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
reinit_completion(&ctrl->idle_comp);
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_PUSH_IDLE);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_PUSH_IDLE);
|
||||
|
||||
if (!wait_for_completion_timeout(&ctrl->idle_comp,
|
||||
IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES))
|
||||
@@ -171,22 +290,50 @@ static void msm_dp_ctrl_config_ctrl(struct msm_dp_ctrl_private *ctrl)
|
||||
if (ctrl->panel->psr_cap.version)
|
||||
config |= DP_CONFIGURATION_CTRL_SEND_VSC;
|
||||
|
||||
msm_dp_catalog_ctrl_config_ctrl(ctrl->catalog, config);
|
||||
drm_dbg_dp(ctrl->drm_dev, "DP_CONFIGURATION_CTRL=0x%x\n", config);
|
||||
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_CONFIGURATION_CTRL, config);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_lane_mapping(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 ln_0 = 0, ln_1 = 1, ln_2 = 2, ln_3 = 3; /* One-to-One mapping */
|
||||
u32 ln_mapping;
|
||||
|
||||
ln_mapping = ln_0 << LANE0_MAPPING_SHIFT;
|
||||
ln_mapping |= ln_1 << LANE1_MAPPING_SHIFT;
|
||||
ln_mapping |= ln_2 << LANE2_MAPPING_SHIFT;
|
||||
ln_mapping |= ln_3 << LANE3_MAPPING_SHIFT;
|
||||
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_LOGICAL2PHYSICAL_LANE_MAPPING,
|
||||
ln_mapping);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_configure_source_params(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
u32 cc, tb;
|
||||
u32 colorimetry_cfg, test_bits_depth, misc_val;
|
||||
|
||||
msm_dp_catalog_ctrl_lane_mapping(ctrl->catalog);
|
||||
msm_dp_catalog_setup_peripheral_flush(ctrl->catalog);
|
||||
msm_dp_ctrl_lane_mapping(ctrl);
|
||||
msm_dp_setup_peripheral_flush(ctrl);
|
||||
|
||||
msm_dp_ctrl_config_ctrl(ctrl);
|
||||
|
||||
tb = msm_dp_link_get_test_bits_depth(ctrl->link,
|
||||
ctrl->panel->msm_dp_mode.bpp);
|
||||
cc = msm_dp_link_get_colorimetry_config(ctrl->link);
|
||||
msm_dp_catalog_ctrl_config_misc(ctrl->catalog, cc, tb);
|
||||
test_bits_depth = msm_dp_link_get_test_bits_depth(ctrl->link, ctrl->panel->msm_dp_mode.bpp);
|
||||
colorimetry_cfg = msm_dp_link_get_colorimetry_config(ctrl->link);
|
||||
|
||||
misc_val = msm_dp_read_link(ctrl->catalog, REG_DP_MISC1_MISC0);
|
||||
|
||||
/* clear bpp bits */
|
||||
misc_val &= ~(0x07 << DP_MISC0_TEST_BITS_DEPTH_SHIFT);
|
||||
misc_val |= colorimetry_cfg << DP_MISC0_COLORIMETRY_CFG_SHIFT;
|
||||
misc_val |= test_bits_depth << DP_MISC0_TEST_BITS_DEPTH_SHIFT;
|
||||
/* Configure clock to synchronous mode */
|
||||
misc_val |= DP_MISC0_SYNCHRONOUS_CLK;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "misc settings = 0x%x\n", misc_val);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_MISC1_MISC0, misc_val);
|
||||
|
||||
msm_dp_panel_timing_cfg(ctrl->panel);
|
||||
}
|
||||
|
||||
@@ -1003,8 +1150,9 @@ static void msm_dp_ctrl_setup_tr_unit(struct msm_dp_ctrl_private *ctrl)
|
||||
pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n",
|
||||
msm_dp_tu, valid_boundary, valid_boundary2);
|
||||
|
||||
msm_dp_catalog_ctrl_update_transfer_unit(ctrl->catalog,
|
||||
msm_dp_tu, valid_boundary, valid_boundary2);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_VALID_BOUNDARY, valid_boundary);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_TU, msm_dp_tu);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_VALID_BOUNDARY_2, valid_boundary2);
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_wait4video_ready(struct msm_dp_ctrl_private *ctrl)
|
||||
@@ -1113,6 +1261,30 @@ static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
|
||||
return ret == 1;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_set_pattern_state_bit(struct msm_dp_ctrl_private *ctrl,
|
||||
u32 state_bit)
|
||||
{
|
||||
int bit, ret;
|
||||
u32 data;
|
||||
|
||||
bit = BIT(state_bit - 1);
|
||||
drm_dbg_dp(ctrl->drm_dev, "hw: bit=%d train=%d\n", bit, state_bit);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, bit);
|
||||
|
||||
bit = BIT(state_bit - 1) << DP_MAINLINK_READY_LINK_TRAINING_SHIFT;
|
||||
|
||||
/* Poll for mainlink ready status */
|
||||
ret = readx_poll_timeout(readl, ctrl->catalog->link_base + REG_DP_MAINLINK_READY,
|
||||
data, data & bit,
|
||||
POLLING_SLEEP_US, POLLING_TIMEOUT_US);
|
||||
if (ret < 0) {
|
||||
DRM_ERROR("set state_bit for link_train=%d failed\n", state_bit);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
|
||||
int *training_step, enum drm_dp_phy dp_phy)
|
||||
{
|
||||
@@ -1124,11 +1296,11 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
|
||||
delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux,
|
||||
ctrl->panel->dpcd, dp_phy, false);
|
||||
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, 0);
|
||||
|
||||
*training_step = DP_TRAINING_1;
|
||||
|
||||
ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, 1);
|
||||
ret = msm_dp_ctrl_set_pattern_state_bit(ctrl, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
|
||||
@@ -1242,7 +1414,7 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
|
||||
delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
|
||||
ctrl->panel->dpcd, dp_phy, false);
|
||||
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, 0);
|
||||
|
||||
*training_step = DP_TRAINING_2;
|
||||
|
||||
@@ -1257,7 +1429,7 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
|
||||
state_ctrl_bit = 2;
|
||||
}
|
||||
|
||||
ret = msm_dp_catalog_ctrl_set_pattern_state_bit(ctrl->catalog, state_ctrl_bit);
|
||||
ret = msm_dp_ctrl_set_pattern_state_bit(ctrl, state_ctrl_bit);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -1359,7 +1531,7 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
|
||||
}
|
||||
|
||||
end:
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1369,7 +1541,7 @@ static int msm_dp_ctrl_setup_main_link(struct msm_dp_ctrl_private *ctrl,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, true);
|
||||
msm_dp_ctrl_mainlink_enable(ctrl);
|
||||
|
||||
if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
|
||||
return ret;
|
||||
@@ -1508,7 +1680,7 @@ void msm_dp_ctrl_reset_irq_ctrl(struct msm_dp_ctrl *msm_dp_ctrl, bool enable)
|
||||
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
|
||||
msm_dp_catalog_ctrl_reset(ctrl->catalog);
|
||||
msm_dp_ctrl_reset(ctrl);
|
||||
|
||||
/*
|
||||
* all dp controller programmable registers will not
|
||||
@@ -1519,16 +1691,60 @@ void msm_dp_ctrl_reset_irq_ctrl(struct msm_dp_ctrl *msm_dp_ctrl, bool enable)
|
||||
msm_dp_catalog_ctrl_enable_irq(ctrl->catalog, enable);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_enable_sdp(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
|
||||
/* trigger sdp */
|
||||
msm_dp_write_link(msm_dp_catalog, MMSS_DP_SDP_CFG3, UPDATE_SDP);
|
||||
msm_dp_write_link(msm_dp_catalog, MMSS_DP_SDP_CFG3, 0x0);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_psr_enter(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 cmd;
|
||||
|
||||
cmd = msm_dp_read_link(msm_dp_catalog, REG_PSR_CMD);
|
||||
|
||||
cmd &= ~(PSR_ENTER | PSR_EXIT);
|
||||
cmd |= PSR_ENTER;
|
||||
|
||||
msm_dp_ctrl_enable_sdp(ctrl);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_PSR_CMD, cmd);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_psr_exit(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 cmd;
|
||||
|
||||
cmd = msm_dp_read_link(msm_dp_catalog, REG_PSR_CMD);
|
||||
|
||||
cmd &= ~(PSR_ENTER | PSR_EXIT);
|
||||
cmd |= PSR_EXIT;
|
||||
|
||||
msm_dp_ctrl_enable_sdp(ctrl);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_PSR_CMD, cmd);
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_config_psr(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
{
|
||||
u8 cfg;
|
||||
struct msm_dp_ctrl_private *ctrl = container_of(msm_dp_ctrl,
|
||||
struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 cfg;
|
||||
|
||||
if (!ctrl->panel->psr_cap.version)
|
||||
return;
|
||||
|
||||
msm_dp_catalog_ctrl_config_psr(ctrl->catalog);
|
||||
/* enable PSR1 function */
|
||||
cfg = msm_dp_read_link(msm_dp_catalog, REG_PSR_CONFIG);
|
||||
cfg |= PSR1_SUPPORTED;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_PSR_CONFIG, cfg);
|
||||
|
||||
msm_dp_catalog_ctrl_config_psr_interrupt(msm_dp_catalog);
|
||||
msm_dp_ctrl_enable_sdp(ctrl);
|
||||
|
||||
cfg = DP_PSR_ENABLE;
|
||||
drm_dp_dpcd_write(ctrl->aux, DP_PSR_EN_CFG, &cfg, 1);
|
||||
@@ -1554,29 +1770,37 @@ void msm_dp_ctrl_set_psr(struct msm_dp_ctrl *msm_dp_ctrl, bool enter)
|
||||
*/
|
||||
if (enter) {
|
||||
reinit_completion(&ctrl->psr_op_comp);
|
||||
msm_dp_catalog_ctrl_set_psr(ctrl->catalog, true);
|
||||
msm_dp_ctrl_psr_enter(ctrl);
|
||||
|
||||
if (!wait_for_completion_timeout(&ctrl->psr_op_comp,
|
||||
PSR_OPERATION_COMPLETION_TIMEOUT_JIFFIES)) {
|
||||
DRM_ERROR("PSR_ENTRY timedout\n");
|
||||
msm_dp_catalog_ctrl_set_psr(ctrl->catalog, false);
|
||||
msm_dp_ctrl_psr_exit(ctrl);
|
||||
return;
|
||||
}
|
||||
|
||||
msm_dp_ctrl_push_idle(msm_dp_ctrl);
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, 0);
|
||||
|
||||
msm_dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, false);
|
||||
msm_dp_ctrl_psr_mainlink_disable(ctrl);
|
||||
} else {
|
||||
msm_dp_catalog_ctrl_psr_mainlink_enable(ctrl->catalog, true);
|
||||
msm_dp_ctrl_psr_mainlink_enable(ctrl);
|
||||
|
||||
msm_dp_catalog_ctrl_set_psr(ctrl->catalog, false);
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
|
||||
msm_dp_ctrl_psr_exit(ctrl);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
|
||||
msm_dp_ctrl_wait4video_ready(ctrl);
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_phy_reset(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
msm_dp_write_ahb(ctrl->catalog, REG_DP_PHY_CTRL,
|
||||
DP_PHY_CTRL_SW_RESET | DP_PHY_CTRL_SW_RESET_PLL);
|
||||
usleep_range(1000, 1100); /* h/w recommended delay */
|
||||
msm_dp_write_ahb(ctrl->catalog, REG_DP_PHY_CTRL, 0x0);
|
||||
}
|
||||
|
||||
void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
{
|
||||
struct msm_dp_ctrl_private *ctrl;
|
||||
@@ -1585,7 +1809,7 @@ void msm_dp_ctrl_phy_init(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
msm_dp_catalog_ctrl_phy_reset(ctrl->catalog);
|
||||
msm_dp_ctrl_phy_reset(ctrl);
|
||||
phy_init(phy);
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
|
||||
@@ -1600,7 +1824,7 @@ void msm_dp_ctrl_phy_exit(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
msm_dp_catalog_ctrl_phy_reset(ctrl->catalog);
|
||||
msm_dp_ctrl_phy_reset(ctrl);
|
||||
phy_exit(phy);
|
||||
drm_dbg_dp(ctrl->drm_dev, "phy=%p init=%d power_on=%d\n",
|
||||
phy, phy->init_count, phy->power_count);
|
||||
@@ -1611,7 +1835,7 @@ static int msm_dp_ctrl_reinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
||||
struct phy *phy = ctrl->phy;
|
||||
int ret = 0;
|
||||
|
||||
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
ctrl->phy_opts.dp.lanes = ctrl->link->link_params.num_lanes;
|
||||
phy_configure(phy, &ctrl->phy_opts);
|
||||
/*
|
||||
@@ -1642,9 +1866,9 @@ static int msm_dp_ctrl_deinitialize_mainlink(struct msm_dp_ctrl_private *ctrl)
|
||||
|
||||
phy = ctrl->phy;
|
||||
|
||||
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
msm_dp_catalog_ctrl_reset(ctrl->catalog);
|
||||
msm_dp_ctrl_reset(ctrl);
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
|
||||
@@ -1676,13 +1900,97 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
|
||||
|
||||
msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
|
||||
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
|
||||
|
||||
ret = msm_dp_ctrl_wait4video_ready(ctrl);
|
||||
end:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SCRAMBLER_RESET_COUNT_VALUE 0xFC
|
||||
|
||||
static void msm_dp_ctrl_send_phy_pattern(struct msm_dp_ctrl_private *ctrl,
|
||||
u32 pattern)
|
||||
{
|
||||
struct msm_dp_catalog *msm_dp_catalog = ctrl->catalog;
|
||||
u32 value = 0x0;
|
||||
|
||||
/* Make sure to clear the current pattern before starting a new one */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL, 0x0);
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "pattern: %#x\n", pattern);
|
||||
switch (pattern) {
|
||||
case DP_PHY_TEST_PATTERN_D10_2:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_TRAINING_PATTERN1);
|
||||
break;
|
||||
|
||||
case DP_PHY_TEST_PATTERN_ERROR_COUNT:
|
||||
value &= ~(1 << 16);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
value |= SCRAMBLER_RESET_COUNT_VALUE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_LEVELS,
|
||||
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
|
||||
break;
|
||||
|
||||
case DP_PHY_TEST_PATTERN_PRBS7:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_PRBS7);
|
||||
break;
|
||||
|
||||
case DP_PHY_TEST_PATTERN_80BIT_CUSTOM:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_TEST_CUSTOM_PATTERN);
|
||||
/* 00111110000011111000001111100000 */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG0,
|
||||
0x3E0F83E0);
|
||||
/* 00001111100000111110000011111000 */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG1,
|
||||
0x0F83E0F8);
|
||||
/* 1111100000111110 */
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_TEST_80BIT_CUSTOM_PATTERN_REG2,
|
||||
0x0000F83E);
|
||||
break;
|
||||
|
||||
case DP_PHY_TEST_PATTERN_CP2520:
|
||||
value = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
value &= ~DP_MAINLINK_CTRL_SW_BYPASS_SCRAMBLER;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, value);
|
||||
|
||||
value = DP_HBR2_ERM_PATTERN;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
value |= SCRAMBLER_RESET_COUNT_VALUE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_HBR2_COMPLIANCE_SCRAMBLER_RESET,
|
||||
value);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_LEVELS,
|
||||
DP_MAINLINK_SAFE_TO_EXIT_LEVEL_2);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_SYMBOL_ERR_MEASURE);
|
||||
value = msm_dp_read_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL);
|
||||
value |= DP_MAINLINK_CTRL_ENABLE;
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL, value);
|
||||
break;
|
||||
|
||||
case DP_PHY_TEST_PATTERN_SEL_MASK:
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_MAINLINK_CTRL,
|
||||
DP_MAINLINK_CTRL_ENABLE);
|
||||
msm_dp_write_link(msm_dp_catalog, REG_DP_STATE_CTRL,
|
||||
DP_STATE_CTRL_LINK_TRAINING_PATTERN4);
|
||||
break;
|
||||
|
||||
default:
|
||||
drm_dbg_dp(ctrl->drm_dev,
|
||||
"No valid test pattern requested: %#x\n", pattern);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
|
||||
{
|
||||
bool success = false;
|
||||
@@ -1697,11 +2005,11 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
|
||||
DRM_ERROR("Failed to set v/p levels\n");
|
||||
return false;
|
||||
}
|
||||
msm_dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
|
||||
msm_dp_ctrl_send_phy_pattern(ctrl, pattern_requested);
|
||||
msm_dp_ctrl_update_phy_vx_px(ctrl, DP_PHY_DPRX);
|
||||
msm_dp_link_send_test_response(ctrl->link);
|
||||
|
||||
pattern_sent = msm_dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
|
||||
pattern_sent = msm_dp_read_link(ctrl->catalog, REG_DP_MAINLINK_READY);
|
||||
|
||||
switch (pattern_sent) {
|
||||
case MR_LINK_TRAINING1:
|
||||
@@ -1980,6 +2288,62 @@ static int msm_dp_ctrl_link_retrain(struct msm_dp_ctrl_private *ctrl)
|
||||
return msm_dp_ctrl_setup_main_link(ctrl, &training_step);
|
||||
}
|
||||
|
||||
static void msm_dp_ctrl_config_msa(struct msm_dp_ctrl_private *ctrl,
|
||||
u32 rate, u32 stream_rate_khz,
|
||||
bool is_ycbcr_420)
|
||||
{
|
||||
u32 pixel_m, pixel_n;
|
||||
u32 mvid, nvid, pixel_div = 0, dispcc_input_rate;
|
||||
u32 const nvid_fixed = DP_LINK_CONSTANT_N_VALUE;
|
||||
u32 const link_rate_hbr2 = 540000;
|
||||
u32 const link_rate_hbr3 = 810000;
|
||||
unsigned long den, num;
|
||||
|
||||
if (rate == link_rate_hbr3)
|
||||
pixel_div = 6;
|
||||
else if (rate == 162000 || rate == 270000)
|
||||
pixel_div = 2;
|
||||
else if (rate == link_rate_hbr2)
|
||||
pixel_div = 4;
|
||||
else
|
||||
DRM_ERROR("Invalid pixel mux divider\n");
|
||||
|
||||
dispcc_input_rate = (rate * 10) / pixel_div;
|
||||
|
||||
rational_best_approximation(dispcc_input_rate, stream_rate_khz,
|
||||
(unsigned long)(1 << 16) - 1,
|
||||
(unsigned long)(1 << 16) - 1, &den, &num);
|
||||
|
||||
den = ~(den - num);
|
||||
den = den & 0xFFFF;
|
||||
pixel_m = num;
|
||||
pixel_n = den;
|
||||
|
||||
mvid = (pixel_m & 0xFFFF) * 5;
|
||||
nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF);
|
||||
|
||||
if (nvid < nvid_fixed) {
|
||||
u32 temp;
|
||||
|
||||
temp = (nvid_fixed / nvid) * nvid;
|
||||
mvid = (nvid_fixed / nvid) * mvid;
|
||||
nvid = temp;
|
||||
}
|
||||
|
||||
if (is_ycbcr_420)
|
||||
mvid /= 2;
|
||||
|
||||
if (link_rate_hbr2 == rate)
|
||||
nvid *= 2;
|
||||
|
||||
if (link_rate_hbr3 == rate)
|
||||
nvid *= 3;
|
||||
|
||||
drm_dbg_dp(ctrl->drm_dev, "mvid=0x%x, nvid=0x%x\n", mvid, nvid);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_SOFTWARE_MVID, mvid);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_SOFTWARE_NVID, nvid);
|
||||
}
|
||||
|
||||
int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -2045,7 +2409,7 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
|
||||
|
||||
msm_dp_ctrl_configure_source_params(ctrl);
|
||||
|
||||
msm_dp_catalog_ctrl_config_msa(ctrl->catalog,
|
||||
msm_dp_ctrl_config_msa(ctrl,
|
||||
ctrl->link->link_params.rate,
|
||||
pixel_rate_orig,
|
||||
ctrl->panel->msm_dp_mode.out_fmt_is_yuv_420);
|
||||
@@ -2054,13 +2418,13 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
|
||||
|
||||
msm_dp_ctrl_setup_tr_unit(ctrl);
|
||||
|
||||
msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
|
||||
msm_dp_write_link(ctrl->catalog, REG_DP_STATE_CTRL, DP_STATE_CTRL_SEND_VIDEO);
|
||||
|
||||
ret = msm_dp_ctrl_wait4video_ready(ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mainlink_ready = msm_dp_catalog_ctrl_mainlink_ready(ctrl->catalog);
|
||||
mainlink_ready = msm_dp_ctrl_mainlink_ready(ctrl);
|
||||
drm_dbg_dp(ctrl->drm_dev,
|
||||
"mainlink %s\n", mainlink_ready ? "READY" : "NOT READY");
|
||||
|
||||
@@ -2081,7 +2445,7 @@ void msm_dp_ctrl_off_link_stream(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
/* set dongle to D3 (power off) mode */
|
||||
msm_dp_link_psm_config(ctrl->link, &ctrl->panel->link_info, true);
|
||||
|
||||
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
clk_disable_unprepare(ctrl->pixel_clk);
|
||||
@@ -2109,7 +2473,7 @@ void msm_dp_ctrl_off_link(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
ctrl = container_of(msm_dp_ctrl, struct msm_dp_ctrl_private, msm_dp_ctrl);
|
||||
phy = ctrl->phy;
|
||||
|
||||
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
dev_pm_opp_set_rate(ctrl->dev, 0);
|
||||
msm_dp_ctrl_link_clk_disable(&ctrl->msm_dp_ctrl);
|
||||
@@ -2133,9 +2497,9 @@ void msm_dp_ctrl_off(struct msm_dp_ctrl *msm_dp_ctrl)
|
||||
|
||||
msm_dp_panel_disable_vsc_sdp(ctrl->panel);
|
||||
|
||||
msm_dp_catalog_ctrl_mainlink_ctrl(ctrl->catalog, false);
|
||||
msm_dp_ctrl_mainlink_disable(ctrl);
|
||||
|
||||
msm_dp_catalog_ctrl_reset(ctrl->catalog);
|
||||
msm_dp_ctrl_reset(ctrl);
|
||||
|
||||
if (ctrl->stream_clks_on) {
|
||||
clk_disable_unprepare(ctrl->pixel_clk);
|
||||
|
||||
@@ -390,7 +390,7 @@ static void msm_dp_panel_send_vsc_sdp(struct msm_dp_panel_private *panel, struct
|
||||
|
||||
static void msm_dp_panel_update_sdp(struct msm_dp_panel_private *panel)
|
||||
{
|
||||
u32 hw_revision = panel->catalog->hw_revision;
|
||||
u32 hw_revision = panel->msm_dp_panel.hw_revision;
|
||||
|
||||
if (hw_revision >= DP_HW_VERSION_1_0 &&
|
||||
hw_revision < DP_HW_VERSION_1_2) {
|
||||
|
||||
@@ -38,6 +38,7 @@ struct msm_dp_panel {
|
||||
struct msm_dp_panel_psr psr_cap;
|
||||
bool video_test;
|
||||
bool vsc_sdp_supported;
|
||||
u32 hw_revision;
|
||||
|
||||
u32 max_dp_lanes;
|
||||
u32 max_dp_link_rate;
|
||||
|
||||
Reference in New Issue
Block a user