diff options
author | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-06-15 09:02:12 -0400 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> | 2013-08-09 17:17:43 -0400 |
commit | 6978f123776594b251d26dac9bcdf3ce8e9781c8 (patch) | |
tree | f33b49179d6fad67fd723b5c4bda8d5ef230200b /drivers/gpu/drm/rcar-du/rcar_du_encoder.c | |
parent | 9e8be27233c1e98b06edeb801640b1f96b09e466 (diff) |
drm/rcar-du: Merge LVDS and VGA encoder code
Create a single rcar_du_encoder structure that implements a KMS encoder.
The current implementation is straightforward and only configures CRTC
output routing.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Diffstat (limited to 'drivers/gpu/drm/rcar-du/rcar_du_encoder.c')
-rw-r--r-- | drivers/gpu/drm/rcar-du/rcar_du_encoder.c | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c new file mode 100644 index 000000000000..15a56433c80c --- /dev/null +++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c | |||
@@ -0,0 +1,148 @@ | |||
1 | /* | ||
2 | * rcar_du_encoder.c -- R-Car Display Unit Encoder | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas 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 <drm/drmP.h> | ||
15 | #include <drm/drm_crtc.h> | ||
16 | #include <drm/drm_crtc_helper.h> | ||
17 | |||
18 | #include "rcar_du_drv.h" | ||
19 | #include "rcar_du_encoder.h" | ||
20 | #include "rcar_du_kms.h" | ||
21 | #include "rcar_du_lvdscon.h" | ||
22 | #include "rcar_du_vgacon.h" | ||
23 | |||
24 | /* ----------------------------------------------------------------------------- | ||
25 | * Common connector functions | ||
26 | */ | ||
27 | |||
28 | struct drm_encoder * | ||
29 | rcar_du_connector_best_encoder(struct drm_connector *connector) | ||
30 | { | ||
31 | struct rcar_du_connector *rcon = to_rcar_connector(connector); | ||
32 | |||
33 | return &rcon->encoder->encoder; | ||
34 | } | ||
35 | |||
36 | /* ----------------------------------------------------------------------------- | ||
37 | * Encoder | ||
38 | */ | ||
39 | |||
40 | static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode) | ||
41 | { | ||
42 | } | ||
43 | |||
44 | static bool rcar_du_encoder_mode_fixup(struct drm_encoder *encoder, | ||
45 | const struct drm_display_mode *mode, | ||
46 | struct drm_display_mode *adjusted_mode) | ||
47 | { | ||
48 | const struct drm_display_mode *panel_mode; | ||
49 | struct drm_device *dev = encoder->dev; | ||
50 | struct drm_connector *connector; | ||
51 | bool found = false; | ||
52 | |||
53 | /* DAC encoders have currently no restriction on the mode. */ | ||
54 | if (encoder->encoder_type == DRM_MODE_ENCODER_DAC) | ||
55 | return true; | ||
56 | |||
57 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
58 | if (connector->encoder == encoder) { | ||
59 | found = true; | ||
60 | break; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | if (!found) { | ||
65 | dev_dbg(dev->dev, "mode_fixup: no connector found\n"); | ||
66 | return false; | ||
67 | } | ||
68 | |||
69 | if (list_empty(&connector->modes)) { | ||
70 | dev_dbg(dev->dev, "mode_fixup: empty modes list\n"); | ||
71 | return false; | ||
72 | } | ||
73 | |||
74 | panel_mode = list_first_entry(&connector->modes, | ||
75 | struct drm_display_mode, head); | ||
76 | |||
77 | /* We're not allowed to modify the resolution. */ | ||
78 | if (mode->hdisplay != panel_mode->hdisplay || | ||
79 | mode->vdisplay != panel_mode->vdisplay) | ||
80 | return false; | ||
81 | |||
82 | /* The flat panel mode is fixed, just copy it to the adjusted mode. */ | ||
83 | drm_mode_copy(adjusted_mode, panel_mode); | ||
84 | |||
85 | return true; | ||
86 | } | ||
87 | |||
88 | static void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder) | ||
89 | { | ||
90 | } | ||
91 | |||
92 | static void rcar_du_encoder_mode_commit(struct drm_encoder *encoder) | ||
93 | { | ||
94 | } | ||
95 | |||
96 | static void rcar_du_encoder_mode_set(struct drm_encoder *encoder, | ||
97 | struct drm_display_mode *mode, | ||
98 | struct drm_display_mode *adjusted_mode) | ||
99 | { | ||
100 | struct rcar_du_encoder *renc = to_rcar_encoder(encoder); | ||
101 | |||
102 | rcar_du_crtc_route_output(encoder->crtc, renc->output); | ||
103 | } | ||
104 | |||
105 | static const struct drm_encoder_helper_funcs encoder_helper_funcs = { | ||
106 | .dpms = rcar_du_encoder_dpms, | ||
107 | .mode_fixup = rcar_du_encoder_mode_fixup, | ||
108 | .prepare = rcar_du_encoder_mode_prepare, | ||
109 | .commit = rcar_du_encoder_mode_commit, | ||
110 | .mode_set = rcar_du_encoder_mode_set, | ||
111 | }; | ||
112 | |||
113 | static const struct drm_encoder_funcs encoder_funcs = { | ||
114 | .destroy = drm_encoder_cleanup, | ||
115 | }; | ||
116 | |||
117 | int rcar_du_encoder_init(struct rcar_du_device *rcdu, | ||
118 | enum rcar_du_encoder_type type, unsigned int output, | ||
119 | const struct rcar_du_encoder_data *data) | ||
120 | { | ||
121 | struct rcar_du_encoder *renc; | ||
122 | int ret; | ||
123 | |||
124 | renc = devm_kzalloc(rcdu->dev, sizeof(*renc), GFP_KERNEL); | ||
125 | if (renc == NULL) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | renc->output = output; | ||
129 | |||
130 | ret = drm_encoder_init(rcdu->ddev, &renc->encoder, &encoder_funcs, | ||
131 | type); | ||
132 | if (ret < 0) | ||
133 | return ret; | ||
134 | |||
135 | drm_encoder_helper_add(&renc->encoder, &encoder_helper_funcs); | ||
136 | |||
137 | switch (type) { | ||
138 | case RCAR_DU_ENCODER_LVDS: | ||
139 | return rcar_du_lvds_connector_init(rcdu, renc, | ||
140 | &data->u.lvds.panel); | ||
141 | |||
142 | case RCAR_DU_ENCODER_VGA: | ||
143 | return rcar_du_vga_connector_init(rcdu, renc); | ||
144 | |||
145 | default: | ||
146 | return -EINVAL; | ||
147 | } | ||
148 | } | ||