aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx/parallel-display.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/imx/parallel-display.c')
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c149
1 files changed, 95 insertions, 54 deletions
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 2d1fd02cd3d6..1dad297b01fd 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -16,6 +16,7 @@
16#include <linux/component.h> 16#include <linux/component.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <drm/drmP.h> 18#include <drm/drmP.h>
19#include <drm/drm_atomic_helper.h>
19#include <drm/drm_fb_helper.h> 20#include <drm/drm_fb_helper.h>
20#include <drm/drm_crtc_helper.h> 21#include <drm/drm_crtc_helper.h>
21#include <drm/drm_panel.h> 22#include <drm/drm_panel.h>
@@ -25,9 +26,6 @@
25 26
26#include "imx-drm.h" 27#include "imx-drm.h"
27 28
28#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
29#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
30
31struct imx_parallel_display { 29struct imx_parallel_display {
32 struct drm_connector connector; 30 struct drm_connector connector;
33 struct drm_encoder encoder; 31 struct drm_encoder encoder;
@@ -37,8 +35,19 @@ struct imx_parallel_display {
37 u32 bus_format; 35 u32 bus_format;
38 struct drm_display_mode mode; 36 struct drm_display_mode mode;
39 struct drm_panel *panel; 37 struct drm_panel *panel;
38 struct drm_bridge *bridge;
40}; 39};
41 40
41static inline struct imx_parallel_display *con_to_imxpd(struct drm_connector *c)
42{
43 return container_of(c, struct imx_parallel_display, connector);
44}
45
46static inline struct imx_parallel_display *enc_to_imxpd(struct drm_encoder *e)
47{
48 return container_of(e, struct imx_parallel_display, encoder);
49}
50
42static enum drm_connector_status imx_pd_connector_detect( 51static enum drm_connector_status imx_pd_connector_detect(
43 struct drm_connector *connector, bool force) 52 struct drm_connector *connector, bool force)
44{ 53{
@@ -53,11 +62,7 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
53 62
54 if (imxpd->panel && imxpd->panel->funcs && 63 if (imxpd->panel && imxpd->panel->funcs &&
55 imxpd->panel->funcs->get_modes) { 64 imxpd->panel->funcs->get_modes) {
56 struct drm_display_info *di = &connector->display_info;
57
58 num_modes = imxpd->panel->funcs->get_modes(imxpd->panel); 65 num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
59 if (!imxpd->bus_format && di->num_bus_formats)
60 imxpd->bus_format = di->bus_formats[0];
61 if (num_modes > 0) 66 if (num_modes > 0)
62 return num_modes; 67 return num_modes;
63 } 68 }
@@ -69,10 +74,16 @@ static int imx_pd_connector_get_modes(struct drm_connector *connector)
69 74
70 if (np) { 75 if (np) {
71 struct drm_display_mode *mode = drm_mode_create(connector->dev); 76 struct drm_display_mode *mode = drm_mode_create(connector->dev);
77 int ret;
72 78
73 if (!mode) 79 if (!mode)
74 return -EINVAL; 80 return -EINVAL;
75 of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE); 81
82 ret = of_get_drm_display_mode(np, &imxpd->mode,
83 OF_USE_NATIVE_MODE);
84 if (ret)
85 return ret;
86
76 drm_mode_copy(mode, &imxpd->mode); 87 drm_mode_copy(mode, &imxpd->mode);
77 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 88 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
78 drm_mode_probed_add(connector, mode); 89 drm_mode_probed_add(connector, mode);
@@ -90,24 +101,7 @@ static struct drm_encoder *imx_pd_connector_best_encoder(
90 return &imxpd->encoder; 101 return &imxpd->encoder;
91} 102}
92 103
93static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) 104static void imx_pd_encoder_enable(struct drm_encoder *encoder)
94{
95 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
96
97 if (mode != DRM_MODE_DPMS_ON)
98 drm_panel_disable(imxpd->panel);
99 else
100 drm_panel_enable(imxpd->panel);
101}
102
103static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
104{
105 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
106 imx_drm_set_bus_config(encoder, imxpd->bus_format, 2, 3,
107 imxpd->connector.display_info.bus_flags);
108}
109
110static void imx_pd_encoder_commit(struct drm_encoder *encoder)
111{ 105{
112 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); 106 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
113 107
@@ -115,12 +109,6 @@ static void imx_pd_encoder_commit(struct drm_encoder *encoder)
115 drm_panel_enable(imxpd->panel); 109 drm_panel_enable(imxpd->panel);
116} 110}
117 111
118static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
119 struct drm_display_mode *orig_mode,
120 struct drm_display_mode *mode)
121{
122}
123
124static void imx_pd_encoder_disable(struct drm_encoder *encoder) 112static void imx_pd_encoder_disable(struct drm_encoder *encoder)
125{ 113{
126 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); 114 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
@@ -129,11 +117,33 @@ static void imx_pd_encoder_disable(struct drm_encoder *encoder)
129 drm_panel_unprepare(imxpd->panel); 117 drm_panel_unprepare(imxpd->panel);
130} 118}
131 119
120static int imx_pd_encoder_atomic_check(struct drm_encoder *encoder,
121 struct drm_crtc_state *crtc_state,
122 struct drm_connector_state *conn_state)
123{
124 struct imx_crtc_state *imx_crtc_state = to_imx_crtc_state(crtc_state);
125 struct drm_display_info *di = &conn_state->connector->display_info;
126 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
127
128 imx_crtc_state->bus_flags = di->bus_flags;
129 if (!imxpd->bus_format && di->num_bus_formats)
130 imx_crtc_state->bus_format = di->bus_formats[0];
131 else
132 imx_crtc_state->bus_format = imxpd->bus_format;
133 imx_crtc_state->di_hsync_pin = 2;
134 imx_crtc_state->di_vsync_pin = 3;
135
136 return 0;
137}
138
132static const struct drm_connector_funcs imx_pd_connector_funcs = { 139static const struct drm_connector_funcs imx_pd_connector_funcs = {
133 .dpms = drm_helper_connector_dpms, 140 .dpms = drm_atomic_helper_connector_dpms,
134 .fill_modes = drm_helper_probe_single_connector_modes, 141 .fill_modes = drm_helper_probe_single_connector_modes,
135 .detect = imx_pd_connector_detect, 142 .detect = imx_pd_connector_detect,
136 .destroy = imx_drm_connector_destroy, 143 .destroy = imx_drm_connector_destroy,
144 .reset = drm_atomic_helper_connector_reset,
145 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
146 .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
137}; 147};
138 148
139static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { 149static const struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
@@ -146,20 +156,18 @@ static const struct drm_encoder_funcs imx_pd_encoder_funcs = {
146}; 156};
147 157
148static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { 158static const struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
149 .dpms = imx_pd_encoder_dpms, 159 .enable = imx_pd_encoder_enable,
150 .prepare = imx_pd_encoder_prepare,
151 .commit = imx_pd_encoder_commit,
152 .mode_set = imx_pd_encoder_mode_set,
153 .disable = imx_pd_encoder_disable, 160 .disable = imx_pd_encoder_disable,
161 .atomic_check = imx_pd_encoder_atomic_check,
154}; 162};
155 163
156static int imx_pd_register(struct drm_device *drm, 164static int imx_pd_register(struct drm_device *drm,
157 struct imx_parallel_display *imxpd) 165 struct imx_parallel_display *imxpd)
158{ 166{
167 struct drm_encoder *encoder = &imxpd->encoder;
159 int ret; 168 int ret;
160 169
161 ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder, 170 ret = imx_drm_encoder_parse_of(drm, encoder, imxpd->dev->of_node);
162 imxpd->dev->of_node);
163 if (ret) 171 if (ret)
164 return ret; 172 return ret;
165 173
@@ -170,19 +178,33 @@ static int imx_pd_register(struct drm_device *drm,
170 */ 178 */
171 imxpd->connector.dpms = DRM_MODE_DPMS_OFF; 179 imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
172 180
173 drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs); 181 drm_encoder_helper_add(encoder, &imx_pd_encoder_helper_funcs);
174 drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs, 182 drm_encoder_init(drm, encoder, &imx_pd_encoder_funcs,
175 DRM_MODE_ENCODER_NONE, NULL); 183 DRM_MODE_ENCODER_NONE, NULL);
176 184
177 drm_connector_helper_add(&imxpd->connector, 185 if (!imxpd->bridge) {
178 &imx_pd_connector_helper_funcs); 186 drm_connector_helper_add(&imxpd->connector,
179 drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs, 187 &imx_pd_connector_helper_funcs);
180 DRM_MODE_CONNECTOR_VGA); 188 drm_connector_init(drm, &imxpd->connector,
189 &imx_pd_connector_funcs,
190 DRM_MODE_CONNECTOR_VGA);
191 }
181 192
182 if (imxpd->panel) 193 if (imxpd->panel)
183 drm_panel_attach(imxpd->panel, &imxpd->connector); 194 drm_panel_attach(imxpd->panel, &imxpd->connector);
184 195
185 drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder); 196 if (imxpd->bridge) {
197 imxpd->bridge->encoder = encoder;
198 encoder->bridge = imxpd->bridge;
199 ret = drm_bridge_attach(drm, imxpd->bridge);
200 if (ret < 0) {
201 dev_err(imxpd->dev, "failed to attach bridge: %d\n",
202 ret);
203 return ret;
204 }
205 } else {
206 drm_mode_connector_attach_encoder(&imxpd->connector, encoder);
207 }
186 208
187 return 0; 209 return 0;
188} 210}
@@ -195,6 +217,7 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
195 const u8 *edidp; 217 const u8 *edidp;
196 struct imx_parallel_display *imxpd; 218 struct imx_parallel_display *imxpd;
197 int ret; 219 int ret;
220 u32 bus_format = 0;
198 const char *fmt; 221 const char *fmt;
199 222
200 imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL); 223 imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
@@ -208,14 +231,15 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
208 ret = of_property_read_string(np, "interface-pix-fmt", &fmt); 231 ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
209 if (!ret) { 232 if (!ret) {
210 if (!strcmp(fmt, "rgb24")) 233 if (!strcmp(fmt, "rgb24"))
211 imxpd->bus_format = MEDIA_BUS_FMT_RGB888_1X24; 234 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
212 else if (!strcmp(fmt, "rgb565")) 235 else if (!strcmp(fmt, "rgb565"))
213 imxpd->bus_format = MEDIA_BUS_FMT_RGB565_1X16; 236 bus_format = MEDIA_BUS_FMT_RGB565_1X16;
214 else if (!strcmp(fmt, "bgr666")) 237 else if (!strcmp(fmt, "bgr666"))
215 imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X18; 238 bus_format = MEDIA_BUS_FMT_RGB666_1X18;
216 else if (!strcmp(fmt, "lvds666")) 239 else if (!strcmp(fmt, "lvds666"))
217 imxpd->bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI; 240 bus_format = MEDIA_BUS_FMT_RGB666_1X24_CPADHI;
218 } 241 }
242 imxpd->bus_format = bus_format;
219 243
220 /* port@1 is the output port */ 244 /* port@1 is the output port */
221 ep = of_graph_get_endpoint_by_regs(np, 1, -1); 245 ep = of_graph_get_endpoint_by_regs(np, 1, -1);
@@ -223,13 +247,30 @@ static int imx_pd_bind(struct device *dev, struct device *master, void *data)
223 struct device_node *remote; 247 struct device_node *remote;
224 248
225 remote = of_graph_get_remote_port_parent(ep); 249 remote = of_graph_get_remote_port_parent(ep);
250 if (!remote) {
251 dev_warn(dev, "endpoint %s not connected\n",
252 ep->full_name);
253 of_node_put(ep);
254 return -ENODEV;
255 }
226 of_node_put(ep); 256 of_node_put(ep);
227 if (remote) { 257
228 imxpd->panel = of_drm_find_panel(remote); 258 imxpd->panel = of_drm_find_panel(remote);
229 of_node_put(remote); 259 if (imxpd->panel) {
260 dev_dbg(dev, "found panel %s\n", remote->full_name);
261 } else {
262 imxpd->bridge = of_drm_find_bridge(remote);
263 if (imxpd->bridge)
264 dev_dbg(dev, "found bridge %s\n",
265 remote->full_name);
230 } 266 }
231 if (!imxpd->panel) 267 if (!imxpd->panel && !imxpd->bridge) {
268 dev_dbg(dev, "waiting for panel or bridge %s\n",
269 remote->full_name);
270 of_node_put(remote);
232 return -EPROBE_DEFER; 271 return -EPROBE_DEFER;
272 }
273 of_node_put(remote);
233 } 274 }
234 275
235 imxpd->dev = dev; 276 imxpd->dev = dev;