]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blob - drivers/video/omap2/dsscomp/base.c
OMAPDSS:DSSCOMP: Ignore display resolution for WB source overlay
[android-sdk/kernel-video.git] / drivers / video / omap2 / dsscomp / base.c
1 /*
2  * linux/drivers/video/omap2/dsscomp/base.c
3  *
4  * DSS Composition basic operation support
5  *
6  * Copyright (C) 2011 Texas Instruments, Inc
7  * Author: Lajos Molnar <molnar@ti.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2 as published by
11  * the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
22 #include <linux/kernel.h>
24 #include <linux/notifier.h>
25 #include "../../../drivers/gpu/drm/omapdrm/omap_dmm_tiler.h"
27 #include <video/omapdss.h>
28 #include <video/dsscomp.h>
29 #include <plat/dsscomp.h>
31 #include "dsscomp.h"
33 int debug;
34 module_param(debug, int, 0644);
36 /* color formats supported - bitfield info is used for truncation logic */
37 static const struct color_info {
38         int a_ix, a_bt; /* bitfields */
39         int r_ix, r_bt;
40         int g_ix, g_bt;
41         int b_ix, b_bt;
42         int x_bt;
43         enum omap_color_mode mode;
44         const char *name;
45 } fmts[2][16] = { {
46         { 0,  0, 0,  0, 0,  0, 0, 0, 1, OMAP_DSS_COLOR_CLUT1, "BITMAP1" },
47         { 0,  0, 0,  0, 0,  0, 0, 0, 2, OMAP_DSS_COLOR_CLUT2, "BITMAP2" },
48         { 0,  0, 0,  0, 0,  0, 0, 0, 4, OMAP_DSS_COLOR_CLUT4, "BITMAP4" },
49         { 0,  0, 0,  0, 0,  0, 0, 0, 8, OMAP_DSS_COLOR_CLUT8, "BITMAP8" },
50         { 0,  0, 8,  4, 4,  4, 0, 4, 4, OMAP_DSS_COLOR_RGB12U, "xRGB12-4444" },
51         { 12, 4, 8,  4, 4,  4, 0, 4, 0, OMAP_DSS_COLOR_ARGB16, "ARGB16-4444" },
52         { 0,  0, 11, 5, 5,  6, 0, 5, 0, OMAP_DSS_COLOR_RGB16, "RGB16-565" },
53         { 15, 1, 10, 5, 5,  5, 0, 5, 0, OMAP_DSS_COLOR_ARGB16_1555,
54                                                                 "ARGB16-1555" },
55         { 0,  0, 16, 8, 8,  8, 0, 8, 8, OMAP_DSS_COLOR_RGB24U, "xRGB24-8888" },
56         { 0,  0, 16, 8, 8,  8, 0, 8, 0, OMAP_DSS_COLOR_RGB24P, "RGB24-888" },
57         { 0,  0, 12, 4, 8,  4, 4, 4, 4, OMAP_DSS_COLOR_RGBX16, "RGBx12-4444" },
58         { 0,  4, 12, 4, 8,  4, 4, 4, 0, OMAP_DSS_COLOR_RGBA16, "RGBA16-4444" },
59         { 24, 8, 16, 8, 8,  8, 0, 8, 0, OMAP_DSS_COLOR_ARGB32, "ARGB32-8888" },
60         { 0,  8, 24, 8, 16, 8, 8, 8, 0, OMAP_DSS_COLOR_RGBA32, "RGBA32-8888" },
61         { 0,  0, 24, 8, 16, 8, 8, 8, 8, OMAP_DSS_COLOR_RGBX32, "RGBx24-8888" },
62         { 0,  0, 10, 5, 5,  5, 0, 5, 1, OMAP_DSS_COLOR_XRGB16_1555,
63                                                                 "xRGB15-1555" },
64 }, {
65         { 0,  0, 0,  0, 0,  0, 0, 0, 12, OMAP_DSS_COLOR_NV12, "NV12" },
66         { 0,  0, 12, 4, 8,  4, 4, 4, 4, OMAP_DSS_COLOR_RGBX16, "RGBx12-4444" },
67         { 0,  4, 12, 4, 8,  4, 4, 4, 0, OMAP_DSS_COLOR_RGBA16, "RGBA16-4444" },
68         { 0,  0, 0,  0, 0,  0, 0, 0, 0, 0, "invalid" },
69         { 0,  0, 8,  4, 4,  4, 0, 4, 4, OMAP_DSS_COLOR_RGB12U, "xRGB12-4444" },
70         { 12, 4, 8,  4, 4,  4, 0, 4, 0, OMAP_DSS_COLOR_ARGB16, "ARGB16-4444" },
71         { 0,  0, 11, 5, 5,  6, 0, 5, 0, OMAP_DSS_COLOR_RGB16, "RGB16-565" },
72         { 15, 1, 10, 5, 5,  5, 0, 5, 0, OMAP_DSS_COLOR_ARGB16_1555,
73                                                                 "ARGB16-1555" },
74         { 0,  0, 16, 8, 8,  8, 0, 8, 8, OMAP_DSS_COLOR_RGB24U, "xRGB24-8888" },
75         { 0,  0, 16, 8, 8,  8, 0, 8, 0, OMAP_DSS_COLOR_RGB24P, "RGB24-888" },
76         { 0,  0, 0,  0, 0,  0, 0, 0, 16, OMAP_DSS_COLOR_YUV2, "YUYV" },
77         { 0,  0, 0,  0, 0,  0, 0, 0, 16, OMAP_DSS_COLOR_UYVY, "UYVY" },
78         { 24, 8, 16, 8, 8,  8, 0, 8, 0, OMAP_DSS_COLOR_ARGB32, "ARGB32-8888" },
79         { 0,  8, 24, 8, 16, 8, 8, 8, 0, OMAP_DSS_COLOR_RGBA32, "RGBA32-8888" },
80         { 0,  0, 24, 8, 16, 8, 8, 8, 8, OMAP_DSS_COLOR_RGBX32, "RGBx24-8888" },
81         { 0,  0, 10, 5, 5,  5, 0, 5, 1, OMAP_DSS_COLOR_XRGB16_1555,
82                                                                 "xRGB15-1555" },
83 } };
85 static const struct color_info *get_color_info(enum omap_color_mode mode)
86 {
87         int i;
88         for (i = 0; i < sizeof(fmts) / sizeof(fmts[0][0]); i++)
89                 if (fmts[0][i].mode == mode)
90                         return fmts[0] + i;
91         return NULL;
92 }
94 static int color_mode_to_bpp(enum omap_color_mode color_mode)
95 {
96         const struct color_info *ci = get_color_info(color_mode);
97         if (!ci)
98                 return 0;
100         return ci->a_bt + ci->r_bt + ci->g_bt + ci->b_bt + ci->x_bt;
103 #ifdef CONFIG_DEBUG_FS
104 const char *dsscomp_get_color_name(enum omap_color_mode m)
106         const struct color_info *ci = get_color_info(m);
107         return ci ? ci->name : NULL;
109 #endif
111 union rect {
112         struct {
113                 s32 x;
114                 s32 y;
115                 s32 w;
116                 s32 h;
117         };
118         struct {
119                 s32 xy[2];
120                 s32 wh[2];
121         };
122         struct dss2_rect_t r;
123 };
125 static int crop_to_rect(union rect *crop, union rect *win, union rect *vis,
126                                                 int rotation, int mirror)
128         int c, swap = rotation & 1;
130         /* align crop window with display coordinates */
131         if (swap)
132                 crop->y -= (crop->h = -crop->h);
133         if (rotation & 2)
134                 crop->xy[!swap] -= (crop->wh[!swap] = -crop->wh[!swap]);
135         if ((!mirror) ^ !(rotation & 2))
136                 crop->xy[swap] -= (crop->wh[swap] = -crop->wh[swap]);
138         for (c = 0; c < 2; c++) {
139                 /* see if complete buffer is outside the vis or it is
140                    fully cropped or scaled to 0 */
141                 if (win->wh[c] <= 0 || vis->wh[c] <= 0 ||
142                     win->xy[c] + win->wh[c] <= vis->xy[c] ||
143                     win->xy[c] >= vis->xy[c] + vis->wh[c] ||
144                     !crop->wh[c ^ swap])
145                         return -ENOENT;
147                 /* crop left/top */
148                 if (win->xy[c] < vis->xy[c]) {
149                         /* correction term */
150                         int a = (vis->xy[c] - win->xy[c]) *
151                                                 crop->wh[c ^ swap] / win->wh[c];
152                         crop->xy[c ^ swap] += a;
153                         crop->wh[c ^ swap] -= a;
154                         win->wh[c] -= vis->xy[c] - win->xy[c];
155                         win->xy[c] = vis->xy[c];
156                 }
157                 /* crop right/bottom */
158                 if (win->xy[c] + win->wh[c] > vis->xy[c] + vis->wh[c]) {
159                         crop->wh[c ^ swap] = crop->wh[c ^ swap] *
160                                 (vis->xy[c] + vis->wh[c] - win->xy[c]) /
161                                                                 win->wh[c];
162                         win->wh[c] = vis->xy[c] + vis->wh[c] - win->xy[c];
163                 }
165                 if (!crop->wh[c ^ swap] || !win->wh[c])
166                         return -ENOENT;
167         }
169         /* realign crop window to buffer coordinates */
170         if (rotation & 2)
171                 crop->xy[!swap] -= (crop->wh[!swap] = -crop->wh[!swap]);
172         if ((!mirror) ^ !(rotation & 2))
173                 crop->xy[swap] -= (crop->wh[swap] = -crop->wh[swap]);
174         if (swap)
175                 crop->y -= (crop->h = -crop->h);
176         return 0;
179 int set_dss_ovl_info(struct dss2_ovl_info *oi)
181         struct omap_overlay_info info;
182         struct omap_overlay *ovl;
183         struct dss2_ovl_cfg *cfg;
184         union rect crop, win, vis;
185         int c;
186         int bpp;
187         enum tiler_fmt fmt;
189         /* check overlay number */
190         if (!oi || oi->cfg.ix >= omap_dss_get_num_overlays())
191                 return -EINVAL;
192         cfg = &oi->cfg;
193         ovl = omap_dss_get_overlay(cfg->ix);
195         /* just in case there are new fields, we get the current info */
196         ovl->get_overlay_info(ovl, &info);
198         if (!cfg->enabled)
199                 goto done;
201         /* copied params */
202         info.zorder = cfg->zorder;
204         if (cfg->zonly)
205                 goto done;
207         info.global_alpha = cfg->global_alpha;
208         info.pre_mult_alpha = cfg->pre_mult_alpha;
209         info.wb_source = cfg->wb_source;
210         info.rotation = cfg->rotation;
211         info.mirror = cfg->mirror;
212         info.color_mode = cfg->color_mode;
214         /* crop to screen */
215         crop.r = cfg->crop;
216         win.r = cfg->win;
217         vis.x = vis.y = 0;
218         vis.w = ovl->manager->output->device->panel.timings.x_res;
219         vis.h = ovl->manager->output->device->panel.timings.y_res;
221         if (!info.wb_source)
222                 if (crop_to_rect(&crop, &win, &vis, cfg->rotation,
223                                                 cfg->mirror) || vis.w < 2)
224                         goto done;
226         /* adjust crop to UV pixel boundaries */
227         for (c = 0; c < (cfg->color_mode == OMAP_DSS_COLOR_NV12 ? 2 :
228                 (cfg->color_mode &
229                  (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) ? 1 : 0); c++) {
230                 /* keep the output window to avoid trembling edges */
231                 crop.wh[c] += crop.xy[c] & 1;   /* round down start */
232                 crop.xy[c] &= ~1;
233                 crop.wh[c] += crop.wh[c] & 1;   /* round up end */
235                 /*
236                  * Buffer is aligned on UV pixel boundaries, so no
237                  * worries about extending crop region.
238                  */
239         }
241         info.width  = crop.w;
242         info.height = crop.h;
243         if (cfg->rotation & 1)
244                 /* DISPC uses swapped height/width for 90/270 degrees */
245                 swap(info.width, info.height);
246         info.pos_x = win.x;
247         info.pos_y = win.y;
248         info.out_width = win.w;
249         info.out_height = win.h;
251         /* calculate addresses and cropping */
252         info.paddr = oi->ba;
253         info.p_uv_addr = (info.color_mode == OMAP_DSS_COLOR_NV12) ? oi->uv : 0;
255         /* check for TILER 2D buffer */
256         if (tiler_get_fmt(info.paddr, &fmt) && fmt >= TILFMT_8BIT &&
257                         fmt <= TILFMT_32BIT) {
258                 int bpp = 1 << (fmt - TILFMT_8BIT);
259                 struct tiler_view_t t;
261                 /* crop to top-left */
263                 /*
264                  * DSS supports YUV422 on 32-bit mode, but its technically
265                  * 2 bytes-per-pixel.
266                  * Also RGB24-888 is 3 bytes-per-pixel even though no
267                  * tiler pixel format matches this.
268                  */
269                 if (cfg->color_mode &
270                                 (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY))
271                         bpp = 2;
272                 else if (cfg->color_mode == OMAP_DSS_COLOR_RGB24P)
273                         bpp = 3;
275                 tilview_create(&t, info.paddr, cfg->width, cfg->height);
276                 info.paddr -= t.tsptr;
277                 tilview_crop(&t, 0, crop.y, cfg->width, crop.h);
278                 info.paddr += t.tsptr + bpp * crop.x;
280                 info.rotation_type = OMAP_DSS_ROT_TILER;
281                 info.screen_width = 0;
283                 /* for NV12 format also crop NV12 */
284                 if (info.color_mode == OMAP_DSS_COLOR_NV12) {
285                         tilview_create(&t, info.p_uv_addr,
286                                         cfg->width >> 1, cfg->height >> 1);
287                         info.p_uv_addr -= t.tsptr;
288                         tilview_crop(&t, 0, crop.y >> 1, cfg->width >> 1,
289                                                                 crop.h >> 1);
290                         info.p_uv_addr += t.tsptr + bpp * crop.x;
291                 }
292         } else {
293                 /* program tiler 1D as SDMA */
295                 int bpp = color_mode_to_bpp(cfg->color_mode);
296                 if (!bpp) {
297                         pr_warn("invalid color format %u for ovl%d\n",
298                                                 cfg->color_mode, cfg->ix);
299                         goto done;
300                 }
302                 info.screen_width = cfg->stride * 8 / (bpp == 12 ? 8 : bpp);
303                 info.paddr += crop.x * (bpp / 8) + crop.y * cfg->stride;
305                 /* for NV12 format also crop NV12 */
306                 if (info.color_mode == OMAP_DSS_COLOR_NV12)
307                         info.p_uv_addr += crop.x * (bpp / 8) +
308                                 (crop.y >> 1) * cfg->stride;
310                 /* no rotation on DMA buffer */
311                 if (cfg->rotation & 3 || cfg->mirror)
312                         return -EINVAL;
314                 info.rotation_type = OMAP_DSS_ROT_DMA;
315         }
317         info.max_x_decim = cfg->decim.max_x ? : 255;
318         info.max_y_decim = cfg->decim.max_y ? : 255;
319         info.min_x_decim = cfg->decim.min_x ? : 1;
320         info.min_y_decim = cfg->decim.min_y ? : 1;
321 #if 0
322         info.pic_height = cfg->height;
324         info.field = 0;
325         if (cfg->ilace & OMAP_DSS_ILACE_SEQ)
326                 info.field |= OMAP_FLAG_IBUF;
327         if (cfg->ilace & OMAP_DSS_ILACE_SWAP)
328                 info.field |= OMAP_FLAG_ISWAP;
329         /*
330          * Ignore OMAP_DSS_ILACE as there is no real support yet for
331          * interlaced interleaved vs progressive buffers
332          */
333         if (ovl->manager &&
334             ovl->manager->device &&
335             !strcmp(ovl->manager->device->name, "hdmi") &&
336             is_hdmi_interlaced())
337                 info.field |= OMAP_FLAG_IDEV;
339         info.out_wb = 0;
340 #endif
342         info.cconv = cfg->cconv;
344 done:
345         pr_debug("ovl%d: en=%d %x/%x ", ovl->id, ovl->is_enabled(ovl),
346                         info.paddr, info.p_uv_addr);
347         pr_debug("(%dx%d|%d) => ", info.width, info.height, info.screen_width);
348         pr_debug("(%dx%d) @ ", info.out_width, info.out_height);
349         pr_debug("(%d,%d) rot=%d ", info.pos_x, info.pos_y, info.rotation);
350         pr_debug("mir=%d col=%x z=%d ", info.mirror, info.color_mode,
351                         info.zorder);
352         pr_debug("al=%02x prem=%d\n", info.global_alpha, info.pre_mult_alpha);
353         /* set overlay info */
354         return ovl->set_overlay_info(ovl, &info);
357 void swap_rb_in_ovl_info(struct dss2_ovl_info *oi)
359         /* we need to swap YUV color matrix if we are swapping R and B */
360         if (oi->cfg.color_mode &
361             (OMAP_DSS_COLOR_NV12 | OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) {
362                 swap(oi->cfg.cconv.ry, oi->cfg.cconv.by);
363                 swap(oi->cfg.cconv.rcr, oi->cfg.cconv.bcr);
364                 swap(oi->cfg.cconv.rcb, oi->cfg.cconv.bcb);
365         }
368 struct omap_overlay_manager *find_dss_mgr(int display_ix)
370         struct omap_overlay_manager *mgr;
371         char name[32];
372         int i;
374         sprintf(name, "display%d", display_ix);
376         for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
377                 mgr = omap_dss_get_overlay_manager(i);
378                 if (mgr->output->device && !strcmp(name, dev_name(&mgr->output->device->dev)))
379                         return mgr;
380         }
381         return NULL;
384 int set_dss_mgr_info(struct dss2_mgr_info *mi, struct omapdss_ovl_cb *cb)
386         struct omap_overlay_manager_info info;
387         struct omap_overlay_manager *mgr;
389         if (!mi)
390                 return -EINVAL;
391         mgr = find_dss_mgr(mi->ix);
392         if (!mgr)
393                 return -EINVAL;
395         /* just in case there are new fields, we get the current info */
396         mgr->get_manager_info(mgr, &info);
398         /* we support alpha-enabled only if we have free zorder */
399         /* :FIXME: for now DSS has this as an ovl cap */
400         if (alpha_only) {
401                 if (!mi->alpha_blending)
402                         return -EINVAL;
403                 info.partial_alpha_enabled = false;
404         } else {
405                 info.partial_alpha_enabled = mi->alpha_blending;
406         }
408         info.default_color = mi->default_color;
409         info.trans_enabled = mi->trans_enabled && !mi->alpha_blending;
410         info.trans_key = mi->trans_key;
411         info.trans_key_type = mi->trans_key_type;
413         info.cpr_coefs = mi->cpr_coefs;
414         info.cpr_enable = mi->cpr_enabled;
415         info.cb = *cb;
417         return mgr->set_manager_info(mgr, &info);
420 void swap_rb_in_mgr_info(struct dss2_mgr_info *mi)
422         const struct omap_dss_cpr_coefs c = { 256, 0, 0, 0, 256, 0, 0, 0, 256 };
424         /* set default CPR */
425         if (!mi->cpr_enabled)
426                 mi->cpr_coefs = c;
427         mi->cpr_enabled = true;
429         /* swap red and blue */
430         swap(mi->cpr_coefs.rr, mi->cpr_coefs.br);
431         swap(mi->cpr_coefs.rg, mi->cpr_coefs.bg);
432         swap(mi->cpr_coefs.rb, mi->cpr_coefs.bb);
435 /*
436  * ===========================================================================
437  *                              DEBUG METHODS
438  * ===========================================================================
439  */
440 void dump_ovl_info(struct dsscomp_dev *cdev, struct dss2_ovl_info *oi)
442         struct dss2_ovl_cfg *c = &oi->cfg;
443         const struct color_info *ci;
445         if (!(debug & DEBUG_OVERLAYS) ||
446             !(debug & DEBUG_COMPOSITIONS))
447                 return;
449         ci = get_color_info(c->color_mode);
450         if (c->zonly) {
451                 dev_info(DEV(cdev), "ovl%d(%s z%d)\n", c->ix, c->enabled ?
452                                         "ON" : "off", c->zorder);
453                 return;
454         }
455         dev_info(DEV(cdev), "ovl%d(%s ", c->ix, c->enabled ? "ON" : "off");
456         dev_info(DEV(cdev), "z%d %s", c->zorder, ci ? (ci->name ? :
457                                         "(none)") : "(invalid)");
458         dev_info(DEV(cdev), "%s", c->pre_mult_alpha ? " premult" : "");
459         dev_info(DEV(cdev), "*%d%%", (c->global_alpha * 100 + 128) / 255);
460         dev_info(DEV(cdev), "%d*%d:%d,%d+", c->width, c->height, c->crop.x,
461                                         c->crop.y);
462         dev_info(DEV(cdev), "%d,%d rot%d", c->crop.w, c->crop.h, c->rotation);
463         dev_info(DEV(cdev), "%s => %d,", c->mirror ? "+mir" : "", c->win.x);
464         dev_info(DEV(cdev), "%d+%d,%d ", c->win.y, c->win.w, c->win.h);
465         dev_info(DEV(cdev), "%p/%p|%d)\n", (void *)oi->ba, (void *)oi->uv,
466                                         c->stride);
469 static void print_mgr_info(struct dsscomp_dev *cdev,
470                         struct dss2_mgr_info *mi)
472         pr_cont("(dis%d(%s) alpha=%d col=%08x ilace=%d) ",
473                 mi->ix,
474                 (mi->ix < cdev->num_displays && cdev->displays[mi->ix]) ?
475                 cdev->displays[mi->ix]->name : "NONE",
476                 mi->alpha_blending, mi->default_color,
477                 mi->interlaced);
480 void dump_comp_info(struct dsscomp_dev *cdev, struct dsscomp_setup_mgr_data *d,
481                         const char *phase)
483         if (!(debug & DEBUG_COMPOSITIONS))
484                 return;
486         dev_info(DEV(cdev), "[%p] %s: %c%c%c ",
487                  *phase == 'q' ? (void *)d->sync_id : d, phase,
488                  (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-',
489                  (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-',
490                  (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-');
491         print_mgr_info(cdev, &d->mgr);
492         pr_cont("n=%d\n", d->num_ovls);
495 void dump_total_comp_info(struct dsscomp_dev *cdev,
496                         struct dsscomp_setup_dispc_data *d,
497                         const char *phase)
499         int i;
501         if (!(debug & DEBUG_COMPOSITIONS))
502                 return;
504         dev_info(DEV(cdev), "[%p] ", *phase == 'q' ? (void *)d->sync_id : d);
505         dev_info(DEV(cdev), "%s: %c", phase,
506                         (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-');
507         dev_info(DEV(cdev), "%c",
508                         (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-');
509         dev_info(DEV(cdev), "%c ",
510                         (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-');
512         for (i = 0; i < d->num_mgrs && i < ARRAY_SIZE(d->mgrs); i++)
513                 print_mgr_info(cdev, d->mgrs + i);
514         pr_cont("n=%d\n", d->num_ovls);