1 // SPDX-License-Identifier: GPL-2.0+
3 * rcar_du_encoder.c -- R-Car Display Unit Encoder
5 * Copyright (C) 2013-2014 Renesas Electronics Corporation
7 * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
10 #include <linux/export.h>
12 #include <drm/drm_bridge.h>
13 #include <drm/drm_crtc.h>
14 #include <drm/drm_modeset_helper_vtables.h>
15 #include <drm/drm_panel.h>
17 #include "rcar_du_drv.h"
18 #include "rcar_du_encoder.h"
19 #include "rcar_du_kms.h"
20 #include "rcar_lvds.h"
22 /* -----------------------------------------------------------------------------
26 static const struct drm_encoder_helper_funcs encoder_helper_funcs
= {
29 static const struct drm_encoder_funcs encoder_funcs
= {
30 .destroy
= drm_encoder_cleanup
,
33 static unsigned int rcar_du_encoder_count_ports(struct device_node
*node
)
35 struct device_node
*ports
;
36 struct device_node
*port
;
37 unsigned int num_ports
= 0;
39 ports
= of_get_child_by_name(node
, "ports");
41 ports
= of_node_get(node
);
43 for_each_child_of_node(ports
, port
) {
44 if (of_node_name_eq(port
, "port"))
53 int rcar_du_encoder_init(struct rcar_du_device
*rcdu
,
54 enum rcar_du_output output
,
55 struct device_node
*enc_node
)
57 struct rcar_du_encoder
*renc
;
58 struct drm_encoder
*encoder
;
59 struct drm_bridge
*bridge
;
62 renc
= devm_kzalloc(rcdu
->dev
, sizeof(*renc
), GFP_KERNEL
);
66 rcdu
->encoders
[output
] = renc
;
67 renc
->output
= output
;
68 encoder
= rcar_encoder_to_drm_encoder(renc
);
70 dev_dbg(rcdu
->dev
, "initializing encoder %pOF for output %u\n",
74 * Locate the DRM bridge from the DT node. For the DPAD outputs, if the
75 * DT node has a single port, assume that it describes a panel and
76 * create a panel bridge.
78 if ((output
== RCAR_DU_OUTPUT_DPAD0
||
79 output
== RCAR_DU_OUTPUT_DPAD1
) &&
80 rcar_du_encoder_count_ports(enc_node
) == 1) {
81 struct drm_panel
*panel
= of_drm_find_panel(enc_node
);
88 bridge
= devm_drm_panel_bridge_add_typed(rcdu
->dev
, panel
,
89 DRM_MODE_CONNECTOR_DPI
);
91 ret
= PTR_ERR(bridge
);
95 bridge
= of_drm_find_bridge(enc_node
);
103 * On Gen3 skip the LVDS1 output if the LVDS1 encoder is used as a
104 * companion for LVDS0 in dual-link mode.
106 if (rcdu
->info
->gen
>= 3 && output
== RCAR_DU_OUTPUT_LVDS1
) {
107 if (rcar_lvds_dual_link(bridge
)) {
113 ret
= drm_encoder_init(rcdu
->ddev
, encoder
, &encoder_funcs
,
114 DRM_MODE_ENCODER_NONE
, NULL
);
118 drm_encoder_helper_add(encoder
, &encoder_helper_funcs
);
121 * Attach the bridge to the encoder. The bridge will create the
124 ret
= drm_bridge_attach(encoder
, bridge
, NULL
);
126 drm_encoder_cleanup(encoder
);
133 encoder
->funcs
->destroy(encoder
);
134 devm_kfree(rcdu
->dev
, renc
);