diff options
-rw-r--r-- | drivers/video/fbdev/mxsfb.c | 68 |
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 | ||
319 | static 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 | |||
325 | static 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 | |||
319 | static void mxsfb_enable_controller(struct fb_info *fb_info) | 331 | static 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; | 722 | err: |
723 | if (ret) | ||
724 | mxsfb_disable_axi_clk(host); | ||
725 | |||
726 | return ret; | ||
693 | } | 727 | } |
694 | 728 | ||
695 | static int mxsfb_init_fbinfo_dt(struct mxsfb_info *host, | 729 | static 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 | ||
964 | static struct platform_driver mxsfb_driver = { | 1004 | static struct platform_driver mxsfb_driver = { |