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>
16 #include <drm/drm_simple_kms_helper.h>
18 #include "rcar_du_drv.h"
19 #include "rcar_du_encoder.h"
20 #include "rcar_du_kms.h"
21 #include "rcar_lvds.h"
23 /* -----------------------------------------------------------------------------
27 static unsigned int rcar_du_encoder_count_ports(struct device_node
*node
)
29 struct device_node
*ports
;
30 struct device_node
*port
;
31 unsigned int num_ports
= 0;
33 ports
= of_get_child_by_name(node
, "ports");
35 ports
= of_node_get(node
);
37 for_each_child_of_node(ports
, port
) {
38 if (of_node_name_eq(port
, "port"))
47 int rcar_du_encoder_init(struct rcar_du_device
*rcdu
,
48 enum rcar_du_output output
,
49 struct device_node
*enc_node
)
51 struct rcar_du_encoder
*renc
;
52 struct drm_encoder
*encoder
;
53 struct drm_bridge
*bridge
;
56 renc
= devm_kzalloc(rcdu
->dev
, sizeof(*renc
), GFP_KERNEL
);
60 rcdu
->encoders
[output
] = renc
;
61 renc
->output
= output
;
62 encoder
= rcar_encoder_to_drm_encoder(renc
);
64 dev_dbg(rcdu
->dev
, "initializing encoder %pOF for output %u\n",
68 * Locate the DRM bridge from the DT node. For the DPAD outputs, if the
69 * DT node has a single port, assume that it describes a panel and
70 * create a panel bridge.
72 if ((output
== RCAR_DU_OUTPUT_DPAD0
||
73 output
== RCAR_DU_OUTPUT_DPAD1
) &&
74 rcar_du_encoder_count_ports(enc_node
) == 1) {
75 struct drm_panel
*panel
= of_drm_find_panel(enc_node
);
82 bridge
= devm_drm_panel_bridge_add_typed(rcdu
->dev
, panel
,
83 DRM_MODE_CONNECTOR_DPI
);
85 ret
= PTR_ERR(bridge
);
89 bridge
= of_drm_find_bridge(enc_node
);
97 * On Gen3 skip the LVDS1 output if the LVDS1 encoder is used as a
98 * companion for LVDS0 in dual-link mode.
100 if (rcdu
->info
->gen
>= 3 && output
== RCAR_DU_OUTPUT_LVDS1
) {
101 if (rcar_lvds_dual_link(bridge
)) {
107 ret
= drm_simple_encoder_init(rcdu
->ddev
, encoder
,
108 DRM_MODE_ENCODER_NONE
);
113 * Attach the bridge to the encoder. The bridge will create the
116 ret
= drm_bridge_attach(encoder
, bridge
, NULL
, 0);
118 drm_encoder_cleanup(encoder
);
125 encoder
->funcs
->destroy(encoder
);
126 devm_kfree(rcdu
->dev
, renc
);