aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/imx/parallel-display.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-12-15 18:52:01 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2014-12-15 18:52:01 -0500
commit988adfdffdd43cfd841df734664727993076d7cb (patch)
tree6794f7bba8f595500c2b7d33376ad6614adcfaf2 /drivers/gpu/drm/imx/parallel-display.c
parent26178ec11ef3c6c814bf16a0a2b9c2f7242e3c64 (diff)
parent4e0cd68115620bc3236ff4e58e4c073948629b41 (diff)
Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie: "Highlights: - AMD KFD driver merge This is the AMD HSA interface for exposing a lowlevel interface for GPGPU use. They have an open source userspace built on top of this interface, and the code looks as good as it was going to get out of tree. - Initial atomic modesetting work The need for an atomic modesetting interface to allow userspace to try and send a complete set of modesetting state to the driver has arisen, and been suffering from neglect this past year. No more, the start of the common code and changes for msm driver to use it are in this tree. Ongoing work to get the userspace ioctl finished and the code clean will probably wait until next kernel. - DisplayID 1.3 and tiled monitor exposed to userspace. Tiled monitor property is now exposed for userspace to make use of. - Rockchip drm driver merged. - imx gpu driver moved out of staging Other stuff: - core: panel - MIPI DSI + new panels. expose suggested x/y properties for virtual GPUs - i915: Initial Skylake (SKL) support gen3/4 reset work start of dri1/ums removal infoframe tracking fixes for lots of things. - nouveau: tegra k1 voltage support GM204 modesetting support GT21x memory reclocking work - radeon: CI dpm fixes GPUVM improvements Initial DPM fan control - rcar-du: HDMI support added removed some support for old boards slave encoder driver for Analog Devices adv7511 - exynos: Exynos4415 SoC support - msm: a4xx gpu support atomic helper conversion - tegra: iommu support universal plane support ganged-mode DSI support - sti: HDMI i2c improvements - vmwgfx: some late fixes. - qxl: use suggested x/y properties" * 'drm-next' of git://people.freedesktop.org/~airlied/linux: (969 commits) drm: sti: fix module compilation issue drm/i915: save/restore GMBUS freq across suspend/resume on gen4 drm: sti: correctly cleanup CRTC and planes drm: sti: add HQVDP plane drm: sti: add cursor plane drm: sti: enable auxiliary CRTC drm: sti: fix delay in VTG programming drm: sti: prepare sti_tvout to support auxiliary crtc drm: sti: use drm_crtc_vblank_{on/off} instead of drm_vblank_{on/off} drm: sti: fix hdmi avi infoframe drm: sti: remove event lock while disabling vblank drm: sti: simplify gdp code drm: sti: clear all mixer control drm: sti: remove gpio for HDMI hot plug detection drm: sti: allow to change hdmi ddc i2c adapter drm/doc: Document drm_add_modes_noedid() usage drm/i915: Remove '& 0xffff' from the mask given to WA_REG() drm/i915: Invert the mask and val arguments in wa_add() and WA_REG() drm: Zero out DRM object memory upon cleanup drm/i915/bdw: Fix the write setting up the WIZ hashing mode ...
Diffstat (limited to 'drivers/gpu/drm/imx/parallel-display.c')
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
new file mode 100644
index 000000000000..8a76a5c1c34b
--- /dev/null
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -0,0 +1,295 @@
1/*
2 * i.MX drm driver - parallel display implementation
3 *
4 * Copyright (C) 2012 Sascha Hauer, Pengutronix
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1301, USA.
19 */
20
21#include <linux/component.h>
22#include <linux/module.h>
23#include <drm/drmP.h>
24#include <drm/drm_fb_helper.h>
25#include <drm/drm_crtc_helper.h>
26#include <drm/drm_panel.h>
27#include <linux/videodev2.h>
28#include <video/of_display_timing.h>
29
30#include "imx-drm.h"
31
32#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector)
33#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder)
34
35struct imx_parallel_display {
36 struct drm_connector connector;
37 struct drm_encoder encoder;
38 struct device *dev;
39 void *edid;
40 int edid_len;
41 u32 interface_pix_fmt;
42 int mode_valid;
43 struct drm_display_mode mode;
44 struct drm_panel *panel;
45};
46
47static enum drm_connector_status imx_pd_connector_detect(
48 struct drm_connector *connector, bool force)
49{
50 return connector_status_connected;
51}
52
53static int imx_pd_connector_get_modes(struct drm_connector *connector)
54{
55 struct imx_parallel_display *imxpd = con_to_imxpd(connector);
56 struct device_node *np = imxpd->dev->of_node;
57 int num_modes = 0;
58
59 if (imxpd->panel && imxpd->panel->funcs &&
60 imxpd->panel->funcs->get_modes) {
61 num_modes = imxpd->panel->funcs->get_modes(imxpd->panel);
62 if (num_modes > 0)
63 return num_modes;
64 }
65
66 if (imxpd->edid) {
67 drm_mode_connector_update_edid_property(connector, imxpd->edid);
68 num_modes = drm_add_edid_modes(connector, imxpd->edid);
69 }
70
71 if (imxpd->mode_valid) {
72 struct drm_display_mode *mode = drm_mode_create(connector->dev);
73
74 if (!mode)
75 return -EINVAL;
76 drm_mode_copy(mode, &imxpd->mode);
77 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
78 drm_mode_probed_add(connector, mode);
79 num_modes++;
80 }
81
82 if (np) {
83 struct drm_display_mode *mode = drm_mode_create(connector->dev);
84
85 if (!mode)
86 return -EINVAL;
87 of_get_drm_display_mode(np, &imxpd->mode, OF_USE_NATIVE_MODE);
88 drm_mode_copy(mode, &imxpd->mode);
89 mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
90 drm_mode_probed_add(connector, mode);
91 num_modes++;
92 }
93
94 return num_modes;
95}
96
97static struct drm_encoder *imx_pd_connector_best_encoder(
98 struct drm_connector *connector)
99{
100 struct imx_parallel_display *imxpd = con_to_imxpd(connector);
101
102 return &imxpd->encoder;
103}
104
105static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode)
106{
107 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
108
109 if (mode != DRM_MODE_DPMS_ON)
110 drm_panel_disable(imxpd->panel);
111 else
112 drm_panel_enable(imxpd->panel);
113}
114
115static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder,
116 const struct drm_display_mode *mode,
117 struct drm_display_mode *adjusted_mode)
118{
119 return true;
120}
121
122static void imx_pd_encoder_prepare(struct drm_encoder *encoder)
123{
124 struct imx_parallel_display *imxpd = enc_to_imxpd(encoder);
125
126 imx_drm_panel_format(encoder, imxpd->interface_pix_fmt);
127}
128
129static void imx_pd_encoder_commit(struct drm_encoder *encoder)
130{
131}
132
133static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
134 struct drm_display_mode *mode,
135 struct drm_display_mode *adjusted_mode)
136{
137}
138
139static void imx_pd_encoder_disable(struct drm_encoder *encoder)
140{
141}
142
143static struct drm_connector_funcs imx_pd_connector_funcs = {
144 .dpms = drm_helper_connector_dpms,
145 .fill_modes = drm_helper_probe_single_connector_modes,
146 .detect = imx_pd_connector_detect,
147 .destroy = imx_drm_connector_destroy,
148};
149
150static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = {
151 .get_modes = imx_pd_connector_get_modes,
152 .best_encoder = imx_pd_connector_best_encoder,
153};
154
155static struct drm_encoder_funcs imx_pd_encoder_funcs = {
156 .destroy = imx_drm_encoder_destroy,
157};
158
159static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = {
160 .dpms = imx_pd_encoder_dpms,
161 .mode_fixup = imx_pd_encoder_mode_fixup,
162 .prepare = imx_pd_encoder_prepare,
163 .commit = imx_pd_encoder_commit,
164 .mode_set = imx_pd_encoder_mode_set,
165 .disable = imx_pd_encoder_disable,
166};
167
168static int imx_pd_register(struct drm_device *drm,
169 struct imx_parallel_display *imxpd)
170{
171 int ret;
172
173 ret = imx_drm_encoder_parse_of(drm, &imxpd->encoder,
174 imxpd->dev->of_node);
175 if (ret)
176 return ret;
177
178 /* set the connector's dpms to OFF so that
179 * drm_helper_connector_dpms() won't return
180 * immediately since the current state is ON
181 * at this point.
182 */
183 imxpd->connector.dpms = DRM_MODE_DPMS_OFF;
184
185 drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs);
186 drm_encoder_init(drm, &imxpd->encoder, &imx_pd_encoder_funcs,
187 DRM_MODE_ENCODER_NONE);
188
189 drm_connector_helper_add(&imxpd->connector,
190 &imx_pd_connector_helper_funcs);
191 drm_connector_init(drm, &imxpd->connector, &imx_pd_connector_funcs,
192 DRM_MODE_CONNECTOR_VGA);
193
194 if (imxpd->panel)
195 drm_panel_attach(imxpd->panel, &imxpd->connector);
196
197 drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder);
198
199 imxpd->connector.encoder = &imxpd->encoder;
200
201 return 0;
202}
203
204static int imx_pd_bind(struct device *dev, struct device *master, void *data)
205{
206 struct drm_device *drm = data;
207 struct device_node *np = dev->of_node;
208 struct device_node *panel_node;
209 const u8 *edidp;
210 struct imx_parallel_display *imxpd;
211 int ret;
212 const char *fmt;
213
214 imxpd = devm_kzalloc(dev, sizeof(*imxpd), GFP_KERNEL);
215 if (!imxpd)
216 return -ENOMEM;
217
218 edidp = of_get_property(np, "edid", &imxpd->edid_len);
219 if (edidp)
220 imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL);
221
222 ret = of_property_read_string(np, "interface-pix-fmt", &fmt);
223 if (!ret) {
224 if (!strcmp(fmt, "rgb24"))
225 imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24;
226 else if (!strcmp(fmt, "rgb565"))
227 imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565;
228 else if (!strcmp(fmt, "bgr666"))
229 imxpd->interface_pix_fmt = V4L2_PIX_FMT_BGR666;
230 else if (!strcmp(fmt, "lvds666"))
231 imxpd->interface_pix_fmt =
232 v4l2_fourcc('L', 'V', 'D', '6');
233 }
234
235 panel_node = of_parse_phandle(np, "fsl,panel", 0);
236 if (panel_node)
237 imxpd->panel = of_drm_find_panel(panel_node);
238
239 imxpd->dev = dev;
240
241 ret = imx_pd_register(drm, imxpd);
242 if (ret)
243 return ret;
244
245 dev_set_drvdata(dev, imxpd);
246
247 return 0;
248}
249
250static void imx_pd_unbind(struct device *dev, struct device *master,
251 void *data)
252{
253 struct imx_parallel_display *imxpd = dev_get_drvdata(dev);
254
255 imxpd->encoder.funcs->destroy(&imxpd->encoder);
256 imxpd->connector.funcs->destroy(&imxpd->connector);
257}
258
259static const struct component_ops imx_pd_ops = {
260 .bind = imx_pd_bind,
261 .unbind = imx_pd_unbind,
262};
263
264static int imx_pd_probe(struct platform_device *pdev)
265{
266 return component_add(&pdev->dev, &imx_pd_ops);
267}
268
269static int imx_pd_remove(struct platform_device *pdev)
270{
271 component_del(&pdev->dev, &imx_pd_ops);
272 return 0;
273}
274
275static const struct of_device_id imx_pd_dt_ids[] = {
276 { .compatible = "fsl,imx-parallel-display", },
277 { /* sentinel */ }
278};
279MODULE_DEVICE_TABLE(of, imx_pd_dt_ids);
280
281static struct platform_driver imx_pd_driver = {
282 .probe = imx_pd_probe,
283 .remove = imx_pd_remove,
284 .driver = {
285 .of_match_table = imx_pd_dt_ids,
286 .name = "imx-parallel-display",
287 },
288};
289
290module_platform_driver(imx_pd_driver);
291
292MODULE_DESCRIPTION("i.MX parallel display driver");
293MODULE_AUTHOR("Sascha Hauer, Pengutronix");
294MODULE_LICENSE("GPL");
295MODULE_ALIAS("platform:imx-parallel-display");