]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/gpu/drm/rcar-du/rcar_du_kms.c
drm: Renesas R-Car Display Unit DRM driver
[karo-tx-linux.git] / drivers / gpu / drm / rcar-du / rcar_du_kms.c
1 /*
2  * rcar_du_kms.c  --  R-Car Display Unit Mode Setting
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 #include <drm/drm_fb_cma_helper.h>
18 #include <drm/drm_gem_cma_helper.h>
19
20 #include "rcar_du_crtc.h"
21 #include "rcar_du_drv.h"
22 #include "rcar_du_kms.h"
23 #include "rcar_du_lvds.h"
24 #include "rcar_du_regs.h"
25 #include "rcar_du_vga.h"
26
27 /* -----------------------------------------------------------------------------
28  * Format helpers
29  */
30
31 static const struct rcar_du_format_info rcar_du_format_infos[] = {
32         {
33                 .fourcc = DRM_FORMAT_RGB565,
34                 .bpp = 16,
35                 .planes = 1,
36                 .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
37                 .edf = PnDDCR4_EDF_NONE,
38         }, {
39                 .fourcc = DRM_FORMAT_ARGB1555,
40                 .bpp = 16,
41                 .planes = 1,
42                 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
43                 .edf = PnDDCR4_EDF_NONE,
44         }, {
45                 .fourcc = DRM_FORMAT_XRGB1555,
46                 .bpp = 16,
47                 .planes = 1,
48                 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_ARGB,
49                 .edf = PnDDCR4_EDF_NONE,
50         }, {
51                 .fourcc = DRM_FORMAT_XRGB8888,
52                 .bpp = 32,
53                 .planes = 1,
54                 .pnmr = PnMR_SPIM_TP | PnMR_DDDF_16BPP,
55                 .edf = PnDDCR4_EDF_RGB888,
56         }, {
57                 .fourcc = DRM_FORMAT_ARGB8888,
58                 .bpp = 32,
59                 .planes = 1,
60                 .pnmr = PnMR_SPIM_ALP | PnMR_DDDF_16BPP,
61                 .edf = PnDDCR4_EDF_ARGB8888,
62         }, {
63                 .fourcc = DRM_FORMAT_UYVY,
64                 .bpp = 16,
65                 .planes = 1,
66                 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
67                 .edf = PnDDCR4_EDF_NONE,
68         }, {
69                 .fourcc = DRM_FORMAT_YUYV,
70                 .bpp = 16,
71                 .planes = 1,
72                 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
73                 .edf = PnDDCR4_EDF_NONE,
74         }, {
75                 .fourcc = DRM_FORMAT_NV12,
76                 .bpp = 12,
77                 .planes = 2,
78                 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
79                 .edf = PnDDCR4_EDF_NONE,
80         }, {
81                 .fourcc = DRM_FORMAT_NV21,
82                 .bpp = 12,
83                 .planes = 2,
84                 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
85                 .edf = PnDDCR4_EDF_NONE,
86         }, {
87                 /* In YUV 4:2:2, only NV16 is supported (NV61 isn't) */
88                 .fourcc = DRM_FORMAT_NV16,
89                 .bpp = 16,
90                 .planes = 2,
91                 .pnmr = PnMR_SPIM_TP_OFF | PnMR_DDDF_YC,
92                 .edf = PnDDCR4_EDF_NONE,
93         },
94 };
95
96 const struct rcar_du_format_info *rcar_du_format_info(u32 fourcc)
97 {
98         unsigned int i;
99
100         for (i = 0; i < ARRAY_SIZE(rcar_du_format_infos); ++i) {
101                 if (rcar_du_format_infos[i].fourcc == fourcc)
102                         return &rcar_du_format_infos[i];
103         }
104
105         return NULL;
106 }
107
108 /* -----------------------------------------------------------------------------
109  * Common connector and encoder functions
110  */
111
112 struct drm_encoder *
113 rcar_du_connector_best_encoder(struct drm_connector *connector)
114 {
115         struct rcar_du_connector *rcon = to_rcar_connector(connector);
116
117         return &rcon->encoder->encoder;
118 }
119
120 void rcar_du_encoder_mode_prepare(struct drm_encoder *encoder)
121 {
122 }
123
124 void rcar_du_encoder_mode_set(struct drm_encoder *encoder,
125                               struct drm_display_mode *mode,
126                               struct drm_display_mode *adjusted_mode)
127 {
128         struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
129
130         rcar_du_crtc_route_output(encoder->crtc, renc->output);
131 }
132
133 void rcar_du_encoder_mode_commit(struct drm_encoder *encoder)
134 {
135 }
136
137 /* -----------------------------------------------------------------------------
138  * Frame buffer
139  */
140
141 static struct drm_framebuffer *
142 rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
143                   struct drm_mode_fb_cmd2 *mode_cmd)
144 {
145         const struct rcar_du_format_info *format;
146
147         format = rcar_du_format_info(mode_cmd->pixel_format);
148         if (format == NULL) {
149                 dev_dbg(dev->dev, "unsupported pixel format %08x\n",
150                         mode_cmd->pixel_format);
151                 return ERR_PTR(-EINVAL);
152         }
153
154         if (mode_cmd->pitches[0] & 15 || mode_cmd->pitches[0] >= 8192) {
155                 dev_dbg(dev->dev, "invalid pitch value %u\n",
156                         mode_cmd->pitches[0]);
157                 return ERR_PTR(-EINVAL);
158         }
159
160         if (format->planes == 2) {
161                 if (mode_cmd->pitches[1] != mode_cmd->pitches[0]) {
162                         dev_dbg(dev->dev,
163                                 "luma and chroma pitches do not match\n");
164                         return ERR_PTR(-EINVAL);
165                 }
166         }
167
168         return drm_fb_cma_create(dev, file_priv, mode_cmd);
169 }
170
171 static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
172         .fb_create = rcar_du_fb_create,
173 };
174
175 int rcar_du_modeset_init(struct rcar_du_device *rcdu)
176 {
177         struct drm_device *dev = rcdu->ddev;
178         struct drm_encoder *encoder;
179         unsigned int i;
180         int ret;
181
182         drm_mode_config_init(rcdu->ddev);
183
184         rcdu->ddev->mode_config.min_width = 0;
185         rcdu->ddev->mode_config.min_height = 0;
186         rcdu->ddev->mode_config.max_width = 4095;
187         rcdu->ddev->mode_config.max_height = 2047;
188         rcdu->ddev->mode_config.funcs = &rcar_du_mode_config_funcs;
189
190         ret = rcar_du_plane_init(rcdu);
191         if (ret < 0)
192                 return ret;
193
194         for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i)
195                 rcar_du_crtc_create(rcdu, i);
196
197         rcdu->used_crtcs = 0;
198         rcdu->num_crtcs = i;
199
200         for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
201                 const struct rcar_du_encoder_data *pdata =
202                         &rcdu->pdata->encoders[i];
203
204                 if (pdata->output >= ARRAY_SIZE(rcdu->crtcs)) {
205                         dev_warn(rcdu->dev,
206                                  "encoder %u references unexisting output %u, skipping\n",
207                                  i, pdata->output);
208                         continue;
209                 }
210
211                 switch (pdata->encoder) {
212                 case RCAR_DU_ENCODER_VGA:
213                         rcar_du_vga_init(rcdu, &pdata->u.vga, pdata->output);
214                         break;
215
216                 case RCAR_DU_ENCODER_LVDS:
217                         rcar_du_lvds_init(rcdu, &pdata->u.lvds, pdata->output);
218                         break;
219
220                 default:
221                         break;
222                 }
223         }
224
225         /* Set the possible CRTCs and possible clones. All encoders can be
226          * driven by the CRTC associated with the output they're connected to,
227          * as well as by CRTC 0.
228          */
229         list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
230                 struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
231
232                 encoder->possible_crtcs = (1 << 0) | (1 << renc->output);
233                 encoder->possible_clones = 1 << 0;
234         }
235
236         ret = rcar_du_plane_register(rcdu);
237         if (ret < 0)
238                 return ret;
239
240         drm_kms_helper_poll_init(rcdu->ddev);
241
242         drm_helper_disable_unused_functions(rcdu->ddev);
243
244         return 0;
245 }