1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ |
4 | * Author: Archit Taneja <archit@ti.com> |
5 | */ |
6 | |
7 | #include <linux/kernel.h> |
8 | #include <linux/module.h> |
9 | #include <linux/platform_device.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/of.h> |
12 | #include <linux/of_graph.h> |
13 | |
14 | #include <drm/drm_bridge.h> |
15 | #include <drm/drm_panel.h> |
16 | |
17 | #include "dss.h" |
18 | #include "omapdss.h" |
19 | |
20 | int omapdss_device_init_output(struct omap_dss_device *out, |
21 | struct drm_bridge *local_bridge) |
22 | { |
23 | struct device_node *remote_node; |
24 | int ret; |
25 | |
26 | remote_node = of_graph_get_remote_node(node: out->dev->of_node, |
27 | port: out->of_port, endpoint: 0); |
28 | if (!remote_node) { |
29 | dev_dbg(out->dev, "failed to find video sink\n" ); |
30 | return 0; |
31 | } |
32 | |
33 | out->bridge = of_drm_find_bridge(np: remote_node); |
34 | out->panel = of_drm_find_panel(np: remote_node); |
35 | if (IS_ERR(ptr: out->panel)) |
36 | out->panel = NULL; |
37 | |
38 | of_node_put(node: remote_node); |
39 | |
40 | if (out->panel) { |
41 | struct drm_bridge *bridge; |
42 | |
43 | bridge = drm_panel_bridge_add(panel: out->panel); |
44 | if (IS_ERR(ptr: bridge)) { |
45 | dev_err(out->dev, |
46 | "unable to create panel bridge (%ld)\n" , |
47 | PTR_ERR(bridge)); |
48 | ret = PTR_ERR(ptr: bridge); |
49 | goto error; |
50 | } |
51 | |
52 | out->bridge = bridge; |
53 | } |
54 | |
55 | if (local_bridge) { |
56 | if (!out->bridge) { |
57 | ret = -EPROBE_DEFER; |
58 | goto error; |
59 | } |
60 | |
61 | out->next_bridge = out->bridge; |
62 | out->bridge = local_bridge; |
63 | } |
64 | |
65 | if (!out->bridge) { |
66 | ret = -EPROBE_DEFER; |
67 | goto error; |
68 | } |
69 | |
70 | return 0; |
71 | |
72 | error: |
73 | omapdss_device_cleanup_output(out); |
74 | return ret; |
75 | } |
76 | |
77 | void omapdss_device_cleanup_output(struct omap_dss_device *out) |
78 | { |
79 | if (out->bridge && out->panel) |
80 | drm_panel_bridge_remove(bridge: out->next_bridge ? |
81 | out->next_bridge : out->bridge); |
82 | } |
83 | |
84 | void dss_mgr_set_timings(struct omap_dss_device *dssdev, |
85 | const struct videomode *vm) |
86 | { |
87 | omap_crtc_dss_set_timings(priv: dssdev->dss->mgr_ops_priv, |
88 | channel: dssdev->dispc_channel, vm); |
89 | } |
90 | |
91 | void dss_mgr_set_lcd_config(struct omap_dss_device *dssdev, |
92 | const struct dss_lcd_mgr_config *config) |
93 | { |
94 | omap_crtc_dss_set_lcd_config(priv: dssdev->dss->mgr_ops_priv, |
95 | channel: dssdev->dispc_channel, config); |
96 | } |
97 | |
98 | int dss_mgr_enable(struct omap_dss_device *dssdev) |
99 | { |
100 | return omap_crtc_dss_enable(priv: dssdev->dss->mgr_ops_priv, |
101 | channel: dssdev->dispc_channel); |
102 | } |
103 | |
104 | void dss_mgr_disable(struct omap_dss_device *dssdev) |
105 | { |
106 | omap_crtc_dss_disable(priv: dssdev->dss->mgr_ops_priv, |
107 | channel: dssdev->dispc_channel); |
108 | } |
109 | |
110 | void dss_mgr_start_update(struct omap_dss_device *dssdev) |
111 | { |
112 | omap_crtc_dss_start_update(priv: dssdev->dss->mgr_ops_priv, |
113 | channel: dssdev->dispc_channel); |
114 | } |
115 | |
116 | int dss_mgr_register_framedone_handler(struct omap_dss_device *dssdev, |
117 | void (*handler)(void *), void *data) |
118 | { |
119 | struct dss_device *dss = dssdev->dss; |
120 | |
121 | return omap_crtc_dss_register_framedone(priv: dss->mgr_ops_priv, |
122 | channel: dssdev->dispc_channel, |
123 | handler, data); |
124 | } |
125 | |
126 | void dss_mgr_unregister_framedone_handler(struct omap_dss_device *dssdev, |
127 | void (*handler)(void *), void *data) |
128 | { |
129 | struct dss_device *dss = dssdev->dss; |
130 | |
131 | omap_crtc_dss_unregister_framedone(priv: dss->mgr_ops_priv, |
132 | channel: dssdev->dispc_channel, |
133 | handler, data); |
134 | } |
135 | |