diff options
| author | Ajay Singh Parmar <aparmar@codeaurora.org> | 2016-06-10 16:44:56 -0700 |
|---|---|---|
| committer | Dhaval Patel <pdhaval@codeaurora.org> | 2016-08-01 11:58:14 -0700 |
| commit | 1de12c6e3dde44a9f96f7f405b77427e1a9ddba2 (patch) | |
| tree | fad4a67beb2d0ddcfcf746b8eb7693bdfc70d8ee /drivers/gpu | |
| parent | 64f9a26886686dee4803d979c5baecab8b71dcc1 (diff) | |
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>
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/display_manager.c | 387 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/display_manager.h | 145 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_ctrl.c | 4 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_display.c | 24 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_display.h | 10 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/dsi-staging/dsi_phy.c | 6 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.c | 3 | ||||
| -rw-r--r-- | drivers/gpu/drm/msm/msm_drv.h | 5 |
8 files changed, 579 insertions, 5 deletions
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 000000000000..45d1433dce93 --- /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 000000000000..0b7462b7bb53 --- /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 1fac1b9a4843..04a3a79f2f1d 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 @@ error: /** * 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 @@ void __init dsi_ctrl_drv_register(void) /** * 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 87a28dcfcf7d..47fa70823bc3 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 @@ error: 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 @@ int dsi_display_unprepare(struct dsi_display *display) 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 976baf6b8553..a8c0ebf6d0d6 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_probe(struct platform_device *pdev); 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 d53ef1140f99..1ccbbe7df573 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 @@ static struct platform_driver dsi_phy_platform_driver = { .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 @@ int dsi_phy_set_timing_params(struct msm_dsi_phy *phy, 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 67c4518e22e1..52479155de49 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -18,6 +18,7 @@ #include "msm_drv.h" #include "msm_gpu.h" #include "msm_kms.h" +#include "display_manager.h" static void msm_fb_output_poll_changed(struct drm_device *dev) { @@ -1169,6 +1170,7 @@ static struct platform_driver msm_platform_driver = { static int __init msm_drm_register(void) { DBG("init"); + display_manager_register(); msm_dsi_register(); msm_edp_register(); hdmi_register(); @@ -1184,6 +1186,7 @@ static void __exit msm_drm_unregister(void) adreno_unregister(); msm_edp_unregister(); msm_dsi_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 22d3e11fe821..2efc584ad5d4 100644 --- a/drivers/gpu/drm/msm/msm_drv.h +++ b/drivers/gpu/drm/msm/msm_drv.h @@ -102,6 +102,8 @@ struct msm_vblank_ctrl { spinlock_t lock; }; +struct display_manager; + struct msm_drm_private { struct msm_kms *kms; @@ -123,6 +125,9 @@ struct msm_drm_private { /* 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; |
