]> Git Repo - linux.git/blob - drivers/gpu/drm/logicvc/logicvc_interface.c
Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[linux.git] / drivers / gpu / drm / logicvc / logicvc_interface.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2019-2022 Bootlin
4  * Author: Paul Kocialkowski <[email protected]>
5  */
6
7 #include <linux/types.h>
8
9 #include <drm/drm_atomic_helper.h>
10 #include <drm/drm_bridge.h>
11 #include <drm/drm_connector.h>
12 #include <drm/drm_crtc_helper.h>
13 #include <drm/drm_drv.h>
14 #include <drm/drm_encoder.h>
15 #include <drm/drm_gem_cma_helper.h>
16 #include <drm/drm_modeset_helper_vtables.h>
17 #include <drm/drm_of.h>
18 #include <drm/drm_panel.h>
19 #include <drm/drm_print.h>
20 #include <drm/drm_probe_helper.h>
21
22 #include "logicvc_crtc.h"
23 #include "logicvc_drm.h"
24 #include "logicvc_interface.h"
25 #include "logicvc_regs.h"
26
27 #define logicvc_interface_from_drm_encoder(c) \
28         container_of(c, struct logicvc_interface, drm_encoder)
29 #define logicvc_interface_from_drm_connector(c) \
30         container_of(c, struct logicvc_interface, drm_connector)
31
32 static void logicvc_encoder_enable(struct drm_encoder *drm_encoder)
33 {
34         struct logicvc_drm *logicvc = logicvc_drm(drm_encoder->dev);
35         struct logicvc_interface *interface =
36                 logicvc_interface_from_drm_encoder(drm_encoder);
37
38         regmap_update_bits(logicvc->regmap, LOGICVC_POWER_CTRL_REG,
39                            LOGICVC_POWER_CTRL_VIDEO_ENABLE,
40                            LOGICVC_POWER_CTRL_VIDEO_ENABLE);
41
42         if (interface->drm_panel) {
43                 drm_panel_prepare(interface->drm_panel);
44                 drm_panel_enable(interface->drm_panel);
45         }
46 }
47
48 static void logicvc_encoder_disable(struct drm_encoder *drm_encoder)
49 {
50         struct logicvc_interface *interface =
51                 logicvc_interface_from_drm_encoder(drm_encoder);
52
53         if (interface->drm_panel) {
54                 drm_panel_disable(interface->drm_panel);
55                 drm_panel_unprepare(interface->drm_panel);
56         }
57 }
58
59 static const struct drm_encoder_helper_funcs logicvc_encoder_helper_funcs = {
60         .enable                 = logicvc_encoder_enable,
61         .disable                = logicvc_encoder_disable,
62 };
63
64 static const struct drm_encoder_funcs logicvc_encoder_funcs = {
65         .destroy                = drm_encoder_cleanup,
66 };
67
68 static int logicvc_connector_get_modes(struct drm_connector *drm_connector)
69 {
70         struct logicvc_interface *interface =
71                 logicvc_interface_from_drm_connector(drm_connector);
72
73         if (interface->drm_panel)
74                 return drm_panel_get_modes(interface->drm_panel, drm_connector);
75
76         WARN_ONCE(1, "Retrieving modes from a native connector is not implemented.");
77
78         return 0;
79 }
80
81 static const struct drm_connector_helper_funcs logicvc_connector_helper_funcs = {
82         .get_modes              = logicvc_connector_get_modes,
83 };
84
85 static const struct drm_connector_funcs logicvc_connector_funcs = {
86         .reset                  = drm_atomic_helper_connector_reset,
87         .fill_modes             = drm_helper_probe_single_connector_modes,
88         .destroy                = drm_connector_cleanup,
89         .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
90         .atomic_destroy_state   = drm_atomic_helper_connector_destroy_state,
91 };
92
93 static int logicvc_interface_encoder_type(struct logicvc_drm *logicvc)
94 {
95         switch (logicvc->config.display_interface) {
96         case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS:
97         case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS_CAMERA:
98         case LOGICVC_DISPLAY_INTERFACE_LVDS_3BITS:
99                 return DRM_MODE_ENCODER_LVDS;
100         case LOGICVC_DISPLAY_INTERFACE_DVI:
101                 return DRM_MODE_ENCODER_TMDS;
102         case LOGICVC_DISPLAY_INTERFACE_RGB:
103                 return DRM_MODE_ENCODER_DPI;
104         default:
105                 return DRM_MODE_ENCODER_NONE;
106         }
107 }
108
109 static int logicvc_interface_connector_type(struct logicvc_drm *logicvc)
110 {
111         switch (logicvc->config.display_interface) {
112         case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS:
113         case LOGICVC_DISPLAY_INTERFACE_LVDS_4BITS_CAMERA:
114         case LOGICVC_DISPLAY_INTERFACE_LVDS_3BITS:
115                 return DRM_MODE_CONNECTOR_LVDS;
116         case LOGICVC_DISPLAY_INTERFACE_DVI:
117                 return DRM_MODE_CONNECTOR_DVID;
118         case LOGICVC_DISPLAY_INTERFACE_RGB:
119                 return DRM_MODE_CONNECTOR_DPI;
120         default:
121                 return DRM_MODE_CONNECTOR_Unknown;
122         }
123 }
124
125 static bool logicvc_interface_native_connector(struct logicvc_drm *logicvc)
126 {
127         switch (logicvc->config.display_interface) {
128         case LOGICVC_DISPLAY_INTERFACE_DVI:
129                 return true;
130         default:
131                 return false;
132         }
133 }
134
135 void logicvc_interface_attach_crtc(struct logicvc_drm *logicvc)
136 {
137         uint32_t possible_crtcs = drm_crtc_mask(&logicvc->crtc->drm_crtc);
138
139         logicvc->interface->drm_encoder.possible_crtcs = possible_crtcs;
140 }
141
142 int logicvc_interface_init(struct logicvc_drm *logicvc)
143 {
144         struct logicvc_interface *interface;
145         struct drm_device *drm_dev = &logicvc->drm_dev;
146         struct device *dev = drm_dev->dev;
147         struct device_node *of_node = dev->of_node;
148         int encoder_type = logicvc_interface_encoder_type(logicvc);
149         int connector_type = logicvc_interface_connector_type(logicvc);
150         bool native_connector = logicvc_interface_native_connector(logicvc);
151         int ret;
152
153         interface = devm_kzalloc(dev, sizeof(*interface), GFP_KERNEL);
154         if (!interface) {
155                 ret = -ENOMEM;
156                 goto error_early;
157         }
158
159         ret = drm_of_find_panel_or_bridge(of_node, 0, 0, &interface->drm_panel,
160                                           &interface->drm_bridge);
161         if (ret == -EPROBE_DEFER)
162                 goto error_early;
163
164         ret = drm_encoder_init(drm_dev, &interface->drm_encoder,
165                                &logicvc_encoder_funcs, encoder_type, NULL);
166         if (ret) {
167                 drm_err(drm_dev, "Failed to initialize encoder\n");
168                 goto error_early;
169         }
170
171         drm_encoder_helper_add(&interface->drm_encoder,
172                                &logicvc_encoder_helper_funcs);
173
174         if (native_connector || interface->drm_panel) {
175                 ret = drm_connector_init(drm_dev, &interface->drm_connector,
176                                          &logicvc_connector_funcs,
177                                          connector_type);
178                 if (ret) {
179                         drm_err(drm_dev, "Failed to initialize connector\n");
180                         goto error_encoder;
181                 }
182
183                 drm_connector_helper_add(&interface->drm_connector,
184                                          &logicvc_connector_helper_funcs);
185
186                 ret = drm_connector_attach_encoder(&interface->drm_connector,
187                                                    &interface->drm_encoder);
188                 if (ret) {
189                         drm_err(drm_dev,
190                                 "Failed to attach connector to encoder\n");
191                         goto error_encoder;
192                 }
193         }
194
195         if (interface->drm_bridge) {
196                 ret = drm_bridge_attach(&interface->drm_encoder,
197                                         interface->drm_bridge, NULL, 0);
198                 if (ret) {
199                         drm_err(drm_dev,
200                                 "Failed to attach bridge to encoder\n");
201                         goto error_encoder;
202                 }
203         }
204
205         logicvc->interface = interface;
206
207         return 0;
208
209 error_encoder:
210         drm_encoder_cleanup(&interface->drm_encoder);
211
212 error_early:
213         return ret;
214 }
This page took 0.044133 seconds and 4 git commands to generate.