GNU Linux-libre 4.14.251-gnu1
[releases.git] / drivers / gpu / drm / rcar-du / rcar_du_encoder.c
1 /*
2  * rcar_du_encoder.c  --  R-Car Display Unit Encoder
3  *
4  * Copyright (C) 2013-2014 Renesas Electronics Corporation
5  *
6  * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  */
13
14 #include <linux/export.h>
15
16 #include <drm/drmP.h>
17 #include <drm/drm_crtc.h>
18 #include <drm/drm_crtc_helper.h>
19 #include <drm/drm_panel.h>
20
21 #include "rcar_du_drv.h"
22 #include "rcar_du_encoder.h"
23 #include "rcar_du_kms.h"
24 #include "rcar_du_lvdscon.h"
25 #include "rcar_du_lvdsenc.h"
26
27 /* -----------------------------------------------------------------------------
28  * Encoder
29  */
30
31 static void rcar_du_encoder_disable(struct drm_encoder *encoder)
32 {
33         struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
34
35         if (renc->connector && renc->connector->panel) {
36                 drm_panel_disable(renc->connector->panel);
37                 drm_panel_unprepare(renc->connector->panel);
38         }
39
40         if (renc->lvds)
41                 rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, false);
42 }
43
44 static void rcar_du_encoder_enable(struct drm_encoder *encoder)
45 {
46         struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
47
48         if (renc->lvds)
49                 rcar_du_lvdsenc_enable(renc->lvds, encoder->crtc, true);
50
51         if (renc->connector && renc->connector->panel) {
52                 drm_panel_prepare(renc->connector->panel);
53                 drm_panel_enable(renc->connector->panel);
54         }
55 }
56
57 static int rcar_du_encoder_atomic_check(struct drm_encoder *encoder,
58                                         struct drm_crtc_state *crtc_state,
59                                         struct drm_connector_state *conn_state)
60 {
61         struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
62         struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
63         const struct drm_display_mode *mode = &crtc_state->mode;
64         struct drm_connector *connector = conn_state->connector;
65         struct drm_device *dev = encoder->dev;
66
67         /*
68          * Only panel-related encoder types require validation here, everything
69          * else is handled by the bridge drivers.
70          */
71         if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
72                 const struct drm_display_mode *panel_mode;
73
74                 if (list_empty(&connector->modes)) {
75                         dev_dbg(dev->dev, "encoder: empty modes list\n");
76                         return -EINVAL;
77                 }
78
79                 panel_mode = list_first_entry(&connector->modes,
80                                               struct drm_display_mode, head);
81
82                 /* We're not allowed to modify the resolution. */
83                 if (mode->hdisplay != panel_mode->hdisplay ||
84                     mode->vdisplay != panel_mode->vdisplay)
85                         return -EINVAL;
86
87                 /*
88                  * The flat panel mode is fixed, just copy it to the adjusted
89                  * mode.
90                  */
91                 drm_mode_copy(adjusted_mode, panel_mode);
92         }
93
94         if (renc->lvds)
95                 rcar_du_lvdsenc_atomic_check(renc->lvds, adjusted_mode);
96
97         return 0;
98 }
99
100 static void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
101                                      struct drm_crtc_state *crtc_state,
102                                      struct drm_connector_state *conn_state)
103 {
104         struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
105         struct drm_display_info *info = &conn_state->connector->display_info;
106         enum rcar_lvds_mode mode;
107
108         rcar_du_crtc_route_output(crtc_state->crtc, renc->output);
109
110         if (!renc->lvds) {
111                 /*
112                  * The DU driver creates connectors only for the outputs of the
113                  * internal LVDS encoders.
114                  */
115                 renc->connector = NULL;
116                 return;
117         }
118
119         renc->connector = to_rcar_connector(conn_state->connector);
120
121         if (!info->num_bus_formats || !info->bus_formats) {
122                 dev_err(encoder->dev->dev, "no LVDS bus format reported\n");
123                 return;
124         }
125
126         switch (info->bus_formats[0]) {
127         case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
128         case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
129                 mode = RCAR_LVDS_MODE_JEIDA;
130                 break;
131         case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
132                 mode = RCAR_LVDS_MODE_VESA;
133                 break;
134         default:
135                 dev_err(encoder->dev->dev,
136                         "unsupported LVDS bus format 0x%04x\n",
137                         info->bus_formats[0]);
138                 return;
139         }
140
141         if (info->bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
142                 mode |= RCAR_LVDS_MODE_MIRROR;
143
144         rcar_du_lvdsenc_set_mode(renc->lvds, mode);
145 }
146
147 static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
148         .atomic_mode_set = rcar_du_encoder_mode_set,
149         .disable = rcar_du_encoder_disable,
150         .enable = rcar_du_encoder_enable,
151         .atomic_check = rcar_du_encoder_atomic_check,
152 };
153
154 static const struct drm_encoder_funcs encoder_funcs = {
155         .destroy = drm_encoder_cleanup,
156 };
157
158 int rcar_du_encoder_init(struct rcar_du_device *rcdu,
159                          enum rcar_du_output output,
160                          struct device_node *enc_node,
161                          struct device_node *con_node)
162 {
163         struct rcar_du_encoder *renc;
164         struct drm_encoder *encoder;
165         struct drm_bridge *bridge = NULL;
166         int ret;
167
168         renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL);
169         if (renc == NULL)
170                 return -ENOMEM;
171
172         renc->output = output;
173         encoder = rcar_encoder_to_drm_encoder(renc);
174
175         switch (output) {
176         case RCAR_DU_OUTPUT_LVDS0:
177                 renc->lvds = rcdu->lvds[0];
178                 break;
179
180         case RCAR_DU_OUTPUT_LVDS1:
181                 renc->lvds = rcdu->lvds[1];
182                 break;
183
184         default:
185                 break;
186         }
187
188         if (enc_node) {
189                 dev_dbg(rcdu->dev, "initializing encoder %pOF for output %u\n",
190                         enc_node, output);
191
192                 /* Locate the DRM bridge from the encoder DT node. */
193                 bridge = of_drm_find_bridge(enc_node);
194                 if (!bridge) {
195                         ret = -EPROBE_DEFER;
196                         goto done;
197                 }
198         } else {
199                 dev_dbg(rcdu->dev,
200                         "initializing internal encoder for output %u\n",
201                         output);
202         }
203
204         ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
205                                DRM_MODE_ENCODER_NONE, NULL);
206         if (ret < 0)
207                 goto done;
208
209         drm_encoder_helper_add(encoder, &encoder_helper_funcs);
210
211         if (bridge) {
212                 /*
213                  * Attach the bridge to the encoder. The bridge will create the
214                  * connector.
215                  */
216                 ret = drm_bridge_attach(encoder, bridge, NULL);
217                 if (ret) {
218                         drm_encoder_cleanup(encoder);
219                         return ret;
220                 }
221         } else {
222                 /* There's no bridge, create the connector manually. */
223                 switch (output) {
224                 case RCAR_DU_OUTPUT_LVDS0:
225                 case RCAR_DU_OUTPUT_LVDS1:
226                         ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
227                         break;
228
229                 default:
230                         ret = -EINVAL;
231                         break;
232                 }
233         }
234
235 done:
236         if (ret < 0) {
237                 if (encoder->name)
238                         encoder->funcs->destroy(encoder);
239                 devm_kfree(rcdu->dev, renc);
240         }
241
242         return ret;
243 }