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