|
@@ -530,13 +530,6 @@ struct manager_cache_data {
|
|
|
|
|
|
bool manual_update;
|
|
|
bool do_manual_update;
|
|
|
-
|
|
|
- /* manual update region */
|
|
|
- u16 x, y, w, h;
|
|
|
-
|
|
|
- /* enlarge the update area if the update area contains scaled
|
|
|
- * overlays */
|
|
|
- bool enlarge_update_area;
|
|
|
};
|
|
|
|
|
|
static struct {
|
|
@@ -762,65 +755,11 @@ static int overlay_enabled(struct omap_overlay *ovl)
|
|
|
return ovl->info.enabled && ovl->manager && ovl->manager->device;
|
|
|
}
|
|
|
|
|
|
-/* Is rect1 a subset of rect2? */
|
|
|
-static bool rectangle_subset(int x1, int y1, int w1, int h1,
|
|
|
- int x2, int y2, int w2, int h2)
|
|
|
-{
|
|
|
- if (x1 < x2 || y1 < y2)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (x1 + w1 > x2 + w2)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (y1 + h1 > y2 + h2)
|
|
|
- return false;
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-/* Do rect1 and rect2 overlap? */
|
|
|
-static bool rectangle_intersects(int x1, int y1, int w1, int h1,
|
|
|
- int x2, int y2, int w2, int h2)
|
|
|
-{
|
|
|
- if (x1 >= x2 + w2)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (x2 >= x1 + w1)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (y1 >= y2 + h2)
|
|
|
- return false;
|
|
|
-
|
|
|
- if (y2 >= y1 + h1)
|
|
|
- return false;
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc)
|
|
|
-{
|
|
|
- struct omap_overlay_info *oi = &oc->info;
|
|
|
-
|
|
|
- if (oi->out_width != 0 && oi->width != oi->out_width)
|
|
|
- return true;
|
|
|
-
|
|
|
- if (oi->out_height != 0 && oi->height != oi->out_height)
|
|
|
- return true;
|
|
|
-
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
static int configure_overlay(enum omap_plane plane)
|
|
|
{
|
|
|
struct overlay_cache_data *c;
|
|
|
- struct manager_cache_data *mc;
|
|
|
- struct omap_overlay_info *oi, new_oi;
|
|
|
- struct omap_overlay_manager_info *mi;
|
|
|
- u16 outw, outh;
|
|
|
- u16 x, y, w, h;
|
|
|
- u32 paddr;
|
|
|
+ struct omap_overlay_info *oi;
|
|
|
int r;
|
|
|
- u16 orig_w, orig_h, orig_outw, orig_outh;
|
|
|
|
|
|
DSSDBGF("%d", plane);
|
|
|
|
|
@@ -832,120 +771,7 @@ static int configure_overlay(enum omap_plane plane)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- mc = &dss_cache.manager_cache[c->channel];
|
|
|
- mi = &mc->info;
|
|
|
-
|
|
|
- x = oi->pos_x;
|
|
|
- y = oi->pos_y;
|
|
|
- w = oi->width;
|
|
|
- h = oi->height;
|
|
|
- outw = oi->out_width == 0 ? oi->width : oi->out_width;
|
|
|
- outh = oi->out_height == 0 ? oi->height : oi->out_height;
|
|
|
- paddr = oi->paddr;
|
|
|
-
|
|
|
- orig_w = w;
|
|
|
- orig_h = h;
|
|
|
- orig_outw = outw;
|
|
|
- orig_outh = outh;
|
|
|
-
|
|
|
- if (mc->manual_update && mc->do_manual_update) {
|
|
|
- unsigned bpp;
|
|
|
- unsigned scale_x_m = w, scale_x_d = outw;
|
|
|
- unsigned scale_y_m = h, scale_y_d = outh;
|
|
|
-
|
|
|
- /* If the overlay is outside the update region, disable it */
|
|
|
- if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h,
|
|
|
- x, y, outw, outh)) {
|
|
|
- dispc_ovl_enable(plane, 0);
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- switch (oi->color_mode) {
|
|
|
- case OMAP_DSS_COLOR_NV12:
|
|
|
- bpp = 8;
|
|
|
- break;
|
|
|
- case OMAP_DSS_COLOR_RGB16:
|
|
|
- case OMAP_DSS_COLOR_ARGB16:
|
|
|
- case OMAP_DSS_COLOR_YUV2:
|
|
|
- case OMAP_DSS_COLOR_UYVY:
|
|
|
- case OMAP_DSS_COLOR_RGBA16:
|
|
|
- case OMAP_DSS_COLOR_RGBX16:
|
|
|
- case OMAP_DSS_COLOR_ARGB16_1555:
|
|
|
- case OMAP_DSS_COLOR_XRGB16_1555:
|
|
|
- bpp = 16;
|
|
|
- break;
|
|
|
-
|
|
|
- case OMAP_DSS_COLOR_RGB24P:
|
|
|
- bpp = 24;
|
|
|
- break;
|
|
|
-
|
|
|
- case OMAP_DSS_COLOR_RGB24U:
|
|
|
- case OMAP_DSS_COLOR_ARGB32:
|
|
|
- case OMAP_DSS_COLOR_RGBA32:
|
|
|
- case OMAP_DSS_COLOR_RGBX32:
|
|
|
- bpp = 32;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- BUG();
|
|
|
- }
|
|
|
-
|
|
|
- if (mc->x > oi->pos_x) {
|
|
|
- x = 0;
|
|
|
- outw -= (mc->x - oi->pos_x);
|
|
|
- paddr += (mc->x - oi->pos_x) *
|
|
|
- scale_x_m / scale_x_d * bpp / 8;
|
|
|
- } else {
|
|
|
- x = oi->pos_x - mc->x;
|
|
|
- }
|
|
|
-
|
|
|
- if (mc->y > oi->pos_y) {
|
|
|
- y = 0;
|
|
|
- outh -= (mc->y - oi->pos_y);
|
|
|
- paddr += (mc->y - oi->pos_y) *
|
|
|
- scale_y_m / scale_y_d *
|
|
|
- oi->screen_width * bpp / 8;
|
|
|
- } else {
|
|
|
- y = oi->pos_y - mc->y;
|
|
|
- }
|
|
|
-
|
|
|
- if (mc->w < (x + outw))
|
|
|
- outw -= (x + outw) - (mc->w);
|
|
|
-
|
|
|
- if (mc->h < (y + outh))
|
|
|
- outh -= (y + outh) - (mc->h);
|
|
|
-
|
|
|
- w = w * outw / orig_outw;
|
|
|
- h = h * outh / orig_outh;
|
|
|
-
|
|
|
- /* YUV mode overlay's input width has to be even and the
|
|
|
- * algorithm above may adjust the width to be odd.
|
|
|
- *
|
|
|
- * Here we adjust the width if needed, preferring to increase
|
|
|
- * the width if the original width was bigger.
|
|
|
- */
|
|
|
- if ((w & 1) &&
|
|
|
- (oi->color_mode == OMAP_DSS_COLOR_YUV2 ||
|
|
|
- oi->color_mode == OMAP_DSS_COLOR_UYVY)) {
|
|
|
- if (orig_w > w)
|
|
|
- w += 1;
|
|
|
- else
|
|
|
- w -= 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- new_oi = *oi;
|
|
|
-
|
|
|
- /* update new_oi members which could have been possibly updated */
|
|
|
- new_oi.pos_x = x;
|
|
|
- new_oi.pos_y = y;
|
|
|
- new_oi.width = w;
|
|
|
- new_oi.height = h;
|
|
|
- new_oi.out_width = outw;
|
|
|
- new_oi.out_height = outh;
|
|
|
- new_oi.paddr = paddr;
|
|
|
-
|
|
|
- r = dispc_ovl_setup(plane, &new_oi, c->ilace, c->channel,
|
|
|
+ r = dispc_ovl_setup(plane, oi, c->ilace, c->channel,
|
|
|
c->replication, c->fifo_low, c->fifo_high);
|
|
|
if (r) {
|
|
|
/* this shouldn't happen */
|
|
@@ -1070,170 +896,23 @@ static int configure_dispc(void)
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
-/* Make the coordinates even. There are some strange problems with OMAP and
|
|
|
- * partial DSI update when the update widths are odd. */
|
|
|
-static void make_even(u16 *x, u16 *w)
|
|
|
-{
|
|
|
- u16 x1, x2;
|
|
|
-
|
|
|
- x1 = *x;
|
|
|
- x2 = *x + *w;
|
|
|
-
|
|
|
- x1 &= ~1;
|
|
|
- x2 = ALIGN(x2, 2);
|
|
|
-
|
|
|
- *x = x1;
|
|
|
- *w = x2 - x1;
|
|
|
-}
|
|
|
-
|
|
|
-/* Configure dispc for partial update. Return possibly modified update
|
|
|
- * area */
|
|
|
-void dss_setup_partial_planes(struct omap_dss_device *dssdev,
|
|
|
- u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area)
|
|
|
+void dss_start_update(struct omap_dss_device *dssdev)
|
|
|
{
|
|
|
- struct overlay_cache_data *oc;
|
|
|
struct manager_cache_data *mc;
|
|
|
- struct omap_overlay_info *oi;
|
|
|
+ struct overlay_cache_data *oc;
|
|
|
const int num_ovls = dss_feat_get_num_ovls();
|
|
|
+ const int num_mgrs = dss_feat_get_num_mgrs();
|
|
|
struct omap_overlay_manager *mgr;
|
|
|
int i;
|
|
|
- u16 x, y, w, h;
|
|
|
- unsigned long flags;
|
|
|
- bool area_changed;
|
|
|
-
|
|
|
- x = *xi;
|
|
|
- y = *yi;
|
|
|
- w = *wi;
|
|
|
- h = *hi;
|
|
|
-
|
|
|
- DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n",
|
|
|
- *xi, *yi, *wi, *hi);
|
|
|
|
|
|
mgr = dssdev->manager;
|
|
|
|
|
|
- if (!mgr) {
|
|
|
- DSSDBG("no manager\n");
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- make_even(&x, &w);
|
|
|
-
|
|
|
- spin_lock_irqsave(&dss_cache.lock, flags);
|
|
|
-
|
|
|
- /*
|
|
|
- * Execute the outer loop until the inner loop has completed
|
|
|
- * once without increasing the update area. This will ensure that
|
|
|
- * all scaled overlays end up completely within the update area.
|
|
|
- */
|
|
|
- do {
|
|
|
- area_changed = false;
|
|
|
-
|
|
|
- /* We need to show the whole overlay if it is scaled. So look
|
|
|
- * for those, and make the update area larger if found.
|
|
|
- * Also mark the overlay cache dirty */
|
|
|
- for (i = 0; i < num_ovls; ++i) {
|
|
|
- unsigned x1, y1, x2, y2;
|
|
|
- unsigned outw, outh;
|
|
|
-
|
|
|
- oc = &dss_cache.overlay_cache[i];
|
|
|
- oi = &oc->info;
|
|
|
-
|
|
|
- if (oc->channel != mgr->id)
|
|
|
- continue;
|
|
|
-
|
|
|
- oc->dirty = true;
|
|
|
-
|
|
|
- if (!enlarge_update_area)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (!oc->enabled)
|
|
|
- continue;
|
|
|
-
|
|
|
- if (!dispc_is_overlay_scaled(oc))
|
|
|
- continue;
|
|
|
-
|
|
|
- outw = oi->out_width == 0 ?
|
|
|
- oi->width : oi->out_width;
|
|
|
- outh = oi->out_height == 0 ?
|
|
|
- oi->height : oi->out_height;
|
|
|
-
|
|
|
- /* is the overlay outside the update region? */
|
|
|
- if (!rectangle_intersects(x, y, w, h,
|
|
|
- oi->pos_x, oi->pos_y,
|
|
|
- outw, outh))
|
|
|
- continue;
|
|
|
-
|
|
|
- /* if the overlay totally inside the update region? */
|
|
|
- if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh,
|
|
|
- x, y, w, h))
|
|
|
- continue;
|
|
|
-
|
|
|
- if (x > oi->pos_x)
|
|
|
- x1 = oi->pos_x;
|
|
|
- else
|
|
|
- x1 = x;
|
|
|
-
|
|
|
- if (y > oi->pos_y)
|
|
|
- y1 = oi->pos_y;
|
|
|
- else
|
|
|
- y1 = y;
|
|
|
-
|
|
|
- if ((x + w) < (oi->pos_x + outw))
|
|
|
- x2 = oi->pos_x + outw;
|
|
|
- else
|
|
|
- x2 = x + w;
|
|
|
-
|
|
|
- if ((y + h) < (oi->pos_y + outh))
|
|
|
- y2 = oi->pos_y + outh;
|
|
|
- else
|
|
|
- y2 = y + h;
|
|
|
-
|
|
|
- x = x1;
|
|
|
- y = y1;
|
|
|
- w = x2 - x1;
|
|
|
- h = y2 - y1;
|
|
|
-
|
|
|
- make_even(&x, &w);
|
|
|
-
|
|
|
- DSSDBG("changing upd area due to ovl(%d) "
|
|
|
- "scaling %d,%d %dx%d\n",
|
|
|
- i, x, y, w, h);
|
|
|
-
|
|
|
- area_changed = true;
|
|
|
- }
|
|
|
- } while (area_changed);
|
|
|
-
|
|
|
mc = &dss_cache.manager_cache[mgr->id];
|
|
|
- mc->do_manual_update = true;
|
|
|
- mc->enlarge_update_area = enlarge_update_area;
|
|
|
- mc->x = x;
|
|
|
- mc->y = y;
|
|
|
- mc->w = w;
|
|
|
- mc->h = h;
|
|
|
|
|
|
+ mc->do_manual_update = true;
|
|
|
configure_dispc();
|
|
|
-
|
|
|
mc->do_manual_update = false;
|
|
|
|
|
|
- spin_unlock_irqrestore(&dss_cache.lock, flags);
|
|
|
-
|
|
|
- *xi = x;
|
|
|
- *yi = y;
|
|
|
- *wi = w;
|
|
|
- *hi = h;
|
|
|
-}
|
|
|
-
|
|
|
-void dss_start_update(struct omap_dss_device *dssdev)
|
|
|
-{
|
|
|
- struct manager_cache_data *mc;
|
|
|
- struct overlay_cache_data *oc;
|
|
|
- const int num_ovls = dss_feat_get_num_ovls();
|
|
|
- const int num_mgrs = dss_feat_get_num_mgrs();
|
|
|
- struct omap_overlay_manager *mgr;
|
|
|
- int i;
|
|
|
-
|
|
|
- mgr = dssdev->manager;
|
|
|
-
|
|
|
for (i = 0; i < num_ovls; ++i) {
|
|
|
oc = &dss_cache.overlay_cache[i];
|
|
|
if (oc->channel != mgr->id)
|