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