]>
Commit | Line | Data |
---|---|---|
637e6194 LP |
1 | /* |
2 | * R-Car Display Unit HDMI Encoder | |
3 | * | |
4 | * Copyright (C) 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/slab.h> | |
15 | ||
16 | #include <drm/drmP.h> | |
17 | #include <drm/drm_crtc.h> | |
18 | #include <drm/drm_crtc_helper.h> | |
637e6194 LP |
19 | |
20 | #include "rcar_du_drv.h" | |
21 | #include "rcar_du_encoder.h" | |
22 | #include "rcar_du_hdmienc.h" | |
5e433b63 | 23 | #include "rcar_du_lvdsenc.h" |
637e6194 LP |
24 | |
25 | struct rcar_du_hdmienc { | |
26 | struct rcar_du_encoder *renc; | |
58706b88 | 27 | bool enabled; |
637e6194 LP |
28 | }; |
29 | ||
30 | #define to_rcar_hdmienc(e) (to_rcar_encoder(e)->hdmi) | |
637e6194 | 31 | |
58706b88 | 32 | static void rcar_du_hdmienc_disable(struct drm_encoder *encoder) |
637e6194 LP |
33 | { |
34 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); | |
3dbf11e4 | 35 | |
58706b88 LP |
36 | if (hdmienc->renc->lvds) |
37 | rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc, | |
38 | false); | |
39 | ||
40 | hdmienc->enabled = false; | |
41 | } | |
42 | ||
43 | static void rcar_du_hdmienc_enable(struct drm_encoder *encoder) | |
44 | { | |
45 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); | |
637e6194 | 46 | |
58706b88 | 47 | if (hdmienc->renc->lvds) |
44ef7ed5 LP |
48 | rcar_du_lvdsenc_enable(hdmienc->renc->lvds, encoder->crtc, |
49 | true); | |
5e433b63 | 50 | |
58706b88 LP |
51 | hdmienc->enabled = true; |
52 | } | |
5e433b63 | 53 | |
ede7714f LP |
54 | static int rcar_du_hdmienc_atomic_check(struct drm_encoder *encoder, |
55 | struct drm_crtc_state *crtc_state, | |
56 | struct drm_connector_state *conn_state) | |
637e6194 | 57 | { |
5e433b63 | 58 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); |
ede7714f | 59 | struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode; |
637e6194 | 60 | |
5e433b63 | 61 | if (hdmienc->renc->lvds) |
d9829a32 LP |
62 | rcar_du_lvdsenc_atomic_check(hdmienc->renc->lvds, |
63 | adjusted_mode); | |
5e433b63 | 64 | |
1d926114 | 65 | return 0; |
637e6194 LP |
66 | } |
67 | ||
1d926114 | 68 | |
637e6194 LP |
69 | static void rcar_du_hdmienc_mode_set(struct drm_encoder *encoder, |
70 | struct drm_display_mode *mode, | |
71 | struct drm_display_mode *adjusted_mode) | |
72 | { | |
73 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); | |
637e6194 LP |
74 | |
75 | rcar_du_crtc_route_output(encoder->crtc, hdmienc->renc->output); | |
76 | } | |
77 | ||
78 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | |
637e6194 | 79 | .mode_set = rcar_du_hdmienc_mode_set, |
58706b88 LP |
80 | .disable = rcar_du_hdmienc_disable, |
81 | .enable = rcar_du_hdmienc_enable, | |
ede7714f | 82 | .atomic_check = rcar_du_hdmienc_atomic_check, |
637e6194 LP |
83 | }; |
84 | ||
85 | static void rcar_du_hdmienc_cleanup(struct drm_encoder *encoder) | |
86 | { | |
87 | struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder); | |
88 | ||
58706b88 LP |
89 | if (hdmienc->enabled) |
90 | rcar_du_hdmienc_disable(encoder); | |
637e6194 LP |
91 | |
92 | drm_encoder_cleanup(encoder); | |
637e6194 LP |
93 | } |
94 | ||
95 | static const struct drm_encoder_funcs encoder_funcs = { | |
96 | .destroy = rcar_du_hdmienc_cleanup, | |
97 | }; | |
98 | ||
99 | int rcar_du_hdmienc_init(struct rcar_du_device *rcdu, | |
100 | struct rcar_du_encoder *renc, struct device_node *np) | |
101 | { | |
102 | struct drm_encoder *encoder = rcar_encoder_to_drm_encoder(renc); | |
1d926114 | 103 | struct drm_bridge *bridge; |
637e6194 LP |
104 | struct rcar_du_hdmienc *hdmienc; |
105 | int ret; | |
106 | ||
107 | hdmienc = devm_kzalloc(rcdu->dev, sizeof(*hdmienc), GFP_KERNEL); | |
108 | if (hdmienc == NULL) | |
109 | return -ENOMEM; | |
110 | ||
1d926114 AT |
111 | /* Locate drm bridge from the hdmi encoder DT node */ |
112 | bridge = of_drm_find_bridge(np); | |
113 | if (!bridge) | |
637e6194 | 114 | return -EPROBE_DEFER; |
637e6194 LP |
115 | |
116 | ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs, | |
13a3d91f | 117 | DRM_MODE_ENCODER_TMDS, NULL); |
637e6194 | 118 | if (ret < 0) |
1d926114 | 119 | return ret; |
637e6194 LP |
120 | |
121 | drm_encoder_helper_add(encoder, &encoder_helper_funcs); | |
122 | ||
123 | renc->hdmi = hdmienc; | |
124 | hdmienc->renc = renc; | |
125 | ||
1d926114 AT |
126 | /* Link drm_bridge to encoder */ |
127 | bridge->encoder = encoder; | |
29986cc8 | 128 | encoder->bridge = bridge; |
1d926114 AT |
129 | |
130 | ret = drm_bridge_attach(rcdu->ddev, bridge); | |
131 | if (ret) { | |
132 | drm_encoder_cleanup(encoder); | |
133 | return ret; | |
134 | } | |
637e6194 | 135 | |
1d926114 | 136 | return 0; |
637e6194 | 137 | } |