diff options
author | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2011-06-01 08:54:06 -0400 |
---|---|---|
committer | Tomi Valkeinen <tomi.valkeinen@ti.com> | 2011-07-25 03:22:07 -0400 |
commit | 49ea86f3fae21dd0334668b621e9c88f43a73c86 (patch) | |
tree | c1940d9d5f9de067c0474448848f54318cbfcefd /drivers/video | |
parent | 39020710e707a01d80ea6c9e55dad4de93bb4730 (diff) |
OMAP: DSS2: DISPC: Fix context save/restore
The current method of saving and restoring the context could cause a
restore before saving, effectively "restoring" zero values to registers.
Add ctx_valid field to indicate if the saved context is valid and can be
restored.
Also restructure the code to save the ctx_loss_count in save_context(),
which makes more sense than the previous method of storing new
ctx_loss_count in dispc_need_ctx_restore.
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/omap2/dss/dispc.c | 97 |
1 files changed, 38 insertions, 59 deletions
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 7c1b7c1e4b6..0f3961a1ce2 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -114,6 +114,7 @@ static struct { | |||
114 | u32 error_irqs; | 114 | u32 error_irqs; |
115 | struct work_struct error_work; | 115 | struct work_struct error_work; |
116 | 116 | ||
117 | bool ctx_valid; | ||
117 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; | 118 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; |
118 | 119 | ||
119 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 120 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
@@ -146,6 +147,23 @@ static inline u32 dispc_read_reg(const u16 idx) | |||
146 | return __raw_readl(dispc.base + idx); | 147 | return __raw_readl(dispc.base + idx); |
147 | } | 148 | } |
148 | 149 | ||
150 | static int dispc_get_ctx_loss_count(void) | ||
151 | { | ||
152 | struct device *dev = &dispc.pdev->dev; | ||
153 | struct omap_display_platform_data *pdata = dev->platform_data; | ||
154 | struct omap_dss_board_info *board_data = pdata->board_data; | ||
155 | int cnt; | ||
156 | |||
157 | if (!board_data->get_context_loss_count) | ||
158 | return -ENOENT; | ||
159 | |||
160 | cnt = board_data->get_context_loss_count(dev); | ||
161 | |||
162 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
163 | |||
164 | return cnt; | ||
165 | } | ||
166 | |||
149 | #define SR(reg) \ | 167 | #define SR(reg) \ |
150 | dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) | 168 | dispc.ctx[DISPC_##reg / sizeof(u32)] = dispc_read_reg(DISPC_##reg) |
151 | #define RR(reg) \ | 169 | #define RR(reg) \ |
@@ -322,14 +340,30 @@ static void dispc_save_context(void) | |||
322 | 340 | ||
323 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | 341 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) |
324 | SR(DIVISOR); | 342 | SR(DIVISOR); |
343 | |||
344 | dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); | ||
345 | dispc.ctx_valid = true; | ||
346 | |||
347 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); | ||
325 | } | 348 | } |
326 | 349 | ||
327 | static void dispc_restore_context(void) | 350 | static void dispc_restore_context(void) |
328 | { | 351 | { |
329 | int i; | 352 | int i, ctx; |
330 | 353 | ||
331 | DSSDBG("dispc_restore_context\n"); | 354 | DSSDBG("dispc_restore_context\n"); |
332 | 355 | ||
356 | if (!dispc.ctx_valid) | ||
357 | return; | ||
358 | |||
359 | ctx = dispc_get_ctx_loss_count(); | ||
360 | |||
361 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) | ||
362 | return; | ||
363 | |||
364 | DSSDBG("ctx_loss_count: saved %d, current %d\n", | ||
365 | dispc.ctx_loss_cnt, ctx); | ||
366 | |||
333 | /*RR(IRQENABLE);*/ | 367 | /*RR(IRQENABLE);*/ |
334 | /*RR(CONTROL);*/ | 368 | /*RR(CONTROL);*/ |
335 | RR(CONFIG); | 369 | RR(CONFIG); |
@@ -508,65 +542,13 @@ static void dispc_restore_context(void) | |||
508 | * the context is fully restored | 542 | * the context is fully restored |
509 | */ | 543 | */ |
510 | RR(IRQENABLE); | 544 | RR(IRQENABLE); |
545 | |||
546 | DSSDBG("context restored\n"); | ||
511 | } | 547 | } |
512 | 548 | ||
513 | #undef SR | 549 | #undef SR |
514 | #undef RR | 550 | #undef RR |
515 | 551 | ||
516 | static void dispc_init_ctx_loss_count(void) | ||
517 | { | ||
518 | struct device *dev = &dispc.pdev->dev; | ||
519 | struct omap_display_platform_data *pdata = dev->platform_data; | ||
520 | struct omap_dss_board_info *board_data = pdata->board_data; | ||
521 | int cnt = 0; | ||
522 | |||
523 | /* | ||
524 | * get_context_loss_count returns negative on error. We'll ignore the | ||
525 | * error and store the error to ctx_loss_cnt, which will cause | ||
526 | * dispc_need_ctx_restore() call to return true. | ||
527 | */ | ||
528 | |||
529 | if (board_data->get_context_loss_count) | ||
530 | cnt = board_data->get_context_loss_count(dev); | ||
531 | |||
532 | WARN_ON(cnt < 0); | ||
533 | |||
534 | dispc.ctx_loss_cnt = cnt; | ||
535 | |||
536 | DSSDBG("initial ctx_loss_cnt %u\n", cnt); | ||
537 | } | ||
538 | |||
539 | static bool dispc_need_ctx_restore(void) | ||
540 | { | ||
541 | struct device *dev = &dispc.pdev->dev; | ||
542 | struct omap_display_platform_data *pdata = dev->platform_data; | ||
543 | struct omap_dss_board_info *board_data = pdata->board_data; | ||
544 | int cnt; | ||
545 | |||
546 | /* | ||
547 | * If get_context_loss_count is not available, assume that we need | ||
548 | * context restore always. | ||
549 | */ | ||
550 | if (!board_data->get_context_loss_count) | ||
551 | return true; | ||
552 | |||
553 | cnt = board_data->get_context_loss_count(dev); | ||
554 | if (cnt < 0) { | ||
555 | dev_err(dev, "getting context loss count failed, will force " | ||
556 | "context restore\n"); | ||
557 | dispc.ctx_loss_cnt = cnt; | ||
558 | return true; | ||
559 | } | ||
560 | |||
561 | if (cnt == dispc.ctx_loss_cnt) | ||
562 | return false; | ||
563 | |||
564 | DSSDBG("ctx_loss_cnt %d -> %d\n", dispc.ctx_loss_cnt, cnt); | ||
565 | dispc.ctx_loss_cnt = cnt; | ||
566 | |||
567 | return true; | ||
568 | } | ||
569 | |||
570 | int dispc_runtime_get(void) | 552 | int dispc_runtime_get(void) |
571 | { | 553 | { |
572 | int r; | 554 | int r; |
@@ -3709,8 +3691,6 @@ static int omap_dispchw_probe(struct platform_device *pdev) | |||
3709 | goto err_irq; | 3691 | goto err_irq; |
3710 | } | 3692 | } |
3711 | 3693 | ||
3712 | dispc_init_ctx_loss_count(); | ||
3713 | |||
3714 | pm_runtime_enable(&pdev->dev); | 3694 | pm_runtime_enable(&pdev->dev); |
3715 | 3695 | ||
3716 | r = dispc_runtime_get(); | 3696 | r = dispc_runtime_get(); |
@@ -3769,8 +3749,7 @@ static int dispc_runtime_resume(struct device *dev) | |||
3769 | return r; | 3749 | return r; |
3770 | 3750 | ||
3771 | clk_enable(dispc.dss_clk); | 3751 | clk_enable(dispc.dss_clk); |
3772 | if (dispc_need_ctx_restore()) | 3752 | dispc_restore_context(); |
3773 | dispc_restore_context(); | ||
3774 | 3753 | ||
3775 | return 0; | 3754 | return 0; |
3776 | } | 3755 | } |