summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/msm/dp/dp_display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/msm/dp/dp_display.c')
-rw-r--r--drivers/gpu/drm/msm/dp/dp_display.c193
1 files changed, 89 insertions, 104 deletions
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index 084086033..ffbfde922 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -9,19 +9,19 @@
#include <linux/debugfs.h>
#include <linux/component.h>
#include <linux/of_irq.h>
+#include <linux/phy/phy.h>
#include <linux/delay.h>
#include <drm/display/drm_dp_aux_bus.h>
+#include <drm/drm_edid.h>
#include "msm_drv.h"
#include "msm_kms.h"
-#include "dp_parser.h"
-#include "dp_power.h"
+#include "dp_ctrl.h"
#include "dp_catalog.h"
#include "dp_aux.h"
#include "dp_reg.h"
#include "dp_link.h"
#include "dp_panel.h"
-#include "dp_ctrl.h"
#include "dp_display.h"
#include "dp_drm.h"
#include "dp_audio.h"
@@ -88,8 +88,6 @@ struct dp_display_private {
struct drm_device *drm_dev;
struct dentry *root;
- struct dp_parser *parser;
- struct dp_power *power;
struct dp_catalog *catalog;
struct drm_dp_aux *aux;
struct dp_link *link;
@@ -113,7 +111,7 @@ struct dp_display_private {
struct dp_event event_list[DP_EVENT_Q_MAX];
spinlock_t event_lock;
- bool wide_bus_en;
+ bool wide_bus_supported;
struct dp_audio *audio;
};
@@ -122,7 +120,7 @@ struct msm_dp_desc {
phys_addr_t io_start;
unsigned int id;
unsigned int connector_type;
- bool wide_bus_en;
+ bool wide_bus_supported;
};
static const struct msm_dp_desc sc7180_dp_descs[] = {
@@ -131,8 +129,8 @@ static const struct msm_dp_desc sc7180_dp_descs[] = {
};
static const struct msm_dp_desc sc7280_dp_descs[] = {
- { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
{}
};
@@ -144,22 +142,22 @@ static const struct msm_dp_desc sc8180x_dp_descs[] = {
};
static const struct msm_dp_desc sc8280xp_dp_descs[] = {
- { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x22090000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
- { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
+ { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x22090000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x22098000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
+ { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_supported = true },
{}
};
static const struct msm_dp_desc sc8280xp_edp_descs[] = {
- { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
- { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
- { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
- { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
+ { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+ { .io_start = 0x0aea0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+ { .io_start = 0x2209a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
+ { .io_start = 0x220a0000, .id = MSM_DP_CONTROLLER_3, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_supported = true },
{}
};
@@ -374,12 +372,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
int rc = 0;
struct edid *edid;
- dp->panel->max_dp_lanes = dp->parser->max_dp_lanes;
- dp->panel->max_dp_link_rate = dp->parser->max_dp_link_rate;
-
- drm_dbg_dp(dp->drm_dev, "max_lanes=%d max_link_rate=%d\n",
- dp->panel->max_dp_lanes, dp->panel->max_dp_link_rate);
-
rc = dp_panel_read_sink_caps(dp->panel, dp->dp_display.connector);
if (rc)
goto end;
@@ -399,8 +391,6 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
dp->audio_supported = drm_detect_monitor_audio(edid);
dp_panel_handle_sink_request(dp->panel);
- dp->dp_display.max_dp_lanes = dp->parser->max_dp_lanes;
-
/*
* set sink to normal operation mode -- D0
* before dpcd read
@@ -450,7 +440,7 @@ static void dp_display_host_init(struct dp_display_private *dp)
dp->dp_display.connector_type, dp->core_initialized,
dp->phy_initialized);
- dp_power_init(dp->power);
+ dp_ctrl_core_clk_enable(dp->ctrl);
dp_ctrl_reset_irq_ctrl(dp->ctrl, true);
dp_aux_init(dp->aux);
dp->core_initialized = true;
@@ -464,7 +454,7 @@ static void dp_display_host_deinit(struct dp_display_private *dp)
dp_ctrl_reset_irq_ctrl(dp->ctrl, false);
dp_aux_deinit(dp->aux);
- dp_power_deinit(dp->power);
+ dp_ctrl_core_clk_disable(dp->ctrl);
dp->core_initialized = false;
}
@@ -494,7 +484,7 @@ static void dp_display_handle_video_request(struct dp_display_private *dp)
}
}
-static int dp_display_handle_port_ststus_changed(struct dp_display_private *dp)
+static int dp_display_handle_port_status_changed(struct dp_display_private *dp)
{
int rc = 0;
@@ -551,7 +541,7 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
drm_dbg_dp(dp->drm_dev, "hpd_state=%d sink_request=%d\n",
dp->hpd_state, sink_request);
if (sink_request & DS_PORT_STATUS_CHANGED)
- rc = dp_display_handle_port_ststus_changed(dp);
+ rc = dp_display_handle_port_status_changed(dp);
else
rc = dp_display_handle_irq_hpd(dp);
}
@@ -565,8 +555,6 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
int ret;
struct platform_device *pdev = dp->dp_display.pdev;
- dp_aux_enable_xfers(dp->aux, true);
-
mutex_lock(&dp->event_mutex);
state = dp->hpd_state;
@@ -632,8 +620,6 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
u32 state;
struct platform_device *pdev = dp->dp_display.pdev;
- dp_aux_enable_xfers(dp->aux, false);
-
mutex_lock(&dp->event_mutex);
state = dp->hpd_state;
@@ -736,16 +722,13 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
struct dp_panel_in panel_in = {
.dev = dev,
};
+ struct phy *phy;
- dp->parser = dp_parser_get(dp->dp_display.pdev);
- if (IS_ERR(dp->parser)) {
- rc = PTR_ERR(dp->parser);
- DRM_ERROR("failed to initialize parser, rc = %d\n", rc);
- dp->parser = NULL;
- goto error;
- }
+ phy = devm_phy_get(dev, "dp");
+ if (IS_ERR(phy))
+ return PTR_ERR(phy);
- dp->catalog = dp_catalog_get(dev, &dp->parser->io);
+ dp->catalog = dp_catalog_get(dev);
if (IS_ERR(dp->catalog)) {
rc = PTR_ERR(dp->catalog);
DRM_ERROR("failed to initialize catalog, rc = %d\n", rc);
@@ -753,15 +736,9 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error;
}
- dp->power = dp_power_get(dev, dp->parser);
- if (IS_ERR(dp->power)) {
- rc = PTR_ERR(dp->power);
- DRM_ERROR("failed to initialize power, rc = %d\n", rc);
- dp->power = NULL;
- goto error;
- }
-
- dp->aux = dp_aux_get(dev, dp->catalog, dp->dp_display.is_edp);
+ dp->aux = dp_aux_get(dev, dp->catalog,
+ phy,
+ dp->dp_display.is_edp);
if (IS_ERR(dp->aux)) {
rc = PTR_ERR(dp->aux);
DRM_ERROR("failed to initialize aux, rc = %d\n", rc);
@@ -790,7 +767,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
}
dp->ctrl = dp_ctrl_get(dev, dp->link, dp->panel, dp->aux,
- dp->power, dp->catalog, dp->parser);
+ dp->catalog,
+ phy);
if (IS_ERR(dp->ctrl)) {
rc = PTR_ERR(dp->ctrl);
DRM_ERROR("failed to initialize ctrl, rc = %d\n", rc);
@@ -806,10 +784,6 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error_ctrl;
}
- /* populate wide_bus_en to differernt layers */
- dp->ctrl->wide_bus_en = dp->wide_bus_en;
- dp->catalog->wide_bus_en = dp->wide_bus_en;
-
return rc;
error_ctrl:
@@ -830,6 +804,7 @@ static int dp_display_set_mode(struct msm_dp *dp_display,
drm_mode_copy(&dp->panel->dp_mode.drm_mode, &mode->drm_mode);
dp->panel->dp_mode.bpp = mode->bpp;
dp->panel->dp_mode.capabilities = mode->capabilities;
+ dp->panel->dp_mode.out_fmt_is_yuv_420 = mode->out_fmt_is_yuv_420;
dp_panel_init_panel_info(dp->panel);
return 0;
}
@@ -958,6 +933,10 @@ enum drm_mode_status dp_bridge_mode_valid(struct drm_bridge *bridge,
dp_display = container_of(dp, struct dp_display_private, dp_display);
link_info = &dp_display->panel->link_info;
+ if (drm_mode_is_420_only(&dp->connector->display_info, mode) &&
+ dp_display->panel->vsc_sdp_supported)
+ mode_pclk_khz /= 2;
+
mode_bpp = dp->connector->display_info.bpc * num_components;
if (!mode_bpp)
mode_bpp = default_bpp;
@@ -1232,16 +1211,25 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde
return NULL;
}
-static int dp_display_get_next_bridge(struct msm_dp *dp);
-
static int dp_display_probe_tail(struct device *dev)
{
struct msm_dp *dp = dev_get_drvdata(dev);
int ret;
- ret = dp_display_get_next_bridge(dp);
- if (ret)
- return ret;
+ /*
+ * External bridges are mandatory for eDP interfaces: one has to
+ * provide at least an eDP panel (which gets wrapped into panel-bridge).
+ *
+ * For DisplayPort interfaces external bridges are optional, so
+ * silently ignore an error if one is not present (-ENODEV).
+ */
+ dp->next_bridge = devm_drm_of_get_bridge(&dp->pdev->dev, dp->pdev->dev.of_node, 1, 0);
+ if (IS_ERR(dp->next_bridge)) {
+ ret = PTR_ERR(dp->next_bridge);
+ dp->next_bridge = NULL;
+ if (dp->is_edp || ret != -ENODEV)
+ return ret;
+ }
ret = component_add(dev, &dp_display_comp_ops);
if (ret)
@@ -1278,7 +1266,7 @@ static int dp_display_probe(struct platform_device *pdev)
dp->name = "drm_dp";
dp->id = desc->id;
dp->dp_display.connector_type = desc->connector_type;
- dp->wide_bus_en = desc->wide_bus_en;
+ dp->wide_bus_supported = desc->wide_bus_supported;
dp->dp_display.is_edp =
(dp->dp_display.connector_type == DRM_MODE_CONNECTOR_eDP);
@@ -1288,18 +1276,6 @@ static int dp_display_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
- rc = dp->parser->parse(dp->parser);
- if (rc) {
- DRM_ERROR("device tree parsing failed\n");
- goto err;
- }
-
- rc = dp_power_client_init(dp->power);
- if (rc) {
- DRM_ERROR("Power client create failed\n");
- goto err;
- }
-
/* setup event q */
mutex_init(&dp->event_mutex);
init_waitqueue_head(&dp->event_q);
@@ -1418,13 +1394,34 @@ void __exit msm_dp_unregister(void)
platform_driver_unregister(&dp_display_driver);
}
+bool msm_dp_is_yuv_420_enabled(const struct msm_dp *dp_display,
+ const struct drm_display_mode *mode)
+{
+ struct dp_display_private *dp;
+ const struct drm_display_info *info;
+
+ dp = container_of(dp_display, struct dp_display_private, dp_display);
+ info = &dp_display->connector->display_info;
+
+ return dp->panel->vsc_sdp_supported && drm_mode_is_420_only(info, mode);
+}
+
+bool msm_dp_needs_periph_flush(const struct msm_dp *dp_display,
+ const struct drm_display_mode *mode)
+{
+ return msm_dp_is_yuv_420_enabled(dp_display, mode);
+}
+
bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
{
struct dp_display_private *dp;
dp = container_of(dp_display, struct dp_display_private, dp_display);
- return dp->wide_bus_en;
+ if (dp->dp_mode.out_fmt_is_yuv_420)
+ return false;
+
+ return dp->wide_bus_supported;
}
void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, bool is_edp)
@@ -1446,32 +1443,8 @@ void dp_display_debugfs_init(struct msm_dp *dp_display, struct dentry *root, boo
}
}
-static int dp_display_get_next_bridge(struct msm_dp *dp)
-{
- int rc;
- struct dp_display_private *dp_priv;
-
- dp_priv = container_of(dp, struct dp_display_private, dp_display);
-
- /*
- * External bridges are mandatory for eDP interfaces: one has to
- * provide at least an eDP panel (which gets wrapped into panel-bridge).
- *
- * For DisplayPort interfaces external bridges are optional, so
- * silently ignore an error if one is not present (-ENODEV).
- */
- rc = devm_dp_parser_find_next_bridge(&dp->pdev->dev, dp_priv->parser);
- if (!dp->is_edp && rc == -ENODEV)
- return 0;
-
- if (!rc)
- dp->next_bridge = dp_priv->parser->next_bridge;
-
- return rc;
-}
-
int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
- struct drm_encoder *encoder)
+ struct drm_encoder *encoder, bool yuv_supported)
{
struct dp_display_private *dp_priv;
int ret;
@@ -1487,7 +1460,7 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
return ret;
}
- dp_display->connector = dp_drm_connector_init(dp_display, encoder);
+ dp_display->connector = dp_drm_connector_init(dp_display, encoder, yuv_supported);
if (IS_ERR(dp_display->connector)) {
ret = PTR_ERR(dp_display->connector);
DRM_DEV_ERROR(dev->dev,
@@ -1617,8 +1590,10 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
struct msm_dp_bridge *dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = dp_bridge->dp_display;
struct dp_display_private *dp_display;
+ struct dp_panel *dp_panel;
dp_display = container_of(dp, struct dp_display_private, dp_display);
+ dp_panel = dp_display->panel;
memset(&dp_display->dp_mode, 0x0, sizeof(struct dp_display_mode));
@@ -1637,6 +1612,16 @@ void dp_bridge_mode_set(struct drm_bridge *drm_bridge,
dp_display->dp_mode.h_active_low =
!!(dp_display->dp_mode.drm_mode.flags & DRM_MODE_FLAG_NHSYNC);
+
+ dp_display->dp_mode.out_fmt_is_yuv_420 =
+ drm_mode_is_420_only(&dp->connector->display_info, adjusted_mode) &&
+ dp_panel->vsc_sdp_supported;
+
+ /* populate wide_bus_support to different layers */
+ dp_display->ctrl->wide_bus_en =
+ dp_display->dp_mode.out_fmt_is_yuv_420 ? false : dp_display->wide_bus_supported;
+ dp_display->catalog->wide_bus_en =
+ dp_display->dp_mode.out_fmt_is_yuv_420 ? false : dp_display->wide_bus_supported;
}
void dp_bridge_hpd_enable(struct drm_bridge *bridge)