1caab277bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
29960aa7cSTomi Valkeinen /*
31b409fdaSAlexander A. Klimov * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/
49960aa7cSTomi Valkeinen * Author: Archit Taneja <archit@ti.com>
59960aa7cSTomi Valkeinen */
69960aa7cSTomi Valkeinen
79960aa7cSTomi Valkeinen #include <linux/kernel.h>
89960aa7cSTomi Valkeinen #include <linux/module.h>
99960aa7cSTomi Valkeinen #include <linux/platform_device.h>
109960aa7cSTomi Valkeinen #include <linux/slab.h>
119960aa7cSTomi Valkeinen #include <linux/of.h>
1279107f27SLaurent Pinchart #include <linux/of_graph.h>
139960aa7cSTomi Valkeinen
14ee68c743SBoris Brezillon #include <drm/drm_bridge.h>
1530b71761SLaurent Pinchart #include <drm/drm_panel.h>
1630b71761SLaurent Pinchart
17845417b3SLaurent Pinchart #include "dss.h"
1832043da7SPeter Ujfalusi #include "omapdss.h"
199960aa7cSTomi Valkeinen
omapdss_device_init_output(struct omap_dss_device * out,struct drm_bridge * local_bridge)20326a1166SLaurent Pinchart int omapdss_device_init_output(struct omap_dss_device *out,
21326a1166SLaurent Pinchart struct drm_bridge *local_bridge)
229960aa7cSTomi Valkeinen {
2379107f27SLaurent Pinchart struct device_node *remote_node;
24a779618bSLaurent Pinchart int ret;
2579107f27SLaurent Pinchart
268090f7ebSLaurent Pinchart remote_node = of_graph_get_remote_node(out->dev->of_node,
27c83fefd7SLaurent Pinchart out->of_port, 0);
2879107f27SLaurent Pinchart if (!remote_node) {
2979107f27SLaurent Pinchart dev_dbg(out->dev, "failed to find video sink\n");
3079107f27SLaurent Pinchart return 0;
31d17eb453SLaurent Pinchart }
32d17eb453SLaurent Pinchart
3379107f27SLaurent Pinchart out->bridge = of_drm_find_bridge(remote_node);
3430b71761SLaurent Pinchart out->panel = of_drm_find_panel(remote_node);
3530b71761SLaurent Pinchart if (IS_ERR(out->panel))
3630b71761SLaurent Pinchart out->panel = NULL;
3779107f27SLaurent Pinchart
3879107f27SLaurent Pinchart of_node_put(remote_node);
3979107f27SLaurent Pinchart
40a779618bSLaurent Pinchart if (out->panel) {
41a779618bSLaurent Pinchart struct drm_bridge *bridge;
42a779618bSLaurent Pinchart
43a779618bSLaurent Pinchart bridge = drm_panel_bridge_add(out->panel);
44a779618bSLaurent Pinchart if (IS_ERR(bridge)) {
45a779618bSLaurent Pinchart dev_err(out->dev,
46a779618bSLaurent Pinchart "unable to create panel bridge (%ld)\n",
47a779618bSLaurent Pinchart PTR_ERR(bridge));
48a779618bSLaurent Pinchart ret = PTR_ERR(bridge);
49a779618bSLaurent Pinchart goto error;
50a779618bSLaurent Pinchart }
51a779618bSLaurent Pinchart
52a779618bSLaurent Pinchart out->bridge = bridge;
53a779618bSLaurent Pinchart }
54a779618bSLaurent Pinchart
55326a1166SLaurent Pinchart if (local_bridge) {
56e7e67d9aSLaurent Pinchart if (!out->bridge) {
57e7e67d9aSLaurent Pinchart ret = -EPROBE_DEFER;
58e7e67d9aSLaurent Pinchart goto error;
59e7e67d9aSLaurent Pinchart }
60e7e67d9aSLaurent Pinchart
61326a1166SLaurent Pinchart out->next_bridge = out->bridge;
62326a1166SLaurent Pinchart out->bridge = local_bridge;
63326a1166SLaurent Pinchart }
64326a1166SLaurent Pinchart
65811860ddSSebastian Reichel if (!out->bridge) {
66326a1166SLaurent Pinchart ret = -EPROBE_DEFER;
67326a1166SLaurent Pinchart goto error;
68326a1166SLaurent Pinchart }
69326a1166SLaurent Pinchart
70326a1166SLaurent Pinchart return 0;
71a779618bSLaurent Pinchart
72a779618bSLaurent Pinchart error:
73326a1166SLaurent Pinchart omapdss_device_cleanup_output(out);
74a779618bSLaurent Pinchart return ret;
759960aa7cSTomi Valkeinen }
76d17eb453SLaurent Pinchart
omapdss_device_cleanup_output(struct omap_dss_device * out)77d17eb453SLaurent Pinchart void omapdss_device_cleanup_output(struct omap_dss_device *out)
78d17eb453SLaurent Pinchart {
79a779618bSLaurent Pinchart if (out->bridge && out->panel)
80326a1166SLaurent Pinchart drm_panel_bridge_remove(out->next_bridge ?
81326a1166SLaurent Pinchart out->next_bridge : out->bridge);
82d17eb453SLaurent Pinchart }
839960aa7cSTomi Valkeinen
dss_mgr_set_timings(struct omap_dss_device * dssdev,const struct videomode * vm)8428d79f3eSLaurent Pinchart void dss_mgr_set_timings(struct omap_dss_device *dssdev,
8528d79f3eSLaurent Pinchart const struct videomode *vm)
869960aa7cSTomi Valkeinen {
87*05ec6128STomi Valkeinen omap_crtc_dss_set_timings(dssdev->dss->mgr_ops_priv,
88845417b3SLaurent Pinchart dssdev->dispc_channel, vm);
899960aa7cSTomi Valkeinen }
909960aa7cSTomi Valkeinen
dss_mgr_set_lcd_config(struct omap_dss_device * dssdev,const struct dss_lcd_mgr_config * config)9128d79f3eSLaurent Pinchart void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev,
929960aa7cSTomi Valkeinen const struct dss_lcd_mgr_config *config)
939960aa7cSTomi Valkeinen {
94*05ec6128STomi Valkeinen omap_crtc_dss_set_lcd_config(dssdev->dss->mgr_ops_priv,
9564cb8179SLaurent Pinchart dssdev->dispc_channel, config);
969960aa7cSTomi Valkeinen }
979960aa7cSTomi Valkeinen
dss_mgr_enable(struct omap_dss_device * dssdev)9828d79f3eSLaurent Pinchart int dss_mgr_enable(struct omap_dss_device *dssdev)
999960aa7cSTomi Valkeinen {
100*05ec6128STomi Valkeinen return omap_crtc_dss_enable(dssdev->dss->mgr_ops_priv,
101845417b3SLaurent Pinchart dssdev->dispc_channel);
1029960aa7cSTomi Valkeinen }
1039960aa7cSTomi Valkeinen
dss_mgr_disable(struct omap_dss_device * dssdev)10428d79f3eSLaurent Pinchart void dss_mgr_disable(struct omap_dss_device *dssdev)
1059960aa7cSTomi Valkeinen {
106*05ec6128STomi Valkeinen omap_crtc_dss_disable(dssdev->dss->mgr_ops_priv,
107845417b3SLaurent Pinchart dssdev->dispc_channel);
1089960aa7cSTomi Valkeinen }
1099960aa7cSTomi Valkeinen
dss_mgr_start_update(struct omap_dss_device * dssdev)11028d79f3eSLaurent Pinchart void dss_mgr_start_update(struct omap_dss_device *dssdev)
1119960aa7cSTomi Valkeinen {
112*05ec6128STomi Valkeinen omap_crtc_dss_start_update(dssdev->dss->mgr_ops_priv,
113845417b3SLaurent Pinchart dssdev->dispc_channel);
1149960aa7cSTomi Valkeinen }
1159960aa7cSTomi Valkeinen
dss_mgr_register_framedone_handler(struct omap_dss_device * dssdev,void (* handler)(void *),void * data)11628d79f3eSLaurent Pinchart int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev,
1179960aa7cSTomi Valkeinen void (*handler)(void *), void *data)
1189960aa7cSTomi Valkeinen {
119845417b3SLaurent Pinchart struct dss_device *dss = dssdev->dss;
120845417b3SLaurent Pinchart
121*05ec6128STomi Valkeinen return omap_crtc_dss_register_framedone(dss->mgr_ops_priv,
12264cb8179SLaurent Pinchart dssdev->dispc_channel,
12328d79f3eSLaurent Pinchart handler, data);
1249960aa7cSTomi Valkeinen }
1259960aa7cSTomi Valkeinen
dss_mgr_unregister_framedone_handler(struct omap_dss_device * dssdev,void (* handler)(void *),void * data)12628d79f3eSLaurent Pinchart void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev,
1279960aa7cSTomi Valkeinen void (*handler)(void *), void *data)
1289960aa7cSTomi Valkeinen {
129845417b3SLaurent Pinchart struct dss_device *dss = dssdev->dss;
130845417b3SLaurent Pinchart
131*05ec6128STomi Valkeinen omap_crtc_dss_unregister_framedone(dss->mgr_ops_priv,
13264cb8179SLaurent Pinchart dssdev->dispc_channel,
13328d79f3eSLaurent Pinchart handler, data);
1349960aa7cSTomi Valkeinen }
135