2 * Copyright (C) 2014 Traphandler
3 * Copyright (C) 2014 Free Electrons
4 * Copyright (C) 2014 Atmel
6 * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
7 * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as published by
11 * the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along with
19 * this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/of_graph.h>
25 #include <drm/drm_panel.h>
27 #include "atmel_hlcdc_dc.h"
30 * Atmel HLCDC RGB connector structure
32 * This structure stores RGB slave device information.
34 * @connector: DRM connector
35 * @encoder: DRM encoder
36 * @dc: pointer to the atmel_hlcdc_dc structure
37 * @panel: panel connected on the RGB output
39 struct atmel_hlcdc_rgb_output
{
40 struct drm_connector connector
;
41 struct drm_encoder encoder
;
42 struct atmel_hlcdc_dc
*dc
;
43 struct drm_panel
*panel
;
46 static inline struct atmel_hlcdc_rgb_output
*
47 drm_connector_to_atmel_hlcdc_rgb_output(struct drm_connector
*connector
)
49 return container_of(connector
, struct atmel_hlcdc_rgb_output
,
53 static inline struct atmel_hlcdc_rgb_output
*
54 drm_encoder_to_atmel_hlcdc_rgb_output(struct drm_encoder
*encoder
)
56 return container_of(encoder
, struct atmel_hlcdc_rgb_output
, encoder
);
59 static void atmel_hlcdc_rgb_encoder_enable(struct drm_encoder
*encoder
)
61 struct atmel_hlcdc_rgb_output
*rgb
=
62 drm_encoder_to_atmel_hlcdc_rgb_output(encoder
);
65 drm_panel_prepare(rgb
->panel
);
66 drm_panel_enable(rgb
->panel
);
70 static void atmel_hlcdc_rgb_encoder_disable(struct drm_encoder
*encoder
)
72 struct atmel_hlcdc_rgb_output
*rgb
=
73 drm_encoder_to_atmel_hlcdc_rgb_output(encoder
);
76 drm_panel_disable(rgb
->panel
);
77 drm_panel_unprepare(rgb
->panel
);
81 static const struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs
= {
82 .disable
= atmel_hlcdc_rgb_encoder_disable
,
83 .enable
= atmel_hlcdc_rgb_encoder_enable
,
86 static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder
*encoder
)
88 drm_encoder_cleanup(encoder
);
89 memset(encoder
, 0, sizeof(*encoder
));
92 static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs
= {
93 .destroy
= atmel_hlcdc_rgb_encoder_destroy
,
96 static int atmel_hlcdc_panel_get_modes(struct drm_connector
*connector
)
98 struct atmel_hlcdc_rgb_output
*rgb
=
99 drm_connector_to_atmel_hlcdc_rgb_output(connector
);
102 return rgb
->panel
->funcs
->get_modes(rgb
->panel
);
107 static int atmel_hlcdc_rgb_mode_valid(struct drm_connector
*connector
,
108 struct drm_display_mode
*mode
)
110 struct atmel_hlcdc_rgb_output
*rgb
=
111 drm_connector_to_atmel_hlcdc_rgb_output(connector
);
113 return atmel_hlcdc_dc_mode_valid(rgb
->dc
, mode
);
116 static const struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs
= {
117 .get_modes
= atmel_hlcdc_panel_get_modes
,
118 .mode_valid
= atmel_hlcdc_rgb_mode_valid
,
121 static enum drm_connector_status
122 atmel_hlcdc_panel_connector_detect(struct drm_connector
*connector
, bool force
)
124 struct atmel_hlcdc_rgb_output
*rgb
=
125 drm_connector_to_atmel_hlcdc_rgb_output(connector
);
128 return connector_status_connected
;
130 return connector_status_disconnected
;
134 atmel_hlcdc_panel_connector_destroy(struct drm_connector
*connector
)
136 struct atmel_hlcdc_rgb_output
*rgb
=
137 drm_connector_to_atmel_hlcdc_rgb_output(connector
);
140 drm_panel_detach(rgb
->panel
);
142 drm_connector_cleanup(connector
);
145 static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs
= {
146 .dpms
= drm_atomic_helper_connector_dpms
,
147 .detect
= atmel_hlcdc_panel_connector_detect
,
148 .fill_modes
= drm_helper_probe_single_connector_modes
,
149 .destroy
= atmel_hlcdc_panel_connector_destroy
,
150 .reset
= drm_atomic_helper_connector_reset
,
151 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
152 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
155 static int atmel_hlcdc_check_endpoint(struct drm_device
*dev
,
156 const struct of_endpoint
*ep
)
158 struct device_node
*np
;
161 np
= of_graph_get_remote_port_parent(ep
->local_node
);
163 obj
= of_drm_find_panel(np
);
165 obj
= of_drm_find_bridge(np
);
169 return obj
? 0 : -EPROBE_DEFER
;
172 static int atmel_hlcdc_attach_endpoint(struct drm_device
*dev
,
173 const struct of_endpoint
*ep
)
175 struct atmel_hlcdc_dc
*dc
= dev
->dev_private
;
176 struct atmel_hlcdc_rgb_output
*output
;
177 struct device_node
*np
;
178 struct drm_panel
*panel
;
179 struct drm_bridge
*bridge
;
182 output
= devm_kzalloc(dev
->dev
, sizeof(*output
), GFP_KERNEL
);
188 drm_encoder_helper_add(&output
->encoder
,
189 &atmel_hlcdc_panel_encoder_helper_funcs
);
190 ret
= drm_encoder_init(dev
, &output
->encoder
,
191 &atmel_hlcdc_panel_encoder_funcs
,
192 DRM_MODE_ENCODER_NONE
, NULL
);
196 output
->encoder
.possible_crtcs
= 0x1;
198 np
= of_graph_get_remote_port_parent(ep
->local_node
);
202 panel
= of_drm_find_panel(np
);
205 output
->connector
.dpms
= DRM_MODE_DPMS_OFF
;
206 output
->connector
.polled
= DRM_CONNECTOR_POLL_CONNECT
;
207 drm_connector_helper_add(&output
->connector
,
208 &atmel_hlcdc_panel_connector_helper_funcs
);
209 ret
= drm_connector_init(dev
, &output
->connector
,
210 &atmel_hlcdc_panel_connector_funcs
,
211 DRM_MODE_CONNECTOR_Unknown
);
213 goto err_encoder_cleanup
;
215 drm_mode_connector_attach_encoder(&output
->connector
,
218 ret
= drm_panel_attach(panel
, &output
->connector
);
220 drm_connector_cleanup(&output
->connector
);
221 goto err_encoder_cleanup
;
224 output
->panel
= panel
;
229 bridge
= of_drm_find_bridge(np
);
233 output
->encoder
.bridge
= bridge
;
234 bridge
->encoder
= &output
->encoder
;
235 ret
= drm_bridge_attach(dev
, bridge
);
241 drm_encoder_cleanup(&output
->encoder
);
246 int atmel_hlcdc_create_outputs(struct drm_device
*dev
)
248 struct device_node
*ep_np
= NULL
;
249 struct of_endpoint ep
;
252 for_each_endpoint_of_node(dev
->dev
->of_node
, ep_np
) {
253 ret
= of_graph_parse_endpoint(ep_np
, &ep
);
255 ret
= atmel_hlcdc_check_endpoint(dev
, &ep
);
263 for_each_endpoint_of_node(dev
->dev
->of_node
, ep_np
) {
264 ret
= of_graph_parse_endpoint(ep_np
, &ep
);
266 ret
= atmel_hlcdc_attach_endpoint(dev
, &ep
);