diff options
author | Dave Airlie <airlied@redhat.com> | 2022-09-11 21:46:57 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2022-09-11 22:03:07 +1000 |
commit | fb34d8a04e5876552cd0d4f9e14400ee13f116fb (patch) | |
tree | 4bdd1c43f67c6c013d2b08b11cecfd576fa1fa4b /drivers/gpu/drm/bridge | |
parent | 8284bae723f025cb6a8431566757a3854a3c53eb (diff) | |
parent | 5d832b6694e094b176627ed9918a1b21c56fb742 (diff) | |
download | linux-fb34d8a04e5876552cd0d4f9e14400ee13f116fb.tar.bz2 |
Merge tag 'drm-misc-next-2022-09-09' of git://anongit.freedesktop.org/drm/drm-misc into drm-next
drm-misc-next for v6.1-rc1:
[airlied - fix sun4i_tv build]
UAPI Changes:
- Hide unregistered connectors from GETCONNECTOR ioctl.
- drm/virtio no longer advertises LINEAR modifier, as it doesn't work.
-
Cross-subsystem Changes:
- Fix GPF in udmabuf failure path.
Core Changes:
- Rework TTM placement to use intersect/compatible functions.
- Drop legacy DP-MST support.
- More DP-MST related fixes, and move all state into atomic.
- Make DRM_MIPI_DBI select DRM_KMS_HELPER.
- Add audio_infoframe packing for DP.
- Add logging when some atomic check functions fail.
- Assorted documentation updates and fixes.
Driver Changes:
- Assorted cleanups and fixes in msm, lcdif, nouveau, virtio,
panel/ilitek, bridge/icn6211, tve200, gma500, bridge/*, panfrost, via,
bochs, qxl, sun4i.
- Add add AUO B133UAN02.1, IVO M133NW4J-R3, Innolux N120ACA-EA1 eDP panels.
- Improve DP-MST modeset state handling in amdgpu, nouveau, i915.
- Drop DP-MST from radeon driver, it was broken and only user of legacy
DP-MST.
- Handle unplugging better in vc4.
- Simplify drm cmdparser tests.
- Add DP support to ti-sn65dsi86.
- Add MT8195 DP support to mediatek.
- Support RGB565, XRGB64, and ARGB64 formats in vkms.
- Convert sun4i tv support to atomic.
- Refactor vc4/vec TV Modesetting, and fix timings.
- Use atomic helpers instead of simple display helpers in ssd130x.
Maintainer changes:
- Add Douglas Anderson as reviewer for panel-edp.
Signed-off-by: Dave Airlie <airlied@redhat.com>
From: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/a489485b-3ebc-c734-0f80-aed963d89efe@linux.intel.com
Diffstat (limited to 'drivers/gpu/drm/bridge')
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/anx7625.c | 37 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/analogix/anx7625.h | 6 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 3 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/chipone-icn6211.c | 44 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/chrontel-ch7033.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/ite-it6505.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 4 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/parade-ps8640.c | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 13 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/tc358767.c | 15 | ||||
-rw-r--r-- | drivers/gpu/drm/bridge/ti-sn65dsi86.c | 72 |
11 files changed, 186 insertions, 36 deletions
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c index 79fc7a50b497..0c323b5a1c99 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.c +++ b/drivers/gpu/drm/bridge/analogix/anx7625.c @@ -1440,6 +1440,20 @@ static void anx7625_start_dp_work(struct anx7625_data *ctx) static int anx7625_read_hpd_status_p0(struct anx7625_data *ctx) { + int ret; + + /* Set irq detect window to 2ms */ + ret = anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT0_7, HPD_TIME & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT8_15, + (HPD_TIME >> 8) & 0xFF); + ret |= anx7625_reg_write(ctx, ctx->i2c.tx_p2_client, + HPD_DET_TIMER_BIT16_23, + (HPD_TIME >> 16) & 0xFF); + if (ret < 0) + return ret; + return anx7625_reg_read(ctx, ctx->i2c.rx_p0_client, SYSTEM_STSTUS); } @@ -1797,8 +1811,13 @@ static int anx7625_audio_hw_params(struct device *dev, void *data, int wl, ch, rate; int ret = 0; - if (fmt->fmt != HDMI_DSP_A) { - DRM_DEV_ERROR(dev, "only supports DSP_A\n"); + if (anx7625_sink_detect(ctx) == connector_status_disconnected) { + DRM_DEV_DEBUG_DRIVER(dev, "DP not connected\n"); + return 0; + } + + if (fmt->fmt != HDMI_DSP_A && fmt->fmt != HDMI_I2S) { + DRM_DEV_ERROR(dev, "only supports DSP_A & I2S\n"); return -EINVAL; } @@ -1806,10 +1825,16 @@ static int anx7625_audio_hw_params(struct device *dev, void *data, params->sample_rate, params->sample_width, params->cea.channels); - ret |= anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, - AUDIO_CHANNEL_STATUS_6, - ~I2S_SLAVE_MODE, - TDM_SLAVE_MODE); + if (fmt->fmt == HDMI_DSP_A) + ret = anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_6, + ~I2S_SLAVE_MODE, + TDM_SLAVE_MODE); + else + ret = anx7625_write_and_or(ctx, ctx->i2c.tx_p2_client, + AUDIO_CHANNEL_STATUS_6, + ~TDM_SLAVE_MODE, + I2S_SLAVE_MODE); /* Word length */ switch (params->sample_width) { diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.h b/drivers/gpu/drm/bridge/analogix/anx7625.h index e257a84db962..14f33d6be289 100644 --- a/drivers/gpu/drm/bridge/analogix/anx7625.h +++ b/drivers/gpu/drm/bridge/analogix/anx7625.h @@ -132,6 +132,12 @@ #define I2S_SLAVE_MODE 0x08 #define AUDIO_LAYOUT 0x01 +#define HPD_DET_TIMER_BIT0_7 0xea +#define HPD_DET_TIMER_BIT8_15 0xeb +#define HPD_DET_TIMER_BIT16_23 0xec +/* HPD debounce time 2ms for 27M clock */ +#define HPD_TIME 54000 + #define AUDIO_CONTROL_REGISTER 0xe6 #define TDM_TIMING_MODE 0x08 diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c index ab63e7b11944..31442a922502 100644 --- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c +++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c @@ -2605,7 +2605,8 @@ static int cdns_mhdp_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); cancel_work_sync(&mhdp->modeset_retry_work); - flush_scheduled_work(); + flush_work(&mhdp->hpd_work); + /* Ignoring mhdp->hdcp.check_work and mhdp->hdcp.prop_work here. */ clk_disable_unprepare(mhdp->clk); diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c index b07d2d16c3cf..bf920c3503aa 100644 --- a/drivers/gpu/drm/bridge/chipone-icn6211.c +++ b/drivers/gpu/drm/bridge/chipone-icn6211.c @@ -11,6 +11,7 @@ #include <linux/bitfield.h> #include <linux/bits.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> @@ -151,6 +152,8 @@ struct chipone { struct regulator *vdd1; struct regulator *vdd2; struct regulator *vdd3; + struct clk *refclk; + unsigned long refclk_rate; bool interface_i2c; }; @@ -259,7 +262,7 @@ static void chipone_configure_pll(struct chipone *icn, /* * DSI byte clock frequency (input into PLL) is calculated as: - * DSI_CLK = mode clock * bpp / dsi_data_lanes / 8 + * DSI_CLK = HS clock / 4 * * DPI pixel clock frequency (output from PLL) is mode clock. * @@ -273,8 +276,10 @@ static void chipone_configure_pll(struct chipone *icn, * It seems the PLL input clock after applying P pre-divider have * to be lower than 20 MHz. */ - fin = mode_clock * mipi_dsi_pixel_format_to_bpp(icn->dsi->format) / - icn->dsi->lanes / 8; /* in Hz */ + if (icn->refclk) + fin = icn->refclk_rate; + else + fin = icn->dsi->hs_rate / 4; /* in Hz */ /* Minimum value of P predivider for PLL input in 5..20 MHz */ p_min = clamp(DIV_ROUND_UP(fin, 20000000), 1U, 31U); @@ -319,16 +324,18 @@ static void chipone_configure_pll(struct chipone *icn, best_p_pot = !(best_p & 1); dev_dbg(icn->dev, - "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in=%d Hz ; DPI f_out=%d Hz\n", + "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in(%s)=%d Hz ; DPI f_out=%d Hz\n", best_p >> best_p_pot, best_p_pot, best_m, best_s + 1, - min_delta, fin, (fin * best_m) / (best_p << (best_s + 1))); + min_delta, icn->refclk ? "EXT" : "DSI", fin, + (fin * best_m) / (best_p << (best_s + 1))); ref_div = PLL_REF_DIV_P(best_p >> best_p_pot) | PLL_REF_DIV_S(best_s); if (best_p_pot) /* Prefer /2 pre-divider */ ref_div |= PLL_REF_DIV_Pe; - /* Clock source selection fixed to MIPI DSI clock lane */ - chipone_writeb(icn, PLL_CTRL(6), PLL_CTRL_6_MIPI_CLK); + /* Clock source selection either external clock or MIPI DSI clock lane */ + chipone_writeb(icn, PLL_CTRL(6), + icn->refclk ? PLL_CTRL_6_EXTERNAL : PLL_CTRL_6_MIPI_CLK); chipone_writeb(icn, PLL_REF_DIV, ref_div); chipone_writeb(icn, PLL_INT(0), best_m); } @@ -464,6 +471,11 @@ static void chipone_atomic_pre_enable(struct drm_bridge *bridge, "failed to enable VDD3 regulator: %d\n", ret); } + ret = clk_prepare_enable(icn->refclk); + if (ret) + DRM_DEV_ERROR(icn->dev, + "failed to enable RECLK clock: %d\n", ret); + gpiod_set_value(icn->enable_gpio, 1); usleep_range(10000, 11000); @@ -474,6 +486,8 @@ static void chipone_atomic_post_disable(struct drm_bridge *bridge, { struct chipone *icn = bridge_to_chipone(bridge); + clk_disable_unprepare(icn->refclk); + if (icn->vdd1) regulator_disable(icn->vdd1); @@ -515,6 +529,8 @@ static int chipone_dsi_attach(struct chipone *icn) dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET; + dsi->hs_rate = 500000000; + dsi->lp_rate = 16000000; ret = mipi_dsi_attach(dsi); if (ret < 0) @@ -617,6 +633,20 @@ static int chipone_parse_dt(struct chipone *icn) struct device *dev = icn->dev; int ret; + icn->refclk = devm_clk_get_optional(dev, "refclk"); + if (IS_ERR(icn->refclk)) { + ret = PTR_ERR(icn->refclk); + DRM_DEV_ERROR(dev, "failed to get REFCLK clock: %d\n", ret); + return ret; + } else if (icn->refclk) { + icn->refclk_rate = clk_get_rate(icn->refclk); + if (icn->refclk_rate < 10000000 || icn->refclk_rate > 154000000) { + DRM_DEV_ERROR(dev, "REFCLK out of range: %ld Hz\n", + icn->refclk_rate); + return -EINVAL; + } + } + icn->vdd1 = devm_regulator_get_optional(dev, "vdd1"); if (IS_ERR(icn->vdd1)) { ret = PTR_ERR(icn->vdd1); diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c index ba060277c3fd..c5719908ce2d 100644 --- a/drivers/gpu/drm/bridge/chrontel-ch7033.c +++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c @@ -68,6 +68,7 @@ enum { BYTE_SWAP_GBR = 3, BYTE_SWAP_BRG = 4, BYTE_SWAP_BGR = 5, + BYTE_SWAP_MAX = 6, }; /* Page 0, Register 0x19 */ @@ -355,6 +356,8 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge, int hsynclen = mode->hsync_end - mode->hsync_start; int vbporch = mode->vsync_start - mode->vdisplay; int vsynclen = mode->vsync_end - mode->vsync_start; + u8 byte_swap; + int ret; /* * Page 4 @@ -398,8 +401,16 @@ static void ch7033_bridge_mode_set(struct drm_bridge *bridge, regmap_write(priv->regmap, 0x15, vbporch); regmap_write(priv->regmap, 0x16, vsynclen); - /* Input color swap. */ - regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR); + /* Input color swap. Byte order is optional and will default to + * BYTE_SWAP_BGR to preserve backwards compatibility with existing + * driver. + */ + ret = of_property_read_u8(priv->bridge.of_node, "chrontel,byteswap", + &byte_swap); + if (!ret && byte_swap < BYTE_SWAP_MAX) + regmap_update_bits(priv->regmap, 0x18, SWAP, byte_swap); + else + regmap_update_bits(priv->regmap, 0x18, SWAP, BYTE_SWAP_BGR); /* Input clock and sync polarity. */ regmap_update_bits(priv->regmap, 0x19, 0x1, mode->clock >> 16); diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c index f9251ec49bf0..2bb957cffd94 100644 --- a/drivers/gpu/drm/bridge/ite-it6505.c +++ b/drivers/gpu/drm/bridge/ite-it6505.c @@ -2951,9 +2951,6 @@ static void it6505_bridge_atomic_enable(struct drm_bridge *bridge, if (ret) dev_err(dev, "Failed to setup AVI infoframe: %d", ret); - it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, - DP_SET_POWER_D0); - it6505_update_video_parameter(it6505, mode); ret = it6505_send_video_infoframe(it6505, &frame); @@ -2963,6 +2960,9 @@ static void it6505_bridge_atomic_enable(struct drm_bridge *bridge, it6505_int_mask_enable(it6505); it6505_video_reset(it6505); + + it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, + DP_SET_POWER_D0); } static void it6505_bridge_atomic_disable(struct drm_bridge *bridge, @@ -2974,9 +2974,9 @@ static void it6505_bridge_atomic_disable(struct drm_bridge *bridge, DRM_DEV_DEBUG_DRIVER(dev, "start"); if (it6505->powered) { - it6505_video_disable(it6505); it6505_drm_dp_link_set_power(&it6505->aux, &it6505->link, DP_SET_POWER_D3); + it6505_video_disable(it6505); } } diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c index cce98bf2a4e7..72248a565579 100644 --- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c +++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c @@ -296,7 +296,9 @@ static void ge_b850v3_lvds_remove(void) * This check is to avoid both the drivers * removing the bridge in their remove() function */ - if (!ge_b850v3_lvds_ptr) + if (!ge_b850v3_lvds_ptr || + !ge_b850v3_lvds_ptr->stdp2690_i2c || + !ge_b850v3_lvds_ptr->stdp4028_i2c) goto out; drm_bridge_remove(&ge_b850v3_lvds_ptr->bridge); diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c index 49107a6cdac1..d7483c13c569 100644 --- a/drivers/gpu/drm/bridge/parade-ps8640.c +++ b/drivers/gpu/drm/bridge/parade-ps8640.c @@ -375,6 +375,11 @@ static int __maybe_unused ps8640_resume(struct device *dev) gpiod_set_value(ps_bridge->gpio_reset, 1); usleep_range(2000, 2500); gpiod_set_value(ps_bridge->gpio_reset, 0); + /* Double reset for T4 and T5 */ + msleep(50); + gpiod_set_value(ps_bridge->gpio_reset, 1); + msleep(50); + gpiod_set_value(ps_bridge->gpio_reset, 0); /* * Mystery 200 ms delay for the "MCU to be ready". It's unclear if diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c index 25a60eb4d67c..40d8ca37f5bc 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c @@ -3096,6 +3096,7 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) { struct dw_hdmi *hdmi = dev_id; u8 intr_stat, phy_int_pol, phy_pol_mask, phy_stat; + enum drm_connector_status status = connector_status_unknown; intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0); phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0); @@ -3134,13 +3135,15 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id) cec_notifier_phys_addr_invalidate(hdmi->cec_notifier); mutex_unlock(&hdmi->cec_notifier_mutex); } - } - if (intr_stat & HDMI_IH_PHY_STAT0_HPD) { - enum drm_connector_status status = phy_int_pol & HDMI_PHY_HPD - ? connector_status_connected - : connector_status_disconnected; + if (phy_stat & HDMI_PHY_HPD) + status = connector_status_connected; + + if (!(phy_stat & (HDMI_PHY_HPD | HDMI_PHY_RX_SENSE))) + status = connector_status_disconnected; + } + if (status != connector_status_unknown) { dev_dbg(hdmi->dev, "EVENT=%s\n", status == connector_status_connected ? "plugin" : "plugout"); diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c index baaed4d37911..89e060b273ef 100644 --- a/drivers/gpu/drm/bridge/tc358767.c +++ b/drivers/gpu/drm/bridge/tc358767.c @@ -1913,22 +1913,23 @@ static int tc_mipi_dsi_host_attach(struct tc_data *tc) static int tc_probe_dpi_bridge_endpoint(struct tc_data *tc) { struct device *dev = tc->dev; + struct drm_bridge *bridge; struct drm_panel *panel; int ret; /* port@1 is the DPI input/output port */ - ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, NULL); + ret = drm_of_find_panel_or_bridge(dev->of_node, 1, 0, &panel, &bridge); if (ret && ret != -ENODEV) return ret; if (panel) { - struct drm_bridge *panel_bridge; - - panel_bridge = devm_drm_panel_bridge_add(dev, panel); - if (IS_ERR(panel_bridge)) - return PTR_ERR(panel_bridge); + bridge = devm_drm_panel_bridge_add(dev, panel); + if (IS_ERR(bridge)) + return PTR_ERR(bridge); + } - tc->panel_bridge = panel_bridge; + if (bridge) { + tc->panel_bridge = bridge; tc->bridge.type = DRM_MODE_CONNECTOR_DPI; tc->bridge.funcs = &tc_dpi_bridge_funcs; diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index 90bbabde1595..3c3561942eb6 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -29,6 +29,7 @@ #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> #include <drm/drm_bridge_connector.h> +#include <drm/drm_edid.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_of.h> #include <drm/drm_panel.h> @@ -68,6 +69,7 @@ #define BPP_18_RGB BIT(0) #define SN_HPD_DISABLE_REG 0x5C #define HPD_DISABLE BIT(0) +#define HPD_DEBOUNCED_STATE BIT(4) #define SN_GPIO_IO_REG 0x5E #define SN_GPIO_INPUT_SHIFT 4 #define SN_GPIO_OUTPUT_SHIFT 0 @@ -92,6 +94,8 @@ #define SN_DATARATE_CONFIG_REG 0x94 #define DP_DATARATE_MASK GENMASK(7, 5) #define DP_DATARATE(x) ((x) << 5) +#define SN_TRAINING_SETTING_REG 0x95 +#define SCRAMBLE_DISABLE BIT(4) #define SN_ML_TX_MODE_REG 0x96 #define ML_TX_MAIN_LINK_OFF 0 #define ML_TX_NORMAL_MODE BIT(0) @@ -747,6 +751,29 @@ ti_sn_bridge_mode_valid(struct drm_bridge *bridge, if (mode->clock > 594000) return MODE_CLOCK_HIGH; + /* + * The front and back porch registers are 8 bits, and pulse width + * registers are 15 bits, so reject any modes with larger periods. + */ + + if ((mode->hsync_start - mode->hdisplay) > 0xff) + return MODE_HBLANK_WIDE; + + if ((mode->vsync_start - mode->vdisplay) > 0xff) + return MODE_VBLANK_WIDE; + + if ((mode->hsync_end - mode->hsync_start) > 0x7fff) + return MODE_HSYNC_WIDE; + + if ((mode->vsync_end - mode->vsync_start) > 0x7fff) + return MODE_VSYNC_WIDE; + + if ((mode->htotal - mode->hsync_end) > 0xff) + return MODE_HBLANK_WIDE; + + if ((mode->vtotal - mode->vsync_end) > 0xff) + return MODE_VBLANK_WIDE; + return MODE_OK; } @@ -1047,12 +1074,23 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge, /* * The SN65DSI86 only supports ASSR Display Authentication method and - * this method is enabled by default. An eDP panel must support this + * this method is enabled for eDP panels. An eDP panel must support this * authentication method. We need to enable this method in the eDP panel * at DisplayPort address 0x0010A prior to link training. + * + * As only ASSR is supported by SN65DSI86, for full DisplayPort displays + * we need to disable the scrambler. */ - drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET, - DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); + if (pdata->bridge.type == DRM_MODE_CONNECTOR_eDP) { + drm_dp_dpcd_writeb(&pdata->aux, DP_EDP_CONFIGURATION_SET, + DP_ALTERNATE_SCRAMBLER_RESET_ENABLE); + + regmap_update_bits(pdata->regmap, SN_TRAINING_SETTING_REG, + SCRAMBLE_DISABLE, 0); + } else { + regmap_update_bits(pdata->regmap, SN_TRAINING_SETTING_REG, + SCRAMBLE_DISABLE, SCRAMBLE_DISABLE); + } bpp = ti_sn_bridge_get_bpp(connector); /* Set the DP output format (18 bpp or 24 bpp) */ @@ -1122,10 +1160,33 @@ static void ti_sn_bridge_atomic_post_disable(struct drm_bridge *bridge, pm_runtime_put_sync(pdata->dev); } +static enum drm_connector_status ti_sn_bridge_detect(struct drm_bridge *bridge) +{ + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); + int val = 0; + + pm_runtime_get_sync(pdata->dev); + regmap_read(pdata->regmap, SN_HPD_DISABLE_REG, &val); + pm_runtime_put_autosuspend(pdata->dev); + + return val & HPD_DEBOUNCED_STATE ? connector_status_connected + : connector_status_disconnected; +} + +static struct edid *ti_sn_bridge_get_edid(struct drm_bridge *bridge, + struct drm_connector *connector) +{ + struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge); + + return drm_get_edid(connector, &pdata->aux.ddc); +} + static const struct drm_bridge_funcs ti_sn_bridge_funcs = { .attach = ti_sn_bridge_attach, .detach = ti_sn_bridge_detach, .mode_valid = ti_sn_bridge_mode_valid, + .get_edid = ti_sn_bridge_get_edid, + .detect = ti_sn_bridge_detect, .atomic_pre_enable = ti_sn_bridge_atomic_pre_enable, .atomic_enable = ti_sn_bridge_atomic_enable, .atomic_disable = ti_sn_bridge_atomic_disable, @@ -1218,6 +1279,11 @@ static int ti_sn_bridge_probe(struct auxiliary_device *adev, pdata->bridge.funcs = &ti_sn_bridge_funcs; pdata->bridge.of_node = np; + pdata->bridge.type = pdata->next_bridge->type == DRM_MODE_CONNECTOR_DisplayPort + ? DRM_MODE_CONNECTOR_DisplayPort : DRM_MODE_CONNECTOR_eDP; + + if (pdata->bridge.type == DRM_MODE_CONNECTOR_DisplayPort) + pdata->bridge.ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT; drm_bridge_add(&pdata->bridge); |