diff options
author | Lajos Molnar <molnar@ti.com> | 2011-07-30 14:22:27 -0500 |
---|---|---|
committer | Erik Gilling <konkers@android.com> | 2011-08-24 12:04:35 -0700 |
commit | 577b782ec3341998c125d907b76bd9fdc3d844da (patch) | |
tree | 2882560233b2485eaaeede2bb8da0c2c848083f1 | |
parent | c461439981073241065be7ff72610ce1faa2a3bd (diff) | |
download | kernel_samsung_tuna-577b782ec3341998c125d907b76bd9fdc3d844da.zip kernel_samsung_tuna-577b782ec3341998c125d907b76bd9fdc3d844da.tar.gz kernel_samsung_tuna-577b782ec3341998c125d907b76bd9fdc3d844da.tar.bz2 |
OMAP:OMAPLFB/OMAPDSS: Added support for cloning
Changed gralloc_queue to use a struct that specifies all displays
Cloned buffers are not referenced in multiple slots of the buffers
array for Post2. Instead cloned overlays refer to the index of
the buffer to be cloned.
Overlays that were specified in prior compositions, but are no
longer specified will be blanked (including overlays on managers
that are no longer specified.)
Also changed to return and error instead of BUG() if receiving
invalid struct in ProcessFlipV2.
Change-Id: Icbed3e43d4871781ffc5124fae77fb813f8b8dca
Signed-off-by: Lajos Molnar <molnar@ti.com>
-rw-r--r-- | drivers/gpu/pvr/omaplfb/omaplfb_displayclass.c | 30 | ||||
-rw-r--r-- | drivers/gpu/pvr/omaplfb/omaplfb_linux.c | 3 | ||||
-rw-r--r-- | drivers/video/omap2/dsscomp/base.c | 6 | ||||
-rw-r--r-- | drivers/video/omap2/dsscomp/gralloc.c | 159 | ||||
-rw-r--r-- | drivers/video/omap2/dsscomp/queue.c | 1 | ||||
-rw-r--r-- | include/video/dsscomp.h | 71 |
6 files changed, 175 insertions, 95 deletions
diff --git a/drivers/gpu/pvr/omaplfb/omaplfb_displayclass.c b/drivers/gpu/pvr/omaplfb/omaplfb_displayclass.c index 79a00e5..6d802f3 100644 --- a/drivers/gpu/pvr/omaplfb/omaplfb_displayclass.c +++ b/drivers/gpu/pvr/omaplfb/omaplfb_displayclass.c @@ -422,7 +422,6 @@ static PVRSRV_ERROR CreateDCSwapChain(IMG_HANDLE hDevice, goto ExitUnLock; } - UNREFERENCED_PARAMETER(ui32Flags); #if defined(PVR_OMAPFB3_UPDATE_MODE) @@ -820,7 +819,18 @@ static IMG_BOOL ProcessFlipV2(IMG_HANDLE hCmdCookie, struct tiler_pa_info *apsTilerPAs[5]; IMG_UINT32 i, k; - BUG_ON(uiDssDataLength != sizeof(*psDssData)); + if(uiDssDataLength != sizeof(*psDssData)) + { + WARN(1, "invalid size of private data (%d vs %d)", + uiDssDataLength, sizeof(*psDssData)); + return IMG_FALSE; + } + + if(psDssData->num_ovls == 0 || ui32NumMemInfos == 0) + { + WARN(1, "must have at least one layer"); + return IMG_FALSE; + } for(i = k = 0; i < ui32NumMemInfos && i < ARRAY_SIZE(apsTilerPAs); i++, k++) { @@ -870,12 +880,19 @@ static IMG_BOOL ProcessFlipV2(IMG_HANDLE hCmdCookie, (u32)LinuxMemAreaToCpuPAddr(psLinuxMemArea, j << PAGE_SHIFT).uiAddr; } - + /* need base address for in-page offset */ psDssData->ovls[k].ba = (u32)ppsMemInfos[i]->pvLinAddrKM; apsTilerPAs[k] = psTilerInfo; } - BUG_ON(psDssData->num_ovls == 0); + /* set up cloned layer addresses (but don't duplicate tiler_pas) */ + for(i = k; i < psDssData->num_ovls && i < ARRAY_SIZE(apsTilerPAs); i++) + { + unsigned int ix = psDssData->ovls[i].ba; + apsTilerPAs[i] = apsTilerPAs[ix]; + psDssData->ovls[i].ba = psDssData->ovls[ix].ba; + psDssData->ovls[i].uv = psDssData->ovls[ix].uv; + } dsscomp_gralloc_queue(psDssData, apsTilerPAs, (void *)psDevInfo->sPVRJTable.pfnPVRSRVCmdComplete, @@ -895,14 +912,9 @@ static IMG_BOOL ProcessFlip(IMG_HANDLE hCmdCookie, IMG_UINT32 ui32DataSize, IMG_VOID *pvData) { - DISPLAYCLASS_FLIP_COMMAND2 *psFlipCmd2; DISPLAYCLASS_FLIP_COMMAND *psFlipCmd; OMAPLFB_DEVINFO *psDevInfo; - struct dsscomp_setup_mgr_data *dss_data; - struct tiler_pa_info *tiler_pas[5]; - unsigned long i; - if(!hCmdCookie || !pvData) { return IMG_FALSE; diff --git a/drivers/gpu/pvr/omaplfb/omaplfb_linux.c b/drivers/gpu/pvr/omaplfb/omaplfb_linux.c index 865c7d0..f2d2847 100644 --- a/drivers/gpu/pvr/omaplfb/omaplfb_linux.c +++ b/drivers/gpu/pvr/omaplfb/omaplfb_linux.c @@ -278,7 +278,8 @@ void OMAPLFBFlip(OMAPLFB_DEVINFO *psDevInfo, OMAPLFB_BUFFER *psBuffer) struct fb_fix_screeninfo sFBFix = psDevInfo->psLINFBInfo->fix; struct dsscomp_setup_dispc_data d = { .num_ovls = 1, - .mgr.alpha_blending = 1, + .num_mgrs = 1, + .mgrs[0].alpha_blending = 1, .ovls[0] = { .cfg = { .win.w = sFBVar.xres, diff --git a/drivers/video/omap2/dsscomp/base.c b/drivers/video/omap2/dsscomp/base.c index b54fc50..7d208e1 100644 --- a/drivers/video/omap2/dsscomp/base.c +++ b/drivers/video/omap2/dsscomp/base.c @@ -478,6 +478,8 @@ void dump_total_comp_info(struct dsscomp_dev *cdev, struct dsscomp_setup_dispc_data *d, const char *phase) { + int i; + if (!(debug & DEBUG_COMPOSITIONS)) return; @@ -486,6 +488,8 @@ void dump_total_comp_info(struct dsscomp_dev *cdev, (d->mode & DSSCOMP_SETUP_MODE_APPLY) ? 'A' : '-', (d->mode & DSSCOMP_SETUP_MODE_DISPLAY) ? 'D' : '-', (d->mode & DSSCOMP_SETUP_MODE_CAPTURE) ? 'C' : '-'); - print_mgr_info(cdev, &d->mgr); + + for (i = 0; i < d->num_mgrs && i < ARRAY_SIZE(d->mgrs); i++) + print_mgr_info(cdev, d->mgrs + i); printk("n=%d\n", d->num_ovls); } diff --git a/drivers/video/omap2/dsscomp/gralloc.c b/drivers/video/omap2/dsscomp/gralloc.c index fe3e2a2..e2a9515 100644 --- a/drivers/video/omap2/dsscomp/gralloc.c +++ b/drivers/video/omap2/dsscomp/gralloc.c @@ -37,7 +37,7 @@ struct dsscomp_gralloc_t { /* queued gralloc compositions */ static LIST_HEAD(flip_queue); -static u32 ovl_set_mask; +static u32 ovl_use_mask[MAX_MANAGERS]; static void unpin_tiler_blocks(struct list_head *slots) { @@ -127,10 +127,15 @@ int dsscomp_gralloc_queue(struct dsscomp_setup_dispc_data *d, int r = 0; struct omap_dss_device *dev; struct omap_overlay_manager *mgr; - dsscomp_t comp; - u32 ovl_new_set_mask = 0; + dsscomp_t comp[MAX_MANAGERS]; + u32 ovl_new_use_mask[MAX_MANAGERS]; + u32 mgr_set_mask = 0; + u32 ovl_set_mask = 0; + + u32 channels[ARRAY_SIZE(d->mgrs)], ch; int skip; struct dsscomp_gralloc_t *gsync; + struct dss2_rect_t win = { .w = 0 }; /* reserve tiler areas if not already done so */ dsscomp_gralloc_init(cdev); @@ -162,47 +167,100 @@ int dsscomp_gralloc_queue(struct dsscomp_setup_dispc_data *d, mutex_unlock(&mtx); + d->num_mgrs = min(d->num_mgrs, (u16) ARRAY_SIZE(d->mgrs)); + d->num_ovls = min(d->num_ovls, (u16) ARRAY_SIZE(d->ovls)); + + memset(comp, 0, sizeof(comp)); + memset(ovl_new_use_mask, 0, sizeof(ovl_new_use_mask)); + if (skip) - goto skip_mgr; + goto skip_comp; + + d->mode = DSSCOMP_SETUP_DISPLAY; + + /* mark managers we are using */ + for (i = 0; i < d->num_mgrs; i++) { + /* verify display is valid & connected, ignore if not */ + if (d->mgrs[i].ix >= cdev->num_displays) + continue; + dev = cdev->displays[d->mgrs[i].ix]; + if (!dev) { + dev_warn(DEV(cdev), "failed to get display%d\n", + d->mgrs[i].ix); + continue; + } + mgr = dev->manager; + if (!mgr) { + dev_warn(DEV(cdev), "no manager for display%d\n", + d->mgrs[i].ix); + continue; + } + channels[i] = ch = mgr->id; + mgr_set_mask |= 1 << ch; - /* verify display is valid and connected */ - if (d->mgr.ix >= cdev->num_displays) { - r = -EINVAL; - goto skip_mgr; - } - dev = cdev->displays[d->mgr.ix]; - if (!dev) { - r = -EINVAL; - goto skip_mgr; - } - mgr = dev->manager; - if (!mgr) { - r = -ENODEV; - goto skip_mgr; + /* swap red & blue if requested */ + if (d->mgrs[i].swap_rb) + swap_rb_in_mgr_info(d->mgrs + i); } - comp = dsscomp_new(mgr); - if (IS_ERR(comp)) { - r = PTR_ERR(comp); - goto skip_mgr; - } + /* create dsscomp objects for set managers (including active ones) */ + for (ch = 0; ch < MAX_MANAGERS; ch++) { + if (!(mgr_set_mask & (1 << ch)) && !ovl_use_mask[ch]) + continue; - comp->frm.mode = DSSCOMP_SETUP_DISPLAY; - comp->must_apply = true; + mgr = cdev->mgrs[ch]; - /* swap red & blue if requested */ - if (d->mgr.swap_rb) { - swap_rb_in_mgr_info(&d->mgr); - for (i = 0; i < d->num_ovls; i++) - swap_rb_in_ovl_info(d->ovls + i); + comp[ch] = dsscomp_new(mgr); + if (IS_ERR(comp[ch])) { + comp[ch] = NULL; + dev_warn(DEV(cdev), "failed to get composition on %s\n", + mgr->name); + continue; + } + + /* set basic manager information for blanked managers */ + if (!(mgr_set_mask & (1 << ch))) { + struct dss2_mgr_info mi = { + .alpha_blending = true, + .ix = comp[ch]->frm.mgr.ix, + }; + dsscomp_set_mgr(comp[ch], &mi); + } + + comp[ch]->must_apply = true; + r = dsscomp_setup(comp[ch], d->mode, win); + if (r) + dev_err(DEV(cdev), "failed to setup comp (%d)\n", r); + } + + /* configure manager data from gralloc composition */ + for (i = 0; i < d->num_mgrs; i++) { + ch = channels[i]; + r = dsscomp_set_mgr(comp[ch], d->mgrs + i); + if (r) + dev_err(DEV(cdev), "failed to set mgr%d (%d)\n", ch, r); } /* NOTE: none of the dsscomp sets should fail as composition is new */ - r = dsscomp_set_mgr(comp, &d->mgr); - if (r) - dev_err(DEV(cdev), "failed to set mgr (%d)\n", r); for (i = 0; i < d->num_ovls; i++) { struct dss2_ovl_info *oi = d->ovls + i; + u32 mgr_ix = oi->cfg.mgr_ix; + + /* verify manager index */ + if (mgr_ix >= d->num_mgrs) { + dev_err(DEV(cdev), "invalid manager for ovl%d\n", + oi->cfg.ix); + continue; + } + ch = channels[mgr_ix]; + + /* skip overlays on compositions we could not create */ + if (!comp[ch]) + continue; + + /* swap red & blue if requested */ + if (d->mgrs[mgr_ix].swap_rb) + swap_rb_in_ovl_info(d->ovls + i); /* map non-TILER buffers to 1D */ if (pas[i] && oi->cfg.enabled) { @@ -228,43 +286,44 @@ int dsscomp_gralloc_queue(struct dsscomp_setup_dispc_data *d, } if (oi->cfg.enabled) - ovl_new_set_mask |= 1 << oi->cfg.ix; + ovl_new_use_mask[ch] |= 1 << oi->cfg.ix; - r = dsscomp_set_ovl(comp, oi); + r = dsscomp_set_ovl(comp[ch], oi); if (r) dev_err(DEV(cdev), "failed to set ovl%d (%d)\n", oi->cfg.ix, r); + else + ovl_set_mask |= 1 << oi->cfg.ix; } - r = dsscomp_setup(comp, d->mode, d->win); - if (r) - dev_err(DEV(cdev), "failed to setup comp (%d)\n", r); - - if (r) { - dsscomp_drop(comp); - } else { + for (ch = 0; ch < MAX_MANAGERS; ch++) { /* disable all overlays not specifically set from prior frame */ - u32 mask = ovl_set_mask & ~ovl_new_set_mask; + u32 mask = ovl_use_mask[ch] & ~ovl_set_mask; + + if (!comp[ch]) + continue; + while (mask) { struct dss2_ovl_info oi = { .cfg.zonly = true, .cfg.enabled = false, .cfg.ix = fls(mask) - 1, }; - dsscomp_set_ovl(comp, &oi); + dsscomp_set_ovl(comp[ch], &oi); mask &= ~(1 << oi.cfg.ix); } - comp->extra_cb = dsscomp_gralloc_cb; - comp->extra_cb_data = gsync; + /* associate dsscomp objects with this gralloc composition */ + comp[ch]->extra_cb = dsscomp_gralloc_cb; + comp[ch]->extra_cb_data = gsync; atomic_inc(&gsync->refs); - r = dsscomp_delayed_apply(comp); + r = dsscomp_delayed_apply(comp[ch]); if (r) dev_err(DEV(cdev), "failed to apply comp (%d)\n", r); else - ovl_set_mask = ovl_new_set_mask; + ovl_use_mask[ch] = ovl_new_use_mask[ch]; } -skip_mgr: +skip_comp: /* release sync object ref - this completes unapplied compositions */ dsscomp_gralloc_cb(gsync, DSS_COMPLETION_RELEASED); @@ -284,7 +343,7 @@ static void dsscomp_early_suspend_cb(void *data, int status) static void dsscomp_early_suspend(struct early_suspend *h) { struct dsscomp_setup_dispc_data d = { - .mgr.alpha_blending = 1, + .num_mgrs = 0, }; int err; diff --git a/drivers/video/omap2/dsscomp/queue.c b/drivers/video/omap2/dsscomp/queue.c index 0f8c8a6..b6f625b 100644 --- a/drivers/video/omap2/dsscomp/queue.c +++ b/drivers/video/omap2/dsscomp/queue.c @@ -579,7 +579,6 @@ skip_ovl_set: done: return r; } -EXPORT_SYMBOL(dsscomp_apply); struct dsscomp_apply_work { struct work_struct work; diff --git a/include/video/dsscomp.h b/include/video/dsscomp.h index 6ffa436..3ce86d4 100644 --- a/include/video/dsscomp.h +++ b/include/video/dsscomp.h @@ -228,8 +228,8 @@ struct dss2_decim { * * 2) configure DSS pipelines for display/manager using DSSCOMP_SETUP_MANAGER * ioctl. You can delay applying the settings until an dss2_manager_apply() - * with the same sync_id is called if the APPLY bit of setup mode is not - * set. However the CAPTURE/DISPLAY bits of the setup mode settings will + * is called for the internal composition object, if the APPLY bit of setup mode + * is not set. However the CAPTURE/DISPLAY bits of the setup mode settings will * determine if at this time a capture will take place (in case of capture * only mode). You may also set up additional pipelines with * dss2_overlay_setup() before this. @@ -237,7 +237,15 @@ struct dss2_decim { * 3) On OMAP4/5 you can use the DSS WB pipeline to copy (and convert) a buffer * using DSS. Use the DSSCOMP_WB_COPY ioctl for this. This is a blocking * call, and it may possibly fail if an ongoing WB capture mode has been - * schedule (which is outside of the current scope of the DSS2 interface.) + * scheduled (which is outside of the current scope of the DSS2 interface.) + * + * There is also a one-shot configuration API (DSSCOMP_SETUP_DISPC). This + * allows you to set-up all overlays on all managers in one call. This call + * performs additional functionality: + * + * - it maps userspace 1D buffers into TILER 1D for the duration of the display + * - it disables all overlays that were specified before, but are no longer + * specified * */ @@ -312,6 +320,7 @@ struct dss2_ovl_cfg { __u8 zorder; /* 0..3 */ __u8 enabled; /* bool */ __u8 zonly; /* only set zorder and enabled bit */ + __u8 mgr_ix; /* mgr index */ } __attribute__ ((aligned(4))); enum omapdss_buffer_type { @@ -356,9 +365,7 @@ struct dss2_ovl_info { * * The following information is deemed to be set globally, so it is not * included: - * - gamma correction - * - color phase correction - * + * gamma correction * whether to enable zorder (always enabled) * whether to replicate/truncate color fields (it is decided per the * whole manager/overlay settings, and is enabled unless overlay is @@ -369,7 +376,7 @@ struct dss2_ovl_info { * trans_enabled is true, and alpha_blending is false. */ struct dss2_mgr_info { - __u32 ix; /* display index same as sysfs/display# */ + __u32 ix; /* display index same as sysfs/display# */ __u32 default_color; @@ -379,7 +386,7 @@ struct dss2_mgr_info { __u8 trans_enabled; /* bool */ - __u8 interlaced; /* bool */ + __u8 interlaced; /* bool */ __u8 alpha_blending; /* bool - overrides trans_enabled */ __u8 cpr_enabled; /* bool */ __u8 swap_rb; /* bool - swap red and blue */ @@ -410,13 +417,15 @@ struct dss2_mgr_info { * on failure. * * If get_sync_obj is true, it returns fd on success, or a negative value - * on failure. You can use the fd to wait on (using poll()). It gets - * ready when frame has been eclipsed by another frame. + * on failure. You can use the fd to wait on (using DSSCOMP_WAIT ioctl()). * * Note: frames do not get eclipsed when the display turns off. Queue a * blank frame to eclipse old frames. Blank frames get eclipsed when * programmed into DSS. * + * (A blank frame is queued to the display automatically in Android before + * the display is turned off.) + * * All overlays to be used on the frame must be listed. There is no way * to add another overlay to a defined frame. */ @@ -439,7 +448,7 @@ enum dsscomp_setup_mode { }; struct dsscomp_setup_mgr_data { - __u32 sync_id; /* synchronization ID */ + __u32 sync_id; /* synchronization ID - for debugging */ struct dss2_rect_t win; /* update region, set w/h to 0 for fullscreen */ enum dsscomp_setup_mode mode; @@ -479,18 +488,28 @@ struct dsscomp_check_ovl_data { }; /* - * This structure is used to set up the entire DISPC (all managers). - * For now we only have LCD manager supported. + * This structure is used to set up the entire DISPC (all managers), + * and is analogous to dsscomp_setup_mgr_data. + * + * Additional features: + * - all overlays that were specified in a prior use of this + * structure, and are no longer specified, will be disabled. + * - 1D buffers under 4M will be mapped into TILER1D. + * + * Limitations: + * - only DISPLAY mode is supported (DISPLAY and APPLY bits will + * automatically be set) + * - getting a sync object is not supported. */ struct dsscomp_setup_dispc_data { - __u32 sync_id; /* synchronization ID */ + __u32 sync_id; /* synchronization ID - for debugging */ - struct dss2_rect_t win; /* update region, set w/h to 0 for fullscreen */ enum dsscomp_setup_mode mode; __u16 num_ovls; /* # of overlays used in the composition */ + __u16 num_mgrs; /* # of managers used in the composition */ __u16 get_sync_obj; /* ioctl should return a sync object */ - struct dss2_mgr_info mgr; + struct dss2_mgr_info mgrs[3]; struct dss2_ovl_info ovls[5]; /* up to 5 overlays to set up */ }; @@ -539,13 +558,10 @@ struct dsscomp_display_info { * subsequent composition does not update/specify all overlays used by * the prior composition; moreover, even if it uses the same buffers.) * - * Non-existing sync IDs are assumed to have been programmed, displayed and - * released. (They are assumed to be no-longer existing sync IDs.) + * Set timeout to desired timeout value in microseconds. * - * Set timeout to desired timeout value in microseconds. Set timeout - * to 0 if you want to return a sync object (file descriptor) instead of - * waiting for the event. You can then poll on this sync object to - * wait for the specified event. + * This ioctl must be used on the sync object returned by the + * DSSCOMP_SETUP_MGR or DSSCOMP_SETUP_DISPC ioctls. * * Returns: >=0 on success, <0 error value on failure (e.g. -ETIME). */ @@ -560,17 +576,6 @@ struct dsscomp_wait_data { enum dsscomp_wait_phase phase; /* phase to wait for */ }; -/* - * ioctl: DSSCOMP_LAST_RELEASED, struct dsscomp_wait_data - * - * Non-blocking sync. - * - * Fills in the sync_id of the last released frame on a - * display specified by ix. - * - * Returns 0 on success, non-0 error value on failure. - */ - /* IOCTLS */ #define DSSCOMP_SETUP_MGR _IOW('O', 128, struct dsscomp_setup_mgr_data) #define DSSCOMP_CHECK_OVL _IOWR('O', 129, struct dsscomp_check_ovl_data) |