]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/kernel-video.git/blob - drivers/video/omap2/dsscomp/base.c
65db6e270a4148306dece10b551c22c39cde14e2
[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         info.force_1d = cfg->force_1d;
216         /* mflag for the overlay */
217         info.mflag_en = cfg->mflag_en;
219         /* crop to screen */
220         crop.r = cfg->crop;
221         win.r = cfg->win;
222         vis.x = vis.y = 0;
223         vis.w = ovl->manager->output->device->panel.timings.x_res;
224         vis.h = ovl->manager->output->device->panel.timings.y_res;
226         if (!info.wb_source)
227                 if (crop_to_rect(&crop, &win, &vis, cfg->rotation,
228                                                 cfg->mirror) || vis.w < 2)
229                         goto done;
231         /* adjust crop to UV pixel boundaries */
232         for (c = 0; c < (cfg->color_mode == OMAP_DSS_COLOR_NV12 ? 2 :
233                 (cfg->color_mode &
234                  (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) ? 1 : 0); c++) {
235                 /* keep the output window to avoid trembling edges */
236                 crop.wh[c] += crop.xy[c] & 1;   /* round down start */
237                 crop.xy[c] &= ~1;
238                 crop.wh[c] += crop.wh[c] & 1;   /* round up end */
240                 /*
241                  * Buffer is aligned on UV pixel boundaries, so no
242                  * worries about extending crop region.
243                  */
244         }
246         info.width  = crop.w;
247         info.height = crop.h;
248         if (cfg->rotation & 1)
249                 /* DISPC uses swapped height/width for 90/270 degrees */
250                 swap(info.width, info.height);
251         info.pos_x = win.x;
252         info.pos_y = win.y;
253         info.out_width = win.w;
254         info.out_height = win.h;
256         /* calculate addresses and cropping */
257         info.paddr = oi->ba;
258         info.p_uv_addr = (info.color_mode == OMAP_DSS_COLOR_NV12) ? oi->uv : 0;
260         /* check for TILER 2D buffer */
261         if (tiler_get_fmt(info.paddr, &fmt) && fmt >= TILFMT_8BIT &&
262                         fmt <= TILFMT_32BIT) {
263                 int bpp = 1 << (fmt - TILFMT_8BIT);
264                 struct tiler_view_t t;
266                 /* crop to top-left */
268                 /*
269                  * DSS supports YUV422 on 32-bit mode, but its technically
270                  * 2 bytes-per-pixel.
271                  * Also RGB24-888 is 3 bytes-per-pixel even though no
272                  * tiler pixel format matches this.
273                  */
274                 if (cfg->color_mode &
275                                 (OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY))
276                         bpp = 2;
277                 else if (cfg->color_mode == OMAP_DSS_COLOR_RGB24P)
278                         bpp = 3;
280                 tilview_create(&t, info.paddr, cfg->width, cfg->height);
281                 info.paddr -= t.tsptr;
282                 tilview_crop(&t, 0, crop.y, cfg->width, crop.h);
283                 info.paddr += t.tsptr + bpp * crop.x;
285                 info.rotation_type = OMAP_DSS_ROT_TILER;
286                 info.screen_width = 0;
288                 /* for NV12 format also crop NV12 */
289                 if (info.color_mode == OMAP_DSS_COLOR_NV12) {
290                         tilview_create(&t, info.p_uv_addr,
291                                         cfg->width >> 1, cfg->height >> 1);
292                         info.p_uv_addr -= t.tsptr;
293                         tilview_crop(&t, 0, crop.y >> 1, cfg->width >> 1,
294                                                                 crop.h >> 1);
295                         info.p_uv_addr += t.tsptr + bpp * crop.x;
296                 }
297         } else {
298                 /* program tiler 1D as SDMA */
300                 int bpp = color_mode_to_bpp(cfg->color_mode);
301                 if (!bpp) {
302                         pr_warn("invalid color format %u for ovl%d\n",
303                                                 cfg->color_mode, cfg->ix);
304                         goto done;
305                 }
307                 info.screen_width = cfg->stride * 8 / (bpp == 12 ? 8 : bpp);
308                 info.paddr += crop.x * (bpp / 8) + crop.y * cfg->stride;
310                 /* for NV12 format also crop NV12 */
311                 if (info.color_mode == OMAP_DSS_COLOR_NV12)
312                         info.p_uv_addr += crop.x * (bpp / 8) +
313                                 (crop.y >> 1) * cfg->stride;
315                 /* no rotation on DMA buffer */
316                 if (cfg->rotation & 3 || cfg->mirror)
317                         return -EINVAL;
319                 info.rotation_type = OMAP_DSS_ROT_DMA;
320         }
322         info.max_x_decim = cfg->decim.max_x ? : 255;
323         info.max_y_decim = cfg->decim.max_y ? : 255;
324         info.min_x_decim = cfg->decim.min_x ? : 1;
325         info.min_y_decim = cfg->decim.min_y ? : 1;
326 #if 0
327         info.pic_height = cfg->height;
329         info.field = 0;
330         if (cfg->ilace & OMAP_DSS_ILACE_SEQ)
331                 info.field |= OMAP_FLAG_IBUF;
332         if (cfg->ilace & OMAP_DSS_ILACE_SWAP)
333                 info.field |= OMAP_FLAG_ISWAP;
334         /*
335          * Ignore OMAP_DSS_ILACE as there is no real support yet for
336          * interlaced interleaved vs progressive buffers
337          */
338         if (ovl->manager &&
339             ovl->manager->device &&
340             !strcmp(ovl->manager->device->name, "hdmi") &&
341             is_hdmi_interlaced())
342                 info.field |= OMAP_FLAG_IDEV;
344         info.out_wb = 0;
345 #endif
347         info.cconv = cfg->cconv;
349 done:
350         pr_debug("ovl%d: en=%d %x/%x ", ovl->id, ovl->is_enabled(ovl),
351                         info.paddr, info.p_uv_addr);
352         pr_debug("(%dx%d|%d) => ", info.width, info.height, info.screen_width);
353         pr_debug("(%dx%d) @ ", info.out_width, info.out_height);
354         pr_debug("(%d,%d) rot=%d ", info.pos_x, info.pos_y, info.rotation);
355         pr_debug("mir=%d col=%x z=%d ", info.mirror, info.color_mode,
356                         info.zorder);
357         pr_debug("al=%02x prem=%d\n", info.global_alpha, info.pre_mult_alpha);
358         /* set overlay info */
359         return ovl->set_overlay_info(ovl, &info);
362 void swap_rb_in_ovl_info(struct dss2_ovl_info *oi)
364         /* we need to swap YUV color matrix if we are swapping R and B */
365         if (oi->cfg.color_mode &
366             (OMAP_DSS_COLOR_NV12 | OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_UYVY)) {
367                 swap(oi->cfg.cconv.ry, oi->cfg.cconv.by);
368                 swap(oi->cfg.cconv.rcr, oi->cfg.cconv.bcr);
369                 swap(oi->cfg.cconv.rcb, oi->cfg.cconv.bcb);
370         }
373 struct omap_overlay_manager *find_dss_mgr(int display_ix)
375         struct omap_overlay_manager *mgr;
376         char name[32];
377         int i;
379         sprintf(name, "display%d", display_ix);
381         for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) {
382                 mgr = omap_dss_get_overlay_manager(i);
383                 if (mgr->output->device && !strcmp(name, dev_name(&mgr->output->device->dev)))
384                         return mgr;
385         }
386         return NULL;
389 int set_dss_mgr_info(struct dss2_mgr_info *mi, struct omapdss_ovl_cb *cb)
391         struct omap_overlay_manager_info info;
392         struct omap_overlay_manager *mgr;
394         if (!mi)
395                 return -EINVAL;
396         mgr = find_dss_mgr(mi->ix);
397         if (!mgr)
398                 return -EINVAL;
400         /* just in case there are new fields, we get the current info */
401         mgr->get_manager_info(mgr, &info);
403         /* we support alpha-enabled only if we have free zorder */
404         /* :FIXME: for now DSS has this as an ovl cap */
405         if (alpha_only) {
406                 if (!mi->alpha_blending)
407                         return -EINVAL;
408                 info.partial_alpha_enabled = false;
409         } else {
410                 info.partial_alpha_enabled = mi->alpha_blending;
411         }
413         info.default_color = mi->default_color;
414         info.trans_enabled = mi->trans_enabled && !mi->alpha_blending;
415         info.trans_key = mi->trans_key;
416         info.trans_key_type = mi->trans_key_type;
418         info.cpr_coefs = mi->cpr_coefs;
419         info.cpr_enable = mi->cpr_enabled;
420         info.cb = *cb;
422         return mgr->set_manager_info(mgr, &info);
425 void swap_rb_in_mgr_info(struct dss2_mgr_info *mi)
427         const struct omap_dss_cpr_coefs c = { 256, 0, 0, 0, 256, 0, 0, 0, 256 };
429         /* set default CPR */
430         if (!mi->cpr_enabled)
431                 mi->cpr_coefs = c;
432         mi->cpr_enabled = true;
434         /* swap red and blue */
435         swap(mi->cpr_coefs.rr, mi->cpr_coefs.br);
436         swap(mi->cpr_coefs.rg, mi->cpr_coefs.bg);
437         swap(mi->cpr_coefs.rb, mi->cpr_coefs.bb);
440 /*
441  * ===========================================================================
442  *                              DEBUG METHODS
443  * ===========================================================================
444  */
445 void dump_ovl_info(struct dsscomp_dev *cdev, struct dss2_ovl_info *oi)
447         struct dss2_ovl_cfg *c = &oi->cfg;
448         const struct color_info *ci;
450         if (!(debug & DEBUG_OVERLAYS) ||
451             !(debug & DEBUG_COMPOSITIONS))
452                 return;
454         ci = get_color_info(c->color_mode);
455         if (c->zonly) {
456                 dev_info(DEV(cdev), "ovl%d(%s z%d)\n", c->ix, c->enabled ?
457                                         "ON" : "off", c->zorder);
458                 return;
459         }
460         dev_info(DEV(cdev), "ovl%d(%s ", c->ix, c->enabled ? "ON" : "off");
461         dev_info(DEV(cdev), "z%d %s", c->zorder, ci ? (ci->name ? :
462                                         "(none)") : "(invalid)");
463         dev_info(DEV(cdev), "%s", c->pre_mult_alpha ? " premult" : "");
464         dev_info(DEV(cdev), "*%d%%", (c->global_alpha * 100 + 128) / 255);
465         dev_info(DEV(cdev), "%d*%d:%d,%d+", c->width, c->height, c->crop.x,
466                                         c->crop.y);
467         dev_info(DEV(cdev), "%d,%d rot%d", c->crop.w, c->crop.h, c->rotation);
468         dev_info(DEV(cdev), "%s => %d,", c->mirror ? "+mir" : "", c->win.x);
469         dev_info(DEV(cdev), "%d+%d,%d ", c->win.y, c->win.w, c->win.h);
470         dev_info(DEV(cdev), "%p/%p|%d)\n", (void *)oi->ba, (void *)oi->uv,
471                                         c->stride);
474 static void print_mgr_info(struct dsscomp_dev *cdev,
475                         struct dss2_mgr_info *mi)
477         pr_cont("(dis%d(%s) alpha=%d col=%08x ilace=%d) ",
478                 mi->ix,
479                 (mi->ix < cdev->num_displays && cdev->displays[mi->ix]) ?
480                 cdev->displays[mi->ix]->name : "NONE",
481                 mi->alpha_blending, mi->default_color,
482                 mi->interlaced);
485 void dump_comp_info(struct dsscomp_dev *cdev, struct dsscomp_setup_mgr_data *d,
486                         const char *phase)
488         if (!(debug & DEBUG_COMPOSITIONS))
489                 return;
491         dev_info(DEV(cdev), "[%p] %s: %c%c%c ",
492                  *phase == 'q' ? (void *)d->sync_id : d, phase,
493                  (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-',
494                  (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-',
495                  (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-');
496         print_mgr_info(cdev, &d->mgr);
497         pr_cont("n=%d\n", d->num_ovls);
500 void dump_total_comp_info(struct dsscomp_dev *cdev,
501                         struct dsscomp_setup_dispc_data *d,
502                         const char *phase)
504         int i;
506         if (!(debug & DEBUG_COMPOSITIONS))
507                 return;
509         dev_info(DEV(cdev), "[%p] ", *phase == 'q' ? (void *)d->sync_id : d);
510         dev_info(DEV(cdev), "%s: %c", phase,
511                         (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-');
512         dev_info(DEV(cdev), "%c",
513                         (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-');
514         dev_info(DEV(cdev), "%c ",
515                         (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-');
517         for (i = 0; i < d->num_mgrs && i < ARRAY_SIZE(d->mgrs); i++)
518                 print_mgr_info(cdev, d->mgrs + i);
519         pr_cont("n=%d\n", d->num_ovls);