aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiu Ying <Ying.Liu@freescale.com>2015-04-03 00:51:05 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-07-21 13:10:05 -0400
commitab12dcd70c11074e6ed28b0304f059a075e33db0 (patch)
tree5ff7a5e9d8eb44252edbb83a247e7c6b4f03ef34
parent25d8f169eee423940158a0ab33ed5dd1dd995cf9 (diff)
video: mxsfb: Make sure axi clock is enabled when accessing registers
commit 2fa3b4c4a78a5db3502ab9e32630ea660ff923d0 upstream. The LCDIF engines embedded in i.MX6sl and i.MX6sx SoCs need the axi clock as the engine's system clock. The clock should be enabled when accessing LCDIF registers, otherwise the kernel would hang up. We should also keep the clock enabled when the engine is being active to scan out frames from memory. This patch makes sure the axi clock is enabled when accessing registers so that the kernel hang up issue can be fixed. Reported-by: Peter Chen <peter.chen@freescale.com> Tested-by: Peter Chen <peter.chen@freescale.com> Signed-off-by: Liu Ying <Ying.Liu@freescale.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/video/fbdev/mxsfb.c68
1 files changed, 54 insertions, 14 deletions
diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c
index f8ac4a452f26..0f64165b0147 100644
--- a/drivers/video/fbdev/mxsfb.c
+++ b/drivers/video/fbdev/mxsfb.c
@@ -316,6 +316,18 @@ static int mxsfb_check_var(struct fb_var_screeninfo *var,
316 return 0; 316 return 0;
317} 317}
318 318
319static inline void mxsfb_enable_axi_clk(struct mxsfb_info *host)
320{
321 if (host->clk_axi)
322 clk_prepare_enable(host->clk_axi);
323}
324
325static inline void mxsfb_disable_axi_clk(struct mxsfb_info *host)
326{
327 if (host->clk_axi)
328 clk_disable_unprepare(host->clk_axi);
329}
330
319static void mxsfb_enable_controller(struct fb_info *fb_info) 331static void mxsfb_enable_controller(struct fb_info *fb_info)
320{ 332{
321 struct mxsfb_info *host = to_imxfb_host(fb_info); 333 struct mxsfb_info *host = to_imxfb_host(fb_info);
@@ -333,14 +345,13 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
333 } 345 }
334 } 346 }
335 347
336 if (host->clk_axi)
337 clk_prepare_enable(host->clk_axi);
338
339 if (host->clk_disp_axi) 348 if (host->clk_disp_axi)
340 clk_prepare_enable(host->clk_disp_axi); 349 clk_prepare_enable(host->clk_disp_axi);
341 clk_prepare_enable(host->clk); 350 clk_prepare_enable(host->clk);
342 clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U); 351 clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
343 352
353 mxsfb_enable_axi_clk(host);
354
344 /* if it was disabled, re-enable the mode again */ 355 /* if it was disabled, re-enable the mode again */
345 writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET); 356 writel(CTRL_DOTCLK_MODE, host->base + LCDC_CTRL + REG_SET);
346 357
@@ -380,11 +391,11 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
380 reg = readl(host->base + LCDC_VDCTRL4); 391 reg = readl(host->base + LCDC_VDCTRL4);
381 writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4); 392 writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
382 393
394 mxsfb_disable_axi_clk(host);
395
383 clk_disable_unprepare(host->clk); 396 clk_disable_unprepare(host->clk);
384 if (host->clk_disp_axi) 397 if (host->clk_disp_axi)
385 clk_disable_unprepare(host->clk_disp_axi); 398 clk_disable_unprepare(host->clk_disp_axi);
386 if (host->clk_axi)
387 clk_disable_unprepare(host->clk_axi);
388 399
389 host->enabled = 0; 400 host->enabled = 0;
390 401
@@ -421,6 +432,8 @@ static int mxsfb_set_par(struct fb_info *fb_info)
421 mxsfb_disable_controller(fb_info); 432 mxsfb_disable_controller(fb_info);
422 } 433 }
423 434
435 mxsfb_enable_axi_clk(host);
436
424 /* clear the FIFOs */ 437 /* clear the FIFOs */
425 writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET); 438 writel(CTRL1_FIFO_CLEAR, host->base + LCDC_CTRL1 + REG_SET);
426 439
@@ -438,6 +451,7 @@ static int mxsfb_set_par(struct fb_info *fb_info)
438 ctrl |= CTRL_SET_WORD_LENGTH(3); 451 ctrl |= CTRL_SET_WORD_LENGTH(3);
439 switch (host->ld_intf_width) { 452 switch (host->ld_intf_width) {
440 case STMLCDIF_8BIT: 453 case STMLCDIF_8BIT:
454 mxsfb_disable_axi_clk(host);
441 dev_err(&host->pdev->dev, 455 dev_err(&host->pdev->dev,
442 "Unsupported LCD bus width mapping\n"); 456 "Unsupported LCD bus width mapping\n");
443 return -EINVAL; 457 return -EINVAL;
@@ -451,6 +465,7 @@ static int mxsfb_set_par(struct fb_info *fb_info)
451 writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1); 465 writel(CTRL1_SET_BYTE_PACKAGING(0x7), host->base + LCDC_CTRL1);
452 break; 466 break;
453 default: 467 default:
468 mxsfb_disable_axi_clk(host);
454 dev_err(&host->pdev->dev, "Unhandled color depth of %u\n", 469 dev_err(&host->pdev->dev, "Unhandled color depth of %u\n",
455 fb_info->var.bits_per_pixel); 470 fb_info->var.bits_per_pixel);
456 return -EINVAL; 471 return -EINVAL;
@@ -504,6 +519,8 @@ static int mxsfb_set_par(struct fb_info *fb_info)
504 fb_info->fix.line_length * fb_info->var.yoffset, 519 fb_info->fix.line_length * fb_info->var.yoffset,
505 host->base + host->devdata->next_buf); 520 host->base + host->devdata->next_buf);
506 521
522 mxsfb_disable_axi_clk(host);
523
507 if (reenable) 524 if (reenable)
508 mxsfb_enable_controller(fb_info); 525 mxsfb_enable_controller(fb_info);
509 526
@@ -582,10 +599,14 @@ static int mxsfb_pan_display(struct fb_var_screeninfo *var,
582 599
583 offset = fb_info->fix.line_length * var->yoffset; 600 offset = fb_info->fix.line_length * var->yoffset;
584 601
602 mxsfb_enable_axi_clk(host);
603
585 /* update on next VSYNC */ 604 /* update on next VSYNC */
586 writel(fb_info->fix.smem_start + offset, 605 writel(fb_info->fix.smem_start + offset,
587 host->base + host->devdata->next_buf); 606 host->base + host->devdata->next_buf);
588 607
608 mxsfb_disable_axi_clk(host);
609
589 return 0; 610 return 0;
590} 611}
591 612
@@ -608,13 +629,17 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
608 unsigned line_count; 629 unsigned line_count;
609 unsigned period; 630 unsigned period;
610 unsigned long pa, fbsize; 631 unsigned long pa, fbsize;
611 int bits_per_pixel, ofs; 632 int bits_per_pixel, ofs, ret = 0;
612 u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl; 633 u32 transfer_count, vdctrl0, vdctrl2, vdctrl3, vdctrl4, ctrl;
613 634
635 mxsfb_enable_axi_clk(host);
636
614 /* Only restore the mode when the controller is running */ 637 /* Only restore the mode when the controller is running */
615 ctrl = readl(host->base + LCDC_CTRL); 638 ctrl = readl(host->base + LCDC_CTRL);
616 if (!(ctrl & CTRL_RUN)) 639 if (!(ctrl & CTRL_RUN)) {
617 return -EINVAL; 640 ret = -EINVAL;
641 goto err;
642 }
618 643
619 vdctrl0 = readl(host->base + LCDC_VDCTRL0); 644 vdctrl0 = readl(host->base + LCDC_VDCTRL0);
620 vdctrl2 = readl(host->base + LCDC_VDCTRL2); 645 vdctrl2 = readl(host->base + LCDC_VDCTRL2);
@@ -635,7 +660,8 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
635 break; 660 break;
636 case 1: 661 case 1:
637 default: 662 default:
638 return -EINVAL; 663 ret = -EINVAL;
664 goto err;
639 } 665 }
640 666
641 fb_info->var.bits_per_pixel = bits_per_pixel; 667 fb_info->var.bits_per_pixel = bits_per_pixel;
@@ -673,10 +699,14 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
673 699
674 pa = readl(host->base + host->devdata->cur_buf); 700 pa = readl(host->base + host->devdata->cur_buf);
675 fbsize = fb_info->fix.line_length * vmode->yres; 701 fbsize = fb_info->fix.line_length * vmode->yres;
676 if (pa < fb_info->fix.smem_start) 702 if (pa < fb_info->fix.smem_start) {
677 return -EINVAL; 703 ret = -EINVAL;
678 if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) 704 goto err;
679 return -EINVAL; 705 }
706 if (pa + fbsize > fb_info->fix.smem_start + fb_info->fix.smem_len) {
707 ret = -EINVAL;
708 goto err;
709 }
680 ofs = pa - fb_info->fix.smem_start; 710 ofs = pa - fb_info->fix.smem_start;
681 if (ofs) { 711 if (ofs) {
682 memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize); 712 memmove(fb_info->screen_base, fb_info->screen_base + ofs, fbsize);
@@ -689,7 +719,11 @@ static int mxsfb_restore_mode(struct mxsfb_info *host,
689 clk_prepare_enable(host->clk); 719 clk_prepare_enable(host->clk);
690 host->enabled = 1; 720 host->enabled = 1;
691 721
692 return 0; 722err:
723 if (ret)
724 mxsfb_disable_axi_clk(host);
725
726 return ret;
693} 727}
694 728
695static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host, 729static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host,
@@ -915,7 +949,9 @@ static int mxsfb_probe(struct platform_device *pdev)
915 } 949 }
916 950
917 if (!host->enabled) { 951 if (!host->enabled) {
952 mxsfb_enable_axi_clk(host);
918 writel(0, host->base + LCDC_CTRL); 953 writel(0, host->base + LCDC_CTRL);
954 mxsfb_disable_axi_clk(host);
919 mxsfb_set_par(fb_info); 955 mxsfb_set_par(fb_info);
920 mxsfb_enable_controller(fb_info); 956 mxsfb_enable_controller(fb_info);
921 } 957 }
@@ -954,11 +990,15 @@ static void mxsfb_shutdown(struct platform_device *pdev)
954 struct fb_info *fb_info = platform_get_drvdata(pdev); 990 struct fb_info *fb_info = platform_get_drvdata(pdev);
955 struct mxsfb_info *host = to_imxfb_host(fb_info); 991 struct mxsfb_info *host = to_imxfb_host(fb_info);
956 992
993 mxsfb_enable_axi_clk(host);
994
957 /* 995 /*
958 * Force stop the LCD controller as keeping it running during reboot 996 * Force stop the LCD controller as keeping it running during reboot
959 * might interfere with the BootROM's boot mode pads sampling. 997 * might interfere with the BootROM's boot mode pads sampling.
960 */ 998 */
961 writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR); 999 writel(CTRL_RUN, host->base + LCDC_CTRL + REG_CLR);
1000
1001 mxsfb_disable_axi_clk(host);
962} 1002}
963 1003
964static struct platform_driver mxsfb_driver = { 1004static struct platform_driver mxsfb_driver = {