Merge branch 'msm-next-lumag' into HEAD
[linux-2.6-microblaze.git] / drivers / gpu / drm / msm / dp / dp_display.c
index 7ff60e5..bde1a7c 100644 (file)
@@ -122,61 +122,64 @@ struct dp_display_private {
 
 struct msm_dp_desc {
        phys_addr_t io_start;
+       unsigned int id;
        unsigned int connector_type;
        bool wide_bus_en;
 };
 
-struct msm_dp_config {
-       const struct msm_dp_desc *descs;
-       size_t num_descs;
-};
-
 static const struct msm_dp_desc sc7180_dp_descs[] = {
-       [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
-};
-
-static const struct msm_dp_config sc7180_dp_cfg = {
-       .descs = sc7180_dp_descs,
-       .num_descs = ARRAY_SIZE(sc7180_dp_descs),
+       { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+       {}
 };
 
 static const struct msm_dp_desc sc7280_dp_descs[] = {
-       [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort, .wide_bus_en = true },
-       [MSM_DP_CONTROLLER_1] = { .io_start = 0x0aea0000, .connector_type = DRM_MODE_CONNECTOR_eDP, .wide_bus_en = true },
-};
-
-static const struct msm_dp_config sc7280_dp_cfg = {
-       .descs = sc7280_dp_descs,
-       .num_descs = ARRAY_SIZE(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 },
+       {}
 };
 
 static const struct msm_dp_desc sc8180x_dp_descs[] = {
-       [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
-       [MSM_DP_CONTROLLER_1] = { .io_start = 0x0ae98000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
-       [MSM_DP_CONTROLLER_2] = { .io_start = 0x0ae9a000, .connector_type = DRM_MODE_CONNECTOR_eDP },
+       { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+       { .io_start = 0x0ae98000, .id = MSM_DP_CONTROLLER_1, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+       { .io_start = 0x0ae9a000, .id = MSM_DP_CONTROLLER_2, .connector_type = DRM_MODE_CONNECTOR_eDP },
+       {}
 };
 
-static const struct msm_dp_config sc8180x_dp_cfg = {
-       .descs = sc8180x_dp_descs,
-       .num_descs = ARRAY_SIZE(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 },
+       {}
 };
 
-static const struct msm_dp_desc sm8350_dp_descs[] = {
-       [MSM_DP_CONTROLLER_0] = { .io_start = 0x0ae90000, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+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 },
+       {}
 };
 
-static const struct msm_dp_config sm8350_dp_cfg = {
-       .descs = sm8350_dp_descs,
-       .num_descs = ARRAY_SIZE(sm8350_dp_descs),
+static const struct msm_dp_desc sm8350_dp_descs[] = {
+       { .io_start = 0x0ae90000, .id = MSM_DP_CONTROLLER_0, .connector_type = DRM_MODE_CONNECTOR_DisplayPort },
+       {}
 };
 
 static const struct of_device_id dp_dt_match[] = {
-       { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_cfg },
-       { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_cfg },
-       { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_cfg },
-       { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_cfg },
-       { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_cfg },
-       { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_cfg },
+       { .compatible = "qcom,sc7180-dp", .data = &sc7180_dp_descs },
+       { .compatible = "qcom,sc7280-dp", .data = &sc7280_dp_descs },
+       { .compatible = "qcom,sc7280-edp", .data = &sc7280_dp_descs },
+       { .compatible = "qcom,sc8180x-dp", .data = &sc8180x_dp_descs },
+       { .compatible = "qcom,sc8180x-edp", .data = &sc8180x_dp_descs },
+       { .compatible = "qcom,sc8280xp-dp", .data = &sc8280xp_dp_descs },
+       { .compatible = "qcom,sc8280xp-edp", .data = &sc8280xp_edp_descs },
+       { .compatible = "qcom,sdm845-dp", .data = &sc7180_dp_descs },
+       { .compatible = "qcom,sm8350-dp", .data = &sm8350_dp_descs },
        {}
 };
 
@@ -390,6 +393,10 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
        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)
@@ -607,8 +614,10 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
        }
 
        /* enable HDP irq_hpd/replug interrupt */
-       dp_catalog_hpd_config_intr(dp->catalog,
-               DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, true);
+       if (dp->dp_display.internal_hpd)
+               dp_catalog_hpd_config_intr(dp->catalog,
+                                          DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK,
+                                          true);
 
        drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
                        dp->dp_display.connector_type, state);
@@ -648,8 +657,10 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
                        dp->dp_display.connector_type, state);
 
        /* disable irq_hpd/replug interrupts */
-       dp_catalog_hpd_config_intr(dp->catalog,
-               DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK, false);
+       if (dp->dp_display.internal_hpd)
+               dp_catalog_hpd_config_intr(dp->catalog,
+                                          DP_DP_IRQ_HPD_INT_MASK | DP_DP_HPD_REPLUG_INT_MASK,
+                                          false);
 
        /* unplugged, no more irq_hpd handle */
        dp_del_event(dp, EV_IRQ_HPD_INT);
@@ -675,7 +686,8 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
        }
 
        /* disable HPD plug interrupts */
-       dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
+       if (dp->dp_display.internal_hpd)
+               dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, false);
 
        /*
         * We don't need separate work for disconnect as
@@ -693,7 +705,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
        dp_display_handle_plugged_change(&dp->dp_display, false);
 
        /* enable HDP plug interrupt to prepare for next plugin */
-       if (!dp->dp_display.is_edp)
+       if (dp->dp_display.internal_hpd)
                dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK, true);
 
        drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
@@ -1078,8 +1090,8 @@ static void dp_display_config_hpd(struct dp_display_private *dp)
        dp_display_host_init(dp);
        dp_catalog_ctrl_hpd_config(dp->catalog);
 
-       /* Enable plug and unplug interrupts only for external DisplayPort */
-       if (!dp->dp_display.is_edp)
+       /* Enable plug and unplug interrupts only if requested */
+       if (dp->dp_display.internal_hpd)
                dp_catalog_hpd_config_intr(dp->catalog,
                                DP_DP_HPD_PLUG_INT_MASK |
                                DP_DP_HPD_UNPLUG_INT_MASK,
@@ -1262,10 +1274,9 @@ int dp_display_request_irq(struct msm_dp *dp_display)
        return 0;
 }
 
-static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev,
-                                                    unsigned int *id)
+static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pdev)
 {
-       const struct msm_dp_config *cfg = of_device_get_match_data(&pdev->dev);
+       const struct msm_dp_desc *descs = of_device_get_match_data(&pdev->dev);
        struct resource *res;
        int i;
 
@@ -1273,11 +1284,9 @@ static const struct msm_dp_desc *dp_display_get_desc(struct platform_device *pde
        if (!res)
                return NULL;
 
-       for (i = 0; i < cfg->num_descs; i++) {
-               if (cfg->descs[i].io_start == res->start) {
-                       *id = i;
-                       return &cfg->descs[i];
-               }
+       for (i = 0; i < descs[i].io_start; i++) {
+               if (descs[i].io_start == res->start)
+                       return &descs[i];
        }
 
        dev_err(&pdev->dev, "unknown displayport instance\n");
@@ -1299,12 +1308,13 @@ static int dp_display_probe(struct platform_device *pdev)
        if (!dp)
                return -ENOMEM;
 
-       desc = dp_display_get_desc(pdev, &dp->id);
+       desc = dp_display_get_desc(pdev);
        if (!desc)
                return -EINVAL;
 
        dp->pdev = 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->dp_display.is_edp =
@@ -1373,8 +1383,7 @@ static int dp_pm_resume(struct device *dev)
 
        dp_catalog_ctrl_hpd_config(dp->catalog);
 
-
-       if (!dp->dp_display.is_edp)
+       if (dp->dp_display.internal_hpd)
                dp_catalog_hpd_config_intr(dp->catalog,
                                DP_DP_HPD_PLUG_INT_MASK |
                                DP_DP_HPD_UNPLUG_INT_MASK,
@@ -1497,7 +1506,7 @@ void msm_dp_irq_postinstall(struct msm_dp *dp_display)
        dp = container_of(dp_display, struct dp_display_private, dp_display);
 
        if (!dp_display->is_edp)
-               dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 100);
+               dp_add_event(dp, EV_HPD_INIT_SETUP, 0, 0);
 }
 
 bool msm_dp_wide_bus_available(const struct msm_dp *dp_display)
@@ -1771,3 +1780,41 @@ 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);
 }
+
+void dp_bridge_hpd_enable(struct drm_bridge *bridge)
+{
+       struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
+       struct msm_dp *dp_display = dp_bridge->dp_display;
+
+       dp_display->internal_hpd = true;
+}
+
+void dp_bridge_hpd_disable(struct drm_bridge *bridge)
+{
+       struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
+       struct msm_dp *dp_display = dp_bridge->dp_display;
+
+       dp_display->internal_hpd = false;
+}
+
+void dp_bridge_hpd_notify(struct drm_bridge *bridge,
+                         enum drm_connector_status status)
+{
+       struct msm_dp_bridge *dp_bridge = to_dp_bridge(bridge);
+       struct msm_dp *dp_display = dp_bridge->dp_display;
+       struct dp_display_private *dp = container_of(dp_display, struct dp_display_private, dp_display);
+
+       /* Without next_bridge interrupts are handled by the DP core directly */
+       if (dp_display->internal_hpd)
+               return;
+
+       if (!dp->core_initialized) {
+               drm_dbg_dp(dp->drm_dev, "not initialized\n");
+               return;
+       }
+
+       if (!dp_display->is_connected && status == connector_status_connected)
+               dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
+       else if (dp_display->is_connected && status == connector_status_disconnected)
+               dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+}