2 * rcar_du_encoder.c -- R-Car Display Unit Encoder
4 * Copyright (C) 2013-2014 Renesas Electronics Corporation
6 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
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.
14 #include <linux/export.h>
17 #include <drm/drm_crtc.h>
18 #include <drm/drm_crtc_helper.h>
19 #include <drm/drm_panel.h>
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"
27 /* -----------------------------------------------------------------------------
31 static void rcar_du_encoder_disable(struct drm_encoder
*encoder
)
33 struct rcar_du_encoder
*renc
= to_rcar_encoder(encoder
);
35 if (renc
->connector
&& renc
->connector
->panel
) {
36 drm_panel_disable(renc
->connector
->panel
);
37 drm_panel_unprepare(renc
->connector
->panel
);
41 rcar_du_lvdsenc_enable(renc
->lvds
, encoder
->crtc
, false);
44 static void rcar_du_encoder_enable(struct drm_encoder
*encoder
)
46 struct rcar_du_encoder
*renc
= to_rcar_encoder(encoder
);
49 rcar_du_lvdsenc_enable(renc
->lvds
, encoder
->crtc
, true);
51 if (renc
->connector
&& renc
->connector
->panel
) {
52 drm_panel_prepare(renc
->connector
->panel
);
53 drm_panel_enable(renc
->connector
->panel
);
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
)
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
;
68 * Only panel-related encoder types require validation here, everything
69 * else is handled by the bridge drivers.
71 if (connector
->connector_type
== DRM_MODE_CONNECTOR_LVDS
) {
72 const struct drm_display_mode
*panel_mode
;
74 if (list_empty(&connector
->modes
)) {
75 dev_dbg(dev
->dev
, "encoder: empty modes list\n");
79 panel_mode
= list_first_entry(&connector
->modes
,
80 struct drm_display_mode
, head
);
82 /* We're not allowed to modify the resolution. */
83 if (mode
->hdisplay
!= panel_mode
->hdisplay
||
84 mode
->vdisplay
!= panel_mode
->vdisplay
)
88 * The flat panel mode is fixed, just copy it to the adjusted
91 drm_mode_copy(adjusted_mode
, panel_mode
);
95 rcar_du_lvdsenc_atomic_check(renc
->lvds
, adjusted_mode
);
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
)
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
;
108 rcar_du_crtc_route_output(crtc_state
->crtc
, renc
->output
);
112 * The DU driver creates connectors only for the outputs of the
113 * internal LVDS encoders.
115 renc
->connector
= NULL
;
119 renc
->connector
= to_rcar_connector(conn_state
->connector
);
121 if (!info
->num_bus_formats
|| !info
->bus_formats
) {
122 dev_err(encoder
->dev
->dev
, "no LVDS bus format reported\n");
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
;
131 case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG
:
132 mode
= RCAR_LVDS_MODE_VESA
;
135 dev_err(encoder
->dev
->dev
,
136 "unsupported LVDS bus format 0x%04x\n",
137 info
->bus_formats
[0]);
141 if (info
->bus_flags
& DRM_BUS_FLAG_DATA_LSB_TO_MSB
)
142 mode
|= RCAR_LVDS_MODE_MIRROR
;
144 rcar_du_lvdsenc_set_mode(renc
->lvds
, mode
);
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
,
154 static const struct drm_encoder_funcs encoder_funcs
= {
155 .destroy
= drm_encoder_cleanup
,
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
)
163 struct rcar_du_encoder
*renc
;
164 struct drm_encoder
*encoder
;
165 struct drm_bridge
*bridge
= NULL
;
168 renc
= devm_kzalloc(rcdu
->dev
, sizeof(*renc
), GFP_KERNEL
);
172 renc
->output
= output
;
173 encoder
= rcar_encoder_to_drm_encoder(renc
);
176 case RCAR_DU_OUTPUT_LVDS0
:
177 renc
->lvds
= rcdu
->lvds
[0];
180 case RCAR_DU_OUTPUT_LVDS1
:
181 renc
->lvds
= rcdu
->lvds
[1];
189 dev_dbg(rcdu
->dev
, "initializing encoder %pOF for output %u\n",
192 /* Locate the DRM bridge from the encoder DT node. */
193 bridge
= of_drm_find_bridge(enc_node
);
200 "initializing internal encoder for output %u\n",
204 ret
= drm_encoder_init(rcdu
->ddev
, encoder
, &encoder_funcs
,
205 DRM_MODE_ENCODER_NONE
, NULL
);
209 drm_encoder_helper_add(encoder
, &encoder_helper_funcs
);
213 * Attach the bridge to the encoder. The bridge will create the
216 ret
= drm_bridge_attach(encoder
, bridge
, NULL
);
218 drm_encoder_cleanup(encoder
);
222 /* There's no bridge, create the connector manually. */
224 case RCAR_DU_OUTPUT_LVDS0
:
225 case RCAR_DU_OUTPUT_LVDS1
:
226 ret
= rcar_du_lvds_connector_init(rcdu
, renc
, con_node
);
238 encoder
->funcs
->destroy(encoder
);
239 devm_kfree(rcdu
->dev
, renc
);