diff options
-rw-r--r-- | arch/arm/mach-shmobile/board-ap4evb.c | 326 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/clock-sh7367.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/clock-sh7372.c | 78 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/clock-sh7377.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/include/mach/sh7372.h | 10 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/intc-sh7372.c | 28 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/pfc-sh7372.c | 8 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7367.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7372.c | 94 | ||||
-rw-r--r-- | arch/arm/mach-shmobile/setup-sh7377.c | 1 | ||||
-rw-r--r-- | arch/sh/boards/mach-ap325rxa/setup.c | 29 | ||||
-rw-r--r-- | arch/sh/boards/mach-ecovec24/setup.c | 60 | ||||
-rw-r--r-- | arch/sh/boards/mach-kfr2r09/setup.c | 29 | ||||
-rw-r--r-- | arch/sh/boards/mach-migor/setup.c | 58 | ||||
-rw-r--r-- | arch/sh/boards/mach-se/7724/setup.c | 54 | ||||
-rw-r--r-- | drivers/video/sh_mipi_dsi.c | 32 | ||||
-rw-r--r-- | drivers/video/sh_mobile_hdmi.c | 629 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.c | 348 | ||||
-rw-r--r-- | drivers/video/sh_mobile_lcdcfb.h | 41 | ||||
-rw-r--r-- | include/video/sh_mobile_lcdc.h | 5 |
20 files changed, 1222 insertions, 613 deletions
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 14923989ea05..f5d55efda386 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/mtd/mtd.h> | 30 | #include <linux/mtd/mtd.h> |
31 | #include <linux/mtd/partitions.h> | 31 | #include <linux/mtd/partitions.h> |
32 | #include <linux/mtd/physmap.h> | 32 | #include <linux/mtd/physmap.h> |
33 | #include <linux/mmc/host.h> | ||
34 | #include <linux/mmc/sh_mmcif.h> | 33 | #include <linux/mmc/sh_mmcif.h> |
35 | #include <linux/i2c.h> | 34 | #include <linux/i2c.h> |
36 | #include <linux/i2c/tsc2007.h> | 35 | #include <linux/i2c/tsc2007.h> |
@@ -44,6 +43,10 @@ | |||
44 | #include <linux/input/sh_keysc.h> | 43 | #include <linux/input/sh_keysc.h> |
45 | #include <linux/usb/r8a66597.h> | 44 | #include <linux/usb/r8a66597.h> |
46 | 45 | ||
46 | #include <media/sh_mobile_ceu.h> | ||
47 | #include <media/sh_mobile_csi2.h> | ||
48 | #include <media/soc_camera.h> | ||
49 | |||
47 | #include <sound/sh_fsi.h> | 50 | #include <sound/sh_fsi.h> |
48 | 51 | ||
49 | #include <video/sh_mobile_hdmi.h> | 52 | #include <video/sh_mobile_hdmi.h> |
@@ -238,7 +241,7 @@ static struct platform_device smc911x_device = { | |||
238 | /* SH_MMCIF */ | 241 | /* SH_MMCIF */ |
239 | static struct resource sh_mmcif_resources[] = { | 242 | static struct resource sh_mmcif_resources[] = { |
240 | [0] = { | 243 | [0] = { |
241 | .name = "SH_MMCIF", | 244 | .name = "MMCIF", |
242 | .start = 0xE6BD0000, | 245 | .start = 0xE6BD0000, |
243 | .end = 0xE6BD00FF, | 246 | .end = 0xE6BD00FF, |
244 | .flags = IORESOURCE_MEM, | 247 | .flags = IORESOURCE_MEM, |
@@ -375,10 +378,40 @@ static struct platform_device usb1_host_device = { | |||
375 | .resource = usb1_host_resources, | 378 | .resource = usb1_host_resources, |
376 | }; | 379 | }; |
377 | 380 | ||
381 | const static struct fb_videomode ap4evb_lcdc_modes[] = { | ||
382 | { | ||
383 | #ifdef CONFIG_AP4EVB_QHD | ||
384 | .name = "R63302(QHD)", | ||
385 | .xres = 544, | ||
386 | .yres = 961, | ||
387 | .left_margin = 72, | ||
388 | .right_margin = 600, | ||
389 | .hsync_len = 16, | ||
390 | .upper_margin = 8, | ||
391 | .lower_margin = 8, | ||
392 | .vsync_len = 2, | ||
393 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, | ||
394 | #else | ||
395 | .name = "WVGA Panel", | ||
396 | .xres = 800, | ||
397 | .yres = 480, | ||
398 | .left_margin = 220, | ||
399 | .right_margin = 110, | ||
400 | .hsync_len = 70, | ||
401 | .upper_margin = 20, | ||
402 | .lower_margin = 5, | ||
403 | .vsync_len = 5, | ||
404 | .sync = 0, | ||
405 | #endif | ||
406 | }, | ||
407 | }; | ||
408 | |||
378 | static struct sh_mobile_lcdc_info lcdc_info = { | 409 | static struct sh_mobile_lcdc_info lcdc_info = { |
379 | .ch[0] = { | 410 | .ch[0] = { |
380 | .chan = LCDC_CHAN_MAINLCD, | 411 | .chan = LCDC_CHAN_MAINLCD, |
381 | .bpp = 16, | 412 | .bpp = 16, |
413 | .lcd_cfg = ap4evb_lcdc_modes, | ||
414 | .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), | ||
382 | } | 415 | } |
383 | }; | 416 | }; |
384 | 417 | ||
@@ -517,27 +550,6 @@ static struct platform_device *qhd_devices[] __initdata = { | |||
517 | 550 | ||
518 | /* FSI */ | 551 | /* FSI */ |
519 | #define IRQ_FSI evt2irq(0x1840) | 552 | #define IRQ_FSI evt2irq(0x1840) |
520 | #define FSIACKCR 0xE6150018 | ||
521 | static void fsiackcr_init(struct clk *clk) | ||
522 | { | ||
523 | u32 status = __raw_readl(clk->enable_reg); | ||
524 | |||
525 | /* use external clock */ | ||
526 | status &= ~0x000000ff; | ||
527 | status |= 0x00000080; | ||
528 | __raw_writel(status, clk->enable_reg); | ||
529 | } | ||
530 | |||
531 | static struct clk_ops fsiackcr_clk_ops = { | ||
532 | .init = fsiackcr_init, | ||
533 | }; | ||
534 | |||
535 | static struct clk fsiackcr_clk = { | ||
536 | .ops = &fsiackcr_clk_ops, | ||
537 | .enable_reg = (void __iomem *)FSIACKCR, | ||
538 | .rate = 0, /* unknown */ | ||
539 | }; | ||
540 | |||
541 | static struct sh_fsi_platform_info fsi_info = { | 553 | static struct sh_fsi_platform_info fsi_info = { |
542 | .porta_flags = SH_FSI_BRS_INV | | 554 | .porta_flags = SH_FSI_BRS_INV | |
543 | SH_FSI_OUT_SLAVE_MODE | | 555 | SH_FSI_OUT_SLAVE_MODE | |
@@ -577,26 +589,6 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { | |||
577 | .interface_type = RGB24, | 589 | .interface_type = RGB24, |
578 | .clock_divider = 1, | 590 | .clock_divider = 1, |
579 | .flags = LCDC_FLAGS_DWPOL, | 591 | .flags = LCDC_FLAGS_DWPOL, |
580 | .lcd_cfg = { | ||
581 | .name = "HDMI", | ||
582 | /* So far only 720p is supported */ | ||
583 | .xres = 1280, | ||
584 | .yres = 720, | ||
585 | /* | ||
586 | * If left and right margins are not multiples of 8, | ||
587 | * LDHAJR will be adjusted accordingly by the LCDC | ||
588 | * driver. Until we start using EDID, these values | ||
589 | * might have to be adjusted for different monitors. | ||
590 | */ | ||
591 | .left_margin = 200, | ||
592 | .right_margin = 88, | ||
593 | .hsync_len = 48, | ||
594 | .upper_margin = 20, | ||
595 | .lower_margin = 5, | ||
596 | .vsync_len = 5, | ||
597 | .pixclock = 13468, | ||
598 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, | ||
599 | }, | ||
600 | } | 592 | } |
601 | }; | 593 | }; |
602 | 594 | ||
@@ -608,7 +600,7 @@ static struct resource lcdc1_resources[] = { | |||
608 | .flags = IORESOURCE_MEM, | 600 | .flags = IORESOURCE_MEM, |
609 | }, | 601 | }, |
610 | [1] = { | 602 | [1] = { |
611 | .start = intcs_evt2irq(0x17a0), | 603 | .start = intcs_evt2irq(0x1780), |
612 | .flags = IORESOURCE_IRQ, | 604 | .flags = IORESOURCE_IRQ, |
613 | }, | 605 | }, |
614 | }; | 606 | }; |
@@ -689,6 +681,95 @@ static struct platform_device leds_device = { | |||
689 | }, | 681 | }, |
690 | }; | 682 | }; |
691 | 683 | ||
684 | static struct i2c_board_info imx074_info = { | ||
685 | I2C_BOARD_INFO("imx074", 0x1a), | ||
686 | }; | ||
687 | |||
688 | struct soc_camera_link imx074_link = { | ||
689 | .bus_id = 0, | ||
690 | .board_info = &imx074_info, | ||
691 | .i2c_adapter_id = 0, | ||
692 | .module_name = "imx074", | ||
693 | }; | ||
694 | |||
695 | static struct platform_device ap4evb_camera = { | ||
696 | .name = "soc-camera-pdrv", | ||
697 | .id = 0, | ||
698 | .dev = { | ||
699 | .platform_data = &imx074_link, | ||
700 | }, | ||
701 | }; | ||
702 | |||
703 | static struct sh_csi2_client_config csi2_clients[] = { | ||
704 | { | ||
705 | .phy = SH_CSI2_PHY_MAIN, | ||
706 | .lanes = 3, | ||
707 | .channel = 0, | ||
708 | .pdev = &ap4evb_camera, | ||
709 | }, | ||
710 | }; | ||
711 | |||
712 | static struct sh_csi2_pdata csi2_info = { | ||
713 | .type = SH_CSI2C, | ||
714 | .clients = csi2_clients, | ||
715 | .num_clients = ARRAY_SIZE(csi2_clients), | ||
716 | .flags = SH_CSI2_ECC | SH_CSI2_CRC, | ||
717 | }; | ||
718 | |||
719 | static struct resource csi2_resources[] = { | ||
720 | [0] = { | ||
721 | .name = "CSI2", | ||
722 | .start = 0xffc90000, | ||
723 | .end = 0xffc90fff, | ||
724 | .flags = IORESOURCE_MEM, | ||
725 | }, | ||
726 | [1] = { | ||
727 | .start = intcs_evt2irq(0x17a0), | ||
728 | .flags = IORESOURCE_IRQ, | ||
729 | }, | ||
730 | }; | ||
731 | |||
732 | static struct platform_device csi2_device = { | ||
733 | .name = "sh-mobile-csi2", | ||
734 | .id = 0, | ||
735 | .num_resources = ARRAY_SIZE(csi2_resources), | ||
736 | .resource = csi2_resources, | ||
737 | .dev = { | ||
738 | .platform_data = &csi2_info, | ||
739 | }, | ||
740 | }; | ||
741 | |||
742 | static struct sh_mobile_ceu_info sh_mobile_ceu_info = { | ||
743 | .flags = SH_CEU_FLAG_USE_8BIT_BUS, | ||
744 | .csi2_dev = &csi2_device.dev, | ||
745 | }; | ||
746 | |||
747 | static struct resource ceu_resources[] = { | ||
748 | [0] = { | ||
749 | .name = "CEU", | ||
750 | .start = 0xfe910000, | ||
751 | .end = 0xfe91009f, | ||
752 | .flags = IORESOURCE_MEM, | ||
753 | }, | ||
754 | [1] = { | ||
755 | .start = intcs_evt2irq(0x880), | ||
756 | .flags = IORESOURCE_IRQ, | ||
757 | }, | ||
758 | [2] = { | ||
759 | /* place holder for contiguous memory */ | ||
760 | }, | ||
761 | }; | ||
762 | |||
763 | static struct platform_device ceu_device = { | ||
764 | .name = "sh_mobile_ceu", | ||
765 | .id = 0, /* "ceu0" clock */ | ||
766 | .num_resources = ARRAY_SIZE(ceu_resources), | ||
767 | .resource = ceu_resources, | ||
768 | .dev = { | ||
769 | .platform_data = &sh_mobile_ceu_info, | ||
770 | }, | ||
771 | }; | ||
772 | |||
692 | static struct platform_device *ap4evb_devices[] __initdata = { | 773 | static struct platform_device *ap4evb_devices[] __initdata = { |
693 | &leds_device, | 774 | &leds_device, |
694 | &nor_flash_device, | 775 | &nor_flash_device, |
@@ -701,6 +782,9 @@ static struct platform_device *ap4evb_devices[] __initdata = { | |||
701 | &lcdc1_device, | 782 | &lcdc1_device, |
702 | &lcdc_device, | 783 | &lcdc_device, |
703 | &hdmi_device, | 784 | &hdmi_device, |
785 | &csi2_device, | ||
786 | &ceu_device, | ||
787 | &ap4evb_camera, | ||
704 | }; | 788 | }; |
705 | 789 | ||
706 | static int __init hdmi_init_pm_clock(void) | 790 | static int __init hdmi_init_pm_clock(void) |
@@ -715,22 +799,22 @@ static int __init hdmi_init_pm_clock(void) | |||
715 | goto out; | 799 | goto out; |
716 | } | 800 | } |
717 | 801 | ||
718 | ret = clk_set_parent(&pllc2_clk, &dv_clki_div2_clk); | 802 | ret = clk_set_parent(&sh7372_pllc2_clk, &sh7372_dv_clki_div2_clk); |
719 | if (ret < 0) { | 803 | if (ret < 0) { |
720 | pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, pllc2_clk.usecount); | 804 | pr_err("Cannot set PLLC2 parent: %d, %d users\n", ret, sh7372_pllc2_clk.usecount); |
721 | goto out; | 805 | goto out; |
722 | } | 806 | } |
723 | 807 | ||
724 | pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&pllc2_clk)); | 808 | pr_debug("PLLC2 initial frequency %lu\n", clk_get_rate(&sh7372_pllc2_clk)); |
725 | 809 | ||
726 | rate = clk_round_rate(&pllc2_clk, 594000000); | 810 | rate = clk_round_rate(&sh7372_pllc2_clk, 594000000); |
727 | if (rate < 0) { | 811 | if (rate < 0) { |
728 | pr_err("Cannot get suitable rate: %ld\n", rate); | 812 | pr_err("Cannot get suitable rate: %ld\n", rate); |
729 | ret = rate; | 813 | ret = rate; |
730 | goto out; | 814 | goto out; |
731 | } | 815 | } |
732 | 816 | ||
733 | ret = clk_set_rate(&pllc2_clk, rate); | 817 | ret = clk_set_rate(&sh7372_pllc2_clk, rate); |
734 | if (ret < 0) { | 818 | if (ret < 0) { |
735 | pr_err("Cannot set rate %ld: %d\n", rate, ret); | 819 | pr_err("Cannot set rate %ld: %d\n", rate, ret); |
736 | goto out; | 820 | goto out; |
@@ -738,7 +822,7 @@ static int __init hdmi_init_pm_clock(void) | |||
738 | 822 | ||
739 | pr_debug("PLLC2 set frequency %lu\n", rate); | 823 | pr_debug("PLLC2 set frequency %lu\n", rate); |
740 | 824 | ||
741 | ret = clk_set_parent(hdmi_ick, &pllc2_clk); | 825 | ret = clk_set_parent(hdmi_ick, &sh7372_pllc2_clk); |
742 | if (ret < 0) { | 826 | if (ret < 0) { |
743 | pr_err("Cannot set HDMI parent: %d\n", ret); | 827 | pr_err("Cannot set HDMI parent: %d\n", ret); |
744 | goto out; | 828 | goto out; |
@@ -752,11 +836,51 @@ out: | |||
752 | 836 | ||
753 | device_initcall(hdmi_init_pm_clock); | 837 | device_initcall(hdmi_init_pm_clock); |
754 | 838 | ||
839 | #define FSIACK_DUMMY_RATE 48000 | ||
840 | static int __init fsi_init_pm_clock(void) | ||
841 | { | ||
842 | struct clk *fsia_ick; | ||
843 | int ret; | ||
844 | |||
845 | /* | ||
846 | * FSIACK is connected to AK4642, | ||
847 | * and the rate is depend on playing sound rate. | ||
848 | * So, set dummy rate (= 48k) here | ||
849 | */ | ||
850 | ret = clk_set_rate(&sh7372_fsiack_clk, FSIACK_DUMMY_RATE); | ||
851 | if (ret < 0) { | ||
852 | pr_err("Cannot set FSIACK dummy rate: %d\n", ret); | ||
853 | return ret; | ||
854 | } | ||
855 | |||
856 | fsia_ick = clk_get(&fsi_device.dev, "icka"); | ||
857 | if (IS_ERR(fsia_ick)) { | ||
858 | ret = PTR_ERR(fsia_ick); | ||
859 | pr_err("Cannot get FSI ICK: %d\n", ret); | ||
860 | return ret; | ||
861 | } | ||
862 | |||
863 | ret = clk_set_parent(fsia_ick, &sh7372_fsiack_clk); | ||
864 | if (ret < 0) { | ||
865 | pr_err("Cannot set FSI-A parent: %d\n", ret); | ||
866 | goto out; | ||
867 | } | ||
868 | |||
869 | ret = clk_set_rate(fsia_ick, FSIACK_DUMMY_RATE); | ||
870 | if (ret < 0) | ||
871 | pr_err("Cannot set FSI-A rate: %d\n", ret); | ||
872 | |||
873 | out: | ||
874 | clk_put(fsia_ick); | ||
875 | |||
876 | return ret; | ||
877 | } | ||
878 | device_initcall(fsi_init_pm_clock); | ||
879 | |||
755 | /* | 880 | /* |
756 | * FIXME !! | 881 | * FIXME !! |
757 | * | 882 | * |
758 | * gpio_no_direction | 883 | * gpio_no_direction |
759 | * gpio_pull_up | ||
760 | * are quick_hack. | 884 | * are quick_hack. |
761 | * | 885 | * |
762 | * current gpio frame work doesn't have | 886 | * current gpio frame work doesn't have |
@@ -768,49 +892,37 @@ static void __init gpio_no_direction(u32 addr) | |||
768 | __raw_writeb(0x00, addr); | 892 | __raw_writeb(0x00, addr); |
769 | } | 893 | } |
770 | 894 | ||
771 | static void __init gpio_pull_up(u32 addr) | ||
772 | { | ||
773 | u8 data = __raw_readb(addr); | ||
774 | |||
775 | data &= 0x0F; | ||
776 | data |= 0xC0; | ||
777 | __raw_writeb(data, addr); | ||
778 | } | ||
779 | |||
780 | /* TouchScreen */ | 895 | /* TouchScreen */ |
896 | #ifdef CONFIG_AP4EVB_QHD | ||
897 | # define GPIO_TSC_IRQ GPIO_FN_IRQ28_123 | ||
898 | # define GPIO_TSC_PORT GPIO_PORT123 | ||
899 | #else /* WVGA */ | ||
900 | # define GPIO_TSC_IRQ GPIO_FN_IRQ7_40 | ||
901 | # define GPIO_TSC_PORT GPIO_PORT40 | ||
902 | #endif | ||
903 | |||
781 | #define IRQ28 evt2irq(0x3380) /* IRQ28A */ | 904 | #define IRQ28 evt2irq(0x3380) /* IRQ28A */ |
782 | #define IRQ7 evt2irq(0x02e0) /* IRQ7A */ | 905 | #define IRQ7 evt2irq(0x02e0) /* IRQ7A */ |
783 | static int ts_get_pendown_state(void) | 906 | static int ts_get_pendown_state(void) |
784 | { | 907 | { |
785 | int val1, val2; | 908 | int val; |
786 | 909 | ||
787 | gpio_free(GPIO_FN_IRQ28_123); | 910 | gpio_free(GPIO_TSC_IRQ); |
788 | gpio_free(GPIO_FN_IRQ7_40); | ||
789 | 911 | ||
790 | gpio_request(GPIO_PORT123, NULL); | 912 | gpio_request(GPIO_TSC_PORT, NULL); |
791 | gpio_request(GPIO_PORT40, NULL); | ||
792 | 913 | ||
793 | gpio_direction_input(GPIO_PORT123); | 914 | gpio_direction_input(GPIO_TSC_PORT); |
794 | gpio_direction_input(GPIO_PORT40); | ||
795 | 915 | ||
796 | val1 = gpio_get_value(GPIO_PORT123); | 916 | val = gpio_get_value(GPIO_TSC_PORT); |
797 | val2 = gpio_get_value(GPIO_PORT40); | ||
798 | 917 | ||
799 | gpio_request(GPIO_FN_IRQ28_123, NULL); /* for QHD */ | 918 | gpio_request(GPIO_TSC_IRQ, NULL); |
800 | gpio_request(GPIO_FN_IRQ7_40, NULL); /* for WVGA */ | ||
801 | 919 | ||
802 | return val1 ^ val2; | 920 | return !val; |
803 | } | 921 | } |
804 | 922 | ||
805 | #define PORT40CR 0xE6051028 | ||
806 | #define PORT123CR 0xE605007B | ||
807 | static int ts_init(void) | 923 | static int ts_init(void) |
808 | { | 924 | { |
809 | gpio_request(GPIO_FN_IRQ28_123, NULL); /* for QHD */ | 925 | gpio_request(GPIO_TSC_IRQ, NULL); |
810 | gpio_request(GPIO_FN_IRQ7_40, NULL); /* for WVGA */ | ||
811 | |||
812 | gpio_pull_up(PORT40CR); | ||
813 | gpio_pull_up(PORT123CR); | ||
814 | 926 | ||
815 | return 0; | 927 | return 0; |
816 | } | 928 | } |
@@ -955,14 +1067,6 @@ static void __init ap4evb_init(void) | |||
955 | clk_put(clk); | 1067 | clk_put(clk); |
956 | } | 1068 | } |
957 | 1069 | ||
958 | /* change parent of FSI A */ | ||
959 | clk = clk_get(NULL, "fsia_clk"); | ||
960 | if (!IS_ERR(clk)) { | ||
961 | clk_register(&fsiackcr_clk); | ||
962 | clk_set_parent(clk, &fsiackcr_clk); | ||
963 | clk_put(clk); | ||
964 | } | ||
965 | |||
966 | /* | 1070 | /* |
967 | * set irq priority, to avoid sound chopping | 1071 | * set irq priority, to avoid sound chopping |
968 | * when NFS rootfs is used | 1072 | * when NFS rootfs is used |
@@ -977,8 +1081,10 @@ static void __init ap4evb_init(void) | |||
977 | ARRAY_SIZE(i2c1_devices)); | 1081 | ARRAY_SIZE(i2c1_devices)); |
978 | 1082 | ||
979 | #ifdef CONFIG_AP4EVB_QHD | 1083 | #ifdef CONFIG_AP4EVB_QHD |
1084 | |||
980 | /* | 1085 | /* |
981 | * QHD | 1086 | * For QHD Panel (MIPI-DSI, CONFIG_AP4EVB_QHD=y) and |
1087 | * IRQ28 for Touch Panel, set dip switches S3, S43 as OFF, ON. | ||
982 | */ | 1088 | */ |
983 | 1089 | ||
984 | /* enable KEYSC */ | 1090 | /* enable KEYSC */ |
@@ -1004,17 +1110,6 @@ static void __init ap4evb_init(void) | |||
1004 | lcdc_info.ch[0].interface_type = RGB24; | 1110 | lcdc_info.ch[0].interface_type = RGB24; |
1005 | lcdc_info.ch[0].clock_divider = 1; | 1111 | lcdc_info.ch[0].clock_divider = 1; |
1006 | lcdc_info.ch[0].flags = LCDC_FLAGS_DWPOL; | 1112 | lcdc_info.ch[0].flags = LCDC_FLAGS_DWPOL; |
1007 | lcdc_info.ch[0].lcd_cfg.name = "R63302(QHD)"; | ||
1008 | lcdc_info.ch[0].lcd_cfg.xres = 544; | ||
1009 | lcdc_info.ch[0].lcd_cfg.yres = 961; | ||
1010 | lcdc_info.ch[0].lcd_cfg.left_margin = 72; | ||
1011 | lcdc_info.ch[0].lcd_cfg.right_margin = 600; | ||
1012 | lcdc_info.ch[0].lcd_cfg.hsync_len = 16; | ||
1013 | lcdc_info.ch[0].lcd_cfg.upper_margin = 8; | ||
1014 | lcdc_info.ch[0].lcd_cfg.lower_margin = 8; | ||
1015 | lcdc_info.ch[0].lcd_cfg.vsync_len = 2; | ||
1016 | lcdc_info.ch[0].lcd_cfg.sync = FB_SYNC_VERT_HIGH_ACT | | ||
1017 | FB_SYNC_HOR_HIGH_ACT; | ||
1018 | lcdc_info.ch[0].lcd_size_cfg.width = 44; | 1113 | lcdc_info.ch[0].lcd_size_cfg.width = 44; |
1019 | lcdc_info.ch[0].lcd_size_cfg.height = 79; | 1114 | lcdc_info.ch[0].lcd_size_cfg.height = 79; |
1020 | 1115 | ||
@@ -1022,8 +1117,10 @@ static void __init ap4evb_init(void) | |||
1022 | 1117 | ||
1023 | #else | 1118 | #else |
1024 | /* | 1119 | /* |
1025 | * WVGA | 1120 | * For WVGA Panel (18-bit RGB, CONFIG_AP4EVB_WVGA=y) and |
1121 | * IRQ7 for Touch Panel, set dip switches S3, S43 to ON, OFF. | ||
1026 | */ | 1122 | */ |
1123 | |||
1027 | gpio_request(GPIO_FN_LCDD17, NULL); | 1124 | gpio_request(GPIO_FN_LCDD17, NULL); |
1028 | gpio_request(GPIO_FN_LCDD16, NULL); | 1125 | gpio_request(GPIO_FN_LCDD16, NULL); |
1029 | gpio_request(GPIO_FN_LCDD15, NULL); | 1126 | gpio_request(GPIO_FN_LCDD15, NULL); |
@@ -1055,16 +1152,6 @@ static void __init ap4evb_init(void) | |||
1055 | lcdc_info.ch[0].interface_type = RGB18; | 1152 | lcdc_info.ch[0].interface_type = RGB18; |
1056 | lcdc_info.ch[0].clock_divider = 2; | 1153 | lcdc_info.ch[0].clock_divider = 2; |
1057 | lcdc_info.ch[0].flags = 0; | 1154 | lcdc_info.ch[0].flags = 0; |
1058 | lcdc_info.ch[0].lcd_cfg.name = "WVGA Panel"; | ||
1059 | lcdc_info.ch[0].lcd_cfg.xres = 800; | ||
1060 | lcdc_info.ch[0].lcd_cfg.yres = 480; | ||
1061 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
1062 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
1063 | lcdc_info.ch[0].lcd_cfg.hsync_len = 70; | ||
1064 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
1065 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
1066 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
1067 | lcdc_info.ch[0].lcd_cfg.sync = 0; | ||
1068 | lcdc_info.ch[0].lcd_size_cfg.width = 152; | 1155 | lcdc_info.ch[0].lcd_size_cfg.width = 152; |
1069 | lcdc_info.ch[0].lcd_size_cfg.height = 91; | 1156 | lcdc_info.ch[0].lcd_size_cfg.height = 91; |
1070 | 1157 | ||
@@ -1075,6 +1162,23 @@ static void __init ap4evb_init(void) | |||
1075 | i2c_register_board_info(0, &tsc_device, 1); | 1162 | i2c_register_board_info(0, &tsc_device, 1); |
1076 | #endif /* CONFIG_AP4EVB_QHD */ | 1163 | #endif /* CONFIG_AP4EVB_QHD */ |
1077 | 1164 | ||
1165 | /* CEU */ | ||
1166 | |||
1167 | /* | ||
1168 | * TODO: reserve memory for V4L2 DMA buffers, when a suitable API | ||
1169 | * becomes available | ||
1170 | */ | ||
1171 | |||
1172 | /* MIPI-CSI stuff */ | ||
1173 | gpio_request(GPIO_FN_VIO_CKO, NULL); | ||
1174 | |||
1175 | clk = clk_get(NULL, "vck1_clk"); | ||
1176 | if (!IS_ERR(clk)) { | ||
1177 | clk_set_rate(clk, clk_round_rate(clk, 13000000)); | ||
1178 | clk_enable(clk); | ||
1179 | clk_put(clk); | ||
1180 | } | ||
1181 | |||
1078 | sh7372_add_standard_devices(); | 1182 | sh7372_add_standard_devices(); |
1079 | 1183 | ||
1080 | /* HDMI */ | 1184 | /* HDMI */ |
@@ -1097,7 +1201,7 @@ static void __init ap4evb_timer_init(void) | |||
1097 | shmobile_timer.init(); | 1201 | shmobile_timer.init(); |
1098 | 1202 | ||
1099 | /* External clock source */ | 1203 | /* External clock source */ |
1100 | clk_set_rate(&dv_clki_clk, 27000000); | 1204 | clk_set_rate(&sh7372_dv_clki_clk, 27000000); |
1101 | } | 1205 | } |
1102 | 1206 | ||
1103 | static struct sys_timer ap4evb_timer = { | 1207 | static struct sys_timer ap4evb_timer = { |
diff --git a/arch/arm/mach-shmobile/clock-sh7367.c b/arch/arm/mach-shmobile/clock-sh7367.c index b6454c9f2abb..9f78729098f2 100644 --- a/arch/arm/mach-shmobile/clock-sh7367.c +++ b/arch/arm/mach-shmobile/clock-sh7367.c | |||
@@ -321,7 +321,7 @@ static struct clk_lookup lookups[] = { | |||
321 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */ | 321 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[SYMSTP001]), /* SCIFA3 */ |
322 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */ | 322 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[SYMSTP000]), /* SCIFA4 */ |
323 | CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */ | 323 | CLKDEV_DEV_ID("sh_siu", &mstp_clks[SYMSTP231]), /* SIU */ |
324 | CLKDEV_CON_ID("cmt1", &mstp_clks[SYMSTP229]), /* CMT10 */ | 324 | CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[SYMSTP229]), /* CMT10 */ |
325 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */ | 325 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[SYMSTP225]), /* IRDA */ |
326 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */ | 326 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[SYMSTP223]), /* IIC1 */ |
327 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */ | 327 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[SYMSTP222]), /* USBHS */ |
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 759468992ad2..8565aefa21fd 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c | |||
@@ -51,7 +51,7 @@ | |||
51 | #define SMSTPCR4 0xe6150140 | 51 | #define SMSTPCR4 0xe6150140 |
52 | 52 | ||
53 | /* Platforms must set frequency on their DV_CLKI pin */ | 53 | /* Platforms must set frequency on their DV_CLKI pin */ |
54 | struct clk dv_clki_clk = { | 54 | struct clk sh7372_dv_clki_clk = { |
55 | }; | 55 | }; |
56 | 56 | ||
57 | /* Fixed 32 KHz root clock from EXTALR pin */ | 57 | /* Fixed 32 KHz root clock from EXTALR pin */ |
@@ -86,9 +86,9 @@ static struct clk_ops div2_clk_ops = { | |||
86 | }; | 86 | }; |
87 | 87 | ||
88 | /* Divide dv_clki by two */ | 88 | /* Divide dv_clki by two */ |
89 | struct clk dv_clki_div2_clk = { | 89 | struct clk sh7372_dv_clki_div2_clk = { |
90 | .ops = &div2_clk_ops, | 90 | .ops = &div2_clk_ops, |
91 | .parent = &dv_clki_clk, | 91 | .parent = &sh7372_dv_clki_clk, |
92 | }; | 92 | }; |
93 | 93 | ||
94 | /* Divide extal1 by two */ | 94 | /* Divide extal1 by two */ |
@@ -150,7 +150,7 @@ static struct clk pllc1_div2_clk = { | |||
150 | static struct clk *pllc2_parent[] = { | 150 | static struct clk *pllc2_parent[] = { |
151 | [0] = &extal1_div2_clk, | 151 | [0] = &extal1_div2_clk, |
152 | [1] = &extal2_div2_clk, | 152 | [1] = &extal2_div2_clk, |
153 | [2] = &dv_clki_div2_clk, | 153 | [2] = &sh7372_dv_clki_div2_clk, |
154 | }; | 154 | }; |
155 | 155 | ||
156 | /* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */ | 156 | /* Only multipliers 20 * 2 to 46 * 2 are valid, last entry for CPUFREQ_TABLE_END */ |
@@ -284,7 +284,7 @@ static struct clk_ops pllc2_clk_ops = { | |||
284 | .set_parent = pllc2_set_parent, | 284 | .set_parent = pllc2_set_parent, |
285 | }; | 285 | }; |
286 | 286 | ||
287 | struct clk pllc2_clk = { | 287 | struct clk sh7372_pllc2_clk = { |
288 | .ops = &pllc2_clk_ops, | 288 | .ops = &pllc2_clk_ops, |
289 | .parent = &extal1_div2_clk, | 289 | .parent = &extal1_div2_clk, |
290 | .freq_table = pllc2_freq_table, | 290 | .freq_table = pllc2_freq_table, |
@@ -292,19 +292,28 @@ struct clk pllc2_clk = { | |||
292 | .parent_num = ARRAY_SIZE(pllc2_parent), | 292 | .parent_num = ARRAY_SIZE(pllc2_parent), |
293 | }; | 293 | }; |
294 | 294 | ||
295 | /* External input clock (pin name: FSIACK/FSIBCK ) */ | ||
296 | struct clk sh7372_fsiack_clk = { | ||
297 | }; | ||
298 | |||
299 | struct clk sh7372_fsibck_clk = { | ||
300 | }; | ||
301 | |||
295 | static struct clk *main_clks[] = { | 302 | static struct clk *main_clks[] = { |
296 | &dv_clki_clk, | 303 | &sh7372_dv_clki_clk, |
297 | &r_clk, | 304 | &r_clk, |
298 | &sh7372_extal1_clk, | 305 | &sh7372_extal1_clk, |
299 | &sh7372_extal2_clk, | 306 | &sh7372_extal2_clk, |
300 | &dv_clki_div2_clk, | 307 | &sh7372_dv_clki_div2_clk, |
301 | &extal1_div2_clk, | 308 | &extal1_div2_clk, |
302 | &extal2_div2_clk, | 309 | &extal2_div2_clk, |
303 | &extal2_div4_clk, | 310 | &extal2_div4_clk, |
304 | &pllc0_clk, | 311 | &pllc0_clk, |
305 | &pllc1_clk, | 312 | &pllc1_clk, |
306 | &pllc1_div2_clk, | 313 | &pllc1_div2_clk, |
307 | &pllc2_clk, | 314 | &sh7372_pllc2_clk, |
315 | &sh7372_fsiack_clk, | ||
316 | &sh7372_fsibck_clk, | ||
308 | }; | 317 | }; |
309 | 318 | ||
310 | static void div4_kick(struct clk *clk) | 319 | static void div4_kick(struct clk *clk) |
@@ -357,7 +366,7 @@ static struct clk div4_clks[DIV4_NR] = { | |||
357 | }; | 366 | }; |
358 | 367 | ||
359 | enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, | 368 | enum { DIV6_VCK1, DIV6_VCK2, DIV6_VCK3, DIV6_FMSI, DIV6_FMSO, |
360 | DIV6_FSIA, DIV6_FSIB, DIV6_SUB, DIV6_SPU, | 369 | DIV6_SUB, DIV6_SPU, |
361 | DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, | 370 | DIV6_VOU, DIV6_DSIT, DIV6_DSI0P, DIV6_DSI1P, |
362 | DIV6_NR }; | 371 | DIV6_NR }; |
363 | 372 | ||
@@ -367,8 +376,6 @@ static struct clk div6_clks[DIV6_NR] = { | |||
367 | [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), | 376 | [DIV6_VCK3] = SH_CLK_DIV6(&pllc1_div2_clk, VCLKCR3, 0), |
368 | [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0), | 377 | [DIV6_FMSI] = SH_CLK_DIV6(&pllc1_div2_clk, FMSICKCR, 0), |
369 | [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), | 378 | [DIV6_FMSO] = SH_CLK_DIV6(&pllc1_div2_clk, FMSOCKCR, 0), |
370 | [DIV6_FSIA] = SH_CLK_DIV6(&pllc1_div2_clk, FSIACKCR, 0), | ||
371 | [DIV6_FSIB] = SH_CLK_DIV6(&pllc1_div2_clk, FSIBCKCR, 0), | ||
372 | [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0), | 379 | [DIV6_SUB] = SH_CLK_DIV6(&sh7372_extal2_clk, SUBCKCR, 0), |
373 | [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), | 380 | [DIV6_SPU] = SH_CLK_DIV6(&pllc1_div2_clk, SPUCKCR, 0), |
374 | [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), | 381 | [DIV6_VOU] = SH_CLK_DIV6(&pllc1_div2_clk, VOUCKCR, 0), |
@@ -377,24 +384,42 @@ static struct clk div6_clks[DIV6_NR] = { | |||
377 | [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0), | 384 | [DIV6_DSI1P] = SH_CLK_DIV6(&pllc1_div2_clk, DSI1PCKCR, 0), |
378 | }; | 385 | }; |
379 | 386 | ||
380 | enum { DIV6_HDMI, DIV6_REPARENT_NR }; | 387 | enum { DIV6_HDMI, DIV6_FSIA, DIV6_FSIB, DIV6_REPARENT_NR }; |
381 | 388 | ||
382 | /* Indices are important - they are the actual src selecting values */ | 389 | /* Indices are important - they are the actual src selecting values */ |
383 | static struct clk *hdmi_parent[] = { | 390 | static struct clk *hdmi_parent[] = { |
384 | [0] = &pllc1_div2_clk, | 391 | [0] = &pllc1_div2_clk, |
385 | [1] = &pllc2_clk, | 392 | [1] = &sh7372_pllc2_clk, |
386 | [2] = &dv_clki_clk, | 393 | [2] = &sh7372_dv_clki_clk, |
387 | [3] = NULL, /* pllc2_div4 not implemented yet */ | 394 | [3] = NULL, /* pllc2_div4 not implemented yet */ |
388 | }; | 395 | }; |
389 | 396 | ||
397 | static struct clk *fsiackcr_parent[] = { | ||
398 | [0] = &pllc1_div2_clk, | ||
399 | [1] = &sh7372_pllc2_clk, | ||
400 | [2] = &sh7372_fsiack_clk, /* external input for FSI A */ | ||
401 | [3] = NULL, /* setting prohibited */ | ||
402 | }; | ||
403 | |||
404 | static struct clk *fsibckcr_parent[] = { | ||
405 | [0] = &pllc1_div2_clk, | ||
406 | [1] = &sh7372_pllc2_clk, | ||
407 | [2] = &sh7372_fsibck_clk, /* external input for FSI B */ | ||
408 | [3] = NULL, /* setting prohibited */ | ||
409 | }; | ||
410 | |||
390 | static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { | 411 | static struct clk div6_reparent_clks[DIV6_REPARENT_NR] = { |
391 | [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0, | 412 | [DIV6_HDMI] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, HDMICKCR, 0, |
392 | hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2), | 413 | hdmi_parent, ARRAY_SIZE(hdmi_parent), 6, 2), |
414 | [DIV6_FSIA] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIACKCR, 0, | ||
415 | fsiackcr_parent, ARRAY_SIZE(fsiackcr_parent), 6, 2), | ||
416 | [DIV6_FSIB] = SH_CLK_DIV6_EXT(&pllc1_div2_clk, FSIBCKCR, 0, | ||
417 | fsibckcr_parent, ARRAY_SIZE(fsibckcr_parent), 6, 2), | ||
393 | }; | 418 | }; |
394 | 419 | ||
395 | enum { MSTP001, | 420 | enum { MSTP001, |
396 | MSTP131, MSTP130, | 421 | MSTP131, MSTP130, |
397 | MSTP129, MSTP128, MSTP127, MSTP126, | 422 | MSTP129, MSTP128, MSTP127, MSTP126, MSTP125, |
398 | MSTP118, MSTP117, MSTP116, | 423 | MSTP118, MSTP117, MSTP116, |
399 | MSTP106, MSTP101, MSTP100, | 424 | MSTP106, MSTP101, MSTP100, |
400 | MSTP223, | 425 | MSTP223, |
@@ -414,6 +439,7 @@ static struct clk mstp_clks[MSTP_NR] = { | |||
414 | [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ | 439 | [MSTP128] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 28, 0), /* VEU0 */ |
415 | [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU */ | 440 | [MSTP127] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 27, 0), /* CEU */ |
416 | [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2 */ | 441 | [MSTP126] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 26, 0), /* CSI2 */ |
442 | [MSTP125] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 25, 0), /* TMU0 */ | ||
417 | [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */ | 443 | [MSTP118] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 18, 0), /* DSITX */ |
418 | [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ | 444 | [MSTP117] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 17, 0), /* LCDC1 */ |
419 | [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ | 445 | [MSTP116] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR1, 16, 0), /* IIC0 */ |
@@ -429,7 +455,7 @@ static struct clk mstp_clks[MSTP_NR] = { | |||
429 | [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ | 455 | [MSTP201] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 1, 0), /* SCIFA3 */ |
430 | [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ | 456 | [MSTP200] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 0, 0), /* SCIFA4 */ |
431 | [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ | 457 | [MSTP329] = MSTP(&r_clk, SMSTPCR3, 29, 0), /* CMT10 */ |
432 | [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSIA */ | 458 | [MSTP328] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR3, 28, 0), /* FSI2 */ |
433 | [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ | 459 | [MSTP323] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 23, 0), /* IIC1 */ |
434 | [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ | 460 | [MSTP322] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR3, 22, 0), /* USB0 */ |
435 | [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ | 461 | [MSTP314] = MSTP(&div4_clks[DIV4_HP], SMSTPCR3, 14, 0), /* SDHI0 */ |
@@ -445,10 +471,11 @@ static struct clk mstp_clks[MSTP_NR] = { | |||
445 | 471 | ||
446 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } | 472 | #define CLKDEV_CON_ID(_id, _clk) { .con_id = _id, .clk = _clk } |
447 | #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } | 473 | #define CLKDEV_DEV_ID(_id, _clk) { .dev_id = _id, .clk = _clk } |
474 | #define CLKDEV_ICK_ID(_cid, _did, _clk) { .con_id = _cid, .dev_id = _did, .clk = _clk } | ||
448 | 475 | ||
449 | static struct clk_lookup lookups[] = { | 476 | static struct clk_lookup lookups[] = { |
450 | /* main clocks */ | 477 | /* main clocks */ |
451 | CLKDEV_CON_ID("dv_clki_div2_clk", &dv_clki_div2_clk), | 478 | CLKDEV_CON_ID("dv_clki_div2_clk", &sh7372_dv_clki_div2_clk), |
452 | CLKDEV_CON_ID("r_clk", &r_clk), | 479 | CLKDEV_CON_ID("r_clk", &r_clk), |
453 | CLKDEV_CON_ID("extal1", &sh7372_extal1_clk), | 480 | CLKDEV_CON_ID("extal1", &sh7372_extal1_clk), |
454 | CLKDEV_CON_ID("extal2", &sh7372_extal2_clk), | 481 | CLKDEV_CON_ID("extal2", &sh7372_extal2_clk), |
@@ -458,7 +485,7 @@ static struct clk_lookup lookups[] = { | |||
458 | CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), | 485 | CLKDEV_CON_ID("pllc0_clk", &pllc0_clk), |
459 | CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), | 486 | CLKDEV_CON_ID("pllc1_clk", &pllc1_clk), |
460 | CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), | 487 | CLKDEV_CON_ID("pllc1_div2_clk", &pllc1_div2_clk), |
461 | CLKDEV_CON_ID("pllc2_clk", &pllc2_clk), | 488 | CLKDEV_CON_ID("pllc2_clk", &sh7372_pllc2_clk), |
462 | 489 | ||
463 | /* DIV4 clocks */ | 490 | /* DIV4 clocks */ |
464 | CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), | 491 | CLKDEV_CON_ID("i_clk", &div4_clks[DIV4_I]), |
@@ -483,8 +510,8 @@ static struct clk_lookup lookups[] = { | |||
483 | CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), | 510 | CLKDEV_CON_ID("vck3_clk", &div6_clks[DIV6_VCK3]), |
484 | CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), | 511 | CLKDEV_CON_ID("fmsi_clk", &div6_clks[DIV6_FMSI]), |
485 | CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), | 512 | CLKDEV_CON_ID("fmso_clk", &div6_clks[DIV6_FMSO]), |
486 | CLKDEV_CON_ID("fsia_clk", &div6_clks[DIV6_FSIA]), | 513 | CLKDEV_CON_ID("fsia_clk", &div6_reparent_clks[DIV6_FSIA]), |
487 | CLKDEV_CON_ID("fsib_clk", &div6_clks[DIV6_FSIB]), | 514 | CLKDEV_CON_ID("fsib_clk", &div6_reparent_clks[DIV6_FSIB]), |
488 | CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), | 515 | CLKDEV_CON_ID("sub_clk", &div6_clks[DIV6_SUB]), |
489 | CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), | 516 | CLKDEV_CON_ID("spu_clk", &div6_clks[DIV6_SPU]), |
490 | CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), | 517 | CLKDEV_CON_ID("vou_clk", &div6_clks[DIV6_VOU]), |
@@ -501,6 +528,8 @@ static struct clk_lookup lookups[] = { | |||
501 | CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ | 528 | CLKDEV_DEV_ID("uio_pdrv_genirq.1", &mstp_clks[MSTP128]), /* VEU0 */ |
502 | CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU */ | 529 | CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[MSTP127]), /* CEU */ |
503 | CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2 */ | 530 | CLKDEV_DEV_ID("sh-mobile-csi2.0", &mstp_clks[MSTP126]), /* CSI2 */ |
531 | CLKDEV_DEV_ID("sh_tmu.0", &mstp_clks[MSTP125]), /* TMU00 */ | ||
532 | CLKDEV_DEV_ID("sh_tmu.1", &mstp_clks[MSTP125]), /* TMU01 */ | ||
504 | CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ | 533 | CLKDEV_DEV_ID("sh-mipi-dsi.0", &mstp_clks[MSTP118]), /* DSITX */ |
505 | CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ | 534 | CLKDEV_DEV_ID("sh_mobile_lcdc_fb.1", &mstp_clks[MSTP117]), /* LCDC1 */ |
506 | CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ | 535 | CLKDEV_DEV_ID("i2c-sh_mobile.0", &mstp_clks[MSTP116]), /* IIC0 */ |
@@ -516,7 +545,7 @@ static struct clk_lookup lookups[] = { | |||
516 | CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ | 545 | CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP202]), /* SCIFA2 */ |
517 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ | 546 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ |
518 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ | 547 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ |
519 | CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */ | 548 | CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ |
520 | CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ | 549 | CLKDEV_DEV_ID("sh_fsi2", &mstp_clks[MSTP328]), /* FSI2 */ |
521 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ | 550 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ |
522 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ | 551 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP323]), /* USB0 */ |
@@ -531,7 +560,10 @@ static struct clk_lookup lookups[] = { | |||
531 | CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ | 560 | CLKDEV_DEV_ID("r8a66597_hcd.1", &mstp_clks[MSTP406]), /* USB1 */ |
532 | CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ | 561 | CLKDEV_DEV_ID("r8a66597_udc.1", &mstp_clks[MSTP406]), /* USB1 */ |
533 | CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ | 562 | CLKDEV_DEV_ID("sh_keysc.0", &mstp_clks[MSTP403]), /* KEYSC */ |
534 | {.con_id = "ick", .dev_id = "sh-mobile-hdmi", .clk = &div6_reparent_clks[DIV6_HDMI]}, | 563 | |
564 | CLKDEV_ICK_ID("ick", "sh-mobile-hdmi", &div6_reparent_clks[DIV6_HDMI]), | ||
565 | CLKDEV_ICK_ID("icka", "sh_fsi2", &div6_reparent_clks[DIV6_FSIA]), | ||
566 | CLKDEV_ICK_ID("ickb", "sh_fsi2", &div6_reparent_clks[DIV6_FSIB]), | ||
535 | }; | 567 | }; |
536 | 568 | ||
537 | void __init sh7372_clock_init(void) | 569 | void __init sh7372_clock_init(void) |
@@ -548,7 +580,7 @@ void __init sh7372_clock_init(void) | |||
548 | ret = sh_clk_div6_register(div6_clks, DIV6_NR); | 580 | ret = sh_clk_div6_register(div6_clks, DIV6_NR); |
549 | 581 | ||
550 | if (!ret) | 582 | if (!ret) |
551 | ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_NR); | 583 | ret = sh_clk_div6_reparent_register(div6_reparent_clks, DIV6_REPARENT_NR); |
552 | 584 | ||
553 | if (!ret) | 585 | if (!ret) |
554 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); | 586 | ret = sh_clk_mstp32_register(mstp_clks, MSTP_NR); |
diff --git a/arch/arm/mach-shmobile/clock-sh7377.c b/arch/arm/mach-shmobile/clock-sh7377.c index e007c28cf0a8..f91395aeb9ab 100644 --- a/arch/arm/mach-shmobile/clock-sh7377.c +++ b/arch/arm/mach-shmobile/clock-sh7377.c | |||
@@ -333,7 +333,7 @@ static struct clk_lookup lookups[] = { | |||
333 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ | 333 | CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP201]), /* SCIFA3 */ |
334 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ | 334 | CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP200]), /* SCIFA4 */ |
335 | CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */ | 335 | CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP331]), /* SCIFA6 */ |
336 | CLKDEV_CON_ID("cmt1", &mstp_clks[MSTP329]), /* CMT10 */ | 336 | CLKDEV_DEV_ID("sh_cmt.10", &mstp_clks[MSTP329]), /* CMT10 */ |
337 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */ | 337 | CLKDEV_DEV_ID("sh_irda", &mstp_clks[MSTP325]), /* IRDA */ |
338 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ | 338 | CLKDEV_DEV_ID("i2c-sh_mobile.1", &mstp_clks[MSTP323]), /* IIC1 */ |
339 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */ | 339 | CLKDEV_DEV_ID("r8a66597_hcd.0", &mstp_clks[MSTP322]), /* USBHS */ |
diff --git a/arch/arm/mach-shmobile/include/mach/sh7372.h b/arch/arm/mach-shmobile/include/mach/sh7372.h index 33e9700ded7e..147775a94bce 100644 --- a/arch/arm/mach-shmobile/include/mach/sh7372.h +++ b/arch/arm/mach-shmobile/include/mach/sh7372.h | |||
@@ -457,8 +457,12 @@ enum { | |||
457 | SHDMA_SLAVE_SDHI2_TX, | 457 | SHDMA_SLAVE_SDHI2_TX, |
458 | }; | 458 | }; |
459 | 459 | ||
460 | extern struct clk dv_clki_clk; | 460 | extern struct clk sh7372_extal1_clk; |
461 | extern struct clk dv_clki_div2_clk; | 461 | extern struct clk sh7372_extal2_clk; |
462 | extern struct clk pllc2_clk; | 462 | extern struct clk sh7372_dv_clki_clk; |
463 | extern struct clk sh7372_dv_clki_div2_clk; | ||
464 | extern struct clk sh7372_pllc2_clk; | ||
465 | extern struct clk sh7372_fsiack_clk; | ||
466 | extern struct clk sh7372_fsibck_clk; | ||
463 | 467 | ||
464 | #endif /* __ASM_SH7372_H__ */ | 468 | #endif /* __ASM_SH7372_H__ */ |
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c index e3551b56cd03..4cd3cae38e72 100644 --- a/arch/arm/mach-shmobile/intc-sh7372.c +++ b/arch/arm/mach-shmobile/intc-sh7372.c | |||
@@ -369,9 +369,13 @@ enum { | |||
369 | INTCS, | 369 | INTCS, |
370 | 370 | ||
371 | /* interrupt sources INTCS */ | 371 | /* interrupt sources INTCS */ |
372 | |||
373 | /* IRQ0S - IRQ31S */ | ||
372 | VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3, | 374 | VEU_VEU0, VEU_VEU1, VEU_VEU2, VEU_VEU3, |
373 | RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3, | 375 | RTDMAC_1_DEI0, RTDMAC_1_DEI1, RTDMAC_1_DEI2, RTDMAC_1_DEI3, |
374 | CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2, | 376 | CEU, BEU_BEU0, BEU_BEU1, BEU_BEU2, |
377 | /* MFI */ | ||
378 | /* BBIF2 */ | ||
375 | VPU, | 379 | VPU, |
376 | TSIF1, | 380 | TSIF1, |
377 | _3DG_SGX530, | 381 | _3DG_SGX530, |
@@ -379,13 +383,17 @@ enum { | |||
379 | IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, | 383 | IIC2_ALI2, IIC2_TACKI2, IIC2_WAITI2, IIC2_DTEI2, |
380 | IPMMU_IPMMUR, IPMMU_IPMMUR2, | 384 | IPMMU_IPMMUR, IPMMU_IPMMUR2, |
381 | RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR, | 385 | RTDMAC_2_DEI4, RTDMAC_2_DEI5, RTDMAC_2_DADERR, |
386 | /* KEYSC */ | ||
387 | /* TTI20 */ | ||
382 | MSIOF, | 388 | MSIOF, |
383 | IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, | 389 | IIC0_ALI0, IIC0_TACKI0, IIC0_WAITI0, IIC0_DTEI0, |
384 | TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, | 390 | TMU_TUNI0, TMU_TUNI1, TMU_TUNI2, |
385 | CMT0, | 391 | CMT0, |
386 | TSIF0, | 392 | TSIF0, |
393 | /* CMT2 */ | ||
387 | LMB, | 394 | LMB, |
388 | CTI, | 395 | CTI, |
396 | /* RWDT0 */ | ||
389 | ICB, | 397 | ICB, |
390 | JPU_JPEG, | 398 | JPU_JPEG, |
391 | LCDC, | 399 | LCDC, |
@@ -397,11 +405,17 @@ enum { | |||
397 | CSIRX, | 405 | CSIRX, |
398 | DSITX_DSITX0, | 406 | DSITX_DSITX0, |
399 | DSITX_DSITX1, | 407 | DSITX_DSITX1, |
408 | /* SPU2 */ | ||
409 | /* FSI */ | ||
410 | /* FMSI */ | ||
411 | /* HDMI */ | ||
400 | TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, | 412 | TMU1_TUNI0, TMU1_TUNI1, TMU1_TUNI2, |
401 | CMT4, | 413 | CMT4, |
402 | DSITX1_DSITX1_0, | 414 | DSITX1_DSITX1_0, |
403 | DSITX1_DSITX1_1, | 415 | DSITX1_DSITX1_1, |
416 | /* MFIS2 */ | ||
404 | CPORTS2R, | 417 | CPORTS2R, |
418 | /* CEC */ | ||
405 | JPU6E, | 419 | JPU6E, |
406 | 420 | ||
407 | /* interrupt groups INTCS */ | 421 | /* interrupt groups INTCS */ |
@@ -410,12 +424,15 @@ enum { | |||
410 | }; | 424 | }; |
411 | 425 | ||
412 | static struct intc_vect intcs_vectors[] = { | 426 | static struct intc_vect intcs_vectors[] = { |
427 | /* IRQ0S - IRQ31S */ | ||
413 | INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720), | 428 | INTCS_VECT(VEU_VEU0, 0x700), INTCS_VECT(VEU_VEU1, 0x720), |
414 | INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760), | 429 | INTCS_VECT(VEU_VEU2, 0x740), INTCS_VECT(VEU_VEU3, 0x760), |
415 | INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820), | 430 | INTCS_VECT(RTDMAC_1_DEI0, 0x800), INTCS_VECT(RTDMAC_1_DEI1, 0x820), |
416 | INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860), | 431 | INTCS_VECT(RTDMAC_1_DEI2, 0x840), INTCS_VECT(RTDMAC_1_DEI3, 0x860), |
417 | INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0), | 432 | INTCS_VECT(CEU, 0x880), INTCS_VECT(BEU_BEU0, 0x8a0), |
418 | INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0), | 433 | INTCS_VECT(BEU_BEU1, 0x8c0), INTCS_VECT(BEU_BEU2, 0x8e0), |
434 | /* MFI */ | ||
435 | /* BBIF2 */ | ||
419 | INTCS_VECT(VPU, 0x980), | 436 | INTCS_VECT(VPU, 0x980), |
420 | INTCS_VECT(TSIF1, 0x9a0), | 437 | INTCS_VECT(TSIF1, 0x9a0), |
421 | INTCS_VECT(_3DG_SGX530, 0x9e0), | 438 | INTCS_VECT(_3DG_SGX530, 0x9e0), |
@@ -425,14 +442,19 @@ static struct intc_vect intcs_vectors[] = { | |||
425 | INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20), | 442 | INTCS_VECT(IPMMU_IPMMUR, 0xb00), INTCS_VECT(IPMMU_IPMMUR2, 0xb20), |
426 | INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0), | 443 | INTCS_VECT(RTDMAC_2_DEI4, 0xb80), INTCS_VECT(RTDMAC_2_DEI5, 0xba0), |
427 | INTCS_VECT(RTDMAC_2_DADERR, 0xbc0), | 444 | INTCS_VECT(RTDMAC_2_DADERR, 0xbc0), |
445 | /* KEYSC */ | ||
446 | /* TTI20 */ | ||
447 | INTCS_VECT(MSIOF, 0x0d20), | ||
428 | INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20), | 448 | INTCS_VECT(IIC0_ALI0, 0xe00), INTCS_VECT(IIC0_TACKI0, 0xe20), |
429 | INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60), | 449 | INTCS_VECT(IIC0_WAITI0, 0xe40), INTCS_VECT(IIC0_DTEI0, 0xe60), |
430 | INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0), | 450 | INTCS_VECT(TMU_TUNI0, 0xe80), INTCS_VECT(TMU_TUNI1, 0xea0), |
431 | INTCS_VECT(TMU_TUNI2, 0xec0), | 451 | INTCS_VECT(TMU_TUNI2, 0xec0), |
432 | INTCS_VECT(CMT0, 0xf00), | 452 | INTCS_VECT(CMT0, 0xf00), |
433 | INTCS_VECT(TSIF0, 0xf20), | 453 | INTCS_VECT(TSIF0, 0xf20), |
454 | /* CMT2 */ | ||
434 | INTCS_VECT(LMB, 0xf60), | 455 | INTCS_VECT(LMB, 0xf60), |
435 | INTCS_VECT(CTI, 0x400), | 456 | INTCS_VECT(CTI, 0x400), |
457 | /* RWDT0 */ | ||
436 | INTCS_VECT(ICB, 0x480), | 458 | INTCS_VECT(ICB, 0x480), |
437 | INTCS_VECT(JPU_JPEG, 0x560), | 459 | INTCS_VECT(JPU_JPEG, 0x560), |
438 | INTCS_VECT(LCDC, 0x580), | 460 | INTCS_VECT(LCDC, 0x580), |
@@ -446,12 +468,18 @@ static struct intc_vect intcs_vectors[] = { | |||
446 | INTCS_VECT(CSIRX, 0x17a0), | 468 | INTCS_VECT(CSIRX, 0x17a0), |
447 | INTCS_VECT(DSITX_DSITX0, 0x17c0), | 469 | INTCS_VECT(DSITX_DSITX0, 0x17c0), |
448 | INTCS_VECT(DSITX_DSITX1, 0x17e0), | 470 | INTCS_VECT(DSITX_DSITX1, 0x17e0), |
471 | /* SPU2 */ | ||
472 | /* FSI */ | ||
473 | /* FMSI */ | ||
474 | /* HDMI */ | ||
449 | INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920), | 475 | INTCS_VECT(TMU1_TUNI0, 0x1900), INTCS_VECT(TMU1_TUNI1, 0x1920), |
450 | INTCS_VECT(TMU1_TUNI2, 0x1940), | 476 | INTCS_VECT(TMU1_TUNI2, 0x1940), |
451 | INTCS_VECT(CMT4, 0x1980), | 477 | INTCS_VECT(CMT4, 0x1980), |
452 | INTCS_VECT(DSITX1_DSITX1_0, 0x19a0), | 478 | INTCS_VECT(DSITX1_DSITX1_0, 0x19a0), |
453 | INTCS_VECT(DSITX1_DSITX1_1, 0x19c0), | 479 | INTCS_VECT(DSITX1_DSITX1_1, 0x19c0), |
480 | /* MFIS2 */ | ||
454 | INTCS_VECT(CPORTS2R, 0x1a20), | 481 | INTCS_VECT(CPORTS2R, 0x1a20), |
482 | /* CEC */ | ||
455 | INTCS_VECT(JPU6E, 0x1a80), | 483 | INTCS_VECT(JPU6E, 0x1a80), |
456 | 484 | ||
457 | INTC_VECT(INTCS, 0xf80), | 485 | INTC_VECT(INTCS, 0xf80), |
diff --git a/arch/arm/mach-shmobile/pfc-sh7372.c b/arch/arm/mach-shmobile/pfc-sh7372.c index ec420353f8e3..9c265dae138a 100644 --- a/arch/arm/mach-shmobile/pfc-sh7372.c +++ b/arch/arm/mach-shmobile/pfc-sh7372.c | |||
@@ -166,12 +166,12 @@ enum { | |||
166 | MSIOF2_TSYNC_MARK, MSIOF2_TSCK_MARK, MSIOF2_RXD_MARK, | 166 | MSIOF2_TSYNC_MARK, MSIOF2_TSCK_MARK, MSIOF2_RXD_MARK, |
167 | MSIOF2_TXD_MARK, | 167 | MSIOF2_TXD_MARK, |
168 | 168 | ||
169 | /* MSIOF3 */ | 169 | /* BBIF1 */ |
170 | BBIF1_RXD_MARK, BBIF1_TSYNC_MARK, BBIF1_TSCK_MARK, | 170 | BBIF1_RXD_MARK, BBIF1_TSYNC_MARK, BBIF1_TSCK_MARK, |
171 | BBIF1_TXD_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK, | 171 | BBIF1_TXD_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK, |
172 | BBIF1_FLOW_MARK, BB_RX_FLOW_N_MARK, | 172 | BBIF1_FLOW_MARK, BB_RX_FLOW_N_MARK, |
173 | 173 | ||
174 | /* MSIOF4 */ | 174 | /* BBIF2 */ |
175 | BBIF2_TSCK1_MARK, BBIF2_TSYNC1_MARK, | 175 | BBIF2_TSCK1_MARK, BBIF2_TSYNC1_MARK, |
176 | BBIF2_TXD1_MARK, BBIF2_RXD_MARK, | 176 | BBIF2_TXD1_MARK, BBIF2_RXD_MARK, |
177 | 177 | ||
@@ -976,12 +976,12 @@ static struct pinmux_gpio pinmux_gpios[] = { | |||
976 | GPIO_FN(MSIOF2_TSYNC), GPIO_FN(MSIOF2_TSCK), GPIO_FN(MSIOF2_RXD), | 976 | GPIO_FN(MSIOF2_TSYNC), GPIO_FN(MSIOF2_TSCK), GPIO_FN(MSIOF2_RXD), |
977 | GPIO_FN(MSIOF2_TXD), | 977 | GPIO_FN(MSIOF2_TXD), |
978 | 978 | ||
979 | /* MSIOF3 */ | 979 | /* BBIF1 */ |
980 | GPIO_FN(BBIF1_RXD), GPIO_FN(BBIF1_TSYNC), GPIO_FN(BBIF1_TSCK), | 980 | GPIO_FN(BBIF1_RXD), GPIO_FN(BBIF1_TSYNC), GPIO_FN(BBIF1_TSCK), |
981 | GPIO_FN(BBIF1_TXD), GPIO_FN(BBIF1_RSCK), GPIO_FN(BBIF1_RSYNC), | 981 | GPIO_FN(BBIF1_TXD), GPIO_FN(BBIF1_RSCK), GPIO_FN(BBIF1_RSYNC), |
982 | GPIO_FN(BBIF1_FLOW), GPIO_FN(BB_RX_FLOW_N), | 982 | GPIO_FN(BBIF1_FLOW), GPIO_FN(BB_RX_FLOW_N), |
983 | 983 | ||
984 | /* MSIOF4 */ | 984 | /* BBIF2 */ |
985 | GPIO_FN(BBIF2_TSCK1), GPIO_FN(BBIF2_TSYNC1), | 985 | GPIO_FN(BBIF2_TSCK1), GPIO_FN(BBIF2_TSYNC1), |
986 | GPIO_FN(BBIF2_TXD1), GPIO_FN(BBIF2_RXD), | 986 | GPIO_FN(BBIF2_TXD1), GPIO_FN(BBIF2_RXD), |
987 | 987 | ||
diff --git a/arch/arm/mach-shmobile/setup-sh7367.c b/arch/arm/mach-shmobile/setup-sh7367.c index 3148c11a550e..003008c18360 100644 --- a/arch/arm/mach-shmobile/setup-sh7367.c +++ b/arch/arm/mach-shmobile/setup-sh7367.c | |||
@@ -154,7 +154,6 @@ static struct sh_timer_config cmt10_platform_data = { | |||
154 | .name = "CMT10", | 154 | .name = "CMT10", |
155 | .channel_offset = 0x10, | 155 | .channel_offset = 0x10, |
156 | .timer_bit = 0, | 156 | .timer_bit = 0, |
157 | .clk = "r_clk", | ||
158 | .clockevent_rating = 125, | 157 | .clockevent_rating = 125, |
159 | .clocksource_rating = 125, | 158 | .clocksource_rating = 125, |
160 | }; | 159 | }; |
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c index e26686c9d0b6..564a6d0be473 100644 --- a/arch/arm/mach-shmobile/setup-sh7372.c +++ b/arch/arm/mach-shmobile/setup-sh7372.c | |||
@@ -158,7 +158,6 @@ static struct sh_timer_config cmt10_platform_data = { | |||
158 | .name = "CMT10", | 158 | .name = "CMT10", |
159 | .channel_offset = 0x10, | 159 | .channel_offset = 0x10, |
160 | .timer_bit = 0, | 160 | .timer_bit = 0, |
161 | .clk = "cmt1", | ||
162 | .clockevent_rating = 125, | 161 | .clockevent_rating = 125, |
163 | .clocksource_rating = 125, | 162 | .clocksource_rating = 125, |
164 | }; | 163 | }; |
@@ -186,6 +185,67 @@ static struct platform_device cmt10_device = { | |||
186 | .num_resources = ARRAY_SIZE(cmt10_resources), | 185 | .num_resources = ARRAY_SIZE(cmt10_resources), |
187 | }; | 186 | }; |
188 | 187 | ||
188 | /* TMU */ | ||
189 | static struct sh_timer_config tmu00_platform_data = { | ||
190 | .name = "TMU00", | ||
191 | .channel_offset = 0x4, | ||
192 | .timer_bit = 0, | ||
193 | .clockevent_rating = 200, | ||
194 | }; | ||
195 | |||
196 | static struct resource tmu00_resources[] = { | ||
197 | [0] = { | ||
198 | .name = "TMU00", | ||
199 | .start = 0xfff60008, | ||
200 | .end = 0xfff60013, | ||
201 | .flags = IORESOURCE_MEM, | ||
202 | }, | ||
203 | [1] = { | ||
204 | .start = intcs_evt2irq(0xe80), /* TMU_TUNI0 */ | ||
205 | .flags = IORESOURCE_IRQ, | ||
206 | }, | ||
207 | }; | ||
208 | |||
209 | static struct platform_device tmu00_device = { | ||
210 | .name = "sh_tmu", | ||
211 | .id = 0, | ||
212 | .dev = { | ||
213 | .platform_data = &tmu00_platform_data, | ||
214 | }, | ||
215 | .resource = tmu00_resources, | ||
216 | .num_resources = ARRAY_SIZE(tmu00_resources), | ||
217 | }; | ||
218 | |||
219 | static struct sh_timer_config tmu01_platform_data = { | ||
220 | .name = "TMU01", | ||
221 | .channel_offset = 0x10, | ||
222 | .timer_bit = 1, | ||
223 | .clocksource_rating = 200, | ||
224 | }; | ||
225 | |||
226 | static struct resource tmu01_resources[] = { | ||
227 | [0] = { | ||
228 | .name = "TMU01", | ||
229 | .start = 0xfff60014, | ||
230 | .end = 0xfff6001f, | ||
231 | .flags = IORESOURCE_MEM, | ||
232 | }, | ||
233 | [1] = { | ||
234 | .start = intcs_evt2irq(0xea0), /* TMU_TUNI1 */ | ||
235 | .flags = IORESOURCE_IRQ, | ||
236 | }, | ||
237 | }; | ||
238 | |||
239 | static struct platform_device tmu01_device = { | ||
240 | .name = "sh_tmu", | ||
241 | .id = 1, | ||
242 | .dev = { | ||
243 | .platform_data = &tmu01_platform_data, | ||
244 | }, | ||
245 | .resource = tmu01_resources, | ||
246 | .num_resources = ARRAY_SIZE(tmu01_resources), | ||
247 | }; | ||
248 | |||
189 | /* I2C */ | 249 | /* I2C */ |
190 | static struct resource iic0_resources[] = { | 250 | static struct resource iic0_resources[] = { |
191 | [0] = { | 251 | [0] = { |
@@ -419,14 +479,14 @@ static struct resource sh7372_dmae0_resources[] = { | |||
419 | }, | 479 | }, |
420 | { | 480 | { |
421 | /* DMA error IRQ */ | 481 | /* DMA error IRQ */ |
422 | .start = 246, | 482 | .start = evt2irq(0x20c0), |
423 | .end = 246, | 483 | .end = evt2irq(0x20c0), |
424 | .flags = IORESOURCE_IRQ, | 484 | .flags = IORESOURCE_IRQ, |
425 | }, | 485 | }, |
426 | { | 486 | { |
427 | /* IRQ for channels 0-5 */ | 487 | /* IRQ for channels 0-5 */ |
428 | .start = 240, | 488 | .start = evt2irq(0x2000), |
429 | .end = 245, | 489 | .end = evt2irq(0x20a0), |
430 | .flags = IORESOURCE_IRQ, | 490 | .flags = IORESOURCE_IRQ, |
431 | }, | 491 | }, |
432 | }; | 492 | }; |
@@ -447,14 +507,14 @@ static struct resource sh7372_dmae1_resources[] = { | |||
447 | }, | 507 | }, |
448 | { | 508 | { |
449 | /* DMA error IRQ */ | 509 | /* DMA error IRQ */ |
450 | .start = 254, | 510 | .start = evt2irq(0x21c0), |
451 | .end = 254, | 511 | .end = evt2irq(0x21c0), |
452 | .flags = IORESOURCE_IRQ, | 512 | .flags = IORESOURCE_IRQ, |
453 | }, | 513 | }, |
454 | { | 514 | { |
455 | /* IRQ for channels 0-5 */ | 515 | /* IRQ for channels 0-5 */ |
456 | .start = 248, | 516 | .start = evt2irq(0x2100), |
457 | .end = 253, | 517 | .end = evt2irq(0x21a0), |
458 | .flags = IORESOURCE_IRQ, | 518 | .flags = IORESOURCE_IRQ, |
459 | }, | 519 | }, |
460 | }; | 520 | }; |
@@ -475,14 +535,14 @@ static struct resource sh7372_dmae2_resources[] = { | |||
475 | }, | 535 | }, |
476 | { | 536 | { |
477 | /* DMA error IRQ */ | 537 | /* DMA error IRQ */ |
478 | .start = 262, | 538 | .start = evt2irq(0x22c0), |
479 | .end = 262, | 539 | .end = evt2irq(0x22c0), |
480 | .flags = IORESOURCE_IRQ, | 540 | .flags = IORESOURCE_IRQ, |
481 | }, | 541 | }, |
482 | { | 542 | { |
483 | /* IRQ for channels 0-5 */ | 543 | /* IRQ for channels 0-5 */ |
484 | .start = 256, | 544 | .start = evt2irq(0x2200), |
485 | .end = 261, | 545 | .end = evt2irq(0x22a0), |
486 | .flags = IORESOURCE_IRQ, | 546 | .flags = IORESOURCE_IRQ, |
487 | }, | 547 | }, |
488 | }; | 548 | }; |
@@ -526,6 +586,11 @@ static struct platform_device *sh7372_early_devices[] __initdata = { | |||
526 | &scif5_device, | 586 | &scif5_device, |
527 | &scif6_device, | 587 | &scif6_device, |
528 | &cmt10_device, | 588 | &cmt10_device, |
589 | &tmu00_device, | ||
590 | &tmu01_device, | ||
591 | }; | ||
592 | |||
593 | static struct platform_device *sh7372_late_devices[] __initdata = { | ||
529 | &iic0_device, | 594 | &iic0_device, |
530 | &iic1_device, | 595 | &iic1_device, |
531 | &dma0_device, | 596 | &dma0_device, |
@@ -537,6 +602,9 @@ void __init sh7372_add_standard_devices(void) | |||
537 | { | 602 | { |
538 | platform_add_devices(sh7372_early_devices, | 603 | platform_add_devices(sh7372_early_devices, |
539 | ARRAY_SIZE(sh7372_early_devices)); | 604 | ARRAY_SIZE(sh7372_early_devices)); |
605 | |||
606 | platform_add_devices(sh7372_late_devices, | ||
607 | ARRAY_SIZE(sh7372_late_devices)); | ||
540 | } | 608 | } |
541 | 609 | ||
542 | void __init sh7372_add_early_devices(void) | 610 | void __init sh7372_add_early_devices(void) |
diff --git a/arch/arm/mach-shmobile/setup-sh7377.c b/arch/arm/mach-shmobile/setup-sh7377.c index bb4adf17dbf4..575dbd6c2f1d 100644 --- a/arch/arm/mach-shmobile/setup-sh7377.c +++ b/arch/arm/mach-shmobile/setup-sh7377.c | |||
@@ -172,7 +172,6 @@ static struct sh_timer_config cmt10_platform_data = { | |||
172 | .name = "CMT10", | 172 | .name = "CMT10", |
173 | .channel_offset = 0x10, | 173 | .channel_offset = 0x10, |
174 | .timer_bit = 0, | 174 | .timer_bit = 0, |
175 | .clk = "r_clk", | ||
176 | .clockevent_rating = 125, | 175 | .clockevent_rating = 125, |
177 | .clocksource_rating = 125, | 176 | .clocksource_rating = 125, |
178 | }; | 177 | }; |
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 3da116f47f01..00553233a7c5 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c | |||
@@ -176,6 +176,21 @@ static void ap320_wvga_power_off(void *board_data) | |||
176 | __raw_writew(0, FPGA_LCDREG); | 176 | __raw_writew(0, FPGA_LCDREG); |
177 | } | 177 | } |
178 | 178 | ||
179 | const static struct fb_videomode ap325rxa_lcdc_modes[] = { | ||
180 | { | ||
181 | .name = "LB070WV1", | ||
182 | .xres = 800, | ||
183 | .yres = 480, | ||
184 | .left_margin = 32, | ||
185 | .right_margin = 160, | ||
186 | .hsync_len = 8, | ||
187 | .upper_margin = 63, | ||
188 | .lower_margin = 80, | ||
189 | .vsync_len = 1, | ||
190 | .sync = 0, /* hsync and vsync are active low */ | ||
191 | }, | ||
192 | }; | ||
193 | |||
179 | static struct sh_mobile_lcdc_info lcdc_info = { | 194 | static struct sh_mobile_lcdc_info lcdc_info = { |
180 | .clock_source = LCDC_CLK_EXTERNAL, | 195 | .clock_source = LCDC_CLK_EXTERNAL, |
181 | .ch[0] = { | 196 | .ch[0] = { |
@@ -183,18 +198,8 @@ static struct sh_mobile_lcdc_info lcdc_info = { | |||
183 | .bpp = 16, | 198 | .bpp = 16, |
184 | .interface_type = RGB18, | 199 | .interface_type = RGB18, |
185 | .clock_divider = 1, | 200 | .clock_divider = 1, |
186 | .lcd_cfg = { | 201 | .lcd_cfg = ap325rxa_lcdc_modes, |
187 | .name = "LB070WV1", | 202 | .num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes), |
188 | .xres = 800, | ||
189 | .yres = 480, | ||
190 | .left_margin = 32, | ||
191 | .right_margin = 160, | ||
192 | .hsync_len = 8, | ||
193 | .upper_margin = 63, | ||
194 | .lower_margin = 80, | ||
195 | .vsync_len = 1, | ||
196 | .sync = 0, /* hsync and vsync are active low */ | ||
197 | }, | ||
198 | .lcd_size_cfg = { /* 7.0 inch */ | 203 | .lcd_size_cfg = { /* 7.0 inch */ |
199 | .width = 152, | 204 | .width = 152, |
200 | .height = 91, | 205 | .height = 91, |
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 71a3368ab1fc..0161deb770cc 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c | |||
@@ -231,14 +231,41 @@ static struct platform_device usb1_common_device = { | |||
231 | }; | 231 | }; |
232 | 232 | ||
233 | /* LCDC */ | 233 | /* LCDC */ |
234 | const static struct fb_videomode ecovec_lcd_modes[] = { | ||
235 | { | ||
236 | .name = "Panel", | ||
237 | .xres = 800, | ||
238 | .yres = 480, | ||
239 | .left_margin = 220, | ||
240 | .right_margin = 110, | ||
241 | .hsync_len = 70, | ||
242 | .upper_margin = 20, | ||
243 | .lower_margin = 5, | ||
244 | .vsync_len = 5, | ||
245 | .sync = 0, /* hsync and vsync are active low */ | ||
246 | }, | ||
247 | }; | ||
248 | |||
249 | const static struct fb_videomode ecovec_dvi_modes[] = { | ||
250 | { | ||
251 | .name = "DVI", | ||
252 | .xres = 1280, | ||
253 | .yres = 720, | ||
254 | .left_margin = 220, | ||
255 | .right_margin = 110, | ||
256 | .hsync_len = 40, | ||
257 | .upper_margin = 20, | ||
258 | .lower_margin = 5, | ||
259 | .vsync_len = 5, | ||
260 | .sync = 0, /* hsync and vsync are active low */ | ||
261 | }, | ||
262 | }; | ||
263 | |||
234 | static struct sh_mobile_lcdc_info lcdc_info = { | 264 | static struct sh_mobile_lcdc_info lcdc_info = { |
235 | .ch[0] = { | 265 | .ch[0] = { |
236 | .interface_type = RGB18, | 266 | .interface_type = RGB18, |
237 | .chan = LCDC_CHAN_MAINLCD, | 267 | .chan = LCDC_CHAN_MAINLCD, |
238 | .bpp = 16, | 268 | .bpp = 16, |
239 | .lcd_cfg = { | ||
240 | .sync = 0, /* hsync and vsync are active low */ | ||
241 | }, | ||
242 | .lcd_size_cfg = { /* 7.0 inch */ | 269 | .lcd_size_cfg = { /* 7.0 inch */ |
243 | .width = 152, | 270 | .width = 152, |
244 | .height = 91, | 271 | .height = 91, |
@@ -1079,33 +1106,18 @@ static int __init arch_setup(void) | |||
1079 | if (gpio_get_value(GPIO_PTE6)) { | 1106 | if (gpio_get_value(GPIO_PTE6)) { |
1080 | /* DVI */ | 1107 | /* DVI */ |
1081 | lcdc_info.clock_source = LCDC_CLK_EXTERNAL; | 1108 | lcdc_info.clock_source = LCDC_CLK_EXTERNAL; |
1082 | lcdc_info.ch[0].clock_divider = 1, | 1109 | lcdc_info.ch[0].clock_divider = 1; |
1083 | lcdc_info.ch[0].lcd_cfg.name = "DVI"; | 1110 | lcdc_info.ch[0].lcd_cfg = ecovec_dvi_modes; |
1084 | lcdc_info.ch[0].lcd_cfg.xres = 1280; | 1111 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(ecovec_dvi_modes); |
1085 | lcdc_info.ch[0].lcd_cfg.yres = 720; | ||
1086 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
1087 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
1088 | lcdc_info.ch[0].lcd_cfg.hsync_len = 40; | ||
1089 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
1090 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
1091 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
1092 | 1112 | ||
1093 | gpio_set_value(GPIO_PTA2, 1); | 1113 | gpio_set_value(GPIO_PTA2, 1); |
1094 | gpio_set_value(GPIO_PTU1, 1); | 1114 | gpio_set_value(GPIO_PTU1, 1); |
1095 | } else { | 1115 | } else { |
1096 | /* Panel */ | 1116 | /* Panel */ |
1097 | |||
1098 | lcdc_info.clock_source = LCDC_CLK_PERIPHERAL; | 1117 | lcdc_info.clock_source = LCDC_CLK_PERIPHERAL; |
1099 | lcdc_info.ch[0].clock_divider = 2, | 1118 | lcdc_info.ch[0].clock_divider = 2; |
1100 | lcdc_info.ch[0].lcd_cfg.name = "Panel"; | 1119 | lcdc_info.ch[0].lcd_cfg = ecovec_lcd_modes; |
1101 | lcdc_info.ch[0].lcd_cfg.xres = 800; | 1120 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(ecovec_lcd_modes); |
1102 | lcdc_info.ch[0].lcd_cfg.yres = 480; | ||
1103 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
1104 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
1105 | lcdc_info.ch[0].lcd_cfg.hsync_len = 70; | ||
1106 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
1107 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
1108 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
1109 | 1121 | ||
1110 | gpio_set_value(GPIO_PTR1, 1); | 1122 | gpio_set_value(GPIO_PTR1, 1); |
1111 | 1123 | ||
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 68994a163f6c..87d4b90e368c 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c | |||
@@ -126,6 +126,21 @@ static struct platform_device kfr2r09_sh_keysc_device = { | |||
126 | }, | 126 | }, |
127 | }; | 127 | }; |
128 | 128 | ||
129 | const static struct fb_videomode kfr2r09_lcdc_modes[] = { | ||
130 | { | ||
131 | .name = "TX07D34VM0AAA", | ||
132 | .xres = 240, | ||
133 | .yres = 400, | ||
134 | .left_margin = 0, | ||
135 | .right_margin = 16, | ||
136 | .hsync_len = 8, | ||
137 | .upper_margin = 0, | ||
138 | .lower_margin = 1, | ||
139 | .vsync_len = 1, | ||
140 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
141 | }, | ||
142 | }; | ||
143 | |||
129 | static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { | 144 | static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { |
130 | .clock_source = LCDC_CLK_BUS, | 145 | .clock_source = LCDC_CLK_BUS, |
131 | .ch[0] = { | 146 | .ch[0] = { |
@@ -134,18 +149,8 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { | |||
134 | .interface_type = SYS18, | 149 | .interface_type = SYS18, |
135 | .clock_divider = 6, | 150 | .clock_divider = 6, |
136 | .flags = LCDC_FLAGS_DWPOL, | 151 | .flags = LCDC_FLAGS_DWPOL, |
137 | .lcd_cfg = { | 152 | .lcd_cfg = kfr2r09_lcdc_modes, |
138 | .name = "TX07D34VM0AAA", | 153 | .num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes), |
139 | .xres = 240, | ||
140 | .yres = 400, | ||
141 | .left_margin = 0, | ||
142 | .right_margin = 16, | ||
143 | .hsync_len = 8, | ||
144 | .upper_margin = 0, | ||
145 | .lower_margin = 1, | ||
146 | .vsync_len = 1, | ||
147 | .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, | ||
148 | }, | ||
149 | .lcd_size_cfg = { | 154 | .lcd_size_cfg = { |
150 | .width = 35, | 155 | .width = 35, |
151 | .height = 58, | 156 | .height = 58, |
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 662debe4ead2..9204cbb87147 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c | |||
@@ -213,51 +213,55 @@ static struct platform_device migor_nand_flash_device = { | |||
213 | } | 213 | } |
214 | }; | 214 | }; |
215 | 215 | ||
216 | const static struct fb_videomode migor_lcd_modes[] = { | ||
217 | { | ||
218 | #if defined(CONFIG_SH_MIGOR_RTA_WVGA) | ||
219 | .name = "LB070WV1", | ||
220 | .xres = 800, | ||
221 | .yres = 480, | ||
222 | .left_margin = 64, | ||
223 | .right_margin = 16, | ||
224 | .hsync_len = 120, | ||
225 | .sync = 0, | ||
226 | #elif defined(CONFIG_SH_MIGOR_QVGA) | ||
227 | .name = "PH240320T", | ||
228 | .xres = 320, | ||
229 | .yres = 240, | ||
230 | .left_margin = 0, | ||
231 | .right_margin = 16, | ||
232 | .hsync_len = 8, | ||
233 | .sync = FB_SYNC_HOR_HIGH_ACT, | ||
234 | #endif | ||
235 | .upper_margin = 1, | ||
236 | .lower_margin = 17, | ||
237 | .vsync_len = 2, | ||
238 | }, | ||
239 | }; | ||
240 | |||
216 | static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { | 241 | static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { |
217 | #ifdef CONFIG_SH_MIGOR_RTA_WVGA | 242 | #if defined(CONFIG_SH_MIGOR_RTA_WVGA) |
218 | .clock_source = LCDC_CLK_BUS, | 243 | .clock_source = LCDC_CLK_BUS, |
219 | .ch[0] = { | 244 | .ch[0] = { |
220 | .chan = LCDC_CHAN_MAINLCD, | 245 | .chan = LCDC_CHAN_MAINLCD, |
221 | .bpp = 16, | 246 | .bpp = 16, |
222 | .interface_type = RGB16, | 247 | .interface_type = RGB16, |
223 | .clock_divider = 2, | 248 | .clock_divider = 2, |
224 | .lcd_cfg = { | 249 | .lcd_cfg = migor_lcd_modes, |
225 | .name = "LB070WV1", | 250 | .num_cfg = ARRAY_SIZE(migor_lcd_modes), |
226 | .xres = 800, | ||
227 | .yres = 480, | ||
228 | .left_margin = 64, | ||
229 | .right_margin = 16, | ||
230 | .hsync_len = 120, | ||
231 | .upper_margin = 1, | ||
232 | .lower_margin = 17, | ||
233 | .vsync_len = 2, | ||
234 | .sync = 0, | ||
235 | }, | ||
236 | .lcd_size_cfg = { /* 7.0 inch */ | 251 | .lcd_size_cfg = { /* 7.0 inch */ |
237 | .width = 152, | 252 | .width = 152, |
238 | .height = 91, | 253 | .height = 91, |
239 | }, | 254 | }, |
240 | } | 255 | } |
241 | #endif | 256 | #elif defined(CONFIG_SH_MIGOR_QVGA) |
242 | #ifdef CONFIG_SH_MIGOR_QVGA | ||
243 | .clock_source = LCDC_CLK_PERIPHERAL, | 257 | .clock_source = LCDC_CLK_PERIPHERAL, |
244 | .ch[0] = { | 258 | .ch[0] = { |
245 | .chan = LCDC_CHAN_MAINLCD, | 259 | .chan = LCDC_CHAN_MAINLCD, |
246 | .bpp = 16, | 260 | .bpp = 16, |
247 | .interface_type = SYS16A, | 261 | .interface_type = SYS16A, |
248 | .clock_divider = 10, | 262 | .clock_divider = 10, |
249 | .lcd_cfg = { | 263 | .lcd_cfg = migor_lcd_modes, |
250 | .name = "PH240320T", | 264 | .num_cfg = ARRAY_SIZE(migor_lcd_modes), |
251 | .xres = 320, | ||
252 | .yres = 240, | ||
253 | .left_margin = 0, | ||
254 | .right_margin = 16, | ||
255 | .hsync_len = 8, | ||
256 | .upper_margin = 1, | ||
257 | .lower_margin = 17, | ||
258 | .vsync_len = 2, | ||
259 | .sync = FB_SYNC_HOR_HIGH_ACT, | ||
260 | }, | ||
261 | .lcd_size_cfg = { /* 2.4 inch */ | 265 | .lcd_size_cfg = { /* 2.4 inch */ |
262 | .width = 49, | 266 | .width = 49, |
263 | .height = 37, | 267 | .height = 37, |
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 552ebd9ba82b..fe208d6c8ed0 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c | |||
@@ -144,16 +144,42 @@ static struct platform_device nor_flash_device = { | |||
144 | }; | 144 | }; |
145 | 145 | ||
146 | /* LCDC */ | 146 | /* LCDC */ |
147 | const static struct fb_videomode lcdc_720p_modes[] = { | ||
148 | { | ||
149 | .name = "LB070WV1", | ||
150 | .sync = 0, /* hsync and vsync are active low */ | ||
151 | .xres = 1280, | ||
152 | .yres = 720, | ||
153 | .left_margin = 220, | ||
154 | .right_margin = 110, | ||
155 | .hsync_len = 40, | ||
156 | .upper_margin = 20, | ||
157 | .lower_margin = 5, | ||
158 | .vsync_len = 5, | ||
159 | }, | ||
160 | }; | ||
161 | |||
162 | const static struct fb_videomode lcdc_vga_modes[] = { | ||
163 | { | ||
164 | .name = "LB070WV1", | ||
165 | .sync = 0, /* hsync and vsync are active low */ | ||
166 | .xres = 640, | ||
167 | .yres = 480, | ||
168 | .left_margin = 105, | ||
169 | .right_margin = 50, | ||
170 | .hsync_len = 96, | ||
171 | .upper_margin = 33, | ||
172 | .lower_margin = 10, | ||
173 | .vsync_len = 2, | ||
174 | }, | ||
175 | }; | ||
176 | |||
147 | static struct sh_mobile_lcdc_info lcdc_info = { | 177 | static struct sh_mobile_lcdc_info lcdc_info = { |
148 | .clock_source = LCDC_CLK_EXTERNAL, | 178 | .clock_source = LCDC_CLK_EXTERNAL, |
149 | .ch[0] = { | 179 | .ch[0] = { |
150 | .chan = LCDC_CHAN_MAINLCD, | 180 | .chan = LCDC_CHAN_MAINLCD, |
151 | .bpp = 16, | 181 | .bpp = 16, |
152 | .clock_divider = 1, | 182 | .clock_divider = 1, |
153 | .lcd_cfg = { | ||
154 | .name = "LB070WV1", | ||
155 | .sync = 0, /* hsync and vsync are active low */ | ||
156 | }, | ||
157 | .lcd_size_cfg = { /* 7.0 inch */ | 183 | .lcd_size_cfg = { /* 7.0 inch */ |
158 | .width = 152, | 184 | .width = 152, |
159 | .height = 91, | 185 | .height = 91, |
@@ -909,24 +935,12 @@ static int __init devices_setup(void) | |||
909 | 935 | ||
910 | if (sw & SW41_B) { | 936 | if (sw & SW41_B) { |
911 | /* 720p */ | 937 | /* 720p */ |
912 | lcdc_info.ch[0].lcd_cfg.xres = 1280; | 938 | lcdc_info.ch[0].lcd_cfg = lcdc_720p_modes; |
913 | lcdc_info.ch[0].lcd_cfg.yres = 720; | 939 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(lcdc_720p_modes); |
914 | lcdc_info.ch[0].lcd_cfg.left_margin = 220; | ||
915 | lcdc_info.ch[0].lcd_cfg.right_margin = 110; | ||
916 | lcdc_info.ch[0].lcd_cfg.hsync_len = 40; | ||
917 | lcdc_info.ch[0].lcd_cfg.upper_margin = 20; | ||
918 | lcdc_info.ch[0].lcd_cfg.lower_margin = 5; | ||
919 | lcdc_info.ch[0].lcd_cfg.vsync_len = 5; | ||
920 | } else { | 940 | } else { |
921 | /* VGA */ | 941 | /* VGA */ |
922 | lcdc_info.ch[0].lcd_cfg.xres = 640; | 942 | lcdc_info.ch[0].lcd_cfg = lcdc_vga_modes; |
923 | lcdc_info.ch[0].lcd_cfg.yres = 480; | 943 | lcdc_info.ch[0].num_cfg = ARRAY_SIZE(lcdc_vga_modes); |
924 | lcdc_info.ch[0].lcd_cfg.left_margin = 105; | ||
925 | lcdc_info.ch[0].lcd_cfg.right_margin = 50; | ||
926 | lcdc_info.ch[0].lcd_cfg.hsync_len = 96; | ||
927 | lcdc_info.ch[0].lcd_cfg.upper_margin = 33; | ||
928 | lcdc_info.ch[0].lcd_cfg.lower_margin = 10; | ||
929 | lcdc_info.ch[0].lcd_cfg.vsync_len = 2; | ||
930 | } | 944 | } |
931 | 945 | ||
932 | if (sw & SW41_A) { | 946 | if (sw & SW41_A) { |
diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 5699ce0c1780..3f3d431033ca 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c | |||
@@ -123,83 +123,87 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
123 | u32 linelength; | 123 | u32 linelength; |
124 | bool yuv; | 124 | bool yuv; |
125 | 125 | ||
126 | /* Select data format */ | 126 | /* |
127 | * Select data format. MIPI DSI is not hot-pluggable, so, we just use | ||
128 | * the default videomode. If this ever becomes a problem, We'll have to | ||
129 | * move this to mipi_display_on() above and use info->var.xres | ||
130 | */ | ||
127 | switch (pdata->data_format) { | 131 | switch (pdata->data_format) { |
128 | case MIPI_RGB888: | 132 | case MIPI_RGB888: |
129 | pctype = 0; | 133 | pctype = 0; |
130 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 134 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
131 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 135 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
132 | linelength = ch->lcd_cfg.xres * 3; | 136 | linelength = ch->lcd_cfg[0].xres * 3; |
133 | yuv = false; | 137 | yuv = false; |
134 | break; | 138 | break; |
135 | case MIPI_RGB565: | 139 | case MIPI_RGB565: |
136 | pctype = 1; | 140 | pctype = 1; |
137 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 141 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
138 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 142 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
139 | linelength = ch->lcd_cfg.xres * 2; | 143 | linelength = ch->lcd_cfg[0].xres * 2; |
140 | yuv = false; | 144 | yuv = false; |
141 | break; | 145 | break; |
142 | case MIPI_RGB666_LP: | 146 | case MIPI_RGB666_LP: |
143 | pctype = 2; | 147 | pctype = 2; |
144 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 148 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
145 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 149 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
146 | linelength = ch->lcd_cfg.xres * 3; | 150 | linelength = ch->lcd_cfg[0].xres * 3; |
147 | yuv = false; | 151 | yuv = false; |
148 | break; | 152 | break; |
149 | case MIPI_RGB666: | 153 | case MIPI_RGB666: |
150 | pctype = 3; | 154 | pctype = 3; |
151 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 155 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
152 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 156 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
153 | linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; | 157 | linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; |
154 | yuv = false; | 158 | yuv = false; |
155 | break; | 159 | break; |
156 | case MIPI_BGR888: | 160 | case MIPI_BGR888: |
157 | pctype = 8; | 161 | pctype = 8; |
158 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 162 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; |
159 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 163 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
160 | linelength = ch->lcd_cfg.xres * 3; | 164 | linelength = ch->lcd_cfg[0].xres * 3; |
161 | yuv = false; | 165 | yuv = false; |
162 | break; | 166 | break; |
163 | case MIPI_BGR565: | 167 | case MIPI_BGR565: |
164 | pctype = 9; | 168 | pctype = 9; |
165 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 169 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; |
166 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 170 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
167 | linelength = ch->lcd_cfg.xres * 2; | 171 | linelength = ch->lcd_cfg[0].xres * 2; |
168 | yuv = false; | 172 | yuv = false; |
169 | break; | 173 | break; |
170 | case MIPI_BGR666_LP: | 174 | case MIPI_BGR666_LP: |
171 | pctype = 0xa; | 175 | pctype = 0xa; |
172 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 176 | datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; |
173 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; | 177 | pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; |
174 | linelength = ch->lcd_cfg.xres * 3; | 178 | linelength = ch->lcd_cfg[0].xres * 3; |
175 | yuv = false; | 179 | yuv = false; |
176 | break; | 180 | break; |
177 | case MIPI_BGR666: | 181 | case MIPI_BGR666: |
178 | pctype = 0xb; | 182 | pctype = 0xb; |
179 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 183 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; |
180 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; | 184 | pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; |
181 | linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; | 185 | linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; |
182 | yuv = false; | 186 | yuv = false; |
183 | break; | 187 | break; |
184 | case MIPI_YUYV: | 188 | case MIPI_YUYV: |
185 | pctype = 4; | 189 | pctype = 4; |
186 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 190 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
187 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 191 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
188 | linelength = ch->lcd_cfg.xres * 2; | 192 | linelength = ch->lcd_cfg[0].xres * 2; |
189 | yuv = true; | 193 | yuv = true; |
190 | break; | 194 | break; |
191 | case MIPI_UYVY: | 195 | case MIPI_UYVY: |
192 | pctype = 5; | 196 | pctype = 5; |
193 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; | 197 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; |
194 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; | 198 | pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; |
195 | linelength = ch->lcd_cfg.xres * 2; | 199 | linelength = ch->lcd_cfg[0].xres * 2; |
196 | yuv = true; | 200 | yuv = true; |
197 | break; | 201 | break; |
198 | case MIPI_YUV420_L: | 202 | case MIPI_YUV420_L: |
199 | pctype = 6; | 203 | pctype = 6; |
200 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 204 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
201 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 205 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
202 | linelength = (ch->lcd_cfg.xres * 12 + 7) / 8; | 206 | linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8; |
203 | yuv = true; | 207 | yuv = true; |
204 | break; | 208 | break; |
205 | case MIPI_YUV420: | 209 | case MIPI_YUV420: |
@@ -207,7 +211,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
207 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; | 211 | datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; |
208 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; | 212 | pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; |
209 | /* Length of U/V line */ | 213 | /* Length of U/V line */ |
210 | linelength = (ch->lcd_cfg.xres + 1) / 2; | 214 | linelength = (ch->lcd_cfg[0].xres + 1) / 2; |
211 | yuv = true; | 215 | yuv = true; |
212 | break; | 216 | break; |
213 | default: | 217 | default: |
@@ -281,7 +285,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, | |||
281 | iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ | 285 | iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ |
282 | /* | 286 | /* |
283 | * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see | 287 | * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see |
284 | * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default | 288 | * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default |
285 | * (unused, since VMCTR2[HSABM] = 0) | 289 | * (unused, since VMCTR2[HSABM] = 0) |
286 | */ | 290 | */ |
287 | iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ | 291 | iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ |
diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index ef989d94511c..55b3077ff6ff 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <video/sh_mobile_hdmi.h> | 28 | #include <video/sh_mobile_hdmi.h> |
29 | #include <video/sh_mobile_lcdc.h> | 29 | #include <video/sh_mobile_lcdc.h> |
30 | 30 | ||
31 | #include "sh_mobile_lcdcfb.h" | ||
32 | |||
31 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ | 33 | #define HDMI_SYSTEM_CTRL 0x00 /* System control */ |
32 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, | 34 | #define HDMI_L_R_DATA_SWAP_CTRL_RPKT 0x01 /* L/R data swap control, |
33 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ | 35 | bits 19..16 of 20-bit N for Audio Clock Regeneration packet */ |
@@ -206,12 +208,15 @@ enum hotplug_state { | |||
206 | 208 | ||
207 | struct sh_hdmi { | 209 | struct sh_hdmi { |
208 | void __iomem *base; | 210 | void __iomem *base; |
209 | enum hotplug_state hp_state; | 211 | enum hotplug_state hp_state; /* hot-plug status */ |
212 | bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ | ||
210 | struct clk *hdmi_clk; | 213 | struct clk *hdmi_clk; |
211 | struct device *dev; | 214 | struct device *dev; |
212 | struct fb_info *info; | 215 | struct fb_info *info; |
216 | struct mutex mutex; /* Protect the info pointer */ | ||
213 | struct delayed_work edid_work; | 217 | struct delayed_work edid_work; |
214 | struct fb_var_screeninfo var; | 218 | struct fb_var_screeninfo var; |
219 | struct fb_monspecs monspec; | ||
215 | }; | 220 | }; |
216 | 221 | ||
217 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) | 222 | static void hdmi_write(struct sh_hdmi *hdmi, u8 data, u8 reg) |
@@ -277,7 +282,7 @@ static struct snd_soc_codec_driver soc_codec_dev_sh_hdmi = { | |||
277 | */ | 282 | */ |
278 | 283 | ||
279 | /* External video parameter settings */ | 284 | /* External video parameter settings */ |
280 | static void hdmi_external_video_param(struct sh_hdmi *hdmi) | 285 | static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) |
281 | { | 286 | { |
282 | struct fb_var_screeninfo *var = &hdmi->var; | 287 | struct fb_var_screeninfo *var = &hdmi->var; |
283 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; | 288 | u16 htotal, hblank, hdelay, vtotal, vblank, vdelay, voffset; |
@@ -309,9 +314,9 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
309 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) | 314 | if (var->sync & FB_SYNC_VERT_HIGH_ACT) |
310 | sync |= 8; | 315 | sync |= 8; |
311 | 316 | ||
312 | pr_debug("H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", | 317 | dev_dbg(hdmi->dev, "H: %u, %u, %u, %u; V: %u, %u, %u, %u; sync 0x%x\n", |
313 | htotal, hblank, hdelay, var->hsync_len, | 318 | htotal, hblank, hdelay, var->hsync_len, |
314 | vtotal, vblank, vdelay, var->vsync_len, sync); | 319 | vtotal, vblank, vdelay, var->vsync_len, sync); |
315 | 320 | ||
316 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); | 321 | hdmi_write(hdmi, sync | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); |
317 | 322 | ||
@@ -336,7 +341,10 @@ static void hdmi_external_video_param(struct sh_hdmi *hdmi) | |||
336 | 341 | ||
337 | hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); | 342 | hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); |
338 | 343 | ||
339 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for manual mode */ | 344 | /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ |
345 | if (!hdmi->preprogrammed_mode) | ||
346 | hdmi_write(hdmi, sync | 1 | (voffset << 4), | ||
347 | HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); | ||
340 | } | 348 | } |
341 | 349 | ||
342 | /** | 350 | /** |
@@ -454,21 +462,61 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) | |||
454 | } | 462 | } |
455 | 463 | ||
456 | /** | 464 | /** |
457 | * sh_hdmi_phy_config() | 465 | * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode |
458 | */ | 466 | */ |
459 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | 467 | static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) |
460 | { | 468 | { |
461 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ | 469 | if (hdmi->var.yres > 480) { |
462 | hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); | 470 | /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ |
463 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | 471 | /* |
464 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | 472 | * [1:0] Speed_A |
465 | /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ | 473 | * [3:2] Speed_B |
466 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | 474 | * [4] PLLA_Bypass |
467 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | 475 | * [6] DRV_TEST_EN |
468 | hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | 476 | * [7] DRV_TEST_IN |
469 | hdmi_write(hdmi, 0x0E, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | 477 | */ |
470 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | 478 | hdmi_write(hdmi, 0x0f, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); |
471 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | 479 | /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */ |
480 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | ||
481 | /* | ||
482 | * [2:0] BGR_I_OFFSET | ||
483 | * [6:4] BGR_V_OFFSET | ||
484 | */ | ||
485 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | ||
486 | /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ | ||
487 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | ||
488 | /* | ||
489 | * PLLA_CONFIG[15:8]: regulator voltage[0], CP current, | ||
490 | * LPF capacitance, LPF resistance[1] | ||
491 | */ | ||
492 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | ||
493 | /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */ | ||
494 | hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | ||
495 | /* | ||
496 | * PLLB_CONFIG[15:8]: regulator voltage[0], CP current, | ||
497 | * LPF capacitance, LPF resistance[1] | ||
498 | */ | ||
499 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | ||
500 | /* DRV_CONFIG, PE_CONFIG */ | ||
501 | hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | ||
502 | /* | ||
503 | * [2:0] AMON_SEL (4 == LPF voltage) | ||
504 | * [4] PLLA_CONFIG[16] | ||
505 | * [5] PLLB_CONFIG[16] | ||
506 | */ | ||
507 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | ||
508 | } else { | ||
509 | /* for 480p8bit 27MHz */ | ||
510 | hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); | ||
511 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); | ||
512 | hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); | ||
513 | hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); | ||
514 | hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); | ||
515 | hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); | ||
516 | hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); | ||
517 | hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); | ||
518 | hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); | ||
519 | } | ||
472 | } | 520 | } |
473 | 521 | ||
474 | /** | 522 | /** |
@@ -476,6 +524,8 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) | |||
476 | */ | 524 | */ |
477 | static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | 525 | static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) |
478 | { | 526 | { |
527 | u8 vic; | ||
528 | |||
479 | /* AVI InfoFrame */ | 529 | /* AVI InfoFrame */ |
480 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); | 530 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); |
481 | 531 | ||
@@ -500,9 +550,9 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | |||
500 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); | 550 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB1); |
501 | 551 | ||
502 | /* | 552 | /* |
503 | * C = No Data | 553 | * [7:6] C = Colorimetry: no data |
504 | * M = 16:9 Picture Aspect Ratio | 554 | * [5:4] M = 2: 16:9, 1: 4:3 Picture Aspect Ratio |
505 | * R = Same as picture aspect ratio | 555 | * [3:0] R = 8: Active Frame Aspect Ratio: same as picture aspect ratio |
506 | */ | 556 | */ |
507 | hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); | 557 | hdmi_write(hdmi, 0x28, HDMI_CTRL_PKT_BUF_ACCESS_PB2); |
508 | 558 | ||
@@ -516,9 +566,15 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) | |||
516 | 566 | ||
517 | /* | 567 | /* |
518 | * VIC = 1280 x 720p: ignored if external config is used | 568 | * VIC = 1280 x 720p: ignored if external config is used |
519 | * Send 2 for 720 x 480p, 16 for 1080p | 569 | * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode |
520 | */ | 570 | */ |
521 | hdmi_write(hdmi, 4, HDMI_CTRL_PKT_BUF_ACCESS_PB4); | 571 | if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) |
572 | vic = 16; | ||
573 | else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) | ||
574 | vic = 2; | ||
575 | else | ||
576 | vic = 4; | ||
577 | hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); | ||
522 | 578 | ||
523 | /* PR = No Repetition */ | 579 | /* PR = No Repetition */ |
524 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); | 580 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); |
@@ -592,100 +648,6 @@ static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) | |||
592 | } | 648 | } |
593 | 649 | ||
594 | /** | 650 | /** |
595 | * sh_hdmi_gamut_metadata_setup() - Gamut Metadata Packet of CONTROL PACKET | ||
596 | */ | ||
597 | static void sh_hdmi_gamut_metadata_setup(struct sh_hdmi *hdmi) | ||
598 | { | ||
599 | int i; | ||
600 | |||
601 | /* Gamut Metadata Packet */ | ||
602 | hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_INDEX); | ||
603 | |||
604 | /* Packet Type = 0x0A */ | ||
605 | hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
606 | /* Gamut Packet is not used, so default value */ | ||
607 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
608 | /* Gamut Packet is not used, so default value */ | ||
609 | hdmi_write(hdmi, 0x10, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
610 | |||
611 | /* GBD bytes 0 through 27 */ | ||
612 | for (i = 0; i <= 27; i++) | ||
613 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0_63H - PB27_7EH */ | ||
614 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
615 | } | ||
616 | |||
617 | /** | ||
618 | * sh_hdmi_acp_setup() - Audio Content Protection Packet (ACP) | ||
619 | */ | ||
620 | static void sh_hdmi_acp_setup(struct sh_hdmi *hdmi) | ||
621 | { | ||
622 | int i; | ||
623 | |||
624 | /* Audio Content Protection Packet (ACP) */ | ||
625 | hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_INDEX); | ||
626 | |||
627 | /* Packet Type = 0x04 */ | ||
628 | hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
629 | /* ACP_Type */ | ||
630 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
631 | /* Reserved (0) */ | ||
632 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
633 | |||
634 | /* GBD bytes 0 through 27 */ | ||
635 | for (i = 0; i <= 27; i++) | ||
636 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
637 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
638 | } | ||
639 | |||
640 | /** | ||
641 | * sh_hdmi_isrc1_setup() - ISRC1 Packet | ||
642 | */ | ||
643 | static void sh_hdmi_isrc1_setup(struct sh_hdmi *hdmi) | ||
644 | { | ||
645 | int i; | ||
646 | |||
647 | /* ISRC1 Packet */ | ||
648 | hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_INDEX); | ||
649 | |||
650 | /* Packet Type = 0x05 */ | ||
651 | hdmi_write(hdmi, 0x05, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
652 | /* ISRC_Cont, ISRC_Valid, Reserved (0), ISRC_Status */ | ||
653 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
654 | /* Reserved (0) */ | ||
655 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
656 | |||
657 | /* PB0 UPC_EAN_ISRC_0-15 */ | ||
658 | /* Bytes PB16-PB27 shall be set to a value of 0. */ | ||
659 | for (i = 0; i <= 27; i++) | ||
660 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
661 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
662 | } | ||
663 | |||
664 | /** | ||
665 | * sh_hdmi_isrc2_setup() - ISRC2 Packet | ||
666 | */ | ||
667 | static void sh_hdmi_isrc2_setup(struct sh_hdmi *hdmi) | ||
668 | { | ||
669 | int i; | ||
670 | |||
671 | /* ISRC2 Packet */ | ||
672 | hdmi_write(hdmi, 0x03, HDMI_CTRL_PKT_BUF_INDEX); | ||
673 | |||
674 | /* HB0 Packet Type = 0x06 */ | ||
675 | hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_ACCESS_HB0); | ||
676 | /* Reserved (0) */ | ||
677 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); | ||
678 | /* Reserved (0) */ | ||
679 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); | ||
680 | |||
681 | /* PB0 UPC_EAN_ISRC_16-31 */ | ||
682 | /* Bytes PB16-PB27 shall be set to a value of 0. */ | ||
683 | for (i = 0; i <= 27; i++) | ||
684 | /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ | ||
685 | hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); | ||
686 | } | ||
687 | |||
688 | /** | ||
689 | * sh_hdmi_configure() - Initialise HDMI for output | 651 | * sh_hdmi_configure() - Initialise HDMI for output |
690 | */ | 652 | */ |
691 | static void sh_hdmi_configure(struct sh_hdmi *hdmi) | 653 | static void sh_hdmi_configure(struct sh_hdmi *hdmi) |
@@ -705,18 +667,6 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) | |||
705 | /* Audio InfoFrame */ | 667 | /* Audio InfoFrame */ |
706 | sh_hdmi_audio_infoframe_setup(hdmi); | 668 | sh_hdmi_audio_infoframe_setup(hdmi); |
707 | 669 | ||
708 | /* Gamut Metadata packet */ | ||
709 | sh_hdmi_gamut_metadata_setup(hdmi); | ||
710 | |||
711 | /* Audio Content Protection (ACP) Packet */ | ||
712 | sh_hdmi_acp_setup(hdmi); | ||
713 | |||
714 | /* ISRC1 Packet */ | ||
715 | sh_hdmi_isrc1_setup(hdmi); | ||
716 | |||
717 | /* ISRC2 Packet */ | ||
718 | sh_hdmi_isrc2_setup(hdmi); | ||
719 | |||
720 | /* | 670 | /* |
721 | * Control packet auto send with VSYNC control: auto send | 671 | * Control packet auto send with VSYNC control: auto send |
722 | * General control, Gamut metadata, ISRC, and ACP packets | 672 | * General control, Gamut metadata, ISRC, and ACP packets |
@@ -734,17 +684,42 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) | |||
734 | hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); | 684 | hdmi_write(hdmi, 0x40, HDMI_SYSTEM_CTRL); |
735 | } | 685 | } |
736 | 686 | ||
737 | static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) | 687 | static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, |
688 | const struct fb_videomode *mode) | ||
738 | { | 689 | { |
739 | struct fb_var_screeninfo *var = &hdmi->var; | 690 | long target = PICOS2KHZ(mode->pixclock) * 1000, |
740 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 691 | rate = clk_round_rate(hdmi->hdmi_clk, target); |
741 | struct fb_videomode *lcd_cfg = &pdata->lcd_chan->lcd_cfg; | 692 | unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; |
742 | unsigned long height = var->height, width = var->width; | 693 | |
743 | int i; | 694 | dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", |
695 | mode->left_margin, mode->xres, | ||
696 | mode->right_margin, mode->hsync_len, | ||
697 | mode->upper_margin, mode->yres, | ||
698 | mode->lower_margin, mode->vsync_len); | ||
699 | |||
700 | dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, | ||
701 | rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, | ||
702 | mode->refresh); | ||
703 | |||
704 | return rate_error; | ||
705 | } | ||
706 | |||
707 | static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) | ||
708 | { | ||
709 | struct fb_var_screeninfo tmpvar; | ||
710 | struct fb_var_screeninfo *var = &tmpvar; | ||
711 | const struct fb_videomode *mode, *found = NULL; | ||
712 | struct fb_info *info = hdmi->info; | ||
713 | struct fb_modelist *modelist = NULL; | ||
714 | unsigned int f_width = 0, f_height = 0, f_refresh = 0; | ||
715 | unsigned long found_rate_error = ULONG_MAX; /* silly compiler... */ | ||
716 | bool exact_match = false; | ||
744 | u8 edid[128]; | 717 | u8 edid[128]; |
718 | char *forced; | ||
719 | int i; | ||
745 | 720 | ||
746 | /* Read EDID */ | 721 | /* Read EDID */ |
747 | pr_debug("Read back EDID code:"); | 722 | dev_dbg(hdmi->dev, "Read back EDID code:"); |
748 | for (i = 0; i < 128; i++) { | 723 | for (i = 0; i < 128; i++) { |
749 | edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); | 724 | edid[i] = hdmi_read(hdmi, HDMI_EDID_KSV_FIFO_ACCESS_WINDOW); |
750 | #ifdef DEBUG | 725 | #ifdef DEBUG |
@@ -759,29 +734,97 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) | |||
759 | #ifdef DEBUG | 734 | #ifdef DEBUG |
760 | printk(KERN_CONT "\n"); | 735 | printk(KERN_CONT "\n"); |
761 | #endif | 736 | #endif |
762 | fb_parse_edid(edid, var); | 737 | |
763 | pr_debug("%u-%u-%u-%u x %u-%u-%u-%u @ %lu kHz monitor detected\n", | 738 | fb_edid_to_monspecs(edid, &hdmi->monspec); |
764 | var->left_margin, var->xres, var->right_margin, var->hsync_len, | 739 | |
765 | var->upper_margin, var->yres, var->lower_margin, var->vsync_len, | 740 | fb_get_options("sh_mobile_lcdc", &forced); |
766 | PICOS2KHZ(var->pixclock)); | 741 | if (forced && *forced) { |
767 | 742 | /* Only primitive parsing so far */ | |
768 | /* FIXME: Use user-provided configuration instead of EDID */ | 743 | i = sscanf(forced, "%ux%u@%u", |
769 | var->width = width; | 744 | &f_width, &f_height, &f_refresh); |
770 | var->xres = lcd_cfg->xres; | 745 | if (i < 2) { |
771 | var->xres_virtual = lcd_cfg->xres; | 746 | f_width = 0; |
772 | var->left_margin = lcd_cfg->left_margin; | 747 | f_height = 0; |
773 | var->right_margin = lcd_cfg->right_margin; | 748 | } |
774 | var->hsync_len = lcd_cfg->hsync_len; | 749 | dev_dbg(hdmi->dev, "Forced mode %ux%u@%uHz\n", |
775 | var->height = height; | 750 | f_width, f_height, f_refresh); |
776 | var->yres = lcd_cfg->yres; | 751 | } |
777 | var->yres_virtual = lcd_cfg->yres * 2; | 752 | |
778 | var->upper_margin = lcd_cfg->upper_margin; | 753 | /* Walk monitor modes to find the best or the exact match */ |
779 | var->lower_margin = lcd_cfg->lower_margin; | 754 | for (i = 0, mode = hdmi->monspec.modedb; |
780 | var->vsync_len = lcd_cfg->vsync_len; | 755 | f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; |
781 | var->sync = lcd_cfg->sync; | 756 | i++, mode++) { |
782 | var->pixclock = lcd_cfg->pixclock; | 757 | unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); |
783 | 758 | ||
784 | hdmi_external_video_param(hdmi); | 759 | /* No interest in unmatching modes */ |
760 | if (f_width != mode->xres || f_height != mode->yres) | ||
761 | continue; | ||
762 | if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) | ||
763 | /* | ||
764 | * Exact match if either the refresh rate matches or it | ||
765 | * hasn't been specified and we've found a mode, for | ||
766 | * which we can configure the clock precisely | ||
767 | */ | ||
768 | exact_match = true; | ||
769 | else if (found && found_rate_error <= rate_error) | ||
770 | /* | ||
771 | * We otherwise search for the closest matching clock | ||
772 | * rate - either if no refresh rate has been specified | ||
773 | * or we cannot find an exactly matching one | ||
774 | */ | ||
775 | continue; | ||
776 | |||
777 | /* Check if supported: sufficient fb memory, supported clock-rate */ | ||
778 | fb_videomode_to_var(var, mode); | ||
779 | |||
780 | if (info && info->fbops->fb_check_var && | ||
781 | info->fbops->fb_check_var(var, info)) { | ||
782 | exact_match = false; | ||
783 | continue; | ||
784 | } | ||
785 | |||
786 | found = mode; | ||
787 | found_rate_error = rate_error; | ||
788 | } | ||
789 | |||
790 | /* | ||
791 | * TODO 1: if no ->info is present, postpone running the config until | ||
792 | * after ->info first gets registered. | ||
793 | * TODO 2: consider registering the HDMI platform device from the LCDC | ||
794 | * driver, and passing ->info with HDMI platform data. | ||
795 | */ | ||
796 | if (info && !found) { | ||
797 | modelist = hdmi->info->modelist.next && | ||
798 | !list_empty(&hdmi->info->modelist) ? | ||
799 | list_entry(hdmi->info->modelist.next, | ||
800 | struct fb_modelist, list) : | ||
801 | NULL; | ||
802 | |||
803 | if (modelist) { | ||
804 | found = &modelist->mode; | ||
805 | found_rate_error = sh_hdmi_rate_error(hdmi, found); | ||
806 | } | ||
807 | } | ||
808 | |||
809 | /* No cookie today */ | ||
810 | if (!found) | ||
811 | return -ENXIO; | ||
812 | |||
813 | dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", | ||
814 | modelist ? "default" : "EDID", found->xres, found->yres, | ||
815 | found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); | ||
816 | |||
817 | if ((found->xres == 720 && found->yres == 480) || | ||
818 | (found->xres == 1280 && found->yres == 720) || | ||
819 | (found->xres == 1920 && found->yres == 1080)) | ||
820 | hdmi->preprogrammed_mode = true; | ||
821 | else | ||
822 | hdmi->preprogrammed_mode = false; | ||
823 | |||
824 | fb_videomode_to_var(&hdmi->var, found); | ||
825 | sh_hdmi_external_video_param(hdmi); | ||
826 | |||
827 | return 0; | ||
785 | } | 828 | } |
786 | 829 | ||
787 | static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | 830 | static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) |
@@ -809,8 +852,8 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
809 | hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); | 852 | hdmi_write(hdmi, 0xFF, HDMI_INTERRUPT_STATUS_2); |
810 | 853 | ||
811 | if (printk_ratelimit()) | 854 | if (printk_ratelimit()) |
812 | pr_debug("IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", | 855 | dev_dbg(hdmi->dev, "IRQ #%d: Status #1: 0x%x & 0x%x, #2: 0x%x & 0x%x\n", |
813 | irq, status1, mask1, status2, mask2); | 856 | irq, status1, mask1, status2, mask2); |
814 | 857 | ||
815 | if (!((status1 & mask1) | (status2 & mask2))) { | 858 | if (!((status1 & mask1) | (status2 & mask2))) { |
816 | return IRQ_NONE; | 859 | return IRQ_NONE; |
@@ -821,7 +864,7 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
821 | udelay(500); | 864 | udelay(500); |
822 | 865 | ||
823 | msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); | 866 | msens = hdmi_read(hdmi, HDMI_HOT_PLUG_MSENS_STATUS); |
824 | pr_debug("MSENS 0x%x\n", msens); | 867 | dev_dbg(hdmi->dev, "MSENS 0x%x\n", msens); |
825 | /* Check, if hot plug & MSENS pin status are both high */ | 868 | /* Check, if hot plug & MSENS pin status are both high */ |
826 | if ((msens & 0xC0) == 0xC0) { | 869 | if ((msens & 0xC0) == 0xC0) { |
827 | /* Display plug in */ | 870 | /* Display plug in */ |
@@ -857,83 +900,176 @@ static irqreturn_t sh_hdmi_hotplug(int irq, void *dev_id) | |||
857 | return IRQ_HANDLED; | 900 | return IRQ_HANDLED; |
858 | } | 901 | } |
859 | 902 | ||
860 | static void hdmi_display_on(void *arg, struct fb_info *info) | 903 | /* locking: called with info->lock held, or before register_framebuffer() */ |
904 | static void sh_hdmi_display_on(void *arg, struct fb_info *info) | ||
861 | { | 905 | { |
906 | /* | ||
907 | * info is guaranteed to be valid, when we are called, because our | ||
908 | * FB_EVENT_FB_UNBIND notify is also called with info->lock held | ||
909 | */ | ||
862 | struct sh_hdmi *hdmi = arg; | 910 | struct sh_hdmi *hdmi = arg; |
863 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 911 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; |
912 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
864 | 913 | ||
865 | if (info->var.xres != 1280 || info->var.yres != 720) { | 914 | dev_dbg(hdmi->dev, "%s(%p): state %x\n", __func__, |
866 | dev_warn(info->device, "Unsupported framebuffer geometry %ux%u\n", | 915 | pdata->lcd_dev, info->state); |
867 | info->var.xres, info->var.yres); | 916 | |
868 | return; | 917 | /* No need to lock */ |
869 | } | 918 | hdmi->info = info; |
870 | 919 | ||
871 | pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); | ||
872 | /* | 920 | /* |
873 | * FIXME: not a good place to store fb_info. And we cannot nullify it | 921 | * hp_state can be set to |
874 | * even on monitor disconnect. What should the lifecycle be? | 922 | * HDMI_HOTPLUG_DISCONNECTED: on monitor unplug |
923 | * HDMI_HOTPLUG_CONNECTED: on monitor plug-in | ||
924 | * HDMI_HOTPLUG_EDID_DONE: on EDID read completion | ||
875 | */ | 925 | */ |
876 | hdmi->info = info; | ||
877 | switch (hdmi->hp_state) { | 926 | switch (hdmi->hp_state) { |
878 | case HDMI_HOTPLUG_EDID_DONE: | 927 | case HDMI_HOTPLUG_EDID_DONE: |
879 | /* PS mode d->e. All functions are active */ | 928 | /* PS mode d->e. All functions are active */ |
880 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); | 929 | hdmi_write(hdmi, 0x80, HDMI_SYSTEM_CTRL); |
881 | pr_debug("HDMI running\n"); | 930 | dev_dbg(hdmi->dev, "HDMI running\n"); |
882 | break; | 931 | break; |
883 | case HDMI_HOTPLUG_DISCONNECTED: | 932 | case HDMI_HOTPLUG_DISCONNECTED: |
884 | info->state = FBINFO_STATE_SUSPENDED; | 933 | info->state = FBINFO_STATE_SUSPENDED; |
885 | default: | 934 | default: |
886 | hdmi->var = info->var; | 935 | hdmi->var = ch->display_var; |
887 | } | 936 | } |
888 | } | 937 | } |
889 | 938 | ||
890 | static void hdmi_display_off(void *arg) | 939 | /* locking: called with info->lock held */ |
940 | static void sh_hdmi_display_off(void *arg) | ||
891 | { | 941 | { |
892 | struct sh_hdmi *hdmi = arg; | 942 | struct sh_hdmi *hdmi = arg; |
893 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 943 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; |
894 | 944 | ||
895 | pr_debug("%s(%p)\n", __func__, pdata->lcd_dev); | 945 | dev_dbg(hdmi->dev, "%s(%p)\n", __func__, pdata->lcd_dev); |
896 | /* PS mode e->a */ | 946 | /* PS mode e->a */ |
897 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); | 947 | hdmi_write(hdmi, 0x10, HDMI_SYSTEM_CTRL); |
898 | } | 948 | } |
899 | 949 | ||
950 | static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) | ||
951 | { | ||
952 | struct fb_info *info = hdmi->info; | ||
953 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
954 | struct fb_var_screeninfo *new_var = &hdmi->var, *old_var = &ch->display_var; | ||
955 | struct fb_videomode mode1, mode2; | ||
956 | |||
957 | fb_var_to_videomode(&mode1, old_var); | ||
958 | fb_var_to_videomode(&mode2, new_var); | ||
959 | |||
960 | dev_dbg(info->dev, "Old %ux%u, new %ux%u\n", | ||
961 | mode1.xres, mode1.yres, mode2.xres, mode2.yres); | ||
962 | |||
963 | if (fb_mode_is_equal(&mode1, &mode2)) | ||
964 | return false; | ||
965 | |||
966 | dev_dbg(info->dev, "Switching %u -> %u lines\n", | ||
967 | mode1.yres, mode2.yres); | ||
968 | *old_var = *new_var; | ||
969 | |||
970 | return true; | ||
971 | } | ||
972 | |||
973 | /** | ||
974 | * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock | ||
975 | * @hdmi: driver context | ||
976 | * @pixclock: pixel clock period in picoseconds | ||
977 | * return: configured positive rate if successful | ||
978 | * 0 if couldn't set the rate, but managed to enable the clock | ||
979 | * negative error, if couldn't enable the clock | ||
980 | */ | ||
981 | static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) | ||
982 | { | ||
983 | long rate; | ||
984 | int ret; | ||
985 | |||
986 | rate = PICOS2KHZ(pixclock) * 1000; | ||
987 | rate = clk_round_rate(hdmi->hdmi_clk, rate); | ||
988 | if (rate > 0) { | ||
989 | ret = clk_set_rate(hdmi->hdmi_clk, rate); | ||
990 | if (ret < 0) { | ||
991 | dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); | ||
992 | rate = 0; | ||
993 | } else { | ||
994 | dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); | ||
995 | } | ||
996 | } else { | ||
997 | rate = 0; | ||
998 | dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); | ||
999 | } | ||
1000 | |||
1001 | ret = clk_enable(hdmi->hdmi_clk); | ||
1002 | if (ret < 0) { | ||
1003 | dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); | ||
1004 | return ret; | ||
1005 | } | ||
1006 | |||
1007 | return rate; | ||
1008 | } | ||
1009 | |||
900 | /* Hotplug interrupt occurred, read EDID */ | 1010 | /* Hotplug interrupt occurred, read EDID */ |
901 | static void edid_work_fn(struct work_struct *work) | 1011 | static void sh_hdmi_edid_work_fn(struct work_struct *work) |
902 | { | 1012 | { |
903 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); | 1013 | struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work); |
904 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; | 1014 | struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; |
1015 | struct sh_mobile_lcdc_chan *ch; | ||
1016 | int ret; | ||
905 | 1017 | ||
906 | pr_debug("%s(%p): begin, hotplug status %d\n", __func__, | 1018 | dev_dbg(hdmi->dev, "%s(%p): begin, hotplug status %d\n", __func__, |
907 | pdata->lcd_dev, hdmi->hp_state); | 1019 | pdata->lcd_dev, hdmi->hp_state); |
908 | 1020 | ||
909 | if (!pdata->lcd_dev) | 1021 | if (!pdata->lcd_dev) |
910 | return; | 1022 | return; |
911 | 1023 | ||
1024 | mutex_lock(&hdmi->mutex); | ||
1025 | |||
912 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { | 1026 | if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { |
913 | pm_runtime_get_sync(hdmi->dev); | ||
914 | /* A device has been plugged in */ | 1027 | /* A device has been plugged in */ |
915 | sh_hdmi_read_edid(hdmi); | 1028 | pm_runtime_get_sync(hdmi->dev); |
1029 | |||
1030 | ret = sh_hdmi_read_edid(hdmi); | ||
1031 | if (ret < 0) | ||
1032 | goto out; | ||
1033 | |||
1034 | /* Reconfigure the clock */ | ||
1035 | clk_disable(hdmi->hdmi_clk); | ||
1036 | ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); | ||
1037 | if (ret < 0) | ||
1038 | goto out; | ||
1039 | |||
916 | msleep(10); | 1040 | msleep(10); |
917 | sh_hdmi_configure(hdmi); | 1041 | sh_hdmi_configure(hdmi); |
918 | /* Switched to another (d) power-save mode */ | 1042 | /* Switched to another (d) power-save mode */ |
919 | msleep(10); | 1043 | msleep(10); |
920 | 1044 | ||
921 | if (!hdmi->info) | 1045 | if (!hdmi->info) |
922 | return; | 1046 | goto out; |
1047 | |||
1048 | ch = hdmi->info->par; | ||
923 | 1049 | ||
924 | acquire_console_sem(); | 1050 | acquire_console_sem(); |
925 | 1051 | ||
926 | /* HDMI plug in */ | 1052 | /* HDMI plug in */ |
927 | hdmi->info->var = hdmi->var; | 1053 | if (!sh_hdmi_must_reconfigure(hdmi) && |
928 | if (hdmi->info->state != FBINFO_STATE_RUNNING) | 1054 | hdmi->info->state == FBINFO_STATE_RUNNING) { |
1055 | /* | ||
1056 | * First activation with the default monitor - just turn | ||
1057 | * on, if we run a resume here, the logo disappears | ||
1058 | */ | ||
1059 | if (lock_fb_info(hdmi->info)) { | ||
1060 | sh_hdmi_display_on(hdmi, hdmi->info); | ||
1061 | unlock_fb_info(hdmi->info); | ||
1062 | } | ||
1063 | } else { | ||
1064 | /* New monitor or have to wake up */ | ||
929 | fb_set_suspend(hdmi->info, 0); | 1065 | fb_set_suspend(hdmi->info, 0); |
930 | else | 1066 | } |
931 | hdmi_display_on(hdmi, hdmi->info); | ||
932 | 1067 | ||
933 | release_console_sem(); | 1068 | release_console_sem(); |
934 | } else { | 1069 | } else { |
1070 | ret = 0; | ||
935 | if (!hdmi->info) | 1071 | if (!hdmi->info) |
936 | return; | 1072 | goto out; |
937 | 1073 | ||
938 | acquire_console_sem(); | 1074 | acquire_console_sem(); |
939 | 1075 | ||
@@ -942,15 +1078,67 @@ static void edid_work_fn(struct work_struct *work) | |||
942 | 1078 | ||
943 | release_console_sem(); | 1079 | release_console_sem(); |
944 | pm_runtime_put(hdmi->dev); | 1080 | pm_runtime_put(hdmi->dev); |
1081 | fb_destroy_modedb(hdmi->monspec.modedb); | ||
945 | } | 1082 | } |
946 | 1083 | ||
947 | pr_debug("%s(%p): end\n", __func__, pdata->lcd_dev); | 1084 | out: |
1085 | if (ret < 0) | ||
1086 | hdmi->hp_state = HDMI_HOTPLUG_DISCONNECTED; | ||
1087 | mutex_unlock(&hdmi->mutex); | ||
1088 | |||
1089 | dev_dbg(hdmi->dev, "%s(%p): end\n", __func__, pdata->lcd_dev); | ||
1090 | } | ||
1091 | |||
1092 | static int sh_hdmi_notify(struct notifier_block *nb, | ||
1093 | unsigned long action, void *data); | ||
1094 | |||
1095 | static struct notifier_block sh_hdmi_notifier = { | ||
1096 | .notifier_call = sh_hdmi_notify, | ||
1097 | }; | ||
1098 | |||
1099 | static int sh_hdmi_notify(struct notifier_block *nb, | ||
1100 | unsigned long action, void *data) | ||
1101 | { | ||
1102 | struct fb_event *event = data; | ||
1103 | struct fb_info *info = event->info; | ||
1104 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
1105 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | ||
1106 | struct sh_hdmi *hdmi = board_cfg->board_data; | ||
1107 | |||
1108 | if (nb != &sh_hdmi_notifier || !hdmi || hdmi->info != info) | ||
1109 | return NOTIFY_DONE; | ||
1110 | |||
1111 | switch(action) { | ||
1112 | case FB_EVENT_FB_REGISTERED: | ||
1113 | /* Unneeded, activation taken care by sh_hdmi_display_on() */ | ||
1114 | break; | ||
1115 | case FB_EVENT_FB_UNREGISTERED: | ||
1116 | /* | ||
1117 | * We are called from unregister_framebuffer() with the | ||
1118 | * info->lock held. This is bad for us, because we can race with | ||
1119 | * the scheduled work, which has to call fb_set_suspend(), which | ||
1120 | * takes info->lock internally, so, sh_hdmi_edid_work_fn() | ||
1121 | * cannot take and hold info->lock for the whole function | ||
1122 | * duration. Using an additional lock creates a classical AB-BA | ||
1123 | * lock up. Therefore, we have to release the info->lock | ||
1124 | * temporarily, synchronise with the work queue and re-acquire | ||
1125 | * the info->lock. | ||
1126 | */ | ||
1127 | unlock_fb_info(hdmi->info); | ||
1128 | mutex_lock(&hdmi->mutex); | ||
1129 | hdmi->info = NULL; | ||
1130 | mutex_unlock(&hdmi->mutex); | ||
1131 | lock_fb_info(hdmi->info); | ||
1132 | return NOTIFY_OK; | ||
1133 | } | ||
1134 | return NOTIFY_DONE; | ||
948 | } | 1135 | } |
949 | 1136 | ||
950 | static int __init sh_hdmi_probe(struct platform_device *pdev) | 1137 | static int __init sh_hdmi_probe(struct platform_device *pdev) |
951 | { | 1138 | { |
952 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1139 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
953 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1140 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1141 | struct sh_mobile_lcdc_board_cfg *board_cfg; | ||
954 | int irq = platform_get_irq(pdev, 0), ret; | 1142 | int irq = platform_get_irq(pdev, 0), ret; |
955 | struct sh_hdmi *hdmi; | 1143 | struct sh_hdmi *hdmi; |
956 | long rate; | 1144 | long rate; |
@@ -964,10 +1152,7 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
964 | return -ENOMEM; | 1152 | return -ENOMEM; |
965 | } | 1153 | } |
966 | 1154 | ||
967 | ret = snd_soc_register_codec(&pdev->dev, | 1155 | mutex_init(&hdmi->mutex); |
968 | &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); | ||
969 | if (ret < 0) | ||
970 | goto esndreg; | ||
971 | 1156 | ||
972 | hdmi->dev = &pdev->dev; | 1157 | hdmi->dev = &pdev->dev; |
973 | 1158 | ||
@@ -978,30 +1163,14 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
978 | goto egetclk; | 1163 | goto egetclk; |
979 | } | 1164 | } |
980 | 1165 | ||
981 | rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000; | 1166 | /* Some arbitrary relaxed pixclock just to get things started */ |
982 | 1167 | rate = sh_hdmi_clk_configure(hdmi, 37037); | |
983 | rate = clk_round_rate(hdmi->hdmi_clk, rate); | ||
984 | if (rate < 0) { | 1168 | if (rate < 0) { |
985 | ret = rate; | 1169 | ret = rate; |
986 | dev_err(&pdev->dev, "Cannot get suitable rate: %ld\n", rate); | ||
987 | goto erate; | 1170 | goto erate; |
988 | } | 1171 | } |
989 | 1172 | ||
990 | ret = clk_set_rate(hdmi->hdmi_clk, rate); | 1173 | dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); |
991 | if (ret < 0) { | ||
992 | dev_err(&pdev->dev, "Cannot set rate %ld: %d\n", rate, ret); | ||
993 | goto erate; | ||
994 | } | ||
995 | |||
996 | pr_debug("HDMI set frequency %lu\n", rate); | ||
997 | |||
998 | ret = clk_enable(hdmi->hdmi_clk); | ||
999 | if (ret < 0) { | ||
1000 | dev_err(&pdev->dev, "Cannot enable clock: %d\n", ret); | ||
1001 | goto eclkenable; | ||
1002 | } | ||
1003 | |||
1004 | dev_info(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); | ||
1005 | 1174 | ||
1006 | if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { | 1175 | if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { |
1007 | dev_err(&pdev->dev, "HDMI register region already claimed\n"); | 1176 | dev_err(&pdev->dev, "HDMI register region already claimed\n"); |
@@ -1018,18 +1187,18 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1018 | 1187 | ||
1019 | platform_set_drvdata(pdev, hdmi); | 1188 | platform_set_drvdata(pdev, hdmi); |
1020 | 1189 | ||
1021 | #if 1 | ||
1022 | /* Product and revision IDs are 0 in sh-mobile version */ | 1190 | /* Product and revision IDs are 0 in sh-mobile version */ |
1023 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", | 1191 | dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", |
1024 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); | 1192 | hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); |
1025 | #endif | ||
1026 | 1193 | ||
1027 | /* Set up LCDC callbacks */ | 1194 | /* Set up LCDC callbacks */ |
1028 | pdata->lcd_chan->board_cfg.board_data = hdmi; | 1195 | board_cfg = &pdata->lcd_chan->board_cfg; |
1029 | pdata->lcd_chan->board_cfg.display_on = hdmi_display_on; | 1196 | board_cfg->owner = THIS_MODULE; |
1030 | pdata->lcd_chan->board_cfg.display_off = hdmi_display_off; | 1197 | board_cfg->board_data = hdmi; |
1198 | board_cfg->display_on = sh_hdmi_display_on; | ||
1199 | board_cfg->display_off = sh_hdmi_display_off; | ||
1031 | 1200 | ||
1032 | INIT_DELAYED_WORK(&hdmi->edid_work, edid_work_fn); | 1201 | INIT_DELAYED_WORK(&hdmi->edid_work, sh_hdmi_edid_work_fn); |
1033 | 1202 | ||
1034 | pm_runtime_enable(&pdev->dev); | 1203 | pm_runtime_enable(&pdev->dev); |
1035 | pm_runtime_resume(&pdev->dev); | 1204 | pm_runtime_resume(&pdev->dev); |
@@ -1041,8 +1210,17 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) | |||
1041 | goto ereqirq; | 1210 | goto ereqirq; |
1042 | } | 1211 | } |
1043 | 1212 | ||
1213 | ret = snd_soc_register_codec(&pdev->dev, | ||
1214 | &soc_codec_dev_sh_hdmi, &sh_hdmi_dai, 1); | ||
1215 | if (ret < 0) { | ||
1216 | dev_err(&pdev->dev, "codec registration failed\n"); | ||
1217 | goto ecodec; | ||
1218 | } | ||
1219 | |||
1044 | return 0; | 1220 | return 0; |
1045 | 1221 | ||
1222 | ecodec: | ||
1223 | free_irq(irq, hdmi); | ||
1046 | ereqirq: | 1224 | ereqirq: |
1047 | pm_runtime_disable(&pdev->dev); | 1225 | pm_runtime_disable(&pdev->dev); |
1048 | iounmap(hdmi->base); | 1226 | iounmap(hdmi->base); |
@@ -1050,12 +1228,10 @@ emap: | |||
1050 | release_mem_region(res->start, resource_size(res)); | 1228 | release_mem_region(res->start, resource_size(res)); |
1051 | ereqreg: | 1229 | ereqreg: |
1052 | clk_disable(hdmi->hdmi_clk); | 1230 | clk_disable(hdmi->hdmi_clk); |
1053 | eclkenable: | ||
1054 | erate: | 1231 | erate: |
1055 | clk_put(hdmi->hdmi_clk); | 1232 | clk_put(hdmi->hdmi_clk); |
1056 | egetclk: | 1233 | egetclk: |
1057 | snd_soc_unregister_codec(&pdev->dev); | 1234 | mutex_destroy(&hdmi->mutex); |
1058 | esndreg: | ||
1059 | kfree(hdmi); | 1235 | kfree(hdmi); |
1060 | 1236 | ||
1061 | return ret; | 1237 | return ret; |
@@ -1066,21 +1242,26 @@ static int __exit sh_hdmi_remove(struct platform_device *pdev) | |||
1066 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; | 1242 | struct sh_mobile_hdmi_info *pdata = pdev->dev.platform_data; |
1067 | struct sh_hdmi *hdmi = platform_get_drvdata(pdev); | 1243 | struct sh_hdmi *hdmi = platform_get_drvdata(pdev); |
1068 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1244 | struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1245 | struct sh_mobile_lcdc_board_cfg *board_cfg = &pdata->lcd_chan->board_cfg; | ||
1069 | int irq = platform_get_irq(pdev, 0); | 1246 | int irq = platform_get_irq(pdev, 0); |
1070 | 1247 | ||
1071 | snd_soc_unregister_codec(&pdev->dev); | 1248 | snd_soc_unregister_codec(&pdev->dev); |
1072 | 1249 | ||
1073 | pdata->lcd_chan->board_cfg.display_on = NULL; | 1250 | board_cfg->display_on = NULL; |
1074 | pdata->lcd_chan->board_cfg.display_off = NULL; | 1251 | board_cfg->display_off = NULL; |
1075 | pdata->lcd_chan->board_cfg.board_data = NULL; | 1252 | board_cfg->board_data = NULL; |
1253 | board_cfg->owner = NULL; | ||
1076 | 1254 | ||
1255 | /* No new work will be scheduled, wait for running ISR */ | ||
1077 | free_irq(irq, hdmi); | 1256 | free_irq(irq, hdmi); |
1078 | pm_runtime_disable(&pdev->dev); | 1257 | /* Wait for already scheduled work */ |
1079 | cancel_delayed_work_sync(&hdmi->edid_work); | 1258 | cancel_delayed_work_sync(&hdmi->edid_work); |
1259 | pm_runtime_disable(&pdev->dev); | ||
1080 | clk_disable(hdmi->hdmi_clk); | 1260 | clk_disable(hdmi->hdmi_clk); |
1081 | clk_put(hdmi->hdmi_clk); | 1261 | clk_put(hdmi->hdmi_clk); |
1082 | iounmap(hdmi->base); | 1262 | iounmap(hdmi->base); |
1083 | release_mem_region(res->start, resource_size(res)); | 1263 | release_mem_region(res->start, resource_size(res)); |
1264 | mutex_destroy(&hdmi->mutex); | ||
1084 | kfree(hdmi); | 1265 | kfree(hdmi); |
1085 | 1266 | ||
1086 | return 0; | 1267 | return 0; |
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 7a1419279c8f..50963739a409 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c | |||
@@ -12,7 +12,6 @@ | |||
12 | #include <linux/init.h> | 12 | #include <linux/init.h> |
13 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
14 | #include <linux/mm.h> | 14 | #include <linux/mm.h> |
15 | #include <linux/fb.h> | ||
16 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
17 | #include <linux/pm_runtime.h> | 16 | #include <linux/pm_runtime.h> |
18 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
@@ -21,10 +20,12 @@ | |||
21 | #include <linux/vmalloc.h> | 20 | #include <linux/vmalloc.h> |
22 | #include <linux/ioctl.h> | 21 | #include <linux/ioctl.h> |
23 | #include <linux/slab.h> | 22 | #include <linux/slab.h> |
23 | #include <linux/console.h> | ||
24 | #include <video/sh_mobile_lcdc.h> | 24 | #include <video/sh_mobile_lcdc.h> |
25 | #include <asm/atomic.h> | 25 | #include <asm/atomic.h> |
26 | 26 | ||
27 | #define PALETTE_NR 16 | 27 | #include "sh_mobile_lcdcfb.h" |
28 | |||
28 | #define SIDE_B_OFFSET 0x1000 | 29 | #define SIDE_B_OFFSET 0x1000 |
29 | #define MIRROR_OFFSET 0x2000 | 30 | #define MIRROR_OFFSET 0x2000 |
30 | 31 | ||
@@ -53,11 +54,8 @@ static int lcdc_shared_regs[] = { | |||
53 | }; | 54 | }; |
54 | #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) | 55 | #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) |
55 | 56 | ||
56 | /* per-channel registers */ | 57 | #define DEFAULT_XRES 1280 |
57 | enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | 58 | #define DEFAULT_YRES 1024 |
58 | LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, | ||
59 | LDHAJR, | ||
60 | NR_CH_REGS }; | ||
61 | 59 | ||
62 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { | 60 | static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { |
63 | [LDDCKPAT1R] = 0x400, | 61 | [LDDCKPAT1R] = 0x400, |
@@ -112,23 +110,21 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = { | |||
112 | #define LDRCNTR_MRC 0x00000001 | 110 | #define LDRCNTR_MRC 0x00000001 |
113 | #define LDSR_MRS 0x00000100 | 111 | #define LDSR_MRS 0x00000100 |
114 | 112 | ||
115 | struct sh_mobile_lcdc_priv; | 113 | static const struct fb_videomode default_720p = { |
116 | struct sh_mobile_lcdc_chan { | 114 | .name = "HDMI 720p", |
117 | struct sh_mobile_lcdc_priv *lcdc; | 115 | .xres = 1280, |
118 | unsigned long *reg_offs; | 116 | .yres = 720, |
119 | unsigned long ldmt1r_value; | 117 | |
120 | unsigned long enabled; /* ME and SE in LDCNT2R */ | 118 | .left_margin = 200, |
121 | struct sh_mobile_lcdc_chan_cfg cfg; | 119 | .right_margin = 88, |
122 | u32 pseudo_palette[PALETTE_NR]; | 120 | .hsync_len = 48, |
123 | unsigned long saved_ch_regs[NR_CH_REGS]; | 121 | |
124 | struct fb_info *info; | 122 | .upper_margin = 20, |
125 | dma_addr_t dma_handle; | 123 | .lower_margin = 5, |
126 | struct fb_deferred_io defio; | 124 | .vsync_len = 5, |
127 | struct scatterlist *sglist; | 125 | |
128 | unsigned long frame_end; | 126 | .pixclock = 13468, |
129 | unsigned long pan_offset; | 127 | .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, |
130 | wait_queue_head_t frame_end_wait; | ||
131 | struct completion vsync_completion; | ||
132 | }; | 128 | }; |
133 | 129 | ||
134 | struct sh_mobile_lcdc_priv { | 130 | struct sh_mobile_lcdc_priv { |
@@ -409,8 +405,8 @@ static void sh_mobile_lcdc_start_stop(struct sh_mobile_lcdc_priv *priv, | |||
409 | 405 | ||
410 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | 406 | static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) |
411 | { | 407 | { |
412 | struct fb_var_screeninfo *var = &ch->info->var; | 408 | struct fb_var_screeninfo *var = &ch->info->var, *display_var = &ch->display_var; |
413 | unsigned long h_total, hsync_pos; | 409 | unsigned long h_total, hsync_pos, display_h_total; |
414 | u32 tmp; | 410 | u32 tmp; |
415 | 411 | ||
416 | tmp = ch->ldmt1r_value; | 412 | tmp = ch->ldmt1r_value; |
@@ -428,31 +424,33 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
428 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); | 424 | lcdc_write_chan(ch, LDMT3R, ch->cfg.sys_bus_cfg.ldmt3r); |
429 | 425 | ||
430 | /* horizontal configuration */ | 426 | /* horizontal configuration */ |
431 | h_total = var->xres + var->hsync_len + | 427 | h_total = display_var->xres + display_var->hsync_len + |
432 | var->left_margin + var->right_margin; | 428 | display_var->left_margin + display_var->right_margin; |
433 | tmp = h_total / 8; /* HTCN */ | 429 | tmp = h_total / 8; /* HTCN */ |
434 | tmp |= (var->xres / 8) << 16; /* HDCN */ | 430 | tmp |= (min(display_var->xres, var->xres) / 8) << 16; /* HDCN */ |
435 | lcdc_write_chan(ch, LDHCNR, tmp); | 431 | lcdc_write_chan(ch, LDHCNR, tmp); |
436 | 432 | ||
437 | hsync_pos = var->xres + var->right_margin; | 433 | hsync_pos = display_var->xres + display_var->right_margin; |
438 | tmp = hsync_pos / 8; /* HSYNP */ | 434 | tmp = hsync_pos / 8; /* HSYNP */ |
439 | tmp |= (var->hsync_len / 8) << 16; /* HSYNW */ | 435 | tmp |= (display_var->hsync_len / 8) << 16; /* HSYNW */ |
440 | lcdc_write_chan(ch, LDHSYNR, tmp); | 436 | lcdc_write_chan(ch, LDHSYNR, tmp); |
441 | 437 | ||
442 | /* vertical configuration */ | 438 | /* vertical configuration */ |
443 | tmp = var->yres + var->vsync_len + | 439 | tmp = display_var->yres + display_var->vsync_len + |
444 | var->upper_margin + var->lower_margin; /* VTLN */ | 440 | display_var->upper_margin + display_var->lower_margin; /* VTLN */ |
445 | tmp |= var->yres << 16; /* VDLN */ | 441 | tmp |= min(display_var->yres, var->yres) << 16; /* VDLN */ |
446 | lcdc_write_chan(ch, LDVLNR, tmp); | 442 | lcdc_write_chan(ch, LDVLNR, tmp); |
447 | 443 | ||
448 | tmp = var->yres + var->lower_margin; /* VSYNP */ | 444 | tmp = display_var->yres + display_var->lower_margin; /* VSYNP */ |
449 | tmp |= var->vsync_len << 16; /* VSYNW */ | 445 | tmp |= display_var->vsync_len << 16; /* VSYNW */ |
450 | lcdc_write_chan(ch, LDVSYNR, tmp); | 446 | lcdc_write_chan(ch, LDVSYNR, tmp); |
451 | 447 | ||
452 | /* Adjust horizontal synchronisation for HDMI */ | 448 | /* Adjust horizontal synchronisation for HDMI */ |
453 | tmp = ((var->xres & 7) << 24) | | 449 | display_h_total = display_var->xres + display_var->hsync_len + |
454 | ((h_total & 7) << 16) | | 450 | display_var->left_margin + display_var->right_margin; |
455 | ((var->hsync_len & 7) << 8) | | 451 | tmp = ((display_var->xres & 7) << 24) | |
452 | ((display_h_total & 7) << 16) | | ||
453 | ((display_var->hsync_len & 7) << 8) | | ||
456 | hsync_pos; | 454 | hsync_pos; |
457 | lcdc_write_chan(ch, LDHAJR, tmp); | 455 | lcdc_write_chan(ch, LDHAJR, tmp); |
458 | } | 456 | } |
@@ -460,7 +458,6 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) | |||
460 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | 458 | static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) |
461 | { | 459 | { |
462 | struct sh_mobile_lcdc_chan *ch; | 460 | struct sh_mobile_lcdc_chan *ch; |
463 | struct fb_videomode *lcd_cfg; | ||
464 | struct sh_mobile_lcdc_board_cfg *board_cfg; | 461 | struct sh_mobile_lcdc_board_cfg *board_cfg; |
465 | unsigned long tmp; | 462 | unsigned long tmp; |
466 | int k, m; | 463 | int k, m; |
@@ -503,7 +500,8 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
503 | m = 1 << 6; | 500 | m = 1 << 6; |
504 | tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); | 501 | tmp |= m << (lcdc_chan_is_sublcd(ch) ? 8 : 0); |
505 | 502 | ||
506 | lcdc_write_chan(ch, LDDCKPAT1R, 0x00000000); | 503 | /* FIXME: sh7724 can only use 42, 48, 54 and 60 for the divider denominator */ |
504 | lcdc_write_chan(ch, LDDCKPAT1R, 0); | ||
507 | lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); | 505 | lcdc_write_chan(ch, LDDCKPAT2R, (1 << (m/2)) - 1); |
508 | } | 506 | } |
509 | 507 | ||
@@ -518,7 +516,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
518 | 516 | ||
519 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { | 517 | for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { |
520 | ch = &priv->ch[k]; | 518 | ch = &priv->ch[k]; |
521 | lcd_cfg = &ch->cfg.lcd_cfg; | ||
522 | 519 | ||
523 | if (!ch->enabled) | 520 | if (!ch->enabled) |
524 | continue; | 521 | continue; |
@@ -547,7 +544,7 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
547 | 544 | ||
548 | /* set bpp format in PKF[4:0] */ | 545 | /* set bpp format in PKF[4:0] */ |
549 | tmp = lcdc_read_chan(ch, LDDFR); | 546 | tmp = lcdc_read_chan(ch, LDDFR); |
550 | tmp &= ~(0x0001001f); | 547 | tmp &= ~0x0001001f; |
551 | tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; | 548 | tmp |= (ch->info->var.bits_per_pixel == 16) ? 3 : 0; |
552 | lcdc_write_chan(ch, LDDFR, tmp); | 549 | lcdc_write_chan(ch, LDDFR, tmp); |
553 | 550 | ||
@@ -591,8 +588,10 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) | |||
591 | continue; | 588 | continue; |
592 | 589 | ||
593 | board_cfg = &ch->cfg.board_cfg; | 590 | board_cfg = &ch->cfg.board_cfg; |
594 | if (board_cfg->display_on) | 591 | if (try_module_get(board_cfg->owner) && board_cfg->display_on) { |
595 | board_cfg->display_on(board_cfg->board_data, ch->info); | 592 | board_cfg->display_on(board_cfg->board_data, ch->info); |
593 | module_put(board_cfg->owner); | ||
594 | } | ||
596 | } | 595 | } |
597 | 596 | ||
598 | return 0; | 597 | return 0; |
@@ -614,7 +613,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
614 | * flush frame, and wait for frame end interrupt | 613 | * flush frame, and wait for frame end interrupt |
615 | * clean up deferred io and enable clock | 614 | * clean up deferred io and enable clock |
616 | */ | 615 | */ |
617 | if (ch->info->fbdefio) { | 616 | if (ch->info && ch->info->fbdefio) { |
618 | ch->frame_end = 0; | 617 | ch->frame_end = 0; |
619 | schedule_delayed_work(&ch->info->deferred_work, 0); | 618 | schedule_delayed_work(&ch->info->deferred_work, 0); |
620 | wait_event(ch->frame_end_wait, ch->frame_end); | 619 | wait_event(ch->frame_end_wait, ch->frame_end); |
@@ -624,8 +623,10 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) | |||
624 | } | 623 | } |
625 | 624 | ||
626 | board_cfg = &ch->cfg.board_cfg; | 625 | board_cfg = &ch->cfg.board_cfg; |
627 | if (board_cfg->display_off) | 626 | if (try_module_get(board_cfg->owner) && board_cfg->display_off) { |
628 | board_cfg->display_off(board_cfg->board_data); | 627 | board_cfg->display_off(board_cfg->board_data); |
628 | module_put(board_cfg->owner); | ||
629 | } | ||
629 | } | 630 | } |
630 | 631 | ||
631 | /* stop the lcdc */ | 632 | /* stop the lcdc */ |
@@ -704,7 +705,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, | |||
704 | return PTR_ERR(priv->dot_clk); | 705 | return PTR_ERR(priv->dot_clk); |
705 | } | 706 | } |
706 | } | 707 | } |
707 | atomic_set(&priv->hw_usecnt, -1); | ||
708 | 708 | ||
709 | /* Runtime PM support involves two step for this driver: | 709 | /* Runtime PM support involves two step for this driver: |
710 | * 1) Enable Runtime PM | 710 | * 1) Enable Runtime PM |
@@ -837,6 +837,102 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, | |||
837 | return retval; | 837 | return retval; |
838 | } | 838 | } |
839 | 839 | ||
840 | static void sh_mobile_fb_reconfig(struct fb_info *info) | ||
841 | { | ||
842 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
843 | struct fb_videomode mode1, mode2; | ||
844 | struct fb_event event; | ||
845 | int evnt = FB_EVENT_MODE_CHANGE_ALL; | ||
846 | |||
847 | if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par)) | ||
848 | /* More framebuffer users are active */ | ||
849 | return; | ||
850 | |||
851 | fb_var_to_videomode(&mode1, &ch->display_var); | ||
852 | fb_var_to_videomode(&mode2, &info->var); | ||
853 | |||
854 | if (fb_mode_is_equal(&mode1, &mode2)) | ||
855 | return; | ||
856 | |||
857 | /* Display has been re-plugged, framebuffer is free now, reconfigure */ | ||
858 | if (fb_set_var(info, &ch->display_var) < 0) | ||
859 | /* Couldn't reconfigure, hopefully, can continue as before */ | ||
860 | return; | ||
861 | |||
862 | info->fix.line_length = mode2.xres * (ch->cfg.bpp / 8); | ||
863 | |||
864 | /* | ||
865 | * fb_set_var() calls the notifier change internally, only if | ||
866 | * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a | ||
867 | * user event, we have to call the chain ourselves. | ||
868 | */ | ||
869 | event.info = info; | ||
870 | event.data = &mode2; | ||
871 | fb_notifier_call_chain(evnt, &event); | ||
872 | } | ||
873 | |||
874 | /* | ||
875 | * Locking: both .fb_release() and .fb_open() are called with info->lock held if | ||
876 | * user == 1, or with console sem held, if user == 0. | ||
877 | */ | ||
878 | static int sh_mobile_release(struct fb_info *info, int user) | ||
879 | { | ||
880 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
881 | |||
882 | mutex_lock(&ch->open_lock); | ||
883 | dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); | ||
884 | |||
885 | ch->use_count--; | ||
886 | |||
887 | /* Nothing to reconfigure, when called from fbcon */ | ||
888 | if (user) { | ||
889 | acquire_console_sem(); | ||
890 | sh_mobile_fb_reconfig(info); | ||
891 | release_console_sem(); | ||
892 | } | ||
893 | |||
894 | mutex_unlock(&ch->open_lock); | ||
895 | |||
896 | return 0; | ||
897 | } | ||
898 | |||
899 | static int sh_mobile_open(struct fb_info *info, int user) | ||
900 | { | ||
901 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
902 | |||
903 | mutex_lock(&ch->open_lock); | ||
904 | ch->use_count++; | ||
905 | |||
906 | dev_dbg(info->dev, "%s(): %d users\n", __func__, ch->use_count); | ||
907 | mutex_unlock(&ch->open_lock); | ||
908 | |||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
913 | { | ||
914 | struct sh_mobile_lcdc_chan *ch = info->par; | ||
915 | |||
916 | if (var->xres < 160 || var->xres > 1920 || | ||
917 | var->yres < 120 || var->yres > 1080 || | ||
918 | var->left_margin < 32 || var->left_margin > 320 || | ||
919 | var->right_margin < 12 || var->right_margin > 240 || | ||
920 | var->upper_margin < 12 || var->upper_margin > 120 || | ||
921 | var->lower_margin < 1 || var->lower_margin > 64 || | ||
922 | var->hsync_len < 32 || var->hsync_len > 240 || | ||
923 | var->vsync_len < 2 || var->vsync_len > 64 || | ||
924 | var->pixclock < 6000 || var->pixclock > 40000 || | ||
925 | var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { | ||
926 | dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", | ||
927 | var->xres, var->yres, | ||
928 | var->left_margin, var->right_margin, | ||
929 | var->upper_margin, var->lower_margin, | ||
930 | var->hsync_len, var->vsync_len, | ||
931 | var->pixclock); | ||
932 | return -EINVAL; | ||
933 | } | ||
934 | return 0; | ||
935 | } | ||
840 | 936 | ||
841 | static struct fb_ops sh_mobile_lcdc_ops = { | 937 | static struct fb_ops sh_mobile_lcdc_ops = { |
842 | .owner = THIS_MODULE, | 938 | .owner = THIS_MODULE, |
@@ -848,6 +944,9 @@ static struct fb_ops sh_mobile_lcdc_ops = { | |||
848 | .fb_imageblit = sh_mobile_lcdc_imageblit, | 944 | .fb_imageblit = sh_mobile_lcdc_imageblit, |
849 | .fb_pan_display = sh_mobile_fb_pan_display, | 945 | .fb_pan_display = sh_mobile_fb_pan_display, |
850 | .fb_ioctl = sh_mobile_ioctl, | 946 | .fb_ioctl = sh_mobile_ioctl, |
947 | .fb_open = sh_mobile_open, | ||
948 | .fb_release = sh_mobile_release, | ||
949 | .fb_check_var = sh_mobile_check_var, | ||
851 | }; | 950 | }; |
852 | 951 | ||
853 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) | 952 | static int sh_mobile_lcdc_set_bpp(struct fb_var_screeninfo *var, int bpp) |
@@ -958,6 +1057,7 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = { | |||
958 | .runtime_resume = sh_mobile_lcdc_runtime_resume, | 1057 | .runtime_resume = sh_mobile_lcdc_runtime_resume, |
959 | }; | 1058 | }; |
960 | 1059 | ||
1060 | /* locking: called with info->lock held */ | ||
961 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, | 1061 | static int sh_mobile_lcdc_notify(struct notifier_block *nb, |
962 | unsigned long action, void *data) | 1062 | unsigned long action, void *data) |
963 | { | 1063 | { |
@@ -965,53 +1065,40 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, | |||
965 | struct fb_info *info = event->info; | 1065 | struct fb_info *info = event->info; |
966 | struct sh_mobile_lcdc_chan *ch = info->par; | 1066 | struct sh_mobile_lcdc_chan *ch = info->par; |
967 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; | 1067 | struct sh_mobile_lcdc_board_cfg *board_cfg = &ch->cfg.board_cfg; |
968 | struct fb_var_screeninfo *var; | 1068 | int ret; |
969 | 1069 | ||
970 | if (&ch->lcdc->notifier != nb) | 1070 | if (&ch->lcdc->notifier != nb) |
971 | return 0; | 1071 | return NOTIFY_DONE; |
972 | 1072 | ||
973 | dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", | 1073 | dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", |
974 | __func__, action, event->data); | 1074 | __func__, action, event->data); |
975 | 1075 | ||
976 | switch(action) { | 1076 | switch(action) { |
977 | case FB_EVENT_SUSPEND: | 1077 | case FB_EVENT_SUSPEND: |
978 | if (board_cfg->display_off) | 1078 | if (try_module_get(board_cfg->owner) && board_cfg->display_off) { |
979 | board_cfg->display_off(board_cfg->board_data); | 1079 | board_cfg->display_off(board_cfg->board_data); |
1080 | module_put(board_cfg->owner); | ||
1081 | } | ||
980 | pm_runtime_put(info->device); | 1082 | pm_runtime_put(info->device); |
1083 | sh_mobile_lcdc_stop(ch->lcdc); | ||
981 | break; | 1084 | break; |
982 | case FB_EVENT_RESUME: | 1085 | case FB_EVENT_RESUME: |
983 | var = &info->var; | 1086 | mutex_lock(&ch->open_lock); |
1087 | sh_mobile_fb_reconfig(info); | ||
1088 | mutex_unlock(&ch->open_lock); | ||
984 | 1089 | ||
985 | /* HDMI must be enabled before LCDC configuration */ | 1090 | /* HDMI must be enabled before LCDC configuration */ |
986 | if (board_cfg->display_on) | 1091 | if (try_module_get(board_cfg->owner) && board_cfg->display_on) { |
987 | board_cfg->display_on(board_cfg->board_data, ch->info); | 1092 | board_cfg->display_on(board_cfg->board_data, info); |
988 | 1093 | module_put(board_cfg->owner); | |
989 | /* Check if the new display is not in our modelist */ | ||
990 | if (ch->info->modelist.next && | ||
991 | !fb_match_mode(var, &ch->info->modelist)) { | ||
992 | struct fb_videomode mode; | ||
993 | int ret; | ||
994 | |||
995 | /* Can we handle this display? */ | ||
996 | if (var->xres > ch->cfg.lcd_cfg.xres || | ||
997 | var->yres > ch->cfg.lcd_cfg.yres) | ||
998 | return -ENOMEM; | ||
999 | |||
1000 | /* Add to the modelist */ | ||
1001 | fb_var_to_videomode(&mode, var); | ||
1002 | ret = fb_add_videomode(&mode, &ch->info->modelist); | ||
1003 | if (ret < 0) | ||
1004 | return ret; | ||
1005 | } | 1094 | } |
1006 | 1095 | ||
1007 | pm_runtime_get_sync(info->device); | 1096 | ret = sh_mobile_lcdc_start(ch->lcdc); |
1008 | 1097 | if (!ret) | |
1009 | sh_mobile_lcdc_geometry(ch); | 1098 | pm_runtime_get_sync(info->device); |
1010 | |||
1011 | break; | ||
1012 | } | 1099 | } |
1013 | 1100 | ||
1014 | return 0; | 1101 | return NOTIFY_OK; |
1015 | } | 1102 | } |
1016 | 1103 | ||
1017 | static int sh_mobile_lcdc_remove(struct platform_device *pdev); | 1104 | static int sh_mobile_lcdc_remove(struct platform_device *pdev); |
@@ -1020,14 +1107,13 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1020 | { | 1107 | { |
1021 | struct fb_info *info; | 1108 | struct fb_info *info; |
1022 | struct sh_mobile_lcdc_priv *priv; | 1109 | struct sh_mobile_lcdc_priv *priv; |
1023 | struct sh_mobile_lcdc_info *pdata; | 1110 | struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; |
1024 | struct sh_mobile_lcdc_chan_cfg *cfg; | ||
1025 | struct resource *res; | 1111 | struct resource *res; |
1026 | int error; | 1112 | int error; |
1027 | void *buf; | 1113 | void *buf; |
1028 | int i, j; | 1114 | int i, j; |
1029 | 1115 | ||
1030 | if (!pdev->dev.platform_data) { | 1116 | if (!pdata) { |
1031 | dev_err(&pdev->dev, "no platform data defined\n"); | 1117 | dev_err(&pdev->dev, "no platform data defined\n"); |
1032 | return -EINVAL; | 1118 | return -EINVAL; |
1033 | } | 1119 | } |
@@ -1055,31 +1141,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1055 | } | 1141 | } |
1056 | 1142 | ||
1057 | priv->irq = i; | 1143 | priv->irq = i; |
1058 | pdata = pdev->dev.platform_data; | 1144 | atomic_set(&priv->hw_usecnt, -1); |
1059 | 1145 | ||
1060 | j = 0; | 1146 | j = 0; |
1061 | for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { | 1147 | for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { |
1062 | priv->ch[j].lcdc = priv; | 1148 | struct sh_mobile_lcdc_chan *ch = priv->ch + j; |
1063 | memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); | 1149 | |
1150 | ch->lcdc = priv; | ||
1151 | memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); | ||
1064 | 1152 | ||
1065 | error = sh_mobile_lcdc_check_interface(&priv->ch[j]); | 1153 | error = sh_mobile_lcdc_check_interface(ch); |
1066 | if (error) { | 1154 | if (error) { |
1067 | dev_err(&pdev->dev, "unsupported interface type\n"); | 1155 | dev_err(&pdev->dev, "unsupported interface type\n"); |
1068 | goto err1; | 1156 | goto err1; |
1069 | } | 1157 | } |
1070 | init_waitqueue_head(&priv->ch[j].frame_end_wait); | 1158 | init_waitqueue_head(&ch->frame_end_wait); |
1071 | init_completion(&priv->ch[j].vsync_completion); | 1159 | init_completion(&ch->vsync_completion); |
1072 | priv->ch[j].pan_offset = 0; | 1160 | ch->pan_offset = 0; |
1073 | 1161 | ||
1074 | switch (pdata->ch[i].chan) { | 1162 | switch (pdata->ch[i].chan) { |
1075 | case LCDC_CHAN_MAINLCD: | 1163 | case LCDC_CHAN_MAINLCD: |
1076 | priv->ch[j].enabled = 1 << 1; | 1164 | ch->enabled = 1 << 1; |
1077 | priv->ch[j].reg_offs = lcdc_offs_mainlcd; | 1165 | ch->reg_offs = lcdc_offs_mainlcd; |
1078 | j++; | 1166 | j++; |
1079 | break; | 1167 | break; |
1080 | case LCDC_CHAN_SUBLCD: | 1168 | case LCDC_CHAN_SUBLCD: |
1081 | priv->ch[j].enabled = 1 << 2; | 1169 | ch->enabled = 1 << 2; |
1082 | priv->ch[j].reg_offs = lcdc_offs_sublcd; | 1170 | ch->reg_offs = lcdc_offs_sublcd; |
1083 | j++; | 1171 | j++; |
1084 | break; | 1172 | break; |
1085 | } | 1173 | } |
@@ -1103,69 +1191,83 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1103 | 1191 | ||
1104 | for (i = 0; i < j; i++) { | 1192 | for (i = 0; i < j; i++) { |
1105 | struct fb_var_screeninfo *var; | 1193 | struct fb_var_screeninfo *var; |
1106 | struct fb_videomode *lcd_cfg; | 1194 | const struct fb_videomode *lcd_cfg, *max_cfg = NULL; |
1107 | cfg = &priv->ch[i].cfg; | 1195 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; |
1196 | struct sh_mobile_lcdc_chan_cfg *cfg = &ch->cfg; | ||
1197 | const struct fb_videomode *mode = cfg->lcd_cfg; | ||
1198 | unsigned long max_size = 0; | ||
1199 | int k; | ||
1108 | 1200 | ||
1109 | priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); | 1201 | ch->info = framebuffer_alloc(0, &pdev->dev); |
1110 | if (!priv->ch[i].info) { | 1202 | if (!ch->info) { |
1111 | dev_err(&pdev->dev, "unable to allocate fb_info\n"); | 1203 | dev_err(&pdev->dev, "unable to allocate fb_info\n"); |
1112 | error = -ENOMEM; | 1204 | error = -ENOMEM; |
1113 | break; | 1205 | break; |
1114 | } | 1206 | } |
1115 | 1207 | ||
1116 | info = priv->ch[i].info; | 1208 | info = ch->info; |
1117 | var = &info->var; | 1209 | var = &info->var; |
1118 | lcd_cfg = &cfg->lcd_cfg; | ||
1119 | info->fbops = &sh_mobile_lcdc_ops; | 1210 | info->fbops = &sh_mobile_lcdc_ops; |
1120 | var->xres = var->xres_virtual = lcd_cfg->xres; | 1211 | info->par = ch; |
1121 | var->yres = lcd_cfg->yres; | 1212 | |
1213 | mutex_init(&ch->open_lock); | ||
1214 | |||
1215 | for (k = 0, lcd_cfg = mode; | ||
1216 | k < cfg->num_cfg && lcd_cfg; | ||
1217 | k++, lcd_cfg++) { | ||
1218 | unsigned long size = lcd_cfg->yres * lcd_cfg->xres; | ||
1219 | |||
1220 | if (size > max_size) { | ||
1221 | max_cfg = lcd_cfg; | ||
1222 | max_size = size; | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | if (!mode) | ||
1227 | max_size = DEFAULT_XRES * DEFAULT_YRES; | ||
1228 | else if (max_cfg) | ||
1229 | dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", | ||
1230 | max_cfg->xres, max_cfg->yres); | ||
1231 | |||
1232 | info->fix = sh_mobile_lcdc_fix; | ||
1233 | info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; | ||
1234 | |||
1235 | if (!mode) | ||
1236 | mode = &default_720p; | ||
1237 | |||
1238 | fb_videomode_to_var(var, mode); | ||
1122 | /* Default Y virtual resolution is 2x panel size */ | 1239 | /* Default Y virtual resolution is 2x panel size */ |
1123 | var->yres_virtual = var->yres * 2; | 1240 | var->yres_virtual = var->yres * 2; |
1124 | var->width = cfg->lcd_size_cfg.width; | ||
1125 | var->height = cfg->lcd_size_cfg.height; | ||
1126 | var->activate = FB_ACTIVATE_NOW; | 1241 | var->activate = FB_ACTIVATE_NOW; |
1127 | var->left_margin = lcd_cfg->left_margin; | ||
1128 | var->right_margin = lcd_cfg->right_margin; | ||
1129 | var->upper_margin = lcd_cfg->upper_margin; | ||
1130 | var->lower_margin = lcd_cfg->lower_margin; | ||
1131 | var->hsync_len = lcd_cfg->hsync_len; | ||
1132 | var->vsync_len = lcd_cfg->vsync_len; | ||
1133 | var->sync = lcd_cfg->sync; | ||
1134 | var->pixclock = lcd_cfg->pixclock; | ||
1135 | 1242 | ||
1136 | error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); | 1243 | error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); |
1137 | if (error) | 1244 | if (error) |
1138 | break; | 1245 | break; |
1139 | 1246 | ||
1140 | info->fix = sh_mobile_lcdc_fix; | ||
1141 | info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); | ||
1142 | info->fix.smem_len = info->fix.line_length * | ||
1143 | var->yres_virtual; | ||
1144 | |||
1145 | buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, | 1247 | buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, |
1146 | &priv->ch[i].dma_handle, GFP_KERNEL); | 1248 | &ch->dma_handle, GFP_KERNEL); |
1147 | if (!buf) { | 1249 | if (!buf) { |
1148 | dev_err(&pdev->dev, "unable to allocate buffer\n"); | 1250 | dev_err(&pdev->dev, "unable to allocate buffer\n"); |
1149 | error = -ENOMEM; | 1251 | error = -ENOMEM; |
1150 | break; | 1252 | break; |
1151 | } | 1253 | } |
1152 | 1254 | ||
1153 | info->pseudo_palette = &priv->ch[i].pseudo_palette; | 1255 | info->pseudo_palette = &ch->pseudo_palette; |
1154 | info->flags = FBINFO_FLAG_DEFAULT; | 1256 | info->flags = FBINFO_FLAG_DEFAULT; |
1155 | 1257 | ||
1156 | error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); | 1258 | error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); |
1157 | if (error < 0) { | 1259 | if (error < 0) { |
1158 | dev_err(&pdev->dev, "unable to allocate cmap\n"); | 1260 | dev_err(&pdev->dev, "unable to allocate cmap\n"); |
1159 | dma_free_coherent(&pdev->dev, info->fix.smem_len, | 1261 | dma_free_coherent(&pdev->dev, info->fix.smem_len, |
1160 | buf, priv->ch[i].dma_handle); | 1262 | buf, ch->dma_handle); |
1161 | break; | 1263 | break; |
1162 | } | 1264 | } |
1163 | 1265 | ||
1164 | memset(buf, 0, info->fix.smem_len); | 1266 | info->fix.smem_start = ch->dma_handle; |
1165 | info->fix.smem_start = priv->ch[i].dma_handle; | 1267 | info->fix.line_length = var->xres * (cfg->bpp / 8); |
1166 | info->screen_base = buf; | 1268 | info->screen_base = buf; |
1167 | info->device = &pdev->dev; | 1269 | info->device = &pdev->dev; |
1168 | info->par = &priv->ch[i]; | 1270 | ch->display_var = *var; |
1169 | } | 1271 | } |
1170 | 1272 | ||
1171 | if (error) | 1273 | if (error) |
@@ -1179,6 +1281,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1179 | 1281 | ||
1180 | for (i = 0; i < j; i++) { | 1282 | for (i = 0; i < j; i++) { |
1181 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; | 1283 | struct sh_mobile_lcdc_chan *ch = priv->ch + i; |
1284 | const struct fb_videomode *mode = ch->cfg.lcd_cfg; | ||
1285 | |||
1286 | if (!mode) | ||
1287 | mode = &default_720p; | ||
1182 | 1288 | ||
1183 | info = ch->info; | 1289 | info = ch->info; |
1184 | 1290 | ||
@@ -1191,6 +1297,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1191 | } | 1297 | } |
1192 | } | 1298 | } |
1193 | 1299 | ||
1300 | fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist); | ||
1194 | error = register_framebuffer(info); | 1301 | error = register_framebuffer(info); |
1195 | if (error < 0) | 1302 | if (error < 0) |
1196 | goto err1; | 1303 | goto err1; |
@@ -1200,8 +1307,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) | |||
1200 | pdev->name, | 1307 | pdev->name, |
1201 | (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? | 1308 | (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? |
1202 | "mainlcd" : "sublcd", | 1309 | "mainlcd" : "sublcd", |
1203 | (int) ch->cfg.lcd_cfg.xres, | 1310 | info->var.xres, info->var.yres, |
1204 | (int) ch->cfg.lcd_cfg.yres, | ||
1205 | ch->cfg.bpp); | 1311 | ch->cfg.bpp); |
1206 | 1312 | ||
1207 | /* deferred io mode: disable clock to save power */ | 1313 | /* deferred io mode: disable clock to save power */ |
diff --git a/drivers/video/sh_mobile_lcdcfb.h b/drivers/video/sh_mobile_lcdcfb.h new file mode 100644 index 000000000000..9ecee2fba1d7 --- /dev/null +++ b/drivers/video/sh_mobile_lcdcfb.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef SH_MOBILE_LCDCFB_H | ||
2 | #define SH_MOBILE_LCDCFB_H | ||
3 | |||
4 | #include <linux/completion.h> | ||
5 | #include <linux/fb.h> | ||
6 | #include <linux/mutex.h> | ||
7 | #include <linux/wait.h> | ||
8 | |||
9 | /* per-channel registers */ | ||
10 | enum { LDDCKPAT1R, LDDCKPAT2R, LDMT1R, LDMT2R, LDMT3R, LDDFR, LDSM1R, | ||
11 | LDSM2R, LDSA1R, LDMLSR, LDHCNR, LDHSYNR, LDVLNR, LDVSYNR, LDPMR, | ||
12 | LDHAJR, | ||
13 | NR_CH_REGS }; | ||
14 | |||
15 | #define PALETTE_NR 16 | ||
16 | |||
17 | struct sh_mobile_lcdc_priv; | ||
18 | struct fb_info; | ||
19 | |||
20 | struct sh_mobile_lcdc_chan { | ||
21 | struct sh_mobile_lcdc_priv *lcdc; | ||
22 | unsigned long *reg_offs; | ||
23 | unsigned long ldmt1r_value; | ||
24 | unsigned long enabled; /* ME and SE in LDCNT2R */ | ||
25 | struct sh_mobile_lcdc_chan_cfg cfg; | ||
26 | u32 pseudo_palette[PALETTE_NR]; | ||
27 | unsigned long saved_ch_regs[NR_CH_REGS]; | ||
28 | struct fb_info *info; | ||
29 | dma_addr_t dma_handle; | ||
30 | struct fb_deferred_io defio; | ||
31 | struct scatterlist *sglist; | ||
32 | unsigned long frame_end; | ||
33 | unsigned long pan_offset; | ||
34 | wait_queue_head_t frame_end_wait; | ||
35 | struct completion vsync_completion; | ||
36 | struct fb_var_screeninfo display_var; | ||
37 | int use_count; | ||
38 | struct mutex open_lock; /* protects the use counter */ | ||
39 | }; | ||
40 | |||
41 | #endif | ||
diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 55d700e8566e..daabae5817c6 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h | |||
@@ -49,7 +49,9 @@ struct sh_mobile_lcdc_sys_bus_ops { | |||
49 | unsigned long (*read_data)(void *handle); | 49 | unsigned long (*read_data)(void *handle); |
50 | }; | 50 | }; |
51 | 51 | ||
52 | struct module; | ||
52 | struct sh_mobile_lcdc_board_cfg { | 53 | struct sh_mobile_lcdc_board_cfg { |
54 | struct module *owner; | ||
53 | void *board_data; | 55 | void *board_data; |
54 | int (*setup_sys)(void *board_data, void *sys_ops_handle, | 56 | int (*setup_sys)(void *board_data, void *sys_ops_handle, |
55 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); | 57 | struct sh_mobile_lcdc_sys_bus_ops *sys_ops); |
@@ -70,7 +72,8 @@ struct sh_mobile_lcdc_chan_cfg { | |||
70 | int interface_type; /* selects RGBn or SYSn I/F, see above */ | 72 | int interface_type; /* selects RGBn or SYSn I/F, see above */ |
71 | int clock_divider; | 73 | int clock_divider; |
72 | unsigned long flags; /* LCDC_FLAGS_... */ | 74 | unsigned long flags; /* LCDC_FLAGS_... */ |
73 | struct fb_videomode lcd_cfg; | 75 | const struct fb_videomode *lcd_cfg; |
76 | int num_cfg; | ||
74 | struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; | 77 | struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; |
75 | struct sh_mobile_lcdc_board_cfg board_cfg; | 78 | struct sh_mobile_lcdc_board_cfg board_cfg; |
76 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ | 79 | struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ |