diff options
Diffstat (limited to 'drivers/video/da8xx-fb.c')
-rw-r--r-- | drivers/video/da8xx-fb.c | 283 |
1 files changed, 220 insertions, 63 deletions
diff --git a/drivers/video/da8xx-fb.c b/drivers/video/da8xx-fb.c index 113d43a16f54..80665f66ac1a 100644 --- a/drivers/video/da8xx-fb.c +++ b/drivers/video/da8xx-fb.c | |||
@@ -26,7 +26,9 @@ | |||
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
28 | #include <linux/uaccess.h> | 28 | #include <linux/uaccess.h> |
29 | #include <linux/pm_runtime.h> | ||
29 | #include <linux/interrupt.h> | 30 | #include <linux/interrupt.h> |
31 | #include <linux/wait.h> | ||
30 | #include <linux/clk.h> | 32 | #include <linux/clk.h> |
31 | #include <linux/cpufreq.h> | 33 | #include <linux/cpufreq.h> |
32 | #include <linux/console.h> | 34 | #include <linux/console.h> |
@@ -48,6 +50,7 @@ | |||
48 | #define LCD_PL_LOAD_DONE BIT(6) | 50 | #define LCD_PL_LOAD_DONE BIT(6) |
49 | #define LCD_FIFO_UNDERFLOW BIT(5) | 51 | #define LCD_FIFO_UNDERFLOW BIT(5) |
50 | #define LCD_SYNC_LOST BIT(2) | 52 | #define LCD_SYNC_LOST BIT(2) |
53 | #define LCD_FRAME_DONE BIT(0) | ||
51 | 54 | ||
52 | /* LCD DMA Control Register */ | 55 | /* LCD DMA Control Register */ |
53 | #define LCD_DMA_BURST_SIZE(x) ((x) << 4) | 56 | #define LCD_DMA_BURST_SIZE(x) ((x) << 4) |
@@ -86,6 +89,8 @@ | |||
86 | #define LCD_V2_LIDD_CLK_EN BIT(1) | 89 | #define LCD_V2_LIDD_CLK_EN BIT(1) |
87 | #define LCD_V2_CORE_CLK_EN BIT(0) | 90 | #define LCD_V2_CORE_CLK_EN BIT(0) |
88 | #define LCD_V2_LPP_B10 26 | 91 | #define LCD_V2_LPP_B10 26 |
92 | #define LCD_V2_TFT_24BPP_MODE BIT(25) | ||
93 | #define LCD_V2_TFT_24BPP_UNPACK BIT(26) | ||
89 | 94 | ||
90 | /* LCD Raster Timing 2 Register */ | 95 | /* LCD Raster Timing 2 Register */ |
91 | #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) | 96 | #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x) ((x) << 16) |
@@ -135,6 +140,8 @@ static void __iomem *da8xx_fb_reg_base; | |||
135 | static struct resource *lcdc_regs; | 140 | static struct resource *lcdc_regs; |
136 | static unsigned int lcd_revision; | 141 | static unsigned int lcd_revision; |
137 | static irq_handler_t lcdc_irq_handler; | 142 | static irq_handler_t lcdc_irq_handler; |
143 | static wait_queue_head_t frame_done_wq; | ||
144 | static int frame_done_flag; | ||
138 | 145 | ||
139 | static inline unsigned int lcdc_read(unsigned int addr) | 146 | static inline unsigned int lcdc_read(unsigned int addr) |
140 | { | 147 | { |
@@ -156,7 +163,6 @@ struct da8xx_fb_par { | |||
156 | unsigned int dma_end; | 163 | unsigned int dma_end; |
157 | struct clk *lcdc_clk; | 164 | struct clk *lcdc_clk; |
158 | int irq; | 165 | int irq; |
159 | unsigned short pseudo_palette[16]; | ||
160 | unsigned int palette_sz; | 166 | unsigned int palette_sz; |
161 | unsigned int pxl_clk; | 167 | unsigned int pxl_clk; |
162 | int blank; | 168 | int blank; |
@@ -175,6 +181,7 @@ struct da8xx_fb_par { | |||
175 | unsigned int lcd_fck_rate; | 181 | unsigned int lcd_fck_rate; |
176 | #endif | 182 | #endif |
177 | void (*panel_power_ctrl)(int); | 183 | void (*panel_power_ctrl)(int); |
184 | u32 pseudo_palette[16]; | ||
178 | }; | 185 | }; |
179 | 186 | ||
180 | /* Variable Screen Information */ | 187 | /* Variable Screen Information */ |
@@ -288,13 +295,26 @@ static inline void lcd_enable_raster(void) | |||
288 | } | 295 | } |
289 | 296 | ||
290 | /* Disable the Raster Engine of the LCD Controller */ | 297 | /* Disable the Raster Engine of the LCD Controller */ |
291 | static inline void lcd_disable_raster(void) | 298 | static inline void lcd_disable_raster(bool wait_for_frame_done) |
292 | { | 299 | { |
293 | u32 reg; | 300 | u32 reg; |
301 | int ret; | ||
294 | 302 | ||
295 | reg = lcdc_read(LCD_RASTER_CTRL_REG); | 303 | reg = lcdc_read(LCD_RASTER_CTRL_REG); |
296 | if (reg & LCD_RASTER_ENABLE) | 304 | if (reg & LCD_RASTER_ENABLE) |
297 | lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); | 305 | lcdc_write(reg & ~LCD_RASTER_ENABLE, LCD_RASTER_CTRL_REG); |
306 | else | ||
307 | /* return if already disabled */ | ||
308 | return; | ||
309 | |||
310 | if ((wait_for_frame_done == true) && (lcd_revision == LCD_VERSION_2)) { | ||
311 | frame_done_flag = 0; | ||
312 | ret = wait_event_interruptible_timeout(frame_done_wq, | ||
313 | frame_done_flag != 0, | ||
314 | msecs_to_jiffies(50)); | ||
315 | if (ret == 0) | ||
316 | pr_err("LCD Controller timed out\n"); | ||
317 | } | ||
298 | } | 318 | } |
299 | 319 | ||
300 | static void lcd_blit(int load_mode, struct da8xx_fb_par *par) | 320 | static void lcd_blit(int load_mode, struct da8xx_fb_par *par) |
@@ -321,7 +341,8 @@ static void lcd_blit(int load_mode, struct da8xx_fb_par *par) | |||
321 | } else { | 341 | } else { |
322 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | | 342 | reg_int = lcdc_read(LCD_INT_ENABLE_SET_REG) | |
323 | LCD_V2_END_OF_FRAME0_INT_ENA | | 343 | LCD_V2_END_OF_FRAME0_INT_ENA | |
324 | LCD_V2_END_OF_FRAME1_INT_ENA; | 344 | LCD_V2_END_OF_FRAME1_INT_ENA | |
345 | LCD_FRAME_DONE; | ||
325 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); | 346 | lcdc_write(reg_int, LCD_INT_ENABLE_SET_REG); |
326 | } | 347 | } |
327 | reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; | 348 | reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE; |
@@ -499,6 +520,9 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | |||
499 | { | 520 | { |
500 | u32 reg; | 521 | u32 reg; |
501 | 522 | ||
523 | if (bpp > 16 && lcd_revision == LCD_VERSION_1) | ||
524 | return -EINVAL; | ||
525 | |||
502 | /* Set the Panel Width */ | 526 | /* Set the Panel Width */ |
503 | /* Pixels per line = (PPL + 1)*16 */ | 527 | /* Pixels per line = (PPL + 1)*16 */ |
504 | if (lcd_revision == LCD_VERSION_1) { | 528 | if (lcd_revision == LCD_VERSION_1) { |
@@ -542,14 +566,19 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | |||
542 | reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); | 566 | reg = lcdc_read(LCD_RASTER_CTRL_REG) & ~(1 << 8); |
543 | if (raster_order) | 567 | if (raster_order) |
544 | reg |= LCD_RASTER_ORDER; | 568 | reg |= LCD_RASTER_ORDER; |
545 | lcdc_write(reg, LCD_RASTER_CTRL_REG); | 569 | |
570 | par->palette_sz = 16 * 2; | ||
546 | 571 | ||
547 | switch (bpp) { | 572 | switch (bpp) { |
548 | case 1: | 573 | case 1: |
549 | case 2: | 574 | case 2: |
550 | case 4: | 575 | case 4: |
551 | case 16: | 576 | case 16: |
552 | par->palette_sz = 16 * 2; | 577 | break; |
578 | case 24: | ||
579 | reg |= LCD_V2_TFT_24BPP_MODE; | ||
580 | case 32: | ||
581 | reg |= LCD_V2_TFT_24BPP_UNPACK; | ||
553 | break; | 582 | break; |
554 | 583 | ||
555 | case 8: | 584 | case 8: |
@@ -560,9 +589,12 @@ static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height, | |||
560 | return -EINVAL; | 589 | return -EINVAL; |
561 | } | 590 | } |
562 | 591 | ||
592 | lcdc_write(reg, LCD_RASTER_CTRL_REG); | ||
593 | |||
563 | return 0; | 594 | return 0; |
564 | } | 595 | } |
565 | 596 | ||
597 | #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16) | ||
566 | static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | 598 | static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, |
567 | unsigned blue, unsigned transp, | 599 | unsigned blue, unsigned transp, |
568 | struct fb_info *info) | 600 | struct fb_info *info) |
@@ -578,13 +610,38 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
578 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) | 610 | if (info->fix.visual == FB_VISUAL_DIRECTCOLOR) |
579 | return 1; | 611 | return 1; |
580 | 612 | ||
581 | if (info->var.bits_per_pixel == 4) { | 613 | if (info->var.bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) |
582 | if (regno > 15) | 614 | return -EINVAL; |
583 | return 1; | ||
584 | 615 | ||
585 | if (info->var.grayscale) { | 616 | switch (info->fix.visual) { |
586 | pal = regno; | 617 | case FB_VISUAL_TRUECOLOR: |
587 | } else { | 618 | red = CNVT_TOHW(red, info->var.red.length); |
619 | green = CNVT_TOHW(green, info->var.green.length); | ||
620 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
621 | break; | ||
622 | case FB_VISUAL_PSEUDOCOLOR: | ||
623 | switch (info->var.bits_per_pixel) { | ||
624 | case 4: | ||
625 | if (regno > 15) | ||
626 | return -EINVAL; | ||
627 | |||
628 | if (info->var.grayscale) { | ||
629 | pal = regno; | ||
630 | } else { | ||
631 | red >>= 4; | ||
632 | green >>= 8; | ||
633 | blue >>= 12; | ||
634 | |||
635 | pal = red & 0x0f00; | ||
636 | pal |= green & 0x00f0; | ||
637 | pal |= blue & 0x000f; | ||
638 | } | ||
639 | if (regno == 0) | ||
640 | pal |= 0x2000; | ||
641 | palette[regno] = pal; | ||
642 | break; | ||
643 | |||
644 | case 8: | ||
588 | red >>= 4; | 645 | red >>= 4; |
589 | green >>= 8; | 646 | green >>= 8; |
590 | blue >>= 12; | 647 | blue >>= 12; |
@@ -592,36 +649,36 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
592 | pal = (red & 0x0f00); | 649 | pal = (red & 0x0f00); |
593 | pal |= (green & 0x00f0); | 650 | pal |= (green & 0x00f0); |
594 | pal |= (blue & 0x000f); | 651 | pal |= (blue & 0x000f); |
595 | } | ||
596 | if (regno == 0) | ||
597 | pal |= 0x2000; | ||
598 | palette[regno] = pal; | ||
599 | |||
600 | } else if (info->var.bits_per_pixel == 8) { | ||
601 | red >>= 4; | ||
602 | green >>= 8; | ||
603 | blue >>= 12; | ||
604 | |||
605 | pal = (red & 0x0f00); | ||
606 | pal |= (green & 0x00f0); | ||
607 | pal |= (blue & 0x000f); | ||
608 | 652 | ||
609 | if (palette[regno] != pal) { | 653 | if (palette[regno] != pal) { |
610 | update_hw = 1; | 654 | update_hw = 1; |
611 | palette[regno] = pal; | 655 | palette[regno] = pal; |
656 | } | ||
657 | break; | ||
612 | } | 658 | } |
613 | } else if ((info->var.bits_per_pixel == 16) && regno < 16) { | 659 | break; |
614 | red >>= (16 - info->var.red.length); | 660 | } |
615 | red <<= info->var.red.offset; | ||
616 | 661 | ||
617 | green >>= (16 - info->var.green.length); | 662 | /* Truecolor has hardware independent palette */ |
618 | green <<= info->var.green.offset; | 663 | if (info->fix.visual == FB_VISUAL_TRUECOLOR) { |
664 | u32 v; | ||
619 | 665 | ||
620 | blue >>= (16 - info->var.blue.length); | 666 | if (regno > 15) |
621 | blue <<= info->var.blue.offset; | 667 | return -EINVAL; |
622 | 668 | ||
623 | par->pseudo_palette[regno] = red | green | blue; | 669 | v = (red << info->var.red.offset) | |
670 | (green << info->var.green.offset) | | ||
671 | (blue << info->var.blue.offset); | ||
624 | 672 | ||
673 | switch (info->var.bits_per_pixel) { | ||
674 | case 16: | ||
675 | ((u16 *) (info->pseudo_palette))[regno] = v; | ||
676 | break; | ||
677 | case 24: | ||
678 | case 32: | ||
679 | ((u32 *) (info->pseudo_palette))[regno] = v; | ||
680 | break; | ||
681 | } | ||
625 | if (palette[0] != 0x4000) { | 682 | if (palette[0] != 0x4000) { |
626 | update_hw = 1; | 683 | update_hw = 1; |
627 | palette[0] = 0x4000; | 684 | palette[0] = 0x4000; |
@@ -634,11 +691,12 @@ static int fb_setcolreg(unsigned regno, unsigned red, unsigned green, | |||
634 | 691 | ||
635 | return 0; | 692 | return 0; |
636 | } | 693 | } |
694 | #undef CNVT_TOHW | ||
637 | 695 | ||
638 | static void lcd_reset(struct da8xx_fb_par *par) | 696 | static void lcd_reset(struct da8xx_fb_par *par) |
639 | { | 697 | { |
640 | /* Disable the Raster if previously Enabled */ | 698 | /* Disable the Raster if previously Enabled */ |
641 | lcd_disable_raster(); | 699 | lcd_disable_raster(false); |
642 | 700 | ||
643 | /* DMA has to be disabled */ | 701 | /* DMA has to be disabled */ |
644 | lcdc_write(0, LCD_DMA_CTRL_REG); | 702 | lcdc_write(0, LCD_DMA_CTRL_REG); |
@@ -734,7 +792,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) | |||
734 | u32 stat = lcdc_read(LCD_MASKED_STAT_REG); | 792 | u32 stat = lcdc_read(LCD_MASKED_STAT_REG); |
735 | 793 | ||
736 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | 794 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { |
737 | lcd_disable_raster(); | 795 | lcd_disable_raster(false); |
738 | lcdc_write(stat, LCD_MASKED_STAT_REG); | 796 | lcdc_write(stat, LCD_MASKED_STAT_REG); |
739 | lcd_enable_raster(); | 797 | lcd_enable_raster(); |
740 | } else if (stat & LCD_PL_LOAD_DONE) { | 798 | } else if (stat & LCD_PL_LOAD_DONE) { |
@@ -744,7 +802,7 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) | |||
744 | * interrupt via the following write to the status register. If | 802 | * interrupt via the following write to the status register. If |
745 | * this is done after then one gets multiple PL done interrupts. | 803 | * this is done after then one gets multiple PL done interrupts. |
746 | */ | 804 | */ |
747 | lcd_disable_raster(); | 805 | lcd_disable_raster(false); |
748 | 806 | ||
749 | lcdc_write(stat, LCD_MASKED_STAT_REG); | 807 | lcdc_write(stat, LCD_MASKED_STAT_REG); |
750 | 808 | ||
@@ -775,6 +833,14 @@ static irqreturn_t lcdc_irq_handler_rev02(int irq, void *arg) | |||
775 | par->vsync_flag = 1; | 833 | par->vsync_flag = 1; |
776 | wake_up_interruptible(&par->vsync_wait); | 834 | wake_up_interruptible(&par->vsync_wait); |
777 | } | 835 | } |
836 | |||
837 | /* Set only when controller is disabled and at the end of | ||
838 | * active frame | ||
839 | */ | ||
840 | if (stat & BIT(0)) { | ||
841 | frame_done_flag = 1; | ||
842 | wake_up_interruptible(&frame_done_wq); | ||
843 | } | ||
778 | } | 844 | } |
779 | 845 | ||
780 | lcdc_write(0, LCD_END_OF_INT_IND_REG); | 846 | lcdc_write(0, LCD_END_OF_INT_IND_REG); |
@@ -789,7 +855,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) | |||
789 | u32 reg_ras; | 855 | u32 reg_ras; |
790 | 856 | ||
791 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { | 857 | if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) { |
792 | lcd_disable_raster(); | 858 | lcd_disable_raster(false); |
793 | lcdc_write(stat, LCD_STAT_REG); | 859 | lcdc_write(stat, LCD_STAT_REG); |
794 | lcd_enable_raster(); | 860 | lcd_enable_raster(); |
795 | } else if (stat & LCD_PL_LOAD_DONE) { | 861 | } else if (stat & LCD_PL_LOAD_DONE) { |
@@ -799,7 +865,7 @@ static irqreturn_t lcdc_irq_handler_rev01(int irq, void *arg) | |||
799 | * interrupt via the following write to the status register. If | 865 | * interrupt via the following write to the status register. If |
800 | * this is done after then one gets multiple PL done interrupts. | 866 | * this is done after then one gets multiple PL done interrupts. |
801 | */ | 867 | */ |
802 | lcd_disable_raster(); | 868 | lcd_disable_raster(false); |
803 | 869 | ||
804 | lcdc_write(stat, LCD_STAT_REG); | 870 | lcdc_write(stat, LCD_STAT_REG); |
805 | 871 | ||
@@ -842,6 +908,9 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
842 | { | 908 | { |
843 | int err = 0; | 909 | int err = 0; |
844 | 910 | ||
911 | if (var->bits_per_pixel > 16 && lcd_revision == LCD_VERSION_1) | ||
912 | return -EINVAL; | ||
913 | |||
845 | switch (var->bits_per_pixel) { | 914 | switch (var->bits_per_pixel) { |
846 | case 1: | 915 | case 1: |
847 | case 8: | 916 | case 8: |
@@ -877,6 +946,26 @@ static int fb_check_var(struct fb_var_screeninfo *var, | |||
877 | var->transp.length = 0; | 946 | var->transp.length = 0; |
878 | var->nonstd = 0; | 947 | var->nonstd = 0; |
879 | break; | 948 | break; |
949 | case 24: | ||
950 | var->red.offset = 16; | ||
951 | var->red.length = 8; | ||
952 | var->green.offset = 8; | ||
953 | var->green.length = 8; | ||
954 | var->blue.offset = 0; | ||
955 | var->blue.length = 8; | ||
956 | var->nonstd = 0; | ||
957 | break; | ||
958 | case 32: | ||
959 | var->transp.offset = 24; | ||
960 | var->transp.length = 8; | ||
961 | var->red.offset = 16; | ||
962 | var->red.length = 8; | ||
963 | var->green.offset = 8; | ||
964 | var->green.length = 8; | ||
965 | var->blue.offset = 0; | ||
966 | var->blue.length = 8; | ||
967 | var->nonstd = 0; | ||
968 | break; | ||
880 | default: | 969 | default: |
881 | err = -EINVAL; | 970 | err = -EINVAL; |
882 | } | 971 | } |
@@ -898,9 +987,10 @@ static int lcd_da8xx_cpufreq_transition(struct notifier_block *nb, | |||
898 | if (val == CPUFREQ_POSTCHANGE) { | 987 | if (val == CPUFREQ_POSTCHANGE) { |
899 | if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) { | 988 | if (par->lcd_fck_rate != clk_get_rate(par->lcdc_clk)) { |
900 | par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); | 989 | par->lcd_fck_rate = clk_get_rate(par->lcdc_clk); |
901 | lcd_disable_raster(); | 990 | lcd_disable_raster(true); |
902 | lcd_calc_clk_divider(par); | 991 | lcd_calc_clk_divider(par); |
903 | lcd_enable_raster(); | 992 | if (par->blank == FB_BLANK_UNBLANK) |
993 | lcd_enable_raster(); | ||
904 | } | 994 | } |
905 | } | 995 | } |
906 | 996 | ||
@@ -935,7 +1025,7 @@ static int __devexit fb_remove(struct platform_device *dev) | |||
935 | if (par->panel_power_ctrl) | 1025 | if (par->panel_power_ctrl) |
936 | par->panel_power_ctrl(0); | 1026 | par->panel_power_ctrl(0); |
937 | 1027 | ||
938 | lcd_disable_raster(); | 1028 | lcd_disable_raster(true); |
939 | lcdc_write(0, LCD_RASTER_CTRL_REG); | 1029 | lcdc_write(0, LCD_RASTER_CTRL_REG); |
940 | 1030 | ||
941 | /* disable DMA */ | 1031 | /* disable DMA */ |
@@ -948,8 +1038,8 @@ static int __devexit fb_remove(struct platform_device *dev) | |||
948 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, | 1038 | dma_free_coherent(NULL, par->vram_size, par->vram_virt, |
949 | par->vram_phys); | 1039 | par->vram_phys); |
950 | free_irq(par->irq, par); | 1040 | free_irq(par->irq, par); |
951 | clk_disable(par->lcdc_clk); | 1041 | pm_runtime_put_sync(&dev->dev); |
952 | clk_put(par->lcdc_clk); | 1042 | pm_runtime_disable(&dev->dev); |
953 | framebuffer_release(info); | 1043 | framebuffer_release(info); |
954 | iounmap(da8xx_fb_reg_base); | 1044 | iounmap(da8xx_fb_reg_base); |
955 | release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); | 1045 | release_mem_region(lcdc_regs->start, resource_size(lcdc_regs)); |
@@ -1051,7 +1141,7 @@ static int cfb_blank(int blank, struct fb_info *info) | |||
1051 | if (par->panel_power_ctrl) | 1141 | if (par->panel_power_ctrl) |
1052 | par->panel_power_ctrl(0); | 1142 | par->panel_power_ctrl(0); |
1053 | 1143 | ||
1054 | lcd_disable_raster(); | 1144 | lcd_disable_raster(true); |
1055 | break; | 1145 | break; |
1056 | default: | 1146 | default: |
1057 | ret = -EINVAL; | 1147 | ret = -EINVAL; |
@@ -1183,9 +1273,9 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1183 | ret = -ENODEV; | 1273 | ret = -ENODEV; |
1184 | goto err_ioremap; | 1274 | goto err_ioremap; |
1185 | } | 1275 | } |
1186 | ret = clk_enable(fb_clk); | 1276 | |
1187 | if (ret) | 1277 | pm_runtime_enable(&device->dev); |
1188 | goto err_clk_put; | 1278 | pm_runtime_get_sync(&device->dev); |
1189 | 1279 | ||
1190 | /* Determine LCD IP Version */ | 1280 | /* Determine LCD IP Version */ |
1191 | switch (lcdc_read(LCD_PID_REG)) { | 1281 | switch (lcdc_read(LCD_PID_REG)) { |
@@ -1213,7 +1303,7 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1213 | if (i == ARRAY_SIZE(known_lcd_panels)) { | 1303 | if (i == ARRAY_SIZE(known_lcd_panels)) { |
1214 | dev_err(&device->dev, "GLCD: No valid panel found\n"); | 1304 | dev_err(&device->dev, "GLCD: No valid panel found\n"); |
1215 | ret = -ENODEV; | 1305 | ret = -ENODEV; |
1216 | goto err_clk_disable; | 1306 | goto err_pm_runtime_disable; |
1217 | } else | 1307 | } else |
1218 | dev_info(&device->dev, "GLCD: Found %s panel\n", | 1308 | dev_info(&device->dev, "GLCD: Found %s panel\n", |
1219 | fb_pdata->type); | 1309 | fb_pdata->type); |
@@ -1225,7 +1315,7 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1225 | if (!da8xx_fb_info) { | 1315 | if (!da8xx_fb_info) { |
1226 | dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); | 1316 | dev_dbg(&device->dev, "Memory allocation failed for fb_info\n"); |
1227 | ret = -ENOMEM; | 1317 | ret = -ENOMEM; |
1228 | goto err_clk_disable; | 1318 | goto err_pm_runtime_disable; |
1229 | } | 1319 | } |
1230 | 1320 | ||
1231 | par = da8xx_fb_info->par; | 1321 | par = da8xx_fb_info->par; |
@@ -1356,8 +1446,10 @@ static int __devinit fb_probe(struct platform_device *device) | |||
1356 | 1446 | ||
1357 | if (lcd_revision == LCD_VERSION_1) | 1447 | if (lcd_revision == LCD_VERSION_1) |
1358 | lcdc_irq_handler = lcdc_irq_handler_rev01; | 1448 | lcdc_irq_handler = lcdc_irq_handler_rev01; |
1359 | else | 1449 | else { |
1450 | init_waitqueue_head(&frame_done_wq); | ||
1360 | lcdc_irq_handler = lcdc_irq_handler_rev02; | 1451 | lcdc_irq_handler = lcdc_irq_handler_rev02; |
1452 | } | ||
1361 | 1453 | ||
1362 | ret = request_irq(par->irq, lcdc_irq_handler, 0, | 1454 | ret = request_irq(par->irq, lcdc_irq_handler, 0, |
1363 | DRIVER_NAME, par); | 1455 | DRIVER_NAME, par); |
@@ -1385,11 +1477,9 @@ err_release_fb_mem: | |||
1385 | err_release_fb: | 1477 | err_release_fb: |
1386 | framebuffer_release(da8xx_fb_info); | 1478 | framebuffer_release(da8xx_fb_info); |
1387 | 1479 | ||
1388 | err_clk_disable: | 1480 | err_pm_runtime_disable: |
1389 | clk_disable(fb_clk); | 1481 | pm_runtime_put_sync(&device->dev); |
1390 | 1482 | pm_runtime_disable(&device->dev); | |
1391 | err_clk_put: | ||
1392 | clk_put(fb_clk); | ||
1393 | 1483 | ||
1394 | err_ioremap: | 1484 | err_ioremap: |
1395 | iounmap(da8xx_fb_reg_base); | 1485 | iounmap(da8xx_fb_reg_base); |
@@ -1401,6 +1491,69 @@ err_request_mem: | |||
1401 | } | 1491 | } |
1402 | 1492 | ||
1403 | #ifdef CONFIG_PM | 1493 | #ifdef CONFIG_PM |
1494 | struct lcdc_context { | ||
1495 | u32 clk_enable; | ||
1496 | u32 ctrl; | ||
1497 | u32 dma_ctrl; | ||
1498 | u32 raster_timing_0; | ||
1499 | u32 raster_timing_1; | ||
1500 | u32 raster_timing_2; | ||
1501 | u32 int_enable_set; | ||
1502 | u32 dma_frm_buf_base_addr_0; | ||
1503 | u32 dma_frm_buf_ceiling_addr_0; | ||
1504 | u32 dma_frm_buf_base_addr_1; | ||
1505 | u32 dma_frm_buf_ceiling_addr_1; | ||
1506 | u32 raster_ctrl; | ||
1507 | } reg_context; | ||
1508 | |||
1509 | static void lcd_context_save(void) | ||
1510 | { | ||
1511 | if (lcd_revision == LCD_VERSION_2) { | ||
1512 | reg_context.clk_enable = lcdc_read(LCD_CLK_ENABLE_REG); | ||
1513 | reg_context.int_enable_set = lcdc_read(LCD_INT_ENABLE_SET_REG); | ||
1514 | } | ||
1515 | |||
1516 | reg_context.ctrl = lcdc_read(LCD_CTRL_REG); | ||
1517 | reg_context.dma_ctrl = lcdc_read(LCD_DMA_CTRL_REG); | ||
1518 | reg_context.raster_timing_0 = lcdc_read(LCD_RASTER_TIMING_0_REG); | ||
1519 | reg_context.raster_timing_1 = lcdc_read(LCD_RASTER_TIMING_1_REG); | ||
1520 | reg_context.raster_timing_2 = lcdc_read(LCD_RASTER_TIMING_2_REG); | ||
1521 | reg_context.dma_frm_buf_base_addr_0 = | ||
1522 | lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1523 | reg_context.dma_frm_buf_ceiling_addr_0 = | ||
1524 | lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1525 | reg_context.dma_frm_buf_base_addr_1 = | ||
1526 | lcdc_read(LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1527 | reg_context.dma_frm_buf_ceiling_addr_1 = | ||
1528 | lcdc_read(LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1529 | reg_context.raster_ctrl = lcdc_read(LCD_RASTER_CTRL_REG); | ||
1530 | return; | ||
1531 | } | ||
1532 | |||
1533 | static void lcd_context_restore(void) | ||
1534 | { | ||
1535 | if (lcd_revision == LCD_VERSION_2) { | ||
1536 | lcdc_write(reg_context.clk_enable, LCD_CLK_ENABLE_REG); | ||
1537 | lcdc_write(reg_context.int_enable_set, LCD_INT_ENABLE_SET_REG); | ||
1538 | } | ||
1539 | |||
1540 | lcdc_write(reg_context.ctrl, LCD_CTRL_REG); | ||
1541 | lcdc_write(reg_context.dma_ctrl, LCD_DMA_CTRL_REG); | ||
1542 | lcdc_write(reg_context.raster_timing_0, LCD_RASTER_TIMING_0_REG); | ||
1543 | lcdc_write(reg_context.raster_timing_1, LCD_RASTER_TIMING_1_REG); | ||
1544 | lcdc_write(reg_context.raster_timing_2, LCD_RASTER_TIMING_2_REG); | ||
1545 | lcdc_write(reg_context.dma_frm_buf_base_addr_0, | ||
1546 | LCD_DMA_FRM_BUF_BASE_ADDR_0_REG); | ||
1547 | lcdc_write(reg_context.dma_frm_buf_ceiling_addr_0, | ||
1548 | LCD_DMA_FRM_BUF_CEILING_ADDR_0_REG); | ||
1549 | lcdc_write(reg_context.dma_frm_buf_base_addr_1, | ||
1550 | LCD_DMA_FRM_BUF_BASE_ADDR_1_REG); | ||
1551 | lcdc_write(reg_context.dma_frm_buf_ceiling_addr_1, | ||
1552 | LCD_DMA_FRM_BUF_CEILING_ADDR_1_REG); | ||
1553 | lcdc_write(reg_context.raster_ctrl, LCD_RASTER_CTRL_REG); | ||
1554 | return; | ||
1555 | } | ||
1556 | |||
1404 | static int fb_suspend(struct platform_device *dev, pm_message_t state) | 1557 | static int fb_suspend(struct platform_device *dev, pm_message_t state) |
1405 | { | 1558 | { |
1406 | struct fb_info *info = platform_get_drvdata(dev); | 1559 | struct fb_info *info = platform_get_drvdata(dev); |
@@ -1411,8 +1564,9 @@ static int fb_suspend(struct platform_device *dev, pm_message_t state) | |||
1411 | par->panel_power_ctrl(0); | 1564 | par->panel_power_ctrl(0); |
1412 | 1565 | ||
1413 | fb_set_suspend(info, 1); | 1566 | fb_set_suspend(info, 1); |
1414 | lcd_disable_raster(); | 1567 | lcd_disable_raster(true); |
1415 | clk_disable(par->lcdc_clk); | 1568 | lcd_context_save(); |
1569 | pm_runtime_put_sync(&dev->dev); | ||
1416 | console_unlock(); | 1570 | console_unlock(); |
1417 | 1571 | ||
1418 | return 0; | 1572 | return 0; |
@@ -1423,11 +1577,14 @@ static int fb_resume(struct platform_device *dev) | |||
1423 | struct da8xx_fb_par *par = info->par; | 1577 | struct da8xx_fb_par *par = info->par; |
1424 | 1578 | ||
1425 | console_lock(); | 1579 | console_lock(); |
1426 | clk_enable(par->lcdc_clk); | 1580 | pm_runtime_get_sync(&dev->dev); |
1427 | lcd_enable_raster(); | 1581 | lcd_context_restore(); |
1582 | if (par->blank == FB_BLANK_UNBLANK) { | ||
1583 | lcd_enable_raster(); | ||
1428 | 1584 | ||
1429 | if (par->panel_power_ctrl) | 1585 | if (par->panel_power_ctrl) |
1430 | par->panel_power_ctrl(1); | 1586 | par->panel_power_ctrl(1); |
1587 | } | ||
1431 | 1588 | ||
1432 | fb_set_suspend(info, 0); | 1589 | fb_set_suspend(info, 0); |
1433 | console_unlock(); | 1590 | console_unlock(); |