From 5ab8e30c18292cf30de3adc36b0e2ed9d271e4e7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 12 Mar 2010 15:11:19 +0200 Subject: OMAP: DSS2: DSI: Increase HS TX timeout For some reason screen updates of certain odd widths seem to be triggering HS TX timeouts on OMAP 3430, even if bigger updates do not. The reason for this is unknown, but increasing the timeout removes the problem with no (so far) noticeable problems. I haven't seen this problem on OMAP 3630. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 3af207b2bde..eb90de5e107 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2490,7 +2490,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) dsi_set_stop_state_counter(1000); dsi_set_ta_timeout(6400000); dsi_set_lp_rx_timeout(48000); - dsi_set_hs_tx_timeout(1000000); + dsi_set_hs_tx_timeout(8000000); switch (dssdev->ctrl.pixel_size) { case 16: -- cgit v1.2.3-18-g5258 From 825f50b1a498f6e3532c8fcbc093322bb386f9e1 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Tue, 2 Mar 2010 21:30:52 +0200 Subject: OMAP: DSS2: Check if display supports update mode changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check whether the display actually has the set_update_mode() function before calling it. Only the sysfs codepath was broken, the omapfb ioctl had the necessary protection. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index ef8c8529dda..480aeaa5f39 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -82,6 +82,9 @@ static ssize_t display_upd_mode_store(struct device *dev, int val, r; enum omap_dss_update_mode mode; + if (!dssdev->driver->set_update_mode) + return -EINVAL; + val = simple_strtoul(buf, NULL, 10); switch (val) { -- cgit v1.2.3-18-g5258 From a74b260502c0911d14bafb76a20f699b6caa2e91 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 4 Mar 2010 16:03:56 +0200 Subject: OMAP: DSS2: Make wait_for_go() succeed for disabled displays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the display is not active make the wait_for_go() functions return immediately. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/manager.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 9e1fbe531bf..7e1ec5af6c7 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -525,7 +525,7 @@ static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) int i; struct omap_dss_device *dssdev = mgr->device; - if (!dssdev) + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) return 0; if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { @@ -596,11 +596,14 @@ int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) int r; int i; - if (!ovl->manager || !ovl->manager->device) + if (!ovl->manager) return 0; dssdev = ovl->manager->device; + if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) + return 0; + if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) { irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; channel = OMAP_DSS_CHANNEL_DIGIT; -- cgit v1.2.3-18-g5258 From 75c7d59daf502a4eb040e181120fb83b4a8c0719 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Fri, 5 Mar 2010 01:13:11 +0200 Subject: OMAP: DSS2: clear spurious SYNC_LOST_DIGIT interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When DSS transitions from off mode to on VENC may generate a spurious SYNC_LOST_DIGIT error. Just ack it when restoring the context. Also restore IRQENABLE last to avoid triggering interrupts before the context is fully restored. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index e777e352dbc..b8c16034f1e 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -335,7 +335,7 @@ void dispc_save_context(void) void dispc_restore_context(void) { RR(SYSCONFIG); - RR(IRQENABLE); + /*RR(IRQENABLE);*/ /*RR(CONTROL);*/ RR(CONFIG); RR(DEFAULT_COLOR0); @@ -472,6 +472,15 @@ void dispc_restore_context(void) /* enable last, because LCD & DIGIT enable are here */ RR(CONTROL); + + /* clear spurious SYNC_LOST_DIGIT interrupts */ + dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); + + /* + * enable last so IRQs won't trigger before + * the context is fully restored + */ + RR(IRQENABLE); } #undef SR -- cgit v1.2.3-18-g5258 From 8cab90fdb4c71f9a92c09c015aee42ff2149b317 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:09:30 +0300 Subject: OMAP: DSS2: Fix update area calculations with multiple scaled overlays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When there are multiple scaled overlays simply checking whether the update area intersects any of them in order is not enough. If eg. VID1 starts out completely outside the update area but VID2 causes the update area to increase in such a way that VID1 now falls partially within the increased update area VID1 should be rechecked and the update area possibly increased even further to fully encompass VID1. So simply keep looping over the overlays until such time that none of the overlays caused the update area to change. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/manager.c | 141 +++++++++++++++++++++----------------- 1 file changed, 78 insertions(+), 63 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 7e1ec5af6c7..a1d84ef6590 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -972,6 +972,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, int i; u16 x, y, w, h; unsigned long flags; + bool area_changed; x = *xi; y = *yi; @@ -992,70 +993,84 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, spin_lock_irqsave(&dss_cache.lock, flags); - /* 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]; - - if (oc->channel != mgr->id) - continue; - - oc->dirty = true; - - if (!oc->enabled) - continue; - - if (!dispc_is_overlay_scaled(oc)) - continue; - - outw = oc->out_width == 0 ? oc->width : oc->out_width; - outh = oc->out_height == 0 ? oc->height : oc->out_height; - - /* is the overlay outside the update region? */ - if (!rectangle_intersects(x, y, w, h, - oc->pos_x, oc->pos_y, - outw, outh)) - continue; - - /* if the overlay totally inside the update region? */ - if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, - x, y, w, h)) - continue; - - if (x > oc->pos_x) - x1 = oc->pos_x; - else - x1 = x; - - if (y > oc->pos_y) - y1 = oc->pos_y; - else - y1 = y; - - if ((x + w) < (oc->pos_x + outw)) - x2 = oc->pos_x + outw; - else - x2 = x + w; - - if ((y + h) < (oc->pos_y + outh)) - y2 = oc->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", + /* + * 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]; + + if (oc->channel != mgr->id) + continue; + + oc->dirty = true; + + if (!oc->enabled) + continue; + + if (!dispc_is_overlay_scaled(oc)) + continue; + + outw = oc->out_width == 0 ? + oc->width : oc->out_width; + outh = oc->out_height == 0 ? + oc->height : oc->out_height; + + /* is the overlay outside the update region? */ + if (!rectangle_intersects(x, y, w, h, + oc->pos_x, oc->pos_y, + outw, outh)) + continue; + + /* if the overlay totally inside the update region? */ + if (rectangle_subset(oc->pos_x, oc->pos_y, outw, outh, + x, y, w, h)) + continue; + + if (x > oc->pos_x) + x1 = oc->pos_x; + else + x1 = x; + + if (y > oc->pos_y) + y1 = oc->pos_y; + else + y1 = y; + + if ((x + w) < (oc->pos_x + outw)) + x2 = oc->pos_x + outw; + else + x2 = x + w; + + if ((y + h) < (oc->pos_y + outh)) + y2 = oc->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; -- cgit v1.2.3-18-g5258 From 46d3524a1b9155dd9cd57ea28e00db08c7a95c1a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 19:59:26 +0200 Subject: OMAP: DSS2: OMAPFB: Refactor overlay address calculations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Split the overlay address calculations into their own function. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 63 +++++++++++++++++++------------- 1 file changed, 38 insertions(+), 25 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 4b4506da96d..2ac20d230ea 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -822,6 +822,40 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, return offset; } +static void omapfb_calc_addr(const struct omapfb_info *ofbi, + const struct fb_var_screeninfo *var, + const struct fb_fix_screeninfo *fix, + int rotation, u32 *paddr, void __iomem **vaddr) +{ + u32 data_start_p; + void __iomem *data_start_v; + int offset; + + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { + data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); + data_start_v = NULL; + } else { + data_start_p = omapfb_get_region_paddr(ofbi); + data_start_v = omapfb_get_region_vaddr(ofbi); + } + + if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) + offset = calc_rotation_offset_vrfb(var, fix, rotation); + else + offset = calc_rotation_offset_dma(var, fix, rotation); + + data_start_p += offset; + data_start_v += offset; + + if (offset) + DBG("offset %d, %d = %d\n", + var->xoffset, var->yoffset, offset); + + DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); + + *paddr = data_start_p; + *vaddr = data_start_v; +} /* setup overlay according to the fb */ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, @@ -832,9 +866,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, struct fb_var_screeninfo *var = &fbi->var; struct fb_fix_screeninfo *fix = &fbi->fix; enum omap_color_mode mode = 0; - int offset; - u32 data_start_p; - void __iomem *data_start_v; + u32 data_start_p = 0; + void __iomem *data_start_v = NULL; struct omap_overlay_info info; int xres, yres; int screen_width; @@ -861,28 +894,8 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, yres = var->yres; } - - if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { - data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); - data_start_v = NULL; - } else { - data_start_p = omapfb_get_region_paddr(ofbi); - data_start_v = omapfb_get_region_vaddr(ofbi); - } - - if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) - offset = calc_rotation_offset_vrfb(var, fix, rotation); - else - offset = calc_rotation_offset_dma(var, fix, rotation); - - data_start_p += offset; - data_start_v += offset; - - if (offset) - DBG("offset %d, %d = %d\n", - var->xoffset, var->yoffset, offset); - - DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); + omapfb_calc_addr(ofbi, var, fix, rotation, + &data_start_p, &data_start_v); r = fb_mode_to_dss_mode(var, &mode); if (r) { -- cgit v1.2.3-18-g5258 From 276a1d4337c9c261f42d5a7f813d96ca18f67c2b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 20:05:38 +0200 Subject: OMAP: DSS2: OMAPFB: Check var even if there isn't memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If video memory hasn't been allocate have check_fb_var() still check most of the settings, just skip the ones involving the size of the memory region. Also skip the memory address calculations in omapfb_setup_overlay() if there's no memory. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 2ac20d230ea..ccccf3d71a3 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -668,9 +668,6 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) DBG("check_fb_var %d\n", ofbi->id); - if (ofbi->region.size == 0) - return 0; - r = fb_mode_to_dss_mode(var, &mode); if (r) { DBG("cannot convert var to omap dss mode\n"); @@ -690,7 +687,8 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) if (check_fb_res_bounds(var)) return -EINVAL; - if (check_fb_size(ofbi, var)) + /* When no memory is allocated ignore the size check */ + if (ofbi->region.size != 0 && check_fb_size(ofbi, var)) return -EINVAL; if (var->xres + var->xoffset > var->xres_virtual) @@ -894,8 +892,9 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, yres = var->yres; } - omapfb_calc_addr(ofbi, var, fix, rotation, - &data_start_p, &data_start_v); + if (ofbi->region.size) + omapfb_calc_addr(ofbi, var, fix, rotation, + &data_start_p, &data_start_v); r = fb_mode_to_dss_mode(var, &mode); if (r) { -- cgit v1.2.3-18-g5258 From 2ad0c50b84ee984aa58b09b46aef5c9f1d95e469 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 20:13:44 +0200 Subject: OMAP: DSS2: OMAPFB: Skip unnecessary set_overlay_info() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In omapfb_enable_overlay() if the overlay state is already what we want skip the set_overlay_info(). Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index cd54fdbfd8b..c9866be0460 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -148,6 +148,8 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, struct omap_overlay_info info; ovl->get_overlay_info(ovl, &info); + if (info.enabled == enable) + return 0; info.enabled = enable; return ovl->set_overlay_info(ovl, &info); } -- cgit v1.2.3-18-g5258 From 078ff546a806b2c2ab74c25c8edd4c6d4680656a Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 20:36:51 +0200 Subject: OMAP: DSS2: OMAPFB: Add support for switching memory regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Separate the memory region from the framebuffer device a little bit. It's now possible to select the memory region used by the framebuffer device using the new mem_idx parameter of omapfb_plane_info. If the mem_idx is specified it will be interpreted as an index into the memory regions array, if it's not specified the framebuffer's index is used instead. So by default each framebuffer keeps using it's own memory region which preserves backwards compatibility. This allows cloning the same memory region to several overlays and yet each overlay can be controlled independently since they can be associated with separate framebuffer devices. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 125 ++++++++++++++++++++++++------ drivers/video/omap2/omapfb/omapfb-main.c | 71 ++++++++++------- drivers/video/omap2/omapfb/omapfb-sysfs.c | 37 ++++++--- drivers/video/omap2/omapfb/omapfb.h | 9 ++- 4 files changed, 179 insertions(+), 63 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 9c7361871d7..6635bd75aff 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -34,12 +34,37 @@ #include "omapfb.h" +static u8 get_mem_idx(struct omapfb_info *ofbi) +{ + if (ofbi->id == ofbi->region->id) + return 0; + + return OMAPFB_MEM_IDX_ENABLED | ofbi->region->id; +} + +static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, + u8 mem_idx) +{ + struct omapfb2_device *fbdev = ofbi->fbdev; + + if (mem_idx & OMAPFB_MEM_IDX_ENABLED) + mem_idx &= OMAPFB_MEM_IDX_MASK; + else + mem_idx = ofbi->id; + + if (mem_idx >= fbdev->num_fbs) + return NULL; + + return &fbdev->regions[mem_idx]; +} + static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) { struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_overlay *ovl; - struct omap_overlay_info info; + struct omap_overlay_info old_info; + struct omapfb2_mem_region *old_rg, *new_rg; int r = 0; DBG("omapfb_setup_plane\n"); @@ -52,7 +77,14 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; - if (pi->enabled && !ofbi->region.size) { + old_rg = ofbi->region; + new_rg = get_mem_region(ofbi, pi->mem_idx); + if (!new_rg) { + r = -EINVAL; + goto out; + } + + if (pi->enabled && !new_rg->size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. @@ -61,27 +93,60 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) goto out; } - ovl->get_overlay_info(ovl, &info); + ovl->get_overlay_info(ovl, &old_info); - info.pos_x = pi->pos_x; - info.pos_y = pi->pos_y; - info.out_width = pi->out_width; - info.out_height = pi->out_height; - info.enabled = pi->enabled; + if (old_rg != new_rg) { + ofbi->region = new_rg; + set_fb_fix(fbi); + } - r = ovl->set_overlay_info(ovl, &info); - if (r) - goto out; + if (pi->enabled) { + struct omap_overlay_info info; + + r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, + pi->out_width, pi->out_height); + if (r) + goto undo; - if (ovl->manager) { - r = ovl->manager->apply(ovl->manager); + ovl->get_overlay_info(ovl, &info); + + if (!info.enabled) { + info.enabled = pi->enabled; + r = ovl->set_overlay_info(ovl, &info); + if (r) + goto undo; + } + } else { + struct omap_overlay_info info; + + ovl->get_overlay_info(ovl, &info); + + info.enabled = pi->enabled; + info.pos_x = pi->pos_x; + info.pos_y = pi->pos_y; + info.out_width = pi->out_width; + info.out_height = pi->out_height; + + r = ovl->set_overlay_info(ovl, &info); if (r) - goto out; + goto undo; } -out: - if (r) - dev_err(fbdev->dev, "setup_plane failed\n"); + if (ovl->manager) + ovl->manager->apply(ovl->manager); + + return 0; + + undo: + if (old_rg != new_rg) { + ofbi->region = old_rg; + set_fb_fix(fbi); + } + + ovl->set_overlay_info(ovl, &old_info); + out: + dev_err(fbdev->dev, "setup_plane failed\n"); + return r; } @@ -92,8 +157,8 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ofbi->num_overlays != 1) { memset(pi, 0, sizeof(*pi)); } else { - struct omap_overlay_info *ovli; struct omap_overlay *ovl; + struct omap_overlay_info *ovli; ovl = ofbi->overlays[0]; ovli = &ovl->info; @@ -103,6 +168,7 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) pi->enabled = ovli->enabled; pi->channel_out = 0; /* xxx */ pi->mirror = 0; + pi->mem_idx = get_mem_idx(ofbi); pi->out_width = ovli->out_width; pi->out_height = ovli->out_height; } @@ -123,11 +189,24 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) size = PAGE_ALIGN(mi->size); - rg = &ofbi->region; + rg = ofbi->region; - for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->info.enabled) - return -EBUSY; + if (atomic_read(&rg->map_count)) + return -EBUSY; + + for (i = 0; i < fbdev->num_fbs; i++) { + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); + int j; + + if (ofbi2->region != rg) + continue; + + for (j = 0; j < ofbi2->num_overlays; j++) { + if (ofbi2->overlays[j]->info.enabled) { + r = -EBUSY; + return r; + } + } } if (rg->size != size || rg->type != mi->type) { @@ -146,7 +225,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; memset(mi, 0, sizeof(*mi)); mi->size = rg->size; diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ccccf3d71a3..4a0588022b3 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -157,7 +157,7 @@ static void fill_fb(struct fb_info *fbi) static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) { - const struct vrfb *vrfb = &ofbi->region.vrfb; + const struct vrfb *vrfb = &ofbi->region->vrfb; unsigned offset; switch (rot) { @@ -185,27 +185,27 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) static u32 omapfb_get_region_rot_paddr(const struct omapfb_info *ofbi, int rot) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { - return ofbi->region.vrfb.paddr[rot] + return ofbi->region->vrfb.paddr[rot] + omapfb_get_vrfb_offset(ofbi, rot); } else { - return ofbi->region.paddr; + return ofbi->region->paddr; } } static u32 omapfb_get_region_paddr(const struct omapfb_info *ofbi) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) - return ofbi->region.vrfb.paddr[0]; + return ofbi->region->vrfb.paddr[0]; else - return ofbi->region.paddr; + return ofbi->region->paddr; } static void __iomem *omapfb_get_region_vaddr(const struct omapfb_info *ofbi) { if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) - return ofbi->region.vrfb.vaddr[0]; + return ofbi->region->vrfb.vaddr[0]; else - return ofbi->region.vaddr; + return ofbi->region->vaddr; } static struct omapfb_colormode omapfb_colormodes[] = { @@ -450,7 +450,7 @@ static int check_vrfb_fb_size(unsigned long region_size, static int check_fb_size(const struct omapfb_info *ofbi, struct fb_var_screeninfo *var) { - unsigned long max_frame_size = ofbi->region.size; + unsigned long max_frame_size = ofbi->region->size; int bytespp = var->bits_per_pixel >> 3; unsigned long line_size = var->xres_virtual * bytespp; @@ -497,7 +497,7 @@ static int check_fb_size(const struct omapfb_info *ofbi, static int setup_vrfb_rotation(struct fb_info *fbi) { struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_mem_region *rg = &ofbi->region; + struct omapfb2_mem_region *rg = ofbi->region; struct vrfb *vrfb = &rg->vrfb; struct fb_var_screeninfo *var = &fbi->var; struct fb_fix_screeninfo *fix = &fbi->fix; @@ -558,9 +558,9 @@ static int setup_vrfb_rotation(struct fb_info *fbi) return r; /* used by open/write in fbmem.c */ - fbi->screen_base = ofbi->region.vrfb.vaddr[0]; + fbi->screen_base = ofbi->region->vrfb.vaddr[0]; - fix->smem_start = ofbi->region.vrfb.paddr[0]; + fix->smem_start = ofbi->region->vrfb.paddr[0]; switch (var->nonstd) { case OMAPFB_COLOR_YUV422: @@ -599,7 +599,7 @@ void set_fb_fix(struct fb_info *fbi) struct fb_fix_screeninfo *fix = &fbi->fix; struct fb_var_screeninfo *var = &fbi->var; struct omapfb_info *ofbi = FB2OFB(fbi); - struct omapfb2_mem_region *rg = &ofbi->region; + struct omapfb2_mem_region *rg = ofbi->region; DBG("set_fb_fix\n"); @@ -688,7 +688,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) return -EINVAL; /* When no memory is allocated ignore the size check */ - if (ofbi->region.size != 0 && check_fb_size(ofbi, var)) + if (ofbi->region->size != 0 && check_fb_size(ofbi, var)) return -EINVAL; if (var->xres + var->xoffset > var->xres_virtual) @@ -856,7 +856,7 @@ static void omapfb_calc_addr(const struct omapfb_info *ofbi, } /* setup overlay according to the fb */ -static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, +int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, u16 posx, u16 posy, u16 outw, u16 outh) { int r = 0; @@ -892,7 +892,7 @@ static int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, yres = var->yres; } - if (ofbi->region.size) + if (ofbi->region->size) omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p, &data_start_v); @@ -971,7 +971,7 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) DBG("apply_changes, fb %d, ovl %d\n", ofbi->id, ovl->id); - if (ofbi->region.size == 0) { + if (ofbi->region->size == 0) { /* the fb is not available. disable the overlay */ omapfb_overlay_enable(ovl, 0); if (!init && ovl->manager) @@ -1071,16 +1071,16 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, static void mmap_user_open(struct vm_area_struct *vma) { - struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; + struct omapfb2_mem_region *rg = vma->vm_private_data; - atomic_inc(&ofbi->map_count); + atomic_inc(&rg->map_count); } static void mmap_user_close(struct vm_area_struct *vma) { - struct omapfb_info *ofbi = (struct omapfb_info *)vma->vm_private_data; + struct omapfb2_mem_region *rg = vma->vm_private_data; - atomic_dec(&ofbi->map_count); + atomic_dec(&rg->map_count); } static struct vm_operations_struct mmap_user_ops = { @@ -1092,6 +1092,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) { struct omapfb_info *ofbi = FB2OFB(fbi); struct fb_fix_screeninfo *fix = &fbi->fix; + struct omapfb2_mem_region *rg; unsigned long off; unsigned long start; u32 len; @@ -1102,6 +1103,8 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; + rg = ofbi->region; + start = omapfb_get_region_paddr(ofbi); len = fix->smem_len; if (off >= len) @@ -1117,12 +1120,12 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) vma->vm_flags |= VM_IO | VM_RESERVED; vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_ops = &mmap_user_ops; - vma->vm_private_data = ofbi; + vma->vm_private_data = rg; if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; /* vm_ops.open won't be called for mmap itself. */ - atomic_inc(&ofbi->map_count); + atomic_inc(&rg->map_count); return 0; } @@ -1312,7 +1315,9 @@ static void omapfb_free_fbmem(struct fb_info *fbi) struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; + + WARN_ON(atomic_read(&rg->map_count)); if (rg->paddr) if (omap_vram_free(rg->paddr, rg->size)) @@ -1367,8 +1372,15 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, void __iomem *vaddr; int r; - rg = &ofbi->region; - memset(rg, 0, sizeof(*rg)); + rg = ofbi->region; + + rg->paddr = 0; + rg->vaddr = NULL; + memset(&rg->vrfb, 0, sizeof rg->vrfb); + rg->size = 0; + rg->type = 0; + rg->alloc = false; + rg->map = false; size = PAGE_ALIGN(size); @@ -1621,7 +1633,7 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) for (i = 0; i < fbdev->num_fbs; i++) { struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[i]); struct omapfb2_mem_region *rg; - rg = &ofbi->region; + rg = ofbi->region; DBG("region%d phys %08x virt %p size=%lu\n", i, @@ -1638,7 +1650,7 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omap_dss_device *display = fb2display(fbi); - struct omapfb2_mem_region *rg = &ofbi->region; + struct omapfb2_mem_region *rg = ofbi->region; unsigned long old_size = rg->size; unsigned long old_paddr = rg->paddr; int old_type = rg->type; @@ -1721,7 +1733,7 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) fbi->flags = FBINFO_FLAG_DEFAULT; fbi->pseudo_palette = fbdev->pseudo_palette; - if (ofbi->region.size == 0) { + if (ofbi->region->size == 0) { clear_fb_info(fbi); return 0; } @@ -1883,6 +1895,9 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ofbi->fbdev = fbdev; ofbi->id = i; + ofbi->region = &fbdev->regions[i]; + ofbi->region->id = i; + /* assign these early, so that fb alloc can use them */ ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : OMAP_DSS_ROT_DMA; diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 5179219128b..dea1aa46a7d 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -64,7 +64,7 @@ static ssize_t store_rotate_type(struct device *dev, if (rot_type == ofbi->rotation_type) goto out; - if (ofbi->region.size) { + if (ofbi->region->size) { r = -EBUSY; goto out; } @@ -408,7 +408,7 @@ static ssize_t show_size(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region.size); + return snprintf(buf, PAGE_SIZE, "%lu\n", ofbi->region->size); } static ssize_t store_size(struct device *dev, struct device_attribute *attr, @@ -416,6 +416,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); + struct omapfb2_device *fbdev = ofbi->fbdev; + struct omapfb2_mem_region *rg; unsigned long size; int r; int i; @@ -425,15 +427,30 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, if (!lock_fb_info(fbi)) return -ENODEV; - for (i = 0; i < ofbi->num_overlays; i++) { - if (ofbi->overlays[i]->info.enabled) { - r = -EBUSY; - goto out; + rg = ofbi->region; + + if (atomic_read(&rg->map_count)) { + r = -EBUSY; + goto out; + } + + for (i = 0; i < fbdev->num_fbs; i++) { + struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); + int j; + + if (ofbi2->region != rg) + continue; + + for (j = 0; j < ofbi2->num_overlays; j++) { + if (ofbi2->overlays[j]->info.enabled) { + r = -EBUSY; + goto out; + } } } - if (size != ofbi->region.size) { - r = omapfb_realloc_fbmem(fbi, size, ofbi->region.type); + if (size != ofbi->region->size) { + r = omapfb_realloc_fbmem(fbi, size, ofbi->region->type); if (r) { dev_err(dev, "realloc fbmem failed\n"); goto out; @@ -453,7 +470,7 @@ static ssize_t show_phys(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region.paddr); + return snprintf(buf, PAGE_SIZE, "%0x\n", ofbi->region->paddr); } static ssize_t show_virt(struct device *dev, @@ -462,7 +479,7 @@ static ssize_t show_virt(struct device *dev, struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region.vaddr); + return snprintf(buf, PAGE_SIZE, "%p\n", ofbi->region->vaddr); } static struct device_attribute omapfb_attrs[] = { diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index c9866be0460..02f1ba9b228 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -44,6 +44,7 @@ extern unsigned int omapfb_debug; #define OMAPFB_MAX_OVL_PER_FB 3 struct omapfb2_mem_region { + int id; u32 paddr; void __iomem *vaddr; struct vrfb vrfb; @@ -51,13 +52,13 @@ struct omapfb2_mem_region { u8 type; /* OMAPFB_PLANE_MEM_* */ bool alloc; /* allocated by the driver */ bool map; /* kernel mapped by the driver */ + atomic_t map_count; }; /* appended to fb_info */ struct omapfb_info { int id; - struct omapfb2_mem_region region; - atomic_t map_count; + struct omapfb2_mem_region *region; int num_overlays; struct omap_overlay *overlays[OMAPFB_MAX_OVL_PER_FB]; struct omapfb2_device *fbdev; @@ -76,6 +77,7 @@ struct omapfb2_device { unsigned num_fbs; struct fb_info *fbs[10]; + struct omapfb2_mem_region regions[10]; unsigned num_displays; struct omap_dss_device *displays[10]; @@ -117,6 +119,9 @@ int omapfb_update_window(struct fb_info *fbi, int dss_mode_to_fb_mode(enum omap_color_mode dssmode, struct fb_var_screeninfo *var); +int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, + u16 posx, u16 posy, u16 outw, u16 outh); + /* find the display connected to this fb, if any */ static inline struct omap_dss_device *fb2display(struct fb_info *fbi) { -- cgit v1.2.3-18-g5258 From 430571d59a0b51c6541c153ad8b08e72fef26098 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 20:43:23 +0200 Subject: OMAP: DSS2: OMAPFB: Add locking for memory regions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add locking to the memory regions to make sure the memory region size won't be changed while some other piece of code is performing some checks or setup based on that information. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 44 ++++++++++++++++------ drivers/video/omap2/omapfb/omapfb-main.c | 62 +++++++++++++++++++++++++++---- drivers/video/omap2/omapfb/omapfb-sysfs.c | 37 +++++++++++++++++- drivers/video/omap2/omapfb/omapfb.h | 18 +++++++++ 4 files changed, 140 insertions(+), 21 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 6635bd75aff..69bcbfca47f 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -55,7 +55,7 @@ static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, if (mem_idx >= fbdev->num_fbs) return NULL; - return &fbdev->regions[mem_idx]; + return omapfb_get_mem_region(&fbdev->regions[mem_idx]); } static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) @@ -77,11 +77,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; - old_rg = ofbi->region; + old_rg = omapfb_get_mem_region(ofbi->region); new_rg = get_mem_region(ofbi, pi->mem_idx); if (!new_rg) { r = -EINVAL; - goto out; + goto put_old; } if (pi->enabled && !new_rg->size) { @@ -90,7 +90,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) * until it's reallocated. */ r = -EINVAL; - goto out; + goto put_new; } ovl->get_overlay_info(ovl, &old_info); @@ -135,6 +135,9 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ovl->manager) ovl->manager->apply(ovl->manager); + omapfb_put_mem_region(new_rg); + omapfb_put_mem_region(old_rg); + return 0; undo: @@ -144,6 +147,10 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) } ovl->set_overlay_info(ovl, &old_info); + put_new: + omapfb_put_mem_region(new_rg); + put_old: + omapfb_put_mem_region(old_rg); out: dev_err(fbdev->dev, "setup_plane failed\n"); @@ -181,7 +188,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_device *fbdev = ofbi->fbdev; struct omapfb2_mem_region *rg; - int r, i; + int r = 0, i; size_t size; if (mi->type > OMAPFB_MEMTYPE_MAX) @@ -191,8 +198,18 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) rg = ofbi->region; - if (atomic_read(&rg->map_count)) - return -EBUSY; + /* FIXME probably should be a rwsem ... */ + mutex_lock(&rg->mtx); + while (rg->ref) { + mutex_unlock(&rg->mtx); + schedule(); + mutex_lock(&rg->mtx); + } + + if (atomic_read(&rg->map_count)) { + r = -EBUSY; + goto out; + } for (i = 0; i < fbdev->num_fbs; i++) { struct omapfb_info *ofbi2 = FB2OFB(fbdev->fbs[i]); @@ -204,7 +221,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) for (j = 0; j < ofbi2->num_overlays; j++) { if (ofbi2->overlays[j]->info.enabled) { r = -EBUSY; - return r; + goto out; } } } @@ -213,11 +230,14 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) r = omapfb_realloc_fbmem(fbi, size, mi->type); if (r) { dev_err(fbdev->dev, "realloc fbmem failed\n"); - return r; + goto out; } } - return 0; + out: + mutex_unlock(&rg->mtx); + + return r; } static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) @@ -225,12 +245,14 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) struct omapfb_info *ofbi = FB2OFB(fbi); struct omapfb2_mem_region *rg; - rg = ofbi->region; + rg = omapfb_get_mem_region(ofbi->region); memset(mi, 0, sizeof(*mi)); mi->size = rg->size; mi->type = rg->type; + omapfb_put_mem_region(rg); + return 0; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 4a0588022b3..eb4338bbaa2 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1019,36 +1019,48 @@ err: * DO NOT MODIFY PAR */ static int omapfb_check_var(struct fb_var_screeninfo *var, struct fb_info *fbi) { + struct omapfb_info *ofbi = FB2OFB(fbi); int r; DBG("check_var(%d)\n", FB2OFB(fbi)->id); + omapfb_get_mem_region(ofbi->region); + r = check_fb_var(fbi, var); + omapfb_put_mem_region(ofbi->region); + return r; } /* set the video mode according to info->var */ static int omapfb_set_par(struct fb_info *fbi) { + struct omapfb_info *ofbi = FB2OFB(fbi); int r; DBG("set_par(%d)\n", FB2OFB(fbi)->id); + omapfb_get_mem_region(ofbi->region); + set_fb_fix(fbi); r = setup_vrfb_rotation(fbi); if (r) - return r; + goto out; r = omapfb_apply_changes(fbi, 0); + out: + omapfb_put_mem_region(ofbi->region); + return r; } static int omapfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *fbi) { + struct omapfb_info *ofbi = FB2OFB(fbi); struct fb_var_screeninfo new_var; int r; @@ -1064,8 +1076,12 @@ static int omapfb_pan_display(struct fb_var_screeninfo *var, fbi->var = new_var; + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 0); + omapfb_put_mem_region(ofbi->region); + return r; } @@ -1073,14 +1089,18 @@ static void mmap_user_open(struct vm_area_struct *vma) { struct omapfb2_mem_region *rg = vma->vm_private_data; + omapfb_get_mem_region(rg); atomic_inc(&rg->map_count); + omapfb_put_mem_region(rg); } static void mmap_user_close(struct vm_area_struct *vma) { struct omapfb2_mem_region *rg = vma->vm_private_data; + omapfb_get_mem_region(rg); atomic_dec(&rg->map_count); + omapfb_put_mem_region(rg); } static struct vm_operations_struct mmap_user_ops = { @@ -1096,6 +1116,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) unsigned long off; unsigned long start; u32 len; + int r = -EINVAL; if (vma->vm_end - vma->vm_start == 0) return 0; @@ -1103,14 +1124,14 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) return -EINVAL; off = vma->vm_pgoff << PAGE_SHIFT; - rg = ofbi->region; + rg = omapfb_get_mem_region(ofbi->region); start = omapfb_get_region_paddr(ofbi); len = fix->smem_len; if (off >= len) - return -EINVAL; + goto error; if ((vma->vm_end - vma->vm_start + off) > len) - return -EINVAL; + goto error; off += start; @@ -1122,11 +1143,23 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) vma->vm_ops = &mmap_user_ops; vma->vm_private_data = rg; if (io_remap_pfn_range(vma, vma->vm_start, off >> PAGE_SHIFT, - vma->vm_end - vma->vm_start, vma->vm_page_prot)) - return -EAGAIN; + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) { + r = -EAGAIN; + goto error; + } + /* vm_ops.open won't be called for mmap itself. */ atomic_inc(&rg->map_count); + + omapfb_put_mem_region(rg); + return 0; + + error: + omapfb_put_mem_region(ofbi->region); + + return r; } /* Store a single color palette entry into a pseudo palette or the hardware @@ -1897,6 +1930,7 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ofbi->region = &fbdev->regions[i]; ofbi->region->id = i; + mutex_init(&ofbi->region->mtx); /* assign these early, so that fb alloc can use them */ ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : @@ -1927,7 +1961,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) /* setup fb_infos */ for (i = 0; i < fbdev->num_fbs; i++) { - r = omapfb_fb_init(fbdev, fbdev->fbs[i]); + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + omapfb_get_mem_region(ofbi->region); + r = omapfb_fb_init(fbdev, fbi); + omapfb_put_mem_region(ofbi->region); + if (r) { dev_err(fbdev->dev, "failed to setup fb_info\n"); return r; @@ -1948,7 +1988,13 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) DBG("framebuffers registered\n"); for (i = 0; i < fbdev->num_fbs; i++) { - r = omapfb_apply_changes(fbdev->fbs[i], 1); + struct fb_info *fbi = fbdev->fbs[i]; + struct omapfb_info *ofbi = FB2OFB(fbi); + + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 1); + omapfb_put_mem_region(ofbi->region); + if (r) { dev_err(fbdev->dev, "failed to change mode\n"); return r; diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index dea1aa46a7d..74c11b24310 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -49,6 +49,7 @@ static ssize_t store_rotate_type(struct device *dev, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); + struct omapfb2_mem_region *rg; enum omap_dss_rotation_type rot_type; int r; @@ -64,9 +65,11 @@ static ssize_t store_rotate_type(struct device *dev, if (rot_type == ofbi->rotation_type) goto out; - if (ofbi->region->size) { + rg = omapfb_get_mem_region(ofbi->region); + + if (rg->size) { r = -EBUSY; - goto out; + goto put_region; } ofbi->rotation_type = rot_type; @@ -75,6 +78,8 @@ static ssize_t store_rotate_type(struct device *dev, * Since the VRAM for this FB is not allocated at the moment we don't * need to do any further parameter checking at this point. */ +put_region: + omapfb_put_mem_region(rg); out: unlock_fb_info(fbi); @@ -111,6 +116,8 @@ static ssize_t store_mirror(struct device *dev, ofbi->mirror = mirror; + omapfb_get_mem_region(ofbi->region); + memcpy(&new_var, &fbi->var, sizeof(new_var)); r = check_fb_var(fbi, &new_var); if (r) @@ -125,6 +132,8 @@ static ssize_t store_mirror(struct device *dev, r = count; out: + omapfb_put_mem_region(ofbi->region); + unlock_fb_info(fbi); return r; @@ -263,11 +272,15 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, DBG("detaching %d\n", ofbi->overlays[i]->id); + omapfb_get_mem_region(ofbi->region); + omapfb_overlay_enable(ovl, 0); if (ovl->manager) ovl->manager->apply(ovl->manager); + omapfb_put_mem_region(ofbi->region); + for (t = i + 1; t < ofbi->num_overlays; t++) { ofbi->rotation[t-1] = ofbi->rotation[t]; ofbi->overlays[t-1] = ofbi->overlays[t]; @@ -300,7 +313,12 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr, } if (added) { + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 0); + + omapfb_put_mem_region(ofbi->region); + if (r) goto out; } @@ -388,7 +406,12 @@ static ssize_t store_overlays_rotate(struct device *dev, for (i = 0; i < num_ovls; ++i) ofbi->rotation[i] = rotation[i]; + omapfb_get_mem_region(ofbi->region); + r = omapfb_apply_changes(fbi, 0); + + omapfb_put_mem_region(ofbi->region); + if (r) goto out; @@ -429,6 +452,14 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, rg = ofbi->region; + /* FIXME probably should be a rwsem ... */ + mutex_lock(&rg->mtx); + while (rg->ref) { + mutex_unlock(&rg->mtx); + schedule(); + mutex_lock(&rg->mtx); + } + if (atomic_read(&rg->map_count)) { r = -EBUSY; goto out; @@ -459,6 +490,8 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, r = count; out: + mutex_unlock(&rg->mtx); + unlock_fb_info(fbi); return r; diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 02f1ba9b228..db3aef5172c 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -52,6 +52,8 @@ struct omapfb2_mem_region { u8 type; /* OMAPFB_PLANE_MEM_* */ bool alloc; /* allocated by the driver */ bool map; /* kernel mapped by the driver */ + struct mutex mtx; + unsigned int ref; atomic_t map_count; }; @@ -159,4 +161,20 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, return ovl->set_overlay_info(ovl, &info); } +static inline struct omapfb2_mem_region * +omapfb_get_mem_region(struct omapfb2_mem_region *rg) +{ + mutex_lock(&rg->mtx); + rg->ref++; + mutex_unlock(&rg->mtx); + return rg; +} + +static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg) +{ + mutex_lock(&rg->mtx); + rg->ref--; + mutex_unlock(&rg->mtx); +} + #endif -- cgit v1.2.3-18-g5258 From 2f642a17503838e256b8b7e9f1153512e2efc38b Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 20:58:03 +0200 Subject: OMAP: DSS2: OMAPFB: Convert the memory region locking to rwsem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit R/W semaphore is a good fit for the memory region locking pattern. So use it. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 10 ++-------- drivers/video/omap2/omapfb/omapfb-main.c | 2 +- drivers/video/omap2/omapfb/omapfb-sysfs.c | 10 ++-------- drivers/video/omap2/omapfb/omapfb.h | 13 +++++-------- 4 files changed, 10 insertions(+), 25 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 69bcbfca47f..3a10146dc12 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -198,13 +198,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) rg = ofbi->region; - /* FIXME probably should be a rwsem ... */ - mutex_lock(&rg->mtx); - while (rg->ref) { - mutex_unlock(&rg->mtx); - schedule(); - mutex_lock(&rg->mtx); - } + down_write(&rg->lock); if (atomic_read(&rg->map_count)) { r = -EBUSY; @@ -235,7 +229,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) } out: - mutex_unlock(&rg->mtx); + up_write(&rg->lock); return r; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index eb4338bbaa2..a3f72ba7995 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1930,7 +1930,7 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) ofbi->region = &fbdev->regions[i]; ofbi->region->id = i; - mutex_init(&ofbi->region->mtx); + init_rwsem(&ofbi->region->lock); /* assign these early, so that fb alloc can use them */ ofbi->rotation_type = def_vrfb ? OMAP_DSS_ROT_VRFB : diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 74c11b24310..724b760404f 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -452,13 +452,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, rg = ofbi->region; - /* FIXME probably should be a rwsem ... */ - mutex_lock(&rg->mtx); - while (rg->ref) { - mutex_unlock(&rg->mtx); - schedule(); - mutex_lock(&rg->mtx); - } + down_write(&rg->lock); if (atomic_read(&rg->map_count)) { r = -EBUSY; @@ -490,7 +484,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, r = count; out: - mutex_unlock(&rg->mtx); + up_write(&rg->lock); unlock_fb_info(fbi); diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index db3aef5172c..195a760eef5 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -27,6 +27,8 @@ #define DEBUG #endif +#include + #include #ifdef DEBUG @@ -52,9 +54,8 @@ struct omapfb2_mem_region { u8 type; /* OMAPFB_PLANE_MEM_* */ bool alloc; /* allocated by the driver */ bool map; /* kernel mapped by the driver */ - struct mutex mtx; - unsigned int ref; atomic_t map_count; + struct rw_semaphore lock; }; /* appended to fb_info */ @@ -164,17 +165,13 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, static inline struct omapfb2_mem_region * omapfb_get_mem_region(struct omapfb2_mem_region *rg) { - mutex_lock(&rg->mtx); - rg->ref++; - mutex_unlock(&rg->mtx); + down_read(&rg->lock); return rg; } static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg) { - mutex_lock(&rg->mtx); - rg->ref--; - mutex_unlock(&rg->mtx); + up_read(&rg->lock); } #endif -- cgit v1.2.3-18-g5258 From 3d84b65aa63833a2ac07b1cc626984a1e1485fed Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 21:42:06 +0200 Subject: OMAP: DSS2: OMAPFB: Make lockdep happy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When more than one memory region needs to be lockd at the same time use the memory region id to fix the order in which the locks are taken. Also one needs to use the _nested() versions of the locking primitives. The memory region id can serve as the lock class there as well. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 45 +++++++++++++++++++++++-------- drivers/video/omap2/omapfb/omapfb-sysfs.c | 2 +- drivers/video/omap2/omapfb/omapfb.h | 2 +- 3 files changed, 36 insertions(+), 13 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 3a10146dc12..7975a99c33f 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -55,7 +55,7 @@ static struct omapfb2_mem_region *get_mem_region(struct omapfb_info *ofbi, if (mem_idx >= fbdev->num_fbs) return NULL; - return omapfb_get_mem_region(&fbdev->regions[mem_idx]); + return &fbdev->regions[mem_idx]; } static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) @@ -77,20 +77,30 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) /* XXX uses only the first overlay */ ovl = ofbi->overlays[0]; - old_rg = omapfb_get_mem_region(ofbi->region); + old_rg = ofbi->region; new_rg = get_mem_region(ofbi, pi->mem_idx); if (!new_rg) { r = -EINVAL; - goto put_old; + goto out; } + /* Take the locks in a specific order to keep lockdep happy */ + if (old_rg->id < new_rg->id) { + omapfb_get_mem_region(old_rg); + omapfb_get_mem_region(new_rg); + } else if (new_rg->id < old_rg->id) { + omapfb_get_mem_region(new_rg); + omapfb_get_mem_region(old_rg); + } else + omapfb_get_mem_region(old_rg); + if (pi->enabled && !new_rg->size) { /* * This plane's memory was freed, can't enable it * until it's reallocated. */ r = -EINVAL; - goto put_new; + goto put_mem; } ovl->get_overlay_info(ovl, &old_info); @@ -135,8 +145,15 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) if (ovl->manager) ovl->manager->apply(ovl->manager); - omapfb_put_mem_region(new_rg); - omapfb_put_mem_region(old_rg); + /* Release the locks in a specific order to keep lockdep happy */ + if (old_rg->id > new_rg->id) { + omapfb_put_mem_region(old_rg); + omapfb_put_mem_region(new_rg); + } else if (new_rg->id > old_rg->id) { + omapfb_put_mem_region(new_rg); + omapfb_put_mem_region(old_rg); + } else + omapfb_put_mem_region(old_rg); return 0; @@ -147,10 +164,16 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) } ovl->set_overlay_info(ovl, &old_info); - put_new: - omapfb_put_mem_region(new_rg); - put_old: - omapfb_put_mem_region(old_rg); + put_mem: + /* Release the locks in a specific order to keep lockdep happy */ + if (old_rg->id > new_rg->id) { + omapfb_put_mem_region(old_rg); + omapfb_put_mem_region(new_rg); + } else if (new_rg->id > old_rg->id) { + omapfb_put_mem_region(new_rg); + omapfb_put_mem_region(old_rg); + } else + omapfb_put_mem_region(old_rg); out: dev_err(fbdev->dev, "setup_plane failed\n"); @@ -198,7 +221,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) rg = ofbi->region; - down_write(&rg->lock); + down_write_nested(&rg->lock, rg->id); if (atomic_read(&rg->map_count)) { r = -EBUSY; diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 724b760404f..1e714bb48d3 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -452,7 +452,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, rg = ofbi->region; - down_write(&rg->lock); + down_write_nested(&rg->lock, rg->id); if (atomic_read(&rg->map_count)) { r = -EBUSY; diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 195a760eef5..676b55d9894 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -165,7 +165,7 @@ static inline int omapfb_overlay_enable(struct omap_overlay *ovl, static inline struct omapfb2_mem_region * omapfb_get_mem_region(struct omapfb2_mem_region *rg) { - down_read(&rg->lock); + down_read_nested(&rg->lock, rg->id); return rg; } -- cgit v1.2.3-18-g5258 From 1ceafc00910439c8e5450fae189b69427725992c Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Wed, 17 Mar 2010 21:28:50 +0200 Subject: OMAP: DSS2: OMAPFB: Add some locking debug checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trigger WARN_ON() messages from various places in the code in case the memory region is not currently locked. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 2 ++ drivers/video/omap2/omapfb/omapfb-main.c | 6 ++++++ drivers/video/omap2/omapfb/omapfb-sysfs.c | 2 ++ drivers/video/omap2/omapfb/omapfb.h | 3 +++ 4 files changed, 13 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 7975a99c33f..d1f56d37405 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -222,6 +222,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) rg = ofbi->region; down_write_nested(&rg->lock, rg->id); + atomic_inc(&rg->lock_count); if (atomic_read(&rg->map_count)) { r = -EBUSY; @@ -252,6 +253,7 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) } out: + atomic_dec(&rg->lock_count); up_write(&rg->lock); return r; diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index a3f72ba7995..a545e8d4817 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -668,6 +668,8 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) DBG("check_fb_var %d\n", ofbi->id); + WARN_ON(!atomic_read(&ofbi->region->lock_count)); + r = fb_mode_to_dss_mode(var, &mode); if (r) { DBG("cannot convert var to omap dss mode\n"); @@ -873,6 +875,8 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, int rotation = var->rotate; int i; + WARN_ON(!atomic_read(&ofbi->region->lock_count)); + for (i = 0; i < ofbi->num_overlays; i++) { if (ovl != ofbi->overlays[i]) continue; @@ -966,6 +970,8 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) fill_fb(fbi); #endif + WARN_ON(!atomic_read(&ofbi->region->lock_count)); + for (i = 0; i < ofbi->num_overlays; i++) { ovl = ofbi->overlays[i]; diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 1e714bb48d3..51c13c366bf 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -453,6 +453,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, rg = ofbi->region; down_write_nested(&rg->lock, rg->id); + atomic_inc(&rg->lock_count); if (atomic_read(&rg->map_count)) { r = -EBUSY; @@ -484,6 +485,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, r = count; out: + atomic_dec(&rg->lock_count); up_write(&rg->lock); unlock_fb_info(fbi); diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 676b55d9894..1305fc9880b 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h @@ -56,6 +56,7 @@ struct omapfb2_mem_region { bool map; /* kernel mapped by the driver */ atomic_t map_count; struct rw_semaphore lock; + atomic_t lock_count; }; /* appended to fb_info */ @@ -166,11 +167,13 @@ static inline struct omapfb2_mem_region * omapfb_get_mem_region(struct omapfb2_mem_region *rg) { down_read_nested(&rg->lock, rg->id); + atomic_inc(&rg->lock_count); return rg; } static inline void omapfb_put_mem_region(struct omapfb2_mem_region *rg) { + atomic_dec(&rg->lock_count); up_read(&rg->lock); } -- cgit v1.2.3-18-g5258 From 86a7867ebff675f5f5816222c5a2c64b35f8bea6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 16 Mar 2010 16:19:06 +0200 Subject: OMAP: DSS2: DSI: print errors in dsi_vc_flush_receive_data() dsi_vc_flush_receive_data() is meant to dump data when something has gone wrong, and thus we should use DSSERR, not DSSDBG. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index eb90de5e107..542c6e2a3ff 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1854,19 +1854,19 @@ static u16 dsi_vc_flush_receive_data(int channel) u32 val; u8 dt; val = dsi_read_reg(DSI_VC_SHORT_PACKET_HEADER(channel)); - DSSDBG("\trawval %#08x\n", val); + DSSERR("\trawval %#08x\n", val); dt = FLD_GET(val, 5, 0); if (dt == DSI_DT_RX_ACK_WITH_ERR) { u16 err = FLD_GET(val, 23, 8); dsi_show_rx_ack_with_err(err); } else if (dt == DSI_DT_RX_SHORT_READ_1) { - DSSDBG("\tDCS short response, 1 byte: %#x\n", + DSSERR("\tDCS short response, 1 byte: %#x\n", FLD_GET(val, 23, 8)); } else if (dt == DSI_DT_RX_SHORT_READ_2) { - DSSDBG("\tDCS short response, 2 byte: %#x\n", + DSSERR("\tDCS short response, 2 byte: %#x\n", FLD_GET(val, 23, 8)); } else if (dt == DSI_DT_RX_DCS_LONG_READ) { - DSSDBG("\tDCS long response, len %d\n", + DSSERR("\tDCS long response, len %d\n", FLD_GET(val, 23, 8)); dsi_vc_flush_long_data(channel); } else { -- cgit v1.2.3-18-g5258 From 0f16aa0ae6b84d7ae72fbe8999e6a94cb78edd4e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Apr 2010 09:57:19 +0300 Subject: OMAP: DSS2: DSI: use a private workqueue Using the shared workqueue led to to a deadlock in the case where the display was unblanked via keyboard. What happens is something like this: - User presses a key context 1: - drivers/char/keyboard.c calls schedule_console_callback() - fb_unblank takes the console semaphore - dsi bus lock is taken, and frame transfer is started (dsi bus lock is left on) - Unblank code tries to set the panel backlight, which tries to take dsi bus lock, but is blocked while the frame transfer is going on context 2, shared workqueue, console_callback in drivers/char/vt.c: - Tries to take console semaphore - Blocks, as console semaphore is being held by context 1 - No other shared workqueue work can be run context 3, HW irq, caused by FRAMEDONE interrupt: - Interrupt handler schedules framedone-work in shared workqueue - Framedone-work is never ran, as the shared workqueue is blocked. This means that the unblank thread stays blocked, which means that context 2 stays blocked. While I think the real problem is in keyboard/virtual terminal code, using a private workqueue in the DSI driver is perhaps safer and more robust than using the shared one. The DSI works should not be delayed more than a millisecond or so, and even if the private workqueue gives us no hard promise of doing so, it's still safer bet than the shared workqueue. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 542c6e2a3ff..de3fdab46f3 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -238,6 +238,8 @@ static struct bool te_enabled; + struct workqueue_struct *workqueue; + struct work_struct framedone_work; void (*framedone_callback)(int, void *); void *framedone_data; @@ -2759,6 +2761,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, unsigned packet_payload; unsigned packet_len; u32 l; + int r; const unsigned channel = dsi.update_channel; /* line buffer is 1024 x 24bits */ /* XXX: for some reason using full buffer size causes considerable TX @@ -2809,8 +2812,9 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, dsi_perf_mark_start(); - schedule_delayed_work(&dsi.framedone_timeout_work, + r = queue_delayed_work(dsi.workqueue, &dsi.framedone_timeout_work, msecs_to_jiffies(250)); + BUG_ON(r == 0); dss_start_update(dssdev); @@ -2841,6 +2845,11 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) DSSERR("Framedone not received for 250ms!\n"); + /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after + * 250ms which would conflict with this timeout work. What should be + * done is first cancel the transfer on the HW, and then cancel the + * possibly scheduled framedone work */ + /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); @@ -2873,6 +2882,7 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) static void dsi_framedone_irq_callback(void *data, u32 mask) { + int r; /* Note: We get FRAMEDONE when DISPC has finished sending pixels and * turns itself off. However, DSI still has the pixels in its buffers, * and is sending the data. @@ -2881,7 +2891,8 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); - schedule_work(&dsi.framedone_work); + r = queue_work(dsi.workqueue, &dsi.framedone_work); + BUG_ON(r == 0); } static void dsi_handle_framedone(void) @@ -3292,6 +3303,10 @@ int dsi_init(struct platform_device *pdev) mutex_init(&dsi.lock); sema_init(&dsi.bus_lock, 1); + dsi.workqueue = create_singlethread_workqueue("dsi"); + if (dsi.workqueue == NULL) + return -ENOMEM; + INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, dsi_framedone_timeout_work_callback); @@ -3328,6 +3343,7 @@ int dsi_init(struct platform_device *pdev) err2: iounmap(dsi.base); err1: + destroy_workqueue(dsi.workqueue); return r; } @@ -3335,6 +3351,8 @@ void dsi_exit(void) { iounmap(dsi.base); + destroy_workqueue(dsi.workqueue); + DSSDBG("omap_dsi_exit\n"); } -- cgit v1.2.3-18-g5258 From 0c244f770f7fdb3e6779b3433aac9cfb6deb3255 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:19:29 +0300 Subject: OMAP: DSS2: DSI: change dsi_vc_dcs_read_2 parameters Change dsi_vc_dcs_read_2() data parameter to two u8 parameters to make the byte-order clear. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index de3fdab46f3..767f6fb2bdf 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2235,11 +2235,12 @@ int dsi_vc_dcs_read_1(int channel, u8 dcs_cmd, u8 *data) } EXPORT_SYMBOL(dsi_vc_dcs_read_1); -int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) +int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u8 *data1, u8 *data2) { + u8 buf[2]; int r; - r = dsi_vc_dcs_read(channel, dcs_cmd, (u8 *)data, 2); + r = dsi_vc_dcs_read(channel, dcs_cmd, buf, 2); if (r < 0) return r; @@ -2247,6 +2248,9 @@ int dsi_vc_dcs_read_2(int channel, u8 dcs_cmd, u16 *data) if (r != 2) return -EIO; + *data1 = buf[0]; + *data2 = buf[1]; + return 0; } EXPORT_SYMBOL(dsi_vc_dcs_read_2); -- cgit v1.2.3-18-g5258 From b63ac1e31422077bed8257a519c6668f8868ed2b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 9 Apr 2010 13:20:57 +0300 Subject: OMAP: DSS2: DSI: handle error in synchronous write Check if the peripheral answered something, and if so, dump the data and return an error. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 767f6fb2bdf..5b621767455 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2089,6 +2089,13 @@ int dsi_vc_dcs_write(int channel, u8 *data, int len) if (r) goto err; + if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { /* RX_FIFO_NOT_EMPTY */ + DSSERR("rx fifo not empty after write, dumping data:\n"); + dsi_vc_flush_receive_data(channel); + r = -EIO; + goto err; + } + return 0; err: DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", -- cgit v1.2.3-18-g5258 From 4ffa35713e263fbf4975e14bc6f4a515b7701349 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 12 Apr 2010 10:40:12 +0300 Subject: OMAP: DSS2: DSI: change DSI timeout functions Using nanoseconds as arguments to functions that set the DSI timeouts was perhaps not so good idea. The timeouts are based on different DSI clocks, so the possible range for the timeouts vary greatly depending on the clocks. Also, the multipliers used with the timeouts cause big gaps in the timeout range, meaning that the nanosecond based functions could cause the timeout to be quite far from the intended value. This patch changes the functions to take the plain tick values with the multiplier enable/disable bits, and sets the TA/LP_RX/HS_TX timeouts to maximum. While the timeouts could be much lower, the fact is that when TA/LP_RX/HS_TX timeout happens, we are in an error situation and not in a hurry anyway. STOP_STATE_COUNTER is a different matter, but it is only used at initialization time, and won't normally affect the performance. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 216 +++++++++++------------------------------- 1 file changed, 56 insertions(+), 160 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 5b621767455..613796b54f0 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2277,212 +2277,108 @@ int dsi_vc_set_max_rx_packet_size(int channel, u16 len) } EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); -static void dsi_set_lp_rx_timeout(unsigned long ns) +static void dsi_set_lp_rx_timeout(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in DSI_FCK */ + BUG_ON(ticks > 0x1fff); + /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("LP_TX_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING2); r = FLD_MOD(r, 1, 15, 15); /* LP_RX_TO */ - r = FLD_MOD(r, x16, 14, 14); /* LP_RX_TO_X16 */ - r = FLD_MOD(r, x4, 13, 13); /* LP_RX_TO_X4 */ + r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* LP_RX_TO_X16 */ + r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* LP_RX_TO_X4 */ r = FLD_MOD(r, ticks, 12, 0); /* LP_RX_COUNTER */ dsi_write_reg(DSI_TIMING2, r); - DSSDBG("LP_RX_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("LP_RX_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_ta_timeout(unsigned long ns) +static void dsi_set_ta_timeout(unsigned ticks, bool x8, bool x16) { - u32 r; - unsigned x8, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; + + BUG_ON(ticks > 0x1fff); /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x8 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 8; - x8 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x8 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (8 * 16); - x8 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("TA_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x8 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING1); r = FLD_MOD(r, 1, 31, 31); /* TA_TO */ - r = FLD_MOD(r, x16, 30, 30); /* TA_TO_X16 */ - r = FLD_MOD(r, x8, 29, 29); /* TA_TO_X8 */ + r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* TA_TO_X16 */ + r = FLD_MOD(r, x8 ? 1 : 0, 29, 29); /* TA_TO_X8 */ r = FLD_MOD(r, ticks, 28, 16); /* TA_TO_COUNTER */ dsi_write_reg(DSI_TIMING1, r); - DSSDBG("TA_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x8 ? " x8" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x8 ? 8 : 1); + + DSSDBG("TA_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x8 ? " x8" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_stop_state_counter(unsigned long ns) +static void dsi_set_stop_state_counter(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in DSI_FCK */ + BUG_ON(ticks > 0x1fff); + /* ticks in DSI_FCK */ fck = dsi_fclk_rate(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("STOP_STATE_COUNTER_IO over limit, " - "setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING1); r = FLD_MOD(r, 1, 15, 15); /* FORCE_TX_STOP_MODE_IO */ - r = FLD_MOD(r, x16, 14, 14); /* STOP_STATE_X16_IO */ - r = FLD_MOD(r, x4, 13, 13); /* STOP_STATE_X4_IO */ + r = FLD_MOD(r, x16 ? 1 : 0, 14, 14); /* STOP_STATE_X16_IO */ + r = FLD_MOD(r, x4 ? 1 : 0, 13, 13); /* STOP_STATE_X4_IO */ r = FLD_MOD(r, ticks, 12, 0); /* STOP_STATE_COUNTER_IO */ dsi_write_reg(DSI_TIMING1, r); - DSSDBG("STOP_STATE_COUNTER %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("STOP_STATE_COUNTER %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } -static void dsi_set_hs_tx_timeout(unsigned long ns) +static void dsi_set_hs_tx_timeout(unsigned ticks, bool x4, bool x16) { - u32 r; - unsigned x4, x16; unsigned long fck; - unsigned long ticks; + unsigned long total_ticks; + u32 r; - /* ticks in TxByteClkHS */ + BUG_ON(ticks > 0x1fff); + /* ticks in TxByteClkHS */ fck = dsi_get_txbyteclkhs(); - ticks = (fck / 1000 / 1000) * ns / 1000; - x4 = 0; - x16 = 0; - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 4; - x4 = 1; - x16 = 0; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / 16; - x4 = 0; - x16 = 1; - } - - if (ticks > 0x1fff) { - ticks = (fck / 1000 / 1000) * ns / 1000 / (4 * 16); - x4 = 1; - x16 = 1; - } - - if (ticks > 0x1fff) { - DSSWARN("HS_TX_TO over limit, setting it to max\n"); - ticks = 0x1fff; - x4 = 1; - x16 = 1; - } r = dsi_read_reg(DSI_TIMING2); r = FLD_MOD(r, 1, 31, 31); /* HS_TX_TO */ - r = FLD_MOD(r, x16, 30, 30); /* HS_TX_TO_X16 */ - r = FLD_MOD(r, x4, 29, 29); /* HS_TX_TO_X8 (4 really) */ + r = FLD_MOD(r, x16 ? 1 : 0, 30, 30); /* HS_TX_TO_X16 */ + r = FLD_MOD(r, x4 ? 1 : 0, 29, 29); /* HS_TX_TO_X8 (4 really) */ r = FLD_MOD(r, ticks, 28, 16); /* HS_TX_TO_COUNTER */ dsi_write_reg(DSI_TIMING2, r); - DSSDBG("HS_TX_TO %lu ns (%#lx ticks%s%s)\n", - (ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1) * 1000) / - (fck / 1000 / 1000), - ticks, x4 ? " x4" : "", x16 ? " x16" : ""); + total_ticks = ticks * (x16 ? 16 : 1) * (x4 ? 4 : 1); + + DSSDBG("HS_TX_TO %lu ticks (%#x%s%s) = %lu ns\n", + total_ticks, + ticks, x4 ? " x4" : "", x16 ? " x16" : "", + (total_ticks * 1000) / (fck / 1000 / 1000)); } static int dsi_proto_config(struct omap_dss_device *dssdev) { @@ -2500,10 +2396,10 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) DSI_FIFO_SIZE_32); /* XXX what values for the timeouts? */ - dsi_set_stop_state_counter(1000); - dsi_set_ta_timeout(6400000); - dsi_set_lp_rx_timeout(48000); - dsi_set_hs_tx_timeout(8000000); + dsi_set_stop_state_counter(0x1000, false, false); + dsi_set_ta_timeout(0x1fff, true, true); + dsi_set_lp_rx_timeout(0x1fff, true, true); + dsi_set_hs_tx_timeout(0x1fff, true, true); switch (dssdev->ctrl.pixel_size) { case 16: -- cgit v1.2.3-18-g5258 From 1cbc8703e1c510a245a7bd5e269987402ffc9e18 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 15 Apr 2010 16:41:07 +0300 Subject: OMAP: DSS2: Taal: add locks to taal_bl_update_status taal_bl_update_status was missing locks to protect taal_data. This caused a kernel crash randomly, as the code attempted to set the brightness while the OMAP's DSI block was actually disabled. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index aaf5d308a04..d2e2ac7444e 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -290,24 +290,26 @@ static int taal_bl_update_status(struct backlight_device *dev) dev_dbg(&dssdev->dev, "update brightness to %d\n", level); + mutex_lock(&td->lock); + if (td->use_dsi_bl) { if (td->enabled) { dsi_bus_lock(); r = taal_dcs_write_1(DCS_BRIGHTNESS, level); dsi_bus_unlock(); - if (r) - return r; + } else { + r = 0; } } else { if (!dssdev->set_backlight) - return -EINVAL; - - r = dssdev->set_backlight(dssdev, level); - if (r) - return r; + r = -EINVAL; + else + r = dssdev->set_backlight(dssdev, level); } - return 0; + mutex_unlock(&td->lock); + + return r; } static int taal_bl_get_intensity(struct backlight_device *dev) -- cgit v1.2.3-18-g5258 From 006db7b4304303f014a0c13f479715885b603e9f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 9 Apr 2010 12:25:59 +0300 Subject: OMAP: DSS2: Taal: Add panel hardware reset Issue a proper reset pulse on the reset line instead of just doing power on/off. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 44 ++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 4 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index d2e2ac7444e..8fbb94e2bf5 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -490,6 +490,22 @@ static struct attribute_group taal_attr_group = { .attrs = taal_attrs, }; +static void taal_hw_reset(struct omap_dss_device *dssdev) +{ + if (dssdev->reset_gpio == -1) + return; + + gpio_set_value(dssdev->reset_gpio, 1); + udelay(10); + /* reset the panel */ + gpio_set_value(dssdev->reset_gpio, 0); + /* assert reset for at least 10us */ + udelay(10); + gpio_set_value(dssdev->reset_gpio, 1); + /* wait 5ms after releasing reset */ + msleep(5); +} + static int taal_probe(struct omap_dss_device *dssdev) { struct backlight_properties props; @@ -527,6 +543,8 @@ static int taal_probe(struct omap_dss_device *dssdev) dev_set_drvdata(&dssdev->dev, td); + taal_hw_reset(dssdev); + /* if no platform set_backlight() defined, presume DSI backlight * control */ memset(&props, 0, sizeof(struct backlight_properties)); @@ -628,6 +646,9 @@ static void taal_remove(struct omap_dss_device *dssdev) cancel_delayed_work_sync(&td->esd_work); destroy_workqueue(td->esd_wq); + /* reset, to be sure that the panel is in a valid state */ + taal_hw_reset(dssdev); + kfree(td); } @@ -654,6 +675,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) goto err0; } + taal_hw_reset(dssdev); + omapdss_dsi_vc_enable_hs(TCH, false); r = taal_sleep_out(td); @@ -704,6 +727,10 @@ static int taal_power_on(struct omap_dss_device *dssdev) return 0; err: + dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); + + taal_hw_reset(dssdev); + omapdss_dsi_display_disable(dssdev); err0: dsi_bus_unlock(); @@ -716,16 +743,24 @@ err0: static void taal_power_off(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int r; dsi_bus_lock(); cancel_delayed_work(&td->esd_work); - taal_dcs_write_0(DCS_DISPLAY_OFF); - taal_sleep_in(td); + r = taal_dcs_write_0(DCS_DISPLAY_OFF); + if (!r) { + r = taal_sleep_in(td); + /* wait a bit so that the message goes through */ + msleep(10); + } - /* wait a bit so that the message goes through */ - msleep(10); + if (r) { + dev_err(&dssdev->dev, + "error disabling panel, issuing HW reset\n"); + taal_hw_reset(dssdev); + } omapdss_dsi_display_disable(dssdev); @@ -1186,6 +1221,7 @@ err: dev_err(&dssdev->dev, "performing LCD reset\n"); taal_power_off(dssdev); + taal_hw_reset(dssdev); taal_power_on(dssdev); dsi_bus_unlock(); -- cgit v1.2.3-18-g5258 From 6b316715b4b96da49fcac0fa07082692eebca8af Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 28 Apr 2010 11:15:18 +0300 Subject: OMAP: DSS2: Taal: Add locks to protect taal data access Avoid potential race conditions in sysfs access to taal data. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 8fbb94e2bf5..0eed3282a7a 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -364,6 +364,8 @@ static ssize_t taal_num_errors_show(struct device *dev, u8 errors; int r; + mutex_lock(&td->lock); + if (td->enabled) { dsi_bus_lock(); r = taal_dcs_read_1(DCS_READ_NUM_ERRORS, &errors); @@ -372,6 +374,8 @@ static ssize_t taal_num_errors_show(struct device *dev, r = -ENODEV; } + mutex_unlock(&td->lock); + if (r) return r; @@ -386,6 +390,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, u8 id1, id2, id3; int r; + mutex_lock(&td->lock); + if (td->enabled) { dsi_bus_lock(); r = taal_get_id(&id1, &id2, &id3); @@ -394,6 +400,8 @@ static ssize_t taal_hw_revision_show(struct device *dev, r = -ENODEV; } + mutex_unlock(&td->lock); + if (r) return r; @@ -443,6 +451,8 @@ static ssize_t store_cabc_mode(struct device *dev, if (i == ARRAY_SIZE(cabc_modes)) return -EINVAL; + mutex_lock(&td->lock); + if (td->enabled) { dsi_bus_lock(); if (!td->cabc_broken) @@ -452,6 +462,8 @@ static ssize_t store_cabc_mode(struct device *dev, td->cabc_mode = i; + mutex_unlock(&td->lock); + return count; } -- cgit v1.2.3-18-g5258 From 75392bfe3ecc8dc89acf2165a34f8aa039346fb4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 27 Apr 2010 14:40:30 +0300 Subject: OMAP: DSS2: Taal: Remove platform enable/disable After the addition of proper hardware reset, taal_hw_reset(), there's no need for an additional platform enable/disable. Remove them. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 0eed3282a7a..3421be3d85d 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -670,12 +670,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) u8 id1, id2, id3; int r; - if (dssdev->platform_enable) { - r = dssdev->platform_enable(dssdev); - if (r) - return r; - } - /* it seems we have to wait a bit until taal is ready */ msleep(5); @@ -746,8 +740,6 @@ err: omapdss_dsi_display_disable(dssdev); err0: dsi_bus_unlock(); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); return r; } @@ -776,9 +768,6 @@ static void taal_power_off(struct omap_dss_device *dssdev) omapdss_dsi_display_disable(dssdev); - if (dssdev->platform_disable) - dssdev->platform_disable(dssdev); - td->enabled = 0; dsi_bus_unlock(); -- cgit v1.2.3-18-g5258 From 2f1e5f606a1330fa9d1d89e88670c3dec7fbe36f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 9 Apr 2010 13:52:33 +0300 Subject: OMAP: DSS2: Taal: Fix request_irq() error handling Separate gpio_request() and request_irq() error handling. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 3421be3d85d..af0750e91a5 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -603,7 +603,7 @@ static int taal_probe(struct omap_dss_device *dssdev) if (r) { dev_err(&dssdev->dev, "IRQ request failed\n"); gpio_free(gpio); - goto err3; + goto err4; } init_completion(&td->te_completion); @@ -614,16 +614,16 @@ static int taal_probe(struct omap_dss_device *dssdev) r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); if (r) { dev_err(&dssdev->dev, "failed to create sysfs files\n"); - goto err4; + goto err5; } return 0; +err5: + if (td->use_ext_te) + free_irq(gpio_to_irq(dssdev->phy.dsi.ext_te_gpio), dssdev); err4: - if (td->use_ext_te) { - int gpio = dssdev->phy.dsi.ext_te_gpio; - free_irq(gpio_to_irq(gpio), dssdev); - gpio_free(gpio); - } + if (td->use_ext_te) + gpio_free(dssdev->phy.dsi.ext_te_gpio); err3: backlight_device_unregister(bldev); err2: -- cgit v1.2.3-18-g5258 From d803bb6e68872ea474ef8caba33abb47c8ee19da Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 9 Apr 2010 14:01:37 +0300 Subject: OMAP: DSS2: Taal: Remove ESD work cancel from driver probe error handling ESD work is never queued in probe, no need to cancel it on probe error. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index af0750e91a5..b1e968d9e8b 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -627,7 +627,6 @@ err4: err3: backlight_device_unregister(bldev); err2: - cancel_delayed_work_sync(&td->esd_work); destroy_workqueue(td->esd_wq); err1: kfree(td); -- cgit v1.2.3-18-g5258 From f2a8b75c137acb048a627379cf7e93b8b7c29191 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 9 Apr 2010 14:15:12 +0300 Subject: OMAP: DSS2: Taal: Improve taal_power_on() error handling Check return values and bail out on errors. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index b1e968d9e8b..2c2f1924b2c 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -696,16 +696,32 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) td->cabc_broken = true; - taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); - taal_dcs_write_1(DCS_CTRL_DISPLAY, (1<<2) | (1<<5)); /* BL | BCTRL */ + r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); + if (r) + goto err; - taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ + r = taal_dcs_write_1(DCS_CTRL_DISPLAY, + (1<<2) | (1<<5)); /* BL | BCTRL */ + if (r) + goto err; - taal_set_addr_mode(td->rotate, td->mirror); - if (!td->cabc_broken) - taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); + r = taal_dcs_write_1(DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ + if (r) + goto err; - taal_dcs_write_0(DCS_DISPLAY_ON); + r = taal_set_addr_mode(td->rotate, td->mirror); + if (r) + goto err; + + if (!td->cabc_broken) { + r = taal_dcs_write_1(DCS_WRITE_CABC, td->cabc_mode); + if (r) + goto err; + } + + r = taal_dcs_write_0(DCS_DISPLAY_ON); + if (r) + goto err; r = _taal_enable_te(dssdev, td->te_enabled); if (r) -- cgit v1.2.3-18-g5258 From ee52c0ae68c42c5a0c26462b141a521fcc70849a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 12 Apr 2010 09:36:05 +0300 Subject: OMAP: DSS2: Taal: Ensure panel is enabled in enable_te() and run_test() Bail out from taal_enable_te() and taal_run_test() if panel is not enabled. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 31 +++++++++++++++++++++++-------- 1 file changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 2c2f1924b2c..4e594bb50f4 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -946,11 +946,8 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { - struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; - td->te_enabled = enable; - if (enable) r = taal_dcs_write_1(DCS_TEAR_ON, 0); else @@ -973,11 +970,22 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) mutex_lock(&td->lock); dsi_bus_lock(); - r = _taal_enable_te(dssdev, enable); + if (td->enabled) { + r = _taal_enable_te(dssdev, enable); + if (r) + goto err; + } + + td->te_enabled = enable; dsi_bus_unlock(); mutex_unlock(&td->lock); + return 0; +err: + dsi_bus_unlock(); + mutex_unlock(&td->lock); + return r; } @@ -1077,23 +1085,30 @@ static int taal_run_test(struct omap_dss_device *dssdev, int test_num) int r; mutex_lock(&td->lock); + + if (!td->enabled) { + r = -ENODEV; + goto err1; + } + dsi_bus_lock(); r = taal_dcs_read_1(DCS_GET_ID1, &id1); if (r) - goto err; + goto err2; r = taal_dcs_read_1(DCS_GET_ID2, &id2); if (r) - goto err; + goto err2; r = taal_dcs_read_1(DCS_GET_ID3, &id3); if (r) - goto err; + goto err2; dsi_bus_unlock(); mutex_unlock(&td->lock); return 0; -err: +err2: dsi_bus_unlock(); +err1: mutex_unlock(&td->lock); return r; } -- cgit v1.2.3-18-g5258 From 2c2fc151245df37dba17f4ae1760bfa97e4fd3c5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 12 Apr 2010 10:06:14 +0300 Subject: OMAP: DSS2: Taal: Change DSI bus locking to avoid deadlock in ESD work Move dsi_bus_lock/unlock() out of taal_power_on/off() to avoid deadlock in taal_esd_work(). Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 4e594bb50f4..137bad23a64 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -672,8 +672,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) /* it seems we have to wait a bit until taal is ready */ msleep(5); - dsi_bus_lock(); - r = omapdss_dsi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DSI\n"); @@ -744,8 +742,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) omapdss_dsi_vc_enable_hs(TCH, true); - dsi_bus_unlock(); - return 0; err: dev_err(&dssdev->dev, "error while enabling panel, issuing HW reset\n"); @@ -754,8 +750,6 @@ err: omapdss_dsi_display_disable(dssdev); err0: - dsi_bus_unlock(); - return r; } @@ -764,8 +758,6 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; - dsi_bus_lock(); - cancel_delayed_work(&td->esd_work); r = taal_dcs_write_0(DCS_DISPLAY_OFF); @@ -784,8 +776,6 @@ static void taal_power_off(struct omap_dss_device *dssdev) omapdss_dsi_display_disable(dssdev); td->enabled = 0; - - dsi_bus_unlock(); } static int taal_enable(struct omap_dss_device *dssdev) @@ -802,7 +792,12 @@ static int taal_enable(struct omap_dss_device *dssdev) goto err; } + dsi_bus_lock(); + r = taal_power_on(dssdev); + + dsi_bus_unlock(); + if (r) goto err; @@ -825,9 +820,13 @@ static void taal_disable(struct omap_dss_device *dssdev) mutex_lock(&td->lock); + dsi_bus_lock(); + if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) taal_power_off(dssdev); + dsi_bus_unlock(); + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; mutex_unlock(&td->lock); @@ -847,7 +846,12 @@ static int taal_suspend(struct omap_dss_device *dssdev) goto err; } + dsi_bus_lock(); + taal_power_off(dssdev); + + dsi_bus_unlock(); + dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; mutex_unlock(&td->lock); @@ -872,7 +876,12 @@ static int taal_resume(struct omap_dss_device *dssdev) goto err; } + dsi_bus_lock(); + r = taal_power_on(dssdev); + + dsi_bus_unlock(); + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; mutex_unlock(&td->lock); -- cgit v1.2.3-18-g5258 From fed44b7af8d9ce4c2c3d10a2e22e34ab596568a4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 12 Apr 2010 10:25:21 +0300 Subject: OMAP: DSS2: Taal: Check taal_power_on() return value in taal_resume() Change state only if power on was succesful. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 137bad23a64..19b5975a231 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -882,7 +882,10 @@ static int taal_resume(struct omap_dss_device *dssdev) dsi_bus_unlock(); - dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; + if (r) + dssdev->state = OMAP_DSS_DISPLAY_DISABLED; + else + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; mutex_unlock(&td->lock); -- cgit v1.2.3-18-g5258 From 4571a023f5e9b18ca79e67ae6135b26624589ed9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Mon, 12 Apr 2010 10:23:46 +0300 Subject: OMAP: DSS2: Taal: Change ESD work management Move ESD work queuing and cancelling out of taal_power_on/off() to avoid problems related to taal_esd_work() calling the power on/off functions. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 19b5975a231..383003ca092 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -654,7 +654,7 @@ static void taal_remove(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); backlight_device_unregister(bldev); - cancel_delayed_work_sync(&td->esd_work); + cancel_delayed_work(&td->esd_work); destroy_workqueue(td->esd_wq); /* reset, to be sure that the panel is in a valid state */ @@ -725,10 +725,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; -#ifdef TAAL_USE_ESD_CHECK - queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); -#endif - td->enabled = 1; if (!td->intro_printed) { @@ -758,8 +754,6 @@ static void taal_power_off(struct omap_dss_device *dssdev) struct taal_data *td = dev_get_drvdata(&dssdev->dev); int r; - cancel_delayed_work(&td->esd_work); - r = taal_dcs_write_0(DCS_DISPLAY_OFF); if (!r) { r = taal_sleep_in(td); @@ -801,6 +795,10 @@ static int taal_enable(struct omap_dss_device *dssdev) if (r) goto err; +#ifdef TAAL_USE_ESD_CHECK + queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); +#endif + dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; mutex_unlock(&td->lock); @@ -820,6 +818,8 @@ static void taal_disable(struct omap_dss_device *dssdev) mutex_lock(&td->lock); + cancel_delayed_work(&td->esd_work); + dsi_bus_lock(); if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) @@ -846,6 +846,8 @@ static int taal_suspend(struct omap_dss_device *dssdev) goto err; } + cancel_delayed_work(&td->esd_work); + dsi_bus_lock(); taal_power_off(dssdev); @@ -882,10 +884,15 @@ static int taal_resume(struct omap_dss_device *dssdev) dsi_bus_unlock(); - if (r) + if (r) { dssdev->state = OMAP_DSS_DISPLAY_DISABLED; - else + } else { dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; +#ifdef TAAL_USE_ESD_CHECK + queue_delayed_work(td->esd_wq, &td->esd_work, + TAAL_ESD_CHECK_PERIOD); +#endif + } mutex_unlock(&td->lock); -- cgit v1.2.3-18-g5258 From d2b657873839fd401798ba277868fc8442997443 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 15 Apr 2010 12:24:36 +0300 Subject: OMAP: DSS2: Taal: Change probe error handling labels Switch from numbered to named labels to make it easier to add new labels for error handling. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 383003ca092..2f896787468 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -539,7 +539,7 @@ static int taal_probe(struct omap_dss_device *dssdev) td = kzalloc(sizeof(*td), GFP_KERNEL); if (!td) { r = -ENOMEM; - goto err0; + goto err; } td->dssdev = dssdev; @@ -549,7 +549,7 @@ static int taal_probe(struct omap_dss_device *dssdev) if (td->esd_wq == NULL) { dev_err(&dssdev->dev, "can't create ESD workqueue\n"); r = -ENOMEM; - goto err1; + goto err_wq; } INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); @@ -571,7 +571,7 @@ static int taal_probe(struct omap_dss_device *dssdev) &taal_bl_ops, &props); if (IS_ERR(bldev)) { r = PTR_ERR(bldev); - goto err2; + goto err_bl; } td->bldev = bldev; @@ -591,7 +591,7 @@ static int taal_probe(struct omap_dss_device *dssdev) r = gpio_request(gpio, "taal irq"); if (r) { dev_err(&dssdev->dev, "GPIO request failed\n"); - goto err3; + goto err_gpio; } gpio_direction_input(gpio); @@ -603,7 +603,7 @@ static int taal_probe(struct omap_dss_device *dssdev) if (r) { dev_err(&dssdev->dev, "IRQ request failed\n"); gpio_free(gpio); - goto err4; + goto err_irq; } init_completion(&td->te_completion); @@ -614,23 +614,23 @@ static int taal_probe(struct omap_dss_device *dssdev) r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); if (r) { dev_err(&dssdev->dev, "failed to create sysfs files\n"); - goto err5; + goto err_sysfs; } return 0; -err5: +err_sysfs: if (td->use_ext_te) free_irq(gpio_to_irq(dssdev->phy.dsi.ext_te_gpio), dssdev); -err4: +err_irq: if (td->use_ext_te) gpio_free(dssdev->phy.dsi.ext_te_gpio); -err3: +err_gpio: backlight_device_unregister(bldev); -err2: +err_bl: destroy_workqueue(td->esd_wq); -err1: +err_wq: kfree(td); -err0: +err: return r; } -- cgit v1.2.3-18-g5258 From 7ae2fb1192f0510991a833ca1dd4baace9bd8977 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 13 Apr 2010 10:57:52 +0300 Subject: OMAP: DSS2: Taal: Add proper external TE support Add gpio irq based external TE support with timeout. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 93 +++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 18 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 2f896787468..e52631efe7e 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -65,6 +64,8 @@ /* #define TAAL_USE_ESD_CHECK */ #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) +static irqreturn_t taal_te_isr(int irq, void *data); +static void taal_te_timeout_work_callback(struct work_struct *work); static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); struct taal_data { @@ -85,7 +86,15 @@ struct taal_data { bool te_enabled; bool use_ext_te; - struct completion te_completion; + + atomic_t do_update; + struct { + u16 x; + u16 y; + u16 w; + u16 h; + } update_region; + struct delayed_work te_timeout_work; bool use_dsi_bl; @@ -346,16 +355,6 @@ static void taal_get_resolution(struct omap_dss_device *dssdev, } } -static irqreturn_t taal_te_isr(int irq, void *data) -{ - struct omap_dss_device *dssdev = data; - struct taal_data *td = dev_get_drvdata(&dssdev->dev); - - complete_all(&td->te_completion); - - return IRQ_HANDLED; -} - static ssize_t taal_num_errors_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -545,6 +544,8 @@ static int taal_probe(struct omap_dss_device *dssdev) mutex_init(&td->lock); + atomic_set(&td->do_update, 0); + td->esd_wq = create_singlethread_workqueue("taal_esd"); if (td->esd_wq == NULL) { dev_err(&dssdev->dev, "can't create ESD workqueue\n"); @@ -606,9 +607,12 @@ static int taal_probe(struct omap_dss_device *dssdev) goto err_irq; } - init_completion(&td->te_completion); + INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, + taal_te_timeout_work_callback); td->use_ext_te = true; + + dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } r = sysfs_create_group(&dssdev->dev.kobj, &taal_attr_group); @@ -909,6 +913,47 @@ static void taal_framedone_cb(int err, void *data) dsi_bus_unlock(); } +static irqreturn_t taal_te_isr(int irq, void *data) +{ + struct omap_dss_device *dssdev = data; + struct taal_data *td = dev_get_drvdata(&dssdev->dev); + int old; + int r; + + old = atomic_cmpxchg(&td->do_update, 1, 0); + + if (old) { + cancel_delayed_work(&td->te_timeout_work); + + r = omap_dsi_update(dssdev, TCH, + td->update_region.x, + td->update_region.y, + td->update_region.w, + td->update_region.h, + taal_framedone_cb, dssdev); + if (r) + goto err; + } + + return IRQ_HANDLED; +err: + dev_err(&dssdev->dev, "start update failed\n"); + dsi_bus_unlock(); + return IRQ_HANDLED; +} + +static void taal_te_timeout_work_callback(struct work_struct *work) +{ + struct taal_data *td = container_of(work, struct taal_data, + te_timeout_work.work); + struct omap_dss_device *dssdev = td->dssdev; + + dev_err(&dssdev->dev, "TE not received for 250ms!\n"); + + atomic_set(&td->do_update, 0); + dsi_bus_unlock(); +} + static int taal_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { @@ -933,10 +978,21 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - r = omap_dsi_update(dssdev, TCH, x, y, w, h, - taal_framedone_cb, dssdev); - if (r) - goto err; + if (td->te_enabled && td->use_ext_te) { + td->update_region.x = x; + td->update_region.y = y; + td->update_region.w = w; + td->update_region.h = h; + barrier(); + schedule_delayed_work(&td->te_timeout_work, + msecs_to_jiffies(250)); + atomic_set(&td->do_update, 1); + } else { + r = omap_dsi_update(dssdev, TCH, x, y, w, h, + taal_framedone_cb, dssdev); + if (r) + goto err; + } /* note: no bus_unlock here. unlock is in framedone_cb */ mutex_unlock(&td->lock); @@ -972,7 +1028,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) else r = taal_dcs_write_0(DCS_TEAR_OFF); - omapdss_dsi_enable_te(dssdev, enable); + if (!td->use_ext_te) + omapdss_dsi_enable_te(dssdev, enable); /* XXX for some reason, DSI TE breaks if we don't wait here. * Panel bug? Needs more studying */ -- cgit v1.2.3-18-g5258 From 8d3573c88a5a7b67a5fec5eb457efa3616fe56b7 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:23:44 +0300 Subject: OMAP: DSS2: Taal: Use Nokia DSI panel data Get board specific information from the Nokia DSI panel data structure instead of the DSS. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 59 ++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 21 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index e52631efe7e..df720c31288 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -33,6 +33,7 @@ #include #include +#include /* DSI Virtual channel. Hardcoded for now. */ #define TCH 0 @@ -85,7 +86,6 @@ struct taal_data { bool mirror; bool te_enabled; - bool use_ext_te; atomic_t do_update; struct { @@ -107,6 +107,12 @@ struct taal_data { struct delayed_work esd_work; }; +static inline struct nokia_dsi_panel_data +*get_panel_data(const struct omap_dss_device *dssdev) +{ + return (struct nokia_dsi_panel_data *) dssdev->data; +} + static void taal_esd_work(struct work_struct *work); static void hw_guard_start(struct taal_data *td, int guard_msec) @@ -288,6 +294,7 @@ static int taal_bl_update_status(struct backlight_device *dev) { struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; int level; @@ -310,10 +317,10 @@ static int taal_bl_update_status(struct backlight_device *dev) r = 0; } } else { - if (!dssdev->set_backlight) + if (!panel_data->set_backlight) r = -EINVAL; else - r = dssdev->set_backlight(dssdev, level); + r = panel_data->set_backlight(dssdev, level); } mutex_unlock(&td->lock); @@ -503,16 +510,18 @@ static struct attribute_group taal_attr_group = { static void taal_hw_reset(struct omap_dss_device *dssdev) { - if (dssdev->reset_gpio == -1) + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); + + if (panel_data->reset_gpio == -1) return; - gpio_set_value(dssdev->reset_gpio, 1); + gpio_set_value(panel_data->reset_gpio, 1); udelay(10); /* reset the panel */ - gpio_set_value(dssdev->reset_gpio, 0); + gpio_set_value(panel_data->reset_gpio, 0); /* assert reset for at least 10us */ udelay(10); - gpio_set_value(dssdev->reset_gpio, 1); + gpio_set_value(panel_data->reset_gpio, 1); /* wait 5ms after releasing reset */ msleep(5); } @@ -522,6 +531,7 @@ static int taal_probe(struct omap_dss_device *dssdev) struct backlight_properties props; struct taal_data *td; struct backlight_device *bldev; + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; const struct omap_video_timings taal_panel_timings = { @@ -531,6 +541,11 @@ static int taal_probe(struct omap_dss_device *dssdev) dev_dbg(&dssdev->dev, "probe\n"); + if (!panel_data || !panel_data->name) { + r = -EINVAL; + goto err; + } + dssdev->panel.config = OMAP_DSS_LCD_TFT; dssdev->panel.timings = taal_panel_timings; dssdev->ctrl.pixel_size = 24; @@ -561,7 +576,7 @@ static int taal_probe(struct omap_dss_device *dssdev) /* if no platform set_backlight() defined, presume DSI backlight * control */ memset(&props, 0, sizeof(struct backlight_properties)); - if (!dssdev->set_backlight) + if (!panel_data->set_backlight) td->use_dsi_bl = true; if (td->use_dsi_bl) @@ -586,8 +601,8 @@ static int taal_probe(struct omap_dss_device *dssdev) taal_bl_update_status(bldev); - if (dssdev->phy.dsi.ext_te) { - int gpio = dssdev->phy.dsi.ext_te_gpio; + if (panel_data->use_ext_te) { + int gpio = panel_data->ext_te_gpio; r = gpio_request(gpio, "taal irq"); if (r) { @@ -610,8 +625,6 @@ static int taal_probe(struct omap_dss_device *dssdev) INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, taal_te_timeout_work_callback); - td->use_ext_te = true; - dev_dbg(&dssdev->dev, "Using GPIO TE\n"); } @@ -623,11 +636,11 @@ static int taal_probe(struct omap_dss_device *dssdev) return 0; err_sysfs: - if (td->use_ext_te) - free_irq(gpio_to_irq(dssdev->phy.dsi.ext_te_gpio), dssdev); + if (panel_data->use_ext_te) + free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); err_irq: - if (td->use_ext_te) - gpio_free(dssdev->phy.dsi.ext_te_gpio); + if (panel_data->use_ext_te) + gpio_free(panel_data->ext_te_gpio); err_gpio: backlight_device_unregister(bldev); err_bl: @@ -641,14 +654,15 @@ err: static void taal_remove(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); struct backlight_device *bldev; dev_dbg(&dssdev->dev, "remove\n"); sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); - if (td->use_ext_te) { - int gpio = dssdev->phy.dsi.ext_te_gpio; + if (panel_data->use_ext_te) { + int gpio = panel_data->ext_te_gpio; free_irq(gpio_to_irq(gpio), dssdev); gpio_free(gpio); } @@ -958,6 +972,7 @@ static int taal_update(struct omap_dss_device *dssdev, u16 x, u16 y, u16 w, u16 h) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); @@ -978,7 +993,7 @@ static int taal_update(struct omap_dss_device *dssdev, if (r) goto err; - if (td->te_enabled && td->use_ext_te) { + if (td->te_enabled && panel_data->use_ext_te) { td->update_region.x = x; td->update_region.y = y; td->update_region.w = w; @@ -1021,6 +1036,7 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; if (enable) @@ -1028,7 +1044,7 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) else r = taal_dcs_write_0(DCS_TEAR_OFF); - if (!td->use_ext_te) + if (!panel_data->use_ext_te) omapdss_dsi_enable_te(dssdev, enable); /* XXX for some reason, DSI TE breaks if we don't wait here. @@ -1272,6 +1288,7 @@ static void taal_esd_work(struct work_struct *work) struct taal_data *td = container_of(work, struct taal_data, esd_work.work); struct omap_dss_device *dssdev = td->dssdev; + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); u8 state1, state2; int r; @@ -1312,7 +1329,7 @@ static void taal_esd_work(struct work_struct *work) } /* Self-diagnostics result is also shown on TE GPIO line. We need * to re-enable TE after self diagnostics */ - if (td->use_ext_te && td->te_enabled) { + if (td->te_enabled && panel_data->use_ext_te) { r = taal_dcs_write_1(DCS_TEAR_ON, 0); if (r) goto err; -- cgit v1.2.3-18-g5258 From 448dfe968099b130e6163bdcb4b839a2fb36484d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 15 Apr 2010 12:42:16 +0300 Subject: OMAP: DSS2: Taal: Configure ESD check in DSI panel data Make ESD check usage configurable in DSI panel data, as opposed to a define. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index df720c31288..eb95e97fd9b 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -62,7 +62,6 @@ #define DCS_GET_ID2 0xdb #define DCS_GET_ID3 0xdc -/* #define TAAL_USE_ESD_CHECK */ #define TAAL_ESD_CHECK_PERIOD msecs_to_jiffies(5000) static irqreturn_t taal_te_isr(int irq, void *data); @@ -793,6 +792,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) static int taal_enable(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "enable\n"); @@ -813,9 +813,9 @@ static int taal_enable(struct omap_dss_device *dssdev) if (r) goto err; -#ifdef TAAL_USE_ESD_CHECK - queue_delayed_work(td->esd_wq, &td->esd_work, TAAL_ESD_CHECK_PERIOD); -#endif + if (panel_data->use_esd_check) + queue_delayed_work(td->esd_wq, &td->esd_work, + TAAL_ESD_CHECK_PERIOD); dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; @@ -885,6 +885,7 @@ err: static int taal_resume(struct omap_dss_device *dssdev) { struct taal_data *td = dev_get_drvdata(&dssdev->dev); + struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; dev_dbg(&dssdev->dev, "resume\n"); @@ -906,10 +907,9 @@ static int taal_resume(struct omap_dss_device *dssdev) dssdev->state = OMAP_DSS_DISPLAY_DISABLED; } else { dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; -#ifdef TAAL_USE_ESD_CHECK - queue_delayed_work(td->esd_wq, &td->esd_work, - TAAL_ESD_CHECK_PERIOD); -#endif + if (panel_data->use_esd_check) + queue_delayed_work(td->esd_wq, &td->esd_work, + TAAL_ESD_CHECK_PERIOD); } mutex_unlock(&td->lock); -- cgit v1.2.3-18-g5258 From e7f6c3f2fbad84aacff1483c0f144364d8be82bc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 15 Apr 2010 12:55:38 +0300 Subject: OMAP: DSS2: Taal: Add panel specific configuration structure Add a structure for panel specific configration to be able to support more than one panel in the future. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 108 ++++++++++++++++++++++++------ 1 file changed, 87 insertions(+), 21 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index eb95e97fd9b..311bd5fb14a 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -68,6 +68,58 @@ static irqreturn_t taal_te_isr(int irq, void *data); static void taal_te_timeout_work_callback(struct work_struct *work); static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); +/** + * struct panel_config - panel configuration + * @name: panel name + * @type: panel type + * @timings: panel resolution + * @sleep: various panel specific delays, passed to msleep() if non-zero + * @reset_sequence: reset sequence timings, passed to udelay() if non-zero + */ +struct panel_config { + const char *name; + int type; + + struct omap_video_timings timings; + + struct { + unsigned int sleep_in; + unsigned int sleep_out; + unsigned int hw_reset; + unsigned int enable_te; + } sleep; + + struct { + unsigned int high; + unsigned int low; + } reset_sequence; +}; + +enum { + PANEL_TAAL, +}; + +static struct panel_config panel_configs[] = { + { + .name = "taal", + .type = PANEL_TAAL, + .timings = { + .x_res = 864, + .y_res = 480, + }, + .sleep = { + .sleep_in = 5, + .sleep_out = 5, + .hw_reset = 5, + .enable_te = 100, /* possible panel bug */ + }, + .reset_sequence = { + .high = 10, + .low = 10, + }, + }, +}; + struct taal_data { struct mutex lock; @@ -104,6 +156,8 @@ struct taal_data { struct workqueue_struct *esd_wq; struct delayed_work esd_work; + + struct panel_config *panel_config; }; static inline struct nokia_dsi_panel_data @@ -173,7 +227,8 @@ static int taal_sleep_in(struct taal_data *td) hw_guard_start(td, 120); - msleep(5); + if (td->panel_config->sleep.sleep_in) + msleep(td->panel_config->sleep.sleep_in); return 0; } @@ -190,7 +245,8 @@ static int taal_sleep_out(struct taal_data *td) hw_guard_start(td, 120); - msleep(5); + if (td->panel_config->sleep.sleep_out) + msleep(td->panel_config->sleep.sleep_out); return 0; } @@ -509,20 +565,24 @@ static struct attribute_group taal_attr_group = { static void taal_hw_reset(struct omap_dss_device *dssdev) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); if (panel_data->reset_gpio == -1) return; gpio_set_value(panel_data->reset_gpio, 1); - udelay(10); + if (td->panel_config->reset_sequence.high) + udelay(td->panel_config->reset_sequence.high); /* reset the panel */ gpio_set_value(panel_data->reset_gpio, 0); - /* assert reset for at least 10us */ - udelay(10); + /* assert reset */ + if (td->panel_config->reset_sequence.low) + udelay(td->panel_config->reset_sequence.low); gpio_set_value(panel_data->reset_gpio, 1); - /* wait 5ms after releasing reset */ - msleep(5); + /* wait after releasing reset */ + if (td->panel_config->sleep.hw_reset) + msleep(td->panel_config->sleep.hw_reset); } static int taal_probe(struct omap_dss_device *dssdev) @@ -531,12 +591,8 @@ static int taal_probe(struct omap_dss_device *dssdev) struct taal_data *td; struct backlight_device *bldev; struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); - int r; - - const struct omap_video_timings taal_panel_timings = { - .x_res = 864, - .y_res = 480, - }; + struct panel_config *panel_config = NULL; + int r, i; dev_dbg(&dssdev->dev, "probe\n"); @@ -545,8 +601,20 @@ static int taal_probe(struct omap_dss_device *dssdev) goto err; } + for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { + if (strcmp(panel_data->name, panel_configs[i].name) == 0) { + panel_config = &panel_configs[i]; + break; + } + } + + if (!panel_config) { + r = -EINVAL; + goto err; + } + dssdev->panel.config = OMAP_DSS_LCD_TFT; - dssdev->panel.timings = taal_panel_timings; + dssdev->panel.timings = panel_config->timings; dssdev->ctrl.pixel_size = 24; td = kzalloc(sizeof(*td), GFP_KERNEL); @@ -555,6 +623,7 @@ static int taal_probe(struct omap_dss_device *dssdev) goto err; } td->dssdev = dssdev; + td->panel_config = panel_config; mutex_init(&td->lock); @@ -686,9 +755,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) u8 id1, id2, id3; int r; - /* it seems we have to wait a bit until taal is ready */ - msleep(5); - r = omapdss_dsi_display_enable(dssdev); if (r) { dev_err(&dssdev->dev, "failed to enable DSI\n"); @@ -774,7 +840,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) r = taal_dcs_write_0(DCS_DISPLAY_OFF); if (!r) { r = taal_sleep_in(td); - /* wait a bit so that the message goes through */ + /* HACK: wait a bit so that the message goes through */ msleep(10); } @@ -1036,6 +1102,7 @@ static int taal_sync(struct omap_dss_device *dssdev) static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) { + struct taal_data *td = dev_get_drvdata(&dssdev->dev); struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); int r; @@ -1047,9 +1114,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) if (!panel_data->use_ext_te) omapdss_dsi_enable_te(dssdev, enable); - /* XXX for some reason, DSI TE breaks if we don't wait here. - * Panel bug? Needs more studying */ - msleep(100); + if (td->panel_config->sleep.enable_te) + msleep(td->panel_config->sleep.enable_te); return r; } -- cgit v1.2.3-18-g5258 From 0f45bddf0420ace2ddb7c4faa11f139b42c6eea5 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 16 Apr 2010 14:21:14 +0300 Subject: OMAP: DSS2: Taal: Print panel name in addition to revision The driver will support other panels in addition to Taal, print also the name. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 311bd5fb14a..cbe0214e2f0 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -811,8 +811,8 @@ static int taal_power_on(struct omap_dss_device *dssdev) td->enabled = 1; if (!td->intro_printed) { - dev_info(&dssdev->dev, "revision %02x.%02x.%02x\n", - id1, id2, id3); + dev_info(&dssdev->dev, "%s panel revision %02x.%02x.%02x\n", + td->panel_config->name, id1, id2, id3); if (td->cabc_broken) dev_info(&dssdev->dev, "old Taal version, CABC disabled\n"); -- cgit v1.2.3-18-g5258 From c8cd4547dcb350331cf80f5729ee648d8120783e Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:24:46 +0300 Subject: OMAP: DSS2: Taal: Add regulator configuration support Add support for configuring regulators in the panel specific configuration data. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 83 +++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index cbe0214e2f0..941f1f208c9 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,73 @@ static irqreturn_t taal_te_isr(int irq, void *data); static void taal_te_timeout_work_callback(struct work_struct *work); static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); +struct panel_regulator { + struct regulator *regulator; + const char *name; + int min_uV; + int max_uV; +}; + +static void free_regulators(struct panel_regulator *regulators, int n) +{ + int i; + + for (i = 0; i < n; i++) { + /* disable/put in reverse order */ + regulator_disable(regulators[n - i - 1].regulator); + regulator_put(regulators[n - i - 1].regulator); + } +} + +static int init_regulators(struct omap_dss_device *dssdev, + struct panel_regulator *regulators, int n) +{ + int r, i, v; + + for (i = 0; i < n; i++) { + struct regulator *reg; + + reg = regulator_get(&dssdev->dev, regulators[i].name); + if (IS_ERR(reg)) { + dev_err(&dssdev->dev, "failed to get regulator %s\n", + regulators[i].name); + r = PTR_ERR(reg); + goto err; + } + + /* FIXME: better handling of fixed vs. variable regulators */ + v = regulator_get_voltage(reg); + if (v < regulators[i].min_uV || v > regulators[i].max_uV) { + r = regulator_set_voltage(reg, regulators[i].min_uV, + regulators[i].max_uV); + if (r) { + dev_err(&dssdev->dev, + "failed to set regulator %s voltage\n", + regulators[i].name); + regulator_put(reg); + goto err; + } + } + + r = regulator_enable(reg); + if (r) { + dev_err(&dssdev->dev, "failed to enable regulator %s\n", + regulators[i].name); + regulator_put(reg); + goto err; + } + + regulators[i].regulator = reg; + } + + return 0; + +err: + free_regulators(regulators, i); + + return r; +} + /** * struct panel_config - panel configuration * @name: panel name @@ -75,6 +143,8 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); * @timings: panel resolution * @sleep: various panel specific delays, passed to msleep() if non-zero * @reset_sequence: reset sequence timings, passed to udelay() if non-zero + * @regulators: array of panel regulators + * @num_regulators: number of regulators in the array */ struct panel_config { const char *name; @@ -93,6 +163,9 @@ struct panel_config { unsigned int high; unsigned int low; } reset_sequence; + + struct panel_regulator *regulators; + int num_regulators; }; enum { @@ -629,6 +702,11 @@ static int taal_probe(struct omap_dss_device *dssdev) atomic_set(&td->do_update, 0); + r = init_regulators(dssdev, panel_config->regulators, + panel_config->num_regulators); + if (r) + goto err_reg; + td->esd_wq = create_singlethread_workqueue("taal_esd"); if (td->esd_wq == NULL) { dev_err(&dssdev->dev, "can't create ESD workqueue\n"); @@ -714,6 +792,8 @@ err_gpio: err_bl: destroy_workqueue(td->esd_wq); err_wq: + free_regulators(panel_config->regulators, panel_config->num_regulators); +err_reg: kfree(td); err: return r; @@ -746,6 +826,9 @@ static void taal_remove(struct omap_dss_device *dssdev) /* reset, to be sure that the panel is in a valid state */ taal_hw_reset(dssdev); + free_regulators(td->panel_config->regulators, + td->panel_config->num_regulators); + kfree(td); } -- cgit v1.2.3-18-g5258 From 1e8943dbae98f48fc485fb9a671e94972b234cb2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 15 Apr 2010 17:07:39 +0300 Subject: OMAP: DSS2: Taal: CABC workaround is Taal specific Prepare for supporting panels other than Taal in this driver. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 941f1f208c9..2a91d5662c0 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -856,8 +856,9 @@ static int taal_power_on(struct omap_dss_device *dssdev) if (r) goto err; - /* on early revisions CABC is broken */ - if (id2 == 0x00 || id2 == 0xff || id2 == 0x81) + /* on early Taal revisions CABC is broken */ + if (td->panel_config->type == PANEL_TAAL && + (id2 == 0x00 || id2 == 0xff || id2 == 0x81)) td->cabc_broken = true; r = taal_dcs_write_1(DCS_BRIGHTNESS, 0xff); -- cgit v1.2.3-18-g5258 From 481dfa0eb915fb248c93ea37cd6e669b91ee9f8e Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Apr 2010 22:50:04 +0200 Subject: OMAP: DSS2: DSI: Disable PCKFREE on error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not leave the free running pixel clock enabled if the DSI PLL reset times out. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 613796b54f0..72b859cc3a5 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1100,6 +1100,7 @@ int dsi_pll_init(struct omap_dss_device *dssdev, bool enable_hsclk, if (wait_for_bit_change(DSI_PLL_STATUS, 0, 1) != 1) { DSSERR("PLL not coming out of reset.\n"); r = -ENODEV; + dispc_pck_free_enable(0); goto err1; } -- cgit v1.2.3-18-g5258 From ebf0a3fef2240983fbc994f15d8c3d8a20102480 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Apr 2010 22:50:05 +0200 Subject: OMAP: DSS2: DSI: Print an error message if DSI clock calc fails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print an error message if dsi_calc_clock_rates() fails just like it's done when dispc_calc_clock_rates() fails. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 72b859cc3a5..04d84d13488 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2967,8 +2967,10 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) cinfo.regm3 = dssdev->phy.dsi.div.regm3; cinfo.regm4 = dssdev->phy.dsi.div.regm4; r = dsi_calc_clock_rates(&cinfo); - if (r) + if (r) { + DSSERR("Failed to calc dsi clocks\n"); return r; + } r = dsi_pll_set_clock_div(&cinfo); if (r) { -- cgit v1.2.3-18-g5258 From e406f9079b993f4d5d7b5a3452b11df81ff2aef0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:28:12 +0300 Subject: OMAP: DSS2: DSI: Wait for DSI PLL clocks to be active before selecting them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The TRM tells us to wait for the DSI PLL derived clocks to become active before selecting them for use. I didn't actually have any issues which this would fix but according to the TRM it seems to be the right thing to do. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 12 ++++++++++++ drivers/video/omap2/dss/dss.c | 6 ++++++ drivers/video/omap2/dss/dss.h | 8 ++++++++ 3 files changed, 26 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 04d84d13488..6035904f131 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3195,6 +3195,18 @@ int dsi_init_display(struct omap_dss_device *dssdev) return 0; } +void dsi_wait_dsi1_pll_active(void) +{ + if (wait_for_bit_change(DSI_PLL_STATUS, 7, 1) != 1) + DSSERR("DSI1 PLL clock not active\n"); +} + +void dsi_wait_dsi2_pll_active(void) +{ + if (wait_for_bit_change(DSI_PLL_STATUS, 8, 1) != 1) + DSSERR("DSI2 PLL clock not active\n"); +} + int dsi_init(struct platform_device *pdev) { u32 rev; diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 24b18258654..77c3621c917 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c @@ -265,6 +265,9 @@ void dss_select_dispc_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + if (clk_src == DSS_SRC_DSI1_PLL_FCLK) + dsi_wait_dsi1_pll_active(); + REG_FLD_MOD(DSS_CONTROL, b, 0, 0); /* DISPC_CLK_SWITCH */ dss.dispc_clk_source = clk_src; @@ -279,6 +282,9 @@ void dss_select_dsi_clk_source(enum dss_clk_source clk_src) b = clk_src == DSS_SRC_DSS1_ALWON_FCLK ? 0 : 1; + if (clk_src == DSS_SRC_DSI2_PLL_FCLK) + dsi_wait_dsi2_pll_active(); + REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ dss.dsi_clk_source = clk_src; diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 786f433fd57..66e8e97d06a 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -281,6 +281,8 @@ void dsi_pll_uninit(void); void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, u32 fifo_size, enum omap_burst_size *burst_size, u32 *fifo_low, u32 *fifo_high); +void dsi_wait_dsi1_pll_active(void); +void dsi_wait_dsi2_pll_active(void); #else static inline int dsi_init(struct platform_device *pdev) { @@ -289,6 +291,12 @@ static inline int dsi_init(struct platform_device *pdev) static inline void dsi_exit(void) { } +static inline void dsi_wait_dsi1_pll_active(void) +{ +} +static inline void dsi_wait_dsi2_pll_active(void) +{ +} #endif /* DPI */ -- cgit v1.2.3-18-g5258 From d73701044b70924f450fc6b161d952b38b7d0182 Mon Sep 17 00:00:00 2001 From: Ville Syrjälä Date: Thu, 22 Apr 2010 22:50:09 +0200 Subject: OMAP: DSS2: DSI: Disable interface when disabling the display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Once the DSI PLL is separated from the DSI display a full DSI reset will not be performed every time the display is enabled so the interface and VCs must be disabled when disabling the display. If the VCs are not disabled some register accesses will abort. Signed-off-by: Ville Syrjälä Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 6035904f131..20291570f7a 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3068,6 +3068,13 @@ err0: static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev) { + /* disable interface */ + dsi_if_enable(0); + dsi_vc_enable(0, 0); + dsi_vc_enable(1, 0); + dsi_vc_enable(2, 0); + dsi_vc_enable(3, 0); + dss_select_dispc_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dss_select_dsi_clk_source(DSS_SRC_DSS1_ALWON_FCLK); dsi_complexio_uninit(); -- cgit v1.2.3-18-g5258 From 9ecd96842bc6312fdb2f84b6379a6f92686e2fd0 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 30 Apr 2010 11:24:33 +0300 Subject: OMAP: DSS2: DSI: change dsi_vc_config_l4/vp() Change dsi_vc_config_l4/vp() to loop for the VC_BUSY flag to change, and return an error if it fails. Busy looping is bad, but there's no interrupt that can be used for all the cases where VC can be busy. So the caller should first try to make sure that the VC is not busy, if possible, and then call dsi_vc_config_l4/vp(). Most notable case when the caller cannot be sure if the VC is busy is after frame has been sent. Usually DSI buffers have been emptied until we need to reconfig the VC, but in some rare cases the VC can still be busy, and this patch will handle that case. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 20291570f7a..bbed3a13f9a 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -1743,42 +1743,52 @@ static void dsi_vc_initial_config(int channel) dsi.vc[channel].mode = DSI_VC_MODE_L4; } -static void dsi_vc_config_l4(int channel) +static int dsi_vc_config_l4(int channel) { if (dsi.vc[channel].mode == DSI_VC_MODE_L4) - return; + return 0; DSSDBGF("%d", channel); dsi_vc_enable(channel, 0); - if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ + /* VC_BUSY */ + if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { DSSERR("vc(%d) busy when trying to config for L4\n", channel); + return -EIO; + } REG_FLD_MOD(DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_L4; + + return 0; } -static void dsi_vc_config_vp(int channel) +static int dsi_vc_config_vp(int channel) { if (dsi.vc[channel].mode == DSI_VC_MODE_VP) - return; + return 0; DSSDBGF("%d", channel); dsi_vc_enable(channel, 0); - if (REG_GET(DSI_VC_CTRL(channel), 15, 15)) /* VC_BUSY */ + /* VC_BUSY */ + if (wait_for_bit_change(DSI_VC_CTRL(channel), 15, 0) != 0) { DSSERR("vc(%d) busy when trying to config for VP\n", channel); + return -EIO; + } REG_FLD_MOD(DSI_VC_CTRL(channel), 1, 1, 1); /* SOURCE, 1 = video port */ dsi_vc_enable(channel, 1); dsi.vc[channel].mode = DSI_VC_MODE_VP; + + return 0; } -- cgit v1.2.3-18-g5258 From ab83b14c829e35436b423947bb5b151133314346 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:31:01 +0300 Subject: OMAP: DSS2: DSI: use BTA to end the frame transfer Previously a work was started on FRAMEDONE interrupt, and this work either sent a BTA synchronously or looped until TE_SIZE was zero, to wait for the end of the transfer. This patch changes a BTA to be sent asynchronously from FRAMEDONE interrupt, and when a BTA interrupt is received, the transfer is finished. This way we do the whole process asynchronously, and also inside interrupt context. This will give us much better latency to handle the end of the frame than with the previous work based solution. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dispc.c | 5 +- drivers/video/omap2/dss/dsi.c | 116 +++++++++++++++++++--------------------- 2 files changed, 58 insertions(+), 63 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index b8c16034f1e..5ecdc000409 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -3028,7 +3029,7 @@ void dispc_fake_vsync_irq(void) u32 irqstatus = DISPC_IRQ_VSYNC; int i; - local_irq_disable(); + WARN_ON(!in_interrupt()); for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { struct omap_dispc_isr_data *isr_data; @@ -3040,8 +3041,6 @@ void dispc_fake_vsync_irq(void) if (isr_data->mask & irqstatus) isr_data->isr(isr_data->arg, irqstatus); } - - local_irq_enable(); } #endif diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index bbed3a13f9a..32297b4f7ab 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -232,6 +232,7 @@ static struct unsigned pll_locked; struct completion bta_completion; + void (*bta_callback)(void); int update_channel; struct dsi_update_region update_region; @@ -240,7 +241,6 @@ static struct struct workqueue_struct *workqueue; - struct work_struct framedone_work; void (*framedone_callback)(int, void *); void *framedone_data; @@ -511,9 +511,13 @@ void dsi_irq_handler(void) dss_collect_irq_stats(vcstatus, dsi.irq_stats.vc_irqs[i]); #endif - if (vcstatus & DSI_VC_IRQ_BTA) + if (vcstatus & DSI_VC_IRQ_BTA) { complete(&dsi.bta_completion); + if (dsi.bta_callback) + dsi.bta_callback(); + } + if (vcstatus & DSI_VC_IRQ_ERROR_MASK) { DSSERR("DSI VC(%d) error, vc irqstatus %x\n", i, vcstatus); @@ -2756,69 +2760,70 @@ static void dsi_te_timeout(unsigned long arg) } #endif -static void dsi_framedone_timeout_work_callback(struct work_struct *work) +static void dsi_handle_framedone(int error) { - int r; const int channel = dsi.update_channel; - DSSERR("Framedone not received for 250ms!\n"); + cancel_delayed_work(&dsi.framedone_timeout_work); - /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after - * 250ms which would conflict with this timeout work. What should be - * done is first cancel the transfer on the HW, and then cancel the - * possibly scheduled framedone work */ + dsi_vc_disable_bta_irq(channel); /* SIDLEMODE back to smart-idle */ dispc_enable_sidle(); + dsi.bta_callback = NULL; + if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ } - /* Send BTA after the frame. We need this for the TE to work, as TE - * trigger is only sent for BTAs without preceding packet. Thus we need - * to BTA after the pixel packets so that next BTA will cause TE - * trigger. - * - * This is not needed when TE is not in use, but we do it anyway to - * make sure that the transfer has been completed. It would be more - * optimal, but more complex, to wait only just before starting next - * transfer. */ - r = dsi_vc_send_bta_sync(channel); - if (r) - DSSERR("BTA after framedone failed\n"); - /* RX_FIFO_NOT_EMPTY */ if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { DSSERR("Received error during frame transfer:\n"); dsi_vc_flush_receive_data(channel); + if (!error) + error = -EIO; } - dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); + dsi.framedone_callback(error, dsi.framedone_data); + + if (!error) + dsi_perf_show("DISPC"); } -static void dsi_framedone_irq_callback(void *data, u32 mask) +static void dsi_framedone_timeout_work_callback(struct work_struct *work) { - int r; - /* Note: We get FRAMEDONE when DISPC has finished sending pixels and - * turns itself off. However, DSI still has the pixels in its buffers, - * and is sending the data. - */ + /* XXX While extremely unlikely, we could get FRAMEDONE interrupt after + * 250ms which would conflict with this timeout work. What should be + * done is first cancel the transfer on the HW, and then cancel the + * possibly scheduled framedone work. However, cancelling the transfer + * on the HW is buggy, and would probably require resetting the whole + * DSI */ - /* SIDLEMODE back to smart-idle */ - dispc_enable_sidle(); + DSSERR("Framedone not received for 250ms!\n"); - r = queue_work(dsi.workqueue, &dsi.framedone_work); - BUG_ON(r == 0); + dsi_handle_framedone(-ETIMEDOUT); } -static void dsi_handle_framedone(void) +static void dsi_framedone_bta_callback(void) +{ + dsi_handle_framedone(0); + +#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC + dispc_fake_vsync_irq(); +#endif +} + +static void dsi_framedone_irq_callback(void *data, u32 mask) { - int r; const int channel = dsi.update_channel; + int r; - DSSDBG("FRAMEDONE\n"); + /* Note: We get FRAMEDONE when DISPC has finished sending pixels and + * turns itself off. However, DSI still has the pixels in its buffers, + * and is sending the data. + */ if (dsi.te_enabled) { /* enable LP_RX_TO again after the TE */ @@ -2833,33 +2838,25 @@ static void dsi_handle_framedone(void) * This is not needed when TE is not in use, but we do it anyway to * make sure that the transfer has been completed. It would be more * optimal, but more complex, to wait only just before starting next - * transfer. */ - r = dsi_vc_send_bta_sync(channel); - if (r) - DSSERR("BTA after framedone failed\n"); - - /* RX_FIFO_NOT_EMPTY */ - if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { - DSSERR("Received error during frame transfer:\n"); - dsi_vc_flush_receive_data(channel); - } - -#ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC - dispc_fake_vsync_irq(); -#endif -} - -static void dsi_framedone_work_callback(struct work_struct *work) -{ - DSSDBGF(); + * transfer. + * + * Also, as there's no interrupt telling when the transfer has been + * done and the channel could be reconfigured, the only way is to + * busyloop until TE_SIZE is zero. With BTA we can do this + * asynchronously. + * */ - cancel_delayed_work_sync(&dsi.framedone_timeout_work); + dsi.bta_callback = dsi_framedone_bta_callback; - dsi_handle_framedone(); + barrier(); - dsi_perf_show("DISPC"); + dsi_vc_enable_bta_irq(channel); - dsi.framedone_callback(0, dsi.framedone_data); + r = dsi_vc_send_bta(channel); + if (r) { + DSSERR("BTA after framedone failed\n"); + dsi_handle_framedone(-EIO); + } } int omap_dsi_prepare_update(struct omap_dss_device *dssdev, @@ -3246,7 +3243,6 @@ int dsi_init(struct platform_device *pdev) if (dsi.workqueue == NULL) return -ENOMEM; - INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, dsi_framedone_timeout_work_callback); -- cgit v1.2.3-18-g5258 From 26a8c2507a224d39003665cd6e7678520c733c04 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Wed, 9 Jun 2010 15:31:34 +0300 Subject: OMAP: DSS2: change manual update scaling setup Currently the update area on manual update displays is automatically enlargened to fully cover scaled overlays. This patch makes that optional, allowing the panel driver to choose if it's used or not. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 2 +- drivers/video/omap2/dss/dsi.c | 6 ++- drivers/video/omap2/dss/dss.h | 3 +- drivers/video/omap2/dss/manager.c | 69 ++++++++++++++++++------------- drivers/video/omap2/dss/rfbi.c | 2 +- 5 files changed, 48 insertions(+), 34 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 2a91d5662c0..6848e3633ed 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -1135,7 +1135,7 @@ static int taal_update(struct omap_dss_device *dssdev, goto err; } - r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h); + r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); if (r) goto err; diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 32297b4f7ab..d0881e948bc 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2860,7 +2860,8 @@ static void dsi_framedone_irq_callback(void *data, u32 mask) } int omap_dsi_prepare_update(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h) + u16 *x, u16 *y, u16 *w, u16 *h, + bool enlarge_update_area) { u16 dw, dh; @@ -2884,7 +2885,8 @@ int omap_dsi_prepare_update(struct omap_dss_device *dssdev, dsi_perf_mark_setup(); if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h); + dss_setup_partial_planes(dssdev, x, y, w, h, + enlarge_update_area); dispc_set_lcd_size(*w, *h); } diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 66e8e97d06a..5c7940d5f28 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h @@ -199,7 +199,8 @@ int dss_init_overlay_managers(struct platform_device *pdev); void dss_uninit_overlay_managers(struct platform_device *pdev); int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); void dss_setup_partial_planes(struct omap_dss_device *dssdev, - u16 *x, u16 *y, u16 *w, u16 *h); + u16 *x, u16 *y, u16 *w, u16 *h, + bool enlarge_update_area); void dss_start_update(struct omap_dss_device *dssdev); /* overlay */ diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index a1d84ef6590..4b09fcb432b 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -440,6 +440,10 @@ struct manager_cache_data { /* 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 { @@ -721,6 +725,7 @@ static int configure_overlay(enum omap_plane plane) u16 x, y, w, h; u32 paddr; int r; + u16 orig_w, orig_h, orig_outw, orig_outh; DSSDBGF("%d", plane); @@ -741,8 +746,16 @@ static int configure_overlay(enum omap_plane plane) outh = c->out_height == 0 ? c->height : c->out_height; paddr = c->paddr; + orig_w = w; + orig_h = h; + orig_outw = outw; + orig_outh = outh; + if (c->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)) { @@ -773,39 +786,33 @@ static int configure_overlay(enum omap_plane plane) BUG(); } - if (dispc_is_overlay_scaled(c)) { - /* If the overlay is scaled, the update area has - * already been enlarged to cover the whole overlay. We - * only need to adjust x/y here */ - x = c->pos_x - mc->x; - y = c->pos_y - mc->y; + if (mc->x > c->pos_x) { + x = 0; + outw -= (mc->x - c->pos_x); + paddr += (mc->x - c->pos_x) * + scale_x_m / scale_x_d * bpp / 8; } else { - if (mc->x > c->pos_x) { - x = 0; - w -= (mc->x - c->pos_x); - paddr += (mc->x - c->pos_x) * bpp / 8; - } else { - x = c->pos_x - mc->x; - } + x = c->pos_x - mc->x; + } - if (mc->y > c->pos_y) { - y = 0; - h -= (mc->y - c->pos_y); - paddr += (mc->y - c->pos_y) * c->screen_width * - bpp / 8; - } else { - y = c->pos_y - mc->y; - } + if (mc->y > c->pos_y) { + y = 0; + outh -= (mc->y - c->pos_y); + paddr += (mc->y - c->pos_y) * + scale_y_m / scale_y_d * + c->screen_width * bpp / 8; + } else { + y = c->pos_y - mc->y; + } - if (mc->w < (x+w)) - w -= (x+w) - (mc->w); + if (mc->w < (x + outw)) + outw -= (x + outw) - (mc->w); - if (mc->h < (y+h)) - h -= (y+h) - (mc->h); + if (mc->h < (y + outh)) + outh -= (y + outh) - (mc->h); - outw = w; - outh = h; - } + w = w * outw / orig_outw; + h = h * outh / orig_outh; } r = dispc_setup_plane(plane, @@ -963,7 +970,7 @@ static void make_even(u16 *x, u16 *w) /* 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) + u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) { struct overlay_cache_data *oc; struct manager_cache_data *mc; @@ -1015,6 +1022,9 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, oc->dirty = true; + if (!enlarge_update_area) + continue; + if (!oc->enabled) continue; @@ -1074,6 +1084,7 @@ void dss_setup_partial_planes(struct omap_dss_device *dssdev, 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; diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index cc23f53cc62..bbe62464e92 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c @@ -886,7 +886,7 @@ int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, return -EINVAL; if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { - dss_setup_partial_planes(dssdev, x, y, w, h); + dss_setup_partial_planes(dssdev, x, y, w, h, true); dispc_set_lcd_size(*w, *h); } -- cgit v1.2.3-18-g5258 From fa15c79b9a75cdc5eaabfed7413a9e098c841022 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 14 May 2010 17:42:07 +0300 Subject: OMAP: DSS2: DSI: Remove BTA after set_max_rx_packet_size SMRPS function always sent BTA after sending the SMRPS packet. This is not needed, and also caused some (buggy) panels to bug. This patch removes the BTA. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index d0881e948bc..18fe332d06e 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2279,16 +2279,8 @@ EXPORT_SYMBOL(dsi_vc_dcs_read_2); int dsi_vc_set_max_rx_packet_size(int channel, u16 len) { - int r; - r = dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, + return dsi_vc_send_short(channel, DSI_DT_SET_MAX_RET_PKG_SIZE, len, 0); - - if (r) - return r; - - r = dsi_vc_send_bta_sync(channel); - - return r; } EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); -- cgit v1.2.3-18-g5258 From bbecb50b5f609e0291cce83e10b5500cc8d688c6 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Mon, 10 May 2010 14:35:33 +0300 Subject: OMAP: DSS2: DSI: Add error IRQ mask for DSI complexIO The code presumed that all ComplexIO interrupts are errors. This is not the case. This patch adds proper error mask for CIO interrupt handling. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 18fe332d06e..1358d301ac3 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -165,6 +165,14 @@ struct dsi_reg { u16 idx; }; #define DSI_CIO_IRQ_ERRCONTENTIONLP1_3 (1 << 25) #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL0 (1 << 30) #define DSI_CIO_IRQ_ULPSACTIVENOT_ALL1 (1 << 31) +#define DSI_CIO_IRQ_ERROR_MASK \ + (DSI_CIO_IRQ_ERRSYNCESC1 | DSI_CIO_IRQ_ERRSYNCESC2 | \ + DSI_CIO_IRQ_ERRSYNCESC3 | DSI_CIO_IRQ_ERRESC1 | DSI_CIO_IRQ_ERRESC2 | \ + DSI_CIO_IRQ_ERRESC3 | DSI_CIO_IRQ_ERRCONTROL1 | \ + DSI_CIO_IRQ_ERRCONTROL2 | DSI_CIO_IRQ_ERRCONTROL3 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_1 | DSI_CIO_IRQ_ERRCONTENTIONLP1_1 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_2 | DSI_CIO_IRQ_ERRCONTENTIONLP1_2 | \ + DSI_CIO_IRQ_ERRCONTENTIONLP0_3 | DSI_CIO_IRQ_ERRCONTENTIONLP1_3) #define DSI_DT_DCS_SHORT_WRITE_0 0x05 #define DSI_DT_DCS_SHORT_WRITE_1 0x15 @@ -542,8 +550,12 @@ void dsi_irq_handler(void) /* flush posted write */ dsi_read_reg(DSI_COMPLEXIO_IRQ_STATUS); - DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); - print_irq_status_cio(ciostatus); + if (ciostatus & DSI_CIO_IRQ_ERROR_MASK) { + DSSERR("DSI CIO error, cio irqstatus %x\n", ciostatus); + print_irq_status_cio(ciostatus); + } else if (debug_irq) { + print_irq_status_cio(ciostatus); + } } dsi_write_reg(DSI_IRQSTATUS, irqstatus & ~DSI_IRQ_CHANNEL_MASK); @@ -590,11 +602,8 @@ static void _dsi_initialize_irq(void) for (i = 0; i < 4; ++i) dsi_write_reg(DSI_VC_IRQENABLE(i), l); - /* XXX zonda responds incorrectly, causing control error: - Exit from LP-ESC mode to LP11 uses wrong transition states on the - data lines LP0 and LN0. */ - dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, - -1 & (~DSI_CIO_IRQ_ERRCONTROL2)); + l = DSI_CIO_IRQ_ERROR_MASK; + dsi_write_reg(DSI_COMPLEXIO_IRQ_ENABLE, l); } static u32 dsi_get_errors(void) -- cgit v1.2.3-18-g5258 From 36194b4792bacf8a02e713536487af60938f06dd Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 18 May 2010 13:35:37 +0300 Subject: OMAP: DSS2: DSI: increase FIFO low threshold The current FIFO low threshold was too low, and caused the FIFO to run empty when core domain went to INA state between FIFO fills. This patch increases the low threshold to keep that from happening. The threshold values depend quite much on the HW and the use cases, so this should actually be somehow configurable from board files, perhaps. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 1358d301ac3..2ceddb83f24 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -3195,7 +3195,7 @@ void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, burst_size_bytes = 16 * 32 / 8; *fifo_high = fifo_size - burst_size_bytes; - *fifo_low = fifo_size - burst_size_bytes * 8; + *fifo_low = fifo_size - burst_size_bytes * 2; } int dsi_init_display(struct omap_dss_device *dssdev) -- cgit v1.2.3-18-g5258 From a602771c43ed7f1a02c7766c94fda74ac5d72a8b Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Tue, 25 May 2010 17:01:28 +0300 Subject: OMAP: DSS2: DSI: detect unsupported update requests OMAP DSS HW cannot send updates with odd widths. Normally the widths are made even while preparing the update. This patch adds a BUG_ON() to check if the update width is even. This is to detect broken updates cleanly, as otherwise the OMAP DSS HW will just halt, leading to obscure error situations. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 2ceddb83f24..a6e0f647554 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2902,6 +2902,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, { dsi.update_channel = channel; + /* OMAP DSS cannot send updates of odd widths. + * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON + * here to make sure we catch erroneous updates. Otherwise we'll only + * see rather obscure HW error happening, as DSS halts. */ + BUG_ON(x % 2 == 1); + if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { dsi.framedone_callback = callback; dsi.framedone_data = data; -- cgit v1.2.3-18-g5258 From ffb63c95b2fa52b02b45537d18f0ca698bef5496 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Fri, 21 May 2010 10:09:18 +0300 Subject: OMAP: DSS2: Taal: Optimize enable_te, rotate, mirror when value unchanged Skip any further processing of taal_enable_te(), taal_rotate(), and taal_mirror() if value remains unchanged. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-taal.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 6848e3633ed..e1c765d1141 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c @@ -1210,6 +1210,10 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) int r; mutex_lock(&td->lock); + + if (td->te_enabled == enable) + goto end; + dsi_bus_lock(); if (td->enabled) { @@ -1221,6 +1225,7 @@ static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) td->te_enabled = enable; dsi_bus_unlock(); +end: mutex_unlock(&td->lock); return 0; @@ -1251,6 +1256,10 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) dev_dbg(&dssdev->dev, "rotate %d\n", rotate); mutex_lock(&td->lock); + + if (td->rotate == rotate) + goto end; + dsi_bus_lock(); if (td->enabled) { @@ -1262,6 +1271,7 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) td->rotate = rotate; dsi_bus_unlock(); +end: mutex_unlock(&td->lock); return 0; err: @@ -1290,6 +1300,10 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) dev_dbg(&dssdev->dev, "mirror %d\n", enable); mutex_lock(&td->lock); + + if (td->mirror == enable) + goto end; + dsi_bus_lock(); if (td->enabled) { r = taal_set_addr_mode(td->rotate, enable); @@ -1300,6 +1314,7 @@ static int taal_mirror(struct omap_dss_device *dssdev, bool enable) td->mirror = enable; dsi_bus_unlock(); +end: mutex_unlock(&td->lock); return 0; err: -- cgit v1.2.3-18-g5258 From 9325588757aa7d08bf2ca9c63b669d0d7aa2fc40 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 1 Jun 2010 15:12:12 +0300 Subject: OMAP: DSS2: OMAPFB: Check fb2display() return value Make sure NULL return value of fb2display() is not referenced. Found by Coverity. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 2 +- drivers/video/omap2/omapfb/omapfb-main.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index d1f56d37405..994f6a091b4 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -858,7 +858,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) break; } - if (!display->driver->enable_te) { + if (!display || !display->driver->enable_te) { r = -ENODEV; break; } diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index a545e8d4817..db307e3c1dd 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1271,6 +1271,9 @@ static int omapfb_blank(int blank, struct fb_info *fbi) int do_update = 0; int r = 0; + if (!display) + return -EINVAL; + omapfb_lock(fbdev); switch (blank) { -- cgit v1.2.3-18-g5258 From 86f2d7dd72e1ff4656107e42a12c999a7b9c26d4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 1 Jun 2010 17:25:10 +0300 Subject: OMAP: DSS2: OMAPFB: Remove redundant rotate range check Unsigned rotate can never be less than zero. Found by Coverity. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index db307e3c1dd..8303776647f 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -683,7 +683,7 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) } } - if (var->rotate < 0 || var->rotate > 3) + if (var->rotate > 3) return -EINVAL; if (check_fb_res_bounds(var)) -- cgit v1.2.3-18-g5258 From 7f8b183059edc6c74654301431d520a91539e45f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 1 Jun 2010 17:33:54 +0300 Subject: OMAP: DSS2: OMAPFB: Remove redundant color register range check Unsigned regno can never be less than zero. Found by Coverity. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 8303776647f..4abb1d17231 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -1208,11 +1208,6 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, if (r != 0) break; - if (regno < 0) { - r = -EINVAL; - break; - } - if (regno < 16) { u16 pal; pal = ((red >> (16 - var->red.length)) << -- cgit v1.2.3-18-g5258 From 5cb33e2166067e1fff7ebc3b849ec70a6fd7ec1d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 1 Jun 2010 18:08:18 +0300 Subject: OMAP: DSS2: OMAPFB: Fix sysfs mirror input check Using bool silently converted input to 0 or 1, making the range check useless. Use unsigned long instead, and convert to bool later. Found by Coverity. Signed-off-by: Jani Nikula Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 51c13c366bf..6f9c72cd6bb 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c @@ -102,7 +102,7 @@ static ssize_t store_mirror(struct device *dev, { struct fb_info *fbi = dev_get_drvdata(dev); struct omapfb_info *ofbi = FB2OFB(fbi); - bool mirror; + unsigned long mirror; int r; struct fb_var_screeninfo new_var; -- cgit v1.2.3-18-g5258 From f55fdcfe88c5a23115b6d93674ad1e082e841091 Mon Sep 17 00:00:00 2001 From: Tomi Valkeinen Date: Thu, 3 Jun 2010 16:27:46 +0300 Subject: OMAP: DSS2: adjust YUV overlay width to be even An overlay in YUV mode has to have an even input width, because data for each pixel is divided between two adjacent pixels. The algorithm handling manual update overlay adjusting may adjust the overlay width to be odd. This patch adds a check for that situation, and makes the width even. The width is increased by one if it is possible (the unadjusted input width is larger than the width), and decreased by one if increasing is not possible. Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/manager.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 4b09fcb432b..6a649ab5539 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c @@ -813,6 +813,21 @@ static int configure_overlay(enum omap_plane plane) 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) && + (c->color_mode == OMAP_DSS_COLOR_YUV2 || + c->color_mode == OMAP_DSS_COLOR_UYVY)) { + if (orig_w > w) + w += 1; + else + w -= 1; + } } r = dispc_setup_plane(plane, -- cgit v1.2.3-18-g5258 From edecee858ea5540075cbd84ada8bb07f952fd758 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Tue, 22 Jun 2010 10:14:01 +0200 Subject: OMAP: DSS2: Remove extra return statement Remove extra return statement in omapdss_default_get_recommended_bpp from overlay.c Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/display.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 480aeaa5f39..22dd7a474f7 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c @@ -346,7 +346,6 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) case OMAP_DISPLAY_TYPE_VENC: case OMAP_DISPLAY_TYPE_SDI: return 24; - return 24; default: BUG(); } -- cgit v1.2.3-18-g5258 From e26ed44c950ed9d1feb7719100f475e4e80f1419 Mon Sep 17 00:00:00 2001 From: Afzal Mohammed Date: Thu, 1 Jul 2010 15:40:01 +0200 Subject: OMAP: DSS2: OMAPFB: Fix probe error path Move sysfs entry creation to omapfb_probe() from omapfb_create_framebuffers(). This will make sure that sysfs entry is not left behind in case of unsuccessful probe due to failure in enabling fb0 of omapfb_create_framebuffers(). Signed-off-by: Afzal Mohammed Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index 4abb1d17231..e51b7bf6430 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2005,13 +2005,6 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) } } - DBG("create sysfs for fbs\n"); - r = omapfb_create_sysfs(fbdev); - if (r) { - dev_err(fbdev->dev, "failed to create sysfs entries\n"); - return r; - } - /* Enable fb0 */ if (fbdev->num_fbs > 0) { struct omapfb_info *ofbi = FB2OFB(fbdev->fbs[0]); @@ -2297,6 +2290,13 @@ static int omapfb_probe(struct platform_device *pdev) } } + DBG("create sysfs for fbs\n"); + r = omapfb_create_sysfs(fbdev); + if (r) { + dev_err(fbdev->dev, "failed to create sysfs entries\n"); + goto cleanup; + } + return 0; cleanup: -- cgit v1.2.3-18-g5258 From e8c66dcf5aa8df2d1b1f249519c920d3a45dd613 Mon Sep 17 00:00:00 2001 From: Maurus Cuelenaere Date: Thu, 22 Jul 2010 00:40:58 +0200 Subject: OMAP: DSS2: OMAPFB: Fix invalid bpp for PAL and NTSC modes omapfb_mode_to_timings() sets the bpp to 0 when bootarg omapfb.mode is set to either "pal" or "ntsc". This patch corrects this by setting the bpp to 24, as would be done if omapdss_default_get_recommended_bpp() would be called. Signed-off-by: Maurus Cuelenaere Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index e51b7bf6430..04034d410d6 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c @@ -2038,11 +2038,11 @@ static int omapfb_mode_to_timings(const char *mode_str, #ifdef CONFIG_OMAP2_DSS_VENC if (strcmp(mode_str, "pal") == 0) { *timings = omap_dss_pal_timings; - *bpp = 0; + *bpp = 24; return 0; } else if (strcmp(mode_str, "ntsc") == 0) { *timings = omap_dss_ntsc_timings; - *bpp = 0; + *bpp = 24; return 0; } #endif -- cgit v1.2.3-18-g5258 From 451cfbfc27b45a4aebd1e536f2b79c8b7113fbc9 Mon Sep 17 00:00:00 2001 From: Igor Grinberg Date: Mon, 12 Jul 2010 12:42:50 +0200 Subject: OMAP: DSS2: TDO35S: fix video signaling TDO35S samples the data on the falling adge of the pixel clock, therefore the data strobe should be on the raising edge. Signed-off-by: Igor Grinberg Signed-off-by: Mike Rapoport Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/displays/panel-toppoly-tdo35s.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c index fa434ca6e4b..e320e67d06f 100644 --- a/drivers/video/omap2/displays/panel-toppoly-tdo35s.c +++ b/drivers/video/omap2/displays/panel-toppoly-tdo35s.c @@ -73,8 +73,12 @@ static void toppoly_tdo_panel_power_off(struct omap_dss_device *dssdev) static int toppoly_tdo_panel_probe(struct omap_dss_device *dssdev) { - dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | - OMAP_DSS_LCD_IHS; + dssdev->panel.config = OMAP_DSS_LCD_TFT | + OMAP_DSS_LCD_IVS | + OMAP_DSS_LCD_IHS | + OMAP_DSS_LCD_IPC | + OMAP_DSS_LCD_ONOFF; + dssdev->panel.timings = toppoly_tdo_panel_timings; return 0; -- cgit v1.2.3-18-g5258 From e9c31afcffe3df90ebac343611b2f0177bf3cbe4 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Wed, 14 Jul 2010 14:11:50 +0200 Subject: OMAP: DSS2: Fix error path in omap_dsi_update() In the case of an error on calling dsi_update_screen_l4(), a successful framedone callback is still sent to panel-taal. An error should be returned to taal_update() instead. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/dsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index a6e0f647554..b3fa3a7db91 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c @@ -2920,7 +2920,12 @@ int omap_dsi_update(struct omap_dss_device *dssdev, dsi_update_screen_dispc(dssdev, x, y, w, h); } else { - dsi_update_screen_l4(dssdev, x, y, w, h); + int r; + + r = dsi_update_screen_l4(dssdev, x, y, w, h); + if (r) + return r; + dsi_perf_show("L4"); callback(0, data); } -- cgit v1.2.3-18-g5258 From f3c77d6332d979b74364ce2f3fc027ff6c0e00d1 Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Mon, 2 Aug 2010 15:14:11 +0200 Subject: OMAP: DSS2: Replace strncmp() with sysfs_streq() in overlay_manager_store() The function overlay_manager_store currently fails if the sysfs input is a prefix string of an existing overlay manager name. This occurs because strncmp compares the two strings only till the length of the input sysfs string. So a sysfs input "lcd" will match manager name "lcd2" which is incorrect behavior. The use of sysfs_streq here will prevent this false positive match to occur. Signed-off-by: Archit Taneja Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/dss/overlay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index 82336583ade..244dca81a39 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c @@ -65,7 +65,7 @@ static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { mgr = omap_dss_get_overlay_manager(i); - if (strncmp(buf, mgr->name, len) == 0) + if (sysfs_streq(buf, mgr->name)) break; mgr = NULL; -- cgit v1.2.3-18-g5258 From ece350d3949e9a60b39e4f9853be118e98d48fbc Mon Sep 17 00:00:00 2001 From: Grazvydas Ignotas Date: Fri, 2 Jul 2010 22:54:56 +0200 Subject: OMAP: DSS2: OMAPFB: add support for FBIO_WAITFORVSYNC FBIO_WAITFORVSYNC is a stardard ioctl for waiting vsync, already used by some userspace, so add it as an alias for OMAPFB_WAITFORVSYNC. Signed-off-by: Grazvydas Ignotas Signed-off-by: Tomi Valkeinen --- drivers/video/omap2/omapfb/omapfb-ioctl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/video/omap2') diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 994f6a091b4..6f435450987 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c @@ -610,6 +610,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) struct omapfb_vram_info vram_info; struct omapfb_tearsync_info tearsync_info; struct omapfb_display_info display_info; + u32 crt; } p; int r = 0; @@ -768,6 +769,17 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) r = -EFAULT; break; + case FBIO_WAITFORVSYNC: + if (get_user(p.crt, (__u32 __user *)arg)) { + r = -EFAULT; + break; + } + if (p.crt != 0) { + r = -ENODEV; + break; + } + /* FALLTHROUGH */ + case OMAPFB_WAITFORVSYNC: DBG("ioctl WAITFORVSYNC\n"); if (!display) { -- cgit v1.2.3-18-g5258