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 /drivers/video | |
| 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>
Diffstat (limited to 'drivers/video')
| -rw-r--r-- | drivers/video/Kconfig | 5 | ||||
| -rw-r--r-- | drivers/video/pxafb.c | 307 | ||||
| -rw-r--r-- | drivers/video/pxafb.h | 12 |
3 files changed, 281 insertions, 43 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; |
