xref: /linux/drivers/gpu/drm/bridge/of-display-mode-bridge.c (revision 9611c0ce215a66770ccbe5c126bf57ba8c31bcad)
1*ba2db93cSDamon Ding // SPDX-License-Identifier: GPL-2.0+
2*ba2db93cSDamon Ding /*
3*ba2db93cSDamon Ding  * Copyright (C) 2012 Sascha Hauer, Pengutronix
4*ba2db93cSDamon Ding  *
5*ba2db93cSDamon Ding  * bridge driver for legacy DT bindings, utilizing display-timings node
6*ba2db93cSDamon Ding  *
7*ba2db93cSDamon Ding  * Author: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
8*ba2db93cSDamon Ding  */
9*ba2db93cSDamon Ding 
10*ba2db93cSDamon Ding #include <linux/export.h>
11*ba2db93cSDamon Ding 
12*ba2db93cSDamon Ding #include <drm/drm_bridge.h>
13*ba2db93cSDamon Ding #include <drm/drm_modes.h>
14*ba2db93cSDamon Ding #include <drm/drm_probe_helper.h>
15*ba2db93cSDamon Ding #include <drm/bridge/of-display-mode-bridge.h>
16*ba2db93cSDamon Ding 
17*ba2db93cSDamon Ding #include <video/of_display_timing.h>
18*ba2db93cSDamon Ding #include <video/of_videomode.h>
19*ba2db93cSDamon Ding 
20*ba2db93cSDamon Ding struct of_display_mode_bridge {
21*ba2db93cSDamon Ding 	struct drm_bridge base;
22*ba2db93cSDamon Ding 
23*ba2db93cSDamon Ding 	struct drm_display_mode mode;
24*ba2db93cSDamon Ding 	u32 bus_flags;
25*ba2db93cSDamon Ding };
26*ba2db93cSDamon Ding 
27*ba2db93cSDamon Ding #define to_of_display_mode_bridge(bridge) container_of(bridge, struct of_display_mode_bridge, base)
28*ba2db93cSDamon Ding 
29*ba2db93cSDamon Ding static int of_display_mode_bridge_attach(struct drm_bridge *bridge,
30*ba2db93cSDamon Ding 					 struct drm_encoder *encoder,
31*ba2db93cSDamon Ding 					 enum drm_bridge_attach_flags flags)
32*ba2db93cSDamon Ding {
33*ba2db93cSDamon Ding 	if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
34*ba2db93cSDamon Ding 		return -EINVAL;
35*ba2db93cSDamon Ding 
36*ba2db93cSDamon Ding 	return 0;
37*ba2db93cSDamon Ding }
38*ba2db93cSDamon Ding 
39*ba2db93cSDamon Ding static int of_display_mode_bridge_get_modes(struct drm_bridge *bridge,
40*ba2db93cSDamon Ding 					    struct drm_connector *connector)
41*ba2db93cSDamon Ding {
42*ba2db93cSDamon Ding 	struct of_display_mode_bridge *of_bridge = to_of_display_mode_bridge(bridge);
43*ba2db93cSDamon Ding 	int ret;
44*ba2db93cSDamon Ding 
45*ba2db93cSDamon Ding 	ret = drm_connector_helper_get_modes_fixed(connector, &of_bridge->mode);
46*ba2db93cSDamon Ding 	if (ret)
47*ba2db93cSDamon Ding 		return ret;
48*ba2db93cSDamon Ding 
49*ba2db93cSDamon Ding 	connector->display_info.bus_flags = of_bridge->bus_flags;
50*ba2db93cSDamon Ding 
51*ba2db93cSDamon Ding 	return 0;
52*ba2db93cSDamon Ding }
53*ba2db93cSDamon Ding 
54*ba2db93cSDamon Ding struct drm_bridge_funcs of_display_mode_bridge_funcs = {
55*ba2db93cSDamon Ding 	.attach = of_display_mode_bridge_attach,
56*ba2db93cSDamon Ding 	.get_modes = of_display_mode_bridge_get_modes,
57*ba2db93cSDamon Ding };
58*ba2db93cSDamon Ding 
59*ba2db93cSDamon Ding struct drm_bridge *devm_drm_of_display_mode_bridge(struct device *dev,
60*ba2db93cSDamon Ding 						   struct device_node *np,
61*ba2db93cSDamon Ding 						   int type)
62*ba2db93cSDamon Ding {
63*ba2db93cSDamon Ding 	struct of_display_mode_bridge *of_bridge;
64*ba2db93cSDamon Ding 	int ret;
65*ba2db93cSDamon Ding 
66*ba2db93cSDamon Ding 	of_bridge = devm_drm_bridge_alloc(dev, struct of_display_mode_bridge,
67*ba2db93cSDamon Ding 					  base, &of_display_mode_bridge_funcs);
68*ba2db93cSDamon Ding 	if (IS_ERR(of_bridge))
69*ba2db93cSDamon Ding 		return ERR_CAST(of_bridge);
70*ba2db93cSDamon Ding 
71*ba2db93cSDamon Ding 	ret = of_get_drm_display_mode(np,
72*ba2db93cSDamon Ding 				      &of_bridge->mode,
73*ba2db93cSDamon Ding 				      &of_bridge->bus_flags,
74*ba2db93cSDamon Ding 				      OF_USE_NATIVE_MODE);
75*ba2db93cSDamon Ding 	if (ret)
76*ba2db93cSDamon Ding 		return ERR_PTR(ret);
77*ba2db93cSDamon Ding 
78*ba2db93cSDamon Ding 	of_bridge->mode.type |= DRM_MODE_TYPE_DRIVER;
79*ba2db93cSDamon Ding 
80*ba2db93cSDamon Ding 	of_bridge->base.of_node = np;
81*ba2db93cSDamon Ding 	of_bridge->base.ops = DRM_BRIDGE_OP_MODES;
82*ba2db93cSDamon Ding 	of_bridge->base.type = type;
83*ba2db93cSDamon Ding 
84*ba2db93cSDamon Ding 	ret = devm_drm_bridge_add(dev, &of_bridge->base);
85*ba2db93cSDamon Ding 	if (ret)
86*ba2db93cSDamon Ding 		return ERR_PTR(ret);
87*ba2db93cSDamon Ding 
88*ba2db93cSDamon Ding 	return &of_bridge->base;
89*ba2db93cSDamon Ding }
90*ba2db93cSDamon Ding EXPORT_SYMBOL_GPL(devm_drm_of_display_mode_bridge);
91*ba2db93cSDamon Ding 
92*ba2db93cSDamon Ding MODULE_LICENSE("GPL");
93*ba2db93cSDamon Ding MODULE_DESCRIPTION("DRM bridge driver for legacy DT bindings");
94