diff options
author | Eric Miao <eric.miao@marvell.com> | 2008-04-30 03:52:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-30 11:29:32 -0400 |
commit | 3c42a449107bf76c59b8e0b6a30d070e9696e49c (patch) | |
tree | f8277f579a034ebdb8d750d83179e843bff7dc0d | |
parent | 90eabbf0ec0c626cf5d186214cf8fc79150a7a29 (diff) |
pxafb: preliminary smart panel interface support
Signed-off-by: Daniel Mack <daniel@caiaq.de>
Signed-off-by: Eric Miao <eric.miao@marvell.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Cc: Russell King <rmk@arm.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | drivers/video/Kconfig | 5 | ||||
-rw-r--r-- | drivers/video/pxafb.c | 307 | ||||
-rw-r--r-- | drivers/video/pxafb.h | 12 | ||||
-rw-r--r-- | include/asm-arm/arch-pxa/pxafb.h | 26 | ||||
-rw-r--r-- | include/asm-arm/arch-pxa/regs-lcd.h | 34 |
5 files changed, 337 insertions, 47 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index a576dc261732..20a2bbd14ed7 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1774,6 +1774,11 @@ config FB_PXA | |||
1774 | 1774 | ||
1775 | If unsure, say N. | 1775 | If unsure, say N. |
1776 | 1776 | ||
1777 | config FB_PXA_SMARTPANEL | ||
1778 | bool "PXA Smartpanel LCD support" | ||
1779 | default y | ||
1780 | depends on FB_PXA | ||
1781 | |||
1777 | config FB_PXA_PARAMETERS | 1782 | config FB_PXA_PARAMETERS |
1778 | bool "PXA LCD command line parameters" | 1783 | bool "PXA LCD command line parameters" |
1779 | default n | 1784 | default n |
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c index d11ea78a06d5..a4d656497e9d 100644 --- a/drivers/video/pxafb.c +++ b/drivers/video/pxafb.c | |||
@@ -40,6 +40,8 @@ | |||
40 | #include <linux/clk.h> | 40 | #include <linux/clk.h> |
41 | #include <linux/err.h> | 41 | #include <linux/err.h> |
42 | #include <linux/completion.h> | 42 | #include <linux/completion.h> |
43 | #include <linux/kthread.h> | ||
44 | #include <linux/freezer.h> | ||
43 | 45 | ||
44 | #include <asm/hardware.h> | 46 | #include <asm/hardware.h> |
45 | #include <asm/io.h> | 47 | #include <asm/io.h> |
@@ -455,7 +457,7 @@ static int pxafb_mmap(struct fb_info *info, | |||
455 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; | 457 | unsigned long off = vma->vm_pgoff << PAGE_SHIFT; |
456 | 458 | ||
457 | if (off < info->fix.smem_len) { | 459 | if (off < info->fix.smem_len) { |
458 | vma->vm_pgoff += 1; | 460 | vma->vm_pgoff += fbi->video_offset / PAGE_SIZE; |
459 | return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, | 461 | return dma_mmap_writecombine(fbi->dev, vma, fbi->map_cpu, |
460 | fbi->map_dma, fbi->map_size); | 462 | fbi->map_dma, fbi->map_size); |
461 | } | 463 | } |
@@ -594,6 +596,183 @@ static int setup_frame_dma(struct pxafb_info *fbi, int dma, int pal, | |||
594 | return 0; | 596 | return 0; |
595 | } | 597 | } |
596 | 598 | ||
599 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
600 | static int setup_smart_dma(struct pxafb_info *fbi) | ||
601 | { | ||
602 | struct pxafb_dma_descriptor *dma_desc; | ||
603 | unsigned long dma_desc_off, cmd_buff_off; | ||
604 | |||
605 | dma_desc = &fbi->dma_buff->dma_desc[DMA_CMD]; | ||
606 | dma_desc_off = offsetof(struct pxafb_dma_buff, dma_desc[DMA_CMD]); | ||
607 | cmd_buff_off = offsetof(struct pxafb_dma_buff, cmd_buff); | ||
608 | |||
609 | dma_desc->fdadr = fbi->dma_buff_phys + dma_desc_off; | ||
610 | dma_desc->fsadr = fbi->dma_buff_phys + cmd_buff_off; | ||
611 | dma_desc->fidr = 0; | ||
612 | dma_desc->ldcmd = fbi->n_smart_cmds * sizeof(uint16_t); | ||
613 | |||
614 | fbi->fdadr[DMA_CMD] = dma_desc->fdadr; | ||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | int pxafb_smart_flush(struct fb_info *info) | ||
619 | { | ||
620 | struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb); | ||
621 | uint32_t prsr; | ||
622 | int ret = 0; | ||
623 | |||
624 | /* disable controller until all registers are set up */ | ||
625 | lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB); | ||
626 | |||
627 | /* 1. make it an even number of commands to align on 32-bit boundary | ||
628 | * 2. add the interrupt command to the end of the chain so we can | ||
629 | * keep track of the end of the transfer | ||
630 | */ | ||
631 | |||
632 | while (fbi->n_smart_cmds & 1) | ||
633 | fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_NOOP; | ||
634 | |||
635 | fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_INTERRUPT; | ||
636 | fbi->smart_cmds[fbi->n_smart_cmds++] = SMART_CMD_WAIT_FOR_VSYNC; | ||
637 | setup_smart_dma(fbi); | ||
638 | |||
639 | /* continue to execute next command */ | ||
640 | prsr = lcd_readl(fbi, PRSR) | PRSR_ST_OK | PRSR_CON_NT; | ||
641 | lcd_writel(fbi, PRSR, prsr); | ||
642 | |||
643 | /* stop the processor in case it executed "wait for sync" cmd */ | ||
644 | lcd_writel(fbi, CMDCR, 0x0001); | ||
645 | |||
646 | /* don't send interrupts for fifo underruns on channel 6 */ | ||
647 | lcd_writel(fbi, LCCR5, LCCR5_IUM(6)); | ||
648 | |||
649 | lcd_writel(fbi, LCCR1, fbi->reg_lccr1); | ||
650 | lcd_writel(fbi, LCCR2, fbi->reg_lccr2); | ||
651 | lcd_writel(fbi, LCCR3, fbi->reg_lccr3); | ||
652 | lcd_writel(fbi, FDADR0, fbi->fdadr[0]); | ||
653 | lcd_writel(fbi, FDADR6, fbi->fdadr[6]); | ||
654 | |||
655 | /* begin sending */ | ||
656 | lcd_writel(fbi, LCCR0, fbi->reg_lccr0 | LCCR0_ENB); | ||
657 | |||
658 | if (wait_for_completion_timeout(&fbi->command_done, HZ/2) == 0) { | ||
659 | pr_warning("%s: timeout waiting for command done\n", | ||
660 | __func__); | ||
661 | ret = -ETIMEDOUT; | ||
662 | } | ||
663 | |||
664 | /* quick disable */ | ||
665 | prsr = lcd_readl(fbi, PRSR) & ~(PRSR_ST_OK | PRSR_CON_NT); | ||
666 | lcd_writel(fbi, PRSR, prsr); | ||
667 | lcd_writel(fbi, LCCR0, fbi->reg_lccr0 & ~LCCR0_ENB); | ||
668 | lcd_writel(fbi, FDADR6, 0); | ||
669 | fbi->n_smart_cmds = 0; | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds) | ||
674 | { | ||
675 | int i; | ||
676 | struct pxafb_info *fbi = container_of(info, struct pxafb_info, fb); | ||
677 | |||
678 | /* leave 2 commands for INTERRUPT and WAIT_FOR_SYNC */ | ||
679 | for (i = 0; i < n_cmds; i++) { | ||
680 | if (fbi->n_smart_cmds == CMD_BUFF_SIZE - 8) | ||
681 | pxafb_smart_flush(info); | ||
682 | |||
683 | fbi->smart_cmds[fbi->n_smart_cmds++] = *cmds++; | ||
684 | } | ||
685 | |||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | static unsigned int __smart_timing(unsigned time_ns, unsigned long lcd_clk) | ||
690 | { | ||
691 | unsigned int t = (time_ns * (lcd_clk / 1000000) / 1000); | ||
692 | return (t == 0) ? 1 : t; | ||
693 | } | ||
694 | |||
695 | static void setup_smart_timing(struct pxafb_info *fbi, | ||
696 | struct fb_var_screeninfo *var) | ||
697 | { | ||
698 | struct pxafb_mach_info *inf = fbi->dev->platform_data; | ||
699 | struct pxafb_mode_info *mode = &inf->modes[0]; | ||
700 | unsigned long lclk = clk_get_rate(fbi->clk); | ||
701 | unsigned t1, t2, t3, t4; | ||
702 | |||
703 | t1 = max(mode->a0csrd_set_hld, mode->a0cswr_set_hld); | ||
704 | t2 = max(mode->rd_pulse_width, mode->wr_pulse_width); | ||
705 | t3 = mode->op_hold_time; | ||
706 | t4 = mode->cmd_inh_time; | ||
707 | |||
708 | fbi->reg_lccr1 = | ||
709 | LCCR1_DisWdth(var->xres) | | ||
710 | LCCR1_BegLnDel(__smart_timing(t1, lclk)) | | ||
711 | LCCR1_EndLnDel(__smart_timing(t2, lclk)) | | ||
712 | LCCR1_HorSnchWdth(__smart_timing(t3, lclk)); | ||
713 | |||
714 | fbi->reg_lccr2 = LCCR2_DisHght(var->yres); | ||
715 | fbi->reg_lccr3 = LCCR3_PixClkDiv(__smart_timing(t4, lclk)); | ||
716 | |||
717 | /* FIXME: make this configurable */ | ||
718 | fbi->reg_cmdcr = 1; | ||
719 | } | ||
720 | |||
721 | static int pxafb_smart_thread(void *arg) | ||
722 | { | ||
723 | struct pxafb_info *fbi = (struct pxafb_info *) arg; | ||
724 | struct pxafb_mach_info *inf = fbi->dev->platform_data; | ||
725 | |||
726 | if (!fbi || !inf->smart_update) { | ||
727 | pr_err("%s: not properly initialized, thread terminated\n", | ||
728 | __func__); | ||
729 | return -EINVAL; | ||
730 | } | ||
731 | |||
732 | pr_debug("%s(): task starting\n", __func__); | ||
733 | |||
734 | set_freezable(); | ||
735 | while (!kthread_should_stop()) { | ||
736 | |||
737 | if (try_to_freeze()) | ||
738 | continue; | ||
739 | |||
740 | if (fbi->state == C_ENABLE) { | ||
741 | inf->smart_update(&fbi->fb); | ||
742 | complete(&fbi->refresh_done); | ||
743 | } | ||
744 | |||
745 | set_current_state(TASK_INTERRUPTIBLE); | ||
746 | schedule_timeout(30 * HZ / 1000); | ||
747 | } | ||
748 | |||
749 | pr_debug("%s(): task ending\n", __func__); | ||
750 | return 0; | ||
751 | } | ||
752 | |||
753 | static int pxafb_smart_init(struct pxafb_info *fbi) | ||
754 | { | ||
755 | fbi->smart_thread = kthread_run(pxafb_smart_thread, fbi, | ||
756 | "lcd_refresh"); | ||
757 | if (IS_ERR(fbi->smart_thread)) { | ||
758 | printk(KERN_ERR "%s: unable to create kernel thread\n", | ||
759 | __func__); | ||
760 | return PTR_ERR(fbi->smart_thread); | ||
761 | } | ||
762 | return 0; | ||
763 | } | ||
764 | #else | ||
765 | int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int n_cmds) | ||
766 | { | ||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | int pxafb_smart_flush(struct fb_info *info) | ||
771 | { | ||
772 | return 0; | ||
773 | } | ||
774 | #endif /* CONFIG_FB_SMART_PANEL */ | ||
775 | |||
597 | static void setup_parallel_timing(struct pxafb_info *fbi, | 776 | static void setup_parallel_timing(struct pxafb_info *fbi, |
598 | struct fb_var_screeninfo *var) | 777 | struct fb_var_screeninfo *var) |
599 | { | 778 | { |
@@ -643,47 +822,55 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, | |||
643 | size_t nbytes; | 822 | size_t nbytes; |
644 | 823 | ||
645 | #if DEBUG_VAR | 824 | #if DEBUG_VAR |
646 | if (var->xres < 16 || var->xres > 1024) | 825 | if (!(fbi->lccr0 & LCCR0_LCDT)) { |
647 | printk(KERN_ERR "%s: invalid xres %d\n", | 826 | if (var->xres < 16 || var->xres > 1024) |
648 | fbi->fb.fix.id, var->xres); | 827 | printk(KERN_ERR "%s: invalid xres %d\n", |
649 | switch (var->bits_per_pixel) { | 828 | fbi->fb.fix.id, var->xres); |
650 | case 1: | 829 | switch (var->bits_per_pixel) { |
651 | case 2: | 830 | case 1: |
652 | case 4: | 831 | case 2: |
653 | case 8: | 832 | case 4: |
654 | case 16: | 833 | case 8: |
655 | break; | 834 | case 16: |
656 | default: | 835 | break; |
657 | printk(KERN_ERR "%s: invalid bit depth %d\n", | 836 | default: |
658 | fbi->fb.fix.id, var->bits_per_pixel); | 837 | printk(KERN_ERR "%s: invalid bit depth %d\n", |
659 | break; | 838 | fbi->fb.fix.id, var->bits_per_pixel); |
839 | break; | ||
840 | } | ||
841 | |||
842 | if (var->hsync_len < 1 || var->hsync_len > 64) | ||
843 | printk(KERN_ERR "%s: invalid hsync_len %d\n", | ||
844 | fbi->fb.fix.id, var->hsync_len); | ||
845 | if (var->left_margin < 1 || var->left_margin > 255) | ||
846 | printk(KERN_ERR "%s: invalid left_margin %d\n", | ||
847 | fbi->fb.fix.id, var->left_margin); | ||
848 | if (var->right_margin < 1 || var->right_margin > 255) | ||
849 | printk(KERN_ERR "%s: invalid right_margin %d\n", | ||
850 | fbi->fb.fix.id, var->right_margin); | ||
851 | if (var->yres < 1 || var->yres > 1024) | ||
852 | printk(KERN_ERR "%s: invalid yres %d\n", | ||
853 | fbi->fb.fix.id, var->yres); | ||
854 | if (var->vsync_len < 1 || var->vsync_len > 64) | ||
855 | printk(KERN_ERR "%s: invalid vsync_len %d\n", | ||
856 | fbi->fb.fix.id, var->vsync_len); | ||
857 | if (var->upper_margin < 0 || var->upper_margin > 255) | ||
858 | printk(KERN_ERR "%s: invalid upper_margin %d\n", | ||
859 | fbi->fb.fix.id, var->upper_margin); | ||
860 | if (var->lower_margin < 0 || var->lower_margin > 255) | ||
861 | printk(KERN_ERR "%s: invalid lower_margin %d\n", | ||
862 | fbi->fb.fix.id, var->lower_margin); | ||
660 | } | 863 | } |
661 | if (var->hsync_len < 1 || var->hsync_len > 64) | ||
662 | printk(KERN_ERR "%s: invalid hsync_len %d\n", | ||
663 | fbi->fb.fix.id, var->hsync_len); | ||
664 | if (var->left_margin < 1 || var->left_margin > 255) | ||
665 | printk(KERN_ERR "%s: invalid left_margin %d\n", | ||
666 | fbi->fb.fix.id, var->left_margin); | ||
667 | if (var->right_margin < 1 || var->right_margin > 255) | ||
668 | printk(KERN_ERR "%s: invalid right_margin %d\n", | ||
669 | fbi->fb.fix.id, var->right_margin); | ||
670 | if (var->yres < 1 || var->yres > 1024) | ||
671 | printk(KERN_ERR "%s: invalid yres %d\n", | ||
672 | fbi->fb.fix.id, var->yres); | ||
673 | if (var->vsync_len < 1 || var->vsync_len > 64) | ||
674 | printk(KERN_ERR "%s: invalid vsync_len %d\n", | ||
675 | fbi->fb.fix.id, var->vsync_len); | ||
676 | if (var->upper_margin < 0 || var->upper_margin > 255) | ||
677 | printk(KERN_ERR "%s: invalid upper_margin %d\n", | ||
678 | fbi->fb.fix.id, var->upper_margin); | ||
679 | if (var->lower_margin < 0 || var->lower_margin > 255) | ||
680 | printk(KERN_ERR "%s: invalid lower_margin %d\n", | ||
681 | fbi->fb.fix.id, var->lower_margin); | ||
682 | #endif | 864 | #endif |
683 | /* Update shadow copy atomically */ | 865 | /* Update shadow copy atomically */ |
684 | local_irq_save(flags); | 866 | local_irq_save(flags); |
685 | 867 | ||
686 | setup_parallel_timing(fbi, var); | 868 | #ifdef CONFIG_FB_PXA_SMARTPANEL |
869 | if (fbi->lccr0 & LCCR0_LCDT) | ||
870 | setup_smart_timing(fbi, var); | ||
871 | else | ||
872 | #endif | ||
873 | setup_parallel_timing(fbi, var); | ||
687 | 874 | ||
688 | fbi->reg_lccr0 = fbi->lccr0 | | 875 | fbi->reg_lccr0 = fbi->lccr0 | |
689 | (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | | 876 | (LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | |
@@ -698,7 +885,7 @@ static int pxafb_activate_var(struct fb_var_screeninfo *var, | |||
698 | setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes); | 885 | setup_frame_dma(fbi, DMA_LOWER, PAL_NONE, nbytes, nbytes); |
699 | } | 886 | } |
700 | 887 | ||
701 | if (var->bits_per_pixel >= 16) | 888 | if ((var->bits_per_pixel >= 16) || (fbi->lccr0 & LCCR0_LCDT)) |
702 | setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes); | 889 | setup_frame_dma(fbi, DMA_BASE, PAL_NONE, 0, nbytes); |
703 | else | 890 | else |
704 | setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes); | 891 | setup_frame_dma(fbi, DMA_BASE, PAL_BASE, 0, nbytes); |
@@ -801,6 +988,9 @@ static void pxafb_enable_controller(struct pxafb_info *fbi) | |||
801 | /* enable LCD controller clock */ | 988 | /* enable LCD controller clock */ |
802 | clk_enable(fbi->clk); | 989 | clk_enable(fbi->clk); |
803 | 990 | ||
991 | if (fbi->lccr0 & LCCR0_LCDT) | ||
992 | return; | ||
993 | |||
804 | /* Sequence from 11.7.10 */ | 994 | /* Sequence from 11.7.10 */ |
805 | lcd_writel(fbi, LCCR3, fbi->reg_lccr3); | 995 | lcd_writel(fbi, LCCR3, fbi->reg_lccr3); |
806 | lcd_writel(fbi, LCCR2, fbi->reg_lccr2); | 996 | lcd_writel(fbi, LCCR2, fbi->reg_lccr2); |
@@ -816,6 +1006,14 @@ static void pxafb_disable_controller(struct pxafb_info *fbi) | |||
816 | { | 1006 | { |
817 | uint32_t lccr0; | 1007 | uint32_t lccr0; |
818 | 1008 | ||
1009 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
1010 | if (fbi->lccr0 & LCCR0_LCDT) { | ||
1011 | wait_for_completion_timeout(&fbi->refresh_done, | ||
1012 | 200 * HZ / 1000); | ||
1013 | return; | ||
1014 | } | ||
1015 | #endif | ||
1016 | |||
819 | /* Clear LCD Status Register */ | 1017 | /* Clear LCD Status Register */ |
820 | lcd_writel(fbi, LCSR, 0xffffffff); | 1018 | lcd_writel(fbi, LCSR, 0xffffffff); |
821 | 1019 | ||
@@ -843,6 +1041,11 @@ static irqreturn_t pxafb_handle_irq(int irq, void *dev_id) | |||
843 | complete(&fbi->disable_done); | 1041 | complete(&fbi->disable_done); |
844 | } | 1042 | } |
845 | 1043 | ||
1044 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
1045 | if (lcsr & LCSR_CMD_INT) | ||
1046 | complete(&fbi->command_done); | ||
1047 | #endif | ||
1048 | |||
846 | lcd_writel(fbi, LCSR, lcsr); | 1049 | lcd_writel(fbi, LCSR, lcsr); |
847 | return IRQ_HANDLED; | 1050 | return IRQ_HANDLED; |
848 | } | 1051 | } |
@@ -1050,15 +1253,17 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) | |||
1050 | * We reserve one page for the palette, plus the size | 1253 | * We reserve one page for the palette, plus the size |
1051 | * of the framebuffer. | 1254 | * of the framebuffer. |
1052 | */ | 1255 | */ |
1053 | fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + PAGE_SIZE); | 1256 | fbi->video_offset = PAGE_ALIGN(sizeof(struct pxafb_dma_buff)); |
1257 | fbi->map_size = PAGE_ALIGN(fbi->fb.fix.smem_len + fbi->video_offset); | ||
1054 | fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, | 1258 | fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size, |
1055 | &fbi->map_dma, GFP_KERNEL); | 1259 | &fbi->map_dma, GFP_KERNEL); |
1056 | 1260 | ||
1057 | if (fbi->map_cpu) { | 1261 | if (fbi->map_cpu) { |
1058 | /* prevent initial garbage on screen */ | 1262 | /* prevent initial garbage on screen */ |
1059 | memset(fbi->map_cpu, 0, fbi->map_size); | 1263 | memset(fbi->map_cpu, 0, fbi->map_size); |
1060 | fbi->fb.screen_base = fbi->map_cpu + PAGE_SIZE; | 1264 | fbi->fb.screen_base = fbi->map_cpu + fbi->video_offset; |
1061 | fbi->screen_dma = fbi->map_dma + PAGE_SIZE; | 1265 | fbi->screen_dma = fbi->map_dma + fbi->video_offset; |
1266 | |||
1062 | /* | 1267 | /* |
1063 | * FIXME: this is actually the wrong thing to place in | 1268 | * FIXME: this is actually the wrong thing to place in |
1064 | * smem_start. But fbdev suffers from the problem that | 1269 | * smem_start. But fbdev suffers from the problem that |
@@ -1068,9 +1273,14 @@ static int __init pxafb_map_video_memory(struct pxafb_info *fbi) | |||
1068 | fbi->fb.fix.smem_start = fbi->screen_dma; | 1273 | fbi->fb.fix.smem_start = fbi->screen_dma; |
1069 | fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; | 1274 | fbi->palette_size = fbi->fb.var.bits_per_pixel == 8 ? 256 : 16; |
1070 | 1275 | ||
1071 | fbi->dma_buff = (void *)fbi->map_cpu; | 1276 | fbi->dma_buff = (void *) fbi->map_cpu; |
1072 | fbi->dma_buff_phys = fbi->map_dma; | 1277 | fbi->dma_buff_phys = fbi->map_dma; |
1073 | fbi->palette_cpu = (u16 *)&fbi->dma_buff->palette[0]; | 1278 | fbi->palette_cpu = (u16 *) fbi->dma_buff->palette; |
1279 | |||
1280 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
1281 | fbi->smart_cmds = (uint16_t *) fbi->dma_buff->cmd_buff; | ||
1282 | fbi->n_smart_cmds = 0; | ||
1283 | #endif | ||
1074 | } | 1284 | } |
1075 | 1285 | ||
1076 | return fbi->map_cpu ? 0 : -ENOMEM; | 1286 | return fbi->map_cpu ? 0 : -ENOMEM; |
@@ -1191,6 +1401,10 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev) | |||
1191 | INIT_WORK(&fbi->task, pxafb_task); | 1401 | INIT_WORK(&fbi->task, pxafb_task); |
1192 | init_MUTEX(&fbi->ctrlr_sem); | 1402 | init_MUTEX(&fbi->ctrlr_sem); |
1193 | init_completion(&fbi->disable_done); | 1403 | init_completion(&fbi->disable_done); |
1404 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
1405 | init_completion(&fbi->command_done); | ||
1406 | init_completion(&fbi->refresh_done); | ||
1407 | #endif | ||
1194 | 1408 | ||
1195 | return fbi; | 1409 | return fbi; |
1196 | } | 1410 | } |
@@ -1510,6 +1724,13 @@ static int __init pxafb_probe(struct platform_device *dev) | |||
1510 | goto failed_free_mem; | 1724 | goto failed_free_mem; |
1511 | } | 1725 | } |
1512 | 1726 | ||
1727 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
1728 | ret = pxafb_smart_init(fbi); | ||
1729 | if (ret) { | ||
1730 | dev_err(&dev->dev, "failed to initialize smartpanel\n"); | ||
1731 | goto failed_free_irq; | ||
1732 | } | ||
1733 | #endif | ||
1513 | /* | 1734 | /* |
1514 | * This makes sure that our colour bitfield | 1735 | * This makes sure that our colour bitfield |
1515 | * descriptors are correctly initialised. | 1736 | * descriptors are correctly initialised. |
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h index c627b83497da..8238dc826429 100644 --- a/drivers/video/pxafb.h +++ b/drivers/video/pxafb.h | |||
@@ -52,9 +52,11 @@ enum { | |||
52 | 52 | ||
53 | /* maximum palette size - 256 entries, each 4 bytes long */ | 53 | /* maximum palette size - 256 entries, each 4 bytes long */ |
54 | #define PALETTE_SIZE (256 * 4) | 54 | #define PALETTE_SIZE (256 * 4) |
55 | #define CMD_BUFF_SIZE (1024 * 50) | ||
55 | 56 | ||
56 | struct pxafb_dma_buff { | 57 | struct pxafb_dma_buff { |
57 | unsigned char palette[PAL_MAX * PALETTE_SIZE]; | 58 | unsigned char palette[PAL_MAX * PALETTE_SIZE]; |
59 | uint16_t cmd_buff[CMD_BUFF_SIZE]; | ||
58 | struct pxafb_dma_descriptor pal_desc[PAL_MAX]; | 60 | struct pxafb_dma_descriptor pal_desc[PAL_MAX]; |
59 | struct pxafb_dma_descriptor dma_desc[DMA_MAX]; | 61 | struct pxafb_dma_descriptor dma_desc[DMA_MAX]; |
60 | }; | 62 | }; |
@@ -84,6 +86,7 @@ struct pxafb_info { | |||
84 | dma_addr_t screen_dma; /* physical address of frame buffer */ | 86 | dma_addr_t screen_dma; /* physical address of frame buffer */ |
85 | u16 * palette_cpu; /* virtual address of palette memory */ | 87 | u16 * palette_cpu; /* virtual address of palette memory */ |
86 | u_int palette_size; | 88 | u_int palette_size; |
89 | ssize_t video_offset; | ||
87 | 90 | ||
88 | u_int lccr0; | 91 | u_int lccr0; |
89 | u_int lccr3; | 92 | u_int lccr3; |
@@ -97,6 +100,7 @@ struct pxafb_info { | |||
97 | u_int reg_lccr2; | 100 | u_int reg_lccr2; |
98 | u_int reg_lccr3; | 101 | u_int reg_lccr3; |
99 | u_int reg_lccr4; | 102 | u_int reg_lccr4; |
103 | u_int reg_cmdcr; | ||
100 | 104 | ||
101 | unsigned long hsync_time; | 105 | unsigned long hsync_time; |
102 | 106 | ||
@@ -108,6 +112,14 @@ struct pxafb_info { | |||
108 | 112 | ||
109 | struct completion disable_done; | 113 | struct completion disable_done; |
110 | 114 | ||
115 | #ifdef CONFIG_FB_PXA_SMARTPANEL | ||
116 | uint16_t *smart_cmds; | ||
117 | size_t n_smart_cmds; | ||
118 | struct completion command_done; | ||
119 | struct completion refresh_done; | ||
120 | struct task_struct *smart_thread; | ||
121 | #endif | ||
122 | |||
111 | #ifdef CONFIG_CPU_FREQ | 123 | #ifdef CONFIG_CPU_FREQ |
112 | struct notifier_block freq_transition; | 124 | struct notifier_block freq_transition; |
113 | struct notifier_block freq_policy; | 125 | struct notifier_block freq_policy; |
diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h index 41a6c2297f9f..bbd22396841a 100644 --- a/include/asm-arm/arch-pxa/pxafb.h +++ b/include/asm-arm/arch-pxa/pxafb.h | |||
@@ -48,6 +48,7 @@ | |||
48 | #define LCD_COLOR_DSTN_16BPP ((16 << 4) | LCD_TYPE_COLOR_DSTN) | 48 | #define LCD_COLOR_DSTN_16BPP ((16 << 4) | LCD_TYPE_COLOR_DSTN) |
49 | #define LCD_COLOR_TFT_16BPP ((16 << 4) | LCD_TYPE_COLOR_TFT) | 49 | #define LCD_COLOR_TFT_16BPP ((16 << 4) | LCD_TYPE_COLOR_TFT) |
50 | #define LCD_COLOR_TFT_18BPP ((18 << 4) | LCD_TYPE_COLOR_TFT) | 50 | #define LCD_COLOR_TFT_18BPP ((18 << 4) | LCD_TYPE_COLOR_TFT) |
51 | #define LCD_SMART_PANEL_8BPP ((8 << 4) | LCD_TYPE_SMART_PANEL) | ||
51 | #define LCD_SMART_PANEL_16BPP ((16 << 4) | LCD_TYPE_SMART_PANEL) | 52 | #define LCD_SMART_PANEL_16BPP ((16 << 4) | LCD_TYPE_SMART_PANEL) |
52 | #define LCD_SMART_PANEL_18BPP ((18 << 4) | LCD_TYPE_SMART_PANEL) | 53 | #define LCD_SMART_PANEL_18BPP ((18 << 4) | LCD_TYPE_SMART_PANEL) |
53 | 54 | ||
@@ -69,6 +70,10 @@ struct pxafb_mode_info { | |||
69 | u_short yres; | 70 | u_short yres; |
70 | 71 | ||
71 | u_char bpp; | 72 | u_char bpp; |
73 | u_int cmap_greyscale:1, | ||
74 | unused:31; | ||
75 | |||
76 | /* Parallel Mode Timing */ | ||
72 | u_char hsync_len; | 77 | u_char hsync_len; |
73 | u_char left_margin; | 78 | u_char left_margin; |
74 | u_char right_margin; | 79 | u_char right_margin; |
@@ -78,8 +83,20 @@ struct pxafb_mode_info { | |||
78 | u_char lower_margin; | 83 | u_char lower_margin; |
79 | u_char sync; | 84 | u_char sync; |
80 | 85 | ||
81 | u_int cmap_greyscale:1, | 86 | /* Smart Panel Mode Timing - see PXA27x DM 7.4.15.0.3 for details |
82 | unused:31; | 87 | * Note: |
88 | * 1. all parameters in nanosecond (ns) | ||
89 | * 2. a0cs{rd,wr}_set_hld are controlled by the same register bits | ||
90 | * in pxa27x and pxa3xx, initialize them to the same value or | ||
91 | * the larger one will be used | ||
92 | * 3. same to {rd,wr}_pulse_width | ||
93 | */ | ||
94 | unsigned a0csrd_set_hld; /* A0 and CS Setup/Hold Time before/after L_FCLK_RD */ | ||
95 | unsigned a0cswr_set_hld; /* A0 and CS Setup/Hold Time before/after L_PCLK_WR */ | ||
96 | unsigned wr_pulse_width; /* L_PCLK_WR pulse width */ | ||
97 | unsigned rd_pulse_width; /* L_FCLK_RD pulse width */ | ||
98 | unsigned cmd_inh_time; /* Command Inhibit time between two writes */ | ||
99 | unsigned op_hold_time; /* Output Hold time from L_FCLK_RD negation */ | ||
83 | }; | 100 | }; |
84 | 101 | ||
85 | struct pxafb_mach_info { | 102 | struct pxafb_mach_info { |
@@ -123,8 +140,11 @@ struct pxafb_mach_info { | |||
123 | u_int lccr4; | 140 | u_int lccr4; |
124 | void (*pxafb_backlight_power)(int); | 141 | void (*pxafb_backlight_power)(int); |
125 | void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *); | 142 | void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *); |
126 | 143 | void (*smart_update)(struct fb_info *); | |
127 | }; | 144 | }; |
128 | void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info); | 145 | void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info); |
129 | void set_pxa_fb_parent(struct device *parent_dev); | 146 | void set_pxa_fb_parent(struct device *parent_dev); |
130 | unsigned long pxafb_get_hsync_time(struct device *dev); | 147 | unsigned long pxafb_get_hsync_time(struct device *dev); |
148 | |||
149 | extern int pxafb_smart_queue(struct fb_info *info, uint16_t *cmds, int); | ||
150 | extern int pxafb_smart_flush(struct fb_info *info); | ||
diff --git a/include/asm-arm/arch-pxa/regs-lcd.h b/include/asm-arm/arch-pxa/regs-lcd.h index f84dd47be28a..f762493f5141 100644 --- a/include/asm-arm/arch-pxa/regs-lcd.h +++ b/include/asm-arm/arch-pxa/regs-lcd.h | |||
@@ -7,7 +7,8 @@ | |||
7 | #define LCCR1 (0x004) /* LCD Controller Control Register 1 */ | 7 | #define LCCR1 (0x004) /* LCD Controller Control Register 1 */ |
8 | #define LCCR2 (0x008) /* LCD Controller Control Register 2 */ | 8 | #define LCCR2 (0x008) /* LCD Controller Control Register 2 */ |
9 | #define LCCR3 (0x00C) /* LCD Controller Control Register 3 */ | 9 | #define LCCR3 (0x00C) /* LCD Controller Control Register 3 */ |
10 | #define LCCR4 (0x010) /* LCD Controller Control Register 3 */ | 10 | #define LCCR4 (0x010) /* LCD Controller Control Register 4 */ |
11 | #define LCCR5 (0x014) /* LCD Controller Control Register 5 */ | ||
11 | #define DFBR0 (0x020) /* DMA Channel 0 Frame Branch Register */ | 12 | #define DFBR0 (0x020) /* DMA Channel 0 Frame Branch Register */ |
12 | #define DFBR1 (0x024) /* DMA Channel 1 Frame Branch Register */ | 13 | #define DFBR1 (0x024) /* DMA Channel 1 Frame Branch Register */ |
13 | #define LCSR (0x038) /* LCD Controller Status Register */ | 14 | #define LCSR (0x038) /* LCD Controller Status Register */ |
@@ -15,6 +16,9 @@ | |||
15 | #define TMEDRGBR (0x040) /* TMED RGB Seed Register */ | 16 | #define TMEDRGBR (0x040) /* TMED RGB Seed Register */ |
16 | #define TMEDCR (0x044) /* TMED Control Register */ | 17 | #define TMEDCR (0x044) /* TMED Control Register */ |
17 | 18 | ||
19 | #define CMDCR (0x100) /* Command Control Register */ | ||
20 | #define PRSR (0x104) /* Panel Read Status Register */ | ||
21 | |||
18 | #define LCCR3_1BPP (0 << 24) | 22 | #define LCCR3_1BPP (0 << 24) |
19 | #define LCCR3_2BPP (1 << 24) | 23 | #define LCCR3_2BPP (1 << 24) |
20 | #define LCCR3_4BPP (2 << 24) | 24 | #define LCCR3_4BPP (2 << 24) |
@@ -39,6 +43,9 @@ | |||
39 | #define FSADR1 (0x214) /* DMA Channel 1 Frame Source Address Register */ | 43 | #define FSADR1 (0x214) /* DMA Channel 1 Frame Source Address Register */ |
40 | #define FIDR1 (0x218) /* DMA Channel 1 Frame ID Register */ | 44 | #define FIDR1 (0x218) /* DMA Channel 1 Frame ID Register */ |
41 | #define LDCMD1 (0x21C) /* DMA Channel 1 Command Register */ | 45 | #define LDCMD1 (0x21C) /* DMA Channel 1 Command Register */ |
46 | #define FDADR6 (0x260) /* DMA Channel 6 Frame Descriptor Address Register */ | ||
47 | #define FSADR6 (0x264) /* DMA Channel 6 Frame Source Address Register */ | ||
48 | #define FIDR6 (0x268) /* DMA Channel 6 Frame ID Register */ | ||
42 | 49 | ||
43 | #define LCCR0_ENB (1 << 0) /* LCD Controller enable */ | 50 | #define LCCR0_ENB (1 << 0) /* LCD Controller enable */ |
44 | #define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */ | 51 | #define LCCR0_CMS (1 << 1) /* Color/Monochrome Display Select */ |
@@ -122,6 +129,11 @@ | |||
122 | #define LCCR3_VrtSnchH (LCCR3_VSP*0) /* VSP Active High */ | 129 | #define LCCR3_VrtSnchH (LCCR3_VSP*0) /* VSP Active High */ |
123 | #define LCCR3_VrtSnchL (LCCR3_VSP*1) /* VSP Active Low */ | 130 | #define LCCR3_VrtSnchL (LCCR3_VSP*1) /* VSP Active Low */ |
124 | 131 | ||
132 | #define LCCR5_IUM(x) (1 << ((x) + 23)) /* input underrun mask */ | ||
133 | #define LCCR5_BSM(x) (1 << ((x) + 15)) /* branch mask */ | ||
134 | #define LCCR5_EOFM(x) (1 << ((x) + 7)) /* end of frame mask */ | ||
135 | #define LCCR5_SOFM(x) (1 << ((x) + 0)) /* start of frame mask */ | ||
136 | |||
125 | #define LCSR_LDD (1 << 0) /* LCD Disable Done */ | 137 | #define LCSR_LDD (1 << 0) /* LCD Disable Done */ |
126 | #define LCSR_SOF (1 << 1) /* Start of frame */ | 138 | #define LCSR_SOF (1 << 1) /* Start of frame */ |
127 | #define LCSR_BER (1 << 2) /* Bus error */ | 139 | #define LCSR_BER (1 << 2) /* Bus error */ |
@@ -133,7 +145,27 @@ | |||
133 | #define LCSR_EOF (1 << 8) /* end of frame */ | 145 | #define LCSR_EOF (1 << 8) /* end of frame */ |
134 | #define LCSR_BS (1 << 9) /* branch status */ | 146 | #define LCSR_BS (1 << 9) /* branch status */ |
135 | #define LCSR_SINT (1 << 10) /* subsequent interrupt */ | 147 | #define LCSR_SINT (1 << 10) /* subsequent interrupt */ |
148 | #define LCSR_RD_ST (1 << 11) /* read status */ | ||
149 | #define LCSR_CMD_INT (1 << 12) /* command interrupt */ | ||
136 | 150 | ||
137 | #define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ | 151 | #define LDCMD_PAL (1 << 26) /* instructs DMA to load palette buffer */ |
138 | 152 | ||
153 | /* smartpanel related */ | ||
154 | #define PRSR_DATA(x) ((x) & 0xff) /* Panel Data */ | ||
155 | #define PRSR_A0 (1 << 8) /* Read Data Source */ | ||
156 | #define PRSR_ST_OK (1 << 9) /* Status OK */ | ||
157 | #define PRSR_CON_NT (1 << 10) /* Continue to Next Command */ | ||
158 | |||
159 | #define SMART_CMD_A0 (0x1 << 8) | ||
160 | #define SMART_CMD_READ_STATUS_REG (0x0 << 9) | ||
161 | #define SMART_CMD_READ_FRAME_BUFFER ((0x0 << 9) | SMART_CMD_A0) | ||
162 | #define SMART_CMD_WRITE_COMMAND (0x1 << 9) | ||
163 | #define SMART_CMD_WRITE_DATA ((0x1 << 9) | SMART_CMD_A0) | ||
164 | #define SMART_CMD_WRITE_FRAME ((0x2 << 9) | SMART_CMD_A0) | ||
165 | #define SMART_CMD_WAIT_FOR_VSYNC (0x3 << 9) | ||
166 | #define SMART_CMD_NOOP (0x4 << 9) | ||
167 | #define SMART_CMD_INTERRUPT (0x5 << 9) | ||
168 | |||
169 | #define SMART_CMD(x) (SMART_CMD_WRITE_COMMAND | ((x) & 0xff)) | ||
170 | #define SMART_DAT(x) (SMART_CMD_WRITE_DATA | ((x) & 0xff)) | ||
139 | #endif /* __ASM_ARCH_REGS_LCD_H */ | 171 | #endif /* __ASM_ARCH_REGS_LCD_H */ |