diff options
| author | Tomi Valkeinen <tomi.valkeinen@nokia.com> | 2010-01-12 07:16:41 -0500 |
|---|---|---|
| committer | Tomi Valkeinen <tomi.valkeinen@nokia.com> | 2010-02-24 07:31:28 -0500 |
| commit | 18946f62c6cc8cf051bafca8b7fa72309e8a1067 (patch) | |
| tree | f1e33d76a571ebc4580b15c1b7ba1bec8e441cf6 | |
| parent | 446f7bff703f5f82560afde90fb22b7a1d366bbc (diff) | |
OMAP: DSS2: move update() and sync()
Move update() and sync() from omap_dss_device to omap_dss_driver.
Also, update was hardcoded to use virtual channel 0. This patch adds a
parameter that specifies the VC.
This is part of a larger patch-set, which moves the control from omapdss
driver to the display driver.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@nokia.com>
| -rw-r--r-- | arch/arm/plat-omap/include/plat/display.h | 24 | ||||
| -rw-r--r-- | drivers/video/omap2/displays/panel-taal.c | 76 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/dsi.c | 322 | ||||
| -rw-r--r-- | drivers/video/omap2/dss/rfbi.c | 290 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-ioctl.c | 10 | ||||
| -rw-r--r-- | drivers/video/omap2/omapfb/omapfb-main.c | 10 |
6 files changed, 226 insertions, 506 deletions
diff --git a/arch/arm/plat-omap/include/plat/display.h b/arch/arm/plat-omap/include/plat/display.h index c04aadf3d9f8..e124f11e9bba 100644 --- a/arch/arm/plat-omap/include/plat/display.h +++ b/arch/arm/plat-omap/include/plat/display.h | |||
| @@ -474,9 +474,6 @@ struct omap_dss_device { | |||
| 474 | struct omap_video_timings *timings); | 474 | struct omap_video_timings *timings); |
| 475 | void (*get_timings)(struct omap_dss_device *dssdev, | 475 | void (*get_timings)(struct omap_dss_device *dssdev, |
| 476 | struct omap_video_timings *timings); | 476 | struct omap_video_timings *timings); |
| 477 | int (*update)(struct omap_dss_device *dssdev, | ||
| 478 | u16 x, u16 y, u16 w, u16 h); | ||
| 479 | int (*sync)(struct omap_dss_device *dssdev); | ||
| 480 | 477 | ||
| 481 | int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); | 478 | int (*set_wss)(struct omap_dss_device *dssdev, u32 wss); |
| 482 | u32 (*get_wss)(struct omap_dss_device *dssdev); | 479 | u32 (*get_wss)(struct omap_dss_device *dssdev); |
| @@ -500,15 +497,16 @@ struct omap_dss_driver { | |||
| 500 | int (*resume)(struct omap_dss_device *display); | 497 | int (*resume)(struct omap_dss_device *display); |
| 501 | int (*run_test)(struct omap_dss_device *display, int test); | 498 | int (*run_test)(struct omap_dss_device *display, int test); |
| 502 | 499 | ||
| 503 | void (*setup_update)(struct omap_dss_device *dssdev, | ||
| 504 | u16 x, u16 y, u16 w, u16 h); | ||
| 505 | int (*set_update_mode)(struct omap_dss_device *dssdev, | 500 | int (*set_update_mode)(struct omap_dss_device *dssdev, |
| 506 | enum omap_dss_update_mode); | 501 | enum omap_dss_update_mode); |
| 507 | enum omap_dss_update_mode (*get_update_mode)( | 502 | enum omap_dss_update_mode (*get_update_mode)( |
| 508 | struct omap_dss_device *dssdev); | 503 | struct omap_dss_device *dssdev); |
| 509 | 504 | ||
| 505 | int (*update)(struct omap_dss_device *dssdev, | ||
| 506 | u16 x, u16 y, u16 w, u16 h); | ||
| 507 | int (*sync)(struct omap_dss_device *dssdev); | ||
| 508 | |||
| 510 | int (*enable_te)(struct omap_dss_device *dssdev, bool enable); | 509 | int (*enable_te)(struct omap_dss_device *dssdev, bool enable); |
| 511 | int (*wait_for_te)(struct omap_dss_device *dssdev); | ||
| 512 | int (*get_te)(struct omap_dss_device *dssdev); | 510 | int (*get_te)(struct omap_dss_device *dssdev); |
| 513 | 511 | ||
| 514 | u8 (*get_rotate)(struct omap_dss_device *dssdev); | 512 | u8 (*get_rotate)(struct omap_dss_device *dssdev); |
| @@ -566,4 +564,18 @@ int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | |||
| 566 | void omapdss_dsi_vc_enable_hs(int channel, bool enable); | 564 | void omapdss_dsi_vc_enable_hs(int channel, bool enable); |
| 567 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); | 565 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable); |
| 568 | 566 | ||
| 567 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, | ||
| 568 | u16 *x, u16 *y, u16 *w, u16 *h); | ||
| 569 | int omap_dsi_update(struct omap_dss_device *dssdev, | ||
| 570 | int channel, | ||
| 571 | u16 x, u16 y, u16 w, u16 h, | ||
| 572 | void (*callback)(int, void *), void *data); | ||
| 573 | |||
| 574 | int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, | ||
| 575 | u16 *x, u16 *y, u16 *w, u16 *h); | ||
| 576 | int omap_rfbi_update(struct omap_dss_device *dssdev, | ||
| 577 | u16 x, u16 y, u16 w, u16 h, | ||
| 578 | void (*callback)(void *), void *data); | ||
| 579 | |||
| 580 | |||
| 569 | #endif | 581 | #endif |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 4ccb583b7b67..58293203fc05 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
| @@ -725,10 +725,58 @@ static int taal_resume(struct omap_dss_device *dssdev) | |||
| 725 | return 0; | 725 | return 0; |
| 726 | } | 726 | } |
| 727 | 727 | ||
| 728 | static void taal_setup_update(struct omap_dss_device *dssdev, | 728 | static void taal_framedone_cb(int err, void *data) |
| 729 | { | ||
| 730 | struct omap_dss_device *dssdev = data; | ||
| 731 | dev_dbg(&dssdev->dev, "framedone, err %d\n", err); | ||
| 732 | dsi_bus_unlock(); | ||
| 733 | } | ||
| 734 | |||
| 735 | static int taal_update(struct omap_dss_device *dssdev, | ||
| 729 | u16 x, u16 y, u16 w, u16 h) | 736 | u16 x, u16 y, u16 w, u16 h) |
| 730 | { | 737 | { |
| 731 | taal_set_update_window(x, y, w, h); | 738 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| 739 | int r; | ||
| 740 | |||
| 741 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | ||
| 742 | |||
| 743 | dsi_bus_lock(); | ||
| 744 | |||
| 745 | if (!td->enabled) { | ||
| 746 | r = 0; | ||
| 747 | goto err; | ||
| 748 | } | ||
| 749 | |||
| 750 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h); | ||
| 751 | if (r) | ||
| 752 | goto err; | ||
| 753 | |||
| 754 | r = taal_set_update_window(x, y, w, h); | ||
| 755 | if (r) | ||
| 756 | goto err; | ||
| 757 | |||
| 758 | r = omap_dsi_update(dssdev, TCH, x, y, w, h, | ||
| 759 | taal_framedone_cb, dssdev); | ||
| 760 | if (r) | ||
| 761 | goto err; | ||
| 762 | |||
| 763 | /* note: no bus_unlock here. unlock is in framedone_cb */ | ||
| 764 | return 0; | ||
| 765 | err: | ||
| 766 | dsi_bus_unlock(); | ||
| 767 | return r; | ||
| 768 | } | ||
| 769 | |||
| 770 | static int taal_sync(struct omap_dss_device *dssdev) | ||
| 771 | { | ||
| 772 | dev_dbg(&dssdev->dev, "sync\n"); | ||
| 773 | |||
| 774 | dsi_bus_lock(); | ||
| 775 | dsi_bus_unlock(); | ||
| 776 | |||
| 777 | dev_dbg(&dssdev->dev, "sync done\n"); | ||
| 778 | |||
| 779 | return 0; | ||
| 732 | } | 780 | } |
| 733 | 781 | ||
| 734 | static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) | 782 | static int taal_enable_te(struct omap_dss_device *dssdev, bool enable) |
| @@ -762,24 +810,6 @@ static int taal_get_te(struct omap_dss_device *dssdev) | |||
| 762 | return td->te_enabled; | 810 | return td->te_enabled; |
| 763 | } | 811 | } |
| 764 | 812 | ||
| 765 | static int taal_wait_te(struct omap_dss_device *dssdev) | ||
| 766 | { | ||
| 767 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
| 768 | long wait = msecs_to_jiffies(500); | ||
| 769 | |||
| 770 | if (!td->use_ext_te || !td->te_enabled) | ||
| 771 | return 0; | ||
| 772 | |||
| 773 | INIT_COMPLETION(td->te_completion); | ||
| 774 | wait = wait_for_completion_timeout(&td->te_completion, wait); | ||
| 775 | if (wait == 0) { | ||
| 776 | dev_err(&dssdev->dev, "timeout waiting TE\n"); | ||
| 777 | return -ETIME; | ||
| 778 | } | ||
| 779 | |||
| 780 | return 0; | ||
| 781 | } | ||
| 782 | |||
| 783 | static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | 813 | static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) |
| 784 | { | 814 | { |
| 785 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 815 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
| @@ -1018,15 +1048,17 @@ static struct omap_dss_driver taal_driver = { | |||
| 1018 | .suspend = taal_suspend, | 1048 | .suspend = taal_suspend, |
| 1019 | .resume = taal_resume, | 1049 | .resume = taal_resume, |
| 1020 | 1050 | ||
| 1021 | .setup_update = taal_setup_update, | ||
| 1022 | .set_update_mode = taal_set_update_mode, | 1051 | .set_update_mode = taal_set_update_mode, |
| 1023 | .get_update_mode = taal_get_update_mode, | 1052 | .get_update_mode = taal_get_update_mode, |
| 1053 | |||
| 1054 | .update = taal_update, | ||
| 1055 | .sync = taal_sync, | ||
| 1056 | |||
| 1024 | .get_resolution = taal_get_resolution, | 1057 | .get_resolution = taal_get_resolution, |
| 1025 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | 1058 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, |
| 1026 | 1059 | ||
| 1027 | .enable_te = taal_enable_te, | 1060 | .enable_te = taal_enable_te, |
| 1028 | .get_te = taal_get_te, | 1061 | .get_te = taal_get_te, |
| 1029 | .wait_for_te = taal_wait_te, | ||
| 1030 | 1062 | ||
| 1031 | .set_rotate = taal_rotate, | 1063 | .set_rotate = taal_rotate, |
| 1032 | .get_rotate = taal_get_rotate, | 1064 | .get_rotate = taal_get_rotate, |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index b9fa62027f67..203b18bbddae 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
| @@ -31,8 +31,8 @@ | |||
| 31 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
| 32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
| 33 | #include <linux/regulator/consumer.h> | 33 | #include <linux/regulator/consumer.h> |
| 34 | #include <linux/kthread.h> | ||
| 35 | #include <linux/wait.h> | 34 | #include <linux/wait.h> |
| 35 | #include <linux/workqueue.h> | ||
| 36 | 36 | ||
| 37 | #include <plat/display.h> | 37 | #include <plat/display.h> |
| 38 | #include <plat/clock.h> | 38 | #include <plat/clock.h> |
| @@ -200,7 +200,6 @@ enum dsi_vc_mode { | |||
| 200 | }; | 200 | }; |
| 201 | 201 | ||
| 202 | struct dsi_update_region { | 202 | struct dsi_update_region { |
| 203 | bool dirty; | ||
| 204 | u16 x, y, w, h; | 203 | u16 x, y, w, h; |
| 205 | struct omap_dss_device *device; | 204 | struct omap_dss_device *device; |
| 206 | }; | 205 | }; |
| @@ -234,18 +233,18 @@ static struct | |||
| 234 | 233 | ||
| 235 | struct completion bta_completion; | 234 | struct completion bta_completion; |
| 236 | 235 | ||
| 237 | struct task_struct *thread; | 236 | int update_channel; |
| 238 | wait_queue_head_t waitqueue; | ||
| 239 | |||
| 240 | spinlock_t update_lock; | ||
| 241 | bool framedone_received; | ||
| 242 | struct dsi_update_region update_region; | 237 | struct dsi_update_region update_region; |
| 243 | struct dsi_update_region active_update_region; | ||
| 244 | struct completion update_completion; | ||
| 245 | 238 | ||
| 246 | bool te_enabled; | 239 | bool te_enabled; |
| 247 | bool use_ext_te; | 240 | bool use_ext_te; |
| 248 | 241 | ||
| 242 | struct work_struct framedone_work; | ||
| 243 | void (*framedone_callback)(int, void *); | ||
| 244 | void *framedone_data; | ||
| 245 | |||
| 246 | struct delayed_work framedone_timeout_work; | ||
| 247 | |||
| 249 | #ifdef DSI_CATCH_MISSING_TE | 248 | #ifdef DSI_CATCH_MISSING_TE |
| 250 | struct timer_list te_timer; | 249 | struct timer_list te_timer; |
| 251 | #endif | 250 | #endif |
| @@ -357,9 +356,9 @@ static void dsi_perf_show(const char *name) | |||
| 357 | 356 | ||
| 358 | total_us = setup_us + trans_us; | 357 | total_us = setup_us + trans_us; |
| 359 | 358 | ||
| 360 | total_bytes = dsi.active_update_region.w * | 359 | total_bytes = dsi.update_region.w * |
| 361 | dsi.active_update_region.h * | 360 | dsi.update_region.h * |
| 362 | dsi.active_update_region.device->ctrl.pixel_size / 8; | 361 | dsi.update_region.device->ctrl.pixel_size / 8; |
| 363 | 362 | ||
| 364 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " | 363 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " |
| 365 | "%u bytes, %u kbytes/sec\n", | 364 | "%u bytes, %u kbytes/sec\n", |
| @@ -2725,7 +2724,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
| 2725 | unsigned packet_len; | 2724 | unsigned packet_len; |
| 2726 | u32 l; | 2725 | u32 l; |
| 2727 | bool use_te_trigger; | 2726 | bool use_te_trigger; |
| 2728 | const unsigned channel = 0; | 2727 | const unsigned channel = dsi.update_channel; |
| 2729 | /* line buffer is 1024 x 24bits */ | 2728 | /* line buffer is 1024 x 24bits */ |
| 2730 | /* XXX: for some reason using full buffer size causes considerable TX | 2729 | /* XXX: for some reason using full buffer size causes considerable TX |
| 2731 | * slowdown with update sizes that fill the whole buffer */ | 2730 | * slowdown with update sizes that fill the whole buffer */ |
| @@ -2736,6 +2735,8 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
| 2736 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", | 2735 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", |
| 2737 | x, y, w, h); | 2736 | x, y, w, h); |
| 2738 | 2737 | ||
| 2738 | dsi_vc_config_vp(channel); | ||
| 2739 | |||
| 2739 | bytespp = dssdev->ctrl.pixel_size / 8; | 2740 | bytespp = dssdev->ctrl.pixel_size / 8; |
| 2740 | bytespl = w * bytespp; | 2741 | bytespl = w * bytespp; |
| 2741 | bytespf = bytespl * h; | 2742 | bytespf = bytespl * h; |
| @@ -2773,6 +2774,11 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, | |||
| 2773 | */ | 2774 | */ |
| 2774 | dispc_disable_sidle(); | 2775 | dispc_disable_sidle(); |
| 2775 | 2776 | ||
| 2777 | dsi_perf_mark_start(); | ||
| 2778 | |||
| 2779 | schedule_delayed_work(&dsi.framedone_timeout_work, | ||
| 2780 | msecs_to_jiffies(250)); | ||
| 2781 | |||
| 2776 | dss_start_update(dssdev); | 2782 | dss_start_update(dssdev); |
| 2777 | 2783 | ||
| 2778 | if (use_te_trigger) { | 2784 | if (use_te_trigger) { |
| @@ -2795,47 +2801,63 @@ static void dsi_te_timeout(unsigned long arg) | |||
| 2795 | } | 2801 | } |
| 2796 | #endif | 2802 | #endif |
| 2797 | 2803 | ||
| 2798 | static void dsi_framedone_irq_callback(void *data, u32 mask) | 2804 | static void dsi_framedone_timeout_work_callback(struct work_struct *work) |
| 2799 | { | 2805 | { |
| 2800 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | 2806 | int r; |
| 2801 | * turns itself off. However, DSI still has the pixels in its buffers, | 2807 | const int channel = dsi.update_channel; |
| 2802 | * and is sending the data. | 2808 | bool use_te_trigger; |
| 2803 | */ | 2809 | |
| 2810 | DSSERR("Framedone not received for 250ms!\n"); | ||
| 2804 | 2811 | ||
| 2805 | /* SIDLEMODE back to smart-idle */ | 2812 | /* SIDLEMODE back to smart-idle */ |
| 2806 | dispc_enable_sidle(); | 2813 | dispc_enable_sidle(); |
| 2807 | 2814 | ||
| 2808 | dsi.framedone_received = true; | 2815 | use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; |
| 2809 | wake_up(&dsi.waitqueue); | ||
| 2810 | } | ||
| 2811 | 2816 | ||
| 2812 | static void dsi_set_update_region(struct omap_dss_device *dssdev, | 2817 | if (use_te_trigger) { |
| 2813 | u16 x, u16 y, u16 w, u16 h) | 2818 | /* enable LP_RX_TO again after the TE */ |
| 2814 | { | 2819 | REG_FLD_MOD(DSI_TIMING2, 1, 15, 15); /* LP_RX_TO */ |
| 2815 | spin_lock(&dsi.update_lock); | ||
| 2816 | if (dsi.update_region.dirty) { | ||
| 2817 | dsi.update_region.x = min(x, dsi.update_region.x); | ||
| 2818 | dsi.update_region.y = min(y, dsi.update_region.y); | ||
| 2819 | dsi.update_region.w = max(w, dsi.update_region.w); | ||
| 2820 | dsi.update_region.h = max(h, dsi.update_region.h); | ||
| 2821 | } else { | ||
| 2822 | dsi.update_region.x = x; | ||
| 2823 | dsi.update_region.y = y; | ||
| 2824 | dsi.update_region.w = w; | ||
| 2825 | dsi.update_region.h = h; | ||
| 2826 | } | 2820 | } |
| 2827 | 2821 | ||
| 2828 | dsi.update_region.device = dssdev; | 2822 | /* Send BTA after the frame. We need this for the TE to work, as TE |
| 2829 | dsi.update_region.dirty = true; | 2823 | * trigger is only sent for BTAs without preceding packet. Thus we need |
| 2824 | * to BTA after the pixel packets so that next BTA will cause TE | ||
| 2825 | * trigger. | ||
| 2826 | * | ||
| 2827 | * This is not needed when TE is not in use, but we do it anyway to | ||
| 2828 | * make sure that the transfer has been completed. It would be more | ||
| 2829 | * optimal, but more complex, to wait only just before starting next | ||
| 2830 | * transfer. */ | ||
| 2831 | r = dsi_vc_send_bta_sync(channel); | ||
| 2832 | if (r) | ||
| 2833 | DSSERR("BTA after framedone failed\n"); | ||
| 2834 | |||
| 2835 | /* RX_FIFO_NOT_EMPTY */ | ||
| 2836 | if (REG_GET(DSI_VC_CTRL(channel), 20, 20)) { | ||
| 2837 | DSSERR("Received error during frame transfer:\n"); | ||
| 2838 | dsi_vc_flush_receive_data(channel); | ||
| 2839 | } | ||
| 2840 | |||
| 2841 | dsi.framedone_callback(-ETIMEDOUT, dsi.framedone_data); | ||
| 2842 | } | ||
| 2830 | 2843 | ||
| 2831 | spin_unlock(&dsi.update_lock); | 2844 | static void dsi_framedone_irq_callback(void *data, u32 mask) |
| 2845 | { | ||
| 2846 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | ||
| 2847 | * turns itself off. However, DSI still has the pixels in its buffers, | ||
| 2848 | * and is sending the data. | ||
| 2849 | */ | ||
| 2850 | |||
| 2851 | /* SIDLEMODE back to smart-idle */ | ||
| 2852 | dispc_enable_sidle(); | ||
| 2832 | 2853 | ||
| 2854 | schedule_work(&dsi.framedone_work); | ||
| 2833 | } | 2855 | } |
| 2834 | 2856 | ||
| 2835 | static void dsi_handle_framedone(void) | 2857 | static void dsi_handle_framedone(void) |
| 2836 | { | 2858 | { |
| 2837 | int r; | 2859 | int r; |
| 2838 | const int channel = 0; | 2860 | const int channel = dsi.update_channel; |
| 2839 | bool use_te_trigger; | 2861 | bool use_te_trigger; |
| 2840 | 2862 | ||
| 2841 | use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; | 2863 | use_te_trigger = dsi.te_enabled && !dsi.use_ext_te; |
| @@ -2871,105 +2893,79 @@ static void dsi_handle_framedone(void) | |||
| 2871 | #endif | 2893 | #endif |
| 2872 | } | 2894 | } |
| 2873 | 2895 | ||
| 2874 | static int dsi_update_thread(void *data) | 2896 | static void dsi_framedone_work_callback(struct work_struct *work) |
| 2875 | { | 2897 | { |
| 2876 | unsigned long timeout; | 2898 | DSSDBGF(); |
| 2877 | struct omap_dss_device *device; | ||
| 2878 | u16 x, y, w, h; | ||
| 2879 | |||
| 2880 | while (1) { | ||
| 2881 | wait_event_interruptible(dsi.waitqueue, | ||
| 2882 | dsi.update_region.dirty == true || | ||
| 2883 | kthread_should_stop()); | ||
| 2884 | |||
| 2885 | if (kthread_should_stop()) | ||
| 2886 | break; | ||
| 2887 | |||
| 2888 | dsi_bus_lock(); | ||
| 2889 | |||
| 2890 | if (kthread_should_stop()) { | ||
| 2891 | dsi_bus_unlock(); | ||
| 2892 | break; | ||
| 2893 | } | ||
| 2894 | 2899 | ||
| 2895 | dsi_perf_mark_setup(); | 2900 | cancel_delayed_work_sync(&dsi.framedone_timeout_work); |
| 2896 | 2901 | ||
| 2897 | if (dsi.update_region.dirty) { | 2902 | dsi_handle_framedone(); |
| 2898 | spin_lock(&dsi.update_lock); | ||
| 2899 | dsi.active_update_region = dsi.update_region; | ||
| 2900 | dsi.update_region.dirty = false; | ||
| 2901 | spin_unlock(&dsi.update_lock); | ||
| 2902 | } | ||
| 2903 | 2903 | ||
| 2904 | device = dsi.active_update_region.device; | 2904 | dsi_perf_show("DISPC"); |
| 2905 | x = dsi.active_update_region.x; | ||
| 2906 | y = dsi.active_update_region.y; | ||
| 2907 | w = dsi.active_update_region.w; | ||
| 2908 | h = dsi.active_update_region.h; | ||
| 2909 | 2905 | ||
| 2910 | if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 2906 | dsi.framedone_callback(0, dsi.framedone_data); |
| 2907 | } | ||
| 2911 | 2908 | ||
| 2912 | dss_setup_partial_planes(device, | 2909 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, |
| 2913 | &x, &y, &w, &h); | 2910 | u16 *x, u16 *y, u16 *w, u16 *h) |
| 2911 | { | ||
| 2912 | u16 dw, dh; | ||
| 2914 | 2913 | ||
| 2915 | dispc_set_lcd_size(w, h); | 2914 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
| 2916 | } | ||
| 2917 | 2915 | ||
| 2918 | if (dsi.active_update_region.dirty) { | 2916 | if (*x > dw || *y > dh) |
| 2919 | dsi.active_update_region.dirty = false; | 2917 | return -EINVAL; |
| 2920 | /* XXX TODO we don't need to send the coords, if they | ||
| 2921 | * are the same that are already programmed to the | ||
| 2922 | * panel. That should speed up manual update a bit */ | ||
| 2923 | device->driver->setup_update(device, x, y, w, h); | ||
| 2924 | } | ||
| 2925 | 2918 | ||
| 2926 | dsi_perf_mark_start(); | 2919 | if (*x + *w > dw) |
| 2920 | return -EINVAL; | ||
| 2927 | 2921 | ||
| 2928 | if (device->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 2922 | if (*y + *h > dh) |
| 2929 | dsi_vc_config_vp(0); | 2923 | return -EINVAL; |
| 2930 | 2924 | ||
| 2931 | if (dsi.te_enabled && dsi.use_ext_te) | 2925 | if (*w == 1) |
| 2932 | device->driver->wait_for_te(device); | 2926 | return -EINVAL; |
| 2933 | 2927 | ||
| 2934 | dsi.framedone_received = false; | 2928 | if (*w == 0 || *h == 0) |
| 2929 | return -EINVAL; | ||
| 2935 | 2930 | ||
| 2936 | dsi_update_screen_dispc(device, x, y, w, h); | 2931 | dsi_perf_mark_setup(); |
| 2937 | 2932 | ||
| 2938 | /* wait for framedone */ | 2933 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 2939 | timeout = msecs_to_jiffies(1000); | 2934 | dss_setup_partial_planes(dssdev, x, y, w, h); |
| 2940 | wait_event_timeout(dsi.waitqueue, | 2935 | dispc_set_lcd_size(*w, *h); |
| 2941 | dsi.framedone_received == true, | 2936 | } |
| 2942 | timeout); | ||
| 2943 | 2937 | ||
| 2944 | if (!dsi.framedone_received) { | 2938 | return 0; |
| 2945 | DSSERR("framedone timeout\n"); | 2939 | } |
| 2946 | DSSERR("failed update %d,%d %dx%d\n", | 2940 | EXPORT_SYMBOL(omap_dsi_prepare_update); |
| 2947 | x, y, w, h); | ||
| 2948 | 2941 | ||
| 2949 | dispc_enable_sidle(); | 2942 | int omap_dsi_update(struct omap_dss_device *dssdev, |
| 2950 | device->manager->disable(device->manager); | 2943 | int channel, |
| 2944 | u16 x, u16 y, u16 w, u16 h, | ||
| 2945 | void (*callback)(int, void *), void *data) | ||
| 2946 | { | ||
| 2947 | dsi.update_channel = channel; | ||
| 2951 | 2948 | ||
| 2952 | dsi_reset_tx_fifo(0); | 2949 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 2953 | } else { | 2950 | dsi.framedone_callback = callback; |
| 2954 | dsi_handle_framedone(); | 2951 | dsi.framedone_data = data; |
| 2955 | dsi_perf_show("DISPC"); | ||
| 2956 | } | ||
| 2957 | } else { | ||
| 2958 | dsi_update_screen_l4(device, x, y, w, h); | ||
| 2959 | dsi_perf_show("L4"); | ||
| 2960 | } | ||
| 2961 | 2952 | ||
| 2962 | complete_all(&dsi.update_completion); | 2953 | dsi.update_region.x = x; |
| 2954 | dsi.update_region.y = y; | ||
| 2955 | dsi.update_region.w = w; | ||
| 2956 | dsi.update_region.h = h; | ||
| 2957 | dsi.update_region.device = dssdev; | ||
| 2963 | 2958 | ||
| 2964 | dsi_bus_unlock(); | 2959 | dsi_update_screen_dispc(dssdev, x, y, w, h); |
| 2960 | } else { | ||
| 2961 | dsi_update_screen_l4(dssdev, x, y, w, h); | ||
| 2962 | dsi_perf_show("L4"); | ||
| 2963 | callback(0, data); | ||
| 2965 | } | 2964 | } |
| 2966 | 2965 | ||
| 2967 | DSSDBG("update thread exiting\n"); | ||
| 2968 | |||
| 2969 | return 0; | 2966 | return 0; |
| 2970 | } | 2967 | } |
| 2971 | 2968 | EXPORT_SYMBOL(omap_dsi_update); | |
| 2972 | |||
| 2973 | 2969 | ||
| 2974 | /* Display funcs */ | 2970 | /* Display funcs */ |
| 2975 | 2971 | ||
| @@ -3324,74 +3320,6 @@ err0: | |||
| 3324 | return r; | 3320 | return r; |
| 3325 | } | 3321 | } |
| 3326 | 3322 | ||
| 3327 | static int dsi_display_update(struct omap_dss_device *dssdev, | ||
| 3328 | u16 x, u16 y, u16 w, u16 h) | ||
| 3329 | { | ||
| 3330 | int r = 0; | ||
| 3331 | u16 dw, dh; | ||
| 3332 | |||
| 3333 | DSSDBG("dsi_display_update(%d,%d %dx%d)\n", x, y, w, h); | ||
| 3334 | |||
| 3335 | mutex_lock(&dsi.lock); | ||
| 3336 | |||
| 3337 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
| 3338 | goto end; | ||
| 3339 | |||
| 3340 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
| 3341 | |||
| 3342 | if (x > dw || y > dh) | ||
| 3343 | goto end; | ||
| 3344 | |||
| 3345 | if (x + w > dw) | ||
| 3346 | w = dw - x; | ||
| 3347 | |||
| 3348 | if (y + h > dh) | ||
| 3349 | h = dh - y; | ||
| 3350 | |||
| 3351 | if (w == 0 || h == 0) | ||
| 3352 | goto end; | ||
| 3353 | |||
| 3354 | if (w == 1) { | ||
| 3355 | r = -EINVAL; | ||
| 3356 | goto end; | ||
| 3357 | } | ||
| 3358 | |||
| 3359 | dsi_set_update_region(dssdev, x, y, w, h); | ||
| 3360 | |||
| 3361 | wake_up(&dsi.waitqueue); | ||
| 3362 | |||
| 3363 | end: | ||
| 3364 | mutex_unlock(&dsi.lock); | ||
| 3365 | |||
| 3366 | return r; | ||
| 3367 | } | ||
| 3368 | |||
| 3369 | static int dsi_display_sync(struct omap_dss_device *dssdev) | ||
| 3370 | { | ||
| 3371 | bool wait; | ||
| 3372 | |||
| 3373 | DSSDBG("dsi_display_sync()\n"); | ||
| 3374 | |||
| 3375 | mutex_lock(&dsi.lock); | ||
| 3376 | dsi_bus_lock(); | ||
| 3377 | |||
| 3378 | if (dsi.update_region.dirty) { | ||
| 3379 | INIT_COMPLETION(dsi.update_completion); | ||
| 3380 | wait = true; | ||
| 3381 | } else { | ||
| 3382 | wait = false; | ||
| 3383 | } | ||
| 3384 | |||
| 3385 | dsi_bus_unlock(); | ||
| 3386 | mutex_unlock(&dsi.lock); | ||
| 3387 | |||
| 3388 | if (wait) | ||
| 3389 | wait_for_completion_interruptible(&dsi.update_completion); | ||
| 3390 | |||
| 3391 | DSSDBG("dsi_display_sync() done\n"); | ||
| 3392 | return 0; | ||
| 3393 | } | ||
| 3394 | |||
| 3395 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | 3323 | int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) |
| 3396 | { | 3324 | { |
| 3397 | dsi.te_enabled = enable; | 3325 | dsi.te_enabled = enable; |
| @@ -3420,8 +3348,6 @@ int dsi_init_display(struct omap_dss_device *dssdev) | |||
| 3420 | dssdev->disable = dsi_display_disable; | 3348 | dssdev->disable = dsi_display_disable; |
| 3421 | dssdev->suspend = dsi_display_suspend; | 3349 | dssdev->suspend = dsi_display_suspend; |
| 3422 | dssdev->resume = dsi_display_resume; | 3350 | dssdev->resume = dsi_display_resume; |
| 3423 | dssdev->update = dsi_display_update; | ||
| 3424 | dssdev->sync = dsi_display_sync; | ||
| 3425 | 3351 | ||
| 3426 | /* XXX these should be figured out dynamically */ | 3352 | /* XXX these should be figured out dynamically */ |
| 3427 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | 3353 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | |
| @@ -3437,9 +3363,6 @@ int dsi_init(struct platform_device *pdev) | |||
| 3437 | { | 3363 | { |
| 3438 | u32 rev; | 3364 | u32 rev; |
| 3439 | int r; | 3365 | int r; |
| 3440 | struct sched_param param = { | ||
| 3441 | .sched_priority = MAX_USER_RT_PRIO-1 | ||
| 3442 | }; | ||
| 3443 | 3366 | ||
| 3444 | spin_lock_init(&dsi.errors_lock); | 3367 | spin_lock_init(&dsi.errors_lock); |
| 3445 | dsi.errors = 0; | 3368 | dsi.errors = 0; |
| @@ -3450,28 +3373,19 @@ int dsi_init(struct platform_device *pdev) | |||
| 3450 | #endif | 3373 | #endif |
| 3451 | 3374 | ||
| 3452 | init_completion(&dsi.bta_completion); | 3375 | init_completion(&dsi.bta_completion); |
| 3453 | init_completion(&dsi.update_completion); | ||
| 3454 | |||
| 3455 | dsi.thread = kthread_create(dsi_update_thread, NULL, "dsi"); | ||
| 3456 | if (IS_ERR(dsi.thread)) { | ||
| 3457 | DSSERR("cannot create kthread\n"); | ||
| 3458 | r = PTR_ERR(dsi.thread); | ||
| 3459 | goto err0; | ||
| 3460 | } | ||
| 3461 | sched_setscheduler(dsi.thread, SCHED_FIFO, ¶m); | ||
| 3462 | |||
| 3463 | init_waitqueue_head(&dsi.waitqueue); | ||
| 3464 | spin_lock_init(&dsi.update_lock); | ||
| 3465 | 3376 | ||
| 3466 | mutex_init(&dsi.lock); | 3377 | mutex_init(&dsi.lock); |
| 3467 | sema_init(&dsi.bus_lock, 1); | 3378 | sema_init(&dsi.bus_lock, 1); |
| 3468 | 3379 | ||
| 3380 | INIT_WORK(&dsi.framedone_work, dsi_framedone_work_callback); | ||
| 3381 | INIT_DELAYED_WORK_DEFERRABLE(&dsi.framedone_timeout_work, | ||
| 3382 | dsi_framedone_timeout_work_callback); | ||
| 3383 | |||
| 3469 | #ifdef DSI_CATCH_MISSING_TE | 3384 | #ifdef DSI_CATCH_MISSING_TE |
| 3470 | init_timer(&dsi.te_timer); | 3385 | init_timer(&dsi.te_timer); |
| 3471 | dsi.te_timer.function = dsi_te_timeout; | 3386 | dsi.te_timer.function = dsi_te_timeout; |
| 3472 | dsi.te_timer.data = 0; | 3387 | dsi.te_timer.data = 0; |
| 3473 | #endif | 3388 | #endif |
| 3474 | |||
| 3475 | dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); | 3389 | dsi.base = ioremap(DSI_BASE, DSI_SZ_REGS); |
| 3476 | if (!dsi.base) { | 3390 | if (!dsi.base) { |
| 3477 | DSSERR("can't ioremap DSI\n"); | 3391 | DSSERR("can't ioremap DSI\n"); |
| @@ -3495,21 +3409,15 @@ int dsi_init(struct platform_device *pdev) | |||
| 3495 | 3409 | ||
| 3496 | enable_clocks(0); | 3410 | enable_clocks(0); |
| 3497 | 3411 | ||
| 3498 | wake_up_process(dsi.thread); | ||
| 3499 | |||
| 3500 | return 0; | 3412 | return 0; |
| 3501 | err2: | 3413 | err2: |
| 3502 | iounmap(dsi.base); | 3414 | iounmap(dsi.base); |
| 3503 | err1: | 3415 | err1: |
| 3504 | kthread_stop(dsi.thread); | ||
| 3505 | err0: | ||
| 3506 | return r; | 3416 | return r; |
| 3507 | } | 3417 | } |
| 3508 | 3418 | ||
| 3509 | void dsi_exit(void) | 3419 | void dsi_exit(void) |
| 3510 | { | 3420 | { |
| 3511 | kthread_stop(dsi.thread); | ||
| 3512 | |||
| 3513 | iounmap(dsi.base); | 3421 | iounmap(dsi.base); |
| 3514 | 3422 | ||
| 3515 | DSSDBG("omap_dsi_exit\n"); | 3423 | DSSDBG("omap_dsi_exit\n"); |
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index 71293876fed1..a6b33160666a 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
| @@ -36,8 +36,6 @@ | |||
| 36 | #include <plat/display.h> | 36 | #include <plat/display.h> |
| 37 | #include "dss.h" | 37 | #include "dss.h" |
| 38 | 38 | ||
| 39 | /*#define MEASURE_PERF*/ | ||
| 40 | |||
| 41 | #define RFBI_BASE 0x48050800 | 39 | #define RFBI_BASE 0x48050800 |
| 42 | 40 | ||
| 43 | struct rfbi_reg { u16 idx; }; | 41 | struct rfbi_reg { u16 idx; }; |
| @@ -66,8 +64,6 @@ struct rfbi_reg { u16 idx; }; | |||
| 66 | #define RFBI_VSYNC_WIDTH RFBI_REG(0x0090) | 64 | #define RFBI_VSYNC_WIDTH RFBI_REG(0x0090) |
| 67 | #define RFBI_HSYNC_WIDTH RFBI_REG(0x0094) | 65 | #define RFBI_HSYNC_WIDTH RFBI_REG(0x0094) |
| 68 | 66 | ||
| 69 | #define RFBI_CMD_FIFO_LEN_BYTES (16 * sizeof(struct update_param)) | ||
| 70 | |||
| 71 | #define REG_FLD_MOD(idx, val, start, end) \ | 67 | #define REG_FLD_MOD(idx, val, start, end) \ |
| 72 | rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end)) | 68 | rfbi_write_reg(idx, FLD_MOD(rfbi_read_reg(idx), val, start, end)) |
| 73 | 69 | ||
| @@ -102,7 +98,6 @@ enum update_cmd { | |||
| 102 | 98 | ||
| 103 | static int rfbi_convert_timings(struct rfbi_timings *t); | 99 | static int rfbi_convert_timings(struct rfbi_timings *t); |
| 104 | static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div); | 100 | static void rfbi_get_clk_info(u32 *clk_period, u32 *max_clk_div); |
| 105 | static void process_cmd_fifo(void); | ||
| 106 | 101 | ||
| 107 | static struct { | 102 | static struct { |
| 108 | void __iomem *base; | 103 | void __iomem *base; |
| @@ -125,11 +120,6 @@ static struct { | |||
| 125 | struct completion cmd_done; | 120 | struct completion cmd_done; |
| 126 | atomic_t cmd_fifo_full; | 121 | atomic_t cmd_fifo_full; |
| 127 | atomic_t cmd_pending; | 122 | atomic_t cmd_pending; |
| 128 | #ifdef MEASURE_PERF | ||
| 129 | unsigned perf_bytes; | ||
| 130 | ktime_t perf_setup_time; | ||
| 131 | ktime_t perf_start_time; | ||
| 132 | #endif | ||
| 133 | } rfbi; | 123 | } rfbi; |
| 134 | 124 | ||
| 135 | struct update_region { | 125 | struct update_region { |
| @@ -139,16 +129,6 @@ struct update_region { | |||
| 139 | u16 h; | 129 | u16 h; |
| 140 | }; | 130 | }; |
| 141 | 131 | ||
| 142 | struct update_param { | ||
| 143 | u8 rfbi_module; | ||
| 144 | u8 cmd; | ||
| 145 | |||
| 146 | union { | ||
| 147 | struct update_region r; | ||
| 148 | struct completion *sync; | ||
| 149 | } par; | ||
| 150 | }; | ||
| 151 | |||
| 152 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) | 132 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) |
| 153 | { | 133 | { |
| 154 | __raw_writel(val, rfbi.base + idx.idx); | 134 | __raw_writel(val, rfbi.base + idx.idx); |
| @@ -321,55 +301,6 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, | |||
| 321 | } | 301 | } |
| 322 | EXPORT_SYMBOL(omap_rfbi_write_pixels); | 302 | EXPORT_SYMBOL(omap_rfbi_write_pixels); |
| 323 | 303 | ||
| 324 | #ifdef MEASURE_PERF | ||
| 325 | static void perf_mark_setup(void) | ||
| 326 | { | ||
| 327 | rfbi.perf_setup_time = ktime_get(); | ||
| 328 | } | ||
| 329 | |||
| 330 | static void perf_mark_start(void) | ||
| 331 | { | ||
| 332 | rfbi.perf_start_time = ktime_get(); | ||
| 333 | } | ||
| 334 | |||
| 335 | static void perf_show(const char *name) | ||
| 336 | { | ||
| 337 | ktime_t t, setup_time, trans_time; | ||
| 338 | u32 total_bytes; | ||
| 339 | u32 setup_us, trans_us, total_us; | ||
| 340 | |||
| 341 | t = ktime_get(); | ||
| 342 | |||
| 343 | setup_time = ktime_sub(rfbi.perf_start_time, rfbi.perf_setup_time); | ||
| 344 | setup_us = (u32)ktime_to_us(setup_time); | ||
| 345 | if (setup_us == 0) | ||
| 346 | setup_us = 1; | ||
| 347 | |||
| 348 | trans_time = ktime_sub(t, rfbi.perf_start_time); | ||
| 349 | trans_us = (u32)ktime_to_us(trans_time); | ||
| 350 | if (trans_us == 0) | ||
| 351 | trans_us = 1; | ||
| 352 | |||
| 353 | total_us = setup_us + trans_us; | ||
| 354 | |||
| 355 | total_bytes = rfbi.perf_bytes; | ||
| 356 | |||
| 357 | DSSINFO("%s update %u us + %u us = %u us (%uHz), %u bytes, " | ||
| 358 | "%u kbytes/sec\n", | ||
| 359 | name, | ||
| 360 | setup_us, | ||
| 361 | trans_us, | ||
| 362 | total_us, | ||
| 363 | 1000*1000 / total_us, | ||
| 364 | total_bytes, | ||
| 365 | total_bytes * 1000 / total_us); | ||
| 366 | } | ||
| 367 | #else | ||
| 368 | #define perf_mark_setup() | ||
| 369 | #define perf_mark_start() | ||
| 370 | #define perf_show(x) | ||
| 371 | #endif | ||
| 372 | |||
| 373 | void rfbi_transfer_area(u16 width, u16 height, | 304 | void rfbi_transfer_area(u16 width, u16 height, |
| 374 | void (callback)(void *data), void *data) | 305 | void (callback)(void *data), void *data) |
| 375 | { | 306 | { |
| @@ -396,8 +327,6 @@ void rfbi_transfer_area(u16 width, u16 height, | |||
| 396 | if (!rfbi.te_enabled) | 327 | if (!rfbi.te_enabled) |
| 397 | l = FLD_MOD(l, 1, 4, 4); /* ITE */ | 328 | l = FLD_MOD(l, 1, 4, 4); /* ITE */ |
| 398 | 329 | ||
| 399 | perf_mark_start(); | ||
| 400 | |||
| 401 | rfbi_write_reg(RFBI_CONTROL, l); | 330 | rfbi_write_reg(RFBI_CONTROL, l); |
| 402 | } | 331 | } |
| 403 | 332 | ||
| @@ -407,8 +336,6 @@ static void framedone_callback(void *data, u32 mask) | |||
| 407 | 336 | ||
| 408 | DSSDBG("FRAMEDONE\n"); | 337 | DSSDBG("FRAMEDONE\n"); |
| 409 | 338 | ||
| 410 | perf_show("DISPC"); | ||
| 411 | |||
| 412 | REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0); | 339 | REG_FLD_MOD(RFBI_CONTROL, 0, 0, 0); |
| 413 | 340 | ||
| 414 | rfbi_enable_clocks(0); | 341 | rfbi_enable_clocks(0); |
| @@ -416,11 +343,10 @@ static void framedone_callback(void *data, u32 mask) | |||
| 416 | callback = rfbi.framedone_callback; | 343 | callback = rfbi.framedone_callback; |
| 417 | rfbi.framedone_callback = NULL; | 344 | rfbi.framedone_callback = NULL; |
| 418 | 345 | ||
| 419 | /*callback(rfbi.framedone_callback_data);*/ | 346 | if (callback != NULL) |
| 347 | callback(rfbi.framedone_callback_data); | ||
| 420 | 348 | ||
| 421 | atomic_set(&rfbi.cmd_pending, 0); | 349 | atomic_set(&rfbi.cmd_pending, 0); |
| 422 | |||
| 423 | process_cmd_fifo(); | ||
| 424 | } | 350 | } |
| 425 | 351 | ||
| 426 | #if 1 /* VERBOSE */ | 352 | #if 1 /* VERBOSE */ |
| @@ -937,52 +863,43 @@ int rfbi_configure(int rfbi_module, int bpp, int lines) | |||
| 937 | } | 863 | } |
| 938 | EXPORT_SYMBOL(rfbi_configure); | 864 | EXPORT_SYMBOL(rfbi_configure); |
| 939 | 865 | ||
| 940 | static int rfbi_find_display(struct omap_dss_device *dssdev) | 866 | int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, |
| 867 | u16 *x, u16 *y, u16 *w, u16 *h) | ||
| 941 | { | 868 | { |
| 942 | if (dssdev == rfbi.dssdev[0]) | 869 | u16 dw, dh; |
| 943 | return 0; | ||
| 944 | 870 | ||
| 945 | if (dssdev == rfbi.dssdev[1]) | 871 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
| 946 | return 1; | ||
| 947 | 872 | ||
| 948 | BUG(); | 873 | if (*x > dw || *y > dh) |
| 949 | return -1; | 874 | return -EINVAL; |
| 950 | } | ||
| 951 | 875 | ||
| 876 | if (*x + *w > dw) | ||
| 877 | return -EINVAL; | ||
| 952 | 878 | ||
| 953 | static void signal_fifo_waiters(void) | 879 | if (*y + *h > dh) |
| 954 | { | 880 | return -EINVAL; |
| 955 | if (atomic_read(&rfbi.cmd_fifo_full) > 0) { | ||
| 956 | /* DSSDBG("SIGNALING: Fifo not full for waiter!\n"); */ | ||
| 957 | complete(&rfbi.cmd_done); | ||
| 958 | atomic_dec(&rfbi.cmd_fifo_full); | ||
| 959 | } | ||
| 960 | } | ||
| 961 | 881 | ||
| 962 | /* returns 1 for async op, and 0 for sync op */ | 882 | if (*w == 1) |
| 963 | static int do_update(struct omap_dss_device *dssdev, struct update_region *upd) | 883 | return -EINVAL; |
| 964 | { | ||
| 965 | u16 x = upd->x; | ||
| 966 | u16 y = upd->y; | ||
| 967 | u16 w = upd->w; | ||
| 968 | u16 h = upd->h; | ||
| 969 | 884 | ||
| 970 | perf_mark_setup(); | 885 | if (*w == 0 || *h == 0) |
| 886 | return -EINVAL; | ||
| 971 | 887 | ||
| 972 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 888 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 973 | /*dssdev->driver->enable_te(dssdev, 1); */ | 889 | dss_setup_partial_planes(dssdev, x, y, w, h); |
| 974 | dss_setup_partial_planes(dssdev, &x, &y, &w, &h); | 890 | dispc_set_lcd_size(*w, *h); |
| 975 | } | 891 | } |
| 976 | 892 | ||
| 977 | #ifdef MEASURE_PERF | 893 | return 0; |
| 978 | rfbi.perf_bytes = w * h * 2; /* XXX always 16bit */ | 894 | } |
| 979 | #endif | 895 | EXPORT_SYMBOL(omap_rfbi_prepare_update); |
| 980 | |||
| 981 | dssdev->driver->setup_update(dssdev, x, y, w, h); | ||
| 982 | 896 | ||
| 897 | int omap_rfbi_update(struct omap_dss_device *dssdev, | ||
| 898 | u16 x, u16 y, u16 w, u16 h, | ||
| 899 | void (*callback)(void *), void *data) | ||
| 900 | { | ||
| 983 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | 901 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
| 984 | rfbi_transfer_area(w, h, NULL, NULL); | 902 | rfbi_transfer_area(w, h, callback, data); |
| 985 | return 1; | ||
| 986 | } else { | 903 | } else { |
| 987 | struct omap_overlay *ovl; | 904 | struct omap_overlay *ovl; |
| 988 | void __iomem *addr; | 905 | void __iomem *addr; |
| @@ -994,123 +911,12 @@ static int do_update(struct omap_dss_device *dssdev, struct update_region *upd) | |||
| 994 | 911 | ||
| 995 | omap_rfbi_write_pixels(addr, scr_width, x, y, w, h); | 912 | omap_rfbi_write_pixels(addr, scr_width, x, y, w, h); |
| 996 | 913 | ||
| 997 | perf_show("L4"); | 914 | callback(data); |
| 998 | |||
| 999 | return 0; | ||
| 1000 | } | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | static void process_cmd_fifo(void) | ||
| 1004 | { | ||
| 1005 | int len; | ||
| 1006 | struct update_param p; | ||
| 1007 | struct omap_dss_device *dssdev; | ||
| 1008 | unsigned long flags; | ||
| 1009 | |||
| 1010 | if (atomic_inc_return(&rfbi.cmd_pending) != 1) | ||
| 1011 | return; | ||
| 1012 | |||
| 1013 | while (true) { | ||
| 1014 | spin_lock_irqsave(&rfbi.cmd_lock, flags); | ||
| 1015 | |||
| 1016 | len = kfifo_out(&rfbi.cmd_fifo, (unsigned char *)&p, | ||
| 1017 | sizeof(struct update_param)); | ||
| 1018 | if (len == 0) { | ||
| 1019 | DSSDBG("nothing more in fifo\n"); | ||
| 1020 | atomic_set(&rfbi.cmd_pending, 0); | ||
| 1021 | spin_unlock_irqrestore(&rfbi.cmd_lock, flags); | ||
| 1022 | break; | ||
| 1023 | } | ||
| 1024 | |||
| 1025 | /* DSSDBG("fifo full %d\n", rfbi.cmd_fifo_full.counter);*/ | ||
| 1026 | |||
| 1027 | spin_unlock_irqrestore(&rfbi.cmd_lock, flags); | ||
| 1028 | |||
| 1029 | BUG_ON(len != sizeof(struct update_param)); | ||
| 1030 | BUG_ON(p.rfbi_module > 1); | ||
| 1031 | |||
| 1032 | dssdev = rfbi.dssdev[p.rfbi_module]; | ||
| 1033 | |||
| 1034 | if (p.cmd == RFBI_CMD_UPDATE) { | ||
| 1035 | if (do_update(dssdev, &p.par.r)) | ||
| 1036 | break; /* async op */ | ||
| 1037 | } else if (p.cmd == RFBI_CMD_SYNC) { | ||
| 1038 | DSSDBG("Signaling SYNC done!\n"); | ||
| 1039 | complete(p.par.sync); | ||
| 1040 | } else | ||
| 1041 | BUG(); | ||
| 1042 | } | 915 | } |
| 1043 | 916 | ||
| 1044 | signal_fifo_waiters(); | 917 | return 0; |
| 1045 | } | ||
| 1046 | |||
| 1047 | static void rfbi_push_cmd(struct update_param *p) | ||
| 1048 | { | ||
| 1049 | int ret; | ||
| 1050 | |||
| 1051 | while (1) { | ||
| 1052 | unsigned long flags; | ||
| 1053 | int available; | ||
| 1054 | |||
| 1055 | spin_lock_irqsave(&rfbi.cmd_lock, flags); | ||
| 1056 | available = RFBI_CMD_FIFO_LEN_BYTES - | ||
| 1057 | kfifo_len(&rfbi.cmd_fifo); | ||
| 1058 | |||
| 1059 | /* DSSDBG("%d bytes left in fifo\n", available); */ | ||
| 1060 | if (available < sizeof(struct update_param)) { | ||
| 1061 | DSSDBG("Going to wait because FIFO FULL..\n"); | ||
| 1062 | spin_unlock_irqrestore(&rfbi.cmd_lock, flags); | ||
| 1063 | atomic_inc(&rfbi.cmd_fifo_full); | ||
| 1064 | wait_for_completion(&rfbi.cmd_done); | ||
| 1065 | /*DSSDBG("Woke up because fifo not full anymore\n");*/ | ||
| 1066 | continue; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | ret = kfifo_in(&rfbi.cmd_fifo, (unsigned char *)p, | ||
| 1070 | sizeof(struct update_param)); | ||
| 1071 | /* DSSDBG("pushed %d bytes\n", ret);*/ | ||
| 1072 | |||
| 1073 | spin_unlock_irqrestore(&rfbi.cmd_lock, flags); | ||
| 1074 | |||
| 1075 | BUG_ON(ret != sizeof(struct update_param)); | ||
| 1076 | |||
| 1077 | break; | ||
| 1078 | } | ||
| 1079 | } | ||
| 1080 | |||
| 1081 | static void rfbi_push_update(int rfbi_module, int x, int y, int w, int h) | ||
| 1082 | { | ||
| 1083 | struct update_param p; | ||
| 1084 | |||
| 1085 | p.rfbi_module = rfbi_module; | ||
| 1086 | p.cmd = RFBI_CMD_UPDATE; | ||
| 1087 | |||
| 1088 | p.par.r.x = x; | ||
| 1089 | p.par.r.y = y; | ||
| 1090 | p.par.r.w = w; | ||
| 1091 | p.par.r.h = h; | ||
| 1092 | |||
| 1093 | DSSDBG("RFBI pushed %d,%d %dx%d\n", x, y, w, h); | ||
| 1094 | |||
| 1095 | rfbi_push_cmd(&p); | ||
| 1096 | |||
| 1097 | process_cmd_fifo(); | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | static void rfbi_push_sync(int rfbi_module, struct completion *sync_comp) | ||
| 1101 | { | ||
| 1102 | struct update_param p; | ||
| 1103 | |||
| 1104 | p.rfbi_module = rfbi_module; | ||
| 1105 | p.cmd = RFBI_CMD_SYNC; | ||
| 1106 | p.par.sync = sync_comp; | ||
| 1107 | |||
| 1108 | rfbi_push_cmd(&p); | ||
| 1109 | |||
| 1110 | DSSDBG("RFBI sync pushed to cmd fifo\n"); | ||
| 1111 | |||
| 1112 | process_cmd_fifo(); | ||
| 1113 | } | 918 | } |
| 919 | EXPORT_SYMBOL(omap_rfbi_update); | ||
| 1114 | 920 | ||
| 1115 | void rfbi_dump_regs(struct seq_file *s) | 921 | void rfbi_dump_regs(struct seq_file *s) |
| 1116 | { | 922 | { |
| @@ -1155,12 +961,8 @@ int rfbi_init(void) | |||
| 1155 | { | 961 | { |
| 1156 | u32 rev; | 962 | u32 rev; |
| 1157 | u32 l; | 963 | u32 l; |
| 1158 | int r; | ||
| 1159 | 964 | ||
| 1160 | spin_lock_init(&rfbi.cmd_lock); | 965 | spin_lock_init(&rfbi.cmd_lock); |
| 1161 | r = kfifo_alloc(&rfbi.cmd_fifo, RFBI_CMD_FIFO_LEN_BYTES, GFP_KERNEL); | ||
| 1162 | if (r) | ||
| 1163 | return r; | ||
| 1164 | 966 | ||
| 1165 | init_completion(&rfbi.cmd_done); | 967 | init_completion(&rfbi.cmd_done); |
| 1166 | atomic_set(&rfbi.cmd_fifo_full, 0); | 968 | atomic_set(&rfbi.cmd_fifo_full, 0); |
| @@ -1196,42 +998,10 @@ void rfbi_exit(void) | |||
| 1196 | { | 998 | { |
| 1197 | DSSDBG("rfbi_exit\n"); | 999 | DSSDBG("rfbi_exit\n"); |
| 1198 | 1000 | ||
| 1199 | kfifo_free(&rfbi.cmd_fifo); | ||
| 1200 | |||
| 1201 | iounmap(rfbi.base); | 1001 | iounmap(rfbi.base); |
| 1202 | } | 1002 | } |
| 1203 | 1003 | ||
| 1204 | /* struct omap_display support */ | 1004 | /* struct omap_display support */ |
| 1205 | static int rfbi_display_update(struct omap_dss_device *dssdev, | ||
| 1206 | u16 x, u16 y, u16 w, u16 h) | ||
| 1207 | { | ||
| 1208 | int rfbi_module; | ||
| 1209 | |||
| 1210 | if (w == 0 || h == 0) | ||
| 1211 | return 0; | ||
| 1212 | |||
| 1213 | rfbi_module = rfbi_find_display(dssdev); | ||
| 1214 | |||
| 1215 | rfbi_push_update(rfbi_module, x, y, w, h); | ||
| 1216 | |||
| 1217 | return 0; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | static int rfbi_display_sync(struct omap_dss_device *dssdev) | ||
| 1221 | { | ||
| 1222 | struct completion sync_comp; | ||
| 1223 | int rfbi_module; | ||
| 1224 | |||
| 1225 | rfbi_module = rfbi_find_display(dssdev); | ||
| 1226 | |||
| 1227 | init_completion(&sync_comp); | ||
| 1228 | rfbi_push_sync(rfbi_module, &sync_comp); | ||
| 1229 | DSSDBG("Waiting for SYNC to happen...\n"); | ||
| 1230 | wait_for_completion(&sync_comp); | ||
| 1231 | DSSDBG("Released from SYNC\n"); | ||
| 1232 | return 0; | ||
| 1233 | } | ||
| 1234 | |||
| 1235 | static int rfbi_display_enable(struct omap_dss_device *dssdev) | 1005 | static int rfbi_display_enable(struct omap_dss_device *dssdev) |
| 1236 | { | 1006 | { |
| 1237 | int r; | 1007 | int r; |
| @@ -1291,8 +1061,6 @@ int rfbi_init_display(struct omap_dss_device *dssdev) | |||
| 1291 | { | 1061 | { |
| 1292 | dssdev->enable = rfbi_display_enable; | 1062 | dssdev->enable = rfbi_display_enable; |
| 1293 | dssdev->disable = rfbi_display_disable; | 1063 | dssdev->disable = rfbi_display_disable; |
| 1294 | dssdev->update = rfbi_display_update; | ||
| 1295 | dssdev->sync = rfbi_display_sync; | ||
| 1296 | 1064 | ||
| 1297 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; | 1065 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; |
| 1298 | 1066 | ||
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index 4f68cb0d59de..1ffa760b8545 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
| @@ -172,7 +172,7 @@ static int omapfb_update_window_nolock(struct fb_info *fbi, | |||
| 172 | if (x + w > dw || y + h > dh) | 172 | if (x + w > dw || y + h > dh) |
| 173 | return -EINVAL; | 173 | return -EINVAL; |
| 174 | 174 | ||
| 175 | return display->update(display, x, y, w, h); | 175 | return display->driver->update(display, x, y, w, h); |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | /* This function is exported for SGX driver use */ | 178 | /* This function is exported for SGX driver use */ |
| @@ -496,18 +496,18 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 496 | switch (cmd) { | 496 | switch (cmd) { |
| 497 | case OMAPFB_SYNC_GFX: | 497 | case OMAPFB_SYNC_GFX: |
| 498 | DBG("ioctl SYNC_GFX\n"); | 498 | DBG("ioctl SYNC_GFX\n"); |
| 499 | if (!display || !display->sync) { | 499 | if (!display || !display->driver->sync) { |
| 500 | /* DSS1 never returns an error here, so we neither */ | 500 | /* DSS1 never returns an error here, so we neither */ |
| 501 | /*r = -EINVAL;*/ | 501 | /*r = -EINVAL;*/ |
| 502 | break; | 502 | break; |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | r = display->sync(display); | 505 | r = display->driver->sync(display); |
| 506 | break; | 506 | break; |
| 507 | 507 | ||
| 508 | case OMAPFB_UPDATE_WINDOW_OLD: | 508 | case OMAPFB_UPDATE_WINDOW_OLD: |
| 509 | DBG("ioctl UPDATE_WINDOW_OLD\n"); | 509 | DBG("ioctl UPDATE_WINDOW_OLD\n"); |
| 510 | if (!display || !display->update) { | 510 | if (!display || !display->driver->update) { |
| 511 | r = -EINVAL; | 511 | r = -EINVAL; |
| 512 | break; | 512 | break; |
| 513 | } | 513 | } |
| @@ -525,7 +525,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
| 525 | 525 | ||
| 526 | case OMAPFB_UPDATE_WINDOW: | 526 | case OMAPFB_UPDATE_WINDOW: |
| 527 | DBG("ioctl UPDATE_WINDOW\n"); | 527 | DBG("ioctl UPDATE_WINDOW\n"); |
| 528 | if (!display || !display->update) { | 528 | if (!display || !display->driver->update) { |
| 529 | r = -EINVAL; | 529 | r = -EINVAL; |
| 530 | break; | 530 | break; |
| 531 | } | 531 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index c720842341b2..3dbbddc2d51e 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
| @@ -1254,11 +1254,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
| 1254 | exit: | 1254 | exit: |
| 1255 | omapfb_unlock(fbdev); | 1255 | omapfb_unlock(fbdev); |
| 1256 | 1256 | ||
| 1257 | if (r == 0 && do_update && display->update) { | 1257 | if (r == 0 && do_update && display->driver->update) { |
| 1258 | u16 w, h; | 1258 | u16 w, h; |
| 1259 | display->driver->get_resolution(display, &w, &h); | 1259 | display->driver->get_resolution(display, &w, &h); |
| 1260 | 1260 | ||
| 1261 | r = display->update(display, 0, 0, w, h); | 1261 | r = display->driver->update(display, 0, 0, w, h); |
| 1262 | } | 1262 | } |
| 1263 | 1263 | ||
| 1264 | return r; | 1264 | return r; |
| @@ -1639,8 +1639,8 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
| 1639 | if (old_size == size && old_type == type) | 1639 | if (old_size == size && old_type == type) |
| 1640 | return 0; | 1640 | return 0; |
| 1641 | 1641 | ||
| 1642 | if (display && display->sync) | 1642 | if (display && display->driver->sync) |
| 1643 | display->sync(display); | 1643 | display->driver->sync(display); |
| 1644 | 1644 | ||
| 1645 | omapfb_free_fbmem(fbi); | 1645 | omapfb_free_fbmem(fbi); |
| 1646 | 1646 | ||
| @@ -2221,7 +2221,7 @@ static int omapfb_probe(struct platform_device *pdev) | |||
| 2221 | 2221 | ||
| 2222 | dssdrv->get_resolution(def_display, | 2222 | dssdrv->get_resolution(def_display, |
| 2223 | &w, &h); | 2223 | &w, &h); |
| 2224 | def_display->update(def_display, 0, 0, w, h); | 2224 | def_display->driver->update(def_display, 0, 0, w, h); |
| 2225 | #endif | 2225 | #endif |
| 2226 | } else { | 2226 | } else { |
| 2227 | if (dssdrv->set_update_mode) | 2227 | if (dssdrv->set_update_mode) |
