2 * Copyright 2015 Freescale Semiconductor, Inc.
4 * Freescale DCU drm device driver
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
12 #include <linux/backlight.h>
13 #include <linux/of_graph.h>
16 #include <drm/drm_atomic_helper.h>
17 #include <drm/drm_crtc_helper.h>
18 #include <drm/drm_panel.h>
20 #include "fsl_dcu_drm_drv.h"
24 fsl_dcu_drm_encoder_atomic_check(struct drm_encoder
*encoder
,
25 struct drm_crtc_state
*crtc_state
,
26 struct drm_connector_state
*conn_state
)
31 static void fsl_dcu_drm_encoder_disable(struct drm_encoder
*encoder
)
33 struct drm_device
*dev
= encoder
->dev
;
34 struct fsl_dcu_drm_device
*fsl_dev
= dev
->dev_private
;
37 fsl_tcon_bypass_disable(fsl_dev
->tcon
);
40 static void fsl_dcu_drm_encoder_enable(struct drm_encoder
*encoder
)
42 struct drm_device
*dev
= encoder
->dev
;
43 struct fsl_dcu_drm_device
*fsl_dev
= dev
->dev_private
;
46 fsl_tcon_bypass_enable(fsl_dev
->tcon
);
49 static const struct drm_encoder_helper_funcs encoder_helper_funcs
= {
50 .atomic_check
= fsl_dcu_drm_encoder_atomic_check
,
51 .disable
= fsl_dcu_drm_encoder_disable
,
52 .enable
= fsl_dcu_drm_encoder_enable
,
55 static void fsl_dcu_drm_encoder_destroy(struct drm_encoder
*encoder
)
57 drm_encoder_cleanup(encoder
);
60 static const struct drm_encoder_funcs encoder_funcs
= {
61 .destroy
= fsl_dcu_drm_encoder_destroy
,
64 int fsl_dcu_drm_encoder_create(struct fsl_dcu_drm_device
*fsl_dev
,
65 struct drm_crtc
*crtc
)
67 struct drm_encoder
*encoder
= &fsl_dev
->encoder
;
70 encoder
->possible_crtcs
= 1;
71 ret
= drm_encoder_init(fsl_dev
->drm
, encoder
, &encoder_funcs
,
72 DRM_MODE_ENCODER_LVDS
, NULL
);
76 drm_encoder_helper_add(encoder
, &encoder_helper_funcs
);
81 static void fsl_dcu_drm_connector_destroy(struct drm_connector
*connector
)
83 struct fsl_dcu_drm_connector
*fsl_con
= to_fsl_dcu_connector(connector
);
85 drm_connector_unregister(connector
);
86 drm_panel_detach(fsl_con
->panel
);
87 drm_connector_cleanup(connector
);
90 static enum drm_connector_status
91 fsl_dcu_drm_connector_detect(struct drm_connector
*connector
, bool force
)
93 return connector_status_connected
;
96 static const struct drm_connector_funcs fsl_dcu_drm_connector_funcs
= {
97 .atomic_duplicate_state
= drm_atomic_helper_connector_duplicate_state
,
98 .atomic_destroy_state
= drm_atomic_helper_connector_destroy_state
,
99 .destroy
= fsl_dcu_drm_connector_destroy
,
100 .detect
= fsl_dcu_drm_connector_detect
,
101 .dpms
= drm_atomic_helper_connector_dpms
,
102 .fill_modes
= drm_helper_probe_single_connector_modes
,
103 .reset
= drm_atomic_helper_connector_reset
,
106 static int fsl_dcu_drm_connector_get_modes(struct drm_connector
*connector
)
108 struct fsl_dcu_drm_connector
*fsl_connector
;
109 int (*get_modes
)(struct drm_panel
*panel
);
112 fsl_connector
= to_fsl_dcu_connector(connector
);
113 if (fsl_connector
->panel
&& fsl_connector
->panel
->funcs
&&
114 fsl_connector
->panel
->funcs
->get_modes
) {
115 get_modes
= fsl_connector
->panel
->funcs
->get_modes
;
116 num_modes
= get_modes(fsl_connector
->panel
);
122 static int fsl_dcu_drm_connector_mode_valid(struct drm_connector
*connector
,
123 struct drm_display_mode
*mode
)
125 if (mode
->hdisplay
& 0xf)
131 static const struct drm_connector_helper_funcs connector_helper_funcs
= {
132 .get_modes
= fsl_dcu_drm_connector_get_modes
,
133 .mode_valid
= fsl_dcu_drm_connector_mode_valid
,
136 static int fsl_dcu_attach_panel(struct fsl_dcu_drm_device
*fsl_dev
,
137 struct drm_panel
*panel
)
139 struct drm_encoder
*encoder
= &fsl_dev
->encoder
;
140 struct drm_connector
*connector
= &fsl_dev
->connector
.base
;
141 struct drm_mode_config
*mode_config
= &fsl_dev
->drm
->mode_config
;
144 fsl_dev
->connector
.encoder
= encoder
;
146 ret
= drm_connector_init(fsl_dev
->drm
, connector
,
147 &fsl_dcu_drm_connector_funcs
,
148 DRM_MODE_CONNECTOR_LVDS
);
152 drm_connector_helper_add(connector
, &connector_helper_funcs
);
153 ret
= drm_connector_register(connector
);
157 ret
= drm_mode_connector_attach_encoder(connector
, encoder
);
161 drm_object_property_set_value(&connector
->base
,
162 mode_config
->dpms_property
,
165 ret
= drm_panel_attach(panel
, connector
);
167 dev_err(fsl_dev
->dev
, "failed to attach panel\n");
174 drm_connector_unregister(connector
);
176 drm_connector_cleanup(connector
);
180 static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device
*fsl_dev
,
181 const struct of_endpoint
*ep
)
183 struct drm_bridge
*bridge
;
184 struct device_node
*np
;
186 np
= of_graph_get_remote_port_parent(ep
->local_node
);
188 fsl_dev
->connector
.panel
= of_drm_find_panel(np
);
189 if (fsl_dev
->connector
.panel
) {
191 return fsl_dcu_attach_panel(fsl_dev
, fsl_dev
->connector
.panel
);
194 bridge
= of_drm_find_bridge(np
);
199 fsl_dev
->encoder
.bridge
= bridge
;
200 bridge
->encoder
= &fsl_dev
->encoder
;
202 return drm_bridge_attach(fsl_dev
->drm
, bridge
);
205 int fsl_dcu_create_outputs(struct fsl_dcu_drm_device
*fsl_dev
)
207 struct of_endpoint ep
;
208 struct device_node
*ep_node
, *panel_node
;
211 /* This is for backward compatibility */
212 panel_node
= of_parse_phandle(fsl_dev
->np
, "fsl,panel", 0);
214 fsl_dev
->connector
.panel
= of_drm_find_panel(panel_node
);
215 of_node_put(panel_node
);
216 if (!fsl_dev
->connector
.panel
)
217 return -EPROBE_DEFER
;
218 return fsl_dcu_attach_panel(fsl_dev
, fsl_dev
->connector
.panel
);
221 ep_node
= of_graph_get_next_endpoint(fsl_dev
->np
, NULL
);
225 ret
= of_graph_parse_endpoint(ep_node
, &ep
);
226 of_node_put(ep_node
);
230 return fsl_dcu_attach_endpoint(fsl_dev
, &ep
);