drm/msm: common display interface for mdp driver
Display_manager.h provides a commong display interface for
MDP driver to query DSI, HDMI and DP display properties.
This is a replacement for the previous dsi-manager component.
Change-Id: Ifdd213b3341ca3c21ca13aca4e56d9c2404030ff
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
Signed-off-by: Narendra Muppalla <narendram@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dsi-staging/display_manager.c b/drivers/gpu/drm/msm/dsi-staging/display_manager.c
new file mode 100644
index 0000000..45d1433
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/display_manager.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/of_device.h>
+#include <linux/err.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <linux/msm-bus.h>
+#include <linux/of_irq.h>
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "msm_gpu.h"
+#include "display_manager.h"
+#include "dsi_display.h"
+
+static u32 dm_get_num_of_displays(struct display_manager *disp_m)
+{
+ u32 count = 0;
+
+ count = dsi_display_get_num_of_displays();
+ disp_m->display_count = count;
+ disp_m->dsi_display_count = count;
+
+ /* TODO: get HDMI and DP display count here */
+ return disp_m->display_count;
+}
+
+static int dm_set_active_displays(struct display_manager *disp_m)
+{
+ /* TODO: Make changes from DT config here */
+ return 0;
+}
+
+static int dm_init_active_displays(struct display_manager *disp_m)
+{
+ int rc = 0;
+ int i = 0;
+ struct dsi_display *dsi_display;
+
+ for (i = 0; i < disp_m->dsi_display_count; i++) {
+ dsi_display = dsi_display_get_display_by_index(i);
+ if (!dsi_display || !dsi_display_is_active(dsi_display))
+ continue;
+
+ rc = dsi_display_dev_init(dsi_display);
+ if (rc) {
+ pr_err("failed to init dsi display, rc=%d\n", rc);
+ goto error_deinit_dsi_displays;
+ }
+ }
+
+ /* TODO: INIT HDMI and DP displays here */
+ return rc;
+error_deinit_dsi_displays:
+ for (i = i - 1; i >= 0; i--) {
+ dsi_display = dsi_display_get_display_by_index(i);
+ if (dsi_display && dsi_display_is_active(dsi_display))
+ (void)dsi_display_dev_deinit(dsi_display);
+ }
+
+ return rc;
+}
+
+static int dm_deinit_active_displays(struct display_manager *disp_m)
+{
+ int rc = 0;
+ int i = 0;
+ struct dsi_display *dsi_display;
+
+ for (i = 0; i < disp_m->dsi_display_count; i++) {
+ dsi_display = dsi_display_get_display_by_index(i);
+ if (!dsi_display || !dsi_display_is_active(dsi_display))
+ continue;
+
+ rc = dsi_display_dev_deinit(dsi_display);
+ if (rc)
+ pr_err("failed to deinit dsi display, rc=%d\n", rc);
+ }
+
+ /* TODO: DEINIT HDMI and DP displays here */
+ return rc;
+}
+
+static int disp_manager_comp_ops_bind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ int rc = 0;
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct msm_drm_private *priv = drm->dev_private;
+ struct display_manager *disp_m;
+ struct dsi_display *dsi_display;
+ int i = 0;
+
+ if (!pdev || !drm) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ disp_m = platform_get_drvdata(pdev);
+
+ /* DSI displays */
+ for (i = 0; i < disp_m->dsi_display_count; i++) {
+ dsi_display = dsi_display_get_display_by_index(i);
+ if (!dsi_display) {
+ pr_err("Display does not exist\n");
+ continue;
+ }
+
+ if (!dsi_display_is_active(dsi_display))
+ continue;
+
+ rc = dsi_display_bind(dsi_display, drm);
+ if (rc) {
+ pr_err("Failed to bind dsi display_%d, rc=%d\n", i, rc);
+ goto error_unbind_dsi;
+ }
+ }
+
+ /* TODO: BIND HDMI display here */
+ /* TODO: BIND DP display here */
+
+ priv->dm = disp_m;
+ return rc;
+error_unbind_dsi:
+ for (i = i - 1; i >= 0; i--) {
+ dsi_display = dsi_display_get_display_by_index(i);
+ if (!dsi_display || !dsi_display_is_active(dsi_display))
+ continue;
+ (void)dsi_display_unbind(dsi_display);
+ }
+ return rc;
+}
+
+static void disp_manager_comp_ops_unbind(struct device *dev,
+ struct device *master,
+ void *data)
+{
+ int rc = 0;
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct platform_device *pdev = to_platform_device(dev);
+ struct display_manager *disp_m;
+ struct dsi_display *dsi_display;
+ int i = 0;
+
+ if (!pdev || !drm) {
+ pr_err("Invalid params\n");
+ return;
+ }
+
+ disp_m = platform_get_drvdata(pdev);
+
+ /* DSI displays */
+ for (i = 0; i < disp_m->dsi_display_count; i++) {
+ dsi_display = dsi_display_get_display_by_index(i);
+ if (!dsi_display || !dsi_display_is_active(dsi_display))
+ continue;
+
+ rc = dsi_display_unbind(dsi_display);
+ if (rc)
+ pr_err("failed to unbind dsi display_%d, rc=%d\n",
+ i, rc);
+ }
+
+ /* TODO: UNBIND HDMI display here */
+ /* TODO: UNBIND DP display here */
+}
+
+static const struct of_device_id displays_dt_match[] = {
+ {.compatible = "qcom,dsi-display"},
+ {.compatible = "qcom,hdmi-display"},
+ {.compatible = "qcom,dp-display"},
+ {}
+};
+
+static const struct component_ops disp_manager_comp_ops = {
+ .bind = disp_manager_comp_ops_bind,
+ .unbind = disp_manager_comp_ops_unbind,
+};
+
+static int disp_manager_dev_probe(struct platform_device *pdev)
+{
+ struct display_manager *disp_m;
+ int rc = 0;
+
+ if (!pdev || !pdev->dev.of_node) {
+ pr_err("pdev not found\n");
+ return -ENODEV;
+ }
+
+ disp_m = devm_kzalloc(&pdev->dev, sizeof(*disp_m), GFP_KERNEL);
+ if (!disp_m)
+ return -ENOMEM;
+
+ disp_m->name = "qcom,display-manager";
+
+ of_platform_populate(pdev->dev.of_node, displays_dt_match,
+ NULL, &pdev->dev);
+
+ disp_m->display_count = dm_get_num_of_displays(disp_m);
+ if (!disp_m->display_count) {
+ rc = -ENODEV;
+ pr_err("No display found, rc=%d\n", rc);
+ goto error_free_disp_m;
+ }
+
+ rc = dm_set_active_displays(disp_m);
+ if (rc) {
+ pr_err("failed to set active displays, rc=%d\n", rc);
+ goto error_remove_displays;
+ }
+
+ rc = dm_init_active_displays(disp_m);
+ if (rc) {
+ pr_err("failed to initialize displays, rc=%d\n", rc);
+ goto error_remove_displays;
+ }
+
+ rc = component_add(&pdev->dev, &disp_manager_comp_ops);
+ if (rc) {
+ pr_err("failed to add component, rc=%d\n", rc);
+ goto error_deinit_displays;
+ }
+
+ mutex_init(&disp_m->lock);
+ platform_set_drvdata(pdev, disp_m);
+
+ return rc;
+error_deinit_displays:
+ (void)dm_deinit_active_displays(disp_m);
+error_remove_displays:
+ of_platform_depopulate(&pdev->dev);
+error_free_disp_m:
+ devm_kfree(&pdev->dev, disp_m);
+ return rc;
+}
+
+static int disp_manager_dev_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id disp_manager_dt_match[] = {
+ {.compatible = "qcom,display-manager"},
+ {}
+};
+
+static struct platform_driver disp_manager_driver = {
+ .probe = disp_manager_dev_probe,
+ .remove = disp_manager_dev_remove,
+ .driver = {
+ .name = "msm-display-manager",
+ .of_match_table = disp_manager_dt_match,
+ },
+};
+
+
+int display_manager_get_count(struct display_manager *disp_m)
+{
+ int count;
+
+ if (!disp_m) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&disp_m->lock);
+
+ count = 1; /* TODO: keep track of active displays */
+
+ mutex_unlock(&disp_m->lock);
+ return count;
+}
+
+int display_manager_get_info_by_index(struct display_manager *disp_m,
+ u32 display_index,
+ struct display_info *info)
+{
+ int rc = 0;
+ int i = 0, j = 0;
+ struct dsi_display *display;
+ struct dsi_display_info dsi_info;
+
+ if (!disp_m || !info) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&disp_m->lock);
+
+ for (i = 0; i < disp_m->dsi_display_count; i++) {
+ display = dsi_display_get_display_by_index(i);
+ if (!display || !dsi_display_is_active(display))
+ continue;
+
+ memset(&dsi_info, 0x0, sizeof(dsi_info));
+ rc = dsi_display_get_info(display, &dsi_info);
+ if (rc) {
+ pr_err("failed to get display info, rc=%d\n", rc);
+ goto error;
+ }
+
+ info->intf = DISPLAY_INTF_DSI;
+ info->num_of_h_tiles = dsi_info.num_of_h_tiles;
+
+ for (j = 0; j < info->num_of_h_tiles; j++)
+ info->h_tile_instance[j] = dsi_info.h_tile_ids[j];
+
+ info->is_hot_pluggable = dsi_info.is_hot_pluggable;
+ info->is_connected = dsi_info.is_connected;
+ info->is_edid_supported = dsi_info.is_edid_supported;
+ info->max_width = 1920; /* TODO: */
+ info->max_height = 1080; /* TODO: */
+ info->compression = DISPLAY_COMPRESSION_NONE;
+ break;
+ }
+
+error:
+ mutex_unlock(&disp_m->lock);
+ return rc;
+}
+
+int display_manager_drm_init_by_index(struct display_manager *disp_m,
+ u32 display_index,
+ struct drm_encoder *encoder)
+{
+ int rc = 0;
+ int i = 0;
+ struct dsi_display *display;
+
+ if (!disp_m || !encoder) {
+ pr_err("Invalid params\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&disp_m->lock);
+
+ for (i = 0; i < disp_m->dsi_display_count; i++) {
+ display = dsi_display_get_display_by_index(i);
+ if (!display || !dsi_display_is_active(display))
+ continue;
+
+ dsi_display_drm_init(display, encoder);
+ break;
+ }
+
+ mutex_unlock(&disp_m->lock);
+
+ return rc;
+
+}
+
+int display_manager_drm_deinit_by_index(struct display_manager *disp_m,
+ u32 display_index)
+{
+ return 0;
+}
+
+
+void display_manager_register(void)
+{
+ dsi_phy_drv_register();
+ dsi_ctrl_drv_register();
+ dsi_display_register();
+
+ platform_driver_register(&disp_manager_driver);
+}
+void display_manager_unregister(void)
+{
+ platform_driver_unregister(&disp_manager_driver);
+ dsi_display_unregister();
+ dsi_ctrl_drv_register();
+ dsi_phy_drv_unregister();
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/display_manager.h b/drivers/gpu/drm/msm/dsi-staging/display_manager.h
new file mode 100644
index 0000000..0b7462b
--- /dev/null
+++ b/drivers/gpu/drm/msm/dsi-staging/display_manager.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _DISPLAY_MANAGER_H_
+#define _DISPLAY_MANAGER_H_
+
+#define MAX_H_TILES_PER_DISPLAY 2
+
+/**
+ * enum display_interface_type - enumerates display interface types
+ * @DISPLAY_INTF_DSI: DSI interface
+ * @DISPLAY_INTF_HDMI: HDMI interface
+ * @DISPLAY_INTF_DP: Display Port interface
+ */
+enum display_interface_type {
+ DISPLAY_INTF_DSI = 0,
+ DISPLAY_INTF_HDMI,
+ DISPLAY_INTF_DP,
+ DISPLAY_INTF_MAX,
+};
+
+/**
+ * enum display_compression_type - compression method used for pixel stream
+ * @DISPLAY_COMPRESISON_NONE: Pixel data is not compressed.
+ * @DISPLAY_COMPRESSION_DSC: DSC compresison is used.
+ * @DISPLAY_COMPRESSION_FBC: FBC compression is used.
+ */
+enum display_compression_type {
+ DISPLAY_COMPRESSION_NONE = 0,
+ DISPLAY_COMPRESSION_DSC,
+ DISPLAY_COMPRESSION_FBC,
+ DISPLAY_COMPRESISON_MAX
+};
+
+
+/**
+ * struct display_info - defines display properties
+ * @intf: The interface on which display is connected to SOC.
+ * @num_of_h_tiles: number of horizontal tiles in case of split interface.
+ * @h_tile_instance: controller instance used per tile. Number of elements is
+ * based on num_of_h_tiles.
+ * @is_hot_pluggable: Set to true if hot plug detection is supported.
+ * @is_connected: Set to true if display is connected.
+ * @is_edid_supported: True if display supports EDID.
+ * @max_width: Max width of display. In case of hot pluggable display,
+ * this is max width supported by controller.
+ * @max_height: Max height of display. In case of hot pluggable display,
+ * this is max height supported by controller.
+ * @compression: Compression supported by the display.
+ */
+struct display_info {
+ enum display_interface_type intf;
+
+ u32 num_of_h_tiles;
+ u32 h_tile_instance[MAX_H_TILES_PER_DISPLAY];
+
+ bool is_hot_pluggable;
+ bool is_connected;
+ bool is_edid_supported;
+
+ u32 max_width;
+ u32 max_height;
+
+ enum display_compression_type compression;
+};
+
+struct display_manager {
+ struct platform_device *pdev;
+ const char *name;
+
+ struct mutex lock;
+ u32 display_count;
+ u32 dsi_display_count;
+ u32 hdmi_display_count;
+ u32 dp_display_count;
+ /* Debug fs */
+ struct dentry *debugfs_root;
+};
+
+/**
+ * display_manager_get_count() - returns the number of display present
+ * @disp_m: Handle to Display manager.
+ *
+ * Returns the sum total of DSI, HDMI and DP display present on the board.
+ *
+ * Return: error code (< 0) in case of error or number of display ( >= 0)
+ */
+int display_manager_get_count(struct display_manager *disp_m);
+
+/**
+ * display_manager_get_info_by_index() - returns display information
+ * @disp_m: Handle to Display manager.
+ * @display_index: display index (valid indices are 0 to (display_count - 1).
+ * @info: Structure where display info is copied.
+ *
+ * Return: error code.
+ */
+int display_manager_get_info_by_index(struct display_manager *disp_m,
+ u32 display_index,
+ struct display_info *info);
+
+/**
+ * display_manager_drm_init_by_index() - initialize drm objects for display
+ * @disp_m: Handle to Display manager.
+ * @display_index: display index (valid indices are 0 to (display_count - 1).
+ * @encoder: Pointer to encoder object to which display is attached.
+ *
+ * Return: error code.
+ */
+int display_manager_drm_init_by_index(struct display_manager *disp_m,
+ u32 display_index,
+ struct drm_encoder *encoder);
+
+/**
+ * display_manager_drm_deinit_by_index() - detroys drm objects
+ * @disp_m: Handle to Display manager.
+ * @display_index: display index (valid indices are 0 to (display_count - 1).
+ *
+ * Return: error code.
+ */
+int display_manager_drm_deinit_by_index(struct display_manager *disp_m,
+ u32 display_index);
+
+/**
+ * display_manager_register() - register display interface drivers
+ */
+void display_manager_register(void);
+
+/**
+ * display_manager_unregister() - unregisters display interface drivers
+ */
+void display_manager_unregister(void);
+
+#endif /* _DISPLAY_MANAGER_H_ */
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
index 1fac1b9..04a3a79 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c
@@ -2335,7 +2335,7 @@
/**
* dsi_ctrl_drv_register() - register platform driver for dsi controller
*/
-void __init dsi_ctrl_drv_register(void)
+void dsi_ctrl_drv_register(void)
{
platform_driver_register(&dsi_ctrl_driver);
}
@@ -2343,7 +2343,7 @@
/**
* dsi_ctrl_drv_unregister() - unregister platform driver
*/
-void __exit dsi_ctrl_drv_unregister(void)
+void dsi_ctrl_drv_unregister(void)
{
platform_driver_unregister(&dsi_ctrl_driver);
}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
index 87a28dc..47fa708 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c
@@ -29,6 +29,11 @@
static DEFINE_MUTEX(dsi_display_list_lock);
static LIST_HEAD(dsi_display_list);
+static const struct of_device_id dsi_display_dt_match[] = {
+ {.compatible = "qcom,dsi-display"},
+ {}
+};
+
static struct dsi_display *main_display;
static ssize_t debugfs_dump_info_read(struct file *file,
@@ -1259,6 +1264,15 @@
return rc;
}
+static struct platform_driver dsi_display_driver = {
+ .probe = dsi_display_dev_probe,
+ .remove = dsi_display_dev_remove,
+ .driver = {
+ .name = "msm-dsi-display",
+ .of_match_table = dsi_display_dt_match,
+ },
+};
+
int dsi_display_dev_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -2129,3 +2143,13 @@
mutex_unlock(&display->display_lock);
return rc;
}
+
+void dsi_display_register(void)
+{
+ platform_driver_register(&dsi_display_driver);
+}
+
+void dsi_display_unregister(void)
+{
+ platform_driver_unregister(&dsi_display_driver);
+}
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
index 976baf6b..a8c0ebf 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.h
@@ -189,6 +189,16 @@
int dsi_display_dev_remove(struct platform_device *pdev);
/**
+ * dsi_display_register() - register dsi display platform driver
+ */
+void dsi_display_register(void);
+
+/**
+ * dsi_display_unregister() - unregister dsi display platform driver
+ */
+void dsi_display_unregister(void);
+
+/**
* dsi_display_get_num_of_displays() - returns number of display devices
* supported.
*
diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
index d53ef1140..1ccbbe7 100644
--- a/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
+++ b/drivers/gpu/drm/msm/dsi-staging/dsi_phy.c
@@ -510,7 +510,7 @@
.probe = dsi_phy_driver_probe,
.remove = dsi_phy_driver_remove,
.driver = {
- .name = "msm_dsi_phy",
+ .name = "dsi_phy",
.of_match_table = msm_dsi_phy_of_match,
},
};
@@ -848,12 +848,12 @@
return rc;
}
-void __init dsi_phy_drv_register(void)
+void dsi_phy_drv_register(void)
{
platform_driver_register(&dsi_phy_platform_driver);
}
-void __exit dsi_phy_drv_unregister(void)
+void dsi_phy_drv_unregister(void)
{
platform_driver_unregister(&dsi_phy_platform_driver);
}
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index f6e2e23..e4e37a3 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -20,6 +20,7 @@
#include "msm_fence.h"
#include "msm_gpu.h"
#include "msm_kms.h"
+#include "display_manager.h"
/*
@@ -1090,6 +1091,7 @@
{
DBG("init");
msm_mdp_register();
+ display_manager_register();
msm_dsi_register();
msm_edp_register();
msm_hdmi_register();
@@ -1105,7 +1107,7 @@
adreno_unregister();
msm_edp_unregister();
msm_dsi_unregister();
- msm_mdp_unregister();
+ display_manager_unregister();
}
module_init(msm_drm_register);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index 8a3f522..7c1d630 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -100,6 +100,8 @@
spinlock_t lock;
};
+struct display_manager;
+
struct msm_drm_private {
struct drm_device *dev;
@@ -126,6 +128,9 @@
/* DSI is shared by mdp4 and mdp5 */
struct msm_dsi *dsi[2];
+ /* Display manager for SDE driver */
+ struct display_manager *dm;
+
/* when we have more than one 'msm_gpu' these need to be an array: */
struct msm_gpu *gpu;
struct msm_file_private *lastctx;