diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/video/omap2 | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/video/omap2')
52 files changed, 9087 insertions, 17328 deletions
diff --git a/drivers/video/omap2/Kconfig b/drivers/video/omap2/Kconfig index b07b2b042e7..d877c361abd 100644 --- a/drivers/video/omap2/Kconfig +++ b/drivers/video/omap2/Kconfig | |||
@@ -1,10 +1,9 @@ | |||
1 | config OMAP2_VRFB | 1 | config OMAP2_VRAM |
2 | bool | 2 | bool |
3 | 3 | ||
4 | if ARCH_OMAP2PLUS | 4 | config OMAP2_VRFB |
5 | bool | ||
5 | 6 | ||
6 | source "drivers/video/omap2/dss/Kconfig" | 7 | source "drivers/video/omap2/dss/Kconfig" |
7 | source "drivers/video/omap2/omapfb/Kconfig" | 8 | source "drivers/video/omap2/omapfb/Kconfig" |
8 | source "drivers/video/omap2/displays/Kconfig" | 9 | source "drivers/video/omap2/displays/Kconfig" |
9 | |||
10 | endif | ||
diff --git a/drivers/video/omap2/Makefile b/drivers/video/omap2/Makefile index 5ea7cb9aed1..5ddef129f79 100644 --- a/drivers/video/omap2/Makefile +++ b/drivers/video/omap2/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | obj-$(CONFIG_OMAP2_VRAM) += vram.o | ||
1 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o | 2 | obj-$(CONFIG_OMAP2_VRFB) += vrfb.o |
2 | 3 | ||
3 | obj-$(CONFIG_OMAP2_DSS) += dss/ | 4 | obj-$(CONFIG_OMAP2_DSS) += dss/ |
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index c3853c92279..609a2807317 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig | |||
@@ -10,13 +10,6 @@ config PANEL_GENERIC_DPI | |||
10 | Supports LCD Panel used in TI SDP3430 and EVM boards, | 10 | Supports LCD Panel used in TI SDP3430 and EVM boards, |
11 | OMAP3517 EVM boards and CM-T35. | 11 | OMAP3517 EVM boards and CM-T35. |
12 | 12 | ||
13 | config PANEL_TFP410 | ||
14 | tristate "TFP410 DPI-to-DVI chip" | ||
15 | depends on OMAP2_DSS_DPI && I2C | ||
16 | help | ||
17 | Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID | ||
18 | information from the monitor. | ||
19 | |||
20 | config PANEL_LGPHILIPS_LB035Q02 | 13 | config PANEL_LGPHILIPS_LB035Q02 |
21 | tristate "LG.Philips LB035Q02 LCD Panel" | 14 | tristate "LG.Philips LB035Q02 LCD Panel" |
22 | depends on OMAP2_DSS_DPI && SPI | 15 | depends on OMAP2_DSS_DPI && SPI |
@@ -26,30 +19,20 @@ config PANEL_LGPHILIPS_LB035Q02 | |||
26 | config PANEL_SHARP_LS037V7DW01 | 19 | config PANEL_SHARP_LS037V7DW01 |
27 | tristate "Sharp LS037V7DW01 LCD Panel" | 20 | tristate "Sharp LS037V7DW01 LCD Panel" |
28 | depends on OMAP2_DSS_DPI | 21 | depends on OMAP2_DSS_DPI |
29 | depends on BACKLIGHT_CLASS_DEVICE | 22 | select BACKLIGHT_CLASS_DEVICE |
30 | help | 23 | help |
31 | LCD Panel used in TI's SDP3430 and EVM boards | 24 | LCD Panel used in TI's SDP3430 and EVM boards |
32 | 25 | ||
33 | config PANEL_NEC_NL8048HL11_01B | 26 | config PANEL_NEC_NL8048HL11_01B |
34 | tristate "NEC NL8048HL11-01B Panel" | 27 | tristate "NEC NL8048HL11-01B Panel" |
35 | depends on OMAP2_DSS_DPI | 28 | depends on OMAP2_DSS_DPI |
36 | depends on SPI | ||
37 | depends on BACKLIGHT_CLASS_DEVICE | ||
38 | help | 29 | help |
39 | This NEC NL8048HL11-01B panel is TFT LCD | 30 | This NEC NL8048HL11-01B panel is TFT LCD |
40 | used in the Zoom2/3/3630 sdp boards. | 31 | used in the Zoom2/3/3630 sdp boards. |
41 | 32 | ||
42 | config PANEL_PICODLP | ||
43 | tristate "TI PICO DLP mini-projector" | ||
44 | depends on OMAP2_DSS_DPI && I2C | ||
45 | help | ||
46 | A mini-projector used in TI's SDP4430 and EVM boards | ||
47 | For more info please visit http://www.dlp.com/projector/ | ||
48 | |||
49 | config PANEL_TAAL | 33 | config PANEL_TAAL |
50 | tristate "Taal DSI Panel" | 34 | tristate "Taal DSI Panel" |
51 | depends on OMAP2_DSS_DSI | 35 | depends on OMAP2_DSS_DSI |
52 | depends on BACKLIGHT_CLASS_DEVICE | ||
53 | help | 36 | help |
54 | Taal DSI command mode panel from TPO. | 37 | Taal DSI command mode panel from TPO. |
55 | 38 | ||
@@ -62,14 +45,7 @@ config PANEL_TPO_TD043MTEA1 | |||
62 | config PANEL_ACX565AKM | 45 | config PANEL_ACX565AKM |
63 | tristate "ACX565AKM Panel" | 46 | tristate "ACX565AKM Panel" |
64 | depends on OMAP2_DSS_SDI && SPI | 47 | depends on OMAP2_DSS_SDI && SPI |
65 | depends on BACKLIGHT_CLASS_DEVICE | 48 | select BACKLIGHT_CLASS_DEVICE |
66 | help | 49 | help |
67 | This is the LCD panel used on Nokia N900 | 50 | This is the LCD panel used on Nokia N900 |
68 | |||
69 | config PANEL_N8X0 | ||
70 | tristate "N8X0 Panel" | ||
71 | depends on OMAP2_DSS_RFBI && SPI | ||
72 | depends on BACKLIGHT_CLASS_DEVICE | ||
73 | help | ||
74 | This is the LCD panel used on Nokia N8x0 | ||
75 | endmenu | 51 | endmenu |
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index 58a5176b07b..0f601ab3abf 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile | |||
@@ -1,11 +1,8 @@ | |||
1 | obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o | 1 | obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o |
2 | obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o | ||
3 | obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o | 2 | obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o |
4 | obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o | 3 | obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o |
5 | obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o | 4 | obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o |
6 | 5 | ||
7 | obj-$(CONFIG_PANEL_TAAL) += panel-taal.o | 6 | obj-$(CONFIG_PANEL_TAAL) += panel-taal.o |
8 | obj-$(CONFIG_PANEL_PICODLP) += panel-picodlp.o | ||
9 | obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o | 7 | obj-$(CONFIG_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o |
10 | obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o | 8 | obj-$(CONFIG_PANEL_ACX565AKM) += panel-acx565akm.o |
11 | obj-$(CONFIG_PANEL_N8X0) += panel-n8x0.o | ||
diff --git a/drivers/video/omap2/displays/panel-acx565akm.c b/drivers/video/omap2/displays/panel-acx565akm.c index 72699f88c00..dbd59b8e5b3 100644 --- a/drivers/video/omap2/displays/panel-acx565akm.c +++ b/drivers/video/omap2/displays/panel-acx565akm.c | |||
@@ -487,13 +487,6 @@ static struct omap_video_timings acx_panel_timings = { | |||
487 | .vfp = 3, | 487 | .vfp = 3, |
488 | .vsw = 3, | 488 | .vsw = 3, |
489 | .vbp = 4, | 489 | .vbp = 4, |
490 | |||
491 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
492 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
493 | |||
494 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
495 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
496 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
497 | }; | 490 | }; |
498 | 491 | ||
499 | static int acx_panel_probe(struct omap_dss_device *dssdev) | 492 | static int acx_panel_probe(struct omap_dss_device *dssdev) |
@@ -505,7 +498,8 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
505 | struct backlight_properties props; | 498 | struct backlight_properties props; |
506 | 499 | ||
507 | dev_dbg(&dssdev->dev, "%s\n", __func__); | 500 | dev_dbg(&dssdev->dev, "%s\n", __func__); |
508 | 501 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | |
502 | OMAP_DSS_LCD_IHS; | ||
509 | /* FIXME AC bias ? */ | 503 | /* FIXME AC bias ? */ |
510 | dssdev->panel.timings = acx_panel_timings; | 504 | dssdev->panel.timings = acx_panel_timings; |
511 | 505 | ||
@@ -538,7 +532,6 @@ static int acx_panel_probe(struct omap_dss_device *dssdev) | |||
538 | 532 | ||
539 | /*------- Backlight control --------*/ | 533 | /*------- Backlight control --------*/ |
540 | 534 | ||
541 | memset(&props, 0, sizeof(props)); | ||
542 | props.fb_blank = FB_BLANK_UNBLANK; | 535 | props.fb_blank = FB_BLANK_UNBLANK; |
543 | props.power = FB_BLANK_UNBLANK; | 536 | props.power = FB_BLANK_UNBLANK; |
544 | props.type = BACKLIGHT_RAW; | 537 | props.type = BACKLIGHT_RAW; |
@@ -600,9 +593,6 @@ static int acx_panel_power_on(struct omap_dss_device *dssdev) | |||
600 | 593 | ||
601 | mutex_lock(&md->mutex); | 594 | mutex_lock(&md->mutex); |
602 | 595 | ||
603 | omapdss_sdi_set_timings(dssdev, &dssdev->panel.timings); | ||
604 | omapdss_sdi_set_datapairs(dssdev, dssdev->phy.sdi.datapairs); | ||
605 | |||
606 | r = omapdss_sdi_display_enable(dssdev); | 596 | r = omapdss_sdi_display_enable(dssdev); |
607 | if (r) { | 597 | if (r) { |
608 | pr_err("%s sdi enable failed\n", __func__); | 598 | pr_err("%s sdi enable failed\n", __func__); |
@@ -710,12 +700,48 @@ static void acx_panel_disable(struct omap_dss_device *dssdev) | |||
710 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 700 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
711 | } | 701 | } |
712 | 702 | ||
703 | static int acx_panel_suspend(struct omap_dss_device *dssdev) | ||
704 | { | ||
705 | dev_dbg(&dssdev->dev, "%s\n", __func__); | ||
706 | acx_panel_power_off(dssdev); | ||
707 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | static int acx_panel_resume(struct omap_dss_device *dssdev) | ||
712 | { | ||
713 | int r; | ||
714 | |||
715 | dev_dbg(&dssdev->dev, "%s\n", __func__); | ||
716 | r = acx_panel_power_on(dssdev); | ||
717 | if (r) | ||
718 | return r; | ||
719 | |||
720 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
721 | return 0; | ||
722 | } | ||
723 | |||
713 | static void acx_panel_set_timings(struct omap_dss_device *dssdev, | 724 | static void acx_panel_set_timings(struct omap_dss_device *dssdev, |
714 | struct omap_video_timings *timings) | 725 | struct omap_video_timings *timings) |
715 | { | 726 | { |
716 | omapdss_sdi_set_timings(dssdev, timings); | 727 | int r; |
728 | |||
729 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
730 | omapdss_sdi_display_disable(dssdev); | ||
717 | 731 | ||
718 | dssdev->panel.timings = *timings; | 732 | dssdev->panel.timings = *timings; |
733 | |||
734 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
735 | r = omapdss_sdi_display_enable(dssdev); | ||
736 | if (r) | ||
737 | dev_err(&dssdev->dev, "%s enable failed\n", __func__); | ||
738 | } | ||
739 | } | ||
740 | |||
741 | static void acx_panel_get_timings(struct omap_dss_device *dssdev, | ||
742 | struct omap_video_timings *timings) | ||
743 | { | ||
744 | *timings = dssdev->panel.timings; | ||
719 | } | 745 | } |
720 | 746 | ||
721 | static int acx_panel_check_timings(struct omap_dss_device *dssdev, | 747 | static int acx_panel_check_timings(struct omap_dss_device *dssdev, |
@@ -731,8 +757,11 @@ static struct omap_dss_driver acx_panel_driver = { | |||
731 | 757 | ||
732 | .enable = acx_panel_enable, | 758 | .enable = acx_panel_enable, |
733 | .disable = acx_panel_disable, | 759 | .disable = acx_panel_disable, |
760 | .suspend = acx_panel_suspend, | ||
761 | .resume = acx_panel_resume, | ||
734 | 762 | ||
735 | .set_timings = acx_panel_set_timings, | 763 | .set_timings = acx_panel_set_timings, |
764 | .get_timings = acx_panel_get_timings, | ||
736 | .check_timings = acx_panel_check_timings, | 765 | .check_timings = acx_panel_check_timings, |
737 | 766 | ||
738 | .get_recommended_bpp = acx_get_recommended_bpp, | 767 | .get_recommended_bpp = acx_get_recommended_bpp, |
@@ -774,13 +803,25 @@ static int acx565akm_spi_remove(struct spi_device *spi) | |||
774 | static struct spi_driver acx565akm_spi_driver = { | 803 | static struct spi_driver acx565akm_spi_driver = { |
775 | .driver = { | 804 | .driver = { |
776 | .name = "acx565akm", | 805 | .name = "acx565akm", |
806 | .bus = &spi_bus_type, | ||
777 | .owner = THIS_MODULE, | 807 | .owner = THIS_MODULE, |
778 | }, | 808 | }, |
779 | .probe = acx565akm_spi_probe, | 809 | .probe = acx565akm_spi_probe, |
780 | .remove = acx565akm_spi_remove, | 810 | .remove = __devexit_p(acx565akm_spi_remove), |
781 | }; | 811 | }; |
782 | 812 | ||
783 | module_spi_driver(acx565akm_spi_driver); | 813 | static int __init acx565akm_init(void) |
814 | { | ||
815 | return spi_register_driver(&acx565akm_spi_driver); | ||
816 | } | ||
817 | |||
818 | static void __exit acx565akm_exit(void) | ||
819 | { | ||
820 | spi_unregister_driver(&acx565akm_spi_driver); | ||
821 | } | ||
822 | |||
823 | module_init(acx565akm_init); | ||
824 | module_exit(acx565akm_exit); | ||
784 | 825 | ||
785 | MODULE_AUTHOR("Nokia Corporation"); | 826 | MODULE_AUTHOR("Nokia Corporation"); |
786 | MODULE_DESCRIPTION("acx565akm LCD Driver"); | 827 | MODULE_DESCRIPTION("acx565akm LCD Driver"); |
diff --git a/drivers/video/omap2/displays/panel-generic-dpi.c b/drivers/video/omap2/displays/panel-generic-dpi.c index 54ca8ae2107..9c90f75653f 100644 --- a/drivers/video/omap2/displays/panel-generic-dpi.c +++ b/drivers/video/omap2/displays/panel-generic-dpi.c | |||
@@ -40,6 +40,12 @@ | |||
40 | struct panel_config { | 40 | struct panel_config { |
41 | struct omap_video_timings timings; | 41 | struct omap_video_timings timings; |
42 | 42 | ||
43 | int acbi; /* ac-bias pin transitions per interrupt */ | ||
44 | /* Unit: line clocks */ | ||
45 | int acb; /* ac-bias pin frequency */ | ||
46 | |||
47 | enum omap_panel_config config; | ||
48 | |||
43 | int power_on_delay; | 49 | int power_on_delay; |
44 | int power_off_delay; | 50 | int power_off_delay; |
45 | 51 | ||
@@ -52,6 +58,30 @@ struct panel_config { | |||
52 | 58 | ||
53 | /* Panel configurations */ | 59 | /* Panel configurations */ |
54 | static struct panel_config generic_dpi_panels[] = { | 60 | static struct panel_config generic_dpi_panels[] = { |
61 | /* Generic Panel */ | ||
62 | { | ||
63 | { | ||
64 | .x_res = 640, | ||
65 | .y_res = 480, | ||
66 | |||
67 | .pixel_clock = 23500, | ||
68 | |||
69 | .hfp = 48, | ||
70 | .hsw = 32, | ||
71 | .hbp = 80, | ||
72 | |||
73 | .vfp = 3, | ||
74 | .vsw = 4, | ||
75 | .vbp = 7, | ||
76 | }, | ||
77 | .acbi = 0x0, | ||
78 | .acb = 0x0, | ||
79 | .config = OMAP_DSS_LCD_TFT, | ||
80 | .power_on_delay = 0, | ||
81 | .power_off_delay = 0, | ||
82 | .name = "generic", | ||
83 | }, | ||
84 | |||
55 | /* Sharp LQ043T1DG01 */ | 85 | /* Sharp LQ043T1DG01 */ |
56 | { | 86 | { |
57 | { | 87 | { |
@@ -67,13 +97,11 @@ static struct panel_config generic_dpi_panels[] = { | |||
67 | .vsw = 11, | 97 | .vsw = 11, |
68 | .vfp = 3, | 98 | .vfp = 3, |
69 | .vbp = 2, | 99 | .vbp = 2, |
70 | |||
71 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
72 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
73 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
74 | .de_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
75 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
76 | }, | 100 | }, |
101 | .acbi = 0x0, | ||
102 | .acb = 0x0, | ||
103 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
104 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, | ||
77 | .power_on_delay = 50, | 105 | .power_on_delay = 50, |
78 | .power_off_delay = 100, | 106 | .power_off_delay = 100, |
79 | .name = "sharp_lq", | 107 | .name = "sharp_lq", |
@@ -94,13 +122,11 @@ static struct panel_config generic_dpi_panels[] = { | |||
94 | .vsw = 1, | 122 | .vsw = 1, |
95 | .vfp = 1, | 123 | .vfp = 1, |
96 | .vbp = 1, | 124 | .vbp = 1, |
97 | |||
98 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
99 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
100 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
101 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
102 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
103 | }, | 125 | }, |
126 | .acbi = 0x0, | ||
127 | .acb = 0x28, | ||
128 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
129 | OMAP_DSS_LCD_IHS, | ||
104 | .power_on_delay = 50, | 130 | .power_on_delay = 50, |
105 | .power_off_delay = 100, | 131 | .power_off_delay = 100, |
106 | .name = "sharp_ls", | 132 | .name = "sharp_ls", |
@@ -121,13 +147,12 @@ static struct panel_config generic_dpi_panels[] = { | |||
121 | .vfp = 4, | 147 | .vfp = 4, |
122 | .vsw = 2, | 148 | .vsw = 2, |
123 | .vbp = 2, | 149 | .vbp = 2, |
124 | |||
125 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
126 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
127 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
128 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
129 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
130 | }, | 150 | }, |
151 | .acbi = 0x0, | ||
152 | .acb = 0x0, | ||
153 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
154 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC | | ||
155 | OMAP_DSS_LCD_ONOFF, | ||
131 | .power_on_delay = 0, | 156 | .power_on_delay = 0, |
132 | .power_off_delay = 0, | 157 | .power_off_delay = 0, |
133 | .name = "toppoly_tdo35s", | 158 | .name = "toppoly_tdo35s", |
@@ -148,13 +173,11 @@ static struct panel_config generic_dpi_panels[] = { | |||
148 | .vfp = 4, | 173 | .vfp = 4, |
149 | .vsw = 10, | 174 | .vsw = 10, |
150 | .vbp = 12 - 10, | 175 | .vbp = 12 - 10, |
151 | |||
152 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
153 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
154 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
155 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
156 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
157 | }, | 176 | }, |
177 | .acbi = 0x0, | ||
178 | .acb = 0x0, | ||
179 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
180 | OMAP_DSS_LCD_IHS, | ||
158 | .power_on_delay = 0, | 181 | .power_on_delay = 0, |
159 | .power_off_delay = 0, | 182 | .power_off_delay = 0, |
160 | .name = "samsung_lte430wq_f0c", | 183 | .name = "samsung_lte430wq_f0c", |
@@ -175,13 +198,11 @@ static struct panel_config generic_dpi_panels[] = { | |||
175 | .vsw = 2, | 198 | .vsw = 2, |
176 | .vfp = 4, | 199 | .vfp = 4, |
177 | .vbp = 11, | 200 | .vbp = 11, |
178 | |||
179 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
180 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
181 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
182 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
183 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
184 | }, | 201 | }, |
202 | .acbi = 0x0, | ||
203 | .acb = 0x0, | ||
204 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
205 | OMAP_DSS_LCD_IHS, | ||
185 | .power_on_delay = 0, | 206 | .power_on_delay = 0, |
186 | .power_off_delay = 0, | 207 | .power_off_delay = 0, |
187 | .name = "seiko_70wvw1tz3", | 208 | .name = "seiko_70wvw1tz3", |
@@ -202,342 +223,15 @@ static struct panel_config generic_dpi_panels[] = { | |||
202 | .vsw = 10, | 223 | .vsw = 10, |
203 | .vfp = 2, | 224 | .vfp = 2, |
204 | .vbp = 2, | 225 | .vbp = 2, |
205 | |||
206 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
207 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
208 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
209 | .de_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
210 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
211 | }, | 226 | }, |
227 | .acbi = 0x0, | ||
228 | .acb = 0x0, | ||
229 | .config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
230 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO, | ||
212 | .power_on_delay = 0, | 231 | .power_on_delay = 0, |
213 | .power_off_delay = 0, | 232 | .power_off_delay = 0, |
214 | .name = "powertip_ph480272t", | 233 | .name = "powertip_ph480272t", |
215 | }, | 234 | }, |
216 | |||
217 | /* Innolux AT070TN83 */ | ||
218 | { | ||
219 | { | ||
220 | .x_res = 800, | ||
221 | .y_res = 480, | ||
222 | |||
223 | .pixel_clock = 40000, | ||
224 | |||
225 | .hsw = 48, | ||
226 | .hfp = 1, | ||
227 | .hbp = 1, | ||
228 | |||
229 | .vsw = 3, | ||
230 | .vfp = 12, | ||
231 | .vbp = 25, | ||
232 | |||
233 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
234 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
235 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
236 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
237 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
238 | }, | ||
239 | .power_on_delay = 0, | ||
240 | .power_off_delay = 0, | ||
241 | .name = "innolux_at070tn83", | ||
242 | }, | ||
243 | |||
244 | /* NEC NL2432DR22-11B */ | ||
245 | { | ||
246 | { | ||
247 | .x_res = 240, | ||
248 | .y_res = 320, | ||
249 | |||
250 | .pixel_clock = 5400, | ||
251 | |||
252 | .hsw = 3, | ||
253 | .hfp = 3, | ||
254 | .hbp = 39, | ||
255 | |||
256 | .vsw = 1, | ||
257 | .vfp = 2, | ||
258 | .vbp = 7, | ||
259 | |||
260 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
261 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
262 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
263 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
264 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
265 | }, | ||
266 | .name = "nec_nl2432dr22-11b", | ||
267 | }, | ||
268 | |||
269 | /* Unknown panel used in OMAP H4 */ | ||
270 | { | ||
271 | { | ||
272 | .x_res = 240, | ||
273 | .y_res = 320, | ||
274 | |||
275 | .pixel_clock = 6250, | ||
276 | |||
277 | .hsw = 15, | ||
278 | .hfp = 15, | ||
279 | .hbp = 60, | ||
280 | |||
281 | .vsw = 1, | ||
282 | .vfp = 1, | ||
283 | .vbp = 1, | ||
284 | |||
285 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
286 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
287 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
288 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
289 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
290 | }, | ||
291 | .name = "h4", | ||
292 | }, | ||
293 | |||
294 | /* Unknown panel used in Samsung OMAP2 Apollon */ | ||
295 | { | ||
296 | { | ||
297 | .x_res = 480, | ||
298 | .y_res = 272, | ||
299 | |||
300 | .pixel_clock = 6250, | ||
301 | |||
302 | .hsw = 41, | ||
303 | .hfp = 2, | ||
304 | .hbp = 2, | ||
305 | |||
306 | .vsw = 10, | ||
307 | .vfp = 2, | ||
308 | .vbp = 2, | ||
309 | |||
310 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
311 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
312 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
313 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
314 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
315 | }, | ||
316 | .name = "apollon", | ||
317 | }, | ||
318 | /* FocalTech ETM070003DH6 */ | ||
319 | { | ||
320 | { | ||
321 | .x_res = 800, | ||
322 | .y_res = 480, | ||
323 | |||
324 | .pixel_clock = 28000, | ||
325 | |||
326 | .hsw = 48, | ||
327 | .hfp = 40, | ||
328 | .hbp = 40, | ||
329 | |||
330 | .vsw = 3, | ||
331 | .vfp = 13, | ||
332 | .vbp = 29, | ||
333 | |||
334 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
335 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
336 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
337 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
338 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
339 | }, | ||
340 | .name = "focaltech_etm070003dh6", | ||
341 | }, | ||
342 | |||
343 | /* Microtips Technologies - UMSH-8173MD */ | ||
344 | { | ||
345 | { | ||
346 | .x_res = 800, | ||
347 | .y_res = 480, | ||
348 | |||
349 | .pixel_clock = 34560, | ||
350 | |||
351 | .hsw = 13, | ||
352 | .hfp = 101, | ||
353 | .hbp = 101, | ||
354 | |||
355 | .vsw = 23, | ||
356 | .vfp = 1, | ||
357 | .vbp = 1, | ||
358 | |||
359 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
360 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
361 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
362 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
363 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
364 | }, | ||
365 | .power_on_delay = 0, | ||
366 | .power_off_delay = 0, | ||
367 | .name = "microtips_umsh_8173md", | ||
368 | }, | ||
369 | |||
370 | /* OrtusTech COM43H4M10XTC */ | ||
371 | { | ||
372 | { | ||
373 | .x_res = 480, | ||
374 | .y_res = 272, | ||
375 | |||
376 | .pixel_clock = 8000, | ||
377 | |||
378 | .hsw = 41, | ||
379 | .hfp = 8, | ||
380 | .hbp = 4, | ||
381 | |||
382 | .vsw = 10, | ||
383 | .vfp = 4, | ||
384 | .vbp = 2, | ||
385 | |||
386 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
387 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
388 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
389 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
390 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
391 | }, | ||
392 | .name = "ortustech_com43h4m10xtc", | ||
393 | }, | ||
394 | |||
395 | /* Innolux AT080TN52 */ | ||
396 | { | ||
397 | { | ||
398 | .x_res = 800, | ||
399 | .y_res = 600, | ||
400 | |||
401 | .pixel_clock = 41142, | ||
402 | |||
403 | .hsw = 20, | ||
404 | .hfp = 210, | ||
405 | .hbp = 46, | ||
406 | |||
407 | .vsw = 10, | ||
408 | .vfp = 12, | ||
409 | .vbp = 23, | ||
410 | |||
411 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
412 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
413 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
414 | .de_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
415 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
416 | }, | ||
417 | .name = "innolux_at080tn52", | ||
418 | }, | ||
419 | |||
420 | /* Mitsubishi AA084SB01 */ | ||
421 | { | ||
422 | { | ||
423 | .x_res = 800, | ||
424 | .y_res = 600, | ||
425 | .pixel_clock = 40000, | ||
426 | |||
427 | .hsw = 1, | ||
428 | .hfp = 254, | ||
429 | .hbp = 1, | ||
430 | |||
431 | .vsw = 1, | ||
432 | .vfp = 26, | ||
433 | .vbp = 1, | ||
434 | |||
435 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
436 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
437 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
438 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
439 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
440 | }, | ||
441 | .name = "mitsubishi_aa084sb01", | ||
442 | }, | ||
443 | /* EDT ET0500G0DH6 */ | ||
444 | { | ||
445 | { | ||
446 | .x_res = 800, | ||
447 | .y_res = 480, | ||
448 | .pixel_clock = 33260, | ||
449 | |||
450 | .hsw = 128, | ||
451 | .hfp = 216, | ||
452 | .hbp = 40, | ||
453 | |||
454 | .vsw = 2, | ||
455 | .vfp = 35, | ||
456 | .vbp = 10, | ||
457 | |||
458 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
459 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
460 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
461 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
462 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
463 | }, | ||
464 | .name = "edt_et0500g0dh6", | ||
465 | }, | ||
466 | |||
467 | /* Prime-View PD050VL1 */ | ||
468 | { | ||
469 | { | ||
470 | .x_res = 640, | ||
471 | .y_res = 480, | ||
472 | |||
473 | .pixel_clock = 25000, | ||
474 | |||
475 | .hsw = 96, | ||
476 | .hfp = 18, | ||
477 | .hbp = 46, | ||
478 | |||
479 | .vsw = 2, | ||
480 | .vfp = 10, | ||
481 | .vbp = 33, | ||
482 | |||
483 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
484 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
485 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
486 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
487 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
488 | }, | ||
489 | .name = "primeview_pd050vl1", | ||
490 | }, | ||
491 | |||
492 | /* Prime-View PM070WL4 */ | ||
493 | { | ||
494 | { | ||
495 | .x_res = 800, | ||
496 | .y_res = 480, | ||
497 | |||
498 | .pixel_clock = 32000, | ||
499 | |||
500 | .hsw = 128, | ||
501 | .hfp = 42, | ||
502 | .hbp = 86, | ||
503 | |||
504 | .vsw = 2, | ||
505 | .vfp = 10, | ||
506 | .vbp = 33, | ||
507 | |||
508 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
509 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
510 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
511 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
512 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
513 | }, | ||
514 | .name = "primeview_pm070wl4", | ||
515 | }, | ||
516 | |||
517 | /* Prime-View PD104SLF */ | ||
518 | { | ||
519 | { | ||
520 | .x_res = 800, | ||
521 | .y_res = 600, | ||
522 | |||
523 | .pixel_clock = 40000, | ||
524 | |||
525 | .hsw = 128, | ||
526 | .hfp = 42, | ||
527 | .hbp = 86, | ||
528 | |||
529 | .vsw = 4, | ||
530 | .vfp = 1, | ||
531 | .vbp = 23, | ||
532 | |||
533 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
534 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
535 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
536 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
537 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
538 | }, | ||
539 | .name = "primeview_pd104slf", | ||
540 | }, | ||
541 | }; | 235 | }; |
542 | 236 | ||
543 | struct panel_drv_data { | 237 | struct panel_drv_data { |
@@ -545,8 +239,6 @@ struct panel_drv_data { | |||
545 | struct omap_dss_device *dssdev; | 239 | struct omap_dss_device *dssdev; |
546 | 240 | ||
547 | struct panel_config *panel_config; | 241 | struct panel_config *panel_config; |
548 | |||
549 | struct mutex lock; | ||
550 | }; | 242 | }; |
551 | 243 | ||
552 | static inline struct panel_generic_dpi_data | 244 | static inline struct panel_generic_dpi_data |
@@ -565,9 +257,6 @@ static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev) | |||
565 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 257 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
566 | return 0; | 258 | return 0; |
567 | 259 | ||
568 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
569 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
570 | |||
571 | r = omapdss_dpi_display_enable(dssdev); | 260 | r = omapdss_dpi_display_enable(dssdev); |
572 | if (r) | 261 | if (r) |
573 | goto err0; | 262 | goto err0; |
@@ -630,7 +319,10 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
630 | if (!panel_config) | 319 | if (!panel_config) |
631 | return -EINVAL; | 320 | return -EINVAL; |
632 | 321 | ||
322 | dssdev->panel.config = panel_config->config; | ||
633 | dssdev->panel.timings = panel_config->timings; | 323 | dssdev->panel.timings = panel_config->timings; |
324 | dssdev->panel.acb = panel_config->acb; | ||
325 | dssdev->panel.acbi = panel_config->acbi; | ||
634 | 326 | ||
635 | drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); | 327 | drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); |
636 | if (!drv_data) | 328 | if (!drv_data) |
@@ -639,8 +331,6 @@ static int generic_dpi_panel_probe(struct omap_dss_device *dssdev) | |||
639 | drv_data->dssdev = dssdev; | 331 | drv_data->dssdev = dssdev; |
640 | drv_data->panel_config = panel_config; | 332 | drv_data->panel_config = panel_config; |
641 | 333 | ||
642 | mutex_init(&drv_data->lock); | ||
643 | |||
644 | dev_set_drvdata(&dssdev->dev, drv_data); | 334 | dev_set_drvdata(&dssdev->dev, drv_data); |
645 | 335 | ||
646 | return 0; | 336 | return 0; |
@@ -659,74 +349,62 @@ static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev) | |||
659 | 349 | ||
660 | static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) | 350 | static int generic_dpi_panel_enable(struct omap_dss_device *dssdev) |
661 | { | 351 | { |
662 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 352 | int r = 0; |
663 | int r; | ||
664 | |||
665 | mutex_lock(&drv_data->lock); | ||
666 | 353 | ||
667 | r = generic_dpi_panel_power_on(dssdev); | 354 | r = generic_dpi_panel_power_on(dssdev); |
668 | if (r) | 355 | if (r) |
669 | goto err; | 356 | return r; |
670 | 357 | ||
671 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 358 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
672 | err: | ||
673 | mutex_unlock(&drv_data->lock); | ||
674 | 359 | ||
675 | return r; | 360 | return 0; |
676 | } | 361 | } |
677 | 362 | ||
678 | static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) | 363 | static void generic_dpi_panel_disable(struct omap_dss_device *dssdev) |
679 | { | 364 | { |
680 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 365 | generic_dpi_panel_power_off(dssdev); |
681 | 366 | ||
682 | mutex_lock(&drv_data->lock); | 367 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
368 | } | ||
683 | 369 | ||
370 | static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev) | ||
371 | { | ||
684 | generic_dpi_panel_power_off(dssdev); | 372 | generic_dpi_panel_power_off(dssdev); |
685 | 373 | ||
686 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 374 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; |
687 | 375 | ||
688 | mutex_unlock(&drv_data->lock); | 376 | return 0; |
689 | } | 377 | } |
690 | 378 | ||
691 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, | 379 | static int generic_dpi_panel_resume(struct omap_dss_device *dssdev) |
692 | struct omap_video_timings *timings) | ||
693 | { | 380 | { |
694 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 381 | int r = 0; |
695 | 382 | ||
696 | mutex_lock(&drv_data->lock); | 383 | r = generic_dpi_panel_power_on(dssdev); |
384 | if (r) | ||
385 | return r; | ||
697 | 386 | ||
698 | omapdss_dpi_set_timings(dssdev, timings); | 387 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
699 | 388 | ||
700 | dssdev->panel.timings = *timings; | 389 | return 0; |
390 | } | ||
701 | 391 | ||
702 | mutex_unlock(&drv_data->lock); | 392 | static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev, |
393 | struct omap_video_timings *timings) | ||
394 | { | ||
395 | dpi_set_timings(dssdev, timings); | ||
703 | } | 396 | } |
704 | 397 | ||
705 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, | 398 | static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev, |
706 | struct omap_video_timings *timings) | 399 | struct omap_video_timings *timings) |
707 | { | 400 | { |
708 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | ||
709 | |||
710 | mutex_lock(&drv_data->lock); | ||
711 | |||
712 | *timings = dssdev->panel.timings; | 401 | *timings = dssdev->panel.timings; |
713 | |||
714 | mutex_unlock(&drv_data->lock); | ||
715 | } | 402 | } |
716 | 403 | ||
717 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, | 404 | static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev, |
718 | struct omap_video_timings *timings) | 405 | struct omap_video_timings *timings) |
719 | { | 406 | { |
720 | struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev); | 407 | return dpi_check_timings(dssdev, timings); |
721 | int r; | ||
722 | |||
723 | mutex_lock(&drv_data->lock); | ||
724 | |||
725 | r = dpi_check_timings(dssdev, timings); | ||
726 | |||
727 | mutex_unlock(&drv_data->lock); | ||
728 | |||
729 | return r; | ||
730 | } | 408 | } |
731 | 409 | ||
732 | static struct omap_dss_driver dpi_driver = { | 410 | static struct omap_dss_driver dpi_driver = { |
@@ -735,6 +413,8 @@ static struct omap_dss_driver dpi_driver = { | |||
735 | 413 | ||
736 | .enable = generic_dpi_panel_enable, | 414 | .enable = generic_dpi_panel_enable, |
737 | .disable = generic_dpi_panel_disable, | 415 | .disable = generic_dpi_panel_disable, |
416 | .suspend = generic_dpi_panel_suspend, | ||
417 | .resume = generic_dpi_panel_resume, | ||
738 | 418 | ||
739 | .set_timings = generic_dpi_panel_set_timings, | 419 | .set_timings = generic_dpi_panel_set_timings, |
740 | .get_timings = generic_dpi_panel_get_timings, | 420 | .get_timings = generic_dpi_panel_get_timings, |
diff --git a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c index 6e5abe8fd2d..e0eb35be303 100644 --- a/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c +++ b/drivers/video/omap2/displays/panel-lgphilips-lb035q02.c | |||
@@ -40,12 +40,6 @@ static struct omap_video_timings lb035q02_timings = { | |||
40 | .vsw = 2, | 40 | .vsw = 2, |
41 | .vfp = 4, | 41 | .vfp = 4, |
42 | .vbp = 18, | 42 | .vbp = 18, |
43 | |||
44 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
45 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
46 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
47 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
48 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
49 | }; | 43 | }; |
50 | 44 | ||
51 | static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) | 45 | static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) |
@@ -55,9 +49,6 @@ static int lb035q02_panel_power_on(struct omap_dss_device *dssdev) | |||
55 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 49 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
56 | return 0; | 50 | return 0; |
57 | 51 | ||
58 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
59 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
60 | |||
61 | r = omapdss_dpi_display_enable(dssdev); | 52 | r = omapdss_dpi_display_enable(dssdev); |
62 | if (r) | 53 | if (r) |
63 | goto err0; | 54 | goto err0; |
@@ -91,6 +82,8 @@ static int lb035q02_panel_probe(struct omap_dss_device *dssdev) | |||
91 | struct lb035q02_data *ld; | 82 | struct lb035q02_data *ld; |
92 | int r; | 83 | int r; |
93 | 84 | ||
85 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
86 | OMAP_DSS_LCD_IHS; | ||
94 | dssdev->panel.timings = lb035q02_timings; | 87 | dssdev->panel.timings = lb035q02_timings; |
95 | 88 | ||
96 | ld = kzalloc(sizeof(*ld), GFP_KERNEL); | 89 | ld = kzalloc(sizeof(*ld), GFP_KERNEL); |
@@ -143,12 +136,46 @@ static void lb035q02_panel_disable(struct omap_dss_device *dssdev) | |||
143 | mutex_unlock(&ld->lock); | 136 | mutex_unlock(&ld->lock); |
144 | } | 137 | } |
145 | 138 | ||
139 | static int lb035q02_panel_suspend(struct omap_dss_device *dssdev) | ||
140 | { | ||
141 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | ||
142 | |||
143 | mutex_lock(&ld->lock); | ||
144 | |||
145 | lb035q02_panel_power_off(dssdev); | ||
146 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
147 | |||
148 | mutex_unlock(&ld->lock); | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int lb035q02_panel_resume(struct omap_dss_device *dssdev) | ||
153 | { | ||
154 | struct lb035q02_data *ld = dev_get_drvdata(&dssdev->dev); | ||
155 | int r; | ||
156 | |||
157 | mutex_lock(&ld->lock); | ||
158 | |||
159 | r = lb035q02_panel_power_on(dssdev); | ||
160 | if (r) | ||
161 | goto err; | ||
162 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
163 | |||
164 | mutex_unlock(&ld->lock); | ||
165 | return 0; | ||
166 | err: | ||
167 | mutex_unlock(&ld->lock); | ||
168 | return r; | ||
169 | } | ||
170 | |||
146 | static struct omap_dss_driver lb035q02_driver = { | 171 | static struct omap_dss_driver lb035q02_driver = { |
147 | .probe = lb035q02_panel_probe, | 172 | .probe = lb035q02_panel_probe, |
148 | .remove = lb035q02_panel_remove, | 173 | .remove = lb035q02_panel_remove, |
149 | 174 | ||
150 | .enable = lb035q02_panel_enable, | 175 | .enable = lb035q02_panel_enable, |
151 | .disable = lb035q02_panel_disable, | 176 | .disable = lb035q02_panel_disable, |
177 | .suspend = lb035q02_panel_suspend, | ||
178 | .resume = lb035q02_panel_resume, | ||
152 | 179 | ||
153 | .driver = { | 180 | .driver = { |
154 | .name = "lgphilips_lb035q02_panel", | 181 | .name = "lgphilips_lb035q02_panel", |
@@ -216,13 +243,13 @@ static void init_lb035q02_panel(struct spi_device *spi) | |||
216 | lb035q02_write_reg(spi, 0x3b, 0x0806); | 243 | lb035q02_write_reg(spi, 0x3b, 0x0806); |
217 | } | 244 | } |
218 | 245 | ||
219 | static int lb035q02_panel_spi_probe(struct spi_device *spi) | 246 | static int __devinit lb035q02_panel_spi_probe(struct spi_device *spi) |
220 | { | 247 | { |
221 | init_lb035q02_panel(spi); | 248 | init_lb035q02_panel(spi); |
222 | return omap_dss_register_driver(&lb035q02_driver); | 249 | return omap_dss_register_driver(&lb035q02_driver); |
223 | } | 250 | } |
224 | 251 | ||
225 | static int lb035q02_panel_spi_remove(struct spi_device *spi) | 252 | static int __devexit lb035q02_panel_spi_remove(struct spi_device *spi) |
226 | { | 253 | { |
227 | omap_dss_unregister_driver(&lb035q02_driver); | 254 | omap_dss_unregister_driver(&lb035q02_driver); |
228 | return 0; | 255 | return 0; |
@@ -234,9 +261,19 @@ static struct spi_driver lb035q02_spi_driver = { | |||
234 | .owner = THIS_MODULE, | 261 | .owner = THIS_MODULE, |
235 | }, | 262 | }, |
236 | .probe = lb035q02_panel_spi_probe, | 263 | .probe = lb035q02_panel_spi_probe, |
237 | .remove = lb035q02_panel_spi_remove, | 264 | .remove = __devexit_p(lb035q02_panel_spi_remove), |
238 | }; | 265 | }; |
239 | 266 | ||
240 | module_spi_driver(lb035q02_spi_driver); | 267 | static int __init lb035q02_panel_drv_init(void) |
268 | { | ||
269 | return spi_register_driver(&lb035q02_spi_driver); | ||
270 | } | ||
271 | |||
272 | static void __exit lb035q02_panel_drv_exit(void) | ||
273 | { | ||
274 | spi_unregister_driver(&lb035q02_spi_driver); | ||
275 | } | ||
241 | 276 | ||
277 | module_init(lb035q02_panel_drv_init); | ||
278 | module_exit(lb035q02_panel_drv_exit); | ||
242 | MODULE_LICENSE("GPL"); | 279 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap2/displays/panel-n8x0.c b/drivers/video/omap2/displays/panel-n8x0.c deleted file mode 100644 index dd129475080..00000000000 --- a/drivers/video/omap2/displays/panel-n8x0.c +++ /dev/null | |||
@@ -1,687 +0,0 @@ | |||
1 | /* #define DEBUG */ | ||
2 | |||
3 | #include <linux/module.h> | ||
4 | #include <linux/delay.h> | ||
5 | #include <linux/slab.h> | ||
6 | #include <linux/gpio.h> | ||
7 | #include <linux/spi/spi.h> | ||
8 | #include <linux/backlight.h> | ||
9 | #include <linux/fb.h> | ||
10 | |||
11 | #include <video/omapdss.h> | ||
12 | #include <video/omap-panel-n8x0.h> | ||
13 | |||
14 | #define BLIZZARD_REV_CODE 0x00 | ||
15 | #define BLIZZARD_CONFIG 0x02 | ||
16 | #define BLIZZARD_PLL_DIV 0x04 | ||
17 | #define BLIZZARD_PLL_LOCK_RANGE 0x06 | ||
18 | #define BLIZZARD_PLL_CLOCK_SYNTH_0 0x08 | ||
19 | #define BLIZZARD_PLL_CLOCK_SYNTH_1 0x0a | ||
20 | #define BLIZZARD_PLL_MODE 0x0c | ||
21 | #define BLIZZARD_CLK_SRC 0x0e | ||
22 | #define BLIZZARD_MEM_BANK0_ACTIVATE 0x10 | ||
23 | #define BLIZZARD_MEM_BANK0_STATUS 0x14 | ||
24 | #define BLIZZARD_PANEL_CONFIGURATION 0x28 | ||
25 | #define BLIZZARD_HDISP 0x2a | ||
26 | #define BLIZZARD_HNDP 0x2c | ||
27 | #define BLIZZARD_VDISP0 0x2e | ||
28 | #define BLIZZARD_VDISP1 0x30 | ||
29 | #define BLIZZARD_VNDP 0x32 | ||
30 | #define BLIZZARD_HSW 0x34 | ||
31 | #define BLIZZARD_VSW 0x38 | ||
32 | #define BLIZZARD_DISPLAY_MODE 0x68 | ||
33 | #define BLIZZARD_INPUT_WIN_X_START_0 0x6c | ||
34 | #define BLIZZARD_DATA_SOURCE_SELECT 0x8e | ||
35 | #define BLIZZARD_DISP_MEM_DATA_PORT 0x90 | ||
36 | #define BLIZZARD_DISP_MEM_READ_ADDR0 0x92 | ||
37 | #define BLIZZARD_POWER_SAVE 0xE6 | ||
38 | #define BLIZZARD_NDISP_CTRL_STATUS 0xE8 | ||
39 | |||
40 | /* Data source select */ | ||
41 | /* For S1D13745 */ | ||
42 | #define BLIZZARD_SRC_WRITE_LCD_BACKGROUND 0x00 | ||
43 | #define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE 0x01 | ||
44 | #define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE 0x04 | ||
45 | #define BLIZZARD_SRC_DISABLE_OVERLAY 0x05 | ||
46 | /* For S1D13744 */ | ||
47 | #define BLIZZARD_SRC_WRITE_LCD 0x00 | ||
48 | #define BLIZZARD_SRC_BLT_LCD 0x06 | ||
49 | |||
50 | #define BLIZZARD_COLOR_RGB565 0x01 | ||
51 | #define BLIZZARD_COLOR_YUV420 0x09 | ||
52 | |||
53 | #define BLIZZARD_VERSION_S1D13745 0x01 /* Hailstorm */ | ||
54 | #define BLIZZARD_VERSION_S1D13744 0x02 /* Blizzard */ | ||
55 | |||
56 | #define MIPID_CMD_READ_DISP_ID 0x04 | ||
57 | #define MIPID_CMD_READ_RED 0x06 | ||
58 | #define MIPID_CMD_READ_GREEN 0x07 | ||
59 | #define MIPID_CMD_READ_BLUE 0x08 | ||
60 | #define MIPID_CMD_READ_DISP_STATUS 0x09 | ||
61 | #define MIPID_CMD_RDDSDR 0x0F | ||
62 | #define MIPID_CMD_SLEEP_IN 0x10 | ||
63 | #define MIPID_CMD_SLEEP_OUT 0x11 | ||
64 | #define MIPID_CMD_DISP_OFF 0x28 | ||
65 | #define MIPID_CMD_DISP_ON 0x29 | ||
66 | |||
67 | static struct panel_drv_data { | ||
68 | struct mutex lock; | ||
69 | |||
70 | struct omap_dss_device *dssdev; | ||
71 | struct spi_device *spidev; | ||
72 | struct backlight_device *bldev; | ||
73 | |||
74 | int blizzard_ver; | ||
75 | } s_drv_data; | ||
76 | |||
77 | |||
78 | static inline | ||
79 | struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev) | ||
80 | { | ||
81 | return dssdev->data; | ||
82 | } | ||
83 | |||
84 | static inline | ||
85 | struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev) | ||
86 | { | ||
87 | return &s_drv_data; | ||
88 | } | ||
89 | |||
90 | |||
91 | static inline void blizzard_cmd(u8 cmd) | ||
92 | { | ||
93 | omap_rfbi_write_command(&cmd, 1); | ||
94 | } | ||
95 | |||
96 | static inline void blizzard_write(u8 cmd, const u8 *buf, int len) | ||
97 | { | ||
98 | omap_rfbi_write_command(&cmd, 1); | ||
99 | omap_rfbi_write_data(buf, len); | ||
100 | } | ||
101 | |||
102 | static inline void blizzard_read(u8 cmd, u8 *buf, int len) | ||
103 | { | ||
104 | omap_rfbi_write_command(&cmd, 1); | ||
105 | omap_rfbi_read_data(buf, len); | ||
106 | } | ||
107 | |||
108 | static u8 blizzard_read_reg(u8 cmd) | ||
109 | { | ||
110 | u8 data; | ||
111 | blizzard_read(cmd, &data, 1); | ||
112 | return data; | ||
113 | } | ||
114 | |||
115 | static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev, | ||
116 | int x, int y, int w, int h) | ||
117 | { | ||
118 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
119 | u8 tmp[18]; | ||
120 | int x_end, y_end; | ||
121 | |||
122 | x_end = x + w - 1; | ||
123 | y_end = y + h - 1; | ||
124 | |||
125 | tmp[0] = x; | ||
126 | tmp[1] = x >> 8; | ||
127 | tmp[2] = y; | ||
128 | tmp[3] = y >> 8; | ||
129 | tmp[4] = x_end; | ||
130 | tmp[5] = x_end >> 8; | ||
131 | tmp[6] = y_end; | ||
132 | tmp[7] = y_end >> 8; | ||
133 | |||
134 | /* scaling? */ | ||
135 | tmp[8] = x; | ||
136 | tmp[9] = x >> 8; | ||
137 | tmp[10] = y; | ||
138 | tmp[11] = y >> 8; | ||
139 | tmp[12] = x_end; | ||
140 | tmp[13] = x_end >> 8; | ||
141 | tmp[14] = y_end; | ||
142 | tmp[15] = y_end >> 8; | ||
143 | |||
144 | tmp[16] = BLIZZARD_COLOR_RGB565; | ||
145 | |||
146 | if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745) | ||
147 | tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND; | ||
148 | else | ||
149 | tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ? | ||
150 | BLIZZARD_SRC_WRITE_LCD : | ||
151 | BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE; | ||
152 | |||
153 | omapdss_rfbi_set_pixel_size(dssdev, 16); | ||
154 | omapdss_rfbi_set_data_lines(dssdev, 8); | ||
155 | |||
156 | omap_rfbi_configure(dssdev); | ||
157 | |||
158 | blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18); | ||
159 | |||
160 | omapdss_rfbi_set_pixel_size(dssdev, 16); | ||
161 | omapdss_rfbi_set_data_lines(dssdev, 16); | ||
162 | |||
163 | omap_rfbi_configure(dssdev); | ||
164 | } | ||
165 | |||
166 | static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf, | ||
167 | int wlen, u8 *rbuf, int rlen) | ||
168 | { | ||
169 | struct spi_message m; | ||
170 | struct spi_transfer *x, xfer[4]; | ||
171 | u16 w; | ||
172 | int r; | ||
173 | |||
174 | spi_message_init(&m); | ||
175 | |||
176 | memset(xfer, 0, sizeof(xfer)); | ||
177 | x = &xfer[0]; | ||
178 | |||
179 | cmd &= 0xff; | ||
180 | x->tx_buf = &cmd; | ||
181 | x->bits_per_word = 9; | ||
182 | x->len = 2; | ||
183 | spi_message_add_tail(x, &m); | ||
184 | |||
185 | if (wlen) { | ||
186 | x++; | ||
187 | x->tx_buf = wbuf; | ||
188 | x->len = wlen; | ||
189 | x->bits_per_word = 9; | ||
190 | spi_message_add_tail(x, &m); | ||
191 | } | ||
192 | |||
193 | if (rlen) { | ||
194 | x++; | ||
195 | x->rx_buf = &w; | ||
196 | x->len = 1; | ||
197 | spi_message_add_tail(x, &m); | ||
198 | |||
199 | if (rlen > 1) { | ||
200 | /* Arrange for the extra clock before the first | ||
201 | * data bit. | ||
202 | */ | ||
203 | x->bits_per_word = 9; | ||
204 | x->len = 2; | ||
205 | |||
206 | x++; | ||
207 | x->rx_buf = &rbuf[1]; | ||
208 | x->len = rlen - 1; | ||
209 | spi_message_add_tail(x, &m); | ||
210 | } | ||
211 | } | ||
212 | |||
213 | r = spi_sync(spi, &m); | ||
214 | if (r < 0) | ||
215 | dev_dbg(&spi->dev, "spi_sync %d\n", r); | ||
216 | |||
217 | if (rlen) | ||
218 | rbuf[0] = w & 0xff; | ||
219 | } | ||
220 | |||
221 | static inline void mipid_cmd(struct spi_device *spi, int cmd) | ||
222 | { | ||
223 | mipid_transfer(spi, cmd, NULL, 0, NULL, 0); | ||
224 | } | ||
225 | |||
226 | static inline void mipid_write(struct spi_device *spi, | ||
227 | int reg, const u8 *buf, int len) | ||
228 | { | ||
229 | mipid_transfer(spi, reg, buf, len, NULL, 0); | ||
230 | } | ||
231 | |||
232 | static inline void mipid_read(struct spi_device *spi, | ||
233 | int reg, u8 *buf, int len) | ||
234 | { | ||
235 | mipid_transfer(spi, reg, NULL, 0, buf, len); | ||
236 | } | ||
237 | |||
238 | static void set_data_lines(struct spi_device *spi, int data_lines) | ||
239 | { | ||
240 | u16 par; | ||
241 | |||
242 | switch (data_lines) { | ||
243 | case 16: | ||
244 | par = 0x150; | ||
245 | break; | ||
246 | case 18: | ||
247 | par = 0x160; | ||
248 | break; | ||
249 | case 24: | ||
250 | par = 0x170; | ||
251 | break; | ||
252 | } | ||
253 | |||
254 | mipid_write(spi, 0x3a, (u8 *)&par, 2); | ||
255 | } | ||
256 | |||
257 | static void send_init_string(struct spi_device *spi) | ||
258 | { | ||
259 | u16 initpar[] = { 0x0102, 0x0100, 0x0100 }; | ||
260 | mipid_write(spi, 0xc2, (u8 *)initpar, sizeof(initpar)); | ||
261 | } | ||
262 | |||
263 | static void send_display_on(struct spi_device *spi) | ||
264 | { | ||
265 | mipid_cmd(spi, MIPID_CMD_DISP_ON); | ||
266 | } | ||
267 | |||
268 | static void send_display_off(struct spi_device *spi) | ||
269 | { | ||
270 | mipid_cmd(spi, MIPID_CMD_DISP_OFF); | ||
271 | } | ||
272 | |||
273 | static void send_sleep_out(struct spi_device *spi) | ||
274 | { | ||
275 | mipid_cmd(spi, MIPID_CMD_SLEEP_OUT); | ||
276 | msleep(120); | ||
277 | } | ||
278 | |||
279 | static void send_sleep_in(struct spi_device *spi) | ||
280 | { | ||
281 | mipid_cmd(spi, MIPID_CMD_SLEEP_IN); | ||
282 | msleep(50); | ||
283 | } | ||
284 | |||
285 | static int n8x0_panel_power_on(struct omap_dss_device *dssdev) | ||
286 | { | ||
287 | int r; | ||
288 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
289 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
290 | struct spi_device *spi = ddata->spidev; | ||
291 | u8 rev, conf; | ||
292 | u8 display_id[3]; | ||
293 | const char *panel_name; | ||
294 | |||
295 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
296 | return 0; | ||
297 | |||
298 | gpio_direction_output(bdata->ctrl_pwrdown, 1); | ||
299 | |||
300 | if (bdata->platform_enable) { | ||
301 | r = bdata->platform_enable(dssdev); | ||
302 | if (r) | ||
303 | goto err_plat_en; | ||
304 | } | ||
305 | |||
306 | omapdss_rfbi_set_size(dssdev, dssdev->panel.timings.x_res, | ||
307 | dssdev->panel.timings.y_res); | ||
308 | omapdss_rfbi_set_pixel_size(dssdev, dssdev->ctrl.pixel_size); | ||
309 | omapdss_rfbi_set_data_lines(dssdev, dssdev->phy.rfbi.data_lines); | ||
310 | omapdss_rfbi_set_interface_timings(dssdev, &dssdev->ctrl.rfbi_timings); | ||
311 | |||
312 | r = omapdss_rfbi_display_enable(dssdev); | ||
313 | if (r) | ||
314 | goto err_rfbi_en; | ||
315 | |||
316 | rev = blizzard_read_reg(BLIZZARD_REV_CODE); | ||
317 | conf = blizzard_read_reg(BLIZZARD_CONFIG); | ||
318 | |||
319 | switch (rev & 0xfc) { | ||
320 | case 0x9c: | ||
321 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744; | ||
322 | dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d " | ||
323 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
324 | break; | ||
325 | case 0xa4: | ||
326 | ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745; | ||
327 | dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d " | ||
328 | "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07); | ||
329 | break; | ||
330 | default: | ||
331 | dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev); | ||
332 | r = -ENODEV; | ||
333 | goto err_inv_chip; | ||
334 | } | ||
335 | |||
336 | /* panel */ | ||
337 | |||
338 | gpio_direction_output(bdata->panel_reset, 1); | ||
339 | |||
340 | mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3); | ||
341 | dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n", | ||
342 | display_id[0], display_id[1], display_id[2]); | ||
343 | |||
344 | switch (display_id[0]) { | ||
345 | case 0x45: | ||
346 | panel_name = "lph8923"; | ||
347 | break; | ||
348 | case 0x83: | ||
349 | panel_name = "ls041y3"; | ||
350 | break; | ||
351 | default: | ||
352 | dev_err(&dssdev->dev, "invalid display ID 0x%x\n", | ||
353 | display_id[0]); | ||
354 | r = -ENODEV; | ||
355 | goto err_inv_panel; | ||
356 | } | ||
357 | |||
358 | dev_info(&dssdev->dev, "%s rev %02x LCD detected\n", | ||
359 | panel_name, display_id[1]); | ||
360 | |||
361 | send_sleep_out(spi); | ||
362 | send_init_string(spi); | ||
363 | set_data_lines(spi, 24); | ||
364 | send_display_on(spi); | ||
365 | |||
366 | return 0; | ||
367 | |||
368 | err_inv_panel: | ||
369 | /* | ||
370 | * HACK: we should turn off the panel here, but there is some problem | ||
371 | * with the initialization sequence, and we fail to init the panel if we | ||
372 | * have turned it off | ||
373 | */ | ||
374 | /* gpio_direction_output(bdata->panel_reset, 0); */ | ||
375 | err_inv_chip: | ||
376 | omapdss_rfbi_display_disable(dssdev); | ||
377 | err_rfbi_en: | ||
378 | if (bdata->platform_disable) | ||
379 | bdata->platform_disable(dssdev); | ||
380 | err_plat_en: | ||
381 | gpio_direction_output(bdata->ctrl_pwrdown, 0); | ||
382 | return r; | ||
383 | } | ||
384 | |||
385 | static void n8x0_panel_power_off(struct omap_dss_device *dssdev) | ||
386 | { | ||
387 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
388 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
389 | struct spi_device *spi = ddata->spidev; | ||
390 | |||
391 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
392 | return; | ||
393 | |||
394 | send_display_off(spi); | ||
395 | send_sleep_in(spi); | ||
396 | |||
397 | if (bdata->platform_disable) | ||
398 | bdata->platform_disable(dssdev); | ||
399 | |||
400 | /* | ||
401 | * HACK: we should turn off the panel here, but there is some problem | ||
402 | * with the initialization sequence, and we fail to init the panel if we | ||
403 | * have turned it off | ||
404 | */ | ||
405 | /* gpio_direction_output(bdata->panel_reset, 0); */ | ||
406 | gpio_direction_output(bdata->ctrl_pwrdown, 0); | ||
407 | omapdss_rfbi_display_disable(dssdev); | ||
408 | } | ||
409 | |||
410 | static const struct rfbi_timings n8x0_panel_timings = { | ||
411 | .cs_on_time = 0, | ||
412 | |||
413 | .we_on_time = 9000, | ||
414 | .we_off_time = 18000, | ||
415 | .we_cycle_time = 36000, | ||
416 | |||
417 | .re_on_time = 9000, | ||
418 | .re_off_time = 27000, | ||
419 | .re_cycle_time = 36000, | ||
420 | |||
421 | .access_time = 27000, | ||
422 | .cs_off_time = 36000, | ||
423 | |||
424 | .cs_pulse_width = 0, | ||
425 | }; | ||
426 | |||
427 | static int n8x0_bl_update_status(struct backlight_device *dev) | ||
428 | { | ||
429 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | ||
430 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
431 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
432 | int r; | ||
433 | int level; | ||
434 | |||
435 | mutex_lock(&ddata->lock); | ||
436 | |||
437 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
438 | dev->props.power == FB_BLANK_UNBLANK) | ||
439 | level = dev->props.brightness; | ||
440 | else | ||
441 | level = 0; | ||
442 | |||
443 | dev_dbg(&dssdev->dev, "update brightness to %d\n", level); | ||
444 | |||
445 | if (!bdata->set_backlight) | ||
446 | r = -EINVAL; | ||
447 | else | ||
448 | r = bdata->set_backlight(dssdev, level); | ||
449 | |||
450 | mutex_unlock(&ddata->lock); | ||
451 | |||
452 | return r; | ||
453 | } | ||
454 | |||
455 | static int n8x0_bl_get_intensity(struct backlight_device *dev) | ||
456 | { | ||
457 | if (dev->props.fb_blank == FB_BLANK_UNBLANK && | ||
458 | dev->props.power == FB_BLANK_UNBLANK) | ||
459 | return dev->props.brightness; | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | static const struct backlight_ops n8x0_bl_ops = { | ||
465 | .get_brightness = n8x0_bl_get_intensity, | ||
466 | .update_status = n8x0_bl_update_status, | ||
467 | }; | ||
468 | |||
469 | static int n8x0_panel_probe(struct omap_dss_device *dssdev) | ||
470 | { | ||
471 | struct panel_n8x0_data *bdata = get_board_data(dssdev); | ||
472 | struct panel_drv_data *ddata; | ||
473 | struct backlight_device *bldev; | ||
474 | struct backlight_properties props; | ||
475 | int r; | ||
476 | |||
477 | dev_dbg(&dssdev->dev, "probe\n"); | ||
478 | |||
479 | if (!bdata) | ||
480 | return -EINVAL; | ||
481 | |||
482 | s_drv_data.dssdev = dssdev; | ||
483 | |||
484 | ddata = &s_drv_data; | ||
485 | |||
486 | mutex_init(&ddata->lock); | ||
487 | |||
488 | dssdev->panel.timings.x_res = 800; | ||
489 | dssdev->panel.timings.y_res = 480; | ||
490 | dssdev->ctrl.pixel_size = 16; | ||
491 | dssdev->ctrl.rfbi_timings = n8x0_panel_timings; | ||
492 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
493 | |||
494 | memset(&props, 0, sizeof(props)); | ||
495 | props.max_brightness = 127; | ||
496 | props.type = BACKLIGHT_PLATFORM; | ||
497 | bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev, | ||
498 | dssdev, &n8x0_bl_ops, &props); | ||
499 | if (IS_ERR(bldev)) { | ||
500 | r = PTR_ERR(bldev); | ||
501 | dev_err(&dssdev->dev, "register backlight failed\n"); | ||
502 | return r; | ||
503 | } | ||
504 | |||
505 | ddata->bldev = bldev; | ||
506 | |||
507 | bldev->props.fb_blank = FB_BLANK_UNBLANK; | ||
508 | bldev->props.power = FB_BLANK_UNBLANK; | ||
509 | bldev->props.brightness = 127; | ||
510 | |||
511 | n8x0_bl_update_status(bldev); | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static void n8x0_panel_remove(struct omap_dss_device *dssdev) | ||
517 | { | ||
518 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
519 | struct backlight_device *bldev; | ||
520 | |||
521 | dev_dbg(&dssdev->dev, "remove\n"); | ||
522 | |||
523 | bldev = ddata->bldev; | ||
524 | bldev->props.power = FB_BLANK_POWERDOWN; | ||
525 | n8x0_bl_update_status(bldev); | ||
526 | backlight_device_unregister(bldev); | ||
527 | |||
528 | dev_set_drvdata(&dssdev->dev, NULL); | ||
529 | } | ||
530 | |||
531 | static int n8x0_panel_enable(struct omap_dss_device *dssdev) | ||
532 | { | ||
533 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
534 | int r; | ||
535 | |||
536 | dev_dbg(&dssdev->dev, "enable\n"); | ||
537 | |||
538 | mutex_lock(&ddata->lock); | ||
539 | |||
540 | rfbi_bus_lock(); | ||
541 | |||
542 | r = n8x0_panel_power_on(dssdev); | ||
543 | |||
544 | rfbi_bus_unlock(); | ||
545 | |||
546 | if (r) { | ||
547 | mutex_unlock(&ddata->lock); | ||
548 | return r; | ||
549 | } | ||
550 | |||
551 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
552 | |||
553 | mutex_unlock(&ddata->lock); | ||
554 | |||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static void n8x0_panel_disable(struct omap_dss_device *dssdev) | ||
559 | { | ||
560 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
561 | |||
562 | dev_dbg(&dssdev->dev, "disable\n"); | ||
563 | |||
564 | mutex_lock(&ddata->lock); | ||
565 | |||
566 | rfbi_bus_lock(); | ||
567 | |||
568 | n8x0_panel_power_off(dssdev); | ||
569 | |||
570 | rfbi_bus_unlock(); | ||
571 | |||
572 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
573 | |||
574 | mutex_unlock(&ddata->lock); | ||
575 | } | ||
576 | |||
577 | static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev, | ||
578 | u16 *xres, u16 *yres) | ||
579 | { | ||
580 | *xres = dssdev->panel.timings.x_res; | ||
581 | *yres = dssdev->panel.timings.y_res; | ||
582 | } | ||
583 | |||
584 | static void update_done(void *data) | ||
585 | { | ||
586 | rfbi_bus_unlock(); | ||
587 | } | ||
588 | |||
589 | static int n8x0_panel_update(struct omap_dss_device *dssdev, | ||
590 | u16 x, u16 y, u16 w, u16 h) | ||
591 | { | ||
592 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
593 | u16 dw, dh; | ||
594 | |||
595 | dev_dbg(&dssdev->dev, "update\n"); | ||
596 | |||
597 | dw = dssdev->panel.timings.x_res; | ||
598 | dh = dssdev->panel.timings.y_res; | ||
599 | |||
600 | if (x != 0 || y != 0 || w != dw || h != dh) { | ||
601 | dev_err(&dssdev->dev, "invaid update region %d, %d, %d, %d\n", | ||
602 | x, y, w, h); | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | mutex_lock(&ddata->lock); | ||
607 | rfbi_bus_lock(); | ||
608 | |||
609 | blizzard_ctrl_setup_update(dssdev, x, y, w, h); | ||
610 | |||
611 | omap_rfbi_update(dssdev, update_done, NULL); | ||
612 | |||
613 | mutex_unlock(&ddata->lock); | ||
614 | |||
615 | return 0; | ||
616 | } | ||
617 | |||
618 | static int n8x0_panel_sync(struct omap_dss_device *dssdev) | ||
619 | { | ||
620 | struct panel_drv_data *ddata = get_drv_data(dssdev); | ||
621 | |||
622 | dev_dbg(&dssdev->dev, "sync\n"); | ||
623 | |||
624 | mutex_lock(&ddata->lock); | ||
625 | rfbi_bus_lock(); | ||
626 | rfbi_bus_unlock(); | ||
627 | mutex_unlock(&ddata->lock); | ||
628 | |||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static struct omap_dss_driver n8x0_panel_driver = { | ||
633 | .probe = n8x0_panel_probe, | ||
634 | .remove = n8x0_panel_remove, | ||
635 | |||
636 | .enable = n8x0_panel_enable, | ||
637 | .disable = n8x0_panel_disable, | ||
638 | |||
639 | .update = n8x0_panel_update, | ||
640 | .sync = n8x0_panel_sync, | ||
641 | |||
642 | .get_resolution = n8x0_panel_get_resolution, | ||
643 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
644 | |||
645 | .driver = { | ||
646 | .name = "n8x0_panel", | ||
647 | .owner = THIS_MODULE, | ||
648 | }, | ||
649 | }; | ||
650 | |||
651 | /* PANEL */ | ||
652 | |||
653 | static int mipid_spi_probe(struct spi_device *spi) | ||
654 | { | ||
655 | int r; | ||
656 | |||
657 | dev_dbg(&spi->dev, "mipid_spi_probe\n"); | ||
658 | |||
659 | spi->mode = SPI_MODE_0; | ||
660 | |||
661 | s_drv_data.spidev = spi; | ||
662 | |||
663 | r = omap_dss_register_driver(&n8x0_panel_driver); | ||
664 | if (r) | ||
665 | pr_err("n8x0_panel: dss driver registration failed\n"); | ||
666 | |||
667 | return r; | ||
668 | } | ||
669 | |||
670 | static int mipid_spi_remove(struct spi_device *spi) | ||
671 | { | ||
672 | dev_dbg(&spi->dev, "mipid_spi_remove\n"); | ||
673 | omap_dss_unregister_driver(&n8x0_panel_driver); | ||
674 | return 0; | ||
675 | } | ||
676 | |||
677 | static struct spi_driver mipid_spi_driver = { | ||
678 | .driver = { | ||
679 | .name = "lcd_mipid", | ||
680 | .owner = THIS_MODULE, | ||
681 | }, | ||
682 | .probe = mipid_spi_probe, | ||
683 | .remove = mipid_spi_remove, | ||
684 | }; | ||
685 | module_spi_driver(mipid_spi_driver); | ||
686 | |||
687 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c index c4e9c2b1b46..2ba9d0ca187 100644 --- a/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c +++ b/drivers/video/omap2/displays/panel-nec-nl8048hl11-01b.c | |||
@@ -76,12 +76,6 @@ static struct omap_video_timings nec_8048_panel_timings = { | |||
76 | .vfp = 3, | 76 | .vfp = 3, |
77 | .vsw = 1, | 77 | .vsw = 1, |
78 | .vbp = 4, | 78 | .vbp = 4, |
79 | |||
80 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
81 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
82 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
83 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
84 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
85 | }; | 79 | }; |
86 | 80 | ||
87 | static int nec_8048_bl_update_status(struct backlight_device *bl) | 81 | static int nec_8048_bl_update_status(struct backlight_device *bl) |
@@ -122,6 +116,9 @@ static int nec_8048_panel_probe(struct omap_dss_device *dssdev) | |||
122 | struct backlight_properties props; | 116 | struct backlight_properties props; |
123 | int r; | 117 | int r; |
124 | 118 | ||
119 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
120 | OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_RF | | ||
121 | OMAP_DSS_LCD_ONOFF; | ||
125 | dssdev->panel.timings = nec_8048_panel_timings; | 122 | dssdev->panel.timings = nec_8048_panel_timings; |
126 | 123 | ||
127 | necd = kzalloc(sizeof(*necd), GFP_KERNEL); | 124 | necd = kzalloc(sizeof(*necd), GFP_KERNEL); |
@@ -166,74 +163,50 @@ static void nec_8048_panel_remove(struct omap_dss_device *dssdev) | |||
166 | kfree(necd); | 163 | kfree(necd); |
167 | } | 164 | } |
168 | 165 | ||
169 | static int nec_8048_panel_power_on(struct omap_dss_device *dssdev) | 166 | static int nec_8048_panel_enable(struct omap_dss_device *dssdev) |
170 | { | 167 | { |
171 | int r; | 168 | int r = 0; |
172 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | 169 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); |
173 | struct backlight_device *bl = necd->bl; | 170 | struct backlight_device *bl = necd->bl; |
174 | 171 | ||
175 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
176 | return 0; | ||
177 | |||
178 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
179 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
180 | |||
181 | r = omapdss_dpi_display_enable(dssdev); | ||
182 | if (r) | ||
183 | goto err0; | ||
184 | |||
185 | if (dssdev->platform_enable) { | 172 | if (dssdev->platform_enable) { |
186 | r = dssdev->platform_enable(dssdev); | 173 | r = dssdev->platform_enable(dssdev); |
187 | if (r) | 174 | if (r) |
188 | goto err1; | 175 | return r; |
189 | } | 176 | } |
190 | 177 | ||
191 | r = nec_8048_bl_update_status(bl); | 178 | r = nec_8048_bl_update_status(bl); |
192 | if (r < 0) | 179 | if (r < 0) |
193 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); | 180 | dev_err(&dssdev->dev, "failed to set lcd brightness\n"); |
194 | 181 | ||
195 | return 0; | 182 | r = omapdss_dpi_display_enable(dssdev); |
196 | err1: | 183 | |
197 | omapdss_dpi_display_disable(dssdev); | ||
198 | err0: | ||
199 | return r; | 184 | return r; |
200 | } | 185 | } |
201 | 186 | ||
202 | static void nec_8048_panel_power_off(struct omap_dss_device *dssdev) | 187 | static void nec_8048_panel_disable(struct omap_dss_device *dssdev) |
203 | { | 188 | { |
204 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); | 189 | struct nec_8048_data *necd = dev_get_drvdata(&dssdev->dev); |
205 | struct backlight_device *bl = necd->bl; | 190 | struct backlight_device *bl = necd->bl; |
206 | 191 | ||
207 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 192 | omapdss_dpi_display_disable(dssdev); |
208 | return; | ||
209 | 193 | ||
210 | bl->props.brightness = 0; | 194 | bl->props.brightness = 0; |
211 | nec_8048_bl_update_status(bl); | 195 | nec_8048_bl_update_status(bl); |
212 | 196 | ||
213 | if (dssdev->platform_disable) | 197 | if (dssdev->platform_disable) |
214 | dssdev->platform_disable(dssdev); | 198 | dssdev->platform_disable(dssdev); |
215 | |||
216 | omapdss_dpi_display_disable(dssdev); | ||
217 | } | 199 | } |
218 | 200 | ||
219 | static int nec_8048_panel_enable(struct omap_dss_device *dssdev) | 201 | static int nec_8048_panel_suspend(struct omap_dss_device *dssdev) |
220 | { | 202 | { |
221 | int r; | 203 | nec_8048_panel_disable(dssdev); |
222 | |||
223 | r = nec_8048_panel_power_on(dssdev); | ||
224 | if (r) | ||
225 | return r; | ||
226 | |||
227 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
228 | |||
229 | return 0; | 204 | return 0; |
230 | } | 205 | } |
231 | 206 | ||
232 | static void nec_8048_panel_disable(struct omap_dss_device *dssdev) | 207 | static int nec_8048_panel_resume(struct omap_dss_device *dssdev) |
233 | { | 208 | { |
234 | nec_8048_panel_power_off(dssdev); | 209 | return nec_8048_panel_enable(dssdev); |
235 | |||
236 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
237 | } | 210 | } |
238 | 211 | ||
239 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) | 212 | static int nec_8048_recommended_bpp(struct omap_dss_device *dssdev) |
@@ -246,6 +219,8 @@ static struct omap_dss_driver nec_8048_driver = { | |||
246 | .remove = nec_8048_panel_remove, | 219 | .remove = nec_8048_panel_remove, |
247 | .enable = nec_8048_panel_enable, | 220 | .enable = nec_8048_panel_enable, |
248 | .disable = nec_8048_panel_disable, | 221 | .disable = nec_8048_panel_disable, |
222 | .suspend = nec_8048_panel_suspend, | ||
223 | .resume = nec_8048_panel_resume, | ||
249 | .get_recommended_bpp = nec_8048_recommended_bpp, | 224 | .get_recommended_bpp = nec_8048_recommended_bpp, |
250 | 225 | ||
251 | .driver = { | 226 | .driver = { |
@@ -323,17 +298,28 @@ static int nec_8048_spi_resume(struct spi_device *spi) | |||
323 | 298 | ||
324 | static struct spi_driver nec_8048_spi_driver = { | 299 | static struct spi_driver nec_8048_spi_driver = { |
325 | .probe = nec_8048_spi_probe, | 300 | .probe = nec_8048_spi_probe, |
326 | .remove = nec_8048_spi_remove, | 301 | .remove = __devexit_p(nec_8048_spi_remove), |
327 | .suspend = nec_8048_spi_suspend, | 302 | .suspend = nec_8048_spi_suspend, |
328 | .resume = nec_8048_spi_resume, | 303 | .resume = nec_8048_spi_resume, |
329 | .driver = { | 304 | .driver = { |
330 | .name = "nec_8048_spi", | 305 | .name = "nec_8048_spi", |
306 | .bus = &spi_bus_type, | ||
331 | .owner = THIS_MODULE, | 307 | .owner = THIS_MODULE, |
332 | }, | 308 | }, |
333 | }; | 309 | }; |
334 | 310 | ||
335 | module_spi_driver(nec_8048_spi_driver); | 311 | static int __init nec_8048_lcd_init(void) |
312 | { | ||
313 | return spi_register_driver(&nec_8048_spi_driver); | ||
314 | } | ||
315 | |||
316 | static void __exit nec_8048_lcd_exit(void) | ||
317 | { | ||
318 | return spi_unregister_driver(&nec_8048_spi_driver); | ||
319 | } | ||
336 | 320 | ||
321 | module_init(nec_8048_lcd_init); | ||
322 | module_exit(nec_8048_lcd_exit); | ||
337 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); | 323 | MODULE_AUTHOR("Erik Gilling <konkers@android.com>"); |
338 | MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); | 324 | MODULE_DESCRIPTION("NEC-nl8048hl11-01b Driver"); |
339 | MODULE_LICENSE("GPL"); | 325 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap2/displays/panel-picodlp.c b/drivers/video/omap2/displays/panel-picodlp.c deleted file mode 100644 index 1b94018aac3..00000000000 --- a/drivers/video/omap2/displays/panel-picodlp.c +++ /dev/null | |||
@@ -1,558 +0,0 @@ | |||
1 | /* | ||
2 | * picodlp panel driver | ||
3 | * picodlp_i2c_driver: i2c_client driver | ||
4 | * | ||
5 | * Copyright (C) 2009-2011 Texas Instruments | ||
6 | * Author: Mythri P K <mythripk@ti.com> | ||
7 | * Mayuresh Janorkar <mayur@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/mutex.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/gpio.h> | ||
32 | |||
33 | #include <video/omapdss.h> | ||
34 | #include <video/omap-panel-picodlp.h> | ||
35 | |||
36 | #include "panel-picodlp.h" | ||
37 | |||
38 | struct picodlp_data { | ||
39 | struct mutex lock; | ||
40 | struct i2c_client *picodlp_i2c_client; | ||
41 | }; | ||
42 | |||
43 | static struct i2c_board_info picodlp_i2c_board_info = { | ||
44 | I2C_BOARD_INFO("picodlp_i2c_driver", 0x1b), | ||
45 | }; | ||
46 | |||
47 | struct picodlp_i2c_data { | ||
48 | struct mutex xfer_lock; | ||
49 | }; | ||
50 | |||
51 | static struct i2c_device_id picodlp_i2c_id[] = { | ||
52 | { "picodlp_i2c_driver", 0 }, | ||
53 | { } | ||
54 | }; | ||
55 | |||
56 | struct picodlp_i2c_command { | ||
57 | u8 reg; | ||
58 | u32 value; | ||
59 | }; | ||
60 | |||
61 | static struct omap_video_timings pico_ls_timings = { | ||
62 | .x_res = 864, | ||
63 | .y_res = 480, | ||
64 | .hsw = 7, | ||
65 | .hfp = 11, | ||
66 | .hbp = 7, | ||
67 | |||
68 | .pixel_clock = 19200, | ||
69 | |||
70 | .vsw = 2, | ||
71 | .vfp = 3, | ||
72 | .vbp = 14, | ||
73 | |||
74 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
75 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
76 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
77 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
78 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
79 | }; | ||
80 | |||
81 | static inline struct picodlp_panel_data | ||
82 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
83 | { | ||
84 | return (struct picodlp_panel_data *) dssdev->data; | ||
85 | } | ||
86 | |||
87 | static u32 picodlp_i2c_read(struct i2c_client *client, u8 reg) | ||
88 | { | ||
89 | u8 read_cmd[] = {READ_REG_SELECT, reg}, data[4]; | ||
90 | struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); | ||
91 | struct i2c_msg msg[2]; | ||
92 | |||
93 | mutex_lock(&picodlp_i2c_data->xfer_lock); | ||
94 | |||
95 | msg[0].addr = client->addr; | ||
96 | msg[0].flags = 0; | ||
97 | msg[0].len = 2; | ||
98 | msg[0].buf = read_cmd; | ||
99 | |||
100 | msg[1].addr = client->addr; | ||
101 | msg[1].flags = I2C_M_RD; | ||
102 | msg[1].len = 4; | ||
103 | msg[1].buf = data; | ||
104 | |||
105 | i2c_transfer(client->adapter, msg, 2); | ||
106 | mutex_unlock(&picodlp_i2c_data->xfer_lock); | ||
107 | return (data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24)); | ||
108 | } | ||
109 | |||
110 | static int picodlp_i2c_write_block(struct i2c_client *client, | ||
111 | u8 *data, int len) | ||
112 | { | ||
113 | struct i2c_msg msg; | ||
114 | int i, r, msg_count = 1; | ||
115 | |||
116 | struct picodlp_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client); | ||
117 | |||
118 | if (len < 1 || len > 32) { | ||
119 | dev_err(&client->dev, | ||
120 | "too long syn_write_block len %d\n", len); | ||
121 | return -EIO; | ||
122 | } | ||
123 | mutex_lock(&picodlp_i2c_data->xfer_lock); | ||
124 | |||
125 | msg.addr = client->addr; | ||
126 | msg.flags = 0; | ||
127 | msg.len = len; | ||
128 | msg.buf = data; | ||
129 | r = i2c_transfer(client->adapter, &msg, msg_count); | ||
130 | mutex_unlock(&picodlp_i2c_data->xfer_lock); | ||
131 | |||
132 | /* | ||
133 | * i2c_transfer returns: | ||
134 | * number of messages sent in case of success | ||
135 | * a negative error number in case of failure | ||
136 | */ | ||
137 | if (r != msg_count) | ||
138 | goto err; | ||
139 | |||
140 | /* In case of success */ | ||
141 | for (i = 0; i < len; i++) | ||
142 | dev_dbg(&client->dev, | ||
143 | "addr %x bw 0x%02x[%d]: 0x%02x\n", | ||
144 | client->addr, data[0] + i, i, data[i]); | ||
145 | |||
146 | return 0; | ||
147 | err: | ||
148 | dev_err(&client->dev, "picodlp_i2c_write error\n"); | ||
149 | return r; | ||
150 | } | ||
151 | |||
152 | static int picodlp_i2c_write(struct i2c_client *client, u8 reg, u32 value) | ||
153 | { | ||
154 | u8 data[5]; | ||
155 | int i; | ||
156 | |||
157 | data[0] = reg; | ||
158 | for (i = 1; i < 5; i++) | ||
159 | data[i] = (value >> (32 - (i) * 8)) & 0xFF; | ||
160 | |||
161 | return picodlp_i2c_write_block(client, data, 5); | ||
162 | } | ||
163 | |||
164 | static int picodlp_i2c_write_array(struct i2c_client *client, | ||
165 | const struct picodlp_i2c_command commands[], | ||
166 | int count) | ||
167 | { | ||
168 | int i, r = 0; | ||
169 | for (i = 0; i < count; i++) { | ||
170 | r = picodlp_i2c_write(client, commands[i].reg, | ||
171 | commands[i].value); | ||
172 | if (r) | ||
173 | return r; | ||
174 | } | ||
175 | return r; | ||
176 | } | ||
177 | |||
178 | static int picodlp_wait_for_dma_done(struct i2c_client *client) | ||
179 | { | ||
180 | u8 trial = 100; | ||
181 | |||
182 | do { | ||
183 | msleep(1); | ||
184 | if (!trial--) | ||
185 | return -ETIMEDOUT; | ||
186 | } while (picodlp_i2c_read(client, MAIN_STATUS) & DMA_STATUS); | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /** | ||
192 | * picodlp_i2c_init: i2c_initialization routine | ||
193 | * client: i2c_client for communication | ||
194 | * | ||
195 | * return | ||
196 | * 0 : Success, no error | ||
197 | * error code : Failure | ||
198 | */ | ||
199 | static int picodlp_i2c_init(struct i2c_client *client) | ||
200 | { | ||
201 | int r; | ||
202 | static const struct picodlp_i2c_command init_cmd_set1[] = { | ||
203 | {SOFT_RESET, 1}, | ||
204 | {DMD_PARK_TRIGGER, 1}, | ||
205 | {MISC_REG, 5}, | ||
206 | {SEQ_CONTROL, 0}, | ||
207 | {SEQ_VECTOR, 0x100}, | ||
208 | {DMD_BLOCK_COUNT, 7}, | ||
209 | {DMD_VCC_CONTROL, 0x109}, | ||
210 | {DMD_PARK_PULSE_COUNT, 0xA}, | ||
211 | {DMD_PARK_PULSE_WIDTH, 0xB}, | ||
212 | {DMD_PARK_DELAY, 0x2ED}, | ||
213 | {DMD_SHADOW_ENABLE, 0}, | ||
214 | {FLASH_OPCODE, 0xB}, | ||
215 | {FLASH_DUMMY_BYTES, 1}, | ||
216 | {FLASH_ADDR_BYTES, 3}, | ||
217 | {PBC_CONTROL, 0}, | ||
218 | {FLASH_START_ADDR, CMT_LUT_0_START_ADDR}, | ||
219 | {FLASH_READ_BYTES, CMT_LUT_0_SIZE}, | ||
220 | {CMT_SPLASH_LUT_START_ADDR, 0}, | ||
221 | {CMT_SPLASH_LUT_DEST_SELECT, CMT_LUT_ALL}, | ||
222 | {PBC_CONTROL, 1}, | ||
223 | }; | ||
224 | |||
225 | static const struct picodlp_i2c_command init_cmd_set2[] = { | ||
226 | {PBC_CONTROL, 0}, | ||
227 | {CMT_SPLASH_LUT_DEST_SELECT, 0}, | ||
228 | {PBC_CONTROL, 0}, | ||
229 | {FLASH_START_ADDR, SEQUENCE_0_START_ADDR}, | ||
230 | {FLASH_READ_BYTES, SEQUENCE_0_SIZE}, | ||
231 | {SEQ_RESET_LUT_START_ADDR, 0}, | ||
232 | {SEQ_RESET_LUT_DEST_SELECT, SEQ_SEQ_LUT}, | ||
233 | {PBC_CONTROL, 1}, | ||
234 | }; | ||
235 | |||
236 | static const struct picodlp_i2c_command init_cmd_set3[] = { | ||
237 | {PBC_CONTROL, 0}, | ||
238 | {SEQ_RESET_LUT_DEST_SELECT, 0}, | ||
239 | {PBC_CONTROL, 0}, | ||
240 | {FLASH_START_ADDR, DRC_TABLE_0_START_ADDR}, | ||
241 | {FLASH_READ_BYTES, DRC_TABLE_0_SIZE}, | ||
242 | {SEQ_RESET_LUT_START_ADDR, 0}, | ||
243 | {SEQ_RESET_LUT_DEST_SELECT, SEQ_DRC_LUT_ALL}, | ||
244 | {PBC_CONTROL, 1}, | ||
245 | }; | ||
246 | |||
247 | static const struct picodlp_i2c_command init_cmd_set4[] = { | ||
248 | {PBC_CONTROL, 0}, | ||
249 | {SEQ_RESET_LUT_DEST_SELECT, 0}, | ||
250 | {SDC_ENABLE, 1}, | ||
251 | {AGC_CTRL, 7}, | ||
252 | {CCA_C1A, 0x100}, | ||
253 | {CCA_C1B, 0x0}, | ||
254 | {CCA_C1C, 0x0}, | ||
255 | {CCA_C2A, 0x0}, | ||
256 | {CCA_C2B, 0x100}, | ||
257 | {CCA_C2C, 0x0}, | ||
258 | {CCA_C3A, 0x0}, | ||
259 | {CCA_C3B, 0x0}, | ||
260 | {CCA_C3C, 0x100}, | ||
261 | {CCA_C7A, 0x100}, | ||
262 | {CCA_C7B, 0x100}, | ||
263 | {CCA_C7C, 0x100}, | ||
264 | {CCA_ENABLE, 1}, | ||
265 | {CPU_IF_MODE, 1}, | ||
266 | {SHORT_FLIP, 1}, | ||
267 | {CURTAIN_CONTROL, 0}, | ||
268 | {DMD_PARK_TRIGGER, 0}, | ||
269 | {R_DRIVE_CURRENT, 0x298}, | ||
270 | {G_DRIVE_CURRENT, 0x298}, | ||
271 | {B_DRIVE_CURRENT, 0x298}, | ||
272 | {RGB_DRIVER_ENABLE, 7}, | ||
273 | {SEQ_CONTROL, 0}, | ||
274 | {ACTGEN_CONTROL, 0x10}, | ||
275 | {SEQUENCE_MODE, SEQ_LOCK}, | ||
276 | {DATA_FORMAT, RGB888}, | ||
277 | {INPUT_RESOLUTION, WVGA_864_LANDSCAPE}, | ||
278 | {INPUT_SOURCE, PARALLEL_RGB}, | ||
279 | {CPU_IF_SYNC_METHOD, 1}, | ||
280 | {SEQ_CONTROL, 1} | ||
281 | }; | ||
282 | |||
283 | r = picodlp_i2c_write_array(client, init_cmd_set1, | ||
284 | ARRAY_SIZE(init_cmd_set1)); | ||
285 | if (r) | ||
286 | return r; | ||
287 | |||
288 | r = picodlp_wait_for_dma_done(client); | ||
289 | if (r) | ||
290 | return r; | ||
291 | |||
292 | r = picodlp_i2c_write_array(client, init_cmd_set2, | ||
293 | ARRAY_SIZE(init_cmd_set2)); | ||
294 | if (r) | ||
295 | return r; | ||
296 | |||
297 | r = picodlp_wait_for_dma_done(client); | ||
298 | if (r) | ||
299 | return r; | ||
300 | |||
301 | r = picodlp_i2c_write_array(client, init_cmd_set3, | ||
302 | ARRAY_SIZE(init_cmd_set3)); | ||
303 | if (r) | ||
304 | return r; | ||
305 | |||
306 | r = picodlp_wait_for_dma_done(client); | ||
307 | if (r) | ||
308 | return r; | ||
309 | |||
310 | r = picodlp_i2c_write_array(client, init_cmd_set4, | ||
311 | ARRAY_SIZE(init_cmd_set4)); | ||
312 | if (r) | ||
313 | return r; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int picodlp_i2c_probe(struct i2c_client *client, | ||
319 | const struct i2c_device_id *id) | ||
320 | { | ||
321 | struct picodlp_i2c_data *picodlp_i2c_data; | ||
322 | |||
323 | picodlp_i2c_data = kzalloc(sizeof(struct picodlp_i2c_data), GFP_KERNEL); | ||
324 | |||
325 | if (!picodlp_i2c_data) | ||
326 | return -ENOMEM; | ||
327 | |||
328 | mutex_init(&picodlp_i2c_data->xfer_lock); | ||
329 | i2c_set_clientdata(client, picodlp_i2c_data); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int picodlp_i2c_remove(struct i2c_client *client) | ||
335 | { | ||
336 | struct picodlp_i2c_data *picodlp_i2c_data = | ||
337 | i2c_get_clientdata(client); | ||
338 | kfree(picodlp_i2c_data); | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static struct i2c_driver picodlp_i2c_driver = { | ||
343 | .driver = { | ||
344 | .name = "picodlp_i2c_driver", | ||
345 | }, | ||
346 | .probe = picodlp_i2c_probe, | ||
347 | .remove = picodlp_i2c_remove, | ||
348 | .id_table = picodlp_i2c_id, | ||
349 | }; | ||
350 | |||
351 | static int picodlp_panel_power_on(struct omap_dss_device *dssdev) | ||
352 | { | ||
353 | int r, trial = 100; | ||
354 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | ||
355 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | ||
356 | |||
357 | if (dssdev->platform_enable) { | ||
358 | r = dssdev->platform_enable(dssdev); | ||
359 | if (r) | ||
360 | return r; | ||
361 | } | ||
362 | |||
363 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | ||
364 | msleep(1); | ||
365 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 1); | ||
366 | |||
367 | while (!gpio_get_value(picodlp_pdata->emu_done_gpio)) { | ||
368 | if (!trial--) { | ||
369 | dev_err(&dssdev->dev, "emu_done signal not" | ||
370 | " going high\n"); | ||
371 | return -ETIMEDOUT; | ||
372 | } | ||
373 | msleep(5); | ||
374 | } | ||
375 | /* | ||
376 | * As per dpp2600 programming guide, | ||
377 | * it is required to sleep for 1000ms after emu_done signal goes high | ||
378 | * then only i2c commands can be successfully sent to dpp2600 | ||
379 | */ | ||
380 | msleep(1000); | ||
381 | |||
382 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
383 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
384 | |||
385 | r = omapdss_dpi_display_enable(dssdev); | ||
386 | if (r) { | ||
387 | dev_err(&dssdev->dev, "failed to enable DPI\n"); | ||
388 | goto err1; | ||
389 | } | ||
390 | |||
391 | r = picodlp_i2c_init(picod->picodlp_i2c_client); | ||
392 | if (r) | ||
393 | goto err; | ||
394 | |||
395 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
396 | |||
397 | return r; | ||
398 | err: | ||
399 | omapdss_dpi_display_disable(dssdev); | ||
400 | err1: | ||
401 | if (dssdev->platform_disable) | ||
402 | dssdev->platform_disable(dssdev); | ||
403 | |||
404 | return r; | ||
405 | } | ||
406 | |||
407 | static void picodlp_panel_power_off(struct omap_dss_device *dssdev) | ||
408 | { | ||
409 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | ||
410 | |||
411 | omapdss_dpi_display_disable(dssdev); | ||
412 | |||
413 | gpio_set_value(picodlp_pdata->emu_done_gpio, 0); | ||
414 | gpio_set_value(picodlp_pdata->pwrgood_gpio, 0); | ||
415 | |||
416 | if (dssdev->platform_disable) | ||
417 | dssdev->platform_disable(dssdev); | ||
418 | } | ||
419 | |||
420 | static int picodlp_panel_probe(struct omap_dss_device *dssdev) | ||
421 | { | ||
422 | struct picodlp_data *picod; | ||
423 | struct picodlp_panel_data *picodlp_pdata = get_panel_data(dssdev); | ||
424 | struct i2c_adapter *adapter; | ||
425 | struct i2c_client *picodlp_i2c_client; | ||
426 | int r = 0, picodlp_adapter_id; | ||
427 | |||
428 | dssdev->panel.timings = pico_ls_timings; | ||
429 | |||
430 | picod = kzalloc(sizeof(struct picodlp_data), GFP_KERNEL); | ||
431 | if (!picod) | ||
432 | return -ENOMEM; | ||
433 | |||
434 | mutex_init(&picod->lock); | ||
435 | |||
436 | picodlp_adapter_id = picodlp_pdata->picodlp_adapter_id; | ||
437 | |||
438 | adapter = i2c_get_adapter(picodlp_adapter_id); | ||
439 | if (!adapter) { | ||
440 | dev_err(&dssdev->dev, "can't get i2c adapter\n"); | ||
441 | r = -ENODEV; | ||
442 | goto err; | ||
443 | } | ||
444 | |||
445 | picodlp_i2c_client = i2c_new_device(adapter, &picodlp_i2c_board_info); | ||
446 | if (!picodlp_i2c_client) { | ||
447 | dev_err(&dssdev->dev, "can't add i2c device::" | ||
448 | " picodlp_i2c_client is NULL\n"); | ||
449 | r = -ENODEV; | ||
450 | goto err; | ||
451 | } | ||
452 | |||
453 | picod->picodlp_i2c_client = picodlp_i2c_client; | ||
454 | |||
455 | dev_set_drvdata(&dssdev->dev, picod); | ||
456 | return r; | ||
457 | err: | ||
458 | kfree(picod); | ||
459 | return r; | ||
460 | } | ||
461 | |||
462 | static void picodlp_panel_remove(struct omap_dss_device *dssdev) | ||
463 | { | ||
464 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | ||
465 | |||
466 | i2c_unregister_device(picod->picodlp_i2c_client); | ||
467 | dev_set_drvdata(&dssdev->dev, NULL); | ||
468 | dev_dbg(&dssdev->dev, "removing picodlp panel\n"); | ||
469 | |||
470 | kfree(picod); | ||
471 | } | ||
472 | |||
473 | static int picodlp_panel_enable(struct omap_dss_device *dssdev) | ||
474 | { | ||
475 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | ||
476 | int r; | ||
477 | |||
478 | dev_dbg(&dssdev->dev, "enabling picodlp panel\n"); | ||
479 | |||
480 | mutex_lock(&picod->lock); | ||
481 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
482 | mutex_unlock(&picod->lock); | ||
483 | return -EINVAL; | ||
484 | } | ||
485 | |||
486 | r = picodlp_panel_power_on(dssdev); | ||
487 | mutex_unlock(&picod->lock); | ||
488 | |||
489 | return r; | ||
490 | } | ||
491 | |||
492 | static void picodlp_panel_disable(struct omap_dss_device *dssdev) | ||
493 | { | ||
494 | struct picodlp_data *picod = dev_get_drvdata(&dssdev->dev); | ||
495 | |||
496 | mutex_lock(&picod->lock); | ||
497 | /* Turn off DLP Power */ | ||
498 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
499 | picodlp_panel_power_off(dssdev); | ||
500 | |||
501 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
502 | mutex_unlock(&picod->lock); | ||
503 | |||
504 | dev_dbg(&dssdev->dev, "disabling picodlp panel\n"); | ||
505 | } | ||
506 | |||
507 | static void picodlp_get_resolution(struct omap_dss_device *dssdev, | ||
508 | u16 *xres, u16 *yres) | ||
509 | { | ||
510 | *xres = dssdev->panel.timings.x_res; | ||
511 | *yres = dssdev->panel.timings.y_res; | ||
512 | } | ||
513 | |||
514 | static struct omap_dss_driver picodlp_driver = { | ||
515 | .probe = picodlp_panel_probe, | ||
516 | .remove = picodlp_panel_remove, | ||
517 | |||
518 | .enable = picodlp_panel_enable, | ||
519 | .disable = picodlp_panel_disable, | ||
520 | |||
521 | .get_resolution = picodlp_get_resolution, | ||
522 | |||
523 | .driver = { | ||
524 | .name = "picodlp_panel", | ||
525 | .owner = THIS_MODULE, | ||
526 | }, | ||
527 | }; | ||
528 | |||
529 | static int __init picodlp_init(void) | ||
530 | { | ||
531 | int r = 0; | ||
532 | |||
533 | r = i2c_add_driver(&picodlp_i2c_driver); | ||
534 | if (r) { | ||
535 | printk(KERN_WARNING "picodlp_i2c_driver" \ | ||
536 | " registration failed\n"); | ||
537 | return r; | ||
538 | } | ||
539 | |||
540 | r = omap_dss_register_driver(&picodlp_driver); | ||
541 | if (r) | ||
542 | i2c_del_driver(&picodlp_i2c_driver); | ||
543 | |||
544 | return r; | ||
545 | } | ||
546 | |||
547 | static void __exit picodlp_exit(void) | ||
548 | { | ||
549 | i2c_del_driver(&picodlp_i2c_driver); | ||
550 | omap_dss_unregister_driver(&picodlp_driver); | ||
551 | } | ||
552 | |||
553 | module_init(picodlp_init); | ||
554 | module_exit(picodlp_exit); | ||
555 | |||
556 | MODULE_AUTHOR("Mythri P K <mythripk@ti.com>"); | ||
557 | MODULE_DESCRIPTION("picodlp driver"); | ||
558 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-picodlp.h b/drivers/video/omap2/displays/panel-picodlp.h deleted file mode 100644 index a34b431a726..00000000000 --- a/drivers/video/omap2/displays/panel-picodlp.h +++ /dev/null | |||
@@ -1,288 +0,0 @@ | |||
1 | /* | ||
2 | * Header file required by picodlp panel driver | ||
3 | * | ||
4 | * Copyright (C) 2009-2011 Texas Instruments | ||
5 | * Author: Mythri P K <mythripk@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #ifndef __OMAP2_DISPLAY_PANEL_PICODLP_H | ||
21 | #define __OMAP2_DISPLAY_PANEL_PICODLP_H | ||
22 | |||
23 | /* Commands used for configuring picodlp panel */ | ||
24 | |||
25 | #define MAIN_STATUS 0x03 | ||
26 | #define PBC_CONTROL 0x08 | ||
27 | #define INPUT_SOURCE 0x0B | ||
28 | #define INPUT_RESOLUTION 0x0C | ||
29 | #define DATA_FORMAT 0x0D | ||
30 | #define IMG_ROTATION 0x0E | ||
31 | #define LONG_FLIP 0x0F | ||
32 | #define SHORT_FLIP 0x10 | ||
33 | #define TEST_PAT_SELECT 0x11 | ||
34 | #define R_DRIVE_CURRENT 0x12 | ||
35 | #define G_DRIVE_CURRENT 0x13 | ||
36 | #define B_DRIVE_CURRENT 0x14 | ||
37 | #define READ_REG_SELECT 0x15 | ||
38 | #define RGB_DRIVER_ENABLE 0x16 | ||
39 | |||
40 | #define CPU_IF_MODE 0x18 | ||
41 | #define FRAME_RATE 0x19 | ||
42 | #define CPU_IF_SYNC_METHOD 0x1A | ||
43 | #define CPU_IF_SOF 0x1B | ||
44 | #define CPU_IF_EOF 0x1C | ||
45 | #define CPU_IF_SLEEP 0x1D | ||
46 | |||
47 | #define SEQUENCE_MODE 0x1E | ||
48 | #define SOFT_RESET 0x1F | ||
49 | #define FRONT_END_RESET 0x21 | ||
50 | #define AUTO_PWR_ENABLE 0x22 | ||
51 | |||
52 | #define VSYNC_LINE_DELAY 0x23 | ||
53 | #define CPU_PI_HORIZ_START 0x24 | ||
54 | #define CPU_PI_VERT_START 0x25 | ||
55 | #define CPU_PI_HORIZ_WIDTH 0x26 | ||
56 | #define CPU_PI_VERT_HEIGHT 0x27 | ||
57 | |||
58 | #define PIXEL_MASK_CROP 0x28 | ||
59 | #define CROP_FIRST_LINE 0x29 | ||
60 | #define CROP_LAST_LINE 0x2A | ||
61 | #define CROP_FIRST_PIXEL 0x2B | ||
62 | #define CROP_LAST_PIXEL 0x2C | ||
63 | #define DMD_PARK_TRIGGER 0x2D | ||
64 | |||
65 | #define MISC_REG 0x30 | ||
66 | |||
67 | /* AGC registers */ | ||
68 | #define AGC_CTRL 0x50 | ||
69 | #define AGC_CLIPPED_PIXS 0x55 | ||
70 | #define AGC_BRIGHT_PIXS 0x56 | ||
71 | #define AGC_BG_PIXS 0x57 | ||
72 | #define AGC_SAFETY_MARGIN 0x17 | ||
73 | |||
74 | /* Color Coordinate Adjustment registers */ | ||
75 | #define CCA_ENABLE 0x5E | ||
76 | #define CCA_C1A 0x5F | ||
77 | #define CCA_C1B 0x60 | ||
78 | #define CCA_C1C 0x61 | ||
79 | #define CCA_C2A 0x62 | ||
80 | #define CCA_C2B 0x63 | ||
81 | #define CCA_C2C 0x64 | ||
82 | #define CCA_C3A 0x65 | ||
83 | #define CCA_C3B 0x66 | ||
84 | #define CCA_C3C 0x67 | ||
85 | #define CCA_C7A 0x71 | ||
86 | #define CCA_C7B 0x72 | ||
87 | #define CCA_C7C 0x73 | ||
88 | |||
89 | /** | ||
90 | * DLP Pico Processor 2600 comes with flash | ||
91 | * We can do DMA operations from flash for accessing Look Up Tables | ||
92 | */ | ||
93 | #define DMA_STATUS 0x100 | ||
94 | #define FLASH_ADDR_BYTES 0x74 | ||
95 | #define FLASH_DUMMY_BYTES 0x75 | ||
96 | #define FLASH_WRITE_BYTES 0x76 | ||
97 | #define FLASH_READ_BYTES 0x77 | ||
98 | #define FLASH_OPCODE 0x78 | ||
99 | #define FLASH_START_ADDR 0x79 | ||
100 | #define FLASH_DUMMY2 0x7A | ||
101 | #define FLASH_WRITE_DATA 0x7B | ||
102 | |||
103 | #define TEMPORAL_DITH_DISABLE 0x7E | ||
104 | #define SEQ_CONTROL 0x82 | ||
105 | #define SEQ_VECTOR 0x83 | ||
106 | |||
107 | /* DMD is Digital Micromirror Device */ | ||
108 | #define DMD_BLOCK_COUNT 0x84 | ||
109 | #define DMD_VCC_CONTROL 0x86 | ||
110 | #define DMD_PARK_PULSE_COUNT 0x87 | ||
111 | #define DMD_PARK_PULSE_WIDTH 0x88 | ||
112 | #define DMD_PARK_DELAY 0x89 | ||
113 | #define DMD_SHADOW_ENABLE 0x8E | ||
114 | #define SEQ_STATUS 0x8F | ||
115 | #define FLASH_CLOCK_CONTROL 0x98 | ||
116 | #define DMD_PARK 0x2D | ||
117 | |||
118 | #define SDRAM_BIST_ENABLE 0x46 | ||
119 | #define DDR_DRIVER_STRENGTH 0x9A | ||
120 | #define SDC_ENABLE 0x9D | ||
121 | #define SDC_BUFF_SWAP_DISABLE 0xA3 | ||
122 | #define CURTAIN_CONTROL 0xA6 | ||
123 | #define DDR_BUS_SWAP_ENABLE 0xA7 | ||
124 | #define DMD_TRC_ENABLE 0xA8 | ||
125 | #define DMD_BUS_SWAP_ENABLE 0xA9 | ||
126 | |||
127 | #define ACTGEN_ENABLE 0xAE | ||
128 | #define ACTGEN_CONTROL 0xAF | ||
129 | #define ACTGEN_HORIZ_BP 0xB0 | ||
130 | #define ACTGEN_VERT_BP 0xB1 | ||
131 | |||
132 | /* Look Up Table access */ | ||
133 | #define CMT_SPLASH_LUT_START_ADDR 0xFA | ||
134 | #define CMT_SPLASH_LUT_DEST_SELECT 0xFB | ||
135 | #define CMT_SPLASH_LUT_DATA 0xFC | ||
136 | #define SEQ_RESET_LUT_START_ADDR 0xFD | ||
137 | #define SEQ_RESET_LUT_DEST_SELECT 0xFE | ||
138 | #define SEQ_RESET_LUT_DATA 0xFF | ||
139 | |||
140 | /* Input source definitions */ | ||
141 | #define PARALLEL_RGB 0 | ||
142 | #define INT_TEST_PATTERN 1 | ||
143 | #define SPLASH_SCREEN 2 | ||
144 | #define CPU_INTF 3 | ||
145 | #define BT656 4 | ||
146 | |||
147 | /* Standard input resolution definitions */ | ||
148 | #define QWVGA_LANDSCAPE 3 /* (427h*240v) */ | ||
149 | #define WVGA_864_LANDSCAPE 21 /* (864h*480v) */ | ||
150 | #define WVGA_DMD_OPTICAL_TEST 35 /* (608h*684v) */ | ||
151 | |||
152 | /* Standard data format definitions */ | ||
153 | #define RGB565 0 | ||
154 | #define RGB666 1 | ||
155 | #define RGB888 2 | ||
156 | |||
157 | /* Test Pattern definitions */ | ||
158 | #define TPG_CHECKERBOARD 0 | ||
159 | #define TPG_BLACK 1 | ||
160 | #define TPG_WHITE 2 | ||
161 | #define TPG_RED 3 | ||
162 | #define TPG_BLUE 4 | ||
163 | #define TPG_GREEN 5 | ||
164 | #define TPG_VLINES_BLACK 6 | ||
165 | #define TPG_HLINES_BLACK 7 | ||
166 | #define TPG_VLINES_ALT 8 | ||
167 | #define TPG_HLINES_ALT 9 | ||
168 | #define TPG_DIAG_LINES 10 | ||
169 | #define TPG_GREYRAMP_VERT 11 | ||
170 | #define TPG_GREYRAMP_HORIZ 12 | ||
171 | #define TPG_ANSI_CHECKERBOARD 13 | ||
172 | |||
173 | /* sequence mode definitions */ | ||
174 | #define SEQ_FREE_RUN 0 | ||
175 | #define SEQ_LOCK 1 | ||
176 | |||
177 | /* curtain color definitions */ | ||
178 | #define CURTAIN_BLACK 0 | ||
179 | #define CURTAIN_RED 1 | ||
180 | #define CURTAIN_GREEN 2 | ||
181 | #define CURTAIN_BLUE 3 | ||
182 | #define CURTAIN_YELLOW 4 | ||
183 | #define CURTAIN_MAGENTA 5 | ||
184 | #define CURTAIN_CYAN 6 | ||
185 | #define CURTAIN_WHITE 7 | ||
186 | |||
187 | /* LUT definitions */ | ||
188 | #define CMT_LUT_NONE 0 | ||
189 | #define CMT_LUT_GREEN 1 | ||
190 | #define CMT_LUT_RED 2 | ||
191 | #define CMT_LUT_BLUE 3 | ||
192 | #define CMT_LUT_ALL 4 | ||
193 | #define SPLASH_LUT 5 | ||
194 | |||
195 | #define SEQ_LUT_NONE 0 | ||
196 | #define SEQ_DRC_LUT_0 1 | ||
197 | #define SEQ_DRC_LUT_1 2 | ||
198 | #define SEQ_DRC_LUT_2 3 | ||
199 | #define SEQ_DRC_LUT_3 4 | ||
200 | #define SEQ_SEQ_LUT 5 | ||
201 | #define SEQ_DRC_LUT_ALL 6 | ||
202 | #define WPC_PROGRAM_LUT 7 | ||
203 | |||
204 | #define BITSTREAM_START_ADDR 0x00000000 | ||
205 | #define BITSTREAM_SIZE 0x00040000 | ||
206 | |||
207 | #define WPC_FW_0_START_ADDR 0x00040000 | ||
208 | #define WPC_FW_0_SIZE 0x00000ce8 | ||
209 | |||
210 | #define SEQUENCE_0_START_ADDR 0x00044000 | ||
211 | #define SEQUENCE_0_SIZE 0x00001000 | ||
212 | |||
213 | #define SEQUENCE_1_START_ADDR 0x00045000 | ||
214 | #define SEQUENCE_1_SIZE 0x00000d10 | ||
215 | |||
216 | #define SEQUENCE_2_START_ADDR 0x00046000 | ||
217 | #define SEQUENCE_2_SIZE 0x00000d10 | ||
218 | |||
219 | #define SEQUENCE_3_START_ADDR 0x00047000 | ||
220 | #define SEQUENCE_3_SIZE 0x00000d10 | ||
221 | |||
222 | #define SEQUENCE_4_START_ADDR 0x00048000 | ||
223 | #define SEQUENCE_4_SIZE 0x00000d10 | ||
224 | |||
225 | #define SEQUENCE_5_START_ADDR 0x00049000 | ||
226 | #define SEQUENCE_5_SIZE 0x00000d10 | ||
227 | |||
228 | #define SEQUENCE_6_START_ADDR 0x0004a000 | ||
229 | #define SEQUENCE_6_SIZE 0x00000d10 | ||
230 | |||
231 | #define CMT_LUT_0_START_ADDR 0x0004b200 | ||
232 | #define CMT_LUT_0_SIZE 0x00000600 | ||
233 | |||
234 | #define CMT_LUT_1_START_ADDR 0x0004b800 | ||
235 | #define CMT_LUT_1_SIZE 0x00000600 | ||
236 | |||
237 | #define CMT_LUT_2_START_ADDR 0x0004be00 | ||
238 | #define CMT_LUT_2_SIZE 0x00000600 | ||
239 | |||
240 | #define CMT_LUT_3_START_ADDR 0x0004c400 | ||
241 | #define CMT_LUT_3_SIZE 0x00000600 | ||
242 | |||
243 | #define CMT_LUT_4_START_ADDR 0x0004ca00 | ||
244 | #define CMT_LUT_4_SIZE 0x00000600 | ||
245 | |||
246 | #define CMT_LUT_5_START_ADDR 0x0004d000 | ||
247 | #define CMT_LUT_5_SIZE 0x00000600 | ||
248 | |||
249 | #define CMT_LUT_6_START_ADDR 0x0004d600 | ||
250 | #define CMT_LUT_6_SIZE 0x00000600 | ||
251 | |||
252 | #define DRC_TABLE_0_START_ADDR 0x0004dc00 | ||
253 | #define DRC_TABLE_0_SIZE 0x00000100 | ||
254 | |||
255 | #define SPLASH_0_START_ADDR 0x0004dd00 | ||
256 | #define SPLASH_0_SIZE 0x00032280 | ||
257 | |||
258 | #define SEQUENCE_7_START_ADDR 0x00080000 | ||
259 | #define SEQUENCE_7_SIZE 0x00000d10 | ||
260 | |||
261 | #define SEQUENCE_8_START_ADDR 0x00081800 | ||
262 | #define SEQUENCE_8_SIZE 0x00000d10 | ||
263 | |||
264 | #define SEQUENCE_9_START_ADDR 0x00083000 | ||
265 | #define SEQUENCE_9_SIZE 0x00000d10 | ||
266 | |||
267 | #define CMT_LUT_7_START_ADDR 0x0008e000 | ||
268 | #define CMT_LUT_7_SIZE 0x00000600 | ||
269 | |||
270 | #define CMT_LUT_8_START_ADDR 0x0008e800 | ||
271 | #define CMT_LUT_8_SIZE 0x00000600 | ||
272 | |||
273 | #define CMT_LUT_9_START_ADDR 0x0008f000 | ||
274 | #define CMT_LUT_9_SIZE 0x00000600 | ||
275 | |||
276 | #define SPLASH_1_START_ADDR 0x0009a000 | ||
277 | #define SPLASH_1_SIZE 0x00032280 | ||
278 | |||
279 | #define SPLASH_2_START_ADDR 0x000cd000 | ||
280 | #define SPLASH_2_SIZE 0x00032280 | ||
281 | |||
282 | #define SPLASH_3_START_ADDR 0x00100000 | ||
283 | #define SPLASH_3_SIZE 0x00032280 | ||
284 | |||
285 | #define OPT_SPLASH_0_START_ADDR 0x00134000 | ||
286 | #define OPT_SPLASH_0_SIZE 0x000cb100 | ||
287 | |||
288 | #endif | ||
diff --git a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c index cada8c621e0..ba38b3ad17d 100644 --- a/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c +++ b/drivers/video/omap2/displays/panel-sharp-ls037v7dw01.c | |||
@@ -44,12 +44,6 @@ static struct omap_video_timings sharp_ls_timings = { | |||
44 | .vsw = 1, | 44 | .vsw = 1, |
45 | .vfp = 1, | 45 | .vfp = 1, |
46 | .vbp = 1, | 46 | .vbp = 1, |
47 | |||
48 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
49 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
50 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
51 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
52 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
53 | }; | 47 | }; |
54 | 48 | ||
55 | static int sharp_ls_bl_update_status(struct backlight_device *bl) | 49 | static int sharp_ls_bl_update_status(struct backlight_device *bl) |
@@ -92,6 +86,9 @@ static int sharp_ls_panel_probe(struct omap_dss_device *dssdev) | |||
92 | struct sharp_data *sd; | 86 | struct sharp_data *sd; |
93 | int r; | 87 | int r; |
94 | 88 | ||
89 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS | | ||
90 | OMAP_DSS_LCD_IHS; | ||
91 | dssdev->panel.acb = 0x28; | ||
95 | dssdev->panel.timings = sharp_ls_timings; | 92 | dssdev->panel.timings = sharp_ls_timings; |
96 | 93 | ||
97 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | 94 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); |
@@ -142,9 +139,6 @@ static int sharp_ls_power_on(struct omap_dss_device *dssdev) | |||
142 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 139 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
143 | return 0; | 140 | return 0; |
144 | 141 | ||
145 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
146 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
147 | |||
148 | r = omapdss_dpi_display_enable(dssdev); | 142 | r = omapdss_dpi_display_enable(dssdev); |
149 | if (r) | 143 | if (r) |
150 | goto err0; | 144 | goto err0; |
@@ -194,12 +188,29 @@ static void sharp_ls_panel_disable(struct omap_dss_device *dssdev) | |||
194 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 188 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
195 | } | 189 | } |
196 | 190 | ||
191 | static int sharp_ls_panel_suspend(struct omap_dss_device *dssdev) | ||
192 | { | ||
193 | sharp_ls_power_off(dssdev); | ||
194 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | static int sharp_ls_panel_resume(struct omap_dss_device *dssdev) | ||
199 | { | ||
200 | int r; | ||
201 | r = sharp_ls_power_on(dssdev); | ||
202 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
203 | return r; | ||
204 | } | ||
205 | |||
197 | static struct omap_dss_driver sharp_ls_driver = { | 206 | static struct omap_dss_driver sharp_ls_driver = { |
198 | .probe = sharp_ls_panel_probe, | 207 | .probe = sharp_ls_panel_probe, |
199 | .remove = __exit_p(sharp_ls_panel_remove), | 208 | .remove = __exit_p(sharp_ls_panel_remove), |
200 | 209 | ||
201 | .enable = sharp_ls_panel_enable, | 210 | .enable = sharp_ls_panel_enable, |
202 | .disable = sharp_ls_panel_disable, | 211 | .disable = sharp_ls_panel_disable, |
212 | .suspend = sharp_ls_panel_suspend, | ||
213 | .resume = sharp_ls_panel_resume, | ||
203 | 214 | ||
204 | .driver = { | 215 | .driver = { |
205 | .name = "sharp_ls_panel", | 216 | .name = "sharp_ls_panel", |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index a32407a5735..4e888ac09b3 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -30,16 +30,31 @@ | |||
30 | #include <linux/gpio.h> | 30 | #include <linux/gpio.h> |
31 | #include <linux/workqueue.h> | 31 | #include <linux/workqueue.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/regulator/consumer.h> | ||
33 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
34 | 35 | ||
35 | #include <video/omapdss.h> | 36 | #include <video/omapdss.h> |
36 | #include <video/omap-panel-nokia-dsi.h> | 37 | #include <video/omap-panel-nokia-dsi.h> |
37 | #include <video/mipi_display.h> | ||
38 | 38 | ||
39 | /* DSI Virtual channel. Hardcoded for now. */ | 39 | /* DSI Virtual channel. Hardcoded for now. */ |
40 | #define TCH 0 | 40 | #define TCH 0 |
41 | 41 | ||
42 | #define DCS_READ_NUM_ERRORS 0x05 | 42 | #define DCS_READ_NUM_ERRORS 0x05 |
43 | #define DCS_READ_POWER_MODE 0x0a | ||
44 | #define DCS_READ_MADCTL 0x0b | ||
45 | #define DCS_READ_PIXEL_FORMAT 0x0c | ||
46 | #define DCS_RDDSDR 0x0f | ||
47 | #define DCS_SLEEP_IN 0x10 | ||
48 | #define DCS_SLEEP_OUT 0x11 | ||
49 | #define DCS_DISPLAY_OFF 0x28 | ||
50 | #define DCS_DISPLAY_ON 0x29 | ||
51 | #define DCS_COLUMN_ADDR 0x2a | ||
52 | #define DCS_PAGE_ADDR 0x2b | ||
53 | #define DCS_MEMORY_WRITE 0x2c | ||
54 | #define DCS_TEAR_OFF 0x34 | ||
55 | #define DCS_TEAR_ON 0x35 | ||
56 | #define DCS_MEM_ACC_CTRL 0x36 | ||
57 | #define DCS_PIXEL_FORMAT 0x3a | ||
43 | #define DCS_BRIGHTNESS 0x51 | 58 | #define DCS_BRIGHTNESS 0x51 |
44 | #define DCS_CTRL_DISPLAY 0x53 | 59 | #define DCS_CTRL_DISPLAY 0x53 |
45 | #define DCS_WRITE_CABC 0x55 | 60 | #define DCS_WRITE_CABC 0x55 |
@@ -54,6 +69,73 @@ static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable); | |||
54 | 69 | ||
55 | static int taal_panel_reset(struct omap_dss_device *dssdev); | 70 | static int taal_panel_reset(struct omap_dss_device *dssdev); |
56 | 71 | ||
72 | struct panel_regulator { | ||
73 | struct regulator *regulator; | ||
74 | const char *name; | ||
75 | int min_uV; | ||
76 | int max_uV; | ||
77 | }; | ||
78 | |||
79 | static void free_regulators(struct panel_regulator *regulators, int n) | ||
80 | { | ||
81 | int i; | ||
82 | |||
83 | for (i = 0; i < n; i++) { | ||
84 | /* disable/put in reverse order */ | ||
85 | regulator_disable(regulators[n - i - 1].regulator); | ||
86 | regulator_put(regulators[n - i - 1].regulator); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | static int init_regulators(struct omap_dss_device *dssdev, | ||
91 | struct panel_regulator *regulators, int n) | ||
92 | { | ||
93 | int r, i, v; | ||
94 | |||
95 | for (i = 0; i < n; i++) { | ||
96 | struct regulator *reg; | ||
97 | |||
98 | reg = regulator_get(&dssdev->dev, regulators[i].name); | ||
99 | if (IS_ERR(reg)) { | ||
100 | dev_err(&dssdev->dev, "failed to get regulator %s\n", | ||
101 | regulators[i].name); | ||
102 | r = PTR_ERR(reg); | ||
103 | goto err; | ||
104 | } | ||
105 | |||
106 | /* FIXME: better handling of fixed vs. variable regulators */ | ||
107 | v = regulator_get_voltage(reg); | ||
108 | if (v < regulators[i].min_uV || v > regulators[i].max_uV) { | ||
109 | r = regulator_set_voltage(reg, regulators[i].min_uV, | ||
110 | regulators[i].max_uV); | ||
111 | if (r) { | ||
112 | dev_err(&dssdev->dev, | ||
113 | "failed to set regulator %s voltage\n", | ||
114 | regulators[i].name); | ||
115 | regulator_put(reg); | ||
116 | goto err; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | r = regulator_enable(reg); | ||
121 | if (r) { | ||
122 | dev_err(&dssdev->dev, "failed to enable regulator %s\n", | ||
123 | regulators[i].name); | ||
124 | regulator_put(reg); | ||
125 | goto err; | ||
126 | } | ||
127 | |||
128 | regulators[i].regulator = reg; | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | |||
133 | err: | ||
134 | free_regulators(regulators, i); | ||
135 | |||
136 | return r; | ||
137 | } | ||
138 | |||
57 | /** | 139 | /** |
58 | * struct panel_config - panel configuration | 140 | * struct panel_config - panel configuration |
59 | * @name: panel name | 141 | * @name: panel name |
@@ -82,6 +164,8 @@ struct panel_config { | |||
82 | unsigned int low; | 164 | unsigned int low; |
83 | } reset_sequence; | 165 | } reset_sequence; |
84 | 166 | ||
167 | struct panel_regulator *regulators; | ||
168 | int num_regulators; | ||
85 | }; | 169 | }; |
86 | 170 | ||
87 | enum { | 171 | enum { |
@@ -121,18 +205,6 @@ struct taal_data { | |||
121 | 205 | ||
122 | struct omap_dss_device *dssdev; | 206 | struct omap_dss_device *dssdev; |
123 | 207 | ||
124 | /* panel specific HW info */ | ||
125 | struct panel_config *panel_config; | ||
126 | |||
127 | /* panel HW configuration from DT or platform data */ | ||
128 | int reset_gpio; | ||
129 | int ext_te_gpio; | ||
130 | |||
131 | bool use_dsi_backlight; | ||
132 | |||
133 | struct omap_dsi_pin_config pin_config; | ||
134 | |||
135 | /* runtime variables */ | ||
136 | bool enabled; | 208 | bool enabled; |
137 | u8 rotate; | 209 | u8 rotate; |
138 | bool mirror; | 210 | bool mirror; |
@@ -140,10 +212,18 @@ struct taal_data { | |||
140 | bool te_enabled; | 212 | bool te_enabled; |
141 | 213 | ||
142 | atomic_t do_update; | 214 | atomic_t do_update; |
215 | struct { | ||
216 | u16 x; | ||
217 | u16 y; | ||
218 | u16 w; | ||
219 | u16 h; | ||
220 | } update_region; | ||
143 | int channel; | 221 | int channel; |
144 | 222 | ||
145 | struct delayed_work te_timeout_work; | 223 | struct delayed_work te_timeout_work; |
146 | 224 | ||
225 | bool use_dsi_bl; | ||
226 | |||
147 | bool cabc_broken; | 227 | bool cabc_broken; |
148 | unsigned cabc_mode; | 228 | unsigned cabc_mode; |
149 | 229 | ||
@@ -157,8 +237,16 @@ struct taal_data { | |||
157 | bool ulps_enabled; | 237 | bool ulps_enabled; |
158 | unsigned ulps_timeout; | 238 | unsigned ulps_timeout; |
159 | struct delayed_work ulps_work; | 239 | struct delayed_work ulps_work; |
240 | |||
241 | struct panel_config *panel_config; | ||
160 | }; | 242 | }; |
161 | 243 | ||
244 | static inline struct nokia_dsi_panel_data | ||
245 | *get_panel_data(const struct omap_dss_device *dssdev) | ||
246 | { | ||
247 | return (struct nokia_dsi_panel_data *) dssdev->data; | ||
248 | } | ||
249 | |||
162 | static void taal_esd_work(struct work_struct *work); | 250 | static void taal_esd_work(struct work_struct *work); |
163 | static void taal_ulps_work(struct work_struct *work); | 251 | static void taal_ulps_work(struct work_struct *work); |
164 | 252 | ||
@@ -214,7 +302,7 @@ static int taal_sleep_in(struct taal_data *td) | |||
214 | 302 | ||
215 | hw_guard_wait(td); | 303 | hw_guard_wait(td); |
216 | 304 | ||
217 | cmd = MIPI_DCS_ENTER_SLEEP_MODE; | 305 | cmd = DCS_SLEEP_IN; |
218 | r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1); | 306 | r = dsi_vc_dcs_write_nosync(td->dssdev, td->channel, &cmd, 1); |
219 | if (r) | 307 | if (r) |
220 | return r; | 308 | return r; |
@@ -233,7 +321,7 @@ static int taal_sleep_out(struct taal_data *td) | |||
233 | 321 | ||
234 | hw_guard_wait(td); | 322 | hw_guard_wait(td); |
235 | 323 | ||
236 | r = taal_dcs_write_0(td, MIPI_DCS_EXIT_SLEEP_MODE); | 324 | r = taal_dcs_write_0(td, DCS_SLEEP_OUT); |
237 | if (r) | 325 | if (r) |
238 | return r; | 326 | return r; |
239 | 327 | ||
@@ -268,7 +356,7 @@ static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) | |||
268 | u8 mode; | 356 | u8 mode; |
269 | int b5, b6, b7; | 357 | int b5, b6, b7; |
270 | 358 | ||
271 | r = taal_dcs_read_1(td, MIPI_DCS_GET_ADDRESS_MODE, &mode); | 359 | r = taal_dcs_read_1(td, DCS_READ_MADCTL, &mode); |
272 | if (r) | 360 | if (r) |
273 | return r; | 361 | return r; |
274 | 362 | ||
@@ -302,7 +390,7 @@ static int taal_set_addr_mode(struct taal_data *td, u8 rotate, bool mirror) | |||
302 | mode &= ~((1<<7) | (1<<6) | (1<<5)); | 390 | mode &= ~((1<<7) | (1<<6) | (1<<5)); |
303 | mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); | 391 | mode |= (b7 << 7) | (b6 << 6) | (b5 << 5); |
304 | 392 | ||
305 | return taal_dcs_write_1(td, MIPI_DCS_SET_ADDRESS_MODE, mode); | 393 | return taal_dcs_write_1(td, DCS_MEM_ACC_CTRL, mode); |
306 | } | 394 | } |
307 | 395 | ||
308 | static int taal_set_update_window(struct taal_data *td, | 396 | static int taal_set_update_window(struct taal_data *td, |
@@ -315,7 +403,7 @@ static int taal_set_update_window(struct taal_data *td, | |||
315 | u16 y2 = y + h - 1; | 403 | u16 y2 = y + h - 1; |
316 | 404 | ||
317 | u8 buf[5]; | 405 | u8 buf[5]; |
318 | buf[0] = MIPI_DCS_SET_COLUMN_ADDRESS; | 406 | buf[0] = DCS_COLUMN_ADDR; |
319 | buf[1] = (x1 >> 8) & 0xff; | 407 | buf[1] = (x1 >> 8) & 0xff; |
320 | buf[2] = (x1 >> 0) & 0xff; | 408 | buf[2] = (x1 >> 0) & 0xff; |
321 | buf[3] = (x2 >> 8) & 0xff; | 409 | buf[3] = (x2 >> 8) & 0xff; |
@@ -325,7 +413,7 @@ static int taal_set_update_window(struct taal_data *td, | |||
325 | if (r) | 413 | if (r) |
326 | return r; | 414 | return r; |
327 | 415 | ||
328 | buf[0] = MIPI_DCS_SET_PAGE_ADDRESS; | 416 | buf[0] = DCS_PAGE_ADDR; |
329 | buf[1] = (y1 >> 8) & 0xff; | 417 | buf[1] = (y1 >> 8) & 0xff; |
330 | buf[2] = (y1 >> 0) & 0xff; | 418 | buf[2] = (y1 >> 0) & 0xff; |
331 | buf[3] = (y2 >> 8) & 0xff; | 419 | buf[3] = (y2 >> 8) & 0xff; |
@@ -375,6 +463,7 @@ static void taal_cancel_ulps_work(struct omap_dss_device *dssdev) | |||
375 | static int taal_enter_ulps(struct omap_dss_device *dssdev) | 463 | static int taal_enter_ulps(struct omap_dss_device *dssdev) |
376 | { | 464 | { |
377 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 465 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
466 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
378 | int r; | 467 | int r; |
379 | 468 | ||
380 | if (td->ulps_enabled) | 469 | if (td->ulps_enabled) |
@@ -386,8 +475,7 @@ static int taal_enter_ulps(struct omap_dss_device *dssdev) | |||
386 | if (r) | 475 | if (r) |
387 | goto err; | 476 | goto err; |
388 | 477 | ||
389 | if (gpio_is_valid(td->ext_te_gpio)) | 478 | disable_irq(gpio_to_irq(panel_data->ext_te_gpio)); |
390 | disable_irq(gpio_to_irq(td->ext_te_gpio)); | ||
391 | 479 | ||
392 | omapdss_dsi_display_disable(dssdev, false, true); | 480 | omapdss_dsi_display_disable(dssdev, false, true); |
393 | 481 | ||
@@ -409,6 +497,7 @@ err: | |||
409 | static int taal_exit_ulps(struct omap_dss_device *dssdev) | 497 | static int taal_exit_ulps(struct omap_dss_device *dssdev) |
410 | { | 498 | { |
411 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 499 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
500 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
412 | int r; | 501 | int r; |
413 | 502 | ||
414 | if (!td->ulps_enabled) | 503 | if (!td->ulps_enabled) |
@@ -428,8 +517,7 @@ static int taal_exit_ulps(struct omap_dss_device *dssdev) | |||
428 | goto err2; | 517 | goto err2; |
429 | } | 518 | } |
430 | 519 | ||
431 | if (gpio_is_valid(td->ext_te_gpio)) | 520 | enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); |
432 | enable_irq(gpio_to_irq(td->ext_te_gpio)); | ||
433 | 521 | ||
434 | taal_queue_ulps_work(dssdev); | 522 | taal_queue_ulps_work(dssdev); |
435 | 523 | ||
@@ -442,8 +530,7 @@ err2: | |||
442 | 530 | ||
443 | r = taal_panel_reset(dssdev); | 531 | r = taal_panel_reset(dssdev); |
444 | if (!r) { | 532 | if (!r) { |
445 | if (gpio_is_valid(td->ext_te_gpio)) | 533 | enable_irq(gpio_to_irq(panel_data->ext_te_gpio)); |
446 | enable_irq(gpio_to_irq(td->ext_te_gpio)); | ||
447 | td->ulps_enabled = false; | 534 | td->ulps_enabled = false; |
448 | } | 535 | } |
449 | err1: | 536 | err1: |
@@ -468,6 +555,7 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
468 | { | 555 | { |
469 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); | 556 | struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev); |
470 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 557 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
558 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
471 | int r; | 559 | int r; |
472 | int level; | 560 | int level; |
473 | 561 | ||
@@ -481,16 +569,23 @@ static int taal_bl_update_status(struct backlight_device *dev) | |||
481 | 569 | ||
482 | mutex_lock(&td->lock); | 570 | mutex_lock(&td->lock); |
483 | 571 | ||
484 | if (td->enabled) { | 572 | if (td->use_dsi_bl) { |
485 | dsi_bus_lock(dssdev); | 573 | if (td->enabled) { |
574 | dsi_bus_lock(dssdev); | ||
486 | 575 | ||
487 | r = taal_wake_up(dssdev); | 576 | r = taal_wake_up(dssdev); |
488 | if (!r) | 577 | if (!r) |
489 | r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level); | 578 | r = taal_dcs_write_1(td, DCS_BRIGHTNESS, level); |
490 | 579 | ||
491 | dsi_bus_unlock(dssdev); | 580 | dsi_bus_unlock(dssdev); |
581 | } else { | ||
582 | r = 0; | ||
583 | } | ||
492 | } else { | 584 | } else { |
493 | r = 0; | 585 | if (!panel_data->set_backlight) |
586 | r = -EINVAL; | ||
587 | else | ||
588 | r = panel_data->set_backlight(dssdev, level); | ||
494 | } | 589 | } |
495 | 590 | ||
496 | mutex_unlock(&td->lock); | 591 | mutex_unlock(&td->lock); |
@@ -512,6 +607,12 @@ static const struct backlight_ops taal_bl_ops = { | |||
512 | .update_status = taal_bl_update_status, | 607 | .update_status = taal_bl_update_status, |
513 | }; | 608 | }; |
514 | 609 | ||
610 | static void taal_get_timings(struct omap_dss_device *dssdev, | ||
611 | struct omap_video_timings *timings) | ||
612 | { | ||
613 | *timings = dssdev->panel.timings; | ||
614 | } | ||
615 | |||
515 | static void taal_get_resolution(struct omap_dss_device *dssdev, | 616 | static void taal_get_resolution(struct omap_dss_device *dssdev, |
516 | u16 *xres, u16 *yres) | 617 | u16 *xres, u16 *yres) |
517 | { | 618 | { |
@@ -531,7 +632,7 @@ static ssize_t taal_num_errors_show(struct device *dev, | |||
531 | { | 632 | { |
532 | struct omap_dss_device *dssdev = to_dss_device(dev); | 633 | struct omap_dss_device *dssdev = to_dss_device(dev); |
533 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 634 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
534 | u8 errors = 0; | 635 | u8 errors; |
535 | int r; | 636 | int r; |
536 | 637 | ||
537 | mutex_lock(&td->lock); | 638 | mutex_lock(&td->lock); |
@@ -840,153 +941,145 @@ static struct attribute_group taal_attr_group = { | |||
840 | static void taal_hw_reset(struct omap_dss_device *dssdev) | 941 | static void taal_hw_reset(struct omap_dss_device *dssdev) |
841 | { | 942 | { |
842 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 943 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
944 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
843 | 945 | ||
844 | if (!gpio_is_valid(td->reset_gpio)) | 946 | if (panel_data->reset_gpio == -1) |
845 | return; | 947 | return; |
846 | 948 | ||
847 | gpio_set_value(td->reset_gpio, 1); | 949 | gpio_set_value(panel_data->reset_gpio, 1); |
848 | if (td->panel_config->reset_sequence.high) | 950 | if (td->panel_config->reset_sequence.high) |
849 | udelay(td->panel_config->reset_sequence.high); | 951 | udelay(td->panel_config->reset_sequence.high); |
850 | /* reset the panel */ | 952 | /* reset the panel */ |
851 | gpio_set_value(td->reset_gpio, 0); | 953 | gpio_set_value(panel_data->reset_gpio, 0); |
852 | /* assert reset */ | 954 | /* assert reset */ |
853 | if (td->panel_config->reset_sequence.low) | 955 | if (td->panel_config->reset_sequence.low) |
854 | udelay(td->panel_config->reset_sequence.low); | 956 | udelay(td->panel_config->reset_sequence.low); |
855 | gpio_set_value(td->reset_gpio, 1); | 957 | gpio_set_value(panel_data->reset_gpio, 1); |
856 | /* wait after releasing reset */ | 958 | /* wait after releasing reset */ |
857 | if (td->panel_config->sleep.hw_reset) | 959 | if (td->panel_config->sleep.hw_reset) |
858 | msleep(td->panel_config->sleep.hw_reset); | 960 | msleep(td->panel_config->sleep.hw_reset); |
859 | } | 961 | } |
860 | 962 | ||
861 | static void taal_probe_pdata(struct taal_data *td, | ||
862 | const struct nokia_dsi_panel_data *pdata) | ||
863 | { | ||
864 | td->reset_gpio = pdata->reset_gpio; | ||
865 | |||
866 | if (pdata->use_ext_te) | ||
867 | td->ext_te_gpio = pdata->ext_te_gpio; | ||
868 | else | ||
869 | td->ext_te_gpio = -1; | ||
870 | |||
871 | td->esd_interval = pdata->esd_interval; | ||
872 | td->ulps_timeout = pdata->ulps_timeout; | ||
873 | |||
874 | td->use_dsi_backlight = pdata->use_dsi_backlight; | ||
875 | |||
876 | td->pin_config = pdata->pin_config; | ||
877 | } | ||
878 | |||
879 | static int taal_probe(struct omap_dss_device *dssdev) | 963 | static int taal_probe(struct omap_dss_device *dssdev) |
880 | { | 964 | { |
881 | struct backlight_properties props; | 965 | struct backlight_properties props; |
882 | struct taal_data *td; | 966 | struct taal_data *td; |
883 | struct backlight_device *bldev = NULL; | 967 | struct backlight_device *bldev; |
968 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
969 | struct panel_config *panel_config = NULL; | ||
884 | int r, i; | 970 | int r, i; |
885 | const char *panel_name; | ||
886 | 971 | ||
887 | dev_dbg(&dssdev->dev, "probe\n"); | 972 | dev_dbg(&dssdev->dev, "probe\n"); |
888 | 973 | ||
889 | td = devm_kzalloc(&dssdev->dev, sizeof(*td), GFP_KERNEL); | 974 | if (!panel_data || !panel_data->name) { |
890 | if (!td) | 975 | r = -EINVAL; |
891 | return -ENOMEM; | 976 | goto err; |
892 | |||
893 | dev_set_drvdata(&dssdev->dev, td); | ||
894 | td->dssdev = dssdev; | ||
895 | |||
896 | if (dssdev->data) { | ||
897 | const struct nokia_dsi_panel_data *pdata = dssdev->data; | ||
898 | |||
899 | taal_probe_pdata(td, pdata); | ||
900 | |||
901 | panel_name = pdata->name; | ||
902 | } else { | ||
903 | return -ENODEV; | ||
904 | } | 977 | } |
905 | 978 | ||
906 | if (panel_name == NULL) | ||
907 | return -EINVAL; | ||
908 | |||
909 | for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { | 979 | for (i = 0; i < ARRAY_SIZE(panel_configs); i++) { |
910 | if (strcmp(panel_name, panel_configs[i].name) == 0) { | 980 | if (strcmp(panel_data->name, panel_configs[i].name) == 0) { |
911 | td->panel_config = &panel_configs[i]; | 981 | panel_config = &panel_configs[i]; |
912 | break; | 982 | break; |
913 | } | 983 | } |
914 | } | 984 | } |
915 | 985 | ||
916 | if (!td->panel_config) | 986 | if (!panel_config) { |
917 | return -EINVAL; | 987 | r = -EINVAL; |
918 | 988 | goto err; | |
919 | dssdev->panel.timings = td->panel_config->timings; | ||
920 | dssdev->panel.dsi_pix_fmt = OMAP_DSS_DSI_FMT_RGB888; | ||
921 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | ||
922 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; | ||
923 | |||
924 | mutex_init(&td->lock); | ||
925 | |||
926 | atomic_set(&td->do_update, 0); | ||
927 | |||
928 | if (gpio_is_valid(td->reset_gpio)) { | ||
929 | r = devm_gpio_request_one(&dssdev->dev, td->reset_gpio, | ||
930 | GPIOF_OUT_INIT_LOW, "taal rst"); | ||
931 | if (r) { | ||
932 | dev_err(&dssdev->dev, "failed to request reset gpio\n"); | ||
933 | return r; | ||
934 | } | ||
935 | } | 989 | } |
936 | 990 | ||
937 | if (gpio_is_valid(td->ext_te_gpio)) { | 991 | dssdev->panel.config = OMAP_DSS_LCD_TFT; |
938 | r = devm_gpio_request_one(&dssdev->dev, td->ext_te_gpio, | 992 | dssdev->panel.timings = panel_config->timings; |
939 | GPIOF_IN, "taal irq"); | 993 | dssdev->ctrl.pixel_size = 24; |
940 | if (r) { | ||
941 | dev_err(&dssdev->dev, "GPIO request failed\n"); | ||
942 | return r; | ||
943 | } | ||
944 | 994 | ||
945 | r = devm_request_irq(&dssdev->dev, gpio_to_irq(td->ext_te_gpio), | 995 | td = kzalloc(sizeof(*td), GFP_KERNEL); |
946 | taal_te_isr, | 996 | if (!td) { |
947 | IRQF_TRIGGER_RISING, | 997 | r = -ENOMEM; |
948 | "taal vsync", dssdev); | 998 | goto err; |
999 | } | ||
1000 | td->dssdev = dssdev; | ||
1001 | td->panel_config = panel_config; | ||
1002 | td->esd_interval = panel_data->esd_interval; | ||
1003 | td->ulps_enabled = false; | ||
1004 | td->ulps_timeout = panel_data->ulps_timeout; | ||
949 | 1005 | ||
950 | if (r) { | 1006 | mutex_init(&td->lock); |
951 | dev_err(&dssdev->dev, "IRQ request failed\n"); | ||
952 | return r; | ||
953 | } | ||
954 | 1007 | ||
955 | INIT_DEFERRABLE_WORK(&td->te_timeout_work, | 1008 | atomic_set(&td->do_update, 0); |
956 | taal_te_timeout_work_callback); | ||
957 | 1009 | ||
958 | dev_dbg(&dssdev->dev, "Using GPIO TE\n"); | 1010 | r = init_regulators(dssdev, panel_config->regulators, |
959 | } | 1011 | panel_config->num_regulators); |
1012 | if (r) | ||
1013 | goto err_reg; | ||
960 | 1014 | ||
961 | td->workqueue = create_singlethread_workqueue("taal_esd"); | 1015 | td->workqueue = create_singlethread_workqueue("taal_esd"); |
962 | if (td->workqueue == NULL) { | 1016 | if (td->workqueue == NULL) { |
963 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); | 1017 | dev_err(&dssdev->dev, "can't create ESD workqueue\n"); |
964 | return -ENOMEM; | 1018 | r = -ENOMEM; |
1019 | goto err_wq; | ||
965 | } | 1020 | } |
966 | INIT_DEFERRABLE_WORK(&td->esd_work, taal_esd_work); | 1021 | INIT_DELAYED_WORK_DEFERRABLE(&td->esd_work, taal_esd_work); |
967 | INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); | 1022 | INIT_DELAYED_WORK(&td->ulps_work, taal_ulps_work); |
968 | 1023 | ||
1024 | dev_set_drvdata(&dssdev->dev, td); | ||
1025 | |||
969 | taal_hw_reset(dssdev); | 1026 | taal_hw_reset(dssdev); |
970 | 1027 | ||
971 | if (td->use_dsi_backlight) { | 1028 | /* if no platform set_backlight() defined, presume DSI backlight |
972 | memset(&props, 0, sizeof(struct backlight_properties)); | 1029 | * control */ |
1030 | memset(&props, 0, sizeof(struct backlight_properties)); | ||
1031 | if (!panel_data->set_backlight) | ||
1032 | td->use_dsi_bl = true; | ||
1033 | |||
1034 | if (td->use_dsi_bl) | ||
973 | props.max_brightness = 255; | 1035 | props.max_brightness = 255; |
1036 | else | ||
1037 | props.max_brightness = 127; | ||
1038 | |||
1039 | props.type = BACKLIGHT_RAW; | ||
1040 | bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev, | ||
1041 | dssdev, &taal_bl_ops, &props); | ||
1042 | if (IS_ERR(bldev)) { | ||
1043 | r = PTR_ERR(bldev); | ||
1044 | goto err_bl; | ||
1045 | } | ||
1046 | |||
1047 | td->bldev = bldev; | ||
1048 | |||
1049 | bldev->props.fb_blank = FB_BLANK_UNBLANK; | ||
1050 | bldev->props.power = FB_BLANK_UNBLANK; | ||
1051 | if (td->use_dsi_bl) | ||
1052 | bldev->props.brightness = 255; | ||
1053 | else | ||
1054 | bldev->props.brightness = 127; | ||
974 | 1055 | ||
975 | props.type = BACKLIGHT_RAW; | 1056 | taal_bl_update_status(bldev); |
976 | bldev = backlight_device_register(dev_name(&dssdev->dev), | 1057 | |
977 | &dssdev->dev, dssdev, &taal_bl_ops, &props); | 1058 | if (panel_data->use_ext_te) { |
978 | if (IS_ERR(bldev)) { | 1059 | int gpio = panel_data->ext_te_gpio; |
979 | r = PTR_ERR(bldev); | 1060 | |
980 | goto err_bl; | 1061 | r = gpio_request(gpio, "taal irq"); |
1062 | if (r) { | ||
1063 | dev_err(&dssdev->dev, "GPIO request failed\n"); | ||
1064 | goto err_gpio; | ||
981 | } | 1065 | } |
982 | 1066 | ||
983 | td->bldev = bldev; | 1067 | gpio_direction_input(gpio); |
984 | 1068 | ||
985 | bldev->props.fb_blank = FB_BLANK_UNBLANK; | 1069 | r = request_irq(gpio_to_irq(gpio), taal_te_isr, |
986 | bldev->props.power = FB_BLANK_UNBLANK; | 1070 | IRQF_DISABLED | IRQF_TRIGGER_RISING, |
987 | bldev->props.brightness = 255; | 1071 | "taal vsync", dssdev); |
988 | 1072 | ||
989 | taal_bl_update_status(bldev); | 1073 | if (r) { |
1074 | dev_err(&dssdev->dev, "IRQ request failed\n"); | ||
1075 | gpio_free(gpio); | ||
1076 | goto err_irq; | ||
1077 | } | ||
1078 | |||
1079 | INIT_DELAYED_WORK_DEFERRABLE(&td->te_timeout_work, | ||
1080 | taal_te_timeout_work_callback); | ||
1081 | |||
1082 | dev_dbg(&dssdev->dev, "Using GPIO TE\n"); | ||
990 | } | 1083 | } |
991 | 1084 | ||
992 | r = omap_dsi_request_vc(dssdev, &td->channel); | 1085 | r = omap_dsi_request_vc(dssdev, &td->channel); |
@@ -1012,16 +1105,27 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
1012 | err_vc_id: | 1105 | err_vc_id: |
1013 | omap_dsi_release_vc(dssdev, td->channel); | 1106 | omap_dsi_release_vc(dssdev, td->channel); |
1014 | err_req_vc: | 1107 | err_req_vc: |
1015 | if (bldev != NULL) | 1108 | if (panel_data->use_ext_te) |
1016 | backlight_device_unregister(bldev); | 1109 | free_irq(gpio_to_irq(panel_data->ext_te_gpio), dssdev); |
1110 | err_irq: | ||
1111 | if (panel_data->use_ext_te) | ||
1112 | gpio_free(panel_data->ext_te_gpio); | ||
1113 | err_gpio: | ||
1114 | backlight_device_unregister(bldev); | ||
1017 | err_bl: | 1115 | err_bl: |
1018 | destroy_workqueue(td->workqueue); | 1116 | destroy_workqueue(td->workqueue); |
1117 | err_wq: | ||
1118 | free_regulators(panel_config->regulators, panel_config->num_regulators); | ||
1119 | err_reg: | ||
1120 | kfree(td); | ||
1121 | err: | ||
1019 | return r; | 1122 | return r; |
1020 | } | 1123 | } |
1021 | 1124 | ||
1022 | static void __exit taal_remove(struct omap_dss_device *dssdev) | 1125 | static void __exit taal_remove(struct omap_dss_device *dssdev) |
1023 | { | 1126 | { |
1024 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1127 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1128 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
1025 | struct backlight_device *bldev; | 1129 | struct backlight_device *bldev; |
1026 | 1130 | ||
1027 | dev_dbg(&dssdev->dev, "remove\n"); | 1131 | dev_dbg(&dssdev->dev, "remove\n"); |
@@ -1029,19 +1133,28 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) | |||
1029 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); | 1133 | sysfs_remove_group(&dssdev->dev.kobj, &taal_attr_group); |
1030 | omap_dsi_release_vc(dssdev, td->channel); | 1134 | omap_dsi_release_vc(dssdev, td->channel); |
1031 | 1135 | ||
1032 | bldev = td->bldev; | 1136 | if (panel_data->use_ext_te) { |
1033 | if (bldev != NULL) { | 1137 | int gpio = panel_data->ext_te_gpio; |
1034 | bldev->props.power = FB_BLANK_POWERDOWN; | 1138 | free_irq(gpio_to_irq(gpio), dssdev); |
1035 | taal_bl_update_status(bldev); | 1139 | gpio_free(gpio); |
1036 | backlight_device_unregister(bldev); | ||
1037 | } | 1140 | } |
1038 | 1141 | ||
1142 | bldev = td->bldev; | ||
1143 | bldev->props.power = FB_BLANK_POWERDOWN; | ||
1144 | taal_bl_update_status(bldev); | ||
1145 | backlight_device_unregister(bldev); | ||
1146 | |||
1039 | taal_cancel_ulps_work(dssdev); | 1147 | taal_cancel_ulps_work(dssdev); |
1040 | taal_cancel_esd_work(dssdev); | 1148 | taal_cancel_esd_work(dssdev); |
1041 | destroy_workqueue(td->workqueue); | 1149 | destroy_workqueue(td->workqueue); |
1042 | 1150 | ||
1043 | /* reset, to be sure that the panel is in a valid state */ | 1151 | /* reset, to be sure that the panel is in a valid state */ |
1044 | taal_hw_reset(dssdev); | 1152 | taal_hw_reset(dssdev); |
1153 | |||
1154 | free_regulators(td->panel_config->regulators, | ||
1155 | td->panel_config->num_regulators); | ||
1156 | |||
1157 | kfree(td); | ||
1045 | } | 1158 | } |
1046 | 1159 | ||
1047 | static int taal_power_on(struct omap_dss_device *dssdev) | 1160 | static int taal_power_on(struct omap_dss_device *dssdev) |
@@ -1050,23 +1163,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1050 | u8 id1, id2, id3; | 1163 | u8 id1, id2, id3; |
1051 | int r; | 1164 | int r; |
1052 | 1165 | ||
1053 | r = omapdss_dsi_configure_pins(dssdev, &td->pin_config); | ||
1054 | if (r) { | ||
1055 | dev_err(&dssdev->dev, "failed to configure DSI pins\n"); | ||
1056 | goto err0; | ||
1057 | }; | ||
1058 | |||
1059 | omapdss_dsi_set_size(dssdev, dssdev->panel.timings.x_res, | ||
1060 | dssdev->panel.timings.y_res); | ||
1061 | omapdss_dsi_set_pixel_format(dssdev, OMAP_DSS_DSI_FMT_RGB888); | ||
1062 | omapdss_dsi_set_operation_mode(dssdev, OMAP_DSS_DSI_CMD_MODE); | ||
1063 | |||
1064 | r = omapdss_dsi_set_clocks(dssdev, 216000000, 10000000); | ||
1065 | if (r) { | ||
1066 | dev_err(&dssdev->dev, "failed to set HS and LP clocks\n"); | ||
1067 | goto err0; | ||
1068 | } | ||
1069 | |||
1070 | r = omapdss_dsi_display_enable(dssdev); | 1166 | r = omapdss_dsi_display_enable(dssdev); |
1071 | if (r) { | 1167 | if (r) { |
1072 | dev_err(&dssdev->dev, "failed to enable DSI\n"); | 1168 | dev_err(&dssdev->dev, "failed to enable DSI\n"); |
@@ -1099,8 +1195,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1099 | if (r) | 1195 | if (r) |
1100 | goto err; | 1196 | goto err; |
1101 | 1197 | ||
1102 | r = taal_dcs_write_1(td, MIPI_DCS_SET_PIXEL_FORMAT, | 1198 | r = taal_dcs_write_1(td, DCS_PIXEL_FORMAT, 0x7); /* 24bit/pixel */ |
1103 | MIPI_DCS_PIXEL_FMT_24BIT); | ||
1104 | if (r) | 1199 | if (r) |
1105 | goto err; | 1200 | goto err; |
1106 | 1201 | ||
@@ -1114,7 +1209,7 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1114 | goto err; | 1209 | goto err; |
1115 | } | 1210 | } |
1116 | 1211 | ||
1117 | r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_ON); | 1212 | r = taal_dcs_write_0(td, DCS_DISPLAY_ON); |
1118 | if (r) | 1213 | if (r) |
1119 | goto err; | 1214 | goto err; |
1120 | 1215 | ||
@@ -1122,10 +1217,6 @@ static int taal_power_on(struct omap_dss_device *dssdev) | |||
1122 | if (r) | 1217 | if (r) |
1123 | goto err; | 1218 | goto err; |
1124 | 1219 | ||
1125 | r = dsi_enable_video_output(dssdev, td->channel); | ||
1126 | if (r) | ||
1127 | goto err; | ||
1128 | |||
1129 | td->enabled = 1; | 1220 | td->enabled = 1; |
1130 | 1221 | ||
1131 | if (!td->intro_printed) { | 1222 | if (!td->intro_printed) { |
@@ -1155,9 +1246,7 @@ static void taal_power_off(struct omap_dss_device *dssdev) | |||
1155 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1246 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1156 | int r; | 1247 | int r; |
1157 | 1248 | ||
1158 | dsi_disable_video_output(dssdev, td->channel); | 1249 | r = taal_dcs_write_0(td, DCS_DISPLAY_OFF); |
1159 | |||
1160 | r = taal_dcs_write_0(td, MIPI_DCS_SET_DISPLAY_OFF); | ||
1161 | if (!r) | 1250 | if (!r) |
1162 | r = taal_sleep_in(td); | 1251 | r = taal_sleep_in(td); |
1163 | 1252 | ||
@@ -1245,6 +1334,76 @@ static void taal_disable(struct omap_dss_device *dssdev) | |||
1245 | mutex_unlock(&td->lock); | 1334 | mutex_unlock(&td->lock); |
1246 | } | 1335 | } |
1247 | 1336 | ||
1337 | static int taal_suspend(struct omap_dss_device *dssdev) | ||
1338 | { | ||
1339 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1340 | int r; | ||
1341 | |||
1342 | dev_dbg(&dssdev->dev, "suspend\n"); | ||
1343 | |||
1344 | mutex_lock(&td->lock); | ||
1345 | |||
1346 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | ||
1347 | r = -EINVAL; | ||
1348 | goto err; | ||
1349 | } | ||
1350 | |||
1351 | taal_cancel_ulps_work(dssdev); | ||
1352 | taal_cancel_esd_work(dssdev); | ||
1353 | |||
1354 | dsi_bus_lock(dssdev); | ||
1355 | |||
1356 | r = taal_wake_up(dssdev); | ||
1357 | if (!r) | ||
1358 | taal_power_off(dssdev); | ||
1359 | |||
1360 | dsi_bus_unlock(dssdev); | ||
1361 | |||
1362 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | ||
1363 | |||
1364 | mutex_unlock(&td->lock); | ||
1365 | |||
1366 | return 0; | ||
1367 | err: | ||
1368 | mutex_unlock(&td->lock); | ||
1369 | return r; | ||
1370 | } | ||
1371 | |||
1372 | static int taal_resume(struct omap_dss_device *dssdev) | ||
1373 | { | ||
1374 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | ||
1375 | int r; | ||
1376 | |||
1377 | dev_dbg(&dssdev->dev, "resume\n"); | ||
1378 | |||
1379 | mutex_lock(&td->lock); | ||
1380 | |||
1381 | if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) { | ||
1382 | r = -EINVAL; | ||
1383 | goto err; | ||
1384 | } | ||
1385 | |||
1386 | dsi_bus_lock(dssdev); | ||
1387 | |||
1388 | r = taal_power_on(dssdev); | ||
1389 | |||
1390 | dsi_bus_unlock(dssdev); | ||
1391 | |||
1392 | if (r) { | ||
1393 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
1394 | } else { | ||
1395 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
1396 | taal_queue_esd_work(dssdev); | ||
1397 | } | ||
1398 | |||
1399 | mutex_unlock(&td->lock); | ||
1400 | |||
1401 | return r; | ||
1402 | err: | ||
1403 | mutex_unlock(&td->lock); | ||
1404 | return r; | ||
1405 | } | ||
1406 | |||
1248 | static void taal_framedone_cb(int err, void *data) | 1407 | static void taal_framedone_cb(int err, void *data) |
1249 | { | 1408 | { |
1250 | struct omap_dss_device *dssdev = data; | 1409 | struct omap_dss_device *dssdev = data; |
@@ -1264,8 +1423,12 @@ static irqreturn_t taal_te_isr(int irq, void *data) | |||
1264 | if (old) { | 1423 | if (old) { |
1265 | cancel_delayed_work(&td->te_timeout_work); | 1424 | cancel_delayed_work(&td->te_timeout_work); |
1266 | 1425 | ||
1267 | r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, | 1426 | r = omap_dsi_update(dssdev, td->channel, |
1268 | dssdev); | 1427 | td->update_region.x, |
1428 | td->update_region.y, | ||
1429 | td->update_region.w, | ||
1430 | td->update_region.h, | ||
1431 | taal_framedone_cb, dssdev); | ||
1269 | if (r) | 1432 | if (r) |
1270 | goto err; | 1433 | goto err; |
1271 | } | 1434 | } |
@@ -1293,6 +1456,7 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
1293 | u16 x, u16 y, u16 w, u16 h) | 1456 | u16 x, u16 y, u16 w, u16 h) |
1294 | { | 1457 | { |
1295 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1458 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1459 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
1296 | int r; | 1460 | int r; |
1297 | 1461 | ||
1298 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); | 1462 | dev_dbg(&dssdev->dev, "update %d, %d, %d x %d\n", x, y, w, h); |
@@ -1309,20 +1473,26 @@ static int taal_update(struct omap_dss_device *dssdev, | |||
1309 | goto err; | 1473 | goto err; |
1310 | } | 1474 | } |
1311 | 1475 | ||
1312 | /* XXX no need to send this every frame, but dsi break if not done */ | 1476 | r = omap_dsi_prepare_update(dssdev, &x, &y, &w, &h, true); |
1313 | r = taal_set_update_window(td, 0, 0, | ||
1314 | td->panel_config->timings.x_res, | ||
1315 | td->panel_config->timings.y_res); | ||
1316 | if (r) | 1477 | if (r) |
1317 | goto err; | 1478 | goto err; |
1318 | 1479 | ||
1319 | if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { | 1480 | r = taal_set_update_window(td, x, y, w, h); |
1481 | if (r) | ||
1482 | goto err; | ||
1483 | |||
1484 | if (td->te_enabled && panel_data->use_ext_te) { | ||
1485 | td->update_region.x = x; | ||
1486 | td->update_region.y = y; | ||
1487 | td->update_region.w = w; | ||
1488 | td->update_region.h = h; | ||
1489 | barrier(); | ||
1320 | schedule_delayed_work(&td->te_timeout_work, | 1490 | schedule_delayed_work(&td->te_timeout_work, |
1321 | msecs_to_jiffies(250)); | 1491 | msecs_to_jiffies(250)); |
1322 | atomic_set(&td->do_update, 1); | 1492 | atomic_set(&td->do_update, 1); |
1323 | } else { | 1493 | } else { |
1324 | r = omap_dsi_update(dssdev, td->channel, taal_framedone_cb, | 1494 | r = omap_dsi_update(dssdev, td->channel, x, y, w, h, |
1325 | dssdev); | 1495 | taal_framedone_cb, dssdev); |
1326 | if (r) | 1496 | if (r) |
1327 | goto err; | 1497 | goto err; |
1328 | } | 1498 | } |
@@ -1355,14 +1525,15 @@ static int taal_sync(struct omap_dss_device *dssdev) | |||
1355 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) | 1525 | static int _taal_enable_te(struct omap_dss_device *dssdev, bool enable) |
1356 | { | 1526 | { |
1357 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1527 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1528 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
1358 | int r; | 1529 | int r; |
1359 | 1530 | ||
1360 | if (enable) | 1531 | if (enable) |
1361 | r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); | 1532 | r = taal_dcs_write_1(td, DCS_TEAR_ON, 0); |
1362 | else | 1533 | else |
1363 | r = taal_dcs_write_0(td, MIPI_DCS_SET_TEAR_OFF); | 1534 | r = taal_dcs_write_0(td, DCS_TEAR_OFF); |
1364 | 1535 | ||
1365 | if (!gpio_is_valid(td->ext_te_gpio)) | 1536 | if (!panel_data->use_ext_te) |
1366 | omapdss_dsi_enable_te(dssdev, enable); | 1537 | omapdss_dsi_enable_te(dssdev, enable); |
1367 | 1538 | ||
1368 | if (td->panel_config->sleep.enable_te) | 1539 | if (td->panel_config->sleep.enable_te) |
@@ -1422,7 +1593,6 @@ static int taal_get_te(struct omap_dss_device *dssdev) | |||
1422 | static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | 1593 | static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) |
1423 | { | 1594 | { |
1424 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1595 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1425 | u16 dw, dh; | ||
1426 | int r; | 1596 | int r; |
1427 | 1597 | ||
1428 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); | 1598 | dev_dbg(&dssdev->dev, "rotate %d\n", rotate); |
@@ -1444,16 +1614,6 @@ static int taal_rotate(struct omap_dss_device *dssdev, u8 rotate) | |||
1444 | goto err; | 1614 | goto err; |
1445 | } | 1615 | } |
1446 | 1616 | ||
1447 | if (rotate == 0 || rotate == 2) { | ||
1448 | dw = dssdev->panel.timings.x_res; | ||
1449 | dh = dssdev->panel.timings.y_res; | ||
1450 | } else { | ||
1451 | dw = dssdev->panel.timings.y_res; | ||
1452 | dh = dssdev->panel.timings.x_res; | ||
1453 | } | ||
1454 | |||
1455 | omapdss_dsi_set_size(dssdev, dw, dh); | ||
1456 | |||
1457 | td->rotate = rotate; | 1617 | td->rotate = rotate; |
1458 | 1618 | ||
1459 | dsi_bus_unlock(dssdev); | 1619 | dsi_bus_unlock(dssdev); |
@@ -1672,6 +1832,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1672 | struct taal_data *td = container_of(work, struct taal_data, | 1832 | struct taal_data *td = container_of(work, struct taal_data, |
1673 | esd_work.work); | 1833 | esd_work.work); |
1674 | struct omap_dss_device *dssdev = td->dssdev; | 1834 | struct omap_dss_device *dssdev = td->dssdev; |
1835 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
1675 | u8 state1, state2; | 1836 | u8 state1, state2; |
1676 | int r; | 1837 | int r; |
1677 | 1838 | ||
@@ -1690,7 +1851,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1690 | goto err; | 1851 | goto err; |
1691 | } | 1852 | } |
1692 | 1853 | ||
1693 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state1); | 1854 | r = taal_dcs_read_1(td, DCS_RDDSDR, &state1); |
1694 | if (r) { | 1855 | if (r) { |
1695 | dev_err(&dssdev->dev, "failed to read Taal status\n"); | 1856 | dev_err(&dssdev->dev, "failed to read Taal status\n"); |
1696 | goto err; | 1857 | goto err; |
@@ -1703,7 +1864,7 @@ static void taal_esd_work(struct work_struct *work) | |||
1703 | goto err; | 1864 | goto err; |
1704 | } | 1865 | } |
1705 | 1866 | ||
1706 | r = taal_dcs_read_1(td, MIPI_DCS_GET_DIAGNOSTIC_RESULT, &state2); | 1867 | r = taal_dcs_read_1(td, DCS_RDDSDR, &state2); |
1707 | if (r) { | 1868 | if (r) { |
1708 | dev_err(&dssdev->dev, "failed to read Taal status\n"); | 1869 | dev_err(&dssdev->dev, "failed to read Taal status\n"); |
1709 | goto err; | 1870 | goto err; |
@@ -1718,8 +1879,8 @@ static void taal_esd_work(struct work_struct *work) | |||
1718 | } | 1879 | } |
1719 | /* Self-diagnostics result is also shown on TE GPIO line. We need | 1880 | /* Self-diagnostics result is also shown on TE GPIO line. We need |
1720 | * to re-enable TE after self diagnostics */ | 1881 | * to re-enable TE after self diagnostics */ |
1721 | if (td->te_enabled && gpio_is_valid(td->ext_te_gpio)) { | 1882 | if (td->te_enabled && panel_data->use_ext_te) { |
1722 | r = taal_dcs_write_1(td, MIPI_DCS_SET_TEAR_ON, 0); | 1883 | r = taal_dcs_write_1(td, DCS_TEAR_ON, 0); |
1723 | if (r) | 1884 | if (r) |
1724 | goto err; | 1885 | goto err; |
1725 | } | 1886 | } |
@@ -1748,6 +1909,8 @@ static struct omap_dss_driver taal_driver = { | |||
1748 | 1909 | ||
1749 | .enable = taal_enable, | 1910 | .enable = taal_enable, |
1750 | .disable = taal_disable, | 1911 | .disable = taal_disable, |
1912 | .suspend = taal_suspend, | ||
1913 | .resume = taal_resume, | ||
1751 | 1914 | ||
1752 | .update = taal_update, | 1915 | .update = taal_update, |
1753 | .sync = taal_sync, | 1916 | .sync = taal_sync, |
@@ -1765,6 +1928,8 @@ static struct omap_dss_driver taal_driver = { | |||
1765 | .run_test = taal_run_test, | 1928 | .run_test = taal_run_test, |
1766 | .memory_read = taal_memory_read, | 1929 | .memory_read = taal_memory_read, |
1767 | 1930 | ||
1931 | .get_timings = taal_get_timings, | ||
1932 | |||
1768 | .driver = { | 1933 | .driver = { |
1769 | .name = "taal", | 1934 | .name = "taal", |
1770 | .owner = THIS_MODULE, | 1935 | .owner = THIS_MODULE, |
diff --git a/drivers/video/omap2/displays/panel-tfp410.c b/drivers/video/omap2/displays/panel-tfp410.c deleted file mode 100644 index 8281baafe1e..00000000000 --- a/drivers/video/omap2/displays/panel-tfp410.c +++ /dev/null | |||
@@ -1,353 +0,0 @@ | |||
1 | /* | ||
2 | * TFP410 DPI-to-DVI chip | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments Inc | ||
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <video/omapdss.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <drm/drm_edid.h> | ||
26 | |||
27 | #include <video/omap-panel-tfp410.h> | ||
28 | |||
29 | static const struct omap_video_timings tfp410_default_timings = { | ||
30 | .x_res = 640, | ||
31 | .y_res = 480, | ||
32 | |||
33 | .pixel_clock = 23500, | ||
34 | |||
35 | .hfp = 48, | ||
36 | .hsw = 32, | ||
37 | .hbp = 80, | ||
38 | |||
39 | .vfp = 3, | ||
40 | .vsw = 4, | ||
41 | .vbp = 7, | ||
42 | |||
43 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
44 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
45 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE, | ||
46 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
47 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
48 | }; | ||
49 | |||
50 | struct panel_drv_data { | ||
51 | struct omap_dss_device *dssdev; | ||
52 | |||
53 | struct mutex lock; | ||
54 | |||
55 | int pd_gpio; | ||
56 | |||
57 | struct i2c_adapter *i2c_adapter; | ||
58 | }; | ||
59 | |||
60 | static int tfp410_power_on(struct omap_dss_device *dssdev) | ||
61 | { | ||
62 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
63 | int r; | ||
64 | |||
65 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
66 | return 0; | ||
67 | |||
68 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
69 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
70 | |||
71 | r = omapdss_dpi_display_enable(dssdev); | ||
72 | if (r) | ||
73 | goto err0; | ||
74 | |||
75 | if (gpio_is_valid(ddata->pd_gpio)) | ||
76 | gpio_set_value_cansleep(ddata->pd_gpio, 1); | ||
77 | |||
78 | return 0; | ||
79 | err0: | ||
80 | return r; | ||
81 | } | ||
82 | |||
83 | static void tfp410_power_off(struct omap_dss_device *dssdev) | ||
84 | { | ||
85 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
86 | |||
87 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
88 | return; | ||
89 | |||
90 | if (gpio_is_valid(ddata->pd_gpio)) | ||
91 | gpio_set_value_cansleep(ddata->pd_gpio, 0); | ||
92 | |||
93 | omapdss_dpi_display_disable(dssdev); | ||
94 | } | ||
95 | |||
96 | static int tfp410_probe(struct omap_dss_device *dssdev) | ||
97 | { | ||
98 | struct panel_drv_data *ddata; | ||
99 | int r; | ||
100 | int i2c_bus_num; | ||
101 | |||
102 | ddata = devm_kzalloc(&dssdev->dev, sizeof(*ddata), GFP_KERNEL); | ||
103 | if (!ddata) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | dssdev->panel.timings = tfp410_default_timings; | ||
107 | |||
108 | ddata->dssdev = dssdev; | ||
109 | mutex_init(&ddata->lock); | ||
110 | |||
111 | if (dssdev->data) { | ||
112 | struct tfp410_platform_data *pdata = dssdev->data; | ||
113 | |||
114 | ddata->pd_gpio = pdata->power_down_gpio; | ||
115 | i2c_bus_num = pdata->i2c_bus_num; | ||
116 | } else { | ||
117 | ddata->pd_gpio = -1; | ||
118 | i2c_bus_num = -1; | ||
119 | } | ||
120 | |||
121 | if (gpio_is_valid(ddata->pd_gpio)) { | ||
122 | r = devm_gpio_request_one(&dssdev->dev, ddata->pd_gpio, | ||
123 | GPIOF_OUT_INIT_LOW, "tfp410 pd"); | ||
124 | if (r) { | ||
125 | dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", | ||
126 | ddata->pd_gpio); | ||
127 | return r; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | if (i2c_bus_num != -1) { | ||
132 | struct i2c_adapter *adapter; | ||
133 | |||
134 | adapter = i2c_get_adapter(i2c_bus_num); | ||
135 | if (!adapter) { | ||
136 | dev_err(&dssdev->dev, "Failed to get I2C adapter, bus %d\n", | ||
137 | i2c_bus_num); | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | ddata->i2c_adapter = adapter; | ||
142 | } | ||
143 | |||
144 | dev_set_drvdata(&dssdev->dev, ddata); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) | ||
150 | { | ||
151 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
152 | |||
153 | mutex_lock(&ddata->lock); | ||
154 | |||
155 | if (ddata->i2c_adapter) | ||
156 | i2c_put_adapter(ddata->i2c_adapter); | ||
157 | |||
158 | dev_set_drvdata(&dssdev->dev, NULL); | ||
159 | |||
160 | mutex_unlock(&ddata->lock); | ||
161 | } | ||
162 | |||
163 | static int tfp410_enable(struct omap_dss_device *dssdev) | ||
164 | { | ||
165 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
166 | int r; | ||
167 | |||
168 | mutex_lock(&ddata->lock); | ||
169 | |||
170 | r = tfp410_power_on(dssdev); | ||
171 | if (r == 0) | ||
172 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
173 | |||
174 | mutex_unlock(&ddata->lock); | ||
175 | |||
176 | return r; | ||
177 | } | ||
178 | |||
179 | static void tfp410_disable(struct omap_dss_device *dssdev) | ||
180 | { | ||
181 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
182 | |||
183 | mutex_lock(&ddata->lock); | ||
184 | |||
185 | tfp410_power_off(dssdev); | ||
186 | |||
187 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
188 | |||
189 | mutex_unlock(&ddata->lock); | ||
190 | } | ||
191 | |||
192 | static void tfp410_set_timings(struct omap_dss_device *dssdev, | ||
193 | struct omap_video_timings *timings) | ||
194 | { | ||
195 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
196 | |||
197 | mutex_lock(&ddata->lock); | ||
198 | omapdss_dpi_set_timings(dssdev, timings); | ||
199 | dssdev->panel.timings = *timings; | ||
200 | mutex_unlock(&ddata->lock); | ||
201 | } | ||
202 | |||
203 | static void tfp410_get_timings(struct omap_dss_device *dssdev, | ||
204 | struct omap_video_timings *timings) | ||
205 | { | ||
206 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
207 | |||
208 | mutex_lock(&ddata->lock); | ||
209 | *timings = dssdev->panel.timings; | ||
210 | mutex_unlock(&ddata->lock); | ||
211 | } | ||
212 | |||
213 | static int tfp410_check_timings(struct omap_dss_device *dssdev, | ||
214 | struct omap_video_timings *timings) | ||
215 | { | ||
216 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
217 | int r; | ||
218 | |||
219 | mutex_lock(&ddata->lock); | ||
220 | r = dpi_check_timings(dssdev, timings); | ||
221 | mutex_unlock(&ddata->lock); | ||
222 | |||
223 | return r; | ||
224 | } | ||
225 | |||
226 | |||
227 | static int tfp410_ddc_read(struct i2c_adapter *adapter, | ||
228 | unsigned char *buf, u16 count, u8 offset) | ||
229 | { | ||
230 | int r, retries; | ||
231 | |||
232 | for (retries = 3; retries > 0; retries--) { | ||
233 | struct i2c_msg msgs[] = { | ||
234 | { | ||
235 | .addr = DDC_ADDR, | ||
236 | .flags = 0, | ||
237 | .len = 1, | ||
238 | .buf = &offset, | ||
239 | }, { | ||
240 | .addr = DDC_ADDR, | ||
241 | .flags = I2C_M_RD, | ||
242 | .len = count, | ||
243 | .buf = buf, | ||
244 | } | ||
245 | }; | ||
246 | |||
247 | r = i2c_transfer(adapter, msgs, 2); | ||
248 | if (r == 2) | ||
249 | return 0; | ||
250 | |||
251 | if (r != -EAGAIN) | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | return r < 0 ? r : -EIO; | ||
256 | } | ||
257 | |||
258 | static int tfp410_read_edid(struct omap_dss_device *dssdev, | ||
259 | u8 *edid, int len) | ||
260 | { | ||
261 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
262 | int r, l, bytes_read; | ||
263 | |||
264 | mutex_lock(&ddata->lock); | ||
265 | |||
266 | if (!ddata->i2c_adapter) { | ||
267 | r = -ENODEV; | ||
268 | goto err; | ||
269 | } | ||
270 | |||
271 | l = min(EDID_LENGTH, len); | ||
272 | r = tfp410_ddc_read(ddata->i2c_adapter, edid, l, 0); | ||
273 | if (r) | ||
274 | goto err; | ||
275 | |||
276 | bytes_read = l; | ||
277 | |||
278 | /* if there are extensions, read second block */ | ||
279 | if (len > EDID_LENGTH && edid[0x7e] > 0) { | ||
280 | l = min(EDID_LENGTH, len - EDID_LENGTH); | ||
281 | |||
282 | r = tfp410_ddc_read(ddata->i2c_adapter, edid + EDID_LENGTH, | ||
283 | l, EDID_LENGTH); | ||
284 | if (r) | ||
285 | goto err; | ||
286 | |||
287 | bytes_read += l; | ||
288 | } | ||
289 | |||
290 | mutex_unlock(&ddata->lock); | ||
291 | |||
292 | return bytes_read; | ||
293 | |||
294 | err: | ||
295 | mutex_unlock(&ddata->lock); | ||
296 | return r; | ||
297 | } | ||
298 | |||
299 | static bool tfp410_detect(struct omap_dss_device *dssdev) | ||
300 | { | ||
301 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | ||
302 | unsigned char out; | ||
303 | int r; | ||
304 | |||
305 | mutex_lock(&ddata->lock); | ||
306 | |||
307 | if (!ddata->i2c_adapter) | ||
308 | goto out; | ||
309 | |||
310 | r = tfp410_ddc_read(ddata->i2c_adapter, &out, 1, 0); | ||
311 | |||
312 | mutex_unlock(&ddata->lock); | ||
313 | |||
314 | return r == 0; | ||
315 | |||
316 | out: | ||
317 | mutex_unlock(&ddata->lock); | ||
318 | return true; | ||
319 | } | ||
320 | |||
321 | static struct omap_dss_driver tfp410_driver = { | ||
322 | .probe = tfp410_probe, | ||
323 | .remove = __exit_p(tfp410_remove), | ||
324 | |||
325 | .enable = tfp410_enable, | ||
326 | .disable = tfp410_disable, | ||
327 | |||
328 | .set_timings = tfp410_set_timings, | ||
329 | .get_timings = tfp410_get_timings, | ||
330 | .check_timings = tfp410_check_timings, | ||
331 | |||
332 | .read_edid = tfp410_read_edid, | ||
333 | .detect = tfp410_detect, | ||
334 | |||
335 | .driver = { | ||
336 | .name = "tfp410", | ||
337 | .owner = THIS_MODULE, | ||
338 | }, | ||
339 | }; | ||
340 | |||
341 | static int __init tfp410_init(void) | ||
342 | { | ||
343 | return omap_dss_register_driver(&tfp410_driver); | ||
344 | } | ||
345 | |||
346 | static void __exit tfp410_exit(void) | ||
347 | { | ||
348 | omap_dss_unregister_driver(&tfp410_driver); | ||
349 | } | ||
350 | |||
351 | module_init(tfp410_init); | ||
352 | module_exit(tfp410_exit); | ||
353 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c index 6b6643911d2..2462b9ec666 100644 --- a/drivers/video/omap2/displays/panel-tpo-td043mtea1.c +++ b/drivers/video/omap2/displays/panel-tpo-td043mtea1.c | |||
@@ -47,20 +47,16 @@ | |||
47 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) | 47 | TPO_R03_EN_PRE_CHARGE | TPO_R03_SOFTWARE_CTL) |
48 | 48 | ||
49 | static const u16 tpo_td043_def_gamma[12] = { | 49 | static const u16 tpo_td043_def_gamma[12] = { |
50 | 105, 315, 381, 431, 490, 537, 579, 686, 780, 837, 880, 1023 | 50 | 106, 200, 289, 375, 460, 543, 625, 705, 785, 864, 942, 1020 |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct tpo_td043_device { | 53 | struct tpo_td043_device { |
54 | struct spi_device *spi; | 54 | struct spi_device *spi; |
55 | struct regulator *vcc_reg; | 55 | struct regulator *vcc_reg; |
56 | int nreset_gpio; | ||
57 | u16 gamma[12]; | 56 | u16 gamma[12]; |
58 | u32 mode; | 57 | u32 mode; |
59 | u32 hmirror:1; | 58 | u32 hmirror:1; |
60 | u32 vmirror:1; | 59 | u32 vmirror:1; |
61 | u32 powered_on:1; | ||
62 | u32 spi_suspended:1; | ||
63 | u32 power_on_resume:1; | ||
64 | }; | 60 | }; |
65 | 61 | ||
66 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) | 62 | static int tpo_td043_write(struct spi_device *spi, u8 addr, u8 data) |
@@ -267,27 +263,30 @@ static const struct omap_video_timings tpo_td043_timings = { | |||
267 | .vsw = 1, | 263 | .vsw = 1, |
268 | .vfp = 39, | 264 | .vfp = 39, |
269 | .vbp = 34, | 265 | .vbp = 34, |
270 | |||
271 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
272 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
273 | .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE, | ||
274 | .de_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
275 | .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES, | ||
276 | }; | 266 | }; |
277 | 267 | ||
278 | static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | 268 | static int tpo_td043_power_on(struct omap_dss_device *dssdev) |
279 | { | 269 | { |
280 | int nreset_gpio = tpo_td043->nreset_gpio; | 270 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); |
271 | int nreset_gpio = dssdev->reset_gpio; | ||
281 | int r; | 272 | int r; |
282 | 273 | ||
283 | if (tpo_td043->powered_on) | 274 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
284 | return 0; | 275 | return 0; |
285 | 276 | ||
286 | r = regulator_enable(tpo_td043->vcc_reg); | 277 | r = omapdss_dpi_display_enable(dssdev); |
287 | if (r != 0) | 278 | if (r) |
288 | return r; | 279 | goto err0; |
280 | |||
281 | if (dssdev->platform_enable) { | ||
282 | r = dssdev->platform_enable(dssdev); | ||
283 | if (r) | ||
284 | goto err1; | ||
285 | } | ||
286 | |||
287 | regulator_enable(tpo_td043->vcc_reg); | ||
289 | 288 | ||
290 | /* wait for panel to stabilize */ | 289 | /* wait for power up */ |
291 | msleep(160); | 290 | msleep(160); |
292 | 291 | ||
293 | if (gpio_is_valid(nreset_gpio)) | 292 | if (gpio_is_valid(nreset_gpio)) |
@@ -302,15 +301,19 @@ static int tpo_td043_power_on(struct tpo_td043_device *tpo_td043) | |||
302 | tpo_td043->vmirror); | 301 | tpo_td043->vmirror); |
303 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); | 302 | tpo_td043_write_gamma(tpo_td043->spi, tpo_td043->gamma); |
304 | 303 | ||
305 | tpo_td043->powered_on = 1; | ||
306 | return 0; | 304 | return 0; |
305 | err1: | ||
306 | omapdss_dpi_display_disable(dssdev); | ||
307 | err0: | ||
308 | return r; | ||
307 | } | 309 | } |
308 | 310 | ||
309 | static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | 311 | static void tpo_td043_power_off(struct omap_dss_device *dssdev) |
310 | { | 312 | { |
311 | int nreset_gpio = tpo_td043->nreset_gpio; | 313 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); |
314 | int nreset_gpio = dssdev->reset_gpio; | ||
312 | 315 | ||
313 | if (!tpo_td043->powered_on) | 316 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
314 | return; | 317 | return; |
315 | 318 | ||
316 | tpo_td043_write(tpo_td043->spi, 3, | 319 | tpo_td043_write(tpo_td043->spi, 3, |
@@ -326,79 +329,54 @@ static void tpo_td043_power_off(struct tpo_td043_device *tpo_td043) | |||
326 | 329 | ||
327 | regulator_disable(tpo_td043->vcc_reg); | 330 | regulator_disable(tpo_td043->vcc_reg); |
328 | 331 | ||
329 | tpo_td043->powered_on = 0; | 332 | if (dssdev->platform_disable) |
333 | dssdev->platform_disable(dssdev); | ||
334 | |||
335 | omapdss_dpi_display_disable(dssdev); | ||
330 | } | 336 | } |
331 | 337 | ||
332 | static int tpo_td043_enable_dss(struct omap_dss_device *dssdev) | 338 | static int tpo_td043_enable(struct omap_dss_device *dssdev) |
333 | { | 339 | { |
334 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 340 | int ret; |
335 | int r; | ||
336 | |||
337 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | ||
338 | return 0; | ||
339 | |||
340 | omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings); | ||
341 | omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines); | ||
342 | |||
343 | r = omapdss_dpi_display_enable(dssdev); | ||
344 | if (r) | ||
345 | goto err0; | ||
346 | 341 | ||
347 | if (dssdev->platform_enable) { | 342 | dev_dbg(&dssdev->dev, "enable\n"); |
348 | r = dssdev->platform_enable(dssdev); | ||
349 | if (r) | ||
350 | goto err1; | ||
351 | } | ||
352 | 343 | ||
353 | /* | 344 | ret = tpo_td043_power_on(dssdev); |
354 | * If we are resuming from system suspend, SPI clocks might not be | 345 | if (ret) |
355 | * enabled yet, so we'll program the LCD from SPI PM resume callback. | 346 | return ret; |
356 | */ | ||
357 | if (!tpo_td043->spi_suspended) { | ||
358 | r = tpo_td043_power_on(tpo_td043); | ||
359 | if (r) | ||
360 | goto err1; | ||
361 | } | ||
362 | 347 | ||
363 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 348 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
364 | 349 | ||
365 | return 0; | 350 | return 0; |
366 | err1: | ||
367 | omapdss_dpi_display_disable(dssdev); | ||
368 | err0: | ||
369 | return r; | ||
370 | } | 351 | } |
371 | 352 | ||
372 | static void tpo_td043_disable_dss(struct omap_dss_device *dssdev) | 353 | static void tpo_td043_disable(struct omap_dss_device *dssdev) |
373 | { | 354 | { |
374 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&dssdev->dev); | 355 | dev_dbg(&dssdev->dev, "disable\n"); |
375 | |||
376 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
377 | return; | ||
378 | |||
379 | if (dssdev->platform_disable) | ||
380 | dssdev->platform_disable(dssdev); | ||
381 | 356 | ||
382 | omapdss_dpi_display_disable(dssdev); | 357 | tpo_td043_power_off(dssdev); |
383 | 358 | ||
384 | if (!tpo_td043->spi_suspended) | 359 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
385 | tpo_td043_power_off(tpo_td043); | ||
386 | } | 360 | } |
387 | 361 | ||
388 | static int tpo_td043_enable(struct omap_dss_device *dssdev) | 362 | static int tpo_td043_suspend(struct omap_dss_device *dssdev) |
389 | { | 363 | { |
390 | dev_dbg(&dssdev->dev, "enable\n"); | 364 | tpo_td043_power_off(dssdev); |
391 | 365 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | |
392 | return tpo_td043_enable_dss(dssdev); | 366 | return 0; |
393 | } | 367 | } |
394 | 368 | ||
395 | static void tpo_td043_disable(struct omap_dss_device *dssdev) | 369 | static int tpo_td043_resume(struct omap_dss_device *dssdev) |
396 | { | 370 | { |
397 | dev_dbg(&dssdev->dev, "disable\n"); | 371 | int r = 0; |
372 | |||
373 | r = tpo_td043_power_on(dssdev); | ||
374 | if (r) | ||
375 | return r; | ||
398 | 376 | ||
399 | tpo_td043_disable_dss(dssdev); | 377 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
400 | 378 | ||
401 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 379 | return 0; |
402 | } | 380 | } |
403 | 381 | ||
404 | static int tpo_td043_probe(struct omap_dss_device *dssdev) | 382 | static int tpo_td043_probe(struct omap_dss_device *dssdev) |
@@ -414,6 +392,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
414 | return -ENODEV; | 392 | return -ENODEV; |
415 | } | 393 | } |
416 | 394 | ||
395 | dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IHS | | ||
396 | OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IPC; | ||
417 | dssdev->panel.timings = tpo_td043_timings; | 397 | dssdev->panel.timings = tpo_td043_timings; |
418 | dssdev->ctrl.pixel_size = 24; | 398 | dssdev->ctrl.pixel_size = 24; |
419 | 399 | ||
@@ -428,12 +408,17 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
428 | } | 408 | } |
429 | 409 | ||
430 | if (gpio_is_valid(nreset_gpio)) { | 410 | if (gpio_is_valid(nreset_gpio)) { |
431 | ret = gpio_request_one(nreset_gpio, GPIOF_OUT_INIT_LOW, | 411 | ret = gpio_request(nreset_gpio, "lcd reset"); |
432 | "lcd reset"); | ||
433 | if (ret < 0) { | 412 | if (ret < 0) { |
434 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); | 413 | dev_err(&dssdev->dev, "couldn't request reset GPIO\n"); |
435 | goto fail_gpio_req; | 414 | goto fail_gpio_req; |
436 | } | 415 | } |
416 | |||
417 | ret = gpio_direction_output(nreset_gpio, 0); | ||
418 | if (ret < 0) { | ||
419 | dev_err(&dssdev->dev, "couldn't set GPIO direction\n"); | ||
420 | goto fail_gpio_direction; | ||
421 | } | ||
437 | } | 422 | } |
438 | 423 | ||
439 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); | 424 | ret = sysfs_create_group(&dssdev->dev.kobj, &tpo_td043_attr_group); |
@@ -442,6 +427,8 @@ static int tpo_td043_probe(struct omap_dss_device *dssdev) | |||
442 | 427 | ||
443 | return 0; | 428 | return 0; |
444 | 429 | ||
430 | fail_gpio_direction: | ||
431 | gpio_free(nreset_gpio); | ||
445 | fail_gpio_req: | 432 | fail_gpio_req: |
446 | regulator_put(tpo_td043->vcc_reg); | 433 | regulator_put(tpo_td043->vcc_reg); |
447 | fail_regulator: | 434 | fail_regulator: |
@@ -462,32 +449,17 @@ static void tpo_td043_remove(struct omap_dss_device *dssdev) | |||
462 | gpio_free(nreset_gpio); | 449 | gpio_free(nreset_gpio); |
463 | } | 450 | } |
464 | 451 | ||
465 | static void tpo_td043_set_timings(struct omap_dss_device *dssdev, | ||
466 | struct omap_video_timings *timings) | ||
467 | { | ||
468 | omapdss_dpi_set_timings(dssdev, timings); | ||
469 | |||
470 | dssdev->panel.timings = *timings; | ||
471 | } | ||
472 | |||
473 | static int tpo_td043_check_timings(struct omap_dss_device *dssdev, | ||
474 | struct omap_video_timings *timings) | ||
475 | { | ||
476 | return dpi_check_timings(dssdev, timings); | ||
477 | } | ||
478 | |||
479 | static struct omap_dss_driver tpo_td043_driver = { | 452 | static struct omap_dss_driver tpo_td043_driver = { |
480 | .probe = tpo_td043_probe, | 453 | .probe = tpo_td043_probe, |
481 | .remove = tpo_td043_remove, | 454 | .remove = tpo_td043_remove, |
482 | 455 | ||
483 | .enable = tpo_td043_enable, | 456 | .enable = tpo_td043_enable, |
484 | .disable = tpo_td043_disable, | 457 | .disable = tpo_td043_disable, |
458 | .suspend = tpo_td043_suspend, | ||
459 | .resume = tpo_td043_resume, | ||
485 | .set_mirror = tpo_td043_set_hmirror, | 460 | .set_mirror = tpo_td043_set_hmirror, |
486 | .get_mirror = tpo_td043_get_hmirror, | 461 | .get_mirror = tpo_td043_get_hmirror, |
487 | 462 | ||
488 | .set_timings = tpo_td043_set_timings, | ||
489 | .check_timings = tpo_td043_check_timings, | ||
490 | |||
491 | .driver = { | 463 | .driver = { |
492 | .name = "tpo_td043mtea1_panel", | 464 | .name = "tpo_td043mtea1_panel", |
493 | .owner = THIS_MODULE, | 465 | .owner = THIS_MODULE, |
@@ -519,7 +491,6 @@ static int tpo_td043_spi_probe(struct spi_device *spi) | |||
519 | return -ENOMEM; | 491 | return -ENOMEM; |
520 | 492 | ||
521 | tpo_td043->spi = spi; | 493 | tpo_td043->spi = spi; |
522 | tpo_td043->nreset_gpio = dssdev->reset_gpio; | ||
523 | dev_set_drvdata(&spi->dev, tpo_td043); | 494 | dev_set_drvdata(&spi->dev, tpo_td043); |
524 | dev_set_drvdata(&dssdev->dev, tpo_td043); | 495 | dev_set_drvdata(&dssdev->dev, tpo_td043); |
525 | 496 | ||
@@ -528,7 +499,7 @@ static int tpo_td043_spi_probe(struct spi_device *spi) | |||
528 | return 0; | 499 | return 0; |
529 | } | 500 | } |
530 | 501 | ||
531 | static int tpo_td043_spi_remove(struct spi_device *spi) | 502 | static int __devexit tpo_td043_spi_remove(struct spi_device *spi) |
532 | { | 503 | { |
533 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); | 504 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(&spi->dev); |
534 | 505 | ||
@@ -538,52 +509,28 @@ static int tpo_td043_spi_remove(struct spi_device *spi) | |||
538 | return 0; | 509 | return 0; |
539 | } | 510 | } |
540 | 511 | ||
541 | #ifdef CONFIG_PM_SLEEP | ||
542 | static int tpo_td043_spi_suspend(struct device *dev) | ||
543 | { | ||
544 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
545 | |||
546 | dev_dbg(dev, "tpo_td043_spi_suspend, tpo %p\n", tpo_td043); | ||
547 | |||
548 | tpo_td043->power_on_resume = tpo_td043->powered_on; | ||
549 | tpo_td043_power_off(tpo_td043); | ||
550 | tpo_td043->spi_suspended = 1; | ||
551 | |||
552 | return 0; | ||
553 | } | ||
554 | |||
555 | static int tpo_td043_spi_resume(struct device *dev) | ||
556 | { | ||
557 | struct tpo_td043_device *tpo_td043 = dev_get_drvdata(dev); | ||
558 | int ret; | ||
559 | |||
560 | dev_dbg(dev, "tpo_td043_spi_resume\n"); | ||
561 | |||
562 | if (tpo_td043->power_on_resume) { | ||
563 | ret = tpo_td043_power_on(tpo_td043); | ||
564 | if (ret) | ||
565 | return ret; | ||
566 | } | ||
567 | tpo_td043->spi_suspended = 0; | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | #endif | ||
572 | |||
573 | static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm, | ||
574 | tpo_td043_spi_suspend, tpo_td043_spi_resume); | ||
575 | |||
576 | static struct spi_driver tpo_td043_spi_driver = { | 512 | static struct spi_driver tpo_td043_spi_driver = { |
577 | .driver = { | 513 | .driver = { |
578 | .name = "tpo_td043mtea1_panel_spi", | 514 | .name = "tpo_td043mtea1_panel_spi", |
515 | .bus = &spi_bus_type, | ||
579 | .owner = THIS_MODULE, | 516 | .owner = THIS_MODULE, |
580 | .pm = &tpo_td043_spi_pm, | ||
581 | }, | 517 | }, |
582 | .probe = tpo_td043_spi_probe, | 518 | .probe = tpo_td043_spi_probe, |
583 | .remove = tpo_td043_spi_remove, | 519 | .remove = __devexit_p(tpo_td043_spi_remove), |
584 | }; | 520 | }; |
585 | 521 | ||
586 | module_spi_driver(tpo_td043_spi_driver); | 522 | static int __init tpo_td043_init(void) |
523 | { | ||
524 | return spi_register_driver(&tpo_td043_spi_driver); | ||
525 | } | ||
526 | |||
527 | static void __exit tpo_td043_exit(void) | ||
528 | { | ||
529 | spi_unregister_driver(&tpo_td043_spi_driver); | ||
530 | } | ||
531 | |||
532 | module_init(tpo_td043_init); | ||
533 | module_exit(tpo_td043_exit); | ||
587 | 534 | ||
588 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); | 535 | MODULE_AUTHOR("Gražvydas Ignotas <notasas@gmail.com>"); |
589 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); | 536 | MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver"); |
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig index cb0f145c707..0d12524db14 100644 --- a/drivers/video/omap2/dss/Kconfig +++ b/drivers/video/omap2/dss/Kconfig | |||
@@ -1,30 +1,33 @@ | |||
1 | menuconfig OMAP2_DSS | 1 | menuconfig OMAP2_DSS |
2 | tristate "OMAP2+ Display Subsystem support" | 2 | tristate "OMAP2+ Display Subsystem support (EXPERIMENTAL)" |
3 | depends on ARCH_OMAP2PLUS | ||
3 | help | 4 | help |
4 | OMAP2+ Display Subsystem support. | 5 | OMAP2+ Display Subsystem support. |
5 | 6 | ||
6 | if OMAP2_DSS | 7 | if OMAP2_DSS |
7 | 8 | ||
8 | config OMAP2_DSS_DEBUG | 9 | config OMAP2_VRAM_SIZE |
9 | bool "Debug support" | 10 | int "VRAM size (MB)" |
10 | default n | 11 | range 0 32 |
12 | default 0 | ||
11 | help | 13 | help |
12 | This enables printing of debug messages. Alternatively, debug messages | 14 | The amount of SDRAM to reserve at boot time for video RAM use. |
13 | can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting | 15 | This VRAM will be used by omapfb and other drivers that need |
14 | appropriate flags in <debugfs>/dynamic_debug/control. | 16 | large continuous RAM area for video use. |
15 | 17 | ||
16 | config OMAP2_DSS_DEBUGFS | 18 | You can also set this with "vram=<bytes>" kernel argument, or |
17 | bool "Debugfs filesystem support" | 19 | in the board file. |
18 | depends on DEBUG_FS | 20 | |
19 | default n | 21 | config OMAP2_DSS_DEBUG_SUPPORT |
22 | bool "Debug support" | ||
23 | default y | ||
20 | help | 24 | help |
21 | This enables debugfs for OMAPDSS at <debugfs>/omapdss. This enables | 25 | This enables debug messages. You need to enable printing |
22 | querying about clock configuration and register configuration of dss, | 26 | with 'debug' module parameter. |
23 | dispc, dsi, hdmi and rfbi. | ||
24 | 27 | ||
25 | config OMAP2_DSS_COLLECT_IRQ_STATS | 28 | config OMAP2_DSS_COLLECT_IRQ_STATS |
26 | bool "Collect DSS IRQ statistics" | 29 | bool "Collect DSS IRQ statistics" |
27 | depends on OMAP2_DSS_DEBUGFS | 30 | depends on OMAP2_DSS_DEBUG_SUPPORT |
28 | default n | 31 | default n |
29 | help | 32 | help |
30 | Collect DSS IRQ statistics, printable via debugfs. | 33 | Collect DSS IRQ statistics, printable via debugfs. |
@@ -49,7 +52,7 @@ config OMAP2_DSS_RFBI | |||
49 | DBI is a bus between the host processor and a peripheral, | 52 | DBI is a bus between the host processor and a peripheral, |
50 | such as a display or a framebuffer chip. | 53 | such as a display or a framebuffer chip. |
51 | 54 | ||
52 | See http://www.mipi.org/ for DBI specifications. | 55 | See http://www.mipi.org/ for DBI spesifications. |
53 | 56 | ||
54 | config OMAP2_DSS_VENC | 57 | config OMAP2_DSS_VENC |
55 | bool "VENC support" | 58 | bool "VENC support" |
@@ -59,16 +62,15 @@ config OMAP2_DSS_VENC | |||
59 | 62 | ||
60 | config OMAP4_DSS_HDMI | 63 | config OMAP4_DSS_HDMI |
61 | bool "HDMI support" | 64 | bool "HDMI support" |
65 | depends on ARCH_OMAP4 | ||
62 | default y | 66 | default y |
63 | help | 67 | help |
64 | HDMI Interface. This adds the High Definition Multimedia Interface. | 68 | HDMI Interface. This adds the High Definition Multimedia Interface. |
65 | See http://www.hdmi.org/ for HDMI specification. | 69 | See http://www.hdmi.org/ for HDMI specification. |
66 | 70 | ||
67 | config OMAP4_DSS_HDMI_AUDIO | ||
68 | bool | ||
69 | |||
70 | config OMAP2_DSS_SDI | 71 | config OMAP2_DSS_SDI |
71 | bool "SDI support" | 72 | bool "SDI support" |
73 | depends on ARCH_OMAP3 | ||
72 | default n | 74 | default n |
73 | help | 75 | help |
74 | SDI (Serial Display Interface) support. | 76 | SDI (Serial Display Interface) support. |
@@ -78,6 +80,7 @@ config OMAP2_DSS_SDI | |||
78 | 80 | ||
79 | config OMAP2_DSS_DSI | 81 | config OMAP2_DSS_DSI |
80 | bool "DSI support" | 82 | bool "DSI support" |
83 | depends on ARCH_OMAP3 || ARCH_OMAP4 | ||
81 | default n | 84 | default n |
82 | help | 85 | help |
83 | MIPI DSI (Display Serial Interface) support. | 86 | MIPI DSI (Display Serial Interface) support. |
@@ -85,7 +88,16 @@ config OMAP2_DSS_DSI | |||
85 | DSI is a high speed half-duplex serial interface between the host | 88 | DSI is a high speed half-duplex serial interface between the host |
86 | processor and a peripheral, such as a display or a framebuffer chip. | 89 | processor and a peripheral, such as a display or a framebuffer chip. |
87 | 90 | ||
88 | See http://www.mipi.org/ for DSI specifications. | 91 | See http://www.mipi.org/ for DSI spesifications. |
92 | |||
93 | config OMAP2_DSS_FAKE_VSYNC | ||
94 | bool "Fake VSYNC irq from manual update displays" | ||
95 | default n | ||
96 | help | ||
97 | If this is selected, DSI will generate a fake DISPC VSYNC interrupt | ||
98 | when DSI has sent a frame. This is only needed with DSI or RFBI | ||
99 | displays using manual mode, and you want VSYNC to, for example, | ||
100 | time animation. | ||
89 | 101 | ||
90 | config OMAP2_DSS_MIN_FCK_PER_PCK | 102 | config OMAP2_DSS_MIN_FCK_PER_PCK |
91 | int "Minimum FCK/PCK ratio (for scaling)" | 103 | int "Minimum FCK/PCK ratio (for scaling)" |
diff --git a/drivers/video/omap2/dss/Makefile b/drivers/video/omap2/dss/Makefile index 61949ff7940..10d9d3bb3e2 100644 --- a/drivers/video/omap2/dss/Makefile +++ b/drivers/video/omap2/dss/Makefile | |||
@@ -1,15 +1,9 @@ | |||
1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o | 1 | obj-$(CONFIG_OMAP2_DSS) += omapdss.o |
2 | # Core DSS files | 2 | omapdss-y := core.o dss.o dss_features.o dispc.o display.o manager.o overlay.o |
3 | omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ | ||
4 | output.o | ||
5 | # DSS compat layer files | ||
6 | omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ | ||
7 | dispc-compat.o display-sysfs.o | ||
8 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o | 3 | omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o |
9 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o | 4 | omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o |
10 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o venc_panel.o | 5 | omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o |
11 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o | 6 | omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o |
12 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o | 7 | omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o |
13 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ | 8 | omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi.o \ |
14 | hdmi_panel.o ti_hdmi_4xxx_ip.o | 9 | hdmi_omap4_panel.o |
15 | ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG | ||
diff --git a/drivers/video/omap2/dss/apply.c b/drivers/video/omap2/dss/apply.c deleted file mode 100644 index d446bdfc4c8..00000000000 --- a/drivers/video/omap2/dss/apply.c +++ /dev/null | |||
@@ -1,1671 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Texas Instruments | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #define DSS_SUBSYS_NAME "APPLY" | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | |||
26 | #include <video/omapdss.h> | ||
27 | |||
28 | #include "dss.h" | ||
29 | #include "dss_features.h" | ||
30 | #include "dispc-compat.h" | ||
31 | |||
32 | /* | ||
33 | * We have 4 levels of cache for the dispc settings. First two are in SW and | ||
34 | * the latter two in HW. | ||
35 | * | ||
36 | * set_info() | ||
37 | * v | ||
38 | * +--------------------+ | ||
39 | * | user_info | | ||
40 | * +--------------------+ | ||
41 | * v | ||
42 | * apply() | ||
43 | * v | ||
44 | * +--------------------+ | ||
45 | * | info | | ||
46 | * +--------------------+ | ||
47 | * v | ||
48 | * write_regs() | ||
49 | * v | ||
50 | * +--------------------+ | ||
51 | * | shadow registers | | ||
52 | * +--------------------+ | ||
53 | * v | ||
54 | * VFP or lcd/digit_enable | ||
55 | * v | ||
56 | * +--------------------+ | ||
57 | * | registers | | ||
58 | * +--------------------+ | ||
59 | */ | ||
60 | |||
61 | struct ovl_priv_data { | ||
62 | |||
63 | bool user_info_dirty; | ||
64 | struct omap_overlay_info user_info; | ||
65 | |||
66 | bool info_dirty; | ||
67 | struct omap_overlay_info info; | ||
68 | |||
69 | bool shadow_info_dirty; | ||
70 | |||
71 | bool extra_info_dirty; | ||
72 | bool shadow_extra_info_dirty; | ||
73 | |||
74 | bool enabled; | ||
75 | u32 fifo_low, fifo_high; | ||
76 | |||
77 | /* | ||
78 | * True if overlay is to be enabled. Used to check and calculate configs | ||
79 | * for the overlay before it is enabled in the HW. | ||
80 | */ | ||
81 | bool enabling; | ||
82 | }; | ||
83 | |||
84 | struct mgr_priv_data { | ||
85 | |||
86 | bool user_info_dirty; | ||
87 | struct omap_overlay_manager_info user_info; | ||
88 | |||
89 | bool info_dirty; | ||
90 | struct omap_overlay_manager_info info; | ||
91 | |||
92 | bool shadow_info_dirty; | ||
93 | |||
94 | /* If true, GO bit is up and shadow registers cannot be written. | ||
95 | * Never true for manual update displays */ | ||
96 | bool busy; | ||
97 | |||
98 | /* If true, dispc output is enabled */ | ||
99 | bool updating; | ||
100 | |||
101 | /* If true, a display is enabled using this manager */ | ||
102 | bool enabled; | ||
103 | |||
104 | bool extra_info_dirty; | ||
105 | bool shadow_extra_info_dirty; | ||
106 | |||
107 | struct omap_video_timings timings; | ||
108 | struct dss_lcd_mgr_config lcd_config; | ||
109 | |||
110 | void (*framedone_handler)(void *); | ||
111 | void *framedone_handler_data; | ||
112 | }; | ||
113 | |||
114 | static struct { | ||
115 | struct ovl_priv_data ovl_priv_data_array[MAX_DSS_OVERLAYS]; | ||
116 | struct mgr_priv_data mgr_priv_data_array[MAX_DSS_MANAGERS]; | ||
117 | |||
118 | bool irq_enabled; | ||
119 | } dss_data; | ||
120 | |||
121 | /* protects dss_data */ | ||
122 | static spinlock_t data_lock; | ||
123 | /* lock for blocking functions */ | ||
124 | static DEFINE_MUTEX(apply_lock); | ||
125 | static DECLARE_COMPLETION(extra_updated_completion); | ||
126 | |||
127 | static void dss_register_vsync_isr(void); | ||
128 | |||
129 | static struct ovl_priv_data *get_ovl_priv(struct omap_overlay *ovl) | ||
130 | { | ||
131 | return &dss_data.ovl_priv_data_array[ovl->id]; | ||
132 | } | ||
133 | |||
134 | static struct mgr_priv_data *get_mgr_priv(struct omap_overlay_manager *mgr) | ||
135 | { | ||
136 | return &dss_data.mgr_priv_data_array[mgr->id]; | ||
137 | } | ||
138 | |||
139 | static void apply_init_priv(void) | ||
140 | { | ||
141 | const int num_ovls = dss_feat_get_num_ovls(); | ||
142 | struct mgr_priv_data *mp; | ||
143 | int i; | ||
144 | |||
145 | spin_lock_init(&data_lock); | ||
146 | |||
147 | for (i = 0; i < num_ovls; ++i) { | ||
148 | struct ovl_priv_data *op; | ||
149 | |||
150 | op = &dss_data.ovl_priv_data_array[i]; | ||
151 | |||
152 | op->info.global_alpha = 255; | ||
153 | |||
154 | switch (i) { | ||
155 | case 0: | ||
156 | op->info.zorder = 0; | ||
157 | break; | ||
158 | case 1: | ||
159 | op->info.zorder = | ||
160 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 3 : 0; | ||
161 | break; | ||
162 | case 2: | ||
163 | op->info.zorder = | ||
164 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 2 : 0; | ||
165 | break; | ||
166 | case 3: | ||
167 | op->info.zorder = | ||
168 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER) ? 1 : 0; | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | op->user_info = op->info; | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * Initialize some of the lcd_config fields for TV manager, this lets | ||
177 | * us prevent checking if the manager is LCD or TV at some places | ||
178 | */ | ||
179 | mp = &dss_data.mgr_priv_data_array[OMAP_DSS_CHANNEL_DIGIT]; | ||
180 | |||
181 | mp->lcd_config.video_port_width = 24; | ||
182 | mp->lcd_config.clock_info.lck_div = 1; | ||
183 | mp->lcd_config.clock_info.pck_div = 1; | ||
184 | } | ||
185 | |||
186 | /* | ||
187 | * A LCD manager's stallmode decides whether it is in manual or auto update. TV | ||
188 | * manager is always auto update, stallmode field for TV manager is false by | ||
189 | * default | ||
190 | */ | ||
191 | static bool ovl_manual_update(struct omap_overlay *ovl) | ||
192 | { | ||
193 | struct mgr_priv_data *mp = get_mgr_priv(ovl->manager); | ||
194 | |||
195 | return mp->lcd_config.stallmode; | ||
196 | } | ||
197 | |||
198 | static bool mgr_manual_update(struct omap_overlay_manager *mgr) | ||
199 | { | ||
200 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
201 | |||
202 | return mp->lcd_config.stallmode; | ||
203 | } | ||
204 | |||
205 | static int dss_check_settings_low(struct omap_overlay_manager *mgr, | ||
206 | bool applying) | ||
207 | { | ||
208 | struct omap_overlay_info *oi; | ||
209 | struct omap_overlay_manager_info *mi; | ||
210 | struct omap_overlay *ovl; | ||
211 | struct omap_overlay_info *ois[MAX_DSS_OVERLAYS]; | ||
212 | struct ovl_priv_data *op; | ||
213 | struct mgr_priv_data *mp; | ||
214 | |||
215 | mp = get_mgr_priv(mgr); | ||
216 | |||
217 | if (!mp->enabled) | ||
218 | return 0; | ||
219 | |||
220 | if (applying && mp->user_info_dirty) | ||
221 | mi = &mp->user_info; | ||
222 | else | ||
223 | mi = &mp->info; | ||
224 | |||
225 | /* collect the infos to be tested into the array */ | ||
226 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
227 | op = get_ovl_priv(ovl); | ||
228 | |||
229 | if (!op->enabled && !op->enabling) | ||
230 | oi = NULL; | ||
231 | else if (applying && op->user_info_dirty) | ||
232 | oi = &op->user_info; | ||
233 | else | ||
234 | oi = &op->info; | ||
235 | |||
236 | ois[ovl->id] = oi; | ||
237 | } | ||
238 | |||
239 | return dss_mgr_check(mgr, mi, &mp->timings, &mp->lcd_config, ois); | ||
240 | } | ||
241 | |||
242 | /* | ||
243 | * check manager and overlay settings using overlay_info from data->info | ||
244 | */ | ||
245 | static int dss_check_settings(struct omap_overlay_manager *mgr) | ||
246 | { | ||
247 | return dss_check_settings_low(mgr, false); | ||
248 | } | ||
249 | |||
250 | /* | ||
251 | * check manager and overlay settings using overlay_info from ovl->info if | ||
252 | * dirty and from data->info otherwise | ||
253 | */ | ||
254 | static int dss_check_settings_apply(struct omap_overlay_manager *mgr) | ||
255 | { | ||
256 | return dss_check_settings_low(mgr, true); | ||
257 | } | ||
258 | |||
259 | static bool need_isr(void) | ||
260 | { | ||
261 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
262 | int i; | ||
263 | |||
264 | for (i = 0; i < num_mgrs; ++i) { | ||
265 | struct omap_overlay_manager *mgr; | ||
266 | struct mgr_priv_data *mp; | ||
267 | struct omap_overlay *ovl; | ||
268 | |||
269 | mgr = omap_dss_get_overlay_manager(i); | ||
270 | mp = get_mgr_priv(mgr); | ||
271 | |||
272 | if (!mp->enabled) | ||
273 | continue; | ||
274 | |||
275 | if (mgr_manual_update(mgr)) { | ||
276 | /* to catch FRAMEDONE */ | ||
277 | if (mp->updating) | ||
278 | return true; | ||
279 | } else { | ||
280 | /* to catch GO bit going down */ | ||
281 | if (mp->busy) | ||
282 | return true; | ||
283 | |||
284 | /* to write new values to registers */ | ||
285 | if (mp->info_dirty) | ||
286 | return true; | ||
287 | |||
288 | /* to set GO bit */ | ||
289 | if (mp->shadow_info_dirty) | ||
290 | return true; | ||
291 | |||
292 | /* | ||
293 | * NOTE: we don't check extra_info flags for disabled | ||
294 | * managers, once the manager is enabled, the extra_info | ||
295 | * related manager changes will be taken in by HW. | ||
296 | */ | ||
297 | |||
298 | /* to write new values to registers */ | ||
299 | if (mp->extra_info_dirty) | ||
300 | return true; | ||
301 | |||
302 | /* to set GO bit */ | ||
303 | if (mp->shadow_extra_info_dirty) | ||
304 | return true; | ||
305 | |||
306 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
307 | struct ovl_priv_data *op; | ||
308 | |||
309 | op = get_ovl_priv(ovl); | ||
310 | |||
311 | /* | ||
312 | * NOTE: we check extra_info flags even for | ||
313 | * disabled overlays, as extra_infos need to be | ||
314 | * always written. | ||
315 | */ | ||
316 | |||
317 | /* to write new values to registers */ | ||
318 | if (op->extra_info_dirty) | ||
319 | return true; | ||
320 | |||
321 | /* to set GO bit */ | ||
322 | if (op->shadow_extra_info_dirty) | ||
323 | return true; | ||
324 | |||
325 | if (!op->enabled) | ||
326 | continue; | ||
327 | |||
328 | /* to write new values to registers */ | ||
329 | if (op->info_dirty) | ||
330 | return true; | ||
331 | |||
332 | /* to set GO bit */ | ||
333 | if (op->shadow_info_dirty) | ||
334 | return true; | ||
335 | } | ||
336 | } | ||
337 | } | ||
338 | |||
339 | return false; | ||
340 | } | ||
341 | |||
342 | static bool need_go(struct omap_overlay_manager *mgr) | ||
343 | { | ||
344 | struct omap_overlay *ovl; | ||
345 | struct mgr_priv_data *mp; | ||
346 | struct ovl_priv_data *op; | ||
347 | |||
348 | mp = get_mgr_priv(mgr); | ||
349 | |||
350 | if (mp->shadow_info_dirty || mp->shadow_extra_info_dirty) | ||
351 | return true; | ||
352 | |||
353 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
354 | op = get_ovl_priv(ovl); | ||
355 | if (op->shadow_info_dirty || op->shadow_extra_info_dirty) | ||
356 | return true; | ||
357 | } | ||
358 | |||
359 | return false; | ||
360 | } | ||
361 | |||
362 | /* returns true if an extra_info field is currently being updated */ | ||
363 | static bool extra_info_update_ongoing(void) | ||
364 | { | ||
365 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
366 | int i; | ||
367 | |||
368 | for (i = 0; i < num_mgrs; ++i) { | ||
369 | struct omap_overlay_manager *mgr; | ||
370 | struct omap_overlay *ovl; | ||
371 | struct mgr_priv_data *mp; | ||
372 | |||
373 | mgr = omap_dss_get_overlay_manager(i); | ||
374 | mp = get_mgr_priv(mgr); | ||
375 | |||
376 | if (!mp->enabled) | ||
377 | continue; | ||
378 | |||
379 | if (!mp->updating) | ||
380 | continue; | ||
381 | |||
382 | if (mp->extra_info_dirty || mp->shadow_extra_info_dirty) | ||
383 | return true; | ||
384 | |||
385 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
386 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
387 | |||
388 | if (op->extra_info_dirty || op->shadow_extra_info_dirty) | ||
389 | return true; | ||
390 | } | ||
391 | } | ||
392 | |||
393 | return false; | ||
394 | } | ||
395 | |||
396 | /* wait until no extra_info updates are pending */ | ||
397 | static void wait_pending_extra_info_updates(void) | ||
398 | { | ||
399 | bool updating; | ||
400 | unsigned long flags; | ||
401 | unsigned long t; | ||
402 | int r; | ||
403 | |||
404 | spin_lock_irqsave(&data_lock, flags); | ||
405 | |||
406 | updating = extra_info_update_ongoing(); | ||
407 | |||
408 | if (!updating) { | ||
409 | spin_unlock_irqrestore(&data_lock, flags); | ||
410 | return; | ||
411 | } | ||
412 | |||
413 | init_completion(&extra_updated_completion); | ||
414 | |||
415 | spin_unlock_irqrestore(&data_lock, flags); | ||
416 | |||
417 | t = msecs_to_jiffies(500); | ||
418 | r = wait_for_completion_timeout(&extra_updated_completion, t); | ||
419 | if (r == 0) | ||
420 | DSSWARN("timeout in wait_pending_extra_info_updates\n"); | ||
421 | } | ||
422 | |||
423 | static inline struct omap_dss_device *dss_ovl_get_device(struct omap_overlay *ovl) | ||
424 | { | ||
425 | return ovl->manager ? | ||
426 | (ovl->manager->output ? ovl->manager->output->device : NULL) : | ||
427 | NULL; | ||
428 | } | ||
429 | |||
430 | static inline struct omap_dss_device *dss_mgr_get_device(struct omap_overlay_manager *mgr) | ||
431 | { | ||
432 | return mgr->output ? mgr->output->device : NULL; | ||
433 | } | ||
434 | |||
435 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | ||
436 | { | ||
437 | unsigned long timeout = msecs_to_jiffies(500); | ||
438 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
439 | u32 irq; | ||
440 | int r; | ||
441 | |||
442 | r = dispc_runtime_get(); | ||
443 | if (r) | ||
444 | return r; | ||
445 | |||
446 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC) | ||
447 | irq = DISPC_IRQ_EVSYNC_ODD; | ||
448 | else if (dssdev->type == OMAP_DISPLAY_TYPE_HDMI) | ||
449 | irq = DISPC_IRQ_EVSYNC_EVEN; | ||
450 | else | ||
451 | irq = dispc_mgr_get_vsync_irq(mgr->id); | ||
452 | |||
453 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
454 | |||
455 | dispc_runtime_put(); | ||
456 | |||
457 | return r; | ||
458 | } | ||
459 | |||
460 | static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | ||
461 | { | ||
462 | unsigned long timeout = msecs_to_jiffies(500); | ||
463 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
464 | u32 irq; | ||
465 | unsigned long flags; | ||
466 | int r; | ||
467 | int i; | ||
468 | |||
469 | spin_lock_irqsave(&data_lock, flags); | ||
470 | |||
471 | if (mgr_manual_update(mgr)) { | ||
472 | spin_unlock_irqrestore(&data_lock, flags); | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | if (!mp->enabled) { | ||
477 | spin_unlock_irqrestore(&data_lock, flags); | ||
478 | return 0; | ||
479 | } | ||
480 | |||
481 | spin_unlock_irqrestore(&data_lock, flags); | ||
482 | |||
483 | r = dispc_runtime_get(); | ||
484 | if (r) | ||
485 | return r; | ||
486 | |||
487 | irq = dispc_mgr_get_vsync_irq(mgr->id); | ||
488 | |||
489 | i = 0; | ||
490 | while (1) { | ||
491 | bool shadow_dirty, dirty; | ||
492 | |||
493 | spin_lock_irqsave(&data_lock, flags); | ||
494 | dirty = mp->info_dirty; | ||
495 | shadow_dirty = mp->shadow_info_dirty; | ||
496 | spin_unlock_irqrestore(&data_lock, flags); | ||
497 | |||
498 | if (!dirty && !shadow_dirty) { | ||
499 | r = 0; | ||
500 | break; | ||
501 | } | ||
502 | |||
503 | /* 4 iterations is the worst case: | ||
504 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
505 | * 2 - first VSYNC, dirty = true | ||
506 | * 3 - dirty = false, shadow_dirty = true | ||
507 | * 4 - shadow_dirty = false */ | ||
508 | if (i++ == 3) { | ||
509 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | ||
510 | mgr->id); | ||
511 | r = 0; | ||
512 | break; | ||
513 | } | ||
514 | |||
515 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
516 | if (r == -ERESTARTSYS) | ||
517 | break; | ||
518 | |||
519 | if (r) { | ||
520 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | ||
521 | break; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | dispc_runtime_put(); | ||
526 | |||
527 | return r; | ||
528 | } | ||
529 | |||
530 | static int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) | ||
531 | { | ||
532 | unsigned long timeout = msecs_to_jiffies(500); | ||
533 | struct ovl_priv_data *op; | ||
534 | struct mgr_priv_data *mp; | ||
535 | u32 irq; | ||
536 | unsigned long flags; | ||
537 | int r; | ||
538 | int i; | ||
539 | |||
540 | if (!ovl->manager) | ||
541 | return 0; | ||
542 | |||
543 | mp = get_mgr_priv(ovl->manager); | ||
544 | |||
545 | spin_lock_irqsave(&data_lock, flags); | ||
546 | |||
547 | if (ovl_manual_update(ovl)) { | ||
548 | spin_unlock_irqrestore(&data_lock, flags); | ||
549 | return 0; | ||
550 | } | ||
551 | |||
552 | if (!mp->enabled) { | ||
553 | spin_unlock_irqrestore(&data_lock, flags); | ||
554 | return 0; | ||
555 | } | ||
556 | |||
557 | spin_unlock_irqrestore(&data_lock, flags); | ||
558 | |||
559 | r = dispc_runtime_get(); | ||
560 | if (r) | ||
561 | return r; | ||
562 | |||
563 | irq = dispc_mgr_get_vsync_irq(ovl->manager->id); | ||
564 | |||
565 | op = get_ovl_priv(ovl); | ||
566 | i = 0; | ||
567 | while (1) { | ||
568 | bool shadow_dirty, dirty; | ||
569 | |||
570 | spin_lock_irqsave(&data_lock, flags); | ||
571 | dirty = op->info_dirty; | ||
572 | shadow_dirty = op->shadow_info_dirty; | ||
573 | spin_unlock_irqrestore(&data_lock, flags); | ||
574 | |||
575 | if (!dirty && !shadow_dirty) { | ||
576 | r = 0; | ||
577 | break; | ||
578 | } | ||
579 | |||
580 | /* 4 iterations is the worst case: | ||
581 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
582 | * 2 - first VSYNC, dirty = true | ||
583 | * 3 - dirty = false, shadow_dirty = true | ||
584 | * 4 - shadow_dirty = false */ | ||
585 | if (i++ == 3) { | ||
586 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | ||
587 | ovl->id); | ||
588 | r = 0; | ||
589 | break; | ||
590 | } | ||
591 | |||
592 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
593 | if (r == -ERESTARTSYS) | ||
594 | break; | ||
595 | |||
596 | if (r) { | ||
597 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | ||
598 | break; | ||
599 | } | ||
600 | } | ||
601 | |||
602 | dispc_runtime_put(); | ||
603 | |||
604 | return r; | ||
605 | } | ||
606 | |||
607 | static void dss_ovl_write_regs(struct omap_overlay *ovl) | ||
608 | { | ||
609 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
610 | struct omap_overlay_info *oi; | ||
611 | bool replication; | ||
612 | struct mgr_priv_data *mp; | ||
613 | int r; | ||
614 | |||
615 | DSSDBG("writing ovl %d regs", ovl->id); | ||
616 | |||
617 | if (!op->enabled || !op->info_dirty) | ||
618 | return; | ||
619 | |||
620 | oi = &op->info; | ||
621 | |||
622 | mp = get_mgr_priv(ovl->manager); | ||
623 | |||
624 | replication = dss_ovl_use_replication(mp->lcd_config, oi->color_mode); | ||
625 | |||
626 | r = dispc_ovl_setup(ovl->id, oi, replication, &mp->timings, false); | ||
627 | if (r) { | ||
628 | /* | ||
629 | * We can't do much here, as this function can be called from | ||
630 | * vsync interrupt. | ||
631 | */ | ||
632 | DSSERR("dispc_ovl_setup failed for ovl %d\n", ovl->id); | ||
633 | |||
634 | /* This will leave fifo configurations in a nonoptimal state */ | ||
635 | op->enabled = false; | ||
636 | dispc_ovl_enable(ovl->id, false); | ||
637 | return; | ||
638 | } | ||
639 | |||
640 | op->info_dirty = false; | ||
641 | if (mp->updating) | ||
642 | op->shadow_info_dirty = true; | ||
643 | } | ||
644 | |||
645 | static void dss_ovl_write_regs_extra(struct omap_overlay *ovl) | ||
646 | { | ||
647 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
648 | struct mgr_priv_data *mp; | ||
649 | |||
650 | DSSDBG("writing ovl %d regs extra", ovl->id); | ||
651 | |||
652 | if (!op->extra_info_dirty) | ||
653 | return; | ||
654 | |||
655 | /* note: write also when op->enabled == false, so that the ovl gets | ||
656 | * disabled */ | ||
657 | |||
658 | dispc_ovl_enable(ovl->id, op->enabled); | ||
659 | dispc_ovl_set_fifo_threshold(ovl->id, op->fifo_low, op->fifo_high); | ||
660 | |||
661 | mp = get_mgr_priv(ovl->manager); | ||
662 | |||
663 | op->extra_info_dirty = false; | ||
664 | if (mp->updating) | ||
665 | op->shadow_extra_info_dirty = true; | ||
666 | } | ||
667 | |||
668 | static void dss_mgr_write_regs(struct omap_overlay_manager *mgr) | ||
669 | { | ||
670 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
671 | struct omap_overlay *ovl; | ||
672 | |||
673 | DSSDBG("writing mgr %d regs", mgr->id); | ||
674 | |||
675 | if (!mp->enabled) | ||
676 | return; | ||
677 | |||
678 | WARN_ON(mp->busy); | ||
679 | |||
680 | /* Commit overlay settings */ | ||
681 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
682 | dss_ovl_write_regs(ovl); | ||
683 | dss_ovl_write_regs_extra(ovl); | ||
684 | } | ||
685 | |||
686 | if (mp->info_dirty) { | ||
687 | dispc_mgr_setup(mgr->id, &mp->info); | ||
688 | |||
689 | mp->info_dirty = false; | ||
690 | if (mp->updating) | ||
691 | mp->shadow_info_dirty = true; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | static void dss_mgr_write_regs_extra(struct omap_overlay_manager *mgr) | ||
696 | { | ||
697 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
698 | |||
699 | DSSDBG("writing mgr %d regs extra", mgr->id); | ||
700 | |||
701 | if (!mp->extra_info_dirty) | ||
702 | return; | ||
703 | |||
704 | dispc_mgr_set_timings(mgr->id, &mp->timings); | ||
705 | |||
706 | /* lcd_config parameters */ | ||
707 | if (dss_mgr_is_lcd(mgr->id)) | ||
708 | dispc_mgr_set_lcd_config(mgr->id, &mp->lcd_config); | ||
709 | |||
710 | mp->extra_info_dirty = false; | ||
711 | if (mp->updating) | ||
712 | mp->shadow_extra_info_dirty = true; | ||
713 | } | ||
714 | |||
715 | static void dss_write_regs(void) | ||
716 | { | ||
717 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
718 | int i; | ||
719 | |||
720 | for (i = 0; i < num_mgrs; ++i) { | ||
721 | struct omap_overlay_manager *mgr; | ||
722 | struct mgr_priv_data *mp; | ||
723 | int r; | ||
724 | |||
725 | mgr = omap_dss_get_overlay_manager(i); | ||
726 | mp = get_mgr_priv(mgr); | ||
727 | |||
728 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | ||
729 | continue; | ||
730 | |||
731 | r = dss_check_settings(mgr); | ||
732 | if (r) { | ||
733 | DSSERR("cannot write registers for manager %s: " | ||
734 | "illegal configuration\n", mgr->name); | ||
735 | continue; | ||
736 | } | ||
737 | |||
738 | dss_mgr_write_regs(mgr); | ||
739 | dss_mgr_write_regs_extra(mgr); | ||
740 | } | ||
741 | } | ||
742 | |||
743 | static void dss_set_go_bits(void) | ||
744 | { | ||
745 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
746 | int i; | ||
747 | |||
748 | for (i = 0; i < num_mgrs; ++i) { | ||
749 | struct omap_overlay_manager *mgr; | ||
750 | struct mgr_priv_data *mp; | ||
751 | |||
752 | mgr = omap_dss_get_overlay_manager(i); | ||
753 | mp = get_mgr_priv(mgr); | ||
754 | |||
755 | if (!mp->enabled || mgr_manual_update(mgr) || mp->busy) | ||
756 | continue; | ||
757 | |||
758 | if (!need_go(mgr)) | ||
759 | continue; | ||
760 | |||
761 | mp->busy = true; | ||
762 | |||
763 | if (!dss_data.irq_enabled && need_isr()) | ||
764 | dss_register_vsync_isr(); | ||
765 | |||
766 | dispc_mgr_go(mgr->id); | ||
767 | } | ||
768 | |||
769 | } | ||
770 | |||
771 | static void mgr_clear_shadow_dirty(struct omap_overlay_manager *mgr) | ||
772 | { | ||
773 | struct omap_overlay *ovl; | ||
774 | struct mgr_priv_data *mp; | ||
775 | struct ovl_priv_data *op; | ||
776 | |||
777 | mp = get_mgr_priv(mgr); | ||
778 | mp->shadow_info_dirty = false; | ||
779 | mp->shadow_extra_info_dirty = false; | ||
780 | |||
781 | list_for_each_entry(ovl, &mgr->overlays, list) { | ||
782 | op = get_ovl_priv(ovl); | ||
783 | op->shadow_info_dirty = false; | ||
784 | op->shadow_extra_info_dirty = false; | ||
785 | } | ||
786 | } | ||
787 | |||
788 | static void dss_mgr_start_update_compat(struct omap_overlay_manager *mgr) | ||
789 | { | ||
790 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
791 | unsigned long flags; | ||
792 | int r; | ||
793 | |||
794 | spin_lock_irqsave(&data_lock, flags); | ||
795 | |||
796 | WARN_ON(mp->updating); | ||
797 | |||
798 | r = dss_check_settings(mgr); | ||
799 | if (r) { | ||
800 | DSSERR("cannot start manual update: illegal configuration\n"); | ||
801 | spin_unlock_irqrestore(&data_lock, flags); | ||
802 | return; | ||
803 | } | ||
804 | |||
805 | dss_mgr_write_regs(mgr); | ||
806 | dss_mgr_write_regs_extra(mgr); | ||
807 | |||
808 | mp->updating = true; | ||
809 | |||
810 | if (!dss_data.irq_enabled && need_isr()) | ||
811 | dss_register_vsync_isr(); | ||
812 | |||
813 | dispc_mgr_enable_sync(mgr->id); | ||
814 | |||
815 | spin_unlock_irqrestore(&data_lock, flags); | ||
816 | } | ||
817 | |||
818 | static void dss_apply_irq_handler(void *data, u32 mask); | ||
819 | |||
820 | static void dss_register_vsync_isr(void) | ||
821 | { | ||
822 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
823 | u32 mask; | ||
824 | int r, i; | ||
825 | |||
826 | mask = 0; | ||
827 | for (i = 0; i < num_mgrs; ++i) | ||
828 | mask |= dispc_mgr_get_vsync_irq(i); | ||
829 | |||
830 | for (i = 0; i < num_mgrs; ++i) | ||
831 | mask |= dispc_mgr_get_framedone_irq(i); | ||
832 | |||
833 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); | ||
834 | WARN_ON(r); | ||
835 | |||
836 | dss_data.irq_enabled = true; | ||
837 | } | ||
838 | |||
839 | static void dss_unregister_vsync_isr(void) | ||
840 | { | ||
841 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
842 | u32 mask; | ||
843 | int r, i; | ||
844 | |||
845 | mask = 0; | ||
846 | for (i = 0; i < num_mgrs; ++i) | ||
847 | mask |= dispc_mgr_get_vsync_irq(i); | ||
848 | |||
849 | for (i = 0; i < num_mgrs; ++i) | ||
850 | mask |= dispc_mgr_get_framedone_irq(i); | ||
851 | |||
852 | r = omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, mask); | ||
853 | WARN_ON(r); | ||
854 | |||
855 | dss_data.irq_enabled = false; | ||
856 | } | ||
857 | |||
858 | static void dss_apply_irq_handler(void *data, u32 mask) | ||
859 | { | ||
860 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
861 | int i; | ||
862 | bool extra_updating; | ||
863 | |||
864 | spin_lock(&data_lock); | ||
865 | |||
866 | /* clear busy, updating flags, shadow_dirty flags */ | ||
867 | for (i = 0; i < num_mgrs; i++) { | ||
868 | struct omap_overlay_manager *mgr; | ||
869 | struct mgr_priv_data *mp; | ||
870 | |||
871 | mgr = omap_dss_get_overlay_manager(i); | ||
872 | mp = get_mgr_priv(mgr); | ||
873 | |||
874 | if (!mp->enabled) | ||
875 | continue; | ||
876 | |||
877 | mp->updating = dispc_mgr_is_enabled(i); | ||
878 | |||
879 | if (!mgr_manual_update(mgr)) { | ||
880 | bool was_busy = mp->busy; | ||
881 | mp->busy = dispc_mgr_go_busy(i); | ||
882 | |||
883 | if (was_busy && !mp->busy) | ||
884 | mgr_clear_shadow_dirty(mgr); | ||
885 | } | ||
886 | } | ||
887 | |||
888 | dss_write_regs(); | ||
889 | dss_set_go_bits(); | ||
890 | |||
891 | extra_updating = extra_info_update_ongoing(); | ||
892 | if (!extra_updating) | ||
893 | complete_all(&extra_updated_completion); | ||
894 | |||
895 | /* call framedone handlers for manual update displays */ | ||
896 | for (i = 0; i < num_mgrs; i++) { | ||
897 | struct omap_overlay_manager *mgr; | ||
898 | struct mgr_priv_data *mp; | ||
899 | |||
900 | mgr = omap_dss_get_overlay_manager(i); | ||
901 | mp = get_mgr_priv(mgr); | ||
902 | |||
903 | if (!mgr_manual_update(mgr) || !mp->framedone_handler) | ||
904 | continue; | ||
905 | |||
906 | if (mask & dispc_mgr_get_framedone_irq(i)) | ||
907 | mp->framedone_handler(mp->framedone_handler_data); | ||
908 | } | ||
909 | |||
910 | if (!need_isr()) | ||
911 | dss_unregister_vsync_isr(); | ||
912 | |||
913 | spin_unlock(&data_lock); | ||
914 | } | ||
915 | |||
916 | static void omap_dss_mgr_apply_ovl(struct omap_overlay *ovl) | ||
917 | { | ||
918 | struct ovl_priv_data *op; | ||
919 | |||
920 | op = get_ovl_priv(ovl); | ||
921 | |||
922 | if (!op->user_info_dirty) | ||
923 | return; | ||
924 | |||
925 | op->user_info_dirty = false; | ||
926 | op->info_dirty = true; | ||
927 | op->info = op->user_info; | ||
928 | } | ||
929 | |||
930 | static void omap_dss_mgr_apply_mgr(struct omap_overlay_manager *mgr) | ||
931 | { | ||
932 | struct mgr_priv_data *mp; | ||
933 | |||
934 | mp = get_mgr_priv(mgr); | ||
935 | |||
936 | if (!mp->user_info_dirty) | ||
937 | return; | ||
938 | |||
939 | mp->user_info_dirty = false; | ||
940 | mp->info_dirty = true; | ||
941 | mp->info = mp->user_info; | ||
942 | } | ||
943 | |||
944 | static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | ||
945 | { | ||
946 | unsigned long flags; | ||
947 | struct omap_overlay *ovl; | ||
948 | int r; | ||
949 | |||
950 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); | ||
951 | |||
952 | spin_lock_irqsave(&data_lock, flags); | ||
953 | |||
954 | r = dss_check_settings_apply(mgr); | ||
955 | if (r) { | ||
956 | spin_unlock_irqrestore(&data_lock, flags); | ||
957 | DSSERR("failed to apply settings: illegal configuration.\n"); | ||
958 | return r; | ||
959 | } | ||
960 | |||
961 | /* Configure overlays */ | ||
962 | list_for_each_entry(ovl, &mgr->overlays, list) | ||
963 | omap_dss_mgr_apply_ovl(ovl); | ||
964 | |||
965 | /* Configure manager */ | ||
966 | omap_dss_mgr_apply_mgr(mgr); | ||
967 | |||
968 | dss_write_regs(); | ||
969 | dss_set_go_bits(); | ||
970 | |||
971 | spin_unlock_irqrestore(&data_lock, flags); | ||
972 | |||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | static void dss_apply_ovl_enable(struct omap_overlay *ovl, bool enable) | ||
977 | { | ||
978 | struct ovl_priv_data *op; | ||
979 | |||
980 | op = get_ovl_priv(ovl); | ||
981 | |||
982 | if (op->enabled == enable) | ||
983 | return; | ||
984 | |||
985 | op->enabled = enable; | ||
986 | op->extra_info_dirty = true; | ||
987 | } | ||
988 | |||
989 | static void dss_apply_ovl_fifo_thresholds(struct omap_overlay *ovl, | ||
990 | u32 fifo_low, u32 fifo_high) | ||
991 | { | ||
992 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
993 | |||
994 | if (op->fifo_low == fifo_low && op->fifo_high == fifo_high) | ||
995 | return; | ||
996 | |||
997 | op->fifo_low = fifo_low; | ||
998 | op->fifo_high = fifo_high; | ||
999 | op->extra_info_dirty = true; | ||
1000 | } | ||
1001 | |||
1002 | static void dss_ovl_setup_fifo(struct omap_overlay *ovl) | ||
1003 | { | ||
1004 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1005 | u32 fifo_low, fifo_high; | ||
1006 | bool use_fifo_merge = false; | ||
1007 | |||
1008 | if (!op->enabled && !op->enabling) | ||
1009 | return; | ||
1010 | |||
1011 | dispc_ovl_compute_fifo_thresholds(ovl->id, &fifo_low, &fifo_high, | ||
1012 | use_fifo_merge, ovl_manual_update(ovl)); | ||
1013 | |||
1014 | dss_apply_ovl_fifo_thresholds(ovl, fifo_low, fifo_high); | ||
1015 | } | ||
1016 | |||
1017 | static void dss_mgr_setup_fifos(struct omap_overlay_manager *mgr) | ||
1018 | { | ||
1019 | struct omap_overlay *ovl; | ||
1020 | struct mgr_priv_data *mp; | ||
1021 | |||
1022 | mp = get_mgr_priv(mgr); | ||
1023 | |||
1024 | if (!mp->enabled) | ||
1025 | return; | ||
1026 | |||
1027 | list_for_each_entry(ovl, &mgr->overlays, list) | ||
1028 | dss_ovl_setup_fifo(ovl); | ||
1029 | } | ||
1030 | |||
1031 | static void dss_setup_fifos(void) | ||
1032 | { | ||
1033 | const int num_mgrs = omap_dss_get_num_overlay_managers(); | ||
1034 | struct omap_overlay_manager *mgr; | ||
1035 | int i; | ||
1036 | |||
1037 | for (i = 0; i < num_mgrs; ++i) { | ||
1038 | mgr = omap_dss_get_overlay_manager(i); | ||
1039 | dss_mgr_setup_fifos(mgr); | ||
1040 | } | ||
1041 | } | ||
1042 | |||
1043 | static int dss_mgr_enable_compat(struct omap_overlay_manager *mgr) | ||
1044 | { | ||
1045 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1046 | unsigned long flags; | ||
1047 | int r; | ||
1048 | |||
1049 | mutex_lock(&apply_lock); | ||
1050 | |||
1051 | if (mp->enabled) | ||
1052 | goto out; | ||
1053 | |||
1054 | spin_lock_irqsave(&data_lock, flags); | ||
1055 | |||
1056 | mp->enabled = true; | ||
1057 | |||
1058 | r = dss_check_settings(mgr); | ||
1059 | if (r) { | ||
1060 | DSSERR("failed to enable manager %d: check_settings failed\n", | ||
1061 | mgr->id); | ||
1062 | goto err; | ||
1063 | } | ||
1064 | |||
1065 | dss_setup_fifos(); | ||
1066 | |||
1067 | dss_write_regs(); | ||
1068 | dss_set_go_bits(); | ||
1069 | |||
1070 | if (!mgr_manual_update(mgr)) | ||
1071 | mp->updating = true; | ||
1072 | |||
1073 | if (!dss_data.irq_enabled && need_isr()) | ||
1074 | dss_register_vsync_isr(); | ||
1075 | |||
1076 | spin_unlock_irqrestore(&data_lock, flags); | ||
1077 | |||
1078 | if (!mgr_manual_update(mgr)) | ||
1079 | dispc_mgr_enable_sync(mgr->id); | ||
1080 | |||
1081 | out: | ||
1082 | mutex_unlock(&apply_lock); | ||
1083 | |||
1084 | return 0; | ||
1085 | |||
1086 | err: | ||
1087 | mp->enabled = false; | ||
1088 | spin_unlock_irqrestore(&data_lock, flags); | ||
1089 | mutex_unlock(&apply_lock); | ||
1090 | return r; | ||
1091 | } | ||
1092 | |||
1093 | static void dss_mgr_disable_compat(struct omap_overlay_manager *mgr) | ||
1094 | { | ||
1095 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1096 | unsigned long flags; | ||
1097 | |||
1098 | mutex_lock(&apply_lock); | ||
1099 | |||
1100 | if (!mp->enabled) | ||
1101 | goto out; | ||
1102 | |||
1103 | if (!mgr_manual_update(mgr)) | ||
1104 | dispc_mgr_disable_sync(mgr->id); | ||
1105 | |||
1106 | spin_lock_irqsave(&data_lock, flags); | ||
1107 | |||
1108 | mp->updating = false; | ||
1109 | mp->enabled = false; | ||
1110 | |||
1111 | spin_unlock_irqrestore(&data_lock, flags); | ||
1112 | |||
1113 | out: | ||
1114 | mutex_unlock(&apply_lock); | ||
1115 | } | ||
1116 | |||
1117 | static int dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
1118 | struct omap_overlay_manager_info *info) | ||
1119 | { | ||
1120 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1121 | unsigned long flags; | ||
1122 | int r; | ||
1123 | |||
1124 | r = dss_mgr_simple_check(mgr, info); | ||
1125 | if (r) | ||
1126 | return r; | ||
1127 | |||
1128 | spin_lock_irqsave(&data_lock, flags); | ||
1129 | |||
1130 | mp->user_info = *info; | ||
1131 | mp->user_info_dirty = true; | ||
1132 | |||
1133 | spin_unlock_irqrestore(&data_lock, flags); | ||
1134 | |||
1135 | return 0; | ||
1136 | } | ||
1137 | |||
1138 | static void dss_mgr_get_info(struct omap_overlay_manager *mgr, | ||
1139 | struct omap_overlay_manager_info *info) | ||
1140 | { | ||
1141 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1142 | unsigned long flags; | ||
1143 | |||
1144 | spin_lock_irqsave(&data_lock, flags); | ||
1145 | |||
1146 | *info = mp->user_info; | ||
1147 | |||
1148 | spin_unlock_irqrestore(&data_lock, flags); | ||
1149 | } | ||
1150 | |||
1151 | static int dss_mgr_set_output(struct omap_overlay_manager *mgr, | ||
1152 | struct omap_dss_output *output) | ||
1153 | { | ||
1154 | int r; | ||
1155 | |||
1156 | mutex_lock(&apply_lock); | ||
1157 | |||
1158 | if (mgr->output) { | ||
1159 | DSSERR("manager %s is already connected to an output\n", | ||
1160 | mgr->name); | ||
1161 | r = -EINVAL; | ||
1162 | goto err; | ||
1163 | } | ||
1164 | |||
1165 | if ((mgr->supported_outputs & output->id) == 0) { | ||
1166 | DSSERR("output does not support manager %s\n", | ||
1167 | mgr->name); | ||
1168 | r = -EINVAL; | ||
1169 | goto err; | ||
1170 | } | ||
1171 | |||
1172 | output->manager = mgr; | ||
1173 | mgr->output = output; | ||
1174 | |||
1175 | mutex_unlock(&apply_lock); | ||
1176 | |||
1177 | return 0; | ||
1178 | err: | ||
1179 | mutex_unlock(&apply_lock); | ||
1180 | return r; | ||
1181 | } | ||
1182 | |||
1183 | static int dss_mgr_unset_output(struct omap_overlay_manager *mgr) | ||
1184 | { | ||
1185 | int r; | ||
1186 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1187 | unsigned long flags; | ||
1188 | |||
1189 | mutex_lock(&apply_lock); | ||
1190 | |||
1191 | if (!mgr->output) { | ||
1192 | DSSERR("failed to unset output, output not set\n"); | ||
1193 | r = -EINVAL; | ||
1194 | goto err; | ||
1195 | } | ||
1196 | |||
1197 | spin_lock_irqsave(&data_lock, flags); | ||
1198 | |||
1199 | if (mp->enabled) { | ||
1200 | DSSERR("output can't be unset when manager is enabled\n"); | ||
1201 | r = -EINVAL; | ||
1202 | goto err1; | ||
1203 | } | ||
1204 | |||
1205 | spin_unlock_irqrestore(&data_lock, flags); | ||
1206 | |||
1207 | mgr->output->manager = NULL; | ||
1208 | mgr->output = NULL; | ||
1209 | |||
1210 | mutex_unlock(&apply_lock); | ||
1211 | |||
1212 | return 0; | ||
1213 | err1: | ||
1214 | spin_unlock_irqrestore(&data_lock, flags); | ||
1215 | err: | ||
1216 | mutex_unlock(&apply_lock); | ||
1217 | |||
1218 | return r; | ||
1219 | } | ||
1220 | |||
1221 | static void dss_apply_mgr_timings(struct omap_overlay_manager *mgr, | ||
1222 | const struct omap_video_timings *timings) | ||
1223 | { | ||
1224 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1225 | |||
1226 | mp->timings = *timings; | ||
1227 | mp->extra_info_dirty = true; | ||
1228 | } | ||
1229 | |||
1230 | static void dss_mgr_set_timings_compat(struct omap_overlay_manager *mgr, | ||
1231 | const struct omap_video_timings *timings) | ||
1232 | { | ||
1233 | unsigned long flags; | ||
1234 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1235 | |||
1236 | spin_lock_irqsave(&data_lock, flags); | ||
1237 | |||
1238 | if (mp->updating) { | ||
1239 | DSSERR("cannot set timings for %s: manager needs to be disabled\n", | ||
1240 | mgr->name); | ||
1241 | goto out; | ||
1242 | } | ||
1243 | |||
1244 | dss_apply_mgr_timings(mgr, timings); | ||
1245 | out: | ||
1246 | spin_unlock_irqrestore(&data_lock, flags); | ||
1247 | } | ||
1248 | |||
1249 | static void dss_apply_mgr_lcd_config(struct omap_overlay_manager *mgr, | ||
1250 | const struct dss_lcd_mgr_config *config) | ||
1251 | { | ||
1252 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1253 | |||
1254 | mp->lcd_config = *config; | ||
1255 | mp->extra_info_dirty = true; | ||
1256 | } | ||
1257 | |||
1258 | static void dss_mgr_set_lcd_config_compat(struct omap_overlay_manager *mgr, | ||
1259 | const struct dss_lcd_mgr_config *config) | ||
1260 | { | ||
1261 | unsigned long flags; | ||
1262 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1263 | |||
1264 | spin_lock_irqsave(&data_lock, flags); | ||
1265 | |||
1266 | if (mp->enabled) { | ||
1267 | DSSERR("cannot apply lcd config for %s: manager needs to be disabled\n", | ||
1268 | mgr->name); | ||
1269 | goto out; | ||
1270 | } | ||
1271 | |||
1272 | dss_apply_mgr_lcd_config(mgr, config); | ||
1273 | out: | ||
1274 | spin_unlock_irqrestore(&data_lock, flags); | ||
1275 | } | ||
1276 | |||
1277 | static int dss_ovl_set_info(struct omap_overlay *ovl, | ||
1278 | struct omap_overlay_info *info) | ||
1279 | { | ||
1280 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1281 | unsigned long flags; | ||
1282 | int r; | ||
1283 | |||
1284 | r = dss_ovl_simple_check(ovl, info); | ||
1285 | if (r) | ||
1286 | return r; | ||
1287 | |||
1288 | spin_lock_irqsave(&data_lock, flags); | ||
1289 | |||
1290 | op->user_info = *info; | ||
1291 | op->user_info_dirty = true; | ||
1292 | |||
1293 | spin_unlock_irqrestore(&data_lock, flags); | ||
1294 | |||
1295 | return 0; | ||
1296 | } | ||
1297 | |||
1298 | static void dss_ovl_get_info(struct omap_overlay *ovl, | ||
1299 | struct omap_overlay_info *info) | ||
1300 | { | ||
1301 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1302 | unsigned long flags; | ||
1303 | |||
1304 | spin_lock_irqsave(&data_lock, flags); | ||
1305 | |||
1306 | *info = op->user_info; | ||
1307 | |||
1308 | spin_unlock_irqrestore(&data_lock, flags); | ||
1309 | } | ||
1310 | |||
1311 | static int dss_ovl_set_manager(struct omap_overlay *ovl, | ||
1312 | struct omap_overlay_manager *mgr) | ||
1313 | { | ||
1314 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1315 | unsigned long flags; | ||
1316 | int r; | ||
1317 | |||
1318 | if (!mgr) | ||
1319 | return -EINVAL; | ||
1320 | |||
1321 | mutex_lock(&apply_lock); | ||
1322 | |||
1323 | if (ovl->manager) { | ||
1324 | DSSERR("overlay '%s' already has a manager '%s'\n", | ||
1325 | ovl->name, ovl->manager->name); | ||
1326 | r = -EINVAL; | ||
1327 | goto err; | ||
1328 | } | ||
1329 | |||
1330 | r = dispc_runtime_get(); | ||
1331 | if (r) | ||
1332 | goto err; | ||
1333 | |||
1334 | spin_lock_irqsave(&data_lock, flags); | ||
1335 | |||
1336 | if (op->enabled) { | ||
1337 | spin_unlock_irqrestore(&data_lock, flags); | ||
1338 | DSSERR("overlay has to be disabled to change the manager\n"); | ||
1339 | r = -EINVAL; | ||
1340 | goto err1; | ||
1341 | } | ||
1342 | |||
1343 | dispc_ovl_set_channel_out(ovl->id, mgr->id); | ||
1344 | |||
1345 | ovl->manager = mgr; | ||
1346 | list_add_tail(&ovl->list, &mgr->overlays); | ||
1347 | |||
1348 | spin_unlock_irqrestore(&data_lock, flags); | ||
1349 | |||
1350 | dispc_runtime_put(); | ||
1351 | |||
1352 | mutex_unlock(&apply_lock); | ||
1353 | |||
1354 | return 0; | ||
1355 | |||
1356 | err1: | ||
1357 | dispc_runtime_put(); | ||
1358 | err: | ||
1359 | mutex_unlock(&apply_lock); | ||
1360 | return r; | ||
1361 | } | ||
1362 | |||
1363 | static int dss_ovl_unset_manager(struct omap_overlay *ovl) | ||
1364 | { | ||
1365 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1366 | unsigned long flags; | ||
1367 | int r; | ||
1368 | |||
1369 | mutex_lock(&apply_lock); | ||
1370 | |||
1371 | if (!ovl->manager) { | ||
1372 | DSSERR("failed to detach overlay: manager not set\n"); | ||
1373 | r = -EINVAL; | ||
1374 | goto err; | ||
1375 | } | ||
1376 | |||
1377 | spin_lock_irqsave(&data_lock, flags); | ||
1378 | |||
1379 | if (op->enabled) { | ||
1380 | spin_unlock_irqrestore(&data_lock, flags); | ||
1381 | DSSERR("overlay has to be disabled to unset the manager\n"); | ||
1382 | r = -EINVAL; | ||
1383 | goto err; | ||
1384 | } | ||
1385 | |||
1386 | spin_unlock_irqrestore(&data_lock, flags); | ||
1387 | |||
1388 | /* wait for pending extra_info updates to ensure the ovl is disabled */ | ||
1389 | wait_pending_extra_info_updates(); | ||
1390 | |||
1391 | /* | ||
1392 | * For a manual update display, there is no guarantee that the overlay | ||
1393 | * is really disabled in HW, we may need an extra update from this | ||
1394 | * manager before the configurations can go in. Return an error if the | ||
1395 | * overlay needed an update from the manager. | ||
1396 | * | ||
1397 | * TODO: Instead of returning an error, try to do a dummy manager update | ||
1398 | * here to disable the overlay in hardware. Use the *GATED fields in | ||
1399 | * the DISPC_CONFIG registers to do a dummy update. | ||
1400 | */ | ||
1401 | spin_lock_irqsave(&data_lock, flags); | ||
1402 | |||
1403 | if (ovl_manual_update(ovl) && op->extra_info_dirty) { | ||
1404 | spin_unlock_irqrestore(&data_lock, flags); | ||
1405 | DSSERR("need an update to change the manager\n"); | ||
1406 | r = -EINVAL; | ||
1407 | goto err; | ||
1408 | } | ||
1409 | |||
1410 | ovl->manager = NULL; | ||
1411 | list_del(&ovl->list); | ||
1412 | |||
1413 | spin_unlock_irqrestore(&data_lock, flags); | ||
1414 | |||
1415 | mutex_unlock(&apply_lock); | ||
1416 | |||
1417 | return 0; | ||
1418 | err: | ||
1419 | mutex_unlock(&apply_lock); | ||
1420 | return r; | ||
1421 | } | ||
1422 | |||
1423 | static bool dss_ovl_is_enabled(struct omap_overlay *ovl) | ||
1424 | { | ||
1425 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1426 | unsigned long flags; | ||
1427 | bool e; | ||
1428 | |||
1429 | spin_lock_irqsave(&data_lock, flags); | ||
1430 | |||
1431 | e = op->enabled; | ||
1432 | |||
1433 | spin_unlock_irqrestore(&data_lock, flags); | ||
1434 | |||
1435 | return e; | ||
1436 | } | ||
1437 | |||
1438 | static int dss_ovl_enable(struct omap_overlay *ovl) | ||
1439 | { | ||
1440 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1441 | unsigned long flags; | ||
1442 | int r; | ||
1443 | |||
1444 | mutex_lock(&apply_lock); | ||
1445 | |||
1446 | if (op->enabled) { | ||
1447 | r = 0; | ||
1448 | goto err1; | ||
1449 | } | ||
1450 | |||
1451 | if (ovl->manager == NULL || ovl->manager->output == NULL) { | ||
1452 | r = -EINVAL; | ||
1453 | goto err1; | ||
1454 | } | ||
1455 | |||
1456 | spin_lock_irqsave(&data_lock, flags); | ||
1457 | |||
1458 | op->enabling = true; | ||
1459 | |||
1460 | r = dss_check_settings(ovl->manager); | ||
1461 | if (r) { | ||
1462 | DSSERR("failed to enable overlay %d: check_settings failed\n", | ||
1463 | ovl->id); | ||
1464 | goto err2; | ||
1465 | } | ||
1466 | |||
1467 | dss_setup_fifos(); | ||
1468 | |||
1469 | op->enabling = false; | ||
1470 | dss_apply_ovl_enable(ovl, true); | ||
1471 | |||
1472 | dss_write_regs(); | ||
1473 | dss_set_go_bits(); | ||
1474 | |||
1475 | spin_unlock_irqrestore(&data_lock, flags); | ||
1476 | |||
1477 | mutex_unlock(&apply_lock); | ||
1478 | |||
1479 | return 0; | ||
1480 | err2: | ||
1481 | op->enabling = false; | ||
1482 | spin_unlock_irqrestore(&data_lock, flags); | ||
1483 | err1: | ||
1484 | mutex_unlock(&apply_lock); | ||
1485 | return r; | ||
1486 | } | ||
1487 | |||
1488 | static int dss_ovl_disable(struct omap_overlay *ovl) | ||
1489 | { | ||
1490 | struct ovl_priv_data *op = get_ovl_priv(ovl); | ||
1491 | unsigned long flags; | ||
1492 | int r; | ||
1493 | |||
1494 | mutex_lock(&apply_lock); | ||
1495 | |||
1496 | if (!op->enabled) { | ||
1497 | r = 0; | ||
1498 | goto err; | ||
1499 | } | ||
1500 | |||
1501 | if (ovl->manager == NULL || ovl->manager->output == NULL) { | ||
1502 | r = -EINVAL; | ||
1503 | goto err; | ||
1504 | } | ||
1505 | |||
1506 | spin_lock_irqsave(&data_lock, flags); | ||
1507 | |||
1508 | dss_apply_ovl_enable(ovl, false); | ||
1509 | dss_write_regs(); | ||
1510 | dss_set_go_bits(); | ||
1511 | |||
1512 | spin_unlock_irqrestore(&data_lock, flags); | ||
1513 | |||
1514 | mutex_unlock(&apply_lock); | ||
1515 | |||
1516 | return 0; | ||
1517 | |||
1518 | err: | ||
1519 | mutex_unlock(&apply_lock); | ||
1520 | return r; | ||
1521 | } | ||
1522 | |||
1523 | static int dss_mgr_register_framedone_handler_compat(struct omap_overlay_manager *mgr, | ||
1524 | void (*handler)(void *), void *data) | ||
1525 | { | ||
1526 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1527 | |||
1528 | if (mp->framedone_handler) | ||
1529 | return -EBUSY; | ||
1530 | |||
1531 | mp->framedone_handler = handler; | ||
1532 | mp->framedone_handler_data = data; | ||
1533 | |||
1534 | return 0; | ||
1535 | } | ||
1536 | |||
1537 | static void dss_mgr_unregister_framedone_handler_compat(struct omap_overlay_manager *mgr, | ||
1538 | void (*handler)(void *), void *data) | ||
1539 | { | ||
1540 | struct mgr_priv_data *mp = get_mgr_priv(mgr); | ||
1541 | |||
1542 | WARN_ON(mp->framedone_handler != handler || | ||
1543 | mp->framedone_handler_data != data); | ||
1544 | |||
1545 | mp->framedone_handler = NULL; | ||
1546 | mp->framedone_handler_data = NULL; | ||
1547 | } | ||
1548 | |||
1549 | static const struct dss_mgr_ops apply_mgr_ops = { | ||
1550 | .start_update = dss_mgr_start_update_compat, | ||
1551 | .enable = dss_mgr_enable_compat, | ||
1552 | .disable = dss_mgr_disable_compat, | ||
1553 | .set_timings = dss_mgr_set_timings_compat, | ||
1554 | .set_lcd_config = dss_mgr_set_lcd_config_compat, | ||
1555 | .register_framedone_handler = dss_mgr_register_framedone_handler_compat, | ||
1556 | .unregister_framedone_handler = dss_mgr_unregister_framedone_handler_compat, | ||
1557 | }; | ||
1558 | |||
1559 | static int compat_refcnt; | ||
1560 | static DEFINE_MUTEX(compat_init_lock); | ||
1561 | |||
1562 | int omapdss_compat_init(void) | ||
1563 | { | ||
1564 | struct platform_device *pdev = dss_get_core_pdev(); | ||
1565 | struct omap_dss_device *dssdev = NULL; | ||
1566 | int i, r; | ||
1567 | |||
1568 | mutex_lock(&compat_init_lock); | ||
1569 | |||
1570 | if (compat_refcnt++ > 0) | ||
1571 | goto out; | ||
1572 | |||
1573 | apply_init_priv(); | ||
1574 | |||
1575 | dss_init_overlay_managers(pdev); | ||
1576 | dss_init_overlays(pdev); | ||
1577 | |||
1578 | for (i = 0; i < omap_dss_get_num_overlay_managers(); i++) { | ||
1579 | struct omap_overlay_manager *mgr; | ||
1580 | |||
1581 | mgr = omap_dss_get_overlay_manager(i); | ||
1582 | |||
1583 | mgr->set_output = &dss_mgr_set_output; | ||
1584 | mgr->unset_output = &dss_mgr_unset_output; | ||
1585 | mgr->apply = &omap_dss_mgr_apply; | ||
1586 | mgr->set_manager_info = &dss_mgr_set_info; | ||
1587 | mgr->get_manager_info = &dss_mgr_get_info; | ||
1588 | mgr->wait_for_go = &dss_mgr_wait_for_go; | ||
1589 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | ||
1590 | mgr->get_device = &dss_mgr_get_device; | ||
1591 | } | ||
1592 | |||
1593 | for (i = 0; i < omap_dss_get_num_overlays(); i++) { | ||
1594 | struct omap_overlay *ovl = omap_dss_get_overlay(i); | ||
1595 | |||
1596 | ovl->is_enabled = &dss_ovl_is_enabled; | ||
1597 | ovl->enable = &dss_ovl_enable; | ||
1598 | ovl->disable = &dss_ovl_disable; | ||
1599 | ovl->set_manager = &dss_ovl_set_manager; | ||
1600 | ovl->unset_manager = &dss_ovl_unset_manager; | ||
1601 | ovl->set_overlay_info = &dss_ovl_set_info; | ||
1602 | ovl->get_overlay_info = &dss_ovl_get_info; | ||
1603 | ovl->wait_for_go = &dss_mgr_wait_for_go_ovl; | ||
1604 | ovl->get_device = &dss_ovl_get_device; | ||
1605 | } | ||
1606 | |||
1607 | r = dss_install_mgr_ops(&apply_mgr_ops); | ||
1608 | if (r) | ||
1609 | goto err_mgr_ops; | ||
1610 | |||
1611 | for_each_dss_dev(dssdev) { | ||
1612 | r = display_init_sysfs(pdev, dssdev); | ||
1613 | /* XXX uninit sysfs files on error */ | ||
1614 | if (r) | ||
1615 | goto err_disp_sysfs; | ||
1616 | } | ||
1617 | |||
1618 | dispc_runtime_get(); | ||
1619 | |||
1620 | r = dss_dispc_initialize_irq(); | ||
1621 | if (r) | ||
1622 | goto err_init_irq; | ||
1623 | |||
1624 | dispc_runtime_put(); | ||
1625 | |||
1626 | out: | ||
1627 | mutex_unlock(&compat_init_lock); | ||
1628 | |||
1629 | return 0; | ||
1630 | |||
1631 | err_init_irq: | ||
1632 | dispc_runtime_put(); | ||
1633 | |||
1634 | err_disp_sysfs: | ||
1635 | dss_uninstall_mgr_ops(); | ||
1636 | |||
1637 | err_mgr_ops: | ||
1638 | dss_uninit_overlay_managers(pdev); | ||
1639 | dss_uninit_overlays(pdev); | ||
1640 | |||
1641 | compat_refcnt--; | ||
1642 | |||
1643 | mutex_unlock(&compat_init_lock); | ||
1644 | |||
1645 | return r; | ||
1646 | } | ||
1647 | EXPORT_SYMBOL(omapdss_compat_init); | ||
1648 | |||
1649 | void omapdss_compat_uninit(void) | ||
1650 | { | ||
1651 | struct platform_device *pdev = dss_get_core_pdev(); | ||
1652 | struct omap_dss_device *dssdev = NULL; | ||
1653 | |||
1654 | mutex_lock(&compat_init_lock); | ||
1655 | |||
1656 | if (--compat_refcnt > 0) | ||
1657 | goto out; | ||
1658 | |||
1659 | dss_dispc_uninitialize_irq(); | ||
1660 | |||
1661 | for_each_dss_dev(dssdev) | ||
1662 | display_uninit_sysfs(pdev, dssdev); | ||
1663 | |||
1664 | dss_uninstall_mgr_ops(); | ||
1665 | |||
1666 | dss_uninit_overlay_managers(pdev); | ||
1667 | dss_uninit_overlays(pdev); | ||
1668 | out: | ||
1669 | mutex_unlock(&compat_init_lock); | ||
1670 | } | ||
1671 | EXPORT_SYMBOL(omapdss_compat_uninit); | ||
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c index f8779d4750b..76821fefce9 100644 --- a/drivers/video/omap2/dss/core.c +++ b/drivers/video/omap2/dss/core.c | |||
@@ -32,8 +32,6 @@ | |||
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/device.h> | 33 | #include <linux/device.h> |
34 | #include <linux/regulator/consumer.h> | 34 | #include <linux/regulator/consumer.h> |
35 | #include <linux/suspend.h> | ||
36 | #include <linux/slab.h> | ||
37 | 35 | ||
38 | #include <video/omapdss.h> | 36 | #include <video/omapdss.h> |
39 | 37 | ||
@@ -45,31 +43,19 @@ static struct { | |||
45 | 43 | ||
46 | struct regulator *vdds_dsi_reg; | 44 | struct regulator *vdds_dsi_reg; |
47 | struct regulator *vdds_sdi_reg; | 45 | struct regulator *vdds_sdi_reg; |
48 | |||
49 | const char *default_display_name; | ||
50 | } core; | 46 | } core; |
51 | 47 | ||
52 | static char *def_disp_name; | 48 | static char *def_disp_name; |
53 | module_param_named(def_disp, def_disp_name, charp, 0); | 49 | module_param_named(def_disp, def_disp_name, charp, 0); |
54 | MODULE_PARM_DESC(def_disp, "default display name"); | 50 | MODULE_PARM_DESC(def_disp, "default display name"); |
55 | 51 | ||
56 | const char *omapdss_get_default_display_name(void) | 52 | #ifdef DEBUG |
57 | { | 53 | unsigned int dss_debug; |
58 | return core.default_display_name; | 54 | module_param_named(debug, dss_debug, bool, 0644); |
59 | } | 55 | #endif |
60 | EXPORT_SYMBOL(omapdss_get_default_display_name); | ||
61 | |||
62 | enum omapdss_version omapdss_get_version(void) | ||
63 | { | ||
64 | struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; | ||
65 | return pdata->version; | ||
66 | } | ||
67 | EXPORT_SYMBOL(omapdss_get_version); | ||
68 | 56 | ||
69 | struct platform_device *dss_get_core_pdev(void) | 57 | static int omap_dss_register_device(struct omap_dss_device *); |
70 | { | 58 | static void omap_dss_unregister_device(struct omap_dss_device *); |
71 | return core.pdev; | ||
72 | } | ||
73 | 59 | ||
74 | /* REGULATORS */ | 60 | /* REGULATORS */ |
75 | 61 | ||
@@ -101,37 +87,7 @@ struct regulator *dss_get_vdds_sdi(void) | |||
101 | return reg; | 87 | return reg; |
102 | } | 88 | } |
103 | 89 | ||
104 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask) | 90 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) |
105 | { | ||
106 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | ||
107 | |||
108 | if (!board_data->dsi_enable_pads) | ||
109 | return -ENOENT; | ||
110 | |||
111 | return board_data->dsi_enable_pads(dsi_id, lane_mask); | ||
112 | } | ||
113 | |||
114 | void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask) | ||
115 | { | ||
116 | struct omap_dss_board_info *board_data = core.pdev->dev.platform_data; | ||
117 | |||
118 | if (!board_data->dsi_disable_pads) | ||
119 | return; | ||
120 | |||
121 | return board_data->dsi_disable_pads(dsi_id, lane_mask); | ||
122 | } | ||
123 | |||
124 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput) | ||
125 | { | ||
126 | struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; | ||
127 | |||
128 | if (pdata->set_min_bus_tput) | ||
129 | return pdata->set_min_bus_tput(dev, tput); | ||
130 | else | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) | ||
135 | static int dss_debug_show(struct seq_file *s, void *unused) | 91 | static int dss_debug_show(struct seq_file *s, void *unused) |
136 | { | 92 | { |
137 | void (*func)(struct seq_file *) = s->private; | 93 | void (*func)(struct seq_file *) = s->private; |
@@ -165,6 +121,30 @@ static int dss_initialize_debugfs(void) | |||
165 | debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, | 121 | debugfs_create_file("clk", S_IRUGO, dss_debugfs_dir, |
166 | &dss_debug_dump_clocks, &dss_debug_fops); | 122 | &dss_debug_dump_clocks, &dss_debug_fops); |
167 | 123 | ||
124 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
125 | debugfs_create_file("dispc_irq", S_IRUGO, dss_debugfs_dir, | ||
126 | &dispc_dump_irqs, &dss_debug_fops); | ||
127 | #endif | ||
128 | |||
129 | #if defined(CONFIG_OMAP2_DSS_DSI) && defined(CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS) | ||
130 | dsi_create_debugfs_files_irq(dss_debugfs_dir, &dss_debug_fops); | ||
131 | #endif | ||
132 | |||
133 | debugfs_create_file("dss", S_IRUGO, dss_debugfs_dir, | ||
134 | &dss_dump_regs, &dss_debug_fops); | ||
135 | debugfs_create_file("dispc", S_IRUGO, dss_debugfs_dir, | ||
136 | &dispc_dump_regs, &dss_debug_fops); | ||
137 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
138 | debugfs_create_file("rfbi", S_IRUGO, dss_debugfs_dir, | ||
139 | &rfbi_dump_regs, &dss_debug_fops); | ||
140 | #endif | ||
141 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
142 | dsi_create_debugfs_files_reg(dss_debugfs_dir, &dss_debug_fops); | ||
143 | #endif | ||
144 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
145 | debugfs_create_file("venc", S_IRUGO, dss_debugfs_dir, | ||
146 | &venc_dump_regs, &dss_debug_fops); | ||
147 | #endif | ||
168 | return 0; | 148 | return 0; |
169 | } | 149 | } |
170 | 150 | ||
@@ -173,20 +153,7 @@ static void dss_uninitialize_debugfs(void) | |||
173 | if (dss_debugfs_dir) | 153 | if (dss_debugfs_dir) |
174 | debugfs_remove_recursive(dss_debugfs_dir); | 154 | debugfs_remove_recursive(dss_debugfs_dir); |
175 | } | 155 | } |
176 | 156 | #else /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ | |
177 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) | ||
178 | { | ||
179 | struct dentry *d; | ||
180 | |||
181 | d = debugfs_create_file(name, S_IRUGO, dss_debugfs_dir, | ||
182 | write, &dss_debug_fops); | ||
183 | |||
184 | if (IS_ERR(d)) | ||
185 | return PTR_ERR(d); | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | #else /* CONFIG_OMAP2_DSS_DEBUGFS */ | ||
190 | static inline int dss_initialize_debugfs(void) | 157 | static inline int dss_initialize_debugfs(void) |
191 | { | 158 | { |
192 | return 0; | 159 | return 0; |
@@ -194,68 +161,121 @@ static inline int dss_initialize_debugfs(void) | |||
194 | static inline void dss_uninitialize_debugfs(void) | 161 | static inline void dss_uninitialize_debugfs(void) |
195 | { | 162 | { |
196 | } | 163 | } |
197 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)) | 164 | #endif /* CONFIG_DEBUG_FS && CONFIG_OMAP2_DSS_DEBUG_SUPPORT */ |
198 | { | ||
199 | return 0; | ||
200 | } | ||
201 | #endif /* CONFIG_OMAP2_DSS_DEBUGFS */ | ||
202 | 165 | ||
203 | /* PLATFORM DEVICE */ | 166 | /* PLATFORM DEVICE */ |
204 | static int omap_dss_pm_notif(struct notifier_block *b, unsigned long v, void *d) | 167 | static int omap_dss_probe(struct platform_device *pdev) |
205 | { | 168 | { |
206 | DSSDBG("pm notif %lu\n", v); | 169 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
170 | int r; | ||
171 | int i; | ||
207 | 172 | ||
208 | switch (v) { | 173 | core.pdev = pdev; |
209 | case PM_SUSPEND_PREPARE: | 174 | |
210 | DSSDBG("suspending displays\n"); | 175 | dss_features_init(); |
211 | return dss_suspend_all_devices(); | ||
212 | 176 | ||
213 | case PM_POST_SUSPEND: | 177 | dss_init_overlay_managers(pdev); |
214 | DSSDBG("resuming displays\n"); | 178 | dss_init_overlays(pdev); |
215 | return dss_resume_all_devices(); | ||
216 | 179 | ||
217 | default: | 180 | r = dss_init_platform_driver(); |
218 | return 0; | 181 | if (r) { |
182 | DSSERR("Failed to initialize DSS platform driver\n"); | ||
183 | goto err_dss; | ||
219 | } | 184 | } |
220 | } | ||
221 | 185 | ||
222 | static struct notifier_block omap_dss_pm_notif_block = { | 186 | r = dispc_init_platform_driver(); |
223 | .notifier_call = omap_dss_pm_notif, | 187 | if (r) { |
224 | }; | 188 | DSSERR("Failed to initialize dispc platform driver\n"); |
189 | goto err_dispc; | ||
190 | } | ||
225 | 191 | ||
226 | static int __init omap_dss_probe(struct platform_device *pdev) | 192 | r = rfbi_init_platform_driver(); |
227 | { | 193 | if (r) { |
228 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 194 | DSSERR("Failed to initialize rfbi platform driver\n"); |
229 | int r; | 195 | goto err_rfbi; |
196 | } | ||
230 | 197 | ||
231 | core.pdev = pdev; | 198 | r = venc_init_platform_driver(); |
199 | if (r) { | ||
200 | DSSERR("Failed to initialize venc platform driver\n"); | ||
201 | goto err_venc; | ||
202 | } | ||
203 | |||
204 | r = dsi_init_platform_driver(); | ||
205 | if (r) { | ||
206 | DSSERR("Failed to initialize DSI platform driver\n"); | ||
207 | goto err_dsi; | ||
208 | } | ||
232 | 209 | ||
233 | dss_features_init(omapdss_get_version()); | 210 | r = hdmi_init_platform_driver(); |
211 | if (r) { | ||
212 | DSSERR("Failed to initialize hdmi\n"); | ||
213 | goto err_hdmi; | ||
214 | } | ||
234 | 215 | ||
235 | r = dss_initialize_debugfs(); | 216 | r = dss_initialize_debugfs(); |
236 | if (r) | 217 | if (r) |
237 | goto err_debugfs; | 218 | goto err_debugfs; |
238 | 219 | ||
239 | if (def_disp_name) | 220 | for (i = 0; i < pdata->num_devices; ++i) { |
240 | core.default_display_name = def_disp_name; | 221 | struct omap_dss_device *dssdev = pdata->devices[i]; |
241 | else if (pdata->default_device) | 222 | |
242 | core.default_display_name = pdata->default_device->name; | 223 | r = omap_dss_register_device(dssdev); |
224 | if (r) { | ||
225 | DSSERR("device %d %s register failed %d\n", i, | ||
226 | dssdev->name ?: "unnamed", r); | ||
243 | 227 | ||
244 | register_pm_notifier(&omap_dss_pm_notif_block); | 228 | while (--i >= 0) |
229 | omap_dss_unregister_device(pdata->devices[i]); | ||
230 | |||
231 | goto err_register; | ||
232 | } | ||
233 | |||
234 | if (def_disp_name && strcmp(def_disp_name, dssdev->name) == 0) | ||
235 | pdata->default_device = dssdev; | ||
236 | } | ||
245 | 237 | ||
246 | return 0; | 238 | return 0; |
247 | 239 | ||
240 | err_register: | ||
241 | dss_uninitialize_debugfs(); | ||
248 | err_debugfs: | 242 | err_debugfs: |
243 | hdmi_uninit_platform_driver(); | ||
244 | err_hdmi: | ||
245 | dsi_uninit_platform_driver(); | ||
246 | err_dsi: | ||
247 | venc_uninit_platform_driver(); | ||
248 | err_venc: | ||
249 | dispc_uninit_platform_driver(); | ||
250 | err_dispc: | ||
251 | rfbi_uninit_platform_driver(); | ||
252 | err_rfbi: | ||
253 | dss_uninit_platform_driver(); | ||
254 | err_dss: | ||
249 | 255 | ||
250 | return r; | 256 | return r; |
251 | } | 257 | } |
252 | 258 | ||
253 | static int omap_dss_remove(struct platform_device *pdev) | 259 | static int omap_dss_remove(struct platform_device *pdev) |
254 | { | 260 | { |
255 | unregister_pm_notifier(&omap_dss_pm_notif_block); | 261 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
262 | int i; | ||
256 | 263 | ||
257 | dss_uninitialize_debugfs(); | 264 | dss_uninitialize_debugfs(); |
258 | 265 | ||
266 | hdmi_uninit_platform_driver(); | ||
267 | dsi_uninit_platform_driver(); | ||
268 | venc_uninit_platform_driver(); | ||
269 | rfbi_uninit_platform_driver(); | ||
270 | dispc_uninit_platform_driver(); | ||
271 | dss_uninit_platform_driver(); | ||
272 | |||
273 | dss_uninit_overlays(pdev); | ||
274 | dss_uninit_overlay_managers(pdev); | ||
275 | |||
276 | for (i = 0; i < pdata->num_devices; ++i) | ||
277 | omap_dss_unregister_device(pdata->devices[i]); | ||
278 | |||
259 | return 0; | 279 | return 0; |
260 | } | 280 | } |
261 | 281 | ||
@@ -265,9 +285,26 @@ static void omap_dss_shutdown(struct platform_device *pdev) | |||
265 | dss_disable_all_devices(); | 285 | dss_disable_all_devices(); |
266 | } | 286 | } |
267 | 287 | ||
288 | static int omap_dss_suspend(struct platform_device *pdev, pm_message_t state) | ||
289 | { | ||
290 | DSSDBG("suspend %d\n", state.event); | ||
291 | |||
292 | return dss_suspend_all_devices(); | ||
293 | } | ||
294 | |||
295 | static int omap_dss_resume(struct platform_device *pdev) | ||
296 | { | ||
297 | DSSDBG("resume\n"); | ||
298 | |||
299 | return dss_resume_all_devices(); | ||
300 | } | ||
301 | |||
268 | static struct platform_driver omap_dss_driver = { | 302 | static struct platform_driver omap_dss_driver = { |
303 | .probe = omap_dss_probe, | ||
269 | .remove = omap_dss_remove, | 304 | .remove = omap_dss_remove, |
270 | .shutdown = omap_dss_shutdown, | 305 | .shutdown = omap_dss_shutdown, |
306 | .suspend = omap_dss_suspend, | ||
307 | .resume = omap_dss_resume, | ||
271 | .driver = { | 308 | .driver = { |
272 | .name = "omapdss", | 309 | .name = "omapdss", |
273 | .owner = THIS_MODULE, | 310 | .owner = THIS_MODULE, |
@@ -338,15 +375,23 @@ static int dss_driver_probe(struct device *dev) | |||
338 | int r; | 375 | int r; |
339 | struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); | 376 | struct omap_dss_driver *dssdrv = to_dss_driver(dev->driver); |
340 | struct omap_dss_device *dssdev = to_dss_device(dev); | 377 | struct omap_dss_device *dssdev = to_dss_device(dev); |
378 | struct omap_dss_board_info *pdata = core.pdev->dev.platform_data; | ||
379 | bool force; | ||
341 | 380 | ||
342 | DSSDBG("driver_probe: dev %s/%s, drv %s\n", | 381 | DSSDBG("driver_probe: dev %s/%s, drv %s\n", |
343 | dev_name(dev), dssdev->driver_name, | 382 | dev_name(dev), dssdev->driver_name, |
344 | dssdrv->driver.name); | 383 | dssdrv->driver.name); |
345 | 384 | ||
385 | dss_init_device(core.pdev, dssdev); | ||
386 | |||
387 | force = pdata->default_device == dssdev; | ||
388 | dss_recheck_connections(dssdev, force); | ||
389 | |||
346 | r = dssdrv->probe(dssdev); | 390 | r = dssdrv->probe(dssdev); |
347 | 391 | ||
348 | if (r) { | 392 | if (r) { |
349 | DSSERR("driver probe failed: %d\n", r); | 393 | DSSERR("driver probe failed: %d\n", r); |
394 | dss_uninit_device(core.pdev, dssdev); | ||
350 | return r; | 395 | return r; |
351 | } | 396 | } |
352 | 397 | ||
@@ -367,6 +412,8 @@ static int dss_driver_remove(struct device *dev) | |||
367 | 412 | ||
368 | dssdrv->remove(dssdev); | 413 | dssdrv->remove(dssdev); |
369 | 414 | ||
415 | dss_uninit_device(core.pdev, dssdev); | ||
416 | |||
370 | dssdev->driver = NULL; | 417 | dssdev->driver = NULL; |
371 | 418 | ||
372 | return 0; | 419 | return 0; |
@@ -383,8 +430,6 @@ int omap_dss_register_driver(struct omap_dss_driver *dssdriver) | |||
383 | if (dssdriver->get_recommended_bpp == NULL) | 430 | if (dssdriver->get_recommended_bpp == NULL) |
384 | dssdriver->get_recommended_bpp = | 431 | dssdriver->get_recommended_bpp = |
385 | omapdss_default_get_recommended_bpp; | 432 | omapdss_default_get_recommended_bpp; |
386 | if (dssdriver->get_timings == NULL) | ||
387 | dssdriver->get_timings = omapdss_default_get_timings; | ||
388 | 433 | ||
389 | return driver_register(&dssdriver->driver); | 434 | return driver_register(&dssdriver->driver); |
390 | } | 435 | } |
@@ -397,72 +442,61 @@ void omap_dss_unregister_driver(struct omap_dss_driver *dssdriver) | |||
397 | EXPORT_SYMBOL(omap_dss_unregister_driver); | 442 | EXPORT_SYMBOL(omap_dss_unregister_driver); |
398 | 443 | ||
399 | /* DEVICE */ | 444 | /* DEVICE */ |
445 | static void reset_device(struct device *dev, int check) | ||
446 | { | ||
447 | u8 *dev_p = (u8 *)dev; | ||
448 | u8 *dev_end = dev_p + sizeof(*dev); | ||
449 | void *saved_pdata; | ||
450 | |||
451 | saved_pdata = dev->platform_data; | ||
452 | if (check) { | ||
453 | /* | ||
454 | * Check if there is any other setting than platform_data | ||
455 | * in struct device; warn that these will be reset by our | ||
456 | * init. | ||
457 | */ | ||
458 | dev->platform_data = NULL; | ||
459 | while (dev_p < dev_end) { | ||
460 | if (*dev_p) { | ||
461 | WARN("%s: struct device fields will be " | ||
462 | "discarded\n", | ||
463 | __func__); | ||
464 | break; | ||
465 | } | ||
466 | dev_p++; | ||
467 | } | ||
468 | } | ||
469 | memset(dev, 0, sizeof(*dev)); | ||
470 | dev->platform_data = saved_pdata; | ||
471 | } | ||
472 | |||
400 | 473 | ||
401 | static void omap_dss_dev_release(struct device *dev) | 474 | static void omap_dss_dev_release(struct device *dev) |
402 | { | 475 | { |
403 | struct omap_dss_device *dssdev = to_dss_device(dev); | 476 | reset_device(dev, 0); |
404 | kfree(dssdev); | ||
405 | } | 477 | } |
406 | 478 | ||
407 | static int disp_num_counter; | 479 | static int omap_dss_register_device(struct omap_dss_device *dssdev) |
408 | |||
409 | struct omap_dss_device *dss_alloc_and_init_device(struct device *parent) | ||
410 | { | 480 | { |
411 | struct omap_dss_device *dssdev; | 481 | static int dev_num; |
412 | 482 | ||
413 | dssdev = kzalloc(sizeof(*dssdev), GFP_KERNEL); | 483 | WARN_ON(!dssdev->driver_name); |
414 | if (!dssdev) | ||
415 | return NULL; | ||
416 | 484 | ||
485 | reset_device(&dssdev->dev, 1); | ||
417 | dssdev->dev.bus = &dss_bus_type; | 486 | dssdev->dev.bus = &dss_bus_type; |
418 | dssdev->dev.parent = parent; | 487 | dssdev->dev.parent = &dss_bus; |
419 | dssdev->dev.release = omap_dss_dev_release; | 488 | dssdev->dev.release = omap_dss_dev_release; |
420 | dev_set_name(&dssdev->dev, "display%d", disp_num_counter++); | 489 | dev_set_name(&dssdev->dev, "display%d", dev_num++); |
421 | 490 | return device_register(&dssdev->dev); | |
422 | device_initialize(&dssdev->dev); | ||
423 | |||
424 | return dssdev; | ||
425 | } | ||
426 | |||
427 | int dss_add_device(struct omap_dss_device *dssdev) | ||
428 | { | ||
429 | return device_add(&dssdev->dev); | ||
430 | } | ||
431 | |||
432 | void dss_put_device(struct omap_dss_device *dssdev) | ||
433 | { | ||
434 | put_device(&dssdev->dev); | ||
435 | } | 491 | } |
436 | 492 | ||
437 | void dss_unregister_device(struct omap_dss_device *dssdev) | 493 | static void omap_dss_unregister_device(struct omap_dss_device *dssdev) |
438 | { | 494 | { |
439 | device_unregister(&dssdev->dev); | 495 | device_unregister(&dssdev->dev); |
440 | } | 496 | } |
441 | 497 | ||
442 | static int dss_unregister_dss_dev(struct device *dev, void *data) | ||
443 | { | ||
444 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
445 | dss_unregister_device(dssdev); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | void dss_unregister_child_devices(struct device *parent) | ||
450 | { | ||
451 | device_for_each_child(parent, NULL, dss_unregister_dss_dev); | ||
452 | } | ||
453 | |||
454 | void dss_copy_device_pdata(struct omap_dss_device *dst, | ||
455 | const struct omap_dss_device *src) | ||
456 | { | ||
457 | u8 *d = (u8 *)dst; | ||
458 | u8 *s = (u8 *)src; | ||
459 | size_t dsize = sizeof(struct device); | ||
460 | |||
461 | memcpy(d + dsize, s + dsize, sizeof(struct omap_dss_device) - dsize); | ||
462 | } | ||
463 | |||
464 | /* BUS */ | 498 | /* BUS */ |
465 | static int __init omap_dss_bus_register(void) | 499 | static int omap_dss_bus_register(void) |
466 | { | 500 | { |
467 | int r; | 501 | int r; |
468 | 502 | ||
@@ -484,105 +518,6 @@ static int __init omap_dss_bus_register(void) | |||
484 | } | 518 | } |
485 | 519 | ||
486 | /* INIT */ | 520 | /* INIT */ |
487 | static int (*dss_output_drv_reg_funcs[])(void) __initdata = { | ||
488 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
489 | dsi_init_platform_driver, | ||
490 | #endif | ||
491 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
492 | dpi_init_platform_driver, | ||
493 | #endif | ||
494 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
495 | sdi_init_platform_driver, | ||
496 | #endif | ||
497 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
498 | rfbi_init_platform_driver, | ||
499 | #endif | ||
500 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
501 | venc_init_platform_driver, | ||
502 | #endif | ||
503 | #ifdef CONFIG_OMAP4_DSS_HDMI | ||
504 | hdmi_init_platform_driver, | ||
505 | #endif | ||
506 | }; | ||
507 | |||
508 | static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = { | ||
509 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
510 | dsi_uninit_platform_driver, | ||
511 | #endif | ||
512 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
513 | dpi_uninit_platform_driver, | ||
514 | #endif | ||
515 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
516 | sdi_uninit_platform_driver, | ||
517 | #endif | ||
518 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
519 | rfbi_uninit_platform_driver, | ||
520 | #endif | ||
521 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
522 | venc_uninit_platform_driver, | ||
523 | #endif | ||
524 | #ifdef CONFIG_OMAP4_DSS_HDMI | ||
525 | hdmi_uninit_platform_driver, | ||
526 | #endif | ||
527 | }; | ||
528 | |||
529 | static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)]; | ||
530 | |||
531 | static int __init omap_dss_register_drivers(void) | ||
532 | { | ||
533 | int r; | ||
534 | int i; | ||
535 | |||
536 | r = platform_driver_probe(&omap_dss_driver, omap_dss_probe); | ||
537 | if (r) | ||
538 | return r; | ||
539 | |||
540 | r = dss_init_platform_driver(); | ||
541 | if (r) { | ||
542 | DSSERR("Failed to initialize DSS platform driver\n"); | ||
543 | goto err_dss; | ||
544 | } | ||
545 | |||
546 | r = dispc_init_platform_driver(); | ||
547 | if (r) { | ||
548 | DSSERR("Failed to initialize dispc platform driver\n"); | ||
549 | goto err_dispc; | ||
550 | } | ||
551 | |||
552 | /* | ||
553 | * It's ok if the output-driver register fails. It happens, for example, | ||
554 | * when there is no output-device (e.g. SDI for OMAP4). | ||
555 | */ | ||
556 | for (i = 0; i < ARRAY_SIZE(dss_output_drv_reg_funcs); ++i) { | ||
557 | r = dss_output_drv_reg_funcs[i](); | ||
558 | if (r == 0) | ||
559 | dss_output_drv_loaded[i] = true; | ||
560 | } | ||
561 | |||
562 | return 0; | ||
563 | |||
564 | err_dispc: | ||
565 | dss_uninit_platform_driver(); | ||
566 | err_dss: | ||
567 | platform_driver_unregister(&omap_dss_driver); | ||
568 | |||
569 | return r; | ||
570 | } | ||
571 | |||
572 | static void __exit omap_dss_unregister_drivers(void) | ||
573 | { | ||
574 | int i; | ||
575 | |||
576 | for (i = 0; i < ARRAY_SIZE(dss_output_drv_unreg_funcs); ++i) { | ||
577 | if (dss_output_drv_loaded[i]) | ||
578 | dss_output_drv_unreg_funcs[i](); | ||
579 | } | ||
580 | |||
581 | dispc_uninit_platform_driver(); | ||
582 | dss_uninit_platform_driver(); | ||
583 | |||
584 | platform_driver_unregister(&omap_dss_driver); | ||
585 | } | ||
586 | 521 | ||
587 | #ifdef CONFIG_OMAP2_DSS_MODULE | 522 | #ifdef CONFIG_OMAP2_DSS_MODULE |
588 | static void omap_dss_bus_unregister(void) | 523 | static void omap_dss_bus_unregister(void) |
@@ -600,7 +535,7 @@ static int __init omap_dss_init(void) | |||
600 | if (r) | 535 | if (r) |
601 | return r; | 536 | return r; |
602 | 537 | ||
603 | r = omap_dss_register_drivers(); | 538 | r = platform_driver_register(&omap_dss_driver); |
604 | if (r) { | 539 | if (r) { |
605 | omap_dss_bus_unregister(); | 540 | omap_dss_bus_unregister(); |
606 | return r; | 541 | return r; |
@@ -621,7 +556,7 @@ static void __exit omap_dss_exit(void) | |||
621 | core.vdds_sdi_reg = NULL; | 556 | core.vdds_sdi_reg = NULL; |
622 | } | 557 | } |
623 | 558 | ||
624 | omap_dss_unregister_drivers(); | 559 | platform_driver_unregister(&omap_dss_driver); |
625 | 560 | ||
626 | omap_dss_bus_unregister(); | 561 | omap_dss_bus_unregister(); |
627 | } | 562 | } |
@@ -636,7 +571,7 @@ static int __init omap_dss_init(void) | |||
636 | 571 | ||
637 | static int __init omap_dss_init2(void) | 572 | static int __init omap_dss_init2(void) |
638 | { | 573 | { |
639 | return omap_dss_register_drivers(); | 574 | return platform_driver_register(&omap_dss_driver); |
640 | } | 575 | } |
641 | 576 | ||
642 | core_initcall(omap_dss_init); | 577 | core_initcall(omap_dss_init); |
diff --git a/drivers/video/omap2/dss/dispc-compat.c b/drivers/video/omap2/dss/dispc-compat.c deleted file mode 100644 index 928884c9a0a..00000000000 --- a/drivers/video/omap2/dss/dispc-compat.c +++ /dev/null | |||
@@ -1,667 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Texas Instruments | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #define DSS_SUBSYS_NAME "APPLY" | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | |||
29 | #include <video/omapdss.h> | ||
30 | |||
31 | #include "dss.h" | ||
32 | #include "dss_features.h" | ||
33 | #include "dispc-compat.h" | ||
34 | |||
35 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
36 | DISPC_IRQ_OCP_ERR | \ | ||
37 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
38 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
39 | DISPC_IRQ_SYNC_LOST | \ | ||
40 | DISPC_IRQ_SYNC_LOST_DIGIT) | ||
41 | |||
42 | #define DISPC_MAX_NR_ISRS 8 | ||
43 | |||
44 | struct omap_dispc_isr_data { | ||
45 | omap_dispc_isr_t isr; | ||
46 | void *arg; | ||
47 | u32 mask; | ||
48 | }; | ||
49 | |||
50 | struct dispc_irq_stats { | ||
51 | unsigned long last_reset; | ||
52 | unsigned irq_count; | ||
53 | unsigned irqs[32]; | ||
54 | }; | ||
55 | |||
56 | static struct { | ||
57 | spinlock_t irq_lock; | ||
58 | u32 irq_error_mask; | ||
59 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
60 | u32 error_irqs; | ||
61 | struct work_struct error_work; | ||
62 | |||
63 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
64 | spinlock_t irq_stats_lock; | ||
65 | struct dispc_irq_stats irq_stats; | ||
66 | #endif | ||
67 | } dispc_compat; | ||
68 | |||
69 | |||
70 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
71 | static void dispc_dump_irqs(struct seq_file *s) | ||
72 | { | ||
73 | unsigned long flags; | ||
74 | struct dispc_irq_stats stats; | ||
75 | |||
76 | spin_lock_irqsave(&dispc_compat.irq_stats_lock, flags); | ||
77 | |||
78 | stats = dispc_compat.irq_stats; | ||
79 | memset(&dispc_compat.irq_stats, 0, sizeof(dispc_compat.irq_stats)); | ||
80 | dispc_compat.irq_stats.last_reset = jiffies; | ||
81 | |||
82 | spin_unlock_irqrestore(&dispc_compat.irq_stats_lock, flags); | ||
83 | |||
84 | seq_printf(s, "period %u ms\n", | ||
85 | jiffies_to_msecs(jiffies - stats.last_reset)); | ||
86 | |||
87 | seq_printf(s, "irqs %d\n", stats.irq_count); | ||
88 | #define PIS(x) \ | ||
89 | seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); | ||
90 | |||
91 | PIS(FRAMEDONE); | ||
92 | PIS(VSYNC); | ||
93 | PIS(EVSYNC_EVEN); | ||
94 | PIS(EVSYNC_ODD); | ||
95 | PIS(ACBIAS_COUNT_STAT); | ||
96 | PIS(PROG_LINE_NUM); | ||
97 | PIS(GFX_FIFO_UNDERFLOW); | ||
98 | PIS(GFX_END_WIN); | ||
99 | PIS(PAL_GAMMA_MASK); | ||
100 | PIS(OCP_ERR); | ||
101 | PIS(VID1_FIFO_UNDERFLOW); | ||
102 | PIS(VID1_END_WIN); | ||
103 | PIS(VID2_FIFO_UNDERFLOW); | ||
104 | PIS(VID2_END_WIN); | ||
105 | if (dss_feat_get_num_ovls() > 3) { | ||
106 | PIS(VID3_FIFO_UNDERFLOW); | ||
107 | PIS(VID3_END_WIN); | ||
108 | } | ||
109 | PIS(SYNC_LOST); | ||
110 | PIS(SYNC_LOST_DIGIT); | ||
111 | PIS(WAKEUP); | ||
112 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
113 | PIS(FRAMEDONE2); | ||
114 | PIS(VSYNC2); | ||
115 | PIS(ACBIAS_COUNT_STAT2); | ||
116 | PIS(SYNC_LOST2); | ||
117 | } | ||
118 | if (dss_has_feature(FEAT_MGR_LCD3)) { | ||
119 | PIS(FRAMEDONE3); | ||
120 | PIS(VSYNC3); | ||
121 | PIS(ACBIAS_COUNT_STAT3); | ||
122 | PIS(SYNC_LOST3); | ||
123 | } | ||
124 | #undef PIS | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | /* dispc.irq_lock has to be locked by the caller */ | ||
129 | static void _omap_dispc_set_irqs(void) | ||
130 | { | ||
131 | u32 mask; | ||
132 | int i; | ||
133 | struct omap_dispc_isr_data *isr_data; | ||
134 | |||
135 | mask = dispc_compat.irq_error_mask; | ||
136 | |||
137 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
138 | isr_data = &dispc_compat.registered_isr[i]; | ||
139 | |||
140 | if (isr_data->isr == NULL) | ||
141 | continue; | ||
142 | |||
143 | mask |= isr_data->mask; | ||
144 | } | ||
145 | |||
146 | dispc_write_irqenable(mask); | ||
147 | } | ||
148 | |||
149 | int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | ||
150 | { | ||
151 | int i; | ||
152 | int ret; | ||
153 | unsigned long flags; | ||
154 | struct omap_dispc_isr_data *isr_data; | ||
155 | |||
156 | if (isr == NULL) | ||
157 | return -EINVAL; | ||
158 | |||
159 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
160 | |||
161 | /* check for duplicate entry */ | ||
162 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
163 | isr_data = &dispc_compat.registered_isr[i]; | ||
164 | if (isr_data->isr == isr && isr_data->arg == arg && | ||
165 | isr_data->mask == mask) { | ||
166 | ret = -EINVAL; | ||
167 | goto err; | ||
168 | } | ||
169 | } | ||
170 | |||
171 | isr_data = NULL; | ||
172 | ret = -EBUSY; | ||
173 | |||
174 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
175 | isr_data = &dispc_compat.registered_isr[i]; | ||
176 | |||
177 | if (isr_data->isr != NULL) | ||
178 | continue; | ||
179 | |||
180 | isr_data->isr = isr; | ||
181 | isr_data->arg = arg; | ||
182 | isr_data->mask = mask; | ||
183 | ret = 0; | ||
184 | |||
185 | break; | ||
186 | } | ||
187 | |||
188 | if (ret) | ||
189 | goto err; | ||
190 | |||
191 | _omap_dispc_set_irqs(); | ||
192 | |||
193 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
194 | |||
195 | return 0; | ||
196 | err: | ||
197 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
198 | |||
199 | return ret; | ||
200 | } | ||
201 | EXPORT_SYMBOL(omap_dispc_register_isr); | ||
202 | |||
203 | int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) | ||
204 | { | ||
205 | int i; | ||
206 | unsigned long flags; | ||
207 | int ret = -EINVAL; | ||
208 | struct omap_dispc_isr_data *isr_data; | ||
209 | |||
210 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
211 | |||
212 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
213 | isr_data = &dispc_compat.registered_isr[i]; | ||
214 | if (isr_data->isr != isr || isr_data->arg != arg || | ||
215 | isr_data->mask != mask) | ||
216 | continue; | ||
217 | |||
218 | /* found the correct isr */ | ||
219 | |||
220 | isr_data->isr = NULL; | ||
221 | isr_data->arg = NULL; | ||
222 | isr_data->mask = 0; | ||
223 | |||
224 | ret = 0; | ||
225 | break; | ||
226 | } | ||
227 | |||
228 | if (ret == 0) | ||
229 | _omap_dispc_set_irqs(); | ||
230 | |||
231 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
232 | |||
233 | return ret; | ||
234 | } | ||
235 | EXPORT_SYMBOL(omap_dispc_unregister_isr); | ||
236 | |||
237 | static void print_irq_status(u32 status) | ||
238 | { | ||
239 | if ((status & dispc_compat.irq_error_mask) == 0) | ||
240 | return; | ||
241 | |||
242 | #define PIS(x) (status & DISPC_IRQ_##x) ? (#x " ") : "" | ||
243 | |||
244 | pr_debug("DISPC IRQ: 0x%x: %s%s%s%s%s%s%s%s%s\n", | ||
245 | status, | ||
246 | PIS(OCP_ERR), | ||
247 | PIS(GFX_FIFO_UNDERFLOW), | ||
248 | PIS(VID1_FIFO_UNDERFLOW), | ||
249 | PIS(VID2_FIFO_UNDERFLOW), | ||
250 | dss_feat_get_num_ovls() > 3 ? PIS(VID3_FIFO_UNDERFLOW) : "", | ||
251 | PIS(SYNC_LOST), | ||
252 | PIS(SYNC_LOST_DIGIT), | ||
253 | dss_has_feature(FEAT_MGR_LCD2) ? PIS(SYNC_LOST2) : "", | ||
254 | dss_has_feature(FEAT_MGR_LCD3) ? PIS(SYNC_LOST3) : ""); | ||
255 | #undef PIS | ||
256 | } | ||
257 | |||
258 | /* Called from dss.c. Note that we don't touch clocks here, | ||
259 | * but we presume they are on because we got an IRQ. However, | ||
260 | * an irq handler may turn the clocks off, so we may not have | ||
261 | * clock later in the function. */ | ||
262 | static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) | ||
263 | { | ||
264 | int i; | ||
265 | u32 irqstatus, irqenable; | ||
266 | u32 handledirqs = 0; | ||
267 | u32 unhandled_errors; | ||
268 | struct omap_dispc_isr_data *isr_data; | ||
269 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
270 | |||
271 | spin_lock(&dispc_compat.irq_lock); | ||
272 | |||
273 | irqstatus = dispc_read_irqstatus(); | ||
274 | irqenable = dispc_read_irqenable(); | ||
275 | |||
276 | /* IRQ is not for us */ | ||
277 | if (!(irqstatus & irqenable)) { | ||
278 | spin_unlock(&dispc_compat.irq_lock); | ||
279 | return IRQ_NONE; | ||
280 | } | ||
281 | |||
282 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
283 | spin_lock(&dispc_compat.irq_stats_lock); | ||
284 | dispc_compat.irq_stats.irq_count++; | ||
285 | dss_collect_irq_stats(irqstatus, dispc_compat.irq_stats.irqs); | ||
286 | spin_unlock(&dispc_compat.irq_stats_lock); | ||
287 | #endif | ||
288 | |||
289 | print_irq_status(irqstatus); | ||
290 | |||
291 | /* Ack the interrupt. Do it here before clocks are possibly turned | ||
292 | * off */ | ||
293 | dispc_clear_irqstatus(irqstatus); | ||
294 | /* flush posted write */ | ||
295 | dispc_read_irqstatus(); | ||
296 | |||
297 | /* make a copy and unlock, so that isrs can unregister | ||
298 | * themselves */ | ||
299 | memcpy(registered_isr, dispc_compat.registered_isr, | ||
300 | sizeof(registered_isr)); | ||
301 | |||
302 | spin_unlock(&dispc_compat.irq_lock); | ||
303 | |||
304 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
305 | isr_data = ®istered_isr[i]; | ||
306 | |||
307 | if (!isr_data->isr) | ||
308 | continue; | ||
309 | |||
310 | if (isr_data->mask & irqstatus) { | ||
311 | isr_data->isr(isr_data->arg, irqstatus); | ||
312 | handledirqs |= isr_data->mask; | ||
313 | } | ||
314 | } | ||
315 | |||
316 | spin_lock(&dispc_compat.irq_lock); | ||
317 | |||
318 | unhandled_errors = irqstatus & ~handledirqs & dispc_compat.irq_error_mask; | ||
319 | |||
320 | if (unhandled_errors) { | ||
321 | dispc_compat.error_irqs |= unhandled_errors; | ||
322 | |||
323 | dispc_compat.irq_error_mask &= ~unhandled_errors; | ||
324 | _omap_dispc_set_irqs(); | ||
325 | |||
326 | schedule_work(&dispc_compat.error_work); | ||
327 | } | ||
328 | |||
329 | spin_unlock(&dispc_compat.irq_lock); | ||
330 | |||
331 | return IRQ_HANDLED; | ||
332 | } | ||
333 | |||
334 | static void dispc_error_worker(struct work_struct *work) | ||
335 | { | ||
336 | int i; | ||
337 | u32 errors; | ||
338 | unsigned long flags; | ||
339 | static const unsigned fifo_underflow_bits[] = { | ||
340 | DISPC_IRQ_GFX_FIFO_UNDERFLOW, | ||
341 | DISPC_IRQ_VID1_FIFO_UNDERFLOW, | ||
342 | DISPC_IRQ_VID2_FIFO_UNDERFLOW, | ||
343 | DISPC_IRQ_VID3_FIFO_UNDERFLOW, | ||
344 | }; | ||
345 | |||
346 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
347 | errors = dispc_compat.error_irqs; | ||
348 | dispc_compat.error_irqs = 0; | ||
349 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
350 | |||
351 | dispc_runtime_get(); | ||
352 | |||
353 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
354 | struct omap_overlay *ovl; | ||
355 | unsigned bit; | ||
356 | |||
357 | ovl = omap_dss_get_overlay(i); | ||
358 | bit = fifo_underflow_bits[i]; | ||
359 | |||
360 | if (bit & errors) { | ||
361 | DSSERR("FIFO UNDERFLOW on %s, disabling the overlay\n", | ||
362 | ovl->name); | ||
363 | dispc_ovl_enable(ovl->id, false); | ||
364 | dispc_mgr_go(ovl->manager->id); | ||
365 | msleep(50); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
370 | struct omap_overlay_manager *mgr; | ||
371 | unsigned bit; | ||
372 | |||
373 | mgr = omap_dss_get_overlay_manager(i); | ||
374 | bit = dispc_mgr_get_sync_lost_irq(i); | ||
375 | |||
376 | if (bit & errors) { | ||
377 | int j; | ||
378 | |||
379 | DSSERR("SYNC_LOST on channel %s, restarting the output " | ||
380 | "with video overlays disabled\n", | ||
381 | mgr->name); | ||
382 | |||
383 | dss_mgr_disable(mgr); | ||
384 | |||
385 | for (j = 0; j < omap_dss_get_num_overlays(); ++j) { | ||
386 | struct omap_overlay *ovl; | ||
387 | ovl = omap_dss_get_overlay(j); | ||
388 | |||
389 | if (ovl->id != OMAP_DSS_GFX && | ||
390 | ovl->manager == mgr) | ||
391 | ovl->disable(ovl); | ||
392 | } | ||
393 | |||
394 | dss_mgr_enable(mgr); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | if (errors & DISPC_IRQ_OCP_ERR) { | ||
399 | DSSERR("OCP_ERR\n"); | ||
400 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
401 | struct omap_overlay_manager *mgr; | ||
402 | |||
403 | mgr = omap_dss_get_overlay_manager(i); | ||
404 | dss_mgr_disable(mgr); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | spin_lock_irqsave(&dispc_compat.irq_lock, flags); | ||
409 | dispc_compat.irq_error_mask |= errors; | ||
410 | _omap_dispc_set_irqs(); | ||
411 | spin_unlock_irqrestore(&dispc_compat.irq_lock, flags); | ||
412 | |||
413 | dispc_runtime_put(); | ||
414 | } | ||
415 | |||
416 | int dss_dispc_initialize_irq(void) | ||
417 | { | ||
418 | int r; | ||
419 | |||
420 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
421 | spin_lock_init(&dispc_compat.irq_stats_lock); | ||
422 | dispc_compat.irq_stats.last_reset = jiffies; | ||
423 | dss_debugfs_create_file("dispc_irq", dispc_dump_irqs); | ||
424 | #endif | ||
425 | |||
426 | spin_lock_init(&dispc_compat.irq_lock); | ||
427 | |||
428 | memset(dispc_compat.registered_isr, 0, | ||
429 | sizeof(dispc_compat.registered_isr)); | ||
430 | |||
431 | dispc_compat.irq_error_mask = DISPC_IRQ_MASK_ERROR; | ||
432 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
433 | dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; | ||
434 | if (dss_has_feature(FEAT_MGR_LCD3)) | ||
435 | dispc_compat.irq_error_mask |= DISPC_IRQ_SYNC_LOST3; | ||
436 | if (dss_feat_get_num_ovls() > 3) | ||
437 | dispc_compat.irq_error_mask |= DISPC_IRQ_VID3_FIFO_UNDERFLOW; | ||
438 | |||
439 | /* | ||
440 | * there's SYNC_LOST_DIGIT waiting after enabling the DSS, | ||
441 | * so clear it | ||
442 | */ | ||
443 | dispc_clear_irqstatus(dispc_read_irqstatus()); | ||
444 | |||
445 | INIT_WORK(&dispc_compat.error_work, dispc_error_worker); | ||
446 | |||
447 | _omap_dispc_set_irqs(); | ||
448 | |||
449 | r = dispc_request_irq(omap_dispc_irq_handler, &dispc_compat); | ||
450 | if (r) { | ||
451 | DSSERR("dispc_request_irq failed\n"); | ||
452 | return r; | ||
453 | } | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | void dss_dispc_uninitialize_irq(void) | ||
459 | { | ||
460 | dispc_free_irq(&dispc_compat); | ||
461 | } | ||
462 | |||
463 | static void dispc_mgr_disable_isr(void *data, u32 mask) | ||
464 | { | ||
465 | struct completion *compl = data; | ||
466 | complete(compl); | ||
467 | } | ||
468 | |||
469 | static void dispc_mgr_enable_lcd_out(enum omap_channel channel) | ||
470 | { | ||
471 | dispc_mgr_enable(channel, true); | ||
472 | } | ||
473 | |||
474 | static void dispc_mgr_disable_lcd_out(enum omap_channel channel) | ||
475 | { | ||
476 | DECLARE_COMPLETION_ONSTACK(framedone_compl); | ||
477 | int r; | ||
478 | u32 irq; | ||
479 | |||
480 | if (dispc_mgr_is_enabled(channel) == false) | ||
481 | return; | ||
482 | |||
483 | /* | ||
484 | * When we disable LCD output, we need to wait for FRAMEDONE to know | ||
485 | * that DISPC has finished with the LCD output. | ||
486 | */ | ||
487 | |||
488 | irq = dispc_mgr_get_framedone_irq(channel); | ||
489 | |||
490 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
491 | irq); | ||
492 | if (r) | ||
493 | DSSERR("failed to register FRAMEDONE isr\n"); | ||
494 | |||
495 | dispc_mgr_enable(channel, false); | ||
496 | |||
497 | /* if we couldn't register for framedone, just sleep and exit */ | ||
498 | if (r) { | ||
499 | msleep(100); | ||
500 | return; | ||
501 | } | ||
502 | |||
503 | if (!wait_for_completion_timeout(&framedone_compl, | ||
504 | msecs_to_jiffies(100))) | ||
505 | DSSERR("timeout waiting for FRAME DONE\n"); | ||
506 | |||
507 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
508 | irq); | ||
509 | if (r) | ||
510 | DSSERR("failed to unregister FRAMEDONE isr\n"); | ||
511 | } | ||
512 | |||
513 | static void dispc_digit_out_enable_isr(void *data, u32 mask) | ||
514 | { | ||
515 | struct completion *compl = data; | ||
516 | |||
517 | /* ignore any sync lost interrupts */ | ||
518 | if (mask & (DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD)) | ||
519 | complete(compl); | ||
520 | } | ||
521 | |||
522 | static void dispc_mgr_enable_digit_out(void) | ||
523 | { | ||
524 | DECLARE_COMPLETION_ONSTACK(vsync_compl); | ||
525 | int r; | ||
526 | u32 irq_mask; | ||
527 | |||
528 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == true) | ||
529 | return; | ||
530 | |||
531 | /* | ||
532 | * Digit output produces some sync lost interrupts during the first | ||
533 | * frame when enabling. Those need to be ignored, so we register for the | ||
534 | * sync lost irq to prevent the error handler from triggering. | ||
535 | */ | ||
536 | |||
537 | irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT) | | ||
538 | dispc_mgr_get_sync_lost_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
539 | |||
540 | r = omap_dispc_register_isr(dispc_digit_out_enable_isr, &vsync_compl, | ||
541 | irq_mask); | ||
542 | if (r) { | ||
543 | DSSERR("failed to register %x isr\n", irq_mask); | ||
544 | return; | ||
545 | } | ||
546 | |||
547 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, true); | ||
548 | |||
549 | /* wait for the first evsync */ | ||
550 | if (!wait_for_completion_timeout(&vsync_compl, msecs_to_jiffies(100))) | ||
551 | DSSERR("timeout waiting for digit out to start\n"); | ||
552 | |||
553 | r = omap_dispc_unregister_isr(dispc_digit_out_enable_isr, &vsync_compl, | ||
554 | irq_mask); | ||
555 | if (r) | ||
556 | DSSERR("failed to unregister %x isr\n", irq_mask); | ||
557 | } | ||
558 | |||
559 | static void dispc_mgr_disable_digit_out(void) | ||
560 | { | ||
561 | DECLARE_COMPLETION_ONSTACK(framedone_compl); | ||
562 | int r, i; | ||
563 | u32 irq_mask; | ||
564 | int num_irqs; | ||
565 | |||
566 | if (dispc_mgr_is_enabled(OMAP_DSS_CHANNEL_DIGIT) == false) | ||
567 | return; | ||
568 | |||
569 | /* | ||
570 | * When we disable the digit output, we need to wait for FRAMEDONE to | ||
571 | * know that DISPC has finished with the output. | ||
572 | */ | ||
573 | |||
574 | irq_mask = dispc_mgr_get_framedone_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
575 | num_irqs = 1; | ||
576 | |||
577 | if (!irq_mask) { | ||
578 | /* | ||
579 | * omap 2/3 don't have framedone irq for TV, so we need to use | ||
580 | * vsyncs for this. | ||
581 | */ | ||
582 | |||
583 | irq_mask = dispc_mgr_get_vsync_irq(OMAP_DSS_CHANNEL_DIGIT); | ||
584 | /* | ||
585 | * We need to wait for both even and odd vsyncs. Note that this | ||
586 | * is not totally reliable, as we could get a vsync interrupt | ||
587 | * before we disable the output, which leads to timeout in the | ||
588 | * wait_for_completion. | ||
589 | */ | ||
590 | num_irqs = 2; | ||
591 | } | ||
592 | |||
593 | r = omap_dispc_register_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
594 | irq_mask); | ||
595 | if (r) | ||
596 | DSSERR("failed to register %x isr\n", irq_mask); | ||
597 | |||
598 | dispc_mgr_enable(OMAP_DSS_CHANNEL_DIGIT, false); | ||
599 | |||
600 | /* if we couldn't register the irq, just sleep and exit */ | ||
601 | if (r) { | ||
602 | msleep(100); | ||
603 | return; | ||
604 | } | ||
605 | |||
606 | for (i = 0; i < num_irqs; ++i) { | ||
607 | if (!wait_for_completion_timeout(&framedone_compl, | ||
608 | msecs_to_jiffies(100))) | ||
609 | DSSERR("timeout waiting for digit out to stop\n"); | ||
610 | } | ||
611 | |||
612 | r = omap_dispc_unregister_isr(dispc_mgr_disable_isr, &framedone_compl, | ||
613 | irq_mask); | ||
614 | if (r) | ||
615 | DSSERR("failed to unregister %x isr\n", irq_mask); | ||
616 | } | ||
617 | |||
618 | void dispc_mgr_enable_sync(enum omap_channel channel) | ||
619 | { | ||
620 | if (dss_mgr_is_lcd(channel)) | ||
621 | dispc_mgr_enable_lcd_out(channel); | ||
622 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
623 | dispc_mgr_enable_digit_out(); | ||
624 | else | ||
625 | WARN_ON(1); | ||
626 | } | ||
627 | |||
628 | void dispc_mgr_disable_sync(enum omap_channel channel) | ||
629 | { | ||
630 | if (dss_mgr_is_lcd(channel)) | ||
631 | dispc_mgr_disable_lcd_out(channel); | ||
632 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
633 | dispc_mgr_disable_digit_out(); | ||
634 | else | ||
635 | WARN_ON(1); | ||
636 | } | ||
637 | |||
638 | int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | ||
639 | unsigned long timeout) | ||
640 | { | ||
641 | void dispc_irq_wait_handler(void *data, u32 mask) | ||
642 | { | ||
643 | complete((struct completion *)data); | ||
644 | } | ||
645 | |||
646 | int r; | ||
647 | DECLARE_COMPLETION_ONSTACK(completion); | ||
648 | |||
649 | r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, | ||
650 | irqmask); | ||
651 | |||
652 | if (r) | ||
653 | return r; | ||
654 | |||
655 | timeout = wait_for_completion_interruptible_timeout(&completion, | ||
656 | timeout); | ||
657 | |||
658 | omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); | ||
659 | |||
660 | if (timeout == 0) | ||
661 | return -ETIMEDOUT; | ||
662 | |||
663 | if (timeout == -ERESTARTSYS) | ||
664 | return -ERESTARTSYS; | ||
665 | |||
666 | return 0; | ||
667 | } | ||
diff --git a/drivers/video/omap2/dss/dispc-compat.h b/drivers/video/omap2/dss/dispc-compat.h deleted file mode 100644 index 14a69b3d4fb..00000000000 --- a/drivers/video/omap2/dss/dispc-compat.h +++ /dev/null | |||
@@ -1,30 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Texas Instruments | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #ifndef __OMAP2_DSS_DISPC_COMPAT_H | ||
19 | #define __OMAP2_DSS_DISPC_COMPAT_H | ||
20 | |||
21 | void dispc_mgr_enable_sync(enum omap_channel channel); | ||
22 | void dispc_mgr_disable_sync(enum omap_channel channel); | ||
23 | |||
24 | int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, | ||
25 | unsigned long timeout); | ||
26 | |||
27 | int dss_dispc_initialize_irq(void); | ||
28 | void dss_dispc_uninitialize_irq(void); | ||
29 | |||
30 | #endif | ||
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index 05ff2b91d9e..0f3961a1ce2 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/export.h> | ||
29 | #include <linux/clk.h> | 28 | #include <linux/clk.h> |
30 | #include <linux/io.h> | 29 | #include <linux/io.h> |
31 | #include <linux/jiffies.h> | 30 | #include <linux/jiffies.h> |
@@ -33,9 +32,12 @@ | |||
33 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
34 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
35 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
35 | #include <linux/interrupt.h> | ||
36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/pm_runtime.h> | 37 | #include <linux/pm_runtime.h> |
38 | #include <linux/sizes.h> | 38 | |
39 | #include <plat/sram.h> | ||
40 | #include <plat/clock.h> | ||
39 | 41 | ||
40 | #include <video/omapdss.h> | 42 | #include <video/omapdss.h> |
41 | 43 | ||
@@ -46,6 +48,37 @@ | |||
46 | /* DISPC */ | 48 | /* DISPC */ |
47 | #define DISPC_SZ_REGS SZ_4K | 49 | #define DISPC_SZ_REGS SZ_4K |
48 | 50 | ||
51 | #define DISPC_IRQ_MASK_ERROR (DISPC_IRQ_GFX_FIFO_UNDERFLOW | \ | ||
52 | DISPC_IRQ_OCP_ERR | \ | ||
53 | DISPC_IRQ_VID1_FIFO_UNDERFLOW | \ | ||
54 | DISPC_IRQ_VID2_FIFO_UNDERFLOW | \ | ||
55 | DISPC_IRQ_SYNC_LOST | \ | ||
56 | DISPC_IRQ_SYNC_LOST_DIGIT) | ||
57 | |||
58 | #define DISPC_MAX_NR_ISRS 8 | ||
59 | |||
60 | struct omap_dispc_isr_data { | ||
61 | omap_dispc_isr_t isr; | ||
62 | void *arg; | ||
63 | u32 mask; | ||
64 | }; | ||
65 | |||
66 | struct dispc_h_coef { | ||
67 | s8 hc4; | ||
68 | s8 hc3; | ||
69 | u8 hc2; | ||
70 | s8 hc1; | ||
71 | s8 hc0; | ||
72 | }; | ||
73 | |||
74 | struct dispc_v_coef { | ||
75 | s8 vc22; | ||
76 | s8 vc2; | ||
77 | u8 vc1; | ||
78 | s8 vc0; | ||
79 | s8 vc00; | ||
80 | }; | ||
81 | |||
49 | enum omap_burst_size { | 82 | enum omap_burst_size { |
50 | BURST_SIZE_X2 = 0, | 83 | BURST_SIZE_X2 = 0, |
51 | BURST_SIZE_X4 = 1, | 84 | BURST_SIZE_X4 = 1, |
@@ -58,37 +91,12 @@ enum omap_burst_size { | |||
58 | #define REG_FLD_MOD(idx, val, start, end) \ | 91 | #define REG_FLD_MOD(idx, val, start, end) \ |
59 | dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) | 92 | dispc_write_reg(idx, FLD_MOD(dispc_read_reg(idx), val, start, end)) |
60 | 93 | ||
61 | struct dispc_features { | 94 | struct dispc_irq_stats { |
62 | u8 sw_start; | 95 | unsigned long last_reset; |
63 | u8 fp_start; | 96 | unsigned irq_count; |
64 | u8 bp_start; | 97 | unsigned irqs[32]; |
65 | u16 sw_max; | ||
66 | u16 vp_max; | ||
67 | u16 hp_max; | ||
68 | u8 mgr_width_start; | ||
69 | u8 mgr_height_start; | ||
70 | u16 mgr_width_max; | ||
71 | u16 mgr_height_max; | ||
72 | int (*calc_scaling) (unsigned long pclk, unsigned long lclk, | ||
73 | const struct omap_video_timings *mgr_timings, | ||
74 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
75 | enum omap_color_mode color_mode, bool *five_taps, | ||
76 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
77 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem); | ||
78 | unsigned long (*calc_core_clk) (unsigned long pclk, | ||
79 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
80 | bool mem_to_mem); | ||
81 | u8 num_fifos; | ||
82 | |||
83 | /* swap GFX & WB fifos */ | ||
84 | bool gfx_fifo_workaround:1; | ||
85 | |||
86 | /* no DISPC_IRQ_FRAMEDONETV on this SoC */ | ||
87 | bool no_framedone_tv:1; | ||
88 | }; | 98 | }; |
89 | 99 | ||
90 | #define DISPC_MAX_NR_FIFOS 5 | ||
91 | |||
92 | static struct { | 100 | static struct { |
93 | struct platform_device *pdev; | 101 | struct platform_device *pdev; |
94 | void __iomem *base; | 102 | void __iomem *base; |
@@ -96,15 +104,23 @@ static struct { | |||
96 | int ctx_loss_cnt; | 104 | int ctx_loss_cnt; |
97 | 105 | ||
98 | int irq; | 106 | int irq; |
107 | struct clk *dss_clk; | ||
99 | 108 | ||
100 | u32 fifo_size[DISPC_MAX_NR_FIFOS]; | 109 | u32 fifo_size[3]; |
101 | /* maps which plane is using a fifo. fifo-id -> plane-id */ | 110 | |
102 | int fifo_assignment[DISPC_MAX_NR_FIFOS]; | 111 | spinlock_t irq_lock; |
112 | u32 irq_error_mask; | ||
113 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
114 | u32 error_irqs; | ||
115 | struct work_struct error_work; | ||
103 | 116 | ||
104 | bool ctx_valid; | 117 | bool ctx_valid; |
105 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; | 118 | u32 ctx[DISPC_SZ_REGS / sizeof(u32)]; |
106 | 119 | ||
107 | const struct dispc_features *feat; | 120 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
121 | spinlock_t irq_stats_lock; | ||
122 | struct dispc_irq_stats irq_stats; | ||
123 | #endif | ||
108 | } dispc; | 124 | } dispc; |
109 | 125 | ||
110 | enum omap_color_component { | 126 | enum omap_color_component { |
@@ -119,104 +135,7 @@ enum omap_color_component { | |||
119 | DISPC_COLOR_COMPONENT_UV = 1 << 1, | 135 | DISPC_COLOR_COMPONENT_UV = 1 << 1, |
120 | }; | 136 | }; |
121 | 137 | ||
122 | enum mgr_reg_fields { | 138 | static void _omap_dispc_set_irqs(void); |
123 | DISPC_MGR_FLD_ENABLE, | ||
124 | DISPC_MGR_FLD_STNTFT, | ||
125 | DISPC_MGR_FLD_GO, | ||
126 | DISPC_MGR_FLD_TFTDATALINES, | ||
127 | DISPC_MGR_FLD_STALLMODE, | ||
128 | DISPC_MGR_FLD_TCKENABLE, | ||
129 | DISPC_MGR_FLD_TCKSELECTION, | ||
130 | DISPC_MGR_FLD_CPR, | ||
131 | DISPC_MGR_FLD_FIFOHANDCHECK, | ||
132 | /* used to maintain a count of the above fields */ | ||
133 | DISPC_MGR_FLD_NUM, | ||
134 | }; | ||
135 | |||
136 | static const struct { | ||
137 | const char *name; | ||
138 | u32 vsync_irq; | ||
139 | u32 framedone_irq; | ||
140 | u32 sync_lost_irq; | ||
141 | struct reg_field reg_desc[DISPC_MGR_FLD_NUM]; | ||
142 | } mgr_desc[] = { | ||
143 | [OMAP_DSS_CHANNEL_LCD] = { | ||
144 | .name = "LCD", | ||
145 | .vsync_irq = DISPC_IRQ_VSYNC, | ||
146 | .framedone_irq = DISPC_IRQ_FRAMEDONE, | ||
147 | .sync_lost_irq = DISPC_IRQ_SYNC_LOST, | ||
148 | .reg_desc = { | ||
149 | [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 0, 0 }, | ||
150 | [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL, 3, 3 }, | ||
151 | [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 5, 5 }, | ||
152 | [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL, 9, 8 }, | ||
153 | [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL, 11, 11 }, | ||
154 | [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 10, 10 }, | ||
155 | [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 11, 11 }, | ||
156 | [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG, 15, 15 }, | ||
157 | [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 }, | ||
158 | }, | ||
159 | }, | ||
160 | [OMAP_DSS_CHANNEL_DIGIT] = { | ||
161 | .name = "DIGIT", | ||
162 | .vsync_irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN, | ||
163 | .framedone_irq = DISPC_IRQ_FRAMEDONETV, | ||
164 | .sync_lost_irq = DISPC_IRQ_SYNC_LOST_DIGIT, | ||
165 | .reg_desc = { | ||
166 | [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL, 1, 1 }, | ||
167 | [DISPC_MGR_FLD_STNTFT] = { }, | ||
168 | [DISPC_MGR_FLD_GO] = { DISPC_CONTROL, 6, 6 }, | ||
169 | [DISPC_MGR_FLD_TFTDATALINES] = { }, | ||
170 | [DISPC_MGR_FLD_STALLMODE] = { }, | ||
171 | [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG, 12, 12 }, | ||
172 | [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG, 13, 13 }, | ||
173 | [DISPC_MGR_FLD_CPR] = { }, | ||
174 | [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG, 16, 16 }, | ||
175 | }, | ||
176 | }, | ||
177 | [OMAP_DSS_CHANNEL_LCD2] = { | ||
178 | .name = "LCD2", | ||
179 | .vsync_irq = DISPC_IRQ_VSYNC2, | ||
180 | .framedone_irq = DISPC_IRQ_FRAMEDONE2, | ||
181 | .sync_lost_irq = DISPC_IRQ_SYNC_LOST2, | ||
182 | .reg_desc = { | ||
183 | [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL2, 0, 0 }, | ||
184 | [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL2, 3, 3 }, | ||
185 | [DISPC_MGR_FLD_GO] = { DISPC_CONTROL2, 5, 5 }, | ||
186 | [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL2, 9, 8 }, | ||
187 | [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL2, 11, 11 }, | ||
188 | [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG2, 10, 10 }, | ||
189 | [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG2, 11, 11 }, | ||
190 | [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG2, 15, 15 }, | ||
191 | [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG2, 16, 16 }, | ||
192 | }, | ||
193 | }, | ||
194 | [OMAP_DSS_CHANNEL_LCD3] = { | ||
195 | .name = "LCD3", | ||
196 | .vsync_irq = DISPC_IRQ_VSYNC3, | ||
197 | .framedone_irq = DISPC_IRQ_FRAMEDONE3, | ||
198 | .sync_lost_irq = DISPC_IRQ_SYNC_LOST3, | ||
199 | .reg_desc = { | ||
200 | [DISPC_MGR_FLD_ENABLE] = { DISPC_CONTROL3, 0, 0 }, | ||
201 | [DISPC_MGR_FLD_STNTFT] = { DISPC_CONTROL3, 3, 3 }, | ||
202 | [DISPC_MGR_FLD_GO] = { DISPC_CONTROL3, 5, 5 }, | ||
203 | [DISPC_MGR_FLD_TFTDATALINES] = { DISPC_CONTROL3, 9, 8 }, | ||
204 | [DISPC_MGR_FLD_STALLMODE] = { DISPC_CONTROL3, 11, 11 }, | ||
205 | [DISPC_MGR_FLD_TCKENABLE] = { DISPC_CONFIG3, 10, 10 }, | ||
206 | [DISPC_MGR_FLD_TCKSELECTION] = { DISPC_CONFIG3, 11, 11 }, | ||
207 | [DISPC_MGR_FLD_CPR] = { DISPC_CONFIG3, 15, 15 }, | ||
208 | [DISPC_MGR_FLD_FIFOHANDCHECK] = { DISPC_CONFIG3, 16, 16 }, | ||
209 | }, | ||
210 | }, | ||
211 | }; | ||
212 | |||
213 | struct color_conv_coef { | ||
214 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | ||
215 | int full_range; | ||
216 | }; | ||
217 | |||
218 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane); | ||
219 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane); | ||
220 | 139 | ||
221 | static inline void dispc_write_reg(const u16 idx, u32 val) | 140 | static inline void dispc_write_reg(const u16 idx, u32 val) |
222 | { | 141 | { |
@@ -228,16 +147,21 @@ static inline u32 dispc_read_reg(const u16 idx) | |||
228 | return __raw_readl(dispc.base + idx); | 147 | return __raw_readl(dispc.base + idx); |
229 | } | 148 | } |
230 | 149 | ||
231 | static u32 mgr_fld_read(enum omap_channel channel, enum mgr_reg_fields regfld) | 150 | static int dispc_get_ctx_loss_count(void) |
232 | { | 151 | { |
233 | const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld]; | 152 | struct device *dev = &dispc.pdev->dev; |
234 | return REG_GET(rfld.reg, rfld.high, rfld.low); | 153 | struct omap_display_platform_data *pdata = dev->platform_data; |
235 | } | 154 | struct omap_dss_board_info *board_data = pdata->board_data; |
155 | int cnt; | ||
156 | |||
157 | if (!board_data->get_context_loss_count) | ||
158 | return -ENOENT; | ||
159 | |||
160 | cnt = board_data->get_context_loss_count(dev); | ||
236 | 161 | ||
237 | static void mgr_fld_write(enum omap_channel channel, | 162 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); |
238 | enum mgr_reg_fields regfld, int val) { | 163 | |
239 | const struct reg_field rfld = mgr_desc[channel].reg_desc[regfld]; | 164 | return cnt; |
240 | REG_FLD_MOD(rfld.reg, val, rfld.high, rfld.low); | ||
241 | } | 165 | } |
242 | 166 | ||
243 | #define SR(reg) \ | 167 | #define SR(reg) \ |
@@ -247,107 +171,177 @@ static void mgr_fld_write(enum omap_channel channel, | |||
247 | 171 | ||
248 | static void dispc_save_context(void) | 172 | static void dispc_save_context(void) |
249 | { | 173 | { |
250 | int i, j; | 174 | int i; |
251 | 175 | ||
252 | DSSDBG("dispc_save_context\n"); | 176 | DSSDBG("dispc_save_context\n"); |
253 | 177 | ||
254 | SR(IRQENABLE); | 178 | SR(IRQENABLE); |
255 | SR(CONTROL); | 179 | SR(CONTROL); |
256 | SR(CONFIG); | 180 | SR(CONFIG); |
181 | SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD)); | ||
182 | SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT)); | ||
183 | SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD)); | ||
184 | SR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT)); | ||
257 | SR(LINE_NUMBER); | 185 | SR(LINE_NUMBER); |
258 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || | 186 | SR(TIMING_H(OMAP_DSS_CHANNEL_LCD)); |
259 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) | 187 | SR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); |
188 | SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); | ||
189 | SR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); | ||
190 | if (dss_has_feature(FEAT_GLOBAL_ALPHA)) | ||
260 | SR(GLOBAL_ALPHA); | 191 | SR(GLOBAL_ALPHA); |
192 | SR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); | ||
193 | SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); | ||
261 | if (dss_has_feature(FEAT_MGR_LCD2)) { | 194 | if (dss_has_feature(FEAT_MGR_LCD2)) { |
262 | SR(CONTROL2); | 195 | SR(CONTROL2); |
196 | SR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2)); | ||
197 | SR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2)); | ||
198 | SR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2)); | ||
199 | SR(TIMING_H(OMAP_DSS_CHANNEL_LCD2)); | ||
200 | SR(TIMING_V(OMAP_DSS_CHANNEL_LCD2)); | ||
201 | SR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2)); | ||
202 | SR(DIVISORo(OMAP_DSS_CHANNEL_LCD2)); | ||
263 | SR(CONFIG2); | 203 | SR(CONFIG2); |
264 | } | 204 | } |
265 | if (dss_has_feature(FEAT_MGR_LCD3)) { | ||
266 | SR(CONTROL3); | ||
267 | SR(CONFIG3); | ||
268 | } | ||
269 | 205 | ||
270 | for (i = 0; i < dss_feat_get_num_mgrs(); i++) { | 206 | SR(OVL_BA0(OMAP_DSS_GFX)); |
271 | SR(DEFAULT_COLOR(i)); | 207 | SR(OVL_BA1(OMAP_DSS_GFX)); |
272 | SR(TRANS_COLOR(i)); | 208 | SR(OVL_POSITION(OMAP_DSS_GFX)); |
273 | SR(SIZE_MGR(i)); | 209 | SR(OVL_SIZE(OMAP_DSS_GFX)); |
274 | if (i == OMAP_DSS_CHANNEL_DIGIT) | 210 | SR(OVL_ATTRIBUTES(OMAP_DSS_GFX)); |
275 | continue; | 211 | SR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX)); |
276 | SR(TIMING_H(i)); | 212 | SR(OVL_ROW_INC(OMAP_DSS_GFX)); |
277 | SR(TIMING_V(i)); | 213 | SR(OVL_PIXEL_INC(OMAP_DSS_GFX)); |
278 | SR(POL_FREQ(i)); | 214 | SR(OVL_WINDOW_SKIP(OMAP_DSS_GFX)); |
279 | SR(DIVISORo(i)); | 215 | SR(OVL_TABLE_BA(OMAP_DSS_GFX)); |
280 | 216 | ||
281 | SR(DATA_CYCLE1(i)); | 217 | SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD)); |
282 | SR(DATA_CYCLE2(i)); | 218 | SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); |
283 | SR(DATA_CYCLE3(i)); | 219 | SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); |
284 | 220 | ||
221 | if (dss_has_feature(FEAT_CPR)) { | ||
222 | SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); | ||
223 | SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); | ||
224 | SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); | ||
225 | } | ||
226 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
285 | if (dss_has_feature(FEAT_CPR)) { | 227 | if (dss_has_feature(FEAT_CPR)) { |
286 | SR(CPR_COEF_R(i)); | 228 | SR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); |
287 | SR(CPR_COEF_G(i)); | 229 | SR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); |
288 | SR(CPR_COEF_B(i)); | 230 | SR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); |
289 | } | 231 | } |
232 | |||
233 | SR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); | ||
234 | SR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); | ||
235 | SR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); | ||
290 | } | 236 | } |
291 | 237 | ||
292 | for (i = 0; i < dss_feat_get_num_ovls(); i++) { | 238 | if (dss_has_feature(FEAT_PRELOAD)) |
293 | SR(OVL_BA0(i)); | 239 | SR(OVL_PRELOAD(OMAP_DSS_GFX)); |
294 | SR(OVL_BA1(i)); | ||
295 | SR(OVL_POSITION(i)); | ||
296 | SR(OVL_SIZE(i)); | ||
297 | SR(OVL_ATTRIBUTES(i)); | ||
298 | SR(OVL_FIFO_THRESHOLD(i)); | ||
299 | SR(OVL_ROW_INC(i)); | ||
300 | SR(OVL_PIXEL_INC(i)); | ||
301 | if (dss_has_feature(FEAT_PRELOAD)) | ||
302 | SR(OVL_PRELOAD(i)); | ||
303 | if (i == OMAP_DSS_GFX) { | ||
304 | SR(OVL_WINDOW_SKIP(i)); | ||
305 | SR(OVL_TABLE_BA(i)); | ||
306 | continue; | ||
307 | } | ||
308 | SR(OVL_FIR(i)); | ||
309 | SR(OVL_PICTURE_SIZE(i)); | ||
310 | SR(OVL_ACCU0(i)); | ||
311 | SR(OVL_ACCU1(i)); | ||
312 | 240 | ||
313 | for (j = 0; j < 8; j++) | 241 | /* VID1 */ |
314 | SR(OVL_FIR_COEF_H(i, j)); | 242 | SR(OVL_BA0(OMAP_DSS_VIDEO1)); |
243 | SR(OVL_BA1(OMAP_DSS_VIDEO1)); | ||
244 | SR(OVL_POSITION(OMAP_DSS_VIDEO1)); | ||
245 | SR(OVL_SIZE(OMAP_DSS_VIDEO1)); | ||
246 | SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); | ||
247 | SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); | ||
248 | SR(OVL_ROW_INC(OMAP_DSS_VIDEO1)); | ||
249 | SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); | ||
250 | SR(OVL_FIR(OMAP_DSS_VIDEO1)); | ||
251 | SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); | ||
252 | SR(OVL_ACCU0(OMAP_DSS_VIDEO1)); | ||
253 | SR(OVL_ACCU1(OMAP_DSS_VIDEO1)); | ||
315 | 254 | ||
316 | for (j = 0; j < 8; j++) | 255 | for (i = 0; i < 8; i++) |
317 | SR(OVL_FIR_COEF_HV(i, j)); | 256 | SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i)); |
318 | 257 | ||
319 | for (j = 0; j < 5; j++) | 258 | for (i = 0; i < 8; i++) |
320 | SR(OVL_CONV_COEF(i, j)); | 259 | SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i)); |
321 | 260 | ||
322 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | 261 | for (i = 0; i < 5; i++) |
323 | for (j = 0; j < 8; j++) | 262 | SR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); |
324 | SR(OVL_FIR_COEF_V(i, j)); | 263 | |
325 | } | 264 | if (dss_has_feature(FEAT_FIR_COEF_V)) { |
265 | for (i = 0; i < 8; i++) | ||
266 | SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); | ||
267 | } | ||
326 | 268 | ||
327 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | 269 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { |
328 | SR(OVL_BA0_UV(i)); | 270 | SR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); |
329 | SR(OVL_BA1_UV(i)); | 271 | SR(OVL_BA1_UV(OMAP_DSS_VIDEO1)); |
330 | SR(OVL_FIR2(i)); | 272 | SR(OVL_FIR2(OMAP_DSS_VIDEO1)); |
331 | SR(OVL_ACCU2_0(i)); | 273 | SR(OVL_ACCU2_0(OMAP_DSS_VIDEO1)); |
332 | SR(OVL_ACCU2_1(i)); | 274 | SR(OVL_ACCU2_1(OMAP_DSS_VIDEO1)); |
333 | 275 | ||
334 | for (j = 0; j < 8; j++) | 276 | for (i = 0; i < 8; i++) |
335 | SR(OVL_FIR_COEF_H2(i, j)); | 277 | SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i)); |
336 | 278 | ||
337 | for (j = 0; j < 8; j++) | 279 | for (i = 0; i < 8; i++) |
338 | SR(OVL_FIR_COEF_HV2(i, j)); | 280 | SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i)); |
339 | 281 | ||
340 | for (j = 0; j < 8; j++) | 282 | for (i = 0; i < 8; i++) |
341 | SR(OVL_FIR_COEF_V2(i, j)); | 283 | SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i)); |
342 | } | 284 | } |
343 | if (dss_has_feature(FEAT_ATTR2)) | 285 | if (dss_has_feature(FEAT_ATTR2)) |
344 | SR(OVL_ATTRIBUTES2(i)); | 286 | SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); |
287 | |||
288 | if (dss_has_feature(FEAT_PRELOAD)) | ||
289 | SR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); | ||
290 | |||
291 | /* VID2 */ | ||
292 | SR(OVL_BA0(OMAP_DSS_VIDEO2)); | ||
293 | SR(OVL_BA1(OMAP_DSS_VIDEO2)); | ||
294 | SR(OVL_POSITION(OMAP_DSS_VIDEO2)); | ||
295 | SR(OVL_SIZE(OMAP_DSS_VIDEO2)); | ||
296 | SR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); | ||
297 | SR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); | ||
298 | SR(OVL_ROW_INC(OMAP_DSS_VIDEO2)); | ||
299 | SR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); | ||
300 | SR(OVL_FIR(OMAP_DSS_VIDEO2)); | ||
301 | SR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); | ||
302 | SR(OVL_ACCU0(OMAP_DSS_VIDEO2)); | ||
303 | SR(OVL_ACCU1(OMAP_DSS_VIDEO2)); | ||
304 | |||
305 | for (i = 0; i < 8; i++) | ||
306 | SR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i)); | ||
307 | |||
308 | for (i = 0; i < 8; i++) | ||
309 | SR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i)); | ||
310 | |||
311 | for (i = 0; i < 5; i++) | ||
312 | SR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); | ||
313 | |||
314 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | ||
315 | for (i = 0; i < 8; i++) | ||
316 | SR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); | ||
317 | } | ||
318 | |||
319 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | ||
320 | SR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); | ||
321 | SR(OVL_BA1_UV(OMAP_DSS_VIDEO2)); | ||
322 | SR(OVL_FIR2(OMAP_DSS_VIDEO2)); | ||
323 | SR(OVL_ACCU2_0(OMAP_DSS_VIDEO2)); | ||
324 | SR(OVL_ACCU2_1(OMAP_DSS_VIDEO2)); | ||
325 | |||
326 | for (i = 0; i < 8; i++) | ||
327 | SR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i)); | ||
328 | |||
329 | for (i = 0; i < 8; i++) | ||
330 | SR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i)); | ||
331 | |||
332 | for (i = 0; i < 8; i++) | ||
333 | SR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i)); | ||
345 | } | 334 | } |
335 | if (dss_has_feature(FEAT_ATTR2)) | ||
336 | SR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); | ||
337 | |||
338 | if (dss_has_feature(FEAT_PRELOAD)) | ||
339 | SR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); | ||
346 | 340 | ||
347 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | 341 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) |
348 | SR(DIVISOR); | 342 | SR(DIVISOR); |
349 | 343 | ||
350 | dispc.ctx_loss_cnt = dss_get_ctx_loss_count(); | 344 | dispc.ctx_loss_cnt = dispc_get_ctx_loss_count(); |
351 | dispc.ctx_valid = true; | 345 | dispc.ctx_valid = true; |
352 | 346 | ||
353 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); | 347 | DSSDBG("context saved, ctx_loss_count %d\n", dispc.ctx_loss_cnt); |
@@ -355,14 +349,14 @@ static void dispc_save_context(void) | |||
355 | 349 | ||
356 | static void dispc_restore_context(void) | 350 | static void dispc_restore_context(void) |
357 | { | 351 | { |
358 | int i, j, ctx; | 352 | int i, ctx; |
359 | 353 | ||
360 | DSSDBG("dispc_restore_context\n"); | 354 | DSSDBG("dispc_restore_context\n"); |
361 | 355 | ||
362 | if (!dispc.ctx_valid) | 356 | if (!dispc.ctx_valid) |
363 | return; | 357 | return; |
364 | 358 | ||
365 | ctx = dss_get_ctx_loss_count(); | 359 | ctx = dispc_get_ctx_loss_count(); |
366 | 360 | ||
367 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) | 361 | if (ctx >= 0 && ctx == dispc.ctx_loss_cnt) |
368 | return; | 362 | return; |
@@ -373,91 +367,165 @@ static void dispc_restore_context(void) | |||
373 | /*RR(IRQENABLE);*/ | 367 | /*RR(IRQENABLE);*/ |
374 | /*RR(CONTROL);*/ | 368 | /*RR(CONTROL);*/ |
375 | RR(CONFIG); | 369 | RR(CONFIG); |
370 | RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD)); | ||
371 | RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT)); | ||
372 | RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD)); | ||
373 | RR(TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT)); | ||
376 | RR(LINE_NUMBER); | 374 | RR(LINE_NUMBER); |
377 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || | 375 | RR(TIMING_H(OMAP_DSS_CHANNEL_LCD)); |
378 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) | 376 | RR(TIMING_V(OMAP_DSS_CHANNEL_LCD)); |
377 | RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD)); | ||
378 | RR(DIVISORo(OMAP_DSS_CHANNEL_LCD)); | ||
379 | if (dss_has_feature(FEAT_GLOBAL_ALPHA)) | ||
379 | RR(GLOBAL_ALPHA); | 380 | RR(GLOBAL_ALPHA); |
380 | if (dss_has_feature(FEAT_MGR_LCD2)) | 381 | RR(SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); |
382 | RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); | ||
383 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
384 | RR(DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2)); | ||
385 | RR(TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2)); | ||
386 | RR(SIZE_MGR(OMAP_DSS_CHANNEL_LCD2)); | ||
387 | RR(TIMING_H(OMAP_DSS_CHANNEL_LCD2)); | ||
388 | RR(TIMING_V(OMAP_DSS_CHANNEL_LCD2)); | ||
389 | RR(POL_FREQ(OMAP_DSS_CHANNEL_LCD2)); | ||
390 | RR(DIVISORo(OMAP_DSS_CHANNEL_LCD2)); | ||
381 | RR(CONFIG2); | 391 | RR(CONFIG2); |
382 | if (dss_has_feature(FEAT_MGR_LCD3)) | 392 | } |
383 | RR(CONFIG3); | 393 | |
384 | 394 | RR(OVL_BA0(OMAP_DSS_GFX)); | |
385 | for (i = 0; i < dss_feat_get_num_mgrs(); i++) { | 395 | RR(OVL_BA1(OMAP_DSS_GFX)); |
386 | RR(DEFAULT_COLOR(i)); | 396 | RR(OVL_POSITION(OMAP_DSS_GFX)); |
387 | RR(TRANS_COLOR(i)); | 397 | RR(OVL_SIZE(OMAP_DSS_GFX)); |
388 | RR(SIZE_MGR(i)); | 398 | RR(OVL_ATTRIBUTES(OMAP_DSS_GFX)); |
389 | if (i == OMAP_DSS_CHANNEL_DIGIT) | 399 | RR(OVL_FIFO_THRESHOLD(OMAP_DSS_GFX)); |
390 | continue; | 400 | RR(OVL_ROW_INC(OMAP_DSS_GFX)); |
391 | RR(TIMING_H(i)); | 401 | RR(OVL_PIXEL_INC(OMAP_DSS_GFX)); |
392 | RR(TIMING_V(i)); | 402 | RR(OVL_WINDOW_SKIP(OMAP_DSS_GFX)); |
393 | RR(POL_FREQ(i)); | 403 | RR(OVL_TABLE_BA(OMAP_DSS_GFX)); |
394 | RR(DIVISORo(i)); | ||
395 | 404 | ||
396 | RR(DATA_CYCLE1(i)); | 405 | |
397 | RR(DATA_CYCLE2(i)); | 406 | RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD)); |
398 | RR(DATA_CYCLE3(i)); | 407 | RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); |
408 | RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); | ||
409 | |||
410 | if (dss_has_feature(FEAT_CPR)) { | ||
411 | RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); | ||
412 | RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); | ||
413 | RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); | ||
414 | } | ||
415 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
416 | RR(DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); | ||
417 | RR(DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); | ||
418 | RR(DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); | ||
399 | 419 | ||
400 | if (dss_has_feature(FEAT_CPR)) { | 420 | if (dss_has_feature(FEAT_CPR)) { |
401 | RR(CPR_COEF_R(i)); | 421 | RR(CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); |
402 | RR(CPR_COEF_G(i)); | 422 | RR(CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); |
403 | RR(CPR_COEF_B(i)); | 423 | RR(CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); |
404 | } | 424 | } |
405 | } | 425 | } |
406 | 426 | ||
407 | for (i = 0; i < dss_feat_get_num_ovls(); i++) { | 427 | if (dss_has_feature(FEAT_PRELOAD)) |
408 | RR(OVL_BA0(i)); | 428 | RR(OVL_PRELOAD(OMAP_DSS_GFX)); |
409 | RR(OVL_BA1(i)); | ||
410 | RR(OVL_POSITION(i)); | ||
411 | RR(OVL_SIZE(i)); | ||
412 | RR(OVL_ATTRIBUTES(i)); | ||
413 | RR(OVL_FIFO_THRESHOLD(i)); | ||
414 | RR(OVL_ROW_INC(i)); | ||
415 | RR(OVL_PIXEL_INC(i)); | ||
416 | if (dss_has_feature(FEAT_PRELOAD)) | ||
417 | RR(OVL_PRELOAD(i)); | ||
418 | if (i == OMAP_DSS_GFX) { | ||
419 | RR(OVL_WINDOW_SKIP(i)); | ||
420 | RR(OVL_TABLE_BA(i)); | ||
421 | continue; | ||
422 | } | ||
423 | RR(OVL_FIR(i)); | ||
424 | RR(OVL_PICTURE_SIZE(i)); | ||
425 | RR(OVL_ACCU0(i)); | ||
426 | RR(OVL_ACCU1(i)); | ||
427 | 429 | ||
428 | for (j = 0; j < 8; j++) | 430 | /* VID1 */ |
429 | RR(OVL_FIR_COEF_H(i, j)); | 431 | RR(OVL_BA0(OMAP_DSS_VIDEO1)); |
432 | RR(OVL_BA1(OMAP_DSS_VIDEO1)); | ||
433 | RR(OVL_POSITION(OMAP_DSS_VIDEO1)); | ||
434 | RR(OVL_SIZE(OMAP_DSS_VIDEO1)); | ||
435 | RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); | ||
436 | RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); | ||
437 | RR(OVL_ROW_INC(OMAP_DSS_VIDEO1)); | ||
438 | RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); | ||
439 | RR(OVL_FIR(OMAP_DSS_VIDEO1)); | ||
440 | RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); | ||
441 | RR(OVL_ACCU0(OMAP_DSS_VIDEO1)); | ||
442 | RR(OVL_ACCU1(OMAP_DSS_VIDEO1)); | ||
430 | 443 | ||
431 | for (j = 0; j < 8; j++) | 444 | for (i = 0; i < 8; i++) |
432 | RR(OVL_FIR_COEF_HV(i, j)); | 445 | RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, i)); |
433 | 446 | ||
434 | for (j = 0; j < 5; j++) | 447 | for (i = 0; i < 8; i++) |
435 | RR(OVL_CONV_COEF(i, j)); | 448 | RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, i)); |
436 | 449 | ||
437 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | 450 | for (i = 0; i < 5; i++) |
438 | for (j = 0; j < 8; j++) | 451 | RR(OVL_CONV_COEF(OMAP_DSS_VIDEO1, i)); |
439 | RR(OVL_FIR_COEF_V(i, j)); | ||
440 | } | ||
441 | 452 | ||
442 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | 453 | if (dss_has_feature(FEAT_FIR_COEF_V)) { |
443 | RR(OVL_BA0_UV(i)); | 454 | for (i = 0; i < 8; i++) |
444 | RR(OVL_BA1_UV(i)); | 455 | RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, i)); |
445 | RR(OVL_FIR2(i)); | 456 | } |
446 | RR(OVL_ACCU2_0(i)); | ||
447 | RR(OVL_ACCU2_1(i)); | ||
448 | 457 | ||
449 | for (j = 0; j < 8; j++) | 458 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { |
450 | RR(OVL_FIR_COEF_H2(i, j)); | 459 | RR(OVL_BA0_UV(OMAP_DSS_VIDEO1)); |
460 | RR(OVL_BA1_UV(OMAP_DSS_VIDEO1)); | ||
461 | RR(OVL_FIR2(OMAP_DSS_VIDEO1)); | ||
462 | RR(OVL_ACCU2_0(OMAP_DSS_VIDEO1)); | ||
463 | RR(OVL_ACCU2_1(OMAP_DSS_VIDEO1)); | ||
451 | 464 | ||
452 | for (j = 0; j < 8; j++) | 465 | for (i = 0; i < 8; i++) |
453 | RR(OVL_FIR_COEF_HV2(i, j)); | 466 | RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, i)); |
454 | 467 | ||
455 | for (j = 0; j < 8; j++) | 468 | for (i = 0; i < 8; i++) |
456 | RR(OVL_FIR_COEF_V2(i, j)); | 469 | RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, i)); |
457 | } | 470 | |
458 | if (dss_has_feature(FEAT_ATTR2)) | 471 | for (i = 0; i < 8; i++) |
459 | RR(OVL_ATTRIBUTES2(i)); | 472 | RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, i)); |
473 | } | ||
474 | if (dss_has_feature(FEAT_ATTR2)) | ||
475 | RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); | ||
476 | |||
477 | if (dss_has_feature(FEAT_PRELOAD)) | ||
478 | RR(OVL_PRELOAD(OMAP_DSS_VIDEO1)); | ||
479 | |||
480 | /* VID2 */ | ||
481 | RR(OVL_BA0(OMAP_DSS_VIDEO2)); | ||
482 | RR(OVL_BA1(OMAP_DSS_VIDEO2)); | ||
483 | RR(OVL_POSITION(OMAP_DSS_VIDEO2)); | ||
484 | RR(OVL_SIZE(OMAP_DSS_VIDEO2)); | ||
485 | RR(OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); | ||
486 | RR(OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); | ||
487 | RR(OVL_ROW_INC(OMAP_DSS_VIDEO2)); | ||
488 | RR(OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); | ||
489 | RR(OVL_FIR(OMAP_DSS_VIDEO2)); | ||
490 | RR(OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); | ||
491 | RR(OVL_ACCU0(OMAP_DSS_VIDEO2)); | ||
492 | RR(OVL_ACCU1(OMAP_DSS_VIDEO2)); | ||
493 | |||
494 | for (i = 0; i < 8; i++) | ||
495 | RR(OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, i)); | ||
496 | |||
497 | for (i = 0; i < 8; i++) | ||
498 | RR(OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, i)); | ||
499 | |||
500 | for (i = 0; i < 5; i++) | ||
501 | RR(OVL_CONV_COEF(OMAP_DSS_VIDEO2, i)); | ||
502 | |||
503 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | ||
504 | for (i = 0; i < 8; i++) | ||
505 | RR(OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, i)); | ||
506 | } | ||
507 | |||
508 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | ||
509 | RR(OVL_BA0_UV(OMAP_DSS_VIDEO2)); | ||
510 | RR(OVL_BA1_UV(OMAP_DSS_VIDEO2)); | ||
511 | RR(OVL_FIR2(OMAP_DSS_VIDEO2)); | ||
512 | RR(OVL_ACCU2_0(OMAP_DSS_VIDEO2)); | ||
513 | RR(OVL_ACCU2_1(OMAP_DSS_VIDEO2)); | ||
514 | |||
515 | for (i = 0; i < 8; i++) | ||
516 | RR(OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, i)); | ||
517 | |||
518 | for (i = 0; i < 8; i++) | ||
519 | RR(OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, i)); | ||
520 | |||
521 | for (i = 0; i < 8; i++) | ||
522 | RR(OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, i)); | ||
460 | } | 523 | } |
524 | if (dss_has_feature(FEAT_ATTR2)) | ||
525 | RR(OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); | ||
526 | |||
527 | if (dss_has_feature(FEAT_PRELOAD)) | ||
528 | RR(OVL_PRELOAD(OMAP_DSS_VIDEO2)); | ||
461 | 529 | ||
462 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | 530 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) |
463 | RR(DIVISOR); | 531 | RR(DIVISOR); |
@@ -466,10 +534,8 @@ static void dispc_restore_context(void) | |||
466 | RR(CONTROL); | 534 | RR(CONTROL); |
467 | if (dss_has_feature(FEAT_MGR_LCD2)) | 535 | if (dss_has_feature(FEAT_MGR_LCD2)) |
468 | RR(CONTROL2); | 536 | RR(CONTROL2); |
469 | if (dss_has_feature(FEAT_MGR_LCD3)) | ||
470 | RR(CONTROL3); | ||
471 | /* clear spurious SYNC_LOST_DIGIT interrupts */ | 537 | /* clear spurious SYNC_LOST_DIGIT interrupts */ |
472 | dispc_clear_irqstatus(DISPC_IRQ_SYNC_LOST_DIGIT); | 538 | dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); |
473 | 539 | ||
474 | /* | 540 | /* |
475 | * enable last so IRQs won't trigger before | 541 | * enable last so IRQs won't trigger before |
@@ -493,7 +559,6 @@ int dispc_runtime_get(void) | |||
493 | WARN_ON(r < 0); | 559 | WARN_ON(r < 0); |
494 | return r < 0 ? r : 0; | 560 | return r < 0 ? r : 0; |
495 | } | 561 | } |
496 | EXPORT_SYMBOL(dispc_runtime_get); | ||
497 | 562 | ||
498 | void dispc_runtime_put(void) | 563 | void dispc_runtime_put(void) |
499 | { | 564 | { |
@@ -501,143 +566,214 @@ void dispc_runtime_put(void) | |||
501 | 566 | ||
502 | DSSDBG("dispc_runtime_put\n"); | 567 | DSSDBG("dispc_runtime_put\n"); |
503 | 568 | ||
504 | r = pm_runtime_put_sync(&dispc.pdev->dev); | 569 | r = pm_runtime_put(&dispc.pdev->dev); |
505 | WARN_ON(r < 0 && r != -ENOSYS); | 570 | WARN_ON(r < 0); |
506 | } | ||
507 | EXPORT_SYMBOL(dispc_runtime_put); | ||
508 | |||
509 | u32 dispc_mgr_get_vsync_irq(enum omap_channel channel) | ||
510 | { | ||
511 | return mgr_desc[channel].vsync_irq; | ||
512 | } | 571 | } |
513 | EXPORT_SYMBOL(dispc_mgr_get_vsync_irq); | ||
514 | 572 | ||
515 | u32 dispc_mgr_get_framedone_irq(enum omap_channel channel) | ||
516 | { | ||
517 | if (channel == OMAP_DSS_CHANNEL_DIGIT && dispc.feat->no_framedone_tv) | ||
518 | return 0; | ||
519 | |||
520 | return mgr_desc[channel].framedone_irq; | ||
521 | } | ||
522 | EXPORT_SYMBOL(dispc_mgr_get_framedone_irq); | ||
523 | 573 | ||
524 | u32 dispc_mgr_get_sync_lost_irq(enum omap_channel channel) | 574 | bool dispc_go_busy(enum omap_channel channel) |
525 | { | 575 | { |
526 | return mgr_desc[channel].sync_lost_irq; | 576 | int bit; |
527 | } | ||
528 | EXPORT_SYMBOL(dispc_mgr_get_sync_lost_irq); | ||
529 | 577 | ||
530 | u32 dispc_wb_get_framedone_irq(void) | 578 | if (channel == OMAP_DSS_CHANNEL_LCD || |
531 | { | 579 | channel == OMAP_DSS_CHANNEL_LCD2) |
532 | return DISPC_IRQ_FRAMEDONEWB; | 580 | bit = 5; /* GOLCD */ |
533 | } | 581 | else |
582 | bit = 6; /* GODIGIT */ | ||
534 | 583 | ||
535 | bool dispc_mgr_go_busy(enum omap_channel channel) | 584 | if (channel == OMAP_DSS_CHANNEL_LCD2) |
536 | { | 585 | return REG_GET(DISPC_CONTROL2, bit, bit) == 1; |
537 | return mgr_fld_read(channel, DISPC_MGR_FLD_GO) == 1; | 586 | else |
587 | return REG_GET(DISPC_CONTROL, bit, bit) == 1; | ||
538 | } | 588 | } |
539 | EXPORT_SYMBOL(dispc_mgr_go_busy); | ||
540 | 589 | ||
541 | void dispc_mgr_go(enum omap_channel channel) | 590 | void dispc_go(enum omap_channel channel) |
542 | { | 591 | { |
543 | WARN_ON(dispc_mgr_is_enabled(channel) == false); | 592 | int bit; |
544 | WARN_ON(dispc_mgr_go_busy(channel)); | 593 | bool enable_bit, go_bit; |
545 | |||
546 | DSSDBG("GO %s\n", mgr_desc[channel].name); | ||
547 | 594 | ||
548 | mgr_fld_write(channel, DISPC_MGR_FLD_GO, 1); | 595 | if (channel == OMAP_DSS_CHANNEL_LCD || |
549 | } | 596 | channel == OMAP_DSS_CHANNEL_LCD2) |
550 | EXPORT_SYMBOL(dispc_mgr_go); | 597 | bit = 0; /* LCDENABLE */ |
598 | else | ||
599 | bit = 1; /* DIGITALENABLE */ | ||
551 | 600 | ||
552 | bool dispc_wb_go_busy(void) | 601 | /* if the channel is not enabled, we don't need GO */ |
553 | { | 602 | if (channel == OMAP_DSS_CHANNEL_LCD2) |
554 | return REG_GET(DISPC_CONTROL2, 6, 6) == 1; | 603 | enable_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; |
555 | } | 604 | else |
605 | enable_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; | ||
556 | 606 | ||
557 | void dispc_wb_go(void) | 607 | if (!enable_bit) |
558 | { | 608 | return; |
559 | enum omap_plane plane = OMAP_DSS_WB; | ||
560 | bool enable, go; | ||
561 | 609 | ||
562 | enable = REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0) == 1; | 610 | if (channel == OMAP_DSS_CHANNEL_LCD || |
611 | channel == OMAP_DSS_CHANNEL_LCD2) | ||
612 | bit = 5; /* GOLCD */ | ||
613 | else | ||
614 | bit = 6; /* GODIGIT */ | ||
563 | 615 | ||
564 | if (!enable) | 616 | if (channel == OMAP_DSS_CHANNEL_LCD2) |
565 | return; | 617 | go_bit = REG_GET(DISPC_CONTROL2, bit, bit) == 1; |
618 | else | ||
619 | go_bit = REG_GET(DISPC_CONTROL, bit, bit) == 1; | ||
566 | 620 | ||
567 | go = REG_GET(DISPC_CONTROL2, 6, 6) == 1; | 621 | if (go_bit) { |
568 | if (go) { | 622 | DSSERR("GO bit not down for channel %d\n", channel); |
569 | DSSERR("GO bit not down for WB\n"); | ||
570 | return; | 623 | return; |
571 | } | 624 | } |
572 | 625 | ||
573 | REG_FLD_MOD(DISPC_CONTROL2, 1, 6, 6); | 626 | DSSDBG("GO %s\n", channel == OMAP_DSS_CHANNEL_LCD ? "LCD" : |
627 | (channel == OMAP_DSS_CHANNEL_LCD2 ? "LCD2" : "DIGIT")); | ||
628 | |||
629 | if (channel == OMAP_DSS_CHANNEL_LCD2) | ||
630 | REG_FLD_MOD(DISPC_CONTROL2, 1, bit, bit); | ||
631 | else | ||
632 | REG_FLD_MOD(DISPC_CONTROL, 1, bit, bit); | ||
574 | } | 633 | } |
575 | 634 | ||
576 | static void dispc_ovl_write_firh_reg(enum omap_plane plane, int reg, u32 value) | 635 | static void _dispc_write_firh_reg(enum omap_plane plane, int reg, u32 value) |
577 | { | 636 | { |
578 | dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); | 637 | dispc_write_reg(DISPC_OVL_FIR_COEF_H(plane, reg), value); |
579 | } | 638 | } |
580 | 639 | ||
581 | static void dispc_ovl_write_firhv_reg(enum omap_plane plane, int reg, u32 value) | 640 | static void _dispc_write_firhv_reg(enum omap_plane plane, int reg, u32 value) |
582 | { | 641 | { |
583 | dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value); | 642 | dispc_write_reg(DISPC_OVL_FIR_COEF_HV(plane, reg), value); |
584 | } | 643 | } |
585 | 644 | ||
586 | static void dispc_ovl_write_firv_reg(enum omap_plane plane, int reg, u32 value) | 645 | static void _dispc_write_firv_reg(enum omap_plane plane, int reg, u32 value) |
587 | { | 646 | { |
588 | dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value); | 647 | dispc_write_reg(DISPC_OVL_FIR_COEF_V(plane, reg), value); |
589 | } | 648 | } |
590 | 649 | ||
591 | static void dispc_ovl_write_firh2_reg(enum omap_plane plane, int reg, u32 value) | 650 | static void _dispc_write_firh2_reg(enum omap_plane plane, int reg, u32 value) |
592 | { | 651 | { |
593 | BUG_ON(plane == OMAP_DSS_GFX); | 652 | BUG_ON(plane == OMAP_DSS_GFX); |
594 | 653 | ||
595 | dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value); | 654 | dispc_write_reg(DISPC_OVL_FIR_COEF_H2(plane, reg), value); |
596 | } | 655 | } |
597 | 656 | ||
598 | static void dispc_ovl_write_firhv2_reg(enum omap_plane plane, int reg, | 657 | static void _dispc_write_firhv2_reg(enum omap_plane plane, int reg, u32 value) |
599 | u32 value) | ||
600 | { | 658 | { |
601 | BUG_ON(plane == OMAP_DSS_GFX); | 659 | BUG_ON(plane == OMAP_DSS_GFX); |
602 | 660 | ||
603 | dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value); | 661 | dispc_write_reg(DISPC_OVL_FIR_COEF_HV2(plane, reg), value); |
604 | } | 662 | } |
605 | 663 | ||
606 | static void dispc_ovl_write_firv2_reg(enum omap_plane plane, int reg, u32 value) | 664 | static void _dispc_write_firv2_reg(enum omap_plane plane, int reg, u32 value) |
607 | { | 665 | { |
608 | BUG_ON(plane == OMAP_DSS_GFX); | 666 | BUG_ON(plane == OMAP_DSS_GFX); |
609 | 667 | ||
610 | dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); | 668 | dispc_write_reg(DISPC_OVL_FIR_COEF_V2(plane, reg), value); |
611 | } | 669 | } |
612 | 670 | ||
613 | static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, | 671 | static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup, |
614 | int fir_vinc, int five_taps, | 672 | int vscaleup, int five_taps, |
615 | enum omap_color_component color_comp) | 673 | enum omap_color_component color_comp) |
616 | { | 674 | { |
617 | const struct dispc_coef *h_coef, *v_coef; | 675 | /* Coefficients for horizontal up-sampling */ |
676 | static const struct dispc_h_coef coef_hup[8] = { | ||
677 | { 0, 0, 128, 0, 0 }, | ||
678 | { -1, 13, 124, -8, 0 }, | ||
679 | { -2, 30, 112, -11, -1 }, | ||
680 | { -5, 51, 95, -11, -2 }, | ||
681 | { 0, -9, 73, 73, -9 }, | ||
682 | { -2, -11, 95, 51, -5 }, | ||
683 | { -1, -11, 112, 30, -2 }, | ||
684 | { 0, -8, 124, 13, -1 }, | ||
685 | }; | ||
686 | |||
687 | /* Coefficients for vertical up-sampling */ | ||
688 | static const struct dispc_v_coef coef_vup_3tap[8] = { | ||
689 | { 0, 0, 128, 0, 0 }, | ||
690 | { 0, 3, 123, 2, 0 }, | ||
691 | { 0, 12, 111, 5, 0 }, | ||
692 | { 0, 32, 89, 7, 0 }, | ||
693 | { 0, 0, 64, 64, 0 }, | ||
694 | { 0, 7, 89, 32, 0 }, | ||
695 | { 0, 5, 111, 12, 0 }, | ||
696 | { 0, 2, 123, 3, 0 }, | ||
697 | }; | ||
698 | |||
699 | static const struct dispc_v_coef coef_vup_5tap[8] = { | ||
700 | { 0, 0, 128, 0, 0 }, | ||
701 | { -1, 13, 124, -8, 0 }, | ||
702 | { -2, 30, 112, -11, -1 }, | ||
703 | { -5, 51, 95, -11, -2 }, | ||
704 | { 0, -9, 73, 73, -9 }, | ||
705 | { -2, -11, 95, 51, -5 }, | ||
706 | { -1, -11, 112, 30, -2 }, | ||
707 | { 0, -8, 124, 13, -1 }, | ||
708 | }; | ||
709 | |||
710 | /* Coefficients for horizontal down-sampling */ | ||
711 | static const struct dispc_h_coef coef_hdown[8] = { | ||
712 | { 0, 36, 56, 36, 0 }, | ||
713 | { 4, 40, 55, 31, -2 }, | ||
714 | { 8, 44, 54, 27, -5 }, | ||
715 | { 12, 48, 53, 22, -7 }, | ||
716 | { -9, 17, 52, 51, 17 }, | ||
717 | { -7, 22, 53, 48, 12 }, | ||
718 | { -5, 27, 54, 44, 8 }, | ||
719 | { -2, 31, 55, 40, 4 }, | ||
720 | }; | ||
721 | |||
722 | /* Coefficients for vertical down-sampling */ | ||
723 | static const struct dispc_v_coef coef_vdown_3tap[8] = { | ||
724 | { 0, 36, 56, 36, 0 }, | ||
725 | { 0, 40, 57, 31, 0 }, | ||
726 | { 0, 45, 56, 27, 0 }, | ||
727 | { 0, 50, 55, 23, 0 }, | ||
728 | { 0, 18, 55, 55, 0 }, | ||
729 | { 0, 23, 55, 50, 0 }, | ||
730 | { 0, 27, 56, 45, 0 }, | ||
731 | { 0, 31, 57, 40, 0 }, | ||
732 | }; | ||
733 | |||
734 | static const struct dispc_v_coef coef_vdown_5tap[8] = { | ||
735 | { 0, 36, 56, 36, 0 }, | ||
736 | { 4, 40, 55, 31, -2 }, | ||
737 | { 8, 44, 54, 27, -5 }, | ||
738 | { 12, 48, 53, 22, -7 }, | ||
739 | { -9, 17, 52, 51, 17 }, | ||
740 | { -7, 22, 53, 48, 12 }, | ||
741 | { -5, 27, 54, 44, 8 }, | ||
742 | { -2, 31, 55, 40, 4 }, | ||
743 | }; | ||
744 | |||
745 | const struct dispc_h_coef *h_coef; | ||
746 | const struct dispc_v_coef *v_coef; | ||
618 | int i; | 747 | int i; |
619 | 748 | ||
620 | h_coef = dispc_ovl_get_scale_coef(fir_hinc, true); | 749 | if (hscaleup) |
621 | v_coef = dispc_ovl_get_scale_coef(fir_vinc, five_taps); | 750 | h_coef = coef_hup; |
751 | else | ||
752 | h_coef = coef_hdown; | ||
753 | |||
754 | if (vscaleup) | ||
755 | v_coef = five_taps ? coef_vup_5tap : coef_vup_3tap; | ||
756 | else | ||
757 | v_coef = five_taps ? coef_vdown_5tap : coef_vdown_3tap; | ||
622 | 758 | ||
623 | for (i = 0; i < 8; i++) { | 759 | for (i = 0; i < 8; i++) { |
624 | u32 h, hv; | 760 | u32 h, hv; |
625 | 761 | ||
626 | h = FLD_VAL(h_coef[i].hc0_vc00, 7, 0) | 762 | h = FLD_VAL(h_coef[i].hc0, 7, 0) |
627 | | FLD_VAL(h_coef[i].hc1_vc0, 15, 8) | 763 | | FLD_VAL(h_coef[i].hc1, 15, 8) |
628 | | FLD_VAL(h_coef[i].hc2_vc1, 23, 16) | 764 | | FLD_VAL(h_coef[i].hc2, 23, 16) |
629 | | FLD_VAL(h_coef[i].hc3_vc2, 31, 24); | 765 | | FLD_VAL(h_coef[i].hc3, 31, 24); |
630 | hv = FLD_VAL(h_coef[i].hc4_vc22, 7, 0) | 766 | hv = FLD_VAL(h_coef[i].hc4, 7, 0) |
631 | | FLD_VAL(v_coef[i].hc1_vc0, 15, 8) | 767 | | FLD_VAL(v_coef[i].vc0, 15, 8) |
632 | | FLD_VAL(v_coef[i].hc2_vc1, 23, 16) | 768 | | FLD_VAL(v_coef[i].vc1, 23, 16) |
633 | | FLD_VAL(v_coef[i].hc3_vc2, 31, 24); | 769 | | FLD_VAL(v_coef[i].vc2, 31, 24); |
634 | 770 | ||
635 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { | 771 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) { |
636 | dispc_ovl_write_firh_reg(plane, i, h); | 772 | _dispc_write_firh_reg(plane, i, h); |
637 | dispc_ovl_write_firhv_reg(plane, i, hv); | 773 | _dispc_write_firhv_reg(plane, i, hv); |
638 | } else { | 774 | } else { |
639 | dispc_ovl_write_firh2_reg(plane, i, h); | 775 | _dispc_write_firh2_reg(plane, i, h); |
640 | dispc_ovl_write_firhv2_reg(plane, i, hv); | 776 | _dispc_write_firhv2_reg(plane, i, hv); |
641 | } | 777 | } |
642 | 778 | ||
643 | } | 779 | } |
@@ -645,98 +781,100 @@ static void dispc_ovl_set_scale_coef(enum omap_plane plane, int fir_hinc, | |||
645 | if (five_taps) { | 781 | if (five_taps) { |
646 | for (i = 0; i < 8; i++) { | 782 | for (i = 0; i < 8; i++) { |
647 | u32 v; | 783 | u32 v; |
648 | v = FLD_VAL(v_coef[i].hc0_vc00, 7, 0) | 784 | v = FLD_VAL(v_coef[i].vc00, 7, 0) |
649 | | FLD_VAL(v_coef[i].hc4_vc22, 15, 8); | 785 | | FLD_VAL(v_coef[i].vc22, 15, 8); |
650 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) | 786 | if (color_comp == DISPC_COLOR_COMPONENT_RGB_Y) |
651 | dispc_ovl_write_firv_reg(plane, i, v); | 787 | _dispc_write_firv_reg(plane, i, v); |
652 | else | 788 | else |
653 | dispc_ovl_write_firv2_reg(plane, i, v); | 789 | _dispc_write_firv2_reg(plane, i, v); |
654 | } | 790 | } |
655 | } | 791 | } |
656 | } | 792 | } |
657 | 793 | ||
658 | 794 | static void _dispc_setup_color_conv_coef(void) | |
659 | static void dispc_ovl_write_color_conv_coef(enum omap_plane plane, | ||
660 | const struct color_conv_coef *ct) | ||
661 | { | 795 | { |
662 | #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) | 796 | const struct color_conv_coef { |
663 | 797 | int ry, rcr, rcb, gy, gcr, gcb, by, bcr, bcb; | |
664 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 0), CVAL(ct->rcr, ct->ry)); | 798 | int full_range; |
665 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 1), CVAL(ct->gy, ct->rcb)); | 799 | } ctbl_bt601_5 = { |
666 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 2), CVAL(ct->gcb, ct->gcr)); | 800 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, |
667 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 3), CVAL(ct->bcr, ct->by)); | 801 | }; |
668 | dispc_write_reg(DISPC_OVL_CONV_COEF(plane, 4), CVAL(0, ct->bcb)); | ||
669 | 802 | ||
670 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), ct->full_range, 11, 11); | 803 | const struct color_conv_coef *ct; |
671 | 804 | ||
672 | #undef CVAL | 805 | #define CVAL(x, y) (FLD_VAL(x, 26, 16) | FLD_VAL(y, 10, 0)) |
673 | } | ||
674 | 806 | ||
675 | static void dispc_setup_color_conv_coef(void) | 807 | ct = &ctbl_bt601_5; |
676 | { | 808 | |
677 | int i; | 809 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0), |
678 | int num_ovl = dss_feat_get_num_ovls(); | 810 | CVAL(ct->rcr, ct->ry)); |
679 | int num_wb = dss_feat_get_num_wbs(); | 811 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1), |
680 | const struct color_conv_coef ctbl_bt601_5_ovl = { | 812 | CVAL(ct->gy, ct->rcb)); |
681 | 298, 409, 0, 298, -208, -100, 298, 0, 517, 0, | 813 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2), |
682 | }; | 814 | CVAL(ct->gcb, ct->gcr)); |
683 | const struct color_conv_coef ctbl_bt601_5_wb = { | 815 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3), |
684 | 66, 112, -38, 129, -94, -74, 25, -18, 112, 0, | 816 | CVAL(ct->bcr, ct->by)); |
685 | }; | 817 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4), |
818 | CVAL(0, ct->bcb)); | ||
819 | |||
820 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0), | ||
821 | CVAL(ct->rcr, ct->ry)); | ||
822 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1), | ||
823 | CVAL(ct->gy, ct->rcb)); | ||
824 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2), | ||
825 | CVAL(ct->gcb, ct->gcr)); | ||
826 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3), | ||
827 | CVAL(ct->bcr, ct->by)); | ||
828 | dispc_write_reg(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4), | ||
829 | CVAL(0, ct->bcb)); | ||
686 | 830 | ||
687 | for (i = 1; i < num_ovl; i++) | 831 | #undef CVAL |
688 | dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_ovl); | ||
689 | 832 | ||
690 | for (; i < num_wb; i++) | 833 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1), |
691 | dispc_ovl_write_color_conv_coef(i, &ctbl_bt601_5_wb); | 834 | ct->full_range, 11, 11); |
835 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2), | ||
836 | ct->full_range, 11, 11); | ||
692 | } | 837 | } |
693 | 838 | ||
694 | static void dispc_ovl_set_ba0(enum omap_plane plane, u32 paddr) | 839 | |
840 | static void _dispc_set_plane_ba0(enum omap_plane plane, u32 paddr) | ||
695 | { | 841 | { |
696 | dispc_write_reg(DISPC_OVL_BA0(plane), paddr); | 842 | dispc_write_reg(DISPC_OVL_BA0(plane), paddr); |
697 | } | 843 | } |
698 | 844 | ||
699 | static void dispc_ovl_set_ba1(enum omap_plane plane, u32 paddr) | 845 | static void _dispc_set_plane_ba1(enum omap_plane plane, u32 paddr) |
700 | { | 846 | { |
701 | dispc_write_reg(DISPC_OVL_BA1(plane), paddr); | 847 | dispc_write_reg(DISPC_OVL_BA1(plane), paddr); |
702 | } | 848 | } |
703 | 849 | ||
704 | static void dispc_ovl_set_ba0_uv(enum omap_plane plane, u32 paddr) | 850 | static void _dispc_set_plane_ba0_uv(enum omap_plane plane, u32 paddr) |
705 | { | 851 | { |
706 | dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr); | 852 | dispc_write_reg(DISPC_OVL_BA0_UV(plane), paddr); |
707 | } | 853 | } |
708 | 854 | ||
709 | static void dispc_ovl_set_ba1_uv(enum omap_plane plane, u32 paddr) | 855 | static void _dispc_set_plane_ba1_uv(enum omap_plane plane, u32 paddr) |
710 | { | 856 | { |
711 | dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); | 857 | dispc_write_reg(DISPC_OVL_BA1_UV(plane), paddr); |
712 | } | 858 | } |
713 | 859 | ||
714 | static void dispc_ovl_set_pos(enum omap_plane plane, | 860 | static void _dispc_set_plane_pos(enum omap_plane plane, int x, int y) |
715 | enum omap_overlay_caps caps, int x, int y) | ||
716 | { | 861 | { |
717 | u32 val; | 862 | u32 val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); |
718 | |||
719 | if ((caps & OMAP_DSS_OVL_CAP_POS) == 0) | ||
720 | return; | ||
721 | |||
722 | val = FLD_VAL(y, 26, 16) | FLD_VAL(x, 10, 0); | ||
723 | 863 | ||
724 | dispc_write_reg(DISPC_OVL_POSITION(plane), val); | 864 | dispc_write_reg(DISPC_OVL_POSITION(plane), val); |
725 | } | 865 | } |
726 | 866 | ||
727 | static void dispc_ovl_set_input_size(enum omap_plane plane, int width, | 867 | static void _dispc_set_pic_size(enum omap_plane plane, int width, int height) |
728 | int height) | ||
729 | { | 868 | { |
730 | u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 869 | u32 val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
731 | 870 | ||
732 | if (plane == OMAP_DSS_GFX || plane == OMAP_DSS_WB) | 871 | if (plane == OMAP_DSS_GFX) |
733 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | 872 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); |
734 | else | 873 | else |
735 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); | 874 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); |
736 | } | 875 | } |
737 | 876 | ||
738 | static void dispc_ovl_set_output_size(enum omap_plane plane, int width, | 877 | static void _dispc_set_vid_size(enum omap_plane plane, int width, int height) |
739 | int height) | ||
740 | { | 878 | { |
741 | u32 val; | 879 | u32 val; |
742 | 880 | ||
@@ -744,65 +882,47 @@ static void dispc_ovl_set_output_size(enum omap_plane plane, int width, | |||
744 | 882 | ||
745 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | 883 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
746 | 884 | ||
747 | if (plane == OMAP_DSS_WB) | 885 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); |
748 | dispc_write_reg(DISPC_OVL_PICTURE_SIZE(plane), val); | ||
749 | else | ||
750 | dispc_write_reg(DISPC_OVL_SIZE(plane), val); | ||
751 | } | ||
752 | |||
753 | static void dispc_ovl_set_zorder(enum omap_plane plane, | ||
754 | enum omap_overlay_caps caps, u8 zorder) | ||
755 | { | ||
756 | if ((caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) | ||
757 | return; | ||
758 | |||
759 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), zorder, 27, 26); | ||
760 | } | 886 | } |
761 | 887 | ||
762 | static void dispc_ovl_enable_zorder_planes(void) | 888 | static void _dispc_set_pre_mult_alpha(enum omap_plane plane, bool enable) |
763 | { | 889 | { |
764 | int i; | 890 | if (!dss_has_feature(FEAT_PRE_MULT_ALPHA)) |
765 | |||
766 | if (!dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) | ||
767 | return; | 891 | return; |
768 | 892 | ||
769 | for (i = 0; i < dss_feat_get_num_ovls(); i++) | 893 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && |
770 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(i), 1, 25, 25); | 894 | plane == OMAP_DSS_VIDEO1) |
771 | } | ||
772 | |||
773 | static void dispc_ovl_set_pre_mult_alpha(enum omap_plane plane, | ||
774 | enum omap_overlay_caps caps, bool enable) | ||
775 | { | ||
776 | if ((caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) | ||
777 | return; | 895 | return; |
778 | 896 | ||
779 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); | 897 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 28, 28); |
780 | } | 898 | } |
781 | 899 | ||
782 | static void dispc_ovl_setup_global_alpha(enum omap_plane plane, | 900 | static void _dispc_setup_global_alpha(enum omap_plane plane, u8 global_alpha) |
783 | enum omap_overlay_caps caps, u8 global_alpha) | ||
784 | { | 901 | { |
785 | static const unsigned shifts[] = { 0, 8, 16, 24, }; | 902 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) |
786 | int shift; | 903 | return; |
787 | 904 | ||
788 | if ((caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) | 905 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && |
906 | plane == OMAP_DSS_VIDEO1) | ||
789 | return; | 907 | return; |
790 | 908 | ||
791 | shift = shifts[plane]; | 909 | if (plane == OMAP_DSS_GFX) |
792 | REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, shift + 7, shift); | 910 | REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 7, 0); |
911 | else if (plane == OMAP_DSS_VIDEO2) | ||
912 | REG_FLD_MOD(DISPC_GLOBAL_ALPHA, global_alpha, 23, 16); | ||
793 | } | 913 | } |
794 | 914 | ||
795 | static void dispc_ovl_set_pix_inc(enum omap_plane plane, s32 inc) | 915 | static void _dispc_set_pix_inc(enum omap_plane plane, s32 inc) |
796 | { | 916 | { |
797 | dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc); | 917 | dispc_write_reg(DISPC_OVL_PIXEL_INC(plane), inc); |
798 | } | 918 | } |
799 | 919 | ||
800 | static void dispc_ovl_set_row_inc(enum omap_plane plane, s32 inc) | 920 | static void _dispc_set_row_inc(enum omap_plane plane, s32 inc) |
801 | { | 921 | { |
802 | dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc); | 922 | dispc_write_reg(DISPC_OVL_ROW_INC(plane), inc); |
803 | } | 923 | } |
804 | 924 | ||
805 | static void dispc_ovl_set_color_mode(enum omap_plane plane, | 925 | static void _dispc_set_color_mode(enum omap_plane plane, |
806 | enum omap_color_mode color_mode) | 926 | enum omap_color_mode color_mode) |
807 | { | 927 | { |
808 | u32 m = 0; | 928 | u32 m = 0; |
@@ -810,11 +930,11 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
810 | switch (color_mode) { | 930 | switch (color_mode) { |
811 | case OMAP_DSS_COLOR_NV12: | 931 | case OMAP_DSS_COLOR_NV12: |
812 | m = 0x0; break; | 932 | m = 0x0; break; |
813 | case OMAP_DSS_COLOR_RGBX16: | 933 | case OMAP_DSS_COLOR_RGB12U: |
814 | m = 0x1; break; | 934 | m = 0x1; break; |
815 | case OMAP_DSS_COLOR_RGBA16: | 935 | case OMAP_DSS_COLOR_RGBA16: |
816 | m = 0x2; break; | 936 | m = 0x2; break; |
817 | case OMAP_DSS_COLOR_RGB12U: | 937 | case OMAP_DSS_COLOR_RGBX16: |
818 | m = 0x4; break; | 938 | m = 0x4; break; |
819 | case OMAP_DSS_COLOR_ARGB16: | 939 | case OMAP_DSS_COLOR_ARGB16: |
820 | m = 0x5; break; | 940 | m = 0x5; break; |
@@ -839,7 +959,7 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
839 | case OMAP_DSS_COLOR_XRGB16_1555: | 959 | case OMAP_DSS_COLOR_XRGB16_1555: |
840 | m = 0xf; break; | 960 | m = 0xf; break; |
841 | default: | 961 | default: |
842 | BUG(); return; | 962 | BUG(); break; |
843 | } | 963 | } |
844 | } else { | 964 | } else { |
845 | switch (color_mode) { | 965 | switch (color_mode) { |
@@ -863,9 +983,9 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
863 | m = 0x8; break; | 983 | m = 0x8; break; |
864 | case OMAP_DSS_COLOR_RGB24P: | 984 | case OMAP_DSS_COLOR_RGB24P: |
865 | m = 0x9; break; | 985 | m = 0x9; break; |
866 | case OMAP_DSS_COLOR_RGBX16: | 986 | case OMAP_DSS_COLOR_YUV2: |
867 | m = 0xa; break; | 987 | m = 0xa; break; |
868 | case OMAP_DSS_COLOR_RGBA16: | 988 | case OMAP_DSS_COLOR_UYVY: |
869 | m = 0xb; break; | 989 | m = 0xb; break; |
870 | case OMAP_DSS_COLOR_ARGB32: | 990 | case OMAP_DSS_COLOR_ARGB32: |
871 | m = 0xc; break; | 991 | m = 0xc; break; |
@@ -876,26 +996,15 @@ static void dispc_ovl_set_color_mode(enum omap_plane plane, | |||
876 | case OMAP_DSS_COLOR_XRGB16_1555: | 996 | case OMAP_DSS_COLOR_XRGB16_1555: |
877 | m = 0xf; break; | 997 | m = 0xf; break; |
878 | default: | 998 | default: |
879 | BUG(); return; | 999 | BUG(); break; |
880 | } | 1000 | } |
881 | } | 1001 | } |
882 | 1002 | ||
883 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); | 1003 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), m, 4, 1); |
884 | } | 1004 | } |
885 | 1005 | ||
886 | static void dispc_ovl_configure_burst_type(enum omap_plane plane, | 1006 | void dispc_set_channel_out(enum omap_plane plane, |
887 | enum omap_dss_rotation_type rotation_type) | 1007 | enum omap_channel channel) |
888 | { | ||
889 | if (dss_has_feature(FEAT_BURST_2D) == 0) | ||
890 | return; | ||
891 | |||
892 | if (rotation_type == OMAP_DSS_ROT_TILER) | ||
893 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 1, 29, 29); | ||
894 | else | ||
895 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), 0, 29, 29); | ||
896 | } | ||
897 | |||
898 | void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | ||
899 | { | 1008 | { |
900 | int shift; | 1009 | int shift; |
901 | u32 val; | 1010 | u32 val; |
@@ -907,7 +1016,6 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | |||
907 | break; | 1016 | break; |
908 | case OMAP_DSS_VIDEO1: | 1017 | case OMAP_DSS_VIDEO1: |
909 | case OMAP_DSS_VIDEO2: | 1018 | case OMAP_DSS_VIDEO2: |
910 | case OMAP_DSS_VIDEO3: | ||
911 | shift = 16; | 1019 | shift = 16; |
912 | break; | 1020 | break; |
913 | default: | 1021 | default: |
@@ -930,18 +1038,8 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | |||
930 | chan = 0; | 1038 | chan = 0; |
931 | chan2 = 1; | 1039 | chan2 = 1; |
932 | break; | 1040 | break; |
933 | case OMAP_DSS_CHANNEL_LCD3: | ||
934 | if (dss_has_feature(FEAT_MGR_LCD3)) { | ||
935 | chan = 0; | ||
936 | chan2 = 2; | ||
937 | } else { | ||
938 | BUG(); | ||
939 | return; | ||
940 | } | ||
941 | break; | ||
942 | default: | 1041 | default: |
943 | BUG(); | 1042 | BUG(); |
944 | return; | ||
945 | } | 1043 | } |
946 | 1044 | ||
947 | val = FLD_MOD(val, chan, shift, shift); | 1045 | val = FLD_MOD(val, chan, shift, shift); |
@@ -951,63 +1049,25 @@ void dispc_ovl_set_channel_out(enum omap_plane plane, enum omap_channel channel) | |||
951 | } | 1049 | } |
952 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 1050 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
953 | } | 1051 | } |
954 | EXPORT_SYMBOL(dispc_ovl_set_channel_out); | ||
955 | 1052 | ||
956 | static enum omap_channel dispc_ovl_get_channel_out(enum omap_plane plane) | 1053 | static void dispc_set_burst_size(enum omap_plane plane, |
1054 | enum omap_burst_size burst_size) | ||
957 | { | 1055 | { |
958 | int shift; | 1056 | int shift; |
959 | u32 val; | ||
960 | enum omap_channel channel; | ||
961 | 1057 | ||
962 | switch (plane) { | 1058 | switch (plane) { |
963 | case OMAP_DSS_GFX: | 1059 | case OMAP_DSS_GFX: |
964 | shift = 8; | 1060 | shift = 6; |
965 | break; | 1061 | break; |
966 | case OMAP_DSS_VIDEO1: | 1062 | case OMAP_DSS_VIDEO1: |
967 | case OMAP_DSS_VIDEO2: | 1063 | case OMAP_DSS_VIDEO2: |
968 | case OMAP_DSS_VIDEO3: | 1064 | shift = 14; |
969 | shift = 16; | ||
970 | break; | 1065 | break; |
971 | default: | 1066 | default: |
972 | BUG(); | 1067 | BUG(); |
973 | return 0; | 1068 | return; |
974 | } | ||
975 | |||
976 | val = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | ||
977 | |||
978 | if (dss_has_feature(FEAT_MGR_LCD3)) { | ||
979 | if (FLD_GET(val, 31, 30) == 0) | ||
980 | channel = FLD_GET(val, shift, shift); | ||
981 | else if (FLD_GET(val, 31, 30) == 1) | ||
982 | channel = OMAP_DSS_CHANNEL_LCD2; | ||
983 | else | ||
984 | channel = OMAP_DSS_CHANNEL_LCD3; | ||
985 | } else if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
986 | if (FLD_GET(val, 31, 30) == 0) | ||
987 | channel = FLD_GET(val, shift, shift); | ||
988 | else | ||
989 | channel = OMAP_DSS_CHANNEL_LCD2; | ||
990 | } else { | ||
991 | channel = FLD_GET(val, shift, shift); | ||
992 | } | 1069 | } |
993 | 1070 | ||
994 | return channel; | ||
995 | } | ||
996 | |||
997 | void dispc_wb_set_channel_in(enum dss_writeback_channel channel) | ||
998 | { | ||
999 | enum omap_plane plane = OMAP_DSS_WB; | ||
1000 | |||
1001 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), channel, 18, 16); | ||
1002 | } | ||
1003 | |||
1004 | static void dispc_ovl_set_burst_size(enum omap_plane plane, | ||
1005 | enum omap_burst_size burst_size) | ||
1006 | { | ||
1007 | static const unsigned shifts[] = { 6, 14, 14, 14, 14, }; | ||
1008 | int shift; | ||
1009 | |||
1010 | shift = shifts[plane]; | ||
1011 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); | 1071 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), burst_size, shift + 1, shift); |
1012 | } | 1072 | } |
1013 | 1073 | ||
@@ -1017,11 +1077,11 @@ static void dispc_configure_burst_sizes(void) | |||
1017 | const int burst_size = BURST_SIZE_X8; | 1077 | const int burst_size = BURST_SIZE_X8; |
1018 | 1078 | ||
1019 | /* Configure burst size always to maximum size */ | 1079 | /* Configure burst size always to maximum size */ |
1020 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) | 1080 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) |
1021 | dispc_ovl_set_burst_size(i, burst_size); | 1081 | dispc_set_burst_size(i, burst_size); |
1022 | } | 1082 | } |
1023 | 1083 | ||
1024 | static u32 dispc_ovl_get_burst_size(enum omap_plane plane) | 1084 | u32 dispc_get_burst_size(enum omap_plane plane) |
1025 | { | 1085 | { |
1026 | unsigned unit = dss_feat_get_burst_size_unit(); | 1086 | unsigned unit = dss_feat_get_burst_size_unit(); |
1027 | /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ | 1087 | /* burst multiplier is always x8 (see dispc_configure_burst_sizes()) */ |
@@ -1042,20 +1102,26 @@ void dispc_enable_gamma_table(bool enable) | |||
1042 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); | 1102 | REG_FLD_MOD(DISPC_CONFIG, enable, 9, 9); |
1043 | } | 1103 | } |
1044 | 1104 | ||
1045 | static void dispc_mgr_enable_cpr(enum omap_channel channel, bool enable) | 1105 | void dispc_enable_cpr(enum omap_channel channel, bool enable) |
1046 | { | 1106 | { |
1047 | if (channel == OMAP_DSS_CHANNEL_DIGIT) | 1107 | u16 reg; |
1108 | |||
1109 | if (channel == OMAP_DSS_CHANNEL_LCD) | ||
1110 | reg = DISPC_CONFIG; | ||
1111 | else if (channel == OMAP_DSS_CHANNEL_LCD2) | ||
1112 | reg = DISPC_CONFIG2; | ||
1113 | else | ||
1048 | return; | 1114 | return; |
1049 | 1115 | ||
1050 | mgr_fld_write(channel, DISPC_MGR_FLD_CPR, enable); | 1116 | REG_FLD_MOD(reg, enable, 15, 15); |
1051 | } | 1117 | } |
1052 | 1118 | ||
1053 | static void dispc_mgr_set_cpr_coef(enum omap_channel channel, | 1119 | void dispc_set_cpr_coef(enum omap_channel channel, |
1054 | const struct omap_dss_cpr_coefs *coefs) | 1120 | struct omap_dss_cpr_coefs *coefs) |
1055 | { | 1121 | { |
1056 | u32 coef_r, coef_g, coef_b; | 1122 | u32 coef_r, coef_g, coef_b; |
1057 | 1123 | ||
1058 | if (!dss_mgr_is_lcd(channel)) | 1124 | if (channel != OMAP_DSS_CHANNEL_LCD && channel != OMAP_DSS_CHANNEL_LCD2) |
1059 | return; | 1125 | return; |
1060 | 1126 | ||
1061 | coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | | 1127 | coef_r = FLD_VAL(coefs->rr, 31, 22) | FLD_VAL(coefs->rg, 20, 11) | |
@@ -1070,7 +1136,7 @@ static void dispc_mgr_set_cpr_coef(enum omap_channel channel, | |||
1070 | dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); | 1136 | dispc_write_reg(DISPC_CPR_COEF_B(channel), coef_b); |
1071 | } | 1137 | } |
1072 | 1138 | ||
1073 | static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) | 1139 | static void _dispc_set_vid_color_conv(enum omap_plane plane, bool enable) |
1074 | { | 1140 | { |
1075 | u32 val; | 1141 | u32 val; |
1076 | 1142 | ||
@@ -1081,34 +1147,38 @@ static void dispc_ovl_set_vid_color_conv(enum omap_plane plane, bool enable) | |||
1081 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); | 1147 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), val); |
1082 | } | 1148 | } |
1083 | 1149 | ||
1084 | static void dispc_ovl_enable_replication(enum omap_plane plane, | 1150 | void dispc_enable_replication(enum omap_plane plane, bool enable) |
1085 | enum omap_overlay_caps caps, bool enable) | ||
1086 | { | 1151 | { |
1087 | static const unsigned shifts[] = { 5, 10, 10, 10 }; | 1152 | int bit; |
1088 | int shift; | ||
1089 | 1153 | ||
1090 | if ((caps & OMAP_DSS_OVL_CAP_REPLICATION) == 0) | 1154 | if (plane == OMAP_DSS_GFX) |
1091 | return; | 1155 | bit = 5; |
1156 | else | ||
1157 | bit = 10; | ||
1092 | 1158 | ||
1093 | shift = shifts[plane]; | 1159 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, bit, bit); |
1094 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable, shift, shift); | ||
1095 | } | 1160 | } |
1096 | 1161 | ||
1097 | static void dispc_mgr_set_size(enum omap_channel channel, u16 width, | 1162 | void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height) |
1098 | u16 height) | ||
1099 | { | 1163 | { |
1100 | u32 val; | 1164 | u32 val; |
1101 | 1165 | BUG_ON((width > (1 << 11)) || (height > (1 << 11))); | |
1102 | val = FLD_VAL(height - 1, dispc.feat->mgr_height_start, 16) | | 1166 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); |
1103 | FLD_VAL(width - 1, dispc.feat->mgr_width_start, 0); | ||
1104 | |||
1105 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); | 1167 | dispc_write_reg(DISPC_SIZE_MGR(channel), val); |
1106 | } | 1168 | } |
1107 | 1169 | ||
1108 | static void dispc_init_fifos(void) | 1170 | void dispc_set_digit_size(u16 width, u16 height) |
1171 | { | ||
1172 | u32 val; | ||
1173 | BUG_ON((width > (1 << 11)) || (height > (1 << 11))); | ||
1174 | val = FLD_VAL(height - 1, 26, 16) | FLD_VAL(width - 1, 10, 0); | ||
1175 | dispc_write_reg(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT), val); | ||
1176 | } | ||
1177 | |||
1178 | static void dispc_read_plane_fifo_sizes(void) | ||
1109 | { | 1179 | { |
1110 | u32 size; | 1180 | u32 size; |
1111 | int fifo; | 1181 | int plane; |
1112 | u8 start, end; | 1182 | u8 start, end; |
1113 | u32 unit; | 1183 | u32 unit; |
1114 | 1184 | ||
@@ -1116,56 +1186,19 @@ static void dispc_init_fifos(void) | |||
1116 | 1186 | ||
1117 | dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); | 1187 | dss_feat_get_reg_field(FEAT_REG_FIFOSIZE, &start, &end); |
1118 | 1188 | ||
1119 | for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { | 1189 | for (plane = 0; plane < ARRAY_SIZE(dispc.fifo_size); ++plane) { |
1120 | size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(fifo), start, end); | 1190 | size = REG_GET(DISPC_OVL_FIFO_SIZE_STATUS(plane), start, end); |
1121 | size *= unit; | 1191 | size *= unit; |
1122 | dispc.fifo_size[fifo] = size; | 1192 | dispc.fifo_size[plane] = size; |
1123 | |||
1124 | /* | ||
1125 | * By default fifos are mapped directly to overlays, fifo 0 to | ||
1126 | * ovl 0, fifo 1 to ovl 1, etc. | ||
1127 | */ | ||
1128 | dispc.fifo_assignment[fifo] = fifo; | ||
1129 | } | ||
1130 | |||
1131 | /* | ||
1132 | * The GFX fifo on OMAP4 is smaller than the other fifos. The small fifo | ||
1133 | * causes problems with certain use cases, like using the tiler in 2D | ||
1134 | * mode. The below hack swaps the fifos of GFX and WB planes, thus | ||
1135 | * giving GFX plane a larger fifo. WB but should work fine with a | ||
1136 | * smaller fifo. | ||
1137 | */ | ||
1138 | if (dispc.feat->gfx_fifo_workaround) { | ||
1139 | u32 v; | ||
1140 | |||
1141 | v = dispc_read_reg(DISPC_GLOBAL_BUFFER); | ||
1142 | |||
1143 | v = FLD_MOD(v, 4, 2, 0); /* GFX BUF top to WB */ | ||
1144 | v = FLD_MOD(v, 4, 5, 3); /* GFX BUF bottom to WB */ | ||
1145 | v = FLD_MOD(v, 0, 26, 24); /* WB BUF top to GFX */ | ||
1146 | v = FLD_MOD(v, 0, 29, 27); /* WB BUF bottom to GFX */ | ||
1147 | |||
1148 | dispc_write_reg(DISPC_GLOBAL_BUFFER, v); | ||
1149 | |||
1150 | dispc.fifo_assignment[OMAP_DSS_GFX] = OMAP_DSS_WB; | ||
1151 | dispc.fifo_assignment[OMAP_DSS_WB] = OMAP_DSS_GFX; | ||
1152 | } | 1193 | } |
1153 | } | 1194 | } |
1154 | 1195 | ||
1155 | static u32 dispc_ovl_get_fifo_size(enum omap_plane plane) | 1196 | u32 dispc_get_plane_fifo_size(enum omap_plane plane) |
1156 | { | 1197 | { |
1157 | int fifo; | 1198 | return dispc.fifo_size[plane]; |
1158 | u32 size = 0; | ||
1159 | |||
1160 | for (fifo = 0; fifo < dispc.feat->num_fifos; ++fifo) { | ||
1161 | if (dispc.fifo_assignment[fifo] == plane) | ||
1162 | size += dispc.fifo_size[fifo]; | ||
1163 | } | ||
1164 | |||
1165 | return size; | ||
1166 | } | 1199 | } |
1167 | 1200 | ||
1168 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | 1201 | void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) |
1169 | { | 1202 | { |
1170 | u8 hi_start, hi_end, lo_start, lo_end; | 1203 | u8 hi_start, hi_end, lo_start, lo_end; |
1171 | u32 unit; | 1204 | u32 unit; |
@@ -1181,13 +1214,13 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | |||
1181 | dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); | 1214 | dss_feat_get_reg_field(FEAT_REG_FIFOHIGHTHRESHOLD, &hi_start, &hi_end); |
1182 | dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); | 1215 | dss_feat_get_reg_field(FEAT_REG_FIFOLOWTHRESHOLD, &lo_start, &lo_end); |
1183 | 1216 | ||
1184 | DSSDBG("fifo(%d) threshold (bytes), old %u/%u, new %u/%u\n", | 1217 | DSSDBG("fifo(%d) low/high old %u/%u, new %u/%u\n", |
1185 | plane, | 1218 | plane, |
1186 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), | 1219 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), |
1187 | lo_start, lo_end) * unit, | 1220 | lo_start, lo_end), |
1188 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), | 1221 | REG_GET(DISPC_OVL_FIFO_THRESHOLD(plane), |
1189 | hi_start, hi_end) * unit, | 1222 | hi_start, hi_end), |
1190 | low * unit, high * unit); | 1223 | low, high); |
1191 | 1224 | ||
1192 | dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), | 1225 | dispc_write_reg(DISPC_OVL_FIFO_THRESHOLD(plane), |
1193 | FLD_VAL(high, hi_start, hi_end) | | 1226 | FLD_VAL(high, hi_start, hi_end) | |
@@ -1196,63 +1229,11 @@ void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high) | |||
1196 | 1229 | ||
1197 | void dispc_enable_fifomerge(bool enable) | 1230 | void dispc_enable_fifomerge(bool enable) |
1198 | { | 1231 | { |
1199 | if (!dss_has_feature(FEAT_FIFO_MERGE)) { | ||
1200 | WARN_ON(enable); | ||
1201 | return; | ||
1202 | } | ||
1203 | |||
1204 | DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); | 1232 | DSSDBG("FIFO merge %s\n", enable ? "enabled" : "disabled"); |
1205 | REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); | 1233 | REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 14, 14); |
1206 | } | 1234 | } |
1207 | 1235 | ||
1208 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | 1236 | static void _dispc_set_fir(enum omap_plane plane, |
1209 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, | ||
1210 | bool manual_update) | ||
1211 | { | ||
1212 | /* | ||
1213 | * All sizes are in bytes. Both the buffer and burst are made of | ||
1214 | * buffer_units, and the fifo thresholds must be buffer_unit aligned. | ||
1215 | */ | ||
1216 | |||
1217 | unsigned buf_unit = dss_feat_get_buffer_size_unit(); | ||
1218 | unsigned ovl_fifo_size, total_fifo_size, burst_size; | ||
1219 | int i; | ||
1220 | |||
1221 | burst_size = dispc_ovl_get_burst_size(plane); | ||
1222 | ovl_fifo_size = dispc_ovl_get_fifo_size(plane); | ||
1223 | |||
1224 | if (use_fifomerge) { | ||
1225 | total_fifo_size = 0; | ||
1226 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) | ||
1227 | total_fifo_size += dispc_ovl_get_fifo_size(i); | ||
1228 | } else { | ||
1229 | total_fifo_size = ovl_fifo_size; | ||
1230 | } | ||
1231 | |||
1232 | /* | ||
1233 | * We use the same low threshold for both fifomerge and non-fifomerge | ||
1234 | * cases, but for fifomerge we calculate the high threshold using the | ||
1235 | * combined fifo size | ||
1236 | */ | ||
1237 | |||
1238 | if (manual_update && dss_has_feature(FEAT_OMAP3_DSI_FIFO_BUG)) { | ||
1239 | *fifo_low = ovl_fifo_size - burst_size * 2; | ||
1240 | *fifo_high = total_fifo_size - burst_size; | ||
1241 | } else if (plane == OMAP_DSS_WB) { | ||
1242 | /* | ||
1243 | * Most optimal configuration for writeback is to push out data | ||
1244 | * to the interconnect the moment writeback pushes enough pixels | ||
1245 | * in the FIFO to form a burst | ||
1246 | */ | ||
1247 | *fifo_low = 0; | ||
1248 | *fifo_high = burst_size; | ||
1249 | } else { | ||
1250 | *fifo_low = ovl_fifo_size - burst_size; | ||
1251 | *fifo_high = total_fifo_size - buf_unit; | ||
1252 | } | ||
1253 | } | ||
1254 | |||
1255 | static void dispc_ovl_set_fir(enum omap_plane plane, | ||
1256 | int hinc, int vinc, | 1237 | int hinc, int vinc, |
1257 | enum omap_color_component color_comp) | 1238 | enum omap_color_component color_comp) |
1258 | { | 1239 | { |
@@ -1275,7 +1256,7 @@ static void dispc_ovl_set_fir(enum omap_plane plane, | |||
1275 | } | 1256 | } |
1276 | } | 1257 | } |
1277 | 1258 | ||
1278 | static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) | 1259 | static void _dispc_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) |
1279 | { | 1260 | { |
1280 | u32 val; | 1261 | u32 val; |
1281 | u8 hor_start, hor_end, vert_start, vert_end; | 1262 | u8 hor_start, hor_end, vert_start, vert_end; |
@@ -1289,7 +1270,7 @@ static void dispc_ovl_set_vid_accu0(enum omap_plane plane, int haccu, int vaccu) | |||
1289 | dispc_write_reg(DISPC_OVL_ACCU0(plane), val); | 1270 | dispc_write_reg(DISPC_OVL_ACCU0(plane), val); |
1290 | } | 1271 | } |
1291 | 1272 | ||
1292 | static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) | 1273 | static void _dispc_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) |
1293 | { | 1274 | { |
1294 | u32 val; | 1275 | u32 val; |
1295 | u8 hor_start, hor_end, vert_start, vert_end; | 1276 | u8 hor_start, hor_end, vert_start, vert_end; |
@@ -1303,8 +1284,7 @@ static void dispc_ovl_set_vid_accu1(enum omap_plane plane, int haccu, int vaccu) | |||
1303 | dispc_write_reg(DISPC_OVL_ACCU1(plane), val); | 1284 | dispc_write_reg(DISPC_OVL_ACCU1(plane), val); |
1304 | } | 1285 | } |
1305 | 1286 | ||
1306 | static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu, | 1287 | static void _dispc_set_vid_accu2_0(enum omap_plane plane, int haccu, int vaccu) |
1307 | int vaccu) | ||
1308 | { | 1288 | { |
1309 | u32 val; | 1289 | u32 val; |
1310 | 1290 | ||
@@ -1312,8 +1292,7 @@ static void dispc_ovl_set_vid_accu2_0(enum omap_plane plane, int haccu, | |||
1312 | dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val); | 1292 | dispc_write_reg(DISPC_OVL_ACCU2_0(plane), val); |
1313 | } | 1293 | } |
1314 | 1294 | ||
1315 | static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu, | 1295 | static void _dispc_set_vid_accu2_1(enum omap_plane plane, int haccu, int vaccu) |
1316 | int vaccu) | ||
1317 | { | 1296 | { |
1318 | u32 val; | 1297 | u32 val; |
1319 | 1298 | ||
@@ -1321,111 +1300,27 @@ static void dispc_ovl_set_vid_accu2_1(enum omap_plane plane, int haccu, | |||
1321 | dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val); | 1300 | dispc_write_reg(DISPC_OVL_ACCU2_1(plane), val); |
1322 | } | 1301 | } |
1323 | 1302 | ||
1324 | static void dispc_ovl_set_scale_param(enum omap_plane plane, | 1303 | static void _dispc_set_scale_param(enum omap_plane plane, |
1325 | u16 orig_width, u16 orig_height, | 1304 | u16 orig_width, u16 orig_height, |
1326 | u16 out_width, u16 out_height, | 1305 | u16 out_width, u16 out_height, |
1327 | bool five_taps, u8 rotation, | 1306 | bool five_taps, u8 rotation, |
1328 | enum omap_color_component color_comp) | 1307 | enum omap_color_component color_comp) |
1329 | { | 1308 | { |
1330 | int fir_hinc, fir_vinc; | 1309 | int fir_hinc, fir_vinc; |
1310 | int hscaleup, vscaleup; | ||
1331 | 1311 | ||
1332 | fir_hinc = 1024 * orig_width / out_width; | 1312 | hscaleup = orig_width <= out_width; |
1333 | fir_vinc = 1024 * orig_height / out_height; | 1313 | vscaleup = orig_height <= out_height; |
1334 | |||
1335 | dispc_ovl_set_scale_coef(plane, fir_hinc, fir_vinc, five_taps, | ||
1336 | color_comp); | ||
1337 | dispc_ovl_set_fir(plane, fir_hinc, fir_vinc, color_comp); | ||
1338 | } | ||
1339 | |||
1340 | static void dispc_ovl_set_accu_uv(enum omap_plane plane, | ||
1341 | u16 orig_width, u16 orig_height, u16 out_width, u16 out_height, | ||
1342 | bool ilace, enum omap_color_mode color_mode, u8 rotation) | ||
1343 | { | ||
1344 | int h_accu2_0, h_accu2_1; | ||
1345 | int v_accu2_0, v_accu2_1; | ||
1346 | int chroma_hinc, chroma_vinc; | ||
1347 | int idx; | ||
1348 | |||
1349 | struct accu { | ||
1350 | s8 h0_m, h0_n; | ||
1351 | s8 h1_m, h1_n; | ||
1352 | s8 v0_m, v0_n; | ||
1353 | s8 v1_m, v1_n; | ||
1354 | }; | ||
1355 | |||
1356 | const struct accu *accu_table; | ||
1357 | const struct accu *accu_val; | ||
1358 | |||
1359 | static const struct accu accu_nv12[4] = { | ||
1360 | { 0, 1, 0, 1 , -1, 2, 0, 1 }, | ||
1361 | { 1, 2, -3, 4 , 0, 1, 0, 1 }, | ||
1362 | { -1, 1, 0, 1 , -1, 2, 0, 1 }, | ||
1363 | { -1, 2, -1, 2 , -1, 1, 0, 1 }, | ||
1364 | }; | ||
1365 | |||
1366 | static const struct accu accu_nv12_ilace[4] = { | ||
1367 | { 0, 1, 0, 1 , -3, 4, -1, 4 }, | ||
1368 | { -1, 4, -3, 4 , 0, 1, 0, 1 }, | ||
1369 | { -1, 1, 0, 1 , -1, 4, -3, 4 }, | ||
1370 | { -3, 4, -3, 4 , -1, 1, 0, 1 }, | ||
1371 | }; | ||
1372 | |||
1373 | static const struct accu accu_yuv[4] = { | ||
1374 | { 0, 1, 0, 1, 0, 1, 0, 1 }, | ||
1375 | { 0, 1, 0, 1, 0, 1, 0, 1 }, | ||
1376 | { -1, 1, 0, 1, 0, 1, 0, 1 }, | ||
1377 | { 0, 1, 0, 1, -1, 1, 0, 1 }, | ||
1378 | }; | ||
1379 | |||
1380 | switch (rotation) { | ||
1381 | case OMAP_DSS_ROT_0: | ||
1382 | idx = 0; | ||
1383 | break; | ||
1384 | case OMAP_DSS_ROT_90: | ||
1385 | idx = 1; | ||
1386 | break; | ||
1387 | case OMAP_DSS_ROT_180: | ||
1388 | idx = 2; | ||
1389 | break; | ||
1390 | case OMAP_DSS_ROT_270: | ||
1391 | idx = 3; | ||
1392 | break; | ||
1393 | default: | ||
1394 | BUG(); | ||
1395 | return; | ||
1396 | } | ||
1397 | |||
1398 | switch (color_mode) { | ||
1399 | case OMAP_DSS_COLOR_NV12: | ||
1400 | if (ilace) | ||
1401 | accu_table = accu_nv12_ilace; | ||
1402 | else | ||
1403 | accu_table = accu_nv12; | ||
1404 | break; | ||
1405 | case OMAP_DSS_COLOR_YUV2: | ||
1406 | case OMAP_DSS_COLOR_UYVY: | ||
1407 | accu_table = accu_yuv; | ||
1408 | break; | ||
1409 | default: | ||
1410 | BUG(); | ||
1411 | return; | ||
1412 | } | ||
1413 | |||
1414 | accu_val = &accu_table[idx]; | ||
1415 | 1314 | ||
1416 | chroma_hinc = 1024 * orig_width / out_width; | 1315 | _dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps, color_comp); |
1417 | chroma_vinc = 1024 * orig_height / out_height; | ||
1418 | 1316 | ||
1419 | h_accu2_0 = (accu_val->h0_m * chroma_hinc / accu_val->h0_n) % 1024; | 1317 | fir_hinc = 1024 * orig_width / out_width; |
1420 | h_accu2_1 = (accu_val->h1_m * chroma_hinc / accu_val->h1_n) % 1024; | 1318 | fir_vinc = 1024 * orig_height / out_height; |
1421 | v_accu2_0 = (accu_val->v0_m * chroma_vinc / accu_val->v0_n) % 1024; | ||
1422 | v_accu2_1 = (accu_val->v1_m * chroma_vinc / accu_val->v1_n) % 1024; | ||
1423 | 1319 | ||
1424 | dispc_ovl_set_vid_accu2_0(plane, h_accu2_0, v_accu2_0); | 1320 | _dispc_set_fir(plane, fir_hinc, fir_vinc, color_comp); |
1425 | dispc_ovl_set_vid_accu2_1(plane, h_accu2_1, v_accu2_1); | ||
1426 | } | 1321 | } |
1427 | 1322 | ||
1428 | static void dispc_ovl_set_scaling_common(enum omap_plane plane, | 1323 | static void _dispc_set_scaling_common(enum omap_plane plane, |
1429 | u16 orig_width, u16 orig_height, | 1324 | u16 orig_width, u16 orig_height, |
1430 | u16 out_width, u16 out_height, | 1325 | u16 out_width, u16 out_height, |
1431 | bool ilace, bool five_taps, | 1326 | bool ilace, bool five_taps, |
@@ -1436,7 +1331,7 @@ static void dispc_ovl_set_scaling_common(enum omap_plane plane, | |||
1436 | int accu1 = 0; | 1331 | int accu1 = 0; |
1437 | u32 l; | 1332 | u32 l; |
1438 | 1333 | ||
1439 | dispc_ovl_set_scale_param(plane, orig_width, orig_height, | 1334 | _dispc_set_scale_param(plane, orig_width, orig_height, |
1440 | out_width, out_height, five_taps, | 1335 | out_width, out_height, five_taps, |
1441 | rotation, DISPC_COLOR_COMPONENT_RGB_Y); | 1336 | rotation, DISPC_COLOR_COMPONENT_RGB_Y); |
1442 | l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | 1337 | l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); |
@@ -1475,11 +1370,11 @@ static void dispc_ovl_set_scaling_common(enum omap_plane plane, | |||
1475 | } | 1370 | } |
1476 | } | 1371 | } |
1477 | 1372 | ||
1478 | dispc_ovl_set_vid_accu0(plane, 0, accu0); | 1373 | _dispc_set_vid_accu0(plane, 0, accu0); |
1479 | dispc_ovl_set_vid_accu1(plane, 0, accu1); | 1374 | _dispc_set_vid_accu1(plane, 0, accu1); |
1480 | } | 1375 | } |
1481 | 1376 | ||
1482 | static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | 1377 | static void _dispc_set_scaling_uv(enum omap_plane plane, |
1483 | u16 orig_width, u16 orig_height, | 1378 | u16 orig_width, u16 orig_height, |
1484 | u16 out_width, u16 out_height, | 1379 | u16 out_width, u16 out_height, |
1485 | bool ilace, bool five_taps, | 1380 | bool ilace, bool five_taps, |
@@ -1488,7 +1383,6 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1488 | { | 1383 | { |
1489 | int scale_x = out_width != orig_width; | 1384 | int scale_x = out_width != orig_width; |
1490 | int scale_y = out_height != orig_height; | 1385 | int scale_y = out_height != orig_height; |
1491 | bool chroma_upscale = plane != OMAP_DSS_WB ? true : false; | ||
1492 | 1386 | ||
1493 | if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) | 1387 | if (!dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) |
1494 | return; | 1388 | return; |
@@ -1496,48 +1390,31 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1496 | color_mode != OMAP_DSS_COLOR_UYVY && | 1390 | color_mode != OMAP_DSS_COLOR_UYVY && |
1497 | color_mode != OMAP_DSS_COLOR_NV12)) { | 1391 | color_mode != OMAP_DSS_COLOR_NV12)) { |
1498 | /* reset chroma resampling for RGB formats */ | 1392 | /* reset chroma resampling for RGB formats */ |
1499 | if (plane != OMAP_DSS_WB) | 1393 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); |
1500 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), 0, 8, 8); | ||
1501 | return; | 1394 | return; |
1502 | } | 1395 | } |
1503 | |||
1504 | dispc_ovl_set_accu_uv(plane, orig_width, orig_height, out_width, | ||
1505 | out_height, ilace, color_mode, rotation); | ||
1506 | |||
1507 | switch (color_mode) { | 1396 | switch (color_mode) { |
1508 | case OMAP_DSS_COLOR_NV12: | 1397 | case OMAP_DSS_COLOR_NV12: |
1509 | if (chroma_upscale) { | 1398 | /* UV is subsampled by 2 vertically*/ |
1510 | /* UV is subsampled by 2 horizontally and vertically */ | 1399 | orig_height >>= 1; |
1511 | orig_height >>= 1; | 1400 | /* UV is subsampled by 2 horz.*/ |
1512 | orig_width >>= 1; | 1401 | orig_width >>= 1; |
1513 | } else { | ||
1514 | /* UV is downsampled by 2 horizontally and vertically */ | ||
1515 | orig_height <<= 1; | ||
1516 | orig_width <<= 1; | ||
1517 | } | ||
1518 | |||
1519 | break; | 1402 | break; |
1520 | case OMAP_DSS_COLOR_YUV2: | 1403 | case OMAP_DSS_COLOR_YUV2: |
1521 | case OMAP_DSS_COLOR_UYVY: | 1404 | case OMAP_DSS_COLOR_UYVY: |
1522 | /* For YUV422 with 90/270 rotation, we don't upsample chroma */ | 1405 | /*For YUV422 with 90/270 rotation, |
1406 | *we don't upsample chroma | ||
1407 | */ | ||
1523 | if (rotation == OMAP_DSS_ROT_0 || | 1408 | if (rotation == OMAP_DSS_ROT_0 || |
1524 | rotation == OMAP_DSS_ROT_180) { | 1409 | rotation == OMAP_DSS_ROT_180) |
1525 | if (chroma_upscale) | 1410 | /* UV is subsampled by 2 hrz*/ |
1526 | /* UV is subsampled by 2 horizontally */ | 1411 | orig_width >>= 1; |
1527 | orig_width >>= 1; | ||
1528 | else | ||
1529 | /* UV is downsampled by 2 horizontally */ | ||
1530 | orig_width <<= 1; | ||
1531 | } | ||
1532 | |||
1533 | /* must use FIR for YUV422 if rotated */ | 1412 | /* must use FIR for YUV422 if rotated */ |
1534 | if (rotation != OMAP_DSS_ROT_0) | 1413 | if (rotation != OMAP_DSS_ROT_0) |
1535 | scale_x = scale_y = true; | 1414 | scale_x = scale_y = true; |
1536 | |||
1537 | break; | 1415 | break; |
1538 | default: | 1416 | default: |
1539 | BUG(); | 1417 | BUG(); |
1540 | return; | ||
1541 | } | 1418 | } |
1542 | 1419 | ||
1543 | if (out_width != orig_width) | 1420 | if (out_width != orig_width) |
@@ -1545,21 +1422,22 @@ static void dispc_ovl_set_scaling_uv(enum omap_plane plane, | |||
1545 | if (out_height != orig_height) | 1422 | if (out_height != orig_height) |
1546 | scale_y = true; | 1423 | scale_y = true; |
1547 | 1424 | ||
1548 | dispc_ovl_set_scale_param(plane, orig_width, orig_height, | 1425 | _dispc_set_scale_param(plane, orig_width, orig_height, |
1549 | out_width, out_height, five_taps, | 1426 | out_width, out_height, five_taps, |
1550 | rotation, DISPC_COLOR_COMPONENT_UV); | 1427 | rotation, DISPC_COLOR_COMPONENT_UV); |
1551 | 1428 | ||
1552 | if (plane != OMAP_DSS_WB) | 1429 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), |
1553 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES2(plane), | 1430 | (scale_x || scale_y) ? 1 : 0, 8, 8); |
1554 | (scale_x || scale_y) ? 1 : 0, 8, 8); | ||
1555 | |||
1556 | /* set H scaling */ | 1431 | /* set H scaling */ |
1557 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); | 1432 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_x ? 1 : 0, 5, 5); |
1558 | /* set V scaling */ | 1433 | /* set V scaling */ |
1559 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); | 1434 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), scale_y ? 1 : 0, 6, 6); |
1435 | |||
1436 | _dispc_set_vid_accu2_0(plane, 0x80, 0); | ||
1437 | _dispc_set_vid_accu2_1(plane, 0x80, 0); | ||
1560 | } | 1438 | } |
1561 | 1439 | ||
1562 | static void dispc_ovl_set_scaling(enum omap_plane plane, | 1440 | static void _dispc_set_scaling(enum omap_plane plane, |
1563 | u16 orig_width, u16 orig_height, | 1441 | u16 orig_width, u16 orig_height, |
1564 | u16 out_width, u16 out_height, | 1442 | u16 out_width, u16 out_height, |
1565 | bool ilace, bool five_taps, | 1443 | bool ilace, bool five_taps, |
@@ -1568,14 +1446,14 @@ static void dispc_ovl_set_scaling(enum omap_plane plane, | |||
1568 | { | 1446 | { |
1569 | BUG_ON(plane == OMAP_DSS_GFX); | 1447 | BUG_ON(plane == OMAP_DSS_GFX); |
1570 | 1448 | ||
1571 | dispc_ovl_set_scaling_common(plane, | 1449 | _dispc_set_scaling_common(plane, |
1572 | orig_width, orig_height, | 1450 | orig_width, orig_height, |
1573 | out_width, out_height, | 1451 | out_width, out_height, |
1574 | ilace, five_taps, | 1452 | ilace, five_taps, |
1575 | fieldmode, color_mode, | 1453 | fieldmode, color_mode, |
1576 | rotation); | 1454 | rotation); |
1577 | 1455 | ||
1578 | dispc_ovl_set_scaling_uv(plane, | 1456 | _dispc_set_scaling_uv(plane, |
1579 | orig_width, orig_height, | 1457 | orig_width, orig_height, |
1580 | out_width, out_height, | 1458 | out_width, out_height, |
1581 | ilace, five_taps, | 1459 | ilace, five_taps, |
@@ -1583,7 +1461,7 @@ static void dispc_ovl_set_scaling(enum omap_plane plane, | |||
1583 | rotation); | 1461 | rotation); |
1584 | } | 1462 | } |
1585 | 1463 | ||
1586 | static void dispc_ovl_set_rotation_attrs(enum omap_plane plane, u8 rotation, | 1464 | static void _dispc_set_rotation_attrs(enum omap_plane plane, u8 rotation, |
1587 | bool mirroring, enum omap_color_mode color_mode) | 1465 | bool mirroring, enum omap_color_mode color_mode) |
1588 | { | 1466 | { |
1589 | bool row_repeat = false; | 1467 | bool row_repeat = false; |
@@ -1667,7 +1545,6 @@ static int color_mode_to_bpp(enum omap_color_mode color_mode) | |||
1667 | return 32; | 1545 | return 32; |
1668 | default: | 1546 | default: |
1669 | BUG(); | 1547 | BUG(); |
1670 | return 0; | ||
1671 | } | 1548 | } |
1672 | } | 1549 | } |
1673 | 1550 | ||
@@ -1681,7 +1558,6 @@ static s32 pixinc(int pixels, u8 ps) | |||
1681 | return 1 - (-pixels + 1) * ps; | 1558 | return 1 - (-pixels + 1) * ps; |
1682 | else | 1559 | else |
1683 | BUG(); | 1560 | BUG(); |
1684 | return 0; | ||
1685 | } | 1561 | } |
1686 | 1562 | ||
1687 | static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | 1563 | static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, |
@@ -1690,7 +1566,7 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | |||
1690 | enum omap_color_mode color_mode, bool fieldmode, | 1566 | enum omap_color_mode color_mode, bool fieldmode, |
1691 | unsigned int field_offset, | 1567 | unsigned int field_offset, |
1692 | unsigned *offset0, unsigned *offset1, | 1568 | unsigned *offset0, unsigned *offset1, |
1693 | s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) | 1569 | s32 *row_inc, s32 *pix_inc) |
1694 | { | 1570 | { |
1695 | u8 ps; | 1571 | u8 ps; |
1696 | 1572 | ||
@@ -1736,10 +1612,10 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | |||
1736 | else | 1612 | else |
1737 | *offset0 = 0; | 1613 | *offset0 = 0; |
1738 | 1614 | ||
1739 | *row_inc = pixinc(1 + | 1615 | *row_inc = pixinc(1 + (screen_width - width) + |
1740 | (y_predecim * screen_width - x_predecim * width) + | 1616 | (fieldmode ? screen_width : 0), |
1741 | (fieldmode ? screen_width : 0), ps); | 1617 | ps); |
1742 | *pix_inc = pixinc(x_predecim, ps); | 1618 | *pix_inc = pixinc(1, ps); |
1743 | break; | 1619 | break; |
1744 | 1620 | ||
1745 | case OMAP_DSS_ROT_0 + 4: | 1621 | case OMAP_DSS_ROT_0 + 4: |
@@ -1757,15 +1633,14 @@ static void calc_vrfb_rotation_offset(u8 rotation, bool mirror, | |||
1757 | *offset0 = field_offset * screen_width * ps; | 1633 | *offset0 = field_offset * screen_width * ps; |
1758 | else | 1634 | else |
1759 | *offset0 = 0; | 1635 | *offset0 = 0; |
1760 | *row_inc = pixinc(1 - | 1636 | *row_inc = pixinc(1 - (screen_width + width) - |
1761 | (y_predecim * screen_width + x_predecim * width) - | 1637 | (fieldmode ? screen_width : 0), |
1762 | (fieldmode ? screen_width : 0), ps); | 1638 | ps); |
1763 | *pix_inc = pixinc(x_predecim, ps); | 1639 | *pix_inc = pixinc(1, ps); |
1764 | break; | 1640 | break; |
1765 | 1641 | ||
1766 | default: | 1642 | default: |
1767 | BUG(); | 1643 | BUG(); |
1768 | return; | ||
1769 | } | 1644 | } |
1770 | } | 1645 | } |
1771 | 1646 | ||
@@ -1775,7 +1650,7 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1775 | enum omap_color_mode color_mode, bool fieldmode, | 1650 | enum omap_color_mode color_mode, bool fieldmode, |
1776 | unsigned int field_offset, | 1651 | unsigned int field_offset, |
1777 | unsigned *offset0, unsigned *offset1, | 1652 | unsigned *offset0, unsigned *offset1, |
1778 | s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) | 1653 | s32 *row_inc, s32 *pix_inc) |
1779 | { | 1654 | { |
1780 | u8 ps; | 1655 | u8 ps; |
1781 | u16 fbw, fbh; | 1656 | u16 fbw, fbh; |
@@ -1817,14 +1692,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1817 | *offset0 = *offset1 + field_offset * screen_width * ps; | 1692 | *offset0 = *offset1 + field_offset * screen_width * ps; |
1818 | else | 1693 | else |
1819 | *offset0 = *offset1; | 1694 | *offset0 = *offset1; |
1820 | *row_inc = pixinc(1 + | 1695 | *row_inc = pixinc(1 + (screen_width - fbw) + |
1821 | (y_predecim * screen_width - fbw * x_predecim) + | 1696 | (fieldmode ? screen_width : 0), |
1822 | (fieldmode ? screen_width : 0), ps); | 1697 | ps); |
1823 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 1698 | *pix_inc = pixinc(1, ps); |
1824 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
1825 | *pix_inc = pixinc(x_predecim, 2 * ps); | ||
1826 | else | ||
1827 | *pix_inc = pixinc(x_predecim, ps); | ||
1828 | break; | 1699 | break; |
1829 | case OMAP_DSS_ROT_90: | 1700 | case OMAP_DSS_ROT_90: |
1830 | *offset1 = screen_width * (fbh - 1) * ps; | 1701 | *offset1 = screen_width * (fbh - 1) * ps; |
@@ -1832,9 +1703,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1832 | *offset0 = *offset1 + field_offset * ps; | 1703 | *offset0 = *offset1 + field_offset * ps; |
1833 | else | 1704 | else |
1834 | *offset0 = *offset1; | 1705 | *offset0 = *offset1; |
1835 | *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) + | 1706 | *row_inc = pixinc(screen_width * (fbh - 1) + 1 + |
1836 | y_predecim + (fieldmode ? 1 : 0), ps); | 1707 | (fieldmode ? 1 : 0), ps); |
1837 | *pix_inc = pixinc(-x_predecim * screen_width, ps); | 1708 | *pix_inc = pixinc(-screen_width, ps); |
1838 | break; | 1709 | break; |
1839 | case OMAP_DSS_ROT_180: | 1710 | case OMAP_DSS_ROT_180: |
1840 | *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps; | 1711 | *offset1 = (screen_width * (fbh - 1) + fbw - 1) * ps; |
@@ -1843,13 +1714,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1843 | else | 1714 | else |
1844 | *offset0 = *offset1; | 1715 | *offset0 = *offset1; |
1845 | *row_inc = pixinc(-1 - | 1716 | *row_inc = pixinc(-1 - |
1846 | (y_predecim * screen_width - fbw * x_predecim) - | 1717 | (screen_width - fbw) - |
1847 | (fieldmode ? screen_width : 0), ps); | 1718 | (fieldmode ? screen_width : 0), |
1848 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 1719 | ps); |
1849 | color_mode == OMAP_DSS_COLOR_UYVY) | 1720 | *pix_inc = pixinc(-1, ps); |
1850 | *pix_inc = pixinc(-x_predecim, 2 * ps); | ||
1851 | else | ||
1852 | *pix_inc = pixinc(-x_predecim, ps); | ||
1853 | break; | 1721 | break; |
1854 | case OMAP_DSS_ROT_270: | 1722 | case OMAP_DSS_ROT_270: |
1855 | *offset1 = (fbw - 1) * ps; | 1723 | *offset1 = (fbw - 1) * ps; |
@@ -1857,9 +1725,9 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1857 | *offset0 = *offset1 - field_offset * ps; | 1725 | *offset0 = *offset1 - field_offset * ps; |
1858 | else | 1726 | else |
1859 | *offset0 = *offset1; | 1727 | *offset0 = *offset1; |
1860 | *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) - | 1728 | *row_inc = pixinc(-screen_width * (fbh - 1) - 1 - |
1861 | y_predecim - (fieldmode ? 1 : 0), ps); | 1729 | (fieldmode ? 1 : 0), ps); |
1862 | *pix_inc = pixinc(x_predecim * screen_width, ps); | 1730 | *pix_inc = pixinc(screen_width, ps); |
1863 | break; | 1731 | break; |
1864 | 1732 | ||
1865 | /* mirroring */ | 1733 | /* mirroring */ |
@@ -1869,14 +1737,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1869 | *offset0 = *offset1 + field_offset * screen_width * ps; | 1737 | *offset0 = *offset1 + field_offset * screen_width * ps; |
1870 | else | 1738 | else |
1871 | *offset0 = *offset1; | 1739 | *offset0 = *offset1; |
1872 | *row_inc = pixinc(y_predecim * screen_width * 2 - 1 + | 1740 | *row_inc = pixinc(screen_width * 2 - 1 + |
1873 | (fieldmode ? screen_width : 0), | 1741 | (fieldmode ? screen_width : 0), |
1874 | ps); | 1742 | ps); |
1875 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 1743 | *pix_inc = pixinc(-1, ps); |
1876 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
1877 | *pix_inc = pixinc(-x_predecim, 2 * ps); | ||
1878 | else | ||
1879 | *pix_inc = pixinc(-x_predecim, ps); | ||
1880 | break; | 1744 | break; |
1881 | 1745 | ||
1882 | case OMAP_DSS_ROT_90 + 4: | 1746 | case OMAP_DSS_ROT_90 + 4: |
@@ -1885,10 +1749,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1885 | *offset0 = *offset1 + field_offset * ps; | 1749 | *offset0 = *offset1 + field_offset * ps; |
1886 | else | 1750 | else |
1887 | *offset0 = *offset1; | 1751 | *offset0 = *offset1; |
1888 | *row_inc = pixinc(-screen_width * (fbh * x_predecim - 1) + | 1752 | *row_inc = pixinc(-screen_width * (fbh - 1) + 1 + |
1889 | y_predecim + (fieldmode ? 1 : 0), | 1753 | (fieldmode ? 1 : 0), |
1890 | ps); | 1754 | ps); |
1891 | *pix_inc = pixinc(x_predecim * screen_width, ps); | 1755 | *pix_inc = pixinc(screen_width, ps); |
1892 | break; | 1756 | break; |
1893 | 1757 | ||
1894 | case OMAP_DSS_ROT_180 + 4: | 1758 | case OMAP_DSS_ROT_180 + 4: |
@@ -1897,14 +1761,10 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1897 | *offset0 = *offset1 - field_offset * screen_width * ps; | 1761 | *offset0 = *offset1 - field_offset * screen_width * ps; |
1898 | else | 1762 | else |
1899 | *offset0 = *offset1; | 1763 | *offset0 = *offset1; |
1900 | *row_inc = pixinc(1 - y_predecim * screen_width * 2 - | 1764 | *row_inc = pixinc(1 - screen_width * 2 - |
1901 | (fieldmode ? screen_width : 0), | 1765 | (fieldmode ? screen_width : 0), |
1902 | ps); | 1766 | ps); |
1903 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 1767 | *pix_inc = pixinc(1, ps); |
1904 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
1905 | *pix_inc = pixinc(x_predecim, 2 * ps); | ||
1906 | else | ||
1907 | *pix_inc = pixinc(x_predecim, ps); | ||
1908 | break; | 1768 | break; |
1909 | 1769 | ||
1910 | case OMAP_DSS_ROT_270 + 4: | 1770 | case OMAP_DSS_ROT_270 + 4: |
@@ -1913,125 +1773,32 @@ static void calc_dma_rotation_offset(u8 rotation, bool mirror, | |||
1913 | *offset0 = *offset1 - field_offset * ps; | 1773 | *offset0 = *offset1 - field_offset * ps; |
1914 | else | 1774 | else |
1915 | *offset0 = *offset1; | 1775 | *offset0 = *offset1; |
1916 | *row_inc = pixinc(screen_width * (fbh * x_predecim - 1) - | 1776 | *row_inc = pixinc(screen_width * (fbh - 1) - 1 - |
1917 | y_predecim - (fieldmode ? 1 : 0), | 1777 | (fieldmode ? 1 : 0), |
1918 | ps); | 1778 | ps); |
1919 | *pix_inc = pixinc(-x_predecim * screen_width, ps); | 1779 | *pix_inc = pixinc(-screen_width, ps); |
1920 | break; | 1780 | break; |
1921 | 1781 | ||
1922 | default: | 1782 | default: |
1923 | BUG(); | 1783 | BUG(); |
1924 | return; | ||
1925 | } | ||
1926 | } | ||
1927 | |||
1928 | static void calc_tiler_rotation_offset(u16 screen_width, u16 width, | ||
1929 | enum omap_color_mode color_mode, bool fieldmode, | ||
1930 | unsigned int field_offset, unsigned *offset0, unsigned *offset1, | ||
1931 | s32 *row_inc, s32 *pix_inc, int x_predecim, int y_predecim) | ||
1932 | { | ||
1933 | u8 ps; | ||
1934 | |||
1935 | switch (color_mode) { | ||
1936 | case OMAP_DSS_COLOR_CLUT1: | ||
1937 | case OMAP_DSS_COLOR_CLUT2: | ||
1938 | case OMAP_DSS_COLOR_CLUT4: | ||
1939 | case OMAP_DSS_COLOR_CLUT8: | ||
1940 | BUG(); | ||
1941 | return; | ||
1942 | default: | ||
1943 | ps = color_mode_to_bpp(color_mode) / 8; | ||
1944 | break; | ||
1945 | } | 1784 | } |
1946 | |||
1947 | DSSDBG("scrw %d, width %d\n", screen_width, width); | ||
1948 | |||
1949 | /* | ||
1950 | * field 0 = even field = bottom field | ||
1951 | * field 1 = odd field = top field | ||
1952 | */ | ||
1953 | *offset1 = 0; | ||
1954 | if (field_offset) | ||
1955 | *offset0 = *offset1 + field_offset * screen_width * ps; | ||
1956 | else | ||
1957 | *offset0 = *offset1; | ||
1958 | *row_inc = pixinc(1 + (y_predecim * screen_width - width * x_predecim) + | ||
1959 | (fieldmode ? screen_width : 0), ps); | ||
1960 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | ||
1961 | color_mode == OMAP_DSS_COLOR_UYVY) | ||
1962 | *pix_inc = pixinc(x_predecim, 2 * ps); | ||
1963 | else | ||
1964 | *pix_inc = pixinc(x_predecim, ps); | ||
1965 | } | ||
1966 | |||
1967 | /* | ||
1968 | * This function is used to avoid synclosts in OMAP3, because of some | ||
1969 | * undocumented horizontal position and timing related limitations. | ||
1970 | */ | ||
1971 | static int check_horiz_timing_omap3(unsigned long pclk, unsigned long lclk, | ||
1972 | const struct omap_video_timings *t, u16 pos_x, | ||
1973 | u16 width, u16 height, u16 out_width, u16 out_height) | ||
1974 | { | ||
1975 | const int ds = DIV_ROUND_UP(height, out_height); | ||
1976 | unsigned long nonactive; | ||
1977 | static const u8 limits[3] = { 8, 10, 20 }; | ||
1978 | u64 val, blank; | ||
1979 | int i; | ||
1980 | |||
1981 | nonactive = t->x_res + t->hfp + t->hsw + t->hbp - out_width; | ||
1982 | |||
1983 | i = 0; | ||
1984 | if (out_height < height) | ||
1985 | i++; | ||
1986 | if (out_width < width) | ||
1987 | i++; | ||
1988 | blank = div_u64((u64)(t->hbp + t->hsw + t->hfp) * lclk, pclk); | ||
1989 | DSSDBG("blanking period + ppl = %llu (limit = %u)\n", blank, limits[i]); | ||
1990 | if (blank <= limits[i]) | ||
1991 | return -EINVAL; | ||
1992 | |||
1993 | /* | ||
1994 | * Pixel data should be prepared before visible display point starts. | ||
1995 | * So, atleast DS-2 lines must have already been fetched by DISPC | ||
1996 | * during nonactive - pos_x period. | ||
1997 | */ | ||
1998 | val = div_u64((u64)(nonactive - pos_x) * lclk, pclk); | ||
1999 | DSSDBG("(nonactive - pos_x) * pcd = %llu max(0, DS - 2) * width = %d\n", | ||
2000 | val, max(0, ds - 2) * width); | ||
2001 | if (val < max(0, ds - 2) * width) | ||
2002 | return -EINVAL; | ||
2003 | |||
2004 | /* | ||
2005 | * All lines need to be refilled during the nonactive period of which | ||
2006 | * only one line can be loaded during the active period. So, atleast | ||
2007 | * DS - 1 lines should be loaded during nonactive period. | ||
2008 | */ | ||
2009 | val = div_u64((u64)nonactive * lclk, pclk); | ||
2010 | DSSDBG("nonactive * pcd = %llu, max(0, DS - 1) * width = %d\n", | ||
2011 | val, max(0, ds - 1) * width); | ||
2012 | if (val < max(0, ds - 1) * width) | ||
2013 | return -EINVAL; | ||
2014 | |||
2015 | return 0; | ||
2016 | } | 1785 | } |
2017 | 1786 | ||
2018 | static unsigned long calc_core_clk_five_taps(unsigned long pclk, | 1787 | static unsigned long calc_fclk_five_taps(enum omap_channel channel, u16 width, |
2019 | const struct omap_video_timings *mgr_timings, u16 width, | ||
2020 | u16 height, u16 out_width, u16 out_height, | 1788 | u16 height, u16 out_width, u16 out_height, |
2021 | enum omap_color_mode color_mode) | 1789 | enum omap_color_mode color_mode) |
2022 | { | 1790 | { |
2023 | u32 core_clk = 0; | 1791 | u32 fclk = 0; |
2024 | u64 tmp; | 1792 | /* FIXME venc pclk? */ |
2025 | 1793 | u64 tmp, pclk = dispc_pclk_rate(channel); | |
2026 | if (height <= out_height && width <= out_width) | ||
2027 | return (unsigned long) pclk; | ||
2028 | 1794 | ||
2029 | if (height > out_height) { | 1795 | if (height > out_height) { |
2030 | unsigned int ppl = mgr_timings->x_res; | 1796 | /* FIXME get real display PPL */ |
1797 | unsigned int ppl = 800; | ||
2031 | 1798 | ||
2032 | tmp = pclk * height * out_width; | 1799 | tmp = pclk * height * out_width; |
2033 | do_div(tmp, 2 * out_height * ppl); | 1800 | do_div(tmp, 2 * out_height * ppl); |
2034 | core_clk = tmp; | 1801 | fclk = tmp; |
2035 | 1802 | ||
2036 | if (height > 2 * out_height) { | 1803 | if (height > 2 * out_height) { |
2037 | if (ppl == out_width) | 1804 | if (ppl == out_width) |
@@ -2039,33 +1806,24 @@ static unsigned long calc_core_clk_five_taps(unsigned long pclk, | |||
2039 | 1806 | ||
2040 | tmp = pclk * (height - 2 * out_height) * out_width; | 1807 | tmp = pclk * (height - 2 * out_height) * out_width; |
2041 | do_div(tmp, 2 * out_height * (ppl - out_width)); | 1808 | do_div(tmp, 2 * out_height * (ppl - out_width)); |
2042 | core_clk = max_t(u32, core_clk, tmp); | 1809 | fclk = max(fclk, (u32) tmp); |
2043 | } | 1810 | } |
2044 | } | 1811 | } |
2045 | 1812 | ||
2046 | if (width > out_width) { | 1813 | if (width > out_width) { |
2047 | tmp = pclk * width; | 1814 | tmp = pclk * width; |
2048 | do_div(tmp, out_width); | 1815 | do_div(tmp, out_width); |
2049 | core_clk = max_t(u32, core_clk, tmp); | 1816 | fclk = max(fclk, (u32) tmp); |
2050 | 1817 | ||
2051 | if (color_mode == OMAP_DSS_COLOR_RGB24U) | 1818 | if (color_mode == OMAP_DSS_COLOR_RGB24U) |
2052 | core_clk <<= 1; | 1819 | fclk <<= 1; |
2053 | } | 1820 | } |
2054 | 1821 | ||
2055 | return core_clk; | 1822 | return fclk; |
2056 | } | 1823 | } |
2057 | 1824 | ||
2058 | static unsigned long calc_core_clk_24xx(unsigned long pclk, u16 width, | 1825 | static unsigned long calc_fclk(enum omap_channel channel, u16 width, |
2059 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | 1826 | u16 height, u16 out_width, u16 out_height) |
2060 | { | ||
2061 | if (height > out_height && width > out_width) | ||
2062 | return pclk * 4; | ||
2063 | else | ||
2064 | return pclk * 2; | ||
2065 | } | ||
2066 | |||
2067 | static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width, | ||
2068 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | ||
2069 | { | 1827 | { |
2070 | unsigned int hf, vf; | 1828 | unsigned int hf, vf; |
2071 | 1829 | ||
@@ -2082,353 +1840,120 @@ static unsigned long calc_core_clk_34xx(unsigned long pclk, u16 width, | |||
2082 | hf = 2; | 1840 | hf = 2; |
2083 | else | 1841 | else |
2084 | hf = 1; | 1842 | hf = 1; |
1843 | |||
2085 | if (height > out_height) | 1844 | if (height > out_height) |
2086 | vf = 2; | 1845 | vf = 2; |
2087 | else | 1846 | else |
2088 | vf = 1; | 1847 | vf = 1; |
2089 | 1848 | ||
2090 | return pclk * vf * hf; | 1849 | /* FIXME venc pclk? */ |
1850 | return dispc_pclk_rate(channel) * vf * hf; | ||
2091 | } | 1851 | } |
2092 | 1852 | ||
2093 | static unsigned long calc_core_clk_44xx(unsigned long pclk, u16 width, | 1853 | int dispc_setup_plane(enum omap_plane plane, |
2094 | u16 height, u16 out_width, u16 out_height, bool mem_to_mem) | 1854 | u32 paddr, u16 screen_width, |
2095 | { | 1855 | u16 pos_x, u16 pos_y, |
2096 | /* | 1856 | u16 width, u16 height, |
2097 | * If the overlay/writeback is in mem to mem mode, there are no | 1857 | u16 out_width, u16 out_height, |
2098 | * downscaling limitations with respect to pixel clock, return 1 as | 1858 | enum omap_color_mode color_mode, |
2099 | * required core clock to represent that we have sufficient enough | 1859 | bool ilace, |
2100 | * core clock to do maximum downscaling | 1860 | enum omap_dss_rotation_type rotation_type, |
2101 | */ | 1861 | u8 rotation, bool mirror, |
2102 | if (mem_to_mem) | 1862 | u8 global_alpha, u8 pre_mult_alpha, |
2103 | return 1; | 1863 | enum omap_channel channel, u32 puv_addr) |
2104 | 1864 | { | |
2105 | if (width > out_width) | 1865 | const int maxdownscale = cpu_is_omap34xx() ? 4 : 2; |
2106 | return DIV_ROUND_UP(pclk, out_width) * width; | 1866 | bool five_taps = 0; |
2107 | else | ||
2108 | return pclk; | ||
2109 | } | ||
2110 | |||
2111 | static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, | ||
2112 | const struct omap_video_timings *mgr_timings, | ||
2113 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2114 | enum omap_color_mode color_mode, bool *five_taps, | ||
2115 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2116 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2117 | { | ||
2118 | int error; | ||
2119 | u16 in_width, in_height; | ||
2120 | int min_factor = min(*decim_x, *decim_y); | ||
2121 | const int maxsinglelinewidth = | ||
2122 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2123 | |||
2124 | *five_taps = false; | ||
2125 | |||
2126 | do { | ||
2127 | in_height = DIV_ROUND_UP(height, *decim_y); | ||
2128 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2129 | *core_clk = dispc.feat->calc_core_clk(pclk, in_width, | ||
2130 | in_height, out_width, out_height, mem_to_mem); | ||
2131 | error = (in_width > maxsinglelinewidth || !*core_clk || | ||
2132 | *core_clk > dispc_core_clk_rate()); | ||
2133 | if (error) { | ||
2134 | if (*decim_x == *decim_y) { | ||
2135 | *decim_x = min_factor; | ||
2136 | ++*decim_y; | ||
2137 | } else { | ||
2138 | swap(*decim_x, *decim_y); | ||
2139 | if (*decim_x < *decim_y) | ||
2140 | ++*decim_x; | ||
2141 | } | ||
2142 | } | ||
2143 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | ||
2144 | |||
2145 | if (in_width > maxsinglelinewidth) { | ||
2146 | DSSERR("Cannot scale max input width exceeded"); | ||
2147 | return -EINVAL; | ||
2148 | } | ||
2149 | return 0; | ||
2150 | } | ||
2151 | |||
2152 | static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, | ||
2153 | const struct omap_video_timings *mgr_timings, | ||
2154 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2155 | enum omap_color_mode color_mode, bool *five_taps, | ||
2156 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2157 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2158 | { | ||
2159 | int error; | ||
2160 | u16 in_width, in_height; | ||
2161 | int min_factor = min(*decim_x, *decim_y); | ||
2162 | const int maxsinglelinewidth = | ||
2163 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2164 | |||
2165 | do { | ||
2166 | in_height = DIV_ROUND_UP(height, *decim_y); | ||
2167 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2168 | *core_clk = calc_core_clk_five_taps(pclk, mgr_timings, | ||
2169 | in_width, in_height, out_width, out_height, color_mode); | ||
2170 | |||
2171 | error = check_horiz_timing_omap3(pclk, lclk, mgr_timings, | ||
2172 | pos_x, in_width, in_height, out_width, | ||
2173 | out_height); | ||
2174 | |||
2175 | if (in_width > maxsinglelinewidth) | ||
2176 | if (in_height > out_height && | ||
2177 | in_height < out_height * 2) | ||
2178 | *five_taps = false; | ||
2179 | if (!*five_taps) | ||
2180 | *core_clk = dispc.feat->calc_core_clk(pclk, in_width, | ||
2181 | in_height, out_width, out_height, | ||
2182 | mem_to_mem); | ||
2183 | |||
2184 | error = (error || in_width > maxsinglelinewidth * 2 || | ||
2185 | (in_width > maxsinglelinewidth && *five_taps) || | ||
2186 | !*core_clk || *core_clk > dispc_core_clk_rate()); | ||
2187 | if (error) { | ||
2188 | if (*decim_x == *decim_y) { | ||
2189 | *decim_x = min_factor; | ||
2190 | ++*decim_y; | ||
2191 | } else { | ||
2192 | swap(*decim_x, *decim_y); | ||
2193 | if (*decim_x < *decim_y) | ||
2194 | ++*decim_x; | ||
2195 | } | ||
2196 | } | ||
2197 | } while (*decim_x <= *x_predecim && *decim_y <= *y_predecim && error); | ||
2198 | |||
2199 | if (check_horiz_timing_omap3(pclk, lclk, mgr_timings, pos_x, width, | ||
2200 | height, out_width, out_height)){ | ||
2201 | DSSERR("horizontal timing too tight\n"); | ||
2202 | return -EINVAL; | ||
2203 | } | ||
2204 | |||
2205 | if (in_width > (maxsinglelinewidth * 2)) { | ||
2206 | DSSERR("Cannot setup scaling"); | ||
2207 | DSSERR("width exceeds maximum width possible"); | ||
2208 | return -EINVAL; | ||
2209 | } | ||
2210 | |||
2211 | if (in_width > maxsinglelinewidth && *five_taps) { | ||
2212 | DSSERR("cannot setup scaling with five taps"); | ||
2213 | return -EINVAL; | ||
2214 | } | ||
2215 | return 0; | ||
2216 | } | ||
2217 | |||
2218 | static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, | ||
2219 | const struct omap_video_timings *mgr_timings, | ||
2220 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2221 | enum omap_color_mode color_mode, bool *five_taps, | ||
2222 | int *x_predecim, int *y_predecim, int *decim_x, int *decim_y, | ||
2223 | u16 pos_x, unsigned long *core_clk, bool mem_to_mem) | ||
2224 | { | ||
2225 | u16 in_width, in_width_max; | ||
2226 | int decim_x_min = *decim_x; | ||
2227 | u16 in_height = DIV_ROUND_UP(height, *decim_y); | ||
2228 | const int maxsinglelinewidth = | ||
2229 | dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); | ||
2230 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | ||
2231 | |||
2232 | if (mem_to_mem) { | ||
2233 | in_width_max = out_width * maxdownscale; | ||
2234 | } else { | ||
2235 | in_width_max = dispc_core_clk_rate() / | ||
2236 | DIV_ROUND_UP(pclk, out_width); | ||
2237 | } | ||
2238 | |||
2239 | *decim_x = DIV_ROUND_UP(width, in_width_max); | ||
2240 | |||
2241 | *decim_x = *decim_x > decim_x_min ? *decim_x : decim_x_min; | ||
2242 | if (*decim_x > *x_predecim) | ||
2243 | return -EINVAL; | ||
2244 | |||
2245 | do { | ||
2246 | in_width = DIV_ROUND_UP(width, *decim_x); | ||
2247 | } while (*decim_x <= *x_predecim && | ||
2248 | in_width > maxsinglelinewidth && ++*decim_x); | ||
2249 | |||
2250 | if (in_width > maxsinglelinewidth) { | ||
2251 | DSSERR("Cannot scale width exceeds max line width"); | ||
2252 | return -EINVAL; | ||
2253 | } | ||
2254 | |||
2255 | *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, | ||
2256 | out_width, out_height, mem_to_mem); | ||
2257 | return 0; | ||
2258 | } | ||
2259 | |||
2260 | static int dispc_ovl_calc_scaling(unsigned long pclk, unsigned long lclk, | ||
2261 | enum omap_overlay_caps caps, | ||
2262 | const struct omap_video_timings *mgr_timings, | ||
2263 | u16 width, u16 height, u16 out_width, u16 out_height, | ||
2264 | enum omap_color_mode color_mode, bool *five_taps, | ||
2265 | int *x_predecim, int *y_predecim, u16 pos_x, | ||
2266 | enum omap_dss_rotation_type rotation_type, bool mem_to_mem) | ||
2267 | { | ||
2268 | const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); | ||
2269 | const int max_decim_limit = 16; | ||
2270 | unsigned long core_clk = 0; | ||
2271 | int decim_x, decim_y, ret; | ||
2272 | |||
2273 | if (width == out_width && height == out_height) | ||
2274 | return 0; | ||
2275 | |||
2276 | if ((caps & OMAP_DSS_OVL_CAP_SCALE) == 0) | ||
2277 | return -EINVAL; | ||
2278 | |||
2279 | if (mem_to_mem) { | ||
2280 | *x_predecim = *y_predecim = 1; | ||
2281 | } else { | ||
2282 | *x_predecim = max_decim_limit; | ||
2283 | *y_predecim = (rotation_type == OMAP_DSS_ROT_TILER && | ||
2284 | dss_has_feature(FEAT_BURST_2D)) ? | ||
2285 | 2 : max_decim_limit; | ||
2286 | } | ||
2287 | |||
2288 | if (color_mode == OMAP_DSS_COLOR_CLUT1 || | ||
2289 | color_mode == OMAP_DSS_COLOR_CLUT2 || | ||
2290 | color_mode == OMAP_DSS_COLOR_CLUT4 || | ||
2291 | color_mode == OMAP_DSS_COLOR_CLUT8) { | ||
2292 | *x_predecim = 1; | ||
2293 | *y_predecim = 1; | ||
2294 | *five_taps = false; | ||
2295 | return 0; | ||
2296 | } | ||
2297 | |||
2298 | decim_x = DIV_ROUND_UP(DIV_ROUND_UP(width, out_width), maxdownscale); | ||
2299 | decim_y = DIV_ROUND_UP(DIV_ROUND_UP(height, out_height), maxdownscale); | ||
2300 | |||
2301 | if (decim_x > *x_predecim || out_width > width * 8) | ||
2302 | return -EINVAL; | ||
2303 | |||
2304 | if (decim_y > *y_predecim || out_height > height * 8) | ||
2305 | return -EINVAL; | ||
2306 | |||
2307 | ret = dispc.feat->calc_scaling(pclk, lclk, mgr_timings, width, height, | ||
2308 | out_width, out_height, color_mode, five_taps, | ||
2309 | x_predecim, y_predecim, &decim_x, &decim_y, pos_x, &core_clk, | ||
2310 | mem_to_mem); | ||
2311 | if (ret) | ||
2312 | return ret; | ||
2313 | |||
2314 | DSSDBG("required core clk rate = %lu Hz\n", core_clk); | ||
2315 | DSSDBG("current core clk rate = %lu Hz\n", dispc_core_clk_rate()); | ||
2316 | |||
2317 | if (!core_clk || core_clk > dispc_core_clk_rate()) { | ||
2318 | DSSERR("failed to set up scaling, " | ||
2319 | "required core clk rate = %lu Hz, " | ||
2320 | "current core clk rate = %lu Hz\n", | ||
2321 | core_clk, dispc_core_clk_rate()); | ||
2322 | return -EINVAL; | ||
2323 | } | ||
2324 | |||
2325 | *x_predecim = decim_x; | ||
2326 | *y_predecim = decim_y; | ||
2327 | return 0; | ||
2328 | } | ||
2329 | |||
2330 | int dispc_ovl_check(enum omap_plane plane, enum omap_channel channel, | ||
2331 | const struct omap_overlay_info *oi, | ||
2332 | const struct omap_video_timings *timings, | ||
2333 | int *x_predecim, int *y_predecim) | ||
2334 | { | ||
2335 | enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); | ||
2336 | bool five_taps = true; | ||
2337 | bool fieldmode = 0; | ||
2338 | u16 in_height = oi->height; | ||
2339 | u16 in_width = oi->width; | ||
2340 | bool ilace = timings->interlace; | ||
2341 | u16 out_width, out_height; | ||
2342 | int pos_x = oi->pos_x; | ||
2343 | unsigned long pclk = dispc_mgr_pclk_rate(channel); | ||
2344 | unsigned long lclk = dispc_mgr_lclk_rate(channel); | ||
2345 | |||
2346 | out_width = oi->out_width == 0 ? oi->width : oi->out_width; | ||
2347 | out_height = oi->out_height == 0 ? oi->height : oi->out_height; | ||
2348 | |||
2349 | if (ilace && oi->height == out_height) | ||
2350 | fieldmode = 1; | ||
2351 | |||
2352 | if (ilace) { | ||
2353 | if (fieldmode) | ||
2354 | in_height /= 2; | ||
2355 | out_height /= 2; | ||
2356 | |||
2357 | DSSDBG("adjusting for ilace: height %d, out_height %d\n", | ||
2358 | in_height, out_height); | ||
2359 | } | ||
2360 | |||
2361 | if (!dss_feat_color_mode_supported(plane, oi->color_mode)) | ||
2362 | return -EINVAL; | ||
2363 | |||
2364 | return dispc_ovl_calc_scaling(pclk, lclk, caps, timings, in_width, | ||
2365 | in_height, out_width, out_height, oi->color_mode, | ||
2366 | &five_taps, x_predecim, y_predecim, pos_x, | ||
2367 | oi->rotation_type, false); | ||
2368 | } | ||
2369 | EXPORT_SYMBOL(dispc_ovl_check); | ||
2370 | |||
2371 | static int dispc_ovl_setup_common(enum omap_plane plane, | ||
2372 | enum omap_overlay_caps caps, u32 paddr, u32 p_uv_addr, | ||
2373 | u16 screen_width, int pos_x, int pos_y, u16 width, u16 height, | ||
2374 | u16 out_width, u16 out_height, enum omap_color_mode color_mode, | ||
2375 | u8 rotation, bool mirror, u8 zorder, u8 pre_mult_alpha, | ||
2376 | u8 global_alpha, enum omap_dss_rotation_type rotation_type, | ||
2377 | bool replication, const struct omap_video_timings *mgr_timings, | ||
2378 | bool mem_to_mem) | ||
2379 | { | ||
2380 | bool five_taps = true; | ||
2381 | bool fieldmode = 0; | 1867 | bool fieldmode = 0; |
2382 | int r, cconv = 0; | 1868 | int cconv = 0; |
2383 | unsigned offset0, offset1; | 1869 | unsigned offset0, offset1; |
2384 | s32 row_inc; | 1870 | s32 row_inc; |
2385 | s32 pix_inc; | 1871 | s32 pix_inc; |
2386 | u16 frame_width, frame_height; | 1872 | u16 frame_height = height; |
2387 | unsigned int field_offset = 0; | 1873 | unsigned int field_offset = 0; |
2388 | u16 in_height = height; | 1874 | |
2389 | u16 in_width = width; | 1875 | DSSDBG("dispc_setup_plane %d, pa %x, sw %d, %d,%d, %dx%d -> " |
2390 | int x_predecim = 1, y_predecim = 1; | 1876 | "%dx%d, ilace %d, cmode %x, rot %d, mir %d chan %d\n", |
2391 | bool ilace = mgr_timings->interlace; | 1877 | plane, paddr, screen_width, pos_x, pos_y, |
2392 | unsigned long pclk = dispc_plane_pclk_rate(plane); | 1878 | width, height, |
2393 | unsigned long lclk = dispc_plane_lclk_rate(plane); | 1879 | out_width, out_height, |
1880 | ilace, color_mode, | ||
1881 | rotation, mirror, channel); | ||
2394 | 1882 | ||
2395 | if (paddr == 0) | 1883 | if (paddr == 0) |
2396 | return -EINVAL; | 1884 | return -EINVAL; |
2397 | 1885 | ||
2398 | out_width = out_width == 0 ? width : out_width; | ||
2399 | out_height = out_height == 0 ? height : out_height; | ||
2400 | |||
2401 | if (ilace && height == out_height) | 1886 | if (ilace && height == out_height) |
2402 | fieldmode = 1; | 1887 | fieldmode = 1; |
2403 | 1888 | ||
2404 | if (ilace) { | 1889 | if (ilace) { |
2405 | if (fieldmode) | 1890 | if (fieldmode) |
2406 | in_height /= 2; | 1891 | height /= 2; |
2407 | pos_y /= 2; | 1892 | pos_y /= 2; |
2408 | out_height /= 2; | 1893 | out_height /= 2; |
2409 | 1894 | ||
2410 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " | 1895 | DSSDBG("adjusting for ilace: height %d, pos_y %d, " |
2411 | "out_height %d\n", in_height, pos_y, | 1896 | "out_height %d\n", |
2412 | out_height); | 1897 | height, pos_y, out_height); |
2413 | } | 1898 | } |
2414 | 1899 | ||
2415 | if (!dss_feat_color_mode_supported(plane, color_mode)) | 1900 | if (!dss_feat_color_mode_supported(plane, color_mode)) |
2416 | return -EINVAL; | 1901 | return -EINVAL; |
2417 | 1902 | ||
2418 | r = dispc_ovl_calc_scaling(pclk, lclk, caps, mgr_timings, in_width, | 1903 | if (plane == OMAP_DSS_GFX) { |
2419 | in_height, out_width, out_height, color_mode, | 1904 | if (width != out_width || height != out_height) |
2420 | &five_taps, &x_predecim, &y_predecim, pos_x, | 1905 | return -EINVAL; |
2421 | rotation_type, mem_to_mem); | 1906 | } else { |
2422 | if (r) | 1907 | /* video plane */ |
2423 | return r; | ||
2424 | 1908 | ||
2425 | in_width = DIV_ROUND_UP(in_width, x_predecim); | 1909 | unsigned long fclk = 0; |
2426 | in_height = DIV_ROUND_UP(in_height, y_predecim); | ||
2427 | 1910 | ||
2428 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | 1911 | if (out_width < width / maxdownscale || |
1912 | out_width > width * 8) | ||
1913 | return -EINVAL; | ||
1914 | |||
1915 | if (out_height < height / maxdownscale || | ||
1916 | out_height > height * 8) | ||
1917 | return -EINVAL; | ||
1918 | |||
1919 | if (color_mode == OMAP_DSS_COLOR_YUV2 || | ||
2429 | color_mode == OMAP_DSS_COLOR_UYVY || | 1920 | color_mode == OMAP_DSS_COLOR_UYVY || |
2430 | color_mode == OMAP_DSS_COLOR_NV12) | 1921 | color_mode == OMAP_DSS_COLOR_NV12) |
2431 | cconv = 1; | 1922 | cconv = 1; |
1923 | |||
1924 | /* Must use 5-tap filter? */ | ||
1925 | five_taps = height > out_height * 2; | ||
1926 | |||
1927 | if (!five_taps) { | ||
1928 | fclk = calc_fclk(channel, width, height, out_width, | ||
1929 | out_height); | ||
1930 | |||
1931 | /* Try 5-tap filter if 3-tap fclk is too high */ | ||
1932 | if (cpu_is_omap34xx() && height > out_height && | ||
1933 | fclk > dispc_fclk_rate()) | ||
1934 | five_taps = true; | ||
1935 | } | ||
1936 | |||
1937 | if (width > (2048 >> five_taps)) { | ||
1938 | DSSERR("failed to set up scaling, fclk too low\n"); | ||
1939 | return -EINVAL; | ||
1940 | } | ||
1941 | |||
1942 | if (five_taps) | ||
1943 | fclk = calc_fclk_five_taps(channel, width, height, | ||
1944 | out_width, out_height, color_mode); | ||
1945 | |||
1946 | DSSDBG("required fclk rate = %lu Hz\n", fclk); | ||
1947 | DSSDBG("current fclk rate = %lu Hz\n", dispc_fclk_rate()); | ||
1948 | |||
1949 | if (!fclk || fclk > dispc_fclk_rate()) { | ||
1950 | DSSERR("failed to set up scaling, " | ||
1951 | "required fclk rate = %lu Hz, " | ||
1952 | "current fclk rate = %lu Hz\n", | ||
1953 | fclk, dispc_fclk_rate()); | ||
1954 | return -EINVAL; | ||
1955 | } | ||
1956 | } | ||
2432 | 1957 | ||
2433 | if (ilace && !fieldmode) { | 1958 | if (ilace && !fieldmode) { |
2434 | /* | 1959 | /* |
@@ -2438,209 +1963,222 @@ static int dispc_ovl_setup_common(enum omap_plane plane, | |||
2438 | * so the integer part must be added to the base address of the | 1963 | * so the integer part must be added to the base address of the |
2439 | * bottom field. | 1964 | * bottom field. |
2440 | */ | 1965 | */ |
2441 | if (!in_height || in_height == out_height) | 1966 | if (!height || height == out_height) |
2442 | field_offset = 0; | 1967 | field_offset = 0; |
2443 | else | 1968 | else |
2444 | field_offset = in_height / out_height / 2; | 1969 | field_offset = height / out_height / 2; |
2445 | } | 1970 | } |
2446 | 1971 | ||
2447 | /* Fields are independent but interleaved in memory. */ | 1972 | /* Fields are independent but interleaved in memory. */ |
2448 | if (fieldmode) | 1973 | if (fieldmode) |
2449 | field_offset = 1; | 1974 | field_offset = 1; |
2450 | 1975 | ||
2451 | offset0 = 0; | 1976 | if (rotation_type == OMAP_DSS_ROT_DMA) |
2452 | offset1 = 0; | 1977 | calc_dma_rotation_offset(rotation, mirror, |
2453 | row_inc = 0; | 1978 | screen_width, width, frame_height, color_mode, |
2454 | pix_inc = 0; | 1979 | fieldmode, field_offset, |
2455 | 1980 | &offset0, &offset1, &row_inc, &pix_inc); | |
2456 | if (plane == OMAP_DSS_WB) { | ||
2457 | frame_width = out_width; | ||
2458 | frame_height = out_height; | ||
2459 | } else { | ||
2460 | frame_width = in_width; | ||
2461 | frame_height = height; | ||
2462 | } | ||
2463 | |||
2464 | if (rotation_type == OMAP_DSS_ROT_TILER) | ||
2465 | calc_tiler_rotation_offset(screen_width, frame_width, | ||
2466 | color_mode, fieldmode, field_offset, | ||
2467 | &offset0, &offset1, &row_inc, &pix_inc, | ||
2468 | x_predecim, y_predecim); | ||
2469 | else if (rotation_type == OMAP_DSS_ROT_DMA) | ||
2470 | calc_dma_rotation_offset(rotation, mirror, screen_width, | ||
2471 | frame_width, frame_height, | ||
2472 | color_mode, fieldmode, field_offset, | ||
2473 | &offset0, &offset1, &row_inc, &pix_inc, | ||
2474 | x_predecim, y_predecim); | ||
2475 | else | 1981 | else |
2476 | calc_vrfb_rotation_offset(rotation, mirror, | 1982 | calc_vrfb_rotation_offset(rotation, mirror, |
2477 | screen_width, frame_width, frame_height, | 1983 | screen_width, width, frame_height, color_mode, |
2478 | color_mode, fieldmode, field_offset, | 1984 | fieldmode, field_offset, |
2479 | &offset0, &offset1, &row_inc, &pix_inc, | 1985 | &offset0, &offset1, &row_inc, &pix_inc); |
2480 | x_predecim, y_predecim); | ||
2481 | 1986 | ||
2482 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", | 1987 | DSSDBG("offset0 %u, offset1 %u, row_inc %d, pix_inc %d\n", |
2483 | offset0, offset1, row_inc, pix_inc); | 1988 | offset0, offset1, row_inc, pix_inc); |
2484 | 1989 | ||
2485 | dispc_ovl_set_color_mode(plane, color_mode); | 1990 | _dispc_set_color_mode(plane, color_mode); |
2486 | 1991 | ||
2487 | dispc_ovl_configure_burst_type(plane, rotation_type); | 1992 | _dispc_set_plane_ba0(plane, paddr + offset0); |
2488 | 1993 | _dispc_set_plane_ba1(plane, paddr + offset1); | |
2489 | dispc_ovl_set_ba0(plane, paddr + offset0); | ||
2490 | dispc_ovl_set_ba1(plane, paddr + offset1); | ||
2491 | 1994 | ||
2492 | if (OMAP_DSS_COLOR_NV12 == color_mode) { | 1995 | if (OMAP_DSS_COLOR_NV12 == color_mode) { |
2493 | dispc_ovl_set_ba0_uv(plane, p_uv_addr + offset0); | 1996 | _dispc_set_plane_ba0_uv(plane, puv_addr + offset0); |
2494 | dispc_ovl_set_ba1_uv(plane, p_uv_addr + offset1); | 1997 | _dispc_set_plane_ba1_uv(plane, puv_addr + offset1); |
2495 | } | 1998 | } |
2496 | 1999 | ||
2497 | dispc_ovl_set_row_inc(plane, row_inc); | ||
2498 | dispc_ovl_set_pix_inc(plane, pix_inc); | ||
2499 | 2000 | ||
2500 | DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, in_width, | 2001 | _dispc_set_row_inc(plane, row_inc); |
2501 | in_height, out_width, out_height); | 2002 | _dispc_set_pix_inc(plane, pix_inc); |
2003 | |||
2004 | DSSDBG("%d,%d %dx%d -> %dx%d\n", pos_x, pos_y, width, height, | ||
2005 | out_width, out_height); | ||
2502 | 2006 | ||
2503 | dispc_ovl_set_pos(plane, caps, pos_x, pos_y); | 2007 | _dispc_set_plane_pos(plane, pos_x, pos_y); |
2504 | 2008 | ||
2505 | dispc_ovl_set_input_size(plane, in_width, in_height); | 2009 | _dispc_set_pic_size(plane, width, height); |
2506 | 2010 | ||
2507 | if (caps & OMAP_DSS_OVL_CAP_SCALE) { | 2011 | if (plane != OMAP_DSS_GFX) { |
2508 | dispc_ovl_set_scaling(plane, in_width, in_height, out_width, | 2012 | _dispc_set_scaling(plane, width, height, |
2509 | out_height, ilace, five_taps, fieldmode, | 2013 | out_width, out_height, |
2014 | ilace, five_taps, fieldmode, | ||
2510 | color_mode, rotation); | 2015 | color_mode, rotation); |
2511 | dispc_ovl_set_output_size(plane, out_width, out_height); | 2016 | _dispc_set_vid_size(plane, out_width, out_height); |
2512 | dispc_ovl_set_vid_color_conv(plane, cconv); | 2017 | _dispc_set_vid_color_conv(plane, cconv); |
2513 | } | 2018 | } |
2514 | 2019 | ||
2515 | dispc_ovl_set_rotation_attrs(plane, rotation, mirror, color_mode); | 2020 | _dispc_set_rotation_attrs(plane, rotation, mirror, color_mode); |
2516 | |||
2517 | dispc_ovl_set_zorder(plane, caps, zorder); | ||
2518 | dispc_ovl_set_pre_mult_alpha(plane, caps, pre_mult_alpha); | ||
2519 | dispc_ovl_setup_global_alpha(plane, caps, global_alpha); | ||
2520 | 2021 | ||
2521 | dispc_ovl_enable_replication(plane, caps, replication); | 2022 | _dispc_set_pre_mult_alpha(plane, pre_mult_alpha); |
2023 | _dispc_setup_global_alpha(plane, global_alpha); | ||
2522 | 2024 | ||
2523 | return 0; | 2025 | return 0; |
2524 | } | 2026 | } |
2525 | 2027 | ||
2526 | int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi, | 2028 | int dispc_enable_plane(enum omap_plane plane, bool enable) |
2527 | bool replication, const struct omap_video_timings *mgr_timings, | ||
2528 | bool mem_to_mem) | ||
2529 | { | 2029 | { |
2530 | int r; | 2030 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); |
2531 | enum omap_overlay_caps caps = dss_feat_get_overlay_caps(plane); | ||
2532 | enum omap_channel channel; | ||
2533 | 2031 | ||
2534 | channel = dispc_ovl_get_channel_out(plane); | 2032 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); |
2535 | 2033 | ||
2536 | DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> " | 2034 | return 0; |
2537 | "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n", | 2035 | } |
2538 | plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x, | ||
2539 | oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height, | ||
2540 | oi->color_mode, oi->rotation, oi->mirror, channel, replication); | ||
2541 | 2036 | ||
2542 | r = dispc_ovl_setup_common(plane, caps, oi->paddr, oi->p_uv_addr, | 2037 | static void dispc_disable_isr(void *data, u32 mask) |
2543 | oi->screen_width, oi->pos_x, oi->pos_y, oi->width, oi->height, | 2038 | { |
2544 | oi->out_width, oi->out_height, oi->color_mode, oi->rotation, | 2039 | struct completion *compl = data; |
2545 | oi->mirror, oi->zorder, oi->pre_mult_alpha, oi->global_alpha, | 2040 | complete(compl); |
2546 | oi->rotation_type, replication, mgr_timings, mem_to_mem); | 2041 | } |
2547 | 2042 | ||
2548 | return r; | 2043 | static void _enable_lcd_out(enum omap_channel channel, bool enable) |
2044 | { | ||
2045 | if (channel == OMAP_DSS_CHANNEL_LCD2) | ||
2046 | REG_FLD_MOD(DISPC_CONTROL2, enable ? 1 : 0, 0, 0); | ||
2047 | else | ||
2048 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 0, 0); | ||
2549 | } | 2049 | } |
2550 | EXPORT_SYMBOL(dispc_ovl_setup); | ||
2551 | 2050 | ||
2552 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | 2051 | static void dispc_enable_lcd_out(enum omap_channel channel, bool enable) |
2553 | bool mem_to_mem, const struct omap_video_timings *mgr_timings) | ||
2554 | { | 2052 | { |
2053 | struct completion frame_done_completion; | ||
2054 | bool is_on; | ||
2555 | int r; | 2055 | int r; |
2556 | u32 l; | 2056 | u32 irq; |
2557 | enum omap_plane plane = OMAP_DSS_WB; | ||
2558 | const int pos_x = 0, pos_y = 0; | ||
2559 | const u8 zorder = 0, global_alpha = 0; | ||
2560 | const bool replication = false; | ||
2561 | bool truncation; | ||
2562 | int in_width = mgr_timings->x_res; | ||
2563 | int in_height = mgr_timings->y_res; | ||
2564 | enum omap_overlay_caps caps = | ||
2565 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA; | ||
2566 | |||
2567 | DSSDBG("dispc_wb_setup, pa %x, pa_uv %x, %d,%d -> %dx%d, cmode %x, " | ||
2568 | "rot %d, mir %d\n", wi->paddr, wi->p_uv_addr, in_width, | ||
2569 | in_height, wi->width, wi->height, wi->color_mode, wi->rotation, | ||
2570 | wi->mirror); | ||
2571 | |||
2572 | r = dispc_ovl_setup_common(plane, caps, wi->paddr, wi->p_uv_addr, | ||
2573 | wi->buf_width, pos_x, pos_y, in_width, in_height, wi->width, | ||
2574 | wi->height, wi->color_mode, wi->rotation, wi->mirror, zorder, | ||
2575 | wi->pre_mult_alpha, global_alpha, wi->rotation_type, | ||
2576 | replication, mgr_timings, mem_to_mem); | ||
2577 | |||
2578 | switch (wi->color_mode) { | ||
2579 | case OMAP_DSS_COLOR_RGB16: | ||
2580 | case OMAP_DSS_COLOR_RGB24P: | ||
2581 | case OMAP_DSS_COLOR_ARGB16: | ||
2582 | case OMAP_DSS_COLOR_RGBA16: | ||
2583 | case OMAP_DSS_COLOR_RGB12U: | ||
2584 | case OMAP_DSS_COLOR_ARGB16_1555: | ||
2585 | case OMAP_DSS_COLOR_XRGB16_1555: | ||
2586 | case OMAP_DSS_COLOR_RGBX16: | ||
2587 | truncation = true; | ||
2588 | break; | ||
2589 | default: | ||
2590 | truncation = false; | ||
2591 | break; | ||
2592 | } | ||
2593 | 2057 | ||
2594 | /* setup extra DISPC_WB_ATTRIBUTES */ | 2058 | /* When we disable LCD output, we need to wait until frame is done. |
2595 | l = dispc_read_reg(DISPC_OVL_ATTRIBUTES(plane)); | 2059 | * Otherwise the DSS is still working, and turning off the clocks |
2596 | l = FLD_MOD(l, truncation, 10, 10); /* TRUNCATIONENABLE */ | 2060 | * prevents DSS from going to OFF mode */ |
2597 | l = FLD_MOD(l, mem_to_mem, 19, 19); /* WRITEBACKMODE */ | 2061 | is_on = channel == OMAP_DSS_CHANNEL_LCD2 ? |
2598 | dispc_write_reg(DISPC_OVL_ATTRIBUTES(plane), l); | 2062 | REG_GET(DISPC_CONTROL2, 0, 0) : |
2063 | REG_GET(DISPC_CONTROL, 0, 0); | ||
2599 | 2064 | ||
2600 | return r; | 2065 | irq = channel == OMAP_DSS_CHANNEL_LCD2 ? DISPC_IRQ_FRAMEDONE2 : |
2601 | } | 2066 | DISPC_IRQ_FRAMEDONE; |
2602 | 2067 | ||
2603 | int dispc_ovl_enable(enum omap_plane plane, bool enable) | 2068 | if (!enable && is_on) { |
2604 | { | 2069 | init_completion(&frame_done_completion); |
2605 | DSSDBG("dispc_enable_plane %d, %d\n", plane, enable); | ||
2606 | 2070 | ||
2607 | REG_FLD_MOD(DISPC_OVL_ATTRIBUTES(plane), enable ? 1 : 0, 0, 0); | 2071 | r = omap_dispc_register_isr(dispc_disable_isr, |
2072 | &frame_done_completion, irq); | ||
2608 | 2073 | ||
2609 | return 0; | 2074 | if (r) |
2610 | } | 2075 | DSSERR("failed to register FRAMEDONE isr\n"); |
2611 | EXPORT_SYMBOL(dispc_ovl_enable); | 2076 | } |
2612 | 2077 | ||
2613 | bool dispc_ovl_enabled(enum omap_plane plane) | 2078 | _enable_lcd_out(channel, enable); |
2614 | { | 2079 | |
2615 | return REG_GET(DISPC_OVL_ATTRIBUTES(plane), 0, 0); | 2080 | if (!enable && is_on) { |
2081 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
2082 | msecs_to_jiffies(100))) | ||
2083 | DSSERR("timeout waiting for FRAME DONE\n"); | ||
2084 | |||
2085 | r = omap_dispc_unregister_isr(dispc_disable_isr, | ||
2086 | &frame_done_completion, irq); | ||
2087 | |||
2088 | if (r) | ||
2089 | DSSERR("failed to unregister FRAMEDONE isr\n"); | ||
2090 | } | ||
2616 | } | 2091 | } |
2617 | EXPORT_SYMBOL(dispc_ovl_enabled); | ||
2618 | 2092 | ||
2619 | void dispc_mgr_enable(enum omap_channel channel, bool enable) | 2093 | static void _enable_digit_out(bool enable) |
2620 | { | 2094 | { |
2621 | mgr_fld_write(channel, DISPC_MGR_FLD_ENABLE, enable); | 2095 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 1, 1); |
2622 | /* flush posted write */ | ||
2623 | mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); | ||
2624 | } | 2096 | } |
2625 | EXPORT_SYMBOL(dispc_mgr_enable); | ||
2626 | 2097 | ||
2627 | bool dispc_mgr_is_enabled(enum omap_channel channel) | 2098 | static void dispc_enable_digit_out(bool enable) |
2628 | { | 2099 | { |
2629 | return !!mgr_fld_read(channel, DISPC_MGR_FLD_ENABLE); | 2100 | struct completion frame_done_completion; |
2101 | int r; | ||
2102 | |||
2103 | if (REG_GET(DISPC_CONTROL, 1, 1) == enable) | ||
2104 | return; | ||
2105 | |||
2106 | if (enable) { | ||
2107 | unsigned long flags; | ||
2108 | /* When we enable digit output, we'll get an extra digit | ||
2109 | * sync lost interrupt, that we need to ignore */ | ||
2110 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
2111 | dispc.irq_error_mask &= ~DISPC_IRQ_SYNC_LOST_DIGIT; | ||
2112 | _omap_dispc_set_irqs(); | ||
2113 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
2114 | } | ||
2115 | |||
2116 | /* When we disable digit output, we need to wait until fields are done. | ||
2117 | * Otherwise the DSS is still working, and turning off the clocks | ||
2118 | * prevents DSS from going to OFF mode. And when enabling, we need to | ||
2119 | * wait for the extra sync losts */ | ||
2120 | init_completion(&frame_done_completion); | ||
2121 | |||
2122 | r = omap_dispc_register_isr(dispc_disable_isr, &frame_done_completion, | ||
2123 | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD); | ||
2124 | if (r) | ||
2125 | DSSERR("failed to register EVSYNC isr\n"); | ||
2126 | |||
2127 | _enable_digit_out(enable); | ||
2128 | |||
2129 | /* XXX I understand from TRM that we should only wait for the | ||
2130 | * current field to complete. But it seems we have to wait | ||
2131 | * for both fields */ | ||
2132 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
2133 | msecs_to_jiffies(100))) | ||
2134 | DSSERR("timeout waiting for EVSYNC\n"); | ||
2135 | |||
2136 | if (!wait_for_completion_timeout(&frame_done_completion, | ||
2137 | msecs_to_jiffies(100))) | ||
2138 | DSSERR("timeout waiting for EVSYNC\n"); | ||
2139 | |||
2140 | r = omap_dispc_unregister_isr(dispc_disable_isr, | ||
2141 | &frame_done_completion, | ||
2142 | DISPC_IRQ_EVSYNC_EVEN | DISPC_IRQ_EVSYNC_ODD); | ||
2143 | if (r) | ||
2144 | DSSERR("failed to unregister EVSYNC isr\n"); | ||
2145 | |||
2146 | if (enable) { | ||
2147 | unsigned long flags; | ||
2148 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
2149 | dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; | ||
2150 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
2151 | dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; | ||
2152 | dispc_write_reg(DISPC_IRQSTATUS, DISPC_IRQ_SYNC_LOST_DIGIT); | ||
2153 | _omap_dispc_set_irqs(); | ||
2154 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
2155 | } | ||
2630 | } | 2156 | } |
2631 | EXPORT_SYMBOL(dispc_mgr_is_enabled); | ||
2632 | 2157 | ||
2633 | void dispc_wb_enable(bool enable) | 2158 | bool dispc_is_channel_enabled(enum omap_channel channel) |
2634 | { | 2159 | { |
2635 | dispc_ovl_enable(OMAP_DSS_WB, enable); | 2160 | if (channel == OMAP_DSS_CHANNEL_LCD) |
2161 | return !!REG_GET(DISPC_CONTROL, 0, 0); | ||
2162 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
2163 | return !!REG_GET(DISPC_CONTROL, 1, 1); | ||
2164 | else if (channel == OMAP_DSS_CHANNEL_LCD2) | ||
2165 | return !!REG_GET(DISPC_CONTROL2, 0, 0); | ||
2166 | else | ||
2167 | BUG(); | ||
2636 | } | 2168 | } |
2637 | 2169 | ||
2638 | bool dispc_wb_is_enabled(void) | 2170 | void dispc_enable_channel(enum omap_channel channel, bool enable) |
2639 | { | 2171 | { |
2640 | return dispc_ovl_enabled(OMAP_DSS_WB); | 2172 | if (channel == OMAP_DSS_CHANNEL_LCD || |
2173 | channel == OMAP_DSS_CHANNEL_LCD2) | ||
2174 | dispc_enable_lcd_out(channel, enable); | ||
2175 | else if (channel == OMAP_DSS_CHANNEL_DIGIT) | ||
2176 | dispc_enable_digit_out(enable); | ||
2177 | else | ||
2178 | BUG(); | ||
2641 | } | 2179 | } |
2642 | 2180 | ||
2643 | static void dispc_lcd_enable_signal_polarity(bool act_high) | 2181 | void dispc_lcd_enable_signal_polarity(bool act_high) |
2644 | { | 2182 | { |
2645 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) | 2183 | if (!dss_has_feature(FEAT_LCDENABLEPOL)) |
2646 | return; | 2184 | return; |
@@ -2664,15 +2202,38 @@ void dispc_pck_free_enable(bool enable) | |||
2664 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); | 2202 | REG_FLD_MOD(DISPC_CONTROL, enable ? 1 : 0, 27, 27); |
2665 | } | 2203 | } |
2666 | 2204 | ||
2667 | static void dispc_mgr_enable_fifohandcheck(enum omap_channel channel, bool enable) | 2205 | void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable) |
2668 | { | 2206 | { |
2669 | mgr_fld_write(channel, DISPC_MGR_FLD_FIFOHANDCHECK, enable); | 2207 | if (channel == OMAP_DSS_CHANNEL_LCD2) |
2208 | REG_FLD_MOD(DISPC_CONFIG2, enable ? 1 : 0, 16, 16); | ||
2209 | else | ||
2210 | REG_FLD_MOD(DISPC_CONFIG, enable ? 1 : 0, 16, 16); | ||
2670 | } | 2211 | } |
2671 | 2212 | ||
2672 | 2213 | ||
2673 | static void dispc_mgr_set_lcd_type_tft(enum omap_channel channel) | 2214 | void dispc_set_lcd_display_type(enum omap_channel channel, |
2215 | enum omap_lcd_display_type type) | ||
2674 | { | 2216 | { |
2675 | mgr_fld_write(channel, DISPC_MGR_FLD_STNTFT, 1); | 2217 | int mode; |
2218 | |||
2219 | switch (type) { | ||
2220 | case OMAP_DSS_LCD_DISPLAY_STN: | ||
2221 | mode = 0; | ||
2222 | break; | ||
2223 | |||
2224 | case OMAP_DSS_LCD_DISPLAY_TFT: | ||
2225 | mode = 1; | ||
2226 | break; | ||
2227 | |||
2228 | default: | ||
2229 | BUG(); | ||
2230 | return; | ||
2231 | } | ||
2232 | |||
2233 | if (channel == OMAP_DSS_CHANNEL_LCD2) | ||
2234 | REG_FLD_MOD(DISPC_CONTROL2, mode, 3, 3); | ||
2235 | else | ||
2236 | REG_FLD_MOD(DISPC_CONTROL, mode, 3, 3); | ||
2676 | } | 2237 | } |
2677 | 2238 | ||
2678 | void dispc_set_loadmode(enum omap_dss_load_mode mode) | 2239 | void dispc_set_loadmode(enum omap_dss_load_mode mode) |
@@ -2681,53 +2242,116 @@ void dispc_set_loadmode(enum omap_dss_load_mode mode) | |||
2681 | } | 2242 | } |
2682 | 2243 | ||
2683 | 2244 | ||
2684 | static void dispc_mgr_set_default_color(enum omap_channel channel, u32 color) | 2245 | void dispc_set_default_color(enum omap_channel channel, u32 color) |
2685 | { | 2246 | { |
2686 | dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); | 2247 | dispc_write_reg(DISPC_DEFAULT_COLOR(channel), color); |
2687 | } | 2248 | } |
2688 | 2249 | ||
2689 | static void dispc_mgr_set_trans_key(enum omap_channel ch, | 2250 | u32 dispc_get_default_color(enum omap_channel channel) |
2251 | { | ||
2252 | u32 l; | ||
2253 | |||
2254 | BUG_ON(channel != OMAP_DSS_CHANNEL_DIGIT && | ||
2255 | channel != OMAP_DSS_CHANNEL_LCD && | ||
2256 | channel != OMAP_DSS_CHANNEL_LCD2); | ||
2257 | |||
2258 | l = dispc_read_reg(DISPC_DEFAULT_COLOR(channel)); | ||
2259 | |||
2260 | return l; | ||
2261 | } | ||
2262 | |||
2263 | void dispc_set_trans_key(enum omap_channel ch, | ||
2690 | enum omap_dss_trans_key_type type, | 2264 | enum omap_dss_trans_key_type type, |
2691 | u32 trans_key) | 2265 | u32 trans_key) |
2692 | { | 2266 | { |
2693 | mgr_fld_write(ch, DISPC_MGR_FLD_TCKSELECTION, type); | 2267 | if (ch == OMAP_DSS_CHANNEL_LCD) |
2268 | REG_FLD_MOD(DISPC_CONFIG, type, 11, 11); | ||
2269 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2270 | REG_FLD_MOD(DISPC_CONFIG, type, 13, 13); | ||
2271 | else /* OMAP_DSS_CHANNEL_LCD2 */ | ||
2272 | REG_FLD_MOD(DISPC_CONFIG2, type, 11, 11); | ||
2694 | 2273 | ||
2695 | dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); | 2274 | dispc_write_reg(DISPC_TRANS_COLOR(ch), trans_key); |
2696 | } | 2275 | } |
2697 | 2276 | ||
2698 | static void dispc_mgr_enable_trans_key(enum omap_channel ch, bool enable) | 2277 | void dispc_get_trans_key(enum omap_channel ch, |
2278 | enum omap_dss_trans_key_type *type, | ||
2279 | u32 *trans_key) | ||
2699 | { | 2280 | { |
2700 | mgr_fld_write(ch, DISPC_MGR_FLD_TCKENABLE, enable); | 2281 | if (type) { |
2282 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2283 | *type = REG_GET(DISPC_CONFIG, 11, 11); | ||
2284 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2285 | *type = REG_GET(DISPC_CONFIG, 13, 13); | ||
2286 | else if (ch == OMAP_DSS_CHANNEL_LCD2) | ||
2287 | *type = REG_GET(DISPC_CONFIG2, 11, 11); | ||
2288 | else | ||
2289 | BUG(); | ||
2290 | } | ||
2291 | |||
2292 | if (trans_key) | ||
2293 | *trans_key = dispc_read_reg(DISPC_TRANS_COLOR(ch)); | ||
2701 | } | 2294 | } |
2702 | 2295 | ||
2703 | static void dispc_mgr_enable_alpha_fixed_zorder(enum omap_channel ch, | 2296 | void dispc_enable_trans_key(enum omap_channel ch, bool enable) |
2704 | bool enable) | 2297 | { |
2298 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2299 | REG_FLD_MOD(DISPC_CONFIG, enable, 10, 10); | ||
2300 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2301 | REG_FLD_MOD(DISPC_CONFIG, enable, 12, 12); | ||
2302 | else /* OMAP_DSS_CHANNEL_LCD2 */ | ||
2303 | REG_FLD_MOD(DISPC_CONFIG2, enable, 10, 10); | ||
2304 | } | ||
2305 | void dispc_enable_alpha_blending(enum omap_channel ch, bool enable) | ||
2705 | { | 2306 | { |
2706 | if (!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) | 2307 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) |
2707 | return; | 2308 | return; |
2708 | 2309 | ||
2709 | if (ch == OMAP_DSS_CHANNEL_LCD) | 2310 | if (ch == OMAP_DSS_CHANNEL_LCD) |
2710 | REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); | 2311 | REG_FLD_MOD(DISPC_CONFIG, enable, 18, 18); |
2711 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | 2312 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) |
2712 | REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); | 2313 | REG_FLD_MOD(DISPC_CONFIG, enable, 19, 19); |
2314 | else /* OMAP_DSS_CHANNEL_LCD2 */ | ||
2315 | REG_FLD_MOD(DISPC_CONFIG2, enable, 18, 18); | ||
2316 | } | ||
2317 | bool dispc_alpha_blending_enabled(enum omap_channel ch) | ||
2318 | { | ||
2319 | bool enabled; | ||
2320 | |||
2321 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) | ||
2322 | return false; | ||
2323 | |||
2324 | if (ch == OMAP_DSS_CHANNEL_LCD) | ||
2325 | enabled = REG_GET(DISPC_CONFIG, 18, 18); | ||
2326 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) | ||
2327 | enabled = REG_GET(DISPC_CONFIG, 19, 19); | ||
2328 | else if (ch == OMAP_DSS_CHANNEL_LCD2) | ||
2329 | enabled = REG_GET(DISPC_CONFIG2, 18, 18); | ||
2330 | else | ||
2331 | BUG(); | ||
2332 | |||
2333 | return enabled; | ||
2713 | } | 2334 | } |
2714 | 2335 | ||
2715 | void dispc_mgr_setup(enum omap_channel channel, | 2336 | |
2716 | const struct omap_overlay_manager_info *info) | 2337 | bool dispc_trans_key_enabled(enum omap_channel ch) |
2717 | { | 2338 | { |
2718 | dispc_mgr_set_default_color(channel, info->default_color); | 2339 | bool enabled; |
2719 | dispc_mgr_set_trans_key(channel, info->trans_key_type, info->trans_key); | 2340 | |
2720 | dispc_mgr_enable_trans_key(channel, info->trans_enabled); | 2341 | if (ch == OMAP_DSS_CHANNEL_LCD) |
2721 | dispc_mgr_enable_alpha_fixed_zorder(channel, | 2342 | enabled = REG_GET(DISPC_CONFIG, 10, 10); |
2722 | info->partial_alpha_enabled); | 2343 | else if (ch == OMAP_DSS_CHANNEL_DIGIT) |
2723 | if (dss_has_feature(FEAT_CPR)) { | 2344 | enabled = REG_GET(DISPC_CONFIG, 12, 12); |
2724 | dispc_mgr_enable_cpr(channel, info->cpr_enable); | 2345 | else if (ch == OMAP_DSS_CHANNEL_LCD2) |
2725 | dispc_mgr_set_cpr_coef(channel, &info->cpr_coefs); | 2346 | enabled = REG_GET(DISPC_CONFIG2, 10, 10); |
2726 | } | 2347 | else |
2348 | BUG(); | ||
2349 | |||
2350 | return enabled; | ||
2727 | } | 2351 | } |
2728 | EXPORT_SYMBOL(dispc_mgr_setup); | ||
2729 | 2352 | ||
2730 | static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_lines) | 2353 | |
2354 | void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines) | ||
2731 | { | 2355 | { |
2732 | int code; | 2356 | int code; |
2733 | 2357 | ||
@@ -2749,211 +2373,153 @@ static void dispc_mgr_set_tft_data_lines(enum omap_channel channel, u8 data_line | |||
2749 | return; | 2373 | return; |
2750 | } | 2374 | } |
2751 | 2375 | ||
2752 | mgr_fld_write(channel, DISPC_MGR_FLD_TFTDATALINES, code); | 2376 | if (channel == OMAP_DSS_CHANNEL_LCD2) |
2377 | REG_FLD_MOD(DISPC_CONTROL2, code, 9, 8); | ||
2378 | else | ||
2379 | REG_FLD_MOD(DISPC_CONTROL, code, 9, 8); | ||
2753 | } | 2380 | } |
2754 | 2381 | ||
2755 | static void dispc_mgr_set_io_pad_mode(enum dss_io_pad_mode mode) | 2382 | void dispc_set_parallel_interface_mode(enum omap_channel channel, |
2383 | enum omap_parallel_interface_mode mode) | ||
2756 | { | 2384 | { |
2757 | u32 l; | 2385 | u32 l; |
2758 | int gpout0, gpout1; | 2386 | int stallmode; |
2387 | int gpout0 = 1; | ||
2388 | int gpout1; | ||
2759 | 2389 | ||
2760 | switch (mode) { | 2390 | switch (mode) { |
2761 | case DSS_IO_PAD_MODE_RESET: | 2391 | case OMAP_DSS_PARALLELMODE_BYPASS: |
2762 | gpout0 = 0; | 2392 | stallmode = 0; |
2763 | gpout1 = 0; | 2393 | gpout1 = 1; |
2764 | break; | 2394 | break; |
2765 | case DSS_IO_PAD_MODE_RFBI: | 2395 | |
2766 | gpout0 = 1; | 2396 | case OMAP_DSS_PARALLELMODE_RFBI: |
2397 | stallmode = 1; | ||
2767 | gpout1 = 0; | 2398 | gpout1 = 0; |
2768 | break; | 2399 | break; |
2769 | case DSS_IO_PAD_MODE_BYPASS: | 2400 | |
2770 | gpout0 = 1; | 2401 | case OMAP_DSS_PARALLELMODE_DSI: |
2402 | stallmode = 1; | ||
2771 | gpout1 = 1; | 2403 | gpout1 = 1; |
2772 | break; | 2404 | break; |
2405 | |||
2773 | default: | 2406 | default: |
2774 | BUG(); | 2407 | BUG(); |
2775 | return; | 2408 | return; |
2776 | } | 2409 | } |
2777 | 2410 | ||
2778 | l = dispc_read_reg(DISPC_CONTROL); | 2411 | if (channel == OMAP_DSS_CHANNEL_LCD2) { |
2779 | l = FLD_MOD(l, gpout0, 15, 15); | 2412 | l = dispc_read_reg(DISPC_CONTROL2); |
2780 | l = FLD_MOD(l, gpout1, 16, 16); | 2413 | l = FLD_MOD(l, stallmode, 11, 11); |
2781 | dispc_write_reg(DISPC_CONTROL, l); | 2414 | dispc_write_reg(DISPC_CONTROL2, l); |
2782 | } | 2415 | } else { |
2783 | 2416 | l = dispc_read_reg(DISPC_CONTROL); | |
2784 | static void dispc_mgr_enable_stallmode(enum omap_channel channel, bool enable) | 2417 | l = FLD_MOD(l, stallmode, 11, 11); |
2785 | { | 2418 | l = FLD_MOD(l, gpout0, 15, 15); |
2786 | mgr_fld_write(channel, DISPC_MGR_FLD_STALLMODE, enable); | 2419 | l = FLD_MOD(l, gpout1, 16, 16); |
2787 | } | 2420 | dispc_write_reg(DISPC_CONTROL, l); |
2788 | 2421 | } | |
2789 | void dispc_mgr_set_lcd_config(enum omap_channel channel, | ||
2790 | const struct dss_lcd_mgr_config *config) | ||
2791 | { | ||
2792 | dispc_mgr_set_io_pad_mode(config->io_pad_mode); | ||
2793 | |||
2794 | dispc_mgr_enable_stallmode(channel, config->stallmode); | ||
2795 | dispc_mgr_enable_fifohandcheck(channel, config->fifohandcheck); | ||
2796 | |||
2797 | dispc_mgr_set_clock_div(channel, &config->clock_info); | ||
2798 | |||
2799 | dispc_mgr_set_tft_data_lines(channel, config->video_port_width); | ||
2800 | |||
2801 | dispc_lcd_enable_signal_polarity(config->lcden_sig_polarity); | ||
2802 | |||
2803 | dispc_mgr_set_lcd_type_tft(channel); | ||
2804 | } | ||
2805 | EXPORT_SYMBOL(dispc_mgr_set_lcd_config); | ||
2806 | |||
2807 | static bool _dispc_mgr_size_ok(u16 width, u16 height) | ||
2808 | { | ||
2809 | return width <= dispc.feat->mgr_width_max && | ||
2810 | height <= dispc.feat->mgr_height_max; | ||
2811 | } | 2422 | } |
2812 | 2423 | ||
2813 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, | 2424 | static bool _dispc_lcd_timings_ok(int hsw, int hfp, int hbp, |
2814 | int vsw, int vfp, int vbp) | 2425 | int vsw, int vfp, int vbp) |
2815 | { | 2426 | { |
2816 | if (hsw < 1 || hsw > dispc.feat->sw_max || | 2427 | if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { |
2817 | hfp < 1 || hfp > dispc.feat->hp_max || | 2428 | if (hsw < 1 || hsw > 64 || |
2818 | hbp < 1 || hbp > dispc.feat->hp_max || | 2429 | hfp < 1 || hfp > 256 || |
2819 | vsw < 1 || vsw > dispc.feat->sw_max || | 2430 | hbp < 1 || hbp > 256 || |
2820 | vfp < 0 || vfp > dispc.feat->vp_max || | 2431 | vsw < 1 || vsw > 64 || |
2821 | vbp < 0 || vbp > dispc.feat->vp_max) | 2432 | vfp < 0 || vfp > 255 || |
2822 | return false; | 2433 | vbp < 0 || vbp > 255) |
2434 | return false; | ||
2435 | } else { | ||
2436 | if (hsw < 1 || hsw > 256 || | ||
2437 | hfp < 1 || hfp > 4096 || | ||
2438 | hbp < 1 || hbp > 4096 || | ||
2439 | vsw < 1 || vsw > 256 || | ||
2440 | vfp < 0 || vfp > 4095 || | ||
2441 | vbp < 0 || vbp > 4095) | ||
2442 | return false; | ||
2443 | } | ||
2444 | |||
2823 | return true; | 2445 | return true; |
2824 | } | 2446 | } |
2825 | 2447 | ||
2826 | bool dispc_mgr_timings_ok(enum omap_channel channel, | 2448 | bool dispc_lcd_timings_ok(struct omap_video_timings *timings) |
2827 | const struct omap_video_timings *timings) | ||
2828 | { | 2449 | { |
2829 | bool timings_ok; | 2450 | return _dispc_lcd_timings_ok(timings->hsw, timings->hfp, |
2830 | 2451 | timings->hbp, timings->vsw, | |
2831 | timings_ok = _dispc_mgr_size_ok(timings->x_res, timings->y_res); | 2452 | timings->vfp, timings->vbp); |
2832 | |||
2833 | if (dss_mgr_is_lcd(channel)) | ||
2834 | timings_ok = timings_ok && _dispc_lcd_timings_ok(timings->hsw, | ||
2835 | timings->hfp, timings->hbp, | ||
2836 | timings->vsw, timings->vfp, | ||
2837 | timings->vbp); | ||
2838 | |||
2839 | return timings_ok; | ||
2840 | } | 2453 | } |
2841 | 2454 | ||
2842 | static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw, | 2455 | static void _dispc_set_lcd_timings(enum omap_channel channel, int hsw, |
2843 | int hfp, int hbp, int vsw, int vfp, int vbp, | 2456 | int hfp, int hbp, int vsw, int vfp, int vbp) |
2844 | enum omap_dss_signal_level vsync_level, | ||
2845 | enum omap_dss_signal_level hsync_level, | ||
2846 | enum omap_dss_signal_edge data_pclk_edge, | ||
2847 | enum omap_dss_signal_level de_level, | ||
2848 | enum omap_dss_signal_edge sync_pclk_edge) | ||
2849 | |||
2850 | { | 2457 | { |
2851 | u32 timing_h, timing_v, l; | 2458 | u32 timing_h, timing_v; |
2852 | bool onoff, rf, ipc; | ||
2853 | 2459 | ||
2854 | timing_h = FLD_VAL(hsw-1, dispc.feat->sw_start, 0) | | 2460 | if (cpu_is_omap24xx() || omap_rev() < OMAP3430_REV_ES3_0) { |
2855 | FLD_VAL(hfp-1, dispc.feat->fp_start, 8) | | 2461 | timing_h = FLD_VAL(hsw-1, 5, 0) | FLD_VAL(hfp-1, 15, 8) | |
2856 | FLD_VAL(hbp-1, dispc.feat->bp_start, 20); | 2462 | FLD_VAL(hbp-1, 27, 20); |
2857 | timing_v = FLD_VAL(vsw-1, dispc.feat->sw_start, 0) | | ||
2858 | FLD_VAL(vfp, dispc.feat->fp_start, 8) | | ||
2859 | FLD_VAL(vbp, dispc.feat->bp_start, 20); | ||
2860 | 2463 | ||
2861 | dispc_write_reg(DISPC_TIMING_H(channel), timing_h); | 2464 | timing_v = FLD_VAL(vsw-1, 5, 0) | FLD_VAL(vfp, 15, 8) | |
2862 | dispc_write_reg(DISPC_TIMING_V(channel), timing_v); | 2465 | FLD_VAL(vbp, 27, 20); |
2466 | } else { | ||
2467 | timing_h = FLD_VAL(hsw-1, 7, 0) | FLD_VAL(hfp-1, 19, 8) | | ||
2468 | FLD_VAL(hbp-1, 31, 20); | ||
2863 | 2469 | ||
2864 | switch (data_pclk_edge) { | 2470 | timing_v = FLD_VAL(vsw-1, 7, 0) | FLD_VAL(vfp, 19, 8) | |
2865 | case OMAPDSS_DRIVE_SIG_RISING_EDGE: | 2471 | FLD_VAL(vbp, 31, 20); |
2866 | ipc = false; | ||
2867 | break; | ||
2868 | case OMAPDSS_DRIVE_SIG_FALLING_EDGE: | ||
2869 | ipc = true; | ||
2870 | break; | ||
2871 | case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: | ||
2872 | default: | ||
2873 | BUG(); | ||
2874 | } | 2472 | } |
2875 | 2473 | ||
2876 | switch (sync_pclk_edge) { | 2474 | dispc_write_reg(DISPC_TIMING_H(channel), timing_h); |
2877 | case OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES: | 2475 | dispc_write_reg(DISPC_TIMING_V(channel), timing_v); |
2878 | onoff = false; | ||
2879 | rf = false; | ||
2880 | break; | ||
2881 | case OMAPDSS_DRIVE_SIG_FALLING_EDGE: | ||
2882 | onoff = true; | ||
2883 | rf = false; | ||
2884 | break; | ||
2885 | case OMAPDSS_DRIVE_SIG_RISING_EDGE: | ||
2886 | onoff = true; | ||
2887 | rf = true; | ||
2888 | break; | ||
2889 | default: | ||
2890 | BUG(); | ||
2891 | }; | ||
2892 | |||
2893 | l = dispc_read_reg(DISPC_POL_FREQ(channel)); | ||
2894 | l |= FLD_VAL(onoff, 17, 17); | ||
2895 | l |= FLD_VAL(rf, 16, 16); | ||
2896 | l |= FLD_VAL(de_level, 15, 15); | ||
2897 | l |= FLD_VAL(ipc, 14, 14); | ||
2898 | l |= FLD_VAL(hsync_level, 13, 13); | ||
2899 | l |= FLD_VAL(vsync_level, 12, 12); | ||
2900 | dispc_write_reg(DISPC_POL_FREQ(channel), l); | ||
2901 | } | 2476 | } |
2902 | 2477 | ||
2903 | /* change name to mode? */ | 2478 | /* change name to mode? */ |
2904 | void dispc_mgr_set_timings(enum omap_channel channel, | 2479 | void dispc_set_lcd_timings(enum omap_channel channel, |
2905 | const struct omap_video_timings *timings) | 2480 | struct omap_video_timings *timings) |
2906 | { | 2481 | { |
2907 | unsigned xtot, ytot; | 2482 | unsigned xtot, ytot; |
2908 | unsigned long ht, vt; | 2483 | unsigned long ht, vt; |
2909 | struct omap_video_timings t = *timings; | ||
2910 | |||
2911 | DSSDBG("channel %d xres %u yres %u\n", channel, t.x_res, t.y_res); | ||
2912 | 2484 | ||
2913 | if (!dispc_mgr_timings_ok(channel, &t)) { | 2485 | if (!_dispc_lcd_timings_ok(timings->hsw, timings->hfp, |
2486 | timings->hbp, timings->vsw, | ||
2487 | timings->vfp, timings->vbp)) | ||
2914 | BUG(); | 2488 | BUG(); |
2915 | return; | ||
2916 | } | ||
2917 | 2489 | ||
2918 | if (dss_mgr_is_lcd(channel)) { | 2490 | _dispc_set_lcd_timings(channel, timings->hsw, timings->hfp, |
2919 | _dispc_mgr_set_lcd_timings(channel, t.hsw, t.hfp, t.hbp, t.vsw, | 2491 | timings->hbp, timings->vsw, timings->vfp, |
2920 | t.vfp, t.vbp, t.vsync_level, t.hsync_level, | 2492 | timings->vbp); |
2921 | t.data_pclk_edge, t.de_level, t.sync_pclk_edge); | ||
2922 | 2493 | ||
2923 | xtot = t.x_res + t.hfp + t.hsw + t.hbp; | 2494 | dispc_set_lcd_size(channel, timings->x_res, timings->y_res); |
2924 | ytot = t.y_res + t.vfp + t.vsw + t.vbp; | ||
2925 | 2495 | ||
2926 | ht = (timings->pixel_clock * 1000) / xtot; | 2496 | xtot = timings->x_res + timings->hfp + timings->hsw + timings->hbp; |
2927 | vt = (timings->pixel_clock * 1000) / xtot / ytot; | 2497 | ytot = timings->y_res + timings->vfp + timings->vsw + timings->vbp; |
2928 | 2498 | ||
2929 | DSSDBG("pck %u\n", timings->pixel_clock); | 2499 | ht = (timings->pixel_clock * 1000) / xtot; |
2930 | DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", | 2500 | vt = (timings->pixel_clock * 1000) / xtot / ytot; |
2931 | t.hsw, t.hfp, t.hbp, t.vsw, t.vfp, t.vbp); | ||
2932 | DSSDBG("vsync_level %d hsync_level %d data_pclk_edge %d de_level %d sync_pclk_edge %d\n", | ||
2933 | t.vsync_level, t.hsync_level, t.data_pclk_edge, | ||
2934 | t.de_level, t.sync_pclk_edge); | ||
2935 | 2501 | ||
2936 | DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); | 2502 | DSSDBG("channel %d xres %u yres %u\n", channel, timings->x_res, |
2937 | } else { | 2503 | timings->y_res); |
2938 | if (t.interlace == true) | 2504 | DSSDBG("pck %u\n", timings->pixel_clock); |
2939 | t.y_res /= 2; | 2505 | DSSDBG("hsw %d hfp %d hbp %d vsw %d vfp %d vbp %d\n", |
2940 | } | 2506 | timings->hsw, timings->hfp, timings->hbp, |
2507 | timings->vsw, timings->vfp, timings->vbp); | ||
2941 | 2508 | ||
2942 | dispc_mgr_set_size(channel, t.x_res, t.y_res); | 2509 | DSSDBG("hsync %luHz, vsync %luHz\n", ht, vt); |
2943 | } | 2510 | } |
2944 | EXPORT_SYMBOL(dispc_mgr_set_timings); | ||
2945 | 2511 | ||
2946 | static void dispc_mgr_set_lcd_divisor(enum omap_channel channel, u16 lck_div, | 2512 | static void dispc_set_lcd_divisor(enum omap_channel channel, u16 lck_div, |
2947 | u16 pck_div) | 2513 | u16 pck_div) |
2948 | { | 2514 | { |
2949 | BUG_ON(lck_div < 1); | 2515 | BUG_ON(lck_div < 1); |
2950 | BUG_ON(pck_div < 1); | 2516 | BUG_ON(pck_div < 2); |
2951 | 2517 | ||
2952 | dispc_write_reg(DISPC_DIVISORo(channel), | 2518 | dispc_write_reg(DISPC_DIVISORo(channel), |
2953 | FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); | 2519 | FLD_VAL(lck_div, 23, 16) | FLD_VAL(pck_div, 7, 0)); |
2954 | } | 2520 | } |
2955 | 2521 | ||
2956 | static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div, | 2522 | static void dispc_get_lcd_divisor(enum omap_channel channel, int *lck_div, |
2957 | int *pck_div) | 2523 | int *pck_div) |
2958 | { | 2524 | { |
2959 | u32 l; | 2525 | u32 l; |
@@ -2969,7 +2535,7 @@ unsigned long dispc_fclk_rate(void) | |||
2969 | 2535 | ||
2970 | switch (dss_get_dispc_clk_source()) { | 2536 | switch (dss_get_dispc_clk_source()) { |
2971 | case OMAP_DSS_CLK_SRC_FCK: | 2537 | case OMAP_DSS_CLK_SRC_FCK: |
2972 | r = dss_get_dispc_clk_rate(); | 2538 | r = clk_get_rate(dispc.dss_clk); |
2973 | break; | 2539 | break; |
2974 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | 2540 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
2975 | dsidev = dsi_get_dsidev_from_id(0); | 2541 | dsidev = dsi_get_dsidev_from_id(0); |
@@ -2981,142 +2547,62 @@ unsigned long dispc_fclk_rate(void) | |||
2981 | break; | 2547 | break; |
2982 | default: | 2548 | default: |
2983 | BUG(); | 2549 | BUG(); |
2984 | return 0; | ||
2985 | } | 2550 | } |
2986 | 2551 | ||
2987 | return r; | 2552 | return r; |
2988 | } | 2553 | } |
2989 | 2554 | ||
2990 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel) | 2555 | unsigned long dispc_lclk_rate(enum omap_channel channel) |
2991 | { | 2556 | { |
2992 | struct platform_device *dsidev; | 2557 | struct platform_device *dsidev; |
2993 | int lcd; | 2558 | int lcd; |
2994 | unsigned long r; | 2559 | unsigned long r; |
2995 | u32 l; | 2560 | u32 l; |
2996 | 2561 | ||
2997 | if (dss_mgr_is_lcd(channel)) { | 2562 | l = dispc_read_reg(DISPC_DIVISORo(channel)); |
2998 | l = dispc_read_reg(DISPC_DIVISORo(channel)); | ||
2999 | |||
3000 | lcd = FLD_GET(l, 23, 16); | ||
3001 | |||
3002 | switch (dss_get_lcd_clk_source(channel)) { | ||
3003 | case OMAP_DSS_CLK_SRC_FCK: | ||
3004 | r = dss_get_dispc_clk_rate(); | ||
3005 | break; | ||
3006 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: | ||
3007 | dsidev = dsi_get_dsidev_from_id(0); | ||
3008 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | ||
3009 | break; | ||
3010 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | ||
3011 | dsidev = dsi_get_dsidev_from_id(1); | ||
3012 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | ||
3013 | break; | ||
3014 | default: | ||
3015 | BUG(); | ||
3016 | return 0; | ||
3017 | } | ||
3018 | |||
3019 | return r / lcd; | ||
3020 | } else { | ||
3021 | return dispc_fclk_rate(); | ||
3022 | } | ||
3023 | } | ||
3024 | |||
3025 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel) | ||
3026 | { | ||
3027 | unsigned long r; | ||
3028 | |||
3029 | if (dss_mgr_is_lcd(channel)) { | ||
3030 | int pcd; | ||
3031 | u32 l; | ||
3032 | |||
3033 | l = dispc_read_reg(DISPC_DIVISORo(channel)); | ||
3034 | |||
3035 | pcd = FLD_GET(l, 7, 0); | ||
3036 | |||
3037 | r = dispc_mgr_lclk_rate(channel); | ||
3038 | |||
3039 | return r / pcd; | ||
3040 | } else { | ||
3041 | enum dss_hdmi_venc_clk_source_select source; | ||
3042 | 2563 | ||
3043 | source = dss_get_hdmi_venc_clk_source(); | 2564 | lcd = FLD_GET(l, 23, 16); |
3044 | 2565 | ||
3045 | switch (source) { | 2566 | switch (dss_get_lcd_clk_source(channel)) { |
3046 | case DSS_VENC_TV_CLK: | 2567 | case OMAP_DSS_CLK_SRC_FCK: |
3047 | return venc_get_pixel_clock(); | 2568 | r = clk_get_rate(dispc.dss_clk); |
3048 | case DSS_HDMI_M_PCLK: | 2569 | break; |
3049 | return hdmi_get_pixel_clock(); | 2570 | case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC: |
3050 | default: | 2571 | dsidev = dsi_get_dsidev_from_id(0); |
3051 | BUG(); | 2572 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); |
3052 | return 0; | 2573 | break; |
3053 | } | 2574 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
2575 | dsidev = dsi_get_dsidev_from_id(1); | ||
2576 | r = dsi_get_pll_hsdiv_dispc_rate(dsidev); | ||
2577 | break; | ||
2578 | default: | ||
2579 | BUG(); | ||
3054 | } | 2580 | } |
3055 | } | ||
3056 | |||
3057 | unsigned long dispc_core_clk_rate(void) | ||
3058 | { | ||
3059 | int lcd; | ||
3060 | unsigned long fclk = dispc_fclk_rate(); | ||
3061 | |||
3062 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) | ||
3063 | lcd = REG_GET(DISPC_DIVISOR, 23, 16); | ||
3064 | else | ||
3065 | lcd = REG_GET(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD), 23, 16); | ||
3066 | |||
3067 | return fclk / lcd; | ||
3068 | } | ||
3069 | |||
3070 | static unsigned long dispc_plane_pclk_rate(enum omap_plane plane) | ||
3071 | { | ||
3072 | enum omap_channel channel; | ||
3073 | |||
3074 | if (plane == OMAP_DSS_WB) | ||
3075 | return 0; | ||
3076 | 2581 | ||
3077 | channel = dispc_ovl_get_channel_out(plane); | 2582 | return r / lcd; |
3078 | |||
3079 | return dispc_mgr_pclk_rate(channel); | ||
3080 | } | 2583 | } |
3081 | 2584 | ||
3082 | static unsigned long dispc_plane_lclk_rate(enum omap_plane plane) | 2585 | unsigned long dispc_pclk_rate(enum omap_channel channel) |
3083 | { | 2586 | { |
3084 | enum omap_channel channel; | 2587 | int pcd; |
3085 | 2588 | unsigned long r; | |
3086 | if (plane == OMAP_DSS_WB) | 2589 | u32 l; |
3087 | return 0; | ||
3088 | |||
3089 | channel = dispc_ovl_get_channel_out(plane); | ||
3090 | |||
3091 | return dispc_mgr_lclk_rate(channel); | ||
3092 | } | ||
3093 | |||
3094 | static void dispc_dump_clocks_channel(struct seq_file *s, enum omap_channel channel) | ||
3095 | { | ||
3096 | int lcd, pcd; | ||
3097 | enum omap_dss_clk_source lcd_clk_src; | ||
3098 | |||
3099 | seq_printf(s, "- %s -\n", mgr_desc[channel].name); | ||
3100 | 2590 | ||
3101 | lcd_clk_src = dss_get_lcd_clk_source(channel); | 2591 | l = dispc_read_reg(DISPC_DIVISORo(channel)); |
3102 | 2592 | ||
3103 | seq_printf(s, "%s clk source = %s (%s)\n", mgr_desc[channel].name, | 2593 | pcd = FLD_GET(l, 7, 0); |
3104 | dss_get_generic_clk_source_name(lcd_clk_src), | ||
3105 | dss_feat_get_clk_source_name(lcd_clk_src)); | ||
3106 | 2594 | ||
3107 | dispc_mgr_get_lcd_divisor(channel, &lcd, &pcd); | 2595 | r = dispc_lclk_rate(channel); |
3108 | 2596 | ||
3109 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | 2597 | return r / pcd; |
3110 | dispc_mgr_lclk_rate(channel), lcd); | ||
3111 | seq_printf(s, "pck\t\t%-16lupck div\t%u\n", | ||
3112 | dispc_mgr_pclk_rate(channel), pcd); | ||
3113 | } | 2598 | } |
3114 | 2599 | ||
3115 | void dispc_dump_clocks(struct seq_file *s) | 2600 | void dispc_dump_clocks(struct seq_file *s) |
3116 | { | 2601 | { |
3117 | int lcd; | 2602 | int lcd, pcd; |
3118 | u32 l; | 2603 | u32 l; |
3119 | enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); | 2604 | enum omap_dss_clk_source dispc_clk_src = dss_get_dispc_clk_source(); |
2605 | enum omap_dss_clk_source lcd_clk_src; | ||
3120 | 2606 | ||
3121 | if (dispc_runtime_get()) | 2607 | if (dispc_runtime_get()) |
3122 | return; | 2608 | return; |
@@ -3137,40 +2623,95 @@ void dispc_dump_clocks(struct seq_file *s) | |||
3137 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | 2623 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", |
3138 | (dispc_fclk_rate()/lcd), lcd); | 2624 | (dispc_fclk_rate()/lcd), lcd); |
3139 | } | 2625 | } |
2626 | seq_printf(s, "- LCD1 -\n"); | ||
3140 | 2627 | ||
3141 | dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD); | 2628 | lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD); |
3142 | 2629 | ||
3143 | if (dss_has_feature(FEAT_MGR_LCD2)) | 2630 | seq_printf(s, "lcd1_clk source = %s (%s)\n", |
3144 | dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD2); | 2631 | dss_get_generic_clk_source_name(lcd_clk_src), |
3145 | if (dss_has_feature(FEAT_MGR_LCD3)) | 2632 | dss_feat_get_clk_source_name(lcd_clk_src)); |
3146 | dispc_dump_clocks_channel(s, OMAP_DSS_CHANNEL_LCD3); | 2633 | |
2634 | dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD, &lcd, &pcd); | ||
2635 | |||
2636 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | ||
2637 | dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD), lcd); | ||
2638 | seq_printf(s, "pck\t\t%-16lupck div\t%u\n", | ||
2639 | dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD), pcd); | ||
2640 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
2641 | seq_printf(s, "- LCD2 -\n"); | ||
2642 | |||
2643 | lcd_clk_src = dss_get_lcd_clk_source(OMAP_DSS_CHANNEL_LCD2); | ||
2644 | |||
2645 | seq_printf(s, "lcd2_clk source = %s (%s)\n", | ||
2646 | dss_get_generic_clk_source_name(lcd_clk_src), | ||
2647 | dss_feat_get_clk_source_name(lcd_clk_src)); | ||
2648 | |||
2649 | dispc_get_lcd_divisor(OMAP_DSS_CHANNEL_LCD2, &lcd, &pcd); | ||
2650 | |||
2651 | seq_printf(s, "lck\t\t%-16lulck div\t%u\n", | ||
2652 | dispc_lclk_rate(OMAP_DSS_CHANNEL_LCD2), lcd); | ||
2653 | seq_printf(s, "pck\t\t%-16lupck div\t%u\n", | ||
2654 | dispc_pclk_rate(OMAP_DSS_CHANNEL_LCD2), pcd); | ||
2655 | } | ||
3147 | 2656 | ||
3148 | dispc_runtime_put(); | 2657 | dispc_runtime_put(); |
3149 | } | 2658 | } |
3150 | 2659 | ||
3151 | static void dispc_dump_regs(struct seq_file *s) | 2660 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
3152 | { | 2661 | void dispc_dump_irqs(struct seq_file *s) |
3153 | int i, j; | 2662 | { |
3154 | const char *mgr_names[] = { | 2663 | unsigned long flags; |
3155 | [OMAP_DSS_CHANNEL_LCD] = "LCD", | 2664 | struct dispc_irq_stats stats; |
3156 | [OMAP_DSS_CHANNEL_DIGIT] = "TV", | 2665 | |
3157 | [OMAP_DSS_CHANNEL_LCD2] = "LCD2", | 2666 | spin_lock_irqsave(&dispc.irq_stats_lock, flags); |
3158 | [OMAP_DSS_CHANNEL_LCD3] = "LCD3", | 2667 | |
3159 | }; | 2668 | stats = dispc.irq_stats; |
3160 | const char *ovl_names[] = { | 2669 | memset(&dispc.irq_stats, 0, sizeof(dispc.irq_stats)); |
3161 | [OMAP_DSS_GFX] = "GFX", | 2670 | dispc.irq_stats.last_reset = jiffies; |
3162 | [OMAP_DSS_VIDEO1] = "VID1", | 2671 | |
3163 | [OMAP_DSS_VIDEO2] = "VID2", | 2672 | spin_unlock_irqrestore(&dispc.irq_stats_lock, flags); |
3164 | [OMAP_DSS_VIDEO3] = "VID3", | 2673 | |
3165 | }; | 2674 | seq_printf(s, "period %u ms\n", |
3166 | const char **p_names; | 2675 | jiffies_to_msecs(jiffies - stats.last_reset)); |
2676 | |||
2677 | seq_printf(s, "irqs %d\n", stats.irq_count); | ||
2678 | #define PIS(x) \ | ||
2679 | seq_printf(s, "%-20s %10d\n", #x, stats.irqs[ffs(DISPC_IRQ_##x)-1]); | ||
2680 | |||
2681 | PIS(FRAMEDONE); | ||
2682 | PIS(VSYNC); | ||
2683 | PIS(EVSYNC_EVEN); | ||
2684 | PIS(EVSYNC_ODD); | ||
2685 | PIS(ACBIAS_COUNT_STAT); | ||
2686 | PIS(PROG_LINE_NUM); | ||
2687 | PIS(GFX_FIFO_UNDERFLOW); | ||
2688 | PIS(GFX_END_WIN); | ||
2689 | PIS(PAL_GAMMA_MASK); | ||
2690 | PIS(OCP_ERR); | ||
2691 | PIS(VID1_FIFO_UNDERFLOW); | ||
2692 | PIS(VID1_END_WIN); | ||
2693 | PIS(VID2_FIFO_UNDERFLOW); | ||
2694 | PIS(VID2_END_WIN); | ||
2695 | PIS(SYNC_LOST); | ||
2696 | PIS(SYNC_LOST_DIGIT); | ||
2697 | PIS(WAKEUP); | ||
2698 | if (dss_has_feature(FEAT_MGR_LCD2)) { | ||
2699 | PIS(FRAMEDONE2); | ||
2700 | PIS(VSYNC2); | ||
2701 | PIS(ACBIAS_COUNT_STAT2); | ||
2702 | PIS(SYNC_LOST2); | ||
2703 | } | ||
2704 | #undef PIS | ||
2705 | } | ||
2706 | #endif | ||
3167 | 2707 | ||
2708 | void dispc_dump_regs(struct seq_file *s) | ||
2709 | { | ||
3168 | #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) | 2710 | #define DUMPREG(r) seq_printf(s, "%-50s %08x\n", #r, dispc_read_reg(r)) |
3169 | 2711 | ||
3170 | if (dispc_runtime_get()) | 2712 | if (dispc_runtime_get()) |
3171 | return; | 2713 | return; |
3172 | 2714 | ||
3173 | /* DISPC common registers */ | ||
3174 | DUMPREG(DISPC_REVISION); | 2715 | DUMPREG(DISPC_REVISION); |
3175 | DUMPREG(DISPC_SYSCONFIG); | 2716 | DUMPREG(DISPC_SYSCONFIG); |
3176 | DUMPREG(DISPC_SYSSTATUS); | 2717 | DUMPREG(DISPC_SYSSTATUS); |
@@ -3179,152 +2720,286 @@ static void dispc_dump_regs(struct seq_file *s) | |||
3179 | DUMPREG(DISPC_CONTROL); | 2720 | DUMPREG(DISPC_CONTROL); |
3180 | DUMPREG(DISPC_CONFIG); | 2721 | DUMPREG(DISPC_CONFIG); |
3181 | DUMPREG(DISPC_CAPABLE); | 2722 | DUMPREG(DISPC_CAPABLE); |
2723 | DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD)); | ||
2724 | DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_DIGIT)); | ||
2725 | DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD)); | ||
2726 | DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_DIGIT)); | ||
3182 | DUMPREG(DISPC_LINE_STATUS); | 2727 | DUMPREG(DISPC_LINE_STATUS); |
3183 | DUMPREG(DISPC_LINE_NUMBER); | 2728 | DUMPREG(DISPC_LINE_NUMBER); |
3184 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER) || | 2729 | DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD)); |
3185 | dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) | 2730 | DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD)); |
2731 | DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD)); | ||
2732 | DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD)); | ||
2733 | if (dss_has_feature(FEAT_GLOBAL_ALPHA)) | ||
3186 | DUMPREG(DISPC_GLOBAL_ALPHA); | 2734 | DUMPREG(DISPC_GLOBAL_ALPHA); |
2735 | DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_DIGIT)); | ||
2736 | DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD)); | ||
3187 | if (dss_has_feature(FEAT_MGR_LCD2)) { | 2737 | if (dss_has_feature(FEAT_MGR_LCD2)) { |
3188 | DUMPREG(DISPC_CONTROL2); | 2738 | DUMPREG(DISPC_CONTROL2); |
3189 | DUMPREG(DISPC_CONFIG2); | 2739 | DUMPREG(DISPC_CONFIG2); |
3190 | } | 2740 | DUMPREG(DISPC_DEFAULT_COLOR(OMAP_DSS_CHANNEL_LCD2)); |
3191 | if (dss_has_feature(FEAT_MGR_LCD3)) { | 2741 | DUMPREG(DISPC_TRANS_COLOR(OMAP_DSS_CHANNEL_LCD2)); |
3192 | DUMPREG(DISPC_CONTROL3); | 2742 | DUMPREG(DISPC_TIMING_H(OMAP_DSS_CHANNEL_LCD2)); |
3193 | DUMPREG(DISPC_CONFIG3); | 2743 | DUMPREG(DISPC_TIMING_V(OMAP_DSS_CHANNEL_LCD2)); |
3194 | } | 2744 | DUMPREG(DISPC_POL_FREQ(OMAP_DSS_CHANNEL_LCD2)); |
3195 | 2745 | DUMPREG(DISPC_DIVISORo(OMAP_DSS_CHANNEL_LCD2)); | |
3196 | #undef DUMPREG | 2746 | DUMPREG(DISPC_SIZE_MGR(OMAP_DSS_CHANNEL_LCD2)); |
3197 | 2747 | } | |
3198 | #define DISPC_REG(i, name) name(i) | 2748 | |
3199 | #define DUMPREG(i, r) seq_printf(s, "%s(%s)%*s %08x\n", #r, p_names[i], \ | 2749 | DUMPREG(DISPC_OVL_BA0(OMAP_DSS_GFX)); |
3200 | (int)(48 - strlen(#r) - strlen(p_names[i])), " ", \ | 2750 | DUMPREG(DISPC_OVL_BA1(OMAP_DSS_GFX)); |
3201 | dispc_read_reg(DISPC_REG(i, r))) | 2751 | DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_GFX)); |
3202 | 2752 | DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_GFX)); | |
3203 | p_names = mgr_names; | 2753 | DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_GFX)); |
3204 | 2754 | DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_GFX)); | |
3205 | /* DISPC channel specific registers */ | 2755 | DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_GFX)); |
3206 | for (i = 0; i < dss_feat_get_num_mgrs(); i++) { | 2756 | DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_GFX)); |
3207 | DUMPREG(i, DISPC_DEFAULT_COLOR); | 2757 | DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_GFX)); |
3208 | DUMPREG(i, DISPC_TRANS_COLOR); | 2758 | DUMPREG(DISPC_OVL_WINDOW_SKIP(OMAP_DSS_GFX)); |
3209 | DUMPREG(i, DISPC_SIZE_MGR); | 2759 | DUMPREG(DISPC_OVL_TABLE_BA(OMAP_DSS_GFX)); |
2760 | |||
2761 | DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD)); | ||
2762 | DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD)); | ||
2763 | DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD)); | ||
3210 | 2764 | ||
3211 | if (i == OMAP_DSS_CHANNEL_DIGIT) | 2765 | if (dss_has_feature(FEAT_CPR)) { |
3212 | continue; | 2766 | DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD)); |
3213 | 2767 | DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD)); | |
3214 | DUMPREG(i, DISPC_DEFAULT_COLOR); | 2768 | DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD)); |
3215 | DUMPREG(i, DISPC_TRANS_COLOR); | 2769 | } |
3216 | DUMPREG(i, DISPC_TIMING_H); | 2770 | if (dss_has_feature(FEAT_MGR_LCD2)) { |
3217 | DUMPREG(i, DISPC_TIMING_V); | 2771 | DUMPREG(DISPC_DATA_CYCLE1(OMAP_DSS_CHANNEL_LCD2)); |
3218 | DUMPREG(i, DISPC_POL_FREQ); | 2772 | DUMPREG(DISPC_DATA_CYCLE2(OMAP_DSS_CHANNEL_LCD2)); |
3219 | DUMPREG(i, DISPC_DIVISORo); | 2773 | DUMPREG(DISPC_DATA_CYCLE3(OMAP_DSS_CHANNEL_LCD2)); |
3220 | DUMPREG(i, DISPC_SIZE_MGR); | ||
3221 | |||
3222 | DUMPREG(i, DISPC_DATA_CYCLE1); | ||
3223 | DUMPREG(i, DISPC_DATA_CYCLE2); | ||
3224 | DUMPREG(i, DISPC_DATA_CYCLE3); | ||
3225 | 2774 | ||
3226 | if (dss_has_feature(FEAT_CPR)) { | 2775 | if (dss_has_feature(FEAT_CPR)) { |
3227 | DUMPREG(i, DISPC_CPR_COEF_R); | 2776 | DUMPREG(DISPC_CPR_COEF_R(OMAP_DSS_CHANNEL_LCD2)); |
3228 | DUMPREG(i, DISPC_CPR_COEF_G); | 2777 | DUMPREG(DISPC_CPR_COEF_G(OMAP_DSS_CHANNEL_LCD2)); |
3229 | DUMPREG(i, DISPC_CPR_COEF_B); | 2778 | DUMPREG(DISPC_CPR_COEF_B(OMAP_DSS_CHANNEL_LCD2)); |
3230 | } | 2779 | } |
3231 | } | 2780 | } |
3232 | 2781 | ||
3233 | p_names = ovl_names; | 2782 | if (dss_has_feature(FEAT_PRELOAD)) |
3234 | 2783 | DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_GFX)); | |
3235 | for (i = 0; i < dss_feat_get_num_ovls(); i++) { | 2784 | |
3236 | DUMPREG(i, DISPC_OVL_BA0); | 2785 | DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO1)); |
3237 | DUMPREG(i, DISPC_OVL_BA1); | 2786 | DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO1)); |
3238 | DUMPREG(i, DISPC_OVL_POSITION); | 2787 | DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO1)); |
3239 | DUMPREG(i, DISPC_OVL_SIZE); | 2788 | DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO1)); |
3240 | DUMPREG(i, DISPC_OVL_ATTRIBUTES); | 2789 | DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO1)); |
3241 | DUMPREG(i, DISPC_OVL_FIFO_THRESHOLD); | 2790 | DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO1)); |
3242 | DUMPREG(i, DISPC_OVL_FIFO_SIZE_STATUS); | 2791 | DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO1)); |
3243 | DUMPREG(i, DISPC_OVL_ROW_INC); | 2792 | DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO1)); |
3244 | DUMPREG(i, DISPC_OVL_PIXEL_INC); | 2793 | DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO1)); |
3245 | if (dss_has_feature(FEAT_PRELOAD)) | 2794 | DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO1)); |
3246 | DUMPREG(i, DISPC_OVL_PRELOAD); | 2795 | DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO1)); |
3247 | 2796 | DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO1)); | |
3248 | if (i == OMAP_DSS_GFX) { | 2797 | DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO1)); |
3249 | DUMPREG(i, DISPC_OVL_WINDOW_SKIP); | 2798 | |
3250 | DUMPREG(i, DISPC_OVL_TABLE_BA); | 2799 | DUMPREG(DISPC_OVL_BA0(OMAP_DSS_VIDEO2)); |
3251 | continue; | 2800 | DUMPREG(DISPC_OVL_BA1(OMAP_DSS_VIDEO2)); |
3252 | } | 2801 | DUMPREG(DISPC_OVL_POSITION(OMAP_DSS_VIDEO2)); |
3253 | 2802 | DUMPREG(DISPC_OVL_SIZE(OMAP_DSS_VIDEO2)); | |
3254 | DUMPREG(i, DISPC_OVL_FIR); | 2803 | DUMPREG(DISPC_OVL_ATTRIBUTES(OMAP_DSS_VIDEO2)); |
3255 | DUMPREG(i, DISPC_OVL_PICTURE_SIZE); | 2804 | DUMPREG(DISPC_OVL_FIFO_THRESHOLD(OMAP_DSS_VIDEO2)); |
3256 | DUMPREG(i, DISPC_OVL_ACCU0); | 2805 | DUMPREG(DISPC_OVL_FIFO_SIZE_STATUS(OMAP_DSS_VIDEO2)); |
3257 | DUMPREG(i, DISPC_OVL_ACCU1); | 2806 | DUMPREG(DISPC_OVL_ROW_INC(OMAP_DSS_VIDEO2)); |
3258 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | 2807 | DUMPREG(DISPC_OVL_PIXEL_INC(OMAP_DSS_VIDEO2)); |
3259 | DUMPREG(i, DISPC_OVL_BA0_UV); | 2808 | DUMPREG(DISPC_OVL_FIR(OMAP_DSS_VIDEO2)); |
3260 | DUMPREG(i, DISPC_OVL_BA1_UV); | 2809 | DUMPREG(DISPC_OVL_PICTURE_SIZE(OMAP_DSS_VIDEO2)); |
3261 | DUMPREG(i, DISPC_OVL_FIR2); | 2810 | DUMPREG(DISPC_OVL_ACCU0(OMAP_DSS_VIDEO2)); |
3262 | DUMPREG(i, DISPC_OVL_ACCU2_0); | 2811 | DUMPREG(DISPC_OVL_ACCU1(OMAP_DSS_VIDEO2)); |
3263 | DUMPREG(i, DISPC_OVL_ACCU2_1); | 2812 | |
3264 | } | 2813 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 0)); |
3265 | if (dss_has_feature(FEAT_ATTR2)) | 2814 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 1)); |
3266 | DUMPREG(i, DISPC_OVL_ATTRIBUTES2); | 2815 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 2)); |
3267 | if (dss_has_feature(FEAT_PRELOAD)) | 2816 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 3)); |
3268 | DUMPREG(i, DISPC_OVL_PRELOAD); | 2817 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 4)); |
2818 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 5)); | ||
2819 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 6)); | ||
2820 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO1, 7)); | ||
2821 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 0)); | ||
2822 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 1)); | ||
2823 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 2)); | ||
2824 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 3)); | ||
2825 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 4)); | ||
2826 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 5)); | ||
2827 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 6)); | ||
2828 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO1, 7)); | ||
2829 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 0)); | ||
2830 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 1)); | ||
2831 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 2)); | ||
2832 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 3)); | ||
2833 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO1, 4)); | ||
2834 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | ||
2835 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 0)); | ||
2836 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 1)); | ||
2837 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 2)); | ||
2838 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 3)); | ||
2839 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 4)); | ||
2840 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 5)); | ||
2841 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 6)); | ||
2842 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO1, 7)); | ||
2843 | } | ||
2844 | |||
2845 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | ||
2846 | DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO1)); | ||
2847 | DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO1)); | ||
2848 | DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO1)); | ||
2849 | DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO1)); | ||
2850 | DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO1)); | ||
2851 | |||
2852 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 0)); | ||
2853 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 1)); | ||
2854 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 2)); | ||
2855 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 3)); | ||
2856 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 4)); | ||
2857 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 5)); | ||
2858 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 6)); | ||
2859 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO1, 7)); | ||
2860 | |||
2861 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 0)); | ||
2862 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 1)); | ||
2863 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 2)); | ||
2864 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 3)); | ||
2865 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 4)); | ||
2866 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 5)); | ||
2867 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 6)); | ||
2868 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO1, 7)); | ||
2869 | |||
2870 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 0)); | ||
2871 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 1)); | ||
2872 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 2)); | ||
2873 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 3)); | ||
2874 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 4)); | ||
2875 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 5)); | ||
2876 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 6)); | ||
2877 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO1, 7)); | ||
2878 | } | ||
2879 | if (dss_has_feature(FEAT_ATTR2)) | ||
2880 | DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO1)); | ||
2881 | |||
2882 | |||
2883 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 0)); | ||
2884 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 1)); | ||
2885 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 2)); | ||
2886 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 3)); | ||
2887 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 4)); | ||
2888 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 5)); | ||
2889 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 6)); | ||
2890 | DUMPREG(DISPC_OVL_FIR_COEF_H(OMAP_DSS_VIDEO2, 7)); | ||
2891 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 0)); | ||
2892 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 1)); | ||
2893 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 2)); | ||
2894 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 3)); | ||
2895 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 4)); | ||
2896 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 5)); | ||
2897 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 6)); | ||
2898 | DUMPREG(DISPC_OVL_FIR_COEF_HV(OMAP_DSS_VIDEO2, 7)); | ||
2899 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 0)); | ||
2900 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 1)); | ||
2901 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 2)); | ||
2902 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 3)); | ||
2903 | DUMPREG(DISPC_OVL_CONV_COEF(OMAP_DSS_VIDEO2, 4)); | ||
2904 | |||
2905 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | ||
2906 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 0)); | ||
2907 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 1)); | ||
2908 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 2)); | ||
2909 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 3)); | ||
2910 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 4)); | ||
2911 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 5)); | ||
2912 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 6)); | ||
2913 | DUMPREG(DISPC_OVL_FIR_COEF_V(OMAP_DSS_VIDEO2, 7)); | ||
2914 | } | ||
2915 | |||
2916 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | ||
2917 | DUMPREG(DISPC_OVL_BA0_UV(OMAP_DSS_VIDEO2)); | ||
2918 | DUMPREG(DISPC_OVL_BA1_UV(OMAP_DSS_VIDEO2)); | ||
2919 | DUMPREG(DISPC_OVL_FIR2(OMAP_DSS_VIDEO2)); | ||
2920 | DUMPREG(DISPC_OVL_ACCU2_0(OMAP_DSS_VIDEO2)); | ||
2921 | DUMPREG(DISPC_OVL_ACCU2_1(OMAP_DSS_VIDEO2)); | ||
2922 | |||
2923 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 0)); | ||
2924 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 1)); | ||
2925 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 2)); | ||
2926 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 3)); | ||
2927 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 4)); | ||
2928 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 5)); | ||
2929 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 6)); | ||
2930 | DUMPREG(DISPC_OVL_FIR_COEF_H2(OMAP_DSS_VIDEO2, 7)); | ||
2931 | |||
2932 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 0)); | ||
2933 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 1)); | ||
2934 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 2)); | ||
2935 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 3)); | ||
2936 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 4)); | ||
2937 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 5)); | ||
2938 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 6)); | ||
2939 | DUMPREG(DISPC_OVL_FIR_COEF_HV2(OMAP_DSS_VIDEO2, 7)); | ||
2940 | |||
2941 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 0)); | ||
2942 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 1)); | ||
2943 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 2)); | ||
2944 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 3)); | ||
2945 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 4)); | ||
2946 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 5)); | ||
2947 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 6)); | ||
2948 | DUMPREG(DISPC_OVL_FIR_COEF_V2(OMAP_DSS_VIDEO2, 7)); | ||
2949 | } | ||
2950 | if (dss_has_feature(FEAT_ATTR2)) | ||
2951 | DUMPREG(DISPC_OVL_ATTRIBUTES2(OMAP_DSS_VIDEO2)); | ||
2952 | |||
2953 | if (dss_has_feature(FEAT_PRELOAD)) { | ||
2954 | DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO1)); | ||
2955 | DUMPREG(DISPC_OVL_PRELOAD(OMAP_DSS_VIDEO2)); | ||
3269 | } | 2956 | } |
3270 | 2957 | ||
3271 | #undef DISPC_REG | 2958 | dispc_runtime_put(); |
3272 | #undef DUMPREG | 2959 | #undef DUMPREG |
2960 | } | ||
3273 | 2961 | ||
3274 | #define DISPC_REG(plane, name, i) name(plane, i) | 2962 | static void _dispc_set_pol_freq(enum omap_channel channel, bool onoff, bool rf, |
3275 | #define DUMPREG(plane, name, i) \ | 2963 | bool ieo, bool ipc, bool ihs, bool ivs, u8 acbi, u8 acb) |
3276 | seq_printf(s, "%s_%d(%s)%*s %08x\n", #name, i, p_names[plane], \ | 2964 | { |
3277 | (int)(46 - strlen(#name) - strlen(p_names[plane])), " ", \ | 2965 | u32 l = 0; |
3278 | dispc_read_reg(DISPC_REG(plane, name, i))) | ||
3279 | |||
3280 | /* Video pipeline coefficient registers */ | ||
3281 | |||
3282 | /* start from OMAP_DSS_VIDEO1 */ | ||
3283 | for (i = 1; i < dss_feat_get_num_ovls(); i++) { | ||
3284 | for (j = 0; j < 8; j++) | ||
3285 | DUMPREG(i, DISPC_OVL_FIR_COEF_H, j); | ||
3286 | |||
3287 | for (j = 0; j < 8; j++) | ||
3288 | DUMPREG(i, DISPC_OVL_FIR_COEF_HV, j); | ||
3289 | |||
3290 | for (j = 0; j < 5; j++) | ||
3291 | DUMPREG(i, DISPC_OVL_CONV_COEF, j); | ||
3292 | |||
3293 | if (dss_has_feature(FEAT_FIR_COEF_V)) { | ||
3294 | for (j = 0; j < 8; j++) | ||
3295 | DUMPREG(i, DISPC_OVL_FIR_COEF_V, j); | ||
3296 | } | ||
3297 | |||
3298 | if (dss_has_feature(FEAT_HANDLE_UV_SEPARATE)) { | ||
3299 | for (j = 0; j < 8; j++) | ||
3300 | DUMPREG(i, DISPC_OVL_FIR_COEF_H2, j); | ||
3301 | 2966 | ||
3302 | for (j = 0; j < 8; j++) | 2967 | DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n", |
3303 | DUMPREG(i, DISPC_OVL_FIR_COEF_HV2, j); | 2968 | onoff, rf, ieo, ipc, ihs, ivs, acbi, acb); |
3304 | 2969 | ||
3305 | for (j = 0; j < 8; j++) | 2970 | l |= FLD_VAL(onoff, 17, 17); |
3306 | DUMPREG(i, DISPC_OVL_FIR_COEF_V2, j); | 2971 | l |= FLD_VAL(rf, 16, 16); |
3307 | } | 2972 | l |= FLD_VAL(ieo, 15, 15); |
3308 | } | 2973 | l |= FLD_VAL(ipc, 14, 14); |
2974 | l |= FLD_VAL(ihs, 13, 13); | ||
2975 | l |= FLD_VAL(ivs, 12, 12); | ||
2976 | l |= FLD_VAL(acbi, 11, 8); | ||
2977 | l |= FLD_VAL(acb, 7, 0); | ||
3309 | 2978 | ||
3310 | dispc_runtime_put(); | 2979 | dispc_write_reg(DISPC_POL_FREQ(channel), l); |
2980 | } | ||
3311 | 2981 | ||
3312 | #undef DISPC_REG | 2982 | void dispc_set_pol_freq(enum omap_channel channel, |
3313 | #undef DUMPREG | 2983 | enum omap_panel_config config, u8 acbi, u8 acb) |
2984 | { | ||
2985 | _dispc_set_pol_freq(channel, (config & OMAP_DSS_LCD_ONOFF) != 0, | ||
2986 | (config & OMAP_DSS_LCD_RF) != 0, | ||
2987 | (config & OMAP_DSS_LCD_IEO) != 0, | ||
2988 | (config & OMAP_DSS_LCD_IPC) != 0, | ||
2989 | (config & OMAP_DSS_LCD_IHS) != 0, | ||
2990 | (config & OMAP_DSS_LCD_IVS) != 0, | ||
2991 | acbi, acb); | ||
3314 | } | 2992 | } |
3315 | 2993 | ||
3316 | /* with fck as input clock rate, find dispc dividers that produce req_pck */ | 2994 | /* with fck as input clock rate, find dispc dividers that produce req_pck */ |
3317 | void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, | 2995 | void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, |
3318 | struct dispc_clock_info *cinfo) | 2996 | struct dispc_clock_info *cinfo) |
3319 | { | 2997 | { |
3320 | u16 pcd_min, pcd_max; | 2998 | u16 pcd_min = is_tft ? 2 : 3; |
3321 | unsigned long best_pck; | 2999 | unsigned long best_pck; |
3322 | u16 best_ld, cur_ld; | 3000 | u16 best_ld, cur_ld; |
3323 | u16 best_pd, cur_pd; | 3001 | u16 best_pd, cur_pd; |
3324 | 3002 | ||
3325 | pcd_min = dss_feat_get_param_min(FEAT_PARAM_DSS_PCD); | ||
3326 | pcd_max = dss_feat_get_param_max(FEAT_PARAM_DSS_PCD); | ||
3327 | |||
3328 | best_pck = 0; | 3003 | best_pck = 0; |
3329 | best_ld = 0; | 3004 | best_ld = 0; |
3330 | best_pd = 0; | 3005 | best_pd = 0; |
@@ -3332,7 +3007,7 @@ void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, | |||
3332 | for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { | 3007 | for (cur_ld = 1; cur_ld <= 255; ++cur_ld) { |
3333 | unsigned long lck = fck / cur_ld; | 3008 | unsigned long lck = fck / cur_ld; |
3334 | 3009 | ||
3335 | for (cur_pd = pcd_min; cur_pd <= pcd_max; ++cur_pd) { | 3010 | for (cur_pd = pcd_min; cur_pd <= 255; ++cur_pd) { |
3336 | unsigned long pck = lck / cur_pd; | 3011 | unsigned long pck = lck / cur_pd; |
3337 | long old_delta = abs(best_pck - req_pck); | 3012 | long old_delta = abs(best_pck - req_pck); |
3338 | long new_delta = abs(pck - req_pck); | 3013 | long new_delta = abs(pck - req_pck); |
@@ -3367,7 +3042,7 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
3367 | { | 3042 | { |
3368 | if (cinfo->lck_div > 255 || cinfo->lck_div == 0) | 3043 | if (cinfo->lck_div > 255 || cinfo->lck_div == 0) |
3369 | return -EINVAL; | 3044 | return -EINVAL; |
3370 | if (cinfo->pck_div < 1 || cinfo->pck_div > 255) | 3045 | if (cinfo->pck_div < 2 || cinfo->pck_div > 255) |
3371 | return -EINVAL; | 3046 | return -EINVAL; |
3372 | 3047 | ||
3373 | cinfo->lck = dispc_fclk_rate / cinfo->lck_div; | 3048 | cinfo->lck = dispc_fclk_rate / cinfo->lck_div; |
@@ -3376,16 +3051,18 @@ int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | |||
3376 | return 0; | 3051 | return 0; |
3377 | } | 3052 | } |
3378 | 3053 | ||
3379 | void dispc_mgr_set_clock_div(enum omap_channel channel, | 3054 | int dispc_set_clock_div(enum omap_channel channel, |
3380 | const struct dispc_clock_info *cinfo) | 3055 | struct dispc_clock_info *cinfo) |
3381 | { | 3056 | { |
3382 | DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); | 3057 | DSSDBG("lck = %lu (%u)\n", cinfo->lck, cinfo->lck_div); |
3383 | DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); | 3058 | DSSDBG("pck = %lu (%u)\n", cinfo->pck, cinfo->pck_div); |
3384 | 3059 | ||
3385 | dispc_mgr_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); | 3060 | dispc_set_lcd_divisor(channel, cinfo->lck_div, cinfo->pck_div); |
3061 | |||
3062 | return 0; | ||
3386 | } | 3063 | } |
3387 | 3064 | ||
3388 | int dispc_mgr_get_clock_div(enum omap_channel channel, | 3065 | int dispc_get_clock_div(enum omap_channel channel, |
3389 | struct dispc_clock_info *cinfo) | 3066 | struct dispc_clock_info *cinfo) |
3390 | { | 3067 | { |
3391 | unsigned long fck; | 3068 | unsigned long fck; |
@@ -3401,247 +3078,617 @@ int dispc_mgr_get_clock_div(enum omap_channel channel, | |||
3401 | return 0; | 3078 | return 0; |
3402 | } | 3079 | } |
3403 | 3080 | ||
3404 | u32 dispc_read_irqstatus(void) | 3081 | /* dispc.irq_lock has to be locked by the caller */ |
3082 | static void _omap_dispc_set_irqs(void) | ||
3405 | { | 3083 | { |
3406 | return dispc_read_reg(DISPC_IRQSTATUS); | 3084 | u32 mask; |
3407 | } | 3085 | u32 old_mask; |
3408 | EXPORT_SYMBOL(dispc_read_irqstatus); | 3086 | int i; |
3087 | struct omap_dispc_isr_data *isr_data; | ||
3409 | 3088 | ||
3410 | void dispc_clear_irqstatus(u32 mask) | 3089 | mask = dispc.irq_error_mask; |
3411 | { | 3090 | |
3412 | dispc_write_reg(DISPC_IRQSTATUS, mask); | 3091 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { |
3092 | isr_data = &dispc.registered_isr[i]; | ||
3093 | |||
3094 | if (isr_data->isr == NULL) | ||
3095 | continue; | ||
3096 | |||
3097 | mask |= isr_data->mask; | ||
3098 | } | ||
3099 | |||
3100 | old_mask = dispc_read_reg(DISPC_IRQENABLE); | ||
3101 | /* clear the irqstatus for newly enabled irqs */ | ||
3102 | dispc_write_reg(DISPC_IRQSTATUS, (mask ^ old_mask) & mask); | ||
3103 | |||
3104 | dispc_write_reg(DISPC_IRQENABLE, mask); | ||
3413 | } | 3105 | } |
3414 | EXPORT_SYMBOL(dispc_clear_irqstatus); | ||
3415 | 3106 | ||
3416 | u32 dispc_read_irqenable(void) | 3107 | int omap_dispc_register_isr(omap_dispc_isr_t isr, void *arg, u32 mask) |
3417 | { | 3108 | { |
3418 | return dispc_read_reg(DISPC_IRQENABLE); | 3109 | int i; |
3110 | int ret; | ||
3111 | unsigned long flags; | ||
3112 | struct omap_dispc_isr_data *isr_data; | ||
3113 | |||
3114 | if (isr == NULL) | ||
3115 | return -EINVAL; | ||
3116 | |||
3117 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
3118 | |||
3119 | /* check for duplicate entry */ | ||
3120 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
3121 | isr_data = &dispc.registered_isr[i]; | ||
3122 | if (isr_data->isr == isr && isr_data->arg == arg && | ||
3123 | isr_data->mask == mask) { | ||
3124 | ret = -EINVAL; | ||
3125 | goto err; | ||
3126 | } | ||
3127 | } | ||
3128 | |||
3129 | isr_data = NULL; | ||
3130 | ret = -EBUSY; | ||
3131 | |||
3132 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
3133 | isr_data = &dispc.registered_isr[i]; | ||
3134 | |||
3135 | if (isr_data->isr != NULL) | ||
3136 | continue; | ||
3137 | |||
3138 | isr_data->isr = isr; | ||
3139 | isr_data->arg = arg; | ||
3140 | isr_data->mask = mask; | ||
3141 | ret = 0; | ||
3142 | |||
3143 | break; | ||
3144 | } | ||
3145 | |||
3146 | if (ret) | ||
3147 | goto err; | ||
3148 | |||
3149 | _omap_dispc_set_irqs(); | ||
3150 | |||
3151 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
3152 | |||
3153 | return 0; | ||
3154 | err: | ||
3155 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
3156 | |||
3157 | return ret; | ||
3419 | } | 3158 | } |
3420 | EXPORT_SYMBOL(dispc_read_irqenable); | 3159 | EXPORT_SYMBOL(omap_dispc_register_isr); |
3421 | 3160 | ||
3422 | void dispc_write_irqenable(u32 mask) | 3161 | int omap_dispc_unregister_isr(omap_dispc_isr_t isr, void *arg, u32 mask) |
3423 | { | 3162 | { |
3424 | u32 old_mask = dispc_read_reg(DISPC_IRQENABLE); | 3163 | int i; |
3164 | unsigned long flags; | ||
3165 | int ret = -EINVAL; | ||
3166 | struct omap_dispc_isr_data *isr_data; | ||
3425 | 3167 | ||
3426 | /* clear the irqstatus for newly enabled irqs */ | 3168 | spin_lock_irqsave(&dispc.irq_lock, flags); |
3427 | dispc_clear_irqstatus((mask ^ old_mask) & mask); | ||
3428 | 3169 | ||
3429 | dispc_write_reg(DISPC_IRQENABLE, mask); | 3170 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { |
3171 | isr_data = &dispc.registered_isr[i]; | ||
3172 | if (isr_data->isr != isr || isr_data->arg != arg || | ||
3173 | isr_data->mask != mask) | ||
3174 | continue; | ||
3175 | |||
3176 | /* found the correct isr */ | ||
3177 | |||
3178 | isr_data->isr = NULL; | ||
3179 | isr_data->arg = NULL; | ||
3180 | isr_data->mask = 0; | ||
3181 | |||
3182 | ret = 0; | ||
3183 | break; | ||
3184 | } | ||
3185 | |||
3186 | if (ret == 0) | ||
3187 | _omap_dispc_set_irqs(); | ||
3188 | |||
3189 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
3190 | |||
3191 | return ret; | ||
3430 | } | 3192 | } |
3431 | EXPORT_SYMBOL(dispc_write_irqenable); | 3193 | EXPORT_SYMBOL(omap_dispc_unregister_isr); |
3432 | 3194 | ||
3433 | void dispc_enable_sidle(void) | 3195 | #ifdef DEBUG |
3196 | static void print_irq_status(u32 status) | ||
3434 | { | 3197 | { |
3435 | REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ | 3198 | if ((status & dispc.irq_error_mask) == 0) |
3199 | return; | ||
3200 | |||
3201 | printk(KERN_DEBUG "DISPC IRQ: 0x%x: ", status); | ||
3202 | |||
3203 | #define PIS(x) \ | ||
3204 | if (status & DISPC_IRQ_##x) \ | ||
3205 | printk(#x " "); | ||
3206 | PIS(GFX_FIFO_UNDERFLOW); | ||
3207 | PIS(OCP_ERR); | ||
3208 | PIS(VID1_FIFO_UNDERFLOW); | ||
3209 | PIS(VID2_FIFO_UNDERFLOW); | ||
3210 | PIS(SYNC_LOST); | ||
3211 | PIS(SYNC_LOST_DIGIT); | ||
3212 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
3213 | PIS(SYNC_LOST2); | ||
3214 | #undef PIS | ||
3215 | |||
3216 | printk("\n"); | ||
3436 | } | 3217 | } |
3218 | #endif | ||
3437 | 3219 | ||
3438 | void dispc_disable_sidle(void) | 3220 | /* Called from dss.c. Note that we don't touch clocks here, |
3221 | * but we presume they are on because we got an IRQ. However, | ||
3222 | * an irq handler may turn the clocks off, so we may not have | ||
3223 | * clock later in the function. */ | ||
3224 | static irqreturn_t omap_dispc_irq_handler(int irq, void *arg) | ||
3439 | { | 3225 | { |
3440 | REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ | 3226 | int i; |
3227 | u32 irqstatus, irqenable; | ||
3228 | u32 handledirqs = 0; | ||
3229 | u32 unhandled_errors; | ||
3230 | struct omap_dispc_isr_data *isr_data; | ||
3231 | struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS]; | ||
3232 | |||
3233 | spin_lock(&dispc.irq_lock); | ||
3234 | |||
3235 | irqstatus = dispc_read_reg(DISPC_IRQSTATUS); | ||
3236 | irqenable = dispc_read_reg(DISPC_IRQENABLE); | ||
3237 | |||
3238 | /* IRQ is not for us */ | ||
3239 | if (!(irqstatus & irqenable)) { | ||
3240 | spin_unlock(&dispc.irq_lock); | ||
3241 | return IRQ_NONE; | ||
3242 | } | ||
3243 | |||
3244 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
3245 | spin_lock(&dispc.irq_stats_lock); | ||
3246 | dispc.irq_stats.irq_count++; | ||
3247 | dss_collect_irq_stats(irqstatus, dispc.irq_stats.irqs); | ||
3248 | spin_unlock(&dispc.irq_stats_lock); | ||
3249 | #endif | ||
3250 | |||
3251 | #ifdef DEBUG | ||
3252 | if (dss_debug) | ||
3253 | print_irq_status(irqstatus); | ||
3254 | #endif | ||
3255 | /* Ack the interrupt. Do it here before clocks are possibly turned | ||
3256 | * off */ | ||
3257 | dispc_write_reg(DISPC_IRQSTATUS, irqstatus); | ||
3258 | /* flush posted write */ | ||
3259 | dispc_read_reg(DISPC_IRQSTATUS); | ||
3260 | |||
3261 | /* make a copy and unlock, so that isrs can unregister | ||
3262 | * themselves */ | ||
3263 | memcpy(registered_isr, dispc.registered_isr, | ||
3264 | sizeof(registered_isr)); | ||
3265 | |||
3266 | spin_unlock(&dispc.irq_lock); | ||
3267 | |||
3268 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
3269 | isr_data = ®istered_isr[i]; | ||
3270 | |||
3271 | if (!isr_data->isr) | ||
3272 | continue; | ||
3273 | |||
3274 | if (isr_data->mask & irqstatus) { | ||
3275 | isr_data->isr(isr_data->arg, irqstatus); | ||
3276 | handledirqs |= isr_data->mask; | ||
3277 | } | ||
3278 | } | ||
3279 | |||
3280 | spin_lock(&dispc.irq_lock); | ||
3281 | |||
3282 | unhandled_errors = irqstatus & ~handledirqs & dispc.irq_error_mask; | ||
3283 | |||
3284 | if (unhandled_errors) { | ||
3285 | dispc.error_irqs |= unhandled_errors; | ||
3286 | |||
3287 | dispc.irq_error_mask &= ~unhandled_errors; | ||
3288 | _omap_dispc_set_irqs(); | ||
3289 | |||
3290 | schedule_work(&dispc.error_work); | ||
3291 | } | ||
3292 | |||
3293 | spin_unlock(&dispc.irq_lock); | ||
3294 | |||
3295 | return IRQ_HANDLED; | ||
3441 | } | 3296 | } |
3442 | 3297 | ||
3443 | static void _omap_dispc_initial_config(void) | 3298 | static void dispc_error_worker(struct work_struct *work) |
3444 | { | 3299 | { |
3445 | u32 l; | 3300 | int i; |
3301 | u32 errors; | ||
3302 | unsigned long flags; | ||
3303 | |||
3304 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
3305 | errors = dispc.error_irqs; | ||
3306 | dispc.error_irqs = 0; | ||
3307 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
3308 | |||
3309 | if (errors & DISPC_IRQ_GFX_FIFO_UNDERFLOW) { | ||
3310 | DSSERR("GFX_FIFO_UNDERFLOW, disabling GFX\n"); | ||
3311 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
3312 | struct omap_overlay *ovl; | ||
3313 | ovl = omap_dss_get_overlay(i); | ||
3314 | |||
3315 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) | ||
3316 | continue; | ||
3317 | |||
3318 | if (ovl->id == 0) { | ||
3319 | dispc_enable_plane(ovl->id, 0); | ||
3320 | dispc_go(ovl->manager->id); | ||
3321 | mdelay(50); | ||
3322 | break; | ||
3323 | } | ||
3324 | } | ||
3325 | } | ||
3446 | 3326 | ||
3447 | /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ | 3327 | if (errors & DISPC_IRQ_VID1_FIFO_UNDERFLOW) { |
3448 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) { | 3328 | DSSERR("VID1_FIFO_UNDERFLOW, disabling VID1\n"); |
3449 | l = dispc_read_reg(DISPC_DIVISOR); | 3329 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { |
3450 | /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ | 3330 | struct omap_overlay *ovl; |
3451 | l = FLD_MOD(l, 1, 0, 0); | 3331 | ovl = omap_dss_get_overlay(i); |
3452 | l = FLD_MOD(l, 1, 23, 16); | 3332 | |
3453 | dispc_write_reg(DISPC_DIVISOR, l); | 3333 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) |
3334 | continue; | ||
3335 | |||
3336 | if (ovl->id == 1) { | ||
3337 | dispc_enable_plane(ovl->id, 0); | ||
3338 | dispc_go(ovl->manager->id); | ||
3339 | mdelay(50); | ||
3340 | break; | ||
3341 | } | ||
3342 | } | ||
3454 | } | 3343 | } |
3455 | 3344 | ||
3456 | /* FUNCGATED */ | 3345 | if (errors & DISPC_IRQ_VID2_FIFO_UNDERFLOW) { |
3457 | if (dss_has_feature(FEAT_FUNCGATED)) | 3346 | DSSERR("VID2_FIFO_UNDERFLOW, disabling VID2\n"); |
3458 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); | 3347 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { |
3348 | struct omap_overlay *ovl; | ||
3349 | ovl = omap_dss_get_overlay(i); | ||
3459 | 3350 | ||
3460 | dispc_setup_color_conv_coef(); | 3351 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) |
3352 | continue; | ||
3461 | 3353 | ||
3462 | dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); | 3354 | if (ovl->id == 2) { |
3355 | dispc_enable_plane(ovl->id, 0); | ||
3356 | dispc_go(ovl->manager->id); | ||
3357 | mdelay(50); | ||
3358 | break; | ||
3359 | } | ||
3360 | } | ||
3361 | } | ||
3463 | 3362 | ||
3464 | dispc_init_fifos(); | 3363 | if (errors & DISPC_IRQ_SYNC_LOST) { |
3364 | struct omap_overlay_manager *manager = NULL; | ||
3365 | bool enable = false; | ||
3465 | 3366 | ||
3466 | dispc_configure_burst_sizes(); | 3367 | DSSERR("SYNC_LOST, disabling LCD\n"); |
3467 | 3368 | ||
3468 | dispc_ovl_enable_zorder_planes(); | 3369 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
3469 | } | 3370 | struct omap_overlay_manager *mgr; |
3470 | 3371 | mgr = omap_dss_get_overlay_manager(i); | |
3471 | static const struct dispc_features omap24xx_dispc_feats __initconst = { | ||
3472 | .sw_start = 5, | ||
3473 | .fp_start = 15, | ||
3474 | .bp_start = 27, | ||
3475 | .sw_max = 64, | ||
3476 | .vp_max = 255, | ||
3477 | .hp_max = 256, | ||
3478 | .mgr_width_start = 10, | ||
3479 | .mgr_height_start = 26, | ||
3480 | .mgr_width_max = 2048, | ||
3481 | .mgr_height_max = 2048, | ||
3482 | .calc_scaling = dispc_ovl_calc_scaling_24xx, | ||
3483 | .calc_core_clk = calc_core_clk_24xx, | ||
3484 | .num_fifos = 3, | ||
3485 | .no_framedone_tv = true, | ||
3486 | }; | ||
3487 | 3372 | ||
3488 | static const struct dispc_features omap34xx_rev1_0_dispc_feats __initconst = { | 3373 | if (mgr->id == OMAP_DSS_CHANNEL_LCD) { |
3489 | .sw_start = 5, | 3374 | manager = mgr; |
3490 | .fp_start = 15, | 3375 | enable = mgr->device->state == |
3491 | .bp_start = 27, | 3376 | OMAP_DSS_DISPLAY_ACTIVE; |
3492 | .sw_max = 64, | 3377 | mgr->device->driver->disable(mgr->device); |
3493 | .vp_max = 255, | 3378 | break; |
3494 | .hp_max = 256, | 3379 | } |
3495 | .mgr_width_start = 10, | 3380 | } |
3496 | .mgr_height_start = 26, | ||
3497 | .mgr_width_max = 2048, | ||
3498 | .mgr_height_max = 2048, | ||
3499 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | ||
3500 | .calc_core_clk = calc_core_clk_34xx, | ||
3501 | .num_fifos = 3, | ||
3502 | .no_framedone_tv = true, | ||
3503 | }; | ||
3504 | 3381 | ||
3505 | static const struct dispc_features omap34xx_rev3_0_dispc_feats __initconst = { | 3382 | if (manager) { |
3506 | .sw_start = 7, | 3383 | struct omap_dss_device *dssdev = manager->device; |
3507 | .fp_start = 19, | 3384 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { |
3508 | .bp_start = 31, | 3385 | struct omap_overlay *ovl; |
3509 | .sw_max = 256, | 3386 | ovl = omap_dss_get_overlay(i); |
3510 | .vp_max = 4095, | ||
3511 | .hp_max = 4096, | ||
3512 | .mgr_width_start = 10, | ||
3513 | .mgr_height_start = 26, | ||
3514 | .mgr_width_max = 2048, | ||
3515 | .mgr_height_max = 2048, | ||
3516 | .calc_scaling = dispc_ovl_calc_scaling_34xx, | ||
3517 | .calc_core_clk = calc_core_clk_34xx, | ||
3518 | .num_fifos = 3, | ||
3519 | .no_framedone_tv = true, | ||
3520 | }; | ||
3521 | 3387 | ||
3522 | static const struct dispc_features omap44xx_dispc_feats __initconst = { | 3388 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) |
3523 | .sw_start = 7, | 3389 | continue; |
3524 | .fp_start = 19, | ||
3525 | .bp_start = 31, | ||
3526 | .sw_max = 256, | ||
3527 | .vp_max = 4095, | ||
3528 | .hp_max = 4096, | ||
3529 | .mgr_width_start = 10, | ||
3530 | .mgr_height_start = 26, | ||
3531 | .mgr_width_max = 2048, | ||
3532 | .mgr_height_max = 2048, | ||
3533 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | ||
3534 | .calc_core_clk = calc_core_clk_44xx, | ||
3535 | .num_fifos = 5, | ||
3536 | .gfx_fifo_workaround = true, | ||
3537 | }; | ||
3538 | 3390 | ||
3539 | static const struct dispc_features omap54xx_dispc_feats __initconst = { | 3391 | if (ovl->id != 0 && ovl->manager == manager) |
3540 | .sw_start = 7, | 3392 | dispc_enable_plane(ovl->id, 0); |
3541 | .fp_start = 19, | 3393 | } |
3542 | .bp_start = 31, | ||
3543 | .sw_max = 256, | ||
3544 | .vp_max = 4095, | ||
3545 | .hp_max = 4096, | ||
3546 | .mgr_width_start = 11, | ||
3547 | .mgr_height_start = 27, | ||
3548 | .mgr_width_max = 4096, | ||
3549 | .mgr_height_max = 4096, | ||
3550 | .calc_scaling = dispc_ovl_calc_scaling_44xx, | ||
3551 | .calc_core_clk = calc_core_clk_44xx, | ||
3552 | .num_fifos = 5, | ||
3553 | .gfx_fifo_workaround = true, | ||
3554 | }; | ||
3555 | 3394 | ||
3556 | static int __init dispc_init_features(struct platform_device *pdev) | 3395 | dispc_go(manager->id); |
3557 | { | 3396 | mdelay(50); |
3558 | const struct dispc_features *src; | 3397 | if (enable) |
3559 | struct dispc_features *dst; | 3398 | dssdev->driver->enable(dssdev); |
3399 | } | ||
3400 | } | ||
3560 | 3401 | ||
3561 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); | 3402 | if (errors & DISPC_IRQ_SYNC_LOST_DIGIT) { |
3562 | if (!dst) { | 3403 | struct omap_overlay_manager *manager = NULL; |
3563 | dev_err(&pdev->dev, "Failed to allocate DISPC Features\n"); | 3404 | bool enable = false; |
3564 | return -ENOMEM; | 3405 | |
3406 | DSSERR("SYNC_LOST_DIGIT, disabling TV\n"); | ||
3407 | |||
3408 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
3409 | struct omap_overlay_manager *mgr; | ||
3410 | mgr = omap_dss_get_overlay_manager(i); | ||
3411 | |||
3412 | if (mgr->id == OMAP_DSS_CHANNEL_DIGIT) { | ||
3413 | manager = mgr; | ||
3414 | enable = mgr->device->state == | ||
3415 | OMAP_DSS_DISPLAY_ACTIVE; | ||
3416 | mgr->device->driver->disable(mgr->device); | ||
3417 | break; | ||
3418 | } | ||
3419 | } | ||
3420 | |||
3421 | if (manager) { | ||
3422 | struct omap_dss_device *dssdev = manager->device; | ||
3423 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
3424 | struct omap_overlay *ovl; | ||
3425 | ovl = omap_dss_get_overlay(i); | ||
3426 | |||
3427 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) | ||
3428 | continue; | ||
3429 | |||
3430 | if (ovl->id != 0 && ovl->manager == manager) | ||
3431 | dispc_enable_plane(ovl->id, 0); | ||
3432 | } | ||
3433 | |||
3434 | dispc_go(manager->id); | ||
3435 | mdelay(50); | ||
3436 | if (enable) | ||
3437 | dssdev->driver->enable(dssdev); | ||
3438 | } | ||
3565 | } | 3439 | } |
3566 | 3440 | ||
3567 | switch (omapdss_get_version()) { | 3441 | if (errors & DISPC_IRQ_SYNC_LOST2) { |
3568 | case OMAPDSS_VER_OMAP24xx: | 3442 | struct omap_overlay_manager *manager = NULL; |
3569 | src = &omap24xx_dispc_feats; | 3443 | bool enable = false; |
3570 | break; | ||
3571 | 3444 | ||
3572 | case OMAPDSS_VER_OMAP34xx_ES1: | 3445 | DSSERR("SYNC_LOST for LCD2, disabling LCD2\n"); |
3573 | src = &omap34xx_rev1_0_dispc_feats; | ||
3574 | break; | ||
3575 | 3446 | ||
3576 | case OMAPDSS_VER_OMAP34xx_ES3: | 3447 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
3577 | case OMAPDSS_VER_OMAP3630: | 3448 | struct omap_overlay_manager *mgr; |
3578 | case OMAPDSS_VER_AM35xx: | 3449 | mgr = omap_dss_get_overlay_manager(i); |
3579 | src = &omap34xx_rev3_0_dispc_feats; | ||
3580 | break; | ||
3581 | 3450 | ||
3582 | case OMAPDSS_VER_OMAP4430_ES1: | 3451 | if (mgr->id == OMAP_DSS_CHANNEL_LCD2) { |
3583 | case OMAPDSS_VER_OMAP4430_ES2: | 3452 | manager = mgr; |
3584 | case OMAPDSS_VER_OMAP4: | 3453 | enable = mgr->device->state == |
3585 | src = &omap44xx_dispc_feats; | 3454 | OMAP_DSS_DISPLAY_ACTIVE; |
3586 | break; | 3455 | mgr->device->driver->disable(mgr->device); |
3456 | break; | ||
3457 | } | ||
3458 | } | ||
3587 | 3459 | ||
3588 | case OMAPDSS_VER_OMAP5: | 3460 | if (manager) { |
3589 | src = &omap54xx_dispc_feats; | 3461 | struct omap_dss_device *dssdev = manager->device; |
3590 | break; | 3462 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { |
3463 | struct omap_overlay *ovl; | ||
3464 | ovl = omap_dss_get_overlay(i); | ||
3591 | 3465 | ||
3592 | default: | 3466 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) |
3593 | return -ENODEV; | 3467 | continue; |
3468 | |||
3469 | if (ovl->id != 0 && ovl->manager == manager) | ||
3470 | dispc_enable_plane(ovl->id, 0); | ||
3471 | } | ||
3472 | |||
3473 | dispc_go(manager->id); | ||
3474 | mdelay(50); | ||
3475 | if (enable) | ||
3476 | dssdev->driver->enable(dssdev); | ||
3477 | } | ||
3478 | } | ||
3479 | |||
3480 | if (errors & DISPC_IRQ_OCP_ERR) { | ||
3481 | DSSERR("OCP_ERR\n"); | ||
3482 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
3483 | struct omap_overlay_manager *mgr; | ||
3484 | mgr = omap_dss_get_overlay_manager(i); | ||
3485 | |||
3486 | if (mgr->caps & OMAP_DSS_OVL_CAP_DISPC) | ||
3487 | mgr->device->driver->disable(mgr->device); | ||
3488 | } | ||
3489 | } | ||
3490 | |||
3491 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
3492 | dispc.irq_error_mask |= errors; | ||
3493 | _omap_dispc_set_irqs(); | ||
3494 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
3495 | } | ||
3496 | |||
3497 | int omap_dispc_wait_for_irq_timeout(u32 irqmask, unsigned long timeout) | ||
3498 | { | ||
3499 | void dispc_irq_wait_handler(void *data, u32 mask) | ||
3500 | { | ||
3501 | complete((struct completion *)data); | ||
3594 | } | 3502 | } |
3595 | 3503 | ||
3596 | memcpy(dst, src, sizeof(*dst)); | 3504 | int r; |
3597 | dispc.feat = dst; | 3505 | DECLARE_COMPLETION_ONSTACK(completion); |
3506 | |||
3507 | r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, | ||
3508 | irqmask); | ||
3509 | |||
3510 | if (r) | ||
3511 | return r; | ||
3512 | |||
3513 | timeout = wait_for_completion_timeout(&completion, timeout); | ||
3514 | |||
3515 | omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); | ||
3516 | |||
3517 | if (timeout == 0) | ||
3518 | return -ETIMEDOUT; | ||
3519 | |||
3520 | if (timeout == -ERESTARTSYS) | ||
3521 | return -ERESTARTSYS; | ||
3598 | 3522 | ||
3599 | return 0; | 3523 | return 0; |
3600 | } | 3524 | } |
3601 | 3525 | ||
3602 | int dispc_request_irq(irq_handler_t handler, void *dev_id) | 3526 | int omap_dispc_wait_for_irq_interruptible_timeout(u32 irqmask, |
3527 | unsigned long timeout) | ||
3603 | { | 3528 | { |
3604 | return devm_request_irq(&dispc.pdev->dev, dispc.irq, handler, | 3529 | void dispc_irq_wait_handler(void *data, u32 mask) |
3605 | IRQF_SHARED, "OMAP DISPC", dev_id); | 3530 | { |
3531 | complete((struct completion *)data); | ||
3532 | } | ||
3533 | |||
3534 | int r; | ||
3535 | DECLARE_COMPLETION_ONSTACK(completion); | ||
3536 | |||
3537 | r = omap_dispc_register_isr(dispc_irq_wait_handler, &completion, | ||
3538 | irqmask); | ||
3539 | |||
3540 | if (r) | ||
3541 | return r; | ||
3542 | |||
3543 | timeout = wait_for_completion_interruptible_timeout(&completion, | ||
3544 | timeout); | ||
3545 | |||
3546 | omap_dispc_unregister_isr(dispc_irq_wait_handler, &completion, irqmask); | ||
3547 | |||
3548 | if (timeout == 0) | ||
3549 | return -ETIMEDOUT; | ||
3550 | |||
3551 | if (timeout == -ERESTARTSYS) | ||
3552 | return -ERESTARTSYS; | ||
3553 | |||
3554 | return 0; | ||
3606 | } | 3555 | } |
3607 | EXPORT_SYMBOL(dispc_request_irq); | ||
3608 | 3556 | ||
3609 | void dispc_free_irq(void *dev_id) | 3557 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC |
3558 | void dispc_fake_vsync_irq(void) | ||
3610 | { | 3559 | { |
3611 | devm_free_irq(&dispc.pdev->dev, dispc.irq, dev_id); | 3560 | u32 irqstatus = DISPC_IRQ_VSYNC; |
3561 | int i; | ||
3562 | |||
3563 | WARN_ON(!in_interrupt()); | ||
3564 | |||
3565 | for (i = 0; i < DISPC_MAX_NR_ISRS; i++) { | ||
3566 | struct omap_dispc_isr_data *isr_data; | ||
3567 | isr_data = &dispc.registered_isr[i]; | ||
3568 | |||
3569 | if (!isr_data->isr) | ||
3570 | continue; | ||
3571 | |||
3572 | if (isr_data->mask & irqstatus) | ||
3573 | isr_data->isr(isr_data->arg, irqstatus); | ||
3574 | } | ||
3575 | } | ||
3576 | #endif | ||
3577 | |||
3578 | static void _omap_dispc_initialize_irq(void) | ||
3579 | { | ||
3580 | unsigned long flags; | ||
3581 | |||
3582 | spin_lock_irqsave(&dispc.irq_lock, flags); | ||
3583 | |||
3584 | memset(dispc.registered_isr, 0, sizeof(dispc.registered_isr)); | ||
3585 | |||
3586 | dispc.irq_error_mask = DISPC_IRQ_MASK_ERROR; | ||
3587 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
3588 | dispc.irq_error_mask |= DISPC_IRQ_SYNC_LOST2; | ||
3589 | |||
3590 | /* there's SYNC_LOST_DIGIT waiting after enabling the DSS, | ||
3591 | * so clear it */ | ||
3592 | dispc_write_reg(DISPC_IRQSTATUS, dispc_read_reg(DISPC_IRQSTATUS)); | ||
3593 | |||
3594 | _omap_dispc_set_irqs(); | ||
3595 | |||
3596 | spin_unlock_irqrestore(&dispc.irq_lock, flags); | ||
3597 | } | ||
3598 | |||
3599 | void dispc_enable_sidle(void) | ||
3600 | { | ||
3601 | REG_FLD_MOD(DISPC_SYSCONFIG, 2, 4, 3); /* SIDLEMODE: smart idle */ | ||
3602 | } | ||
3603 | |||
3604 | void dispc_disable_sidle(void) | ||
3605 | { | ||
3606 | REG_FLD_MOD(DISPC_SYSCONFIG, 1, 4, 3); /* SIDLEMODE: no idle */ | ||
3607 | } | ||
3608 | |||
3609 | static void _omap_dispc_initial_config(void) | ||
3610 | { | ||
3611 | u32 l; | ||
3612 | |||
3613 | /* Exclusively enable DISPC_CORE_CLK and set divider to 1 */ | ||
3614 | if (dss_has_feature(FEAT_CORE_CLK_DIV)) { | ||
3615 | l = dispc_read_reg(DISPC_DIVISOR); | ||
3616 | /* Use DISPC_DIVISOR.LCD, instead of DISPC_DIVISOR1.LCD */ | ||
3617 | l = FLD_MOD(l, 1, 0, 0); | ||
3618 | l = FLD_MOD(l, 1, 23, 16); | ||
3619 | dispc_write_reg(DISPC_DIVISOR, l); | ||
3620 | } | ||
3621 | |||
3622 | /* FUNCGATED */ | ||
3623 | if (dss_has_feature(FEAT_FUNCGATED)) | ||
3624 | REG_FLD_MOD(DISPC_CONFIG, 1, 9, 9); | ||
3625 | |||
3626 | /* L3 firewall setting: enable access to OCM RAM */ | ||
3627 | /* XXX this should be somewhere in plat-omap */ | ||
3628 | if (cpu_is_omap24xx()) | ||
3629 | __raw_writel(0x402000b0, OMAP2_L3_IO_ADDRESS(0x680050a0)); | ||
3630 | |||
3631 | _dispc_setup_color_conv_coef(); | ||
3632 | |||
3633 | dispc_set_loadmode(OMAP_DSS_LOAD_FRAME_ONLY); | ||
3634 | |||
3635 | dispc_read_plane_fifo_sizes(); | ||
3636 | |||
3637 | dispc_configure_burst_sizes(); | ||
3612 | } | 3638 | } |
3613 | EXPORT_SYMBOL(dispc_free_irq); | ||
3614 | 3639 | ||
3615 | /* DISPC HW IP initialisation */ | 3640 | /* DISPC HW IP initialisation */ |
3616 | static int __init omap_dispchw_probe(struct platform_device *pdev) | 3641 | static int omap_dispchw_probe(struct platform_device *pdev) |
3617 | { | 3642 | { |
3618 | u32 rev; | 3643 | u32 rev; |
3619 | int r = 0; | 3644 | int r = 0; |
3620 | struct resource *dispc_mem; | 3645 | struct resource *dispc_mem; |
3646 | struct clk *clk; | ||
3621 | 3647 | ||
3622 | dispc.pdev = pdev; | 3648 | dispc.pdev = pdev; |
3623 | 3649 | ||
3624 | r = dispc_init_features(dispc.pdev); | 3650 | clk = clk_get(&pdev->dev, "fck"); |
3625 | if (r) | 3651 | if (IS_ERR(clk)) { |
3626 | return r; | 3652 | DSSERR("can't get fck\n"); |
3653 | r = PTR_ERR(clk); | ||
3654 | goto err_get_clk; | ||
3655 | } | ||
3656 | |||
3657 | dispc.dss_clk = clk; | ||
3658 | |||
3659 | spin_lock_init(&dispc.irq_lock); | ||
3660 | |||
3661 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
3662 | spin_lock_init(&dispc.irq_stats_lock); | ||
3663 | dispc.irq_stats.last_reset = jiffies; | ||
3664 | #endif | ||
3665 | |||
3666 | INIT_WORK(&dispc.error_work, dispc_error_worker); | ||
3627 | 3667 | ||
3628 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); | 3668 | dispc_mem = platform_get_resource(dispc.pdev, IORESOURCE_MEM, 0); |
3629 | if (!dispc_mem) { | 3669 | if (!dispc_mem) { |
3630 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); | 3670 | DSSERR("can't get IORESOURCE_MEM DISPC\n"); |
3631 | return -EINVAL; | 3671 | r = -EINVAL; |
3672 | goto err_ioremap; | ||
3632 | } | 3673 | } |
3633 | 3674 | dispc.base = ioremap(dispc_mem->start, resource_size(dispc_mem)); | |
3634 | dispc.base = devm_ioremap(&pdev->dev, dispc_mem->start, | ||
3635 | resource_size(dispc_mem)); | ||
3636 | if (!dispc.base) { | 3675 | if (!dispc.base) { |
3637 | DSSERR("can't ioremap DISPC\n"); | 3676 | DSSERR("can't ioremap DISPC\n"); |
3638 | return -ENOMEM; | 3677 | r = -ENOMEM; |
3678 | goto err_ioremap; | ||
3639 | } | 3679 | } |
3640 | |||
3641 | dispc.irq = platform_get_irq(dispc.pdev, 0); | 3680 | dispc.irq = platform_get_irq(dispc.pdev, 0); |
3642 | if (dispc.irq < 0) { | 3681 | if (dispc.irq < 0) { |
3643 | DSSERR("platform_get_irq failed\n"); | 3682 | DSSERR("platform_get_irq failed\n"); |
3644 | return -ENODEV; | 3683 | r = -ENODEV; |
3684 | goto err_irq; | ||
3685 | } | ||
3686 | |||
3687 | r = request_irq(dispc.irq, omap_dispc_irq_handler, IRQF_SHARED, | ||
3688 | "OMAP DISPC", dispc.pdev); | ||
3689 | if (r < 0) { | ||
3690 | DSSERR("request_irq failed\n"); | ||
3691 | goto err_irq; | ||
3645 | } | 3692 | } |
3646 | 3693 | ||
3647 | pm_runtime_enable(&pdev->dev); | 3694 | pm_runtime_enable(&pdev->dev); |
@@ -3652,37 +3699,56 @@ static int __init omap_dispchw_probe(struct platform_device *pdev) | |||
3652 | 3699 | ||
3653 | _omap_dispc_initial_config(); | 3700 | _omap_dispc_initial_config(); |
3654 | 3701 | ||
3702 | _omap_dispc_initialize_irq(); | ||
3703 | |||
3655 | rev = dispc_read_reg(DISPC_REVISION); | 3704 | rev = dispc_read_reg(DISPC_REVISION); |
3656 | dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", | 3705 | dev_dbg(&pdev->dev, "OMAP DISPC rev %d.%d\n", |
3657 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 3706 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
3658 | 3707 | ||
3659 | dispc_runtime_put(); | 3708 | dispc_runtime_put(); |
3660 | 3709 | ||
3661 | dss_debugfs_create_file("dispc", dispc_dump_regs); | ||
3662 | |||
3663 | return 0; | 3710 | return 0; |
3664 | 3711 | ||
3665 | err_runtime_get: | 3712 | err_runtime_get: |
3666 | pm_runtime_disable(&pdev->dev); | 3713 | pm_runtime_disable(&pdev->dev); |
3714 | free_irq(dispc.irq, dispc.pdev); | ||
3715 | err_irq: | ||
3716 | iounmap(dispc.base); | ||
3717 | err_ioremap: | ||
3718 | clk_put(dispc.dss_clk); | ||
3719 | err_get_clk: | ||
3667 | return r; | 3720 | return r; |
3668 | } | 3721 | } |
3669 | 3722 | ||
3670 | static int __exit omap_dispchw_remove(struct platform_device *pdev) | 3723 | static int omap_dispchw_remove(struct platform_device *pdev) |
3671 | { | 3724 | { |
3672 | pm_runtime_disable(&pdev->dev); | 3725 | pm_runtime_disable(&pdev->dev); |
3673 | 3726 | ||
3727 | clk_put(dispc.dss_clk); | ||
3728 | |||
3729 | free_irq(dispc.irq, dispc.pdev); | ||
3730 | iounmap(dispc.base); | ||
3674 | return 0; | 3731 | return 0; |
3675 | } | 3732 | } |
3676 | 3733 | ||
3677 | static int dispc_runtime_suspend(struct device *dev) | 3734 | static int dispc_runtime_suspend(struct device *dev) |
3678 | { | 3735 | { |
3679 | dispc_save_context(); | 3736 | dispc_save_context(); |
3737 | clk_disable(dispc.dss_clk); | ||
3738 | dss_runtime_put(); | ||
3680 | 3739 | ||
3681 | return 0; | 3740 | return 0; |
3682 | } | 3741 | } |
3683 | 3742 | ||
3684 | static int dispc_runtime_resume(struct device *dev) | 3743 | static int dispc_runtime_resume(struct device *dev) |
3685 | { | 3744 | { |
3745 | int r; | ||
3746 | |||
3747 | r = dss_runtime_get(); | ||
3748 | if (r < 0) | ||
3749 | return r; | ||
3750 | |||
3751 | clk_enable(dispc.dss_clk); | ||
3686 | dispc_restore_context(); | 3752 | dispc_restore_context(); |
3687 | 3753 | ||
3688 | return 0; | 3754 | return 0; |
@@ -3694,7 +3760,8 @@ static const struct dev_pm_ops dispc_pm_ops = { | |||
3694 | }; | 3760 | }; |
3695 | 3761 | ||
3696 | static struct platform_driver omap_dispchw_driver = { | 3762 | static struct platform_driver omap_dispchw_driver = { |
3697 | .remove = __exit_p(omap_dispchw_remove), | 3763 | .probe = omap_dispchw_probe, |
3764 | .remove = omap_dispchw_remove, | ||
3698 | .driver = { | 3765 | .driver = { |
3699 | .name = "omapdss_dispc", | 3766 | .name = "omapdss_dispc", |
3700 | .owner = THIS_MODULE, | 3767 | .owner = THIS_MODULE, |
@@ -3702,12 +3769,12 @@ static struct platform_driver omap_dispchw_driver = { | |||
3702 | }, | 3769 | }, |
3703 | }; | 3770 | }; |
3704 | 3771 | ||
3705 | int __init dispc_init_platform_driver(void) | 3772 | int dispc_init_platform_driver(void) |
3706 | { | 3773 | { |
3707 | return platform_driver_probe(&omap_dispchw_driver, omap_dispchw_probe); | 3774 | return platform_driver_register(&omap_dispchw_driver); |
3708 | } | 3775 | } |
3709 | 3776 | ||
3710 | void __exit dispc_uninit_platform_driver(void) | 3777 | void dispc_uninit_platform_driver(void) |
3711 | { | 3778 | { |
3712 | platform_driver_unregister(&omap_dispchw_driver); | 3779 | return platform_driver_unregister(&omap_dispchw_driver); |
3713 | } | 3780 | } |
diff --git a/drivers/video/omap2/dss/dispc.h b/drivers/video/omap2/dss/dispc.h index 222363c6e62..6c9ee0a0efb 100644 --- a/drivers/video/omap2/dss/dispc.h +++ b/drivers/video/omap2/dss/dispc.h | |||
@@ -36,9 +36,6 @@ | |||
36 | #define DISPC_CONTROL2 0x0238 | 36 | #define DISPC_CONTROL2 0x0238 |
37 | #define DISPC_CONFIG2 0x0620 | 37 | #define DISPC_CONFIG2 0x0620 |
38 | #define DISPC_DIVISOR 0x0804 | 38 | #define DISPC_DIVISOR 0x0804 |
39 | #define DISPC_GLOBAL_BUFFER 0x0800 | ||
40 | #define DISPC_CONTROL3 0x0848 | ||
41 | #define DISPC_CONFIG3 0x084C | ||
42 | 39 | ||
43 | /* DISPC overlay registers */ | 40 | /* DISPC overlay registers */ |
44 | #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ | 41 | #define DISPC_OVL_BA0(n) (DISPC_OVL_BASE(n) + \ |
@@ -100,17 +97,6 @@ | |||
100 | #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ | 97 | #define DISPC_OVL_PRELOAD(n) (DISPC_OVL_BASE(n) + \ |
101 | DISPC_PRELOAD_OFFSET(n)) | 98 | DISPC_PRELOAD_OFFSET(n)) |
102 | 99 | ||
103 | /* DISPC up/downsampling FIR filter coefficient structure */ | ||
104 | struct dispc_coef { | ||
105 | s8 hc4_vc22; | ||
106 | s8 hc3_vc2; | ||
107 | u8 hc2_vc1; | ||
108 | s8 hc1_vc0; | ||
109 | s8 hc0_vc00; | ||
110 | }; | ||
111 | |||
112 | const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps); | ||
113 | |||
114 | /* DISPC manager/channel specific registers */ | 100 | /* DISPC manager/channel specific registers */ |
115 | static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) | 101 | static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) |
116 | { | 102 | { |
@@ -121,11 +107,8 @@ static inline u16 DISPC_DEFAULT_COLOR(enum omap_channel channel) | |||
121 | return 0x0050; | 107 | return 0x0050; |
122 | case OMAP_DSS_CHANNEL_LCD2: | 108 | case OMAP_DSS_CHANNEL_LCD2: |
123 | return 0x03AC; | 109 | return 0x03AC; |
124 | case OMAP_DSS_CHANNEL_LCD3: | ||
125 | return 0x0814; | ||
126 | default: | 110 | default: |
127 | BUG(); | 111 | BUG(); |
128 | return 0; | ||
129 | } | 112 | } |
130 | } | 113 | } |
131 | 114 | ||
@@ -138,11 +121,8 @@ static inline u16 DISPC_TRANS_COLOR(enum omap_channel channel) | |||
138 | return 0x0058; | 121 | return 0x0058; |
139 | case OMAP_DSS_CHANNEL_LCD2: | 122 | case OMAP_DSS_CHANNEL_LCD2: |
140 | return 0x03B0; | 123 | return 0x03B0; |
141 | case OMAP_DSS_CHANNEL_LCD3: | ||
142 | return 0x0818; | ||
143 | default: | 124 | default: |
144 | BUG(); | 125 | BUG(); |
145 | return 0; | ||
146 | } | 126 | } |
147 | } | 127 | } |
148 | 128 | ||
@@ -153,14 +133,10 @@ static inline u16 DISPC_TIMING_H(enum omap_channel channel) | |||
153 | return 0x0064; | 133 | return 0x0064; |
154 | case OMAP_DSS_CHANNEL_DIGIT: | 134 | case OMAP_DSS_CHANNEL_DIGIT: |
155 | BUG(); | 135 | BUG(); |
156 | return 0; | ||
157 | case OMAP_DSS_CHANNEL_LCD2: | 136 | case OMAP_DSS_CHANNEL_LCD2: |
158 | return 0x0400; | 137 | return 0x0400; |
159 | case OMAP_DSS_CHANNEL_LCD3: | ||
160 | return 0x0840; | ||
161 | default: | 138 | default: |
162 | BUG(); | 139 | BUG(); |
163 | return 0; | ||
164 | } | 140 | } |
165 | } | 141 | } |
166 | 142 | ||
@@ -171,14 +147,10 @@ static inline u16 DISPC_TIMING_V(enum omap_channel channel) | |||
171 | return 0x0068; | 147 | return 0x0068; |
172 | case OMAP_DSS_CHANNEL_DIGIT: | 148 | case OMAP_DSS_CHANNEL_DIGIT: |
173 | BUG(); | 149 | BUG(); |
174 | return 0; | ||
175 | case OMAP_DSS_CHANNEL_LCD2: | 150 | case OMAP_DSS_CHANNEL_LCD2: |
176 | return 0x0404; | 151 | return 0x0404; |
177 | case OMAP_DSS_CHANNEL_LCD3: | ||
178 | return 0x0844; | ||
179 | default: | 152 | default: |
180 | BUG(); | 153 | BUG(); |
181 | return 0; | ||
182 | } | 154 | } |
183 | } | 155 | } |
184 | 156 | ||
@@ -189,14 +161,10 @@ static inline u16 DISPC_POL_FREQ(enum omap_channel channel) | |||
189 | return 0x006C; | 161 | return 0x006C; |
190 | case OMAP_DSS_CHANNEL_DIGIT: | 162 | case OMAP_DSS_CHANNEL_DIGIT: |
191 | BUG(); | 163 | BUG(); |
192 | return 0; | ||
193 | case OMAP_DSS_CHANNEL_LCD2: | 164 | case OMAP_DSS_CHANNEL_LCD2: |
194 | return 0x0408; | 165 | return 0x0408; |
195 | case OMAP_DSS_CHANNEL_LCD3: | ||
196 | return 0x083C; | ||
197 | default: | 166 | default: |
198 | BUG(); | 167 | BUG(); |
199 | return 0; | ||
200 | } | 168 | } |
201 | } | 169 | } |
202 | 170 | ||
@@ -207,14 +175,10 @@ static inline u16 DISPC_DIVISORo(enum omap_channel channel) | |||
207 | return 0x0070; | 175 | return 0x0070; |
208 | case OMAP_DSS_CHANNEL_DIGIT: | 176 | case OMAP_DSS_CHANNEL_DIGIT: |
209 | BUG(); | 177 | BUG(); |
210 | return 0; | ||
211 | case OMAP_DSS_CHANNEL_LCD2: | 178 | case OMAP_DSS_CHANNEL_LCD2: |
212 | return 0x040C; | 179 | return 0x040C; |
213 | case OMAP_DSS_CHANNEL_LCD3: | ||
214 | return 0x0838; | ||
215 | default: | 180 | default: |
216 | BUG(); | 181 | BUG(); |
217 | return 0; | ||
218 | } | 182 | } |
219 | } | 183 | } |
220 | 184 | ||
@@ -228,11 +192,8 @@ static inline u16 DISPC_SIZE_MGR(enum omap_channel channel) | |||
228 | return 0x0078; | 192 | return 0x0078; |
229 | case OMAP_DSS_CHANNEL_LCD2: | 193 | case OMAP_DSS_CHANNEL_LCD2: |
230 | return 0x03CC; | 194 | return 0x03CC; |
231 | case OMAP_DSS_CHANNEL_LCD3: | ||
232 | return 0x0834; | ||
233 | default: | 195 | default: |
234 | BUG(); | 196 | BUG(); |
235 | return 0; | ||
236 | } | 197 | } |
237 | } | 198 | } |
238 | 199 | ||
@@ -243,14 +204,10 @@ static inline u16 DISPC_DATA_CYCLE1(enum omap_channel channel) | |||
243 | return 0x01D4; | 204 | return 0x01D4; |
244 | case OMAP_DSS_CHANNEL_DIGIT: | 205 | case OMAP_DSS_CHANNEL_DIGIT: |
245 | BUG(); | 206 | BUG(); |
246 | return 0; | ||
247 | case OMAP_DSS_CHANNEL_LCD2: | 207 | case OMAP_DSS_CHANNEL_LCD2: |
248 | return 0x03C0; | 208 | return 0x03C0; |
249 | case OMAP_DSS_CHANNEL_LCD3: | ||
250 | return 0x0828; | ||
251 | default: | 209 | default: |
252 | BUG(); | 210 | BUG(); |
253 | return 0; | ||
254 | } | 211 | } |
255 | } | 212 | } |
256 | 213 | ||
@@ -261,14 +218,10 @@ static inline u16 DISPC_DATA_CYCLE2(enum omap_channel channel) | |||
261 | return 0x01D8; | 218 | return 0x01D8; |
262 | case OMAP_DSS_CHANNEL_DIGIT: | 219 | case OMAP_DSS_CHANNEL_DIGIT: |
263 | BUG(); | 220 | BUG(); |
264 | return 0; | ||
265 | case OMAP_DSS_CHANNEL_LCD2: | 221 | case OMAP_DSS_CHANNEL_LCD2: |
266 | return 0x03C4; | 222 | return 0x03C4; |
267 | case OMAP_DSS_CHANNEL_LCD3: | ||
268 | return 0x082C; | ||
269 | default: | 223 | default: |
270 | BUG(); | 224 | BUG(); |
271 | return 0; | ||
272 | } | 225 | } |
273 | } | 226 | } |
274 | 227 | ||
@@ -279,14 +232,10 @@ static inline u16 DISPC_DATA_CYCLE3(enum omap_channel channel) | |||
279 | return 0x01DC; | 232 | return 0x01DC; |
280 | case OMAP_DSS_CHANNEL_DIGIT: | 233 | case OMAP_DSS_CHANNEL_DIGIT: |
281 | BUG(); | 234 | BUG(); |
282 | return 0; | ||
283 | case OMAP_DSS_CHANNEL_LCD2: | 235 | case OMAP_DSS_CHANNEL_LCD2: |
284 | return 0x03C8; | 236 | return 0x03C8; |
285 | case OMAP_DSS_CHANNEL_LCD3: | ||
286 | return 0x0830; | ||
287 | default: | 237 | default: |
288 | BUG(); | 238 | BUG(); |
289 | return 0; | ||
290 | } | 239 | } |
291 | } | 240 | } |
292 | 241 | ||
@@ -297,14 +246,10 @@ static inline u16 DISPC_CPR_COEF_R(enum omap_channel channel) | |||
297 | return 0x0220; | 246 | return 0x0220; |
298 | case OMAP_DSS_CHANNEL_DIGIT: | 247 | case OMAP_DSS_CHANNEL_DIGIT: |
299 | BUG(); | 248 | BUG(); |
300 | return 0; | ||
301 | case OMAP_DSS_CHANNEL_LCD2: | 249 | case OMAP_DSS_CHANNEL_LCD2: |
302 | return 0x03BC; | 250 | return 0x03BC; |
303 | case OMAP_DSS_CHANNEL_LCD3: | ||
304 | return 0x0824; | ||
305 | default: | 251 | default: |
306 | BUG(); | 252 | BUG(); |
307 | return 0; | ||
308 | } | 253 | } |
309 | } | 254 | } |
310 | 255 | ||
@@ -315,14 +260,10 @@ static inline u16 DISPC_CPR_COEF_G(enum omap_channel channel) | |||
315 | return 0x0224; | 260 | return 0x0224; |
316 | case OMAP_DSS_CHANNEL_DIGIT: | 261 | case OMAP_DSS_CHANNEL_DIGIT: |
317 | BUG(); | 262 | BUG(); |
318 | return 0; | ||
319 | case OMAP_DSS_CHANNEL_LCD2: | 263 | case OMAP_DSS_CHANNEL_LCD2: |
320 | return 0x03B8; | 264 | return 0x03B8; |
321 | case OMAP_DSS_CHANNEL_LCD3: | ||
322 | return 0x0820; | ||
323 | default: | 265 | default: |
324 | BUG(); | 266 | BUG(); |
325 | return 0; | ||
326 | } | 267 | } |
327 | } | 268 | } |
328 | 269 | ||
@@ -333,14 +274,10 @@ static inline u16 DISPC_CPR_COEF_B(enum omap_channel channel) | |||
333 | return 0x0228; | 274 | return 0x0228; |
334 | case OMAP_DSS_CHANNEL_DIGIT: | 275 | case OMAP_DSS_CHANNEL_DIGIT: |
335 | BUG(); | 276 | BUG(); |
336 | return 0; | ||
337 | case OMAP_DSS_CHANNEL_LCD2: | 277 | case OMAP_DSS_CHANNEL_LCD2: |
338 | return 0x03B4; | 278 | return 0x03B4; |
339 | case OMAP_DSS_CHANNEL_LCD3: | ||
340 | return 0x081C; | ||
341 | default: | 279 | default: |
342 | BUG(); | 280 | BUG(); |
343 | return 0; | ||
344 | } | 281 | } |
345 | } | 282 | } |
346 | 283 | ||
@@ -354,13 +291,8 @@ static inline u16 DISPC_OVL_BASE(enum omap_plane plane) | |||
354 | return 0x00BC; | 291 | return 0x00BC; |
355 | case OMAP_DSS_VIDEO2: | 292 | case OMAP_DSS_VIDEO2: |
356 | return 0x014C; | 293 | return 0x014C; |
357 | case OMAP_DSS_VIDEO3: | ||
358 | return 0x0300; | ||
359 | case OMAP_DSS_WB: | ||
360 | return 0x0500; | ||
361 | default: | 294 | default: |
362 | BUG(); | 295 | BUG(); |
363 | return 0; | ||
364 | } | 296 | } |
365 | } | 297 | } |
366 | 298 | ||
@@ -372,12 +304,8 @@ static inline u16 DISPC_BA0_OFFSET(enum omap_plane plane) | |||
372 | case OMAP_DSS_VIDEO1: | 304 | case OMAP_DSS_VIDEO1: |
373 | case OMAP_DSS_VIDEO2: | 305 | case OMAP_DSS_VIDEO2: |
374 | return 0x0000; | 306 | return 0x0000; |
375 | case OMAP_DSS_VIDEO3: | ||
376 | case OMAP_DSS_WB: | ||
377 | return 0x0008; | ||
378 | default: | 307 | default: |
379 | BUG(); | 308 | BUG(); |
380 | return 0; | ||
381 | } | 309 | } |
382 | } | 310 | } |
383 | 311 | ||
@@ -388,12 +316,8 @@ static inline u16 DISPC_BA1_OFFSET(enum omap_plane plane) | |||
388 | case OMAP_DSS_VIDEO1: | 316 | case OMAP_DSS_VIDEO1: |
389 | case OMAP_DSS_VIDEO2: | 317 | case OMAP_DSS_VIDEO2: |
390 | return 0x0004; | 318 | return 0x0004; |
391 | case OMAP_DSS_VIDEO3: | ||
392 | case OMAP_DSS_WB: | ||
393 | return 0x000C; | ||
394 | default: | 319 | default: |
395 | BUG(); | 320 | BUG(); |
396 | return 0; | ||
397 | } | 321 | } |
398 | } | 322 | } |
399 | 323 | ||
@@ -402,18 +326,12 @@ static inline u16 DISPC_BA0_UV_OFFSET(enum omap_plane plane) | |||
402 | switch (plane) { | 326 | switch (plane) { |
403 | case OMAP_DSS_GFX: | 327 | case OMAP_DSS_GFX: |
404 | BUG(); | 328 | BUG(); |
405 | return 0; | ||
406 | case OMAP_DSS_VIDEO1: | 329 | case OMAP_DSS_VIDEO1: |
407 | return 0x0544; | 330 | return 0x0544; |
408 | case OMAP_DSS_VIDEO2: | 331 | case OMAP_DSS_VIDEO2: |
409 | return 0x04BC; | 332 | return 0x04BC; |
410 | case OMAP_DSS_VIDEO3: | ||
411 | return 0x0310; | ||
412 | case OMAP_DSS_WB: | ||
413 | return 0x0118; | ||
414 | default: | 333 | default: |
415 | BUG(); | 334 | BUG(); |
416 | return 0; | ||
417 | } | 335 | } |
418 | } | 336 | } |
419 | 337 | ||
@@ -422,18 +340,12 @@ static inline u16 DISPC_BA1_UV_OFFSET(enum omap_plane plane) | |||
422 | switch (plane) { | 340 | switch (plane) { |
423 | case OMAP_DSS_GFX: | 341 | case OMAP_DSS_GFX: |
424 | BUG(); | 342 | BUG(); |
425 | return 0; | ||
426 | case OMAP_DSS_VIDEO1: | 343 | case OMAP_DSS_VIDEO1: |
427 | return 0x0548; | 344 | return 0x0548; |
428 | case OMAP_DSS_VIDEO2: | 345 | case OMAP_DSS_VIDEO2: |
429 | return 0x04C0; | 346 | return 0x04C0; |
430 | case OMAP_DSS_VIDEO3: | ||
431 | return 0x0314; | ||
432 | case OMAP_DSS_WB: | ||
433 | return 0x011C; | ||
434 | default: | 347 | default: |
435 | BUG(); | 348 | BUG(); |
436 | return 0; | ||
437 | } | 349 | } |
438 | } | 350 | } |
439 | 351 | ||
@@ -444,11 +356,8 @@ static inline u16 DISPC_POS_OFFSET(enum omap_plane plane) | |||
444 | case OMAP_DSS_VIDEO1: | 356 | case OMAP_DSS_VIDEO1: |
445 | case OMAP_DSS_VIDEO2: | 357 | case OMAP_DSS_VIDEO2: |
446 | return 0x0008; | 358 | return 0x0008; |
447 | case OMAP_DSS_VIDEO3: | ||
448 | return 0x009C; | ||
449 | default: | 359 | default: |
450 | BUG(); | 360 | BUG(); |
451 | return 0; | ||
452 | } | 361 | } |
453 | } | 362 | } |
454 | 363 | ||
@@ -459,12 +368,8 @@ static inline u16 DISPC_SIZE_OFFSET(enum omap_plane plane) | |||
459 | case OMAP_DSS_VIDEO1: | 368 | case OMAP_DSS_VIDEO1: |
460 | case OMAP_DSS_VIDEO2: | 369 | case OMAP_DSS_VIDEO2: |
461 | return 0x000C; | 370 | return 0x000C; |
462 | case OMAP_DSS_VIDEO3: | ||
463 | case OMAP_DSS_WB: | ||
464 | return 0x00A8; | ||
465 | default: | 371 | default: |
466 | BUG(); | 372 | BUG(); |
467 | return 0; | ||
468 | } | 373 | } |
469 | } | 374 | } |
470 | 375 | ||
@@ -476,12 +381,8 @@ static inline u16 DISPC_ATTR_OFFSET(enum omap_plane plane) | |||
476 | case OMAP_DSS_VIDEO1: | 381 | case OMAP_DSS_VIDEO1: |
477 | case OMAP_DSS_VIDEO2: | 382 | case OMAP_DSS_VIDEO2: |
478 | return 0x0010; | 383 | return 0x0010; |
479 | case OMAP_DSS_VIDEO3: | ||
480 | case OMAP_DSS_WB: | ||
481 | return 0x0070; | ||
482 | default: | 384 | default: |
483 | BUG(); | 385 | BUG(); |
484 | return 0; | ||
485 | } | 386 | } |
486 | } | 387 | } |
487 | 388 | ||
@@ -490,18 +391,12 @@ static inline u16 DISPC_ATTR2_OFFSET(enum omap_plane plane) | |||
490 | switch (plane) { | 391 | switch (plane) { |
491 | case OMAP_DSS_GFX: | 392 | case OMAP_DSS_GFX: |
492 | BUG(); | 393 | BUG(); |
493 | return 0; | ||
494 | case OMAP_DSS_VIDEO1: | 394 | case OMAP_DSS_VIDEO1: |
495 | return 0x0568; | 395 | return 0x0568; |
496 | case OMAP_DSS_VIDEO2: | 396 | case OMAP_DSS_VIDEO2: |
497 | return 0x04DC; | 397 | return 0x04DC; |
498 | case OMAP_DSS_VIDEO3: | ||
499 | return 0x032C; | ||
500 | case OMAP_DSS_WB: | ||
501 | return 0x0310; | ||
502 | default: | 398 | default: |
503 | BUG(); | 399 | BUG(); |
504 | return 0; | ||
505 | } | 400 | } |
506 | } | 401 | } |
507 | 402 | ||
@@ -513,12 +408,8 @@ static inline u16 DISPC_FIFO_THRESH_OFFSET(enum omap_plane plane) | |||
513 | case OMAP_DSS_VIDEO1: | 408 | case OMAP_DSS_VIDEO1: |
514 | case OMAP_DSS_VIDEO2: | 409 | case OMAP_DSS_VIDEO2: |
515 | return 0x0014; | 410 | return 0x0014; |
516 | case OMAP_DSS_VIDEO3: | ||
517 | case OMAP_DSS_WB: | ||
518 | return 0x008C; | ||
519 | default: | 411 | default: |
520 | BUG(); | 412 | BUG(); |
521 | return 0; | ||
522 | } | 413 | } |
523 | } | 414 | } |
524 | 415 | ||
@@ -530,12 +421,8 @@ static inline u16 DISPC_FIFO_SIZE_STATUS_OFFSET(enum omap_plane plane) | |||
530 | case OMAP_DSS_VIDEO1: | 421 | case OMAP_DSS_VIDEO1: |
531 | case OMAP_DSS_VIDEO2: | 422 | case OMAP_DSS_VIDEO2: |
532 | return 0x0018; | 423 | return 0x0018; |
533 | case OMAP_DSS_VIDEO3: | ||
534 | case OMAP_DSS_WB: | ||
535 | return 0x0088; | ||
536 | default: | 424 | default: |
537 | BUG(); | 425 | BUG(); |
538 | return 0; | ||
539 | } | 426 | } |
540 | } | 427 | } |
541 | 428 | ||
@@ -547,12 +434,8 @@ static inline u16 DISPC_ROW_INC_OFFSET(enum omap_plane plane) | |||
547 | case OMAP_DSS_VIDEO1: | 434 | case OMAP_DSS_VIDEO1: |
548 | case OMAP_DSS_VIDEO2: | 435 | case OMAP_DSS_VIDEO2: |
549 | return 0x001C; | 436 | return 0x001C; |
550 | case OMAP_DSS_VIDEO3: | ||
551 | case OMAP_DSS_WB: | ||
552 | return 0x00A4; | ||
553 | default: | 437 | default: |
554 | BUG(); | 438 | BUG(); |
555 | return 0; | ||
556 | } | 439 | } |
557 | } | 440 | } |
558 | 441 | ||
@@ -564,12 +447,8 @@ static inline u16 DISPC_PIX_INC_OFFSET(enum omap_plane plane) | |||
564 | case OMAP_DSS_VIDEO1: | 447 | case OMAP_DSS_VIDEO1: |
565 | case OMAP_DSS_VIDEO2: | 448 | case OMAP_DSS_VIDEO2: |
566 | return 0x0020; | 449 | return 0x0020; |
567 | case OMAP_DSS_VIDEO3: | ||
568 | case OMAP_DSS_WB: | ||
569 | return 0x0098; | ||
570 | default: | 450 | default: |
571 | BUG(); | 451 | BUG(); |
572 | return 0; | ||
573 | } | 452 | } |
574 | } | 453 | } |
575 | 454 | ||
@@ -580,12 +459,9 @@ static inline u16 DISPC_WINDOW_SKIP_OFFSET(enum omap_plane plane) | |||
580 | return 0x0034; | 459 | return 0x0034; |
581 | case OMAP_DSS_VIDEO1: | 460 | case OMAP_DSS_VIDEO1: |
582 | case OMAP_DSS_VIDEO2: | 461 | case OMAP_DSS_VIDEO2: |
583 | case OMAP_DSS_VIDEO3: | ||
584 | BUG(); | 462 | BUG(); |
585 | return 0; | ||
586 | default: | 463 | default: |
587 | BUG(); | 464 | BUG(); |
588 | return 0; | ||
589 | } | 465 | } |
590 | } | 466 | } |
591 | 467 | ||
@@ -596,12 +472,9 @@ static inline u16 DISPC_TABLE_BA_OFFSET(enum omap_plane plane) | |||
596 | return 0x0038; | 472 | return 0x0038; |
597 | case OMAP_DSS_VIDEO1: | 473 | case OMAP_DSS_VIDEO1: |
598 | case OMAP_DSS_VIDEO2: | 474 | case OMAP_DSS_VIDEO2: |
599 | case OMAP_DSS_VIDEO3: | ||
600 | BUG(); | 475 | BUG(); |
601 | return 0; | ||
602 | default: | 476 | default: |
603 | BUG(); | 477 | BUG(); |
604 | return 0; | ||
605 | } | 478 | } |
606 | } | 479 | } |
607 | 480 | ||
@@ -610,16 +483,11 @@ static inline u16 DISPC_FIR_OFFSET(enum omap_plane plane) | |||
610 | switch (plane) { | 483 | switch (plane) { |
611 | case OMAP_DSS_GFX: | 484 | case OMAP_DSS_GFX: |
612 | BUG(); | 485 | BUG(); |
613 | return 0; | ||
614 | case OMAP_DSS_VIDEO1: | 486 | case OMAP_DSS_VIDEO1: |
615 | case OMAP_DSS_VIDEO2: | 487 | case OMAP_DSS_VIDEO2: |
616 | return 0x0024; | 488 | return 0x0024; |
617 | case OMAP_DSS_VIDEO3: | ||
618 | case OMAP_DSS_WB: | ||
619 | return 0x0090; | ||
620 | default: | 489 | default: |
621 | BUG(); | 490 | BUG(); |
622 | return 0; | ||
623 | } | 491 | } |
624 | } | 492 | } |
625 | 493 | ||
@@ -628,18 +496,12 @@ static inline u16 DISPC_FIR2_OFFSET(enum omap_plane plane) | |||
628 | switch (plane) { | 496 | switch (plane) { |
629 | case OMAP_DSS_GFX: | 497 | case OMAP_DSS_GFX: |
630 | BUG(); | 498 | BUG(); |
631 | return 0; | ||
632 | case OMAP_DSS_VIDEO1: | 499 | case OMAP_DSS_VIDEO1: |
633 | return 0x0580; | 500 | return 0x0580; |
634 | case OMAP_DSS_VIDEO2: | 501 | case OMAP_DSS_VIDEO2: |
635 | return 0x055C; | 502 | return 0x055C; |
636 | case OMAP_DSS_VIDEO3: | ||
637 | return 0x0424; | ||
638 | case OMAP_DSS_WB: | ||
639 | return 0x290; | ||
640 | default: | 503 | default: |
641 | BUG(); | 504 | BUG(); |
642 | return 0; | ||
643 | } | 505 | } |
644 | } | 506 | } |
645 | 507 | ||
@@ -648,16 +510,11 @@ static inline u16 DISPC_PIC_SIZE_OFFSET(enum omap_plane plane) | |||
648 | switch (plane) { | 510 | switch (plane) { |
649 | case OMAP_DSS_GFX: | 511 | case OMAP_DSS_GFX: |
650 | BUG(); | 512 | BUG(); |
651 | return 0; | ||
652 | case OMAP_DSS_VIDEO1: | 513 | case OMAP_DSS_VIDEO1: |
653 | case OMAP_DSS_VIDEO2: | 514 | case OMAP_DSS_VIDEO2: |
654 | return 0x0028; | 515 | return 0x0028; |
655 | case OMAP_DSS_VIDEO3: | ||
656 | case OMAP_DSS_WB: | ||
657 | return 0x0094; | ||
658 | default: | 516 | default: |
659 | BUG(); | 517 | BUG(); |
660 | return 0; | ||
661 | } | 518 | } |
662 | } | 519 | } |
663 | 520 | ||
@@ -667,16 +524,11 @@ static inline u16 DISPC_ACCU0_OFFSET(enum omap_plane plane) | |||
667 | switch (plane) { | 524 | switch (plane) { |
668 | case OMAP_DSS_GFX: | 525 | case OMAP_DSS_GFX: |
669 | BUG(); | 526 | BUG(); |
670 | return 0; | ||
671 | case OMAP_DSS_VIDEO1: | 527 | case OMAP_DSS_VIDEO1: |
672 | case OMAP_DSS_VIDEO2: | 528 | case OMAP_DSS_VIDEO2: |
673 | return 0x002C; | 529 | return 0x002C; |
674 | case OMAP_DSS_VIDEO3: | ||
675 | case OMAP_DSS_WB: | ||
676 | return 0x0000; | ||
677 | default: | 530 | default: |
678 | BUG(); | 531 | BUG(); |
679 | return 0; | ||
680 | } | 532 | } |
681 | } | 533 | } |
682 | 534 | ||
@@ -685,18 +537,12 @@ static inline u16 DISPC_ACCU2_0_OFFSET(enum omap_plane plane) | |||
685 | switch (plane) { | 537 | switch (plane) { |
686 | case OMAP_DSS_GFX: | 538 | case OMAP_DSS_GFX: |
687 | BUG(); | 539 | BUG(); |
688 | return 0; | ||
689 | case OMAP_DSS_VIDEO1: | 540 | case OMAP_DSS_VIDEO1: |
690 | return 0x0584; | 541 | return 0x0584; |
691 | case OMAP_DSS_VIDEO2: | 542 | case OMAP_DSS_VIDEO2: |
692 | return 0x0560; | 543 | return 0x0560; |
693 | case OMAP_DSS_VIDEO3: | ||
694 | return 0x0428; | ||
695 | case OMAP_DSS_WB: | ||
696 | return 0x0294; | ||
697 | default: | 544 | default: |
698 | BUG(); | 545 | BUG(); |
699 | return 0; | ||
700 | } | 546 | } |
701 | } | 547 | } |
702 | 548 | ||
@@ -705,16 +551,11 @@ static inline u16 DISPC_ACCU1_OFFSET(enum omap_plane plane) | |||
705 | switch (plane) { | 551 | switch (plane) { |
706 | case OMAP_DSS_GFX: | 552 | case OMAP_DSS_GFX: |
707 | BUG(); | 553 | BUG(); |
708 | return 0; | ||
709 | case OMAP_DSS_VIDEO1: | 554 | case OMAP_DSS_VIDEO1: |
710 | case OMAP_DSS_VIDEO2: | 555 | case OMAP_DSS_VIDEO2: |
711 | return 0x0030; | 556 | return 0x0030; |
712 | case OMAP_DSS_VIDEO3: | ||
713 | case OMAP_DSS_WB: | ||
714 | return 0x0004; | ||
715 | default: | 557 | default: |
716 | BUG(); | 558 | BUG(); |
717 | return 0; | ||
718 | } | 559 | } |
719 | } | 560 | } |
720 | 561 | ||
@@ -723,18 +564,12 @@ static inline u16 DISPC_ACCU2_1_OFFSET(enum omap_plane plane) | |||
723 | switch (plane) { | 564 | switch (plane) { |
724 | case OMAP_DSS_GFX: | 565 | case OMAP_DSS_GFX: |
725 | BUG(); | 566 | BUG(); |
726 | return 0; | ||
727 | case OMAP_DSS_VIDEO1: | 567 | case OMAP_DSS_VIDEO1: |
728 | return 0x0588; | 568 | return 0x0588; |
729 | case OMAP_DSS_VIDEO2: | 569 | case OMAP_DSS_VIDEO2: |
730 | return 0x0564; | 570 | return 0x0564; |
731 | case OMAP_DSS_VIDEO3: | ||
732 | return 0x042C; | ||
733 | case OMAP_DSS_WB: | ||
734 | return 0x0298; | ||
735 | default: | 571 | default: |
736 | BUG(); | 572 | BUG(); |
737 | return 0; | ||
738 | } | 573 | } |
739 | } | 574 | } |
740 | 575 | ||
@@ -744,16 +579,11 @@ static inline u16 DISPC_FIR_COEF_H_OFFSET(enum omap_plane plane, u16 i) | |||
744 | switch (plane) { | 579 | switch (plane) { |
745 | case OMAP_DSS_GFX: | 580 | case OMAP_DSS_GFX: |
746 | BUG(); | 581 | BUG(); |
747 | return 0; | ||
748 | case OMAP_DSS_VIDEO1: | 582 | case OMAP_DSS_VIDEO1: |
749 | case OMAP_DSS_VIDEO2: | 583 | case OMAP_DSS_VIDEO2: |
750 | return 0x0034 + i * 0x8; | 584 | return 0x0034 + i * 0x8; |
751 | case OMAP_DSS_VIDEO3: | ||
752 | case OMAP_DSS_WB: | ||
753 | return 0x0010 + i * 0x8; | ||
754 | default: | 585 | default: |
755 | BUG(); | 586 | BUG(); |
756 | return 0; | ||
757 | } | 587 | } |
758 | } | 588 | } |
759 | 589 | ||
@@ -763,18 +593,12 @@ static inline u16 DISPC_FIR_COEF_H2_OFFSET(enum omap_plane plane, u16 i) | |||
763 | switch (plane) { | 593 | switch (plane) { |
764 | case OMAP_DSS_GFX: | 594 | case OMAP_DSS_GFX: |
765 | BUG(); | 595 | BUG(); |
766 | return 0; | ||
767 | case OMAP_DSS_VIDEO1: | 596 | case OMAP_DSS_VIDEO1: |
768 | return 0x058C + i * 0x8; | 597 | return 0x058C + i * 0x8; |
769 | case OMAP_DSS_VIDEO2: | 598 | case OMAP_DSS_VIDEO2: |
770 | return 0x0568 + i * 0x8; | 599 | return 0x0568 + i * 0x8; |
771 | case OMAP_DSS_VIDEO3: | ||
772 | return 0x0430 + i * 0x8; | ||
773 | case OMAP_DSS_WB: | ||
774 | return 0x02A0 + i * 0x8; | ||
775 | default: | 600 | default: |
776 | BUG(); | 601 | BUG(); |
777 | return 0; | ||
778 | } | 602 | } |
779 | } | 603 | } |
780 | 604 | ||
@@ -784,16 +608,11 @@ static inline u16 DISPC_FIR_COEF_HV_OFFSET(enum omap_plane plane, u16 i) | |||
784 | switch (plane) { | 608 | switch (plane) { |
785 | case OMAP_DSS_GFX: | 609 | case OMAP_DSS_GFX: |
786 | BUG(); | 610 | BUG(); |
787 | return 0; | ||
788 | case OMAP_DSS_VIDEO1: | 611 | case OMAP_DSS_VIDEO1: |
789 | case OMAP_DSS_VIDEO2: | 612 | case OMAP_DSS_VIDEO2: |
790 | return 0x0038 + i * 0x8; | 613 | return 0x0038 + i * 0x8; |
791 | case OMAP_DSS_VIDEO3: | ||
792 | case OMAP_DSS_WB: | ||
793 | return 0x0014 + i * 0x8; | ||
794 | default: | 614 | default: |
795 | BUG(); | 615 | BUG(); |
796 | return 0; | ||
797 | } | 616 | } |
798 | } | 617 | } |
799 | 618 | ||
@@ -803,18 +622,12 @@ static inline u16 DISPC_FIR_COEF_HV2_OFFSET(enum omap_plane plane, u16 i) | |||
803 | switch (plane) { | 622 | switch (plane) { |
804 | case OMAP_DSS_GFX: | 623 | case OMAP_DSS_GFX: |
805 | BUG(); | 624 | BUG(); |
806 | return 0; | ||
807 | case OMAP_DSS_VIDEO1: | 625 | case OMAP_DSS_VIDEO1: |
808 | return 0x0590 + i * 8; | 626 | return 0x0590 + i * 8; |
809 | case OMAP_DSS_VIDEO2: | 627 | case OMAP_DSS_VIDEO2: |
810 | return 0x056C + i * 0x8; | 628 | return 0x056C + i * 0x8; |
811 | case OMAP_DSS_VIDEO3: | ||
812 | return 0x0434 + i * 0x8; | ||
813 | case OMAP_DSS_WB: | ||
814 | return 0x02A4 + i * 0x8; | ||
815 | default: | 629 | default: |
816 | BUG(); | 630 | BUG(); |
817 | return 0; | ||
818 | } | 631 | } |
819 | } | 632 | } |
820 | 633 | ||
@@ -824,15 +637,11 @@ static inline u16 DISPC_CONV_COEF_OFFSET(enum omap_plane plane, u16 i) | |||
824 | switch (plane) { | 637 | switch (plane) { |
825 | case OMAP_DSS_GFX: | 638 | case OMAP_DSS_GFX: |
826 | BUG(); | 639 | BUG(); |
827 | return 0; | ||
828 | case OMAP_DSS_VIDEO1: | 640 | case OMAP_DSS_VIDEO1: |
829 | case OMAP_DSS_VIDEO2: | 641 | case OMAP_DSS_VIDEO2: |
830 | case OMAP_DSS_VIDEO3: | ||
831 | case OMAP_DSS_WB: | ||
832 | return 0x0074 + i * 0x4; | 642 | return 0x0074 + i * 0x4; |
833 | default: | 643 | default: |
834 | BUG(); | 644 | BUG(); |
835 | return 0; | ||
836 | } | 645 | } |
837 | } | 646 | } |
838 | 647 | ||
@@ -842,17 +651,12 @@ static inline u16 DISPC_FIR_COEF_V_OFFSET(enum omap_plane plane, u16 i) | |||
842 | switch (plane) { | 651 | switch (plane) { |
843 | case OMAP_DSS_GFX: | 652 | case OMAP_DSS_GFX: |
844 | BUG(); | 653 | BUG(); |
845 | return 0; | ||
846 | case OMAP_DSS_VIDEO1: | 654 | case OMAP_DSS_VIDEO1: |
847 | return 0x0124 + i * 0x4; | 655 | return 0x0124 + i * 0x4; |
848 | case OMAP_DSS_VIDEO2: | 656 | case OMAP_DSS_VIDEO2: |
849 | return 0x00B4 + i * 0x4; | 657 | return 0x00B4 + i * 0x4; |
850 | case OMAP_DSS_VIDEO3: | ||
851 | case OMAP_DSS_WB: | ||
852 | return 0x0050 + i * 0x4; | ||
853 | default: | 658 | default: |
854 | BUG(); | 659 | BUG(); |
855 | return 0; | ||
856 | } | 660 | } |
857 | } | 661 | } |
858 | 662 | ||
@@ -862,18 +666,12 @@ static inline u16 DISPC_FIR_COEF_V2_OFFSET(enum omap_plane plane, u16 i) | |||
862 | switch (plane) { | 666 | switch (plane) { |
863 | case OMAP_DSS_GFX: | 667 | case OMAP_DSS_GFX: |
864 | BUG(); | 668 | BUG(); |
865 | return 0; | ||
866 | case OMAP_DSS_VIDEO1: | 669 | case OMAP_DSS_VIDEO1: |
867 | return 0x05CC + i * 0x4; | 670 | return 0x05CC + i * 0x4; |
868 | case OMAP_DSS_VIDEO2: | 671 | case OMAP_DSS_VIDEO2: |
869 | return 0x05A8 + i * 0x4; | 672 | return 0x05A8 + i * 0x4; |
870 | case OMAP_DSS_VIDEO3: | ||
871 | return 0x0470 + i * 0x4; | ||
872 | case OMAP_DSS_WB: | ||
873 | return 0x02E0 + i * 0x4; | ||
874 | default: | 673 | default: |
875 | BUG(); | 674 | BUG(); |
876 | return 0; | ||
877 | } | 675 | } |
878 | } | 676 | } |
879 | 677 | ||
@@ -886,11 +684,8 @@ static inline u16 DISPC_PRELOAD_OFFSET(enum omap_plane plane) | |||
886 | return 0x0174; | 684 | return 0x0174; |
887 | case OMAP_DSS_VIDEO2: | 685 | case OMAP_DSS_VIDEO2: |
888 | return 0x00E8; | 686 | return 0x00E8; |
889 | case OMAP_DSS_VIDEO3: | ||
890 | return 0x00A0; | ||
891 | default: | 687 | default: |
892 | BUG(); | 688 | BUG(); |
893 | return 0; | ||
894 | } | 689 | } |
895 | } | 690 | } |
896 | #endif | 691 | #endif |
diff --git a/drivers/video/omap2/dss/dispc_coefs.c b/drivers/video/omap2/dss/dispc_coefs.c deleted file mode 100644 index 038c15b0421..00000000000 --- a/drivers/video/omap2/dss/dispc_coefs.c +++ /dev/null | |||
@@ -1,325 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/omap2/dss/dispc_coefs.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Texas Instruments | ||
5 | * Author: Chandrabhanu Mahapatra <cmahapatra@ti.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <video/omapdss.h> | ||
22 | |||
23 | #include "dispc.h" | ||
24 | |||
25 | static const struct dispc_coef coef3_M8[8] = { | ||
26 | { 0, 0, 128, 0, 0 }, | ||
27 | { 0, -4, 123, 9, 0 }, | ||
28 | { 0, -4, 108, 24, 0 }, | ||
29 | { 0, -2, 87, 43, 0 }, | ||
30 | { 0, 64, 64, 0, 0 }, | ||
31 | { 0, 43, 87, -2, 0 }, | ||
32 | { 0, 24, 108, -4, 0 }, | ||
33 | { 0, 9, 123, -4, 0 }, | ||
34 | }; | ||
35 | |||
36 | static const struct dispc_coef coef3_M9[8] = { | ||
37 | { 0, 6, 116, 6, 0 }, | ||
38 | { 0, 0, 112, 16, 0 }, | ||
39 | { 0, -2, 100, 30, 0 }, | ||
40 | { 0, -2, 83, 47, 0 }, | ||
41 | { 0, 64, 64, 0, 0 }, | ||
42 | { 0, 47, 83, -2, 0 }, | ||
43 | { 0, 30, 100, -2, 0 }, | ||
44 | { 0, 16, 112, 0, 0 }, | ||
45 | }; | ||
46 | |||
47 | static const struct dispc_coef coef3_M10[8] = { | ||
48 | { 0, 10, 108, 10, 0 }, | ||
49 | { 0, 3, 104, 21, 0 }, | ||
50 | { 0, 0, 94, 34, 0 }, | ||
51 | { 0, -1, 80, 49, 0 }, | ||
52 | { 0, 64, 64, 0, 0 }, | ||
53 | { 0, 49, 80, -1, 0 }, | ||
54 | { 0, 34, 94, 0, 0 }, | ||
55 | { 0, 21, 104, 3, 0 }, | ||
56 | }; | ||
57 | |||
58 | static const struct dispc_coef coef3_M11[8] = { | ||
59 | { 0, 14, 100, 14, 0 }, | ||
60 | { 0, 6, 98, 24, 0 }, | ||
61 | { 0, 2, 90, 36, 0 }, | ||
62 | { 0, 0, 78, 50, 0 }, | ||
63 | { 0, 64, 64, 0, 0 }, | ||
64 | { 0, 50, 78, 0, 0 }, | ||
65 | { 0, 36, 90, 2, 0 }, | ||
66 | { 0, 24, 98, 6, 0 }, | ||
67 | }; | ||
68 | |||
69 | static const struct dispc_coef coef3_M12[8] = { | ||
70 | { 0, 16, 96, 16, 0 }, | ||
71 | { 0, 9, 93, 26, 0 }, | ||
72 | { 0, 4, 86, 38, 0 }, | ||
73 | { 0, 1, 76, 51, 0 }, | ||
74 | { 0, 64, 64, 0, 0 }, | ||
75 | { 0, 51, 76, 1, 0 }, | ||
76 | { 0, 38, 86, 4, 0 }, | ||
77 | { 0, 26, 93, 9, 0 }, | ||
78 | }; | ||
79 | |||
80 | static const struct dispc_coef coef3_M13[8] = { | ||
81 | { 0, 18, 92, 18, 0 }, | ||
82 | { 0, 10, 90, 28, 0 }, | ||
83 | { 0, 5, 83, 40, 0 }, | ||
84 | { 0, 1, 75, 52, 0 }, | ||
85 | { 0, 64, 64, 0, 0 }, | ||
86 | { 0, 52, 75, 1, 0 }, | ||
87 | { 0, 40, 83, 5, 0 }, | ||
88 | { 0, 28, 90, 10, 0 }, | ||
89 | }; | ||
90 | |||
91 | static const struct dispc_coef coef3_M14[8] = { | ||
92 | { 0, 20, 88, 20, 0 }, | ||
93 | { 0, 12, 86, 30, 0 }, | ||
94 | { 0, 6, 81, 41, 0 }, | ||
95 | { 0, 2, 74, 52, 0 }, | ||
96 | { 0, 64, 64, 0, 0 }, | ||
97 | { 0, 52, 74, 2, 0 }, | ||
98 | { 0, 41, 81, 6, 0 }, | ||
99 | { 0, 30, 86, 12, 0 }, | ||
100 | }; | ||
101 | |||
102 | static const struct dispc_coef coef3_M16[8] = { | ||
103 | { 0, 22, 84, 22, 0 }, | ||
104 | { 0, 14, 82, 32, 0 }, | ||
105 | { 0, 8, 78, 42, 0 }, | ||
106 | { 0, 3, 72, 53, 0 }, | ||
107 | { 0, 64, 64, 0, 0 }, | ||
108 | { 0, 53, 72, 3, 0 }, | ||
109 | { 0, 42, 78, 8, 0 }, | ||
110 | { 0, 32, 82, 14, 0 }, | ||
111 | }; | ||
112 | |||
113 | static const struct dispc_coef coef3_M19[8] = { | ||
114 | { 0, 24, 80, 24, 0 }, | ||
115 | { 0, 16, 79, 33, 0 }, | ||
116 | { 0, 9, 76, 43, 0 }, | ||
117 | { 0, 4, 70, 54, 0 }, | ||
118 | { 0, 64, 64, 0, 0 }, | ||
119 | { 0, 54, 70, 4, 0 }, | ||
120 | { 0, 43, 76, 9, 0 }, | ||
121 | { 0, 33, 79, 16, 0 }, | ||
122 | }; | ||
123 | |||
124 | static const struct dispc_coef coef3_M22[8] = { | ||
125 | { 0, 25, 78, 25, 0 }, | ||
126 | { 0, 17, 77, 34, 0 }, | ||
127 | { 0, 10, 74, 44, 0 }, | ||
128 | { 0, 5, 69, 54, 0 }, | ||
129 | { 0, 64, 64, 0, 0 }, | ||
130 | { 0, 54, 69, 5, 0 }, | ||
131 | { 0, 44, 74, 10, 0 }, | ||
132 | { 0, 34, 77, 17, 0 }, | ||
133 | }; | ||
134 | |||
135 | static const struct dispc_coef coef3_M26[8] = { | ||
136 | { 0, 26, 76, 26, 0 }, | ||
137 | { 0, 19, 74, 35, 0 }, | ||
138 | { 0, 11, 72, 45, 0 }, | ||
139 | { 0, 5, 69, 54, 0 }, | ||
140 | { 0, 64, 64, 0, 0 }, | ||
141 | { 0, 54, 69, 5, 0 }, | ||
142 | { 0, 45, 72, 11, 0 }, | ||
143 | { 0, 35, 74, 19, 0 }, | ||
144 | }; | ||
145 | |||
146 | static const struct dispc_coef coef3_M32[8] = { | ||
147 | { 0, 27, 74, 27, 0 }, | ||
148 | { 0, 19, 73, 36, 0 }, | ||
149 | { 0, 12, 71, 45, 0 }, | ||
150 | { 0, 6, 68, 54, 0 }, | ||
151 | { 0, 64, 64, 0, 0 }, | ||
152 | { 0, 54, 68, 6, 0 }, | ||
153 | { 0, 45, 71, 12, 0 }, | ||
154 | { 0, 36, 73, 19, 0 }, | ||
155 | }; | ||
156 | |||
157 | static const struct dispc_coef coef5_M8[8] = { | ||
158 | { 0, 0, 128, 0, 0 }, | ||
159 | { -2, 14, 125, -10, 1 }, | ||
160 | { -6, 33, 114, -15, 2 }, | ||
161 | { -10, 55, 98, -16, 1 }, | ||
162 | { 0, -14, 78, 78, -14 }, | ||
163 | { 1, -16, 98, 55, -10 }, | ||
164 | { 2, -15, 114, 33, -6 }, | ||
165 | { 1, -10, 125, 14, -2 }, | ||
166 | }; | ||
167 | |||
168 | static const struct dispc_coef coef5_M9[8] = { | ||
169 | { -3, 10, 114, 10, -3 }, | ||
170 | { -6, 24, 111, 0, -1 }, | ||
171 | { -8, 40, 103, -7, 0 }, | ||
172 | { -11, 58, 91, -11, 1 }, | ||
173 | { 0, -12, 76, 76, -12 }, | ||
174 | { 1, -11, 91, 58, -11 }, | ||
175 | { 0, -7, 103, 40, -8 }, | ||
176 | { -1, 0, 111, 24, -6 }, | ||
177 | }; | ||
178 | |||
179 | static const struct dispc_coef coef5_M10[8] = { | ||
180 | { -4, 18, 100, 18, -4 }, | ||
181 | { -6, 30, 99, 8, -3 }, | ||
182 | { -8, 44, 93, 0, -1 }, | ||
183 | { -9, 58, 84, -5, 0 }, | ||
184 | { 0, -8, 72, 72, -8 }, | ||
185 | { 0, -5, 84, 58, -9 }, | ||
186 | { -1, 0, 93, 44, -8 }, | ||
187 | { -3, 8, 99, 30, -6 }, | ||
188 | }; | ||
189 | |||
190 | static const struct dispc_coef coef5_M11[8] = { | ||
191 | { -5, 23, 92, 23, -5 }, | ||
192 | { -6, 34, 90, 13, -3 }, | ||
193 | { -6, 45, 85, 6, -2 }, | ||
194 | { -6, 57, 78, 0, -1 }, | ||
195 | { 0, -4, 68, 68, -4 }, | ||
196 | { -1, 0, 78, 57, -6 }, | ||
197 | { -2, 6, 85, 45, -6 }, | ||
198 | { -3, 13, 90, 34, -6 }, | ||
199 | }; | ||
200 | |||
201 | static const struct dispc_coef coef5_M12[8] = { | ||
202 | { -4, 26, 84, 26, -4 }, | ||
203 | { -5, 36, 82, 18, -3 }, | ||
204 | { -4, 46, 78, 10, -2 }, | ||
205 | { -3, 55, 72, 5, -1 }, | ||
206 | { 0, 0, 64, 64, 0 }, | ||
207 | { -1, 5, 72, 55, -3 }, | ||
208 | { -2, 10, 78, 46, -4 }, | ||
209 | { -3, 18, 82, 36, -5 }, | ||
210 | }; | ||
211 | |||
212 | static const struct dispc_coef coef5_M13[8] = { | ||
213 | { -3, 28, 78, 28, -3 }, | ||
214 | { -3, 37, 76, 21, -3 }, | ||
215 | { -2, 45, 73, 14, -2 }, | ||
216 | { 0, 53, 68, 8, -1 }, | ||
217 | { 0, 3, 61, 61, 3 }, | ||
218 | { -1, 8, 68, 53, 0 }, | ||
219 | { -2, 14, 73, 45, -2 }, | ||
220 | { -3, 21, 76, 37, -3 }, | ||
221 | }; | ||
222 | |||
223 | static const struct dispc_coef coef5_M14[8] = { | ||
224 | { -2, 30, 72, 30, -2 }, | ||
225 | { -1, 37, 71, 23, -2 }, | ||
226 | { 0, 45, 69, 16, -2 }, | ||
227 | { 3, 52, 64, 10, -1 }, | ||
228 | { 0, 6, 58, 58, 6 }, | ||
229 | { -1, 10, 64, 52, 3 }, | ||
230 | { -2, 16, 69, 45, 0 }, | ||
231 | { -2, 23, 71, 37, -1 }, | ||
232 | }; | ||
233 | |||
234 | static const struct dispc_coef coef5_M16[8] = { | ||
235 | { 0, 31, 66, 31, 0 }, | ||
236 | { 1, 38, 65, 25, -1 }, | ||
237 | { 3, 44, 62, 20, -1 }, | ||
238 | { 6, 49, 59, 14, 0 }, | ||
239 | { 0, 10, 54, 54, 10 }, | ||
240 | { 0, 14, 59, 49, 6 }, | ||
241 | { -1, 20, 62, 44, 3 }, | ||
242 | { -1, 25, 65, 38, 1 }, | ||
243 | }; | ||
244 | |||
245 | static const struct dispc_coef coef5_M19[8] = { | ||
246 | { 3, 32, 58, 32, 3 }, | ||
247 | { 4, 38, 58, 27, 1 }, | ||
248 | { 7, 42, 55, 23, 1 }, | ||
249 | { 10, 46, 54, 18, 0 }, | ||
250 | { 0, 14, 50, 50, 14 }, | ||
251 | { 0, 18, 54, 46, 10 }, | ||
252 | { 1, 23, 55, 42, 7 }, | ||
253 | { 1, 27, 58, 38, 4 }, | ||
254 | }; | ||
255 | |||
256 | static const struct dispc_coef coef5_M22[8] = { | ||
257 | { 4, 33, 54, 33, 4 }, | ||
258 | { 6, 37, 54, 28, 3 }, | ||
259 | { 9, 41, 53, 24, 1 }, | ||
260 | { 12, 45, 51, 20, 0 }, | ||
261 | { 0, 16, 48, 48, 16 }, | ||
262 | { 0, 20, 51, 45, 12 }, | ||
263 | { 1, 24, 53, 41, 9 }, | ||
264 | { 3, 28, 54, 37, 6 }, | ||
265 | }; | ||
266 | |||
267 | static const struct dispc_coef coef5_M26[8] = { | ||
268 | { 6, 33, 50, 33, 6 }, | ||
269 | { 8, 36, 51, 29, 4 }, | ||
270 | { 11, 40, 50, 25, 2 }, | ||
271 | { 14, 43, 48, 22, 1 }, | ||
272 | { 0, 18, 46, 46, 18 }, | ||
273 | { 1, 22, 48, 43, 14 }, | ||
274 | { 2, 25, 50, 40, 11 }, | ||
275 | { 4, 29, 51, 36, 8 }, | ||
276 | }; | ||
277 | |||
278 | static const struct dispc_coef coef5_M32[8] = { | ||
279 | { 7, 33, 48, 33, 7 }, | ||
280 | { 10, 36, 48, 29, 5 }, | ||
281 | { 13, 39, 47, 26, 3 }, | ||
282 | { 16, 42, 46, 23, 1 }, | ||
283 | { 0, 19, 45, 45, 19 }, | ||
284 | { 1, 23, 46, 42, 16 }, | ||
285 | { 3, 26, 47, 39, 13 }, | ||
286 | { 5, 29, 48, 36, 10 }, | ||
287 | }; | ||
288 | |||
289 | const struct dispc_coef *dispc_ovl_get_scale_coef(int inc, int five_taps) | ||
290 | { | ||
291 | int i; | ||
292 | static const struct { | ||
293 | int Mmin; | ||
294 | int Mmax; | ||
295 | const struct dispc_coef *coef_3; | ||
296 | const struct dispc_coef *coef_5; | ||
297 | } coefs[] = { | ||
298 | { 27, 32, coef3_M32, coef5_M32 }, | ||
299 | { 23, 26, coef3_M26, coef5_M26 }, | ||
300 | { 20, 22, coef3_M22, coef5_M22 }, | ||
301 | { 17, 19, coef3_M19, coef5_M19 }, | ||
302 | { 15, 16, coef3_M16, coef5_M16 }, | ||
303 | { 14, 14, coef3_M14, coef5_M14 }, | ||
304 | { 13, 13, coef3_M13, coef5_M13 }, | ||
305 | { 12, 12, coef3_M12, coef5_M12 }, | ||
306 | { 11, 11, coef3_M11, coef5_M11 }, | ||
307 | { 10, 10, coef3_M10, coef5_M10 }, | ||
308 | { 9, 9, coef3_M9, coef5_M9 }, | ||
309 | { 4, 8, coef3_M8, coef5_M8 }, | ||
310 | /* | ||
311 | * When upscaling more than two times, blockiness and outlines | ||
312 | * around the image are observed when M8 tables are used. M11, | ||
313 | * M16 and M19 tables are used to prevent this. | ||
314 | */ | ||
315 | { 3, 3, coef3_M11, coef5_M11 }, | ||
316 | { 2, 2, coef3_M16, coef5_M16 }, | ||
317 | { 0, 1, coef3_M19, coef5_M19 }, | ||
318 | }; | ||
319 | |||
320 | inc /= 128; | ||
321 | for (i = 0; i < ARRAY_SIZE(coefs); ++i) | ||
322 | if (inc >= coefs[i].Mmin && inc <= coefs[i].Mmax) | ||
323 | return five_taps ? coefs[i].coef_5 : coefs[i].coef_3; | ||
324 | return NULL; | ||
325 | } | ||
diff --git a/drivers/video/omap2/dss/display-sysfs.c b/drivers/video/omap2/dss/display-sysfs.c deleted file mode 100644 index 18211a9ab35..00000000000 --- a/drivers/video/omap2/dss/display-sysfs.c +++ /dev/null | |||
@@ -1,321 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * Some code and ideas taken from drivers/video/omap/ driver | ||
6 | * by Imre Deak. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #define DSS_SUBSYS_NAME "DISPLAY" | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/jiffies.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | |||
28 | #include <video/omapdss.h> | ||
29 | #include "dss.h" | ||
30 | #include "dss_features.h" | ||
31 | |||
32 | static ssize_t display_enabled_show(struct device *dev, | ||
33 | struct device_attribute *attr, char *buf) | ||
34 | { | ||
35 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
36 | bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; | ||
37 | |||
38 | return snprintf(buf, PAGE_SIZE, "%d\n", enabled); | ||
39 | } | ||
40 | |||
41 | static ssize_t display_enabled_store(struct device *dev, | ||
42 | struct device_attribute *attr, | ||
43 | const char *buf, size_t size) | ||
44 | { | ||
45 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
46 | int r; | ||
47 | bool enabled; | ||
48 | |||
49 | r = strtobool(buf, &enabled); | ||
50 | if (r) | ||
51 | return r; | ||
52 | |||
53 | if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { | ||
54 | if (enabled) { | ||
55 | r = dssdev->driver->enable(dssdev); | ||
56 | if (r) | ||
57 | return r; | ||
58 | } else { | ||
59 | dssdev->driver->disable(dssdev); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | return size; | ||
64 | } | ||
65 | |||
66 | static ssize_t display_tear_show(struct device *dev, | ||
67 | struct device_attribute *attr, char *buf) | ||
68 | { | ||
69 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
70 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
71 | dssdev->driver->get_te ? | ||
72 | dssdev->driver->get_te(dssdev) : 0); | ||
73 | } | ||
74 | |||
75 | static ssize_t display_tear_store(struct device *dev, | ||
76 | struct device_attribute *attr, const char *buf, size_t size) | ||
77 | { | ||
78 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
79 | int r; | ||
80 | bool te; | ||
81 | |||
82 | if (!dssdev->driver->enable_te || !dssdev->driver->get_te) | ||
83 | return -ENOENT; | ||
84 | |||
85 | r = strtobool(buf, &te); | ||
86 | if (r) | ||
87 | return r; | ||
88 | |||
89 | r = dssdev->driver->enable_te(dssdev, te); | ||
90 | if (r) | ||
91 | return r; | ||
92 | |||
93 | return size; | ||
94 | } | ||
95 | |||
96 | static ssize_t display_timings_show(struct device *dev, | ||
97 | struct device_attribute *attr, char *buf) | ||
98 | { | ||
99 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
100 | struct omap_video_timings t; | ||
101 | |||
102 | if (!dssdev->driver->get_timings) | ||
103 | return -ENOENT; | ||
104 | |||
105 | dssdev->driver->get_timings(dssdev, &t); | ||
106 | |||
107 | return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", | ||
108 | t.pixel_clock, | ||
109 | t.x_res, t.hfp, t.hbp, t.hsw, | ||
110 | t.y_res, t.vfp, t.vbp, t.vsw); | ||
111 | } | ||
112 | |||
113 | static ssize_t display_timings_store(struct device *dev, | ||
114 | struct device_attribute *attr, const char *buf, size_t size) | ||
115 | { | ||
116 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
117 | struct omap_video_timings t = dssdev->panel.timings; | ||
118 | int r, found; | ||
119 | |||
120 | if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) | ||
121 | return -ENOENT; | ||
122 | |||
123 | found = 0; | ||
124 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
125 | if (strncmp("pal", buf, 3) == 0) { | ||
126 | t = omap_dss_pal_timings; | ||
127 | found = 1; | ||
128 | } else if (strncmp("ntsc", buf, 4) == 0) { | ||
129 | t = omap_dss_ntsc_timings; | ||
130 | found = 1; | ||
131 | } | ||
132 | #endif | ||
133 | if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", | ||
134 | &t.pixel_clock, | ||
135 | &t.x_res, &t.hfp, &t.hbp, &t.hsw, | ||
136 | &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) | ||
137 | return -EINVAL; | ||
138 | |||
139 | r = dssdev->driver->check_timings(dssdev, &t); | ||
140 | if (r) | ||
141 | return r; | ||
142 | |||
143 | dssdev->driver->disable(dssdev); | ||
144 | dssdev->driver->set_timings(dssdev, &t); | ||
145 | r = dssdev->driver->enable(dssdev); | ||
146 | if (r) | ||
147 | return r; | ||
148 | |||
149 | return size; | ||
150 | } | ||
151 | |||
152 | static ssize_t display_rotate_show(struct device *dev, | ||
153 | struct device_attribute *attr, char *buf) | ||
154 | { | ||
155 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
156 | int rotate; | ||
157 | if (!dssdev->driver->get_rotate) | ||
158 | return -ENOENT; | ||
159 | rotate = dssdev->driver->get_rotate(dssdev); | ||
160 | return snprintf(buf, PAGE_SIZE, "%u\n", rotate); | ||
161 | } | ||
162 | |||
163 | static ssize_t display_rotate_store(struct device *dev, | ||
164 | struct device_attribute *attr, const char *buf, size_t size) | ||
165 | { | ||
166 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
167 | int rot, r; | ||
168 | |||
169 | if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) | ||
170 | return -ENOENT; | ||
171 | |||
172 | r = kstrtoint(buf, 0, &rot); | ||
173 | if (r) | ||
174 | return r; | ||
175 | |||
176 | r = dssdev->driver->set_rotate(dssdev, rot); | ||
177 | if (r) | ||
178 | return r; | ||
179 | |||
180 | return size; | ||
181 | } | ||
182 | |||
183 | static ssize_t display_mirror_show(struct device *dev, | ||
184 | struct device_attribute *attr, char *buf) | ||
185 | { | ||
186 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
187 | int mirror; | ||
188 | if (!dssdev->driver->get_mirror) | ||
189 | return -ENOENT; | ||
190 | mirror = dssdev->driver->get_mirror(dssdev); | ||
191 | return snprintf(buf, PAGE_SIZE, "%u\n", mirror); | ||
192 | } | ||
193 | |||
194 | static ssize_t display_mirror_store(struct device *dev, | ||
195 | struct device_attribute *attr, const char *buf, size_t size) | ||
196 | { | ||
197 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
198 | int r; | ||
199 | bool mirror; | ||
200 | |||
201 | if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) | ||
202 | return -ENOENT; | ||
203 | |||
204 | r = strtobool(buf, &mirror); | ||
205 | if (r) | ||
206 | return r; | ||
207 | |||
208 | r = dssdev->driver->set_mirror(dssdev, mirror); | ||
209 | if (r) | ||
210 | return r; | ||
211 | |||
212 | return size; | ||
213 | } | ||
214 | |||
215 | static ssize_t display_wss_show(struct device *dev, | ||
216 | struct device_attribute *attr, char *buf) | ||
217 | { | ||
218 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
219 | unsigned int wss; | ||
220 | |||
221 | if (!dssdev->driver->get_wss) | ||
222 | return -ENOENT; | ||
223 | |||
224 | wss = dssdev->driver->get_wss(dssdev); | ||
225 | |||
226 | return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); | ||
227 | } | ||
228 | |||
229 | static ssize_t display_wss_store(struct device *dev, | ||
230 | struct device_attribute *attr, const char *buf, size_t size) | ||
231 | { | ||
232 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
233 | u32 wss; | ||
234 | int r; | ||
235 | |||
236 | if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) | ||
237 | return -ENOENT; | ||
238 | |||
239 | r = kstrtou32(buf, 0, &wss); | ||
240 | if (r) | ||
241 | return r; | ||
242 | |||
243 | if (wss > 0xfffff) | ||
244 | return -EINVAL; | ||
245 | |||
246 | r = dssdev->driver->set_wss(dssdev, wss); | ||
247 | if (r) | ||
248 | return r; | ||
249 | |||
250 | return size; | ||
251 | } | ||
252 | |||
253 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
254 | display_enabled_show, display_enabled_store); | ||
255 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, | ||
256 | display_tear_show, display_tear_store); | ||
257 | static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, | ||
258 | display_timings_show, display_timings_store); | ||
259 | static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, | ||
260 | display_rotate_show, display_rotate_store); | ||
261 | static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, | ||
262 | display_mirror_show, display_mirror_store); | ||
263 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, | ||
264 | display_wss_show, display_wss_store); | ||
265 | |||
266 | static struct device_attribute *display_sysfs_attrs[] = { | ||
267 | &dev_attr_enabled, | ||
268 | &dev_attr_tear_elim, | ||
269 | &dev_attr_timings, | ||
270 | &dev_attr_rotate, | ||
271 | &dev_attr_mirror, | ||
272 | &dev_attr_wss, | ||
273 | NULL | ||
274 | }; | ||
275 | |||
276 | int display_init_sysfs(struct platform_device *pdev, | ||
277 | struct omap_dss_device *dssdev) | ||
278 | { | ||
279 | struct device_attribute *attr; | ||
280 | int i, r; | ||
281 | |||
282 | /* create device sysfs files */ | ||
283 | i = 0; | ||
284 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | ||
285 | r = device_create_file(&dssdev->dev, attr); | ||
286 | if (r) { | ||
287 | for (i = i - 2; i >= 0; i--) { | ||
288 | attr = display_sysfs_attrs[i]; | ||
289 | device_remove_file(&dssdev->dev, attr); | ||
290 | } | ||
291 | |||
292 | DSSERR("failed to create sysfs file\n"); | ||
293 | return r; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | /* create display? sysfs links */ | ||
298 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | ||
299 | dev_name(&dssdev->dev)); | ||
300 | if (r) { | ||
301 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
302 | device_remove_file(&dssdev->dev, attr); | ||
303 | |||
304 | DSSERR("failed to create sysfs display link\n"); | ||
305 | return r; | ||
306 | } | ||
307 | |||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | void display_uninit_sysfs(struct platform_device *pdev, | ||
312 | struct omap_dss_device *dssdev) | ||
313 | { | ||
314 | struct device_attribute *attr; | ||
315 | int i = 0; | ||
316 | |||
317 | sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); | ||
318 | |||
319 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
320 | device_remove_file(&dssdev->dev, attr); | ||
321 | } | ||
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c index 0aa8ad8f966..94495e45ec5 100644 --- a/drivers/video/omap2/dss/display.c +++ b/drivers/video/omap2/dss/display.c | |||
@@ -31,6 +31,249 @@ | |||
31 | #include "dss.h" | 31 | #include "dss.h" |
32 | #include "dss_features.h" | 32 | #include "dss_features.h" |
33 | 33 | ||
34 | static ssize_t display_enabled_show(struct device *dev, | ||
35 | struct device_attribute *attr, char *buf) | ||
36 | { | ||
37 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
38 | bool enabled = dssdev->state != OMAP_DSS_DISPLAY_DISABLED; | ||
39 | |||
40 | return snprintf(buf, PAGE_SIZE, "%d\n", enabled); | ||
41 | } | ||
42 | |||
43 | static ssize_t display_enabled_store(struct device *dev, | ||
44 | struct device_attribute *attr, | ||
45 | const char *buf, size_t size) | ||
46 | { | ||
47 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
48 | int r, enabled; | ||
49 | |||
50 | r = kstrtoint(buf, 0, &enabled); | ||
51 | if (r) | ||
52 | return r; | ||
53 | |||
54 | enabled = !!enabled; | ||
55 | |||
56 | if (enabled != (dssdev->state != OMAP_DSS_DISPLAY_DISABLED)) { | ||
57 | if (enabled) { | ||
58 | r = dssdev->driver->enable(dssdev); | ||
59 | if (r) | ||
60 | return r; | ||
61 | } else { | ||
62 | dssdev->driver->disable(dssdev); | ||
63 | } | ||
64 | } | ||
65 | |||
66 | return size; | ||
67 | } | ||
68 | |||
69 | static ssize_t display_tear_show(struct device *dev, | ||
70 | struct device_attribute *attr, char *buf) | ||
71 | { | ||
72 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
73 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
74 | dssdev->driver->get_te ? | ||
75 | dssdev->driver->get_te(dssdev) : 0); | ||
76 | } | ||
77 | |||
78 | static ssize_t display_tear_store(struct device *dev, | ||
79 | struct device_attribute *attr, const char *buf, size_t size) | ||
80 | { | ||
81 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
82 | int te, r; | ||
83 | |||
84 | if (!dssdev->driver->enable_te || !dssdev->driver->get_te) | ||
85 | return -ENOENT; | ||
86 | |||
87 | r = kstrtoint(buf, 0, &te); | ||
88 | if (r) | ||
89 | return r; | ||
90 | |||
91 | te = !!te; | ||
92 | |||
93 | r = dssdev->driver->enable_te(dssdev, te); | ||
94 | if (r) | ||
95 | return r; | ||
96 | |||
97 | return size; | ||
98 | } | ||
99 | |||
100 | static ssize_t display_timings_show(struct device *dev, | ||
101 | struct device_attribute *attr, char *buf) | ||
102 | { | ||
103 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
104 | struct omap_video_timings t; | ||
105 | |||
106 | if (!dssdev->driver->get_timings) | ||
107 | return -ENOENT; | ||
108 | |||
109 | dssdev->driver->get_timings(dssdev, &t); | ||
110 | |||
111 | return snprintf(buf, PAGE_SIZE, "%u,%u/%u/%u/%u,%u/%u/%u/%u\n", | ||
112 | t.pixel_clock, | ||
113 | t.x_res, t.hfp, t.hbp, t.hsw, | ||
114 | t.y_res, t.vfp, t.vbp, t.vsw); | ||
115 | } | ||
116 | |||
117 | static ssize_t display_timings_store(struct device *dev, | ||
118 | struct device_attribute *attr, const char *buf, size_t size) | ||
119 | { | ||
120 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
121 | struct omap_video_timings t; | ||
122 | int r, found; | ||
123 | |||
124 | if (!dssdev->driver->set_timings || !dssdev->driver->check_timings) | ||
125 | return -ENOENT; | ||
126 | |||
127 | found = 0; | ||
128 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
129 | if (strncmp("pal", buf, 3) == 0) { | ||
130 | t = omap_dss_pal_timings; | ||
131 | found = 1; | ||
132 | } else if (strncmp("ntsc", buf, 4) == 0) { | ||
133 | t = omap_dss_ntsc_timings; | ||
134 | found = 1; | ||
135 | } | ||
136 | #endif | ||
137 | if (!found && sscanf(buf, "%u,%hu/%hu/%hu/%hu,%hu/%hu/%hu/%hu", | ||
138 | &t.pixel_clock, | ||
139 | &t.x_res, &t.hfp, &t.hbp, &t.hsw, | ||
140 | &t.y_res, &t.vfp, &t.vbp, &t.vsw) != 9) | ||
141 | return -EINVAL; | ||
142 | |||
143 | r = dssdev->driver->check_timings(dssdev, &t); | ||
144 | if (r) | ||
145 | return r; | ||
146 | |||
147 | dssdev->driver->set_timings(dssdev, &t); | ||
148 | |||
149 | return size; | ||
150 | } | ||
151 | |||
152 | static ssize_t display_rotate_show(struct device *dev, | ||
153 | struct device_attribute *attr, char *buf) | ||
154 | { | ||
155 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
156 | int rotate; | ||
157 | if (!dssdev->driver->get_rotate) | ||
158 | return -ENOENT; | ||
159 | rotate = dssdev->driver->get_rotate(dssdev); | ||
160 | return snprintf(buf, PAGE_SIZE, "%u\n", rotate); | ||
161 | } | ||
162 | |||
163 | static ssize_t display_rotate_store(struct device *dev, | ||
164 | struct device_attribute *attr, const char *buf, size_t size) | ||
165 | { | ||
166 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
167 | int rot, r; | ||
168 | |||
169 | if (!dssdev->driver->set_rotate || !dssdev->driver->get_rotate) | ||
170 | return -ENOENT; | ||
171 | |||
172 | r = kstrtoint(buf, 0, &rot); | ||
173 | if (r) | ||
174 | return r; | ||
175 | |||
176 | r = dssdev->driver->set_rotate(dssdev, rot); | ||
177 | if (r) | ||
178 | return r; | ||
179 | |||
180 | return size; | ||
181 | } | ||
182 | |||
183 | static ssize_t display_mirror_show(struct device *dev, | ||
184 | struct device_attribute *attr, char *buf) | ||
185 | { | ||
186 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
187 | int mirror; | ||
188 | if (!dssdev->driver->get_mirror) | ||
189 | return -ENOENT; | ||
190 | mirror = dssdev->driver->get_mirror(dssdev); | ||
191 | return snprintf(buf, PAGE_SIZE, "%u\n", mirror); | ||
192 | } | ||
193 | |||
194 | static ssize_t display_mirror_store(struct device *dev, | ||
195 | struct device_attribute *attr, const char *buf, size_t size) | ||
196 | { | ||
197 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
198 | int mirror, r; | ||
199 | |||
200 | if (!dssdev->driver->set_mirror || !dssdev->driver->get_mirror) | ||
201 | return -ENOENT; | ||
202 | |||
203 | r = kstrtoint(buf, 0, &mirror); | ||
204 | if (r) | ||
205 | return r; | ||
206 | |||
207 | mirror = !!mirror; | ||
208 | |||
209 | r = dssdev->driver->set_mirror(dssdev, mirror); | ||
210 | if (r) | ||
211 | return r; | ||
212 | |||
213 | return size; | ||
214 | } | ||
215 | |||
216 | static ssize_t display_wss_show(struct device *dev, | ||
217 | struct device_attribute *attr, char *buf) | ||
218 | { | ||
219 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
220 | unsigned int wss; | ||
221 | |||
222 | if (!dssdev->driver->get_wss) | ||
223 | return -ENOENT; | ||
224 | |||
225 | wss = dssdev->driver->get_wss(dssdev); | ||
226 | |||
227 | return snprintf(buf, PAGE_SIZE, "0x%05x\n", wss); | ||
228 | } | ||
229 | |||
230 | static ssize_t display_wss_store(struct device *dev, | ||
231 | struct device_attribute *attr, const char *buf, size_t size) | ||
232 | { | ||
233 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
234 | u32 wss; | ||
235 | int r; | ||
236 | |||
237 | if (!dssdev->driver->get_wss || !dssdev->driver->set_wss) | ||
238 | return -ENOENT; | ||
239 | |||
240 | r = kstrtou32(buf, 0, &wss); | ||
241 | if (r) | ||
242 | return r; | ||
243 | |||
244 | if (wss > 0xfffff) | ||
245 | return -EINVAL; | ||
246 | |||
247 | r = dssdev->driver->set_wss(dssdev, wss); | ||
248 | if (r) | ||
249 | return r; | ||
250 | |||
251 | return size; | ||
252 | } | ||
253 | |||
254 | static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
255 | display_enabled_show, display_enabled_store); | ||
256 | static DEVICE_ATTR(tear_elim, S_IRUGO|S_IWUSR, | ||
257 | display_tear_show, display_tear_store); | ||
258 | static DEVICE_ATTR(timings, S_IRUGO|S_IWUSR, | ||
259 | display_timings_show, display_timings_store); | ||
260 | static DEVICE_ATTR(rotate, S_IRUGO|S_IWUSR, | ||
261 | display_rotate_show, display_rotate_store); | ||
262 | static DEVICE_ATTR(mirror, S_IRUGO|S_IWUSR, | ||
263 | display_mirror_show, display_mirror_store); | ||
264 | static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR, | ||
265 | display_wss_show, display_wss_store); | ||
266 | |||
267 | static struct device_attribute *display_sysfs_attrs[] = { | ||
268 | &dev_attr_enabled, | ||
269 | &dev_attr_tear_elim, | ||
270 | &dev_attr_timings, | ||
271 | &dev_attr_rotate, | ||
272 | &dev_attr_mirror, | ||
273 | &dev_attr_wss, | ||
274 | NULL | ||
275 | }; | ||
276 | |||
34 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, | 277 | void omapdss_default_get_resolution(struct omap_dss_device *dssdev, |
35 | u16 *xres, u16 *yres) | 278 | u16 *xres, u16 *yres) |
36 | { | 279 | { |
@@ -39,6 +282,16 @@ void omapdss_default_get_resolution(struct omap_dss_device *dssdev, | |||
39 | } | 282 | } |
40 | EXPORT_SYMBOL(omapdss_default_get_resolution); | 283 | EXPORT_SYMBOL(omapdss_default_get_resolution); |
41 | 284 | ||
285 | void default_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
286 | u32 fifo_size, u32 burst_size, | ||
287 | u32 *fifo_low, u32 *fifo_high) | ||
288 | { | ||
289 | unsigned buf_unit = dss_feat_get_buffer_size_unit(); | ||
290 | |||
291 | *fifo_high = fifo_size - buf_unit; | ||
292 | *fifo_low = fifo_size - burst_size; | ||
293 | } | ||
294 | |||
42 | int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | 295 | int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) |
43 | { | 296 | { |
44 | switch (dssdev->type) { | 297 | switch (dssdev->type) { |
@@ -49,12 +302,8 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | |||
49 | return 16; | 302 | return 16; |
50 | 303 | ||
51 | case OMAP_DISPLAY_TYPE_DBI: | 304 | case OMAP_DISPLAY_TYPE_DBI: |
52 | if (dssdev->ctrl.pixel_size == 24) | ||
53 | return 24; | ||
54 | else | ||
55 | return 16; | ||
56 | case OMAP_DISPLAY_TYPE_DSI: | 305 | case OMAP_DISPLAY_TYPE_DSI: |
57 | if (dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt) > 16) | 306 | if (dssdev->ctrl.pixel_size == 24) |
58 | return 24; | 307 | return 24; |
59 | else | 308 | else |
60 | return 16; | 309 | return 16; |
@@ -64,20 +313,125 @@ int omapdss_default_get_recommended_bpp(struct omap_dss_device *dssdev) | |||
64 | return 24; | 313 | return 24; |
65 | default: | 314 | default: |
66 | BUG(); | 315 | BUG(); |
67 | return 0; | ||
68 | } | 316 | } |
69 | } | 317 | } |
70 | EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); | 318 | EXPORT_SYMBOL(omapdss_default_get_recommended_bpp); |
71 | 319 | ||
72 | void omapdss_default_get_timings(struct omap_dss_device *dssdev, | 320 | /* Checks if replication logic should be used. Only use for active matrix, |
73 | struct omap_video_timings *timings) | 321 | * when overlay is in RGB12U or RGB16 mode, and LCD interface is |
322 | * 18bpp or 24bpp */ | ||
323 | bool dss_use_replication(struct omap_dss_device *dssdev, | ||
324 | enum omap_color_mode mode) | ||
325 | { | ||
326 | int bpp; | ||
327 | |||
328 | if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) | ||
329 | return false; | ||
330 | |||
331 | if (dssdev->type == OMAP_DISPLAY_TYPE_DPI && | ||
332 | (dssdev->panel.config & OMAP_DSS_LCD_TFT) == 0) | ||
333 | return false; | ||
334 | |||
335 | switch (dssdev->type) { | ||
336 | case OMAP_DISPLAY_TYPE_DPI: | ||
337 | bpp = dssdev->phy.dpi.data_lines; | ||
338 | break; | ||
339 | case OMAP_DISPLAY_TYPE_HDMI: | ||
340 | case OMAP_DISPLAY_TYPE_VENC: | ||
341 | case OMAP_DISPLAY_TYPE_SDI: | ||
342 | bpp = 24; | ||
343 | break; | ||
344 | case OMAP_DISPLAY_TYPE_DBI: | ||
345 | case OMAP_DISPLAY_TYPE_DSI: | ||
346 | bpp = dssdev->ctrl.pixel_size; | ||
347 | break; | ||
348 | default: | ||
349 | BUG(); | ||
350 | } | ||
351 | |||
352 | return bpp > 16; | ||
353 | } | ||
354 | |||
355 | void dss_init_device(struct platform_device *pdev, | ||
356 | struct omap_dss_device *dssdev) | ||
74 | { | 357 | { |
75 | *timings = dssdev->panel.timings; | 358 | struct device_attribute *attr; |
359 | int i; | ||
360 | int r; | ||
361 | |||
362 | switch (dssdev->type) { | ||
363 | #ifdef CONFIG_OMAP2_DSS_DPI | ||
364 | case OMAP_DISPLAY_TYPE_DPI: | ||
365 | r = dpi_init_display(dssdev); | ||
366 | break; | ||
367 | #endif | ||
368 | #ifdef CONFIG_OMAP2_DSS_RFBI | ||
369 | case OMAP_DISPLAY_TYPE_DBI: | ||
370 | r = rfbi_init_display(dssdev); | ||
371 | break; | ||
372 | #endif | ||
373 | #ifdef CONFIG_OMAP2_DSS_VENC | ||
374 | case OMAP_DISPLAY_TYPE_VENC: | ||
375 | r = venc_init_display(dssdev); | ||
376 | break; | ||
377 | #endif | ||
378 | #ifdef CONFIG_OMAP2_DSS_SDI | ||
379 | case OMAP_DISPLAY_TYPE_SDI: | ||
380 | r = sdi_init_display(dssdev); | ||
381 | break; | ||
382 | #endif | ||
383 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
384 | case OMAP_DISPLAY_TYPE_DSI: | ||
385 | r = dsi_init_display(dssdev); | ||
386 | break; | ||
387 | #endif | ||
388 | case OMAP_DISPLAY_TYPE_HDMI: | ||
389 | r = hdmi_init_display(dssdev); | ||
390 | break; | ||
391 | default: | ||
392 | DSSERR("Support for display '%s' not compiled in.\n", | ||
393 | dssdev->name); | ||
394 | return; | ||
395 | } | ||
396 | |||
397 | if (r) { | ||
398 | DSSERR("failed to init display %s\n", dssdev->name); | ||
399 | return; | ||
400 | } | ||
401 | |||
402 | /* create device sysfs files */ | ||
403 | i = 0; | ||
404 | while ((attr = display_sysfs_attrs[i++]) != NULL) { | ||
405 | r = device_create_file(&dssdev->dev, attr); | ||
406 | if (r) | ||
407 | DSSERR("failed to create sysfs file\n"); | ||
408 | } | ||
409 | |||
410 | /* create display? sysfs links */ | ||
411 | r = sysfs_create_link(&pdev->dev.kobj, &dssdev->dev.kobj, | ||
412 | dev_name(&dssdev->dev)); | ||
413 | if (r) | ||
414 | DSSERR("failed to create sysfs display link\n"); | ||
415 | } | ||
416 | |||
417 | void dss_uninit_device(struct platform_device *pdev, | ||
418 | struct omap_dss_device *dssdev) | ||
419 | { | ||
420 | struct device_attribute *attr; | ||
421 | int i = 0; | ||
422 | |||
423 | sysfs_remove_link(&pdev->dev.kobj, dev_name(&dssdev->dev)); | ||
424 | |||
425 | while ((attr = display_sysfs_attrs[i++]) != NULL) | ||
426 | device_remove_file(&dssdev->dev, attr); | ||
427 | |||
428 | if (dssdev->manager) | ||
429 | dssdev->manager->unset_device(dssdev->manager); | ||
76 | } | 430 | } |
77 | EXPORT_SYMBOL(omapdss_default_get_timings); | ||
78 | 431 | ||
79 | static int dss_suspend_device(struct device *dev, void *data) | 432 | static int dss_suspend_device(struct device *dev, void *data) |
80 | { | 433 | { |
434 | int r; | ||
81 | struct omap_dss_device *dssdev = to_dss_device(dev); | 435 | struct omap_dss_device *dssdev = to_dss_device(dev); |
82 | 436 | ||
83 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { | 437 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) { |
@@ -85,7 +439,15 @@ static int dss_suspend_device(struct device *dev, void *data) | |||
85 | return 0; | 439 | return 0; |
86 | } | 440 | } |
87 | 441 | ||
88 | dssdev->driver->disable(dssdev); | 442 | if (!dssdev->driver->suspend) { |
443 | DSSERR("display '%s' doesn't implement suspend\n", | ||
444 | dssdev->name); | ||
445 | return -ENOSYS; | ||
446 | } | ||
447 | |||
448 | r = dssdev->driver->suspend(dssdev); | ||
449 | if (r) | ||
450 | return r; | ||
89 | 451 | ||
90 | dssdev->activate_after_resume = true; | 452 | dssdev->activate_after_resume = true; |
91 | 453 | ||
@@ -112,8 +474,8 @@ static int dss_resume_device(struct device *dev, void *data) | |||
112 | int r; | 474 | int r; |
113 | struct omap_dss_device *dssdev = to_dss_device(dev); | 475 | struct omap_dss_device *dssdev = to_dss_device(dev); |
114 | 476 | ||
115 | if (dssdev->activate_after_resume) { | 477 | if (dssdev->activate_after_resume && dssdev->driver->resume) { |
116 | r = dssdev->driver->enable(dssdev); | 478 | r = dssdev->driver->resume(dssdev); |
117 | if (r) | 479 | if (r) |
118 | return r; | 480 | return r; |
119 | } | 481 | } |
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 4af136a04e5..f053b180ecd 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c | |||
@@ -24,84 +24,55 @@ | |||
24 | 24 | ||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
27 | #include <linux/export.h> | ||
28 | #include <linux/err.h> | 27 | #include <linux/err.h> |
29 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
30 | #include <linux/platform_device.h> | 29 | #include <linux/platform_device.h> |
31 | #include <linux/regulator/consumer.h> | 30 | #include <linux/regulator/consumer.h> |
32 | #include <linux/string.h> | ||
33 | 31 | ||
34 | #include <video/omapdss.h> | 32 | #include <video/omapdss.h> |
33 | #include <plat/cpu.h> | ||
35 | 34 | ||
36 | #include "dss.h" | 35 | #include "dss.h" |
37 | #include "dss_features.h" | ||
38 | 36 | ||
39 | static struct { | 37 | static struct { |
40 | struct regulator *vdds_dsi_reg; | 38 | struct regulator *vdds_dsi_reg; |
41 | struct platform_device *dsidev; | 39 | struct platform_device *dsidev; |
42 | |||
43 | struct mutex lock; | ||
44 | |||
45 | struct omap_video_timings timings; | ||
46 | struct dss_lcd_mgr_config mgr_config; | ||
47 | int data_lines; | ||
48 | |||
49 | struct omap_dss_output output; | ||
50 | } dpi; | 40 | } dpi; |
51 | 41 | ||
52 | static struct platform_device *dpi_get_dsidev(enum omap_channel channel) | 42 | static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk) |
53 | { | 43 | { |
54 | /* | 44 | int dsi_module; |
55 | * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL | ||
56 | * would also be used for DISPC fclk. Meaning, when the DPI output is | ||
57 | * disabled, DISPC clock will be disabled, and TV out will stop. | ||
58 | */ | ||
59 | switch (omapdss_get_version()) { | ||
60 | case OMAPDSS_VER_OMAP24xx: | ||
61 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
62 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
63 | case OMAPDSS_VER_OMAP3630: | ||
64 | case OMAPDSS_VER_AM35xx: | ||
65 | return NULL; | ||
66 | default: | ||
67 | break; | ||
68 | } | ||
69 | 45 | ||
70 | switch (channel) { | 46 | dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1; |
71 | case OMAP_DSS_CHANNEL_LCD: | 47 | |
72 | return dsi_get_dsidev_from_id(0); | 48 | return dsi_get_dsidev_from_id(dsi_module); |
73 | case OMAP_DSS_CHANNEL_LCD2: | ||
74 | return dsi_get_dsidev_from_id(1); | ||
75 | default: | ||
76 | return NULL; | ||
77 | } | ||
78 | } | 49 | } |
79 | 50 | ||
80 | static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel) | 51 | static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev) |
81 | { | 52 | { |
82 | switch (channel) { | 53 | if (dssdev->clocks.dispc.dispc_fclk_src == |
83 | case OMAP_DSS_CHANNEL_LCD: | 54 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || |
84 | return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC; | 55 | dssdev->clocks.dispc.dispc_fclk_src == |
85 | case OMAP_DSS_CHANNEL_LCD2: | 56 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC || |
86 | return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; | 57 | dssdev->clocks.dispc.channel.lcd_clk_src == |
87 | default: | 58 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC || |
88 | /* this shouldn't happen */ | 59 | dssdev->clocks.dispc.channel.lcd_clk_src == |
89 | WARN_ON(1); | 60 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC) |
90 | return OMAP_DSS_CLK_SRC_FCK; | 61 | return true; |
91 | } | 62 | else |
63 | return false; | ||
92 | } | 64 | } |
93 | 65 | ||
94 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | 66 | static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, bool is_tft, |
95 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 67 | unsigned long pck_req, unsigned long *fck, int *lck_div, |
96 | int *pck_div) | 68 | int *pck_div) |
97 | { | 69 | { |
98 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
99 | struct dsi_clock_info dsi_cinfo; | 70 | struct dsi_clock_info dsi_cinfo; |
100 | struct dispc_clock_info dispc_cinfo; | 71 | struct dispc_clock_info dispc_cinfo; |
101 | int r; | 72 | int r; |
102 | 73 | ||
103 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo, | 74 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, pck_req, |
104 | &dispc_cinfo); | 75 | &dsi_cinfo, &dispc_cinfo); |
105 | if (r) | 76 | if (r) |
106 | return r; | 77 | return r; |
107 | 78 | ||
@@ -109,10 +80,11 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | |||
109 | if (r) | 80 | if (r) |
110 | return r; | 81 | return r; |
111 | 82 | ||
112 | dss_select_lcd_clk_source(mgr->id, | 83 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); |
113 | dpi_get_alt_clk_src(mgr->id)); | ||
114 | 84 | ||
115 | dpi.mgr_config.clock_info = dispc_cinfo; | 85 | r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); |
86 | if (r) | ||
87 | return r; | ||
116 | 88 | ||
117 | *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; | 89 | *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; |
118 | *lck_div = dispc_cinfo.lck_div; | 90 | *lck_div = dispc_cinfo.lck_div; |
@@ -121,7 +93,7 @@ static int dpi_set_dsi_clk(struct omap_dss_device *dssdev, | |||
121 | return 0; | 93 | return 0; |
122 | } | 94 | } |
123 | 95 | ||
124 | static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, | 96 | static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, bool is_tft, |
125 | unsigned long pck_req, unsigned long *fck, int *lck_div, | 97 | unsigned long pck_req, unsigned long *fck, int *lck_div, |
126 | int *pck_div) | 98 | int *pck_div) |
127 | { | 99 | { |
@@ -129,7 +101,7 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, | |||
129 | struct dispc_clock_info dispc_cinfo; | 101 | struct dispc_clock_info dispc_cinfo; |
130 | int r; | 102 | int r; |
131 | 103 | ||
132 | r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo); | 104 | r = dss_calc_clock_div(is_tft, pck_req, &dss_cinfo, &dispc_cinfo); |
133 | if (r) | 105 | if (r) |
134 | return r; | 106 | return r; |
135 | 107 | ||
@@ -137,7 +109,9 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, | |||
137 | if (r) | 109 | if (r) |
138 | return r; | 110 | return r; |
139 | 111 | ||
140 | dpi.mgr_config.clock_info = dispc_cinfo; | 112 | r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); |
113 | if (r) | ||
114 | return r; | ||
141 | 115 | ||
142 | *fck = dss_cinfo.fck; | 116 | *fck = dss_cinfo.fck; |
143 | *lck_div = dispc_cinfo.lck_div; | 117 | *lck_div = dispc_cinfo.lck_div; |
@@ -148,19 +122,24 @@ static int dpi_set_dispc_clk(struct omap_dss_device *dssdev, | |||
148 | 122 | ||
149 | static int dpi_set_mode(struct omap_dss_device *dssdev) | 123 | static int dpi_set_mode(struct omap_dss_device *dssdev) |
150 | { | 124 | { |
151 | struct omap_video_timings *t = &dpi.timings; | 125 | struct omap_video_timings *t = &dssdev->panel.timings; |
152 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
153 | int lck_div = 0, pck_div = 0; | 126 | int lck_div = 0, pck_div = 0; |
154 | unsigned long fck = 0; | 127 | unsigned long fck = 0; |
155 | unsigned long pck; | 128 | unsigned long pck; |
129 | bool is_tft; | ||
156 | int r = 0; | 130 | int r = 0; |
157 | 131 | ||
158 | if (dpi.dsidev) | 132 | dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, |
159 | r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck, | 133 | dssdev->panel.acbi, dssdev->panel.acb); |
160 | &lck_div, &pck_div); | 134 | |
135 | is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; | ||
136 | |||
137 | if (dpi_use_dsi_pll(dssdev)) | ||
138 | r = dpi_set_dsi_clk(dssdev, is_tft, t->pixel_clock * 1000, | ||
139 | &fck, &lck_div, &pck_div); | ||
161 | else | 140 | else |
162 | r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck, | 141 | r = dpi_set_dispc_clk(dssdev, is_tft, t->pixel_clock * 1000, |
163 | &lck_div, &pck_div); | 142 | &fck, &lck_div, &pck_div); |
164 | if (r) | 143 | if (r) |
165 | return r; | 144 | return r; |
166 | 145 | ||
@@ -174,67 +153,52 @@ static int dpi_set_mode(struct omap_dss_device *dssdev) | |||
174 | t->pixel_clock = pck; | 153 | t->pixel_clock = pck; |
175 | } | 154 | } |
176 | 155 | ||
177 | dss_mgr_set_timings(mgr, t); | 156 | dispc_set_lcd_timings(dssdev->manager->id, t); |
178 | 157 | ||
179 | return 0; | 158 | return 0; |
180 | } | 159 | } |
181 | 160 | ||
182 | static void dpi_config_lcd_manager(struct omap_dss_device *dssdev) | 161 | static void dpi_basic_init(struct omap_dss_device *dssdev) |
183 | { | 162 | { |
184 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 163 | bool is_tft; |
185 | 164 | ||
186 | dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 165 | is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; |
187 | 166 | ||
188 | dpi.mgr_config.stallmode = false; | 167 | dispc_set_parallel_interface_mode(dssdev->manager->id, |
189 | dpi.mgr_config.fifohandcheck = false; | 168 | OMAP_DSS_PARALLELMODE_BYPASS); |
190 | 169 | dispc_set_lcd_display_type(dssdev->manager->id, is_tft ? | |
191 | dpi.mgr_config.video_port_width = dpi.data_lines; | 170 | OMAP_DSS_LCD_DISPLAY_TFT : OMAP_DSS_LCD_DISPLAY_STN); |
192 | 171 | dispc_set_tft_data_lines(dssdev->manager->id, | |
193 | dpi.mgr_config.lcden_sig_polarity = 0; | 172 | dssdev->phy.dpi.data_lines); |
194 | |||
195 | dss_mgr_set_lcd_config(mgr, &dpi.mgr_config); | ||
196 | } | 173 | } |
197 | 174 | ||
198 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | 175 | int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) |
199 | { | 176 | { |
200 | struct omap_dss_output *out = dssdev->output; | ||
201 | int r; | 177 | int r; |
202 | 178 | ||
203 | mutex_lock(&dpi.lock); | ||
204 | |||
205 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) { | ||
206 | DSSERR("no VDSS_DSI regulator\n"); | ||
207 | r = -ENODEV; | ||
208 | goto err_no_reg; | ||
209 | } | ||
210 | |||
211 | if (out == NULL || out->manager == NULL) { | ||
212 | DSSERR("failed to enable display: no output/manager\n"); | ||
213 | r = -ENODEV; | ||
214 | goto err_no_out_mgr; | ||
215 | } | ||
216 | |||
217 | r = omap_dss_start_device(dssdev); | 179 | r = omap_dss_start_device(dssdev); |
218 | if (r) { | 180 | if (r) { |
219 | DSSERR("failed to start device\n"); | 181 | DSSERR("failed to start device\n"); |
220 | goto err_start_dev; | 182 | goto err_start_dev; |
221 | } | 183 | } |
222 | 184 | ||
223 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) { | 185 | if (cpu_is_omap34xx()) { |
224 | r = regulator_enable(dpi.vdds_dsi_reg); | 186 | r = regulator_enable(dpi.vdds_dsi_reg); |
225 | if (r) | 187 | if (r) |
226 | goto err_reg_enable; | 188 | goto err_reg_enable; |
227 | } | 189 | } |
228 | 190 | ||
191 | r = dss_runtime_get(); | ||
192 | if (r) | ||
193 | goto err_get_dss; | ||
194 | |||
229 | r = dispc_runtime_get(); | 195 | r = dispc_runtime_get(); |
230 | if (r) | 196 | if (r) |
231 | goto err_get_dispc; | 197 | goto err_get_dispc; |
232 | 198 | ||
233 | r = dss_dpi_select_source(dssdev->channel); | 199 | dpi_basic_init(dssdev); |
234 | if (r) | ||
235 | goto err_src_sel; | ||
236 | 200 | ||
237 | if (dpi.dsidev) { | 201 | if (dpi_use_dsi_pll(dssdev)) { |
238 | r = dsi_runtime_get(dpi.dsidev); | 202 | r = dsi_runtime_get(dpi.dsidev); |
239 | if (r) | 203 | if (r) |
240 | goto err_get_dsi; | 204 | goto err_get_dsi; |
@@ -248,98 +212,100 @@ int omapdss_dpi_display_enable(struct omap_dss_device *dssdev) | |||
248 | if (r) | 212 | if (r) |
249 | goto err_set_mode; | 213 | goto err_set_mode; |
250 | 214 | ||
251 | dpi_config_lcd_manager(dssdev); | ||
252 | |||
253 | mdelay(2); | 215 | mdelay(2); |
254 | 216 | ||
255 | r = dss_mgr_enable(out->manager); | 217 | dssdev->manager->enable(dssdev->manager); |
256 | if (r) | ||
257 | goto err_mgr_enable; | ||
258 | |||
259 | mutex_unlock(&dpi.lock); | ||
260 | 218 | ||
261 | return 0; | 219 | return 0; |
262 | 220 | ||
263 | err_mgr_enable: | ||
264 | err_set_mode: | 221 | err_set_mode: |
265 | if (dpi.dsidev) | 222 | if (dpi_use_dsi_pll(dssdev)) |
266 | dsi_pll_uninit(dpi.dsidev, true); | 223 | dsi_pll_uninit(dpi.dsidev, true); |
267 | err_dsi_pll_init: | 224 | err_dsi_pll_init: |
268 | if (dpi.dsidev) | 225 | if (dpi_use_dsi_pll(dssdev)) |
269 | dsi_runtime_put(dpi.dsidev); | 226 | dsi_runtime_put(dpi.dsidev); |
270 | err_get_dsi: | 227 | err_get_dsi: |
271 | err_src_sel: | ||
272 | dispc_runtime_put(); | 228 | dispc_runtime_put(); |
273 | err_get_dispc: | 229 | err_get_dispc: |
274 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 230 | dss_runtime_put(); |
231 | err_get_dss: | ||
232 | if (cpu_is_omap34xx()) | ||
275 | regulator_disable(dpi.vdds_dsi_reg); | 233 | regulator_disable(dpi.vdds_dsi_reg); |
276 | err_reg_enable: | 234 | err_reg_enable: |
277 | omap_dss_stop_device(dssdev); | 235 | omap_dss_stop_device(dssdev); |
278 | err_start_dev: | 236 | err_start_dev: |
279 | err_no_out_mgr: | ||
280 | err_no_reg: | ||
281 | mutex_unlock(&dpi.lock); | ||
282 | return r; | 237 | return r; |
283 | } | 238 | } |
284 | EXPORT_SYMBOL(omapdss_dpi_display_enable); | 239 | EXPORT_SYMBOL(omapdss_dpi_display_enable); |
285 | 240 | ||
286 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) | 241 | void omapdss_dpi_display_disable(struct omap_dss_device *dssdev) |
287 | { | 242 | { |
288 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 243 | dssdev->manager->disable(dssdev->manager); |
289 | 244 | ||
290 | mutex_lock(&dpi.lock); | 245 | if (dpi_use_dsi_pll(dssdev)) { |
291 | 246 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | |
292 | dss_mgr_disable(mgr); | ||
293 | |||
294 | if (dpi.dsidev) { | ||
295 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | ||
296 | dsi_pll_uninit(dpi.dsidev, true); | 247 | dsi_pll_uninit(dpi.dsidev, true); |
297 | dsi_runtime_put(dpi.dsidev); | 248 | dsi_runtime_put(dpi.dsidev); |
298 | } | 249 | } |
299 | 250 | ||
300 | dispc_runtime_put(); | 251 | dispc_runtime_put(); |
252 | dss_runtime_put(); | ||
301 | 253 | ||
302 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) | 254 | if (cpu_is_omap34xx()) |
303 | regulator_disable(dpi.vdds_dsi_reg); | 255 | regulator_disable(dpi.vdds_dsi_reg); |
304 | 256 | ||
305 | omap_dss_stop_device(dssdev); | 257 | omap_dss_stop_device(dssdev); |
306 | |||
307 | mutex_unlock(&dpi.lock); | ||
308 | } | 258 | } |
309 | EXPORT_SYMBOL(omapdss_dpi_display_disable); | 259 | EXPORT_SYMBOL(omapdss_dpi_display_disable); |
310 | 260 | ||
311 | void omapdss_dpi_set_timings(struct omap_dss_device *dssdev, | 261 | void dpi_set_timings(struct omap_dss_device *dssdev, |
312 | struct omap_video_timings *timings) | 262 | struct omap_video_timings *timings) |
313 | { | 263 | { |
264 | int r; | ||
265 | |||
314 | DSSDBG("dpi_set_timings\n"); | 266 | DSSDBG("dpi_set_timings\n"); |
267 | dssdev->panel.timings = *timings; | ||
268 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
269 | r = dss_runtime_get(); | ||
270 | if (r) | ||
271 | return; | ||
315 | 272 | ||
316 | mutex_lock(&dpi.lock); | 273 | r = dispc_runtime_get(); |
274 | if (r) { | ||
275 | dss_runtime_put(); | ||
276 | return; | ||
277 | } | ||
317 | 278 | ||
318 | dpi.timings = *timings; | 279 | dpi_set_mode(dssdev); |
280 | dispc_go(dssdev->manager->id); | ||
319 | 281 | ||
320 | mutex_unlock(&dpi.lock); | 282 | dispc_runtime_put(); |
283 | dss_runtime_put(); | ||
284 | } | ||
321 | } | 285 | } |
322 | EXPORT_SYMBOL(omapdss_dpi_set_timings); | 286 | EXPORT_SYMBOL(dpi_set_timings); |
323 | 287 | ||
324 | int dpi_check_timings(struct omap_dss_device *dssdev, | 288 | int dpi_check_timings(struct omap_dss_device *dssdev, |
325 | struct omap_video_timings *timings) | 289 | struct omap_video_timings *timings) |
326 | { | 290 | { |
291 | bool is_tft; | ||
327 | int r; | 292 | int r; |
328 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
329 | int lck_div, pck_div; | 293 | int lck_div, pck_div; |
330 | unsigned long fck; | 294 | unsigned long fck; |
331 | unsigned long pck; | 295 | unsigned long pck; |
332 | struct dispc_clock_info dispc_cinfo; | 296 | struct dispc_clock_info dispc_cinfo; |
333 | 297 | ||
334 | if (mgr && !dispc_mgr_timings_ok(mgr->id, timings)) | 298 | if (!dispc_lcd_timings_ok(timings)) |
335 | return -EINVAL; | 299 | return -EINVAL; |
336 | 300 | ||
337 | if (timings->pixel_clock == 0) | 301 | if (timings->pixel_clock == 0) |
338 | return -EINVAL; | 302 | return -EINVAL; |
339 | 303 | ||
340 | if (dpi.dsidev) { | 304 | is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0; |
305 | |||
306 | if (dpi_use_dsi_pll(dssdev)) { | ||
341 | struct dsi_clock_info dsi_cinfo; | 307 | struct dsi_clock_info dsi_cinfo; |
342 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, | 308 | r = dsi_pll_calc_clock_div_pck(dpi.dsidev, is_tft, |
343 | timings->pixel_clock * 1000, | 309 | timings->pixel_clock * 1000, |
344 | &dsi_cinfo, &dispc_cinfo); | 310 | &dsi_cinfo, &dispc_cinfo); |
345 | 311 | ||
@@ -349,7 +315,7 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
349 | fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; | 315 | fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk; |
350 | } else { | 316 | } else { |
351 | struct dss_clock_info dss_cinfo; | 317 | struct dss_clock_info dss_cinfo; |
352 | r = dss_calc_clock_div(timings->pixel_clock * 1000, | 318 | r = dss_calc_clock_div(is_tft, timings->pixel_clock * 1000, |
353 | &dss_cinfo, &dispc_cinfo); | 319 | &dss_cinfo, &dispc_cinfo); |
354 | 320 | ||
355 | if (r) | 321 | if (r) |
@@ -369,46 +335,11 @@ int dpi_check_timings(struct omap_dss_device *dssdev, | |||
369 | } | 335 | } |
370 | EXPORT_SYMBOL(dpi_check_timings); | 336 | EXPORT_SYMBOL(dpi_check_timings); |
371 | 337 | ||
372 | void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) | 338 | int dpi_init_display(struct omap_dss_device *dssdev) |
373 | { | ||
374 | mutex_lock(&dpi.lock); | ||
375 | |||
376 | dpi.data_lines = data_lines; | ||
377 | |||
378 | mutex_unlock(&dpi.lock); | ||
379 | } | ||
380 | EXPORT_SYMBOL(omapdss_dpi_set_data_lines); | ||
381 | |||
382 | static int __init dpi_verify_dsi_pll(struct platform_device *dsidev) | ||
383 | { | ||
384 | int r; | ||
385 | |||
386 | /* do initial setup with the PLL to see if it is operational */ | ||
387 | |||
388 | r = dsi_runtime_get(dsidev); | ||
389 | if (r) | ||
390 | return r; | ||
391 | |||
392 | r = dsi_pll_init(dsidev, 0, 1); | ||
393 | if (r) { | ||
394 | dsi_runtime_put(dsidev); | ||
395 | return r; | ||
396 | } | ||
397 | |||
398 | dsi_pll_uninit(dsidev, true); | ||
399 | dsi_runtime_put(dsidev); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | static int __init dpi_init_display(struct omap_dss_device *dssdev) | ||
405 | { | 339 | { |
406 | struct platform_device *dsidev; | ||
407 | |||
408 | DSSDBG("init_display\n"); | 340 | DSSDBG("init_display\n"); |
409 | 341 | ||
410 | if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && | 342 | if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) { |
411 | dpi.vdds_dsi_reg == NULL) { | ||
412 | struct regulator *vdds_dsi; | 343 | struct regulator *vdds_dsi; |
413 | 344 | ||
414 | vdds_dsi = dss_get_vdds_dsi(); | 345 | vdds_dsi = dss_get_vdds_dsi(); |
@@ -421,147 +352,21 @@ static int __init dpi_init_display(struct omap_dss_device *dssdev) | |||
421 | dpi.vdds_dsi_reg = vdds_dsi; | 352 | dpi.vdds_dsi_reg = vdds_dsi; |
422 | } | 353 | } |
423 | 354 | ||
424 | /* | 355 | if (dpi_use_dsi_pll(dssdev)) { |
425 | * XXX We shouldn't need dssdev->channel for this. The dsi pll clock | 356 | enum omap_dss_clk_source dispc_fclk_src = |
426 | * source for DPI is SoC integration detail, not something that should | 357 | dssdev->clocks.dispc.dispc_fclk_src; |
427 | * be configured in the dssdev | 358 | dpi.dsidev = dpi_get_dsidev(dispc_fclk_src); |
428 | */ | ||
429 | dsidev = dpi_get_dsidev(dssdev->channel); | ||
430 | |||
431 | if (dsidev && dpi_verify_dsi_pll(dsidev)) { | ||
432 | dsidev = NULL; | ||
433 | DSSWARN("DSI PLL not operational\n"); | ||
434 | } | ||
435 | |||
436 | if (dsidev) | ||
437 | DSSDBG("using DSI PLL for DPI clock\n"); | ||
438 | |||
439 | dpi.dsidev = dsidev; | ||
440 | |||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev) | ||
445 | { | ||
446 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
447 | const char *def_disp_name = omapdss_get_default_display_name(); | ||
448 | struct omap_dss_device *def_dssdev; | ||
449 | int i; | ||
450 | |||
451 | def_dssdev = NULL; | ||
452 | |||
453 | for (i = 0; i < pdata->num_devices; ++i) { | ||
454 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
455 | |||
456 | if (dssdev->type != OMAP_DISPLAY_TYPE_DPI) | ||
457 | continue; | ||
458 | |||
459 | if (def_dssdev == NULL) | ||
460 | def_dssdev = dssdev; | ||
461 | |||
462 | if (def_disp_name != NULL && | ||
463 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
464 | def_dssdev = dssdev; | ||
465 | break; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | return def_dssdev; | ||
470 | } | ||
471 | |||
472 | static void __init dpi_probe_pdata(struct platform_device *dpidev) | ||
473 | { | ||
474 | struct omap_dss_device *plat_dssdev; | ||
475 | struct omap_dss_device *dssdev; | ||
476 | int r; | ||
477 | |||
478 | plat_dssdev = dpi_find_dssdev(dpidev); | ||
479 | |||
480 | if (!plat_dssdev) | ||
481 | return; | ||
482 | |||
483 | dssdev = dss_alloc_and_init_device(&dpidev->dev); | ||
484 | if (!dssdev) | ||
485 | return; | ||
486 | |||
487 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
488 | |||
489 | r = dpi_init_display(dssdev); | ||
490 | if (r) { | ||
491 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
492 | dss_put_device(dssdev); | ||
493 | return; | ||
494 | } | ||
495 | |||
496 | r = omapdss_output_set_device(&dpi.output, dssdev); | ||
497 | if (r) { | ||
498 | DSSERR("failed to connect output to new device: %s\n", | ||
499 | dssdev->name); | ||
500 | dss_put_device(dssdev); | ||
501 | return; | ||
502 | } | ||
503 | |||
504 | r = dss_add_device(dssdev); | ||
505 | if (r) { | ||
506 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
507 | omapdss_output_unset_device(&dpi.output); | ||
508 | dss_put_device(dssdev); | ||
509 | return; | ||
510 | } | 359 | } |
511 | } | ||
512 | |||
513 | static void __init dpi_init_output(struct platform_device *pdev) | ||
514 | { | ||
515 | struct omap_dss_output *out = &dpi.output; | ||
516 | |||
517 | out->pdev = pdev; | ||
518 | out->id = OMAP_DSS_OUTPUT_DPI; | ||
519 | out->type = OMAP_DISPLAY_TYPE_DPI; | ||
520 | |||
521 | dss_register_output(out); | ||
522 | } | ||
523 | |||
524 | static void __exit dpi_uninit_output(struct platform_device *pdev) | ||
525 | { | ||
526 | struct omap_dss_output *out = &dpi.output; | ||
527 | |||
528 | dss_unregister_output(out); | ||
529 | } | ||
530 | |||
531 | static int __init omap_dpi_probe(struct platform_device *pdev) | ||
532 | { | ||
533 | mutex_init(&dpi.lock); | ||
534 | |||
535 | dpi_init_output(pdev); | ||
536 | |||
537 | dpi_probe_pdata(pdev); | ||
538 | 360 | ||
539 | return 0; | 361 | return 0; |
540 | } | 362 | } |
541 | 363 | ||
542 | static int __exit omap_dpi_remove(struct platform_device *pdev) | 364 | int dpi_init(void) |
543 | { | 365 | { |
544 | dss_unregister_child_devices(&pdev->dev); | ||
545 | |||
546 | dpi_uninit_output(pdev); | ||
547 | |||
548 | return 0; | 366 | return 0; |
549 | } | 367 | } |
550 | 368 | ||
551 | static struct platform_driver omap_dpi_driver = { | 369 | void dpi_exit(void) |
552 | .remove = __exit_p(omap_dpi_remove), | ||
553 | .driver = { | ||
554 | .name = "omapdss_dpi", | ||
555 | .owner = THIS_MODULE, | ||
556 | }, | ||
557 | }; | ||
558 | |||
559 | int __init dpi_init_platform_driver(void) | ||
560 | { | 370 | { |
561 | return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe); | ||
562 | } | 371 | } |
563 | 372 | ||
564 | void __exit dpi_uninit_platform_driver(void) | ||
565 | { | ||
566 | platform_driver_unregister(&omap_dpi_driver); | ||
567 | } | ||
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 28d41d16b7b..7adbbeb8433 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -27,7 +27,6 @@ | |||
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
30 | #include <linux/module.h> | ||
31 | #include <linux/semaphore.h> | 30 | #include <linux/semaphore.h> |
32 | #include <linux/seq_file.h> | 31 | #include <linux/seq_file.h> |
33 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
@@ -40,11 +39,12 @@ | |||
40 | #include <linux/pm_runtime.h> | 39 | #include <linux/pm_runtime.h> |
41 | 40 | ||
42 | #include <video/omapdss.h> | 41 | #include <video/omapdss.h> |
43 | #include <video/mipi_display.h> | 42 | #include <plat/clock.h> |
44 | 43 | ||
45 | #include "dss.h" | 44 | #include "dss.h" |
46 | #include "dss_features.h" | 45 | #include "dss_features.h" |
47 | 46 | ||
47 | /*#define VERBOSE_IRQ*/ | ||
48 | #define DSI_CATCH_MISSING_TE | 48 | #define DSI_CATCH_MISSING_TE |
49 | 49 | ||
50 | struct dsi_reg { u16 idx; }; | 50 | struct dsi_reg { u16 idx; }; |
@@ -131,7 +131,7 @@ struct dsi_reg { u16 idx; }; | |||
131 | #define DSI_IRQ_TA_TIMEOUT (1 << 20) | 131 | #define DSI_IRQ_TA_TIMEOUT (1 << 20) |
132 | #define DSI_IRQ_ERROR_MASK \ | 132 | #define DSI_IRQ_ERROR_MASK \ |
133 | (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \ | 133 | (DSI_IRQ_HS_TX_TIMEOUT | DSI_IRQ_LP_RX_TIMEOUT | DSI_IRQ_SYNC_LOST | \ |
134 | DSI_IRQ_TA_TIMEOUT | DSI_IRQ_SYNC_LOST) | 134 | DSI_IRQ_TA_TIMEOUT) |
135 | #define DSI_IRQ_CHANNEL_MASK 0xf | 135 | #define DSI_IRQ_CHANNEL_MASK 0xf |
136 | 136 | ||
137 | /* Virtual channel interrupts */ | 137 | /* Virtual channel interrupts */ |
@@ -198,24 +198,21 @@ struct dsi_reg { u16 idx; }; | |||
198 | DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \ | 198 | DSI_CIO_IRQ_ERRCONTENTIONLP0_4 | DSI_CIO_IRQ_ERRCONTENTIONLP1_4 | \ |
199 | DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5) | 199 | DSI_CIO_IRQ_ERRCONTENTIONLP0_5 | DSI_CIO_IRQ_ERRCONTENTIONLP1_5) |
200 | 200 | ||
201 | #define DSI_DT_DCS_SHORT_WRITE_0 0x05 | ||
202 | #define DSI_DT_DCS_SHORT_WRITE_1 0x15 | ||
203 | #define DSI_DT_DCS_READ 0x06 | ||
204 | #define DSI_DT_SET_MAX_RET_PKG_SIZE 0x37 | ||
205 | #define DSI_DT_NULL_PACKET 0x09 | ||
206 | #define DSI_DT_DCS_LONG_WRITE 0x39 | ||
207 | |||
208 | #define DSI_DT_RX_ACK_WITH_ERR 0x02 | ||
209 | #define DSI_DT_RX_DCS_LONG_READ 0x1c | ||
210 | #define DSI_DT_RX_SHORT_READ_1 0x21 | ||
211 | #define DSI_DT_RX_SHORT_READ_2 0x22 | ||
212 | |||
201 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); | 213 | typedef void (*omap_dsi_isr_t) (void *arg, u32 mask); |
202 | 214 | ||
203 | #define DSI_MAX_NR_ISRS 2 | 215 | #define DSI_MAX_NR_ISRS 2 |
204 | #define DSI_MAX_NR_LANES 5 | ||
205 | |||
206 | enum dsi_lane_function { | ||
207 | DSI_LANE_UNUSED = 0, | ||
208 | DSI_LANE_CLK, | ||
209 | DSI_LANE_DATA1, | ||
210 | DSI_LANE_DATA2, | ||
211 | DSI_LANE_DATA3, | ||
212 | DSI_LANE_DATA4, | ||
213 | }; | ||
214 | |||
215 | struct dsi_lane_config { | ||
216 | enum dsi_lane_function function; | ||
217 | u8 polarity; | ||
218 | }; | ||
219 | 216 | ||
220 | struct dsi_isr_data { | 217 | struct dsi_isr_data { |
221 | omap_dsi_isr_t isr; | 218 | omap_dsi_isr_t isr; |
@@ -231,9 +228,27 @@ enum fifo_size { | |||
231 | DSI_FIFO_SIZE_128 = 4, | 228 | DSI_FIFO_SIZE_128 = 4, |
232 | }; | 229 | }; |
233 | 230 | ||
234 | enum dsi_vc_source { | 231 | enum dsi_vc_mode { |
235 | DSI_VC_SOURCE_L4 = 0, | 232 | DSI_VC_MODE_L4 = 0, |
236 | DSI_VC_SOURCE_VP, | 233 | DSI_VC_MODE_VP, |
234 | }; | ||
235 | |||
236 | enum dsi_lane { | ||
237 | DSI_CLK_P = 1 << 0, | ||
238 | DSI_CLK_N = 1 << 1, | ||
239 | DSI_DATA1_P = 1 << 2, | ||
240 | DSI_DATA1_N = 1 << 3, | ||
241 | DSI_DATA2_P = 1 << 4, | ||
242 | DSI_DATA2_N = 1 << 5, | ||
243 | DSI_DATA3_P = 1 << 6, | ||
244 | DSI_DATA3_N = 1 << 7, | ||
245 | DSI_DATA4_P = 1 << 8, | ||
246 | DSI_DATA4_N = 1 << 9, | ||
247 | }; | ||
248 | |||
249 | struct dsi_update_region { | ||
250 | u16 x, y, w, h; | ||
251 | struct omap_dss_device *device; | ||
237 | }; | 252 | }; |
238 | 253 | ||
239 | struct dsi_irq_stats { | 254 | struct dsi_irq_stats { |
@@ -254,20 +269,20 @@ struct dsi_data { | |||
254 | struct platform_device *pdev; | 269 | struct platform_device *pdev; |
255 | void __iomem *base; | 270 | void __iomem *base; |
256 | 271 | ||
257 | int module_id; | ||
258 | |||
259 | int irq; | 272 | int irq; |
260 | 273 | ||
261 | struct clk *dss_clk; | 274 | struct clk *dss_clk; |
262 | struct clk *sys_clk; | 275 | struct clk *sys_clk; |
263 | 276 | ||
277 | void (*dsi_mux_pads)(bool enable); | ||
278 | |||
264 | struct dsi_clock_info current_cinfo; | 279 | struct dsi_clock_info current_cinfo; |
265 | 280 | ||
266 | bool vdds_dsi_enabled; | 281 | bool vdds_dsi_enabled; |
267 | struct regulator *vdds_dsi_reg; | 282 | struct regulator *vdds_dsi_reg; |
268 | 283 | ||
269 | struct { | 284 | struct { |
270 | enum dsi_vc_source source; | 285 | enum dsi_vc_mode mode; |
271 | struct omap_dss_device *dssdev; | 286 | struct omap_dss_device *dssdev; |
272 | enum fifo_size fifo_size; | 287 | enum fifo_size fifo_size; |
273 | int vc_id; | 288 | int vc_id; |
@@ -284,9 +299,7 @@ struct dsi_data { | |||
284 | struct dsi_isr_tables isr_tables_copy; | 299 | struct dsi_isr_tables isr_tables_copy; |
285 | 300 | ||
286 | int update_channel; | 301 | int update_channel; |
287 | #ifdef DEBUG | 302 | struct dsi_update_region update_region; |
288 | unsigned update_bytes; | ||
289 | #endif | ||
290 | 303 | ||
291 | bool te_enabled; | 304 | bool te_enabled; |
292 | bool ulps_enabled; | 305 | bool ulps_enabled; |
@@ -323,20 +336,9 @@ struct dsi_data { | |||
323 | unsigned long fint_min, fint_max; | 336 | unsigned long fint_min, fint_max; |
324 | unsigned long lpdiv_max; | 337 | unsigned long lpdiv_max; |
325 | 338 | ||
326 | unsigned num_lanes_supported; | 339 | int num_data_lanes; |
327 | |||
328 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; | ||
329 | unsigned num_lanes_used; | ||
330 | 340 | ||
331 | unsigned scp_clk_refcount; | 341 | unsigned scp_clk_refcount; |
332 | |||
333 | struct dss_lcd_mgr_config mgr_config; | ||
334 | struct omap_video_timings timings; | ||
335 | enum omap_dss_dsi_pixel_format pix_fmt; | ||
336 | enum omap_dss_dsi_mode mode; | ||
337 | struct omap_dss_dsi_videomode_timings vm_timings; | ||
338 | |||
339 | struct omap_dss_output output; | ||
340 | }; | 342 | }; |
341 | 343 | ||
342 | struct dsi_packet_sent_handler_data { | 344 | struct dsi_packet_sent_handler_data { |
@@ -344,9 +346,11 @@ struct dsi_packet_sent_handler_data { | |||
344 | struct completion *completion; | 346 | struct completion *completion; |
345 | }; | 347 | }; |
346 | 348 | ||
349 | static struct platform_device *dsi_pdev_map[MAX_NUM_DSI]; | ||
350 | |||
347 | #ifdef DEBUG | 351 | #ifdef DEBUG |
348 | static bool dsi_perf; | 352 | static unsigned int dsi_perf; |
349 | module_param(dsi_perf, bool, 0644); | 353 | module_param_named(dsi_perf, dsi_perf, bool, 0644); |
350 | #endif | 354 | #endif |
351 | 355 | ||
352 | static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev) | 356 | static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dsidev) |
@@ -356,28 +360,22 @@ static inline struct dsi_data *dsi_get_dsidrv_data(struct platform_device *dside | |||
356 | 360 | ||
357 | static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) | 361 | static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss_device *dssdev) |
358 | { | 362 | { |
359 | return dssdev->output->pdev; | 363 | return dsi_pdev_map[dssdev->phy.dsi.module]; |
360 | } | 364 | } |
361 | 365 | ||
362 | struct platform_device *dsi_get_dsidev_from_id(int module) | 366 | struct platform_device *dsi_get_dsidev_from_id(int module) |
363 | { | 367 | { |
364 | struct omap_dss_output *out; | 368 | return dsi_pdev_map[module]; |
365 | enum omap_dss_output_id id; | 369 | } |
366 | |||
367 | switch (module) { | ||
368 | case 0: | ||
369 | id = OMAP_DSS_OUTPUT_DSI1; | ||
370 | break; | ||
371 | case 1: | ||
372 | id = OMAP_DSS_OUTPUT_DSI2; | ||
373 | break; | ||
374 | default: | ||
375 | return NULL; | ||
376 | } | ||
377 | 370 | ||
378 | out = omap_dss_get_output(id); | 371 | static int dsi_get_dsidev_id(struct platform_device *dsidev) |
372 | { | ||
373 | /* TEMP: Pass 0 as the dsi module index till the time the dsi platform | ||
374 | * device names aren't changed to the form "omapdss_dsi.0", | ||
375 | * "omapdss_dsi.1" and so on */ | ||
376 | BUG_ON(dsidev->id != -1); | ||
379 | 377 | ||
380 | return out ? out->pdev : NULL; | 378 | return 0; |
381 | } | 379 | } |
382 | 380 | ||
383 | static inline void dsi_write_reg(struct platform_device *dsidev, | 381 | static inline void dsi_write_reg(struct platform_device *dsidev, |
@@ -429,45 +427,14 @@ static void dsi_completion_handler(void *data, u32 mask) | |||
429 | static inline int wait_for_bit_change(struct platform_device *dsidev, | 427 | static inline int wait_for_bit_change(struct platform_device *dsidev, |
430 | const struct dsi_reg idx, int bitnum, int value) | 428 | const struct dsi_reg idx, int bitnum, int value) |
431 | { | 429 | { |
432 | unsigned long timeout; | 430 | int t = 100000; |
433 | ktime_t wait; | ||
434 | int t; | ||
435 | |||
436 | /* first busyloop to see if the bit changes right away */ | ||
437 | t = 100; | ||
438 | while (t-- > 0) { | ||
439 | if (REG_GET(dsidev, idx, bitnum, bitnum) == value) | ||
440 | return value; | ||
441 | } | ||
442 | |||
443 | /* then loop for 500ms, sleeping for 1ms in between */ | ||
444 | timeout = jiffies + msecs_to_jiffies(500); | ||
445 | while (time_before(jiffies, timeout)) { | ||
446 | if (REG_GET(dsidev, idx, bitnum, bitnum) == value) | ||
447 | return value; | ||
448 | 431 | ||
449 | wait = ns_to_ktime(1000 * 1000); | 432 | while (REG_GET(dsidev, idx, bitnum, bitnum) != value) { |
450 | set_current_state(TASK_UNINTERRUPTIBLE); | 433 | if (--t == 0) |
451 | schedule_hrtimeout(&wait, HRTIMER_MODE_REL); | 434 | return !value; |
452 | } | 435 | } |
453 | 436 | ||
454 | return !value; | 437 | return value; |
455 | } | ||
456 | |||
457 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) | ||
458 | { | ||
459 | switch (fmt) { | ||
460 | case OMAP_DSS_DSI_FMT_RGB888: | ||
461 | case OMAP_DSS_DSI_FMT_RGB666: | ||
462 | return 24; | ||
463 | case OMAP_DSS_DSI_FMT_RGB666_PACKED: | ||
464 | return 18; | ||
465 | case OMAP_DSS_DSI_FMT_RGB565: | ||
466 | return 16; | ||
467 | default: | ||
468 | BUG(); | ||
469 | return 0; | ||
470 | } | ||
471 | } | 438 | } |
472 | 439 | ||
473 | #ifdef DEBUG | 440 | #ifdef DEBUG |
@@ -507,7 +474,9 @@ static void dsi_perf_show(struct platform_device *dsidev, const char *name) | |||
507 | 474 | ||
508 | total_us = setup_us + trans_us; | 475 | total_us = setup_us + trans_us; |
509 | 476 | ||
510 | total_bytes = dsi->update_bytes; | 477 | total_bytes = dsi->update_region.w * |
478 | dsi->update_region.h * | ||
479 | dsi->update_region.device->ctrl.pixel_size / 8; | ||
511 | 480 | ||
512 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " | 481 | printk(KERN_INFO "DSI(%s): %u us + %u us = %u us (%uHz), " |
513 | "%u bytes, %u kbytes/sec\n", | 482 | "%u bytes, %u kbytes/sec\n", |
@@ -534,38 +503,42 @@ static inline void dsi_perf_show(struct platform_device *dsidev, | |||
534 | } | 503 | } |
535 | #endif | 504 | #endif |
536 | 505 | ||
537 | static int verbose_irq; | ||
538 | |||
539 | static void print_irq_status(u32 status) | 506 | static void print_irq_status(u32 status) |
540 | { | 507 | { |
541 | if (status == 0) | 508 | if (status == 0) |
542 | return; | 509 | return; |
543 | 510 | ||
544 | if (!verbose_irq && (status & ~DSI_IRQ_CHANNEL_MASK) == 0) | 511 | #ifndef VERBOSE_IRQ |
512 | if ((status & ~DSI_IRQ_CHANNEL_MASK) == 0) | ||
545 | return; | 513 | return; |
514 | #endif | ||
515 | printk(KERN_DEBUG "DSI IRQ: 0x%x: ", status); | ||
546 | 516 | ||
547 | #define PIS(x) (status & DSI_IRQ_##x) ? (#x " ") : "" | 517 | #define PIS(x) \ |
548 | 518 | if (status & DSI_IRQ_##x) \ | |
549 | pr_debug("DSI IRQ: 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", | 519 | printk(#x " "); |
550 | status, | 520 | #ifdef VERBOSE_IRQ |
551 | verbose_irq ? PIS(VC0) : "", | 521 | PIS(VC0); |
552 | verbose_irq ? PIS(VC1) : "", | 522 | PIS(VC1); |
553 | verbose_irq ? PIS(VC2) : "", | 523 | PIS(VC2); |
554 | verbose_irq ? PIS(VC3) : "", | 524 | PIS(VC3); |
555 | PIS(WAKEUP), | 525 | #endif |
556 | PIS(RESYNC), | 526 | PIS(WAKEUP); |
557 | PIS(PLL_LOCK), | 527 | PIS(RESYNC); |
558 | PIS(PLL_UNLOCK), | 528 | PIS(PLL_LOCK); |
559 | PIS(PLL_RECALL), | 529 | PIS(PLL_UNLOCK); |
560 | PIS(COMPLEXIO_ERR), | 530 | PIS(PLL_RECALL); |
561 | PIS(HS_TX_TIMEOUT), | 531 | PIS(COMPLEXIO_ERR); |
562 | PIS(LP_RX_TIMEOUT), | 532 | PIS(HS_TX_TIMEOUT); |
563 | PIS(TE_TRIGGER), | 533 | PIS(LP_RX_TIMEOUT); |
564 | PIS(ACK_TRIGGER), | 534 | PIS(TE_TRIGGER); |
565 | PIS(SYNC_LOST), | 535 | PIS(ACK_TRIGGER); |
566 | PIS(LDO_POWER_GOOD), | 536 | PIS(SYNC_LOST); |
567 | PIS(TA_TIMEOUT)); | 537 | PIS(LDO_POWER_GOOD); |
538 | PIS(TA_TIMEOUT); | ||
568 | #undef PIS | 539 | #undef PIS |
540 | |||
541 | printk("\n"); | ||
569 | } | 542 | } |
570 | 543 | ||
571 | static void print_irq_status_vc(int channel, u32 status) | 544 | static void print_irq_status_vc(int channel, u32 status) |
@@ -573,24 +546,28 @@ static void print_irq_status_vc(int channel, u32 status) | |||
573 | if (status == 0) | 546 | if (status == 0) |
574 | return; | 547 | return; |
575 | 548 | ||
576 | if (!verbose_irq && (status & ~DSI_VC_IRQ_PACKET_SENT) == 0) | 549 | #ifndef VERBOSE_IRQ |
550 | if ((status & ~DSI_VC_IRQ_PACKET_SENT) == 0) | ||
577 | return; | 551 | return; |
552 | #endif | ||
553 | printk(KERN_DEBUG "DSI VC(%d) IRQ 0x%x: ", channel, status); | ||
578 | 554 | ||
579 | #define PIS(x) (status & DSI_VC_IRQ_##x) ? (#x " ") : "" | 555 | #define PIS(x) \ |
580 | 556 | if (status & DSI_VC_IRQ_##x) \ | |
581 | pr_debug("DSI VC(%d) IRQ 0x%x: %s%s%s%s%s%s%s%s%s\n", | 557 | printk(#x " "); |
582 | channel, | 558 | PIS(CS); |
583 | status, | 559 | PIS(ECC_CORR); |
584 | PIS(CS), | 560 | #ifdef VERBOSE_IRQ |
585 | PIS(ECC_CORR), | 561 | PIS(PACKET_SENT); |
586 | PIS(ECC_NO_CORR), | 562 | #endif |
587 | verbose_irq ? PIS(PACKET_SENT) : "", | 563 | PIS(FIFO_TX_OVF); |
588 | PIS(BTA), | 564 | PIS(FIFO_RX_OVF); |
589 | PIS(FIFO_TX_OVF), | 565 | PIS(BTA); |
590 | PIS(FIFO_RX_OVF), | 566 | PIS(ECC_NO_CORR); |
591 | PIS(FIFO_TX_UDF), | 567 | PIS(FIFO_TX_UDF); |
592 | PIS(PP_BUSY_CHANGE)); | 568 | PIS(PP_BUSY_CHANGE); |
593 | #undef PIS | 569 | #undef PIS |
570 | printk("\n"); | ||
594 | } | 571 | } |
595 | 572 | ||
596 | static void print_irq_status_cio(u32 status) | 573 | static void print_irq_status_cio(u32 status) |
@@ -598,31 +575,34 @@ static void print_irq_status_cio(u32 status) | |||
598 | if (status == 0) | 575 | if (status == 0) |
599 | return; | 576 | return; |
600 | 577 | ||
601 | #define PIS(x) (status & DSI_CIO_IRQ_##x) ? (#x " ") : "" | 578 | printk(KERN_DEBUG "DSI CIO IRQ 0x%x: ", status); |
602 | 579 | ||
603 | pr_debug("DSI CIO IRQ 0x%x: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n", | 580 | #define PIS(x) \ |
604 | status, | 581 | if (status & DSI_CIO_IRQ_##x) \ |
605 | PIS(ERRSYNCESC1), | 582 | printk(#x " "); |
606 | PIS(ERRSYNCESC2), | 583 | PIS(ERRSYNCESC1); |
607 | PIS(ERRSYNCESC3), | 584 | PIS(ERRSYNCESC2); |
608 | PIS(ERRESC1), | 585 | PIS(ERRSYNCESC3); |
609 | PIS(ERRESC2), | 586 | PIS(ERRESC1); |
610 | PIS(ERRESC3), | 587 | PIS(ERRESC2); |
611 | PIS(ERRCONTROL1), | 588 | PIS(ERRESC3); |
612 | PIS(ERRCONTROL2), | 589 | PIS(ERRCONTROL1); |
613 | PIS(ERRCONTROL3), | 590 | PIS(ERRCONTROL2); |
614 | PIS(STATEULPS1), | 591 | PIS(ERRCONTROL3); |
615 | PIS(STATEULPS2), | 592 | PIS(STATEULPS1); |
616 | PIS(STATEULPS3), | 593 | PIS(STATEULPS2); |
617 | PIS(ERRCONTENTIONLP0_1), | 594 | PIS(STATEULPS3); |
618 | PIS(ERRCONTENTIONLP1_1), | 595 | PIS(ERRCONTENTIONLP0_1); |
619 | PIS(ERRCONTENTIONLP0_2), | 596 | PIS(ERRCONTENTIONLP1_1); |
620 | PIS(ERRCONTENTIONLP1_2), | 597 | PIS(ERRCONTENTIONLP0_2); |
621 | PIS(ERRCONTENTIONLP0_3), | 598 | PIS(ERRCONTENTIONLP1_2); |
622 | PIS(ERRCONTENTIONLP1_3), | 599 | PIS(ERRCONTENTIONLP0_3); |
623 | PIS(ULPSACTIVENOT_ALL0), | 600 | PIS(ERRCONTENTIONLP1_3); |
624 | PIS(ULPSACTIVENOT_ALL1)); | 601 | PIS(ULPSACTIVENOT_ALL0); |
602 | PIS(ULPSACTIVENOT_ALL1); | ||
625 | #undef PIS | 603 | #undef PIS |
604 | |||
605 | printk("\n"); | ||
626 | } | 606 | } |
627 | 607 | ||
628 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 608 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
@@ -1083,8 +1063,8 @@ void dsi_runtime_put(struct platform_device *dsidev) | |||
1083 | 1063 | ||
1084 | DSSDBG("dsi_runtime_put\n"); | 1064 | DSSDBG("dsi_runtime_put\n"); |
1085 | 1065 | ||
1086 | r = pm_runtime_put_sync(&dsi->pdev->dev); | 1066 | r = pm_runtime_put(&dsi->pdev->dev); |
1087 | WARN_ON(r < 0 && r != -ENOSYS); | 1067 | WARN_ON(r < 0); |
1088 | } | 1068 | } |
1089 | 1069 | ||
1090 | /* source clock for DSI PLL. this could also be PCLKFREE */ | 1070 | /* source clock for DSI PLL. this could also be PCLKFREE */ |
@@ -1094,9 +1074,9 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, | |||
1094 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1074 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1095 | 1075 | ||
1096 | if (enable) | 1076 | if (enable) |
1097 | clk_prepare_enable(dsi->sys_clk); | 1077 | clk_enable(dsi->sys_clk); |
1098 | else | 1078 | else |
1099 | clk_disable_unprepare(dsi->sys_clk); | 1079 | clk_disable(dsi->sys_clk); |
1100 | 1080 | ||
1101 | if (enable && dsi->pll_locked) { | 1081 | if (enable && dsi->pll_locked) { |
1102 | if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) | 1082 | if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) |
@@ -1104,16 +1084,28 @@ static inline void dsi_enable_pll_clock(struct platform_device *dsidev, | |||
1104 | } | 1084 | } |
1105 | } | 1085 | } |
1106 | 1086 | ||
1087 | #ifdef DEBUG | ||
1107 | static void _dsi_print_reset_status(struct platform_device *dsidev) | 1088 | static void _dsi_print_reset_status(struct platform_device *dsidev) |
1108 | { | 1089 | { |
1109 | u32 l; | 1090 | u32 l; |
1110 | int b0, b1, b2; | 1091 | int b0, b1, b2; |
1111 | 1092 | ||
1093 | if (!dss_debug) | ||
1094 | return; | ||
1095 | |||
1112 | /* A dummy read using the SCP interface to any DSIPHY register is | 1096 | /* A dummy read using the SCP interface to any DSIPHY register is |
1113 | * required after DSIPHY reset to complete the reset of the DSI complex | 1097 | * required after DSIPHY reset to complete the reset of the DSI complex |
1114 | * I/O. */ | 1098 | * I/O. */ |
1115 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); | 1099 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); |
1116 | 1100 | ||
1101 | printk(KERN_DEBUG "DSI resets: "); | ||
1102 | |||
1103 | l = dsi_read_reg(dsidev, DSI_PLL_STATUS); | ||
1104 | printk("PLL (%d) ", FLD_GET(l, 0, 0)); | ||
1105 | |||
1106 | l = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); | ||
1107 | printk("CIO (%d) ", FLD_GET(l, 29, 29)); | ||
1108 | |||
1117 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { | 1109 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { |
1118 | b0 = 28; | 1110 | b0 = 28; |
1119 | b1 = 27; | 1111 | b1 = 27; |
@@ -1124,21 +1116,18 @@ static void _dsi_print_reset_status(struct platform_device *dsidev) | |||
1124 | b2 = 26; | 1116 | b2 = 26; |
1125 | } | 1117 | } |
1126 | 1118 | ||
1127 | #define DSI_FLD_GET(fld, start, end)\ | 1119 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); |
1128 | FLD_GET(dsi_read_reg(dsidev, DSI_##fld), start, end) | 1120 | printk("PHY (%x%x%x, %d, %d, %d)\n", |
1129 | 1121 | FLD_GET(l, b0, b0), | |
1130 | pr_debug("DSI resets: PLL (%d) CIO (%d) PHY (%x%x%x, %d, %d, %d)\n", | 1122 | FLD_GET(l, b1, b1), |
1131 | DSI_FLD_GET(PLL_STATUS, 0, 0), | 1123 | FLD_GET(l, b2, b2), |
1132 | DSI_FLD_GET(COMPLEXIO_CFG1, 29, 29), | 1124 | FLD_GET(l, 29, 29), |
1133 | DSI_FLD_GET(DSIPHY_CFG5, b0, b0), | 1125 | FLD_GET(l, 30, 30), |
1134 | DSI_FLD_GET(DSIPHY_CFG5, b1, b1), | 1126 | FLD_GET(l, 31, 31)); |
1135 | DSI_FLD_GET(DSIPHY_CFG5, b2, b2), | ||
1136 | DSI_FLD_GET(DSIPHY_CFG5, 29, 29), | ||
1137 | DSI_FLD_GET(DSIPHY_CFG5, 30, 30), | ||
1138 | DSI_FLD_GET(DSIPHY_CFG5, 31, 31)); | ||
1139 | |||
1140 | #undef DSI_FLD_GET | ||
1141 | } | 1127 | } |
1128 | #else | ||
1129 | #define _dsi_print_reset_status(x) | ||
1130 | #endif | ||
1142 | 1131 | ||
1143 | static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) | 1132 | static inline int dsi_if_enable(struct platform_device *dsidev, bool enable) |
1144 | { | 1133 | { |
@@ -1179,9 +1168,10 @@ static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev) | |||
1179 | static unsigned long dsi_fclk_rate(struct platform_device *dsidev) | 1168 | static unsigned long dsi_fclk_rate(struct platform_device *dsidev) |
1180 | { | 1169 | { |
1181 | unsigned long r; | 1170 | unsigned long r; |
1171 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
1182 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1172 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1183 | 1173 | ||
1184 | if (dss_get_dsi_clk_source(dsi->module_id) == OMAP_DSS_CLK_SRC_FCK) { | 1174 | if (dss_get_dsi_clk_source(dsi_module) == OMAP_DSS_CLK_SRC_FCK) { |
1185 | /* DSI FCLK source is DSS_CLK_FCK */ | 1175 | /* DSI FCLK source is DSS_CLK_FCK */ |
1186 | r = clk_get_rate(dsi->dss_clk); | 1176 | r = clk_get_rate(dsi->dss_clk); |
1187 | } else { | 1177 | } else { |
@@ -1273,9 +1263,10 @@ static int dsi_pll_power(struct platform_device *dsidev, | |||
1273 | } | 1263 | } |
1274 | 1264 | ||
1275 | /* calculate clock rates using dividers in cinfo */ | 1265 | /* calculate clock rates using dividers in cinfo */ |
1276 | static int dsi_calc_clock_rates(struct platform_device *dsidev, | 1266 | static int dsi_calc_clock_rates(struct omap_dss_device *dssdev, |
1277 | struct dsi_clock_info *cinfo) | 1267 | struct dsi_clock_info *cinfo) |
1278 | { | 1268 | { |
1269 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
1279 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1270 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1280 | 1271 | ||
1281 | if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max) | 1272 | if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max) |
@@ -1290,8 +1281,21 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev, | |||
1290 | if (cinfo->regm_dsi > dsi->regm_dsi_max) | 1281 | if (cinfo->regm_dsi > dsi->regm_dsi_max) |
1291 | return -EINVAL; | 1282 | return -EINVAL; |
1292 | 1283 | ||
1293 | cinfo->clkin = clk_get_rate(dsi->sys_clk); | 1284 | if (cinfo->use_sys_clk) { |
1294 | cinfo->fint = cinfo->clkin / cinfo->regn; | 1285 | cinfo->clkin = clk_get_rate(dsi->sys_clk); |
1286 | /* XXX it is unclear if highfreq should be used | ||
1287 | * with DSS_SYS_CLK source also */ | ||
1288 | cinfo->highfreq = 0; | ||
1289 | } else { | ||
1290 | cinfo->clkin = dispc_pclk_rate(dssdev->manager->id); | ||
1291 | |||
1292 | if (cinfo->clkin < 32000000) | ||
1293 | cinfo->highfreq = 0; | ||
1294 | else | ||
1295 | cinfo->highfreq = 1; | ||
1296 | } | ||
1297 | |||
1298 | cinfo->fint = cinfo->clkin / (cinfo->regn * (cinfo->highfreq ? 2 : 1)); | ||
1295 | 1299 | ||
1296 | if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min) | 1300 | if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min) |
1297 | return -EINVAL; | 1301 | return -EINVAL; |
@@ -1316,7 +1320,7 @@ static int dsi_calc_clock_rates(struct platform_device *dsidev, | |||
1316 | return 0; | 1320 | return 0; |
1317 | } | 1321 | } |
1318 | 1322 | ||
1319 | int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | 1323 | int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, |
1320 | unsigned long req_pck, struct dsi_clock_info *dsi_cinfo, | 1324 | unsigned long req_pck, struct dsi_clock_info *dsi_cinfo, |
1321 | struct dispc_clock_info *dispc_cinfo) | 1325 | struct dispc_clock_info *dispc_cinfo) |
1322 | { | 1326 | { |
@@ -1335,8 +1339,8 @@ int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | |||
1335 | dsi->cache_cinfo.clkin == dss_sys_clk) { | 1339 | dsi->cache_cinfo.clkin == dss_sys_clk) { |
1336 | DSSDBG("DSI clock info found from cache\n"); | 1340 | DSSDBG("DSI clock info found from cache\n"); |
1337 | *dsi_cinfo = dsi->cache_cinfo; | 1341 | *dsi_cinfo = dsi->cache_cinfo; |
1338 | dispc_find_clk_divs(req_pck, dsi_cinfo->dsi_pll_hsdiv_dispc_clk, | 1342 | dispc_find_clk_divs(is_tft, req_pck, |
1339 | dispc_cinfo); | 1343 | dsi_cinfo->dsi_pll_hsdiv_dispc_clk, dispc_cinfo); |
1340 | return 0; | 1344 | return 0; |
1341 | } | 1345 | } |
1342 | 1346 | ||
@@ -1358,21 +1362,27 @@ retry: | |||
1358 | 1362 | ||
1359 | memset(&cur, 0, sizeof(cur)); | 1363 | memset(&cur, 0, sizeof(cur)); |
1360 | cur.clkin = dss_sys_clk; | 1364 | cur.clkin = dss_sys_clk; |
1365 | cur.use_sys_clk = 1; | ||
1366 | cur.highfreq = 0; | ||
1361 | 1367 | ||
1362 | /* 0.75MHz < Fint = clkin / regn < 2.1MHz */ | 1368 | /* no highfreq: 0.75MHz < Fint = clkin / regn < 2.1MHz */ |
1369 | /* highfreq: 0.75MHz < Fint = clkin / (2*regn) < 2.1MHz */ | ||
1363 | /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ | 1370 | /* To reduce PLL lock time, keep Fint high (around 2 MHz) */ |
1364 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { | 1371 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { |
1365 | cur.fint = cur.clkin / cur.regn; | 1372 | if (cur.highfreq == 0) |
1373 | cur.fint = cur.clkin / cur.regn; | ||
1374 | else | ||
1375 | cur.fint = cur.clkin / (2 * cur.regn); | ||
1366 | 1376 | ||
1367 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) | 1377 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) |
1368 | continue; | 1378 | continue; |
1369 | 1379 | ||
1370 | /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ | 1380 | /* DSIPHY(MHz) = (2 * regm / regn) * (clkin / (highfreq + 1)) */ |
1371 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { | 1381 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { |
1372 | unsigned long a, b; | 1382 | unsigned long a, b; |
1373 | 1383 | ||
1374 | a = 2 * cur.regm * (cur.clkin/1000); | 1384 | a = 2 * cur.regm * (cur.clkin/1000); |
1375 | b = cur.regn; | 1385 | b = cur.regn * (cur.highfreq + 1); |
1376 | cur.clkin4ddr = a / b * 1000; | 1386 | cur.clkin4ddr = a / b * 1000; |
1377 | 1387 | ||
1378 | if (cur.clkin4ddr > 1800 * 1000 * 1000) | 1388 | if (cur.clkin4ddr > 1800 * 1000 * 1000) |
@@ -1386,11 +1396,6 @@ retry: | |||
1386 | cur.dsi_pll_hsdiv_dispc_clk = | 1396 | cur.dsi_pll_hsdiv_dispc_clk = |
1387 | cur.clkin4ddr / cur.regm_dispc; | 1397 | cur.clkin4ddr / cur.regm_dispc; |
1388 | 1398 | ||
1389 | if (cur.regm_dispc > 1 && | ||
1390 | cur.regm_dispc % 2 != 0 && | ||
1391 | req_pck >= 1000000) | ||
1392 | continue; | ||
1393 | |||
1394 | /* this will narrow down the search a bit, | 1399 | /* this will narrow down the search a bit, |
1395 | * but still give pixclocks below what was | 1400 | * but still give pixclocks below what was |
1396 | * requested */ | 1401 | * requested */ |
@@ -1407,7 +1412,7 @@ retry: | |||
1407 | 1412 | ||
1408 | match = 1; | 1413 | match = 1; |
1409 | 1414 | ||
1410 | dispc_find_clk_divs(req_pck, | 1415 | dispc_find_clk_divs(is_tft, req_pck, |
1411 | cur.dsi_pll_hsdiv_dispc_clk, | 1416 | cur.dsi_pll_hsdiv_dispc_clk, |
1412 | &cur_dispc); | 1417 | &cur_dispc); |
1413 | 1418 | ||
@@ -1453,148 +1458,6 @@ found: | |||
1453 | return 0; | 1458 | return 0; |
1454 | } | 1459 | } |
1455 | 1460 | ||
1456 | static int dsi_pll_calc_ddrfreq(struct platform_device *dsidev, | ||
1457 | unsigned long req_clkin4ddr, struct dsi_clock_info *cinfo) | ||
1458 | { | ||
1459 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1460 | struct dsi_clock_info cur, best; | ||
1461 | |||
1462 | DSSDBG("dsi_pll_calc_ddrfreq\n"); | ||
1463 | |||
1464 | memset(&best, 0, sizeof(best)); | ||
1465 | memset(&cur, 0, sizeof(cur)); | ||
1466 | |||
1467 | cur.clkin = clk_get_rate(dsi->sys_clk); | ||
1468 | |||
1469 | for (cur.regn = 1; cur.regn < dsi->regn_max; ++cur.regn) { | ||
1470 | cur.fint = cur.clkin / cur.regn; | ||
1471 | |||
1472 | if (cur.fint > dsi->fint_max || cur.fint < dsi->fint_min) | ||
1473 | continue; | ||
1474 | |||
1475 | /* DSIPHY(MHz) = (2 * regm / regn) * clkin */ | ||
1476 | for (cur.regm = 1; cur.regm < dsi->regm_max; ++cur.regm) { | ||
1477 | unsigned long a, b; | ||
1478 | |||
1479 | a = 2 * cur.regm * (cur.clkin/1000); | ||
1480 | b = cur.regn; | ||
1481 | cur.clkin4ddr = a / b * 1000; | ||
1482 | |||
1483 | if (cur.clkin4ddr > 1800 * 1000 * 1000) | ||
1484 | break; | ||
1485 | |||
1486 | if (abs(cur.clkin4ddr - req_clkin4ddr) < | ||
1487 | abs(best.clkin4ddr - req_clkin4ddr)) { | ||
1488 | best = cur; | ||
1489 | DSSDBG("best %ld\n", best.clkin4ddr); | ||
1490 | } | ||
1491 | |||
1492 | if (cur.clkin4ddr == req_clkin4ddr) | ||
1493 | goto found; | ||
1494 | } | ||
1495 | } | ||
1496 | found: | ||
1497 | if (cinfo) | ||
1498 | *cinfo = best; | ||
1499 | |||
1500 | return 0; | ||
1501 | } | ||
1502 | |||
1503 | static void dsi_pll_calc_dsi_fck(struct platform_device *dsidev, | ||
1504 | struct dsi_clock_info *cinfo) | ||
1505 | { | ||
1506 | unsigned long max_dsi_fck; | ||
1507 | |||
1508 | max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK); | ||
1509 | |||
1510 | cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck); | ||
1511 | cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi; | ||
1512 | } | ||
1513 | |||
1514 | static int dsi_pll_calc_dispc_fck(struct platform_device *dsidev, | ||
1515 | unsigned long req_pck, struct dsi_clock_info *cinfo, | ||
1516 | struct dispc_clock_info *dispc_cinfo) | ||
1517 | { | ||
1518 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
1519 | unsigned regm_dispc, best_regm_dispc; | ||
1520 | unsigned long dispc_clk, best_dispc_clk; | ||
1521 | int min_fck_per_pck; | ||
1522 | unsigned long max_dss_fck; | ||
1523 | struct dispc_clock_info best_dispc; | ||
1524 | bool match; | ||
1525 | |||
1526 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
1527 | |||
1528 | min_fck_per_pck = CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK; | ||
1529 | |||
1530 | if (min_fck_per_pck && | ||
1531 | req_pck * min_fck_per_pck > max_dss_fck) { | ||
1532 | DSSERR("Requested pixel clock not possible with the current " | ||
1533 | "OMAP2_DSS_MIN_FCK_PER_PCK setting. Turning " | ||
1534 | "the constraint off.\n"); | ||
1535 | min_fck_per_pck = 0; | ||
1536 | } | ||
1537 | |||
1538 | retry: | ||
1539 | best_regm_dispc = 0; | ||
1540 | best_dispc_clk = 0; | ||
1541 | memset(&best_dispc, 0, sizeof(best_dispc)); | ||
1542 | match = false; | ||
1543 | |||
1544 | for (regm_dispc = 1; regm_dispc < dsi->regm_dispc_max; ++regm_dispc) { | ||
1545 | struct dispc_clock_info cur_dispc; | ||
1546 | |||
1547 | dispc_clk = cinfo->clkin4ddr / regm_dispc; | ||
1548 | |||
1549 | /* this will narrow down the search a bit, | ||
1550 | * but still give pixclocks below what was | ||
1551 | * requested */ | ||
1552 | if (dispc_clk < req_pck) | ||
1553 | break; | ||
1554 | |||
1555 | if (dispc_clk > max_dss_fck) | ||
1556 | continue; | ||
1557 | |||
1558 | if (min_fck_per_pck && dispc_clk < req_pck * min_fck_per_pck) | ||
1559 | continue; | ||
1560 | |||
1561 | match = true; | ||
1562 | |||
1563 | dispc_find_clk_divs(req_pck, dispc_clk, &cur_dispc); | ||
1564 | |||
1565 | if (abs(cur_dispc.pck - req_pck) < | ||
1566 | abs(best_dispc.pck - req_pck)) { | ||
1567 | best_regm_dispc = regm_dispc; | ||
1568 | best_dispc_clk = dispc_clk; | ||
1569 | best_dispc = cur_dispc; | ||
1570 | |||
1571 | if (cur_dispc.pck == req_pck) | ||
1572 | goto found; | ||
1573 | } | ||
1574 | } | ||
1575 | |||
1576 | if (!match) { | ||
1577 | if (min_fck_per_pck) { | ||
1578 | DSSERR("Could not find suitable clock settings.\n" | ||
1579 | "Turning FCK/PCK constraint off and" | ||
1580 | "trying again.\n"); | ||
1581 | min_fck_per_pck = 0; | ||
1582 | goto retry; | ||
1583 | } | ||
1584 | |||
1585 | DSSERR("Could not find suitable clock settings.\n"); | ||
1586 | |||
1587 | return -EINVAL; | ||
1588 | } | ||
1589 | found: | ||
1590 | cinfo->regm_dispc = best_regm_dispc; | ||
1591 | cinfo->dsi_pll_hsdiv_dispc_clk = best_dispc_clk; | ||
1592 | |||
1593 | *dispc_cinfo = best_dispc; | ||
1594 | |||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 1461 | int dsi_pll_set_clock_div(struct platform_device *dsidev, |
1599 | struct dsi_clock_info *cinfo) | 1462 | struct dsi_clock_info *cinfo) |
1600 | { | 1463 | { |
@@ -1605,9 +1468,11 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
1605 | u8 regn_start, regn_end, regm_start, regm_end; | 1468 | u8 regn_start, regn_end, regm_start, regm_end; |
1606 | u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; | 1469 | u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end; |
1607 | 1470 | ||
1608 | DSSDBG("DSI PLL clock config starts"); | 1471 | DSSDBGF(); |
1472 | |||
1473 | dsi->current_cinfo.use_sys_clk = cinfo->use_sys_clk; | ||
1474 | dsi->current_cinfo.highfreq = cinfo->highfreq; | ||
1609 | 1475 | ||
1610 | dsi->current_cinfo.clkin = cinfo->clkin; | ||
1611 | dsi->current_cinfo.fint = cinfo->fint; | 1476 | dsi->current_cinfo.fint = cinfo->fint; |
1612 | dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr; | 1477 | dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr; |
1613 | dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk = | 1478 | dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk = |
@@ -1622,13 +1487,17 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
1622 | 1487 | ||
1623 | DSSDBG("DSI Fint %ld\n", cinfo->fint); | 1488 | DSSDBG("DSI Fint %ld\n", cinfo->fint); |
1624 | 1489 | ||
1625 | DSSDBG("clkin rate %ld\n", cinfo->clkin); | 1490 | DSSDBG("clkin (%s) rate %ld, highfreq %d\n", |
1491 | cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree", | ||
1492 | cinfo->clkin, | ||
1493 | cinfo->highfreq); | ||
1626 | 1494 | ||
1627 | /* DSIPHY == CLKIN4DDR */ | 1495 | /* DSIPHY == CLKIN4DDR */ |
1628 | DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n", | 1496 | DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu / %d = %lu\n", |
1629 | cinfo->regm, | 1497 | cinfo->regm, |
1630 | cinfo->regn, | 1498 | cinfo->regn, |
1631 | cinfo->clkin, | 1499 | cinfo->clkin, |
1500 | cinfo->highfreq + 1, | ||
1632 | cinfo->clkin4ddr); | 1501 | cinfo->clkin4ddr); |
1633 | 1502 | ||
1634 | DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", | 1503 | DSSDBG("Data rate on 1 DSI lane %ld Mbps\n", |
@@ -1671,27 +1540,25 @@ int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
1671 | 1540 | ||
1672 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); | 1541 | BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max); |
1673 | 1542 | ||
1674 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
1675 | |||
1676 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { | 1543 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) { |
1677 | f = cinfo->fint < 1000000 ? 0x3 : | 1544 | f = cinfo->fint < 1000000 ? 0x3 : |
1678 | cinfo->fint < 1250000 ? 0x4 : | 1545 | cinfo->fint < 1250000 ? 0x4 : |
1679 | cinfo->fint < 1500000 ? 0x5 : | 1546 | cinfo->fint < 1500000 ? 0x5 : |
1680 | cinfo->fint < 1750000 ? 0x6 : | 1547 | cinfo->fint < 1750000 ? 0x6 : |
1681 | 0x7; | 1548 | 0x7; |
1682 | |||
1683 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ | ||
1684 | } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) { | ||
1685 | f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4; | ||
1686 | |||
1687 | l = FLD_MOD(l, f, 4, 1); /* PLL_SELFREQDCO */ | ||
1688 | } | 1549 | } |
1689 | 1550 | ||
1551 | l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2); | ||
1552 | |||
1553 | if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) | ||
1554 | l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */ | ||
1555 | l = FLD_MOD(l, cinfo->use_sys_clk ? 0 : 1, | ||
1556 | 11, 11); /* DSI_PLL_CLKSEL */ | ||
1557 | l = FLD_MOD(l, cinfo->highfreq, | ||
1558 | 12, 12); /* DSI_PLL_HIGHFREQ */ | ||
1690 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ | 1559 | l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */ |
1691 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ | 1560 | l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */ |
1692 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ | 1561 | l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */ |
1693 | if (dss_has_feature(FEAT_DSI_PLL_REFSEL)) | ||
1694 | l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */ | ||
1695 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); | 1562 | dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l); |
1696 | 1563 | ||
1697 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ | 1564 | REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */ |
@@ -1741,21 +1608,11 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | |||
1741 | 1608 | ||
1742 | DSSDBG("PLL init\n"); | 1609 | DSSDBG("PLL init\n"); |
1743 | 1610 | ||
1744 | /* | ||
1745 | * It seems that on many OMAPs we need to enable both to have a | ||
1746 | * functional HSDivider. | ||
1747 | */ | ||
1748 | enable_hsclk = enable_hsdiv = true; | ||
1749 | |||
1750 | if (dsi->vdds_dsi_reg == NULL) { | 1611 | if (dsi->vdds_dsi_reg == NULL) { |
1751 | struct regulator *vdds_dsi; | 1612 | struct regulator *vdds_dsi; |
1752 | 1613 | ||
1753 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); | 1614 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); |
1754 | 1615 | ||
1755 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
1756 | if (IS_ERR(vdds_dsi)) | ||
1757 | vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
1758 | |||
1759 | if (IS_ERR(vdds_dsi)) { | 1616 | if (IS_ERR(vdds_dsi)) { |
1760 | DSSERR("can't get VDDS_DSI regulator\n"); | 1617 | DSSERR("can't get VDDS_DSI regulator\n"); |
1761 | return PTR_ERR(vdds_dsi); | 1618 | return PTR_ERR(vdds_dsi); |
@@ -1843,7 +1700,7 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
1843 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1700 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1844 | struct dsi_clock_info *cinfo = &dsi->current_cinfo; | 1701 | struct dsi_clock_info *cinfo = &dsi->current_cinfo; |
1845 | enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; | 1702 | enum omap_dss_clk_source dispc_clk_src, dsi_clk_src; |
1846 | int dsi_module = dsi->module_id; | 1703 | int dsi_module = dsi_get_dsidev_id(dsidev); |
1847 | 1704 | ||
1848 | dispc_clk_src = dss_get_dispc_clk_source(); | 1705 | dispc_clk_src = dss_get_dispc_clk_source(); |
1849 | dsi_clk_src = dss_get_dsi_clk_source(dsi_module); | 1706 | dsi_clk_src = dss_get_dsi_clk_source(dsi_module); |
@@ -1853,26 +1710,25 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev, | |||
1853 | 1710 | ||
1854 | seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); | 1711 | seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1); |
1855 | 1712 | ||
1856 | seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin); | 1713 | seq_printf(s, "dsi pll source = %s\n", |
1714 | cinfo->use_sys_clk ? "dss_sys_clk" : "pclkfree"); | ||
1857 | 1715 | ||
1858 | seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); | 1716 | seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn); |
1859 | 1717 | ||
1860 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", | 1718 | seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n", |
1861 | cinfo->clkin4ddr, cinfo->regm); | 1719 | cinfo->clkin4ddr, cinfo->regm); |
1862 | 1720 | ||
1863 | seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n", | 1721 | seq_printf(s, "%s (%s)\t%-16luregm_dispc %u\t(%s)\n", |
1864 | dss_feat_get_clk_source_name(dsi_module == 0 ? | 1722 | dss_get_generic_clk_source_name(dispc_clk_src), |
1865 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : | 1723 | dss_feat_get_clk_source_name(dispc_clk_src), |
1866 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC), | ||
1867 | cinfo->dsi_pll_hsdiv_dispc_clk, | 1724 | cinfo->dsi_pll_hsdiv_dispc_clk, |
1868 | cinfo->regm_dispc, | 1725 | cinfo->regm_dispc, |
1869 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1726 | dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
1870 | "off" : "on"); | 1727 | "off" : "on"); |
1871 | 1728 | ||
1872 | seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n", | 1729 | seq_printf(s, "%s (%s)\t%-16luregm_dsi %u\t(%s)\n", |
1873 | dss_feat_get_clk_source_name(dsi_module == 0 ? | 1730 | dss_get_generic_clk_source_name(dsi_clk_src), |
1874 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : | 1731 | dss_feat_get_clk_source_name(dsi_clk_src), |
1875 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI), | ||
1876 | cinfo->dsi_pll_hsdiv_dsi_clk, | 1732 | cinfo->dsi_pll_hsdiv_dsi_clk, |
1877 | cinfo->regm_dsi, | 1733 | cinfo->regm_dsi, |
1878 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? | 1734 | dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ? |
@@ -1915,6 +1771,7 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, | |||
1915 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 1771 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
1916 | unsigned long flags; | 1772 | unsigned long flags; |
1917 | struct dsi_irq_stats stats; | 1773 | struct dsi_irq_stats stats; |
1774 | int dsi_module = dsi_get_dsidev_id(dsidev); | ||
1918 | 1775 | ||
1919 | spin_lock_irqsave(&dsi->irq_stats_lock, flags); | 1776 | spin_lock_irqsave(&dsi->irq_stats_lock, flags); |
1920 | 1777 | ||
@@ -1931,7 +1788,7 @@ static void dsi_dump_dsidev_irqs(struct platform_device *dsidev, | |||
1931 | #define PIS(x) \ | 1788 | #define PIS(x) \ |
1932 | seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); | 1789 | seq_printf(s, "%-20s %10d\n", #x, stats.dsi_irqs[ffs(DSI_IRQ_##x)-1]); |
1933 | 1790 | ||
1934 | seq_printf(s, "-- DSI%d interrupts --\n", dsi->module_id + 1); | 1791 | seq_printf(s, "-- DSI%d interrupts --\n", dsi_module + 1); |
1935 | PIS(VC0); | 1792 | PIS(VC0); |
1936 | PIS(VC1); | 1793 | PIS(VC1); |
1937 | PIS(VC2); | 1794 | PIS(VC2); |
@@ -2011,6 +1868,22 @@ static void dsi2_dump_irqs(struct seq_file *s) | |||
2011 | 1868 | ||
2012 | dsi_dump_dsidev_irqs(dsidev, s); | 1869 | dsi_dump_dsidev_irqs(dsidev, s); |
2013 | } | 1870 | } |
1871 | |||
1872 | void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, | ||
1873 | const struct file_operations *debug_fops) | ||
1874 | { | ||
1875 | struct platform_device *dsidev; | ||
1876 | |||
1877 | dsidev = dsi_get_dsidev_from_id(0); | ||
1878 | if (dsidev) | ||
1879 | debugfs_create_file("dsi1_irqs", S_IRUGO, debugfs_dir, | ||
1880 | &dsi1_dump_irqs, debug_fops); | ||
1881 | |||
1882 | dsidev = dsi_get_dsidev_from_id(1); | ||
1883 | if (dsidev) | ||
1884 | debugfs_create_file("dsi2_irqs", S_IRUGO, debugfs_dir, | ||
1885 | &dsi2_dump_irqs, debug_fops); | ||
1886 | } | ||
2014 | #endif | 1887 | #endif |
2015 | 1888 | ||
2016 | static void dsi_dump_dsidev_regs(struct platform_device *dsidev, | 1889 | static void dsi_dump_dsidev_regs(struct platform_device *dsidev, |
@@ -2111,6 +1984,21 @@ static void dsi2_dump_regs(struct seq_file *s) | |||
2111 | dsi_dump_dsidev_regs(dsidev, s); | 1984 | dsi_dump_dsidev_regs(dsidev, s); |
2112 | } | 1985 | } |
2113 | 1986 | ||
1987 | void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, | ||
1988 | const struct file_operations *debug_fops) | ||
1989 | { | ||
1990 | struct platform_device *dsidev; | ||
1991 | |||
1992 | dsidev = dsi_get_dsidev_from_id(0); | ||
1993 | if (dsidev) | ||
1994 | debugfs_create_file("dsi1_regs", S_IRUGO, debugfs_dir, | ||
1995 | &dsi1_dump_regs, debug_fops); | ||
1996 | |||
1997 | dsidev = dsi_get_dsidev_from_id(1); | ||
1998 | if (dsidev) | ||
1999 | debugfs_create_file("dsi2_regs", S_IRUGO, debugfs_dir, | ||
2000 | &dsi2_dump_regs, debug_fops); | ||
2001 | } | ||
2114 | enum dsi_cio_power_state { | 2002 | enum dsi_cio_power_state { |
2115 | DSI_COMPLEXIO_POWER_OFF = 0x0, | 2003 | DSI_COMPLEXIO_POWER_OFF = 0x0, |
2116 | DSI_COMPLEXIO_POWER_ON = 0x1, | 2004 | DSI_COMPLEXIO_POWER_ON = 0x1, |
@@ -2139,6 +2027,34 @@ static int dsi_cio_power(struct platform_device *dsidev, | |||
2139 | return 0; | 2027 | return 0; |
2140 | } | 2028 | } |
2141 | 2029 | ||
2030 | /* Number of data lanes present on DSI interface */ | ||
2031 | static inline int dsi_get_num_data_lanes(struct platform_device *dsidev) | ||
2032 | { | ||
2033 | /* DSI on OMAP3 doesn't have register DSI_GNQ, set number | ||
2034 | * of data lanes as 2 by default */ | ||
2035 | if (dss_has_feature(FEAT_DSI_GNQ)) | ||
2036 | return REG_GET(dsidev, DSI_GNQ, 11, 9); /* NB_DATA_LANES */ | ||
2037 | else | ||
2038 | return 2; | ||
2039 | } | ||
2040 | |||
2041 | /* Number of data lanes used by the dss device */ | ||
2042 | static inline int dsi_get_num_data_lanes_dssdev(struct omap_dss_device *dssdev) | ||
2043 | { | ||
2044 | int num_data_lanes = 0; | ||
2045 | |||
2046 | if (dssdev->phy.dsi.data1_lane != 0) | ||
2047 | num_data_lanes++; | ||
2048 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2049 | num_data_lanes++; | ||
2050 | if (dssdev->phy.dsi.data3_lane != 0) | ||
2051 | num_data_lanes++; | ||
2052 | if (dssdev->phy.dsi.data4_lane != 0) | ||
2053 | num_data_lanes++; | ||
2054 | |||
2055 | return num_data_lanes; | ||
2056 | } | ||
2057 | |||
2142 | static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | 2058 | static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) |
2143 | { | 2059 | { |
2144 | int val; | 2060 | int val; |
@@ -2165,60 +2081,64 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
2165 | return 1194 * 3; /* 1194x24 bits */ | 2081 | return 1194 * 3; /* 1194x24 bits */ |
2166 | case 6: | 2082 | case 6: |
2167 | return 1365 * 3; /* 1365x24 bits */ | 2083 | return 1365 * 3; /* 1365x24 bits */ |
2168 | case 7: | ||
2169 | return 1920 * 3; /* 1920x24 bits */ | ||
2170 | default: | 2084 | default: |
2171 | BUG(); | 2085 | BUG(); |
2172 | return 0; | ||
2173 | } | 2086 | } |
2174 | } | 2087 | } |
2175 | 2088 | ||
2176 | static int dsi_set_lane_config(struct platform_device *dsidev) | 2089 | static void dsi_set_lane_config(struct omap_dss_device *dssdev) |
2177 | { | 2090 | { |
2178 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2091 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2179 | static const u8 offsets[] = { 0, 4, 8, 12, 16 }; | ||
2180 | static const enum dsi_lane_function functions[] = { | ||
2181 | DSI_LANE_CLK, | ||
2182 | DSI_LANE_DATA1, | ||
2183 | DSI_LANE_DATA2, | ||
2184 | DSI_LANE_DATA3, | ||
2185 | DSI_LANE_DATA4, | ||
2186 | }; | ||
2187 | u32 r; | 2092 | u32 r; |
2188 | int i; | 2093 | int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); |
2189 | |||
2190 | r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); | ||
2191 | 2094 | ||
2192 | for (i = 0; i < dsi->num_lanes_used; ++i) { | 2095 | int clk_lane = dssdev->phy.dsi.clk_lane; |
2193 | unsigned offset = offsets[i]; | 2096 | int data1_lane = dssdev->phy.dsi.data1_lane; |
2194 | unsigned polarity, lane_number; | 2097 | int data2_lane = dssdev->phy.dsi.data2_lane; |
2195 | unsigned t; | 2098 | int clk_pol = dssdev->phy.dsi.clk_pol; |
2099 | int data1_pol = dssdev->phy.dsi.data1_pol; | ||
2100 | int data2_pol = dssdev->phy.dsi.data2_pol; | ||
2196 | 2101 | ||
2197 | for (t = 0; t < dsi->num_lanes_supported; ++t) | 2102 | r = dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG1); |
2198 | if (dsi->lanes[t].function == functions[i]) | 2103 | r = FLD_MOD(r, clk_lane, 2, 0); |
2199 | break; | 2104 | r = FLD_MOD(r, clk_pol, 3, 3); |
2200 | 2105 | r = FLD_MOD(r, data1_lane, 6, 4); | |
2201 | if (t == dsi->num_lanes_supported) | 2106 | r = FLD_MOD(r, data1_pol, 7, 7); |
2202 | return -EINVAL; | 2107 | r = FLD_MOD(r, data2_lane, 10, 8); |
2203 | 2108 | r = FLD_MOD(r, data2_pol, 11, 11); | |
2204 | lane_number = t; | 2109 | if (num_data_lanes_dssdev > 2) { |
2205 | polarity = dsi->lanes[t].polarity; | 2110 | int data3_lane = dssdev->phy.dsi.data3_lane; |
2206 | 2111 | int data3_pol = dssdev->phy.dsi.data3_pol; | |
2207 | r = FLD_MOD(r, lane_number + 1, offset + 2, offset); | 2112 | |
2208 | r = FLD_MOD(r, polarity, offset + 3, offset + 3); | 2113 | r = FLD_MOD(r, data3_lane, 14, 12); |
2114 | r = FLD_MOD(r, data3_pol, 15, 15); | ||
2209 | } | 2115 | } |
2116 | if (num_data_lanes_dssdev > 3) { | ||
2117 | int data4_lane = dssdev->phy.dsi.data4_lane; | ||
2118 | int data4_pol = dssdev->phy.dsi.data4_pol; | ||
2210 | 2119 | ||
2211 | /* clear the unused lanes */ | 2120 | r = FLD_MOD(r, data4_lane, 18, 16); |
2212 | for (; i < dsi->num_lanes_supported; ++i) { | 2121 | r = FLD_MOD(r, data4_pol, 19, 19); |
2213 | unsigned offset = offsets[i]; | ||
2214 | |||
2215 | r = FLD_MOD(r, 0, offset + 2, offset); | ||
2216 | r = FLD_MOD(r, 0, offset + 3, offset + 3); | ||
2217 | } | 2122 | } |
2218 | |||
2219 | dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); | 2123 | dsi_write_reg(dsidev, DSI_COMPLEXIO_CFG1, r); |
2220 | 2124 | ||
2221 | return 0; | 2125 | /* The configuration of the DSI complex I/O (number of data lanes, |
2126 | position, differential order) should not be changed while | ||
2127 | DSS.DSI_CLK_CRTRL[20] LP_CLK_ENABLE bit is set to 1. In order for | ||
2128 | the hardware to take into account a new configuration of the complex | ||
2129 | I/O (done in DSS.DSI_COMPLEXIO_CFG1 register), it is recommended to | ||
2130 | follow this sequence: First set the DSS.DSI_CTRL[0] IF_EN bit to 1, | ||
2131 | then reset the DSS.DSI_CTRL[0] IF_EN to 0, then set | ||
2132 | DSS.DSI_CLK_CTRL[20] LP_CLK_ENABLE to 1 and finally set again the | ||
2133 | DSS.DSI_CTRL[0] IF_EN bit to 1. If the sequence is not followed, the | ||
2134 | DSI complex I/O configuration is unknown. */ | ||
2135 | |||
2136 | /* | ||
2137 | REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); | ||
2138 | REG_FLD_MOD(dsidev, DSI_CTRL, 0, 0, 0); | ||
2139 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); | ||
2140 | REG_FLD_MOD(dsidev, DSI_CTRL, 1, 0, 0); | ||
2141 | */ | ||
2222 | } | 2142 | } |
2223 | 2143 | ||
2224 | static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) | 2144 | static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns) |
@@ -2298,16 +2218,9 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2298 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); | 2218 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG0, r); |
2299 | 2219 | ||
2300 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | 2220 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); |
2301 | r = FLD_MOD(r, tlpx_half, 20, 16); | 2221 | r = FLD_MOD(r, tlpx_half, 22, 16); |
2302 | r = FLD_MOD(r, tclk_trail, 15, 8); | 2222 | r = FLD_MOD(r, tclk_trail, 15, 8); |
2303 | r = FLD_MOD(r, tclk_zero, 7, 0); | 2223 | r = FLD_MOD(r, tclk_zero, 7, 0); |
2304 | |||
2305 | if (dss_has_feature(FEAT_DSI_PHY_DCC)) { | ||
2306 | r = FLD_MOD(r, 0, 21, 21); /* DCCEN = disable */ | ||
2307 | r = FLD_MOD(r, 1, 22, 22); /* CLKINP_DIVBY2EN = enable */ | ||
2308 | r = FLD_MOD(r, 1, 23, 23); /* CLKINP_SEL = enable */ | ||
2309 | } | ||
2310 | |||
2311 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); | 2224 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG1, r); |
2312 | 2225 | ||
2313 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); | 2226 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG2); |
@@ -2315,27 +2228,49 @@ static void dsi_cio_timings(struct platform_device *dsidev) | |||
2315 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); | 2228 | dsi_write_reg(dsidev, DSI_DSIPHY_CFG2, r); |
2316 | } | 2229 | } |
2317 | 2230 | ||
2318 | /* lane masks have lane 0 at lsb. mask_p for positive lines, n for negative */ | 2231 | static void dsi_cio_enable_lane_override(struct omap_dss_device *dssdev, |
2319 | static void dsi_cio_enable_lane_override(struct platform_device *dsidev, | 2232 | enum dsi_lane lanes) |
2320 | unsigned mask_p, unsigned mask_n) | ||
2321 | { | 2233 | { |
2234 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2322 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2235 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2323 | int i; | 2236 | int clk_lane = dssdev->phy.dsi.clk_lane; |
2324 | u32 l; | 2237 | int data1_lane = dssdev->phy.dsi.data1_lane; |
2325 | u8 lptxscp_start = dsi->num_lanes_supported == 3 ? 22 : 26; | 2238 | int data2_lane = dssdev->phy.dsi.data2_lane; |
2326 | 2239 | int data3_lane = dssdev->phy.dsi.data3_lane; | |
2327 | l = 0; | 2240 | int data4_lane = dssdev->phy.dsi.data4_lane; |
2328 | 2241 | int clk_pol = dssdev->phy.dsi.clk_pol; | |
2329 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | 2242 | int data1_pol = dssdev->phy.dsi.data1_pol; |
2330 | unsigned p = dsi->lanes[i].polarity; | 2243 | int data2_pol = dssdev->phy.dsi.data2_pol; |
2331 | 2244 | int data3_pol = dssdev->phy.dsi.data3_pol; | |
2332 | if (mask_p & (1 << i)) | 2245 | int data4_pol = dssdev->phy.dsi.data4_pol; |
2333 | l |= 1 << (i * 2 + (p ? 0 : 1)); | 2246 | |
2334 | 2247 | u32 l = 0; | |
2335 | if (mask_n & (1 << i)) | 2248 | u8 lptxscp_start = dsi->num_data_lanes == 2 ? 22 : 26; |
2336 | l |= 1 << (i * 2 + (p ? 1 : 0)); | 2249 | |
2337 | } | 2250 | if (lanes & DSI_CLK_P) |
2338 | 2251 | l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 0 : 1)); | |
2252 | if (lanes & DSI_CLK_N) | ||
2253 | l |= 1 << ((clk_lane - 1) * 2 + (clk_pol ? 1 : 0)); | ||
2254 | |||
2255 | if (lanes & DSI_DATA1_P) | ||
2256 | l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 0 : 1)); | ||
2257 | if (lanes & DSI_DATA1_N) | ||
2258 | l |= 1 << ((data1_lane - 1) * 2 + (data1_pol ? 1 : 0)); | ||
2259 | |||
2260 | if (lanes & DSI_DATA2_P) | ||
2261 | l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 0 : 1)); | ||
2262 | if (lanes & DSI_DATA2_N) | ||
2263 | l |= 1 << ((data2_lane - 1) * 2 + (data2_pol ? 1 : 0)); | ||
2264 | |||
2265 | if (lanes & DSI_DATA3_P) | ||
2266 | l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 0 : 1)); | ||
2267 | if (lanes & DSI_DATA3_N) | ||
2268 | l |= 1 << ((data3_lane - 1) * 2 + (data3_pol ? 1 : 0)); | ||
2269 | |||
2270 | if (lanes & DSI_DATA4_P) | ||
2271 | l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 0 : 1)); | ||
2272 | if (lanes & DSI_DATA4_N) | ||
2273 | l |= 1 << ((data4_lane - 1) * 2 + (data4_pol ? 1 : 0)); | ||
2339 | /* | 2274 | /* |
2340 | * Bits in REGLPTXSCPDAT4TO0DXDY: | 2275 | * Bits in REGLPTXSCPDAT4TO0DXDY: |
2341 | * 17: DY0 18: DX0 | 2276 | * 17: DY0 18: DX0 |
@@ -2365,42 +2300,54 @@ static void dsi_cio_disable_lane_override(struct platform_device *dsidev) | |||
2365 | REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); | 2300 | REG_FLD_MOD(dsidev, DSI_DSIPHY_CFG10, 0, 22, 17); |
2366 | } | 2301 | } |
2367 | 2302 | ||
2368 | static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) | 2303 | static int dsi_cio_wait_tx_clk_esc_reset(struct omap_dss_device *dssdev) |
2369 | { | 2304 | { |
2370 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2305 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2371 | int t, i; | 2306 | int t; |
2372 | bool in_use[DSI_MAX_NR_LANES]; | 2307 | int bits[3]; |
2373 | static const u8 offsets_old[] = { 28, 27, 26 }; | 2308 | bool in_use[3]; |
2374 | static const u8 offsets_new[] = { 24, 25, 26, 27, 28 }; | 2309 | |
2375 | const u8 *offsets; | 2310 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) { |
2376 | 2311 | bits[0] = 28; | |
2377 | if (dss_has_feature(FEAT_DSI_REVERSE_TXCLKESC)) | 2312 | bits[1] = 27; |
2378 | offsets = offsets_old; | 2313 | bits[2] = 26; |
2379 | else | 2314 | } else { |
2380 | offsets = offsets_new; | 2315 | bits[0] = 24; |
2316 | bits[1] = 25; | ||
2317 | bits[2] = 26; | ||
2318 | } | ||
2319 | |||
2320 | in_use[0] = false; | ||
2321 | in_use[1] = false; | ||
2322 | in_use[2] = false; | ||
2381 | 2323 | ||
2382 | for (i = 0; i < dsi->num_lanes_supported; ++i) | 2324 | if (dssdev->phy.dsi.clk_lane != 0) |
2383 | in_use[i] = dsi->lanes[i].function != DSI_LANE_UNUSED; | 2325 | in_use[dssdev->phy.dsi.clk_lane - 1] = true; |
2326 | if (dssdev->phy.dsi.data1_lane != 0) | ||
2327 | in_use[dssdev->phy.dsi.data1_lane - 1] = true; | ||
2328 | if (dssdev->phy.dsi.data2_lane != 0) | ||
2329 | in_use[dssdev->phy.dsi.data2_lane - 1] = true; | ||
2384 | 2330 | ||
2385 | t = 100000; | 2331 | t = 100000; |
2386 | while (true) { | 2332 | while (true) { |
2387 | u32 l; | 2333 | u32 l; |
2334 | int i; | ||
2388 | int ok; | 2335 | int ok; |
2389 | 2336 | ||
2390 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); | 2337 | l = dsi_read_reg(dsidev, DSI_DSIPHY_CFG5); |
2391 | 2338 | ||
2392 | ok = 0; | 2339 | ok = 0; |
2393 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | 2340 | for (i = 0; i < 3; ++i) { |
2394 | if (!in_use[i] || (l & (1 << offsets[i]))) | 2341 | if (!in_use[i] || (l & (1 << bits[i]))) |
2395 | ok++; | 2342 | ok++; |
2396 | } | 2343 | } |
2397 | 2344 | ||
2398 | if (ok == dsi->num_lanes_supported) | 2345 | if (ok == 3) |
2399 | break; | 2346 | break; |
2400 | 2347 | ||
2401 | if (--t == 0) { | 2348 | if (--t == 0) { |
2402 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | 2349 | for (i = 0; i < 3; ++i) { |
2403 | if (!in_use[i] || (l & (1 << offsets[i]))) | 2350 | if (!in_use[i] || (l & (1 << bits[i]))) |
2404 | continue; | 2351 | continue; |
2405 | 2352 | ||
2406 | DSSERR("CIO TXCLKESC%d domain not coming " \ | 2353 | DSSERR("CIO TXCLKESC%d domain not coming " \ |
@@ -2413,32 +2360,18 @@ static int dsi_cio_wait_tx_clk_esc_reset(struct platform_device *dsidev) | |||
2413 | return 0; | 2360 | return 0; |
2414 | } | 2361 | } |
2415 | 2362 | ||
2416 | /* return bitmask of enabled lanes, lane0 being the lsb */ | 2363 | static int dsi_cio_init(struct omap_dss_device *dssdev) |
2417 | static unsigned dsi_get_lane_mask(struct platform_device *dsidev) | ||
2418 | { | ||
2419 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2420 | unsigned mask = 0; | ||
2421 | int i; | ||
2422 | |||
2423 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | ||
2424 | if (dsi->lanes[i].function != DSI_LANE_UNUSED) | ||
2425 | mask |= 1 << i; | ||
2426 | } | ||
2427 | |||
2428 | return mask; | ||
2429 | } | ||
2430 | |||
2431 | static int dsi_cio_init(struct platform_device *dsidev) | ||
2432 | { | 2364 | { |
2365 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2433 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2366 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2434 | int r; | 2367 | int r; |
2368 | int num_data_lanes_dssdev = dsi_get_num_data_lanes_dssdev(dssdev); | ||
2435 | u32 l; | 2369 | u32 l; |
2436 | 2370 | ||
2437 | DSSDBG("DSI CIO init starts"); | 2371 | DSSDBGF(); |
2438 | 2372 | ||
2439 | r = dss_dsi_enable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); | 2373 | if (dsi->dsi_mux_pads) |
2440 | if (r) | 2374 | dsi->dsi_mux_pads(true); |
2441 | return r; | ||
2442 | 2375 | ||
2443 | dsi_enable_scp_clk(dsidev); | 2376 | dsi_enable_scp_clk(dsidev); |
2444 | 2377 | ||
@@ -2453,9 +2386,7 @@ static int dsi_cio_init(struct platform_device *dsidev) | |||
2453 | goto err_scp_clk_dom; | 2386 | goto err_scp_clk_dom; |
2454 | } | 2387 | } |
2455 | 2388 | ||
2456 | r = dsi_set_lane_config(dsidev); | 2389 | dsi_set_lane_config(dssdev); |
2457 | if (r) | ||
2458 | goto err_scp_clk_dom; | ||
2459 | 2390 | ||
2460 | /* set TX STOP MODE timer to maximum for this operation */ | 2391 | /* set TX STOP MODE timer to maximum for this operation */ |
2461 | l = dsi_read_reg(dsidev, DSI_TIMING1); | 2392 | l = dsi_read_reg(dsidev, DSI_TIMING1); |
@@ -2466,8 +2397,7 @@ static int dsi_cio_init(struct platform_device *dsidev) | |||
2466 | dsi_write_reg(dsidev, DSI_TIMING1, l); | 2397 | dsi_write_reg(dsidev, DSI_TIMING1, l); |
2467 | 2398 | ||
2468 | if (dsi->ulps_enabled) { | 2399 | if (dsi->ulps_enabled) { |
2469 | unsigned mask_p; | 2400 | u32 lane_mask = DSI_CLK_P | DSI_DATA1_P | DSI_DATA2_P; |
2470 | int i; | ||
2471 | 2401 | ||
2472 | DSSDBG("manual ulps exit\n"); | 2402 | DSSDBG("manual ulps exit\n"); |
2473 | 2403 | ||
@@ -2476,19 +2406,16 @@ static int dsi_cio_init(struct platform_device *dsidev) | |||
2476 | * ULPS exit sequence, as after reset the DSS HW thinks | 2406 | * ULPS exit sequence, as after reset the DSS HW thinks |
2477 | * that we are not in ULPS mode, and refuses to send the | 2407 | * that we are not in ULPS mode, and refuses to send the |
2478 | * sequence. So we need to send the ULPS exit sequence | 2408 | * sequence. So we need to send the ULPS exit sequence |
2479 | * manually by setting positive lines high and negative lines | 2409 | * manually. |
2480 | * low for 1ms. | ||
2481 | */ | 2410 | */ |
2482 | 2411 | ||
2483 | mask_p = 0; | 2412 | if (num_data_lanes_dssdev > 2) |
2413 | lane_mask |= DSI_DATA3_P; | ||
2484 | 2414 | ||
2485 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | 2415 | if (num_data_lanes_dssdev > 3) |
2486 | if (dsi->lanes[i].function == DSI_LANE_UNUSED) | 2416 | lane_mask |= DSI_DATA4_P; |
2487 | continue; | ||
2488 | mask_p |= 1 << i; | ||
2489 | } | ||
2490 | 2417 | ||
2491 | dsi_cio_enable_lane_override(dsidev, mask_p, 0); | 2418 | dsi_cio_enable_lane_override(dssdev, lane_mask); |
2492 | } | 2419 | } |
2493 | 2420 | ||
2494 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); | 2421 | r = dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ON); |
@@ -2505,7 +2432,7 @@ static int dsi_cio_init(struct platform_device *dsidev) | |||
2505 | dsi_if_enable(dsidev, false); | 2432 | dsi_if_enable(dsidev, false); |
2506 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ | 2433 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 1, 20, 20); /* LP_CLK_ENABLE */ |
2507 | 2434 | ||
2508 | r = dsi_cio_wait_tx_clk_esc_reset(dsidev); | 2435 | r = dsi_cio_wait_tx_clk_esc_reset(dssdev); |
2509 | if (r) | 2436 | if (r) |
2510 | goto err_tx_clk_esc_rst; | 2437 | goto err_tx_clk_esc_rst; |
2511 | 2438 | ||
@@ -2525,12 +2452,6 @@ static int dsi_cio_init(struct platform_device *dsidev) | |||
2525 | 2452 | ||
2526 | dsi_cio_timings(dsidev); | 2453 | dsi_cio_timings(dsidev); |
2527 | 2454 | ||
2528 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
2529 | /* DDR_CLK_ALWAYS_ON */ | ||
2530 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, | ||
2531 | dsi->vm_timings.ddr_clk_always_on, 13, 13); | ||
2532 | } | ||
2533 | |||
2534 | dsi->ulps_enabled = false; | 2455 | dsi->ulps_enabled = false; |
2535 | 2456 | ||
2536 | DSSDBG("CIO init done\n"); | 2457 | DSSDBG("CIO init done\n"); |
@@ -2546,7 +2467,8 @@ err_cio_pwr: | |||
2546 | dsi_cio_disable_lane_override(dsidev); | 2467 | dsi_cio_disable_lane_override(dsidev); |
2547 | err_scp_clk_dom: | 2468 | err_scp_clk_dom: |
2548 | dsi_disable_scp_clk(dsidev); | 2469 | dsi_disable_scp_clk(dsidev); |
2549 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); | 2470 | if (dsi->dsi_mux_pads) |
2471 | dsi->dsi_mux_pads(false); | ||
2550 | return r; | 2472 | return r; |
2551 | } | 2473 | } |
2552 | 2474 | ||
@@ -2554,12 +2476,10 @@ static void dsi_cio_uninit(struct platform_device *dsidev) | |||
2554 | { | 2476 | { |
2555 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2477 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2556 | 2478 | ||
2557 | /* DDR_CLK_ALWAYS_ON */ | ||
2558 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); | ||
2559 | |||
2560 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); | 2479 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_OFF); |
2561 | dsi_disable_scp_clk(dsidev); | 2480 | dsi_disable_scp_clk(dsidev); |
2562 | dss_dsi_disable_pads(dsi->module_id, dsi_get_lane_mask(dsidev)); | 2481 | if (dsi->dsi_mux_pads) |
2482 | dsi->dsi_mux_pads(false); | ||
2563 | } | 2483 | } |
2564 | 2484 | ||
2565 | static void dsi_config_tx_fifo(struct platform_device *dsidev, | 2485 | static void dsi_config_tx_fifo(struct platform_device *dsidev, |
@@ -2583,7 +2503,6 @@ static void dsi_config_tx_fifo(struct platform_device *dsidev, | |||
2583 | if (add + size > 4) { | 2503 | if (add + size > 4) { |
2584 | DSSERR("Illegal FIFO configuration\n"); | 2504 | DSSERR("Illegal FIFO configuration\n"); |
2585 | BUG(); | 2505 | BUG(); |
2586 | return; | ||
2587 | } | 2506 | } |
2588 | 2507 | ||
2589 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); | 2508 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); |
@@ -2616,7 +2535,6 @@ static void dsi_config_rx_fifo(struct platform_device *dsidev, | |||
2616 | if (add + size > 4) { | 2535 | if (add + size > 4) { |
2617 | DSSERR("Illegal FIFO configuration\n"); | 2536 | DSSERR("Illegal FIFO configuration\n"); |
2618 | BUG(); | 2537 | BUG(); |
2619 | return; | ||
2620 | } | 2538 | } |
2621 | 2539 | ||
2622 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); | 2540 | v = FLD_VAL(add, 2, 0) | FLD_VAL(size, 7, 4); |
@@ -2751,14 +2669,13 @@ static int dsi_sync_vc(struct platform_device *dsidev, int channel) | |||
2751 | if (!dsi_vc_is_enabled(dsidev, channel)) | 2669 | if (!dsi_vc_is_enabled(dsidev, channel)) |
2752 | return 0; | 2670 | return 0; |
2753 | 2671 | ||
2754 | switch (dsi->vc[channel].source) { | 2672 | switch (dsi->vc[channel].mode) { |
2755 | case DSI_VC_SOURCE_VP: | 2673 | case DSI_VC_MODE_VP: |
2756 | return dsi_sync_vc_vp(dsidev, channel); | 2674 | return dsi_sync_vc_vp(dsidev, channel); |
2757 | case DSI_VC_SOURCE_L4: | 2675 | case DSI_VC_MODE_L4: |
2758 | return dsi_sync_vc_l4(dsidev, channel); | 2676 | return dsi_sync_vc_l4(dsidev, channel); |
2759 | default: | 2677 | default: |
2760 | BUG(); | 2678 | BUG(); |
2761 | return -EINVAL; | ||
2762 | } | 2679 | } |
2763 | } | 2680 | } |
2764 | 2681 | ||
@@ -2785,7 +2702,7 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) | |||
2785 | { | 2702 | { |
2786 | u32 r; | 2703 | u32 r; |
2787 | 2704 | ||
2788 | DSSDBG("Initial config of virtual channel %d", channel); | 2705 | DSSDBGF("%d", channel); |
2789 | 2706 | ||
2790 | r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); | 2707 | r = dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); |
2791 | 2708 | ||
@@ -2809,15 +2726,14 @@ static void dsi_vc_initial_config(struct platform_device *dsidev, int channel) | |||
2809 | dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); | 2726 | dsi_write_reg(dsidev, DSI_VC_CTRL(channel), r); |
2810 | } | 2727 | } |
2811 | 2728 | ||
2812 | static int dsi_vc_config_source(struct platform_device *dsidev, int channel, | 2729 | static int dsi_vc_config_l4(struct platform_device *dsidev, int channel) |
2813 | enum dsi_vc_source source) | ||
2814 | { | 2730 | { |
2815 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 2731 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
2816 | 2732 | ||
2817 | if (dsi->vc[channel].source == source) | 2733 | if (dsi->vc[channel].mode == DSI_VC_MODE_L4) |
2818 | return 0; | 2734 | return 0; |
2819 | 2735 | ||
2820 | DSSDBG("Source config of virtual channel %d", channel); | 2736 | DSSDBGF("%d", channel); |
2821 | 2737 | ||
2822 | dsi_sync_vc(dsidev, channel); | 2738 | dsi_sync_vc(dsidev, channel); |
2823 | 2739 | ||
@@ -2825,31 +2741,61 @@ static int dsi_vc_config_source(struct platform_device *dsidev, int channel, | |||
2825 | 2741 | ||
2826 | /* VC_BUSY */ | 2742 | /* VC_BUSY */ |
2827 | if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) { | 2743 | if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) { |
2828 | DSSERR("vc(%d) busy when trying to config for VP\n", channel); | 2744 | DSSERR("vc(%d) busy when trying to config for L4\n", channel); |
2829 | return -EIO; | 2745 | return -EIO; |
2830 | } | 2746 | } |
2831 | 2747 | ||
2832 | /* SOURCE, 0 = L4, 1 = video port */ | 2748 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 1, 1); /* SOURCE, 0 = L4 */ |
2833 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), source, 1, 1); | ||
2834 | 2749 | ||
2835 | /* DCS_CMD_ENABLE */ | 2750 | /* DCS_CMD_ENABLE */ |
2836 | if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { | 2751 | if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) |
2837 | bool enable = source == DSI_VC_SOURCE_VP; | 2752 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 30, 30); |
2838 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), enable, 30, 30); | 2753 | |
2754 | dsi_vc_enable(dsidev, channel, 1); | ||
2755 | |||
2756 | dsi->vc[channel].mode = DSI_VC_MODE_L4; | ||
2757 | |||
2758 | return 0; | ||
2759 | } | ||
2760 | |||
2761 | static int dsi_vc_config_vp(struct platform_device *dsidev, int channel) | ||
2762 | { | ||
2763 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2764 | |||
2765 | if (dsi->vc[channel].mode == DSI_VC_MODE_VP) | ||
2766 | return 0; | ||
2767 | |||
2768 | DSSDBGF("%d", channel); | ||
2769 | |||
2770 | dsi_sync_vc(dsidev, channel); | ||
2771 | |||
2772 | dsi_vc_enable(dsidev, channel, 0); | ||
2773 | |||
2774 | /* VC_BUSY */ | ||
2775 | if (wait_for_bit_change(dsidev, DSI_VC_CTRL(channel), 15, 0) != 0) { | ||
2776 | DSSERR("vc(%d) busy when trying to config for VP\n", channel); | ||
2777 | return -EIO; | ||
2839 | } | 2778 | } |
2840 | 2779 | ||
2780 | /* SOURCE, 1 = video port */ | ||
2781 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 1, 1); | ||
2782 | |||
2783 | /* DCS_CMD_ENABLE */ | ||
2784 | if (dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) | ||
2785 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 30, 30); | ||
2786 | |||
2841 | dsi_vc_enable(dsidev, channel, 1); | 2787 | dsi_vc_enable(dsidev, channel, 1); |
2842 | 2788 | ||
2843 | dsi->vc[channel].source = source; | 2789 | dsi->vc[channel].mode = DSI_VC_MODE_VP; |
2844 | 2790 | ||
2845 | return 0; | 2791 | return 0; |
2846 | } | 2792 | } |
2847 | 2793 | ||
2794 | |||
2848 | void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, | 2795 | void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, |
2849 | bool enable) | 2796 | bool enable) |
2850 | { | 2797 | { |
2851 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2798 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
2852 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2853 | 2799 | ||
2854 | DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); | 2800 | DSSDBG("dsi_vc_enable_hs(%d, %d)\n", channel, enable); |
2855 | 2801 | ||
@@ -2864,10 +2810,6 @@ void omapdss_dsi_vc_enable_hs(struct omap_dss_device *dssdev, int channel, | |||
2864 | dsi_if_enable(dsidev, 1); | 2810 | dsi_if_enable(dsidev, 1); |
2865 | 2811 | ||
2866 | dsi_force_tx_stop_mode_io(dsidev); | 2812 | dsi_force_tx_stop_mode_io(dsidev); |
2867 | |||
2868 | /* start the DDR clock by sending a NULL packet */ | ||
2869 | if (dsi->vm_timings.ddr_clk_always_on && enable) | ||
2870 | dsi_vc_send_null(dssdev, channel); | ||
2871 | } | 2813 | } |
2872 | EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); | 2814 | EXPORT_SYMBOL(omapdss_dsi_vc_enable_hs); |
2873 | 2815 | ||
@@ -2931,16 +2873,16 @@ static u16 dsi_vc_flush_receive_data(struct platform_device *dsidev, | |||
2931 | val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); | 2873 | val = dsi_read_reg(dsidev, DSI_VC_SHORT_PACKET_HEADER(channel)); |
2932 | DSSERR("\trawval %#08x\n", val); | 2874 | DSSERR("\trawval %#08x\n", val); |
2933 | dt = FLD_GET(val, 5, 0); | 2875 | dt = FLD_GET(val, 5, 0); |
2934 | if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) { | 2876 | if (dt == DSI_DT_RX_ACK_WITH_ERR) { |
2935 | u16 err = FLD_GET(val, 23, 8); | 2877 | u16 err = FLD_GET(val, 23, 8); |
2936 | dsi_show_rx_ack_with_err(err); | 2878 | dsi_show_rx_ack_with_err(err); |
2937 | } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE) { | 2879 | } else if (dt == DSI_DT_RX_SHORT_READ_1) { |
2938 | DSSERR("\tDCS short response, 1 byte: %#x\n", | 2880 | DSSERR("\tDCS short response, 1 byte: %#x\n", |
2939 | FLD_GET(val, 23, 8)); | 2881 | FLD_GET(val, 23, 8)); |
2940 | } else if (dt == MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE) { | 2882 | } else if (dt == DSI_DT_RX_SHORT_READ_2) { |
2941 | DSSERR("\tDCS short response, 2 byte: %#x\n", | 2883 | DSSERR("\tDCS short response, 2 byte: %#x\n", |
2942 | FLD_GET(val, 23, 8)); | 2884 | FLD_GET(val, 23, 8)); |
2943 | } else if (dt == MIPI_DSI_RX_DCS_LONG_READ_RESPONSE) { | 2885 | } else if (dt == DSI_DT_RX_DCS_LONG_READ) { |
2944 | DSSERR("\tDCS long response, len %d\n", | 2886 | DSSERR("\tDCS long response, len %d\n", |
2945 | FLD_GET(val, 23, 8)); | 2887 | FLD_GET(val, 23, 8)); |
2946 | dsi_vc_flush_long_data(dsidev, channel); | 2888 | dsi_vc_flush_long_data(dsidev, channel); |
@@ -2968,9 +2910,6 @@ static int dsi_vc_send_bta(struct platform_device *dsidev, int channel) | |||
2968 | 2910 | ||
2969 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ | 2911 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 6, 6); /* BTA_EN */ |
2970 | 2912 | ||
2971 | /* flush posted write */ | ||
2972 | dsi_read_reg(dsidev, DSI_VC_CTRL(channel)); | ||
2973 | |||
2974 | return 0; | 2913 | return 0; |
2975 | } | 2914 | } |
2976 | 2915 | ||
@@ -3068,7 +3007,7 @@ static int dsi_vc_send_long(struct platform_device *dsidev, int channel, | |||
3068 | return -EINVAL; | 3007 | return -EINVAL; |
3069 | } | 3008 | } |
3070 | 3009 | ||
3071 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); | 3010 | dsi_vc_config_l4(dsidev, channel); |
3072 | 3011 | ||
3073 | dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc); | 3012 | dsi_vc_write_long_header(dsidev, channel, data_type, len, ecc); |
3074 | 3013 | ||
@@ -3127,7 +3066,7 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel, | |||
3127 | channel, | 3066 | channel, |
3128 | data_type, data & 0xff, (data >> 8) & 0xff); | 3067 | data_type, data & 0xff, (data >> 8) & 0xff); |
3129 | 3068 | ||
3130 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_L4); | 3069 | dsi_vc_config_l4(dsidev, channel); |
3131 | 3070 | ||
3132 | if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) { | 3071 | if (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(channel)), 16, 16)) { |
3133 | DSSERR("ERROR FIFO FULL, aborting transfer\n"); | 3072 | DSSERR("ERROR FIFO FULL, aborting transfer\n"); |
@@ -3146,69 +3085,44 @@ static int dsi_vc_send_short(struct platform_device *dsidev, int channel, | |||
3146 | int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) | 3085 | int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel) |
3147 | { | 3086 | { |
3148 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3087 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3088 | u8 nullpkg[] = {0, 0, 0, 0}; | ||
3149 | 3089 | ||
3150 | return dsi_vc_send_long(dsidev, channel, MIPI_DSI_NULL_PACKET, NULL, | 3090 | return dsi_vc_send_long(dsidev, channel, DSI_DT_NULL_PACKET, nullpkg, |
3151 | 0, 0); | 3091 | 4, 0); |
3152 | } | 3092 | } |
3153 | EXPORT_SYMBOL(dsi_vc_send_null); | 3093 | EXPORT_SYMBOL(dsi_vc_send_null); |
3154 | 3094 | ||
3155 | static int dsi_vc_write_nosync_common(struct platform_device *dsidev, | 3095 | int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, |
3156 | int channel, u8 *data, int len, enum dss_dsi_content_type type) | 3096 | u8 *data, int len) |
3157 | { | 3097 | { |
3098 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3158 | int r; | 3099 | int r; |
3159 | 3100 | ||
3160 | if (len == 0) { | 3101 | BUG_ON(len == 0); |
3161 | BUG_ON(type == DSS_DSI_CONTENT_DCS); | 3102 | |
3162 | r = dsi_vc_send_short(dsidev, channel, | 3103 | if (len == 1) { |
3163 | MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM, 0, 0); | 3104 | r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_0, |
3164 | } else if (len == 1) { | 3105 | data[0], 0); |
3165 | r = dsi_vc_send_short(dsidev, channel, | ||
3166 | type == DSS_DSI_CONTENT_GENERIC ? | ||
3167 | MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM : | ||
3168 | MIPI_DSI_DCS_SHORT_WRITE, data[0], 0); | ||
3169 | } else if (len == 2) { | 3106 | } else if (len == 2) { |
3170 | r = dsi_vc_send_short(dsidev, channel, | 3107 | r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_SHORT_WRITE_1, |
3171 | type == DSS_DSI_CONTENT_GENERIC ? | ||
3172 | MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM : | ||
3173 | MIPI_DSI_DCS_SHORT_WRITE_PARAM, | ||
3174 | data[0] | (data[1] << 8), 0); | 3108 | data[0] | (data[1] << 8), 0); |
3175 | } else { | 3109 | } else { |
3176 | r = dsi_vc_send_long(dsidev, channel, | 3110 | /* 0x39 = DCS Long Write */ |
3177 | type == DSS_DSI_CONTENT_GENERIC ? | 3111 | r = dsi_vc_send_long(dsidev, channel, DSI_DT_DCS_LONG_WRITE, |
3178 | MIPI_DSI_GENERIC_LONG_WRITE : | 3112 | data, len, 0); |
3179 | MIPI_DSI_DCS_LONG_WRITE, data, len, 0); | ||
3180 | } | 3113 | } |
3181 | 3114 | ||
3182 | return r; | 3115 | return r; |
3183 | } | 3116 | } |
3184 | |||
3185 | int dsi_vc_dcs_write_nosync(struct omap_dss_device *dssdev, int channel, | ||
3186 | u8 *data, int len) | ||
3187 | { | ||
3188 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3189 | |||
3190 | return dsi_vc_write_nosync_common(dsidev, channel, data, len, | ||
3191 | DSS_DSI_CONTENT_DCS); | ||
3192 | } | ||
3193 | EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); | 3117 | EXPORT_SYMBOL(dsi_vc_dcs_write_nosync); |
3194 | 3118 | ||
3195 | int dsi_vc_generic_write_nosync(struct omap_dss_device *dssdev, int channel, | 3119 | int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data, |
3196 | u8 *data, int len) | 3120 | int len) |
3197 | { | ||
3198 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3199 | |||
3200 | return dsi_vc_write_nosync_common(dsidev, channel, data, len, | ||
3201 | DSS_DSI_CONTENT_GENERIC); | ||
3202 | } | ||
3203 | EXPORT_SYMBOL(dsi_vc_generic_write_nosync); | ||
3204 | |||
3205 | static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, | ||
3206 | u8 *data, int len, enum dss_dsi_content_type type) | ||
3207 | { | 3121 | { |
3208 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3122 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3209 | int r; | 3123 | int r; |
3210 | 3124 | ||
3211 | r = dsi_vc_write_nosync_common(dsidev, channel, data, len, type); | 3125 | r = dsi_vc_dcs_write_nosync(dssdev, channel, data, len); |
3212 | if (r) | 3126 | if (r) |
3213 | goto err; | 3127 | goto err; |
3214 | 3128 | ||
@@ -3226,39 +3140,18 @@ static int dsi_vc_write_common(struct omap_dss_device *dssdev, int channel, | |||
3226 | 3140 | ||
3227 | return 0; | 3141 | return 0; |
3228 | err: | 3142 | err: |
3229 | DSSERR("dsi_vc_write_common(ch %d, cmd 0x%02x, len %d) failed\n", | 3143 | DSSERR("dsi_vc_dcs_write(ch %d, cmd 0x%02x, len %d) failed\n", |
3230 | channel, data[0], len); | 3144 | channel, data[0], len); |
3231 | return r; | 3145 | return r; |
3232 | } | 3146 | } |
3233 | |||
3234 | int dsi_vc_dcs_write(struct omap_dss_device *dssdev, int channel, u8 *data, | ||
3235 | int len) | ||
3236 | { | ||
3237 | return dsi_vc_write_common(dssdev, channel, data, len, | ||
3238 | DSS_DSI_CONTENT_DCS); | ||
3239 | } | ||
3240 | EXPORT_SYMBOL(dsi_vc_dcs_write); | 3147 | EXPORT_SYMBOL(dsi_vc_dcs_write); |
3241 | 3148 | ||
3242 | int dsi_vc_generic_write(struct omap_dss_device *dssdev, int channel, u8 *data, | ||
3243 | int len) | ||
3244 | { | ||
3245 | return dsi_vc_write_common(dssdev, channel, data, len, | ||
3246 | DSS_DSI_CONTENT_GENERIC); | ||
3247 | } | ||
3248 | EXPORT_SYMBOL(dsi_vc_generic_write); | ||
3249 | |||
3250 | int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd) | 3149 | int dsi_vc_dcs_write_0(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd) |
3251 | { | 3150 | { |
3252 | return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1); | 3151 | return dsi_vc_dcs_write(dssdev, channel, &dcs_cmd, 1); |
3253 | } | 3152 | } |
3254 | EXPORT_SYMBOL(dsi_vc_dcs_write_0); | 3153 | EXPORT_SYMBOL(dsi_vc_dcs_write_0); |
3255 | 3154 | ||
3256 | int dsi_vc_generic_write_0(struct omap_dss_device *dssdev, int channel) | ||
3257 | { | ||
3258 | return dsi_vc_generic_write(dssdev, channel, NULL, 0); | ||
3259 | } | ||
3260 | EXPORT_SYMBOL(dsi_vc_generic_write_0); | ||
3261 | |||
3262 | int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, | 3155 | int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, |
3263 | u8 param) | 3156 | u8 param) |
3264 | { | 3157 | { |
@@ -3269,86 +3162,25 @@ int dsi_vc_dcs_write_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, | |||
3269 | } | 3162 | } |
3270 | EXPORT_SYMBOL(dsi_vc_dcs_write_1); | 3163 | EXPORT_SYMBOL(dsi_vc_dcs_write_1); |
3271 | 3164 | ||
3272 | int dsi_vc_generic_write_1(struct omap_dss_device *dssdev, int channel, | 3165 | int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, |
3273 | u8 param) | 3166 | u8 *buf, int buflen) |
3274 | { | ||
3275 | return dsi_vc_generic_write(dssdev, channel, ¶m, 1); | ||
3276 | } | ||
3277 | EXPORT_SYMBOL(dsi_vc_generic_write_1); | ||
3278 | |||
3279 | int dsi_vc_generic_write_2(struct omap_dss_device *dssdev, int channel, | ||
3280 | u8 param1, u8 param2) | ||
3281 | { | ||
3282 | u8 buf[2]; | ||
3283 | buf[0] = param1; | ||
3284 | buf[1] = param2; | ||
3285 | return dsi_vc_generic_write(dssdev, channel, buf, 2); | ||
3286 | } | ||
3287 | EXPORT_SYMBOL(dsi_vc_generic_write_2); | ||
3288 | |||
3289 | static int dsi_vc_dcs_send_read_request(struct platform_device *dsidev, | ||
3290 | int channel, u8 dcs_cmd) | ||
3291 | { | 3167 | { |
3168 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3292 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3169 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3170 | u32 val; | ||
3171 | u8 dt; | ||
3293 | int r; | 3172 | int r; |
3294 | 3173 | ||
3295 | if (dsi->debug_read) | 3174 | if (dsi->debug_read) |
3296 | DSSDBG("dsi_vc_dcs_send_read_request(ch%d, dcs_cmd %x)\n", | 3175 | DSSDBG("dsi_vc_dcs_read(ch%d, dcs_cmd %x)\n", channel, dcs_cmd); |
3297 | channel, dcs_cmd); | ||
3298 | |||
3299 | r = dsi_vc_send_short(dsidev, channel, MIPI_DSI_DCS_READ, dcs_cmd, 0); | ||
3300 | if (r) { | ||
3301 | DSSERR("dsi_vc_dcs_send_read_request(ch %d, cmd 0x%02x)" | ||
3302 | " failed\n", channel, dcs_cmd); | ||
3303 | return r; | ||
3304 | } | ||
3305 | |||
3306 | return 0; | ||
3307 | } | ||
3308 | 3176 | ||
3309 | static int dsi_vc_generic_send_read_request(struct platform_device *dsidev, | 3177 | r = dsi_vc_send_short(dsidev, channel, DSI_DT_DCS_READ, dcs_cmd, 0); |
3310 | int channel, u8 *reqdata, int reqlen) | 3178 | if (r) |
3311 | { | 3179 | goto err; |
3312 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3313 | u16 data; | ||
3314 | u8 data_type; | ||
3315 | int r; | ||
3316 | |||
3317 | if (dsi->debug_read) | ||
3318 | DSSDBG("dsi_vc_generic_send_read_request(ch %d, reqlen %d)\n", | ||
3319 | channel, reqlen); | ||
3320 | |||
3321 | if (reqlen == 0) { | ||
3322 | data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM; | ||
3323 | data = 0; | ||
3324 | } else if (reqlen == 1) { | ||
3325 | data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM; | ||
3326 | data = reqdata[0]; | ||
3327 | } else if (reqlen == 2) { | ||
3328 | data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM; | ||
3329 | data = reqdata[0] | (reqdata[1] << 8); | ||
3330 | } else { | ||
3331 | BUG(); | ||
3332 | return -EINVAL; | ||
3333 | } | ||
3334 | |||
3335 | r = dsi_vc_send_short(dsidev, channel, data_type, data, 0); | ||
3336 | if (r) { | ||
3337 | DSSERR("dsi_vc_generic_send_read_request(ch %d, reqlen %d)" | ||
3338 | " failed\n", channel, reqlen); | ||
3339 | return r; | ||
3340 | } | ||
3341 | |||
3342 | return 0; | ||
3343 | } | ||
3344 | 3180 | ||
3345 | static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, | 3181 | r = dsi_vc_send_bta_sync(dssdev, channel); |
3346 | u8 *buf, int buflen, enum dss_dsi_content_type type) | 3182 | if (r) |
3347 | { | 3183 | goto err; |
3348 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3349 | u32 val; | ||
3350 | u8 dt; | ||
3351 | int r; | ||
3352 | 3184 | ||
3353 | /* RX_FIFO_NOT_EMPTY */ | 3185 | /* RX_FIFO_NOT_EMPTY */ |
3354 | if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) { | 3186 | if (REG_GET(dsidev, DSI_VC_CTRL(channel), 20, 20) == 0) { |
@@ -3361,20 +3193,16 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, | |||
3361 | if (dsi->debug_read) | 3193 | if (dsi->debug_read) |
3362 | DSSDBG("\theader: %08x\n", val); | 3194 | DSSDBG("\theader: %08x\n", val); |
3363 | dt = FLD_GET(val, 5, 0); | 3195 | dt = FLD_GET(val, 5, 0); |
3364 | if (dt == MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT) { | 3196 | if (dt == DSI_DT_RX_ACK_WITH_ERR) { |
3365 | u16 err = FLD_GET(val, 23, 8); | 3197 | u16 err = FLD_GET(val, 23, 8); |
3366 | dsi_show_rx_ack_with_err(err); | 3198 | dsi_show_rx_ack_with_err(err); |
3367 | r = -EIO; | 3199 | r = -EIO; |
3368 | goto err; | 3200 | goto err; |
3369 | 3201 | ||
3370 | } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ? | 3202 | } else if (dt == DSI_DT_RX_SHORT_READ_1) { |
3371 | MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE : | ||
3372 | MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE)) { | ||
3373 | u8 data = FLD_GET(val, 15, 8); | 3203 | u8 data = FLD_GET(val, 15, 8); |
3374 | if (dsi->debug_read) | 3204 | if (dsi->debug_read) |
3375 | DSSDBG("\t%s short response, 1 byte: %02x\n", | 3205 | DSSDBG("\tDCS short response, 1 byte: %02x\n", data); |
3376 | type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : | ||
3377 | "DCS", data); | ||
3378 | 3206 | ||
3379 | if (buflen < 1) { | 3207 | if (buflen < 1) { |
3380 | r = -EIO; | 3208 | r = -EIO; |
@@ -3384,14 +3212,10 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, | |||
3384 | buf[0] = data; | 3212 | buf[0] = data; |
3385 | 3213 | ||
3386 | return 1; | 3214 | return 1; |
3387 | } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ? | 3215 | } else if (dt == DSI_DT_RX_SHORT_READ_2) { |
3388 | MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE : | ||
3389 | MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE)) { | ||
3390 | u16 data = FLD_GET(val, 23, 8); | 3216 | u16 data = FLD_GET(val, 23, 8); |
3391 | if (dsi->debug_read) | 3217 | if (dsi->debug_read) |
3392 | DSSDBG("\t%s short response, 2 byte: %04x\n", | 3218 | DSSDBG("\tDCS short response, 2 byte: %04x\n", data); |
3393 | type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : | ||
3394 | "DCS", data); | ||
3395 | 3219 | ||
3396 | if (buflen < 2) { | 3220 | if (buflen < 2) { |
3397 | r = -EIO; | 3221 | r = -EIO; |
@@ -3402,15 +3226,11 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, | |||
3402 | buf[1] = (data >> 8) & 0xff; | 3226 | buf[1] = (data >> 8) & 0xff; |
3403 | 3227 | ||
3404 | return 2; | 3228 | return 2; |
3405 | } else if (dt == (type == DSS_DSI_CONTENT_GENERIC ? | 3229 | } else if (dt == DSI_DT_RX_DCS_LONG_READ) { |
3406 | MIPI_DSI_RX_GENERIC_LONG_READ_RESPONSE : | ||
3407 | MIPI_DSI_RX_DCS_LONG_READ_RESPONSE)) { | ||
3408 | int w; | 3230 | int w; |
3409 | int len = FLD_GET(val, 23, 8); | 3231 | int len = FLD_GET(val, 23, 8); |
3410 | if (dsi->debug_read) | 3232 | if (dsi->debug_read) |
3411 | DSSDBG("\t%s long response, len %d\n", | 3233 | DSSDBG("\tDCS long response, len %d\n", len); |
3412 | type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : | ||
3413 | "DCS", len); | ||
3414 | 3234 | ||
3415 | if (len > buflen) { | 3235 | if (len > buflen) { |
3416 | r = -EIO; | 3236 | r = -EIO; |
@@ -3444,127 +3264,60 @@ static int dsi_vc_read_rx_fifo(struct platform_device *dsidev, int channel, | |||
3444 | goto err; | 3264 | goto err; |
3445 | } | 3265 | } |
3446 | 3266 | ||
3267 | BUG(); | ||
3447 | err: | 3268 | err: |
3448 | DSSERR("dsi_vc_read_rx_fifo(ch %d type %s) failed\n", channel, | 3269 | DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", |
3449 | type == DSS_DSI_CONTENT_GENERIC ? "GENERIC" : "DCS"); | 3270 | channel, dcs_cmd); |
3450 | |||
3451 | return r; | 3271 | return r; |
3452 | } | ||
3453 | 3272 | ||
3454 | int dsi_vc_dcs_read(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, | ||
3455 | u8 *buf, int buflen) | ||
3456 | { | ||
3457 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3458 | int r; | ||
3459 | |||
3460 | r = dsi_vc_dcs_send_read_request(dsidev, channel, dcs_cmd); | ||
3461 | if (r) | ||
3462 | goto err; | ||
3463 | |||
3464 | r = dsi_vc_send_bta_sync(dssdev, channel); | ||
3465 | if (r) | ||
3466 | goto err; | ||
3467 | |||
3468 | r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, | ||
3469 | DSS_DSI_CONTENT_DCS); | ||
3470 | if (r < 0) | ||
3471 | goto err; | ||
3472 | |||
3473 | if (r != buflen) { | ||
3474 | r = -EIO; | ||
3475 | goto err; | ||
3476 | } | ||
3477 | |||
3478 | return 0; | ||
3479 | err: | ||
3480 | DSSERR("dsi_vc_dcs_read(ch %d, cmd 0x%02x) failed\n", channel, dcs_cmd); | ||
3481 | return r; | ||
3482 | } | 3273 | } |
3483 | EXPORT_SYMBOL(dsi_vc_dcs_read); | 3274 | EXPORT_SYMBOL(dsi_vc_dcs_read); |
3484 | 3275 | ||
3485 | static int dsi_vc_generic_read(struct omap_dss_device *dssdev, int channel, | 3276 | int dsi_vc_dcs_read_1(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, |
3486 | u8 *reqdata, int reqlen, u8 *buf, int buflen) | 3277 | u8 *data) |
3487 | { | 3278 | { |
3488 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3489 | int r; | 3279 | int r; |
3490 | 3280 | ||
3491 | r = dsi_vc_generic_send_read_request(dsidev, channel, reqdata, reqlen); | 3281 | r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, data, 1); |
3492 | if (r) | ||
3493 | return r; | ||
3494 | 3282 | ||
3495 | r = dsi_vc_send_bta_sync(dssdev, channel); | ||
3496 | if (r) | ||
3497 | return r; | ||
3498 | |||
3499 | r = dsi_vc_read_rx_fifo(dsidev, channel, buf, buflen, | ||
3500 | DSS_DSI_CONTENT_GENERIC); | ||
3501 | if (r < 0) | 3283 | if (r < 0) |
3502 | return r; | 3284 | return r; |
3503 | 3285 | ||
3504 | if (r != buflen) { | 3286 | if (r != 1) |
3505 | r = -EIO; | 3287 | return -EIO; |
3506 | return r; | ||
3507 | } | ||
3508 | 3288 | ||
3509 | return 0; | 3289 | return 0; |
3510 | } | 3290 | } |
3291 | EXPORT_SYMBOL(dsi_vc_dcs_read_1); | ||
3511 | 3292 | ||
3512 | int dsi_vc_generic_read_0(struct omap_dss_device *dssdev, int channel, u8 *buf, | 3293 | int dsi_vc_dcs_read_2(struct omap_dss_device *dssdev, int channel, u8 dcs_cmd, |
3513 | int buflen) | 3294 | u8 *data1, u8 *data2) |
3514 | { | 3295 | { |
3296 | u8 buf[2]; | ||
3515 | int r; | 3297 | int r; |
3516 | 3298 | ||
3517 | r = dsi_vc_generic_read(dssdev, channel, NULL, 0, buf, buflen); | 3299 | r = dsi_vc_dcs_read(dssdev, channel, dcs_cmd, buf, 2); |
3518 | if (r) { | ||
3519 | DSSERR("dsi_vc_generic_read_0(ch %d) failed\n", channel); | ||
3520 | return r; | ||
3521 | } | ||
3522 | |||
3523 | return 0; | ||
3524 | } | ||
3525 | EXPORT_SYMBOL(dsi_vc_generic_read_0); | ||
3526 | 3300 | ||
3527 | int dsi_vc_generic_read_1(struct omap_dss_device *dssdev, int channel, u8 param, | 3301 | if (r < 0) |
3528 | u8 *buf, int buflen) | ||
3529 | { | ||
3530 | int r; | ||
3531 | |||
3532 | r = dsi_vc_generic_read(dssdev, channel, ¶m, 1, buf, buflen); | ||
3533 | if (r) { | ||
3534 | DSSERR("dsi_vc_generic_read_1(ch %d) failed\n", channel); | ||
3535 | return r; | 3302 | return r; |
3536 | } | ||
3537 | |||
3538 | return 0; | ||
3539 | } | ||
3540 | EXPORT_SYMBOL(dsi_vc_generic_read_1); | ||
3541 | |||
3542 | int dsi_vc_generic_read_2(struct omap_dss_device *dssdev, int channel, | ||
3543 | u8 param1, u8 param2, u8 *buf, int buflen) | ||
3544 | { | ||
3545 | int r; | ||
3546 | u8 reqdata[2]; | ||
3547 | 3303 | ||
3548 | reqdata[0] = param1; | 3304 | if (r != 2) |
3549 | reqdata[1] = param2; | 3305 | return -EIO; |
3550 | 3306 | ||
3551 | r = dsi_vc_generic_read(dssdev, channel, reqdata, 2, buf, buflen); | 3307 | *data1 = buf[0]; |
3552 | if (r) { | 3308 | *data2 = buf[1]; |
3553 | DSSERR("dsi_vc_generic_read_2(ch %d) failed\n", channel); | ||
3554 | return r; | ||
3555 | } | ||
3556 | 3309 | ||
3557 | return 0; | 3310 | return 0; |
3558 | } | 3311 | } |
3559 | EXPORT_SYMBOL(dsi_vc_generic_read_2); | 3312 | EXPORT_SYMBOL(dsi_vc_dcs_read_2); |
3560 | 3313 | ||
3561 | int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, | 3314 | int dsi_vc_set_max_rx_packet_size(struct omap_dss_device *dssdev, int channel, |
3562 | u16 len) | 3315 | u16 len) |
3563 | { | 3316 | { |
3564 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3317 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
3565 | 3318 | ||
3566 | return dsi_vc_send_short(dsidev, channel, | 3319 | return dsi_vc_send_short(dsidev, channel, DSI_DT_SET_MAX_RET_PKG_SIZE, |
3567 | MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE, len, 0); | 3320 | len, 0); |
3568 | } | 3321 | } |
3569 | EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); | 3322 | EXPORT_SYMBOL(dsi_vc_set_max_rx_packet_size); |
3570 | 3323 | ||
@@ -3572,10 +3325,9 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3572 | { | 3325 | { |
3573 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3326 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
3574 | DECLARE_COMPLETION_ONSTACK(completion); | 3327 | DECLARE_COMPLETION_ONSTACK(completion); |
3575 | int r, i; | 3328 | int r; |
3576 | unsigned mask; | ||
3577 | 3329 | ||
3578 | DSSDBG("Entering ULPS"); | 3330 | DSSDBGF(); |
3579 | 3331 | ||
3580 | WARN_ON(!dsi_bus_is_locked(dsidev)); | 3332 | WARN_ON(!dsi_bus_is_locked(dsidev)); |
3581 | 3333 | ||
@@ -3584,11 +3336,9 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3584 | if (dsi->ulps_enabled) | 3336 | if (dsi->ulps_enabled) |
3585 | return 0; | 3337 | return 0; |
3586 | 3338 | ||
3587 | /* DDR_CLK_ALWAYS_ON */ | ||
3588 | if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { | 3339 | if (REG_GET(dsidev, DSI_CLK_CTRL, 13, 13)) { |
3589 | dsi_if_enable(dsidev, 0); | 3340 | DSSERR("DDR_CLK_ALWAYS_ON enabled when entering ULPS\n"); |
3590 | REG_FLD_MOD(dsidev, DSI_CLK_CTRL, 0, 13, 13); | 3341 | return -EIO; |
3591 | dsi_if_enable(dsidev, 1); | ||
3592 | } | 3342 | } |
3593 | 3343 | ||
3594 | dsi_sync_vc(dsidev, 0); | 3344 | dsi_sync_vc(dsidev, 0); |
@@ -3618,19 +3368,10 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3618 | if (r) | 3368 | if (r) |
3619 | return r; | 3369 | return r; |
3620 | 3370 | ||
3621 | mask = 0; | ||
3622 | |||
3623 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | ||
3624 | if (dsi->lanes[i].function == DSI_LANE_UNUSED) | ||
3625 | continue; | ||
3626 | mask |= 1 << i; | ||
3627 | } | ||
3628 | /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ | 3371 | /* Assert TxRequestEsc for data lanes and TxUlpsClk for clk lane */ |
3629 | /* LANEx_ULPS_SIG2 */ | 3372 | /* LANEx_ULPS_SIG2 */ |
3630 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, mask, 9, 5); | 3373 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (1 << 0) | (1 << 1) | (1 << 2), |
3631 | 3374 | 7, 5); | |
3632 | /* flush posted write and wait for SCP interface to finish the write */ | ||
3633 | dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); | ||
3634 | 3375 | ||
3635 | if (wait_for_completion_timeout(&completion, | 3376 | if (wait_for_completion_timeout(&completion, |
3636 | msecs_to_jiffies(1000)) == 0) { | 3377 | msecs_to_jiffies(1000)) == 0) { |
@@ -3643,10 +3384,8 @@ static int dsi_enter_ulps(struct platform_device *dsidev) | |||
3643 | DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); | 3384 | DSI_CIO_IRQ_ULPSACTIVENOT_ALL0); |
3644 | 3385 | ||
3645 | /* Reset LANEx_ULPS_SIG2 */ | 3386 | /* Reset LANEx_ULPS_SIG2 */ |
3646 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, 0, 9, 5); | 3387 | REG_FLD_MOD(dsidev, DSI_COMPLEXIO_CFG2, (0 << 0) | (0 << 1) | (0 << 2), |
3647 | 3388 | 7, 5); | |
3648 | /* flush posted write and wait for SCP interface to finish the write */ | ||
3649 | dsi_read_reg(dsidev, DSI_COMPLEXIO_CFG2); | ||
3650 | 3389 | ||
3651 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); | 3390 | dsi_cio_power(dsidev, DSI_COMPLEXIO_POWER_ULPS); |
3652 | 3391 | ||
@@ -3769,256 +3508,9 @@ static void dsi_set_hs_tx_timeout(struct platform_device *dsidev, | |||
3769 | ticks, x4 ? " x4" : "", x16 ? " x16" : "", | 3508 | ticks, x4 ? " x4" : "", x16 ? " x16" : "", |
3770 | (total_ticks * 1000) / (fck / 1000 / 1000)); | 3509 | (total_ticks * 1000) / (fck / 1000 / 1000)); |
3771 | } | 3510 | } |
3772 | |||
3773 | static void dsi_config_vp_num_line_buffers(struct platform_device *dsidev) | ||
3774 | { | ||
3775 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3776 | int num_line_buffers; | ||
3777 | |||
3778 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
3779 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | ||
3780 | unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | ||
3781 | struct omap_video_timings *timings = &dsi->timings; | ||
3782 | /* | ||
3783 | * Don't use line buffers if width is greater than the video | ||
3784 | * port's line buffer size | ||
3785 | */ | ||
3786 | if (line_buf_size <= timings->x_res * bpp / 8) | ||
3787 | num_line_buffers = 0; | ||
3788 | else | ||
3789 | num_line_buffers = 2; | ||
3790 | } else { | ||
3791 | /* Use maximum number of line buffers in command mode */ | ||
3792 | num_line_buffers = 2; | ||
3793 | } | ||
3794 | |||
3795 | /* LINE_BUFFER */ | ||
3796 | REG_FLD_MOD(dsidev, DSI_CTRL, num_line_buffers, 13, 12); | ||
3797 | } | ||
3798 | |||
3799 | static void dsi_config_vp_sync_events(struct platform_device *dsidev) | ||
3800 | { | ||
3801 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3802 | bool vsync_end = dsi->vm_timings.vp_vsync_end; | ||
3803 | bool hsync_end = dsi->vm_timings.vp_hsync_end; | ||
3804 | u32 r; | ||
3805 | |||
3806 | r = dsi_read_reg(dsidev, DSI_CTRL); | ||
3807 | r = FLD_MOD(r, 1, 9, 9); /* VP_DE_POL */ | ||
3808 | r = FLD_MOD(r, 1, 10, 10); /* VP_HSYNC_POL */ | ||
3809 | r = FLD_MOD(r, 1, 11, 11); /* VP_VSYNC_POL */ | ||
3810 | r = FLD_MOD(r, 1, 15, 15); /* VP_VSYNC_START */ | ||
3811 | r = FLD_MOD(r, vsync_end, 16, 16); /* VP_VSYNC_END */ | ||
3812 | r = FLD_MOD(r, 1, 17, 17); /* VP_HSYNC_START */ | ||
3813 | r = FLD_MOD(r, hsync_end, 18, 18); /* VP_HSYNC_END */ | ||
3814 | dsi_write_reg(dsidev, DSI_CTRL, r); | ||
3815 | } | ||
3816 | |||
3817 | static void dsi_config_blanking_modes(struct platform_device *dsidev) | ||
3818 | { | ||
3819 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3820 | int blanking_mode = dsi->vm_timings.blanking_mode; | ||
3821 | int hfp_blanking_mode = dsi->vm_timings.hfp_blanking_mode; | ||
3822 | int hbp_blanking_mode = dsi->vm_timings.hbp_blanking_mode; | ||
3823 | int hsa_blanking_mode = dsi->vm_timings.hsa_blanking_mode; | ||
3824 | u32 r; | ||
3825 | |||
3826 | /* | ||
3827 | * 0 = TX FIFO packets sent or LPS in corresponding blanking periods | ||
3828 | * 1 = Long blanking packets are sent in corresponding blanking periods | ||
3829 | */ | ||
3830 | r = dsi_read_reg(dsidev, DSI_CTRL); | ||
3831 | r = FLD_MOD(r, blanking_mode, 20, 20); /* BLANKING_MODE */ | ||
3832 | r = FLD_MOD(r, hfp_blanking_mode, 21, 21); /* HFP_BLANKING */ | ||
3833 | r = FLD_MOD(r, hbp_blanking_mode, 22, 22); /* HBP_BLANKING */ | ||
3834 | r = FLD_MOD(r, hsa_blanking_mode, 23, 23); /* HSA_BLANKING */ | ||
3835 | dsi_write_reg(dsidev, DSI_CTRL, r); | ||
3836 | } | ||
3837 | |||
3838 | /* | ||
3839 | * According to section 'HS Command Mode Interleaving' in OMAP TRM, Scenario 3 | ||
3840 | * results in maximum transition time for data and clock lanes to enter and | ||
3841 | * exit HS mode. Hence, this is the scenario where the least amount of command | ||
3842 | * mode data can be interleaved. We program the minimum amount of TXBYTECLKHS | ||
3843 | * clock cycles that can be used to interleave command mode data in HS so that | ||
3844 | * all scenarios are satisfied. | ||
3845 | */ | ||
3846 | static int dsi_compute_interleave_hs(int blank, bool ddr_alwon, int enter_hs, | ||
3847 | int exit_hs, int exiths_clk, int ddr_pre, int ddr_post) | ||
3848 | { | ||
3849 | int transition; | ||
3850 | |||
3851 | /* | ||
3852 | * If DDR_CLK_ALWAYS_ON is set, we need to consider HS mode transition | ||
3853 | * time of data lanes only, if it isn't set, we need to consider HS | ||
3854 | * transition time of both data and clock lanes. HS transition time | ||
3855 | * of Scenario 3 is considered. | ||
3856 | */ | ||
3857 | if (ddr_alwon) { | ||
3858 | transition = enter_hs + exit_hs + max(enter_hs, 2) + 1; | ||
3859 | } else { | ||
3860 | int trans1, trans2; | ||
3861 | trans1 = ddr_pre + enter_hs + exit_hs + max(enter_hs, 2) + 1; | ||
3862 | trans2 = ddr_pre + enter_hs + exiths_clk + ddr_post + ddr_pre + | ||
3863 | enter_hs + 1; | ||
3864 | transition = max(trans1, trans2); | ||
3865 | } | ||
3866 | |||
3867 | return blank > transition ? blank - transition : 0; | ||
3868 | } | ||
3869 | |||
3870 | /* | ||
3871 | * According to section 'LP Command Mode Interleaving' in OMAP TRM, Scenario 1 | ||
3872 | * results in maximum transition time for data lanes to enter and exit LP mode. | ||
3873 | * Hence, this is the scenario where the least amount of command mode data can | ||
3874 | * be interleaved. We program the minimum amount of bytes that can be | ||
3875 | * interleaved in LP so that all scenarios are satisfied. | ||
3876 | */ | ||
3877 | static int dsi_compute_interleave_lp(int blank, int enter_hs, int exit_hs, | ||
3878 | int lp_clk_div, int tdsi_fclk) | ||
3879 | { | ||
3880 | int trans_lp; /* time required for a LP transition, in TXBYTECLKHS */ | ||
3881 | int tlp_avail; /* time left for interleaving commands, in CLKIN4DDR */ | ||
3882 | int ttxclkesc; /* period of LP transmit escape clock, in CLKIN4DDR */ | ||
3883 | int thsbyte_clk = 16; /* Period of TXBYTECLKHS clock, in CLKIN4DDR */ | ||
3884 | int lp_inter; /* cmd mode data that can be interleaved, in bytes */ | ||
3885 | |||
3886 | /* maximum LP transition time according to Scenario 1 */ | ||
3887 | trans_lp = exit_hs + max(enter_hs, 2) + 1; | ||
3888 | |||
3889 | /* CLKIN4DDR = 16 * TXBYTECLKHS */ | ||
3890 | tlp_avail = thsbyte_clk * (blank - trans_lp); | ||
3891 | |||
3892 | ttxclkesc = tdsi_fclk * lp_clk_div; | ||
3893 | |||
3894 | lp_inter = ((tlp_avail - 8 * thsbyte_clk - 5 * tdsi_fclk) / ttxclkesc - | ||
3895 | 26) / 16; | ||
3896 | |||
3897 | return max(lp_inter, 0); | ||
3898 | } | ||
3899 | |||
3900 | static void dsi_config_cmd_mode_interleaving(struct omap_dss_device *dssdev) | ||
3901 | { | ||
3902 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3903 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3904 | int blanking_mode; | ||
3905 | int hfp_blanking_mode, hbp_blanking_mode, hsa_blanking_mode; | ||
3906 | int hsa, hfp, hbp, width_bytes, bllp, lp_clk_div; | ||
3907 | int ddr_clk_pre, ddr_clk_post, enter_hs_mode_lat, exit_hs_mode_lat; | ||
3908 | int tclk_trail, ths_exit, exiths_clk; | ||
3909 | bool ddr_alwon; | ||
3910 | struct omap_video_timings *timings = &dsi->timings; | ||
3911 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | ||
3912 | int ndl = dsi->num_lanes_used - 1; | ||
3913 | int dsi_fclk_hsdiv = dssdev->clocks.dsi.regm_dsi + 1; | ||
3914 | int hsa_interleave_hs = 0, hsa_interleave_lp = 0; | ||
3915 | int hfp_interleave_hs = 0, hfp_interleave_lp = 0; | ||
3916 | int hbp_interleave_hs = 0, hbp_interleave_lp = 0; | ||
3917 | int bl_interleave_hs = 0, bl_interleave_lp = 0; | ||
3918 | u32 r; | ||
3919 | |||
3920 | r = dsi_read_reg(dsidev, DSI_CTRL); | ||
3921 | blanking_mode = FLD_GET(r, 20, 20); | ||
3922 | hfp_blanking_mode = FLD_GET(r, 21, 21); | ||
3923 | hbp_blanking_mode = FLD_GET(r, 22, 22); | ||
3924 | hsa_blanking_mode = FLD_GET(r, 23, 23); | ||
3925 | |||
3926 | r = dsi_read_reg(dsidev, DSI_VM_TIMING1); | ||
3927 | hbp = FLD_GET(r, 11, 0); | ||
3928 | hfp = FLD_GET(r, 23, 12); | ||
3929 | hsa = FLD_GET(r, 31, 24); | ||
3930 | |||
3931 | r = dsi_read_reg(dsidev, DSI_CLK_TIMING); | ||
3932 | ddr_clk_post = FLD_GET(r, 7, 0); | ||
3933 | ddr_clk_pre = FLD_GET(r, 15, 8); | ||
3934 | |||
3935 | r = dsi_read_reg(dsidev, DSI_VM_TIMING7); | ||
3936 | exit_hs_mode_lat = FLD_GET(r, 15, 0); | ||
3937 | enter_hs_mode_lat = FLD_GET(r, 31, 16); | ||
3938 | |||
3939 | r = dsi_read_reg(dsidev, DSI_CLK_CTRL); | ||
3940 | lp_clk_div = FLD_GET(r, 12, 0); | ||
3941 | ddr_alwon = FLD_GET(r, 13, 13); | ||
3942 | |||
3943 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); | ||
3944 | ths_exit = FLD_GET(r, 7, 0); | ||
3945 | |||
3946 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | ||
3947 | tclk_trail = FLD_GET(r, 15, 8); | ||
3948 | |||
3949 | exiths_clk = ths_exit + tclk_trail; | ||
3950 | |||
3951 | width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8); | ||
3952 | bllp = hbp + hfp + hsa + DIV_ROUND_UP(width_bytes + 6, ndl); | ||
3953 | |||
3954 | if (!hsa_blanking_mode) { | ||
3955 | hsa_interleave_hs = dsi_compute_interleave_hs(hsa, ddr_alwon, | ||
3956 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3957 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3958 | hsa_interleave_lp = dsi_compute_interleave_lp(hsa, | ||
3959 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3960 | lp_clk_div, dsi_fclk_hsdiv); | ||
3961 | } | ||
3962 | |||
3963 | if (!hfp_blanking_mode) { | ||
3964 | hfp_interleave_hs = dsi_compute_interleave_hs(hfp, ddr_alwon, | ||
3965 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3966 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3967 | hfp_interleave_lp = dsi_compute_interleave_lp(hfp, | ||
3968 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3969 | lp_clk_div, dsi_fclk_hsdiv); | ||
3970 | } | ||
3971 | |||
3972 | if (!hbp_blanking_mode) { | ||
3973 | hbp_interleave_hs = dsi_compute_interleave_hs(hbp, ddr_alwon, | ||
3974 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3975 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3976 | |||
3977 | hbp_interleave_lp = dsi_compute_interleave_lp(hbp, | ||
3978 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3979 | lp_clk_div, dsi_fclk_hsdiv); | ||
3980 | } | ||
3981 | |||
3982 | if (!blanking_mode) { | ||
3983 | bl_interleave_hs = dsi_compute_interleave_hs(bllp, ddr_alwon, | ||
3984 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3985 | exiths_clk, ddr_clk_pre, ddr_clk_post); | ||
3986 | |||
3987 | bl_interleave_lp = dsi_compute_interleave_lp(bllp, | ||
3988 | enter_hs_mode_lat, exit_hs_mode_lat, | ||
3989 | lp_clk_div, dsi_fclk_hsdiv); | ||
3990 | } | ||
3991 | |||
3992 | DSSDBG("DSI HS interleaving(TXBYTECLKHS) HSA %d, HFP %d, HBP %d, BLLP %d\n", | ||
3993 | hsa_interleave_hs, hfp_interleave_hs, hbp_interleave_hs, | ||
3994 | bl_interleave_hs); | ||
3995 | |||
3996 | DSSDBG("DSI LP interleaving(bytes) HSA %d, HFP %d, HBP %d, BLLP %d\n", | ||
3997 | hsa_interleave_lp, hfp_interleave_lp, hbp_interleave_lp, | ||
3998 | bl_interleave_lp); | ||
3999 | |||
4000 | r = dsi_read_reg(dsidev, DSI_VM_TIMING4); | ||
4001 | r = FLD_MOD(r, hsa_interleave_hs, 23, 16); | ||
4002 | r = FLD_MOD(r, hfp_interleave_hs, 15, 8); | ||
4003 | r = FLD_MOD(r, hbp_interleave_hs, 7, 0); | ||
4004 | dsi_write_reg(dsidev, DSI_VM_TIMING4, r); | ||
4005 | |||
4006 | r = dsi_read_reg(dsidev, DSI_VM_TIMING5); | ||
4007 | r = FLD_MOD(r, hsa_interleave_lp, 23, 16); | ||
4008 | r = FLD_MOD(r, hfp_interleave_lp, 15, 8); | ||
4009 | r = FLD_MOD(r, hbp_interleave_lp, 7, 0); | ||
4010 | dsi_write_reg(dsidev, DSI_VM_TIMING5, r); | ||
4011 | |||
4012 | r = dsi_read_reg(dsidev, DSI_VM_TIMING6); | ||
4013 | r = FLD_MOD(r, bl_interleave_hs, 31, 15); | ||
4014 | r = FLD_MOD(r, bl_interleave_lp, 16, 0); | ||
4015 | dsi_write_reg(dsidev, DSI_VM_TIMING6, r); | ||
4016 | } | ||
4017 | |||
4018 | static int dsi_proto_config(struct omap_dss_device *dssdev) | 3511 | static int dsi_proto_config(struct omap_dss_device *dssdev) |
4019 | { | 3512 | { |
4020 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3513 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4021 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4022 | u32 r; | 3514 | u32 r; |
4023 | int buswidth = 0; | 3515 | int buswidth = 0; |
4024 | 3516 | ||
@@ -4038,7 +3530,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
4038 | dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); | 3530 | dsi_set_lp_rx_timeout(dsidev, 0x1fff, true, true); |
4039 | dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); | 3531 | dsi_set_hs_tx_timeout(dsidev, 0x1fff, true, true); |
4040 | 3532 | ||
4041 | switch (dsi_get_pixel_size(dsi->pix_fmt)) { | 3533 | switch (dssdev->ctrl.pixel_size) { |
4042 | case 16: | 3534 | case 16: |
4043 | buswidth = 0; | 3535 | buswidth = 0; |
4044 | break; | 3536 | break; |
@@ -4050,7 +3542,6 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
4050 | break; | 3542 | break; |
4051 | default: | 3543 | default: |
4052 | BUG(); | 3544 | BUG(); |
4053 | return -EINVAL; | ||
4054 | } | 3545 | } |
4055 | 3546 | ||
4056 | r = dsi_read_reg(dsidev, DSI_CTRL); | 3547 | r = dsi_read_reg(dsidev, DSI_CTRL); |
@@ -4060,6 +3551,7 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
4060 | r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/ | 3551 | r = FLD_MOD(r, 1, 4, 4); /* VP_CLK_RATIO, always 1, see errata*/ |
4061 | r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */ | 3552 | r = FLD_MOD(r, buswidth, 7, 6); /* VP_DATA_BUS_WIDTH */ |
4062 | r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ | 3553 | r = FLD_MOD(r, 0, 8, 8); /* VP_CLK_POL */ |
3554 | r = FLD_MOD(r, 2, 13, 12); /* LINE_BUFFER, 2 lines */ | ||
4063 | r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ | 3555 | r = FLD_MOD(r, 1, 14, 14); /* TRIGGER_RESET_MODE */ |
4064 | r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ | 3556 | r = FLD_MOD(r, 1, 19, 19); /* EOT_ENABLE */ |
4065 | if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { | 3557 | if (!dss_has_feature(FEAT_DSI_DCS_CMD_CONFIG_VC)) { |
@@ -4070,14 +3562,6 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
4070 | 3562 | ||
4071 | dsi_write_reg(dsidev, DSI_CTRL, r); | 3563 | dsi_write_reg(dsidev, DSI_CTRL, r); |
4072 | 3564 | ||
4073 | dsi_config_vp_num_line_buffers(dsidev); | ||
4074 | |||
4075 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
4076 | dsi_config_vp_sync_events(dsidev); | ||
4077 | dsi_config_blanking_modes(dsidev); | ||
4078 | dsi_config_cmd_mode_interleaving(dssdev); | ||
4079 | } | ||
4080 | |||
4081 | dsi_vc_initial_config(dsidev, 0); | 3565 | dsi_vc_initial_config(dsidev, 0); |
4082 | dsi_vc_initial_config(dsidev, 1); | 3566 | dsi_vc_initial_config(dsidev, 1); |
4083 | dsi_vc_initial_config(dsidev, 2); | 3567 | dsi_vc_initial_config(dsidev, 2); |
@@ -4086,9 +3570,9 @@ static int dsi_proto_config(struct omap_dss_device *dssdev) | |||
4086 | return 0; | 3570 | return 0; |
4087 | } | 3571 | } |
4088 | 3572 | ||
4089 | static void dsi_proto_timings(struct platform_device *dsidev) | 3573 | static void dsi_proto_timings(struct omap_dss_device *dssdev) |
4090 | { | 3574 | { |
4091 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3575 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4092 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; | 3576 | unsigned tlpx, tclk_zero, tclk_prepare, tclk_trail; |
4093 | unsigned tclk_pre, tclk_post; | 3577 | unsigned tclk_pre, tclk_post; |
4094 | unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; | 3578 | unsigned ths_prepare, ths_prepare_ths_zero, ths_zero; |
@@ -4096,7 +3580,6 @@ static void dsi_proto_timings(struct platform_device *dsidev) | |||
4096 | unsigned ddr_clk_pre, ddr_clk_post; | 3580 | unsigned ddr_clk_pre, ddr_clk_post; |
4097 | unsigned enter_hs_mode_lat, exit_hs_mode_lat; | 3581 | unsigned enter_hs_mode_lat, exit_hs_mode_lat; |
4098 | unsigned ths_eot; | 3582 | unsigned ths_eot; |
4099 | int ndl = dsi->num_lanes_used - 1; | ||
4100 | u32 r; | 3583 | u32 r; |
4101 | 3584 | ||
4102 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); | 3585 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG0); |
@@ -4107,7 +3590,7 @@ static void dsi_proto_timings(struct platform_device *dsidev) | |||
4107 | ths_exit = FLD_GET(r, 7, 0); | 3590 | ths_exit = FLD_GET(r, 7, 0); |
4108 | 3591 | ||
4109 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); | 3592 | r = dsi_read_reg(dsidev, DSI_DSIPHY_CFG1); |
4110 | tlpx = FLD_GET(r, 20, 16) * 2; | 3593 | tlpx = FLD_GET(r, 22, 16) * 2; |
4111 | tclk_trail = FLD_GET(r, 15, 8); | 3594 | tclk_trail = FLD_GET(r, 15, 8); |
4112 | tclk_zero = FLD_GET(r, 7, 0); | 3595 | tclk_zero = FLD_GET(r, 7, 0); |
4113 | 3596 | ||
@@ -4119,7 +3602,7 @@ static void dsi_proto_timings(struct platform_device *dsidev) | |||
4119 | /* min 60ns + 52*UI */ | 3602 | /* min 60ns + 52*UI */ |
4120 | tclk_post = ns2ddr(dsidev, 60) + 26; | 3603 | tclk_post = ns2ddr(dsidev, 60) + 26; |
4121 | 3604 | ||
4122 | ths_eot = DIV_ROUND_UP(4, ndl); | 3605 | ths_eot = DIV_ROUND_UP(4, dsi_get_num_data_lanes_dssdev(dssdev)); |
4123 | 3606 | ||
4124 | ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare, | 3607 | ddr_clk_pre = DIV_ROUND_UP(tclk_pre + tlpx + tclk_zero + tclk_prepare, |
4125 | 4); | 3608 | 4); |
@@ -4149,273 +3632,168 @@ static void dsi_proto_timings(struct platform_device *dsidev) | |||
4149 | 3632 | ||
4150 | DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", | 3633 | DSSDBG("enter_hs_mode_lat %u, exit_hs_mode_lat %u\n", |
4151 | enter_hs_mode_lat, exit_hs_mode_lat); | 3634 | enter_hs_mode_lat, exit_hs_mode_lat); |
4152 | |||
4153 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
4154 | /* TODO: Implement a video mode check_timings function */ | ||
4155 | int hsa = dsi->vm_timings.hsa; | ||
4156 | int hfp = dsi->vm_timings.hfp; | ||
4157 | int hbp = dsi->vm_timings.hbp; | ||
4158 | int vsa = dsi->vm_timings.vsa; | ||
4159 | int vfp = dsi->vm_timings.vfp; | ||
4160 | int vbp = dsi->vm_timings.vbp; | ||
4161 | int window_sync = dsi->vm_timings.window_sync; | ||
4162 | bool hsync_end = dsi->vm_timings.vp_hsync_end; | ||
4163 | struct omap_video_timings *timings = &dsi->timings; | ||
4164 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | ||
4165 | int tl, t_he, width_bytes; | ||
4166 | |||
4167 | t_he = hsync_end ? | ||
4168 | ((hsa == 0 && ndl == 3) ? 1 : DIV_ROUND_UP(4, ndl)) : 0; | ||
4169 | |||
4170 | width_bytes = DIV_ROUND_UP(timings->x_res * bpp, 8); | ||
4171 | |||
4172 | /* TL = t_HS + HSA + t_HE + HFP + ceil((WC + 6) / NDL) + HBP */ | ||
4173 | tl = DIV_ROUND_UP(4, ndl) + (hsync_end ? hsa : 0) + t_he + hfp + | ||
4174 | DIV_ROUND_UP(width_bytes + 6, ndl) + hbp; | ||
4175 | |||
4176 | DSSDBG("HBP: %d, HFP: %d, HSA: %d, TL: %d TXBYTECLKHS\n", hbp, | ||
4177 | hfp, hsync_end ? hsa : 0, tl); | ||
4178 | DSSDBG("VBP: %d, VFP: %d, VSA: %d, VACT: %d lines\n", vbp, vfp, | ||
4179 | vsa, timings->y_res); | ||
4180 | |||
4181 | r = dsi_read_reg(dsidev, DSI_VM_TIMING1); | ||
4182 | r = FLD_MOD(r, hbp, 11, 0); /* HBP */ | ||
4183 | r = FLD_MOD(r, hfp, 23, 12); /* HFP */ | ||
4184 | r = FLD_MOD(r, hsync_end ? hsa : 0, 31, 24); /* HSA */ | ||
4185 | dsi_write_reg(dsidev, DSI_VM_TIMING1, r); | ||
4186 | |||
4187 | r = dsi_read_reg(dsidev, DSI_VM_TIMING2); | ||
4188 | r = FLD_MOD(r, vbp, 7, 0); /* VBP */ | ||
4189 | r = FLD_MOD(r, vfp, 15, 8); /* VFP */ | ||
4190 | r = FLD_MOD(r, vsa, 23, 16); /* VSA */ | ||
4191 | r = FLD_MOD(r, window_sync, 27, 24); /* WINDOW_SYNC */ | ||
4192 | dsi_write_reg(dsidev, DSI_VM_TIMING2, r); | ||
4193 | |||
4194 | r = dsi_read_reg(dsidev, DSI_VM_TIMING3); | ||
4195 | r = FLD_MOD(r, timings->y_res, 14, 0); /* VACT */ | ||
4196 | r = FLD_MOD(r, tl, 31, 16); /* TL */ | ||
4197 | dsi_write_reg(dsidev, DSI_VM_TIMING3, r); | ||
4198 | } | ||
4199 | } | 3635 | } |
4200 | 3636 | ||
4201 | int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, | ||
4202 | const struct omap_dsi_pin_config *pin_cfg) | ||
4203 | { | ||
4204 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4205 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4206 | int num_pins; | ||
4207 | const int *pins; | ||
4208 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; | ||
4209 | int num_lanes; | ||
4210 | int i; | ||
4211 | |||
4212 | static const enum dsi_lane_function functions[] = { | ||
4213 | DSI_LANE_CLK, | ||
4214 | DSI_LANE_DATA1, | ||
4215 | DSI_LANE_DATA2, | ||
4216 | DSI_LANE_DATA3, | ||
4217 | DSI_LANE_DATA4, | ||
4218 | }; | ||
4219 | |||
4220 | num_pins = pin_cfg->num_pins; | ||
4221 | pins = pin_cfg->pins; | ||
4222 | |||
4223 | if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2 | ||
4224 | || num_pins % 2 != 0) | ||
4225 | return -EINVAL; | ||
4226 | |||
4227 | for (i = 0; i < DSI_MAX_NR_LANES; ++i) | ||
4228 | lanes[i].function = DSI_LANE_UNUSED; | ||
4229 | |||
4230 | num_lanes = 0; | ||
4231 | |||
4232 | for (i = 0; i < num_pins; i += 2) { | ||
4233 | u8 lane, pol; | ||
4234 | int dx, dy; | ||
4235 | |||
4236 | dx = pins[i]; | ||
4237 | dy = pins[i + 1]; | ||
4238 | |||
4239 | if (dx < 0 || dx >= dsi->num_lanes_supported * 2) | ||
4240 | return -EINVAL; | ||
4241 | 3637 | ||
4242 | if (dy < 0 || dy >= dsi->num_lanes_supported * 2) | 3638 | #define DSI_DECL_VARS \ |
4243 | return -EINVAL; | 3639 | int __dsi_cb = 0; u32 __dsi_cv = 0; |
4244 | 3640 | ||
4245 | if (dx & 1) { | 3641 | #define DSI_FLUSH(dsidev, ch) \ |
4246 | if (dy != dx - 1) | 3642 | if (__dsi_cb > 0) { \ |
4247 | return -EINVAL; | 3643 | /*DSSDBG("sending long packet %#010x\n", __dsi_cv);*/ \ |
4248 | pol = 1; | 3644 | dsi_write_reg(dsidev, DSI_VC_LONG_PACKET_PAYLOAD(ch), __dsi_cv); \ |
4249 | } else { | 3645 | __dsi_cb = __dsi_cv = 0; \ |
4250 | if (dy != dx + 1) | ||
4251 | return -EINVAL; | ||
4252 | pol = 0; | ||
4253 | } | ||
4254 | |||
4255 | lane = dx / 2; | ||
4256 | |||
4257 | lanes[lane].function = functions[i / 2]; | ||
4258 | lanes[lane].polarity = pol; | ||
4259 | num_lanes++; | ||
4260 | } | 3646 | } |
4261 | 3647 | ||
4262 | memcpy(dsi->lanes, lanes, sizeof(dsi->lanes)); | 3648 | #define DSI_PUSH(dsidev, ch, data) \ |
4263 | dsi->num_lanes_used = num_lanes; | 3649 | do { \ |
4264 | 3650 | __dsi_cv |= (data) << (__dsi_cb * 8); \ | |
4265 | return 0; | 3651 | /*DSSDBG("cv = %#010x, cb = %d\n", __dsi_cv, __dsi_cb);*/ \ |
4266 | } | 3652 | if (++__dsi_cb > 3) \ |
4267 | EXPORT_SYMBOL(omapdss_dsi_configure_pins); | 3653 | DSI_FLUSH(dsidev, ch); \ |
3654 | } while (0) | ||
4268 | 3655 | ||
4269 | int omapdss_dsi_set_clocks(struct omap_dss_device *dssdev, | 3656 | static int dsi_update_screen_l4(struct omap_dss_device *dssdev, |
4270 | unsigned long ddr_clk, unsigned long lp_clk) | 3657 | int x, int y, int w, int h) |
4271 | { | 3658 | { |
3659 | /* Note: supports only 24bit colors in 32bit container */ | ||
4272 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3660 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4273 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3661 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4274 | struct dsi_clock_info cinfo; | 3662 | int first = 1; |
4275 | struct dispc_clock_info dispc_cinfo; | 3663 | int fifo_stalls = 0; |
4276 | unsigned lp_clk_div; | 3664 | int max_dsi_packet_size; |
4277 | unsigned long dsi_fclk; | 3665 | int max_data_per_packet; |
4278 | int bpp = dsi_get_pixel_size(dssdev->panel.dsi_pix_fmt); | 3666 | int max_pixels_per_packet; |
4279 | unsigned long pck; | 3667 | int pixels_left; |
4280 | int r; | 3668 | int bytespp = dssdev->ctrl.pixel_size / 8; |
3669 | int scr_width; | ||
3670 | u32 __iomem *data; | ||
3671 | int start_offset; | ||
3672 | int horiz_inc; | ||
3673 | int current_x; | ||
3674 | struct omap_overlay *ovl; | ||
3675 | |||
3676 | debug_irq = 0; | ||
3677 | |||
3678 | DSSDBG("dsi_update_screen_l4 (%d,%d %dx%d)\n", | ||
3679 | x, y, w, h); | ||
3680 | |||
3681 | ovl = dssdev->manager->overlays[0]; | ||
3682 | |||
3683 | if (ovl->info.color_mode != OMAP_DSS_COLOR_RGB24U) | ||
3684 | return -EINVAL; | ||
4281 | 3685 | ||
4282 | DSSDBG("Setting DSI clocks: ddr_clk %lu, lp_clk %lu", ddr_clk, lp_clk); | 3686 | if (dssdev->ctrl.pixel_size != 24) |
3687 | return -EINVAL; | ||
4283 | 3688 | ||
4284 | mutex_lock(&dsi->lock); | 3689 | scr_width = ovl->info.screen_width; |
3690 | data = ovl->info.vaddr; | ||
4285 | 3691 | ||
4286 | /* Calculate PLL output clock */ | 3692 | start_offset = scr_width * y + x; |
4287 | r = dsi_pll_calc_ddrfreq(dsidev, ddr_clk * 4, &cinfo); | 3693 | horiz_inc = scr_width - w; |
4288 | if (r) | 3694 | current_x = x; |
4289 | goto err; | ||
4290 | 3695 | ||
4291 | /* Calculate PLL's DSI clock */ | 3696 | /* We need header(4) + DCSCMD(1) + pixels(numpix*bytespp) bytes |
4292 | dsi_pll_calc_dsi_fck(dsidev, &cinfo); | 3697 | * in fifo */ |
4293 | 3698 | ||
4294 | /* Calculate PLL's DISPC clock and pck & lck divs */ | 3699 | /* When using CPU, max long packet size is TX buffer size */ |
4295 | pck = cinfo.clkin4ddr / 16 * (dsi->num_lanes_used - 1) * 8 / bpp; | 3700 | max_dsi_packet_size = dsi->vc[0].fifo_size * 32 * 4; |
4296 | DSSDBG("finding dispc dividers for pck %lu\n", pck); | ||
4297 | r = dsi_pll_calc_dispc_fck(dsidev, pck, &cinfo, &dispc_cinfo); | ||
4298 | if (r) | ||
4299 | goto err; | ||
4300 | 3701 | ||
4301 | /* Calculate LP clock */ | 3702 | /* we seem to get better perf if we divide the tx fifo to half, |
4302 | dsi_fclk = cinfo.dsi_pll_hsdiv_dsi_clk; | 3703 | and while the other half is being sent, we fill the other half |
4303 | lp_clk_div = DIV_ROUND_UP(dsi_fclk, lp_clk * 2); | 3704 | max_dsi_packet_size /= 2; */ |
4304 | 3705 | ||
4305 | dssdev->clocks.dsi.regn = cinfo.regn; | 3706 | max_data_per_packet = max_dsi_packet_size - 4 - 1; |
4306 | dssdev->clocks.dsi.regm = cinfo.regm; | ||
4307 | dssdev->clocks.dsi.regm_dispc = cinfo.regm_dispc; | ||
4308 | dssdev->clocks.dsi.regm_dsi = cinfo.regm_dsi; | ||
4309 | 3707 | ||
4310 | dssdev->clocks.dsi.lp_clk_div = lp_clk_div; | 3708 | max_pixels_per_packet = max_data_per_packet / bytespp; |
4311 | 3709 | ||
4312 | dssdev->clocks.dispc.channel.lck_div = dispc_cinfo.lck_div; | 3710 | DSSDBG("max_pixels_per_packet %d\n", max_pixels_per_packet); |
4313 | dssdev->clocks.dispc.channel.pck_div = dispc_cinfo.pck_div; | ||
4314 | 3711 | ||
4315 | dssdev->clocks.dispc.dispc_fclk_src = OMAP_DSS_CLK_SRC_FCK; | 3712 | pixels_left = w * h; |
4316 | 3713 | ||
4317 | dssdev->clocks.dispc.channel.lcd_clk_src = | 3714 | DSSDBG("total pixels %d\n", pixels_left); |
4318 | dsi->module_id == 0 ? | ||
4319 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC : | ||
4320 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC; | ||
4321 | 3715 | ||
4322 | dssdev->clocks.dsi.dsi_fclk_src = | 3716 | data += start_offset; |
4323 | dsi->module_id == 0 ? | ||
4324 | OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI : | ||
4325 | OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI; | ||
4326 | 3717 | ||
4327 | mutex_unlock(&dsi->lock); | 3718 | while (pixels_left > 0) { |
4328 | return 0; | 3719 | /* 0x2c = write_memory_start */ |
4329 | err: | 3720 | /* 0x3c = write_memory_continue */ |
4330 | mutex_unlock(&dsi->lock); | 3721 | u8 dcs_cmd = first ? 0x2c : 0x3c; |
4331 | return r; | 3722 | int pixels; |
4332 | } | 3723 | DSI_DECL_VARS; |
4333 | EXPORT_SYMBOL(omapdss_dsi_set_clocks); | 3724 | first = 0; |
4334 | 3725 | ||
4335 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | 3726 | #if 1 |
4336 | { | 3727 | /* using fifo not empty */ |
4337 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3728 | /* TX_FIFO_NOT_EMPTY */ |
4338 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3729 | while (FLD_GET(dsi_read_reg(dsidev, DSI_VC_CTRL(0)), 5, 5)) { |
4339 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 3730 | fifo_stalls++; |
4340 | int bpp = dsi_get_pixel_size(dsi->pix_fmt); | 3731 | if (fifo_stalls > 0xfffff) { |
4341 | u8 data_type; | 3732 | DSSERR("fifo stalls overflow, pixels left %d\n", |
4342 | u16 word_count; | 3733 | pixels_left); |
4343 | int r; | 3734 | dsi_if_enable(dsidev, 0); |
4344 | 3735 | return -EIO; | |
4345 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3736 | } |
4346 | switch (dsi->pix_fmt) { | 3737 | udelay(1); |
4347 | case OMAP_DSS_DSI_FMT_RGB888: | 3738 | } |
4348 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_24; | 3739 | #elif 1 |
4349 | break; | 3740 | /* using fifo emptiness */ |
4350 | case OMAP_DSS_DSI_FMT_RGB666: | 3741 | while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, 7, 0)+1)*4 < |
4351 | data_type = MIPI_DSI_PIXEL_STREAM_3BYTE_18; | 3742 | max_dsi_packet_size) { |
4352 | break; | 3743 | fifo_stalls++; |
4353 | case OMAP_DSS_DSI_FMT_RGB666_PACKED: | 3744 | if (fifo_stalls > 0xfffff) { |
4354 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_18; | 3745 | DSSERR("fifo stalls overflow, pixels left %d\n", |
4355 | break; | 3746 | pixels_left); |
4356 | case OMAP_DSS_DSI_FMT_RGB565: | 3747 | dsi_if_enable(dsidev, 0); |
4357 | data_type = MIPI_DSI_PACKED_PIXEL_STREAM_16; | 3748 | return -EIO; |
4358 | break; | 3749 | } |
4359 | default: | 3750 | } |
4360 | BUG(); | 3751 | #else |
4361 | return -EINVAL; | 3752 | while ((REG_GET(dsidev, DSI_TX_FIFO_VC_EMPTINESS, |
4362 | }; | 3753 | 7, 0) + 1) * 4 == 0) { |
3754 | fifo_stalls++; | ||
3755 | if (fifo_stalls > 0xfffff) { | ||
3756 | DSSERR("fifo stalls overflow, pixels left %d\n", | ||
3757 | pixels_left); | ||
3758 | dsi_if_enable(dsidev, 0); | ||
3759 | return -EIO; | ||
3760 | } | ||
3761 | } | ||
3762 | #endif | ||
3763 | pixels = min(max_pixels_per_packet, pixels_left); | ||
4363 | 3764 | ||
4364 | dsi_if_enable(dsidev, false); | 3765 | pixels_left -= pixels; |
4365 | dsi_vc_enable(dsidev, channel, false); | ||
4366 | 3766 | ||
4367 | /* MODE, 1 = video mode */ | 3767 | dsi_vc_write_long_header(dsidev, 0, DSI_DT_DCS_LONG_WRITE, |
4368 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 1, 4, 4); | 3768 | 1 + pixels * bytespp, 0); |
4369 | 3769 | ||
4370 | word_count = DIV_ROUND_UP(dsi->timings.x_res * bpp, 8); | 3770 | DSI_PUSH(dsidev, 0, dcs_cmd); |
4371 | 3771 | ||
4372 | dsi_vc_write_long_header(dsidev, channel, data_type, | 3772 | while (pixels-- > 0) { |
4373 | word_count, 0); | 3773 | u32 pix = __raw_readl(data++); |
4374 | 3774 | ||
4375 | dsi_vc_enable(dsidev, channel, true); | 3775 | DSI_PUSH(dsidev, 0, (pix >> 16) & 0xff); |
4376 | dsi_if_enable(dsidev, true); | 3776 | DSI_PUSH(dsidev, 0, (pix >> 8) & 0xff); |
4377 | } | 3777 | DSI_PUSH(dsidev, 0, (pix >> 0) & 0xff); |
4378 | 3778 | ||
4379 | r = dss_mgr_enable(mgr); | 3779 | current_x++; |
4380 | if (r) { | 3780 | if (current_x == x+w) { |
4381 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | 3781 | current_x = x; |
4382 | dsi_if_enable(dsidev, false); | 3782 | data += horiz_inc; |
4383 | dsi_vc_enable(dsidev, channel, false); | 3783 | } |
4384 | } | 3784 | } |
4385 | 3785 | ||
4386 | return r; | 3786 | DSI_FLUSH(dsidev, 0); |
4387 | } | 3787 | } |
4388 | 3788 | ||
4389 | return 0; | 3789 | return 0; |
4390 | } | 3790 | } |
4391 | EXPORT_SYMBOL(dsi_enable_video_output); | ||
4392 | 3791 | ||
4393 | void dsi_disable_video_output(struct omap_dss_device *dssdev, int channel) | 3792 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev, |
3793 | u16 x, u16 y, u16 w, u16 h) | ||
4394 | { | 3794 | { |
4395 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3795 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4396 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3796 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4397 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4398 | |||
4399 | if (dsi->mode == OMAP_DSS_DSI_VIDEO_MODE) { | ||
4400 | dsi_if_enable(dsidev, false); | ||
4401 | dsi_vc_enable(dsidev, channel, false); | ||
4402 | |||
4403 | /* MODE, 0 = command mode */ | ||
4404 | REG_FLD_MOD(dsidev, DSI_VC_CTRL(channel), 0, 4, 4); | ||
4405 | |||
4406 | dsi_vc_enable(dsidev, channel, true); | ||
4407 | dsi_if_enable(dsidev, true); | ||
4408 | } | ||
4409 | |||
4410 | dss_mgr_disable(mgr); | ||
4411 | } | ||
4412 | EXPORT_SYMBOL(dsi_disable_video_output); | ||
4413 | |||
4414 | static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) | ||
4415 | { | ||
4416 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4417 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4418 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4419 | unsigned bytespp; | 3797 | unsigned bytespp; |
4420 | unsigned bytespl; | 3798 | unsigned bytespl; |
4421 | unsigned bytespf; | 3799 | unsigned bytespf; |
@@ -4426,14 +3804,13 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) | |||
4426 | int r; | 3804 | int r; |
4427 | const unsigned channel = dsi->update_channel; | 3805 | const unsigned channel = dsi->update_channel; |
4428 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); | 3806 | const unsigned line_buf_size = dsi_get_line_buf_size(dsidev); |
4429 | u16 w = dsi->timings.x_res; | ||
4430 | u16 h = dsi->timings.y_res; | ||
4431 | 3807 | ||
4432 | DSSDBG("dsi_update_screen_dispc(%dx%d)\n", w, h); | 3808 | DSSDBG("dsi_update_screen_dispc(%d,%d %dx%d)\n", |
3809 | x, y, w, h); | ||
4433 | 3810 | ||
4434 | dsi_vc_config_source(dsidev, channel, DSI_VC_SOURCE_VP); | 3811 | dsi_vc_config_vp(dsidev, channel); |
4435 | 3812 | ||
4436 | bytespp = dsi_get_pixel_size(dsi->pix_fmt) / 8; | 3813 | bytespp = dssdev->ctrl.pixel_size / 8; |
4437 | bytespl = w * bytespp; | 3814 | bytespl = w * bytespp; |
4438 | bytespf = bytespl * h; | 3815 | bytespf = bytespl * h; |
4439 | 3816 | ||
@@ -4454,7 +3831,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) | |||
4454 | l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ | 3831 | l = FLD_VAL(total_len, 23, 0); /* TE_SIZE */ |
4455 | dsi_write_reg(dsidev, DSI_VC_TE(channel), l); | 3832 | dsi_write_reg(dsidev, DSI_VC_TE(channel), l); |
4456 | 3833 | ||
4457 | dsi_vc_write_long_header(dsidev, channel, MIPI_DSI_DCS_LONG_WRITE, | 3834 | dsi_vc_write_long_header(dsidev, channel, DSI_DT_DCS_LONG_WRITE, |
4458 | packet_len, 0); | 3835 | packet_len, 0); |
4459 | 3836 | ||
4460 | if (dsi->te_enabled) | 3837 | if (dsi->te_enabled) |
@@ -4477,9 +3854,7 @@ static void dsi_update_screen_dispc(struct omap_dss_device *dssdev) | |||
4477 | msecs_to_jiffies(250)); | 3854 | msecs_to_jiffies(250)); |
4478 | BUG_ON(r == 0); | 3855 | BUG_ON(r == 0); |
4479 | 3856 | ||
4480 | dss_mgr_set_timings(mgr, &dsi->timings); | 3857 | dss_start_update(dssdev); |
4481 | |||
4482 | dss_mgr_start_update(mgr); | ||
4483 | 3858 | ||
4484 | if (dsi->te_enabled) { | 3859 | if (dsi->te_enabled) { |
4485 | /* disable LP_RX_TO, so that we can receive TE. Time to wait | 3860 | /* disable LP_RX_TO, so that we can receive TE. Time to wait |
@@ -4535,9 +3910,10 @@ static void dsi_framedone_timeout_work_callback(struct work_struct *work) | |||
4535 | dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); | 3910 | dsi_handle_framedone(dsi->pdev, -ETIMEDOUT); |
4536 | } | 3911 | } |
4537 | 3912 | ||
4538 | static void dsi_framedone_irq_callback(void *data) | 3913 | static void dsi_framedone_irq_callback(void *data, u32 mask) |
4539 | { | 3914 | { |
4540 | struct platform_device *dsidev = (struct platform_device *) data; | 3915 | struct omap_dss_device *dssdev = (struct omap_dss_device *) data; |
3916 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4541 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3917 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4542 | 3918 | ||
4543 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and | 3919 | /* Note: We get FRAMEDONE when DISPC has finished sending pixels and |
@@ -4545,135 +3921,144 @@ static void dsi_framedone_irq_callback(void *data) | |||
4545 | * and is sending the data. | 3921 | * and is sending the data. |
4546 | */ | 3922 | */ |
4547 | 3923 | ||
4548 | cancel_delayed_work(&dsi->framedone_timeout_work); | 3924 | __cancel_delayed_work(&dsi->framedone_timeout_work); |
4549 | 3925 | ||
4550 | dsi_handle_framedone(dsidev, 0); | 3926 | dsi_handle_framedone(dsidev, 0); |
3927 | |||
3928 | #ifdef CONFIG_OMAP2_DSS_FAKE_VSYNC | ||
3929 | dispc_fake_vsync_irq(); | ||
3930 | #endif | ||
4551 | } | 3931 | } |
4552 | 3932 | ||
4553 | int omap_dsi_update(struct omap_dss_device *dssdev, int channel, | 3933 | int omap_dsi_prepare_update(struct omap_dss_device *dssdev, |
4554 | void (*callback)(int, void *), void *data) | 3934 | u16 *x, u16 *y, u16 *w, u16 *h, |
3935 | bool enlarge_update_area) | ||
4555 | { | 3936 | { |
4556 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3937 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4557 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4558 | u16 dw, dh; | 3938 | u16 dw, dh; |
4559 | 3939 | ||
4560 | dsi_perf_mark_setup(dsidev); | 3940 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
4561 | 3941 | ||
4562 | dsi->update_channel = channel; | 3942 | if (*x > dw || *y > dh) |
3943 | return -EINVAL; | ||
4563 | 3944 | ||
4564 | dsi->framedone_callback = callback; | 3945 | if (*x + *w > dw) |
4565 | dsi->framedone_data = data; | 3946 | return -EINVAL; |
4566 | 3947 | ||
4567 | dw = dsi->timings.x_res; | 3948 | if (*y + *h > dh) |
4568 | dh = dsi->timings.y_res; | 3949 | return -EINVAL; |
4569 | 3950 | ||
4570 | #ifdef DEBUG | 3951 | if (*w == 1) |
4571 | dsi->update_bytes = dw * dh * | 3952 | return -EINVAL; |
4572 | dsi_get_pixel_size(dsi->pix_fmt) / 8; | 3953 | |
4573 | #endif | 3954 | if (*w == 0 || *h == 0) |
4574 | dsi_update_screen_dispc(dssdev); | 3955 | return -EINVAL; |
3956 | |||
3957 | dsi_perf_mark_setup(dsidev); | ||
3958 | |||
3959 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | ||
3960 | dss_setup_partial_planes(dssdev, x, y, w, h, | ||
3961 | enlarge_update_area); | ||
3962 | dispc_set_lcd_size(dssdev->manager->id, *w, *h); | ||
3963 | } | ||
4575 | 3964 | ||
4576 | return 0; | 3965 | return 0; |
4577 | } | 3966 | } |
4578 | EXPORT_SYMBOL(omap_dsi_update); | 3967 | EXPORT_SYMBOL(omap_dsi_prepare_update); |
4579 | |||
4580 | /* Display funcs */ | ||
4581 | 3968 | ||
4582 | static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) | 3969 | int omap_dsi_update(struct omap_dss_device *dssdev, |
3970 | int channel, | ||
3971 | u16 x, u16 y, u16 w, u16 h, | ||
3972 | void (*callback)(int, void *), void *data) | ||
4583 | { | 3973 | { |
4584 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3974 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4585 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 3975 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4586 | struct dispc_clock_info dispc_cinfo; | ||
4587 | int r; | ||
4588 | unsigned long long fck; | ||
4589 | 3976 | ||
4590 | fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); | 3977 | dsi->update_channel = channel; |
4591 | 3978 | ||
4592 | dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; | 3979 | /* OMAP DSS cannot send updates of odd widths. |
4593 | dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; | 3980 | * omap_dsi_prepare_update() makes the widths even, but add a BUG_ON |
3981 | * here to make sure we catch erroneous updates. Otherwise we'll only | ||
3982 | * see rather obscure HW error happening, as DSS halts. */ | ||
3983 | BUG_ON(x % 2 == 1); | ||
4594 | 3984 | ||
4595 | r = dispc_calc_clock_rates(fck, &dispc_cinfo); | 3985 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
4596 | if (r) { | 3986 | dsi->framedone_callback = callback; |
4597 | DSSERR("Failed to calc dispc clocks\n"); | 3987 | dsi->framedone_data = data; |
4598 | return r; | 3988 | |
4599 | } | 3989 | dsi->update_region.x = x; |
3990 | dsi->update_region.y = y; | ||
3991 | dsi->update_region.w = w; | ||
3992 | dsi->update_region.h = h; | ||
3993 | dsi->update_region.device = dssdev; | ||
3994 | |||
3995 | dsi_update_screen_dispc(dssdev, x, y, w, h); | ||
3996 | } else { | ||
3997 | int r; | ||
4600 | 3998 | ||
4601 | dsi->mgr_config.clock_info = dispc_cinfo; | 3999 | r = dsi_update_screen_l4(dssdev, x, y, w, h); |
4000 | if (r) | ||
4001 | return r; | ||
4002 | |||
4003 | dsi_perf_show(dsidev, "L4"); | ||
4004 | callback(0, data); | ||
4005 | } | ||
4602 | 4006 | ||
4603 | return 0; | 4007 | return 0; |
4604 | } | 4008 | } |
4009 | EXPORT_SYMBOL(omap_dsi_update); | ||
4010 | |||
4011 | /* Display funcs */ | ||
4605 | 4012 | ||
4606 | static int dsi_display_init_dispc(struct omap_dss_device *dssdev) | 4013 | static int dsi_display_init_dispc(struct omap_dss_device *dssdev) |
4607 | { | 4014 | { |
4608 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4609 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4610 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4611 | int r; | 4015 | int r; |
4016 | u32 irq; | ||
4612 | 4017 | ||
4613 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) { | 4018 | irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? |
4614 | dsi->timings.hsw = 1; | 4019 | DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; |
4615 | dsi->timings.hfp = 1; | ||
4616 | dsi->timings.hbp = 1; | ||
4617 | dsi->timings.vsw = 1; | ||
4618 | dsi->timings.vfp = 0; | ||
4619 | dsi->timings.vbp = 0; | ||
4620 | |||
4621 | r = dss_mgr_register_framedone_handler(mgr, | ||
4622 | dsi_framedone_irq_callback, dsidev); | ||
4623 | if (r) { | ||
4624 | DSSERR("can't register FRAMEDONE handler\n"); | ||
4625 | goto err; | ||
4626 | } | ||
4627 | 4020 | ||
4628 | dsi->mgr_config.stallmode = true; | 4021 | r = omap_dispc_register_isr(dsi_framedone_irq_callback, (void *) dssdev, |
4629 | dsi->mgr_config.fifohandcheck = true; | 4022 | irq); |
4630 | } else { | 4023 | if (r) { |
4631 | dsi->mgr_config.stallmode = false; | 4024 | DSSERR("can't get FRAMEDONE irq\n"); |
4632 | dsi->mgr_config.fifohandcheck = false; | 4025 | return r; |
4633 | } | 4026 | } |
4634 | 4027 | ||
4635 | /* | 4028 | dispc_set_lcd_display_type(dssdev->manager->id, |
4636 | * override interlace, logic level and edge related parameters in | 4029 | OMAP_DSS_LCD_DISPLAY_TFT); |
4637 | * omap_video_timings with default values | ||
4638 | */ | ||
4639 | dsi->timings.interlace = false; | ||
4640 | dsi->timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
4641 | dsi->timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
4642 | dsi->timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | ||
4643 | dsi->timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
4644 | dsi->timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
4645 | 4030 | ||
4646 | dss_mgr_set_timings(mgr, &dsi->timings); | 4031 | dispc_set_parallel_interface_mode(dssdev->manager->id, |
4032 | OMAP_DSS_PARALLELMODE_DSI); | ||
4033 | dispc_enable_fifohandcheck(dssdev->manager->id, 1); | ||
4647 | 4034 | ||
4648 | r = dsi_configure_dispc_clocks(dssdev); | 4035 | dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); |
4649 | if (r) | ||
4650 | goto err1; | ||
4651 | 4036 | ||
4652 | dsi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 4037 | { |
4653 | dsi->mgr_config.video_port_width = | 4038 | struct omap_video_timings timings = { |
4654 | dsi_get_pixel_size(dsi->pix_fmt); | 4039 | .hsw = 1, |
4655 | dsi->mgr_config.lcden_sig_polarity = 0; | 4040 | .hfp = 1, |
4041 | .hbp = 1, | ||
4042 | .vsw = 1, | ||
4043 | .vfp = 0, | ||
4044 | .vbp = 0, | ||
4045 | }; | ||
4656 | 4046 | ||
4657 | dss_mgr_set_lcd_config(mgr, &dsi->mgr_config); | 4047 | dispc_set_lcd_timings(dssdev->manager->id, &timings); |
4048 | } | ||
4658 | 4049 | ||
4659 | return 0; | 4050 | return 0; |
4660 | err1: | ||
4661 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) | ||
4662 | dss_mgr_unregister_framedone_handler(mgr, | ||
4663 | dsi_framedone_irq_callback, dsidev); | ||
4664 | err: | ||
4665 | return r; | ||
4666 | } | 4051 | } |
4667 | 4052 | ||
4668 | static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) | 4053 | static void dsi_display_uninit_dispc(struct omap_dss_device *dssdev) |
4669 | { | 4054 | { |
4670 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4055 | u32 irq; |
4671 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4056 | |
4672 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4057 | irq = dssdev->manager->id == OMAP_DSS_CHANNEL_LCD ? |
4058 | DISPC_IRQ_FRAMEDONE : DISPC_IRQ_FRAMEDONE2; | ||
4673 | 4059 | ||
4674 | if (dsi->mode == OMAP_DSS_DSI_CMD_MODE) | 4060 | omap_dispc_unregister_isr(dsi_framedone_irq_callback, (void *) dssdev, |
4675 | dss_mgr_unregister_framedone_handler(mgr, | 4061 | irq); |
4676 | dsi_framedone_irq_callback, dsidev); | ||
4677 | } | 4062 | } |
4678 | 4063 | ||
4679 | static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | 4064 | static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) |
@@ -4682,11 +4067,13 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | |||
4682 | struct dsi_clock_info cinfo; | 4067 | struct dsi_clock_info cinfo; |
4683 | int r; | 4068 | int r; |
4684 | 4069 | ||
4070 | /* we always use DSS_CLK_SYSCK as input clock */ | ||
4071 | cinfo.use_sys_clk = true; | ||
4685 | cinfo.regn = dssdev->clocks.dsi.regn; | 4072 | cinfo.regn = dssdev->clocks.dsi.regn; |
4686 | cinfo.regm = dssdev->clocks.dsi.regm; | 4073 | cinfo.regm = dssdev->clocks.dsi.regm; |
4687 | cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; | 4074 | cinfo.regm_dispc = dssdev->clocks.dsi.regm_dispc; |
4688 | cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; | 4075 | cinfo.regm_dsi = dssdev->clocks.dsi.regm_dsi; |
4689 | r = dsi_calc_clock_rates(dsidev, &cinfo); | 4076 | r = dsi_calc_clock_rates(dssdev, &cinfo); |
4690 | if (r) { | 4077 | if (r) { |
4691 | DSSERR("Failed to calc dsi clocks\n"); | 4078 | DSSERR("Failed to calc dsi clocks\n"); |
4692 | return r; | 4079 | return r; |
@@ -4701,11 +4088,37 @@ static int dsi_configure_dsi_clocks(struct omap_dss_device *dssdev) | |||
4701 | return 0; | 4088 | return 0; |
4702 | } | 4089 | } |
4703 | 4090 | ||
4091 | static int dsi_configure_dispc_clocks(struct omap_dss_device *dssdev) | ||
4092 | { | ||
4093 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4094 | struct dispc_clock_info dispc_cinfo; | ||
4095 | int r; | ||
4096 | unsigned long long fck; | ||
4097 | |||
4098 | fck = dsi_get_pll_hsdiv_dispc_rate(dsidev); | ||
4099 | |||
4100 | dispc_cinfo.lck_div = dssdev->clocks.dispc.channel.lck_div; | ||
4101 | dispc_cinfo.pck_div = dssdev->clocks.dispc.channel.pck_div; | ||
4102 | |||
4103 | r = dispc_calc_clock_rates(fck, &dispc_cinfo); | ||
4104 | if (r) { | ||
4105 | DSSERR("Failed to calc dispc clocks\n"); | ||
4106 | return r; | ||
4107 | } | ||
4108 | |||
4109 | r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); | ||
4110 | if (r) { | ||
4111 | DSSERR("Failed to set dispc clocks\n"); | ||
4112 | return r; | ||
4113 | } | ||
4114 | |||
4115 | return 0; | ||
4116 | } | ||
4117 | |||
4704 | static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | 4118 | static int dsi_display_init_dsi(struct omap_dss_device *dssdev) |
4705 | { | 4119 | { |
4706 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4120 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4707 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4121 | int dsi_module = dsi_get_dsidev_id(dsidev); |
4708 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
4709 | int r; | 4122 | int r; |
4710 | 4123 | ||
4711 | r = dsi_pll_init(dsidev, true, true); | 4124 | r = dsi_pll_init(dsidev, true, true); |
@@ -4716,19 +4129,24 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4716 | if (r) | 4129 | if (r) |
4717 | goto err1; | 4130 | goto err1; |
4718 | 4131 | ||
4719 | dss_select_dsi_clk_source(dsi->module_id, dssdev->clocks.dsi.dsi_fclk_src); | 4132 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); |
4720 | dss_select_lcd_clk_source(mgr->id, | 4133 | dss_select_dsi_clk_source(dsi_module, dssdev->clocks.dsi.dsi_fclk_src); |
4134 | dss_select_lcd_clk_source(dssdev->manager->id, | ||
4721 | dssdev->clocks.dispc.channel.lcd_clk_src); | 4135 | dssdev->clocks.dispc.channel.lcd_clk_src); |
4722 | 4136 | ||
4723 | DSSDBG("PLL OK\n"); | 4137 | DSSDBG("PLL OK\n"); |
4724 | 4138 | ||
4725 | r = dsi_cio_init(dsidev); | 4139 | r = dsi_configure_dispc_clocks(dssdev); |
4140 | if (r) | ||
4141 | goto err2; | ||
4142 | |||
4143 | r = dsi_cio_init(dssdev); | ||
4726 | if (r) | 4144 | if (r) |
4727 | goto err2; | 4145 | goto err2; |
4728 | 4146 | ||
4729 | _dsi_print_reset_status(dsidev); | 4147 | _dsi_print_reset_status(dsidev); |
4730 | 4148 | ||
4731 | dsi_proto_timings(dsidev); | 4149 | dsi_proto_timings(dssdev); |
4732 | dsi_set_lp_clk_divisor(dssdev); | 4150 | dsi_set_lp_clk_divisor(dssdev); |
4733 | 4151 | ||
4734 | if (1) | 4152 | if (1) |
@@ -4750,9 +4168,8 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4750 | err3: | 4168 | err3: |
4751 | dsi_cio_uninit(dsidev); | 4169 | dsi_cio_uninit(dsidev); |
4752 | err2: | 4170 | err2: |
4753 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4171 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
4754 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | 4172 | dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); |
4755 | |||
4756 | err1: | 4173 | err1: |
4757 | dsi_pll_uninit(dsidev, true); | 4174 | dsi_pll_uninit(dsidev, true); |
4758 | err0: | 4175 | err0: |
@@ -4764,7 +4181,7 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
4764 | { | 4181 | { |
4765 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4182 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4766 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4183 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4767 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 4184 | int dsi_module = dsi_get_dsidev_id(dsidev); |
4768 | 4185 | ||
4769 | if (enter_ulps && !dsi->ulps_enabled) | 4186 | if (enter_ulps && !dsi->ulps_enabled) |
4770 | dsi_enter_ulps(dsidev); | 4187 | dsi_enter_ulps(dsidev); |
@@ -4776,8 +4193,8 @@ static void dsi_display_uninit_dsi(struct omap_dss_device *dssdev, | |||
4776 | dsi_vc_enable(dsidev, 2, 0); | 4193 | dsi_vc_enable(dsidev, 2, 0); |
4777 | dsi_vc_enable(dsidev, 3, 0); | 4194 | dsi_vc_enable(dsidev, 3, 0); |
4778 | 4195 | ||
4779 | dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK); | 4196 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); |
4780 | dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK); | 4197 | dss_select_dsi_clk_source(dsi_module, OMAP_DSS_CLK_SRC_FCK); |
4781 | dsi_cio_uninit(dsidev); | 4198 | dsi_cio_uninit(dsidev); |
4782 | dsi_pll_uninit(dsidev, disconnect_lanes); | 4199 | dsi_pll_uninit(dsidev, disconnect_lanes); |
4783 | } | 4200 | } |
@@ -4786,7 +4203,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4786 | { | 4203 | { |
4787 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4204 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4788 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4205 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4789 | struct omap_dss_output *out = dssdev->output; | ||
4790 | int r = 0; | 4206 | int r = 0; |
4791 | 4207 | ||
4792 | DSSDBG("dsi_display_enable\n"); | 4208 | DSSDBG("dsi_display_enable\n"); |
@@ -4795,12 +4211,6 @@ int omapdss_dsi_display_enable(struct omap_dss_device *dssdev) | |||
4795 | 4211 | ||
4796 | mutex_lock(&dsi->lock); | 4212 | mutex_lock(&dsi->lock); |
4797 | 4213 | ||
4798 | if (out == NULL || out->manager == NULL) { | ||
4799 | DSSERR("failed to enable display: no output/manager\n"); | ||
4800 | r = -ENODEV; | ||
4801 | goto err_start_dev; | ||
4802 | } | ||
4803 | |||
4804 | r = omap_dss_start_device(dssdev); | 4214 | r = omap_dss_start_device(dssdev); |
4805 | if (r) { | 4215 | if (r) { |
4806 | DSSERR("failed to start device\n"); | 4216 | DSSERR("failed to start device\n"); |
@@ -4881,93 +4291,31 @@ int omapdss_dsi_enable_te(struct omap_dss_device *dssdev, bool enable) | |||
4881 | } | 4291 | } |
4882 | EXPORT_SYMBOL(omapdss_dsi_enable_te); | 4292 | EXPORT_SYMBOL(omapdss_dsi_enable_te); |
4883 | 4293 | ||
4884 | void omapdss_dsi_set_timings(struct omap_dss_device *dssdev, | 4294 | void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, |
4885 | struct omap_video_timings *timings) | 4295 | u32 fifo_size, u32 burst_size, |
4886 | { | 4296 | u32 *fifo_low, u32 *fifo_high) |
4887 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4888 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4889 | |||
4890 | mutex_lock(&dsi->lock); | ||
4891 | |||
4892 | dsi->timings = *timings; | ||
4893 | |||
4894 | mutex_unlock(&dsi->lock); | ||
4895 | } | ||
4896 | EXPORT_SYMBOL(omapdss_dsi_set_timings); | ||
4897 | |||
4898 | void omapdss_dsi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) | ||
4899 | { | ||
4900 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4901 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4902 | |||
4903 | mutex_lock(&dsi->lock); | ||
4904 | |||
4905 | dsi->timings.x_res = w; | ||
4906 | dsi->timings.y_res = h; | ||
4907 | |||
4908 | mutex_unlock(&dsi->lock); | ||
4909 | } | ||
4910 | EXPORT_SYMBOL(omapdss_dsi_set_size); | ||
4911 | |||
4912 | void omapdss_dsi_set_pixel_format(struct omap_dss_device *dssdev, | ||
4913 | enum omap_dss_dsi_pixel_format fmt) | ||
4914 | { | 4297 | { |
4915 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4298 | *fifo_high = fifo_size - burst_size; |
4916 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4299 | *fifo_low = fifo_size - burst_size * 2; |
4917 | |||
4918 | mutex_lock(&dsi->lock); | ||
4919 | |||
4920 | dsi->pix_fmt = fmt; | ||
4921 | |||
4922 | mutex_unlock(&dsi->lock); | ||
4923 | } | 4300 | } |
4924 | EXPORT_SYMBOL(omapdss_dsi_set_pixel_format); | ||
4925 | 4301 | ||
4926 | void omapdss_dsi_set_operation_mode(struct omap_dss_device *dssdev, | 4302 | int dsi_init_display(struct omap_dss_device *dssdev) |
4927 | enum omap_dss_dsi_mode mode) | ||
4928 | { | 4303 | { |
4929 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 4304 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
4930 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4305 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
4931 | 4306 | int dsi_module = dsi_get_dsidev_id(dsidev); | |
4932 | mutex_lock(&dsi->lock); | ||
4933 | |||
4934 | dsi->mode = mode; | ||
4935 | |||
4936 | mutex_unlock(&dsi->lock); | ||
4937 | } | ||
4938 | EXPORT_SYMBOL(omapdss_dsi_set_operation_mode); | ||
4939 | |||
4940 | void omapdss_dsi_set_videomode_timings(struct omap_dss_device *dssdev, | ||
4941 | struct omap_dss_dsi_videomode_timings *timings) | ||
4942 | { | ||
4943 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
4944 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4945 | |||
4946 | mutex_lock(&dsi->lock); | ||
4947 | |||
4948 | dsi->vm_timings = *timings; | ||
4949 | |||
4950 | mutex_unlock(&dsi->lock); | ||
4951 | } | ||
4952 | EXPORT_SYMBOL(omapdss_dsi_set_videomode_timings); | ||
4953 | |||
4954 | static int __init dsi_init_display(struct omap_dss_device *dssdev) | ||
4955 | { | ||
4956 | struct platform_device *dsidev = | ||
4957 | dsi_get_dsidev_from_id(dssdev->phy.dsi.module); | ||
4958 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
4959 | 4307 | ||
4960 | DSSDBG("DSI init\n"); | 4308 | DSSDBG("DSI init\n"); |
4961 | 4309 | ||
4310 | /* XXX these should be figured out dynamically */ | ||
4311 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE | | ||
4312 | OMAP_DSS_DISPLAY_CAP_TEAR_ELIM; | ||
4313 | |||
4962 | if (dsi->vdds_dsi_reg == NULL) { | 4314 | if (dsi->vdds_dsi_reg == NULL) { |
4963 | struct regulator *vdds_dsi; | 4315 | struct regulator *vdds_dsi; |
4964 | 4316 | ||
4965 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); | 4317 | vdds_dsi = regulator_get(&dsi->pdev->dev, "vdds_dsi"); |
4966 | 4318 | ||
4967 | /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */ | ||
4968 | if (IS_ERR(vdds_dsi)) | ||
4969 | vdds_dsi = regulator_get(&dsi->pdev->dev, "VCXIO"); | ||
4970 | |||
4971 | if (IS_ERR(vdds_dsi)) { | 4319 | if (IS_ERR(vdds_dsi)) { |
4972 | DSSERR("can't get VDDS_DSI regulator\n"); | 4320 | DSSERR("can't get VDDS_DSI regulator\n"); |
4973 | return PTR_ERR(vdds_dsi); | 4321 | return PTR_ERR(vdds_dsi); |
@@ -4976,6 +4324,12 @@ static int __init dsi_init_display(struct omap_dss_device *dssdev) | |||
4976 | dsi->vdds_dsi_reg = vdds_dsi; | 4324 | dsi->vdds_dsi_reg = vdds_dsi; |
4977 | } | 4325 | } |
4978 | 4326 | ||
4327 | if (dsi_get_num_data_lanes_dssdev(dssdev) > dsi->num_data_lanes) { | ||
4328 | DSSERR("DSI%d can't support more than %d data lanes\n", | ||
4329 | dsi_module + 1, dsi->num_data_lanes); | ||
4330 | return -EINVAL; | ||
4331 | } | ||
4332 | |||
4979 | return 0; | 4333 | return 0; |
4980 | } | 4334 | } |
4981 | 4335 | ||
@@ -5081,7 +4435,10 @@ static int dsi_get_clocks(struct platform_device *dsidev) | |||
5081 | 4435 | ||
5082 | dsi->dss_clk = clk; | 4436 | dsi->dss_clk = clk; |
5083 | 4437 | ||
5084 | clk = clk_get(&dsidev->dev, "sys_clk"); | 4438 | if (cpu_is_omap34xx() || cpu_is_omap3630()) |
4439 | clk = clk_get(&dsidev->dev, "dss2_alwon_fck"); | ||
4440 | else | ||
4441 | clk = clk_get(&dsidev->dev, "sys_clk"); | ||
5085 | if (IS_ERR(clk)) { | 4442 | if (IS_ERR(clk)) { |
5086 | DSSERR("can't get sys_clk\n"); | 4443 | DSSERR("can't get sys_clk\n"); |
5087 | clk_put(dsi->dss_clk); | 4444 | clk_put(dsi->dss_clk); |
@@ -5104,118 +4461,30 @@ static void dsi_put_clocks(struct platform_device *dsidev) | |||
5104 | clk_put(dsi->sys_clk); | 4461 | clk_put(dsi->sys_clk); |
5105 | } | 4462 | } |
5106 | 4463 | ||
5107 | static struct omap_dss_device * __init dsi_find_dssdev(struct platform_device *pdev) | ||
5108 | { | ||
5109 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
5110 | struct dsi_data *dsi = dsi_get_dsidrv_data(pdev); | ||
5111 | const char *def_disp_name = omapdss_get_default_display_name(); | ||
5112 | struct omap_dss_device *def_dssdev; | ||
5113 | int i; | ||
5114 | |||
5115 | def_dssdev = NULL; | ||
5116 | |||
5117 | for (i = 0; i < pdata->num_devices; ++i) { | ||
5118 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
5119 | |||
5120 | if (dssdev->type != OMAP_DISPLAY_TYPE_DSI) | ||
5121 | continue; | ||
5122 | |||
5123 | if (dssdev->phy.dsi.module != dsi->module_id) | ||
5124 | continue; | ||
5125 | |||
5126 | if (def_dssdev == NULL) | ||
5127 | def_dssdev = dssdev; | ||
5128 | |||
5129 | if (def_disp_name != NULL && | ||
5130 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
5131 | def_dssdev = dssdev; | ||
5132 | break; | ||
5133 | } | ||
5134 | } | ||
5135 | |||
5136 | return def_dssdev; | ||
5137 | } | ||
5138 | |||
5139 | static void __init dsi_probe_pdata(struct platform_device *dsidev) | ||
5140 | { | ||
5141 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5142 | struct omap_dss_device *plat_dssdev; | ||
5143 | struct omap_dss_device *dssdev; | ||
5144 | int r; | ||
5145 | |||
5146 | plat_dssdev = dsi_find_dssdev(dsidev); | ||
5147 | |||
5148 | if (!plat_dssdev) | ||
5149 | return; | ||
5150 | |||
5151 | dssdev = dss_alloc_and_init_device(&dsidev->dev); | ||
5152 | if (!dssdev) | ||
5153 | return; | ||
5154 | |||
5155 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
5156 | |||
5157 | r = dsi_init_display(dssdev); | ||
5158 | if (r) { | ||
5159 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
5160 | dss_put_device(dssdev); | ||
5161 | return; | ||
5162 | } | ||
5163 | |||
5164 | r = omapdss_output_set_device(&dsi->output, dssdev); | ||
5165 | if (r) { | ||
5166 | DSSERR("failed to connect output to new device: %s\n", | ||
5167 | dssdev->name); | ||
5168 | dss_put_device(dssdev); | ||
5169 | return; | ||
5170 | } | ||
5171 | |||
5172 | r = dss_add_device(dssdev); | ||
5173 | if (r) { | ||
5174 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
5175 | omapdss_output_unset_device(&dsi->output); | ||
5176 | dss_put_device(dssdev); | ||
5177 | return; | ||
5178 | } | ||
5179 | } | ||
5180 | |||
5181 | static void __init dsi_init_output(struct platform_device *dsidev) | ||
5182 | { | ||
5183 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5184 | struct omap_dss_output *out = &dsi->output; | ||
5185 | |||
5186 | out->pdev = dsidev; | ||
5187 | out->id = dsi->module_id == 0 ? | ||
5188 | OMAP_DSS_OUTPUT_DSI1 : OMAP_DSS_OUTPUT_DSI2; | ||
5189 | |||
5190 | out->type = OMAP_DISPLAY_TYPE_DSI; | ||
5191 | |||
5192 | dss_register_output(out); | ||
5193 | } | ||
5194 | |||
5195 | static void __exit dsi_uninit_output(struct platform_device *dsidev) | ||
5196 | { | ||
5197 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
5198 | struct omap_dss_output *out = &dsi->output; | ||
5199 | |||
5200 | dss_unregister_output(out); | ||
5201 | } | ||
5202 | |||
5203 | /* DSI1 HW IP initialisation */ | 4464 | /* DSI1 HW IP initialisation */ |
5204 | static int __init omap_dsihw_probe(struct platform_device *dsidev) | 4465 | static int omap_dsi1hw_probe(struct platform_device *dsidev) |
5205 | { | 4466 | { |
4467 | struct omap_display_platform_data *dss_plat_data; | ||
4468 | struct omap_dss_board_info *board_info; | ||
5206 | u32 rev; | 4469 | u32 rev; |
5207 | int r, i; | 4470 | int r, i, dsi_module = dsi_get_dsidev_id(dsidev); |
5208 | struct resource *dsi_mem; | 4471 | struct resource *dsi_mem; |
5209 | struct dsi_data *dsi; | 4472 | struct dsi_data *dsi; |
5210 | 4473 | ||
5211 | dsi = devm_kzalloc(&dsidev->dev, sizeof(*dsi), GFP_KERNEL); | 4474 | dsi = kzalloc(sizeof(*dsi), GFP_KERNEL); |
5212 | if (!dsi) | 4475 | if (!dsi) { |
5213 | return -ENOMEM; | 4476 | r = -ENOMEM; |
4477 | goto err_alloc; | ||
4478 | } | ||
5214 | 4479 | ||
5215 | dsi->module_id = dsidev->id; | ||
5216 | dsi->pdev = dsidev; | 4480 | dsi->pdev = dsidev; |
4481 | dsi_pdev_map[dsi_module] = dsidev; | ||
5217 | dev_set_drvdata(&dsidev->dev, dsi); | 4482 | dev_set_drvdata(&dsidev->dev, dsi); |
5218 | 4483 | ||
4484 | dss_plat_data = dsidev->dev.platform_data; | ||
4485 | board_info = dss_plat_data->board_data; | ||
4486 | dsi->dsi_mux_pads = board_info->dsi_mux_pads; | ||
4487 | |||
5219 | spin_lock_init(&dsi->irq_lock); | 4488 | spin_lock_init(&dsi->irq_lock); |
5220 | spin_lock_init(&dsi->errors_lock); | 4489 | spin_lock_init(&dsi->errors_lock); |
5221 | dsi->errors = 0; | 4490 | dsi->errors = 0; |
@@ -5228,8 +4497,14 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) | |||
5228 | mutex_init(&dsi->lock); | 4497 | mutex_init(&dsi->lock); |
5229 | sema_init(&dsi->bus_lock, 1); | 4498 | sema_init(&dsi->bus_lock, 1); |
5230 | 4499 | ||
5231 | INIT_DEFERRABLE_WORK(&dsi->framedone_timeout_work, | 4500 | r = dsi_get_clocks(dsidev); |
5232 | dsi_framedone_timeout_work_callback); | 4501 | if (r) |
4502 | goto err_get_clk; | ||
4503 | |||
4504 | pm_runtime_enable(&dsidev->dev); | ||
4505 | |||
4506 | INIT_DELAYED_WORK_DEFERRABLE(&dsi->framedone_timeout_work, | ||
4507 | dsi_framedone_timeout_work_callback); | ||
5233 | 4508 | ||
5234 | #ifdef DSI_CATCH_MISSING_TE | 4509 | #ifdef DSI_CATCH_MISSING_TE |
5235 | init_timer(&dsi->te_timer); | 4510 | init_timer(&dsi->te_timer); |
@@ -5239,95 +4514,70 @@ static int __init omap_dsihw_probe(struct platform_device *dsidev) | |||
5239 | dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0); | 4514 | dsi_mem = platform_get_resource(dsi->pdev, IORESOURCE_MEM, 0); |
5240 | if (!dsi_mem) { | 4515 | if (!dsi_mem) { |
5241 | DSSERR("can't get IORESOURCE_MEM DSI\n"); | 4516 | DSSERR("can't get IORESOURCE_MEM DSI\n"); |
5242 | return -EINVAL; | 4517 | r = -EINVAL; |
4518 | goto err_ioremap; | ||
5243 | } | 4519 | } |
5244 | 4520 | dsi->base = ioremap(dsi_mem->start, resource_size(dsi_mem)); | |
5245 | dsi->base = devm_ioremap(&dsidev->dev, dsi_mem->start, | ||
5246 | resource_size(dsi_mem)); | ||
5247 | if (!dsi->base) { | 4521 | if (!dsi->base) { |
5248 | DSSERR("can't ioremap DSI\n"); | 4522 | DSSERR("can't ioremap DSI\n"); |
5249 | return -ENOMEM; | 4523 | r = -ENOMEM; |
4524 | goto err_ioremap; | ||
5250 | } | 4525 | } |
5251 | |||
5252 | dsi->irq = platform_get_irq(dsi->pdev, 0); | 4526 | dsi->irq = platform_get_irq(dsi->pdev, 0); |
5253 | if (dsi->irq < 0) { | 4527 | if (dsi->irq < 0) { |
5254 | DSSERR("platform_get_irq failed\n"); | 4528 | DSSERR("platform_get_irq failed\n"); |
5255 | return -ENODEV; | 4529 | r = -ENODEV; |
4530 | goto err_get_irq; | ||
5256 | } | 4531 | } |
5257 | 4532 | ||
5258 | r = devm_request_irq(&dsidev->dev, dsi->irq, omap_dsi_irq_handler, | 4533 | r = request_irq(dsi->irq, omap_dsi_irq_handler, IRQF_SHARED, |
5259 | IRQF_SHARED, dev_name(&dsidev->dev), dsi->pdev); | 4534 | dev_name(&dsidev->dev), dsi->pdev); |
5260 | if (r < 0) { | 4535 | if (r < 0) { |
5261 | DSSERR("request_irq failed\n"); | 4536 | DSSERR("request_irq failed\n"); |
5262 | return r; | 4537 | goto err_get_irq; |
5263 | } | 4538 | } |
5264 | 4539 | ||
5265 | /* DSI VCs initialization */ | 4540 | /* DSI VCs initialization */ |
5266 | for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { | 4541 | for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) { |
5267 | dsi->vc[i].source = DSI_VC_SOURCE_L4; | 4542 | dsi->vc[i].mode = DSI_VC_MODE_L4; |
5268 | dsi->vc[i].dssdev = NULL; | 4543 | dsi->vc[i].dssdev = NULL; |
5269 | dsi->vc[i].vc_id = 0; | 4544 | dsi->vc[i].vc_id = 0; |
5270 | } | 4545 | } |
5271 | 4546 | ||
5272 | dsi_calc_clock_param_ranges(dsidev); | 4547 | dsi_calc_clock_param_ranges(dsidev); |
5273 | 4548 | ||
5274 | r = dsi_get_clocks(dsidev); | ||
5275 | if (r) | ||
5276 | return r; | ||
5277 | |||
5278 | pm_runtime_enable(&dsidev->dev); | ||
5279 | |||
5280 | r = dsi_runtime_get(dsidev); | 4549 | r = dsi_runtime_get(dsidev); |
5281 | if (r) | 4550 | if (r) |
5282 | goto err_runtime_get; | 4551 | goto err_get_dsi; |
5283 | 4552 | ||
5284 | rev = dsi_read_reg(dsidev, DSI_REVISION); | 4553 | rev = dsi_read_reg(dsidev, DSI_REVISION); |
5285 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", | 4554 | dev_dbg(&dsidev->dev, "OMAP DSI rev %d.%d\n", |
5286 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 4555 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
5287 | 4556 | ||
5288 | /* DSI on OMAP3 doesn't have register DSI_GNQ, set number | 4557 | dsi->num_data_lanes = dsi_get_num_data_lanes(dsidev); |
5289 | * of data to 3 by default */ | ||
5290 | if (dss_has_feature(FEAT_DSI_GNQ)) | ||
5291 | /* NB_DATA_LANES */ | ||
5292 | dsi->num_lanes_supported = 1 + REG_GET(dsidev, DSI_GNQ, 11, 9); | ||
5293 | else | ||
5294 | dsi->num_lanes_supported = 3; | ||
5295 | |||
5296 | dsi_init_output(dsidev); | ||
5297 | |||
5298 | dsi_probe_pdata(dsidev); | ||
5299 | 4558 | ||
5300 | dsi_runtime_put(dsidev); | 4559 | dsi_runtime_put(dsidev); |
5301 | 4560 | ||
5302 | if (dsi->module_id == 0) | ||
5303 | dss_debugfs_create_file("dsi1_regs", dsi1_dump_regs); | ||
5304 | else if (dsi->module_id == 1) | ||
5305 | dss_debugfs_create_file("dsi2_regs", dsi2_dump_regs); | ||
5306 | |||
5307 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | ||
5308 | if (dsi->module_id == 0) | ||
5309 | dss_debugfs_create_file("dsi1_irqs", dsi1_dump_irqs); | ||
5310 | else if (dsi->module_id == 1) | ||
5311 | dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs); | ||
5312 | #endif | ||
5313 | return 0; | 4561 | return 0; |
5314 | 4562 | ||
5315 | err_runtime_get: | 4563 | err_get_dsi: |
4564 | free_irq(dsi->irq, dsi->pdev); | ||
4565 | err_get_irq: | ||
4566 | iounmap(dsi->base); | ||
4567 | err_ioremap: | ||
5316 | pm_runtime_disable(&dsidev->dev); | 4568 | pm_runtime_disable(&dsidev->dev); |
5317 | dsi_put_clocks(dsidev); | 4569 | err_get_clk: |
4570 | kfree(dsi); | ||
4571 | err_alloc: | ||
5318 | return r; | 4572 | return r; |
5319 | } | 4573 | } |
5320 | 4574 | ||
5321 | static int __exit omap_dsihw_remove(struct platform_device *dsidev) | 4575 | static int omap_dsi1hw_remove(struct platform_device *dsidev) |
5322 | { | 4576 | { |
5323 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | 4577 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); |
5324 | 4578 | ||
5325 | WARN_ON(dsi->scp_clk_refcount > 0); | 4579 | WARN_ON(dsi->scp_clk_refcount > 0); |
5326 | 4580 | ||
5327 | dss_unregister_child_devices(&dsidev->dev); | ||
5328 | |||
5329 | dsi_uninit_output(dsidev); | ||
5330 | |||
5331 | pm_runtime_disable(&dsidev->dev); | 4581 | pm_runtime_disable(&dsidev->dev); |
5332 | 4582 | ||
5333 | dsi_put_clocks(dsidev); | 4583 | dsi_put_clocks(dsidev); |
@@ -5342,25 +4592,47 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev) | |||
5342 | dsi->vdds_dsi_reg = NULL; | 4592 | dsi->vdds_dsi_reg = NULL; |
5343 | } | 4593 | } |
5344 | 4594 | ||
4595 | free_irq(dsi->irq, dsi->pdev); | ||
4596 | iounmap(dsi->base); | ||
4597 | |||
4598 | kfree(dsi); | ||
4599 | |||
5345 | return 0; | 4600 | return 0; |
5346 | } | 4601 | } |
5347 | 4602 | ||
5348 | static int dsi_runtime_suspend(struct device *dev) | 4603 | static int dsi_runtime_suspend(struct device *dev) |
5349 | { | 4604 | { |
4605 | struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); | ||
4606 | |||
4607 | clk_disable(dsi->dss_clk); | ||
4608 | |||
5350 | dispc_runtime_put(); | 4609 | dispc_runtime_put(); |
4610 | dss_runtime_put(); | ||
5351 | 4611 | ||
5352 | return 0; | 4612 | return 0; |
5353 | } | 4613 | } |
5354 | 4614 | ||
5355 | static int dsi_runtime_resume(struct device *dev) | 4615 | static int dsi_runtime_resume(struct device *dev) |
5356 | { | 4616 | { |
4617 | struct dsi_data *dsi = dsi_get_dsidrv_data(to_platform_device(dev)); | ||
5357 | int r; | 4618 | int r; |
5358 | 4619 | ||
4620 | r = dss_runtime_get(); | ||
4621 | if (r) | ||
4622 | goto err_get_dss; | ||
4623 | |||
5359 | r = dispc_runtime_get(); | 4624 | r = dispc_runtime_get(); |
5360 | if (r) | 4625 | if (r) |
5361 | return r; | 4626 | goto err_get_dispc; |
4627 | |||
4628 | clk_enable(dsi->dss_clk); | ||
5362 | 4629 | ||
5363 | return 0; | 4630 | return 0; |
4631 | |||
4632 | err_get_dispc: | ||
4633 | dss_runtime_put(); | ||
4634 | err_get_dss: | ||
4635 | return r; | ||
5364 | } | 4636 | } |
5365 | 4637 | ||
5366 | static const struct dev_pm_ops dsi_pm_ops = { | 4638 | static const struct dev_pm_ops dsi_pm_ops = { |
@@ -5368,21 +4640,22 @@ static const struct dev_pm_ops dsi_pm_ops = { | |||
5368 | .runtime_resume = dsi_runtime_resume, | 4640 | .runtime_resume = dsi_runtime_resume, |
5369 | }; | 4641 | }; |
5370 | 4642 | ||
5371 | static struct platform_driver omap_dsihw_driver = { | 4643 | static struct platform_driver omap_dsi1hw_driver = { |
5372 | .remove = __exit_p(omap_dsihw_remove), | 4644 | .probe = omap_dsi1hw_probe, |
4645 | .remove = omap_dsi1hw_remove, | ||
5373 | .driver = { | 4646 | .driver = { |
5374 | .name = "omapdss_dsi", | 4647 | .name = "omapdss_dsi1", |
5375 | .owner = THIS_MODULE, | 4648 | .owner = THIS_MODULE, |
5376 | .pm = &dsi_pm_ops, | 4649 | .pm = &dsi_pm_ops, |
5377 | }, | 4650 | }, |
5378 | }; | 4651 | }; |
5379 | 4652 | ||
5380 | int __init dsi_init_platform_driver(void) | 4653 | int dsi_init_platform_driver(void) |
5381 | { | 4654 | { |
5382 | return platform_driver_probe(&omap_dsihw_driver, omap_dsihw_probe); | 4655 | return platform_driver_register(&omap_dsi1hw_driver); |
5383 | } | 4656 | } |
5384 | 4657 | ||
5385 | void __exit dsi_uninit_platform_driver(void) | 4658 | void dsi_uninit_platform_driver(void) |
5386 | { | 4659 | { |
5387 | platform_driver_unregister(&omap_dsihw_driver); | 4660 | return platform_driver_unregister(&omap_dsi1hw_driver); |
5388 | } | 4661 | } |
diff --git a/drivers/video/omap2/dss/dss.c b/drivers/video/omap2/dss/dss.c index 054c2a22b3f..0f9c3a6457a 100644 --- a/drivers/video/omap2/dss/dss.c +++ b/drivers/video/omap2/dss/dss.c | |||
@@ -24,18 +24,15 @@ | |||
24 | 24 | ||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/export.h> | ||
28 | #include <linux/err.h> | 27 | #include <linux/err.h> |
29 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
30 | #include <linux/seq_file.h> | 29 | #include <linux/seq_file.h> |
31 | #include <linux/clk.h> | 30 | #include <linux/clk.h> |
32 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
33 | #include <linux/pm_runtime.h> | 32 | #include <linux/pm_runtime.h> |
34 | #include <linux/gfp.h> | ||
35 | #include <linux/sizes.h> | ||
36 | 33 | ||
37 | #include <video/omapdss.h> | 34 | #include <video/omapdss.h> |
38 | 35 | #include <plat/clock.h> | |
39 | #include "dss.h" | 36 | #include "dss.h" |
40 | #include "dss_features.h" | 37 | #include "dss_features.h" |
41 | 38 | ||
@@ -61,23 +58,12 @@ struct dss_reg { | |||
61 | #define REG_FLD_MOD(idx, val, start, end) \ | 58 | #define REG_FLD_MOD(idx, val, start, end) \ |
62 | dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) | 59 | dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end)) |
63 | 60 | ||
64 | static int dss_runtime_get(void); | ||
65 | static void dss_runtime_put(void); | ||
66 | |||
67 | struct dss_features { | ||
68 | u8 fck_div_max; | ||
69 | u8 dss_fck_multiplier; | ||
70 | const char *clk_name; | ||
71 | int (*dpi_select_source)(enum omap_channel channel); | ||
72 | }; | ||
73 | |||
74 | static struct { | 61 | static struct { |
75 | struct platform_device *pdev; | 62 | struct platform_device *pdev; |
76 | void __iomem *base; | 63 | void __iomem *base; |
77 | 64 | ||
78 | struct clk *dpll4_m4_ck; | 65 | struct clk *dpll4_m4_ck; |
79 | struct clk *dss_clk; | 66 | struct clk *dss_clk; |
80 | unsigned long dss_clk_rate; | ||
81 | 67 | ||
82 | unsigned long cache_req_pck; | 68 | unsigned long cache_req_pck; |
83 | unsigned long cache_prate; | 69 | unsigned long cache_prate; |
@@ -90,16 +76,12 @@ static struct { | |||
90 | 76 | ||
91 | bool ctx_valid; | 77 | bool ctx_valid; |
92 | u32 ctx[DSS_SZ_REGS / sizeof(u32)]; | 78 | u32 ctx[DSS_SZ_REGS / sizeof(u32)]; |
93 | |||
94 | const struct dss_features *feat; | ||
95 | } dss; | 79 | } dss; |
96 | 80 | ||
97 | static const char * const dss_generic_clk_source_names[] = { | 81 | static const char * const dss_generic_clk_source_names[] = { |
98 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", | 82 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DSI_PLL_HSDIV_DISPC", |
99 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", | 83 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DSI_PLL_HSDIV_DSI", |
100 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", | 84 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_FCK", |
101 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DSI_PLL2_HSDIV_DISPC", | ||
102 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DSI_PLL2_HSDIV_DSI", | ||
103 | }; | 85 | }; |
104 | 86 | ||
105 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) | 87 | static inline void dss_write_reg(const struct dss_reg idx, u32 val) |
@@ -155,22 +137,7 @@ static void dss_restore_context(void) | |||
155 | #undef SR | 137 | #undef SR |
156 | #undef RR | 138 | #undef RR |
157 | 139 | ||
158 | int dss_get_ctx_loss_count(void) | 140 | void dss_sdi_init(u8 datapairs) |
159 | { | ||
160 | struct omap_dss_board_info *board_data = dss.pdev->dev.platform_data; | ||
161 | int cnt; | ||
162 | |||
163 | if (!board_data->get_context_loss_count) | ||
164 | return -ENOENT; | ||
165 | |||
166 | cnt = board_data->get_context_loss_count(&dss.pdev->dev); | ||
167 | |||
168 | WARN_ONCE(cnt < 0, "get_context_loss_count failed: %d\n", cnt); | ||
169 | |||
170 | return cnt; | ||
171 | } | ||
172 | |||
173 | void dss_sdi_init(int datapairs) | ||
174 | { | 141 | { |
175 | u32 l; | 142 | u32 l; |
176 | 143 | ||
@@ -262,6 +229,7 @@ const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src) | |||
262 | return dss_generic_clk_source_names[clk_src]; | 229 | return dss_generic_clk_source_names[clk_src]; |
263 | } | 230 | } |
264 | 231 | ||
232 | |||
265 | void dss_dump_clocks(struct seq_file *s) | 233 | void dss_dump_clocks(struct seq_file *s) |
266 | { | 234 | { |
267 | unsigned long dpll4_ck_rate; | 235 | unsigned long dpll4_ck_rate; |
@@ -284,10 +252,18 @@ void dss_dump_clocks(struct seq_file *s) | |||
284 | 252 | ||
285 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); | 253 | seq_printf(s, "dpll4_ck %lu\n", dpll4_ck_rate); |
286 | 254 | ||
287 | seq_printf(s, "%s (%s) = %lu / %lu * %d = %lu\n", | 255 | if (cpu_is_omap3630() || cpu_is_omap44xx()) |
288 | fclk_name, fclk_real_name, dpll4_ck_rate, | 256 | seq_printf(s, "%s (%s) = %lu / %lu = %lu\n", |
289 | dpll4_ck_rate / dpll4_m4_ck_rate, | 257 | fclk_name, fclk_real_name, |
290 | dss.feat->dss_fck_multiplier, fclk_rate); | 258 | dpll4_ck_rate, |
259 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
260 | fclk_rate); | ||
261 | else | ||
262 | seq_printf(s, "%s (%s) = %lu / %lu * 2 = %lu\n", | ||
263 | fclk_name, fclk_real_name, | ||
264 | dpll4_ck_rate, | ||
265 | dpll4_ck_rate / dpll4_m4_ck_rate, | ||
266 | fclk_rate); | ||
291 | } else { | 267 | } else { |
292 | seq_printf(s, "%s (%s) = %lu\n", | 268 | seq_printf(s, "%s (%s) = %lu\n", |
293 | fclk_name, fclk_real_name, | 269 | fclk_name, fclk_real_name, |
@@ -297,7 +273,7 @@ void dss_dump_clocks(struct seq_file *s) | |||
297 | dss_runtime_put(); | 273 | dss_runtime_put(); |
298 | } | 274 | } |
299 | 275 | ||
300 | static void dss_dump_regs(struct seq_file *s) | 276 | void dss_dump_regs(struct seq_file *s) |
301 | { | 277 | { |
302 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) | 278 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, dss_read_reg(r)) |
303 | 279 | ||
@@ -320,7 +296,7 @@ static void dss_dump_regs(struct seq_file *s) | |||
320 | #undef DUMPREG | 296 | #undef DUMPREG |
321 | } | 297 | } |
322 | 298 | ||
323 | static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | 299 | void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) |
324 | { | 300 | { |
325 | struct platform_device *dsidev; | 301 | struct platform_device *dsidev; |
326 | int b; | 302 | int b; |
@@ -342,7 +318,6 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src) | |||
342 | break; | 318 | break; |
343 | default: | 319 | default: |
344 | BUG(); | 320 | BUG(); |
345 | return; | ||
346 | } | 321 | } |
347 | 322 | ||
348 | dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); | 323 | dss_feat_get_reg_field(FEAT_REG_DISPC_CLK_SWITCH, &start, &end); |
@@ -356,7 +331,7 @@ void dss_select_dsi_clk_source(int dsi_module, | |||
356 | enum omap_dss_clk_source clk_src) | 331 | enum omap_dss_clk_source clk_src) |
357 | { | 332 | { |
358 | struct platform_device *dsidev; | 333 | struct platform_device *dsidev; |
359 | int b, pos; | 334 | int b; |
360 | 335 | ||
361 | switch (clk_src) { | 336 | switch (clk_src) { |
362 | case OMAP_DSS_CLK_SRC_FCK: | 337 | case OMAP_DSS_CLK_SRC_FCK: |
@@ -376,11 +351,9 @@ void dss_select_dsi_clk_source(int dsi_module, | |||
376 | break; | 351 | break; |
377 | default: | 352 | default: |
378 | BUG(); | 353 | BUG(); |
379 | return; | ||
380 | } | 354 | } |
381 | 355 | ||
382 | pos = dsi_module == 0 ? 1 : 10; | 356 | REG_FLD_MOD(DSS_CONTROL, b, 1, 1); /* DSI_CLK_SWITCH */ |
383 | REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* DSIx_CLK_SWITCH */ | ||
384 | 357 | ||
385 | dss.dsi_clk_source[dsi_module] = clk_src; | 358 | dss.dsi_clk_source[dsi_module] = clk_src; |
386 | } | 359 | } |
@@ -391,10 +364,8 @@ void dss_select_lcd_clk_source(enum omap_channel channel, | |||
391 | struct platform_device *dsidev; | 364 | struct platform_device *dsidev; |
392 | int b, ix, pos; | 365 | int b, ix, pos; |
393 | 366 | ||
394 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) { | 367 | if (!dss_has_feature(FEAT_LCD_CLK_SRC)) |
395 | dss_select_dispc_clk_source(clk_src); | ||
396 | return; | 368 | return; |
397 | } | ||
398 | 369 | ||
399 | switch (clk_src) { | 370 | switch (clk_src) { |
400 | case OMAP_DSS_CLK_SRC_FCK: | 371 | case OMAP_DSS_CLK_SRC_FCK: |
@@ -407,23 +378,19 @@ void dss_select_lcd_clk_source(enum omap_channel channel, | |||
407 | dsi_wait_pll_hsdiv_dispc_active(dsidev); | 378 | dsi_wait_pll_hsdiv_dispc_active(dsidev); |
408 | break; | 379 | break; |
409 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: | 380 | case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC: |
410 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 && | 381 | BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2); |
411 | channel != OMAP_DSS_CHANNEL_LCD3); | ||
412 | b = 1; | 382 | b = 1; |
413 | dsidev = dsi_get_dsidev_from_id(1); | 383 | dsidev = dsi_get_dsidev_from_id(1); |
414 | dsi_wait_pll_hsdiv_dispc_active(dsidev); | 384 | dsi_wait_pll_hsdiv_dispc_active(dsidev); |
415 | break; | 385 | break; |
416 | default: | 386 | default: |
417 | BUG(); | 387 | BUG(); |
418 | return; | ||
419 | } | 388 | } |
420 | 389 | ||
421 | pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : | 390 | pos = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 12; |
422 | (channel == OMAP_DSS_CHANNEL_LCD2 ? 12 : 19); | ||
423 | REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */ | 391 | REG_FLD_MOD(DSS_CONTROL, b, pos, pos); /* LCDx_CLK_SWITCH */ |
424 | 392 | ||
425 | ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : | 393 | ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; |
426 | (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2); | ||
427 | dss.lcd_clk_source[ix] = clk_src; | 394 | dss.lcd_clk_source[ix] = clk_src; |
428 | } | 395 | } |
429 | 396 | ||
@@ -440,8 +407,7 @@ enum omap_dss_clk_source dss_get_dsi_clk_source(int dsi_module) | |||
440 | enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) | 407 | enum omap_dss_clk_source dss_get_lcd_clk_source(enum omap_channel channel) |
441 | { | 408 | { |
442 | if (dss_has_feature(FEAT_LCD_CLK_SRC)) { | 409 | if (dss_has_feature(FEAT_LCD_CLK_SRC)) { |
443 | int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : | 410 | int ix = channel == OMAP_DSS_CHANNEL_LCD ? 0 : 1; |
444 | (channel == OMAP_DSS_CHANNEL_LCD2 ? 1 : 2); | ||
445 | return dss.lcd_clk_source[ix]; | 411 | return dss.lcd_clk_source[ix]; |
446 | } else { | 412 | } else { |
447 | /* LCD_CLK source is the same as DISPC_FCLK source for | 413 | /* LCD_CLK source is the same as DISPC_FCLK source for |
@@ -455,15 +421,17 @@ int dss_calc_clock_rates(struct dss_clock_info *cinfo) | |||
455 | { | 421 | { |
456 | if (dss.dpll4_m4_ck) { | 422 | if (dss.dpll4_m4_ck) { |
457 | unsigned long prate; | 423 | unsigned long prate; |
424 | u16 fck_div_max = 16; | ||
458 | 425 | ||
459 | if (cinfo->fck_div > dss.feat->fck_div_max || | 426 | if (cpu_is_omap3630() || cpu_is_omap44xx()) |
460 | cinfo->fck_div == 0) | 427 | fck_div_max = 32; |
428 | |||
429 | if (cinfo->fck_div > fck_div_max || cinfo->fck_div == 0) | ||
461 | return -EINVAL; | 430 | return -EINVAL; |
462 | 431 | ||
463 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | 432 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); |
464 | 433 | ||
465 | cinfo->fck = prate / cinfo->fck_div * | 434 | cinfo->fck = prate / cinfo->fck_div; |
466 | dss.feat->dss_fck_multiplier; | ||
467 | } else { | 435 | } else { |
468 | if (cinfo->fck_div != 0) | 436 | if (cinfo->fck_div != 0) |
469 | return -EINVAL; | 437 | return -EINVAL; |
@@ -490,11 +458,27 @@ int dss_set_clock_div(struct dss_clock_info *cinfo) | |||
490 | return -EINVAL; | 458 | return -EINVAL; |
491 | } | 459 | } |
492 | 460 | ||
493 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | 461 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); |
462 | |||
463 | return 0; | ||
464 | } | ||
494 | 465 | ||
495 | WARN_ONCE(dss.dss_clk_rate != cinfo->fck, "clk rate mismatch"); | 466 | int dss_get_clock_div(struct dss_clock_info *cinfo) |
467 | { | ||
468 | cinfo->fck = clk_get_rate(dss.dss_clk); | ||
496 | 469 | ||
497 | DSSDBG("fck = %ld (%d)\n", cinfo->fck, cinfo->fck_div); | 470 | if (dss.dpll4_m4_ck) { |
471 | unsigned long prate; | ||
472 | |||
473 | prate = clk_get_rate(clk_get_parent(dss.dpll4_m4_ck)); | ||
474 | |||
475 | if (cpu_is_omap3630() || cpu_is_omap44xx()) | ||
476 | cinfo->fck_div = prate / (cinfo->fck); | ||
477 | else | ||
478 | cinfo->fck_div = prate / (cinfo->fck / 2); | ||
479 | } else { | ||
480 | cinfo->fck_div = 0; | ||
481 | } | ||
498 | 482 | ||
499 | return 0; | 483 | return 0; |
500 | } | 484 | } |
@@ -507,42 +491,8 @@ unsigned long dss_get_dpll4_rate(void) | |||
507 | return 0; | 491 | return 0; |
508 | } | 492 | } |
509 | 493 | ||
510 | unsigned long dss_get_dispc_clk_rate(void) | 494 | int dss_calc_clock_div(bool is_tft, unsigned long req_pck, |
511 | { | 495 | struct dss_clock_info *dss_cinfo, |
512 | return dss.dss_clk_rate; | ||
513 | } | ||
514 | |||
515 | static int dss_setup_default_clock(void) | ||
516 | { | ||
517 | unsigned long max_dss_fck, prate; | ||
518 | unsigned fck_div; | ||
519 | struct dss_clock_info dss_cinfo = { 0 }; | ||
520 | int r; | ||
521 | |||
522 | if (dss.dpll4_m4_ck == NULL) | ||
523 | return 0; | ||
524 | |||
525 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | ||
526 | |||
527 | prate = dss_get_dpll4_rate(); | ||
528 | |||
529 | fck_div = DIV_ROUND_UP(prate * dss.feat->dss_fck_multiplier, | ||
530 | max_dss_fck); | ||
531 | |||
532 | dss_cinfo.fck_div = fck_div; | ||
533 | |||
534 | r = dss_calc_clock_rates(&dss_cinfo); | ||
535 | if (r) | ||
536 | return r; | ||
537 | |||
538 | r = dss_set_clock_div(&dss_cinfo); | ||
539 | if (r) | ||
540 | return r; | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | ||
546 | struct dispc_clock_info *dispc_cinfo) | 496 | struct dispc_clock_info *dispc_cinfo) |
547 | { | 497 | { |
548 | unsigned long prate; | 498 | unsigned long prate; |
@@ -551,7 +501,7 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | |||
551 | 501 | ||
552 | unsigned long fck, max_dss_fck; | 502 | unsigned long fck, max_dss_fck; |
553 | 503 | ||
554 | u16 fck_div; | 504 | u16 fck_div, fck_div_max = 16; |
555 | 505 | ||
556 | int match = 0; | 506 | int match = 0; |
557 | int min_fck_per_pck; | 507 | int min_fck_per_pck; |
@@ -561,8 +511,9 @@ int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | |||
561 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); | 511 | max_dss_fck = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK); |
562 | 512 | ||
563 | fck = clk_get_rate(dss.dss_clk); | 513 | fck = clk_get_rate(dss.dss_clk); |
564 | if (req_pck == dss.cache_req_pck && prate == dss.cache_prate && | 514 | if (req_pck == dss.cache_req_pck && |
565 | dss.cache_dss_cinfo.fck == fck) { | 515 | ((cpu_is_omap34xx() && prate == dss.cache_prate) || |
516 | dss.cache_dss_cinfo.fck == fck)) { | ||
566 | DSSDBG("dispc clock info found from cache.\n"); | 517 | DSSDBG("dispc clock info found from cache.\n"); |
567 | *dss_cinfo = dss.cache_dss_cinfo; | 518 | *dss_cinfo = dss.cache_dss_cinfo; |
568 | *dispc_cinfo = dss.cache_dispc_cinfo; | 519 | *dispc_cinfo = dss.cache_dispc_cinfo; |
@@ -589,7 +540,7 @@ retry: | |||
589 | fck = clk_get_rate(dss.dss_clk); | 540 | fck = clk_get_rate(dss.dss_clk); |
590 | fck_div = 1; | 541 | fck_div = 1; |
591 | 542 | ||
592 | dispc_find_clk_divs(req_pck, fck, &cur_dispc); | 543 | dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); |
593 | match = 1; | 544 | match = 1; |
594 | 545 | ||
595 | best_dss.fck = fck; | 546 | best_dss.fck = fck; |
@@ -599,10 +550,16 @@ retry: | |||
599 | 550 | ||
600 | goto found; | 551 | goto found; |
601 | } else { | 552 | } else { |
602 | for (fck_div = dss.feat->fck_div_max; fck_div > 0; --fck_div) { | 553 | if (cpu_is_omap3630() || cpu_is_omap44xx()) |
554 | fck_div_max = 32; | ||
555 | |||
556 | for (fck_div = fck_div_max; fck_div > 0; --fck_div) { | ||
603 | struct dispc_clock_info cur_dispc; | 557 | struct dispc_clock_info cur_dispc; |
604 | 558 | ||
605 | fck = prate / fck_div * dss.feat->dss_fck_multiplier; | 559 | if (fck_div_max == 32) |
560 | fck = prate / fck_div; | ||
561 | else | ||
562 | fck = prate / fck_div * 2; | ||
606 | 563 | ||
607 | if (fck > max_dss_fck) | 564 | if (fck > max_dss_fck) |
608 | continue; | 565 | continue; |
@@ -613,7 +570,7 @@ retry: | |||
613 | 570 | ||
614 | match = 1; | 571 | match = 1; |
615 | 572 | ||
616 | dispc_find_clk_divs(req_pck, fck, &cur_dispc); | 573 | dispc_find_clk_divs(is_tft, req_pck, fck, &cur_dispc); |
617 | 574 | ||
618 | if (abs(cur_dispc.pck - req_pck) < | 575 | if (abs(cur_dispc.pck - req_pck) < |
619 | abs(best_dispc.pck - req_pck)) { | 576 | abs(best_dispc.pck - req_pck)) { |
@@ -677,91 +634,9 @@ void dss_set_dac_pwrdn_bgz(bool enable) | |||
677 | REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ | 634 | REG_FLD_MOD(DSS_CONTROL, enable, 5, 5); /* DAC Power-Down Control */ |
678 | } | 635 | } |
679 | 636 | ||
680 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select src) | 637 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select hdmi) |
681 | { | 638 | { |
682 | enum omap_display_type dp; | 639 | REG_FLD_MOD(DSS_CONTROL, hdmi, 15, 15); /* VENC_HDMI_SWITCH */ |
683 | dp = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); | ||
684 | |||
685 | /* Complain about invalid selections */ | ||
686 | WARN_ON((src == DSS_VENC_TV_CLK) && !(dp & OMAP_DISPLAY_TYPE_VENC)); | ||
687 | WARN_ON((src == DSS_HDMI_M_PCLK) && !(dp & OMAP_DISPLAY_TYPE_HDMI)); | ||
688 | |||
689 | /* Select only if we have options */ | ||
690 | if ((dp & OMAP_DISPLAY_TYPE_VENC) && (dp & OMAP_DISPLAY_TYPE_HDMI)) | ||
691 | REG_FLD_MOD(DSS_CONTROL, src, 15, 15); /* VENC_HDMI_SWITCH */ | ||
692 | } | ||
693 | |||
694 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void) | ||
695 | { | ||
696 | enum omap_display_type displays; | ||
697 | |||
698 | displays = dss_feat_get_supported_displays(OMAP_DSS_CHANNEL_DIGIT); | ||
699 | if ((displays & OMAP_DISPLAY_TYPE_HDMI) == 0) | ||
700 | return DSS_VENC_TV_CLK; | ||
701 | |||
702 | if ((displays & OMAP_DISPLAY_TYPE_VENC) == 0) | ||
703 | return DSS_HDMI_M_PCLK; | ||
704 | |||
705 | return REG_GET(DSS_CONTROL, 15, 15); | ||
706 | } | ||
707 | |||
708 | static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel) | ||
709 | { | ||
710 | if (channel != OMAP_DSS_CHANNEL_LCD) | ||
711 | return -EINVAL; | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int dss_dpi_select_source_omap4(enum omap_channel channel) | ||
717 | { | ||
718 | int val; | ||
719 | |||
720 | switch (channel) { | ||
721 | case OMAP_DSS_CHANNEL_LCD2: | ||
722 | val = 0; | ||
723 | break; | ||
724 | case OMAP_DSS_CHANNEL_DIGIT: | ||
725 | val = 1; | ||
726 | break; | ||
727 | default: | ||
728 | return -EINVAL; | ||
729 | } | ||
730 | |||
731 | REG_FLD_MOD(DSS_CONTROL, val, 17, 17); | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | static int dss_dpi_select_source_omap5(enum omap_channel channel) | ||
737 | { | ||
738 | int val; | ||
739 | |||
740 | switch (channel) { | ||
741 | case OMAP_DSS_CHANNEL_LCD: | ||
742 | val = 1; | ||
743 | break; | ||
744 | case OMAP_DSS_CHANNEL_LCD2: | ||
745 | val = 2; | ||
746 | break; | ||
747 | case OMAP_DSS_CHANNEL_LCD3: | ||
748 | val = 3; | ||
749 | break; | ||
750 | case OMAP_DSS_CHANNEL_DIGIT: | ||
751 | val = 0; | ||
752 | break; | ||
753 | default: | ||
754 | return -EINVAL; | ||
755 | } | ||
756 | |||
757 | REG_FLD_MOD(DSS_CONTROL, val, 17, 16); | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | int dss_dpi_select_source(enum omap_channel channel) | ||
763 | { | ||
764 | return dss.feat->dpi_select_source(channel); | ||
765 | } | 640 | } |
766 | 641 | ||
767 | static int dss_get_clocks(void) | 642 | static int dss_get_clocks(void) |
@@ -778,14 +653,21 @@ static int dss_get_clocks(void) | |||
778 | 653 | ||
779 | dss.dss_clk = clk; | 654 | dss.dss_clk = clk; |
780 | 655 | ||
781 | if (dss.feat->clk_name) { | 656 | if (cpu_is_omap34xx()) { |
782 | clk = clk_get(NULL, dss.feat->clk_name); | 657 | clk = clk_get(NULL, "dpll4_m4_ck"); |
783 | if (IS_ERR(clk)) { | 658 | if (IS_ERR(clk)) { |
784 | DSSERR("Failed to get %s\n", dss.feat->clk_name); | 659 | DSSERR("Failed to get dpll4_m4_ck\n"); |
785 | r = PTR_ERR(clk); | 660 | r = PTR_ERR(clk); |
786 | goto err; | 661 | goto err; |
787 | } | 662 | } |
788 | } else { | 663 | } else if (cpu_is_omap44xx()) { |
664 | clk = clk_get(NULL, "dpll_per_m5x2_ck"); | ||
665 | if (IS_ERR(clk)) { | ||
666 | DSSERR("Failed to get dpll_per_m5x2_ck\n"); | ||
667 | r = PTR_ERR(clk); | ||
668 | goto err; | ||
669 | } | ||
670 | } else { /* omap24xx */ | ||
789 | clk = NULL; | 671 | clk = NULL; |
790 | } | 672 | } |
791 | 673 | ||
@@ -809,7 +691,12 @@ static void dss_put_clocks(void) | |||
809 | clk_put(dss.dss_clk); | 691 | clk_put(dss.dss_clk); |
810 | } | 692 | } |
811 | 693 | ||
812 | static int dss_runtime_get(void) | 694 | struct clk *dss_get_ick(void) |
695 | { | ||
696 | return clk_get(&dss.pdev->dev, "ick"); | ||
697 | } | ||
698 | |||
699 | int dss_runtime_get(void) | ||
813 | { | 700 | { |
814 | int r; | 701 | int r; |
815 | 702 | ||
@@ -820,18 +707,18 @@ static int dss_runtime_get(void) | |||
820 | return r < 0 ? r : 0; | 707 | return r < 0 ? r : 0; |
821 | } | 708 | } |
822 | 709 | ||
823 | static void dss_runtime_put(void) | 710 | void dss_runtime_put(void) |
824 | { | 711 | { |
825 | int r; | 712 | int r; |
826 | 713 | ||
827 | DSSDBG("dss_runtime_put\n"); | 714 | DSSDBG("dss_runtime_put\n"); |
828 | 715 | ||
829 | r = pm_runtime_put_sync(&dss.pdev->dev); | 716 | r = pm_runtime_put(&dss.pdev->dev); |
830 | WARN_ON(r < 0 && r != -ENOSYS && r != -EBUSY); | 717 | WARN_ON(r < 0); |
831 | } | 718 | } |
832 | 719 | ||
833 | /* DEBUGFS */ | 720 | /* DEBUGFS */ |
834 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) | 721 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) |
835 | void dss_debug_dump_clocks(struct seq_file *s) | 722 | void dss_debug_dump_clocks(struct seq_file *s) |
836 | { | 723 | { |
837 | dss_dump_clocks(s); | 724 | dss_dump_clocks(s); |
@@ -842,89 +729,8 @@ void dss_debug_dump_clocks(struct seq_file *s) | |||
842 | } | 729 | } |
843 | #endif | 730 | #endif |
844 | 731 | ||
845 | static const struct dss_features omap24xx_dss_feats __initconst = { | ||
846 | .fck_div_max = 16, | ||
847 | .dss_fck_multiplier = 2, | ||
848 | .clk_name = NULL, | ||
849 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
850 | }; | ||
851 | |||
852 | static const struct dss_features omap34xx_dss_feats __initconst = { | ||
853 | .fck_div_max = 16, | ||
854 | .dss_fck_multiplier = 2, | ||
855 | .clk_name = "dpll4_m4_ck", | ||
856 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
857 | }; | ||
858 | |||
859 | static const struct dss_features omap3630_dss_feats __initconst = { | ||
860 | .fck_div_max = 32, | ||
861 | .dss_fck_multiplier = 1, | ||
862 | .clk_name = "dpll4_m4_ck", | ||
863 | .dpi_select_source = &dss_dpi_select_source_omap2_omap3, | ||
864 | }; | ||
865 | |||
866 | static const struct dss_features omap44xx_dss_feats __initconst = { | ||
867 | .fck_div_max = 32, | ||
868 | .dss_fck_multiplier = 1, | ||
869 | .clk_name = "dpll_per_m5x2_ck", | ||
870 | .dpi_select_source = &dss_dpi_select_source_omap4, | ||
871 | }; | ||
872 | |||
873 | static const struct dss_features omap54xx_dss_feats __initconst = { | ||
874 | .fck_div_max = 64, | ||
875 | .dss_fck_multiplier = 1, | ||
876 | .clk_name = "dpll_per_h12x2_ck", | ||
877 | .dpi_select_source = &dss_dpi_select_source_omap5, | ||
878 | }; | ||
879 | |||
880 | static int __init dss_init_features(struct platform_device *pdev) | ||
881 | { | ||
882 | const struct dss_features *src; | ||
883 | struct dss_features *dst; | ||
884 | |||
885 | dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL); | ||
886 | if (!dst) { | ||
887 | dev_err(&pdev->dev, "Failed to allocate local DSS Features\n"); | ||
888 | return -ENOMEM; | ||
889 | } | ||
890 | |||
891 | switch (omapdss_get_version()) { | ||
892 | case OMAPDSS_VER_OMAP24xx: | ||
893 | src = &omap24xx_dss_feats; | ||
894 | break; | ||
895 | |||
896 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
897 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
898 | case OMAPDSS_VER_AM35xx: | ||
899 | src = &omap34xx_dss_feats; | ||
900 | break; | ||
901 | |||
902 | case OMAPDSS_VER_OMAP3630: | ||
903 | src = &omap3630_dss_feats; | ||
904 | break; | ||
905 | |||
906 | case OMAPDSS_VER_OMAP4430_ES1: | ||
907 | case OMAPDSS_VER_OMAP4430_ES2: | ||
908 | case OMAPDSS_VER_OMAP4: | ||
909 | src = &omap44xx_dss_feats; | ||
910 | break; | ||
911 | |||
912 | case OMAPDSS_VER_OMAP5: | ||
913 | src = &omap54xx_dss_feats; | ||
914 | break; | ||
915 | |||
916 | default: | ||
917 | return -ENODEV; | ||
918 | } | ||
919 | |||
920 | memcpy(dst, src, sizeof(*dst)); | ||
921 | dss.feat = dst; | ||
922 | |||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | /* DSS HW IP initialisation */ | 732 | /* DSS HW IP initialisation */ |
927 | static int __init omap_dsshw_probe(struct platform_device *pdev) | 733 | static int omap_dsshw_probe(struct platform_device *pdev) |
928 | { | 734 | { |
929 | struct resource *dss_mem; | 735 | struct resource *dss_mem; |
930 | u32 rev; | 736 | u32 rev; |
@@ -932,30 +738,22 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
932 | 738 | ||
933 | dss.pdev = pdev; | 739 | dss.pdev = pdev; |
934 | 740 | ||
935 | r = dss_init_features(dss.pdev); | ||
936 | if (r) | ||
937 | return r; | ||
938 | |||
939 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); | 741 | dss_mem = platform_get_resource(dss.pdev, IORESOURCE_MEM, 0); |
940 | if (!dss_mem) { | 742 | if (!dss_mem) { |
941 | DSSERR("can't get IORESOURCE_MEM DSS\n"); | 743 | DSSERR("can't get IORESOURCE_MEM DSS\n"); |
942 | return -EINVAL; | 744 | r = -EINVAL; |
745 | goto err_ioremap; | ||
943 | } | 746 | } |
944 | 747 | dss.base = ioremap(dss_mem->start, resource_size(dss_mem)); | |
945 | dss.base = devm_ioremap(&pdev->dev, dss_mem->start, | ||
946 | resource_size(dss_mem)); | ||
947 | if (!dss.base) { | 748 | if (!dss.base) { |
948 | DSSERR("can't ioremap DSS\n"); | 749 | DSSERR("can't ioremap DSS\n"); |
949 | return -ENOMEM; | 750 | r = -ENOMEM; |
751 | goto err_ioremap; | ||
950 | } | 752 | } |
951 | 753 | ||
952 | r = dss_get_clocks(); | 754 | r = dss_get_clocks(); |
953 | if (r) | 755 | if (r) |
954 | return r; | 756 | goto err_clocks; |
955 | |||
956 | r = dss_setup_default_clock(); | ||
957 | if (r) | ||
958 | goto err_setup_clocks; | ||
959 | 757 | ||
960 | pm_runtime_enable(&pdev->dev); | 758 | pm_runtime_enable(&pdev->dev); |
961 | 759 | ||
@@ -963,13 +761,9 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
963 | if (r) | 761 | if (r) |
964 | goto err_runtime_get; | 762 | goto err_runtime_get; |
965 | 763 | ||
966 | dss.dss_clk_rate = clk_get_rate(dss.dss_clk); | ||
967 | |||
968 | /* Select DPLL */ | 764 | /* Select DPLL */ |
969 | REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); | 765 | REG_FLD_MOD(DSS_CONTROL, 0, 0, 0); |
970 | 766 | ||
971 | dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK); | ||
972 | |||
973 | #ifdef CONFIG_OMAP2_DSS_VENC | 767 | #ifdef CONFIG_OMAP2_DSS_VENC |
974 | REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ | 768 | REG_FLD_MOD(DSS_CONTROL, 1, 4, 4); /* venc dac demen */ |
975 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ | 769 | REG_FLD_MOD(DSS_CONTROL, 1, 3, 3); /* venc clock 4x enable */ |
@@ -981,25 +775,45 @@ static int __init omap_dsshw_probe(struct platform_device *pdev) | |||
981 | dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; | 775 | dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK; |
982 | dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; | 776 | dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK; |
983 | 777 | ||
778 | r = dpi_init(); | ||
779 | if (r) { | ||
780 | DSSERR("Failed to initialize DPI\n"); | ||
781 | goto err_dpi; | ||
782 | } | ||
783 | |||
784 | r = sdi_init(); | ||
785 | if (r) { | ||
786 | DSSERR("Failed to initialize SDI\n"); | ||
787 | goto err_sdi; | ||
788 | } | ||
789 | |||
984 | rev = dss_read_reg(DSS_REVISION); | 790 | rev = dss_read_reg(DSS_REVISION); |
985 | printk(KERN_INFO "OMAP DSS rev %d.%d\n", | 791 | printk(KERN_INFO "OMAP DSS rev %d.%d\n", |
986 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 792 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
987 | 793 | ||
988 | dss_runtime_put(); | 794 | dss_runtime_put(); |
989 | 795 | ||
990 | dss_debugfs_create_file("dss", dss_dump_regs); | ||
991 | |||
992 | return 0; | 796 | return 0; |
993 | 797 | err_sdi: | |
798 | dpi_exit(); | ||
799 | err_dpi: | ||
800 | dss_runtime_put(); | ||
994 | err_runtime_get: | 801 | err_runtime_get: |
995 | pm_runtime_disable(&pdev->dev); | 802 | pm_runtime_disable(&pdev->dev); |
996 | err_setup_clocks: | ||
997 | dss_put_clocks(); | 803 | dss_put_clocks(); |
804 | err_clocks: | ||
805 | iounmap(dss.base); | ||
806 | err_ioremap: | ||
998 | return r; | 807 | return r; |
999 | } | 808 | } |
1000 | 809 | ||
1001 | static int __exit omap_dsshw_remove(struct platform_device *pdev) | 810 | static int omap_dsshw_remove(struct platform_device *pdev) |
1002 | { | 811 | { |
812 | dpi_exit(); | ||
813 | sdi_exit(); | ||
814 | |||
815 | iounmap(dss.base); | ||
816 | |||
1003 | pm_runtime_disable(&pdev->dev); | 817 | pm_runtime_disable(&pdev->dev); |
1004 | 818 | ||
1005 | dss_put_clocks(); | 819 | dss_put_clocks(); |
@@ -1010,24 +824,13 @@ static int __exit omap_dsshw_remove(struct platform_device *pdev) | |||
1010 | static int dss_runtime_suspend(struct device *dev) | 824 | static int dss_runtime_suspend(struct device *dev) |
1011 | { | 825 | { |
1012 | dss_save_context(); | 826 | dss_save_context(); |
1013 | dss_set_min_bus_tput(dev, 0); | 827 | clk_disable(dss.dss_clk); |
1014 | return 0; | 828 | return 0; |
1015 | } | 829 | } |
1016 | 830 | ||
1017 | static int dss_runtime_resume(struct device *dev) | 831 | static int dss_runtime_resume(struct device *dev) |
1018 | { | 832 | { |
1019 | int r; | 833 | clk_enable(dss.dss_clk); |
1020 | /* | ||
1021 | * Set an arbitrarily high tput request to ensure OPP100. | ||
1022 | * What we should really do is to make a request to stay in OPP100, | ||
1023 | * without any tput requirements, but that is not currently possible | ||
1024 | * via the PM layer. | ||
1025 | */ | ||
1026 | |||
1027 | r = dss_set_min_bus_tput(dev, 1000000000); | ||
1028 | if (r) | ||
1029 | return r; | ||
1030 | |||
1031 | dss_restore_context(); | 834 | dss_restore_context(); |
1032 | return 0; | 835 | return 0; |
1033 | } | 836 | } |
@@ -1038,7 +841,8 @@ static const struct dev_pm_ops dss_pm_ops = { | |||
1038 | }; | 841 | }; |
1039 | 842 | ||
1040 | static struct platform_driver omap_dsshw_driver = { | 843 | static struct platform_driver omap_dsshw_driver = { |
1041 | .remove = __exit_p(omap_dsshw_remove), | 844 | .probe = omap_dsshw_probe, |
845 | .remove = omap_dsshw_remove, | ||
1042 | .driver = { | 846 | .driver = { |
1043 | .name = "omapdss_dss", | 847 | .name = "omapdss_dss", |
1044 | .owner = THIS_MODULE, | 848 | .owner = THIS_MODULE, |
@@ -1046,12 +850,12 @@ static struct platform_driver omap_dsshw_driver = { | |||
1046 | }, | 850 | }, |
1047 | }; | 851 | }; |
1048 | 852 | ||
1049 | int __init dss_init_platform_driver(void) | 853 | int dss_init_platform_driver(void) |
1050 | { | 854 | { |
1051 | return platform_driver_probe(&omap_dsshw_driver, omap_dsshw_probe); | 855 | return platform_driver_register(&omap_dsshw_driver); |
1052 | } | 856 | } |
1053 | 857 | ||
1054 | void dss_uninit_platform_driver(void) | 858 | void dss_uninit_platform_driver(void) |
1055 | { | 859 | { |
1056 | platform_driver_unregister(&omap_dsshw_driver); | 860 | return platform_driver_unregister(&omap_dsshw_driver); |
1057 | } | 861 | } |
diff --git a/drivers/video/omap2/dss/dss.h b/drivers/video/omap2/dss/dss.h index 610c8e563da..9c94b1152c2 100644 --- a/drivers/video/omap2/dss/dss.h +++ b/drivers/video/omap2/dss/dss.h | |||
@@ -23,20 +23,44 @@ | |||
23 | #ifndef __OMAP2_DSS_H | 23 | #ifndef __OMAP2_DSS_H |
24 | #define __OMAP2_DSS_H | 24 | #define __OMAP2_DSS_H |
25 | 25 | ||
26 | #include <linux/interrupt.h> | 26 | #ifdef CONFIG_OMAP2_DSS_DEBUG_SUPPORT |
27 | #define DEBUG | ||
28 | #endif | ||
27 | 29 | ||
28 | #ifdef pr_fmt | 30 | #ifdef DEBUG |
29 | #undef pr_fmt | 31 | extern unsigned int dss_debug; |
32 | #ifdef DSS_SUBSYS_NAME | ||
33 | #define DSSDBG(format, ...) \ | ||
34 | if (dss_debug) \ | ||
35 | printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME ": " format, \ | ||
36 | ## __VA_ARGS__) | ||
37 | #else | ||
38 | #define DSSDBG(format, ...) \ | ||
39 | if (dss_debug) \ | ||
40 | printk(KERN_DEBUG "omapdss: " format, ## __VA_ARGS__) | ||
30 | #endif | 41 | #endif |
31 | 42 | ||
32 | #ifdef DSS_SUBSYS_NAME | 43 | #ifdef DSS_SUBSYS_NAME |
33 | #define pr_fmt(fmt) DSS_SUBSYS_NAME ": " fmt | 44 | #define DSSDBGF(format, ...) \ |
45 | if (dss_debug) \ | ||
46 | printk(KERN_DEBUG "omapdss " DSS_SUBSYS_NAME \ | ||
47 | ": %s(" format ")\n", \ | ||
48 | __func__, \ | ||
49 | ## __VA_ARGS__) | ||
34 | #else | 50 | #else |
35 | #define pr_fmt(fmt) fmt | 51 | #define DSSDBGF(format, ...) \ |
52 | if (dss_debug) \ | ||
53 | printk(KERN_DEBUG "omapdss: " \ | ||
54 | ": %s(" format ")\n", \ | ||
55 | __func__, \ | ||
56 | ## __VA_ARGS__) | ||
57 | #endif | ||
58 | |||
59 | #else /* DEBUG */ | ||
60 | #define DSSDBG(format, ...) | ||
61 | #define DSSDBGF(format, ...) | ||
36 | #endif | 62 | #endif |
37 | 63 | ||
38 | #define DSSDBG(format, ...) \ | ||
39 | pr_debug(format, ## __VA_ARGS__) | ||
40 | 64 | ||
41 | #ifdef DSS_SUBSYS_NAME | 65 | #ifdef DSS_SUBSYS_NAME |
42 | #define DSSERR(format, ...) \ | 66 | #define DSSERR(format, ...) \ |
@@ -73,10 +97,10 @@ | |||
73 | #define FLD_MOD(orig, val, start, end) \ | 97 | #define FLD_MOD(orig, val, start, end) \ |
74 | (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) | 98 | (((orig) & ~FLD_MASK(start, end)) | FLD_VAL(val, start, end)) |
75 | 99 | ||
76 | enum dss_io_pad_mode { | 100 | enum omap_parallel_interface_mode { |
77 | DSS_IO_PAD_MODE_RESET, | 101 | OMAP_DSS_PARALLELMODE_BYPASS, /* MIPI DPI */ |
78 | DSS_IO_PAD_MODE_RFBI, | 102 | OMAP_DSS_PARALLELMODE_RFBI, /* MIPI DBI */ |
79 | DSS_IO_PAD_MODE_BYPASS, | 103 | OMAP_DSS_PARALLELMODE_DSI, |
80 | }; | 104 | }; |
81 | 105 | ||
82 | enum dss_hdmi_venc_clk_source_select { | 106 | enum dss_hdmi_venc_clk_source_select { |
@@ -84,22 +108,6 @@ enum dss_hdmi_venc_clk_source_select { | |||
84 | DSS_HDMI_M_PCLK = 1, | 108 | DSS_HDMI_M_PCLK = 1, |
85 | }; | 109 | }; |
86 | 110 | ||
87 | enum dss_dsi_content_type { | ||
88 | DSS_DSI_CONTENT_DCS, | ||
89 | DSS_DSI_CONTENT_GENERIC, | ||
90 | }; | ||
91 | |||
92 | enum dss_writeback_channel { | ||
93 | DSS_WB_LCD1_MGR = 0, | ||
94 | DSS_WB_LCD2_MGR = 1, | ||
95 | DSS_WB_TV_MGR = 2, | ||
96 | DSS_WB_OVL0 = 3, | ||
97 | DSS_WB_OVL1 = 4, | ||
98 | DSS_WB_OVL2 = 5, | ||
99 | DSS_WB_OVL3 = 6, | ||
100 | DSS_WB_LCD3_MGR = 7, | ||
101 | }; | ||
102 | |||
103 | struct dss_clock_info { | 111 | struct dss_clock_info { |
104 | /* rates that we get with dividers below */ | 112 | /* rates that we get with dividers below */ |
105 | unsigned long fck; | 113 | unsigned long fck; |
@@ -137,123 +145,86 @@ struct dsi_clock_info { | |||
137 | u16 regm_dsi; /* OMAP3: REGM4 | 145 | u16 regm_dsi; /* OMAP3: REGM4 |
138 | * OMAP4: REGM5 */ | 146 | * OMAP4: REGM5 */ |
139 | u16 lp_clk_div; | 147 | u16 lp_clk_div; |
140 | }; | ||
141 | 148 | ||
142 | struct reg_field { | 149 | u8 highfreq; |
143 | u16 reg; | 150 | bool use_sys_clk; |
144 | u8 high; | ||
145 | u8 low; | ||
146 | }; | 151 | }; |
147 | 152 | ||
148 | struct dss_lcd_mgr_config { | 153 | /* HDMI PLL structure */ |
149 | enum dss_io_pad_mode io_pad_mode; | 154 | struct hdmi_pll_info { |
150 | 155 | u16 regn; | |
151 | bool stallmode; | 156 | u16 regm; |
152 | bool fifohandcheck; | 157 | u32 regmf; |
153 | 158 | u16 regm2; | |
154 | struct dispc_clock_info clock_info; | 159 | u16 regsd; |
155 | 160 | u16 dcofreq; | |
156 | int video_port_width; | ||
157 | |||
158 | int lcden_sig_polarity; | ||
159 | }; | 161 | }; |
160 | 162 | ||
161 | struct seq_file; | 163 | struct seq_file; |
162 | struct platform_device; | 164 | struct platform_device; |
163 | 165 | ||
164 | /* core */ | 166 | /* core */ |
165 | struct platform_device *dss_get_core_pdev(void); | ||
166 | struct bus_type *dss_get_bus(void); | 167 | struct bus_type *dss_get_bus(void); |
167 | struct regulator *dss_get_vdds_dsi(void); | 168 | struct regulator *dss_get_vdds_dsi(void); |
168 | struct regulator *dss_get_vdds_sdi(void); | 169 | struct regulator *dss_get_vdds_sdi(void); |
169 | int dss_dsi_enable_pads(int dsi_id, unsigned lane_mask); | ||
170 | void dss_dsi_disable_pads(int dsi_id, unsigned lane_mask); | ||
171 | int dss_set_min_bus_tput(struct device *dev, unsigned long tput); | ||
172 | int dss_debugfs_create_file(const char *name, void (*write)(struct seq_file *)); | ||
173 | |||
174 | struct omap_dss_device *dss_alloc_and_init_device(struct device *parent); | ||
175 | int dss_add_device(struct omap_dss_device *dssdev); | ||
176 | void dss_unregister_device(struct omap_dss_device *dssdev); | ||
177 | void dss_unregister_child_devices(struct device *parent); | ||
178 | void dss_put_device(struct omap_dss_device *dssdev); | ||
179 | void dss_copy_device_pdata(struct omap_dss_device *dst, | ||
180 | const struct omap_dss_device *src); | ||
181 | |||
182 | /* output */ | ||
183 | void dss_register_output(struct omap_dss_output *out); | ||
184 | void dss_unregister_output(struct omap_dss_output *out); | ||
185 | 170 | ||
186 | /* display */ | 171 | /* display */ |
187 | int dss_suspend_all_devices(void); | 172 | int dss_suspend_all_devices(void); |
188 | int dss_resume_all_devices(void); | 173 | int dss_resume_all_devices(void); |
189 | void dss_disable_all_devices(void); | 174 | void dss_disable_all_devices(void); |
190 | 175 | ||
191 | int display_init_sysfs(struct platform_device *pdev, | 176 | void dss_init_device(struct platform_device *pdev, |
192 | struct omap_dss_device *dssdev); | 177 | struct omap_dss_device *dssdev); |
193 | void display_uninit_sysfs(struct platform_device *pdev, | 178 | void dss_uninit_device(struct platform_device *pdev, |
194 | struct omap_dss_device *dssdev); | 179 | struct omap_dss_device *dssdev); |
180 | bool dss_use_replication(struct omap_dss_device *dssdev, | ||
181 | enum omap_color_mode mode); | ||
182 | void default_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
183 | u32 fifo_size, u32 burst_size, | ||
184 | u32 *fifo_low, u32 *fifo_high); | ||
195 | 185 | ||
196 | /* manager */ | 186 | /* manager */ |
197 | int dss_init_overlay_managers(struct platform_device *pdev); | 187 | int dss_init_overlay_managers(struct platform_device *pdev); |
198 | void dss_uninit_overlay_managers(struct platform_device *pdev); | 188 | void dss_uninit_overlay_managers(struct platform_device *pdev); |
199 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, | 189 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl); |
200 | const struct omap_overlay_manager_info *info); | 190 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, |
201 | int dss_mgr_check_timings(struct omap_overlay_manager *mgr, | 191 | u16 *x, u16 *y, u16 *w, u16 *h, |
202 | const struct omap_video_timings *timings); | 192 | bool enlarge_update_area); |
203 | int dss_mgr_check(struct omap_overlay_manager *mgr, | 193 | void dss_start_update(struct omap_dss_device *dssdev); |
204 | struct omap_overlay_manager_info *info, | ||
205 | const struct omap_video_timings *mgr_timings, | ||
206 | const struct dss_lcd_mgr_config *config, | ||
207 | struct omap_overlay_info **overlay_infos); | ||
208 | |||
209 | static inline bool dss_mgr_is_lcd(enum omap_channel id) | ||
210 | { | ||
211 | if (id == OMAP_DSS_CHANNEL_LCD || id == OMAP_DSS_CHANNEL_LCD2 || | ||
212 | id == OMAP_DSS_CHANNEL_LCD3) | ||
213 | return true; | ||
214 | else | ||
215 | return false; | ||
216 | } | ||
217 | |||
218 | int dss_manager_kobj_init(struct omap_overlay_manager *mgr, | ||
219 | struct platform_device *pdev); | ||
220 | void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr); | ||
221 | 194 | ||
222 | /* overlay */ | 195 | /* overlay */ |
223 | void dss_init_overlays(struct platform_device *pdev); | 196 | void dss_init_overlays(struct platform_device *pdev); |
224 | void dss_uninit_overlays(struct platform_device *pdev); | 197 | void dss_uninit_overlays(struct platform_device *pdev); |
198 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev); | ||
225 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); | 199 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr); |
226 | int dss_ovl_simple_check(struct omap_overlay *ovl, | 200 | #ifdef L4_EXAMPLE |
227 | const struct omap_overlay_info *info); | 201 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr); |
228 | int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, | 202 | #endif |
229 | const struct omap_video_timings *mgr_timings); | 203 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force); |
230 | bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, | ||
231 | enum omap_color_mode mode); | ||
232 | int dss_overlay_kobj_init(struct omap_overlay *ovl, | ||
233 | struct platform_device *pdev); | ||
234 | void dss_overlay_kobj_uninit(struct omap_overlay *ovl); | ||
235 | 204 | ||
236 | /* DSS */ | 205 | /* DSS */ |
237 | int dss_init_platform_driver(void) __init; | 206 | int dss_init_platform_driver(void); |
238 | void dss_uninit_platform_driver(void); | 207 | void dss_uninit_platform_driver(void); |
239 | 208 | ||
240 | unsigned long dss_get_dispc_clk_rate(void); | 209 | int dss_runtime_get(void); |
241 | int dss_dpi_select_source(enum omap_channel channel); | 210 | void dss_runtime_put(void); |
211 | |||
212 | struct clk *dss_get_ick(void); | ||
213 | |||
242 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); | 214 | void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select); |
243 | enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void); | ||
244 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); | 215 | const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src); |
245 | void dss_dump_clocks(struct seq_file *s); | 216 | void dss_dump_clocks(struct seq_file *s); |
246 | 217 | ||
247 | #if defined(CONFIG_OMAP2_DSS_DEBUGFS) | 218 | void dss_dump_regs(struct seq_file *s); |
219 | #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_OMAP2_DSS_DEBUG_SUPPORT) | ||
248 | void dss_debug_dump_clocks(struct seq_file *s); | 220 | void dss_debug_dump_clocks(struct seq_file *s); |
249 | #endif | 221 | #endif |
250 | 222 | ||
251 | int dss_get_ctx_loss_count(void); | 223 | void dss_sdi_init(u8 datapairs); |
252 | |||
253 | void dss_sdi_init(int datapairs); | ||
254 | int dss_sdi_enable(void); | 224 | int dss_sdi_enable(void); |
255 | void dss_sdi_disable(void); | 225 | void dss_sdi_disable(void); |
256 | 226 | ||
227 | void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src); | ||
257 | void dss_select_dsi_clk_source(int dsi_module, | 228 | void dss_select_dsi_clk_source(int dsi_module, |
258 | enum omap_dss_clk_source clk_src); | 229 | enum omap_dss_clk_source clk_src); |
259 | void dss_select_lcd_clk_source(enum omap_channel channel, | 230 | void dss_select_lcd_clk_source(enum omap_channel channel, |
@@ -268,12 +239,25 @@ void dss_set_dac_pwrdn_bgz(bool enable); | |||
268 | unsigned long dss_get_dpll4_rate(void); | 239 | unsigned long dss_get_dpll4_rate(void); |
269 | int dss_calc_clock_rates(struct dss_clock_info *cinfo); | 240 | int dss_calc_clock_rates(struct dss_clock_info *cinfo); |
270 | int dss_set_clock_div(struct dss_clock_info *cinfo); | 241 | int dss_set_clock_div(struct dss_clock_info *cinfo); |
271 | int dss_calc_clock_div(unsigned long req_pck, struct dss_clock_info *dss_cinfo, | 242 | int dss_get_clock_div(struct dss_clock_info *cinfo); |
243 | int dss_calc_clock_div(bool is_tft, unsigned long req_pck, | ||
244 | struct dss_clock_info *dss_cinfo, | ||
272 | struct dispc_clock_info *dispc_cinfo); | 245 | struct dispc_clock_info *dispc_cinfo); |
273 | 246 | ||
274 | /* SDI */ | 247 | /* SDI */ |
275 | int sdi_init_platform_driver(void) __init; | 248 | #ifdef CONFIG_OMAP2_DSS_SDI |
276 | void sdi_uninit_platform_driver(void) __exit; | 249 | int sdi_init(void); |
250 | void sdi_exit(void); | ||
251 | int sdi_init_display(struct omap_dss_device *display); | ||
252 | #else | ||
253 | static inline int sdi_init(void) | ||
254 | { | ||
255 | return 0; | ||
256 | } | ||
257 | static inline void sdi_exit(void) | ||
258 | { | ||
259 | } | ||
260 | #endif | ||
277 | 261 | ||
278 | /* DSI */ | 262 | /* DSI */ |
279 | #ifdef CONFIG_OMAP2_DSS_DSI | 263 | #ifdef CONFIG_OMAP2_DSS_DSI |
@@ -281,42 +265,50 @@ void sdi_uninit_platform_driver(void) __exit; | |||
281 | struct dentry; | 265 | struct dentry; |
282 | struct file_operations; | 266 | struct file_operations; |
283 | 267 | ||
284 | int dsi_init_platform_driver(void) __init; | 268 | int dsi_init_platform_driver(void); |
285 | void dsi_uninit_platform_driver(void) __exit; | 269 | void dsi_uninit_platform_driver(void); |
286 | 270 | ||
287 | int dsi_runtime_get(struct platform_device *dsidev); | 271 | int dsi_runtime_get(struct platform_device *dsidev); |
288 | void dsi_runtime_put(struct platform_device *dsidev); | 272 | void dsi_runtime_put(struct platform_device *dsidev); |
289 | 273 | ||
290 | void dsi_dump_clocks(struct seq_file *s); | 274 | void dsi_dump_clocks(struct seq_file *s); |
275 | void dsi_create_debugfs_files_irq(struct dentry *debugfs_dir, | ||
276 | const struct file_operations *debug_fops); | ||
277 | void dsi_create_debugfs_files_reg(struct dentry *debugfs_dir, | ||
278 | const struct file_operations *debug_fops); | ||
291 | 279 | ||
280 | int dsi_init_display(struct omap_dss_device *display); | ||
292 | void dsi_irq_handler(void); | 281 | void dsi_irq_handler(void); |
293 | u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt); | ||
294 | |||
295 | unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); | 282 | unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev); |
296 | int dsi_pll_set_clock_div(struct platform_device *dsidev, | 283 | int dsi_pll_set_clock_div(struct platform_device *dsidev, |
297 | struct dsi_clock_info *cinfo); | 284 | struct dsi_clock_info *cinfo); |
298 | int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | 285 | int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, bool is_tft, |
299 | unsigned long req_pck, struct dsi_clock_info *cinfo, | 286 | unsigned long req_pck, struct dsi_clock_info *cinfo, |
300 | struct dispc_clock_info *dispc_cinfo); | 287 | struct dispc_clock_info *dispc_cinfo); |
301 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, | 288 | int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk, |
302 | bool enable_hsdiv); | 289 | bool enable_hsdiv); |
303 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); | 290 | void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes); |
291 | void dsi_get_overlay_fifo_thresholds(enum omap_plane plane, | ||
292 | u32 fifo_size, u32 burst_size, | ||
293 | u32 *fifo_low, u32 *fifo_high); | ||
304 | void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); | 294 | void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev); |
305 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); | 295 | void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev); |
306 | struct platform_device *dsi_get_dsidev_from_id(int module); | 296 | struct platform_device *dsi_get_dsidev_from_id(int module); |
307 | #else | 297 | #else |
308 | static inline int dsi_runtime_get(struct platform_device *dsidev) | 298 | static inline int dsi_init_platform_driver(void) |
309 | { | 299 | { |
310 | return 0; | 300 | return 0; |
311 | } | 301 | } |
312 | static inline void dsi_runtime_put(struct platform_device *dsidev) | 302 | static inline void dsi_uninit_platform_driver(void) |
313 | { | 303 | { |
314 | } | 304 | } |
315 | static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt) | 305 | static inline int dsi_runtime_get(struct platform_device *dsidev) |
316 | { | 306 | { |
317 | WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__); | ||
318 | return 0; | 307 | return 0; |
319 | } | 308 | } |
309 | static inline void dsi_runtime_put(struct platform_device *dsidev) | ||
310 | { | ||
311 | } | ||
320 | static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) | 312 | static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev) |
321 | { | 313 | { |
322 | WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); | 314 | WARN("%s: DSI not compiled in, returning rate as 0\n", __func__); |
@@ -329,7 +321,7 @@ static inline int dsi_pll_set_clock_div(struct platform_device *dsidev, | |||
329 | return -ENODEV; | 321 | return -ENODEV; |
330 | } | 322 | } |
331 | static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, | 323 | static inline int dsi_pll_calc_clock_div_pck(struct platform_device *dsidev, |
332 | unsigned long req_pck, | 324 | bool is_tft, unsigned long req_pck, |
333 | struct dsi_clock_info *dsi_cinfo, | 325 | struct dsi_clock_info *dsi_cinfo, |
334 | struct dispc_clock_info *dispc_cinfo) | 326 | struct dispc_clock_info *dispc_cinfo) |
335 | { | 327 | { |
@@ -354,122 +346,180 @@ static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev) | |||
354 | } | 346 | } |
355 | static inline struct platform_device *dsi_get_dsidev_from_id(int module) | 347 | static inline struct platform_device *dsi_get_dsidev_from_id(int module) |
356 | { | 348 | { |
349 | WARN("%s: DSI not compiled in, returning platform device as NULL\n", | ||
350 | __func__); | ||
357 | return NULL; | 351 | return NULL; |
358 | } | 352 | } |
359 | #endif | 353 | #endif |
360 | 354 | ||
361 | /* DPI */ | 355 | /* DPI */ |
362 | int dpi_init_platform_driver(void) __init; | 356 | #ifdef CONFIG_OMAP2_DSS_DPI |
363 | void dpi_uninit_platform_driver(void) __exit; | 357 | int dpi_init(void); |
358 | void dpi_exit(void); | ||
359 | int dpi_init_display(struct omap_dss_device *dssdev); | ||
360 | #else | ||
361 | static inline int dpi_init(void) | ||
362 | { | ||
363 | return 0; | ||
364 | } | ||
365 | static inline void dpi_exit(void) | ||
366 | { | ||
367 | } | ||
368 | #endif | ||
364 | 369 | ||
365 | /* DISPC */ | 370 | /* DISPC */ |
366 | int dispc_init_platform_driver(void) __init; | 371 | int dispc_init_platform_driver(void); |
367 | void dispc_uninit_platform_driver(void) __exit; | 372 | void dispc_uninit_platform_driver(void); |
368 | void dispc_dump_clocks(struct seq_file *s); | 373 | void dispc_dump_clocks(struct seq_file *s); |
374 | void dispc_dump_irqs(struct seq_file *s); | ||
375 | void dispc_dump_regs(struct seq_file *s); | ||
376 | void dispc_irq_handler(void); | ||
377 | void dispc_fake_vsync_irq(void); | ||
378 | |||
379 | int dispc_runtime_get(void); | ||
380 | void dispc_runtime_put(void); | ||
369 | 381 | ||
370 | void dispc_enable_sidle(void); | 382 | void dispc_enable_sidle(void); |
371 | void dispc_disable_sidle(void); | 383 | void dispc_disable_sidle(void); |
372 | 384 | ||
385 | void dispc_lcd_enable_signal_polarity(bool act_high); | ||
373 | void dispc_lcd_enable_signal(bool enable); | 386 | void dispc_lcd_enable_signal(bool enable); |
374 | void dispc_pck_free_enable(bool enable); | 387 | void dispc_pck_free_enable(bool enable); |
388 | void dispc_enable_fifohandcheck(enum omap_channel channel, bool enable); | ||
389 | |||
390 | void dispc_set_lcd_size(enum omap_channel channel, u16 width, u16 height); | ||
391 | void dispc_set_digit_size(u16 width, u16 height); | ||
392 | u32 dispc_get_plane_fifo_size(enum omap_plane plane); | ||
393 | void dispc_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | ||
375 | void dispc_enable_fifomerge(bool enable); | 394 | void dispc_enable_fifomerge(bool enable); |
395 | u32 dispc_get_burst_size(enum omap_plane plane); | ||
396 | void dispc_enable_cpr(enum omap_channel channel, bool enable); | ||
397 | void dispc_set_cpr_coef(enum omap_channel channel, | ||
398 | struct omap_dss_cpr_coefs *coefs); | ||
399 | |||
400 | void dispc_set_plane_ba0(enum omap_plane plane, u32 paddr); | ||
401 | void dispc_set_plane_ba1(enum omap_plane plane, u32 paddr); | ||
402 | void dispc_set_plane_pos(enum omap_plane plane, u16 x, u16 y); | ||
403 | void dispc_set_plane_size(enum omap_plane plane, u16 width, u16 height); | ||
404 | void dispc_set_channel_out(enum omap_plane plane, | ||
405 | enum omap_channel channel_out); | ||
406 | |||
376 | void dispc_enable_gamma_table(bool enable); | 407 | void dispc_enable_gamma_table(bool enable); |
408 | int dispc_setup_plane(enum omap_plane plane, | ||
409 | u32 paddr, u16 screen_width, | ||
410 | u16 pos_x, u16 pos_y, | ||
411 | u16 width, u16 height, | ||
412 | u16 out_width, u16 out_height, | ||
413 | enum omap_color_mode color_mode, | ||
414 | bool ilace, | ||
415 | enum omap_dss_rotation_type rotation_type, | ||
416 | u8 rotation, bool mirror, | ||
417 | u8 global_alpha, u8 pre_mult_alpha, | ||
418 | enum omap_channel channel, | ||
419 | u32 puv_addr); | ||
420 | |||
421 | bool dispc_go_busy(enum omap_channel channel); | ||
422 | void dispc_go(enum omap_channel channel); | ||
423 | void dispc_enable_channel(enum omap_channel channel, bool enable); | ||
424 | bool dispc_is_channel_enabled(enum omap_channel channel); | ||
425 | int dispc_enable_plane(enum omap_plane plane, bool enable); | ||
426 | void dispc_enable_replication(enum omap_plane plane, bool enable); | ||
427 | |||
428 | void dispc_set_parallel_interface_mode(enum omap_channel channel, | ||
429 | enum omap_parallel_interface_mode mode); | ||
430 | void dispc_set_tft_data_lines(enum omap_channel channel, u8 data_lines); | ||
431 | void dispc_set_lcd_display_type(enum omap_channel channel, | ||
432 | enum omap_lcd_display_type type); | ||
377 | void dispc_set_loadmode(enum omap_dss_load_mode mode); | 433 | void dispc_set_loadmode(enum omap_dss_load_mode mode); |
378 | 434 | ||
379 | bool dispc_mgr_timings_ok(enum omap_channel channel, | 435 | void dispc_set_default_color(enum omap_channel channel, u32 color); |
380 | const struct omap_video_timings *timings); | 436 | u32 dispc_get_default_color(enum omap_channel channel); |
437 | void dispc_set_trans_key(enum omap_channel ch, | ||
438 | enum omap_dss_trans_key_type type, | ||
439 | u32 trans_key); | ||
440 | void dispc_get_trans_key(enum omap_channel ch, | ||
441 | enum omap_dss_trans_key_type *type, | ||
442 | u32 *trans_key); | ||
443 | void dispc_enable_trans_key(enum omap_channel ch, bool enable); | ||
444 | void dispc_enable_alpha_blending(enum omap_channel ch, bool enable); | ||
445 | bool dispc_trans_key_enabled(enum omap_channel ch); | ||
446 | bool dispc_alpha_blending_enabled(enum omap_channel ch); | ||
447 | |||
448 | bool dispc_lcd_timings_ok(struct omap_video_timings *timings); | ||
449 | void dispc_set_lcd_timings(enum omap_channel channel, | ||
450 | struct omap_video_timings *timings); | ||
381 | unsigned long dispc_fclk_rate(void); | 451 | unsigned long dispc_fclk_rate(void); |
382 | void dispc_find_clk_divs(unsigned long req_pck, unsigned long fck, | 452 | unsigned long dispc_lclk_rate(enum omap_channel channel); |
453 | unsigned long dispc_pclk_rate(enum omap_channel channel); | ||
454 | void dispc_set_pol_freq(enum omap_channel channel, | ||
455 | enum omap_panel_config config, u8 acbi, u8 acb); | ||
456 | void dispc_find_clk_divs(bool is_tft, unsigned long req_pck, unsigned long fck, | ||
383 | struct dispc_clock_info *cinfo); | 457 | struct dispc_clock_info *cinfo); |
384 | int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, | 458 | int dispc_calc_clock_rates(unsigned long dispc_fclk_rate, |
385 | struct dispc_clock_info *cinfo); | 459 | struct dispc_clock_info *cinfo); |
386 | 460 | int dispc_set_clock_div(enum omap_channel channel, | |
387 | 461 | struct dispc_clock_info *cinfo); | |
388 | void dispc_ovl_set_fifo_threshold(enum omap_plane plane, u32 low, u32 high); | 462 | int dispc_get_clock_div(enum omap_channel channel, |
389 | void dispc_ovl_compute_fifo_thresholds(enum omap_plane plane, | ||
390 | u32 *fifo_low, u32 *fifo_high, bool use_fifomerge, | ||
391 | bool manual_update); | ||
392 | |||
393 | unsigned long dispc_mgr_lclk_rate(enum omap_channel channel); | ||
394 | unsigned long dispc_mgr_pclk_rate(enum omap_channel channel); | ||
395 | unsigned long dispc_core_clk_rate(void); | ||
396 | void dispc_mgr_set_clock_div(enum omap_channel channel, | ||
397 | const struct dispc_clock_info *cinfo); | ||
398 | int dispc_mgr_get_clock_div(enum omap_channel channel, | ||
399 | struct dispc_clock_info *cinfo); | 463 | struct dispc_clock_info *cinfo); |
400 | 464 | ||
401 | u32 dispc_wb_get_framedone_irq(void); | ||
402 | bool dispc_wb_go_busy(void); | ||
403 | void dispc_wb_go(void); | ||
404 | void dispc_wb_enable(bool enable); | ||
405 | bool dispc_wb_is_enabled(void); | ||
406 | void dispc_wb_set_channel_in(enum dss_writeback_channel channel); | ||
407 | int dispc_wb_setup(const struct omap_dss_writeback_info *wi, | ||
408 | bool mem_to_mem, const struct omap_video_timings *timings); | ||
409 | 465 | ||
410 | /* VENC */ | 466 | /* VENC */ |
411 | #ifdef CONFIG_OMAP2_DSS_VENC | 467 | #ifdef CONFIG_OMAP2_DSS_VENC |
412 | int venc_init_platform_driver(void) __init; | 468 | int venc_init_platform_driver(void); |
413 | void venc_uninit_platform_driver(void) __exit; | 469 | void venc_uninit_platform_driver(void); |
414 | unsigned long venc_get_pixel_clock(void); | 470 | void venc_dump_regs(struct seq_file *s); |
471 | int venc_init_display(struct omap_dss_device *display); | ||
415 | #else | 472 | #else |
416 | static inline unsigned long venc_get_pixel_clock(void) | 473 | static inline int venc_init_platform_driver(void) |
417 | { | 474 | { |
418 | WARN("%s: VENC not compiled in, returning pclk as 0\n", __func__); | ||
419 | return 0; | 475 | return 0; |
420 | } | 476 | } |
477 | static inline void venc_uninit_platform_driver(void) | ||
478 | { | ||
479 | } | ||
421 | #endif | 480 | #endif |
422 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev); | ||
423 | void omapdss_venc_display_disable(struct omap_dss_device *dssdev); | ||
424 | void omapdss_venc_set_timings(struct omap_dss_device *dssdev, | ||
425 | struct omap_video_timings *timings); | ||
426 | int omapdss_venc_check_timings(struct omap_dss_device *dssdev, | ||
427 | struct omap_video_timings *timings); | ||
428 | u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev); | ||
429 | int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss); | ||
430 | void omapdss_venc_set_type(struct omap_dss_device *dssdev, | ||
431 | enum omap_dss_venc_type type); | ||
432 | void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, | ||
433 | bool invert_polarity); | ||
434 | int venc_panel_init(void); | ||
435 | void venc_panel_exit(void); | ||
436 | 481 | ||
437 | /* HDMI */ | 482 | /* HDMI */ |
438 | #ifdef CONFIG_OMAP4_DSS_HDMI | 483 | #ifdef CONFIG_OMAP4_DSS_HDMI |
439 | int hdmi_init_platform_driver(void) __init; | 484 | int hdmi_init_platform_driver(void); |
440 | void hdmi_uninit_platform_driver(void) __exit; | 485 | void hdmi_uninit_platform_driver(void); |
441 | unsigned long hdmi_get_pixel_clock(void); | 486 | int hdmi_init_display(struct omap_dss_device *dssdev); |
442 | #else | 487 | #else |
443 | static inline unsigned long hdmi_get_pixel_clock(void) | 488 | static inline int hdmi_init_display(struct omap_dss_device *dssdev) |
444 | { | 489 | { |
445 | WARN("%s: HDMI not compiled in, returning pclk as 0\n", __func__); | ||
446 | return 0; | 490 | return 0; |
447 | } | 491 | } |
492 | static inline int hdmi_init_platform_driver(void) | ||
493 | { | ||
494 | return 0; | ||
495 | } | ||
496 | static inline void hdmi_uninit_platform_driver(void) | ||
497 | { | ||
498 | } | ||
448 | #endif | 499 | #endif |
449 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); | 500 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev); |
450 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); | 501 | void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev); |
451 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev); | 502 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev); |
452 | void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev); | ||
453 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, | ||
454 | struct omap_video_timings *timings); | ||
455 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 503 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
456 | struct omap_video_timings *timings); | 504 | struct omap_video_timings *timings); |
457 | int omapdss_hdmi_read_edid(u8 *buf, int len); | ||
458 | bool omapdss_hdmi_detect(void); | ||
459 | int hdmi_panel_init(void); | 505 | int hdmi_panel_init(void); |
460 | void hdmi_panel_exit(void); | 506 | void hdmi_panel_exit(void); |
461 | #ifdef CONFIG_OMAP4_DSS_HDMI_AUDIO | ||
462 | int hdmi_audio_enable(void); | ||
463 | void hdmi_audio_disable(void); | ||
464 | int hdmi_audio_start(void); | ||
465 | void hdmi_audio_stop(void); | ||
466 | bool hdmi_mode_has_audio(void); | ||
467 | int hdmi_audio_config(struct omap_dss_audio *audio); | ||
468 | #endif | ||
469 | 507 | ||
470 | /* RFBI */ | 508 | /* RFBI */ |
471 | int rfbi_init_platform_driver(void) __init; | 509 | #ifdef CONFIG_OMAP2_DSS_RFBI |
472 | void rfbi_uninit_platform_driver(void) __exit; | 510 | int rfbi_init_platform_driver(void); |
511 | void rfbi_uninit_platform_driver(void); | ||
512 | void rfbi_dump_regs(struct seq_file *s); | ||
513 | int rfbi_init_display(struct omap_dss_device *display); | ||
514 | #else | ||
515 | static inline int rfbi_init_platform_driver(void) | ||
516 | { | ||
517 | return 0; | ||
518 | } | ||
519 | static inline void rfbi_uninit_platform_driver(void) | ||
520 | { | ||
521 | } | ||
522 | #endif | ||
473 | 523 | ||
474 | 524 | ||
475 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS | 525 | #ifdef CONFIG_OMAP2_DSS_COLLECT_IRQ_STATS |
diff --git a/drivers/video/omap2/dss/dss_features.c b/drivers/video/omap2/dss/dss_features.c index 18688c12e30..b415c4ee621 100644 --- a/drivers/video/omap2/dss/dss_features.c +++ b/drivers/video/omap2/dss/dss_features.c | |||
@@ -18,12 +18,12 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/module.h> | ||
22 | #include <linux/types.h> | 21 | #include <linux/types.h> |
23 | #include <linux/err.h> | 22 | #include <linux/err.h> |
24 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
25 | 24 | ||
26 | #include <video/omapdss.h> | 25 | #include <video/omapdss.h> |
26 | #include <plat/cpu.h> | ||
27 | 27 | ||
28 | #include "dss.h" | 28 | #include "dss.h" |
29 | #include "dss_features.h" | 29 | #include "dss_features.h" |
@@ -41,21 +41,15 @@ struct omap_dss_features { | |||
41 | const struct dss_reg_field *reg_fields; | 41 | const struct dss_reg_field *reg_fields; |
42 | const int num_reg_fields; | 42 | const int num_reg_fields; |
43 | 43 | ||
44 | const enum dss_feat_id *features; | 44 | const u32 has_feature; |
45 | const int num_features; | ||
46 | 45 | ||
47 | const int num_mgrs; | 46 | const int num_mgrs; |
48 | const int num_ovls; | 47 | const int num_ovls; |
49 | const int num_wbs; | ||
50 | const enum omap_display_type *supported_displays; | 48 | const enum omap_display_type *supported_displays; |
51 | const enum omap_dss_output_id *supported_outputs; | ||
52 | const enum omap_color_mode *supported_color_modes; | 49 | const enum omap_color_mode *supported_color_modes; |
53 | const enum omap_overlay_caps *overlay_caps; | ||
54 | const char * const *clksrc_names; | 50 | const char * const *clksrc_names; |
55 | const struct dss_param_range *dss_params; | 51 | const struct dss_param_range *dss_params; |
56 | 52 | ||
57 | const enum omap_dss_rotation_type supported_rotation_types; | ||
58 | |||
59 | const u32 buffer_size_unit; | 53 | const u32 buffer_size_unit; |
60 | const u32 burst_size_unit; | 54 | const u32 burst_size_unit; |
61 | }; | 55 | }; |
@@ -108,21 +102,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = { | |||
108 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, | 102 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, |
109 | }; | 103 | }; |
110 | 104 | ||
111 | static const struct dss_reg_field omap5_dss_reg_fields[] = { | ||
112 | [FEAT_REG_FIRHINC] = { 12, 0 }, | ||
113 | [FEAT_REG_FIRVINC] = { 28, 16 }, | ||
114 | [FEAT_REG_FIFOLOWTHRESHOLD] = { 15, 0 }, | ||
115 | [FEAT_REG_FIFOHIGHTHRESHOLD] = { 31, 16 }, | ||
116 | [FEAT_REG_FIFOSIZE] = { 15, 0 }, | ||
117 | [FEAT_REG_HORIZONTALACCU] = { 10, 0 }, | ||
118 | [FEAT_REG_VERTICALACCU] = { 26, 16 }, | ||
119 | [FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 }, | ||
120 | [FEAT_REG_DSIPLL_REGN] = { 8, 1 }, | ||
121 | [FEAT_REG_DSIPLL_REGM] = { 20, 9 }, | ||
122 | [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 }, | ||
123 | [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 }, | ||
124 | }; | ||
125 | |||
126 | static const enum omap_display_type omap2_dss_supported_displays[] = { | 105 | static const enum omap_display_type omap2_dss_supported_displays[] = { |
127 | /* OMAP_DSS_CHANNEL_LCD */ | 106 | /* OMAP_DSS_CHANNEL_LCD */ |
128 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, | 107 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI, |
@@ -161,76 +140,6 @@ static const enum omap_display_type omap4_dss_supported_displays[] = { | |||
161 | OMAP_DISPLAY_TYPE_DSI, | 140 | OMAP_DISPLAY_TYPE_DSI, |
162 | }; | 141 | }; |
163 | 142 | ||
164 | static const enum omap_display_type omap5_dss_supported_displays[] = { | ||
165 | /* OMAP_DSS_CHANNEL_LCD */ | ||
166 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | | ||
167 | OMAP_DISPLAY_TYPE_DSI, | ||
168 | |||
169 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
170 | OMAP_DISPLAY_TYPE_HDMI | OMAP_DISPLAY_TYPE_DPI, | ||
171 | |||
172 | /* OMAP_DSS_CHANNEL_LCD2 */ | ||
173 | OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI | | ||
174 | OMAP_DISPLAY_TYPE_DSI, | ||
175 | }; | ||
176 | |||
177 | static const enum omap_dss_output_id omap2_dss_supported_outputs[] = { | ||
178 | /* OMAP_DSS_CHANNEL_LCD */ | ||
179 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI, | ||
180 | |||
181 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
182 | OMAP_DSS_OUTPUT_VENC, | ||
183 | }; | ||
184 | |||
185 | static const enum omap_dss_output_id omap3430_dss_supported_outputs[] = { | ||
186 | /* OMAP_DSS_CHANNEL_LCD */ | ||
187 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
188 | OMAP_DSS_OUTPUT_SDI | OMAP_DSS_OUTPUT_DSI1, | ||
189 | |||
190 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
191 | OMAP_DSS_OUTPUT_VENC, | ||
192 | }; | ||
193 | |||
194 | static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = { | ||
195 | /* OMAP_DSS_CHANNEL_LCD */ | ||
196 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
197 | OMAP_DSS_OUTPUT_DSI1, | ||
198 | |||
199 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
200 | OMAP_DSS_OUTPUT_VENC, | ||
201 | }; | ||
202 | |||
203 | static const enum omap_dss_output_id omap4_dss_supported_outputs[] = { | ||
204 | /* OMAP_DSS_CHANNEL_LCD */ | ||
205 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
206 | OMAP_DSS_OUTPUT_DSI1, | ||
207 | |||
208 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
209 | OMAP_DSS_OUTPUT_VENC | OMAP_DSS_OUTPUT_HDMI | | ||
210 | OMAP_DSS_OUTPUT_DPI, | ||
211 | |||
212 | /* OMAP_DSS_CHANNEL_LCD2 */ | ||
213 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
214 | OMAP_DSS_OUTPUT_DSI2, | ||
215 | }; | ||
216 | |||
217 | static const enum omap_dss_output_id omap5_dss_supported_outputs[] = { | ||
218 | /* OMAP_DSS_CHANNEL_LCD */ | ||
219 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
220 | OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2, | ||
221 | |||
222 | /* OMAP_DSS_CHANNEL_DIGIT */ | ||
223 | OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI, | ||
224 | |||
225 | /* OMAP_DSS_CHANNEL_LCD2 */ | ||
226 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
227 | OMAP_DSS_OUTPUT_DSI1, | ||
228 | |||
229 | /* OMAP_DSS_CHANNEL_LCD3 */ | ||
230 | OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI | | ||
231 | OMAP_DSS_OUTPUT_DSI2, | ||
232 | }; | ||
233 | |||
234 | static const enum omap_color_mode omap2_dss_supported_color_modes[] = { | 143 | static const enum omap_color_mode omap2_dss_supported_color_modes[] = { |
235 | /* OMAP_DSS_GFX */ | 144 | /* OMAP_DSS_GFX */ |
236 | OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | | 145 | OMAP_DSS_COLOR_CLUT1 | OMAP_DSS_COLOR_CLUT2 | |
@@ -279,8 +188,7 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { | |||
279 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | | 188 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB24U | |
280 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 | | 189 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_ARGB32 | |
281 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 | | 190 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_RGBX32 | |
282 | OMAP_DSS_COLOR_ARGB16_1555 | OMAP_DSS_COLOR_RGBX16 | | 191 | OMAP_DSS_COLOR_ARGB16_1555, |
283 | OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_XRGB16_1555, | ||
284 | 192 | ||
285 | /* OMAP_DSS_VIDEO1 */ | 193 | /* OMAP_DSS_VIDEO1 */ |
286 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | | 194 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | |
@@ -301,90 +209,6 @@ static const enum omap_color_mode omap4_dss_supported_color_modes[] = { | |||
301 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | | 209 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | |
302 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | | 210 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | |
303 | OMAP_DSS_COLOR_RGBX32, | 211 | OMAP_DSS_COLOR_RGBX32, |
304 | |||
305 | /* OMAP_DSS_VIDEO3 */ | ||
306 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | | ||
307 | OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | | ||
308 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | | ||
309 | OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | | ||
310 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | | ||
311 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | | ||
312 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | | ||
313 | OMAP_DSS_COLOR_RGBX32, | ||
314 | |||
315 | /* OMAP_DSS_WB */ | ||
316 | OMAP_DSS_COLOR_RGB16 | OMAP_DSS_COLOR_RGB12U | | ||
317 | OMAP_DSS_COLOR_YUV2 | OMAP_DSS_COLOR_ARGB16_1555 | | ||
318 | OMAP_DSS_COLOR_RGBA32 | OMAP_DSS_COLOR_NV12 | | ||
319 | OMAP_DSS_COLOR_RGBA16 | OMAP_DSS_COLOR_RGB24U | | ||
320 | OMAP_DSS_COLOR_RGB24P | OMAP_DSS_COLOR_UYVY | | ||
321 | OMAP_DSS_COLOR_ARGB16 | OMAP_DSS_COLOR_XRGB16_1555 | | ||
322 | OMAP_DSS_COLOR_ARGB32 | OMAP_DSS_COLOR_RGBX16 | | ||
323 | OMAP_DSS_COLOR_RGBX32, | ||
324 | }; | ||
325 | |||
326 | static const enum omap_overlay_caps omap2_dss_overlay_caps[] = { | ||
327 | /* OMAP_DSS_GFX */ | ||
328 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
329 | |||
330 | /* OMAP_DSS_VIDEO1 */ | ||
331 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | | ||
332 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
333 | |||
334 | /* OMAP_DSS_VIDEO2 */ | ||
335 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | | ||
336 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
337 | }; | ||
338 | |||
339 | static const enum omap_overlay_caps omap3430_dss_overlay_caps[] = { | ||
340 | /* OMAP_DSS_GFX */ | ||
341 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_POS | | ||
342 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
343 | |||
344 | /* OMAP_DSS_VIDEO1 */ | ||
345 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | | ||
346 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
347 | |||
348 | /* OMAP_DSS_VIDEO2 */ | ||
349 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | ||
350 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
351 | }; | ||
352 | |||
353 | static const enum omap_overlay_caps omap3630_dss_overlay_caps[] = { | ||
354 | /* OMAP_DSS_GFX */ | ||
355 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | | ||
356 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
357 | |||
358 | /* OMAP_DSS_VIDEO1 */ | ||
359 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_POS | | ||
360 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
361 | |||
362 | /* OMAP_DSS_VIDEO2 */ | ||
363 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | ||
364 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_POS | | ||
365 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
366 | }; | ||
367 | |||
368 | static const enum omap_overlay_caps omap4_dss_overlay_caps[] = { | ||
369 | /* OMAP_DSS_GFX */ | ||
370 | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | | ||
371 | OMAP_DSS_OVL_CAP_ZORDER | OMAP_DSS_OVL_CAP_POS | | ||
372 | OMAP_DSS_OVL_CAP_REPLICATION, | ||
373 | |||
374 | /* OMAP_DSS_VIDEO1 */ | ||
375 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | ||
376 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | | ||
377 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
378 | |||
379 | /* OMAP_DSS_VIDEO2 */ | ||
380 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | ||
381 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | | ||
382 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
383 | |||
384 | /* OMAP_DSS_VIDEO3 */ | ||
385 | OMAP_DSS_OVL_CAP_SCALE | OMAP_DSS_OVL_CAP_GLOBAL_ALPHA | | ||
386 | OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA | OMAP_DSS_OVL_CAP_ZORDER | | ||
387 | OMAP_DSS_OVL_CAP_POS | OMAP_DSS_OVL_CAP_REPLICATION, | ||
388 | }; | 212 | }; |
389 | 213 | ||
390 | static const char * const omap2_dss_clk_source_names[] = { | 214 | static const char * const omap2_dss_clk_source_names[] = { |
@@ -407,213 +231,34 @@ static const char * const omap4_dss_clk_source_names[] = { | |||
407 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", | 231 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "PLL2_CLK2", |
408 | }; | 232 | }; |
409 | 233 | ||
410 | static const char * const omap5_dss_clk_source_names[] = { | ||
411 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC] = "DPLL_DSI1_A_CLK1", | ||
412 | [OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI] = "DPLL_DSI1_A_CLK2", | ||
413 | [OMAP_DSS_CLK_SRC_FCK] = "DSS_CLK", | ||
414 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC] = "DPLL_DSI1_C_CLK1", | ||
415 | [OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI] = "DPLL_DSI1_C_CLK2", | ||
416 | }; | ||
417 | |||
418 | static const struct dss_param_range omap2_dss_param_range[] = { | 234 | static const struct dss_param_range omap2_dss_param_range[] = { |
419 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, | 235 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, |
420 | [FEAT_PARAM_DSS_PCD] = { 2, 255 }, | ||
421 | [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, | 236 | [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 }, |
422 | [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, | 237 | [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 }, |
423 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 }, | 238 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 }, |
424 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 }, | 239 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 }, |
425 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, | 240 | [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 }, |
426 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, | 241 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 }, |
427 | [FEAT_PARAM_DOWNSCALE] = { 1, 2 }, | ||
428 | /* | ||
429 | * Assuming the line width buffer to be 768 pixels as OMAP2 DISPC | ||
430 | * scaler cannot scale a image with width more than 768. | ||
431 | */ | ||
432 | [FEAT_PARAM_LINEWIDTH] = { 1, 768 }, | ||
433 | }; | 242 | }; |
434 | 243 | ||
435 | static const struct dss_param_range omap3_dss_param_range[] = { | 244 | static const struct dss_param_range omap3_dss_param_range[] = { |
436 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, | 245 | [FEAT_PARAM_DSS_FCK] = { 0, 173000000 }, |
437 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | ||
438 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 }, | 246 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 }, |
439 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 }, | 247 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 }, |
440 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 }, | 248 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 }, |
441 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, | 249 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 }, |
442 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, | 250 | [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 }, |
443 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, | 251 | [FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1}, |
444 | [FEAT_PARAM_DSI_FCK] = { 0, 173000000 }, | ||
445 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | ||
446 | [FEAT_PARAM_LINEWIDTH] = { 1, 1024 }, | ||
447 | }; | 252 | }; |
448 | 253 | ||
449 | static const struct dss_param_range omap4_dss_param_range[] = { | 254 | static const struct dss_param_range omap4_dss_param_range[] = { |
450 | [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, | 255 | [FEAT_PARAM_DSS_FCK] = { 0, 186000000 }, |
451 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | ||
452 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, | ||
453 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, | ||
454 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, | ||
455 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | ||
456 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | ||
457 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | ||
458 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | ||
459 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | ||
460 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | ||
461 | }; | ||
462 | |||
463 | static const struct dss_param_range omap5_dss_param_range[] = { | ||
464 | [FEAT_PARAM_DSS_FCK] = { 0, 200000000 }, | ||
465 | [FEAT_PARAM_DSS_PCD] = { 1, 255 }, | ||
466 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, | 256 | [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 }, |
467 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, | 257 | [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 }, |
468 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, | 258 | [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 }, |
469 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, | 259 | [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 }, |
470 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, | 260 | [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 }, |
471 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, | 261 | [FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 }, |
472 | [FEAT_PARAM_DSI_FCK] = { 0, 170000000 }, | ||
473 | [FEAT_PARAM_DOWNSCALE] = { 1, 4 }, | ||
474 | [FEAT_PARAM_LINEWIDTH] = { 1, 2048 }, | ||
475 | }; | ||
476 | |||
477 | static const enum dss_feat_id omap2_dss_feat_list[] = { | ||
478 | FEAT_LCDENABLEPOL, | ||
479 | FEAT_LCDENABLESIGNAL, | ||
480 | FEAT_PCKFREEENABLE, | ||
481 | FEAT_FUNCGATED, | ||
482 | FEAT_ROWREPEATENABLE, | ||
483 | FEAT_RESIZECONF, | ||
484 | }; | ||
485 | |||
486 | static const enum dss_feat_id omap3430_dss_feat_list[] = { | ||
487 | FEAT_LCDENABLEPOL, | ||
488 | FEAT_LCDENABLESIGNAL, | ||
489 | FEAT_PCKFREEENABLE, | ||
490 | FEAT_FUNCGATED, | ||
491 | FEAT_LINEBUFFERSPLIT, | ||
492 | FEAT_ROWREPEATENABLE, | ||
493 | FEAT_RESIZECONF, | ||
494 | FEAT_DSI_PLL_FREQSEL, | ||
495 | FEAT_DSI_REVERSE_TXCLKESC, | ||
496 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | ||
497 | FEAT_CPR, | ||
498 | FEAT_PRELOAD, | ||
499 | FEAT_FIR_COEF_V, | ||
500 | FEAT_ALPHA_FIXED_ZORDER, | ||
501 | FEAT_FIFO_MERGE, | ||
502 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
503 | FEAT_DPI_USES_VDDS_DSI, | ||
504 | }; | ||
505 | |||
506 | static const enum dss_feat_id am35xx_dss_feat_list[] = { | ||
507 | FEAT_LCDENABLEPOL, | ||
508 | FEAT_LCDENABLESIGNAL, | ||
509 | FEAT_PCKFREEENABLE, | ||
510 | FEAT_FUNCGATED, | ||
511 | FEAT_LINEBUFFERSPLIT, | ||
512 | FEAT_ROWREPEATENABLE, | ||
513 | FEAT_RESIZECONF, | ||
514 | FEAT_DSI_PLL_FREQSEL, | ||
515 | FEAT_DSI_REVERSE_TXCLKESC, | ||
516 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | ||
517 | FEAT_CPR, | ||
518 | FEAT_PRELOAD, | ||
519 | FEAT_FIR_COEF_V, | ||
520 | FEAT_ALPHA_FIXED_ZORDER, | ||
521 | FEAT_FIFO_MERGE, | ||
522 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
523 | }; | ||
524 | |||
525 | static const enum dss_feat_id omap3630_dss_feat_list[] = { | ||
526 | FEAT_LCDENABLEPOL, | ||
527 | FEAT_LCDENABLESIGNAL, | ||
528 | FEAT_PCKFREEENABLE, | ||
529 | FEAT_FUNCGATED, | ||
530 | FEAT_LINEBUFFERSPLIT, | ||
531 | FEAT_ROWREPEATENABLE, | ||
532 | FEAT_RESIZECONF, | ||
533 | FEAT_DSI_PLL_PWR_BUG, | ||
534 | FEAT_DSI_PLL_FREQSEL, | ||
535 | FEAT_CPR, | ||
536 | FEAT_PRELOAD, | ||
537 | FEAT_FIR_COEF_V, | ||
538 | FEAT_ALPHA_FIXED_ZORDER, | ||
539 | FEAT_FIFO_MERGE, | ||
540 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
541 | }; | ||
542 | |||
543 | static const enum dss_feat_id omap4430_es1_0_dss_feat_list[] = { | ||
544 | FEAT_MGR_LCD2, | ||
545 | FEAT_CORE_CLK_DIV, | ||
546 | FEAT_LCD_CLK_SRC, | ||
547 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
548 | FEAT_DSI_VC_OCP_WIDTH, | ||
549 | FEAT_DSI_GNQ, | ||
550 | FEAT_HANDLE_UV_SEPARATE, | ||
551 | FEAT_ATTR2, | ||
552 | FEAT_CPR, | ||
553 | FEAT_PRELOAD, | ||
554 | FEAT_FIR_COEF_V, | ||
555 | FEAT_ALPHA_FREE_ZORDER, | ||
556 | FEAT_FIFO_MERGE, | ||
557 | FEAT_BURST_2D, | ||
558 | }; | ||
559 | |||
560 | static const enum dss_feat_id omap4430_es2_0_1_2_dss_feat_list[] = { | ||
561 | FEAT_MGR_LCD2, | ||
562 | FEAT_CORE_CLK_DIV, | ||
563 | FEAT_LCD_CLK_SRC, | ||
564 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
565 | FEAT_DSI_VC_OCP_WIDTH, | ||
566 | FEAT_DSI_GNQ, | ||
567 | FEAT_HDMI_CTS_SWMODE, | ||
568 | FEAT_HANDLE_UV_SEPARATE, | ||
569 | FEAT_ATTR2, | ||
570 | FEAT_CPR, | ||
571 | FEAT_PRELOAD, | ||
572 | FEAT_FIR_COEF_V, | ||
573 | FEAT_ALPHA_FREE_ZORDER, | ||
574 | FEAT_FIFO_MERGE, | ||
575 | FEAT_BURST_2D, | ||
576 | }; | ||
577 | |||
578 | static const enum dss_feat_id omap4_dss_feat_list[] = { | ||
579 | FEAT_MGR_LCD2, | ||
580 | FEAT_CORE_CLK_DIV, | ||
581 | FEAT_LCD_CLK_SRC, | ||
582 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
583 | FEAT_DSI_VC_OCP_WIDTH, | ||
584 | FEAT_DSI_GNQ, | ||
585 | FEAT_HDMI_CTS_SWMODE, | ||
586 | FEAT_HDMI_AUDIO_USE_MCLK, | ||
587 | FEAT_HANDLE_UV_SEPARATE, | ||
588 | FEAT_ATTR2, | ||
589 | FEAT_CPR, | ||
590 | FEAT_PRELOAD, | ||
591 | FEAT_FIR_COEF_V, | ||
592 | FEAT_ALPHA_FREE_ZORDER, | ||
593 | FEAT_FIFO_MERGE, | ||
594 | FEAT_BURST_2D, | ||
595 | }; | ||
596 | |||
597 | static const enum dss_feat_id omap5_dss_feat_list[] = { | ||
598 | FEAT_MGR_LCD2, | ||
599 | FEAT_CORE_CLK_DIV, | ||
600 | FEAT_LCD_CLK_SRC, | ||
601 | FEAT_DSI_DCS_CMD_CONFIG_VC, | ||
602 | FEAT_DSI_VC_OCP_WIDTH, | ||
603 | FEAT_DSI_GNQ, | ||
604 | FEAT_HDMI_CTS_SWMODE, | ||
605 | FEAT_HDMI_AUDIO_USE_MCLK, | ||
606 | FEAT_HANDLE_UV_SEPARATE, | ||
607 | FEAT_ATTR2, | ||
608 | FEAT_CPR, | ||
609 | FEAT_PRELOAD, | ||
610 | FEAT_FIR_COEF_V, | ||
611 | FEAT_ALPHA_FREE_ZORDER, | ||
612 | FEAT_FIFO_MERGE, | ||
613 | FEAT_BURST_2D, | ||
614 | FEAT_DSI_PLL_SELFREQDCO, | ||
615 | FEAT_DSI_PLL_REFSEL, | ||
616 | FEAT_DSI_PHY_DCC, | ||
617 | }; | 262 | }; |
618 | 263 | ||
619 | /* OMAP2 DSS Features */ | 264 | /* OMAP2 DSS Features */ |
@@ -621,18 +266,17 @@ static const struct omap_dss_features omap2_dss_features = { | |||
621 | .reg_fields = omap2_dss_reg_fields, | 266 | .reg_fields = omap2_dss_reg_fields, |
622 | .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), | 267 | .num_reg_fields = ARRAY_SIZE(omap2_dss_reg_fields), |
623 | 268 | ||
624 | .features = omap2_dss_feat_list, | 269 | .has_feature = |
625 | .num_features = ARRAY_SIZE(omap2_dss_feat_list), | 270 | FEAT_LCDENABLEPOL | FEAT_LCDENABLESIGNAL | |
271 | FEAT_PCKFREEENABLE | FEAT_FUNCGATED | | ||
272 | FEAT_ROWREPEATENABLE | FEAT_RESIZECONF, | ||
626 | 273 | ||
627 | .num_mgrs = 2, | 274 | .num_mgrs = 2, |
628 | .num_ovls = 3, | 275 | .num_ovls = 3, |
629 | .supported_displays = omap2_dss_supported_displays, | 276 | .supported_displays = omap2_dss_supported_displays, |
630 | .supported_outputs = omap2_dss_supported_outputs, | ||
631 | .supported_color_modes = omap2_dss_supported_color_modes, | 277 | .supported_color_modes = omap2_dss_supported_color_modes, |
632 | .overlay_caps = omap2_dss_overlay_caps, | ||
633 | .clksrc_names = omap2_dss_clk_source_names, | 278 | .clksrc_names = omap2_dss_clk_source_names, |
634 | .dss_params = omap2_dss_param_range, | 279 | .dss_params = omap2_dss_param_range, |
635 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
636 | .buffer_size_unit = 1, | 280 | .buffer_size_unit = 1, |
637 | .burst_size_unit = 8, | 281 | .burst_size_unit = 8, |
638 | }; | 282 | }; |
@@ -642,42 +286,21 @@ static const struct omap_dss_features omap3430_dss_features = { | |||
642 | .reg_fields = omap3_dss_reg_fields, | 286 | .reg_fields = omap3_dss_reg_fields, |
643 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | 287 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), |
644 | 288 | ||
645 | .features = omap3430_dss_feat_list, | 289 | .has_feature = |
646 | .num_features = ARRAY_SIZE(omap3430_dss_feat_list), | 290 | FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | |
647 | 291 | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | | |
648 | .num_mgrs = 2, | 292 | FEAT_FUNCGATED | FEAT_ROWREPEATENABLE | |
649 | .num_ovls = 3, | 293 | FEAT_LINEBUFFERSPLIT | FEAT_RESIZECONF | |
650 | .supported_displays = omap3430_dss_supported_displays, | 294 | FEAT_DSI_PLL_FREQSEL | FEAT_DSI_REVERSE_TXCLKESC | |
651 | .supported_outputs = omap3430_dss_supported_outputs, | 295 | FEAT_VENC_REQUIRES_TV_DAC_CLK | FEAT_CPR | FEAT_PRELOAD | |
652 | .supported_color_modes = omap3_dss_supported_color_modes, | 296 | FEAT_FIR_COEF_V, |
653 | .overlay_caps = omap3430_dss_overlay_caps, | ||
654 | .clksrc_names = omap3_dss_clk_source_names, | ||
655 | .dss_params = omap3_dss_param_range, | ||
656 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
657 | .buffer_size_unit = 1, | ||
658 | .burst_size_unit = 8, | ||
659 | }; | ||
660 | |||
661 | /* | ||
662 | * AM35xx DSS Features. This is basically OMAP3 DSS Features without the | ||
663 | * vdds_dsi regulator. | ||
664 | */ | ||
665 | static const struct omap_dss_features am35xx_dss_features = { | ||
666 | .reg_fields = omap3_dss_reg_fields, | ||
667 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | ||
668 | |||
669 | .features = am35xx_dss_feat_list, | ||
670 | .num_features = ARRAY_SIZE(am35xx_dss_feat_list), | ||
671 | 297 | ||
672 | .num_mgrs = 2, | 298 | .num_mgrs = 2, |
673 | .num_ovls = 3, | 299 | .num_ovls = 3, |
674 | .supported_displays = omap3430_dss_supported_displays, | 300 | .supported_displays = omap3430_dss_supported_displays, |
675 | .supported_outputs = omap3430_dss_supported_outputs, | ||
676 | .supported_color_modes = omap3_dss_supported_color_modes, | 301 | .supported_color_modes = omap3_dss_supported_color_modes, |
677 | .overlay_caps = omap3430_dss_overlay_caps, | ||
678 | .clksrc_names = omap3_dss_clk_source_names, | 302 | .clksrc_names = omap3_dss_clk_source_names, |
679 | .dss_params = omap3_dss_param_range, | 303 | .dss_params = omap3_dss_param_range, |
680 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
681 | .buffer_size_unit = 1, | 304 | .buffer_size_unit = 1, |
682 | .burst_size_unit = 8, | 305 | .burst_size_unit = 8, |
683 | }; | 306 | }; |
@@ -686,18 +309,21 @@ static const struct omap_dss_features omap3630_dss_features = { | |||
686 | .reg_fields = omap3_dss_reg_fields, | 309 | .reg_fields = omap3_dss_reg_fields, |
687 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), | 310 | .num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields), |
688 | 311 | ||
689 | .features = omap3630_dss_feat_list, | 312 | .has_feature = |
690 | .num_features = ARRAY_SIZE(omap3630_dss_feat_list), | 313 | FEAT_GLOBAL_ALPHA | FEAT_LCDENABLEPOL | |
314 | FEAT_LCDENABLESIGNAL | FEAT_PCKFREEENABLE | | ||
315 | FEAT_PRE_MULT_ALPHA | FEAT_FUNCGATED | | ||
316 | FEAT_ROWREPEATENABLE | FEAT_LINEBUFFERSPLIT | | ||
317 | FEAT_RESIZECONF | FEAT_DSI_PLL_PWR_BUG | | ||
318 | FEAT_DSI_PLL_FREQSEL | FEAT_CPR | FEAT_PRELOAD | | ||
319 | FEAT_FIR_COEF_V, | ||
691 | 320 | ||
692 | .num_mgrs = 2, | 321 | .num_mgrs = 2, |
693 | .num_ovls = 3, | 322 | .num_ovls = 3, |
694 | .supported_displays = omap3630_dss_supported_displays, | 323 | .supported_displays = omap3630_dss_supported_displays, |
695 | .supported_outputs = omap3630_dss_supported_outputs, | ||
696 | .supported_color_modes = omap3_dss_supported_color_modes, | 324 | .supported_color_modes = omap3_dss_supported_color_modes, |
697 | .overlay_caps = omap3630_dss_overlay_caps, | ||
698 | .clksrc_names = omap3_dss_clk_source_names, | 325 | .clksrc_names = omap3_dss_clk_source_names, |
699 | .dss_params = omap3_dss_param_range, | 326 | .dss_params = omap3_dss_param_range, |
700 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_VRFB, | ||
701 | .buffer_size_unit = 1, | 327 | .buffer_size_unit = 1, |
702 | .burst_size_unit = 8, | 328 | .burst_size_unit = 8, |
703 | }; | 329 | }; |
@@ -708,41 +334,20 @@ static const struct omap_dss_features omap4430_es1_0_dss_features = { | |||
708 | .reg_fields = omap4_dss_reg_fields, | 334 | .reg_fields = omap4_dss_reg_fields, |
709 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), | 335 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), |
710 | 336 | ||
711 | .features = omap4430_es1_0_dss_feat_list, | 337 | .has_feature = |
712 | .num_features = ARRAY_SIZE(omap4430_es1_0_dss_feat_list), | 338 | FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | |
713 | 339 | FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | | |
714 | .num_mgrs = 3, | 340 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | |
715 | .num_ovls = 4, | 341 | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | |
716 | .num_wbs = 1, | 342 | FEAT_DSI_GNQ | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | |
717 | .supported_displays = omap4_dss_supported_displays, | 343 | FEAT_CPR | FEAT_PRELOAD | FEAT_FIR_COEF_V, |
718 | .supported_outputs = omap4_dss_supported_outputs, | ||
719 | .supported_color_modes = omap4_dss_supported_color_modes, | ||
720 | .overlay_caps = omap4_dss_overlay_caps, | ||
721 | .clksrc_names = omap4_dss_clk_source_names, | ||
722 | .dss_params = omap4_dss_param_range, | ||
723 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
724 | .buffer_size_unit = 16, | ||
725 | .burst_size_unit = 16, | ||
726 | }; | ||
727 | |||
728 | /* For OMAP4430 ES 2.0, 2.1 and 2.2 revisions */ | ||
729 | static const struct omap_dss_features omap4430_es2_0_1_2_dss_features = { | ||
730 | .reg_fields = omap4_dss_reg_fields, | ||
731 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), | ||
732 | |||
733 | .features = omap4430_es2_0_1_2_dss_feat_list, | ||
734 | .num_features = ARRAY_SIZE(omap4430_es2_0_1_2_dss_feat_list), | ||
735 | 344 | ||
736 | .num_mgrs = 3, | 345 | .num_mgrs = 3, |
737 | .num_ovls = 4, | 346 | .num_ovls = 3, |
738 | .num_wbs = 1, | ||
739 | .supported_displays = omap4_dss_supported_displays, | 347 | .supported_displays = omap4_dss_supported_displays, |
740 | .supported_outputs = omap4_dss_supported_outputs, | ||
741 | .supported_color_modes = omap4_dss_supported_color_modes, | 348 | .supported_color_modes = omap4_dss_supported_color_modes, |
742 | .overlay_caps = omap4_dss_overlay_caps, | ||
743 | .clksrc_names = omap4_dss_clk_source_names, | 349 | .clksrc_names = omap4_dss_clk_source_names, |
744 | .dss_params = omap4_dss_param_range, | 350 | .dss_params = omap4_dss_param_range, |
745 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
746 | .buffer_size_unit = 16, | 351 | .buffer_size_unit = 16, |
747 | .burst_size_unit = 16, | 352 | .burst_size_unit = 16, |
748 | }; | 353 | }; |
@@ -752,106 +357,35 @@ static const struct omap_dss_features omap4_dss_features = { | |||
752 | .reg_fields = omap4_dss_reg_fields, | 357 | .reg_fields = omap4_dss_reg_fields, |
753 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), | 358 | .num_reg_fields = ARRAY_SIZE(omap4_dss_reg_fields), |
754 | 359 | ||
755 | .features = omap4_dss_feat_list, | 360 | .has_feature = |
756 | .num_features = ARRAY_SIZE(omap4_dss_feat_list), | 361 | FEAT_GLOBAL_ALPHA | FEAT_PRE_MULT_ALPHA | |
362 | FEAT_MGR_LCD2 | FEAT_GLOBAL_ALPHA_VID1 | | ||
363 | FEAT_CORE_CLK_DIV | FEAT_LCD_CLK_SRC | | ||
364 | FEAT_DSI_DCS_CMD_CONFIG_VC | FEAT_DSI_VC_OCP_WIDTH | | ||
365 | FEAT_DSI_GNQ | FEAT_HDMI_CTS_SWMODE | | ||
366 | FEAT_HANDLE_UV_SEPARATE | FEAT_ATTR2 | FEAT_CPR | | ||
367 | FEAT_PRELOAD | FEAT_FIR_COEF_V, | ||
757 | 368 | ||
758 | .num_mgrs = 3, | 369 | .num_mgrs = 3, |
759 | .num_ovls = 4, | 370 | .num_ovls = 3, |
760 | .num_wbs = 1, | ||
761 | .supported_displays = omap4_dss_supported_displays, | 371 | .supported_displays = omap4_dss_supported_displays, |
762 | .supported_outputs = omap4_dss_supported_outputs, | ||
763 | .supported_color_modes = omap4_dss_supported_color_modes, | 372 | .supported_color_modes = omap4_dss_supported_color_modes, |
764 | .overlay_caps = omap4_dss_overlay_caps, | ||
765 | .clksrc_names = omap4_dss_clk_source_names, | 373 | .clksrc_names = omap4_dss_clk_source_names, |
766 | .dss_params = omap4_dss_param_range, | 374 | .dss_params = omap4_dss_param_range, |
767 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
768 | .buffer_size_unit = 16, | 375 | .buffer_size_unit = 16, |
769 | .burst_size_unit = 16, | 376 | .burst_size_unit = 16, |
770 | }; | 377 | }; |
771 | 378 | ||
772 | /* OMAP5 DSS Features */ | ||
773 | static const struct omap_dss_features omap5_dss_features = { | ||
774 | .reg_fields = omap5_dss_reg_fields, | ||
775 | .num_reg_fields = ARRAY_SIZE(omap5_dss_reg_fields), | ||
776 | |||
777 | .features = omap5_dss_feat_list, | ||
778 | .num_features = ARRAY_SIZE(omap5_dss_feat_list), | ||
779 | |||
780 | .num_mgrs = 3, | ||
781 | .num_ovls = 4, | ||
782 | .supported_displays = omap5_dss_supported_displays, | ||
783 | .supported_outputs = omap5_dss_supported_outputs, | ||
784 | .supported_color_modes = omap4_dss_supported_color_modes, | ||
785 | .overlay_caps = omap4_dss_overlay_caps, | ||
786 | .clksrc_names = omap5_dss_clk_source_names, | ||
787 | .dss_params = omap5_dss_param_range, | ||
788 | .supported_rotation_types = OMAP_DSS_ROT_DMA | OMAP_DSS_ROT_TILER, | ||
789 | .buffer_size_unit = 16, | ||
790 | .burst_size_unit = 16, | ||
791 | }; | ||
792 | |||
793 | #if defined(CONFIG_OMAP4_DSS_HDMI) | ||
794 | /* HDMI OMAP4 Functions*/ | ||
795 | static const struct ti_hdmi_ip_ops omap4_hdmi_functions = { | ||
796 | |||
797 | .video_configure = ti_hdmi_4xxx_basic_configure, | ||
798 | .phy_enable = ti_hdmi_4xxx_phy_enable, | ||
799 | .phy_disable = ti_hdmi_4xxx_phy_disable, | ||
800 | .read_edid = ti_hdmi_4xxx_read_edid, | ||
801 | .detect = ti_hdmi_4xxx_detect, | ||
802 | .pll_enable = ti_hdmi_4xxx_pll_enable, | ||
803 | .pll_disable = ti_hdmi_4xxx_pll_disable, | ||
804 | .video_enable = ti_hdmi_4xxx_wp_video_start, | ||
805 | .video_disable = ti_hdmi_4xxx_wp_video_stop, | ||
806 | .dump_wrapper = ti_hdmi_4xxx_wp_dump, | ||
807 | .dump_core = ti_hdmi_4xxx_core_dump, | ||
808 | .dump_pll = ti_hdmi_4xxx_pll_dump, | ||
809 | .dump_phy = ti_hdmi_4xxx_phy_dump, | ||
810 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
811 | .audio_enable = ti_hdmi_4xxx_wp_audio_enable, | ||
812 | .audio_disable = ti_hdmi_4xxx_wp_audio_disable, | ||
813 | .audio_start = ti_hdmi_4xxx_audio_start, | ||
814 | .audio_stop = ti_hdmi_4xxx_audio_stop, | ||
815 | .audio_config = ti_hdmi_4xxx_audio_config, | ||
816 | .audio_get_dma_port = ti_hdmi_4xxx_audio_get_dma_port, | ||
817 | #endif | ||
818 | |||
819 | }; | ||
820 | |||
821 | void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data, | ||
822 | enum omapdss_version version) | ||
823 | { | ||
824 | switch (version) { | ||
825 | case OMAPDSS_VER_OMAP4430_ES1: | ||
826 | case OMAPDSS_VER_OMAP4430_ES2: | ||
827 | case OMAPDSS_VER_OMAP4: | ||
828 | ip_data->ops = &omap4_hdmi_functions; | ||
829 | break; | ||
830 | default: | ||
831 | ip_data->ops = NULL; | ||
832 | } | ||
833 | |||
834 | WARN_ON(ip_data->ops == NULL); | ||
835 | } | ||
836 | #endif | ||
837 | |||
838 | /* Functions returning values related to a DSS feature */ | 379 | /* Functions returning values related to a DSS feature */ |
839 | int dss_feat_get_num_mgrs(void) | 380 | int dss_feat_get_num_mgrs(void) |
840 | { | 381 | { |
841 | return omap_current_dss_features->num_mgrs; | 382 | return omap_current_dss_features->num_mgrs; |
842 | } | 383 | } |
843 | EXPORT_SYMBOL(dss_feat_get_num_mgrs); | ||
844 | 384 | ||
845 | int dss_feat_get_num_ovls(void) | 385 | int dss_feat_get_num_ovls(void) |
846 | { | 386 | { |
847 | return omap_current_dss_features->num_ovls; | 387 | return omap_current_dss_features->num_ovls; |
848 | } | 388 | } |
849 | EXPORT_SYMBOL(dss_feat_get_num_ovls); | ||
850 | |||
851 | int dss_feat_get_num_wbs(void) | ||
852 | { | ||
853 | return omap_current_dss_features->num_wbs; | ||
854 | } | ||
855 | 389 | ||
856 | unsigned long dss_feat_get_param_min(enum dss_range_param param) | 390 | unsigned long dss_feat_get_param_min(enum dss_range_param param) |
857 | { | 391 | { |
@@ -867,24 +401,11 @@ enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel | |||
867 | { | 401 | { |
868 | return omap_current_dss_features->supported_displays[channel]; | 402 | return omap_current_dss_features->supported_displays[channel]; |
869 | } | 403 | } |
870 | EXPORT_SYMBOL(dss_feat_get_supported_displays); | ||
871 | |||
872 | enum omap_dss_output_id dss_feat_get_supported_outputs(enum omap_channel channel) | ||
873 | { | ||
874 | return omap_current_dss_features->supported_outputs[channel]; | ||
875 | } | ||
876 | EXPORT_SYMBOL(dss_feat_get_supported_outputs); | ||
877 | 404 | ||
878 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) | 405 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane) |
879 | { | 406 | { |
880 | return omap_current_dss_features->supported_color_modes[plane]; | 407 | return omap_current_dss_features->supported_color_modes[plane]; |
881 | } | 408 | } |
882 | EXPORT_SYMBOL(dss_feat_get_supported_color_modes); | ||
883 | |||
884 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane) | ||
885 | { | ||
886 | return omap_current_dss_features->overlay_caps[plane]; | ||
887 | } | ||
888 | 409 | ||
889 | bool dss_feat_color_mode_supported(enum omap_plane plane, | 410 | bool dss_feat_color_mode_supported(enum omap_plane plane, |
890 | enum omap_color_mode color_mode) | 411 | enum omap_color_mode color_mode) |
@@ -911,16 +432,7 @@ u32 dss_feat_get_burst_size_unit(void) | |||
911 | /* DSS has_feature check */ | 432 | /* DSS has_feature check */ |
912 | bool dss_has_feature(enum dss_feat_id id) | 433 | bool dss_has_feature(enum dss_feat_id id) |
913 | { | 434 | { |
914 | int i; | 435 | return omap_current_dss_features->has_feature & id; |
915 | const enum dss_feat_id *features = omap_current_dss_features->features; | ||
916 | const int num_features = omap_current_dss_features->num_features; | ||
917 | |||
918 | for (i = 0; i < num_features; i++) { | ||
919 | if (features[i] == id) | ||
920 | return true; | ||
921 | } | ||
922 | |||
923 | return false; | ||
924 | } | 436 | } |
925 | 437 | ||
926 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) | 438 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) |
@@ -932,49 +444,18 @@ void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end) | |||
932 | *end = omap_current_dss_features->reg_fields[id].end; | 444 | *end = omap_current_dss_features->reg_fields[id].end; |
933 | } | 445 | } |
934 | 446 | ||
935 | bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type) | 447 | void dss_features_init(void) |
936 | { | ||
937 | return omap_current_dss_features->supported_rotation_types & rot_type; | ||
938 | } | ||
939 | |||
940 | void dss_features_init(enum omapdss_version version) | ||
941 | { | 448 | { |
942 | switch (version) { | 449 | if (cpu_is_omap24xx()) |
943 | case OMAPDSS_VER_OMAP24xx: | ||
944 | omap_current_dss_features = &omap2_dss_features; | 450 | omap_current_dss_features = &omap2_dss_features; |
945 | break; | 451 | else if (cpu_is_omap3630()) |
946 | |||
947 | case OMAPDSS_VER_OMAP34xx_ES1: | ||
948 | case OMAPDSS_VER_OMAP34xx_ES3: | ||
949 | omap_current_dss_features = &omap3430_dss_features; | ||
950 | break; | ||
951 | |||
952 | case OMAPDSS_VER_OMAP3630: | ||
953 | omap_current_dss_features = &omap3630_dss_features; | 452 | omap_current_dss_features = &omap3630_dss_features; |
954 | break; | 453 | else if (cpu_is_omap34xx()) |
955 | 454 | omap_current_dss_features = &omap3430_dss_features; | |
956 | case OMAPDSS_VER_OMAP4430_ES1: | 455 | else if (omap_rev() == OMAP4430_REV_ES1_0) |
957 | omap_current_dss_features = &omap4430_es1_0_dss_features; | 456 | omap_current_dss_features = &omap4430_es1_0_dss_features; |
958 | break; | 457 | else if (cpu_is_omap44xx()) |
959 | |||
960 | case OMAPDSS_VER_OMAP4430_ES2: | ||
961 | omap_current_dss_features = &omap4430_es2_0_1_2_dss_features; | ||
962 | break; | ||
963 | |||
964 | case OMAPDSS_VER_OMAP4: | ||
965 | omap_current_dss_features = &omap4_dss_features; | 458 | omap_current_dss_features = &omap4_dss_features; |
966 | break; | 459 | else |
967 | |||
968 | case OMAPDSS_VER_OMAP5: | ||
969 | omap_current_dss_features = &omap5_dss_features; | ||
970 | break; | ||
971 | |||
972 | case OMAPDSS_VER_AM35xx: | ||
973 | omap_current_dss_features = &am35xx_dss_features; | ||
974 | break; | ||
975 | |||
976 | default: | ||
977 | DSSWARN("Unsupported OMAP version"); | 460 | DSSWARN("Unsupported OMAP version"); |
978 | break; | ||
979 | } | ||
980 | } | 461 | } |
diff --git a/drivers/video/omap2/dss/dss_features.h b/drivers/video/omap2/dss/dss_features.h index 489b9bec4a6..b7398cbcda5 100644 --- a/drivers/video/omap2/dss/dss_features.h +++ b/drivers/video/omap2/dss/dss_features.h | |||
@@ -20,54 +20,41 @@ | |||
20 | #ifndef __OMAP2_DSS_FEATURES_H | 20 | #ifndef __OMAP2_DSS_FEATURES_H |
21 | #define __OMAP2_DSS_FEATURES_H | 21 | #define __OMAP2_DSS_FEATURES_H |
22 | 22 | ||
23 | #if defined(CONFIG_OMAP4_DSS_HDMI) | 23 | #define MAX_DSS_MANAGERS 3 |
24 | #include "ti_hdmi.h" | 24 | #define MAX_DSS_OVERLAYS 3 |
25 | #endif | 25 | #define MAX_DSS_LCD_MANAGERS 2 |
26 | |||
27 | #define MAX_DSS_MANAGERS 4 | ||
28 | #define MAX_DSS_OVERLAYS 4 | ||
29 | #define MAX_DSS_LCD_MANAGERS 3 | ||
30 | #define MAX_NUM_DSI 2 | 26 | #define MAX_NUM_DSI 2 |
31 | 27 | ||
32 | /* DSS has feature id */ | 28 | /* DSS has feature id */ |
33 | enum dss_feat_id { | 29 | enum dss_feat_id { |
34 | FEAT_LCDENABLEPOL, | 30 | FEAT_GLOBAL_ALPHA = 1 << 0, |
35 | FEAT_LCDENABLESIGNAL, | 31 | FEAT_GLOBAL_ALPHA_VID1 = 1 << 1, |
36 | FEAT_PCKFREEENABLE, | 32 | FEAT_PRE_MULT_ALPHA = 1 << 2, |
37 | FEAT_FUNCGATED, | 33 | FEAT_LCDENABLEPOL = 1 << 3, |
38 | FEAT_MGR_LCD2, | 34 | FEAT_LCDENABLESIGNAL = 1 << 4, |
39 | FEAT_MGR_LCD3, | 35 | FEAT_PCKFREEENABLE = 1 << 5, |
40 | FEAT_LINEBUFFERSPLIT, | 36 | FEAT_FUNCGATED = 1 << 6, |
41 | FEAT_ROWREPEATENABLE, | 37 | FEAT_MGR_LCD2 = 1 << 7, |
42 | FEAT_RESIZECONF, | 38 | FEAT_LINEBUFFERSPLIT = 1 << 8, |
39 | FEAT_ROWREPEATENABLE = 1 << 9, | ||
40 | FEAT_RESIZECONF = 1 << 10, | ||
43 | /* Independent core clk divider */ | 41 | /* Independent core clk divider */ |
44 | FEAT_CORE_CLK_DIV, | 42 | FEAT_CORE_CLK_DIV = 1 << 11, |
45 | FEAT_LCD_CLK_SRC, | 43 | FEAT_LCD_CLK_SRC = 1 << 12, |
46 | /* DSI-PLL power command 0x3 is not working */ | 44 | /* DSI-PLL power command 0x3 is not working */ |
47 | FEAT_DSI_PLL_PWR_BUG, | 45 | FEAT_DSI_PLL_PWR_BUG = 1 << 13, |
48 | FEAT_DSI_PLL_FREQSEL, | 46 | FEAT_DSI_PLL_FREQSEL = 1 << 14, |
49 | FEAT_DSI_DCS_CMD_CONFIG_VC, | 47 | FEAT_DSI_DCS_CMD_CONFIG_VC = 1 << 15, |
50 | FEAT_DSI_VC_OCP_WIDTH, | 48 | FEAT_DSI_VC_OCP_WIDTH = 1 << 16, |
51 | FEAT_DSI_REVERSE_TXCLKESC, | 49 | FEAT_DSI_REVERSE_TXCLKESC = 1 << 17, |
52 | FEAT_DSI_GNQ, | 50 | FEAT_DSI_GNQ = 1 << 18, |
53 | FEAT_DPI_USES_VDDS_DSI, | 51 | FEAT_HDMI_CTS_SWMODE = 1 << 19, |
54 | FEAT_HDMI_CTS_SWMODE, | 52 | FEAT_HANDLE_UV_SEPARATE = 1 << 20, |
55 | FEAT_HDMI_AUDIO_USE_MCLK, | 53 | FEAT_ATTR2 = 1 << 21, |
56 | FEAT_HANDLE_UV_SEPARATE, | 54 | FEAT_VENC_REQUIRES_TV_DAC_CLK = 1 << 22, |
57 | FEAT_ATTR2, | 55 | FEAT_CPR = 1 << 23, |
58 | FEAT_VENC_REQUIRES_TV_DAC_CLK, | 56 | FEAT_PRELOAD = 1 << 24, |
59 | FEAT_CPR, | 57 | FEAT_FIR_COEF_V = 1 << 25, |
60 | FEAT_PRELOAD, | ||
61 | FEAT_FIR_COEF_V, | ||
62 | FEAT_ALPHA_FIXED_ZORDER, | ||
63 | FEAT_ALPHA_FREE_ZORDER, | ||
64 | FEAT_FIFO_MERGE, | ||
65 | /* An unknown HW bug causing the normal FIFO thresholds not to work */ | ||
66 | FEAT_OMAP3_DSI_FIFO_BUG, | ||
67 | FEAT_BURST_2D, | ||
68 | FEAT_DSI_PLL_SELFREQDCO, | ||
69 | FEAT_DSI_PLL_REFSEL, | ||
70 | FEAT_DSI_PHY_DCC, | ||
71 | }; | 58 | }; |
72 | 59 | ||
73 | /* DSS register field id */ | 60 | /* DSS register field id */ |
@@ -88,23 +75,21 @@ enum dss_feat_reg_field { | |||
88 | 75 | ||
89 | enum dss_range_param { | 76 | enum dss_range_param { |
90 | FEAT_PARAM_DSS_FCK, | 77 | FEAT_PARAM_DSS_FCK, |
91 | FEAT_PARAM_DSS_PCD, | ||
92 | FEAT_PARAM_DSIPLL_REGN, | 78 | FEAT_PARAM_DSIPLL_REGN, |
93 | FEAT_PARAM_DSIPLL_REGM, | 79 | FEAT_PARAM_DSIPLL_REGM, |
94 | FEAT_PARAM_DSIPLL_REGM_DISPC, | 80 | FEAT_PARAM_DSIPLL_REGM_DISPC, |
95 | FEAT_PARAM_DSIPLL_REGM_DSI, | 81 | FEAT_PARAM_DSIPLL_REGM_DSI, |
96 | FEAT_PARAM_DSIPLL_FINT, | 82 | FEAT_PARAM_DSIPLL_FINT, |
97 | FEAT_PARAM_DSIPLL_LPDIV, | 83 | FEAT_PARAM_DSIPLL_LPDIV, |
98 | FEAT_PARAM_DSI_FCK, | ||
99 | FEAT_PARAM_DOWNSCALE, | ||
100 | FEAT_PARAM_LINEWIDTH, | ||
101 | }; | 84 | }; |
102 | 85 | ||
103 | /* DSS Feature Functions */ | 86 | /* DSS Feature Functions */ |
104 | int dss_feat_get_num_wbs(void); | 87 | int dss_feat_get_num_mgrs(void); |
88 | int dss_feat_get_num_ovls(void); | ||
105 | unsigned long dss_feat_get_param_min(enum dss_range_param param); | 89 | unsigned long dss_feat_get_param_min(enum dss_range_param param); |
106 | unsigned long dss_feat_get_param_max(enum dss_range_param param); | 90 | unsigned long dss_feat_get_param_max(enum dss_range_param param); |
107 | enum omap_overlay_caps dss_feat_get_overlay_caps(enum omap_plane plane); | 91 | enum omap_display_type dss_feat_get_supported_displays(enum omap_channel channel); |
92 | enum omap_color_mode dss_feat_get_supported_color_modes(enum omap_plane plane); | ||
108 | bool dss_feat_color_mode_supported(enum omap_plane plane, | 93 | bool dss_feat_color_mode_supported(enum omap_plane plane, |
109 | enum omap_color_mode color_mode); | 94 | enum omap_color_mode color_mode); |
110 | const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); | 95 | const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); |
@@ -112,13 +97,7 @@ const char *dss_feat_get_clk_source_name(enum omap_dss_clk_source id); | |||
112 | u32 dss_feat_get_buffer_size_unit(void); /* in bytes */ | 97 | u32 dss_feat_get_buffer_size_unit(void); /* in bytes */ |
113 | u32 dss_feat_get_burst_size_unit(void); /* in bytes */ | 98 | u32 dss_feat_get_burst_size_unit(void); /* in bytes */ |
114 | 99 | ||
115 | bool dss_feat_rotation_type_supported(enum omap_dss_rotation_type rot_type); | ||
116 | |||
117 | bool dss_has_feature(enum dss_feat_id id); | 100 | bool dss_has_feature(enum dss_feat_id id); |
118 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); | 101 | void dss_feat_get_reg_field(enum dss_feat_reg_field id, u8 *start, u8 *end); |
119 | void dss_features_init(enum omapdss_version version); | 102 | void dss_features_init(void); |
120 | #if defined(CONFIG_OMAP4_DSS_HDMI) | ||
121 | void dss_init_hdmi_ip_ops(struct hdmi_ip_data *ip_data, | ||
122 | enum omapdss_version version); | ||
123 | #endif | ||
124 | #endif | 103 | #endif |
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 769d0828581..256f27a9064 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -32,45 +32,31 @@ | |||
32 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
33 | #include <linux/pm_runtime.h> | 33 | #include <linux/pm_runtime.h> |
34 | #include <linux/clk.h> | 34 | #include <linux/clk.h> |
35 | #include <linux/gpio.h> | ||
36 | #include <linux/regulator/consumer.h> | ||
37 | #include <video/omapdss.h> | 35 | #include <video/omapdss.h> |
36 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ | ||
37 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
38 | #include <sound/soc.h> | ||
39 | #include <sound/pcm_params.h> | ||
40 | #endif | ||
38 | 41 | ||
39 | #include "ti_hdmi.h" | ||
40 | #include "dss.h" | 42 | #include "dss.h" |
43 | #include "hdmi.h" | ||
41 | #include "dss_features.h" | 44 | #include "dss_features.h" |
42 | 45 | ||
43 | #define HDMI_WP 0x0 | ||
44 | #define HDMI_CORE_SYS 0x400 | ||
45 | #define HDMI_CORE_AV 0x900 | ||
46 | #define HDMI_PLLCTRL 0x200 | ||
47 | #define HDMI_PHY 0x300 | ||
48 | |||
49 | /* HDMI EDID Length move this */ | ||
50 | #define HDMI_EDID_MAX_LENGTH 256 | ||
51 | #define EDID_TIMING_DESCRIPTOR_SIZE 0x12 | ||
52 | #define EDID_DESCRIPTOR_BLOCK0_ADDRESS 0x36 | ||
53 | #define EDID_DESCRIPTOR_BLOCK1_ADDRESS 0x80 | ||
54 | #define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 4 | ||
55 | #define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 4 | ||
56 | |||
57 | #define HDMI_DEFAULT_REGN 16 | ||
58 | #define HDMI_DEFAULT_REGM2 1 | ||
59 | |||
60 | static struct { | 46 | static struct { |
61 | struct mutex lock; | 47 | struct mutex lock; |
48 | struct omap_display_platform_data *pdata; | ||
62 | struct platform_device *pdev; | 49 | struct platform_device *pdev; |
63 | 50 | void __iomem *base_wp; /* HDMI wrapper */ | |
64 | struct hdmi_ip_data ip_data; | 51 | int code; |
52 | int mode; | ||
53 | u8 edid[HDMI_EDID_MAX_LENGTH]; | ||
54 | u8 edid_set; | ||
55 | bool custom_set; | ||
56 | struct hdmi_config cfg; | ||
65 | 57 | ||
66 | struct clk *sys_clk; | 58 | struct clk *sys_clk; |
67 | struct regulator *vdda_hdmi_dac_reg; | 59 | struct clk *hdmi_clk; |
68 | |||
69 | int ct_cp_hpd_gpio; | ||
70 | int ls_oe_gpio; | ||
71 | int hpd_gpio; | ||
72 | |||
73 | struct omap_dss_output output; | ||
74 | } hdmi; | 60 | } hdmi; |
75 | 61 | ||
76 | /* | 62 | /* |
@@ -87,223 +73,101 @@ static struct { | |||
87 | * map it to corresponding CEA or VESA index. | 73 | * map it to corresponding CEA or VESA index. |
88 | */ | 74 | */ |
89 | 75 | ||
90 | static const struct hdmi_config cea_timings[] = { | 76 | static const struct hdmi_timings cea_vesa_timings[OMAP_HDMI_TIMINGS_NB] = { |
91 | { | 77 | { {640, 480, 25200, 96, 16, 48, 2, 10, 33} , 0 , 0}, |
92 | { 640, 480, 25200, 96, 16, 48, 2, 10, 33, | 78 | { {1280, 720, 74250, 40, 440, 220, 5, 5, 20}, 1, 1}, |
93 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | 79 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1}, |
94 | false, }, | 80 | { {720, 480, 27027, 62, 16, 60, 6, 9, 30}, 0, 0}, |
95 | { 1, HDMI_HDMI }, | 81 | { {2880, 576, 108000, 256, 48, 272, 5, 5, 39}, 0, 0}, |
96 | }, | 82 | { {1440, 240, 27027, 124, 38, 114, 3, 4, 15}, 0, 0}, |
97 | { | 83 | { {1440, 288, 27000, 126, 24, 138, 3, 2, 19}, 0, 0}, |
98 | { 720, 480, 27027, 62, 16, 60, 6, 9, 30, | 84 | { {1920, 540, 74250, 44, 528, 148, 5, 2, 15}, 1, 1}, |
99 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | 85 | { {1920, 540, 74250, 44, 88, 148, 5, 2, 15}, 1, 1}, |
100 | false, }, | 86 | { {1920, 1080, 148500, 44, 88, 148, 5, 4, 36}, 1, 1}, |
101 | { 2, HDMI_HDMI }, | 87 | { {720, 576, 27000, 64, 12, 68, 5, 5, 39}, 0, 0}, |
102 | }, | 88 | { {1440, 576, 54000, 128, 24, 136, 5, 5, 39}, 0, 0}, |
103 | { | 89 | { {1920, 1080, 148500, 44, 528, 148, 5, 4, 36}, 1, 1}, |
104 | { 1280, 720, 74250, 40, 110, 220, 5, 5, 20, | 90 | { {2880, 480, 108108, 248, 64, 240, 6, 9, 30}, 0, 0}, |
105 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | 91 | { {1920, 1080, 74250, 44, 638, 148, 5, 4, 36}, 1, 1}, |
106 | false, }, | 92 | /* VESA From Here */ |
107 | { 4, HDMI_HDMI }, | 93 | { {640, 480, 25175, 96, 16, 48, 2 , 11, 31}, 0, 0}, |
108 | }, | 94 | { {800, 600, 40000, 128, 40, 88, 4 , 1, 23}, 1, 1}, |
109 | { | 95 | { {848, 480, 33750, 112, 16, 112, 8 , 6, 23}, 1, 1}, |
110 | { 1920, 540, 74250, 44, 88, 148, 5, 2, 15, | 96 | { {1280, 768, 79500, 128, 64, 192, 7 , 3, 20}, 1, 0}, |
111 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | 97 | { {1280, 800, 83500, 128, 72, 200, 6 , 3, 22}, 1, 0}, |
112 | true, }, | 98 | { {1360, 768, 85500, 112, 64, 256, 6 , 3, 18}, 1, 1}, |
113 | { 5, HDMI_HDMI }, | 99 | { {1280, 960, 108000, 112, 96, 312, 3 , 1, 36}, 1, 1}, |
114 | }, | 100 | { {1280, 1024, 108000, 112, 48, 248, 3 , 1, 38}, 1, 1}, |
115 | { | 101 | { {1024, 768, 65000, 136, 24, 160, 6, 3, 29}, 0, 0}, |
116 | { 1440, 240, 27027, 124, 38, 114, 3, 4, 15, | 102 | { {1400, 1050, 121750, 144, 88, 232, 4, 3, 32}, 1, 0}, |
117 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | 103 | { {1440, 900, 106500, 152, 80, 232, 6, 3, 25}, 1, 0}, |
118 | true, }, | 104 | { {1680, 1050, 146250, 176 , 104, 280, 6, 3, 30}, 1, 0}, |
119 | { 6, HDMI_HDMI }, | 105 | { {1366, 768, 85500, 143, 70, 213, 3, 3, 24}, 1, 1}, |
120 | }, | 106 | { {1920, 1080, 148500, 44, 148, 80, 5, 4, 36}, 1, 1}, |
121 | { | 107 | { {1280, 768, 68250, 32, 48, 80, 7, 3, 12}, 0, 1}, |
122 | { 1920, 1080, 148500, 44, 88, 148, 5, 4, 36, | 108 | { {1400, 1050, 101000, 32, 48, 80, 4, 3, 23}, 0, 1}, |
123 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | 109 | { {1680, 1050, 119000, 32, 48, 80, 6, 3, 21}, 0, 1}, |
124 | false, }, | 110 | { {1280, 800, 79500, 32, 48, 80, 6, 3, 14}, 0, 1}, |
125 | { 16, HDMI_HDMI }, | 111 | { {1280, 720, 74250, 40, 110, 220, 5, 5, 20}, 1, 1} |
126 | }, | ||
127 | { | ||
128 | { 720, 576, 27000, 64, 12, 68, 5, 5, 39, | ||
129 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
130 | false, }, | ||
131 | { 17, HDMI_HDMI }, | ||
132 | }, | ||
133 | { | ||
134 | { 1280, 720, 74250, 40, 440, 220, 5, 5, 20, | ||
135 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
136 | false, }, | ||
137 | { 19, HDMI_HDMI }, | ||
138 | }, | ||
139 | { | ||
140 | { 1920, 540, 74250, 44, 528, 148, 5, 2, 15, | ||
141 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
142 | true, }, | ||
143 | { 20, HDMI_HDMI }, | ||
144 | }, | ||
145 | { | ||
146 | { 1440, 288, 27000, 126, 24, 138, 3, 2, 19, | ||
147 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
148 | true, }, | ||
149 | { 21, HDMI_HDMI }, | ||
150 | }, | ||
151 | { | ||
152 | { 1440, 576, 54000, 128, 24, 136, 5, 5, 39, | ||
153 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
154 | false, }, | ||
155 | { 29, HDMI_HDMI }, | ||
156 | }, | ||
157 | { | ||
158 | { 1920, 1080, 148500, 44, 528, 148, 5, 4, 36, | ||
159 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
160 | false, }, | ||
161 | { 31, HDMI_HDMI }, | ||
162 | }, | ||
163 | { | ||
164 | { 1920, 1080, 74250, 44, 638, 148, 5, 4, 36, | ||
165 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
166 | false, }, | ||
167 | { 32, HDMI_HDMI }, | ||
168 | }, | ||
169 | { | ||
170 | { 2880, 480, 108108, 248, 64, 240, 6, 9, 30, | ||
171 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
172 | false, }, | ||
173 | { 35, HDMI_HDMI }, | ||
174 | }, | ||
175 | { | ||
176 | { 2880, 576, 108000, 256, 48, 272, 5, 5, 39, | ||
177 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
178 | false, }, | ||
179 | { 37, HDMI_HDMI }, | ||
180 | }, | ||
181 | }; | 112 | }; |
182 | 113 | ||
183 | static const struct hdmi_config vesa_timings[] = { | 114 | /* |
184 | /* VESA From Here */ | 115 | * This is a static mapping array which maps the timing values |
185 | { | 116 | * with corresponding CEA / VESA code |
186 | { 640, 480, 25175, 96, 16, 48, 2, 11, 31, | 117 | */ |
187 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | 118 | static const int code_index[OMAP_HDMI_TIMINGS_NB] = { |
188 | false, }, | 119 | 1, 19, 4, 2, 37, 6, 21, 20, 5, 16, 17, 29, 31, 35, 32, |
189 | { 4, HDMI_DVI }, | 120 | /* <--15 CEA 17--> vesa*/ |
190 | }, | 121 | 4, 9, 0xE, 0x17, 0x1C, 0x27, 0x20, 0x23, 0x10, 0x2A, |
191 | { | 122 | 0X2F, 0x3A, 0X51, 0X52, 0x16, 0x29, 0x39, 0x1B |
192 | { 800, 600, 40000, 128, 40, 88, 4, 1, 23, | 123 | }; |
193 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | 124 | |
194 | false, }, | 125 | /* |
195 | { 9, HDMI_DVI }, | 126 | * This is reverse static mapping which maps the CEA / VESA code |
196 | }, | 127 | * to the corresponding timing values |
197 | { | 128 | */ |
198 | { 848, 480, 33750, 112, 16, 112, 8, 6, 23, | 129 | static const int code_cea[39] = { |
199 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | 130 | -1, 0, 3, 3, 2, 8, 5, 5, -1, -1, |
200 | false, }, | 131 | -1, -1, -1, -1, -1, -1, 9, 10, 10, 1, |
201 | { 0xE, HDMI_DVI }, | 132 | 7, 6, 6, -1, -1, -1, -1, -1, -1, 11, |
202 | }, | 133 | 11, 12, 14, -1, -1, 13, 13, 4, 4 |
203 | { | ||
204 | { 1280, 768, 79500, 128, 64, 192, 7, 3, 20, | ||
205 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, | ||
206 | false, }, | ||
207 | { 0x17, HDMI_DVI }, | ||
208 | }, | ||
209 | { | ||
210 | { 1280, 800, 83500, 128, 72, 200, 6, 3, 22, | ||
211 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, | ||
212 | false, }, | ||
213 | { 0x1C, HDMI_DVI }, | ||
214 | }, | ||
215 | { | ||
216 | { 1360, 768, 85500, 112, 64, 256, 6, 3, 18, | ||
217 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
218 | false, }, | ||
219 | { 0x27, HDMI_DVI }, | ||
220 | }, | ||
221 | { | ||
222 | { 1280, 960, 108000, 112, 96, 312, 3, 1, 36, | ||
223 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
224 | false, }, | ||
225 | { 0x20, HDMI_DVI }, | ||
226 | }, | ||
227 | { | ||
228 | { 1280, 1024, 108000, 112, 48, 248, 3, 1, 38, | ||
229 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
230 | false, }, | ||
231 | { 0x23, HDMI_DVI }, | ||
232 | }, | ||
233 | { | ||
234 | { 1024, 768, 65000, 136, 24, 160, 6, 3, 29, | ||
235 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_LOW, | ||
236 | false, }, | ||
237 | { 0x10, HDMI_DVI }, | ||
238 | }, | ||
239 | { | ||
240 | { 1400, 1050, 121750, 144, 88, 232, 4, 3, 32, | ||
241 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, | ||
242 | false, }, | ||
243 | { 0x2A, HDMI_DVI }, | ||
244 | }, | ||
245 | { | ||
246 | { 1440, 900, 106500, 152, 80, 232, 6, 3, 25, | ||
247 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, | ||
248 | false, }, | ||
249 | { 0x2F, HDMI_DVI }, | ||
250 | }, | ||
251 | { | ||
252 | { 1680, 1050, 146250, 176 , 104, 280, 6, 3, 30, | ||
253 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_LOW, | ||
254 | false, }, | ||
255 | { 0x3A, HDMI_DVI }, | ||
256 | }, | ||
257 | { | ||
258 | { 1366, 768, 85500, 143, 70, 213, 3, 3, 24, | ||
259 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
260 | false, }, | ||
261 | { 0x51, HDMI_DVI }, | ||
262 | }, | ||
263 | { | ||
264 | { 1920, 1080, 148500, 44, 148, 80, 5, 4, 36, | ||
265 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
266 | false, }, | ||
267 | { 0x52, HDMI_DVI }, | ||
268 | }, | ||
269 | { | ||
270 | { 1280, 768, 68250, 32, 48, 80, 7, 3, 12, | ||
271 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, | ||
272 | false, }, | ||
273 | { 0x16, HDMI_DVI }, | ||
274 | }, | ||
275 | { | ||
276 | { 1400, 1050, 101000, 32, 48, 80, 4, 3, 23, | ||
277 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, | ||
278 | false, }, | ||
279 | { 0x29, HDMI_DVI }, | ||
280 | }, | ||
281 | { | ||
282 | { 1680, 1050, 119000, 32, 48, 80, 6, 3, 21, | ||
283 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, | ||
284 | false, }, | ||
285 | { 0x39, HDMI_DVI }, | ||
286 | }, | ||
287 | { | ||
288 | { 1280, 800, 79500, 32, 48, 80, 6, 3, 14, | ||
289 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, | ||
290 | false, }, | ||
291 | { 0x1B, HDMI_DVI }, | ||
292 | }, | ||
293 | { | ||
294 | { 1280, 720, 74250, 40, 110, 220, 5, 5, 20, | ||
295 | OMAPDSS_SIG_ACTIVE_HIGH, OMAPDSS_SIG_ACTIVE_HIGH, | ||
296 | false, }, | ||
297 | { 0x55, HDMI_DVI }, | ||
298 | }, | ||
299 | { | ||
300 | { 1920, 1200, 154000, 32, 48, 80, 6, 3, 26, | ||
301 | OMAPDSS_SIG_ACTIVE_LOW, OMAPDSS_SIG_ACTIVE_HIGH, | ||
302 | false, }, | ||
303 | { 0x44, HDMI_DVI }, | ||
304 | }, | ||
305 | }; | 134 | }; |
306 | 135 | ||
136 | static const int code_vesa[85] = { | ||
137 | -1, -1, -1, -1, 15, -1, -1, -1, -1, 16, | ||
138 | -1, -1, -1, -1, 17, -1, 23, -1, -1, -1, | ||
139 | -1, -1, 29, 18, -1, -1, -1, 32, 19, -1, | ||
140 | -1, -1, 21, -1, -1, 22, -1, -1, -1, 20, | ||
141 | -1, 30, 24, -1, -1, -1, -1, 25, -1, -1, | ||
142 | -1, -1, -1, -1, -1, -1, -1, 31, 26, -1, | ||
143 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||
144 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, | ||
145 | -1, 27, 28, -1, 33}; | ||
146 | |||
147 | static const u8 edid_header[8] = {0x0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0}; | ||
148 | |||
149 | static inline void hdmi_write_reg(const struct hdmi_reg idx, u32 val) | ||
150 | { | ||
151 | __raw_writel(val, hdmi.base_wp + idx.idx); | ||
152 | } | ||
153 | |||
154 | static inline u32 hdmi_read_reg(const struct hdmi_reg idx) | ||
155 | { | ||
156 | return __raw_readl(hdmi.base_wp + idx.idx); | ||
157 | } | ||
158 | |||
159 | static inline int hdmi_wait_for_bit_change(const struct hdmi_reg idx, | ||
160 | int b2, int b1, u32 val) | ||
161 | { | ||
162 | u32 t = 0; | ||
163 | while (val != REG_GET(idx, b2, b1)) { | ||
164 | udelay(1); | ||
165 | if (t++ > 10000) | ||
166 | return !val; | ||
167 | } | ||
168 | return val; | ||
169 | } | ||
170 | |||
307 | static int hdmi_runtime_get(void) | 171 | static int hdmi_runtime_get(void) |
308 | { | 172 | { |
309 | int r; | 173 | int r; |
@@ -312,10 +176,7 @@ static int hdmi_runtime_get(void) | |||
312 | 176 | ||
313 | r = pm_runtime_get_sync(&hdmi.pdev->dev); | 177 | r = pm_runtime_get_sync(&hdmi.pdev->dev); |
314 | WARN_ON(r < 0); | 178 | WARN_ON(r < 0); |
315 | if (r < 0) | 179 | return r < 0 ? r : 0; |
316 | return r; | ||
317 | |||
318 | return 0; | ||
319 | } | 180 | } |
320 | 181 | ||
321 | static void hdmi_runtime_put(void) | 182 | static void hdmi_runtime_put(void) |
@@ -324,141 +185,885 @@ static void hdmi_runtime_put(void) | |||
324 | 185 | ||
325 | DSSDBG("hdmi_runtime_put\n"); | 186 | DSSDBG("hdmi_runtime_put\n"); |
326 | 187 | ||
327 | r = pm_runtime_put_sync(&hdmi.pdev->dev); | 188 | r = pm_runtime_put(&hdmi.pdev->dev); |
328 | WARN_ON(r < 0 && r != -ENOSYS); | 189 | WARN_ON(r < 0); |
329 | } | 190 | } |
330 | 191 | ||
331 | static int __init hdmi_init_display(struct omap_dss_device *dssdev) | 192 | int hdmi_init_display(struct omap_dss_device *dssdev) |
332 | { | 193 | { |
333 | int r; | 194 | DSSDBG("init_display\n"); |
334 | 195 | ||
335 | struct gpio gpios[] = { | 196 | return 0; |
336 | { hdmi.ct_cp_hpd_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ct_cp_hpd" }, | 197 | } |
337 | { hdmi.ls_oe_gpio, GPIOF_OUT_INIT_LOW, "hdmi_ls_oe" }, | ||
338 | { hdmi.hpd_gpio, GPIOF_DIR_IN, "hdmi_hpd" }, | ||
339 | }; | ||
340 | 198 | ||
341 | DSSDBG("init_display\n"); | 199 | static int hdmi_pll_init(enum hdmi_clk_refsel refsel, int dcofreq, |
200 | struct hdmi_pll_info *fmt, u16 sd) | ||
201 | { | ||
202 | u32 r; | ||
342 | 203 | ||
343 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); | 204 | /* PLL start always use manual mode */ |
205 | REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 0, 0); | ||
344 | 206 | ||
345 | if (hdmi.vdda_hdmi_dac_reg == NULL) { | 207 | r = hdmi_read_reg(PLLCTRL_CFG1); |
346 | struct regulator *reg; | 208 | r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ |
209 | r = FLD_MOD(r, fmt->regn, 8, 1); /* CFG1_PLL_REGN */ | ||
347 | 210 | ||
348 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); | 211 | hdmi_write_reg(PLLCTRL_CFG1, r); |
349 | 212 | ||
350 | /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ | 213 | r = hdmi_read_reg(PLLCTRL_CFG2); |
351 | if (IS_ERR(reg)) | ||
352 | reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); | ||
353 | 214 | ||
354 | if (IS_ERR(reg)) { | 215 | r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ |
355 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); | 216 | r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ |
356 | return PTR_ERR(reg); | 217 | r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ |
357 | } | 218 | |
219 | if (dcofreq) { | ||
220 | /* divider programming for frequency beyond 1000Mhz */ | ||
221 | REG_FLD_MOD(PLLCTRL_CFG3, sd, 17, 10); | ||
222 | r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ | ||
223 | } else { | ||
224 | r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ | ||
225 | } | ||
226 | |||
227 | hdmi_write_reg(PLLCTRL_CFG2, r); | ||
228 | |||
229 | r = hdmi_read_reg(PLLCTRL_CFG4); | ||
230 | r = FLD_MOD(r, fmt->regm2, 24, 18); | ||
231 | r = FLD_MOD(r, fmt->regmf, 17, 0); | ||
232 | |||
233 | hdmi_write_reg(PLLCTRL_CFG4, r); | ||
234 | |||
235 | /* go now */ | ||
236 | REG_FLD_MOD(PLLCTRL_PLL_GO, 0x1, 0, 0); | ||
237 | |||
238 | /* wait for bit change */ | ||
239 | if (hdmi_wait_for_bit_change(PLLCTRL_PLL_GO, 0, 0, 1) != 1) { | ||
240 | DSSERR("PLL GO bit not set\n"); | ||
241 | return -ETIMEDOUT; | ||
242 | } | ||
243 | |||
244 | /* Wait till the lock bit is set in PLL status */ | ||
245 | if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { | ||
246 | DSSWARN("cannot lock PLL\n"); | ||
247 | DSSWARN("CFG1 0x%x\n", | ||
248 | hdmi_read_reg(PLLCTRL_CFG1)); | ||
249 | DSSWARN("CFG2 0x%x\n", | ||
250 | hdmi_read_reg(PLLCTRL_CFG2)); | ||
251 | DSSWARN("CFG4 0x%x\n", | ||
252 | hdmi_read_reg(PLLCTRL_CFG4)); | ||
253 | return -ETIMEDOUT; | ||
254 | } | ||
255 | |||
256 | DSSDBG("PLL locked!\n"); | ||
257 | |||
258 | return 0; | ||
259 | } | ||
358 | 260 | ||
359 | hdmi.vdda_hdmi_dac_reg = reg; | 261 | /* PHY_PWR_CMD */ |
262 | static int hdmi_set_phy_pwr(enum hdmi_phy_pwr val) | ||
263 | { | ||
264 | /* Command for power control of HDMI PHY */ | ||
265 | REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 7, 6); | ||
266 | |||
267 | /* Status of the power control of HDMI PHY */ | ||
268 | if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 5, 4, val) != val) { | ||
269 | DSSERR("Failed to set PHY power mode to %d\n", val); | ||
270 | return -ETIMEDOUT; | ||
360 | } | 271 | } |
361 | 272 | ||
362 | r = gpio_request_array(gpios, ARRAY_SIZE(gpios)); | 273 | return 0; |
274 | } | ||
275 | |||
276 | /* PLL_PWR_CMD */ | ||
277 | static int hdmi_set_pll_pwr(enum hdmi_pll_pwr val) | ||
278 | { | ||
279 | /* Command for power control of HDMI PLL */ | ||
280 | REG_FLD_MOD(HDMI_WP_PWR_CTRL, val, 3, 2); | ||
281 | |||
282 | /* wait till PHY_PWR_STATUS is set */ | ||
283 | if (hdmi_wait_for_bit_change(HDMI_WP_PWR_CTRL, 1, 0, val) != val) { | ||
284 | DSSERR("Failed to set PHY_PWR_STATUS\n"); | ||
285 | return -ETIMEDOUT; | ||
286 | } | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int hdmi_pll_reset(void) | ||
292 | { | ||
293 | /* SYSRESET controlled by power FSM */ | ||
294 | REG_FLD_MOD(PLLCTRL_PLL_CONTROL, 0x0, 3, 3); | ||
295 | |||
296 | /* READ 0x0 reset is in progress */ | ||
297 | if (hdmi_wait_for_bit_change(PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) { | ||
298 | DSSERR("Failed to sysreset PLL\n"); | ||
299 | return -ETIMEDOUT; | ||
300 | } | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int hdmi_phy_init(void) | ||
306 | { | ||
307 | u16 r = 0; | ||
308 | |||
309 | r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_LDOON); | ||
310 | if (r) | ||
311 | return r; | ||
312 | |||
313 | r = hdmi_set_phy_pwr(HDMI_PHYPWRCMD_TXON); | ||
363 | if (r) | 314 | if (r) |
364 | return r; | 315 | return r; |
365 | 316 | ||
317 | /* | ||
318 | * Read address 0 in order to get the SCP reset done completed | ||
319 | * Dummy access performed to make sure reset is done | ||
320 | */ | ||
321 | hdmi_read_reg(HDMI_TXPHY_TX_CTRL); | ||
322 | |||
323 | /* | ||
324 | * Write to phy address 0 to configure the clock | ||
325 | * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field | ||
326 | */ | ||
327 | REG_FLD_MOD(HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); | ||
328 | |||
329 | /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ | ||
330 | hdmi_write_reg(HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); | ||
331 | |||
332 | /* Setup max LDO voltage */ | ||
333 | REG_FLD_MOD(HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); | ||
334 | |||
335 | /* Write to phy address 3 to change the polarity control */ | ||
336 | REG_FLD_MOD(HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | ||
337 | |||
366 | return 0; | 338 | return 0; |
367 | } | 339 | } |
368 | 340 | ||
369 | static void hdmi_uninit_display(struct omap_dss_device *dssdev) | 341 | static int hdmi_pll_program(struct hdmi_pll_info *fmt) |
370 | { | 342 | { |
371 | DSSDBG("uninit_display\n"); | 343 | u16 r = 0; |
344 | enum hdmi_clk_refsel refsel; | ||
345 | |||
346 | r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); | ||
347 | if (r) | ||
348 | return r; | ||
349 | |||
350 | r = hdmi_set_pll_pwr(HDMI_PLLPWRCMD_BOTHON_ALLCLKS); | ||
351 | if (r) | ||
352 | return r; | ||
353 | |||
354 | r = hdmi_pll_reset(); | ||
355 | if (r) | ||
356 | return r; | ||
357 | |||
358 | refsel = HDMI_REFSEL_SYSCLK; | ||
359 | |||
360 | r = hdmi_pll_init(refsel, fmt->dcofreq, fmt, fmt->regsd); | ||
361 | if (r) | ||
362 | return r; | ||
363 | |||
364 | return 0; | ||
365 | } | ||
372 | 366 | ||
373 | gpio_free(hdmi.ct_cp_hpd_gpio); | 367 | static void hdmi_phy_off(void) |
374 | gpio_free(hdmi.ls_oe_gpio); | 368 | { |
375 | gpio_free(hdmi.hpd_gpio); | 369 | hdmi_set_phy_pwr(HDMI_PHYPWRCMD_OFF); |
376 | } | 370 | } |
377 | 371 | ||
378 | static const struct hdmi_config *hdmi_find_timing( | 372 | static int hdmi_core_ddc_edid(u8 *pedid, int ext) |
379 | const struct hdmi_config *timings_arr, | ||
380 | int len) | ||
381 | { | 373 | { |
382 | int i; | 374 | u32 i, j; |
375 | char checksum = 0; | ||
376 | u32 offset = 0; | ||
377 | |||
378 | /* Turn on CLK for DDC */ | ||
379 | REG_FLD_MOD(HDMI_CORE_AV_DPD, 0x7, 2, 0); | ||
380 | |||
381 | /* | ||
382 | * SW HACK : Without the Delay DDC(i2c bus) reads 0 values / | ||
383 | * right shifted values( The behavior is not consistent and seen only | ||
384 | * with some TV's) | ||
385 | */ | ||
386 | usleep_range(800, 1000); | ||
387 | |||
388 | if (!ext) { | ||
389 | /* Clk SCL Devices */ | ||
390 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0xA, 3, 0); | ||
391 | |||
392 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
393 | if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, | ||
394 | 4, 4, 0) != 0) { | ||
395 | DSSERR("Failed to program DDC\n"); | ||
396 | return -ETIMEDOUT; | ||
397 | } | ||
398 | |||
399 | /* Clear FIFO */ | ||
400 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x9, 3, 0); | ||
401 | |||
402 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
403 | if (hdmi_wait_for_bit_change(HDMI_CORE_DDC_STATUS, | ||
404 | 4, 4, 0) != 0) { | ||
405 | DSSERR("Failed to program DDC\n"); | ||
406 | return -ETIMEDOUT; | ||
407 | } | ||
408 | |||
409 | } else { | ||
410 | if (ext % 2 != 0) | ||
411 | offset = 0x80; | ||
412 | } | ||
413 | |||
414 | /* Load Segment Address Register */ | ||
415 | REG_FLD_MOD(HDMI_CORE_DDC_SEGM, ext/2, 7, 0); | ||
416 | |||
417 | /* Load Slave Address Register */ | ||
418 | REG_FLD_MOD(HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); | ||
383 | 419 | ||
384 | for (i = 0; i < len; i++) { | 420 | /* Load Offset Address Register */ |
385 | if (timings_arr[i].cm.code == hdmi.ip_data.cfg.cm.code) | 421 | REG_FLD_MOD(HDMI_CORE_DDC_OFFSET, offset, 7, 0); |
386 | return &timings_arr[i]; | 422 | |
423 | /* Load Byte Count */ | ||
424 | REG_FLD_MOD(HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); | ||
425 | REG_FLD_MOD(HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); | ||
426 | |||
427 | /* Set DDC_CMD */ | ||
428 | if (ext) | ||
429 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x4, 3, 0); | ||
430 | else | ||
431 | REG_FLD_MOD(HDMI_CORE_DDC_CMD, 0x2, 3, 0); | ||
432 | |||
433 | /* HDMI_CORE_DDC_STATUS_BUS_LOW */ | ||
434 | if (REG_GET(HDMI_CORE_DDC_STATUS, 6, 6) == 1) { | ||
435 | DSSWARN("I2C Bus Low?\n"); | ||
436 | return -EIO; | ||
437 | } | ||
438 | /* HDMI_CORE_DDC_STATUS_NO_ACK */ | ||
439 | if (REG_GET(HDMI_CORE_DDC_STATUS, 5, 5) == 1) { | ||
440 | DSSWARN("I2C No Ack\n"); | ||
441 | return -EIO; | ||
442 | } | ||
443 | |||
444 | i = ext * 128; | ||
445 | j = 0; | ||
446 | while (((REG_GET(HDMI_CORE_DDC_STATUS, 4, 4) == 1) || | ||
447 | (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0)) && | ||
448 | j < 128) { | ||
449 | |||
450 | if (REG_GET(HDMI_CORE_DDC_STATUS, 2, 2) == 0) { | ||
451 | /* FIFO not empty */ | ||
452 | pedid[i++] = REG_GET(HDMI_CORE_DDC_DATA, 7, 0); | ||
453 | j++; | ||
454 | } | ||
387 | } | 455 | } |
388 | return NULL; | 456 | |
457 | for (j = 0; j < 128; j++) | ||
458 | checksum += pedid[j]; | ||
459 | |||
460 | if (checksum != 0) { | ||
461 | DSSERR("E-EDID checksum failed!!\n"); | ||
462 | return -EIO; | ||
463 | } | ||
464 | |||
465 | return 0; | ||
389 | } | 466 | } |
390 | 467 | ||
391 | static const struct hdmi_config *hdmi_get_timings(void) | 468 | static int read_edid(u8 *pedid, u16 max_length) |
392 | { | 469 | { |
393 | const struct hdmi_config *arr; | 470 | int r = 0, n = 0, i = 0; |
394 | int len; | 471 | int max_ext_blocks = (max_length / 128) - 1; |
395 | 472 | ||
396 | if (hdmi.ip_data.cfg.cm.mode == HDMI_DVI) { | 473 | r = hdmi_core_ddc_edid(pedid, 0); |
397 | arr = vesa_timings; | 474 | if (r) { |
398 | len = ARRAY_SIZE(vesa_timings); | 475 | return r; |
399 | } else { | 476 | } else { |
400 | arr = cea_timings; | 477 | n = pedid[0x7e]; |
401 | len = ARRAY_SIZE(cea_timings); | 478 | |
402 | } | 479 | /* |
403 | 480 | * README: need to comply with max_length set by the caller. | |
404 | return hdmi_find_timing(arr, len); | 481 | * Better implementation should be to allocate necessary |
482 | * memory to store EDID according to nb_block field found | ||
483 | * in first block | ||
484 | */ | ||
485 | if (n > max_ext_blocks) | ||
486 | n = max_ext_blocks; | ||
487 | |||
488 | for (i = 1; i <= n; i++) { | ||
489 | r = hdmi_core_ddc_edid(pedid, i); | ||
490 | if (r) | ||
491 | return r; | ||
492 | } | ||
493 | } | ||
494 | return 0; | ||
405 | } | 495 | } |
406 | 496 | ||
407 | static bool hdmi_timings_compare(struct omap_video_timings *timing1, | 497 | static int get_timings_index(void) |
408 | const struct omap_video_timings *timing2) | ||
409 | { | 498 | { |
410 | int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; | 499 | int code; |
411 | 500 | ||
412 | if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) == | 501 | if (hdmi.mode == 0) |
413 | DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) && | 502 | code = code_vesa[hdmi.code]; |
414 | (timing2->x_res == timing1->x_res) && | 503 | else |
415 | (timing2->y_res == timing1->y_res)) { | 504 | code = code_cea[hdmi.code]; |
416 | 505 | ||
417 | timing2_hsync = timing2->hfp + timing2->hsw + timing2->hbp; | 506 | if (code == -1) { |
418 | timing1_hsync = timing1->hfp + timing1->hsw + timing1->hbp; | 507 | /* HDMI code 4 corresponds to 640 * 480 VGA */ |
419 | timing2_vsync = timing2->vfp + timing2->vsw + timing2->vbp; | 508 | hdmi.code = 4; |
420 | timing1_vsync = timing2->vfp + timing2->vsw + timing2->vbp; | 509 | /* DVI mode 1 corresponds to HDMI 0 to DVI */ |
421 | 510 | hdmi.mode = HDMI_DVI; | |
422 | DSSDBG("timing1_hsync = %d timing1_vsync = %d"\ | 511 | |
423 | "timing2_hsync = %d timing2_vsync = %d\n", | 512 | code = code_vesa[hdmi.code]; |
424 | timing1_hsync, timing1_vsync, | ||
425 | timing2_hsync, timing2_vsync); | ||
426 | |||
427 | if ((timing1_hsync == timing2_hsync) && | ||
428 | (timing1_vsync == timing2_vsync)) { | ||
429 | return true; | ||
430 | } | ||
431 | } | 513 | } |
432 | return false; | 514 | return code; |
433 | } | 515 | } |
434 | 516 | ||
435 | static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) | 517 | static struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing) |
436 | { | 518 | { |
437 | int i; | 519 | int i = 0, code = -1, temp_vsync = 0, temp_hsync = 0; |
520 | int timing_vsync = 0, timing_hsync = 0; | ||
521 | struct omap_video_timings temp; | ||
438 | struct hdmi_cm cm = {-1}; | 522 | struct hdmi_cm cm = {-1}; |
439 | DSSDBG("hdmi_get_code\n"); | 523 | DSSDBG("hdmi_get_code\n"); |
440 | 524 | ||
441 | for (i = 0; i < ARRAY_SIZE(cea_timings); i++) { | 525 | for (i = 0; i < OMAP_HDMI_TIMINGS_NB; i++) { |
442 | if (hdmi_timings_compare(timing, &cea_timings[i].timings)) { | 526 | temp = cea_vesa_timings[i].timings; |
443 | cm = cea_timings[i].cm; | 527 | if ((temp.pixel_clock == timing->pixel_clock) && |
444 | goto end; | 528 | (temp.x_res == timing->x_res) && |
529 | (temp.y_res == timing->y_res)) { | ||
530 | |||
531 | temp_hsync = temp.hfp + temp.hsw + temp.hbp; | ||
532 | timing_hsync = timing->hfp + timing->hsw + timing->hbp; | ||
533 | temp_vsync = temp.vfp + temp.vsw + temp.vbp; | ||
534 | timing_vsync = timing->vfp + timing->vsw + timing->vbp; | ||
535 | |||
536 | DSSDBG("temp_hsync = %d , temp_vsync = %d" | ||
537 | "timing_hsync = %d, timing_vsync = %d\n", | ||
538 | temp_hsync, temp_hsync, | ||
539 | timing_hsync, timing_vsync); | ||
540 | |||
541 | if ((temp_hsync == timing_hsync) && | ||
542 | (temp_vsync == timing_vsync)) { | ||
543 | code = i; | ||
544 | cm.code = code_index[i]; | ||
545 | if (code < 14) | ||
546 | cm.mode = HDMI_HDMI; | ||
547 | else | ||
548 | cm.mode = HDMI_DVI; | ||
549 | DSSDBG("Hdmi_code = %d mode = %d\n", | ||
550 | cm.code, cm.mode); | ||
551 | break; | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | return cm; | ||
557 | } | ||
558 | |||
559 | static void get_horz_vert_timing_info(int current_descriptor_addrs, u8 *edid , | ||
560 | struct omap_video_timings *timings) | ||
561 | { | ||
562 | /* X and Y resolution */ | ||
563 | timings->x_res = (((edid[current_descriptor_addrs + 4] & 0xF0) << 4) | | ||
564 | edid[current_descriptor_addrs + 2]); | ||
565 | timings->y_res = (((edid[current_descriptor_addrs + 7] & 0xF0) << 4) | | ||
566 | edid[current_descriptor_addrs + 5]); | ||
567 | |||
568 | timings->pixel_clock = ((edid[current_descriptor_addrs + 1] << 8) | | ||
569 | edid[current_descriptor_addrs]); | ||
570 | |||
571 | timings->pixel_clock = 10 * timings->pixel_clock; | ||
572 | |||
573 | /* HORIZONTAL FRONT PORCH */ | ||
574 | timings->hfp = edid[current_descriptor_addrs + 8] | | ||
575 | ((edid[current_descriptor_addrs + 11] & 0xc0) << 2); | ||
576 | /* HORIZONTAL SYNC WIDTH */ | ||
577 | timings->hsw = edid[current_descriptor_addrs + 9] | | ||
578 | ((edid[current_descriptor_addrs + 11] & 0x30) << 4); | ||
579 | /* HORIZONTAL BACK PORCH */ | ||
580 | timings->hbp = (((edid[current_descriptor_addrs + 4] & 0x0F) << 8) | | ||
581 | edid[current_descriptor_addrs + 3]) - | ||
582 | (timings->hfp + timings->hsw); | ||
583 | /* VERTICAL FRONT PORCH */ | ||
584 | timings->vfp = ((edid[current_descriptor_addrs + 10] & 0xF0) >> 4) | | ||
585 | ((edid[current_descriptor_addrs + 11] & 0x0f) << 2); | ||
586 | /* VERTICAL SYNC WIDTH */ | ||
587 | timings->vsw = (edid[current_descriptor_addrs + 10] & 0x0F) | | ||
588 | ((edid[current_descriptor_addrs + 11] & 0x03) << 4); | ||
589 | /* VERTICAL BACK PORCH */ | ||
590 | timings->vbp = (((edid[current_descriptor_addrs + 7] & 0x0F) << 8) | | ||
591 | edid[current_descriptor_addrs + 6]) - | ||
592 | (timings->vfp + timings->vsw); | ||
593 | |||
594 | } | ||
595 | |||
596 | /* Description : This function gets the resolution information from EDID */ | ||
597 | static void get_edid_timing_data(u8 *edid) | ||
598 | { | ||
599 | u8 count; | ||
600 | u16 current_descriptor_addrs; | ||
601 | struct hdmi_cm cm; | ||
602 | struct omap_video_timings edid_timings; | ||
603 | |||
604 | /* search block 0, there are 4 DTDs arranged in priority order */ | ||
605 | for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) { | ||
606 | current_descriptor_addrs = | ||
607 | EDID_DESCRIPTOR_BLOCK0_ADDRESS + | ||
608 | count * EDID_TIMING_DESCRIPTOR_SIZE; | ||
609 | get_horz_vert_timing_info(current_descriptor_addrs, | ||
610 | edid, &edid_timings); | ||
611 | cm = hdmi_get_code(&edid_timings); | ||
612 | DSSDBG("Block0[%d] value matches code = %d , mode = %d\n", | ||
613 | count, cm.code, cm.mode); | ||
614 | if (cm.code == -1) { | ||
615 | continue; | ||
616 | } else { | ||
617 | hdmi.code = cm.code; | ||
618 | hdmi.mode = cm.mode; | ||
619 | DSSDBG("code = %d , mode = %d\n", | ||
620 | hdmi.code, hdmi.mode); | ||
621 | return; | ||
445 | } | 622 | } |
446 | } | 623 | } |
447 | for (i = 0; i < ARRAY_SIZE(vesa_timings); i++) { | 624 | if (edid[0x7e] != 0x00) { |
448 | if (hdmi_timings_compare(timing, &vesa_timings[i].timings)) { | 625 | for (count = 0; count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR; |
449 | cm = vesa_timings[i].cm; | 626 | count++) { |
450 | goto end; | 627 | current_descriptor_addrs = |
628 | EDID_DESCRIPTOR_BLOCK1_ADDRESS + | ||
629 | count * EDID_TIMING_DESCRIPTOR_SIZE; | ||
630 | get_horz_vert_timing_info(current_descriptor_addrs, | ||
631 | edid, &edid_timings); | ||
632 | cm = hdmi_get_code(&edid_timings); | ||
633 | DSSDBG("Block1[%d] value matches code = %d, mode = %d", | ||
634 | count, cm.code, cm.mode); | ||
635 | if (cm.code == -1) { | ||
636 | continue; | ||
637 | } else { | ||
638 | hdmi.code = cm.code; | ||
639 | hdmi.mode = cm.mode; | ||
640 | DSSDBG("code = %d , mode = %d\n", | ||
641 | hdmi.code, hdmi.mode); | ||
642 | return; | ||
643 | } | ||
451 | } | 644 | } |
452 | } | 645 | } |
453 | 646 | ||
454 | end: return cm; | 647 | DSSINFO("no valid timing found , falling back to VGA\n"); |
648 | hdmi.code = 4; /* setting default value of 640 480 VGA */ | ||
649 | hdmi.mode = HDMI_DVI; | ||
650 | } | ||
651 | |||
652 | static void hdmi_read_edid(struct omap_video_timings *dp) | ||
653 | { | ||
654 | int ret = 0, code; | ||
655 | |||
656 | memset(hdmi.edid, 0, HDMI_EDID_MAX_LENGTH); | ||
657 | |||
658 | if (!hdmi.edid_set) | ||
659 | ret = read_edid(hdmi.edid, HDMI_EDID_MAX_LENGTH); | ||
660 | |||
661 | if (!ret) { | ||
662 | if (!memcmp(hdmi.edid, edid_header, sizeof(edid_header))) { | ||
663 | /* search for timings of default resolution */ | ||
664 | get_edid_timing_data(hdmi.edid); | ||
665 | hdmi.edid_set = true; | ||
666 | } | ||
667 | } else { | ||
668 | DSSWARN("failed to read E-EDID\n"); | ||
669 | } | ||
670 | |||
671 | if (!hdmi.edid_set) { | ||
672 | DSSINFO("fallback to VGA\n"); | ||
673 | hdmi.code = 4; /* setting default value of 640 480 VGA */ | ||
674 | hdmi.mode = HDMI_DVI; | ||
675 | } | ||
676 | |||
677 | code = get_timings_index(); | ||
678 | |||
679 | *dp = cea_vesa_timings[code].timings; | ||
680 | } | ||
681 | |||
682 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, | ||
683 | struct hdmi_core_infoframe_avi *avi_cfg, | ||
684 | struct hdmi_core_packet_enable_repeat *repeat_cfg) | ||
685 | { | ||
686 | DSSDBG("Enter hdmi_core_init\n"); | ||
687 | |||
688 | /* video core */ | ||
689 | video_cfg->ip_bus_width = HDMI_INPUT_8BIT; | ||
690 | video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT; | ||
691 | video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE; | ||
692 | video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; | ||
693 | video_cfg->hdmi_dvi = HDMI_DVI; | ||
694 | video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; | ||
695 | |||
696 | /* info frame */ | ||
697 | avi_cfg->db1_format = 0; | ||
698 | avi_cfg->db1_active_info = 0; | ||
699 | avi_cfg->db1_bar_info_dv = 0; | ||
700 | avi_cfg->db1_scan_info = 0; | ||
701 | avi_cfg->db2_colorimetry = 0; | ||
702 | avi_cfg->db2_aspect_ratio = 0; | ||
703 | avi_cfg->db2_active_fmt_ar = 0; | ||
704 | avi_cfg->db3_itc = 0; | ||
705 | avi_cfg->db3_ec = 0; | ||
706 | avi_cfg->db3_q_range = 0; | ||
707 | avi_cfg->db3_nup_scaling = 0; | ||
708 | avi_cfg->db4_videocode = 0; | ||
709 | avi_cfg->db5_pixel_repeat = 0; | ||
710 | avi_cfg->db6_7_line_eoftop = 0 ; | ||
711 | avi_cfg->db8_9_line_sofbottom = 0; | ||
712 | avi_cfg->db10_11_pixel_eofleft = 0; | ||
713 | avi_cfg->db12_13_pixel_sofright = 0; | ||
714 | |||
715 | /* packet enable and repeat */ | ||
716 | repeat_cfg->audio_pkt = 0; | ||
717 | repeat_cfg->audio_pkt_repeat = 0; | ||
718 | repeat_cfg->avi_infoframe = 0; | ||
719 | repeat_cfg->avi_infoframe_repeat = 0; | ||
720 | repeat_cfg->gen_cntrl_pkt = 0; | ||
721 | repeat_cfg->gen_cntrl_pkt_repeat = 0; | ||
722 | repeat_cfg->generic_pkt = 0; | ||
723 | repeat_cfg->generic_pkt_repeat = 0; | ||
724 | } | ||
725 | |||
726 | static void hdmi_core_powerdown_disable(void) | ||
727 | { | ||
728 | DSSDBG("Enter hdmi_core_powerdown_disable\n"); | ||
729 | REG_FLD_MOD(HDMI_CORE_CTRL1, 0x0, 0, 0); | ||
730 | } | ||
731 | |||
732 | static void hdmi_core_swreset_release(void) | ||
733 | { | ||
734 | DSSDBG("Enter hdmi_core_swreset_release\n"); | ||
735 | REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x0, 0, 0); | ||
736 | } | ||
737 | |||
738 | static void hdmi_core_swreset_assert(void) | ||
739 | { | ||
740 | DSSDBG("Enter hdmi_core_swreset_assert\n"); | ||
741 | REG_FLD_MOD(HDMI_CORE_SYS_SRST, 0x1, 0, 0); | ||
742 | } | ||
743 | |||
744 | /* DSS_HDMI_CORE_VIDEO_CONFIG */ | ||
745 | static void hdmi_core_video_config(struct hdmi_core_video_config *cfg) | ||
746 | { | ||
747 | u32 r = 0; | ||
748 | |||
749 | /* sys_ctrl1 default configuration not tunable */ | ||
750 | r = hdmi_read_reg(HDMI_CORE_CTRL1); | ||
751 | r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5); | ||
752 | r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4); | ||
753 | r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2); | ||
754 | r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1); | ||
755 | hdmi_write_reg(HDMI_CORE_CTRL1, r); | ||
756 | |||
757 | REG_FLD_MOD(HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6); | ||
758 | |||
759 | /* Vid_Mode */ | ||
760 | r = hdmi_read_reg(HDMI_CORE_SYS_VID_MODE); | ||
761 | |||
762 | /* dither truncation configuration */ | ||
763 | if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) { | ||
764 | r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6); | ||
765 | r = FLD_MOD(r, 1, 5, 5); | ||
766 | } else { | ||
767 | r = FLD_MOD(r, cfg->op_dither_truc, 7, 6); | ||
768 | r = FLD_MOD(r, 0, 5, 5); | ||
769 | } | ||
770 | hdmi_write_reg(HDMI_CORE_SYS_VID_MODE, r); | ||
771 | |||
772 | /* HDMI_Ctrl */ | ||
773 | r = hdmi_read_reg(HDMI_CORE_AV_HDMI_CTRL); | ||
774 | r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6); | ||
775 | r = FLD_MOD(r, cfg->pkt_mode, 5, 3); | ||
776 | r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0); | ||
777 | hdmi_write_reg(HDMI_CORE_AV_HDMI_CTRL, r); | ||
778 | |||
779 | /* TMDS_CTRL */ | ||
780 | REG_FLD_MOD(HDMI_CORE_SYS_TMDS_CTRL, | ||
781 | cfg->tclk_sel_clkmult, 6, 5); | ||
782 | } | ||
783 | |||
784 | static void hdmi_core_aux_infoframe_avi_config( | ||
785 | struct hdmi_core_infoframe_avi info_avi) | ||
786 | { | ||
787 | u32 val; | ||
788 | char sum = 0, checksum = 0; | ||
789 | |||
790 | sum += 0x82 + 0x002 + 0x00D; | ||
791 | hdmi_write_reg(HDMI_CORE_AV_AVI_TYPE, 0x082); | ||
792 | hdmi_write_reg(HDMI_CORE_AV_AVI_VERS, 0x002); | ||
793 | hdmi_write_reg(HDMI_CORE_AV_AVI_LEN, 0x00D); | ||
794 | |||
795 | val = (info_avi.db1_format << 5) | | ||
796 | (info_avi.db1_active_info << 4) | | ||
797 | (info_avi.db1_bar_info_dv << 2) | | ||
798 | (info_avi.db1_scan_info); | ||
799 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(0), val); | ||
800 | sum += val; | ||
801 | |||
802 | val = (info_avi.db2_colorimetry << 6) | | ||
803 | (info_avi.db2_aspect_ratio << 4) | | ||
804 | (info_avi.db2_active_fmt_ar); | ||
805 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(1), val); | ||
806 | sum += val; | ||
807 | |||
808 | val = (info_avi.db3_itc << 7) | | ||
809 | (info_avi.db3_ec << 4) | | ||
810 | (info_avi.db3_q_range << 2) | | ||
811 | (info_avi.db3_nup_scaling); | ||
812 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(2), val); | ||
813 | sum += val; | ||
814 | |||
815 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(3), info_avi.db4_videocode); | ||
816 | sum += info_avi.db4_videocode; | ||
817 | |||
818 | val = info_avi.db5_pixel_repeat; | ||
819 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(4), val); | ||
820 | sum += val; | ||
821 | |||
822 | val = info_avi.db6_7_line_eoftop & 0x00FF; | ||
823 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(5), val); | ||
824 | sum += val; | ||
825 | |||
826 | val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); | ||
827 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(6), val); | ||
828 | sum += val; | ||
829 | |||
830 | val = info_avi.db8_9_line_sofbottom & 0x00FF; | ||
831 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(7), val); | ||
832 | sum += val; | ||
833 | |||
834 | val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); | ||
835 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(8), val); | ||
836 | sum += val; | ||
837 | |||
838 | val = info_avi.db10_11_pixel_eofleft & 0x00FF; | ||
839 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(9), val); | ||
840 | sum += val; | ||
841 | |||
842 | val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); | ||
843 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(10), val); | ||
844 | sum += val; | ||
845 | |||
846 | val = info_avi.db12_13_pixel_sofright & 0x00FF; | ||
847 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(11), val); | ||
848 | sum += val; | ||
849 | |||
850 | val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); | ||
851 | hdmi_write_reg(HDMI_CORE_AV_AVI_DBYTE(12), val); | ||
852 | sum += val; | ||
853 | |||
854 | checksum = 0x100 - sum; | ||
855 | hdmi_write_reg(HDMI_CORE_AV_AVI_CHSUM, checksum); | ||
856 | } | ||
857 | |||
858 | static void hdmi_core_av_packet_config( | ||
859 | struct hdmi_core_packet_enable_repeat repeat_cfg) | ||
860 | { | ||
861 | /* enable/repeat the infoframe */ | ||
862 | hdmi_write_reg(HDMI_CORE_AV_PB_CTRL1, | ||
863 | (repeat_cfg.audio_pkt << 5) | | ||
864 | (repeat_cfg.audio_pkt_repeat << 4) | | ||
865 | (repeat_cfg.avi_infoframe << 1) | | ||
866 | (repeat_cfg.avi_infoframe_repeat)); | ||
867 | |||
868 | /* enable/repeat the packet */ | ||
869 | hdmi_write_reg(HDMI_CORE_AV_PB_CTRL2, | ||
870 | (repeat_cfg.gen_cntrl_pkt << 3) | | ||
871 | (repeat_cfg.gen_cntrl_pkt_repeat << 2) | | ||
872 | (repeat_cfg.generic_pkt << 1) | | ||
873 | (repeat_cfg.generic_pkt_repeat)); | ||
874 | } | ||
875 | |||
876 | static void hdmi_wp_init(struct omap_video_timings *timings, | ||
877 | struct hdmi_video_format *video_fmt, | ||
878 | struct hdmi_video_interface *video_int) | ||
879 | { | ||
880 | DSSDBG("Enter hdmi_wp_init\n"); | ||
881 | |||
882 | timings->hbp = 0; | ||
883 | timings->hfp = 0; | ||
884 | timings->hsw = 0; | ||
885 | timings->vbp = 0; | ||
886 | timings->vfp = 0; | ||
887 | timings->vsw = 0; | ||
888 | |||
889 | video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; | ||
890 | video_fmt->y_res = 0; | ||
891 | video_fmt->x_res = 0; | ||
892 | |||
893 | video_int->vsp = 0; | ||
894 | video_int->hsp = 0; | ||
895 | |||
896 | video_int->interlacing = 0; | ||
897 | video_int->tm = 0; /* HDMI_TIMING_SLAVE */ | ||
898 | |||
899 | } | ||
900 | |||
901 | static void hdmi_wp_video_start(bool start) | ||
902 | { | ||
903 | REG_FLD_MOD(HDMI_WP_VIDEO_CFG, start, 31, 31); | ||
904 | } | ||
905 | |||
906 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, | ||
907 | struct omap_video_timings *timings, struct hdmi_config *param) | ||
908 | { | ||
909 | DSSDBG("Enter hdmi_wp_video_init_format\n"); | ||
910 | |||
911 | video_fmt->y_res = param->timings.timings.y_res; | ||
912 | video_fmt->x_res = param->timings.timings.x_res; | ||
913 | |||
914 | timings->hbp = param->timings.timings.hbp; | ||
915 | timings->hfp = param->timings.timings.hfp; | ||
916 | timings->hsw = param->timings.timings.hsw; | ||
917 | timings->vbp = param->timings.timings.vbp; | ||
918 | timings->vfp = param->timings.timings.vfp; | ||
919 | timings->vsw = param->timings.timings.vsw; | ||
920 | } | ||
921 | |||
922 | static void hdmi_wp_video_config_format( | ||
923 | struct hdmi_video_format *video_fmt) | ||
924 | { | ||
925 | u32 l = 0; | ||
926 | |||
927 | REG_FLD_MOD(HDMI_WP_VIDEO_CFG, video_fmt->packing_mode, 10, 8); | ||
928 | |||
929 | l |= FLD_VAL(video_fmt->y_res, 31, 16); | ||
930 | l |= FLD_VAL(video_fmt->x_res, 15, 0); | ||
931 | hdmi_write_reg(HDMI_WP_VIDEO_SIZE, l); | ||
932 | } | ||
933 | |||
934 | static void hdmi_wp_video_config_interface( | ||
935 | struct hdmi_video_interface *video_int) | ||
936 | { | ||
937 | u32 r; | ||
938 | DSSDBG("Enter hdmi_wp_video_config_interface\n"); | ||
939 | |||
940 | r = hdmi_read_reg(HDMI_WP_VIDEO_CFG); | ||
941 | r = FLD_MOD(r, video_int->vsp, 7, 7); | ||
942 | r = FLD_MOD(r, video_int->hsp, 6, 6); | ||
943 | r = FLD_MOD(r, video_int->interlacing, 3, 3); | ||
944 | r = FLD_MOD(r, video_int->tm, 1, 0); | ||
945 | hdmi_write_reg(HDMI_WP_VIDEO_CFG, r); | ||
946 | } | ||
947 | |||
948 | static void hdmi_wp_video_config_timing( | ||
949 | struct omap_video_timings *timings) | ||
950 | { | ||
951 | u32 timing_h = 0; | ||
952 | u32 timing_v = 0; | ||
953 | |||
954 | DSSDBG("Enter hdmi_wp_video_config_timing\n"); | ||
955 | |||
956 | timing_h |= FLD_VAL(timings->hbp, 31, 20); | ||
957 | timing_h |= FLD_VAL(timings->hfp, 19, 8); | ||
958 | timing_h |= FLD_VAL(timings->hsw, 7, 0); | ||
959 | hdmi_write_reg(HDMI_WP_VIDEO_TIMING_H, timing_h); | ||
960 | |||
961 | timing_v |= FLD_VAL(timings->vbp, 31, 20); | ||
962 | timing_v |= FLD_VAL(timings->vfp, 19, 8); | ||
963 | timing_v |= FLD_VAL(timings->vsw, 7, 0); | ||
964 | hdmi_write_reg(HDMI_WP_VIDEO_TIMING_V, timing_v); | ||
965 | } | ||
966 | |||
967 | static void hdmi_basic_configure(struct hdmi_config *cfg) | ||
968 | { | ||
969 | /* HDMI */ | ||
970 | struct omap_video_timings video_timing; | ||
971 | struct hdmi_video_format video_format; | ||
972 | struct hdmi_video_interface video_interface; | ||
973 | /* HDMI core */ | ||
974 | struct hdmi_core_infoframe_avi avi_cfg; | ||
975 | struct hdmi_core_video_config v_core_cfg; | ||
976 | struct hdmi_core_packet_enable_repeat repeat_cfg; | ||
977 | |||
978 | hdmi_wp_init(&video_timing, &video_format, | ||
979 | &video_interface); | ||
980 | |||
981 | hdmi_core_init(&v_core_cfg, | ||
982 | &avi_cfg, | ||
983 | &repeat_cfg); | ||
984 | |||
985 | hdmi_wp_video_init_format(&video_format, | ||
986 | &video_timing, cfg); | ||
987 | |||
988 | hdmi_wp_video_config_timing(&video_timing); | ||
989 | |||
990 | /* video config */ | ||
991 | video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; | ||
455 | 992 | ||
993 | hdmi_wp_video_config_format(&video_format); | ||
994 | |||
995 | video_interface.vsp = cfg->timings.vsync_pol; | ||
996 | video_interface.hsp = cfg->timings.hsync_pol; | ||
997 | video_interface.interlacing = cfg->interlace; | ||
998 | video_interface.tm = 1 ; /* HDMI_TIMING_MASTER_24BIT */ | ||
999 | |||
1000 | hdmi_wp_video_config_interface(&video_interface); | ||
1001 | |||
1002 | /* | ||
1003 | * configure core video part | ||
1004 | * set software reset in the core | ||
1005 | */ | ||
1006 | hdmi_core_swreset_assert(); | ||
1007 | |||
1008 | /* power down off */ | ||
1009 | hdmi_core_powerdown_disable(); | ||
1010 | |||
1011 | v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; | ||
1012 | v_core_cfg.hdmi_dvi = cfg->cm.mode; | ||
1013 | |||
1014 | hdmi_core_video_config(&v_core_cfg); | ||
1015 | |||
1016 | /* release software reset in the core */ | ||
1017 | hdmi_core_swreset_release(); | ||
1018 | |||
1019 | /* | ||
1020 | * configure packet | ||
1021 | * info frame video see doc CEA861-D page 65 | ||
1022 | */ | ||
1023 | avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; | ||
1024 | avi_cfg.db1_active_info = | ||
1025 | HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; | ||
1026 | avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; | ||
1027 | avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; | ||
1028 | avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; | ||
1029 | avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; | ||
1030 | avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; | ||
1031 | avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; | ||
1032 | avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; | ||
1033 | avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; | ||
1034 | avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; | ||
1035 | avi_cfg.db4_videocode = cfg->cm.code; | ||
1036 | avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; | ||
1037 | avi_cfg.db6_7_line_eoftop = 0; | ||
1038 | avi_cfg.db8_9_line_sofbottom = 0; | ||
1039 | avi_cfg.db10_11_pixel_eofleft = 0; | ||
1040 | avi_cfg.db12_13_pixel_sofright = 0; | ||
1041 | |||
1042 | hdmi_core_aux_infoframe_avi_config(avi_cfg); | ||
1043 | |||
1044 | /* enable/repeat the infoframe */ | ||
1045 | repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; | ||
1046 | repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; | ||
1047 | /* wakeup */ | ||
1048 | repeat_cfg.audio_pkt = HDMI_PACKETENABLE; | ||
1049 | repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; | ||
1050 | hdmi_core_av_packet_config(repeat_cfg); | ||
456 | } | 1051 | } |
457 | 1052 | ||
458 | unsigned long hdmi_get_pixel_clock(void) | 1053 | static void update_hdmi_timings(struct hdmi_config *cfg, |
1054 | struct omap_video_timings *timings, int code) | ||
459 | { | 1055 | { |
460 | /* HDMI Pixel Clock in Mhz */ | 1056 | cfg->timings.timings.x_res = timings->x_res; |
461 | return hdmi.ip_data.cfg.timings.pixel_clock * 1000; | 1057 | cfg->timings.timings.y_res = timings->y_res; |
1058 | cfg->timings.timings.hbp = timings->hbp; | ||
1059 | cfg->timings.timings.hfp = timings->hfp; | ||
1060 | cfg->timings.timings.hsw = timings->hsw; | ||
1061 | cfg->timings.timings.vbp = timings->vbp; | ||
1062 | cfg->timings.timings.vfp = timings->vfp; | ||
1063 | cfg->timings.timings.vsw = timings->vsw; | ||
1064 | cfg->timings.timings.pixel_clock = timings->pixel_clock; | ||
1065 | cfg->timings.vsync_pol = cea_vesa_timings[code].vsync_pol; | ||
1066 | cfg->timings.hsync_pol = cea_vesa_timings[code].hsync_pol; | ||
462 | } | 1067 | } |
463 | 1068 | ||
464 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | 1069 | static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, |
@@ -472,161 +1077,123 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
472 | * Input clock is predivided by N + 1 | 1077 | * Input clock is predivided by N + 1 |
473 | * out put of which is reference clk | 1078 | * out put of which is reference clk |
474 | */ | 1079 | */ |
475 | if (dssdev->clocks.hdmi.regn == 0) | 1080 | pi->regn = dssdev->clocks.hdmi.regn; |
476 | pi->regn = HDMI_DEFAULT_REGN; | 1081 | refclk = clkin / (pi->regn + 1); |
477 | else | ||
478 | pi->regn = dssdev->clocks.hdmi.regn; | ||
479 | |||
480 | refclk = clkin / pi->regn; | ||
481 | |||
482 | if (dssdev->clocks.hdmi.regm2 == 0) | ||
483 | pi->regm2 = HDMI_DEFAULT_REGM2; | ||
484 | else | ||
485 | pi->regm2 = dssdev->clocks.hdmi.regm2; | ||
486 | 1082 | ||
487 | /* | 1083 | /* |
488 | * multiplier is pixel_clk/ref_clk | 1084 | * multiplier is pixel_clk/ref_clk |
489 | * Multiplying by 100 to avoid fractional part removal | 1085 | * Multiplying by 100 to avoid fractional part removal |
490 | */ | 1086 | */ |
491 | pi->regm = phy * pi->regm2 / refclk; | 1087 | pi->regm = (phy * 100 / (refclk)) / 100; |
1088 | pi->regm2 = dssdev->clocks.hdmi.regm2; | ||
492 | 1089 | ||
493 | /* | 1090 | /* |
494 | * fractional multiplier is remainder of the difference between | 1091 | * fractional multiplier is remainder of the difference between |
495 | * multiplier and actual phy(required pixel clock thus should be | 1092 | * multiplier and actual phy(required pixel clock thus should be |
496 | * multiplied by 2^18(262144) divided by the reference clock | 1093 | * multiplied by 2^18(262144) divided by the reference clock |
497 | */ | 1094 | */ |
498 | mf = (phy - pi->regm / pi->regm2 * refclk) * 262144; | 1095 | mf = (phy - pi->regm * refclk) * 262144; |
499 | pi->regmf = pi->regm2 * mf / refclk; | 1096 | pi->regmf = mf / (refclk); |
500 | 1097 | ||
501 | /* | 1098 | /* |
502 | * Dcofreq should be set to 1 if required pixel clock | 1099 | * Dcofreq should be set to 1 if required pixel clock |
503 | * is greater than 1000MHz | 1100 | * is greater than 1000MHz |
504 | */ | 1101 | */ |
505 | pi->dcofreq = phy > 1000 * 100; | 1102 | pi->dcofreq = phy > 1000 * 100; |
506 | pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10; | 1103 | pi->regsd = ((pi->regm * clkin / 10) / ((pi->regn + 1) * 250) + 5) / 10; |
507 | |||
508 | /* Set the reference clock to sysclk reference */ | ||
509 | pi->refsel = HDMI_REFSEL_SYSCLK; | ||
510 | 1104 | ||
511 | DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); | 1105 | DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf); |
512 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); | 1106 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); |
513 | } | 1107 | } |
514 | 1108 | ||
515 | static int hdmi_power_on_core(struct omap_dss_device *dssdev) | 1109 | static int hdmi_power_on(struct omap_dss_device *dssdev) |
516 | { | ||
517 | int r; | ||
518 | |||
519 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); | ||
520 | gpio_set_value(hdmi.ls_oe_gpio, 1); | ||
521 | |||
522 | /* wait 300us after CT_CP_HPD for the 5V power output to reach 90% */ | ||
523 | udelay(300); | ||
524 | |||
525 | r = regulator_enable(hdmi.vdda_hdmi_dac_reg); | ||
526 | if (r) | ||
527 | goto err_vdac_enable; | ||
528 | |||
529 | r = hdmi_runtime_get(); | ||
530 | if (r) | ||
531 | goto err_runtime_get; | ||
532 | |||
533 | /* Make selection of HDMI in DSS */ | ||
534 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
535 | |||
536 | return 0; | ||
537 | |||
538 | err_runtime_get: | ||
539 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
540 | err_vdac_enable: | ||
541 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
542 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
543 | return r; | ||
544 | } | ||
545 | |||
546 | static void hdmi_power_off_core(struct omap_dss_device *dssdev) | ||
547 | { | ||
548 | hdmi_runtime_put(); | ||
549 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
550 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
551 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
552 | } | ||
553 | |||
554 | static int hdmi_power_on_full(struct omap_dss_device *dssdev) | ||
555 | { | 1110 | { |
556 | int r; | 1111 | int r, code = 0; |
1112 | struct hdmi_pll_info pll_data; | ||
557 | struct omap_video_timings *p; | 1113 | struct omap_video_timings *p; |
558 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
559 | unsigned long phy; | 1114 | unsigned long phy; |
560 | 1115 | ||
561 | r = hdmi_power_on_core(dssdev); | 1116 | r = hdmi_runtime_get(); |
562 | if (r) | 1117 | if (r) |
563 | return r; | 1118 | return r; |
564 | 1119 | ||
565 | dss_mgr_disable(mgr); | 1120 | dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); |
566 | 1121 | ||
567 | p = &hdmi.ip_data.cfg.timings; | 1122 | p = &dssdev->panel.timings; |
568 | 1123 | ||
569 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res); | 1124 | DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", |
1125 | dssdev->panel.timings.x_res, | ||
1126 | dssdev->panel.timings.y_res); | ||
1127 | |||
1128 | if (!hdmi.custom_set) { | ||
1129 | DSSDBG("Read EDID as no EDID is not set on poweron\n"); | ||
1130 | hdmi_read_edid(p); | ||
1131 | } | ||
1132 | code = get_timings_index(); | ||
1133 | dssdev->panel.timings = cea_vesa_timings[code].timings; | ||
1134 | update_hdmi_timings(&hdmi.cfg, p, code); | ||
570 | 1135 | ||
571 | phy = p->pixel_clock; | 1136 | phy = p->pixel_clock; |
572 | 1137 | ||
573 | hdmi_compute_pll(dssdev, phy, &hdmi.ip_data.pll_data); | 1138 | hdmi_compute_pll(dssdev, phy, &pll_data); |
574 | 1139 | ||
575 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | 1140 | hdmi_wp_video_start(0); |
576 | 1141 | ||
577 | /* config the PLL and PHY hdmi_set_pll_pwrfirst */ | 1142 | /* config the PLL and PHY first */ |
578 | r = hdmi.ip_data.ops->pll_enable(&hdmi.ip_data); | 1143 | r = hdmi_pll_program(&pll_data); |
579 | if (r) { | 1144 | if (r) { |
580 | DSSDBG("Failed to lock PLL\n"); | 1145 | DSSDBG("Failed to lock PLL\n"); |
581 | goto err_pll_enable; | 1146 | goto err; |
582 | } | 1147 | } |
583 | 1148 | ||
584 | r = hdmi.ip_data.ops->phy_enable(&hdmi.ip_data); | 1149 | r = hdmi_phy_init(); |
585 | if (r) { | 1150 | if (r) { |
586 | DSSDBG("Failed to start PHY\n"); | 1151 | DSSDBG("Failed to start PHY\n"); |
587 | goto err_phy_enable; | 1152 | goto err; |
588 | } | 1153 | } |
589 | 1154 | ||
590 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); | 1155 | hdmi.cfg.cm.mode = hdmi.mode; |
1156 | hdmi.cfg.cm.code = hdmi.code; | ||
1157 | hdmi_basic_configure(&hdmi.cfg); | ||
1158 | |||
1159 | /* Make selection of HDMI in DSS */ | ||
1160 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
1161 | |||
1162 | /* Select the dispc clock source as PRCM clock, to ensure that it is not | ||
1163 | * DSI PLL source as the clock selected by DSI PLL might not be | ||
1164 | * sufficient for the resolution selected / that can be changed | ||
1165 | * dynamically by user. This can be moved to single location , say | ||
1166 | * Boardfile. | ||
1167 | */ | ||
1168 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | ||
591 | 1169 | ||
592 | /* bypass TV gamma table */ | 1170 | /* bypass TV gamma table */ |
593 | dispc_enable_gamma_table(0); | 1171 | dispc_enable_gamma_table(0); |
594 | 1172 | ||
595 | /* tv size */ | 1173 | /* tv size */ |
596 | dss_mgr_set_timings(mgr, p); | 1174 | dispc_set_digit_size(dssdev->panel.timings.x_res, |
1175 | dssdev->panel.timings.y_res); | ||
597 | 1176 | ||
598 | r = hdmi.ip_data.ops->video_enable(&hdmi.ip_data); | 1177 | dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 1); |
599 | if (r) | ||
600 | goto err_vid_enable; | ||
601 | 1178 | ||
602 | r = dss_mgr_enable(mgr); | 1179 | hdmi_wp_video_start(1); |
603 | if (r) | ||
604 | goto err_mgr_enable; | ||
605 | 1180 | ||
606 | return 0; | 1181 | return 0; |
607 | 1182 | err: | |
608 | err_mgr_enable: | 1183 | hdmi_runtime_put(); |
609 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | ||
610 | err_vid_enable: | ||
611 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | ||
612 | err_phy_enable: | ||
613 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | ||
614 | err_pll_enable: | ||
615 | hdmi_power_off_core(dssdev); | ||
616 | return -EIO; | 1184 | return -EIO; |
617 | } | 1185 | } |
618 | 1186 | ||
619 | static void hdmi_power_off_full(struct omap_dss_device *dssdev) | 1187 | static void hdmi_power_off(struct omap_dss_device *dssdev) |
620 | { | 1188 | { |
621 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 1189 | dispc_enable_channel(OMAP_DSS_CHANNEL_DIGIT, 0); |
622 | |||
623 | dss_mgr_disable(mgr); | ||
624 | 1190 | ||
625 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | 1191 | hdmi_wp_video_start(0); |
626 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 1192 | hdmi_phy_off(); |
627 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 1193 | hdmi_set_pll_pwr(HDMI_PLLPWRCMD_ALLOFF); |
1194 | hdmi_runtime_put(); | ||
628 | 1195 | ||
629 | hdmi_power_off_core(dssdev); | 1196 | hdmi.edid_set = 0; |
630 | } | 1197 | } |
631 | 1198 | ||
632 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 1199 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
@@ -636,6 +1203,7 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | |||
636 | 1203 | ||
637 | cm = hdmi_get_code(timings); | 1204 | cm = hdmi_get_code(timings); |
638 | if (cm.code == -1) { | 1205 | if (cm.code == -1) { |
1206 | DSSERR("Invalid timing entered\n"); | ||
639 | return -EINVAL; | 1207 | return -EINVAL; |
640 | } | 1208 | } |
641 | 1209 | ||
@@ -643,108 +1211,52 @@ int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | |||
643 | 1211 | ||
644 | } | 1212 | } |
645 | 1213 | ||
646 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev, | 1214 | void omapdss_hdmi_display_set_timing(struct omap_dss_device *dssdev) |
647 | struct omap_video_timings *timings) | ||
648 | { | 1215 | { |
649 | struct hdmi_cm cm; | 1216 | struct hdmi_cm cm; |
650 | const struct hdmi_config *t; | ||
651 | |||
652 | mutex_lock(&hdmi.lock); | ||
653 | |||
654 | cm = hdmi_get_code(timings); | ||
655 | hdmi.ip_data.cfg.cm = cm; | ||
656 | |||
657 | t = hdmi_get_timings(); | ||
658 | if (t != NULL) | ||
659 | hdmi.ip_data.cfg = *t; | ||
660 | 1217 | ||
661 | mutex_unlock(&hdmi.lock); | 1218 | hdmi.custom_set = 1; |
662 | } | 1219 | cm = hdmi_get_code(&dssdev->panel.timings); |
663 | 1220 | hdmi.code = cm.code; | |
664 | static void hdmi_dump_regs(struct seq_file *s) | 1221 | hdmi.mode = cm.mode; |
665 | { | 1222 | omapdss_hdmi_display_enable(dssdev); |
666 | mutex_lock(&hdmi.lock); | 1223 | hdmi.custom_set = 0; |
667 | |||
668 | if (hdmi_runtime_get()) { | ||
669 | mutex_unlock(&hdmi.lock); | ||
670 | return; | ||
671 | } | ||
672 | |||
673 | hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); | ||
674 | hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); | ||
675 | hdmi.ip_data.ops->dump_phy(&hdmi.ip_data, s); | ||
676 | hdmi.ip_data.ops->dump_core(&hdmi.ip_data, s); | ||
677 | |||
678 | hdmi_runtime_put(); | ||
679 | mutex_unlock(&hdmi.lock); | ||
680 | } | ||
681 | |||
682 | int omapdss_hdmi_read_edid(u8 *buf, int len) | ||
683 | { | ||
684 | int r; | ||
685 | |||
686 | mutex_lock(&hdmi.lock); | ||
687 | |||
688 | r = hdmi_runtime_get(); | ||
689 | BUG_ON(r); | ||
690 | |||
691 | r = hdmi.ip_data.ops->read_edid(&hdmi.ip_data, buf, len); | ||
692 | |||
693 | hdmi_runtime_put(); | ||
694 | mutex_unlock(&hdmi.lock); | ||
695 | |||
696 | return r; | ||
697 | } | ||
698 | |||
699 | bool omapdss_hdmi_detect(void) | ||
700 | { | ||
701 | int r; | ||
702 | |||
703 | mutex_lock(&hdmi.lock); | ||
704 | |||
705 | r = hdmi_runtime_get(); | ||
706 | BUG_ON(r); | ||
707 | |||
708 | r = hdmi.ip_data.ops->detect(&hdmi.ip_data); | ||
709 | |||
710 | hdmi_runtime_put(); | ||
711 | mutex_unlock(&hdmi.lock); | ||
712 | |||
713 | return r == 1; | ||
714 | } | 1224 | } |
715 | 1225 | ||
716 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | 1226 | int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) |
717 | { | 1227 | { |
718 | struct omap_dss_output *out = dssdev->output; | ||
719 | int r = 0; | 1228 | int r = 0; |
720 | 1229 | ||
721 | DSSDBG("ENTER hdmi_display_enable\n"); | 1230 | DSSDBG("ENTER hdmi_display_enable\n"); |
722 | 1231 | ||
723 | mutex_lock(&hdmi.lock); | 1232 | mutex_lock(&hdmi.lock); |
724 | 1233 | ||
725 | if (out == NULL || out->manager == NULL) { | ||
726 | DSSERR("failed to enable display: no output/manager\n"); | ||
727 | r = -ENODEV; | ||
728 | goto err0; | ||
729 | } | ||
730 | |||
731 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; | ||
732 | |||
733 | r = omap_dss_start_device(dssdev); | 1234 | r = omap_dss_start_device(dssdev); |
734 | if (r) { | 1235 | if (r) { |
735 | DSSERR("failed to start device\n"); | 1236 | DSSERR("failed to start device\n"); |
736 | goto err0; | 1237 | goto err0; |
737 | } | 1238 | } |
738 | 1239 | ||
739 | r = hdmi_power_on_full(dssdev); | 1240 | if (dssdev->platform_enable) { |
1241 | r = dssdev->platform_enable(dssdev); | ||
1242 | if (r) { | ||
1243 | DSSERR("failed to enable GPIO's\n"); | ||
1244 | goto err1; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | r = hdmi_power_on(dssdev); | ||
740 | if (r) { | 1249 | if (r) { |
741 | DSSERR("failed to power on device\n"); | 1250 | DSSERR("failed to power on device\n"); |
742 | goto err1; | 1251 | goto err2; |
743 | } | 1252 | } |
744 | 1253 | ||
745 | mutex_unlock(&hdmi.lock); | 1254 | mutex_unlock(&hdmi.lock); |
746 | return 0; | 1255 | return 0; |
747 | 1256 | ||
1257 | err2: | ||
1258 | if (dssdev->platform_disable) | ||
1259 | dssdev->platform_disable(dssdev); | ||
748 | err1: | 1260 | err1: |
749 | omap_dss_stop_device(dssdev); | 1261 | omap_dss_stop_device(dssdev); |
750 | err0: | 1262 | err0: |
@@ -758,395 +1270,527 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
758 | 1270 | ||
759 | mutex_lock(&hdmi.lock); | 1271 | mutex_lock(&hdmi.lock); |
760 | 1272 | ||
761 | hdmi_power_off_full(dssdev); | 1273 | hdmi_power_off(dssdev); |
1274 | |||
1275 | if (dssdev->platform_disable) | ||
1276 | dssdev->platform_disable(dssdev); | ||
762 | 1277 | ||
763 | omap_dss_stop_device(dssdev); | 1278 | omap_dss_stop_device(dssdev); |
764 | 1279 | ||
765 | mutex_unlock(&hdmi.lock); | 1280 | mutex_unlock(&hdmi.lock); |
766 | } | 1281 | } |
767 | 1282 | ||
768 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) | 1283 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
1284 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1285 | static void hdmi_wp_audio_config_format( | ||
1286 | struct hdmi_audio_format *aud_fmt) | ||
769 | { | 1287 | { |
770 | int r = 0; | 1288 | u32 r; |
1289 | |||
1290 | DSSDBG("Enter hdmi_wp_audio_config_format\n"); | ||
1291 | |||
1292 | r = hdmi_read_reg(HDMI_WP_AUDIO_CFG); | ||
1293 | r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); | ||
1294 | r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); | ||
1295 | r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); | ||
1296 | r = FLD_MOD(r, aud_fmt->type, 4, 4); | ||
1297 | r = FLD_MOD(r, aud_fmt->justification, 3, 3); | ||
1298 | r = FLD_MOD(r, aud_fmt->sample_order, 2, 2); | ||
1299 | r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1); | ||
1300 | r = FLD_MOD(r, aud_fmt->sample_size, 0, 0); | ||
1301 | hdmi_write_reg(HDMI_WP_AUDIO_CFG, r); | ||
1302 | } | ||
771 | 1303 | ||
772 | DSSDBG("ENTER omapdss_hdmi_core_enable\n"); | 1304 | static void hdmi_wp_audio_config_dma(struct hdmi_audio_dma *aud_dma) |
1305 | { | ||
1306 | u32 r; | ||
773 | 1307 | ||
774 | mutex_lock(&hdmi.lock); | 1308 | DSSDBG("Enter hdmi_wp_audio_config_dma\n"); |
775 | 1309 | ||
776 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; | 1310 | r = hdmi_read_reg(HDMI_WP_AUDIO_CFG2); |
1311 | r = FLD_MOD(r, aud_dma->transfer_size, 15, 8); | ||
1312 | r = FLD_MOD(r, aud_dma->block_size, 7, 0); | ||
1313 | hdmi_write_reg(HDMI_WP_AUDIO_CFG2, r); | ||
777 | 1314 | ||
778 | r = hdmi_power_on_core(dssdev); | 1315 | r = hdmi_read_reg(HDMI_WP_AUDIO_CTRL); |
779 | if (r) { | 1316 | r = FLD_MOD(r, aud_dma->mode, 9, 9); |
780 | DSSERR("failed to power on device\n"); | 1317 | r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0); |
781 | goto err0; | 1318 | hdmi_write_reg(HDMI_WP_AUDIO_CTRL, r); |
782 | } | 1319 | } |
783 | 1320 | ||
784 | mutex_unlock(&hdmi.lock); | 1321 | static void hdmi_core_audio_config(struct hdmi_core_audio_config *cfg) |
785 | return 0; | 1322 | { |
1323 | u32 r; | ||
1324 | |||
1325 | /* audio clock recovery parameters */ | ||
1326 | r = hdmi_read_reg(HDMI_CORE_AV_ACR_CTRL); | ||
1327 | r = FLD_MOD(r, cfg->use_mclk, 2, 2); | ||
1328 | r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); | ||
1329 | r = FLD_MOD(r, cfg->cts_mode, 0, 0); | ||
1330 | hdmi_write_reg(HDMI_CORE_AV_ACR_CTRL, r); | ||
1331 | |||
1332 | REG_FLD_MOD(HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); | ||
1333 | REG_FLD_MOD(HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); | ||
1334 | REG_FLD_MOD(HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); | ||
1335 | |||
1336 | if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) { | ||
1337 | REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0); | ||
1338 | REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0); | ||
1339 | REG_FLD_MOD(HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); | ||
1340 | } else { | ||
1341 | /* | ||
1342 | * HDMI IP uses this configuration to divide the MCLK to | ||
1343 | * update CTS value. | ||
1344 | */ | ||
1345 | REG_FLD_MOD(HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); | ||
1346 | |||
1347 | /* Configure clock for audio packets */ | ||
1348 | REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_1, | ||
1349 | cfg->aud_par_busclk, 7, 0); | ||
1350 | REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_2, | ||
1351 | (cfg->aud_par_busclk >> 8), 7, 0); | ||
1352 | REG_FLD_MOD(HDMI_CORE_AV_AUD_PAR_BUSCLK_3, | ||
1353 | (cfg->aud_par_busclk >> 16), 7, 0); | ||
1354 | } | ||
786 | 1355 | ||
787 | err0: | 1356 | /* Override of SPDIF sample frequency with value in I2S_CHST4 */ |
788 | mutex_unlock(&hdmi.lock); | 1357 | REG_FLD_MOD(HDMI_CORE_AV_SPDIF_CTRL, cfg->fs_override, 1, 1); |
789 | return r; | 1358 | |
1359 | /* I2S parameters */ | ||
1360 | REG_FLD_MOD(HDMI_CORE_AV_I2S_CHST4, cfg->freq_sample, 3, 0); | ||
1361 | |||
1362 | r = hdmi_read_reg(HDMI_CORE_AV_I2S_IN_CTRL); | ||
1363 | r = FLD_MOD(r, cfg->i2s_cfg.en_high_bitrate_aud, 7, 7); | ||
1364 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); | ||
1365 | r = FLD_MOD(r, cfg->i2s_cfg.cbit_order, 5, 5); | ||
1366 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); | ||
1367 | r = FLD_MOD(r, cfg->i2s_cfg.ws_polarity, 3, 3); | ||
1368 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); | ||
1369 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); | ||
1370 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); | ||
1371 | hdmi_write_reg(HDMI_CORE_AV_I2S_IN_CTRL, r); | ||
1372 | |||
1373 | r = hdmi_read_reg(HDMI_CORE_AV_I2S_CHST5); | ||
1374 | r = FLD_MOD(r, cfg->freq_sample, 7, 4); | ||
1375 | r = FLD_MOD(r, cfg->i2s_cfg.word_length, 3, 1); | ||
1376 | r = FLD_MOD(r, cfg->i2s_cfg.word_max_length, 0, 0); | ||
1377 | hdmi_write_reg(HDMI_CORE_AV_I2S_CHST5, r); | ||
1378 | |||
1379 | REG_FLD_MOD(HDMI_CORE_AV_I2S_IN_LEN, cfg->i2s_cfg.in_length_bits, 3, 0); | ||
1380 | |||
1381 | /* Audio channels and mode parameters */ | ||
1382 | REG_FLD_MOD(HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1); | ||
1383 | r = hdmi_read_reg(HDMI_CORE_AV_AUD_MODE); | ||
1384 | r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4); | ||
1385 | r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3); | ||
1386 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); | ||
1387 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); | ||
1388 | hdmi_write_reg(HDMI_CORE_AV_AUD_MODE, r); | ||
790 | } | 1389 | } |
791 | 1390 | ||
792 | void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev) | 1391 | static void hdmi_core_audio_infoframe_config( |
1392 | struct hdmi_core_infoframe_audio *info_aud) | ||
793 | { | 1393 | { |
794 | DSSDBG("Enter omapdss_hdmi_core_disable\n"); | 1394 | u8 val; |
1395 | u8 sum = 0, checksum = 0; | ||
795 | 1396 | ||
796 | mutex_lock(&hdmi.lock); | 1397 | /* |
1398 | * Set audio info frame type, version and length as | ||
1399 | * described in HDMI 1.4a Section 8.2.2 specification. | ||
1400 | * Checksum calculation is defined in Section 5.3.5. | ||
1401 | */ | ||
1402 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_TYPE, 0x84); | ||
1403 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_VERS, 0x01); | ||
1404 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_LEN, 0x0a); | ||
1405 | sum += 0x84 + 0x001 + 0x00a; | ||
797 | 1406 | ||
798 | hdmi_power_off_core(dssdev); | 1407 | val = (info_aud->db1_coding_type << 4) |
1408 | | (info_aud->db1_channel_count - 1); | ||
1409 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(0), val); | ||
1410 | sum += val; | ||
799 | 1411 | ||
800 | mutex_unlock(&hdmi.lock); | 1412 | val = (info_aud->db2_sample_freq << 2) | info_aud->db2_sample_size; |
801 | } | 1413 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(1), val); |
1414 | sum += val; | ||
802 | 1415 | ||
803 | static int hdmi_get_clocks(struct platform_device *pdev) | 1416 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(2), 0x00); |
804 | { | ||
805 | struct clk *clk; | ||
806 | 1417 | ||
807 | clk = clk_get(&pdev->dev, "sys_clk"); | 1418 | val = info_aud->db4_channel_alloc; |
808 | if (IS_ERR(clk)) { | 1419 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(3), val); |
809 | DSSERR("can't get sys_clk\n"); | 1420 | sum += val; |
810 | return PTR_ERR(clk); | ||
811 | } | ||
812 | 1421 | ||
813 | hdmi.sys_clk = clk; | 1422 | val = (info_aud->db5_downmix_inh << 7) | (info_aud->db5_lsv << 3); |
1423 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(4), val); | ||
1424 | sum += val; | ||
814 | 1425 | ||
815 | return 0; | 1426 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(5), 0x00); |
816 | } | 1427 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(6), 0x00); |
1428 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(7), 0x00); | ||
1429 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(8), 0x00); | ||
1430 | hdmi_write_reg(HDMI_CORE_AV_AUD_DBYTE(9), 0x00); | ||
817 | 1431 | ||
818 | static void hdmi_put_clocks(void) | 1432 | checksum = 0x100 - sum; |
819 | { | 1433 | hdmi_write_reg(HDMI_CORE_AV_AUDIO_CHSUM, checksum); |
820 | if (hdmi.sys_clk) | 1434 | |
821 | clk_put(hdmi.sys_clk); | 1435 | /* |
1436 | * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing | ||
1437 | * is available. | ||
1438 | */ | ||
822 | } | 1439 | } |
823 | 1440 | ||
824 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | 1441 | static int hdmi_config_audio_acr(u32 sample_freq, u32 *n, u32 *cts) |
825 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts) | ||
826 | { | 1442 | { |
827 | u32 deep_color; | 1443 | u32 r; |
828 | bool deep_color_correct = false; | 1444 | u32 deep_color = 0; |
829 | u32 pclk = hdmi.ip_data.cfg.timings.pixel_clock; | 1445 | u32 pclk = hdmi.cfg.timings.timings.pixel_clock; |
830 | 1446 | ||
831 | if (n == NULL || cts == NULL) | 1447 | if (n == NULL || cts == NULL) |
832 | return -EINVAL; | 1448 | return -EINVAL; |
833 | |||
834 | /* TODO: When implemented, query deep color mode here. */ | ||
835 | deep_color = 100; | ||
836 | |||
837 | /* | 1449 | /* |
838 | * When using deep color, the default N value (as in the HDMI | 1450 | * Obtain current deep color configuration. This needed |
839 | * specification) yields to an non-integer CTS. Hence, we | 1451 | * to calculate the TMDS clock based on the pixel clock. |
840 | * modify it while keeping the restrictions described in | ||
841 | * section 7.2.1 of the HDMI 1.4a specification. | ||
842 | */ | 1452 | */ |
843 | switch (sample_freq) { | 1453 | r = REG_GET(HDMI_WP_VIDEO_CFG, 1, 0); |
844 | case 32000: | 1454 | switch (r) { |
845 | case 48000: | 1455 | case 1: /* No deep color selected */ |
846 | case 96000: | 1456 | deep_color = 100; |
847 | case 192000: | ||
848 | if (deep_color == 125) | ||
849 | if (pclk == 27027 || pclk == 74250) | ||
850 | deep_color_correct = true; | ||
851 | if (deep_color == 150) | ||
852 | if (pclk == 27027) | ||
853 | deep_color_correct = true; | ||
854 | break; | 1457 | break; |
855 | case 44100: | 1458 | case 2: /* 10-bit deep color selected */ |
856 | case 88200: | 1459 | deep_color = 125; |
857 | case 176400: | 1460 | break; |
858 | if (deep_color == 125) | 1461 | case 3: /* 12-bit deep color selected */ |
859 | if (pclk == 27027) | 1462 | deep_color = 150; |
860 | deep_color_correct = true; | ||
861 | break; | 1463 | break; |
862 | default: | 1464 | default: |
863 | return -EINVAL; | 1465 | return -EINVAL; |
864 | } | 1466 | } |
865 | 1467 | ||
866 | if (deep_color_correct) { | 1468 | switch (sample_freq) { |
867 | switch (sample_freq) { | 1469 | case 32000: |
868 | case 32000: | 1470 | if ((deep_color == 125) && ((pclk == 54054) |
869 | *n = 8192; | 1471 | || (pclk == 74250))) |
870 | break; | ||
871 | case 44100: | ||
872 | *n = 12544; | ||
873 | break; | ||
874 | case 48000: | ||
875 | *n = 8192; | 1472 | *n = 8192; |
876 | break; | 1473 | else |
877 | case 88200: | ||
878 | *n = 25088; | ||
879 | break; | ||
880 | case 96000: | ||
881 | *n = 16384; | ||
882 | break; | ||
883 | case 176400: | ||
884 | *n = 50176; | ||
885 | break; | ||
886 | case 192000: | ||
887 | *n = 32768; | ||
888 | break; | ||
889 | default: | ||
890 | return -EINVAL; | ||
891 | } | ||
892 | } else { | ||
893 | switch (sample_freq) { | ||
894 | case 32000: | ||
895 | *n = 4096; | 1474 | *n = 4096; |
896 | break; | 1475 | break; |
897 | case 44100: | 1476 | case 44100: |
898 | *n = 6272; | 1477 | *n = 6272; |
899 | break; | 1478 | break; |
900 | case 48000: | 1479 | case 48000: |
1480 | if ((deep_color == 125) && ((pclk == 54054) | ||
1481 | || (pclk == 74250))) | ||
1482 | *n = 8192; | ||
1483 | else | ||
901 | *n = 6144; | 1484 | *n = 6144; |
902 | break; | 1485 | break; |
903 | case 88200: | 1486 | default: |
904 | *n = 12544; | 1487 | *n = 0; |
905 | break; | 1488 | return -EINVAL; |
906 | case 96000: | ||
907 | *n = 12288; | ||
908 | break; | ||
909 | case 176400: | ||
910 | *n = 25088; | ||
911 | break; | ||
912 | case 192000: | ||
913 | *n = 24576; | ||
914 | break; | ||
915 | default: | ||
916 | return -EINVAL; | ||
917 | } | ||
918 | } | 1489 | } |
1490 | |||
919 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ | 1491 | /* Calculate CTS. See HDMI 1.3a or 1.4a specifications */ |
920 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); | 1492 | *cts = pclk * (*n / 128) * deep_color / (sample_freq / 10); |
921 | 1493 | ||
922 | return 0; | 1494 | return 0; |
923 | } | 1495 | } |
924 | 1496 | ||
925 | int hdmi_audio_enable(void) | 1497 | static int hdmi_audio_hw_params(struct snd_pcm_substream *substream, |
1498 | struct snd_pcm_hw_params *params, | ||
1499 | struct snd_soc_dai *dai) | ||
926 | { | 1500 | { |
927 | DSSDBG("audio_enable\n"); | 1501 | struct hdmi_audio_format audio_format; |
1502 | struct hdmi_audio_dma audio_dma; | ||
1503 | struct hdmi_core_audio_config core_cfg; | ||
1504 | struct hdmi_core_infoframe_audio aud_if_cfg; | ||
1505 | int err, n, cts; | ||
1506 | enum hdmi_core_audio_sample_freq sample_freq; | ||
1507 | |||
1508 | switch (params_format(params)) { | ||
1509 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1510 | core_cfg.i2s_cfg.word_max_length = | ||
1511 | HDMI_AUDIO_I2S_MAX_WORD_20BITS; | ||
1512 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_16_BITS; | ||
1513 | core_cfg.i2s_cfg.in_length_bits = | ||
1514 | HDMI_AUDIO_I2S_INPUT_LENGTH_16; | ||
1515 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1516 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
1517 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
1518 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1519 | audio_dma.transfer_size = 0x10; | ||
1520 | break; | ||
1521 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1522 | core_cfg.i2s_cfg.word_max_length = | ||
1523 | HDMI_AUDIO_I2S_MAX_WORD_24BITS; | ||
1524 | core_cfg.i2s_cfg.word_length = HDMI_AUDIO_I2S_CHST_WORD_24_BITS; | ||
1525 | core_cfg.i2s_cfg.in_length_bits = | ||
1526 | HDMI_AUDIO_I2S_INPUT_LENGTH_24; | ||
1527 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
1528 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
1529 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1530 | core_cfg.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1531 | audio_dma.transfer_size = 0x20; | ||
1532 | break; | ||
1533 | default: | ||
1534 | return -EINVAL; | ||
1535 | } | ||
928 | 1536 | ||
929 | return hdmi.ip_data.ops->audio_enable(&hdmi.ip_data); | 1537 | switch (params_rate(params)) { |
930 | } | 1538 | case 32000: |
1539 | sample_freq = HDMI_AUDIO_FS_32000; | ||
1540 | break; | ||
1541 | case 44100: | ||
1542 | sample_freq = HDMI_AUDIO_FS_44100; | ||
1543 | break; | ||
1544 | case 48000: | ||
1545 | sample_freq = HDMI_AUDIO_FS_48000; | ||
1546 | break; | ||
1547 | default: | ||
1548 | return -EINVAL; | ||
1549 | } | ||
931 | 1550 | ||
932 | void hdmi_audio_disable(void) | 1551 | err = hdmi_config_audio_acr(params_rate(params), &n, &cts); |
933 | { | 1552 | if (err < 0) |
934 | DSSDBG("audio_disable\n"); | 1553 | return err; |
935 | 1554 | ||
936 | hdmi.ip_data.ops->audio_disable(&hdmi.ip_data); | 1555 | /* Audio wrapper config */ |
937 | } | 1556 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; |
1557 | audio_format.active_chnnls_msk = 0x03; | ||
1558 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
1559 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
1560 | /* Disable start/stop signals of IEC 60958 blocks */ | ||
1561 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF; | ||
938 | 1562 | ||
939 | int hdmi_audio_start(void) | 1563 | audio_dma.block_size = 0xC0; |
940 | { | 1564 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; |
941 | DSSDBG("audio_start\n"); | 1565 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ |
942 | 1566 | ||
943 | return hdmi.ip_data.ops->audio_start(&hdmi.ip_data); | 1567 | hdmi_wp_audio_config_dma(&audio_dma); |
944 | } | 1568 | hdmi_wp_audio_config_format(&audio_format); |
945 | 1569 | ||
946 | void hdmi_audio_stop(void) | 1570 | /* |
947 | { | 1571 | * I2S config |
948 | DSSDBG("audio_stop\n"); | 1572 | */ |
1573 | core_cfg.i2s_cfg.en_high_bitrate_aud = false; | ||
1574 | /* Only used with high bitrate audio */ | ||
1575 | core_cfg.i2s_cfg.cbit_order = false; | ||
1576 | /* Serial data and word select should change on sck rising edge */ | ||
1577 | core_cfg.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
1578 | core_cfg.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
1579 | /* Set I2S word select polarity */ | ||
1580 | core_cfg.i2s_cfg.ws_polarity = HDMI_AUDIO_I2S_WS_POLARITY_LOW_IS_LEFT; | ||
1581 | core_cfg.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
1582 | /* Set serial data to word select shift. See Phillips spec. */ | ||
1583 | core_cfg.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
1584 | /* Enable one of the four available serial data channels */ | ||
1585 | core_cfg.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
1586 | |||
1587 | /* Core audio config */ | ||
1588 | core_cfg.freq_sample = sample_freq; | ||
1589 | core_cfg.n = n; | ||
1590 | core_cfg.cts = cts; | ||
1591 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | ||
1592 | core_cfg.aud_par_busclk = 0; | ||
1593 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
1594 | core_cfg.use_mclk = false; | ||
1595 | } else { | ||
1596 | core_cfg.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
1597 | core_cfg.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
1598 | core_cfg.use_mclk = true; | ||
1599 | core_cfg.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
1600 | } | ||
1601 | core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
1602 | core_cfg.en_spdif = false; | ||
1603 | /* Use sample frequency from channel status word */ | ||
1604 | core_cfg.fs_override = true; | ||
1605 | /* Enable ACR packets */ | ||
1606 | core_cfg.en_acr_pkt = true; | ||
1607 | /* Disable direct streaming digital audio */ | ||
1608 | core_cfg.en_dsd_audio = false; | ||
1609 | /* Use parallel audio interface */ | ||
1610 | core_cfg.en_parallel_aud_input = true; | ||
1611 | |||
1612 | hdmi_core_audio_config(&core_cfg); | ||
949 | 1613 | ||
950 | hdmi.ip_data.ops->audio_stop(&hdmi.ip_data); | 1614 | /* |
1615 | * Configure packet | ||
1616 | * info frame audio see doc CEA861-D page 74 | ||
1617 | */ | ||
1618 | aud_if_cfg.db1_coding_type = HDMI_INFOFRAME_AUDIO_DB1CT_FROM_STREAM; | ||
1619 | aud_if_cfg.db1_channel_count = 2; | ||
1620 | aud_if_cfg.db2_sample_freq = HDMI_INFOFRAME_AUDIO_DB2SF_FROM_STREAM; | ||
1621 | aud_if_cfg.db2_sample_size = HDMI_INFOFRAME_AUDIO_DB2SS_FROM_STREAM; | ||
1622 | aud_if_cfg.db4_channel_alloc = 0x00; | ||
1623 | aud_if_cfg.db5_downmix_inh = false; | ||
1624 | aud_if_cfg.db5_lsv = 0; | ||
1625 | |||
1626 | hdmi_core_audio_infoframe_config(&aud_if_cfg); | ||
1627 | return 0; | ||
951 | } | 1628 | } |
952 | 1629 | ||
953 | bool hdmi_mode_has_audio(void) | 1630 | static int hdmi_audio_trigger(struct snd_pcm_substream *substream, int cmd, |
1631 | struct snd_soc_dai *dai) | ||
954 | { | 1632 | { |
955 | if (hdmi.ip_data.cfg.cm.mode == HDMI_HDMI) | 1633 | int err = 0; |
956 | return true; | 1634 | switch (cmd) { |
957 | else | 1635 | case SNDRV_PCM_TRIGGER_START: |
958 | return false; | 1636 | case SNDRV_PCM_TRIGGER_RESUME: |
959 | } | 1637 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
1638 | REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 1, 0, 0); | ||
1639 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 31, 31); | ||
1640 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 1, 30, 30); | ||
1641 | break; | ||
960 | 1642 | ||
961 | int hdmi_audio_config(struct omap_dss_audio *audio) | 1643 | case SNDRV_PCM_TRIGGER_STOP: |
962 | { | 1644 | case SNDRV_PCM_TRIGGER_SUSPEND: |
963 | return hdmi.ip_data.ops->audio_config(&hdmi.ip_data, audio); | 1645 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1646 | REG_FLD_MOD(HDMI_CORE_AV_AUD_MODE, 0, 0, 0); | ||
1647 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 30, 30); | ||
1648 | REG_FLD_MOD(HDMI_WP_AUDIO_CTRL, 0, 31, 31); | ||
1649 | break; | ||
1650 | default: | ||
1651 | err = -EINVAL; | ||
1652 | } | ||
1653 | return err; | ||
964 | } | 1654 | } |
965 | 1655 | ||
966 | #endif | 1656 | static int hdmi_audio_startup(struct snd_pcm_substream *substream, |
967 | 1657 | struct snd_soc_dai *dai) | |
968 | static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) | ||
969 | { | 1658 | { |
970 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 1659 | if (!hdmi.mode) { |
971 | const char *def_disp_name = omapdss_get_default_display_name(); | 1660 | pr_err("Current video settings do not support audio.\n"); |
972 | struct omap_dss_device *def_dssdev; | 1661 | return -EIO; |
973 | int i; | ||
974 | |||
975 | def_dssdev = NULL; | ||
976 | |||
977 | for (i = 0; i < pdata->num_devices; ++i) { | ||
978 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
979 | |||
980 | if (dssdev->type != OMAP_DISPLAY_TYPE_HDMI) | ||
981 | continue; | ||
982 | |||
983 | if (def_dssdev == NULL) | ||
984 | def_dssdev = dssdev; | ||
985 | |||
986 | if (def_disp_name != NULL && | ||
987 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
988 | def_dssdev = dssdev; | ||
989 | break; | ||
990 | } | ||
991 | } | 1662 | } |
992 | 1663 | return 0; | |
993 | return def_dssdev; | ||
994 | } | 1664 | } |
995 | 1665 | ||
996 | static void __init hdmi_probe_pdata(struct platform_device *pdev) | 1666 | static struct snd_soc_codec_driver hdmi_audio_codec_drv = { |
997 | { | 1667 | }; |
998 | struct omap_dss_device *plat_dssdev; | ||
999 | struct omap_dss_device *dssdev; | ||
1000 | struct omap_dss_hdmi_data *priv; | ||
1001 | int r; | ||
1002 | |||
1003 | plat_dssdev = hdmi_find_dssdev(pdev); | ||
1004 | |||
1005 | if (!plat_dssdev) | ||
1006 | return; | ||
1007 | |||
1008 | dssdev = dss_alloc_and_init_device(&pdev->dev); | ||
1009 | if (!dssdev) | ||
1010 | return; | ||
1011 | |||
1012 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
1013 | 1668 | ||
1014 | priv = dssdev->data; | 1669 | static struct snd_soc_dai_ops hdmi_audio_codec_ops = { |
1670 | .hw_params = hdmi_audio_hw_params, | ||
1671 | .trigger = hdmi_audio_trigger, | ||
1672 | .startup = hdmi_audio_startup, | ||
1673 | }; | ||
1015 | 1674 | ||
1016 | hdmi.ct_cp_hpd_gpio = priv->ct_cp_hpd_gpio; | 1675 | static struct snd_soc_dai_driver hdmi_codec_dai_drv = { |
1017 | hdmi.ls_oe_gpio = priv->ls_oe_gpio; | 1676 | .name = "hdmi-audio-codec", |
1018 | hdmi.hpd_gpio = priv->hpd_gpio; | 1677 | .playback = { |
1678 | .channels_min = 2, | ||
1679 | .channels_max = 2, | ||
1680 | .rates = SNDRV_PCM_RATE_32000 | | ||
1681 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, | ||
1682 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
1683 | SNDRV_PCM_FMTBIT_S24_LE, | ||
1684 | }, | ||
1685 | .ops = &hdmi_audio_codec_ops, | ||
1686 | }; | ||
1687 | #endif | ||
1019 | 1688 | ||
1020 | dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; | 1689 | static int hdmi_get_clocks(struct platform_device *pdev) |
1690 | { | ||
1691 | struct clk *clk; | ||
1021 | 1692 | ||
1022 | r = hdmi_init_display(dssdev); | 1693 | clk = clk_get(&pdev->dev, "sys_clk"); |
1023 | if (r) { | 1694 | if (IS_ERR(clk)) { |
1024 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | 1695 | DSSERR("can't get sys_clk\n"); |
1025 | dss_put_device(dssdev); | 1696 | return PTR_ERR(clk); |
1026 | return; | ||
1027 | } | 1697 | } |
1028 | 1698 | ||
1029 | r = omapdss_output_set_device(&hdmi.output, dssdev); | 1699 | hdmi.sys_clk = clk; |
1030 | if (r) { | ||
1031 | DSSERR("failed to connect output to new device: %s\n", | ||
1032 | dssdev->name); | ||
1033 | dss_put_device(dssdev); | ||
1034 | return; | ||
1035 | } | ||
1036 | 1700 | ||
1037 | r = dss_add_device(dssdev); | 1701 | clk = clk_get(&pdev->dev, "dss_48mhz_clk"); |
1038 | if (r) { | 1702 | if (IS_ERR(clk)) { |
1039 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 1703 | DSSERR("can't get hdmi_clk\n"); |
1040 | omapdss_output_unset_device(&hdmi.output); | 1704 | clk_put(hdmi.sys_clk); |
1041 | hdmi_uninit_display(dssdev); | 1705 | return PTR_ERR(clk); |
1042 | dss_put_device(dssdev); | ||
1043 | return; | ||
1044 | } | 1706 | } |
1045 | } | ||
1046 | 1707 | ||
1047 | static void __init hdmi_init_output(struct platform_device *pdev) | 1708 | hdmi.hdmi_clk = clk; |
1048 | { | ||
1049 | struct omap_dss_output *out = &hdmi.output; | ||
1050 | 1709 | ||
1051 | out->pdev = pdev; | 1710 | return 0; |
1052 | out->id = OMAP_DSS_OUTPUT_HDMI; | ||
1053 | out->type = OMAP_DISPLAY_TYPE_HDMI; | ||
1054 | |||
1055 | dss_register_output(out); | ||
1056 | } | 1711 | } |
1057 | 1712 | ||
1058 | static void __exit hdmi_uninit_output(struct platform_device *pdev) | 1713 | static void hdmi_put_clocks(void) |
1059 | { | 1714 | { |
1060 | struct omap_dss_output *out = &hdmi.output; | 1715 | if (hdmi.sys_clk) |
1061 | 1716 | clk_put(hdmi.sys_clk); | |
1062 | dss_unregister_output(out); | 1717 | if (hdmi.hdmi_clk) |
1718 | clk_put(hdmi.hdmi_clk); | ||
1063 | } | 1719 | } |
1064 | 1720 | ||
1065 | /* HDMI HW IP initialisation */ | 1721 | /* HDMI HW IP initialisation */ |
1066 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | 1722 | static int omapdss_hdmihw_probe(struct platform_device *pdev) |
1067 | { | 1723 | { |
1068 | struct resource *res; | 1724 | struct resource *hdmi_mem; |
1069 | int r; | 1725 | int r; |
1070 | 1726 | ||
1727 | hdmi.pdata = pdev->dev.platform_data; | ||
1071 | hdmi.pdev = pdev; | 1728 | hdmi.pdev = pdev; |
1072 | 1729 | ||
1073 | mutex_init(&hdmi.lock); | 1730 | mutex_init(&hdmi.lock); |
1074 | mutex_init(&hdmi.ip_data.lock); | ||
1075 | 1731 | ||
1076 | res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); | 1732 | hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); |
1077 | if (!res) { | 1733 | if (!hdmi_mem) { |
1078 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); | 1734 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); |
1079 | return -EINVAL; | 1735 | return -EINVAL; |
1080 | } | 1736 | } |
1081 | 1737 | ||
1082 | /* Base address taken from platform */ | 1738 | /* Base address taken from platform */ |
1083 | hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res); | 1739 | hdmi.base_wp = ioremap(hdmi_mem->start, resource_size(hdmi_mem)); |
1084 | if (!hdmi.ip_data.base_wp) { | 1740 | if (!hdmi.base_wp) { |
1085 | DSSERR("can't ioremap WP\n"); | 1741 | DSSERR("can't ioremap WP\n"); |
1086 | return -ENOMEM; | 1742 | return -ENOMEM; |
1087 | } | 1743 | } |
1088 | 1744 | ||
1089 | r = hdmi_get_clocks(pdev); | 1745 | r = hdmi_get_clocks(pdev); |
1090 | if (r) { | 1746 | if (r) { |
1091 | DSSERR("can't get clocks\n"); | 1747 | iounmap(hdmi.base_wp); |
1092 | return r; | 1748 | return r; |
1093 | } | 1749 | } |
1094 | 1750 | ||
1095 | pm_runtime_enable(&pdev->dev); | 1751 | pm_runtime_enable(&pdev->dev); |
1096 | 1752 | ||
1097 | hdmi.ip_data.core_sys_offset = HDMI_CORE_SYS; | 1753 | hdmi_panel_init(); |
1098 | hdmi.ip_data.core_av_offset = HDMI_CORE_AV; | ||
1099 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | ||
1100 | hdmi.ip_data.phy_offset = HDMI_PHY; | ||
1101 | 1754 | ||
1102 | r = hdmi_panel_init(); | 1755 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
1756 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1757 | |||
1758 | /* Register ASoC codec DAI */ | ||
1759 | r = snd_soc_register_codec(&pdev->dev, &hdmi_audio_codec_drv, | ||
1760 | &hdmi_codec_dai_drv, 1); | ||
1103 | if (r) { | 1761 | if (r) { |
1104 | DSSERR("can't init panel\n"); | 1762 | DSSERR("can't register ASoC HDMI audio codec\n"); |
1105 | goto err_panel_init; | 1763 | return r; |
1106 | } | 1764 | } |
1107 | 1765 | #endif | |
1108 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | ||
1109 | |||
1110 | hdmi_init_output(pdev); | ||
1111 | |||
1112 | hdmi_probe_pdata(pdev); | ||
1113 | |||
1114 | return 0; | ||
1115 | |||
1116 | err_panel_init: | ||
1117 | hdmi_put_clocks(); | ||
1118 | return r; | ||
1119 | } | ||
1120 | |||
1121 | static int __exit hdmi_remove_child(struct device *dev, void *data) | ||
1122 | { | ||
1123 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
1124 | hdmi_uninit_display(dssdev); | ||
1125 | return 0; | 1766 | return 0; |
1126 | } | 1767 | } |
1127 | 1768 | ||
1128 | static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | 1769 | static int omapdss_hdmihw_remove(struct platform_device *pdev) |
1129 | { | 1770 | { |
1130 | device_for_each_child(&pdev->dev, NULL, hdmi_remove_child); | ||
1131 | |||
1132 | dss_unregister_child_devices(&pdev->dev); | ||
1133 | |||
1134 | hdmi_panel_exit(); | 1771 | hdmi_panel_exit(); |
1135 | 1772 | ||
1136 | hdmi_uninit_output(pdev); | 1773 | #if defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI) || \ |
1774 | defined(CONFIG_SND_OMAP_SOC_OMAP4_HDMI_MODULE) | ||
1775 | snd_soc_unregister_codec(&pdev->dev); | ||
1776 | #endif | ||
1137 | 1777 | ||
1138 | pm_runtime_disable(&pdev->dev); | 1778 | pm_runtime_disable(&pdev->dev); |
1139 | 1779 | ||
1140 | hdmi_put_clocks(); | 1780 | hdmi_put_clocks(); |
1141 | 1781 | ||
1782 | iounmap(hdmi.base_wp); | ||
1783 | |||
1142 | return 0; | 1784 | return 0; |
1143 | } | 1785 | } |
1144 | 1786 | ||
1145 | static int hdmi_runtime_suspend(struct device *dev) | 1787 | static int hdmi_runtime_suspend(struct device *dev) |
1146 | { | 1788 | { |
1147 | clk_disable_unprepare(hdmi.sys_clk); | 1789 | clk_disable(hdmi.hdmi_clk); |
1790 | clk_disable(hdmi.sys_clk); | ||
1148 | 1791 | ||
1149 | dispc_runtime_put(); | 1792 | dispc_runtime_put(); |
1793 | dss_runtime_put(); | ||
1150 | 1794 | ||
1151 | return 0; | 1795 | return 0; |
1152 | } | 1796 | } |
@@ -1155,13 +1799,24 @@ static int hdmi_runtime_resume(struct device *dev) | |||
1155 | { | 1799 | { |
1156 | int r; | 1800 | int r; |
1157 | 1801 | ||
1802 | r = dss_runtime_get(); | ||
1803 | if (r < 0) | ||
1804 | goto err_get_dss; | ||
1805 | |||
1158 | r = dispc_runtime_get(); | 1806 | r = dispc_runtime_get(); |
1159 | if (r < 0) | 1807 | if (r < 0) |
1160 | return r; | 1808 | goto err_get_dispc; |
1809 | |||
1161 | 1810 | ||
1162 | clk_prepare_enable(hdmi.sys_clk); | 1811 | clk_enable(hdmi.sys_clk); |
1812 | clk_enable(hdmi.hdmi_clk); | ||
1163 | 1813 | ||
1164 | return 0; | 1814 | return 0; |
1815 | |||
1816 | err_get_dispc: | ||
1817 | dss_runtime_put(); | ||
1818 | err_get_dss: | ||
1819 | return r; | ||
1165 | } | 1820 | } |
1166 | 1821 | ||
1167 | static const struct dev_pm_ops hdmi_pm_ops = { | 1822 | static const struct dev_pm_ops hdmi_pm_ops = { |
@@ -1170,7 +1825,8 @@ static const struct dev_pm_ops hdmi_pm_ops = { | |||
1170 | }; | 1825 | }; |
1171 | 1826 | ||
1172 | static struct platform_driver omapdss_hdmihw_driver = { | 1827 | static struct platform_driver omapdss_hdmihw_driver = { |
1173 | .remove = __exit_p(omapdss_hdmihw_remove), | 1828 | .probe = omapdss_hdmihw_probe, |
1829 | .remove = omapdss_hdmihw_remove, | ||
1174 | .driver = { | 1830 | .driver = { |
1175 | .name = "omapdss_hdmi", | 1831 | .name = "omapdss_hdmi", |
1176 | .owner = THIS_MODULE, | 1832 | .owner = THIS_MODULE, |
@@ -1178,12 +1834,12 @@ static struct platform_driver omapdss_hdmihw_driver = { | |||
1178 | }, | 1834 | }, |
1179 | }; | 1835 | }; |
1180 | 1836 | ||
1181 | int __init hdmi_init_platform_driver(void) | 1837 | int hdmi_init_platform_driver(void) |
1182 | { | 1838 | { |
1183 | return platform_driver_probe(&omapdss_hdmihw_driver, omapdss_hdmihw_probe); | 1839 | return platform_driver_register(&omapdss_hdmihw_driver); |
1184 | } | 1840 | } |
1185 | 1841 | ||
1186 | void __exit hdmi_uninit_platform_driver(void) | 1842 | void hdmi_uninit_platform_driver(void) |
1187 | { | 1843 | { |
1188 | platform_driver_unregister(&omapdss_hdmihw_driver); | 1844 | return platform_driver_unregister(&omapdss_hdmihw_driver); |
1189 | } | 1845 | } |
diff --git a/drivers/video/omap2/dss/hdmi_panel.c b/drivers/video/omap2/dss/hdmi_panel.c deleted file mode 100644 index dfb8eda81b6..00000000000 --- a/drivers/video/omap2/dss/hdmi_panel.c +++ /dev/null | |||
@@ -1,414 +0,0 @@ | |||
1 | /* | ||
2 | * hdmi_panel.c | ||
3 | * | ||
4 | * HDMI library support functions for TI OMAP4 processors. | ||
5 | * | ||
6 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * Authors: Mythri P k <mythripk@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/mutex.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <video/omapdss.h> | ||
28 | #include <linux/slab.h> | ||
29 | |||
30 | #include "dss.h" | ||
31 | |||
32 | static struct { | ||
33 | /* This protects the panel ops, mainly when accessing the HDMI IP. */ | ||
34 | struct mutex lock; | ||
35 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
36 | /* This protects the audio ops, specifically. */ | ||
37 | spinlock_t audio_lock; | ||
38 | #endif | ||
39 | } hdmi; | ||
40 | |||
41 | |||
42 | static int hdmi_panel_probe(struct omap_dss_device *dssdev) | ||
43 | { | ||
44 | /* Initialize default timings to VGA in DVI mode */ | ||
45 | const struct omap_video_timings default_timings = { | ||
46 | .x_res = 640, | ||
47 | .y_res = 480, | ||
48 | .pixel_clock = 25175, | ||
49 | .hsw = 96, | ||
50 | .hfp = 16, | ||
51 | .hbp = 48, | ||
52 | .vsw = 2, | ||
53 | .vfp = 11, | ||
54 | .vbp = 31, | ||
55 | |||
56 | .vsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
57 | .hsync_level = OMAPDSS_SIG_ACTIVE_LOW, | ||
58 | |||
59 | .interlace = false, | ||
60 | }; | ||
61 | |||
62 | DSSDBG("ENTER hdmi_panel_probe\n"); | ||
63 | |||
64 | dssdev->panel.timings = default_timings; | ||
65 | |||
66 | DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n", | ||
67 | dssdev->panel.timings.x_res, | ||
68 | dssdev->panel.timings.y_res); | ||
69 | |||
70 | omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | static void hdmi_panel_remove(struct omap_dss_device *dssdev) | ||
76 | { | ||
77 | |||
78 | } | ||
79 | |||
80 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
81 | static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) | ||
82 | { | ||
83 | unsigned long flags; | ||
84 | int r; | ||
85 | |||
86 | mutex_lock(&hdmi.lock); | ||
87 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
88 | |||
89 | /* enable audio only if the display is active and supports audio */ | ||
90 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || | ||
91 | !hdmi_mode_has_audio()) { | ||
92 | DSSERR("audio not supported or display is off\n"); | ||
93 | r = -EPERM; | ||
94 | goto err; | ||
95 | } | ||
96 | |||
97 | r = hdmi_audio_enable(); | ||
98 | |||
99 | if (!r) | ||
100 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
101 | |||
102 | err: | ||
103 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
104 | mutex_unlock(&hdmi.lock); | ||
105 | return r; | ||
106 | } | ||
107 | |||
108 | static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) | ||
109 | { | ||
110 | unsigned long flags; | ||
111 | |||
112 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
113 | |||
114 | hdmi_audio_disable(); | ||
115 | |||
116 | dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED; | ||
117 | |||
118 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
119 | } | ||
120 | |||
121 | static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) | ||
122 | { | ||
123 | unsigned long flags; | ||
124 | int r; | ||
125 | |||
126 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
127 | /* | ||
128 | * No need to check the panel state. It was checked when trasitioning | ||
129 | * to AUDIO_ENABLED. | ||
130 | */ | ||
131 | if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED) { | ||
132 | DSSERR("audio start from invalid state\n"); | ||
133 | r = -EPERM; | ||
134 | goto err; | ||
135 | } | ||
136 | |||
137 | r = hdmi_audio_start(); | ||
138 | |||
139 | if (!r) | ||
140 | dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING; | ||
141 | |||
142 | err: | ||
143 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
144 | return r; | ||
145 | } | ||
146 | |||
147 | static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) | ||
148 | { | ||
149 | unsigned long flags; | ||
150 | |||
151 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
152 | |||
153 | hdmi_audio_stop(); | ||
154 | dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED; | ||
155 | |||
156 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
157 | } | ||
158 | |||
159 | static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) | ||
160 | { | ||
161 | bool r = false; | ||
162 | |||
163 | mutex_lock(&hdmi.lock); | ||
164 | |||
165 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
166 | goto err; | ||
167 | |||
168 | if (!hdmi_mode_has_audio()) | ||
169 | goto err; | ||
170 | |||
171 | r = true; | ||
172 | err: | ||
173 | mutex_unlock(&hdmi.lock); | ||
174 | return r; | ||
175 | } | ||
176 | |||
177 | static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, | ||
178 | struct omap_dss_audio *audio) | ||
179 | { | ||
180 | unsigned long flags; | ||
181 | int r; | ||
182 | |||
183 | mutex_lock(&hdmi.lock); | ||
184 | spin_lock_irqsave(&hdmi.audio_lock, flags); | ||
185 | |||
186 | /* config audio only if the display is active and supports audio */ | ||
187 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE || | ||
188 | !hdmi_mode_has_audio()) { | ||
189 | DSSERR("audio not supported or display is off\n"); | ||
190 | r = -EPERM; | ||
191 | goto err; | ||
192 | } | ||
193 | |||
194 | r = hdmi_audio_config(audio); | ||
195 | |||
196 | if (!r) | ||
197 | dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED; | ||
198 | |||
199 | err: | ||
200 | spin_unlock_irqrestore(&hdmi.audio_lock, flags); | ||
201 | mutex_unlock(&hdmi.lock); | ||
202 | return r; | ||
203 | } | ||
204 | |||
205 | #else | ||
206 | static int hdmi_panel_audio_enable(struct omap_dss_device *dssdev) | ||
207 | { | ||
208 | return -EPERM; | ||
209 | } | ||
210 | |||
211 | static void hdmi_panel_audio_disable(struct omap_dss_device *dssdev) | ||
212 | { | ||
213 | } | ||
214 | |||
215 | static int hdmi_panel_audio_start(struct omap_dss_device *dssdev) | ||
216 | { | ||
217 | return -EPERM; | ||
218 | } | ||
219 | |||
220 | static void hdmi_panel_audio_stop(struct omap_dss_device *dssdev) | ||
221 | { | ||
222 | } | ||
223 | |||
224 | static bool hdmi_panel_audio_supported(struct omap_dss_device *dssdev) | ||
225 | { | ||
226 | return false; | ||
227 | } | ||
228 | |||
229 | static int hdmi_panel_audio_config(struct omap_dss_device *dssdev, | ||
230 | struct omap_dss_audio *audio) | ||
231 | { | ||
232 | return -EPERM; | ||
233 | } | ||
234 | #endif | ||
235 | |||
236 | static int hdmi_panel_enable(struct omap_dss_device *dssdev) | ||
237 | { | ||
238 | int r = 0; | ||
239 | DSSDBG("ENTER hdmi_panel_enable\n"); | ||
240 | |||
241 | mutex_lock(&hdmi.lock); | ||
242 | |||
243 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
244 | r = -EINVAL; | ||
245 | goto err; | ||
246 | } | ||
247 | |||
248 | omapdss_hdmi_display_set_timing(dssdev, &dssdev->panel.timings); | ||
249 | |||
250 | r = omapdss_hdmi_display_enable(dssdev); | ||
251 | if (r) { | ||
252 | DSSERR("failed to power on\n"); | ||
253 | goto err; | ||
254 | } | ||
255 | |||
256 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
257 | |||
258 | err: | ||
259 | mutex_unlock(&hdmi.lock); | ||
260 | |||
261 | return r; | ||
262 | } | ||
263 | |||
264 | static void hdmi_panel_disable(struct omap_dss_device *dssdev) | ||
265 | { | ||
266 | mutex_lock(&hdmi.lock); | ||
267 | |||
268 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
269 | /* | ||
270 | * TODO: notify audio users that the display was disabled. For | ||
271 | * now, disable audio locally to not break our audio state | ||
272 | * machine. | ||
273 | */ | ||
274 | hdmi_panel_audio_disable(dssdev); | ||
275 | omapdss_hdmi_display_disable(dssdev); | ||
276 | } | ||
277 | |||
278 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
279 | |||
280 | mutex_unlock(&hdmi.lock); | ||
281 | } | ||
282 | |||
283 | static void hdmi_get_timings(struct omap_dss_device *dssdev, | ||
284 | struct omap_video_timings *timings) | ||
285 | { | ||
286 | mutex_lock(&hdmi.lock); | ||
287 | |||
288 | *timings = dssdev->panel.timings; | ||
289 | |||
290 | mutex_unlock(&hdmi.lock); | ||
291 | } | ||
292 | |||
293 | static void hdmi_set_timings(struct omap_dss_device *dssdev, | ||
294 | struct omap_video_timings *timings) | ||
295 | { | ||
296 | DSSDBG("hdmi_set_timings\n"); | ||
297 | |||
298 | mutex_lock(&hdmi.lock); | ||
299 | |||
300 | /* | ||
301 | * TODO: notify audio users that there was a timings change. For | ||
302 | * now, disable audio locally to not break our audio state machine. | ||
303 | */ | ||
304 | hdmi_panel_audio_disable(dssdev); | ||
305 | |||
306 | omapdss_hdmi_display_set_timing(dssdev, timings); | ||
307 | dssdev->panel.timings = *timings; | ||
308 | |||
309 | mutex_unlock(&hdmi.lock); | ||
310 | } | ||
311 | |||
312 | static int hdmi_check_timings(struct omap_dss_device *dssdev, | ||
313 | struct omap_video_timings *timings) | ||
314 | { | ||
315 | int r = 0; | ||
316 | |||
317 | DSSDBG("hdmi_check_timings\n"); | ||
318 | |||
319 | mutex_lock(&hdmi.lock); | ||
320 | |||
321 | r = omapdss_hdmi_display_check_timing(dssdev, timings); | ||
322 | |||
323 | mutex_unlock(&hdmi.lock); | ||
324 | return r; | ||
325 | } | ||
326 | |||
327 | static int hdmi_read_edid(struct omap_dss_device *dssdev, u8 *buf, int len) | ||
328 | { | ||
329 | int r; | ||
330 | bool need_enable; | ||
331 | |||
332 | mutex_lock(&hdmi.lock); | ||
333 | |||
334 | need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED; | ||
335 | |||
336 | if (need_enable) { | ||
337 | r = omapdss_hdmi_core_enable(dssdev); | ||
338 | if (r) | ||
339 | goto err; | ||
340 | } | ||
341 | |||
342 | r = omapdss_hdmi_read_edid(buf, len); | ||
343 | |||
344 | if (need_enable) | ||
345 | omapdss_hdmi_core_disable(dssdev); | ||
346 | err: | ||
347 | mutex_unlock(&hdmi.lock); | ||
348 | |||
349 | return r; | ||
350 | } | ||
351 | |||
352 | static bool hdmi_detect(struct omap_dss_device *dssdev) | ||
353 | { | ||
354 | int r; | ||
355 | bool need_enable; | ||
356 | |||
357 | mutex_lock(&hdmi.lock); | ||
358 | |||
359 | need_enable = dssdev->state == OMAP_DSS_DISPLAY_DISABLED; | ||
360 | |||
361 | if (need_enable) { | ||
362 | r = omapdss_hdmi_core_enable(dssdev); | ||
363 | if (r) | ||
364 | goto err; | ||
365 | } | ||
366 | |||
367 | r = omapdss_hdmi_detect(); | ||
368 | |||
369 | if (need_enable) | ||
370 | omapdss_hdmi_core_disable(dssdev); | ||
371 | err: | ||
372 | mutex_unlock(&hdmi.lock); | ||
373 | |||
374 | return r; | ||
375 | } | ||
376 | |||
377 | static struct omap_dss_driver hdmi_driver = { | ||
378 | .probe = hdmi_panel_probe, | ||
379 | .remove = hdmi_panel_remove, | ||
380 | .enable = hdmi_panel_enable, | ||
381 | .disable = hdmi_panel_disable, | ||
382 | .get_timings = hdmi_get_timings, | ||
383 | .set_timings = hdmi_set_timings, | ||
384 | .check_timings = hdmi_check_timings, | ||
385 | .read_edid = hdmi_read_edid, | ||
386 | .detect = hdmi_detect, | ||
387 | .audio_enable = hdmi_panel_audio_enable, | ||
388 | .audio_disable = hdmi_panel_audio_disable, | ||
389 | .audio_start = hdmi_panel_audio_start, | ||
390 | .audio_stop = hdmi_panel_audio_stop, | ||
391 | .audio_supported = hdmi_panel_audio_supported, | ||
392 | .audio_config = hdmi_panel_audio_config, | ||
393 | .driver = { | ||
394 | .name = "hdmi_panel", | ||
395 | .owner = THIS_MODULE, | ||
396 | }, | ||
397 | }; | ||
398 | |||
399 | int hdmi_panel_init(void) | ||
400 | { | ||
401 | mutex_init(&hdmi.lock); | ||
402 | |||
403 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
404 | spin_lock_init(&hdmi.audio_lock); | ||
405 | #endif | ||
406 | |||
407 | return omap_dss_register_driver(&hdmi_driver); | ||
408 | } | ||
409 | |||
410 | void hdmi_panel_exit(void) | ||
411 | { | ||
412 | omap_dss_unregister_driver(&hdmi_driver); | ||
413 | |||
414 | } | ||
diff --git a/drivers/video/omap2/dss/manager-sysfs.c b/drivers/video/omap2/dss/manager-sysfs.c deleted file mode 100644 index 9a2fb59b6f8..00000000000 --- a/drivers/video/omap2/dss/manager-sysfs.c +++ /dev/null | |||
@@ -1,512 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * Some code and ideas taken from drivers/video/omap/ driver | ||
6 | * by Imre Deak. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #define DSS_SUBSYS_NAME "MANAGER" | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/jiffies.h> | ||
28 | |||
29 | #include <video/omapdss.h> | ||
30 | |||
31 | #include "dss.h" | ||
32 | #include "dss_features.h" | ||
33 | |||
34 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) | ||
35 | { | ||
36 | return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); | ||
37 | } | ||
38 | |||
39 | static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) | ||
40 | { | ||
41 | struct omap_dss_device *dssdev = mgr->get_device(mgr); | ||
42 | |||
43 | return snprintf(buf, PAGE_SIZE, "%s\n", dssdev ? | ||
44 | dssdev->name : "<none>"); | ||
45 | } | ||
46 | |||
47 | static ssize_t manager_display_store(struct omap_overlay_manager *mgr, | ||
48 | const char *buf, size_t size) | ||
49 | { | ||
50 | int r = 0; | ||
51 | size_t len = size; | ||
52 | struct omap_dss_device *dssdev = NULL; | ||
53 | |||
54 | int match(struct omap_dss_device *dssdev, void *data) | ||
55 | { | ||
56 | const char *str = data; | ||
57 | return sysfs_streq(dssdev->name, str); | ||
58 | } | ||
59 | |||
60 | if (buf[size-1] == '\n') | ||
61 | --len; | ||
62 | |||
63 | if (len > 0) | ||
64 | dssdev = omap_dss_find_device((void *)buf, match); | ||
65 | |||
66 | if (len > 0 && dssdev == NULL) | ||
67 | return -EINVAL; | ||
68 | |||
69 | if (dssdev) | ||
70 | DSSDBG("display %s found\n", dssdev->name); | ||
71 | |||
72 | if (mgr->output) { | ||
73 | r = mgr->unset_output(mgr); | ||
74 | if (r) { | ||
75 | DSSERR("failed to unset current output\n"); | ||
76 | goto put_device; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | if (dssdev) { | ||
81 | struct omap_dss_output *out = dssdev->output; | ||
82 | |||
83 | /* | ||
84 | * a registered device should have an output connected to it | ||
85 | * already | ||
86 | */ | ||
87 | if (!out) { | ||
88 | DSSERR("device has no output connected to it\n"); | ||
89 | goto put_device; | ||
90 | } | ||
91 | |||
92 | r = mgr->set_output(mgr, out); | ||
93 | if (r) { | ||
94 | DSSERR("failed to set manager output\n"); | ||
95 | goto put_device; | ||
96 | } | ||
97 | |||
98 | r = mgr->apply(mgr); | ||
99 | if (r) { | ||
100 | DSSERR("failed to apply dispc config\n"); | ||
101 | goto put_device; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | put_device: | ||
106 | if (dssdev) | ||
107 | omap_dss_put_device(dssdev); | ||
108 | |||
109 | return r ? r : size; | ||
110 | } | ||
111 | |||
112 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, | ||
113 | char *buf) | ||
114 | { | ||
115 | struct omap_overlay_manager_info info; | ||
116 | |||
117 | mgr->get_manager_info(mgr, &info); | ||
118 | |||
119 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.default_color); | ||
120 | } | ||
121 | |||
122 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, | ||
123 | const char *buf, size_t size) | ||
124 | { | ||
125 | struct omap_overlay_manager_info info; | ||
126 | u32 color; | ||
127 | int r; | ||
128 | |||
129 | r = kstrtouint(buf, 0, &color); | ||
130 | if (r) | ||
131 | return r; | ||
132 | |||
133 | mgr->get_manager_info(mgr, &info); | ||
134 | |||
135 | info.default_color = color; | ||
136 | |||
137 | r = mgr->set_manager_info(mgr, &info); | ||
138 | if (r) | ||
139 | return r; | ||
140 | |||
141 | r = mgr->apply(mgr); | ||
142 | if (r) | ||
143 | return r; | ||
144 | |||
145 | return size; | ||
146 | } | ||
147 | |||
148 | static const char *trans_key_type_str[] = { | ||
149 | "gfx-destination", | ||
150 | "video-source", | ||
151 | }; | ||
152 | |||
153 | static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, | ||
154 | char *buf) | ||
155 | { | ||
156 | enum omap_dss_trans_key_type key_type; | ||
157 | struct omap_overlay_manager_info info; | ||
158 | |||
159 | mgr->get_manager_info(mgr, &info); | ||
160 | |||
161 | key_type = info.trans_key_type; | ||
162 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); | ||
163 | |||
164 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); | ||
165 | } | ||
166 | |||
167 | static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, | ||
168 | const char *buf, size_t size) | ||
169 | { | ||
170 | enum omap_dss_trans_key_type key_type; | ||
171 | struct omap_overlay_manager_info info; | ||
172 | int r; | ||
173 | |||
174 | for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
175 | key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { | ||
176 | if (sysfs_streq(buf, trans_key_type_str[key_type])) | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | if (key_type == ARRAY_SIZE(trans_key_type_str)) | ||
181 | return -EINVAL; | ||
182 | |||
183 | mgr->get_manager_info(mgr, &info); | ||
184 | |||
185 | info.trans_key_type = key_type; | ||
186 | |||
187 | r = mgr->set_manager_info(mgr, &info); | ||
188 | if (r) | ||
189 | return r; | ||
190 | |||
191 | r = mgr->apply(mgr); | ||
192 | if (r) | ||
193 | return r; | ||
194 | |||
195 | return size; | ||
196 | } | ||
197 | |||
198 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, | ||
199 | char *buf) | ||
200 | { | ||
201 | struct omap_overlay_manager_info info; | ||
202 | |||
203 | mgr->get_manager_info(mgr, &info); | ||
204 | |||
205 | return snprintf(buf, PAGE_SIZE, "%#x\n", info.trans_key); | ||
206 | } | ||
207 | |||
208 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | ||
209 | const char *buf, size_t size) | ||
210 | { | ||
211 | struct omap_overlay_manager_info info; | ||
212 | u32 key_value; | ||
213 | int r; | ||
214 | |||
215 | r = kstrtouint(buf, 0, &key_value); | ||
216 | if (r) | ||
217 | return r; | ||
218 | |||
219 | mgr->get_manager_info(mgr, &info); | ||
220 | |||
221 | info.trans_key = key_value; | ||
222 | |||
223 | r = mgr->set_manager_info(mgr, &info); | ||
224 | if (r) | ||
225 | return r; | ||
226 | |||
227 | r = mgr->apply(mgr); | ||
228 | if (r) | ||
229 | return r; | ||
230 | |||
231 | return size; | ||
232 | } | ||
233 | |||
234 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, | ||
235 | char *buf) | ||
236 | { | ||
237 | struct omap_overlay_manager_info info; | ||
238 | |||
239 | mgr->get_manager_info(mgr, &info); | ||
240 | |||
241 | return snprintf(buf, PAGE_SIZE, "%d\n", info.trans_enabled); | ||
242 | } | ||
243 | |||
244 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | ||
245 | const char *buf, size_t size) | ||
246 | { | ||
247 | struct omap_overlay_manager_info info; | ||
248 | bool enable; | ||
249 | int r; | ||
250 | |||
251 | r = strtobool(buf, &enable); | ||
252 | if (r) | ||
253 | return r; | ||
254 | |||
255 | mgr->get_manager_info(mgr, &info); | ||
256 | |||
257 | info.trans_enabled = enable; | ||
258 | |||
259 | r = mgr->set_manager_info(mgr, &info); | ||
260 | if (r) | ||
261 | return r; | ||
262 | |||
263 | r = mgr->apply(mgr); | ||
264 | if (r) | ||
265 | return r; | ||
266 | |||
267 | return size; | ||
268 | } | ||
269 | |||
270 | static ssize_t manager_alpha_blending_enabled_show( | ||
271 | struct omap_overlay_manager *mgr, char *buf) | ||
272 | { | ||
273 | struct omap_overlay_manager_info info; | ||
274 | |||
275 | mgr->get_manager_info(mgr, &info); | ||
276 | |||
277 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | ||
278 | |||
279 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
280 | info.partial_alpha_enabled); | ||
281 | } | ||
282 | |||
283 | static ssize_t manager_alpha_blending_enabled_store( | ||
284 | struct omap_overlay_manager *mgr, | ||
285 | const char *buf, size_t size) | ||
286 | { | ||
287 | struct omap_overlay_manager_info info; | ||
288 | bool enable; | ||
289 | int r; | ||
290 | |||
291 | WARN_ON(!dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)); | ||
292 | |||
293 | r = strtobool(buf, &enable); | ||
294 | if (r) | ||
295 | return r; | ||
296 | |||
297 | mgr->get_manager_info(mgr, &info); | ||
298 | |||
299 | info.partial_alpha_enabled = enable; | ||
300 | |||
301 | r = mgr->set_manager_info(mgr, &info); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | r = mgr->apply(mgr); | ||
306 | if (r) | ||
307 | return r; | ||
308 | |||
309 | return size; | ||
310 | } | ||
311 | |||
312 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, | ||
313 | char *buf) | ||
314 | { | ||
315 | struct omap_overlay_manager_info info; | ||
316 | |||
317 | mgr->get_manager_info(mgr, &info); | ||
318 | |||
319 | return snprintf(buf, PAGE_SIZE, "%d\n", info.cpr_enable); | ||
320 | } | ||
321 | |||
322 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, | ||
323 | const char *buf, size_t size) | ||
324 | { | ||
325 | struct omap_overlay_manager_info info; | ||
326 | int r; | ||
327 | bool enable; | ||
328 | |||
329 | if (!dss_has_feature(FEAT_CPR)) | ||
330 | return -ENODEV; | ||
331 | |||
332 | r = strtobool(buf, &enable); | ||
333 | if (r) | ||
334 | return r; | ||
335 | |||
336 | mgr->get_manager_info(mgr, &info); | ||
337 | |||
338 | if (info.cpr_enable == enable) | ||
339 | return size; | ||
340 | |||
341 | info.cpr_enable = enable; | ||
342 | |||
343 | r = mgr->set_manager_info(mgr, &info); | ||
344 | if (r) | ||
345 | return r; | ||
346 | |||
347 | r = mgr->apply(mgr); | ||
348 | if (r) | ||
349 | return r; | ||
350 | |||
351 | return size; | ||
352 | } | ||
353 | |||
354 | static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, | ||
355 | char *buf) | ||
356 | { | ||
357 | struct omap_overlay_manager_info info; | ||
358 | |||
359 | mgr->get_manager_info(mgr, &info); | ||
360 | |||
361 | return snprintf(buf, PAGE_SIZE, | ||
362 | "%d %d %d %d %d %d %d %d %d\n", | ||
363 | info.cpr_coefs.rr, | ||
364 | info.cpr_coefs.rg, | ||
365 | info.cpr_coefs.rb, | ||
366 | info.cpr_coefs.gr, | ||
367 | info.cpr_coefs.gg, | ||
368 | info.cpr_coefs.gb, | ||
369 | info.cpr_coefs.br, | ||
370 | info.cpr_coefs.bg, | ||
371 | info.cpr_coefs.bb); | ||
372 | } | ||
373 | |||
374 | static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, | ||
375 | const char *buf, size_t size) | ||
376 | { | ||
377 | struct omap_overlay_manager_info info; | ||
378 | struct omap_dss_cpr_coefs coefs; | ||
379 | int r, i; | ||
380 | s16 *arr; | ||
381 | |||
382 | if (!dss_has_feature(FEAT_CPR)) | ||
383 | return -ENODEV; | ||
384 | |||
385 | if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", | ||
386 | &coefs.rr, &coefs.rg, &coefs.rb, | ||
387 | &coefs.gr, &coefs.gg, &coefs.gb, | ||
388 | &coefs.br, &coefs.bg, &coefs.bb) != 9) | ||
389 | return -EINVAL; | ||
390 | |||
391 | arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, | ||
392 | coefs.gr, coefs.gg, coefs.gb, | ||
393 | coefs.br, coefs.bg, coefs.bb }; | ||
394 | |||
395 | for (i = 0; i < 9; ++i) { | ||
396 | if (arr[i] < -512 || arr[i] > 511) | ||
397 | return -EINVAL; | ||
398 | } | ||
399 | |||
400 | mgr->get_manager_info(mgr, &info); | ||
401 | |||
402 | info.cpr_coefs = coefs; | ||
403 | |||
404 | r = mgr->set_manager_info(mgr, &info); | ||
405 | if (r) | ||
406 | return r; | ||
407 | |||
408 | r = mgr->apply(mgr); | ||
409 | if (r) | ||
410 | return r; | ||
411 | |||
412 | return size; | ||
413 | } | ||
414 | |||
415 | struct manager_attribute { | ||
416 | struct attribute attr; | ||
417 | ssize_t (*show)(struct omap_overlay_manager *, char *); | ||
418 | ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); | ||
419 | }; | ||
420 | |||
421 | #define MANAGER_ATTR(_name, _mode, _show, _store) \ | ||
422 | struct manager_attribute manager_attr_##_name = \ | ||
423 | __ATTR(_name, _mode, _show, _store) | ||
424 | |||
425 | static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); | ||
426 | static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, | ||
427 | manager_display_show, manager_display_store); | ||
428 | static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, | ||
429 | manager_default_color_show, manager_default_color_store); | ||
430 | static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, | ||
431 | manager_trans_key_type_show, manager_trans_key_type_store); | ||
432 | static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, | ||
433 | manager_trans_key_value_show, manager_trans_key_value_store); | ||
434 | static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, | ||
435 | manager_trans_key_enabled_show, | ||
436 | manager_trans_key_enabled_store); | ||
437 | static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, | ||
438 | manager_alpha_blending_enabled_show, | ||
439 | manager_alpha_blending_enabled_store); | ||
440 | static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, | ||
441 | manager_cpr_enable_show, | ||
442 | manager_cpr_enable_store); | ||
443 | static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, | ||
444 | manager_cpr_coef_show, | ||
445 | manager_cpr_coef_store); | ||
446 | |||
447 | |||
448 | static struct attribute *manager_sysfs_attrs[] = { | ||
449 | &manager_attr_name.attr, | ||
450 | &manager_attr_display.attr, | ||
451 | &manager_attr_default_color.attr, | ||
452 | &manager_attr_trans_key_type.attr, | ||
453 | &manager_attr_trans_key_value.attr, | ||
454 | &manager_attr_trans_key_enabled.attr, | ||
455 | &manager_attr_alpha_blending_enabled.attr, | ||
456 | &manager_attr_cpr_enable.attr, | ||
457 | &manager_attr_cpr_coef.attr, | ||
458 | NULL | ||
459 | }; | ||
460 | |||
461 | static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, | ||
462 | char *buf) | ||
463 | { | ||
464 | struct omap_overlay_manager *manager; | ||
465 | struct manager_attribute *manager_attr; | ||
466 | |||
467 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
468 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
469 | |||
470 | if (!manager_attr->show) | ||
471 | return -ENOENT; | ||
472 | |||
473 | return manager_attr->show(manager, buf); | ||
474 | } | ||
475 | |||
476 | static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, | ||
477 | const char *buf, size_t size) | ||
478 | { | ||
479 | struct omap_overlay_manager *manager; | ||
480 | struct manager_attribute *manager_attr; | ||
481 | |||
482 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
483 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
484 | |||
485 | if (!manager_attr->store) | ||
486 | return -ENOENT; | ||
487 | |||
488 | return manager_attr->store(manager, buf, size); | ||
489 | } | ||
490 | |||
491 | static const struct sysfs_ops manager_sysfs_ops = { | ||
492 | .show = manager_attr_show, | ||
493 | .store = manager_attr_store, | ||
494 | }; | ||
495 | |||
496 | static struct kobj_type manager_ktype = { | ||
497 | .sysfs_ops = &manager_sysfs_ops, | ||
498 | .default_attrs = manager_sysfs_attrs, | ||
499 | }; | ||
500 | |||
501 | int dss_manager_kobj_init(struct omap_overlay_manager *mgr, | ||
502 | struct platform_device *pdev) | ||
503 | { | ||
504 | return kobject_init_and_add(&mgr->kobj, &manager_ktype, | ||
505 | &pdev->dev.kobj, "manager%d", mgr->id); | ||
506 | } | ||
507 | |||
508 | void dss_manager_kobj_uninit(struct omap_overlay_manager *mgr) | ||
509 | { | ||
510 | kobject_del(&mgr->kobj); | ||
511 | kobject_put(&mgr->kobj); | ||
512 | } | ||
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c index 2551eaa14c4..13d72d5c714 100644 --- a/drivers/video/omap2/dss/manager.c +++ b/drivers/video/omap2/dss/manager.c | |||
@@ -26,223 +26,1649 @@ | |||
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/platform_device.h> | 28 | #include <linux/platform_device.h> |
29 | #include <linux/spinlock.h> | ||
29 | #include <linux/jiffies.h> | 30 | #include <linux/jiffies.h> |
30 | 31 | ||
31 | #include <video/omapdss.h> | 32 | #include <video/omapdss.h> |
33 | #include <plat/cpu.h> | ||
32 | 34 | ||
33 | #include "dss.h" | 35 | #include "dss.h" |
34 | #include "dss_features.h" | 36 | #include "dss_features.h" |
35 | 37 | ||
36 | static int num_managers; | 38 | static int num_managers; |
37 | static struct omap_overlay_manager *managers; | 39 | static struct list_head manager_list; |
38 | 40 | ||
39 | int dss_init_overlay_managers(struct platform_device *pdev) | 41 | static ssize_t manager_name_show(struct omap_overlay_manager *mgr, char *buf) |
40 | { | 42 | { |
41 | int i, r; | 43 | return snprintf(buf, PAGE_SIZE, "%s\n", mgr->name); |
44 | } | ||
42 | 45 | ||
43 | num_managers = dss_feat_get_num_mgrs(); | 46 | static ssize_t manager_display_show(struct omap_overlay_manager *mgr, char *buf) |
47 | { | ||
48 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
49 | mgr->device ? mgr->device->name : "<none>"); | ||
50 | } | ||
44 | 51 | ||
45 | managers = kzalloc(sizeof(struct omap_overlay_manager) * num_managers, | 52 | static ssize_t manager_display_store(struct omap_overlay_manager *mgr, |
46 | GFP_KERNEL); | 53 | const char *buf, size_t size) |
54 | { | ||
55 | int r = 0; | ||
56 | size_t len = size; | ||
57 | struct omap_dss_device *dssdev = NULL; | ||
47 | 58 | ||
48 | BUG_ON(managers == NULL); | 59 | int match(struct omap_dss_device *dssdev, void *data) |
60 | { | ||
61 | const char *str = data; | ||
62 | return sysfs_streq(dssdev->name, str); | ||
63 | } | ||
49 | 64 | ||
50 | for (i = 0; i < num_managers; ++i) { | 65 | if (buf[size-1] == '\n') |
51 | struct omap_overlay_manager *mgr = &managers[i]; | 66 | --len; |
52 | 67 | ||
53 | switch (i) { | 68 | if (len > 0) |
54 | case 0: | 69 | dssdev = omap_dss_find_device((void *)buf, match); |
55 | mgr->name = "lcd"; | 70 | |
56 | mgr->id = OMAP_DSS_CHANNEL_LCD; | 71 | if (len > 0 && dssdev == NULL) |
57 | break; | 72 | return -EINVAL; |
58 | case 1: | 73 | |
59 | mgr->name = "tv"; | 74 | if (dssdev) |
60 | mgr->id = OMAP_DSS_CHANNEL_DIGIT; | 75 | DSSDBG("display %s found\n", dssdev->name); |
61 | break; | 76 | |
62 | case 2: | 77 | if (mgr->device) { |
63 | mgr->name = "lcd2"; | 78 | r = mgr->unset_device(mgr); |
64 | mgr->id = OMAP_DSS_CHANNEL_LCD2; | 79 | if (r) { |
65 | break; | 80 | DSSERR("failed to unset display\n"); |
66 | case 3: | 81 | goto put_device; |
67 | mgr->name = "lcd3"; | ||
68 | mgr->id = OMAP_DSS_CHANNEL_LCD3; | ||
69 | break; | ||
70 | } | 82 | } |
83 | } | ||
71 | 84 | ||
72 | mgr->caps = 0; | 85 | if (dssdev) { |
73 | mgr->supported_displays = | 86 | r = mgr->set_device(mgr, dssdev); |
74 | dss_feat_get_supported_displays(mgr->id); | 87 | if (r) { |
75 | mgr->supported_outputs = | 88 | DSSERR("failed to set manager\n"); |
76 | dss_feat_get_supported_outputs(mgr->id); | 89 | goto put_device; |
90 | } | ||
91 | |||
92 | r = mgr->apply(mgr); | ||
93 | if (r) { | ||
94 | DSSERR("failed to apply dispc config\n"); | ||
95 | goto put_device; | ||
96 | } | ||
97 | } | ||
98 | |||
99 | put_device: | ||
100 | if (dssdev) | ||
101 | omap_dss_put_device(dssdev); | ||
102 | |||
103 | return r ? r : size; | ||
104 | } | ||
105 | |||
106 | static ssize_t manager_default_color_show(struct omap_overlay_manager *mgr, | ||
107 | char *buf) | ||
108 | { | ||
109 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.default_color); | ||
110 | } | ||
111 | |||
112 | static ssize_t manager_default_color_store(struct omap_overlay_manager *mgr, | ||
113 | const char *buf, size_t size) | ||
114 | { | ||
115 | struct omap_overlay_manager_info info; | ||
116 | u32 color; | ||
117 | int r; | ||
118 | |||
119 | if (sscanf(buf, "%d", &color) != 1) | ||
120 | return -EINVAL; | ||
121 | |||
122 | mgr->get_manager_info(mgr, &info); | ||
123 | |||
124 | info.default_color = color; | ||
125 | |||
126 | r = mgr->set_manager_info(mgr, &info); | ||
127 | if (r) | ||
128 | return r; | ||
129 | |||
130 | r = mgr->apply(mgr); | ||
131 | if (r) | ||
132 | return r; | ||
133 | |||
134 | return size; | ||
135 | } | ||
136 | |||
137 | static const char *trans_key_type_str[] = { | ||
138 | "gfx-destination", | ||
139 | "video-source", | ||
140 | }; | ||
141 | |||
142 | static ssize_t manager_trans_key_type_show(struct omap_overlay_manager *mgr, | ||
143 | char *buf) | ||
144 | { | ||
145 | enum omap_dss_trans_key_type key_type; | ||
146 | |||
147 | key_type = mgr->info.trans_key_type; | ||
148 | BUG_ON(key_type >= ARRAY_SIZE(trans_key_type_str)); | ||
149 | |||
150 | return snprintf(buf, PAGE_SIZE, "%s\n", trans_key_type_str[key_type]); | ||
151 | } | ||
152 | |||
153 | static ssize_t manager_trans_key_type_store(struct omap_overlay_manager *mgr, | ||
154 | const char *buf, size_t size) | ||
155 | { | ||
156 | enum omap_dss_trans_key_type key_type; | ||
157 | struct omap_overlay_manager_info info; | ||
158 | int r; | ||
159 | |||
160 | for (key_type = OMAP_DSS_COLOR_KEY_GFX_DST; | ||
161 | key_type < ARRAY_SIZE(trans_key_type_str); key_type++) { | ||
162 | if (sysfs_streq(buf, trans_key_type_str[key_type])) | ||
163 | break; | ||
164 | } | ||
165 | |||
166 | if (key_type == ARRAY_SIZE(trans_key_type_str)) | ||
167 | return -EINVAL; | ||
168 | |||
169 | mgr->get_manager_info(mgr, &info); | ||
170 | |||
171 | info.trans_key_type = key_type; | ||
172 | |||
173 | r = mgr->set_manager_info(mgr, &info); | ||
174 | if (r) | ||
175 | return r; | ||
176 | |||
177 | r = mgr->apply(mgr); | ||
178 | if (r) | ||
179 | return r; | ||
180 | |||
181 | return size; | ||
182 | } | ||
183 | |||
184 | static ssize_t manager_trans_key_value_show(struct omap_overlay_manager *mgr, | ||
185 | char *buf) | ||
186 | { | ||
187 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_key); | ||
188 | } | ||
189 | |||
190 | static ssize_t manager_trans_key_value_store(struct omap_overlay_manager *mgr, | ||
191 | const char *buf, size_t size) | ||
192 | { | ||
193 | struct omap_overlay_manager_info info; | ||
194 | u32 key_value; | ||
195 | int r; | ||
196 | |||
197 | if (sscanf(buf, "%d", &key_value) != 1) | ||
198 | return -EINVAL; | ||
199 | |||
200 | mgr->get_manager_info(mgr, &info); | ||
201 | |||
202 | info.trans_key = key_value; | ||
203 | |||
204 | r = mgr->set_manager_info(mgr, &info); | ||
205 | if (r) | ||
206 | return r; | ||
207 | |||
208 | r = mgr->apply(mgr); | ||
209 | if (r) | ||
210 | return r; | ||
211 | |||
212 | return size; | ||
213 | } | ||
214 | |||
215 | static ssize_t manager_trans_key_enabled_show(struct omap_overlay_manager *mgr, | ||
216 | char *buf) | ||
217 | { | ||
218 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.trans_enabled); | ||
219 | } | ||
220 | |||
221 | static ssize_t manager_trans_key_enabled_store(struct omap_overlay_manager *mgr, | ||
222 | const char *buf, size_t size) | ||
223 | { | ||
224 | struct omap_overlay_manager_info info; | ||
225 | int enable; | ||
226 | int r; | ||
227 | |||
228 | if (sscanf(buf, "%d", &enable) != 1) | ||
229 | return -EINVAL; | ||
230 | |||
231 | mgr->get_manager_info(mgr, &info); | ||
232 | |||
233 | info.trans_enabled = enable ? true : false; | ||
234 | |||
235 | r = mgr->set_manager_info(mgr, &info); | ||
236 | if (r) | ||
237 | return r; | ||
238 | |||
239 | r = mgr->apply(mgr); | ||
240 | if (r) | ||
241 | return r; | ||
242 | |||
243 | return size; | ||
244 | } | ||
245 | |||
246 | static ssize_t manager_alpha_blending_enabled_show( | ||
247 | struct omap_overlay_manager *mgr, char *buf) | ||
248 | { | ||
249 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.alpha_enabled); | ||
250 | } | ||
251 | |||
252 | static ssize_t manager_alpha_blending_enabled_store( | ||
253 | struct omap_overlay_manager *mgr, | ||
254 | const char *buf, size_t size) | ||
255 | { | ||
256 | struct omap_overlay_manager_info info; | ||
257 | int enable; | ||
258 | int r; | ||
259 | |||
260 | if (sscanf(buf, "%d", &enable) != 1) | ||
261 | return -EINVAL; | ||
262 | |||
263 | mgr->get_manager_info(mgr, &info); | ||
264 | |||
265 | info.alpha_enabled = enable ? true : false; | ||
266 | |||
267 | r = mgr->set_manager_info(mgr, &info); | ||
268 | if (r) | ||
269 | return r; | ||
270 | |||
271 | r = mgr->apply(mgr); | ||
272 | if (r) | ||
273 | return r; | ||
274 | |||
275 | return size; | ||
276 | } | ||
277 | |||
278 | static ssize_t manager_cpr_enable_show(struct omap_overlay_manager *mgr, | ||
279 | char *buf) | ||
280 | { | ||
281 | return snprintf(buf, PAGE_SIZE, "%d\n", mgr->info.cpr_enable); | ||
282 | } | ||
283 | |||
284 | static ssize_t manager_cpr_enable_store(struct omap_overlay_manager *mgr, | ||
285 | const char *buf, size_t size) | ||
286 | { | ||
287 | struct omap_overlay_manager_info info; | ||
288 | int v; | ||
289 | int r; | ||
290 | bool enable; | ||
77 | 291 | ||
78 | INIT_LIST_HEAD(&mgr->overlays); | 292 | if (!dss_has_feature(FEAT_CPR)) |
293 | return -ENODEV; | ||
79 | 294 | ||
80 | r = dss_manager_kobj_init(mgr, pdev); | 295 | r = kstrtoint(buf, 0, &v); |
296 | if (r) | ||
297 | return r; | ||
298 | |||
299 | enable = !!v; | ||
300 | |||
301 | mgr->get_manager_info(mgr, &info); | ||
302 | |||
303 | if (info.cpr_enable == enable) | ||
304 | return size; | ||
305 | |||
306 | info.cpr_enable = enable; | ||
307 | |||
308 | r = mgr->set_manager_info(mgr, &info); | ||
309 | if (r) | ||
310 | return r; | ||
311 | |||
312 | r = mgr->apply(mgr); | ||
313 | if (r) | ||
314 | return r; | ||
315 | |||
316 | return size; | ||
317 | } | ||
318 | |||
319 | static ssize_t manager_cpr_coef_show(struct omap_overlay_manager *mgr, | ||
320 | char *buf) | ||
321 | { | ||
322 | struct omap_overlay_manager_info info; | ||
323 | |||
324 | mgr->get_manager_info(mgr, &info); | ||
325 | |||
326 | return snprintf(buf, PAGE_SIZE, | ||
327 | "%d %d %d %d %d %d %d %d %d\n", | ||
328 | info.cpr_coefs.rr, | ||
329 | info.cpr_coefs.rg, | ||
330 | info.cpr_coefs.rb, | ||
331 | info.cpr_coefs.gr, | ||
332 | info.cpr_coefs.gg, | ||
333 | info.cpr_coefs.gb, | ||
334 | info.cpr_coefs.br, | ||
335 | info.cpr_coefs.bg, | ||
336 | info.cpr_coefs.bb); | ||
337 | } | ||
338 | |||
339 | static ssize_t manager_cpr_coef_store(struct omap_overlay_manager *mgr, | ||
340 | const char *buf, size_t size) | ||
341 | { | ||
342 | struct omap_overlay_manager_info info; | ||
343 | struct omap_dss_cpr_coefs coefs; | ||
344 | int r, i; | ||
345 | s16 *arr; | ||
346 | |||
347 | if (!dss_has_feature(FEAT_CPR)) | ||
348 | return -ENODEV; | ||
349 | |||
350 | if (sscanf(buf, "%hd %hd %hd %hd %hd %hd %hd %hd %hd", | ||
351 | &coefs.rr, &coefs.rg, &coefs.rb, | ||
352 | &coefs.gr, &coefs.gg, &coefs.gb, | ||
353 | &coefs.br, &coefs.bg, &coefs.bb) != 9) | ||
354 | return -EINVAL; | ||
355 | |||
356 | arr = (s16[]){ coefs.rr, coefs.rg, coefs.rb, | ||
357 | coefs.gr, coefs.gg, coefs.gb, | ||
358 | coefs.br, coefs.bg, coefs.bb }; | ||
359 | |||
360 | for (i = 0; i < 9; ++i) { | ||
361 | if (arr[i] < -512 || arr[i] > 511) | ||
362 | return -EINVAL; | ||
363 | } | ||
364 | |||
365 | mgr->get_manager_info(mgr, &info); | ||
366 | |||
367 | info.cpr_coefs = coefs; | ||
368 | |||
369 | r = mgr->set_manager_info(mgr, &info); | ||
370 | if (r) | ||
371 | return r; | ||
372 | |||
373 | r = mgr->apply(mgr); | ||
374 | if (r) | ||
375 | return r; | ||
376 | |||
377 | return size; | ||
378 | } | ||
379 | |||
380 | struct manager_attribute { | ||
381 | struct attribute attr; | ||
382 | ssize_t (*show)(struct omap_overlay_manager *, char *); | ||
383 | ssize_t (*store)(struct omap_overlay_manager *, const char *, size_t); | ||
384 | }; | ||
385 | |||
386 | #define MANAGER_ATTR(_name, _mode, _show, _store) \ | ||
387 | struct manager_attribute manager_attr_##_name = \ | ||
388 | __ATTR(_name, _mode, _show, _store) | ||
389 | |||
390 | static MANAGER_ATTR(name, S_IRUGO, manager_name_show, NULL); | ||
391 | static MANAGER_ATTR(display, S_IRUGO|S_IWUSR, | ||
392 | manager_display_show, manager_display_store); | ||
393 | static MANAGER_ATTR(default_color, S_IRUGO|S_IWUSR, | ||
394 | manager_default_color_show, manager_default_color_store); | ||
395 | static MANAGER_ATTR(trans_key_type, S_IRUGO|S_IWUSR, | ||
396 | manager_trans_key_type_show, manager_trans_key_type_store); | ||
397 | static MANAGER_ATTR(trans_key_value, S_IRUGO|S_IWUSR, | ||
398 | manager_trans_key_value_show, manager_trans_key_value_store); | ||
399 | static MANAGER_ATTR(trans_key_enabled, S_IRUGO|S_IWUSR, | ||
400 | manager_trans_key_enabled_show, | ||
401 | manager_trans_key_enabled_store); | ||
402 | static MANAGER_ATTR(alpha_blending_enabled, S_IRUGO|S_IWUSR, | ||
403 | manager_alpha_blending_enabled_show, | ||
404 | manager_alpha_blending_enabled_store); | ||
405 | static MANAGER_ATTR(cpr_enable, S_IRUGO|S_IWUSR, | ||
406 | manager_cpr_enable_show, | ||
407 | manager_cpr_enable_store); | ||
408 | static MANAGER_ATTR(cpr_coef, S_IRUGO|S_IWUSR, | ||
409 | manager_cpr_coef_show, | ||
410 | manager_cpr_coef_store); | ||
411 | |||
412 | |||
413 | static struct attribute *manager_sysfs_attrs[] = { | ||
414 | &manager_attr_name.attr, | ||
415 | &manager_attr_display.attr, | ||
416 | &manager_attr_default_color.attr, | ||
417 | &manager_attr_trans_key_type.attr, | ||
418 | &manager_attr_trans_key_value.attr, | ||
419 | &manager_attr_trans_key_enabled.attr, | ||
420 | &manager_attr_alpha_blending_enabled.attr, | ||
421 | &manager_attr_cpr_enable.attr, | ||
422 | &manager_attr_cpr_coef.attr, | ||
423 | NULL | ||
424 | }; | ||
425 | |||
426 | static ssize_t manager_attr_show(struct kobject *kobj, struct attribute *attr, | ||
427 | char *buf) | ||
428 | { | ||
429 | struct omap_overlay_manager *manager; | ||
430 | struct manager_attribute *manager_attr; | ||
431 | |||
432 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
433 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
434 | |||
435 | if (!manager_attr->show) | ||
436 | return -ENOENT; | ||
437 | |||
438 | return manager_attr->show(manager, buf); | ||
439 | } | ||
440 | |||
441 | static ssize_t manager_attr_store(struct kobject *kobj, struct attribute *attr, | ||
442 | const char *buf, size_t size) | ||
443 | { | ||
444 | struct omap_overlay_manager *manager; | ||
445 | struct manager_attribute *manager_attr; | ||
446 | |||
447 | manager = container_of(kobj, struct omap_overlay_manager, kobj); | ||
448 | manager_attr = container_of(attr, struct manager_attribute, attr); | ||
449 | |||
450 | if (!manager_attr->store) | ||
451 | return -ENOENT; | ||
452 | |||
453 | return manager_attr->store(manager, buf, size); | ||
454 | } | ||
455 | |||
456 | static const struct sysfs_ops manager_sysfs_ops = { | ||
457 | .show = manager_attr_show, | ||
458 | .store = manager_attr_store, | ||
459 | }; | ||
460 | |||
461 | static struct kobj_type manager_ktype = { | ||
462 | .sysfs_ops = &manager_sysfs_ops, | ||
463 | .default_attrs = manager_sysfs_attrs, | ||
464 | }; | ||
465 | |||
466 | /* | ||
467 | * We have 4 levels of cache for the dispc settings. First two are in SW and | ||
468 | * the latter two in HW. | ||
469 | * | ||
470 | * +--------------------+ | ||
471 | * |overlay/manager_info| | ||
472 | * +--------------------+ | ||
473 | * v | ||
474 | * apply() | ||
475 | * v | ||
476 | * +--------------------+ | ||
477 | * | dss_cache | | ||
478 | * +--------------------+ | ||
479 | * v | ||
480 | * configure() | ||
481 | * v | ||
482 | * +--------------------+ | ||
483 | * | shadow registers | | ||
484 | * +--------------------+ | ||
485 | * v | ||
486 | * VFP or lcd/digit_enable | ||
487 | * v | ||
488 | * +--------------------+ | ||
489 | * | registers | | ||
490 | * +--------------------+ | ||
491 | */ | ||
492 | |||
493 | struct overlay_cache_data { | ||
494 | /* If true, cache changed, but not written to shadow registers. Set | ||
495 | * in apply(), cleared when registers written. */ | ||
496 | bool dirty; | ||
497 | /* If true, shadow registers contain changed values not yet in real | ||
498 | * registers. Set when writing to shadow registers, cleared at | ||
499 | * VSYNC/EVSYNC */ | ||
500 | bool shadow_dirty; | ||
501 | |||
502 | bool enabled; | ||
503 | |||
504 | struct omap_overlay_info info; | ||
505 | |||
506 | enum omap_channel channel; | ||
507 | bool replication; | ||
508 | bool ilace; | ||
509 | |||
510 | u32 fifo_low; | ||
511 | u32 fifo_high; | ||
512 | }; | ||
513 | |||
514 | struct manager_cache_data { | ||
515 | /* If true, cache changed, but not written to shadow registers. Set | ||
516 | * in apply(), cleared when registers written. */ | ||
517 | bool dirty; | ||
518 | /* If true, shadow registers contain changed values not yet in real | ||
519 | * registers. Set when writing to shadow registers, cleared at | ||
520 | * VSYNC/EVSYNC */ | ||
521 | bool shadow_dirty; | ||
522 | |||
523 | struct omap_overlay_manager_info info; | ||
524 | |||
525 | bool manual_update; | ||
526 | bool do_manual_update; | ||
527 | |||
528 | /* manual update region */ | ||
529 | u16 x, y, w, h; | ||
530 | |||
531 | /* enlarge the update area if the update area contains scaled | ||
532 | * overlays */ | ||
533 | bool enlarge_update_area; | ||
534 | }; | ||
535 | |||
536 | static struct { | ||
537 | spinlock_t lock; | ||
538 | struct overlay_cache_data overlay_cache[MAX_DSS_OVERLAYS]; | ||
539 | struct manager_cache_data manager_cache[MAX_DSS_MANAGERS]; | ||
540 | |||
541 | bool irq_enabled; | ||
542 | } dss_cache; | ||
543 | |||
544 | |||
545 | |||
546 | static int omap_dss_set_device(struct omap_overlay_manager *mgr, | ||
547 | struct omap_dss_device *dssdev) | ||
548 | { | ||
549 | int i; | ||
550 | int r; | ||
551 | |||
552 | if (dssdev->manager) { | ||
553 | DSSERR("display '%s' already has a manager '%s'\n", | ||
554 | dssdev->name, dssdev->manager->name); | ||
555 | return -EINVAL; | ||
556 | } | ||
557 | |||
558 | if ((mgr->supported_displays & dssdev->type) == 0) { | ||
559 | DSSERR("display '%s' does not support manager '%s'\n", | ||
560 | dssdev->name, mgr->name); | ||
561 | return -EINVAL; | ||
562 | } | ||
563 | |||
564 | for (i = 0; i < mgr->num_overlays; i++) { | ||
565 | struct omap_overlay *ovl = mgr->overlays[i]; | ||
566 | |||
567 | if (ovl->manager != mgr || !ovl->info.enabled) | ||
568 | continue; | ||
569 | |||
570 | r = dss_check_overlay(ovl, dssdev); | ||
81 | if (r) | 571 | if (r) |
82 | DSSERR("failed to create sysfs file\n"); | 572 | return r; |
83 | } | 573 | } |
84 | 574 | ||
575 | dssdev->manager = mgr; | ||
576 | mgr->device = dssdev; | ||
577 | mgr->device_changed = true; | ||
578 | |||
85 | return 0; | 579 | return 0; |
86 | } | 580 | } |
87 | 581 | ||
88 | void dss_uninit_overlay_managers(struct platform_device *pdev) | 582 | static int omap_dss_unset_device(struct omap_overlay_manager *mgr) |
89 | { | 583 | { |
584 | if (!mgr->device) { | ||
585 | DSSERR("failed to unset display, display not set.\n"); | ||
586 | return -EINVAL; | ||
587 | } | ||
588 | |||
589 | mgr->device->manager = NULL; | ||
590 | mgr->device = NULL; | ||
591 | mgr->device_changed = true; | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int dss_mgr_wait_for_vsync(struct omap_overlay_manager *mgr) | ||
597 | { | ||
598 | unsigned long timeout = msecs_to_jiffies(500); | ||
599 | u32 irq; | ||
600 | |||
601 | if (mgr->device->type == OMAP_DISPLAY_TYPE_VENC) { | ||
602 | irq = DISPC_IRQ_EVSYNC_ODD; | ||
603 | } else if (mgr->device->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
604 | irq = DISPC_IRQ_EVSYNC_EVEN; | ||
605 | } else { | ||
606 | if (mgr->id == OMAP_DSS_CHANNEL_LCD) | ||
607 | irq = DISPC_IRQ_VSYNC; | ||
608 | else | ||
609 | irq = DISPC_IRQ_VSYNC2; | ||
610 | } | ||
611 | return omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
612 | } | ||
613 | |||
614 | static int dss_mgr_wait_for_go(struct omap_overlay_manager *mgr) | ||
615 | { | ||
616 | unsigned long timeout = msecs_to_jiffies(500); | ||
617 | struct manager_cache_data *mc; | ||
618 | u32 irq; | ||
619 | int r; | ||
90 | int i; | 620 | int i; |
621 | struct omap_dss_device *dssdev = mgr->device; | ||
91 | 622 | ||
92 | for (i = 0; i < num_managers; ++i) { | 623 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
93 | struct omap_overlay_manager *mgr = &managers[i]; | 624 | return 0; |
94 | dss_manager_kobj_uninit(mgr); | 625 | |
626 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
627 | return 0; | ||
628 | |||
629 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
630 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
631 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
632 | } else { | ||
633 | irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? | ||
634 | DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; | ||
95 | } | 635 | } |
96 | 636 | ||
97 | kfree(managers); | 637 | mc = &dss_cache.manager_cache[mgr->id]; |
98 | managers = NULL; | 638 | i = 0; |
99 | num_managers = 0; | 639 | while (1) { |
640 | unsigned long flags; | ||
641 | bool shadow_dirty, dirty; | ||
642 | |||
643 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
644 | dirty = mc->dirty; | ||
645 | shadow_dirty = mc->shadow_dirty; | ||
646 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
647 | |||
648 | if (!dirty && !shadow_dirty) { | ||
649 | r = 0; | ||
650 | break; | ||
651 | } | ||
652 | |||
653 | /* 4 iterations is the worst case: | ||
654 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
655 | * 2 - first VSYNC, dirty = true | ||
656 | * 3 - dirty = false, shadow_dirty = true | ||
657 | * 4 - shadow_dirty = false */ | ||
658 | if (i++ == 3) { | ||
659 | DSSERR("mgr(%d)->wait_for_go() not finishing\n", | ||
660 | mgr->id); | ||
661 | r = 0; | ||
662 | break; | ||
663 | } | ||
664 | |||
665 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
666 | if (r == -ERESTARTSYS) | ||
667 | break; | ||
668 | |||
669 | if (r) { | ||
670 | DSSERR("mgr(%d)->wait_for_go() timeout\n", mgr->id); | ||
671 | break; | ||
672 | } | ||
673 | } | ||
674 | |||
675 | return r; | ||
100 | } | 676 | } |
101 | 677 | ||
102 | int omap_dss_get_num_overlay_managers(void) | 678 | int dss_mgr_wait_for_go_ovl(struct omap_overlay *ovl) |
103 | { | 679 | { |
104 | return num_managers; | 680 | unsigned long timeout = msecs_to_jiffies(500); |
681 | struct overlay_cache_data *oc; | ||
682 | struct omap_dss_device *dssdev; | ||
683 | u32 irq; | ||
684 | int r; | ||
685 | int i; | ||
686 | |||
687 | if (!ovl->manager) | ||
688 | return 0; | ||
689 | |||
690 | dssdev = ovl->manager->device; | ||
691 | |||
692 | if (!dssdev || dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | ||
693 | return 0; | ||
694 | |||
695 | if (dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) | ||
696 | return 0; | ||
697 | |||
698 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
699 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
700 | irq = DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_EVSYNC_EVEN; | ||
701 | } else { | ||
702 | irq = (dssdev->manager->id == OMAP_DSS_CHANNEL_LCD) ? | ||
703 | DISPC_IRQ_VSYNC : DISPC_IRQ_VSYNC2; | ||
704 | } | ||
705 | |||
706 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
707 | i = 0; | ||
708 | while (1) { | ||
709 | unsigned long flags; | ||
710 | bool shadow_dirty, dirty; | ||
711 | |||
712 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
713 | dirty = oc->dirty; | ||
714 | shadow_dirty = oc->shadow_dirty; | ||
715 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
716 | |||
717 | if (!dirty && !shadow_dirty) { | ||
718 | r = 0; | ||
719 | break; | ||
720 | } | ||
721 | |||
722 | /* 4 iterations is the worst case: | ||
723 | * 1 - initial iteration, dirty = true (between VFP and VSYNC) | ||
724 | * 2 - first VSYNC, dirty = true | ||
725 | * 3 - dirty = false, shadow_dirty = true | ||
726 | * 4 - shadow_dirty = false */ | ||
727 | if (i++ == 3) { | ||
728 | DSSERR("ovl(%d)->wait_for_go() not finishing\n", | ||
729 | ovl->id); | ||
730 | r = 0; | ||
731 | break; | ||
732 | } | ||
733 | |||
734 | r = omap_dispc_wait_for_irq_interruptible_timeout(irq, timeout); | ||
735 | if (r == -ERESTARTSYS) | ||
736 | break; | ||
737 | |||
738 | if (r) { | ||
739 | DSSERR("ovl(%d)->wait_for_go() timeout\n", ovl->id); | ||
740 | break; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | return r; | ||
105 | } | 745 | } |
106 | EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); | ||
107 | 746 | ||
108 | struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) | 747 | static int overlay_enabled(struct omap_overlay *ovl) |
748 | { | ||
749 | return ovl->info.enabled && ovl->manager && ovl->manager->device; | ||
750 | } | ||
751 | |||
752 | /* Is rect1 a subset of rect2? */ | ||
753 | static bool rectangle_subset(int x1, int y1, int w1, int h1, | ||
754 | int x2, int y2, int w2, int h2) | ||
755 | { | ||
756 | if (x1 < x2 || y1 < y2) | ||
757 | return false; | ||
758 | |||
759 | if (x1 + w1 > x2 + w2) | ||
760 | return false; | ||
761 | |||
762 | if (y1 + h1 > y2 + h2) | ||
763 | return false; | ||
764 | |||
765 | return true; | ||
766 | } | ||
767 | |||
768 | /* Do rect1 and rect2 overlap? */ | ||
769 | static bool rectangle_intersects(int x1, int y1, int w1, int h1, | ||
770 | int x2, int y2, int w2, int h2) | ||
109 | { | 771 | { |
110 | if (num >= num_managers) | 772 | if (x1 >= x2 + w2) |
111 | return NULL; | 773 | return false; |
112 | 774 | ||
113 | return &managers[num]; | 775 | if (x2 >= x1 + w1) |
776 | return false; | ||
777 | |||
778 | if (y1 >= y2 + h2) | ||
779 | return false; | ||
780 | |||
781 | if (y2 >= y1 + h1) | ||
782 | return false; | ||
783 | |||
784 | return true; | ||
114 | } | 785 | } |
115 | EXPORT_SYMBOL(omap_dss_get_overlay_manager); | ||
116 | 786 | ||
117 | int dss_mgr_simple_check(struct omap_overlay_manager *mgr, | 787 | static bool dispc_is_overlay_scaled(struct overlay_cache_data *oc) |
118 | const struct omap_overlay_manager_info *info) | ||
119 | { | 788 | { |
120 | if (dss_has_feature(FEAT_ALPHA_FIXED_ZORDER)) { | 789 | struct omap_overlay_info *oi = &oc->info; |
121 | /* | 790 | |
122 | * OMAP3 supports only graphics source transparency color key | 791 | if (oi->out_width != 0 && oi->width != oi->out_width) |
123 | * and alpha blending simultaneously. See TRM 15.4.2.4.2.2 | 792 | return true; |
124 | * Alpha Mode. | 793 | |
794 | if (oi->out_height != 0 && oi->height != oi->out_height) | ||
795 | return true; | ||
796 | |||
797 | return false; | ||
798 | } | ||
799 | |||
800 | static int configure_overlay(enum omap_plane plane) | ||
801 | { | ||
802 | struct overlay_cache_data *c; | ||
803 | struct manager_cache_data *mc; | ||
804 | struct omap_overlay_info *oi; | ||
805 | struct omap_overlay_manager_info *mi; | ||
806 | u16 outw, outh; | ||
807 | u16 x, y, w, h; | ||
808 | u32 paddr; | ||
809 | int r; | ||
810 | u16 orig_w, orig_h, orig_outw, orig_outh; | ||
811 | |||
812 | DSSDBGF("%d", plane); | ||
813 | |||
814 | c = &dss_cache.overlay_cache[plane]; | ||
815 | oi = &c->info; | ||
816 | |||
817 | if (!c->enabled) { | ||
818 | dispc_enable_plane(plane, 0); | ||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | mc = &dss_cache.manager_cache[c->channel]; | ||
823 | mi = &mc->info; | ||
824 | |||
825 | x = oi->pos_x; | ||
826 | y = oi->pos_y; | ||
827 | w = oi->width; | ||
828 | h = oi->height; | ||
829 | outw = oi->out_width == 0 ? oi->width : oi->out_width; | ||
830 | outh = oi->out_height == 0 ? oi->height : oi->out_height; | ||
831 | paddr = oi->paddr; | ||
832 | |||
833 | orig_w = w; | ||
834 | orig_h = h; | ||
835 | orig_outw = outw; | ||
836 | orig_outh = outh; | ||
837 | |||
838 | if (mc->manual_update && mc->do_manual_update) { | ||
839 | unsigned bpp; | ||
840 | unsigned scale_x_m = w, scale_x_d = outw; | ||
841 | unsigned scale_y_m = h, scale_y_d = outh; | ||
842 | |||
843 | /* If the overlay is outside the update region, disable it */ | ||
844 | if (!rectangle_intersects(mc->x, mc->y, mc->w, mc->h, | ||
845 | x, y, outw, outh)) { | ||
846 | dispc_enable_plane(plane, 0); | ||
847 | return 0; | ||
848 | } | ||
849 | |||
850 | switch (oi->color_mode) { | ||
851 | case OMAP_DSS_COLOR_NV12: | ||
852 | bpp = 8; | ||
853 | break; | ||
854 | case OMAP_DSS_COLOR_RGB16: | ||
855 | case OMAP_DSS_COLOR_ARGB16: | ||
856 | case OMAP_DSS_COLOR_YUV2: | ||
857 | case OMAP_DSS_COLOR_UYVY: | ||
858 | case OMAP_DSS_COLOR_RGBA16: | ||
859 | case OMAP_DSS_COLOR_RGBX16: | ||
860 | case OMAP_DSS_COLOR_ARGB16_1555: | ||
861 | case OMAP_DSS_COLOR_XRGB16_1555: | ||
862 | bpp = 16; | ||
863 | break; | ||
864 | |||
865 | case OMAP_DSS_COLOR_RGB24P: | ||
866 | bpp = 24; | ||
867 | break; | ||
868 | |||
869 | case OMAP_DSS_COLOR_RGB24U: | ||
870 | case OMAP_DSS_COLOR_ARGB32: | ||
871 | case OMAP_DSS_COLOR_RGBA32: | ||
872 | case OMAP_DSS_COLOR_RGBX32: | ||
873 | bpp = 32; | ||
874 | break; | ||
875 | |||
876 | default: | ||
877 | BUG(); | ||
878 | } | ||
879 | |||
880 | if (mc->x > oi->pos_x) { | ||
881 | x = 0; | ||
882 | outw -= (mc->x - oi->pos_x); | ||
883 | paddr += (mc->x - oi->pos_x) * | ||
884 | scale_x_m / scale_x_d * bpp / 8; | ||
885 | } else { | ||
886 | x = oi->pos_x - mc->x; | ||
887 | } | ||
888 | |||
889 | if (mc->y > oi->pos_y) { | ||
890 | y = 0; | ||
891 | outh -= (mc->y - oi->pos_y); | ||
892 | paddr += (mc->y - oi->pos_y) * | ||
893 | scale_y_m / scale_y_d * | ||
894 | oi->screen_width * bpp / 8; | ||
895 | } else { | ||
896 | y = oi->pos_y - mc->y; | ||
897 | } | ||
898 | |||
899 | if (mc->w < (x + outw)) | ||
900 | outw -= (x + outw) - (mc->w); | ||
901 | |||
902 | if (mc->h < (y + outh)) | ||
903 | outh -= (y + outh) - (mc->h); | ||
904 | |||
905 | w = w * outw / orig_outw; | ||
906 | h = h * outh / orig_outh; | ||
907 | |||
908 | /* YUV mode overlay's input width has to be even and the | ||
909 | * algorithm above may adjust the width to be odd. | ||
910 | * | ||
911 | * Here we adjust the width if needed, preferring to increase | ||
912 | * the width if the original width was bigger. | ||
125 | */ | 913 | */ |
126 | if (info->partial_alpha_enabled && info->trans_enabled | 914 | if ((w & 1) && |
127 | && info->trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) { | 915 | (oi->color_mode == OMAP_DSS_COLOR_YUV2 || |
128 | DSSERR("check_manager: illegal transparency key\n"); | 916 | oi->color_mode == OMAP_DSS_COLOR_UYVY)) { |
129 | return -EINVAL; | 917 | if (orig_w > w) |
918 | w += 1; | ||
919 | else | ||
920 | w -= 1; | ||
130 | } | 921 | } |
131 | } | 922 | } |
132 | 923 | ||
924 | r = dispc_setup_plane(plane, | ||
925 | paddr, | ||
926 | oi->screen_width, | ||
927 | x, y, | ||
928 | w, h, | ||
929 | outw, outh, | ||
930 | oi->color_mode, | ||
931 | c->ilace, | ||
932 | oi->rotation_type, | ||
933 | oi->rotation, | ||
934 | oi->mirror, | ||
935 | oi->global_alpha, | ||
936 | oi->pre_mult_alpha, | ||
937 | c->channel, | ||
938 | oi->p_uv_addr); | ||
939 | |||
940 | if (r) { | ||
941 | /* this shouldn't happen */ | ||
942 | DSSERR("dispc_setup_plane failed for ovl %d\n", plane); | ||
943 | dispc_enable_plane(plane, 0); | ||
944 | return r; | ||
945 | } | ||
946 | |||
947 | dispc_enable_replication(plane, c->replication); | ||
948 | |||
949 | dispc_set_fifo_threshold(plane, c->fifo_low, c->fifo_high); | ||
950 | |||
951 | dispc_enable_plane(plane, 1); | ||
952 | |||
133 | return 0; | 953 | return 0; |
134 | } | 954 | } |
135 | 955 | ||
136 | static int dss_mgr_check_zorder(struct omap_overlay_manager *mgr, | 956 | static void configure_manager(enum omap_channel channel) |
137 | struct omap_overlay_info **overlay_infos) | 957 | { |
958 | struct omap_overlay_manager_info *mi; | ||
959 | |||
960 | DSSDBGF("%d", channel); | ||
961 | |||
962 | /* picking info from the cache */ | ||
963 | mi = &dss_cache.manager_cache[channel].info; | ||
964 | |||
965 | dispc_set_default_color(channel, mi->default_color); | ||
966 | dispc_set_trans_key(channel, mi->trans_key_type, mi->trans_key); | ||
967 | dispc_enable_trans_key(channel, mi->trans_enabled); | ||
968 | dispc_enable_alpha_blending(channel, mi->alpha_enabled); | ||
969 | if (dss_has_feature(FEAT_CPR)) { | ||
970 | dispc_enable_cpr(channel, mi->cpr_enable); | ||
971 | dispc_set_cpr_coef(channel, &mi->cpr_coefs); | ||
972 | } | ||
973 | } | ||
974 | |||
975 | /* configure_dispc() tries to write values from cache to shadow registers. | ||
976 | * It writes only to those managers/overlays that are not busy. | ||
977 | * returns 0 if everything could be written to shadow registers. | ||
978 | * returns 1 if not everything could be written to shadow registers. */ | ||
979 | static int configure_dispc(void) | ||
138 | { | 980 | { |
139 | struct omap_overlay *ovl1, *ovl2; | 981 | struct overlay_cache_data *oc; |
140 | struct omap_overlay_info *info1, *info2; | 982 | struct manager_cache_data *mc; |
983 | const int num_ovls = dss_feat_get_num_ovls(); | ||
984 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
985 | int i; | ||
986 | int r; | ||
987 | bool mgr_busy[MAX_DSS_MANAGERS]; | ||
988 | bool mgr_go[MAX_DSS_MANAGERS]; | ||
989 | bool busy; | ||
990 | |||
991 | r = 0; | ||
992 | busy = false; | ||
993 | |||
994 | for (i = 0; i < num_mgrs; i++) { | ||
995 | mgr_busy[i] = dispc_go_busy(i); | ||
996 | mgr_go[i] = false; | ||
997 | } | ||
141 | 998 | ||
142 | list_for_each_entry(ovl1, &mgr->overlays, list) { | 999 | /* Commit overlay settings */ |
143 | info1 = overlay_infos[ovl1->id]; | 1000 | for (i = 0; i < num_ovls; ++i) { |
1001 | oc = &dss_cache.overlay_cache[i]; | ||
1002 | mc = &dss_cache.manager_cache[oc->channel]; | ||
144 | 1003 | ||
145 | if (info1 == NULL) | 1004 | if (!oc->dirty) |
146 | continue; | 1005 | continue; |
147 | 1006 | ||
148 | list_for_each_entry(ovl2, &mgr->overlays, list) { | 1007 | if (mc->manual_update && !mc->do_manual_update) |
149 | if (ovl1 == ovl2) | 1008 | continue; |
150 | continue; | ||
151 | 1009 | ||
152 | info2 = overlay_infos[ovl2->id]; | 1010 | if (mgr_busy[oc->channel]) { |
1011 | busy = true; | ||
1012 | continue; | ||
1013 | } | ||
153 | 1014 | ||
154 | if (info2 == NULL) | 1015 | r = configure_overlay(i); |
155 | continue; | 1016 | if (r) |
1017 | DSSERR("configure_overlay %d failed\n", i); | ||
156 | 1018 | ||
157 | if (info1->zorder == info2->zorder) { | 1019 | oc->dirty = false; |
158 | DSSERR("overlays %d and %d have the same " | 1020 | oc->shadow_dirty = true; |
159 | "zorder %d\n", | 1021 | mgr_go[oc->channel] = true; |
160 | ovl1->id, ovl2->id, info1->zorder); | 1022 | } |
161 | return -EINVAL; | 1023 | |
162 | } | 1024 | /* Commit manager settings */ |
1025 | for (i = 0; i < num_mgrs; ++i) { | ||
1026 | mc = &dss_cache.manager_cache[i]; | ||
1027 | |||
1028 | if (!mc->dirty) | ||
1029 | continue; | ||
1030 | |||
1031 | if (mc->manual_update && !mc->do_manual_update) | ||
1032 | continue; | ||
1033 | |||
1034 | if (mgr_busy[i]) { | ||
1035 | busy = true; | ||
1036 | continue; | ||
163 | } | 1037 | } |
1038 | |||
1039 | configure_manager(i); | ||
1040 | mc->dirty = false; | ||
1041 | mc->shadow_dirty = true; | ||
1042 | mgr_go[i] = true; | ||
164 | } | 1043 | } |
165 | 1044 | ||
166 | return 0; | 1045 | /* set GO */ |
1046 | for (i = 0; i < num_mgrs; ++i) { | ||
1047 | mc = &dss_cache.manager_cache[i]; | ||
1048 | |||
1049 | if (!mgr_go[i]) | ||
1050 | continue; | ||
1051 | |||
1052 | /* We don't need GO with manual update display. LCD iface will | ||
1053 | * always be turned off after frame, and new settings will be | ||
1054 | * taken in to use at next update */ | ||
1055 | if (!mc->manual_update) | ||
1056 | dispc_go(i); | ||
1057 | } | ||
1058 | |||
1059 | if (busy) | ||
1060 | r = 1; | ||
1061 | else | ||
1062 | r = 0; | ||
1063 | |||
1064 | return r; | ||
167 | } | 1065 | } |
168 | 1066 | ||
169 | int dss_mgr_check_timings(struct omap_overlay_manager *mgr, | 1067 | /* Make the coordinates even. There are some strange problems with OMAP and |
170 | const struct omap_video_timings *timings) | 1068 | * partial DSI update when the update widths are odd. */ |
1069 | static void make_even(u16 *x, u16 *w) | ||
171 | { | 1070 | { |
172 | if (!dispc_mgr_timings_ok(mgr->id, timings)) { | 1071 | u16 x1, x2; |
173 | DSSERR("check_manager: invalid timings\n"); | ||
174 | return -EINVAL; | ||
175 | } | ||
176 | 1072 | ||
177 | return 0; | 1073 | x1 = *x; |
1074 | x2 = *x + *w; | ||
1075 | |||
1076 | x1 &= ~1; | ||
1077 | x2 = ALIGN(x2, 2); | ||
1078 | |||
1079 | *x = x1; | ||
1080 | *w = x2 - x1; | ||
178 | } | 1081 | } |
179 | 1082 | ||
180 | static int dss_mgr_check_lcd_config(struct omap_overlay_manager *mgr, | 1083 | /* Configure dispc for partial update. Return possibly modified update |
181 | const struct dss_lcd_mgr_config *config) | 1084 | * area */ |
1085 | void dss_setup_partial_planes(struct omap_dss_device *dssdev, | ||
1086 | u16 *xi, u16 *yi, u16 *wi, u16 *hi, bool enlarge_update_area) | ||
182 | { | 1087 | { |
183 | struct dispc_clock_info cinfo = config->clock_info; | 1088 | struct overlay_cache_data *oc; |
184 | int dl = config->video_port_width; | 1089 | struct manager_cache_data *mc; |
185 | bool stallmode = config->stallmode; | 1090 | struct omap_overlay_info *oi; |
186 | bool fifohandcheck = config->fifohandcheck; | 1091 | const int num_ovls = dss_feat_get_num_ovls(); |
1092 | struct omap_overlay_manager *mgr; | ||
1093 | int i; | ||
1094 | u16 x, y, w, h; | ||
1095 | unsigned long flags; | ||
1096 | bool area_changed; | ||
187 | 1097 | ||
188 | if (cinfo.lck_div < 1 || cinfo.lck_div > 255) | 1098 | x = *xi; |
189 | return -EINVAL; | 1099 | y = *yi; |
1100 | w = *wi; | ||
1101 | h = *hi; | ||
190 | 1102 | ||
191 | if (cinfo.pck_div < 1 || cinfo.pck_div > 255) | 1103 | DSSDBG("dispc_setup_partial_planes %d,%d %dx%d\n", |
192 | return -EINVAL; | 1104 | *xi, *yi, *wi, *hi); |
193 | 1105 | ||
194 | if (dl != 12 && dl != 16 && dl != 18 && dl != 24) | 1106 | mgr = dssdev->manager; |
195 | return -EINVAL; | ||
196 | 1107 | ||
197 | /* fifohandcheck should be used only with stallmode */ | 1108 | if (!mgr) { |
198 | if (stallmode == false && fifohandcheck == true) | 1109 | DSSDBG("no manager\n"); |
199 | return -EINVAL; | 1110 | return; |
1111 | } | ||
1112 | |||
1113 | make_even(&x, &w); | ||
1114 | |||
1115 | spin_lock_irqsave(&dss_cache.lock, flags); | ||
200 | 1116 | ||
201 | /* | 1117 | /* |
202 | * io pad mode can be only checked by using dssdev connected to the | 1118 | * Execute the outer loop until the inner loop has completed |
203 | * manager. Ignore checking these for now, add checks when manager | 1119 | * once without increasing the update area. This will ensure that |
204 | * is capable of holding information related to the connected interface | 1120 | * all scaled overlays end up completely within the update area. |
205 | */ | 1121 | */ |
1122 | do { | ||
1123 | area_changed = false; | ||
206 | 1124 | ||
207 | return 0; | 1125 | /* We need to show the whole overlay if it is scaled. So look |
1126 | * for those, and make the update area larger if found. | ||
1127 | * Also mark the overlay cache dirty */ | ||
1128 | for (i = 0; i < num_ovls; ++i) { | ||
1129 | unsigned x1, y1, x2, y2; | ||
1130 | unsigned outw, outh; | ||
1131 | |||
1132 | oc = &dss_cache.overlay_cache[i]; | ||
1133 | oi = &oc->info; | ||
1134 | |||
1135 | if (oc->channel != mgr->id) | ||
1136 | continue; | ||
1137 | |||
1138 | oc->dirty = true; | ||
1139 | |||
1140 | if (!enlarge_update_area) | ||
1141 | continue; | ||
1142 | |||
1143 | if (!oc->enabled) | ||
1144 | continue; | ||
1145 | |||
1146 | if (!dispc_is_overlay_scaled(oc)) | ||
1147 | continue; | ||
1148 | |||
1149 | outw = oi->out_width == 0 ? | ||
1150 | oi->width : oi->out_width; | ||
1151 | outh = oi->out_height == 0 ? | ||
1152 | oi->height : oi->out_height; | ||
1153 | |||
1154 | /* is the overlay outside the update region? */ | ||
1155 | if (!rectangle_intersects(x, y, w, h, | ||
1156 | oi->pos_x, oi->pos_y, | ||
1157 | outw, outh)) | ||
1158 | continue; | ||
1159 | |||
1160 | /* if the overlay totally inside the update region? */ | ||
1161 | if (rectangle_subset(oi->pos_x, oi->pos_y, outw, outh, | ||
1162 | x, y, w, h)) | ||
1163 | continue; | ||
1164 | |||
1165 | if (x > oi->pos_x) | ||
1166 | x1 = oi->pos_x; | ||
1167 | else | ||
1168 | x1 = x; | ||
1169 | |||
1170 | if (y > oi->pos_y) | ||
1171 | y1 = oi->pos_y; | ||
1172 | else | ||
1173 | y1 = y; | ||
1174 | |||
1175 | if ((x + w) < (oi->pos_x + outw)) | ||
1176 | x2 = oi->pos_x + outw; | ||
1177 | else | ||
1178 | x2 = x + w; | ||
1179 | |||
1180 | if ((y + h) < (oi->pos_y + outh)) | ||
1181 | y2 = oi->pos_y + outh; | ||
1182 | else | ||
1183 | y2 = y + h; | ||
1184 | |||
1185 | x = x1; | ||
1186 | y = y1; | ||
1187 | w = x2 - x1; | ||
1188 | h = y2 - y1; | ||
1189 | |||
1190 | make_even(&x, &w); | ||
1191 | |||
1192 | DSSDBG("changing upd area due to ovl(%d) " | ||
1193 | "scaling %d,%d %dx%d\n", | ||
1194 | i, x, y, w, h); | ||
1195 | |||
1196 | area_changed = true; | ||
1197 | } | ||
1198 | } while (area_changed); | ||
1199 | |||
1200 | mc = &dss_cache.manager_cache[mgr->id]; | ||
1201 | mc->do_manual_update = true; | ||
1202 | mc->enlarge_update_area = enlarge_update_area; | ||
1203 | mc->x = x; | ||
1204 | mc->y = y; | ||
1205 | mc->w = w; | ||
1206 | mc->h = h; | ||
1207 | |||
1208 | configure_dispc(); | ||
1209 | |||
1210 | mc->do_manual_update = false; | ||
1211 | |||
1212 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
1213 | |||
1214 | *xi = x; | ||
1215 | *yi = y; | ||
1216 | *wi = w; | ||
1217 | *hi = h; | ||
208 | } | 1218 | } |
209 | 1219 | ||
210 | int dss_mgr_check(struct omap_overlay_manager *mgr, | 1220 | void dss_start_update(struct omap_dss_device *dssdev) |
211 | struct omap_overlay_manager_info *info, | ||
212 | const struct omap_video_timings *mgr_timings, | ||
213 | const struct dss_lcd_mgr_config *lcd_config, | ||
214 | struct omap_overlay_info **overlay_infos) | ||
215 | { | 1221 | { |
1222 | struct manager_cache_data *mc; | ||
1223 | struct overlay_cache_data *oc; | ||
1224 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1225 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
1226 | struct omap_overlay_manager *mgr; | ||
1227 | int i; | ||
1228 | |||
1229 | mgr = dssdev->manager; | ||
1230 | |||
1231 | for (i = 0; i < num_ovls; ++i) { | ||
1232 | oc = &dss_cache.overlay_cache[i]; | ||
1233 | if (oc->channel != mgr->id) | ||
1234 | continue; | ||
1235 | |||
1236 | oc->shadow_dirty = false; | ||
1237 | } | ||
1238 | |||
1239 | for (i = 0; i < num_mgrs; ++i) { | ||
1240 | mc = &dss_cache.manager_cache[i]; | ||
1241 | if (mgr->id != i) | ||
1242 | continue; | ||
1243 | |||
1244 | mc->shadow_dirty = false; | ||
1245 | } | ||
1246 | |||
1247 | dssdev->manager->enable(dssdev->manager); | ||
1248 | } | ||
1249 | |||
1250 | static void dss_apply_irq_handler(void *data, u32 mask) | ||
1251 | { | ||
1252 | struct manager_cache_data *mc; | ||
1253 | struct overlay_cache_data *oc; | ||
1254 | const int num_ovls = dss_feat_get_num_ovls(); | ||
1255 | const int num_mgrs = dss_feat_get_num_mgrs(); | ||
1256 | int i, r; | ||
1257 | bool mgr_busy[MAX_DSS_MANAGERS]; | ||
1258 | u32 irq_mask; | ||
1259 | |||
1260 | for (i = 0; i < num_mgrs; i++) | ||
1261 | mgr_busy[i] = dispc_go_busy(i); | ||
1262 | |||
1263 | spin_lock(&dss_cache.lock); | ||
1264 | |||
1265 | for (i = 0; i < num_ovls; ++i) { | ||
1266 | oc = &dss_cache.overlay_cache[i]; | ||
1267 | if (!mgr_busy[oc->channel]) | ||
1268 | oc->shadow_dirty = false; | ||
1269 | } | ||
1270 | |||
1271 | for (i = 0; i < num_mgrs; ++i) { | ||
1272 | mc = &dss_cache.manager_cache[i]; | ||
1273 | if (!mgr_busy[i]) | ||
1274 | mc->shadow_dirty = false; | ||
1275 | } | ||
1276 | |||
1277 | r = configure_dispc(); | ||
1278 | if (r == 1) | ||
1279 | goto end; | ||
1280 | |||
1281 | /* re-read busy flags */ | ||
1282 | for (i = 0; i < num_mgrs; i++) | ||
1283 | mgr_busy[i] = dispc_go_busy(i); | ||
1284 | |||
1285 | /* keep running as long as there are busy managers, so that | ||
1286 | * we can collect overlay-applied information */ | ||
1287 | for (i = 0; i < num_mgrs; ++i) { | ||
1288 | if (mgr_busy[i]) | ||
1289 | goto end; | ||
1290 | } | ||
1291 | |||
1292 | irq_mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | | ||
1293 | DISPC_IRQ_EVSYNC_EVEN; | ||
1294 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
1295 | irq_mask |= DISPC_IRQ_VSYNC2; | ||
1296 | |||
1297 | omap_dispc_unregister_isr(dss_apply_irq_handler, NULL, irq_mask); | ||
1298 | dss_cache.irq_enabled = false; | ||
1299 | |||
1300 | end: | ||
1301 | spin_unlock(&dss_cache.lock); | ||
1302 | } | ||
1303 | |||
1304 | static int omap_dss_mgr_apply(struct omap_overlay_manager *mgr) | ||
1305 | { | ||
1306 | struct overlay_cache_data *oc; | ||
1307 | struct manager_cache_data *mc; | ||
1308 | int i; | ||
216 | struct omap_overlay *ovl; | 1309 | struct omap_overlay *ovl; |
1310 | int num_planes_enabled = 0; | ||
1311 | bool use_fifomerge; | ||
1312 | unsigned long flags; | ||
217 | int r; | 1313 | int r; |
218 | 1314 | ||
219 | if (dss_has_feature(FEAT_ALPHA_FREE_ZORDER)) { | 1315 | DSSDBG("omap_dss_mgr_apply(%s)\n", mgr->name); |
220 | r = dss_mgr_check_zorder(mgr, overlay_infos); | ||
221 | if (r) | ||
222 | return r; | ||
223 | } | ||
224 | 1316 | ||
225 | r = dss_mgr_check_timings(mgr, mgr_timings); | 1317 | r = dispc_runtime_get(); |
226 | if (r) | 1318 | if (r) |
227 | return r; | 1319 | return r; |
228 | 1320 | ||
229 | r = dss_mgr_check_lcd_config(mgr, lcd_config); | 1321 | spin_lock_irqsave(&dss_cache.lock, flags); |
230 | if (r) | 1322 | |
1323 | /* Configure overlays */ | ||
1324 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
1325 | struct omap_dss_device *dssdev; | ||
1326 | |||
1327 | ovl = omap_dss_get_overlay(i); | ||
1328 | |||
1329 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) | ||
1330 | continue; | ||
1331 | |||
1332 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
1333 | |||
1334 | if (!overlay_enabled(ovl)) { | ||
1335 | if (oc->enabled) { | ||
1336 | oc->enabled = false; | ||
1337 | oc->dirty = true; | ||
1338 | } | ||
1339 | continue; | ||
1340 | } | ||
1341 | |||
1342 | if (!ovl->info_dirty) { | ||
1343 | if (oc->enabled) | ||
1344 | ++num_planes_enabled; | ||
1345 | continue; | ||
1346 | } | ||
1347 | |||
1348 | dssdev = ovl->manager->device; | ||
1349 | |||
1350 | if (dss_check_overlay(ovl, dssdev)) { | ||
1351 | if (oc->enabled) { | ||
1352 | oc->enabled = false; | ||
1353 | oc->dirty = true; | ||
1354 | } | ||
1355 | continue; | ||
1356 | } | ||
1357 | |||
1358 | ovl->info_dirty = false; | ||
1359 | oc->dirty = true; | ||
1360 | oc->info = ovl->info; | ||
1361 | |||
1362 | oc->replication = | ||
1363 | dss_use_replication(dssdev, ovl->info.color_mode); | ||
1364 | |||
1365 | oc->ilace = dssdev->type == OMAP_DISPLAY_TYPE_VENC; | ||
1366 | |||
1367 | oc->channel = ovl->manager->id; | ||
1368 | |||
1369 | oc->enabled = true; | ||
1370 | |||
1371 | ++num_planes_enabled; | ||
1372 | } | ||
1373 | |||
1374 | /* Configure managers */ | ||
1375 | list_for_each_entry(mgr, &manager_list, list) { | ||
1376 | struct omap_dss_device *dssdev; | ||
1377 | |||
1378 | if (!(mgr->caps & OMAP_DSS_OVL_MGR_CAP_DISPC)) | ||
1379 | continue; | ||
1380 | |||
1381 | mc = &dss_cache.manager_cache[mgr->id]; | ||
1382 | |||
1383 | if (mgr->device_changed) { | ||
1384 | mgr->device_changed = false; | ||
1385 | mgr->info_dirty = true; | ||
1386 | } | ||
1387 | |||
1388 | if (!mgr->info_dirty) | ||
1389 | continue; | ||
1390 | |||
1391 | if (!mgr->device) | ||
1392 | continue; | ||
1393 | |||
1394 | dssdev = mgr->device; | ||
1395 | |||
1396 | mgr->info_dirty = false; | ||
1397 | mc->dirty = true; | ||
1398 | mc->info = mgr->info; | ||
1399 | |||
1400 | mc->manual_update = | ||
1401 | dssdev->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
1402 | } | ||
1403 | |||
1404 | /* XXX TODO: Try to get fifomerge working. The problem is that it | ||
1405 | * affects both managers, not individually but at the same time. This | ||
1406 | * means the change has to be well synchronized. I guess the proper way | ||
1407 | * is to have a two step process for fifo merge: | ||
1408 | * fifomerge enable: | ||
1409 | * 1. disable other planes, leaving one plane enabled | ||
1410 | * 2. wait until the planes are disabled on HW | ||
1411 | * 3. config merged fifo thresholds, enable fifomerge | ||
1412 | * fifomerge disable: | ||
1413 | * 1. config unmerged fifo thresholds, disable fifomerge | ||
1414 | * 2. wait until fifo changes are in HW | ||
1415 | * 3. enable planes | ||
1416 | */ | ||
1417 | use_fifomerge = false; | ||
1418 | |||
1419 | /* Configure overlay fifos */ | ||
1420 | for (i = 0; i < omap_dss_get_num_overlays(); ++i) { | ||
1421 | struct omap_dss_device *dssdev; | ||
1422 | u32 size, burst_size; | ||
1423 | |||
1424 | ovl = omap_dss_get_overlay(i); | ||
1425 | |||
1426 | if (!(ovl->caps & OMAP_DSS_OVL_CAP_DISPC)) | ||
1427 | continue; | ||
1428 | |||
1429 | oc = &dss_cache.overlay_cache[ovl->id]; | ||
1430 | |||
1431 | if (!oc->enabled) | ||
1432 | continue; | ||
1433 | |||
1434 | dssdev = ovl->manager->device; | ||
1435 | |||
1436 | size = dispc_get_plane_fifo_size(ovl->id); | ||
1437 | if (use_fifomerge) | ||
1438 | size *= 3; | ||
1439 | |||
1440 | burst_size = dispc_get_burst_size(ovl->id); | ||
1441 | |||
1442 | switch (dssdev->type) { | ||
1443 | case OMAP_DISPLAY_TYPE_DPI: | ||
1444 | case OMAP_DISPLAY_TYPE_DBI: | ||
1445 | case OMAP_DISPLAY_TYPE_SDI: | ||
1446 | case OMAP_DISPLAY_TYPE_VENC: | ||
1447 | case OMAP_DISPLAY_TYPE_HDMI: | ||
1448 | default_get_overlay_fifo_thresholds(ovl->id, size, | ||
1449 | burst_size, &oc->fifo_low, | ||
1450 | &oc->fifo_high); | ||
1451 | break; | ||
1452 | #ifdef CONFIG_OMAP2_DSS_DSI | ||
1453 | case OMAP_DISPLAY_TYPE_DSI: | ||
1454 | dsi_get_overlay_fifo_thresholds(ovl->id, size, | ||
1455 | burst_size, &oc->fifo_low, | ||
1456 | &oc->fifo_high); | ||
1457 | break; | ||
1458 | #endif | ||
1459 | default: | ||
1460 | BUG(); | ||
1461 | } | ||
1462 | } | ||
1463 | |||
1464 | r = 0; | ||
1465 | if (!dss_cache.irq_enabled) { | ||
1466 | u32 mask; | ||
1467 | |||
1468 | mask = DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_ODD | | ||
1469 | DISPC_IRQ_EVSYNC_EVEN; | ||
1470 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
1471 | mask |= DISPC_IRQ_VSYNC2; | ||
1472 | |||
1473 | r = omap_dispc_register_isr(dss_apply_irq_handler, NULL, mask); | ||
1474 | dss_cache.irq_enabled = true; | ||
1475 | } | ||
1476 | configure_dispc(); | ||
1477 | |||
1478 | spin_unlock_irqrestore(&dss_cache.lock, flags); | ||
1479 | |||
1480 | dispc_runtime_put(); | ||
1481 | |||
1482 | return r; | ||
1483 | } | ||
1484 | |||
1485 | static int dss_check_manager(struct omap_overlay_manager *mgr) | ||
1486 | { | ||
1487 | /* OMAP supports only graphics source transparency color key and alpha | ||
1488 | * blending simultaneously. See TRM 15.4.2.4.2.2 Alpha Mode */ | ||
1489 | |||
1490 | if (mgr->info.alpha_enabled && mgr->info.trans_enabled && | ||
1491 | mgr->info.trans_key_type != OMAP_DSS_COLOR_KEY_GFX_DST) | ||
1492 | return -EINVAL; | ||
1493 | |||
1494 | return 0; | ||
1495 | } | ||
1496 | |||
1497 | static int omap_dss_mgr_set_info(struct omap_overlay_manager *mgr, | ||
1498 | struct omap_overlay_manager_info *info) | ||
1499 | { | ||
1500 | int r; | ||
1501 | struct omap_overlay_manager_info old_info; | ||
1502 | |||
1503 | old_info = mgr->info; | ||
1504 | mgr->info = *info; | ||
1505 | |||
1506 | r = dss_check_manager(mgr); | ||
1507 | if (r) { | ||
1508 | mgr->info = old_info; | ||
231 | return r; | 1509 | return r; |
1510 | } | ||
232 | 1511 | ||
233 | list_for_each_entry(ovl, &mgr->overlays, list) { | 1512 | mgr->info_dirty = true; |
234 | struct omap_overlay_info *oi; | ||
235 | int r; | ||
236 | 1513 | ||
237 | oi = overlay_infos[ovl->id]; | 1514 | return 0; |
1515 | } | ||
238 | 1516 | ||
239 | if (oi == NULL) | 1517 | static void omap_dss_mgr_get_info(struct omap_overlay_manager *mgr, |
1518 | struct omap_overlay_manager_info *info) | ||
1519 | { | ||
1520 | *info = mgr->info; | ||
1521 | } | ||
1522 | |||
1523 | static int dss_mgr_enable(struct omap_overlay_manager *mgr) | ||
1524 | { | ||
1525 | dispc_enable_channel(mgr->id, 1); | ||
1526 | return 0; | ||
1527 | } | ||
1528 | |||
1529 | static int dss_mgr_disable(struct omap_overlay_manager *mgr) | ||
1530 | { | ||
1531 | dispc_enable_channel(mgr->id, 0); | ||
1532 | return 0; | ||
1533 | } | ||
1534 | |||
1535 | static void omap_dss_add_overlay_manager(struct omap_overlay_manager *manager) | ||
1536 | { | ||
1537 | ++num_managers; | ||
1538 | list_add_tail(&manager->list, &manager_list); | ||
1539 | } | ||
1540 | |||
1541 | int dss_init_overlay_managers(struct platform_device *pdev) | ||
1542 | { | ||
1543 | int i, r; | ||
1544 | |||
1545 | spin_lock_init(&dss_cache.lock); | ||
1546 | |||
1547 | INIT_LIST_HEAD(&manager_list); | ||
1548 | |||
1549 | num_managers = 0; | ||
1550 | |||
1551 | for (i = 0; i < dss_feat_get_num_mgrs(); ++i) { | ||
1552 | struct omap_overlay_manager *mgr; | ||
1553 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | ||
1554 | |||
1555 | BUG_ON(mgr == NULL); | ||
1556 | |||
1557 | switch (i) { | ||
1558 | case 0: | ||
1559 | mgr->name = "lcd"; | ||
1560 | mgr->id = OMAP_DSS_CHANNEL_LCD; | ||
1561 | break; | ||
1562 | case 1: | ||
1563 | mgr->name = "tv"; | ||
1564 | mgr->id = OMAP_DSS_CHANNEL_DIGIT; | ||
1565 | break; | ||
1566 | case 2: | ||
1567 | mgr->name = "lcd2"; | ||
1568 | mgr->id = OMAP_DSS_CHANNEL_LCD2; | ||
1569 | break; | ||
1570 | } | ||
1571 | |||
1572 | mgr->set_device = &omap_dss_set_device; | ||
1573 | mgr->unset_device = &omap_dss_unset_device; | ||
1574 | mgr->apply = &omap_dss_mgr_apply; | ||
1575 | mgr->set_manager_info = &omap_dss_mgr_set_info; | ||
1576 | mgr->get_manager_info = &omap_dss_mgr_get_info; | ||
1577 | mgr->wait_for_go = &dss_mgr_wait_for_go; | ||
1578 | mgr->wait_for_vsync = &dss_mgr_wait_for_vsync; | ||
1579 | |||
1580 | mgr->enable = &dss_mgr_enable; | ||
1581 | mgr->disable = &dss_mgr_disable; | ||
1582 | |||
1583 | mgr->caps = OMAP_DSS_OVL_MGR_CAP_DISPC; | ||
1584 | mgr->supported_displays = | ||
1585 | dss_feat_get_supported_displays(mgr->id); | ||
1586 | |||
1587 | dss_overlay_setup_dispc_manager(mgr); | ||
1588 | |||
1589 | omap_dss_add_overlay_manager(mgr); | ||
1590 | |||
1591 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, | ||
1592 | &pdev->dev.kobj, "manager%d", i); | ||
1593 | |||
1594 | if (r) { | ||
1595 | DSSERR("failed to create sysfs file\n"); | ||
240 | continue; | 1596 | continue; |
1597 | } | ||
1598 | } | ||
1599 | |||
1600 | #ifdef L4_EXAMPLE | ||
1601 | { | ||
1602 | int omap_dss_mgr_apply_l4(struct omap_overlay_manager *mgr) | ||
1603 | { | ||
1604 | DSSDBG("omap_dss_mgr_apply_l4(%s)\n", mgr->name); | ||
1605 | |||
1606 | return 0; | ||
1607 | } | ||
1608 | |||
1609 | struct omap_overlay_manager *mgr; | ||
1610 | mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); | ||
1611 | |||
1612 | BUG_ON(mgr == NULL); | ||
1613 | |||
1614 | mgr->name = "l4"; | ||
1615 | mgr->supported_displays = | ||
1616 | OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI; | ||
1617 | |||
1618 | mgr->set_device = &omap_dss_set_device; | ||
1619 | mgr->unset_device = &omap_dss_unset_device; | ||
1620 | mgr->apply = &omap_dss_mgr_apply_l4; | ||
1621 | mgr->set_manager_info = &omap_dss_mgr_set_info; | ||
1622 | mgr->get_manager_info = &omap_dss_mgr_get_info; | ||
1623 | |||
1624 | dss_overlay_setup_l4_manager(mgr); | ||
1625 | |||
1626 | omap_dss_add_overlay_manager(mgr); | ||
1627 | |||
1628 | r = kobject_init_and_add(&mgr->kobj, &manager_ktype, | ||
1629 | &pdev->dev.kobj, "managerl4"); | ||
241 | 1630 | ||
242 | r = dss_ovl_check(ovl, oi, mgr_timings); | ||
243 | if (r) | 1631 | if (r) |
244 | return r; | 1632 | DSSERR("failed to create sysfs file\n"); |
245 | } | 1633 | } |
1634 | #endif | ||
246 | 1635 | ||
247 | return 0; | 1636 | return 0; |
248 | } | 1637 | } |
1638 | |||
1639 | void dss_uninit_overlay_managers(struct platform_device *pdev) | ||
1640 | { | ||
1641 | struct omap_overlay_manager *mgr; | ||
1642 | |||
1643 | while (!list_empty(&manager_list)) { | ||
1644 | mgr = list_first_entry(&manager_list, | ||
1645 | struct omap_overlay_manager, list); | ||
1646 | list_del(&mgr->list); | ||
1647 | kobject_del(&mgr->kobj); | ||
1648 | kobject_put(&mgr->kobj); | ||
1649 | kfree(mgr); | ||
1650 | } | ||
1651 | |||
1652 | num_managers = 0; | ||
1653 | } | ||
1654 | |||
1655 | int omap_dss_get_num_overlay_managers(void) | ||
1656 | { | ||
1657 | return num_managers; | ||
1658 | } | ||
1659 | EXPORT_SYMBOL(omap_dss_get_num_overlay_managers); | ||
1660 | |||
1661 | struct omap_overlay_manager *omap_dss_get_overlay_manager(int num) | ||
1662 | { | ||
1663 | int i = 0; | ||
1664 | struct omap_overlay_manager *mgr; | ||
1665 | |||
1666 | list_for_each_entry(mgr, &manager_list, list) { | ||
1667 | if (i++ == num) | ||
1668 | return mgr; | ||
1669 | } | ||
1670 | |||
1671 | return NULL; | ||
1672 | } | ||
1673 | EXPORT_SYMBOL(omap_dss_get_overlay_manager); | ||
1674 | |||
diff --git a/drivers/video/omap2/dss/output.c b/drivers/video/omap2/dss/output.c deleted file mode 100644 index 79dea1a1a73..00000000000 --- a/drivers/video/omap2/dss/output.c +++ /dev/null | |||
@@ -1,180 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Texas Instruments Ltd | ||
3 | * Author: Archit Taneja <archit@ti.com> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License along with | ||
15 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include <video/omapdss.h> | ||
24 | |||
25 | #include "dss.h" | ||
26 | |||
27 | static LIST_HEAD(output_list); | ||
28 | static DEFINE_MUTEX(output_lock); | ||
29 | |||
30 | int omapdss_output_set_device(struct omap_dss_output *out, | ||
31 | struct omap_dss_device *dssdev) | ||
32 | { | ||
33 | int r; | ||
34 | |||
35 | mutex_lock(&output_lock); | ||
36 | |||
37 | if (out->device) { | ||
38 | DSSERR("output already has device %s connected to it\n", | ||
39 | out->device->name); | ||
40 | r = -EINVAL; | ||
41 | goto err; | ||
42 | } | ||
43 | |||
44 | if (out->type != dssdev->type) { | ||
45 | DSSERR("output type and display type don't match\n"); | ||
46 | r = -EINVAL; | ||
47 | goto err; | ||
48 | } | ||
49 | |||
50 | out->device = dssdev; | ||
51 | dssdev->output = out; | ||
52 | |||
53 | mutex_unlock(&output_lock); | ||
54 | |||
55 | return 0; | ||
56 | err: | ||
57 | mutex_unlock(&output_lock); | ||
58 | |||
59 | return r; | ||
60 | } | ||
61 | EXPORT_SYMBOL(omapdss_output_set_device); | ||
62 | |||
63 | int omapdss_output_unset_device(struct omap_dss_output *out) | ||
64 | { | ||
65 | int r; | ||
66 | |||
67 | mutex_lock(&output_lock); | ||
68 | |||
69 | if (!out->device) { | ||
70 | DSSERR("output doesn't have a device connected to it\n"); | ||
71 | r = -EINVAL; | ||
72 | goto err; | ||
73 | } | ||
74 | |||
75 | if (out->device->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
76 | DSSERR("device %s is not disabled, cannot unset device\n", | ||
77 | out->device->name); | ||
78 | r = -EINVAL; | ||
79 | goto err; | ||
80 | } | ||
81 | |||
82 | out->device->output = NULL; | ||
83 | out->device = NULL; | ||
84 | |||
85 | mutex_unlock(&output_lock); | ||
86 | |||
87 | return 0; | ||
88 | err: | ||
89 | mutex_unlock(&output_lock); | ||
90 | |||
91 | return r; | ||
92 | } | ||
93 | EXPORT_SYMBOL(omapdss_output_unset_device); | ||
94 | |||
95 | void dss_register_output(struct omap_dss_output *out) | ||
96 | { | ||
97 | list_add_tail(&out->list, &output_list); | ||
98 | } | ||
99 | |||
100 | void dss_unregister_output(struct omap_dss_output *out) | ||
101 | { | ||
102 | list_del(&out->list); | ||
103 | } | ||
104 | |||
105 | struct omap_dss_output *omap_dss_get_output(enum omap_dss_output_id id) | ||
106 | { | ||
107 | struct omap_dss_output *out; | ||
108 | |||
109 | list_for_each_entry(out, &output_list, list) { | ||
110 | if (out->id == id) | ||
111 | return out; | ||
112 | } | ||
113 | |||
114 | return NULL; | ||
115 | } | ||
116 | |||
117 | static const struct dss_mgr_ops *dss_mgr_ops; | ||
118 | |||
119 | int dss_install_mgr_ops(const struct dss_mgr_ops *mgr_ops) | ||
120 | { | ||
121 | if (dss_mgr_ops) | ||
122 | return -EBUSY; | ||
123 | |||
124 | dss_mgr_ops = mgr_ops; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | EXPORT_SYMBOL(dss_install_mgr_ops); | ||
129 | |||
130 | void dss_uninstall_mgr_ops(void) | ||
131 | { | ||
132 | dss_mgr_ops = NULL; | ||
133 | } | ||
134 | EXPORT_SYMBOL(dss_uninstall_mgr_ops); | ||
135 | |||
136 | void dss_mgr_set_timings(struct omap_overlay_manager *mgr, | ||
137 | const struct omap_video_timings *timings) | ||
138 | { | ||
139 | dss_mgr_ops->set_timings(mgr, timings); | ||
140 | } | ||
141 | EXPORT_SYMBOL(dss_mgr_set_timings); | ||
142 | |||
143 | void dss_mgr_set_lcd_config(struct omap_overlay_manager *mgr, | ||
144 | const struct dss_lcd_mgr_config *config) | ||
145 | { | ||
146 | dss_mgr_ops->set_lcd_config(mgr, config); | ||
147 | } | ||
148 | EXPORT_SYMBOL(dss_mgr_set_lcd_config); | ||
149 | |||
150 | int dss_mgr_enable(struct omap_overlay_manager *mgr) | ||
151 | { | ||
152 | return dss_mgr_ops->enable(mgr); | ||
153 | } | ||
154 | EXPORT_SYMBOL(dss_mgr_enable); | ||
155 | |||
156 | void dss_mgr_disable(struct omap_overlay_manager *mgr) | ||
157 | { | ||
158 | dss_mgr_ops->disable(mgr); | ||
159 | } | ||
160 | EXPORT_SYMBOL(dss_mgr_disable); | ||
161 | |||
162 | void dss_mgr_start_update(struct omap_overlay_manager *mgr) | ||
163 | { | ||
164 | dss_mgr_ops->start_update(mgr); | ||
165 | } | ||
166 | EXPORT_SYMBOL(dss_mgr_start_update); | ||
167 | |||
168 | int dss_mgr_register_framedone_handler(struct omap_overlay_manager *mgr, | ||
169 | void (*handler)(void *), void *data) | ||
170 | { | ||
171 | return dss_mgr_ops->register_framedone_handler(mgr, handler, data); | ||
172 | } | ||
173 | EXPORT_SYMBOL(dss_mgr_register_framedone_handler); | ||
174 | |||
175 | void dss_mgr_unregister_framedone_handler(struct omap_overlay_manager *mgr, | ||
176 | void (*handler)(void *), void *data) | ||
177 | { | ||
178 | dss_mgr_ops->unregister_framedone_handler(mgr, handler, data); | ||
179 | } | ||
180 | EXPORT_SYMBOL(dss_mgr_unregister_framedone_handler); | ||
diff --git a/drivers/video/omap2/dss/overlay-sysfs.c b/drivers/video/omap2/dss/overlay-sysfs.c deleted file mode 100644 index 4cc5ddebfb3..00000000000 --- a/drivers/video/omap2/dss/overlay-sysfs.c +++ /dev/null | |||
@@ -1,456 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * Some code and ideas taken from drivers/video/omap/ driver | ||
6 | * by Imre Deak. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #define DSS_SUBSYS_NAME "OVERLAY" | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/sysfs.h> | ||
26 | #include <linux/kobject.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | |||
29 | #include <video/omapdss.h> | ||
30 | |||
31 | #include "dss.h" | ||
32 | #include "dss_features.h" | ||
33 | |||
34 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) | ||
35 | { | ||
36 | return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); | ||
37 | } | ||
38 | |||
39 | static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) | ||
40 | { | ||
41 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
42 | ovl->manager ? ovl->manager->name : "<none>"); | ||
43 | } | ||
44 | |||
45 | static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, | ||
46 | size_t size) | ||
47 | { | ||
48 | int i, r; | ||
49 | struct omap_overlay_manager *mgr = NULL; | ||
50 | struct omap_overlay_manager *old_mgr; | ||
51 | int len = size; | ||
52 | |||
53 | if (buf[size-1] == '\n') | ||
54 | --len; | ||
55 | |||
56 | if (len > 0) { | ||
57 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { | ||
58 | mgr = omap_dss_get_overlay_manager(i); | ||
59 | |||
60 | if (sysfs_streq(buf, mgr->name)) | ||
61 | break; | ||
62 | |||
63 | mgr = NULL; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | if (len > 0 && mgr == NULL) | ||
68 | return -EINVAL; | ||
69 | |||
70 | if (mgr) | ||
71 | DSSDBG("manager %s found\n", mgr->name); | ||
72 | |||
73 | if (mgr == ovl->manager) | ||
74 | return size; | ||
75 | |||
76 | old_mgr = ovl->manager; | ||
77 | |||
78 | r = dispc_runtime_get(); | ||
79 | if (r) | ||
80 | return r; | ||
81 | |||
82 | /* detach old manager */ | ||
83 | if (old_mgr) { | ||
84 | r = ovl->unset_manager(ovl); | ||
85 | if (r) { | ||
86 | DSSERR("detach failed\n"); | ||
87 | goto err; | ||
88 | } | ||
89 | |||
90 | r = old_mgr->apply(old_mgr); | ||
91 | if (r) | ||
92 | goto err; | ||
93 | } | ||
94 | |||
95 | if (mgr) { | ||
96 | r = ovl->set_manager(ovl, mgr); | ||
97 | if (r) { | ||
98 | DSSERR("Failed to attach overlay\n"); | ||
99 | goto err; | ||
100 | } | ||
101 | |||
102 | r = mgr->apply(mgr); | ||
103 | if (r) | ||
104 | goto err; | ||
105 | } | ||
106 | |||
107 | dispc_runtime_put(); | ||
108 | |||
109 | return size; | ||
110 | |||
111 | err: | ||
112 | dispc_runtime_put(); | ||
113 | return r; | ||
114 | } | ||
115 | |||
116 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) | ||
117 | { | ||
118 | struct omap_overlay_info info; | ||
119 | |||
120 | ovl->get_overlay_info(ovl, &info); | ||
121 | |||
122 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
123 | info.width, info.height); | ||
124 | } | ||
125 | |||
126 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) | ||
127 | { | ||
128 | struct omap_overlay_info info; | ||
129 | |||
130 | ovl->get_overlay_info(ovl, &info); | ||
131 | |||
132 | return snprintf(buf, PAGE_SIZE, "%d\n", info.screen_width); | ||
133 | } | ||
134 | |||
135 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) | ||
136 | { | ||
137 | struct omap_overlay_info info; | ||
138 | |||
139 | ovl->get_overlay_info(ovl, &info); | ||
140 | |||
141 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
142 | info.pos_x, info.pos_y); | ||
143 | } | ||
144 | |||
145 | static ssize_t overlay_position_store(struct omap_overlay *ovl, | ||
146 | const char *buf, size_t size) | ||
147 | { | ||
148 | int r; | ||
149 | char *last; | ||
150 | struct omap_overlay_info info; | ||
151 | |||
152 | ovl->get_overlay_info(ovl, &info); | ||
153 | |||
154 | info.pos_x = simple_strtoul(buf, &last, 10); | ||
155 | ++last; | ||
156 | if (last - buf >= size) | ||
157 | return -EINVAL; | ||
158 | |||
159 | info.pos_y = simple_strtoul(last, &last, 10); | ||
160 | |||
161 | r = ovl->set_overlay_info(ovl, &info); | ||
162 | if (r) | ||
163 | return r; | ||
164 | |||
165 | if (ovl->manager) { | ||
166 | r = ovl->manager->apply(ovl->manager); | ||
167 | if (r) | ||
168 | return r; | ||
169 | } | ||
170 | |||
171 | return size; | ||
172 | } | ||
173 | |||
174 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | ||
175 | { | ||
176 | struct omap_overlay_info info; | ||
177 | |||
178 | ovl->get_overlay_info(ovl, &info); | ||
179 | |||
180 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
181 | info.out_width, info.out_height); | ||
182 | } | ||
183 | |||
184 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | ||
185 | const char *buf, size_t size) | ||
186 | { | ||
187 | int r; | ||
188 | char *last; | ||
189 | struct omap_overlay_info info; | ||
190 | |||
191 | ovl->get_overlay_info(ovl, &info); | ||
192 | |||
193 | info.out_width = simple_strtoul(buf, &last, 10); | ||
194 | ++last; | ||
195 | if (last - buf >= size) | ||
196 | return -EINVAL; | ||
197 | |||
198 | info.out_height = simple_strtoul(last, &last, 10); | ||
199 | |||
200 | r = ovl->set_overlay_info(ovl, &info); | ||
201 | if (r) | ||
202 | return r; | ||
203 | |||
204 | if (ovl->manager) { | ||
205 | r = ovl->manager->apply(ovl->manager); | ||
206 | if (r) | ||
207 | return r; | ||
208 | } | ||
209 | |||
210 | return size; | ||
211 | } | ||
212 | |||
213 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | ||
214 | { | ||
215 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->is_enabled(ovl)); | ||
216 | } | ||
217 | |||
218 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | ||
219 | size_t size) | ||
220 | { | ||
221 | int r; | ||
222 | bool enable; | ||
223 | |||
224 | r = strtobool(buf, &enable); | ||
225 | if (r) | ||
226 | return r; | ||
227 | |||
228 | if (enable) | ||
229 | r = ovl->enable(ovl); | ||
230 | else | ||
231 | r = ovl->disable(ovl); | ||
232 | |||
233 | if (r) | ||
234 | return r; | ||
235 | |||
236 | return size; | ||
237 | } | ||
238 | |||
239 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) | ||
240 | { | ||
241 | struct omap_overlay_info info; | ||
242 | |||
243 | ovl->get_overlay_info(ovl, &info); | ||
244 | |||
245 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
246 | info.global_alpha); | ||
247 | } | ||
248 | |||
249 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | ||
250 | const char *buf, size_t size) | ||
251 | { | ||
252 | int r; | ||
253 | u8 alpha; | ||
254 | struct omap_overlay_info info; | ||
255 | |||
256 | if ((ovl->caps & OMAP_DSS_OVL_CAP_GLOBAL_ALPHA) == 0) | ||
257 | return -ENODEV; | ||
258 | |||
259 | r = kstrtou8(buf, 0, &alpha); | ||
260 | if (r) | ||
261 | return r; | ||
262 | |||
263 | ovl->get_overlay_info(ovl, &info); | ||
264 | |||
265 | info.global_alpha = alpha; | ||
266 | |||
267 | r = ovl->set_overlay_info(ovl, &info); | ||
268 | if (r) | ||
269 | return r; | ||
270 | |||
271 | if (ovl->manager) { | ||
272 | r = ovl->manager->apply(ovl->manager); | ||
273 | if (r) | ||
274 | return r; | ||
275 | } | ||
276 | |||
277 | return size; | ||
278 | } | ||
279 | |||
280 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, | ||
281 | char *buf) | ||
282 | { | ||
283 | struct omap_overlay_info info; | ||
284 | |||
285 | ovl->get_overlay_info(ovl, &info); | ||
286 | |||
287 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
288 | info.pre_mult_alpha); | ||
289 | } | ||
290 | |||
291 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, | ||
292 | const char *buf, size_t size) | ||
293 | { | ||
294 | int r; | ||
295 | u8 alpha; | ||
296 | struct omap_overlay_info info; | ||
297 | |||
298 | if ((ovl->caps & OMAP_DSS_OVL_CAP_PRE_MULT_ALPHA) == 0) | ||
299 | return -ENODEV; | ||
300 | |||
301 | r = kstrtou8(buf, 0, &alpha); | ||
302 | if (r) | ||
303 | return r; | ||
304 | |||
305 | ovl->get_overlay_info(ovl, &info); | ||
306 | |||
307 | info.pre_mult_alpha = alpha; | ||
308 | |||
309 | r = ovl->set_overlay_info(ovl, &info); | ||
310 | if (r) | ||
311 | return r; | ||
312 | |||
313 | if (ovl->manager) { | ||
314 | r = ovl->manager->apply(ovl->manager); | ||
315 | if (r) | ||
316 | return r; | ||
317 | } | ||
318 | |||
319 | return size; | ||
320 | } | ||
321 | |||
322 | static ssize_t overlay_zorder_show(struct omap_overlay *ovl, char *buf) | ||
323 | { | ||
324 | struct omap_overlay_info info; | ||
325 | |||
326 | ovl->get_overlay_info(ovl, &info); | ||
327 | |||
328 | return snprintf(buf, PAGE_SIZE, "%d\n", info.zorder); | ||
329 | } | ||
330 | |||
331 | static ssize_t overlay_zorder_store(struct omap_overlay *ovl, | ||
332 | const char *buf, size_t size) | ||
333 | { | ||
334 | int r; | ||
335 | u8 zorder; | ||
336 | struct omap_overlay_info info; | ||
337 | |||
338 | if ((ovl->caps & OMAP_DSS_OVL_CAP_ZORDER) == 0) | ||
339 | return -ENODEV; | ||
340 | |||
341 | r = kstrtou8(buf, 0, &zorder); | ||
342 | if (r) | ||
343 | return r; | ||
344 | |||
345 | ovl->get_overlay_info(ovl, &info); | ||
346 | |||
347 | info.zorder = zorder; | ||
348 | |||
349 | r = ovl->set_overlay_info(ovl, &info); | ||
350 | if (r) | ||
351 | return r; | ||
352 | |||
353 | if (ovl->manager) { | ||
354 | r = ovl->manager->apply(ovl->manager); | ||
355 | if (r) | ||
356 | return r; | ||
357 | } | ||
358 | |||
359 | return size; | ||
360 | } | ||
361 | |||
362 | struct overlay_attribute { | ||
363 | struct attribute attr; | ||
364 | ssize_t (*show)(struct omap_overlay *, char *); | ||
365 | ssize_t (*store)(struct omap_overlay *, const char *, size_t); | ||
366 | }; | ||
367 | |||
368 | #define OVERLAY_ATTR(_name, _mode, _show, _store) \ | ||
369 | struct overlay_attribute overlay_attr_##_name = \ | ||
370 | __ATTR(_name, _mode, _show, _store) | ||
371 | |||
372 | static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); | ||
373 | static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, | ||
374 | overlay_manager_show, overlay_manager_store); | ||
375 | static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); | ||
376 | static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); | ||
377 | static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, | ||
378 | overlay_position_show, overlay_position_store); | ||
379 | static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, | ||
380 | overlay_output_size_show, overlay_output_size_store); | ||
381 | static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
382 | overlay_enabled_show, overlay_enabled_store); | ||
383 | static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, | ||
384 | overlay_global_alpha_show, overlay_global_alpha_store); | ||
385 | static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, | ||
386 | overlay_pre_mult_alpha_show, | ||
387 | overlay_pre_mult_alpha_store); | ||
388 | static OVERLAY_ATTR(zorder, S_IRUGO|S_IWUSR, | ||
389 | overlay_zorder_show, overlay_zorder_store); | ||
390 | |||
391 | static struct attribute *overlay_sysfs_attrs[] = { | ||
392 | &overlay_attr_name.attr, | ||
393 | &overlay_attr_manager.attr, | ||
394 | &overlay_attr_input_size.attr, | ||
395 | &overlay_attr_screen_width.attr, | ||
396 | &overlay_attr_position.attr, | ||
397 | &overlay_attr_output_size.attr, | ||
398 | &overlay_attr_enabled.attr, | ||
399 | &overlay_attr_global_alpha.attr, | ||
400 | &overlay_attr_pre_mult_alpha.attr, | ||
401 | &overlay_attr_zorder.attr, | ||
402 | NULL | ||
403 | }; | ||
404 | |||
405 | static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, | ||
406 | char *buf) | ||
407 | { | ||
408 | struct omap_overlay *overlay; | ||
409 | struct overlay_attribute *overlay_attr; | ||
410 | |||
411 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
412 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
413 | |||
414 | if (!overlay_attr->show) | ||
415 | return -ENOENT; | ||
416 | |||
417 | return overlay_attr->show(overlay, buf); | ||
418 | } | ||
419 | |||
420 | static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, | ||
421 | const char *buf, size_t size) | ||
422 | { | ||
423 | struct omap_overlay *overlay; | ||
424 | struct overlay_attribute *overlay_attr; | ||
425 | |||
426 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
427 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
428 | |||
429 | if (!overlay_attr->store) | ||
430 | return -ENOENT; | ||
431 | |||
432 | return overlay_attr->store(overlay, buf, size); | ||
433 | } | ||
434 | |||
435 | static const struct sysfs_ops overlay_sysfs_ops = { | ||
436 | .show = overlay_attr_show, | ||
437 | .store = overlay_attr_store, | ||
438 | }; | ||
439 | |||
440 | static struct kobj_type overlay_ktype = { | ||
441 | .sysfs_ops = &overlay_sysfs_ops, | ||
442 | .default_attrs = overlay_sysfs_attrs, | ||
443 | }; | ||
444 | |||
445 | int dss_overlay_kobj_init(struct omap_overlay *ovl, | ||
446 | struct platform_device *pdev) | ||
447 | { | ||
448 | return kobject_init_and_add(&ovl->kobj, &overlay_ktype, | ||
449 | &pdev->dev.kobj, "overlay%d", ovl->id); | ||
450 | } | ||
451 | |||
452 | void dss_overlay_kobj_uninit(struct omap_overlay *ovl) | ||
453 | { | ||
454 | kobject_del(&ovl->kobj); | ||
455 | kobject_put(&ovl->kobj); | ||
456 | } | ||
diff --git a/drivers/video/omap2/dss/overlay.c b/drivers/video/omap2/dss/overlay.c index eccde322c28..c84380c53c3 100644 --- a/drivers/video/omap2/dss/overlay.c +++ b/drivers/video/omap2/dss/overlay.c | |||
@@ -26,140 +26,409 @@ | |||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/sysfs.h> | 28 | #include <linux/sysfs.h> |
29 | #include <linux/kobject.h> | ||
29 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
30 | #include <linux/delay.h> | 31 | #include <linux/delay.h> |
31 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
32 | 33 | ||
33 | #include <video/omapdss.h> | 34 | #include <video/omapdss.h> |
35 | #include <plat/cpu.h> | ||
34 | 36 | ||
35 | #include "dss.h" | 37 | #include "dss.h" |
36 | #include "dss_features.h" | 38 | #include "dss_features.h" |
37 | 39 | ||
38 | static int num_overlays; | 40 | static int num_overlays; |
39 | static struct omap_overlay *overlays; | 41 | static struct list_head overlay_list; |
40 | 42 | ||
41 | int omap_dss_get_num_overlays(void) | 43 | static ssize_t overlay_name_show(struct omap_overlay *ovl, char *buf) |
42 | { | 44 | { |
43 | return num_overlays; | 45 | return snprintf(buf, PAGE_SIZE, "%s\n", ovl->name); |
44 | } | 46 | } |
45 | EXPORT_SYMBOL(omap_dss_get_num_overlays); | ||
46 | 47 | ||
47 | struct omap_overlay *omap_dss_get_overlay(int num) | 48 | static ssize_t overlay_manager_show(struct omap_overlay *ovl, char *buf) |
48 | { | 49 | { |
49 | if (num >= num_overlays) | 50 | return snprintf(buf, PAGE_SIZE, "%s\n", |
50 | return NULL; | 51 | ovl->manager ? ovl->manager->name : "<none>"); |
51 | |||
52 | return &overlays[num]; | ||
53 | } | 52 | } |
54 | EXPORT_SYMBOL(omap_dss_get_overlay); | ||
55 | 53 | ||
56 | void dss_init_overlays(struct platform_device *pdev) | 54 | static ssize_t overlay_manager_store(struct omap_overlay *ovl, const char *buf, |
55 | size_t size) | ||
57 | { | 56 | { |
58 | int i, r; | 57 | int i, r; |
58 | struct omap_overlay_manager *mgr = NULL; | ||
59 | struct omap_overlay_manager *old_mgr; | ||
60 | int len = size; | ||
59 | 61 | ||
60 | num_overlays = dss_feat_get_num_ovls(); | 62 | if (buf[size-1] == '\n') |
63 | --len; | ||
61 | 64 | ||
62 | overlays = kzalloc(sizeof(struct omap_overlay) * num_overlays, | 65 | if (len > 0) { |
63 | GFP_KERNEL); | 66 | for (i = 0; i < omap_dss_get_num_overlay_managers(); ++i) { |
67 | mgr = omap_dss_get_overlay_manager(i); | ||
64 | 68 | ||
65 | BUG_ON(overlays == NULL); | 69 | if (sysfs_streq(buf, mgr->name)) |
70 | break; | ||
66 | 71 | ||
67 | for (i = 0; i < num_overlays; ++i) { | 72 | mgr = NULL; |
68 | struct omap_overlay *ovl = &overlays[i]; | 73 | } |
74 | } | ||
69 | 75 | ||
70 | switch (i) { | 76 | if (len > 0 && mgr == NULL) |
71 | case 0: | 77 | return -EINVAL; |
72 | ovl->name = "gfx"; | 78 | |
73 | ovl->id = OMAP_DSS_GFX; | 79 | if (mgr) |
74 | break; | 80 | DSSDBG("manager %s found\n", mgr->name); |
75 | case 1: | 81 | |
76 | ovl->name = "vid1"; | 82 | if (mgr == ovl->manager) |
77 | ovl->id = OMAP_DSS_VIDEO1; | 83 | return size; |
78 | break; | 84 | |
79 | case 2: | 85 | old_mgr = ovl->manager; |
80 | ovl->name = "vid2"; | 86 | |
81 | ovl->id = OMAP_DSS_VIDEO2; | 87 | r = dispc_runtime_get(); |
82 | break; | 88 | if (r) |
83 | case 3: | 89 | return r; |
84 | ovl->name = "vid3"; | 90 | |
85 | ovl->id = OMAP_DSS_VIDEO3; | 91 | /* detach old manager */ |
86 | break; | 92 | if (old_mgr) { |
93 | r = ovl->unset_manager(ovl); | ||
94 | if (r) { | ||
95 | DSSERR("detach failed\n"); | ||
96 | goto err; | ||
87 | } | 97 | } |
88 | 98 | ||
89 | ovl->caps = dss_feat_get_overlay_caps(ovl->id); | 99 | r = old_mgr->apply(old_mgr); |
90 | ovl->supported_modes = | 100 | if (r) |
91 | dss_feat_get_supported_color_modes(ovl->id); | 101 | goto err; |
102 | } | ||
92 | 103 | ||
93 | r = dss_overlay_kobj_init(ovl, pdev); | 104 | if (mgr) { |
105 | r = ovl->set_manager(ovl, mgr); | ||
106 | if (r) { | ||
107 | DSSERR("Failed to attach overlay\n"); | ||
108 | goto err; | ||
109 | } | ||
110 | |||
111 | r = mgr->apply(mgr); | ||
94 | if (r) | 112 | if (r) |
95 | DSSERR("failed to create sysfs file\n"); | 113 | goto err; |
96 | } | 114 | } |
115 | |||
116 | dispc_runtime_put(); | ||
117 | |||
118 | return size; | ||
119 | |||
120 | err: | ||
121 | dispc_runtime_put(); | ||
122 | return r; | ||
97 | } | 123 | } |
98 | 124 | ||
99 | void dss_uninit_overlays(struct platform_device *pdev) | 125 | static ssize_t overlay_input_size_show(struct omap_overlay *ovl, char *buf) |
100 | { | 126 | { |
101 | int i; | 127 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
128 | ovl->info.width, ovl->info.height); | ||
129 | } | ||
102 | 130 | ||
103 | for (i = 0; i < num_overlays; ++i) { | 131 | static ssize_t overlay_screen_width_show(struct omap_overlay *ovl, char *buf) |
104 | struct omap_overlay *ovl = &overlays[i]; | 132 | { |
105 | dss_overlay_kobj_uninit(ovl); | 133 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.screen_width); |
106 | } | 134 | } |
107 | 135 | ||
108 | kfree(overlays); | 136 | static ssize_t overlay_position_show(struct omap_overlay *ovl, char *buf) |
109 | overlays = NULL; | 137 | { |
110 | num_overlays = 0; | 138 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", |
139 | ovl->info.pos_x, ovl->info.pos_y); | ||
111 | } | 140 | } |
112 | 141 | ||
113 | int dss_ovl_simple_check(struct omap_overlay *ovl, | 142 | static ssize_t overlay_position_store(struct omap_overlay *ovl, |
114 | const struct omap_overlay_info *info) | 143 | const char *buf, size_t size) |
115 | { | 144 | { |
116 | if (info->paddr == 0) { | 145 | int r; |
117 | DSSERR("check_overlay: paddr cannot be 0\n"); | 146 | char *last; |
147 | struct omap_overlay_info info; | ||
148 | |||
149 | ovl->get_overlay_info(ovl, &info); | ||
150 | |||
151 | info.pos_x = simple_strtoul(buf, &last, 10); | ||
152 | ++last; | ||
153 | if (last - buf >= size) | ||
118 | return -EINVAL; | 154 | return -EINVAL; |
119 | } | ||
120 | 155 | ||
121 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | 156 | info.pos_y = simple_strtoul(last, &last, 10); |
122 | if (info->out_width != 0 && info->width != info->out_width) { | ||
123 | DSSERR("check_overlay: overlay %d doesn't support " | ||
124 | "scaling\n", ovl->id); | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | 157 | ||
128 | if (info->out_height != 0 && info->height != info->out_height) { | 158 | r = ovl->set_overlay_info(ovl, &info); |
129 | DSSERR("check_overlay: overlay %d doesn't support " | 159 | if (r) |
130 | "scaling\n", ovl->id); | 160 | return r; |
131 | return -EINVAL; | 161 | |
132 | } | 162 | if (ovl->manager) { |
163 | r = ovl->manager->apply(ovl->manager); | ||
164 | if (r) | ||
165 | return r; | ||
133 | } | 166 | } |
134 | 167 | ||
135 | if ((ovl->supported_modes & info->color_mode) == 0) { | 168 | return size; |
136 | DSSERR("check_overlay: overlay %d doesn't support mode %d\n", | 169 | } |
137 | ovl->id, info->color_mode); | 170 | |
171 | static ssize_t overlay_output_size_show(struct omap_overlay *ovl, char *buf) | ||
172 | { | ||
173 | return snprintf(buf, PAGE_SIZE, "%d,%d\n", | ||
174 | ovl->info.out_width, ovl->info.out_height); | ||
175 | } | ||
176 | |||
177 | static ssize_t overlay_output_size_store(struct omap_overlay *ovl, | ||
178 | const char *buf, size_t size) | ||
179 | { | ||
180 | int r; | ||
181 | char *last; | ||
182 | struct omap_overlay_info info; | ||
183 | |||
184 | ovl->get_overlay_info(ovl, &info); | ||
185 | |||
186 | info.out_width = simple_strtoul(buf, &last, 10); | ||
187 | ++last; | ||
188 | if (last - buf >= size) | ||
138 | return -EINVAL; | 189 | return -EINVAL; |
190 | |||
191 | info.out_height = simple_strtoul(last, &last, 10); | ||
192 | |||
193 | r = ovl->set_overlay_info(ovl, &info); | ||
194 | if (r) | ||
195 | return r; | ||
196 | |||
197 | if (ovl->manager) { | ||
198 | r = ovl->manager->apply(ovl->manager); | ||
199 | if (r) | ||
200 | return r; | ||
139 | } | 201 | } |
140 | 202 | ||
141 | if (info->zorder >= omap_dss_get_num_overlays()) { | 203 | return size; |
142 | DSSERR("check_overlay: zorder %d too high\n", info->zorder); | 204 | } |
143 | return -EINVAL; | 205 | |
206 | static ssize_t overlay_enabled_show(struct omap_overlay *ovl, char *buf) | ||
207 | { | ||
208 | return snprintf(buf, PAGE_SIZE, "%d\n", ovl->info.enabled); | ||
209 | } | ||
210 | |||
211 | static ssize_t overlay_enabled_store(struct omap_overlay *ovl, const char *buf, | ||
212 | size_t size) | ||
213 | { | ||
214 | int r, enable; | ||
215 | struct omap_overlay_info info; | ||
216 | |||
217 | ovl->get_overlay_info(ovl, &info); | ||
218 | |||
219 | r = kstrtoint(buf, 0, &enable); | ||
220 | if (r) | ||
221 | return r; | ||
222 | |||
223 | info.enabled = !!enable; | ||
224 | |||
225 | r = ovl->set_overlay_info(ovl, &info); | ||
226 | if (r) | ||
227 | return r; | ||
228 | |||
229 | if (ovl->manager) { | ||
230 | r = ovl->manager->apply(ovl->manager); | ||
231 | if (r) | ||
232 | return r; | ||
144 | } | 233 | } |
145 | 234 | ||
146 | if (dss_feat_rotation_type_supported(info->rotation_type) == 0) { | 235 | return size; |
147 | DSSERR("check_overlay: rotation type %d not supported\n", | 236 | } |
148 | info->rotation_type); | 237 | |
149 | return -EINVAL; | 238 | static ssize_t overlay_global_alpha_show(struct omap_overlay *ovl, char *buf) |
239 | { | ||
240 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
241 | ovl->info.global_alpha); | ||
242 | } | ||
243 | |||
244 | static ssize_t overlay_global_alpha_store(struct omap_overlay *ovl, | ||
245 | const char *buf, size_t size) | ||
246 | { | ||
247 | int r; | ||
248 | u8 alpha; | ||
249 | struct omap_overlay_info info; | ||
250 | |||
251 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA)) | ||
252 | return -ENODEV; | ||
253 | |||
254 | r = kstrtou8(buf, 0, &alpha); | ||
255 | if (r) | ||
256 | return r; | ||
257 | |||
258 | ovl->get_overlay_info(ovl, &info); | ||
259 | |||
260 | /* Video1 plane does not support global alpha | ||
261 | * to always make it 255 completely opaque | ||
262 | */ | ||
263 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && | ||
264 | ovl->id == OMAP_DSS_VIDEO1) | ||
265 | info.global_alpha = 255; | ||
266 | else | ||
267 | info.global_alpha = alpha; | ||
268 | |||
269 | r = ovl->set_overlay_info(ovl, &info); | ||
270 | if (r) | ||
271 | return r; | ||
272 | |||
273 | if (ovl->manager) { | ||
274 | r = ovl->manager->apply(ovl->manager); | ||
275 | if (r) | ||
276 | return r; | ||
150 | } | 277 | } |
151 | 278 | ||
152 | return 0; | 279 | return size; |
280 | } | ||
281 | |||
282 | static ssize_t overlay_pre_mult_alpha_show(struct omap_overlay *ovl, | ||
283 | char *buf) | ||
284 | { | ||
285 | return snprintf(buf, PAGE_SIZE, "%d\n", | ||
286 | ovl->info.pre_mult_alpha); | ||
153 | } | 287 | } |
154 | 288 | ||
155 | int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, | 289 | static ssize_t overlay_pre_mult_alpha_store(struct omap_overlay *ovl, |
156 | const struct omap_video_timings *mgr_timings) | 290 | const char *buf, size_t size) |
157 | { | 291 | { |
292 | int r; | ||
293 | u8 alpha; | ||
294 | struct omap_overlay_info info; | ||
295 | |||
296 | r = kstrtou8(buf, 0, &alpha); | ||
297 | if (r) | ||
298 | return r; | ||
299 | |||
300 | ovl->get_overlay_info(ovl, &info); | ||
301 | |||
302 | /* only GFX and Video2 plane support pre alpha multiplied | ||
303 | * set zero for Video1 plane | ||
304 | */ | ||
305 | if (!dss_has_feature(FEAT_GLOBAL_ALPHA_VID1) && | ||
306 | ovl->id == OMAP_DSS_VIDEO1) | ||
307 | info.pre_mult_alpha = 0; | ||
308 | else | ||
309 | info.pre_mult_alpha = alpha; | ||
310 | |||
311 | r = ovl->set_overlay_info(ovl, &info); | ||
312 | if (r) | ||
313 | return r; | ||
314 | |||
315 | if (ovl->manager) { | ||
316 | r = ovl->manager->apply(ovl->manager); | ||
317 | if (r) | ||
318 | return r; | ||
319 | } | ||
320 | |||
321 | return size; | ||
322 | } | ||
323 | |||
324 | struct overlay_attribute { | ||
325 | struct attribute attr; | ||
326 | ssize_t (*show)(struct omap_overlay *, char *); | ||
327 | ssize_t (*store)(struct omap_overlay *, const char *, size_t); | ||
328 | }; | ||
329 | |||
330 | #define OVERLAY_ATTR(_name, _mode, _show, _store) \ | ||
331 | struct overlay_attribute overlay_attr_##_name = \ | ||
332 | __ATTR(_name, _mode, _show, _store) | ||
333 | |||
334 | static OVERLAY_ATTR(name, S_IRUGO, overlay_name_show, NULL); | ||
335 | static OVERLAY_ATTR(manager, S_IRUGO|S_IWUSR, | ||
336 | overlay_manager_show, overlay_manager_store); | ||
337 | static OVERLAY_ATTR(input_size, S_IRUGO, overlay_input_size_show, NULL); | ||
338 | static OVERLAY_ATTR(screen_width, S_IRUGO, overlay_screen_width_show, NULL); | ||
339 | static OVERLAY_ATTR(position, S_IRUGO|S_IWUSR, | ||
340 | overlay_position_show, overlay_position_store); | ||
341 | static OVERLAY_ATTR(output_size, S_IRUGO|S_IWUSR, | ||
342 | overlay_output_size_show, overlay_output_size_store); | ||
343 | static OVERLAY_ATTR(enabled, S_IRUGO|S_IWUSR, | ||
344 | overlay_enabled_show, overlay_enabled_store); | ||
345 | static OVERLAY_ATTR(global_alpha, S_IRUGO|S_IWUSR, | ||
346 | overlay_global_alpha_show, overlay_global_alpha_store); | ||
347 | static OVERLAY_ATTR(pre_mult_alpha, S_IRUGO|S_IWUSR, | ||
348 | overlay_pre_mult_alpha_show, | ||
349 | overlay_pre_mult_alpha_store); | ||
350 | |||
351 | static struct attribute *overlay_sysfs_attrs[] = { | ||
352 | &overlay_attr_name.attr, | ||
353 | &overlay_attr_manager.attr, | ||
354 | &overlay_attr_input_size.attr, | ||
355 | &overlay_attr_screen_width.attr, | ||
356 | &overlay_attr_position.attr, | ||
357 | &overlay_attr_output_size.attr, | ||
358 | &overlay_attr_enabled.attr, | ||
359 | &overlay_attr_global_alpha.attr, | ||
360 | &overlay_attr_pre_mult_alpha.attr, | ||
361 | NULL | ||
362 | }; | ||
363 | |||
364 | static ssize_t overlay_attr_show(struct kobject *kobj, struct attribute *attr, | ||
365 | char *buf) | ||
366 | { | ||
367 | struct omap_overlay *overlay; | ||
368 | struct overlay_attribute *overlay_attr; | ||
369 | |||
370 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
371 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
372 | |||
373 | if (!overlay_attr->show) | ||
374 | return -ENOENT; | ||
375 | |||
376 | return overlay_attr->show(overlay, buf); | ||
377 | } | ||
378 | |||
379 | static ssize_t overlay_attr_store(struct kobject *kobj, struct attribute *attr, | ||
380 | const char *buf, size_t size) | ||
381 | { | ||
382 | struct omap_overlay *overlay; | ||
383 | struct overlay_attribute *overlay_attr; | ||
384 | |||
385 | overlay = container_of(kobj, struct omap_overlay, kobj); | ||
386 | overlay_attr = container_of(attr, struct overlay_attribute, attr); | ||
387 | |||
388 | if (!overlay_attr->store) | ||
389 | return -ENOENT; | ||
390 | |||
391 | return overlay_attr->store(overlay, buf, size); | ||
392 | } | ||
393 | |||
394 | static const struct sysfs_ops overlay_sysfs_ops = { | ||
395 | .show = overlay_attr_show, | ||
396 | .store = overlay_attr_store, | ||
397 | }; | ||
398 | |||
399 | static struct kobj_type overlay_ktype = { | ||
400 | .sysfs_ops = &overlay_sysfs_ops, | ||
401 | .default_attrs = overlay_sysfs_attrs, | ||
402 | }; | ||
403 | |||
404 | /* Check if overlay parameters are compatible with display */ | ||
405 | int dss_check_overlay(struct omap_overlay *ovl, struct omap_dss_device *dssdev) | ||
406 | { | ||
407 | struct omap_overlay_info *info; | ||
158 | u16 outw, outh; | 408 | u16 outw, outh; |
159 | u16 dw, dh; | 409 | u16 dw, dh; |
160 | 410 | ||
161 | dw = mgr_timings->x_res; | 411 | if (!dssdev) |
162 | dh = mgr_timings->y_res; | 412 | return 0; |
413 | |||
414 | if (!ovl->info.enabled) | ||
415 | return 0; | ||
416 | |||
417 | info = &ovl->info; | ||
418 | |||
419 | if (info->paddr == 0) { | ||
420 | DSSDBG("check_overlay failed: paddr 0\n"); | ||
421 | return -EINVAL; | ||
422 | } | ||
423 | |||
424 | dssdev->driver->get_resolution(dssdev, &dw, &dh); | ||
425 | |||
426 | DSSDBG("check_overlay %d: (%d,%d %dx%d -> %dx%d) disp (%dx%d)\n", | ||
427 | ovl->id, | ||
428 | info->pos_x, info->pos_y, | ||
429 | info->width, info->height, | ||
430 | info->out_width, info->out_height, | ||
431 | dw, dh); | ||
163 | 432 | ||
164 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { | 433 | if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0) { |
165 | outw = info->width; | 434 | outw = info->width; |
@@ -177,31 +446,319 @@ int dss_ovl_check(struct omap_overlay *ovl, struct omap_overlay_info *info, | |||
177 | } | 446 | } |
178 | 447 | ||
179 | if (dw < info->pos_x + outw) { | 448 | if (dw < info->pos_x + outw) { |
180 | DSSERR("overlay %d horizontally not inside the display area " | 449 | DSSDBG("check_overlay failed 1: %d < %d + %d\n", |
181 | "(%d + %d >= %d)\n", | 450 | dw, info->pos_x, outw); |
182 | ovl->id, info->pos_x, outw, dw); | ||
183 | return -EINVAL; | 451 | return -EINVAL; |
184 | } | 452 | } |
185 | 453 | ||
186 | if (dh < info->pos_y + outh) { | 454 | if (dh < info->pos_y + outh) { |
187 | DSSERR("overlay %d vertically not inside the display area " | 455 | DSSDBG("check_overlay failed 2: %d < %d + %d\n", |
188 | "(%d + %d >= %d)\n", | 456 | dh, info->pos_y, outh); |
189 | ovl->id, info->pos_y, outh, dh); | 457 | return -EINVAL; |
458 | } | ||
459 | |||
460 | if ((ovl->supported_modes & info->color_mode) == 0) { | ||
461 | DSSERR("overlay doesn't support mode %d\n", info->color_mode); | ||
190 | return -EINVAL; | 462 | return -EINVAL; |
191 | } | 463 | } |
192 | 464 | ||
193 | return 0; | 465 | return 0; |
194 | } | 466 | } |
195 | 467 | ||
196 | /* | 468 | static int dss_ovl_set_overlay_info(struct omap_overlay *ovl, |
197 | * Checks if replication logic should be used. Only use when overlay is in | 469 | struct omap_overlay_info *info) |
198 | * RGB12U or RGB16 mode, and video port width interface is 18bpp or 24bpp | ||
199 | */ | ||
200 | bool dss_ovl_use_replication(struct dss_lcd_mgr_config config, | ||
201 | enum omap_color_mode mode) | ||
202 | { | 470 | { |
203 | if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16) | 471 | int r; |
204 | return false; | 472 | struct omap_overlay_info old_info; |
205 | 473 | ||
206 | return config.video_port_width > 16; | 474 | old_info = ovl->info; |
475 | ovl->info = *info; | ||
476 | |||
477 | if (ovl->manager) { | ||
478 | r = dss_check_overlay(ovl, ovl->manager->device); | ||
479 | if (r) { | ||
480 | ovl->info = old_info; | ||
481 | return r; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | ovl->info_dirty = true; | ||
486 | |||
487 | return 0; | ||
207 | } | 488 | } |
489 | |||
490 | static void dss_ovl_get_overlay_info(struct omap_overlay *ovl, | ||
491 | struct omap_overlay_info *info) | ||
492 | { | ||
493 | *info = ovl->info; | ||
494 | } | ||
495 | |||
496 | static int dss_ovl_wait_for_go(struct omap_overlay *ovl) | ||
497 | { | ||
498 | return dss_mgr_wait_for_go_ovl(ovl); | ||
499 | } | ||
500 | |||
501 | static int omap_dss_set_manager(struct omap_overlay *ovl, | ||
502 | struct omap_overlay_manager *mgr) | ||
503 | { | ||
504 | if (!mgr) | ||
505 | return -EINVAL; | ||
506 | |||
507 | if (ovl->manager) { | ||
508 | DSSERR("overlay '%s' already has a manager '%s'\n", | ||
509 | ovl->name, ovl->manager->name); | ||
510 | return -EINVAL; | ||
511 | } | ||
512 | |||
513 | if (ovl->info.enabled) { | ||
514 | DSSERR("overlay has to be disabled to change the manager\n"); | ||
515 | return -EINVAL; | ||
516 | } | ||
517 | |||
518 | ovl->manager = mgr; | ||
519 | |||
520 | /* XXX: When there is an overlay on a DSI manual update display, and | ||
521 | * the overlay is first disabled, then moved to tv, and enabled, we | ||
522 | * seem to get SYNC_LOST_DIGIT error. | ||
523 | * | ||
524 | * Waiting doesn't seem to help, but updating the manual update display | ||
525 | * after disabling the overlay seems to fix this. This hints that the | ||
526 | * overlay is perhaps somehow tied to the LCD output until the output | ||
527 | * is updated. | ||
528 | * | ||
529 | * Userspace workaround for this is to update the LCD after disabling | ||
530 | * the overlay, but before moving the overlay to TV. | ||
531 | */ | ||
532 | dispc_set_channel_out(ovl->id, mgr->id); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int omap_dss_unset_manager(struct omap_overlay *ovl) | ||
538 | { | ||
539 | int r; | ||
540 | |||
541 | if (!ovl->manager) { | ||
542 | DSSERR("failed to detach overlay: manager not set\n"); | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | |||
546 | if (ovl->info.enabled) { | ||
547 | DSSERR("overlay has to be disabled to unset the manager\n"); | ||
548 | return -EINVAL; | ||
549 | } | ||
550 | |||
551 | r = ovl->wait_for_go(ovl); | ||
552 | if (r) | ||
553 | return r; | ||
554 | |||
555 | ovl->manager = NULL; | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | int omap_dss_get_num_overlays(void) | ||
561 | { | ||
562 | return num_overlays; | ||
563 | } | ||
564 | EXPORT_SYMBOL(omap_dss_get_num_overlays); | ||
565 | |||
566 | struct omap_overlay *omap_dss_get_overlay(int num) | ||
567 | { | ||
568 | int i = 0; | ||
569 | struct omap_overlay *ovl; | ||
570 | |||
571 | list_for_each_entry(ovl, &overlay_list, list) { | ||
572 | if (i++ == num) | ||
573 | return ovl; | ||
574 | } | ||
575 | |||
576 | return NULL; | ||
577 | } | ||
578 | EXPORT_SYMBOL(omap_dss_get_overlay); | ||
579 | |||
580 | static void omap_dss_add_overlay(struct omap_overlay *overlay) | ||
581 | { | ||
582 | ++num_overlays; | ||
583 | list_add_tail(&overlay->list, &overlay_list); | ||
584 | } | ||
585 | |||
586 | static struct omap_overlay *dispc_overlays[MAX_DSS_OVERLAYS]; | ||
587 | |||
588 | void dss_overlay_setup_dispc_manager(struct omap_overlay_manager *mgr) | ||
589 | { | ||
590 | mgr->num_overlays = dss_feat_get_num_ovls(); | ||
591 | mgr->overlays = dispc_overlays; | ||
592 | } | ||
593 | |||
594 | #ifdef L4_EXAMPLE | ||
595 | static struct omap_overlay *l4_overlays[1]; | ||
596 | void dss_overlay_setup_l4_manager(struct omap_overlay_manager *mgr) | ||
597 | { | ||
598 | mgr->num_overlays = 1; | ||
599 | mgr->overlays = l4_overlays; | ||
600 | } | ||
601 | #endif | ||
602 | |||
603 | void dss_init_overlays(struct platform_device *pdev) | ||
604 | { | ||
605 | int i, r; | ||
606 | |||
607 | INIT_LIST_HEAD(&overlay_list); | ||
608 | |||
609 | num_overlays = 0; | ||
610 | |||
611 | for (i = 0; i < dss_feat_get_num_ovls(); ++i) { | ||
612 | struct omap_overlay *ovl; | ||
613 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | ||
614 | |||
615 | BUG_ON(ovl == NULL); | ||
616 | |||
617 | switch (i) { | ||
618 | case 0: | ||
619 | ovl->name = "gfx"; | ||
620 | ovl->id = OMAP_DSS_GFX; | ||
621 | ovl->caps = OMAP_DSS_OVL_CAP_DISPC; | ||
622 | ovl->info.global_alpha = 255; | ||
623 | break; | ||
624 | case 1: | ||
625 | ovl->name = "vid1"; | ||
626 | ovl->id = OMAP_DSS_VIDEO1; | ||
627 | ovl->caps = OMAP_DSS_OVL_CAP_SCALE | | ||
628 | OMAP_DSS_OVL_CAP_DISPC; | ||
629 | ovl->info.global_alpha = 255; | ||
630 | break; | ||
631 | case 2: | ||
632 | ovl->name = "vid2"; | ||
633 | ovl->id = OMAP_DSS_VIDEO2; | ||
634 | ovl->caps = OMAP_DSS_OVL_CAP_SCALE | | ||
635 | OMAP_DSS_OVL_CAP_DISPC; | ||
636 | ovl->info.global_alpha = 255; | ||
637 | break; | ||
638 | } | ||
639 | |||
640 | ovl->set_manager = &omap_dss_set_manager; | ||
641 | ovl->unset_manager = &omap_dss_unset_manager; | ||
642 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | ||
643 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | ||
644 | ovl->wait_for_go = &dss_ovl_wait_for_go; | ||
645 | |||
646 | ovl->supported_modes = | ||
647 | dss_feat_get_supported_color_modes(ovl->id); | ||
648 | |||
649 | omap_dss_add_overlay(ovl); | ||
650 | |||
651 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | ||
652 | &pdev->dev.kobj, "overlay%d", i); | ||
653 | |||
654 | if (r) { | ||
655 | DSSERR("failed to create sysfs file\n"); | ||
656 | continue; | ||
657 | } | ||
658 | |||
659 | dispc_overlays[i] = ovl; | ||
660 | } | ||
661 | |||
662 | #ifdef L4_EXAMPLE | ||
663 | { | ||
664 | struct omap_overlay *ovl; | ||
665 | ovl = kzalloc(sizeof(*ovl), GFP_KERNEL); | ||
666 | |||
667 | BUG_ON(ovl == NULL); | ||
668 | |||
669 | ovl->name = "l4"; | ||
670 | ovl->supported_modes = OMAP_DSS_COLOR_RGB24U; | ||
671 | |||
672 | ovl->set_manager = &omap_dss_set_manager; | ||
673 | ovl->unset_manager = &omap_dss_unset_manager; | ||
674 | ovl->set_overlay_info = &dss_ovl_set_overlay_info; | ||
675 | ovl->get_overlay_info = &dss_ovl_get_overlay_info; | ||
676 | |||
677 | omap_dss_add_overlay(ovl); | ||
678 | |||
679 | r = kobject_init_and_add(&ovl->kobj, &overlay_ktype, | ||
680 | &pdev->dev.kobj, "overlayl4"); | ||
681 | |||
682 | if (r) | ||
683 | DSSERR("failed to create sysfs file\n"); | ||
684 | |||
685 | l4_overlays[0] = ovl; | ||
686 | } | ||
687 | #endif | ||
688 | } | ||
689 | |||
690 | /* connect overlays to the new device, if not already connected. if force | ||
691 | * selected, connect always. */ | ||
692 | void dss_recheck_connections(struct omap_dss_device *dssdev, bool force) | ||
693 | { | ||
694 | int i; | ||
695 | struct omap_overlay_manager *lcd_mgr; | ||
696 | struct omap_overlay_manager *tv_mgr; | ||
697 | struct omap_overlay_manager *lcd2_mgr = NULL; | ||
698 | struct omap_overlay_manager *mgr = NULL; | ||
699 | |||
700 | lcd_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD); | ||
701 | tv_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_TV); | ||
702 | if (dss_has_feature(FEAT_MGR_LCD2)) | ||
703 | lcd2_mgr = omap_dss_get_overlay_manager(OMAP_DSS_OVL_MGR_LCD2); | ||
704 | |||
705 | if (dssdev->channel == OMAP_DSS_CHANNEL_LCD2) { | ||
706 | if (!lcd2_mgr->device || force) { | ||
707 | if (lcd2_mgr->device) | ||
708 | lcd2_mgr->unset_device(lcd2_mgr); | ||
709 | lcd2_mgr->set_device(lcd2_mgr, dssdev); | ||
710 | mgr = lcd2_mgr; | ||
711 | } | ||
712 | } else if (dssdev->type != OMAP_DISPLAY_TYPE_VENC | ||
713 | && dssdev->type != OMAP_DISPLAY_TYPE_HDMI) { | ||
714 | if (!lcd_mgr->device || force) { | ||
715 | if (lcd_mgr->device) | ||
716 | lcd_mgr->unset_device(lcd_mgr); | ||
717 | lcd_mgr->set_device(lcd_mgr, dssdev); | ||
718 | mgr = lcd_mgr; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | if (dssdev->type == OMAP_DISPLAY_TYPE_VENC | ||
723 | || dssdev->type == OMAP_DISPLAY_TYPE_HDMI) { | ||
724 | if (!tv_mgr->device || force) { | ||
725 | if (tv_mgr->device) | ||
726 | tv_mgr->unset_device(tv_mgr); | ||
727 | tv_mgr->set_device(tv_mgr, dssdev); | ||
728 | mgr = tv_mgr; | ||
729 | } | ||
730 | } | ||
731 | |||
732 | if (mgr) { | ||
733 | dispc_runtime_get(); | ||
734 | |||
735 | for (i = 0; i < dss_feat_get_num_ovls(); i++) { | ||
736 | struct omap_overlay *ovl; | ||
737 | ovl = omap_dss_get_overlay(i); | ||
738 | if (!ovl->manager || force) { | ||
739 | if (ovl->manager) | ||
740 | omap_dss_unset_manager(ovl); | ||
741 | omap_dss_set_manager(ovl, mgr); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | dispc_runtime_put(); | ||
746 | } | ||
747 | } | ||
748 | |||
749 | void dss_uninit_overlays(struct platform_device *pdev) | ||
750 | { | ||
751 | struct omap_overlay *ovl; | ||
752 | |||
753 | while (!list_empty(&overlay_list)) { | ||
754 | ovl = list_first_entry(&overlay_list, | ||
755 | struct omap_overlay, list); | ||
756 | list_del(&ovl->list); | ||
757 | kobject_del(&ovl->kobj); | ||
758 | kobject_put(&ovl->kobj); | ||
759 | kfree(ovl); | ||
760 | } | ||
761 | |||
762 | num_overlays = 0; | ||
763 | } | ||
764 | |||
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c index e903dd3f54d..39f4c597026 100644 --- a/drivers/video/omap2/dss/rfbi.c +++ b/drivers/video/omap2/dss/rfbi.c | |||
@@ -24,7 +24,6 @@ | |||
24 | 24 | ||
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/dma-mapping.h> | 26 | #include <linux/dma-mapping.h> |
27 | #include <linux/export.h> | ||
28 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
29 | #include <linux/clk.h> | 28 | #include <linux/clk.h> |
30 | #include <linux/io.h> | 29 | #include <linux/io.h> |
@@ -111,13 +110,6 @@ static struct { | |||
111 | struct omap_dss_device *dssdev[2]; | 110 | struct omap_dss_device *dssdev[2]; |
112 | 111 | ||
113 | struct semaphore bus_lock; | 112 | struct semaphore bus_lock; |
114 | |||
115 | struct omap_video_timings timings; | ||
116 | int pixel_size; | ||
117 | int data_lines; | ||
118 | struct rfbi_timings intf_timings; | ||
119 | |||
120 | struct omap_dss_output output; | ||
121 | } rfbi; | 113 | } rfbi; |
122 | 114 | ||
123 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) | 115 | static inline void rfbi_write_reg(const struct rfbi_reg idx, u32 val) |
@@ -147,8 +139,8 @@ static void rfbi_runtime_put(void) | |||
147 | 139 | ||
148 | DSSDBG("rfbi_runtime_put\n"); | 140 | DSSDBG("rfbi_runtime_put\n"); |
149 | 141 | ||
150 | r = pm_runtime_put_sync(&rfbi.pdev->dev); | 142 | r = pm_runtime_put(&rfbi.pdev->dev); |
151 | WARN_ON(r < 0 && r != -ENOSYS); | 143 | WARN_ON(r < 0); |
152 | } | 144 | } |
153 | 145 | ||
154 | void rfbi_bus_lock(void) | 146 | void rfbi_bus_lock(void) |
@@ -307,25 +299,19 @@ void omap_rfbi_write_pixels(const void __iomem *buf, int scr_width, | |||
307 | } | 299 | } |
308 | EXPORT_SYMBOL(omap_rfbi_write_pixels); | 300 | EXPORT_SYMBOL(omap_rfbi_write_pixels); |
309 | 301 | ||
310 | static int rfbi_transfer_area(struct omap_dss_device *dssdev, | 302 | static void rfbi_transfer_area(struct omap_dss_device *dssdev, u16 width, |
311 | void (*callback)(void *data), void *data) | 303 | u16 height, void (*callback)(void *data), void *data) |
312 | { | 304 | { |
313 | u32 l; | 305 | u32 l; |
314 | int r; | ||
315 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
316 | u16 width = rfbi.timings.x_res; | ||
317 | u16 height = rfbi.timings.y_res; | ||
318 | 306 | ||
319 | /*BUG_ON(callback == 0);*/ | 307 | /*BUG_ON(callback == 0);*/ |
320 | BUG_ON(rfbi.framedone_callback != NULL); | 308 | BUG_ON(rfbi.framedone_callback != NULL); |
321 | 309 | ||
322 | DSSDBG("rfbi_transfer_area %dx%d\n", width, height); | 310 | DSSDBG("rfbi_transfer_area %dx%d\n", width, height); |
323 | 311 | ||
324 | dss_mgr_set_timings(mgr, &rfbi.timings); | 312 | dispc_set_lcd_size(dssdev->manager->id, width, height); |
325 | 313 | ||
326 | r = dss_mgr_enable(mgr); | 314 | dispc_enable_channel(dssdev->manager->id, true); |
327 | if (r) | ||
328 | return r; | ||
329 | 315 | ||
330 | rfbi.framedone_callback = callback; | 316 | rfbi.framedone_callback = callback; |
331 | rfbi.framedone_callback_data = data; | 317 | rfbi.framedone_callback_data = data; |
@@ -338,11 +324,9 @@ static int rfbi_transfer_area(struct omap_dss_device *dssdev, | |||
338 | l = FLD_MOD(l, 1, 4, 4); /* ITE */ | 324 | l = FLD_MOD(l, 1, 4, 4); /* ITE */ |
339 | 325 | ||
340 | rfbi_write_reg(RFBI_CONTROL, l); | 326 | rfbi_write_reg(RFBI_CONTROL, l); |
341 | |||
342 | return 0; | ||
343 | } | 327 | } |
344 | 328 | ||
345 | static void framedone_callback(void *data) | 329 | static void framedone_callback(void *data, u32 mask) |
346 | { | 330 | { |
347 | void (*callback)(void *data); | 331 | void (*callback)(void *data); |
348 | 332 | ||
@@ -770,47 +754,69 @@ static int rfbi_configure(int rfbi_module, int bpp, int lines) | |||
770 | return 0; | 754 | return 0; |
771 | } | 755 | } |
772 | 756 | ||
773 | int omap_rfbi_configure(struct omap_dss_device *dssdev) | 757 | int omap_rfbi_configure(struct omap_dss_device *dssdev, int pixel_size, |
758 | int data_lines) | ||
774 | { | 759 | { |
775 | return rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, | 760 | return rfbi_configure(dssdev->phy.rfbi.channel, pixel_size, data_lines); |
776 | rfbi.data_lines); | ||
777 | } | 761 | } |
778 | EXPORT_SYMBOL(omap_rfbi_configure); | 762 | EXPORT_SYMBOL(omap_rfbi_configure); |
779 | 763 | ||
780 | int omap_rfbi_update(struct omap_dss_device *dssdev, void (*callback)(void *), | 764 | int omap_rfbi_prepare_update(struct omap_dss_device *dssdev, |
781 | void *data) | 765 | u16 *x, u16 *y, u16 *w, u16 *h) |
782 | { | 766 | { |
783 | return rfbi_transfer_area(dssdev, callback, data); | 767 | u16 dw, dh; |
784 | } | ||
785 | EXPORT_SYMBOL(omap_rfbi_update); | ||
786 | 768 | ||
787 | void omapdss_rfbi_set_size(struct omap_dss_device *dssdev, u16 w, u16 h) | 769 | dssdev->driver->get_resolution(dssdev, &dw, &dh); |
788 | { | ||
789 | rfbi.timings.x_res = w; | ||
790 | rfbi.timings.y_res = h; | ||
791 | } | ||
792 | EXPORT_SYMBOL(omapdss_rfbi_set_size); | ||
793 | 770 | ||
794 | void omapdss_rfbi_set_pixel_size(struct omap_dss_device *dssdev, int pixel_size) | 771 | if (*x > dw || *y > dh) |
795 | { | 772 | return -EINVAL; |
796 | rfbi.pixel_size = pixel_size; | ||
797 | } | ||
798 | EXPORT_SYMBOL(omapdss_rfbi_set_pixel_size); | ||
799 | 773 | ||
800 | void omapdss_rfbi_set_data_lines(struct omap_dss_device *dssdev, int data_lines) | 774 | if (*x + *w > dw) |
801 | { | 775 | return -EINVAL; |
802 | rfbi.data_lines = data_lines; | 776 | |
777 | if (*y + *h > dh) | ||
778 | return -EINVAL; | ||
779 | |||
780 | if (*w == 1) | ||
781 | return -EINVAL; | ||
782 | |||
783 | if (*w == 0 || *h == 0) | ||
784 | return -EINVAL; | ||
785 | |||
786 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { | ||
787 | dss_setup_partial_planes(dssdev, x, y, w, h, true); | ||
788 | dispc_set_lcd_size(dssdev->manager->id, *w, *h); | ||
789 | } | ||
790 | |||
791 | return 0; | ||
803 | } | 792 | } |
804 | EXPORT_SYMBOL(omapdss_rfbi_set_data_lines); | 793 | EXPORT_SYMBOL(omap_rfbi_prepare_update); |
805 | 794 | ||
806 | void omapdss_rfbi_set_interface_timings(struct omap_dss_device *dssdev, | 795 | int omap_rfbi_update(struct omap_dss_device *dssdev, |
807 | struct rfbi_timings *timings) | 796 | u16 x, u16 y, u16 w, u16 h, |
797 | void (*callback)(void *), void *data) | ||
808 | { | 798 | { |
809 | rfbi.intf_timings = *timings; | 799 | if (dssdev->manager->caps & OMAP_DSS_OVL_MGR_CAP_DISPC) { |
800 | rfbi_transfer_area(dssdev, w, h, callback, data); | ||
801 | } else { | ||
802 | struct omap_overlay *ovl; | ||
803 | void __iomem *addr; | ||
804 | int scr_width; | ||
805 | |||
806 | ovl = dssdev->manager->overlays[0]; | ||
807 | scr_width = ovl->info.screen_width; | ||
808 | addr = ovl->info.vaddr; | ||
809 | |||
810 | omap_rfbi_write_pixels(addr, scr_width, x, y, w, h); | ||
811 | |||
812 | callback(data); | ||
813 | } | ||
814 | |||
815 | return 0; | ||
810 | } | 816 | } |
811 | EXPORT_SYMBOL(omapdss_rfbi_set_interface_timings); | 817 | EXPORT_SYMBOL(omap_rfbi_update); |
812 | 818 | ||
813 | static void rfbi_dump_regs(struct seq_file *s) | 819 | void rfbi_dump_regs(struct seq_file *s) |
814 | { | 820 | { |
815 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) | 821 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, rfbi_read_reg(r)) |
816 | 822 | ||
@@ -850,54 +856,10 @@ static void rfbi_dump_regs(struct seq_file *s) | |||
850 | #undef DUMPREG | 856 | #undef DUMPREG |
851 | } | 857 | } |
852 | 858 | ||
853 | static void rfbi_config_lcd_manager(struct omap_dss_device *dssdev) | ||
854 | { | ||
855 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
856 | struct dss_lcd_mgr_config mgr_config; | ||
857 | |||
858 | mgr_config.io_pad_mode = DSS_IO_PAD_MODE_RFBI; | ||
859 | |||
860 | mgr_config.stallmode = true; | ||
861 | /* Do we need fifohandcheck for RFBI? */ | ||
862 | mgr_config.fifohandcheck = false; | ||
863 | |||
864 | mgr_config.video_port_width = rfbi.pixel_size; | ||
865 | mgr_config.lcden_sig_polarity = 0; | ||
866 | |||
867 | dss_mgr_set_lcd_config(mgr, &mgr_config); | ||
868 | |||
869 | /* | ||
870 | * Set rfbi.timings with default values, the x_res and y_res fields | ||
871 | * are expected to be already configured by the panel driver via | ||
872 | * omapdss_rfbi_set_size() | ||
873 | */ | ||
874 | rfbi.timings.hsw = 1; | ||
875 | rfbi.timings.hfp = 1; | ||
876 | rfbi.timings.hbp = 1; | ||
877 | rfbi.timings.vsw = 1; | ||
878 | rfbi.timings.vfp = 0; | ||
879 | rfbi.timings.vbp = 0; | ||
880 | |||
881 | rfbi.timings.interlace = false; | ||
882 | rfbi.timings.hsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
883 | rfbi.timings.vsync_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
884 | rfbi.timings.data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | ||
885 | rfbi.timings.de_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
886 | rfbi.timings.sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
887 | |||
888 | dss_mgr_set_timings(mgr, &rfbi.timings); | ||
889 | } | ||
890 | |||
891 | int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | 859 | int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) |
892 | { | 860 | { |
893 | struct omap_dss_output *out = dssdev->output; | ||
894 | int r; | 861 | int r; |
895 | 862 | ||
896 | if (out == NULL || out->manager == NULL) { | ||
897 | DSSERR("failed to enable display: no output/manager\n"); | ||
898 | return -ENODEV; | ||
899 | } | ||
900 | |||
901 | r = rfbi_runtime_get(); | 863 | r = rfbi_runtime_get(); |
902 | if (r) | 864 | if (r) |
903 | return r; | 865 | return r; |
@@ -908,19 +870,28 @@ int omapdss_rfbi_display_enable(struct omap_dss_device *dssdev) | |||
908 | goto err0; | 870 | goto err0; |
909 | } | 871 | } |
910 | 872 | ||
911 | r = dss_mgr_register_framedone_handler(out->manager, | 873 | r = omap_dispc_register_isr(framedone_callback, NULL, |
912 | framedone_callback, NULL); | 874 | DISPC_IRQ_FRAMEDONE); |
913 | if (r) { | 875 | if (r) { |
914 | DSSERR("can't get FRAMEDONE irq\n"); | 876 | DSSERR("can't get FRAMEDONE irq\n"); |
915 | goto err1; | 877 | goto err1; |
916 | } | 878 | } |
917 | 879 | ||
918 | rfbi_config_lcd_manager(dssdev); | 880 | dispc_set_lcd_display_type(dssdev->manager->id, |
881 | OMAP_DSS_LCD_DISPLAY_TFT); | ||
882 | |||
883 | dispc_set_parallel_interface_mode(dssdev->manager->id, | ||
884 | OMAP_DSS_PARALLELMODE_RFBI); | ||
919 | 885 | ||
920 | rfbi_configure(dssdev->phy.rfbi.channel, rfbi.pixel_size, | 886 | dispc_set_tft_data_lines(dssdev->manager->id, dssdev->ctrl.pixel_size); |
921 | rfbi.data_lines); | 887 | |
888 | rfbi_configure(dssdev->phy.rfbi.channel, | ||
889 | dssdev->ctrl.pixel_size, | ||
890 | dssdev->phy.rfbi.data_lines); | ||
891 | |||
892 | rfbi_set_timings(dssdev->phy.rfbi.channel, | ||
893 | &dssdev->ctrl.rfbi_timings); | ||
922 | 894 | ||
923 | rfbi_set_timings(dssdev->phy.rfbi.channel, &rfbi.intf_timings); | ||
924 | 895 | ||
925 | return 0; | 896 | return 0; |
926 | err1: | 897 | err1: |
@@ -933,111 +904,23 @@ EXPORT_SYMBOL(omapdss_rfbi_display_enable); | |||
933 | 904 | ||
934 | void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) | 905 | void omapdss_rfbi_display_disable(struct omap_dss_device *dssdev) |
935 | { | 906 | { |
936 | struct omap_dss_output *out = dssdev->output; | 907 | omap_dispc_unregister_isr(framedone_callback, NULL, |
937 | 908 | DISPC_IRQ_FRAMEDONE); | |
938 | dss_mgr_unregister_framedone_handler(out->manager, | ||
939 | framedone_callback, NULL); | ||
940 | omap_dss_stop_device(dssdev); | 909 | omap_dss_stop_device(dssdev); |
941 | 910 | ||
942 | rfbi_runtime_put(); | 911 | rfbi_runtime_put(); |
943 | } | 912 | } |
944 | EXPORT_SYMBOL(omapdss_rfbi_display_disable); | 913 | EXPORT_SYMBOL(omapdss_rfbi_display_disable); |
945 | 914 | ||
946 | static int __init rfbi_init_display(struct omap_dss_device *dssdev) | 915 | int rfbi_init_display(struct omap_dss_device *dssdev) |
947 | { | 916 | { |
948 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; | 917 | rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev; |
918 | dssdev->caps = OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE; | ||
949 | return 0; | 919 | return 0; |
950 | } | 920 | } |
951 | 921 | ||
952 | static struct omap_dss_device * __init rfbi_find_dssdev(struct platform_device *pdev) | ||
953 | { | ||
954 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
955 | const char *def_disp_name = omapdss_get_default_display_name(); | ||
956 | struct omap_dss_device *def_dssdev; | ||
957 | int i; | ||
958 | |||
959 | def_dssdev = NULL; | ||
960 | |||
961 | for (i = 0; i < pdata->num_devices; ++i) { | ||
962 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
963 | |||
964 | if (dssdev->type != OMAP_DISPLAY_TYPE_DBI) | ||
965 | continue; | ||
966 | |||
967 | if (def_dssdev == NULL) | ||
968 | def_dssdev = dssdev; | ||
969 | |||
970 | if (def_disp_name != NULL && | ||
971 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
972 | def_dssdev = dssdev; | ||
973 | break; | ||
974 | } | ||
975 | } | ||
976 | |||
977 | return def_dssdev; | ||
978 | } | ||
979 | |||
980 | static void __init rfbi_probe_pdata(struct platform_device *rfbidev) | ||
981 | { | ||
982 | struct omap_dss_device *plat_dssdev; | ||
983 | struct omap_dss_device *dssdev; | ||
984 | int r; | ||
985 | |||
986 | plat_dssdev = rfbi_find_dssdev(rfbidev); | ||
987 | |||
988 | if (!plat_dssdev) | ||
989 | return; | ||
990 | |||
991 | dssdev = dss_alloc_and_init_device(&rfbidev->dev); | ||
992 | if (!dssdev) | ||
993 | return; | ||
994 | |||
995 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
996 | |||
997 | r = rfbi_init_display(dssdev); | ||
998 | if (r) { | ||
999 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
1000 | dss_put_device(dssdev); | ||
1001 | return; | ||
1002 | } | ||
1003 | |||
1004 | r = omapdss_output_set_device(&rfbi.output, dssdev); | ||
1005 | if (r) { | ||
1006 | DSSERR("failed to connect output to new device: %s\n", | ||
1007 | dssdev->name); | ||
1008 | dss_put_device(dssdev); | ||
1009 | return; | ||
1010 | } | ||
1011 | |||
1012 | r = dss_add_device(dssdev); | ||
1013 | if (r) { | ||
1014 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
1015 | omapdss_output_unset_device(&rfbi.output); | ||
1016 | dss_put_device(dssdev); | ||
1017 | return; | ||
1018 | } | ||
1019 | } | ||
1020 | |||
1021 | static void __init rfbi_init_output(struct platform_device *pdev) | ||
1022 | { | ||
1023 | struct omap_dss_output *out = &rfbi.output; | ||
1024 | |||
1025 | out->pdev = pdev; | ||
1026 | out->id = OMAP_DSS_OUTPUT_DBI; | ||
1027 | out->type = OMAP_DISPLAY_TYPE_DBI; | ||
1028 | |||
1029 | dss_register_output(out); | ||
1030 | } | ||
1031 | |||
1032 | static void __exit rfbi_uninit_output(struct platform_device *pdev) | ||
1033 | { | ||
1034 | struct omap_dss_output *out = &rfbi.output; | ||
1035 | |||
1036 | dss_unregister_output(out); | ||
1037 | } | ||
1038 | |||
1039 | /* RFBI HW IP initialisation */ | 922 | /* RFBI HW IP initialisation */ |
1040 | static int __init omap_rfbihw_probe(struct platform_device *pdev) | 923 | static int omap_rfbihw_probe(struct platform_device *pdev) |
1041 | { | 924 | { |
1042 | u32 rev; | 925 | u32 rev; |
1043 | struct resource *rfbi_mem; | 926 | struct resource *rfbi_mem; |
@@ -1051,67 +934,66 @@ static int __init omap_rfbihw_probe(struct platform_device *pdev) | |||
1051 | rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); | 934 | rfbi_mem = platform_get_resource(rfbi.pdev, IORESOURCE_MEM, 0); |
1052 | if (!rfbi_mem) { | 935 | if (!rfbi_mem) { |
1053 | DSSERR("can't get IORESOURCE_MEM RFBI\n"); | 936 | DSSERR("can't get IORESOURCE_MEM RFBI\n"); |
1054 | return -EINVAL; | 937 | r = -EINVAL; |
938 | goto err_ioremap; | ||
1055 | } | 939 | } |
1056 | 940 | rfbi.base = ioremap(rfbi_mem->start, resource_size(rfbi_mem)); | |
1057 | rfbi.base = devm_ioremap(&pdev->dev, rfbi_mem->start, | ||
1058 | resource_size(rfbi_mem)); | ||
1059 | if (!rfbi.base) { | 941 | if (!rfbi.base) { |
1060 | DSSERR("can't ioremap RFBI\n"); | 942 | DSSERR("can't ioremap RFBI\n"); |
1061 | return -ENOMEM; | 943 | r = -ENOMEM; |
944 | goto err_ioremap; | ||
1062 | } | 945 | } |
1063 | 946 | ||
1064 | clk = clk_get(&pdev->dev, "ick"); | 947 | pm_runtime_enable(&pdev->dev); |
948 | |||
949 | r = rfbi_runtime_get(); | ||
950 | if (r) | ||
951 | goto err_get_rfbi; | ||
952 | |||
953 | msleep(10); | ||
954 | |||
955 | if (cpu_is_omap24xx() || cpu_is_omap34xx() || cpu_is_omap3630()) | ||
956 | clk = dss_get_ick(); | ||
957 | else | ||
958 | clk = clk_get(&pdev->dev, "ick"); | ||
1065 | if (IS_ERR(clk)) { | 959 | if (IS_ERR(clk)) { |
1066 | DSSERR("can't get ick\n"); | 960 | DSSERR("can't get ick\n"); |
1067 | return PTR_ERR(clk); | 961 | r = PTR_ERR(clk); |
962 | goto err_get_ick; | ||
1068 | } | 963 | } |
1069 | 964 | ||
1070 | rfbi.l4_khz = clk_get_rate(clk) / 1000; | 965 | rfbi.l4_khz = clk_get_rate(clk) / 1000; |
1071 | 966 | ||
1072 | clk_put(clk); | 967 | clk_put(clk); |
1073 | 968 | ||
1074 | pm_runtime_enable(&pdev->dev); | ||
1075 | |||
1076 | r = rfbi_runtime_get(); | ||
1077 | if (r) | ||
1078 | goto err_runtime_get; | ||
1079 | |||
1080 | msleep(10); | ||
1081 | |||
1082 | rev = rfbi_read_reg(RFBI_REVISION); | 969 | rev = rfbi_read_reg(RFBI_REVISION); |
1083 | dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", | 970 | dev_dbg(&pdev->dev, "OMAP RFBI rev %d.%d\n", |
1084 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); | 971 | FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0)); |
1085 | 972 | ||
1086 | rfbi_runtime_put(); | 973 | rfbi_runtime_put(); |
1087 | 974 | ||
1088 | dss_debugfs_create_file("rfbi", rfbi_dump_regs); | ||
1089 | |||
1090 | rfbi_init_output(pdev); | ||
1091 | |||
1092 | rfbi_probe_pdata(pdev); | ||
1093 | |||
1094 | return 0; | 975 | return 0; |
1095 | 976 | ||
1096 | err_runtime_get: | 977 | err_get_ick: |
978 | rfbi_runtime_put(); | ||
979 | err_get_rfbi: | ||
1097 | pm_runtime_disable(&pdev->dev); | 980 | pm_runtime_disable(&pdev->dev); |
981 | iounmap(rfbi.base); | ||
982 | err_ioremap: | ||
1098 | return r; | 983 | return r; |
1099 | } | 984 | } |
1100 | 985 | ||
1101 | static int __exit omap_rfbihw_remove(struct platform_device *pdev) | 986 | static int omap_rfbihw_remove(struct platform_device *pdev) |
1102 | { | 987 | { |
1103 | dss_unregister_child_devices(&pdev->dev); | ||
1104 | |||
1105 | rfbi_uninit_output(pdev); | ||
1106 | |||
1107 | pm_runtime_disable(&pdev->dev); | 988 | pm_runtime_disable(&pdev->dev); |
1108 | 989 | iounmap(rfbi.base); | |
1109 | return 0; | 990 | return 0; |
1110 | } | 991 | } |
1111 | 992 | ||
1112 | static int rfbi_runtime_suspend(struct device *dev) | 993 | static int rfbi_runtime_suspend(struct device *dev) |
1113 | { | 994 | { |
1114 | dispc_runtime_put(); | 995 | dispc_runtime_put(); |
996 | dss_runtime_put(); | ||
1115 | 997 | ||
1116 | return 0; | 998 | return 0; |
1117 | } | 999 | } |
@@ -1120,11 +1002,20 @@ static int rfbi_runtime_resume(struct device *dev) | |||
1120 | { | 1002 | { |
1121 | int r; | 1003 | int r; |
1122 | 1004 | ||
1005 | r = dss_runtime_get(); | ||
1006 | if (r < 0) | ||
1007 | goto err_get_dss; | ||
1008 | |||
1123 | r = dispc_runtime_get(); | 1009 | r = dispc_runtime_get(); |
1124 | if (r < 0) | 1010 | if (r < 0) |
1125 | return r; | 1011 | goto err_get_dispc; |
1126 | 1012 | ||
1127 | return 0; | 1013 | return 0; |
1014 | |||
1015 | err_get_dispc: | ||
1016 | dss_runtime_put(); | ||
1017 | err_get_dss: | ||
1018 | return r; | ||
1128 | } | 1019 | } |
1129 | 1020 | ||
1130 | static const struct dev_pm_ops rfbi_pm_ops = { | 1021 | static const struct dev_pm_ops rfbi_pm_ops = { |
@@ -1133,7 +1024,8 @@ static const struct dev_pm_ops rfbi_pm_ops = { | |||
1133 | }; | 1024 | }; |
1134 | 1025 | ||
1135 | static struct platform_driver omap_rfbihw_driver = { | 1026 | static struct platform_driver omap_rfbihw_driver = { |
1136 | .remove = __exit_p(omap_rfbihw_remove), | 1027 | .probe = omap_rfbihw_probe, |
1028 | .remove = omap_rfbihw_remove, | ||
1137 | .driver = { | 1029 | .driver = { |
1138 | .name = "omapdss_rfbi", | 1030 | .name = "omapdss_rfbi", |
1139 | .owner = THIS_MODULE, | 1031 | .owner = THIS_MODULE, |
@@ -1141,12 +1033,12 @@ static struct platform_driver omap_rfbihw_driver = { | |||
1141 | }, | 1033 | }, |
1142 | }; | 1034 | }; |
1143 | 1035 | ||
1144 | int __init rfbi_init_platform_driver(void) | 1036 | int rfbi_init_platform_driver(void) |
1145 | { | 1037 | { |
1146 | return platform_driver_probe(&omap_rfbihw_driver, omap_rfbihw_probe); | 1038 | return platform_driver_register(&omap_rfbihw_driver); |
1147 | } | 1039 | } |
1148 | 1040 | ||
1149 | void __exit rfbi_uninit_platform_driver(void) | 1041 | void rfbi_uninit_platform_driver(void) |
1150 | { | 1042 | { |
1151 | platform_driver_unregister(&omap_rfbihw_driver); | 1043 | return platform_driver_unregister(&omap_rfbihw_driver); |
1152 | } | 1044 | } |
diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index 62b5374ce43..3a688c871a4 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c | |||
@@ -23,9 +23,6 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/regulator/consumer.h> | 25 | #include <linux/regulator/consumer.h> |
26 | #include <linux/export.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/string.h> | ||
29 | 26 | ||
30 | #include <video/omapdss.h> | 27 | #include <video/omapdss.h> |
31 | #include "dss.h" | 28 | #include "dss.h" |
@@ -33,43 +30,31 @@ | |||
33 | static struct { | 30 | static struct { |
34 | bool update_enabled; | 31 | bool update_enabled; |
35 | struct regulator *vdds_sdi_reg; | 32 | struct regulator *vdds_sdi_reg; |
36 | |||
37 | struct dss_lcd_mgr_config mgr_config; | ||
38 | struct omap_video_timings timings; | ||
39 | int datapairs; | ||
40 | |||
41 | struct omap_dss_output output; | ||
42 | } sdi; | 33 | } sdi; |
43 | 34 | ||
44 | static void sdi_config_lcd_manager(struct omap_dss_device *dssdev) | 35 | static void sdi_basic_init(struct omap_dss_device *dssdev) |
45 | { | ||
46 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
47 | 36 | ||
48 | sdi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS; | 37 | { |
49 | 38 | dispc_set_parallel_interface_mode(dssdev->manager->id, | |
50 | sdi.mgr_config.stallmode = false; | 39 | OMAP_DSS_PARALLELMODE_BYPASS); |
51 | sdi.mgr_config.fifohandcheck = false; | ||
52 | 40 | ||
53 | sdi.mgr_config.video_port_width = 24; | 41 | dispc_set_lcd_display_type(dssdev->manager->id, |
54 | sdi.mgr_config.lcden_sig_polarity = 1; | 42 | OMAP_DSS_LCD_DISPLAY_TFT); |
55 | 43 | ||
56 | dss_mgr_set_lcd_config(mgr, &sdi.mgr_config); | 44 | dispc_set_tft_data_lines(dssdev->manager->id, 24); |
45 | dispc_lcd_enable_signal_polarity(1); | ||
57 | } | 46 | } |
58 | 47 | ||
59 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | 48 | int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) |
60 | { | 49 | { |
61 | struct omap_dss_output *out = dssdev->output; | 50 | struct omap_video_timings *t = &dssdev->panel.timings; |
62 | struct omap_video_timings *t = &sdi.timings; | ||
63 | struct dss_clock_info dss_cinfo; | 51 | struct dss_clock_info dss_cinfo; |
64 | struct dispc_clock_info dispc_cinfo; | 52 | struct dispc_clock_info dispc_cinfo; |
53 | u16 lck_div, pck_div; | ||
54 | unsigned long fck; | ||
65 | unsigned long pck; | 55 | unsigned long pck; |
66 | int r; | 56 | int r; |
67 | 57 | ||
68 | if (out == NULL || out->manager == NULL) { | ||
69 | DSSERR("failed to enable display: no output/manager\n"); | ||
70 | return -ENODEV; | ||
71 | } | ||
72 | |||
73 | r = omap_dss_start_device(dssdev); | 58 | r = omap_dss_start_device(dssdev); |
74 | if (r) { | 59 | if (r) { |
75 | DSSERR("failed to start device\n"); | 60 | DSSERR("failed to start device\n"); |
@@ -80,21 +65,32 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
80 | if (r) | 65 | if (r) |
81 | goto err_reg_enable; | 66 | goto err_reg_enable; |
82 | 67 | ||
68 | r = dss_runtime_get(); | ||
69 | if (r) | ||
70 | goto err_get_dss; | ||
71 | |||
83 | r = dispc_runtime_get(); | 72 | r = dispc_runtime_get(); |
84 | if (r) | 73 | if (r) |
85 | goto err_get_dispc; | 74 | goto err_get_dispc; |
86 | 75 | ||
76 | sdi_basic_init(dssdev); | ||
77 | |||
87 | /* 15.5.9.1.2 */ | 78 | /* 15.5.9.1.2 */ |
88 | t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 79 | dssdev->panel.config |= OMAP_DSS_LCD_RF | OMAP_DSS_LCD_ONOFF; |
89 | t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | 80 | |
81 | dispc_set_pol_freq(dssdev->manager->id, dssdev->panel.config, | ||
82 | dssdev->panel.acbi, dssdev->panel.acb); | ||
90 | 83 | ||
91 | r = dss_calc_clock_div(t->pixel_clock * 1000, &dss_cinfo, &dispc_cinfo); | 84 | r = dss_calc_clock_div(1, t->pixel_clock * 1000, |
85 | &dss_cinfo, &dispc_cinfo); | ||
92 | if (r) | 86 | if (r) |
93 | goto err_calc_clock_div; | 87 | goto err_calc_clock_div; |
94 | 88 | ||
95 | sdi.mgr_config.clock_info = dispc_cinfo; | 89 | fck = dss_cinfo.fck; |
90 | lck_div = dispc_cinfo.lck_div; | ||
91 | pck_div = dispc_cinfo.pck_div; | ||
96 | 92 | ||
97 | pck = dss_cinfo.fck / dispc_cinfo.lck_div / dispc_cinfo.pck_div / 1000; | 93 | pck = fck / lck_div / pck_div / 1000; |
98 | 94 | ||
99 | if (pck != t->pixel_clock) { | 95 | if (pck != t->pixel_clock) { |
100 | DSSWARN("Could not find exact pixel clock. Requested %d kHz, " | 96 | DSSWARN("Could not find exact pixel clock. Requested %d kHz, " |
@@ -105,46 +101,34 @@ int omapdss_sdi_display_enable(struct omap_dss_device *dssdev) | |||
105 | } | 101 | } |
106 | 102 | ||
107 | 103 | ||
108 | dss_mgr_set_timings(out->manager, t); | 104 | dispc_set_lcd_timings(dssdev->manager->id, t); |
109 | 105 | ||
110 | r = dss_set_clock_div(&dss_cinfo); | 106 | r = dss_set_clock_div(&dss_cinfo); |
111 | if (r) | 107 | if (r) |
112 | goto err_set_dss_clock_div; | 108 | goto err_set_dss_clock_div; |
113 | 109 | ||
114 | sdi_config_lcd_manager(dssdev); | 110 | r = dispc_set_clock_div(dssdev->manager->id, &dispc_cinfo); |
115 | 111 | if (r) | |
116 | /* | 112 | goto err_set_dispc_clock_div; |
117 | * LCLK and PCLK divisors are located in shadow registers, and we | 113 | |
118 | * normally write them to DISPC registers when enabling the output. | 114 | dss_sdi_init(dssdev->phy.sdi.datapairs); |
119 | * However, SDI uses pck-free as source clock for its PLL, and pck-free | ||
120 | * is affected by the divisors. And as we need the PLL before enabling | ||
121 | * the output, we need to write the divisors early. | ||
122 | * | ||
123 | * It seems just writing to the DISPC register is enough, and we don't | ||
124 | * need to care about the shadow register mechanism for pck-free. The | ||
125 | * exact reason for this is unknown. | ||
126 | */ | ||
127 | dispc_mgr_set_clock_div(out->manager->id, &sdi.mgr_config.clock_info); | ||
128 | |||
129 | dss_sdi_init(sdi.datapairs); | ||
130 | r = dss_sdi_enable(); | 115 | r = dss_sdi_enable(); |
131 | if (r) | 116 | if (r) |
132 | goto err_sdi_enable; | 117 | goto err_sdi_enable; |
133 | mdelay(2); | 118 | mdelay(2); |
134 | 119 | ||
135 | r = dss_mgr_enable(out->manager); | 120 | dssdev->manager->enable(dssdev->manager); |
136 | if (r) | ||
137 | goto err_mgr_enable; | ||
138 | 121 | ||
139 | return 0; | 122 | return 0; |
140 | 123 | ||
141 | err_mgr_enable: | ||
142 | dss_sdi_disable(); | ||
143 | err_sdi_enable: | 124 | err_sdi_enable: |
125 | err_set_dispc_clock_div: | ||
144 | err_set_dss_clock_div: | 126 | err_set_dss_clock_div: |
145 | err_calc_clock_div: | 127 | err_calc_clock_div: |
146 | dispc_runtime_put(); | 128 | dispc_runtime_put(); |
147 | err_get_dispc: | 129 | err_get_dispc: |
130 | dss_runtime_put(); | ||
131 | err_get_dss: | ||
148 | regulator_disable(sdi.vdds_sdi_reg); | 132 | regulator_disable(sdi.vdds_sdi_reg); |
149 | err_reg_enable: | 133 | err_reg_enable: |
150 | omap_dss_stop_device(dssdev); | 134 | omap_dss_stop_device(dssdev); |
@@ -155,13 +139,12 @@ EXPORT_SYMBOL(omapdss_sdi_display_enable); | |||
155 | 139 | ||
156 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | 140 | void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) |
157 | { | 141 | { |
158 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 142 | dssdev->manager->disable(dssdev->manager); |
159 | |||
160 | dss_mgr_disable(mgr); | ||
161 | 143 | ||
162 | dss_sdi_disable(); | 144 | dss_sdi_disable(); |
163 | 145 | ||
164 | dispc_runtime_put(); | 146 | dispc_runtime_put(); |
147 | dss_runtime_put(); | ||
165 | 148 | ||
166 | regulator_disable(sdi.vdds_sdi_reg); | 149 | regulator_disable(sdi.vdds_sdi_reg); |
167 | 150 | ||
@@ -169,20 +152,7 @@ void omapdss_sdi_display_disable(struct omap_dss_device *dssdev) | |||
169 | } | 152 | } |
170 | EXPORT_SYMBOL(omapdss_sdi_display_disable); | 153 | EXPORT_SYMBOL(omapdss_sdi_display_disable); |
171 | 154 | ||
172 | void omapdss_sdi_set_timings(struct omap_dss_device *dssdev, | 155 | int sdi_init_display(struct omap_dss_device *dssdev) |
173 | struct omap_video_timings *timings) | ||
174 | { | ||
175 | sdi.timings = *timings; | ||
176 | } | ||
177 | EXPORT_SYMBOL(omapdss_sdi_set_timings); | ||
178 | |||
179 | void omapdss_sdi_set_datapairs(struct omap_dss_device *dssdev, int datapairs) | ||
180 | { | ||
181 | sdi.datapairs = datapairs; | ||
182 | } | ||
183 | EXPORT_SYMBOL(omapdss_sdi_set_datapairs); | ||
184 | |||
185 | static int __init sdi_init_display(struct omap_dss_device *dssdev) | ||
186 | { | 156 | { |
187 | DSSDBG("SDI init\n"); | 157 | DSSDBG("SDI init\n"); |
188 | 158 | ||
@@ -202,125 +172,11 @@ static int __init sdi_init_display(struct omap_dss_device *dssdev) | |||
202 | return 0; | 172 | return 0; |
203 | } | 173 | } |
204 | 174 | ||
205 | static struct omap_dss_device * __init sdi_find_dssdev(struct platform_device *pdev) | 175 | int sdi_init(void) |
206 | { | ||
207 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
208 | const char *def_disp_name = omapdss_get_default_display_name(); | ||
209 | struct omap_dss_device *def_dssdev; | ||
210 | int i; | ||
211 | |||
212 | def_dssdev = NULL; | ||
213 | |||
214 | for (i = 0; i < pdata->num_devices; ++i) { | ||
215 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
216 | |||
217 | if (dssdev->type != OMAP_DISPLAY_TYPE_SDI) | ||
218 | continue; | ||
219 | |||
220 | if (def_dssdev == NULL) | ||
221 | def_dssdev = dssdev; | ||
222 | |||
223 | if (def_disp_name != NULL && | ||
224 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
225 | def_dssdev = dssdev; | ||
226 | break; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | return def_dssdev; | ||
231 | } | ||
232 | |||
233 | static void __init sdi_probe_pdata(struct platform_device *sdidev) | ||
234 | { | 176 | { |
235 | struct omap_dss_device *plat_dssdev; | ||
236 | struct omap_dss_device *dssdev; | ||
237 | int r; | ||
238 | |||
239 | plat_dssdev = sdi_find_dssdev(sdidev); | ||
240 | |||
241 | if (!plat_dssdev) | ||
242 | return; | ||
243 | |||
244 | dssdev = dss_alloc_and_init_device(&sdidev->dev); | ||
245 | if (!dssdev) | ||
246 | return; | ||
247 | |||
248 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
249 | |||
250 | r = sdi_init_display(dssdev); | ||
251 | if (r) { | ||
252 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
253 | dss_put_device(dssdev); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | r = omapdss_output_set_device(&sdi.output, dssdev); | ||
258 | if (r) { | ||
259 | DSSERR("failed to connect output to new device: %s\n", | ||
260 | dssdev->name); | ||
261 | dss_put_device(dssdev); | ||
262 | return; | ||
263 | } | ||
264 | |||
265 | r = dss_add_device(dssdev); | ||
266 | if (r) { | ||
267 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
268 | omapdss_output_unset_device(&sdi.output); | ||
269 | dss_put_device(dssdev); | ||
270 | return; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | static void __init sdi_init_output(struct platform_device *pdev) | ||
275 | { | ||
276 | struct omap_dss_output *out = &sdi.output; | ||
277 | |||
278 | out->pdev = pdev; | ||
279 | out->id = OMAP_DSS_OUTPUT_SDI; | ||
280 | out->type = OMAP_DISPLAY_TYPE_SDI; | ||
281 | |||
282 | dss_register_output(out); | ||
283 | } | ||
284 | |||
285 | static void __exit sdi_uninit_output(struct platform_device *pdev) | ||
286 | { | ||
287 | struct omap_dss_output *out = &sdi.output; | ||
288 | |||
289 | dss_unregister_output(out); | ||
290 | } | ||
291 | |||
292 | static int __init omap_sdi_probe(struct platform_device *pdev) | ||
293 | { | ||
294 | sdi_init_output(pdev); | ||
295 | |||
296 | sdi_probe_pdata(pdev); | ||
297 | |||
298 | return 0; | 177 | return 0; |
299 | } | 178 | } |
300 | 179 | ||
301 | static int __exit omap_sdi_remove(struct platform_device *pdev) | 180 | void sdi_exit(void) |
302 | { | ||
303 | dss_unregister_child_devices(&pdev->dev); | ||
304 | |||
305 | sdi_uninit_output(pdev); | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static struct platform_driver omap_sdi_driver = { | ||
311 | .remove = __exit_p(omap_sdi_remove), | ||
312 | .driver = { | ||
313 | .name = "omapdss_sdi", | ||
314 | .owner = THIS_MODULE, | ||
315 | }, | ||
316 | }; | ||
317 | |||
318 | int __init sdi_init_platform_driver(void) | ||
319 | { | ||
320 | return platform_driver_probe(&omap_sdi_driver, omap_sdi_probe); | ||
321 | } | ||
322 | |||
323 | void __exit sdi_uninit_platform_driver(void) | ||
324 | { | 181 | { |
325 | platform_driver_unregister(&omap_sdi_driver); | ||
326 | } | 182 | } |
diff --git a/drivers/video/omap2/dss/ti_hdmi.h b/drivers/video/omap2/dss/ti_hdmi.h deleted file mode 100644 index 216aa704f9d..00000000000 --- a/drivers/video/omap2/dss/ti_hdmi.h +++ /dev/null | |||
@@ -1,190 +0,0 @@ | |||
1 | /* | ||
2 | * ti_hdmi.h | ||
3 | * | ||
4 | * HDMI driver definition for TI OMAP4, DM81xx, DM38xx Processor. | ||
5 | * | ||
6 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef _TI_HDMI_H | ||
22 | #define _TI_HDMI_H | ||
23 | |||
24 | struct hdmi_ip_data; | ||
25 | |||
26 | enum hdmi_pll_pwr { | ||
27 | HDMI_PLLPWRCMD_ALLOFF = 0, | ||
28 | HDMI_PLLPWRCMD_PLLONLY = 1, | ||
29 | HDMI_PLLPWRCMD_BOTHON_ALLCLKS = 2, | ||
30 | HDMI_PLLPWRCMD_BOTHON_NOPHYCLK = 3 | ||
31 | }; | ||
32 | |||
33 | enum hdmi_core_hdmi_dvi { | ||
34 | HDMI_DVI = 0, | ||
35 | HDMI_HDMI = 1 | ||
36 | }; | ||
37 | |||
38 | enum hdmi_clk_refsel { | ||
39 | HDMI_REFSEL_PCLK = 0, | ||
40 | HDMI_REFSEL_REF1 = 1, | ||
41 | HDMI_REFSEL_REF2 = 2, | ||
42 | HDMI_REFSEL_SYSCLK = 3 | ||
43 | }; | ||
44 | |||
45 | struct hdmi_cm { | ||
46 | int code; | ||
47 | int mode; | ||
48 | }; | ||
49 | |||
50 | struct hdmi_config { | ||
51 | struct omap_video_timings timings; | ||
52 | struct hdmi_cm cm; | ||
53 | }; | ||
54 | |||
55 | /* HDMI PLL structure */ | ||
56 | struct hdmi_pll_info { | ||
57 | u16 regn; | ||
58 | u16 regm; | ||
59 | u32 regmf; | ||
60 | u16 regm2; | ||
61 | u16 regsd; | ||
62 | u16 dcofreq; | ||
63 | enum hdmi_clk_refsel refsel; | ||
64 | }; | ||
65 | |||
66 | struct ti_hdmi_ip_ops { | ||
67 | |||
68 | void (*video_configure)(struct hdmi_ip_data *ip_data); | ||
69 | |||
70 | int (*phy_enable)(struct hdmi_ip_data *ip_data); | ||
71 | |||
72 | void (*phy_disable)(struct hdmi_ip_data *ip_data); | ||
73 | |||
74 | int (*read_edid)(struct hdmi_ip_data *ip_data, u8 *edid, int len); | ||
75 | |||
76 | bool (*detect)(struct hdmi_ip_data *ip_data); | ||
77 | |||
78 | int (*pll_enable)(struct hdmi_ip_data *ip_data); | ||
79 | |||
80 | void (*pll_disable)(struct hdmi_ip_data *ip_data); | ||
81 | |||
82 | int (*video_enable)(struct hdmi_ip_data *ip_data); | ||
83 | |||
84 | void (*video_disable)(struct hdmi_ip_data *ip_data); | ||
85 | |||
86 | void (*dump_wrapper)(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
87 | |||
88 | void (*dump_core)(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
89 | |||
90 | void (*dump_pll)(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
91 | |||
92 | void (*dump_phy)(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
93 | |||
94 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
95 | int (*audio_enable)(struct hdmi_ip_data *ip_data); | ||
96 | |||
97 | void (*audio_disable)(struct hdmi_ip_data *ip_data); | ||
98 | |||
99 | int (*audio_start)(struct hdmi_ip_data *ip_data); | ||
100 | |||
101 | void (*audio_stop)(struct hdmi_ip_data *ip_data); | ||
102 | |||
103 | int (*audio_config)(struct hdmi_ip_data *ip_data, | ||
104 | struct omap_dss_audio *audio); | ||
105 | |||
106 | int (*audio_get_dma_port)(u32 *offset, u32 *size); | ||
107 | #endif | ||
108 | |||
109 | }; | ||
110 | |||
111 | /* | ||
112 | * Refer to section 8.2 in HDMI 1.3 specification for | ||
113 | * details about infoframe databytes | ||
114 | */ | ||
115 | struct hdmi_core_infoframe_avi { | ||
116 | /* Y0, Y1 rgb,yCbCr */ | ||
117 | u8 db1_format; | ||
118 | /* A0 Active information Present */ | ||
119 | u8 db1_active_info; | ||
120 | /* B0, B1 Bar info data valid */ | ||
121 | u8 db1_bar_info_dv; | ||
122 | /* S0, S1 scan information */ | ||
123 | u8 db1_scan_info; | ||
124 | /* C0, C1 colorimetry */ | ||
125 | u8 db2_colorimetry; | ||
126 | /* M0, M1 Aspect ratio (4:3, 16:9) */ | ||
127 | u8 db2_aspect_ratio; | ||
128 | /* R0...R3 Active format aspect ratio */ | ||
129 | u8 db2_active_fmt_ar; | ||
130 | /* ITC IT content. */ | ||
131 | u8 db3_itc; | ||
132 | /* EC0, EC1, EC2 Extended colorimetry */ | ||
133 | u8 db3_ec; | ||
134 | /* Q1, Q0 Quantization range */ | ||
135 | u8 db3_q_range; | ||
136 | /* SC1, SC0 Non-uniform picture scaling */ | ||
137 | u8 db3_nup_scaling; | ||
138 | /* VIC0..6 Video format identification */ | ||
139 | u8 db4_videocode; | ||
140 | /* PR0..PR3 Pixel repetition factor */ | ||
141 | u8 db5_pixel_repeat; | ||
142 | /* Line number end of top bar */ | ||
143 | u16 db6_7_line_eoftop; | ||
144 | /* Line number start of bottom bar */ | ||
145 | u16 db8_9_line_sofbottom; | ||
146 | /* Pixel number end of left bar */ | ||
147 | u16 db10_11_pixel_eofleft; | ||
148 | /* Pixel number start of right bar */ | ||
149 | u16 db12_13_pixel_sofright; | ||
150 | }; | ||
151 | |||
152 | struct hdmi_ip_data { | ||
153 | void __iomem *base_wp; /* HDMI wrapper */ | ||
154 | unsigned long core_sys_offset; | ||
155 | unsigned long core_av_offset; | ||
156 | unsigned long pll_offset; | ||
157 | unsigned long phy_offset; | ||
158 | const struct ti_hdmi_ip_ops *ops; | ||
159 | struct hdmi_config cfg; | ||
160 | struct hdmi_pll_info pll_data; | ||
161 | struct hdmi_core_infoframe_avi avi_cfg; | ||
162 | |||
163 | /* ti_hdmi_4xxx_ip private data. These should be in a separate struct */ | ||
164 | int hpd_gpio; | ||
165 | struct mutex lock; | ||
166 | }; | ||
167 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data); | ||
168 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data); | ||
169 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, u8 *edid, int len); | ||
170 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data); | ||
171 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data); | ||
172 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data); | ||
173 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data); | ||
174 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data); | ||
175 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data); | ||
176 | void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
177 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
178 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
179 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s); | ||
180 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
181 | int hdmi_compute_acr(u32 sample_freq, u32 *n, u32 *cts); | ||
182 | int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data); | ||
183 | void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data); | ||
184 | int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data); | ||
185 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data); | ||
186 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, | ||
187 | struct omap_dss_audio *audio); | ||
188 | int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size); | ||
189 | #endif | ||
190 | #endif | ||
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c deleted file mode 100644 index e18b222ed73..00000000000 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.c +++ /dev/null | |||
@@ -1,1430 +0,0 @@ | |||
1 | /* | ||
2 | * ti_hdmi_4xxx_ip.c | ||
3 | * | ||
4 | * HDMI TI81xx, TI38xx, TI OMAP4 etc IP driver Library | ||
5 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
6 | * Authors: Yong Zhi | ||
7 | * Mythri pk <mythripk@ti.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License version 2 as published by | ||
11 | * the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along with | ||
19 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/seq_file.h> | ||
31 | #include <linux/gpio.h> | ||
32 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
33 | #include <sound/asound.h> | ||
34 | #include <sound/asoundef.h> | ||
35 | #endif | ||
36 | |||
37 | #include "ti_hdmi_4xxx_ip.h" | ||
38 | #include "dss.h" | ||
39 | #include "dss_features.h" | ||
40 | |||
41 | static inline void hdmi_write_reg(void __iomem *base_addr, | ||
42 | const u16 idx, u32 val) | ||
43 | { | ||
44 | __raw_writel(val, base_addr + idx); | ||
45 | } | ||
46 | |||
47 | static inline u32 hdmi_read_reg(void __iomem *base_addr, | ||
48 | const u16 idx) | ||
49 | { | ||
50 | return __raw_readl(base_addr + idx); | ||
51 | } | ||
52 | |||
53 | static inline void __iomem *hdmi_wp_base(struct hdmi_ip_data *ip_data) | ||
54 | { | ||
55 | return ip_data->base_wp; | ||
56 | } | ||
57 | |||
58 | static inline void __iomem *hdmi_phy_base(struct hdmi_ip_data *ip_data) | ||
59 | { | ||
60 | return ip_data->base_wp + ip_data->phy_offset; | ||
61 | } | ||
62 | |||
63 | static inline void __iomem *hdmi_pll_base(struct hdmi_ip_data *ip_data) | ||
64 | { | ||
65 | return ip_data->base_wp + ip_data->pll_offset; | ||
66 | } | ||
67 | |||
68 | static inline void __iomem *hdmi_av_base(struct hdmi_ip_data *ip_data) | ||
69 | { | ||
70 | return ip_data->base_wp + ip_data->core_av_offset; | ||
71 | } | ||
72 | |||
73 | static inline void __iomem *hdmi_core_sys_base(struct hdmi_ip_data *ip_data) | ||
74 | { | ||
75 | return ip_data->base_wp + ip_data->core_sys_offset; | ||
76 | } | ||
77 | |||
78 | static inline int hdmi_wait_for_bit_change(void __iomem *base_addr, | ||
79 | const u16 idx, | ||
80 | int b2, int b1, u32 val) | ||
81 | { | ||
82 | u32 t = 0; | ||
83 | while (val != REG_GET(base_addr, idx, b2, b1)) { | ||
84 | udelay(1); | ||
85 | if (t++ > 10000) | ||
86 | return !val; | ||
87 | } | ||
88 | return val; | ||
89 | } | ||
90 | |||
91 | static int hdmi_pll_init(struct hdmi_ip_data *ip_data) | ||
92 | { | ||
93 | u32 r; | ||
94 | void __iomem *pll_base = hdmi_pll_base(ip_data); | ||
95 | struct hdmi_pll_info *fmt = &ip_data->pll_data; | ||
96 | |||
97 | /* PLL start always use manual mode */ | ||
98 | REG_FLD_MOD(pll_base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0); | ||
99 | |||
100 | r = hdmi_read_reg(pll_base, PLLCTRL_CFG1); | ||
101 | r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */ | ||
102 | r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */ | ||
103 | |||
104 | hdmi_write_reg(pll_base, PLLCTRL_CFG1, r); | ||
105 | |||
106 | r = hdmi_read_reg(pll_base, PLLCTRL_CFG2); | ||
107 | |||
108 | r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */ | ||
109 | r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */ | ||
110 | r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */ | ||
111 | r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */ | ||
112 | |||
113 | if (fmt->dcofreq) { | ||
114 | /* divider programming for frequency beyond 1000Mhz */ | ||
115 | REG_FLD_MOD(pll_base, PLLCTRL_CFG3, fmt->regsd, 17, 10); | ||
116 | r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */ | ||
117 | } else { | ||
118 | r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */ | ||
119 | } | ||
120 | |||
121 | hdmi_write_reg(pll_base, PLLCTRL_CFG2, r); | ||
122 | |||
123 | r = hdmi_read_reg(pll_base, PLLCTRL_CFG4); | ||
124 | r = FLD_MOD(r, fmt->regm2, 24, 18); | ||
125 | r = FLD_MOD(r, fmt->regmf, 17, 0); | ||
126 | |||
127 | hdmi_write_reg(pll_base, PLLCTRL_CFG4, r); | ||
128 | |||
129 | /* go now */ | ||
130 | REG_FLD_MOD(pll_base, PLLCTRL_PLL_GO, 0x1, 0, 0); | ||
131 | |||
132 | /* wait for bit change */ | ||
133 | if (hdmi_wait_for_bit_change(pll_base, PLLCTRL_PLL_GO, | ||
134 | 0, 0, 1) != 1) { | ||
135 | pr_err("PLL GO bit not set\n"); | ||
136 | return -ETIMEDOUT; | ||
137 | } | ||
138 | |||
139 | /* Wait till the lock bit is set in PLL status */ | ||
140 | if (hdmi_wait_for_bit_change(pll_base, | ||
141 | PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) { | ||
142 | pr_err("cannot lock PLL\n"); | ||
143 | pr_err("CFG1 0x%x\n", | ||
144 | hdmi_read_reg(pll_base, PLLCTRL_CFG1)); | ||
145 | pr_err("CFG2 0x%x\n", | ||
146 | hdmi_read_reg(pll_base, PLLCTRL_CFG2)); | ||
147 | pr_err("CFG4 0x%x\n", | ||
148 | hdmi_read_reg(pll_base, PLLCTRL_CFG4)); | ||
149 | return -ETIMEDOUT; | ||
150 | } | ||
151 | |||
152 | pr_debug("PLL locked!\n"); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* PHY_PWR_CMD */ | ||
158 | static int hdmi_set_phy_pwr(struct hdmi_ip_data *ip_data, enum hdmi_phy_pwr val) | ||
159 | { | ||
160 | /* Return if already the state */ | ||
161 | if (REG_GET(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, 5, 4) == val) | ||
162 | return 0; | ||
163 | |||
164 | /* Command for power control of HDMI PHY */ | ||
165 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 7, 6); | ||
166 | |||
167 | /* Status of the power control of HDMI PHY */ | ||
168 | if (hdmi_wait_for_bit_change(hdmi_wp_base(ip_data), | ||
169 | HDMI_WP_PWR_CTRL, 5, 4, val) != val) { | ||
170 | pr_err("Failed to set PHY power mode to %d\n", val); | ||
171 | return -ETIMEDOUT; | ||
172 | } | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | /* PLL_PWR_CMD */ | ||
178 | static int hdmi_set_pll_pwr(struct hdmi_ip_data *ip_data, enum hdmi_pll_pwr val) | ||
179 | { | ||
180 | /* Command for power control of HDMI PLL */ | ||
181 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, val, 3, 2); | ||
182 | |||
183 | /* wait till PHY_PWR_STATUS is set */ | ||
184 | if (hdmi_wait_for_bit_change(hdmi_wp_base(ip_data), HDMI_WP_PWR_CTRL, | ||
185 | 1, 0, val) != val) { | ||
186 | pr_err("Failed to set PLL_PWR_STATUS\n"); | ||
187 | return -ETIMEDOUT; | ||
188 | } | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int hdmi_pll_reset(struct hdmi_ip_data *ip_data) | ||
194 | { | ||
195 | /* SYSRESET controlled by power FSM */ | ||
196 | REG_FLD_MOD(hdmi_pll_base(ip_data), PLLCTRL_PLL_CONTROL, 0x0, 3, 3); | ||
197 | |||
198 | /* READ 0x0 reset is in progress */ | ||
199 | if (hdmi_wait_for_bit_change(hdmi_pll_base(ip_data), | ||
200 | PLLCTRL_PLL_STATUS, 0, 0, 1) != 1) { | ||
201 | pr_err("Failed to sysreset PLL\n"); | ||
202 | return -ETIMEDOUT; | ||
203 | } | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | int ti_hdmi_4xxx_pll_enable(struct hdmi_ip_data *ip_data) | ||
209 | { | ||
210 | u16 r = 0; | ||
211 | |||
212 | r = hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); | ||
213 | if (r) | ||
214 | return r; | ||
215 | |||
216 | r = hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_BOTHON_ALLCLKS); | ||
217 | if (r) | ||
218 | return r; | ||
219 | |||
220 | r = hdmi_pll_reset(ip_data); | ||
221 | if (r) | ||
222 | return r; | ||
223 | |||
224 | r = hdmi_pll_init(ip_data); | ||
225 | if (r) | ||
226 | return r; | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | void ti_hdmi_4xxx_pll_disable(struct hdmi_ip_data *ip_data) | ||
232 | { | ||
233 | hdmi_set_pll_pwr(ip_data, HDMI_PLLPWRCMD_ALLOFF); | ||
234 | } | ||
235 | |||
236 | static int hdmi_check_hpd_state(struct hdmi_ip_data *ip_data) | ||
237 | { | ||
238 | bool hpd; | ||
239 | int r; | ||
240 | |||
241 | mutex_lock(&ip_data->lock); | ||
242 | |||
243 | hpd = gpio_get_value(ip_data->hpd_gpio); | ||
244 | |||
245 | if (hpd) | ||
246 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_TXON); | ||
247 | else | ||
248 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); | ||
249 | |||
250 | if (r) { | ||
251 | DSSERR("Failed to %s PHY TX power\n", | ||
252 | hpd ? "enable" : "disable"); | ||
253 | goto err; | ||
254 | } | ||
255 | |||
256 | err: | ||
257 | mutex_unlock(&ip_data->lock); | ||
258 | return r; | ||
259 | } | ||
260 | |||
261 | static irqreturn_t hpd_irq_handler(int irq, void *data) | ||
262 | { | ||
263 | struct hdmi_ip_data *ip_data = data; | ||
264 | |||
265 | hdmi_check_hpd_state(ip_data); | ||
266 | |||
267 | return IRQ_HANDLED; | ||
268 | } | ||
269 | |||
270 | int ti_hdmi_4xxx_phy_enable(struct hdmi_ip_data *ip_data) | ||
271 | { | ||
272 | u16 r = 0; | ||
273 | void __iomem *phy_base = hdmi_phy_base(ip_data); | ||
274 | |||
275 | r = hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_LDOON); | ||
276 | if (r) | ||
277 | return r; | ||
278 | |||
279 | /* | ||
280 | * Read address 0 in order to get the SCP reset done completed | ||
281 | * Dummy access performed to make sure reset is done | ||
282 | */ | ||
283 | hdmi_read_reg(phy_base, HDMI_TXPHY_TX_CTRL); | ||
284 | |||
285 | /* | ||
286 | * Write to phy address 0 to configure the clock | ||
287 | * use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field | ||
288 | */ | ||
289 | REG_FLD_MOD(phy_base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30); | ||
290 | |||
291 | /* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */ | ||
292 | hdmi_write_reg(phy_base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000); | ||
293 | |||
294 | /* Setup max LDO voltage */ | ||
295 | REG_FLD_MOD(phy_base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0); | ||
296 | |||
297 | /* Write to phy address 3 to change the polarity control */ | ||
298 | REG_FLD_MOD(phy_base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27); | ||
299 | |||
300 | r = request_threaded_irq(gpio_to_irq(ip_data->hpd_gpio), | ||
301 | NULL, hpd_irq_handler, | ||
302 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | | ||
303 | IRQF_ONESHOT, "hpd", ip_data); | ||
304 | if (r) { | ||
305 | DSSERR("HPD IRQ request failed\n"); | ||
306 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
307 | return r; | ||
308 | } | ||
309 | |||
310 | r = hdmi_check_hpd_state(ip_data); | ||
311 | if (r) { | ||
312 | free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); | ||
313 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
314 | return r; | ||
315 | } | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | void ti_hdmi_4xxx_phy_disable(struct hdmi_ip_data *ip_data) | ||
321 | { | ||
322 | free_irq(gpio_to_irq(ip_data->hpd_gpio), ip_data); | ||
323 | |||
324 | hdmi_set_phy_pwr(ip_data, HDMI_PHYPWRCMD_OFF); | ||
325 | } | ||
326 | |||
327 | static int hdmi_core_ddc_init(struct hdmi_ip_data *ip_data) | ||
328 | { | ||
329 | void __iomem *base = hdmi_core_sys_base(ip_data); | ||
330 | |||
331 | /* Turn on CLK for DDC */ | ||
332 | REG_FLD_MOD(base, HDMI_CORE_AV_DPD, 0x7, 2, 0); | ||
333 | |||
334 | /* IN_PROG */ | ||
335 | if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 1) { | ||
336 | /* Abort transaction */ | ||
337 | REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xf, 3, 0); | ||
338 | /* IN_PROG */ | ||
339 | if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, | ||
340 | 4, 4, 0) != 0) { | ||
341 | DSSERR("Timeout aborting DDC transaction\n"); | ||
342 | return -ETIMEDOUT; | ||
343 | } | ||
344 | } | ||
345 | |||
346 | /* Clk SCL Devices */ | ||
347 | REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0xA, 3, 0); | ||
348 | |||
349 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
350 | if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, | ||
351 | 4, 4, 0) != 0) { | ||
352 | DSSERR("Timeout starting SCL clock\n"); | ||
353 | return -ETIMEDOUT; | ||
354 | } | ||
355 | |||
356 | /* Clear FIFO */ | ||
357 | REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x9, 3, 0); | ||
358 | |||
359 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
360 | if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, | ||
361 | 4, 4, 0) != 0) { | ||
362 | DSSERR("Timeout clearing DDC fifo\n"); | ||
363 | return -ETIMEDOUT; | ||
364 | } | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static int hdmi_core_ddc_edid(struct hdmi_ip_data *ip_data, | ||
370 | u8 *pedid, int ext) | ||
371 | { | ||
372 | void __iomem *base = hdmi_core_sys_base(ip_data); | ||
373 | u32 i; | ||
374 | char checksum; | ||
375 | u32 offset = 0; | ||
376 | |||
377 | /* HDMI_CORE_DDC_STATUS_IN_PROG */ | ||
378 | if (hdmi_wait_for_bit_change(base, HDMI_CORE_DDC_STATUS, | ||
379 | 4, 4, 0) != 0) { | ||
380 | DSSERR("Timeout waiting DDC to be ready\n"); | ||
381 | return -ETIMEDOUT; | ||
382 | } | ||
383 | |||
384 | if (ext % 2 != 0) | ||
385 | offset = 0x80; | ||
386 | |||
387 | /* Load Segment Address Register */ | ||
388 | REG_FLD_MOD(base, HDMI_CORE_DDC_SEGM, ext / 2, 7, 0); | ||
389 | |||
390 | /* Load Slave Address Register */ | ||
391 | REG_FLD_MOD(base, HDMI_CORE_DDC_ADDR, 0xA0 >> 1, 7, 1); | ||
392 | |||
393 | /* Load Offset Address Register */ | ||
394 | REG_FLD_MOD(base, HDMI_CORE_DDC_OFFSET, offset, 7, 0); | ||
395 | |||
396 | /* Load Byte Count */ | ||
397 | REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT1, 0x80, 7, 0); | ||
398 | REG_FLD_MOD(base, HDMI_CORE_DDC_COUNT2, 0x0, 1, 0); | ||
399 | |||
400 | /* Set DDC_CMD */ | ||
401 | if (ext) | ||
402 | REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x4, 3, 0); | ||
403 | else | ||
404 | REG_FLD_MOD(base, HDMI_CORE_DDC_CMD, 0x2, 3, 0); | ||
405 | |||
406 | /* HDMI_CORE_DDC_STATUS_BUS_LOW */ | ||
407 | if (REG_GET(base, HDMI_CORE_DDC_STATUS, 6, 6) == 1) { | ||
408 | pr_err("I2C Bus Low?\n"); | ||
409 | return -EIO; | ||
410 | } | ||
411 | /* HDMI_CORE_DDC_STATUS_NO_ACK */ | ||
412 | if (REG_GET(base, HDMI_CORE_DDC_STATUS, 5, 5) == 1) { | ||
413 | pr_err("I2C No Ack\n"); | ||
414 | return -EIO; | ||
415 | } | ||
416 | |||
417 | for (i = 0; i < 0x80; ++i) { | ||
418 | int t; | ||
419 | |||
420 | /* IN_PROG */ | ||
421 | if (REG_GET(base, HDMI_CORE_DDC_STATUS, 4, 4) == 0) { | ||
422 | DSSERR("operation stopped when reading edid\n"); | ||
423 | return -EIO; | ||
424 | } | ||
425 | |||
426 | t = 0; | ||
427 | /* FIFO_EMPTY */ | ||
428 | while (REG_GET(base, HDMI_CORE_DDC_STATUS, 2, 2) == 1) { | ||
429 | if (t++ > 10000) { | ||
430 | DSSERR("timeout reading edid\n"); | ||
431 | return -ETIMEDOUT; | ||
432 | } | ||
433 | udelay(1); | ||
434 | } | ||
435 | |||
436 | pedid[i] = REG_GET(base, HDMI_CORE_DDC_DATA, 7, 0); | ||
437 | } | ||
438 | |||
439 | checksum = 0; | ||
440 | for (i = 0; i < 0x80; ++i) | ||
441 | checksum += pedid[i]; | ||
442 | |||
443 | if (checksum != 0) { | ||
444 | pr_err("E-EDID checksum failed!!\n"); | ||
445 | return -EIO; | ||
446 | } | ||
447 | |||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | int ti_hdmi_4xxx_read_edid(struct hdmi_ip_data *ip_data, | ||
452 | u8 *edid, int len) | ||
453 | { | ||
454 | int r, l; | ||
455 | |||
456 | if (len < 128) | ||
457 | return -EINVAL; | ||
458 | |||
459 | r = hdmi_core_ddc_init(ip_data); | ||
460 | if (r) | ||
461 | return r; | ||
462 | |||
463 | r = hdmi_core_ddc_edid(ip_data, edid, 0); | ||
464 | if (r) | ||
465 | return r; | ||
466 | |||
467 | l = 128; | ||
468 | |||
469 | if (len >= 128 * 2 && edid[0x7e] > 0) { | ||
470 | r = hdmi_core_ddc_edid(ip_data, edid + 0x80, 1); | ||
471 | if (r) | ||
472 | return r; | ||
473 | l += 128; | ||
474 | } | ||
475 | |||
476 | return l; | ||
477 | } | ||
478 | |||
479 | bool ti_hdmi_4xxx_detect(struct hdmi_ip_data *ip_data) | ||
480 | { | ||
481 | return gpio_get_value(ip_data->hpd_gpio); | ||
482 | } | ||
483 | |||
484 | static void hdmi_core_init(struct hdmi_core_video_config *video_cfg, | ||
485 | struct hdmi_core_infoframe_avi *avi_cfg, | ||
486 | struct hdmi_core_packet_enable_repeat *repeat_cfg) | ||
487 | { | ||
488 | pr_debug("Enter hdmi_core_init\n"); | ||
489 | |||
490 | /* video core */ | ||
491 | video_cfg->ip_bus_width = HDMI_INPUT_8BIT; | ||
492 | video_cfg->op_dither_truc = HDMI_OUTPUTTRUNCATION_8BIT; | ||
493 | video_cfg->deep_color_pkt = HDMI_DEEPCOLORPACKECTDISABLE; | ||
494 | video_cfg->pkt_mode = HDMI_PACKETMODERESERVEDVALUE; | ||
495 | video_cfg->hdmi_dvi = HDMI_DVI; | ||
496 | video_cfg->tclk_sel_clkmult = HDMI_FPLL10IDCK; | ||
497 | |||
498 | /* info frame */ | ||
499 | avi_cfg->db1_format = 0; | ||
500 | avi_cfg->db1_active_info = 0; | ||
501 | avi_cfg->db1_bar_info_dv = 0; | ||
502 | avi_cfg->db1_scan_info = 0; | ||
503 | avi_cfg->db2_colorimetry = 0; | ||
504 | avi_cfg->db2_aspect_ratio = 0; | ||
505 | avi_cfg->db2_active_fmt_ar = 0; | ||
506 | avi_cfg->db3_itc = 0; | ||
507 | avi_cfg->db3_ec = 0; | ||
508 | avi_cfg->db3_q_range = 0; | ||
509 | avi_cfg->db3_nup_scaling = 0; | ||
510 | avi_cfg->db4_videocode = 0; | ||
511 | avi_cfg->db5_pixel_repeat = 0; | ||
512 | avi_cfg->db6_7_line_eoftop = 0 ; | ||
513 | avi_cfg->db8_9_line_sofbottom = 0; | ||
514 | avi_cfg->db10_11_pixel_eofleft = 0; | ||
515 | avi_cfg->db12_13_pixel_sofright = 0; | ||
516 | |||
517 | /* packet enable and repeat */ | ||
518 | repeat_cfg->audio_pkt = 0; | ||
519 | repeat_cfg->audio_pkt_repeat = 0; | ||
520 | repeat_cfg->avi_infoframe = 0; | ||
521 | repeat_cfg->avi_infoframe_repeat = 0; | ||
522 | repeat_cfg->gen_cntrl_pkt = 0; | ||
523 | repeat_cfg->gen_cntrl_pkt_repeat = 0; | ||
524 | repeat_cfg->generic_pkt = 0; | ||
525 | repeat_cfg->generic_pkt_repeat = 0; | ||
526 | } | ||
527 | |||
528 | static void hdmi_core_powerdown_disable(struct hdmi_ip_data *ip_data) | ||
529 | { | ||
530 | pr_debug("Enter hdmi_core_powerdown_disable\n"); | ||
531 | REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_CTRL1, 0x0, 0, 0); | ||
532 | } | ||
533 | |||
534 | static void hdmi_core_swreset_release(struct hdmi_ip_data *ip_data) | ||
535 | { | ||
536 | pr_debug("Enter hdmi_core_swreset_release\n"); | ||
537 | REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_SYS_SRST, 0x0, 0, 0); | ||
538 | } | ||
539 | |||
540 | static void hdmi_core_swreset_assert(struct hdmi_ip_data *ip_data) | ||
541 | { | ||
542 | pr_debug("Enter hdmi_core_swreset_assert\n"); | ||
543 | REG_FLD_MOD(hdmi_core_sys_base(ip_data), HDMI_CORE_SYS_SRST, 0x1, 0, 0); | ||
544 | } | ||
545 | |||
546 | /* HDMI_CORE_VIDEO_CONFIG */ | ||
547 | static void hdmi_core_video_config(struct hdmi_ip_data *ip_data, | ||
548 | struct hdmi_core_video_config *cfg) | ||
549 | { | ||
550 | u32 r = 0; | ||
551 | void __iomem *core_sys_base = hdmi_core_sys_base(ip_data); | ||
552 | |||
553 | /* sys_ctrl1 default configuration not tunable */ | ||
554 | r = hdmi_read_reg(core_sys_base, HDMI_CORE_CTRL1); | ||
555 | r = FLD_MOD(r, HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC, 5, 5); | ||
556 | r = FLD_MOD(r, HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC, 4, 4); | ||
557 | r = FLD_MOD(r, HDMI_CORE_CTRL1_BSEL_24BITBUS, 2, 2); | ||
558 | r = FLD_MOD(r, HDMI_CORE_CTRL1_EDGE_RISINGEDGE, 1, 1); | ||
559 | hdmi_write_reg(core_sys_base, HDMI_CORE_CTRL1, r); | ||
560 | |||
561 | REG_FLD_MOD(core_sys_base, | ||
562 | HDMI_CORE_SYS_VID_ACEN, cfg->ip_bus_width, 7, 6); | ||
563 | |||
564 | /* Vid_Mode */ | ||
565 | r = hdmi_read_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE); | ||
566 | |||
567 | /* dither truncation configuration */ | ||
568 | if (cfg->op_dither_truc > HDMI_OUTPUTTRUNCATION_12BIT) { | ||
569 | r = FLD_MOD(r, cfg->op_dither_truc - 3, 7, 6); | ||
570 | r = FLD_MOD(r, 1, 5, 5); | ||
571 | } else { | ||
572 | r = FLD_MOD(r, cfg->op_dither_truc, 7, 6); | ||
573 | r = FLD_MOD(r, 0, 5, 5); | ||
574 | } | ||
575 | hdmi_write_reg(core_sys_base, HDMI_CORE_SYS_VID_MODE, r); | ||
576 | |||
577 | /* HDMI_Ctrl */ | ||
578 | r = hdmi_read_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_HDMI_CTRL); | ||
579 | r = FLD_MOD(r, cfg->deep_color_pkt, 6, 6); | ||
580 | r = FLD_MOD(r, cfg->pkt_mode, 5, 3); | ||
581 | r = FLD_MOD(r, cfg->hdmi_dvi, 0, 0); | ||
582 | hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_HDMI_CTRL, r); | ||
583 | |||
584 | /* TMDS_CTRL */ | ||
585 | REG_FLD_MOD(core_sys_base, | ||
586 | HDMI_CORE_SYS_TMDS_CTRL, cfg->tclk_sel_clkmult, 6, 5); | ||
587 | } | ||
588 | |||
589 | static void hdmi_core_aux_infoframe_avi_config(struct hdmi_ip_data *ip_data) | ||
590 | { | ||
591 | u32 val; | ||
592 | char sum = 0, checksum = 0; | ||
593 | void __iomem *av_base = hdmi_av_base(ip_data); | ||
594 | struct hdmi_core_infoframe_avi info_avi = ip_data->avi_cfg; | ||
595 | |||
596 | sum += 0x82 + 0x002 + 0x00D; | ||
597 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_TYPE, 0x082); | ||
598 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_VERS, 0x002); | ||
599 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_LEN, 0x00D); | ||
600 | |||
601 | val = (info_avi.db1_format << 5) | | ||
602 | (info_avi.db1_active_info << 4) | | ||
603 | (info_avi.db1_bar_info_dv << 2) | | ||
604 | (info_avi.db1_scan_info); | ||
605 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(0), val); | ||
606 | sum += val; | ||
607 | |||
608 | val = (info_avi.db2_colorimetry << 6) | | ||
609 | (info_avi.db2_aspect_ratio << 4) | | ||
610 | (info_avi.db2_active_fmt_ar); | ||
611 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(1), val); | ||
612 | sum += val; | ||
613 | |||
614 | val = (info_avi.db3_itc << 7) | | ||
615 | (info_avi.db3_ec << 4) | | ||
616 | (info_avi.db3_q_range << 2) | | ||
617 | (info_avi.db3_nup_scaling); | ||
618 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(2), val); | ||
619 | sum += val; | ||
620 | |||
621 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(3), | ||
622 | info_avi.db4_videocode); | ||
623 | sum += info_avi.db4_videocode; | ||
624 | |||
625 | val = info_avi.db5_pixel_repeat; | ||
626 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(4), val); | ||
627 | sum += val; | ||
628 | |||
629 | val = info_avi.db6_7_line_eoftop & 0x00FF; | ||
630 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(5), val); | ||
631 | sum += val; | ||
632 | |||
633 | val = ((info_avi.db6_7_line_eoftop >> 8) & 0x00FF); | ||
634 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(6), val); | ||
635 | sum += val; | ||
636 | |||
637 | val = info_avi.db8_9_line_sofbottom & 0x00FF; | ||
638 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(7), val); | ||
639 | sum += val; | ||
640 | |||
641 | val = ((info_avi.db8_9_line_sofbottom >> 8) & 0x00FF); | ||
642 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(8), val); | ||
643 | sum += val; | ||
644 | |||
645 | val = info_avi.db10_11_pixel_eofleft & 0x00FF; | ||
646 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(9), val); | ||
647 | sum += val; | ||
648 | |||
649 | val = ((info_avi.db10_11_pixel_eofleft >> 8) & 0x00FF); | ||
650 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(10), val); | ||
651 | sum += val; | ||
652 | |||
653 | val = info_avi.db12_13_pixel_sofright & 0x00FF; | ||
654 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(11), val); | ||
655 | sum += val; | ||
656 | |||
657 | val = ((info_avi.db12_13_pixel_sofright >> 8) & 0x00FF); | ||
658 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_DBYTE(12), val); | ||
659 | sum += val; | ||
660 | |||
661 | checksum = 0x100 - sum; | ||
662 | hdmi_write_reg(av_base, HDMI_CORE_AV_AVI_CHSUM, checksum); | ||
663 | } | ||
664 | |||
665 | static void hdmi_core_av_packet_config(struct hdmi_ip_data *ip_data, | ||
666 | struct hdmi_core_packet_enable_repeat repeat_cfg) | ||
667 | { | ||
668 | /* enable/repeat the infoframe */ | ||
669 | hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_PB_CTRL1, | ||
670 | (repeat_cfg.audio_pkt << 5) | | ||
671 | (repeat_cfg.audio_pkt_repeat << 4) | | ||
672 | (repeat_cfg.avi_infoframe << 1) | | ||
673 | (repeat_cfg.avi_infoframe_repeat)); | ||
674 | |||
675 | /* enable/repeat the packet */ | ||
676 | hdmi_write_reg(hdmi_av_base(ip_data), HDMI_CORE_AV_PB_CTRL2, | ||
677 | (repeat_cfg.gen_cntrl_pkt << 3) | | ||
678 | (repeat_cfg.gen_cntrl_pkt_repeat << 2) | | ||
679 | (repeat_cfg.generic_pkt << 1) | | ||
680 | (repeat_cfg.generic_pkt_repeat)); | ||
681 | } | ||
682 | |||
683 | static void hdmi_wp_init(struct omap_video_timings *timings, | ||
684 | struct hdmi_video_format *video_fmt) | ||
685 | { | ||
686 | pr_debug("Enter hdmi_wp_init\n"); | ||
687 | |||
688 | timings->hbp = 0; | ||
689 | timings->hfp = 0; | ||
690 | timings->hsw = 0; | ||
691 | timings->vbp = 0; | ||
692 | timings->vfp = 0; | ||
693 | timings->vsw = 0; | ||
694 | |||
695 | video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444; | ||
696 | video_fmt->y_res = 0; | ||
697 | video_fmt->x_res = 0; | ||
698 | |||
699 | } | ||
700 | |||
701 | int ti_hdmi_4xxx_wp_video_start(struct hdmi_ip_data *ip_data) | ||
702 | { | ||
703 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, true, 31, 31); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | void ti_hdmi_4xxx_wp_video_stop(struct hdmi_ip_data *ip_data) | ||
708 | { | ||
709 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, false, 31, 31); | ||
710 | } | ||
711 | |||
712 | static void hdmi_wp_video_init_format(struct hdmi_video_format *video_fmt, | ||
713 | struct omap_video_timings *timings, struct hdmi_config *param) | ||
714 | { | ||
715 | pr_debug("Enter hdmi_wp_video_init_format\n"); | ||
716 | |||
717 | video_fmt->y_res = param->timings.y_res; | ||
718 | video_fmt->x_res = param->timings.x_res; | ||
719 | |||
720 | timings->hbp = param->timings.hbp; | ||
721 | timings->hfp = param->timings.hfp; | ||
722 | timings->hsw = param->timings.hsw; | ||
723 | timings->vbp = param->timings.vbp; | ||
724 | timings->vfp = param->timings.vfp; | ||
725 | timings->vsw = param->timings.vsw; | ||
726 | } | ||
727 | |||
728 | static void hdmi_wp_video_config_format(struct hdmi_ip_data *ip_data, | ||
729 | struct hdmi_video_format *video_fmt) | ||
730 | { | ||
731 | u32 l = 0; | ||
732 | |||
733 | REG_FLD_MOD(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, | ||
734 | video_fmt->packing_mode, 10, 8); | ||
735 | |||
736 | l |= FLD_VAL(video_fmt->y_res, 31, 16); | ||
737 | l |= FLD_VAL(video_fmt->x_res, 15, 0); | ||
738 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_SIZE, l); | ||
739 | } | ||
740 | |||
741 | static void hdmi_wp_video_config_interface(struct hdmi_ip_data *ip_data) | ||
742 | { | ||
743 | u32 r; | ||
744 | bool vsync_pol, hsync_pol; | ||
745 | pr_debug("Enter hdmi_wp_video_config_interface\n"); | ||
746 | |||
747 | vsync_pol = ip_data->cfg.timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH; | ||
748 | hsync_pol = ip_data->cfg.timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH; | ||
749 | |||
750 | r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG); | ||
751 | r = FLD_MOD(r, vsync_pol, 7, 7); | ||
752 | r = FLD_MOD(r, hsync_pol, 6, 6); | ||
753 | r = FLD_MOD(r, ip_data->cfg.timings.interlace, 3, 3); | ||
754 | r = FLD_MOD(r, 1, 1, 0); /* HDMI_TIMING_MASTER_24BIT */ | ||
755 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_CFG, r); | ||
756 | } | ||
757 | |||
758 | static void hdmi_wp_video_config_timing(struct hdmi_ip_data *ip_data, | ||
759 | struct omap_video_timings *timings) | ||
760 | { | ||
761 | u32 timing_h = 0; | ||
762 | u32 timing_v = 0; | ||
763 | |||
764 | pr_debug("Enter hdmi_wp_video_config_timing\n"); | ||
765 | |||
766 | timing_h |= FLD_VAL(timings->hbp, 31, 20); | ||
767 | timing_h |= FLD_VAL(timings->hfp, 19, 8); | ||
768 | timing_h |= FLD_VAL(timings->hsw, 7, 0); | ||
769 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_TIMING_H, timing_h); | ||
770 | |||
771 | timing_v |= FLD_VAL(timings->vbp, 31, 20); | ||
772 | timing_v |= FLD_VAL(timings->vfp, 19, 8); | ||
773 | timing_v |= FLD_VAL(timings->vsw, 7, 0); | ||
774 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_VIDEO_TIMING_V, timing_v); | ||
775 | } | ||
776 | |||
777 | void ti_hdmi_4xxx_basic_configure(struct hdmi_ip_data *ip_data) | ||
778 | { | ||
779 | /* HDMI */ | ||
780 | struct omap_video_timings video_timing; | ||
781 | struct hdmi_video_format video_format; | ||
782 | /* HDMI core */ | ||
783 | struct hdmi_core_infoframe_avi avi_cfg = ip_data->avi_cfg; | ||
784 | struct hdmi_core_video_config v_core_cfg; | ||
785 | struct hdmi_core_packet_enable_repeat repeat_cfg; | ||
786 | struct hdmi_config *cfg = &ip_data->cfg; | ||
787 | |||
788 | hdmi_wp_init(&video_timing, &video_format); | ||
789 | |||
790 | hdmi_core_init(&v_core_cfg, | ||
791 | &avi_cfg, | ||
792 | &repeat_cfg); | ||
793 | |||
794 | hdmi_wp_video_init_format(&video_format, &video_timing, cfg); | ||
795 | |||
796 | hdmi_wp_video_config_timing(ip_data, &video_timing); | ||
797 | |||
798 | /* video config */ | ||
799 | video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422; | ||
800 | |||
801 | hdmi_wp_video_config_format(ip_data, &video_format); | ||
802 | |||
803 | hdmi_wp_video_config_interface(ip_data); | ||
804 | |||
805 | /* | ||
806 | * configure core video part | ||
807 | * set software reset in the core | ||
808 | */ | ||
809 | hdmi_core_swreset_assert(ip_data); | ||
810 | |||
811 | /* power down off */ | ||
812 | hdmi_core_powerdown_disable(ip_data); | ||
813 | |||
814 | v_core_cfg.pkt_mode = HDMI_PACKETMODE24BITPERPIXEL; | ||
815 | v_core_cfg.hdmi_dvi = cfg->cm.mode; | ||
816 | |||
817 | hdmi_core_video_config(ip_data, &v_core_cfg); | ||
818 | |||
819 | /* release software reset in the core */ | ||
820 | hdmi_core_swreset_release(ip_data); | ||
821 | |||
822 | /* | ||
823 | * configure packet | ||
824 | * info frame video see doc CEA861-D page 65 | ||
825 | */ | ||
826 | avi_cfg.db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB; | ||
827 | avi_cfg.db1_active_info = | ||
828 | HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF; | ||
829 | avi_cfg.db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO; | ||
830 | avi_cfg.db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0; | ||
831 | avi_cfg.db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO; | ||
832 | avi_cfg.db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO; | ||
833 | avi_cfg.db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME; | ||
834 | avi_cfg.db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO; | ||
835 | avi_cfg.db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601; | ||
836 | avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT; | ||
837 | avi_cfg.db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO; | ||
838 | avi_cfg.db4_videocode = cfg->cm.code; | ||
839 | avi_cfg.db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO; | ||
840 | avi_cfg.db6_7_line_eoftop = 0; | ||
841 | avi_cfg.db8_9_line_sofbottom = 0; | ||
842 | avi_cfg.db10_11_pixel_eofleft = 0; | ||
843 | avi_cfg.db12_13_pixel_sofright = 0; | ||
844 | |||
845 | hdmi_core_aux_infoframe_avi_config(ip_data); | ||
846 | |||
847 | /* enable/repeat the infoframe */ | ||
848 | repeat_cfg.avi_infoframe = HDMI_PACKETENABLE; | ||
849 | repeat_cfg.avi_infoframe_repeat = HDMI_PACKETREPEATON; | ||
850 | /* wakeup */ | ||
851 | repeat_cfg.audio_pkt = HDMI_PACKETENABLE; | ||
852 | repeat_cfg.audio_pkt_repeat = HDMI_PACKETREPEATON; | ||
853 | hdmi_core_av_packet_config(ip_data, repeat_cfg); | ||
854 | } | ||
855 | |||
856 | void ti_hdmi_4xxx_wp_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | ||
857 | { | ||
858 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r,\ | ||
859 | hdmi_read_reg(hdmi_wp_base(ip_data), r)) | ||
860 | |||
861 | DUMPREG(HDMI_WP_REVISION); | ||
862 | DUMPREG(HDMI_WP_SYSCONFIG); | ||
863 | DUMPREG(HDMI_WP_IRQSTATUS_RAW); | ||
864 | DUMPREG(HDMI_WP_IRQSTATUS); | ||
865 | DUMPREG(HDMI_WP_PWR_CTRL); | ||
866 | DUMPREG(HDMI_WP_IRQENABLE_SET); | ||
867 | DUMPREG(HDMI_WP_VIDEO_CFG); | ||
868 | DUMPREG(HDMI_WP_VIDEO_SIZE); | ||
869 | DUMPREG(HDMI_WP_VIDEO_TIMING_H); | ||
870 | DUMPREG(HDMI_WP_VIDEO_TIMING_V); | ||
871 | DUMPREG(HDMI_WP_WP_CLK); | ||
872 | DUMPREG(HDMI_WP_AUDIO_CFG); | ||
873 | DUMPREG(HDMI_WP_AUDIO_CFG2); | ||
874 | DUMPREG(HDMI_WP_AUDIO_CTRL); | ||
875 | DUMPREG(HDMI_WP_AUDIO_DATA); | ||
876 | } | ||
877 | |||
878 | void ti_hdmi_4xxx_pll_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | ||
879 | { | ||
880 | #define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\ | ||
881 | hdmi_read_reg(hdmi_pll_base(ip_data), r)) | ||
882 | |||
883 | DUMPPLL(PLLCTRL_PLL_CONTROL); | ||
884 | DUMPPLL(PLLCTRL_PLL_STATUS); | ||
885 | DUMPPLL(PLLCTRL_PLL_GO); | ||
886 | DUMPPLL(PLLCTRL_CFG1); | ||
887 | DUMPPLL(PLLCTRL_CFG2); | ||
888 | DUMPPLL(PLLCTRL_CFG3); | ||
889 | DUMPPLL(PLLCTRL_CFG4); | ||
890 | } | ||
891 | |||
892 | void ti_hdmi_4xxx_core_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | ||
893 | { | ||
894 | int i; | ||
895 | |||
896 | #define CORE_REG(i, name) name(i) | ||
897 | #define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\ | ||
898 | hdmi_read_reg(hdmi_core_sys_base(ip_data), r)) | ||
899 | #define DUMPCOREAV(r) seq_printf(s, "%-35s %08x\n", #r,\ | ||
900 | hdmi_read_reg(hdmi_av_base(ip_data), r)) | ||
901 | #define DUMPCOREAV2(i, r) seq_printf(s, "%s[%d]%*s %08x\n", #r, i, \ | ||
902 | (i < 10) ? 32 - (int)strlen(#r) : 31 - (int)strlen(#r), " ", \ | ||
903 | hdmi_read_reg(hdmi_av_base(ip_data), CORE_REG(i, r))) | ||
904 | |||
905 | DUMPCORE(HDMI_CORE_SYS_VND_IDL); | ||
906 | DUMPCORE(HDMI_CORE_SYS_DEV_IDL); | ||
907 | DUMPCORE(HDMI_CORE_SYS_DEV_IDH); | ||
908 | DUMPCORE(HDMI_CORE_SYS_DEV_REV); | ||
909 | DUMPCORE(HDMI_CORE_SYS_SRST); | ||
910 | DUMPCORE(HDMI_CORE_CTRL1); | ||
911 | DUMPCORE(HDMI_CORE_SYS_SYS_STAT); | ||
912 | DUMPCORE(HDMI_CORE_SYS_DE_DLY); | ||
913 | DUMPCORE(HDMI_CORE_SYS_DE_CTRL); | ||
914 | DUMPCORE(HDMI_CORE_SYS_DE_TOP); | ||
915 | DUMPCORE(HDMI_CORE_SYS_DE_CNTL); | ||
916 | DUMPCORE(HDMI_CORE_SYS_DE_CNTH); | ||
917 | DUMPCORE(HDMI_CORE_SYS_DE_LINL); | ||
918 | DUMPCORE(HDMI_CORE_SYS_DE_LINH_1); | ||
919 | DUMPCORE(HDMI_CORE_SYS_VID_ACEN); | ||
920 | DUMPCORE(HDMI_CORE_SYS_VID_MODE); | ||
921 | DUMPCORE(HDMI_CORE_SYS_INTR_STATE); | ||
922 | DUMPCORE(HDMI_CORE_SYS_INTR1); | ||
923 | DUMPCORE(HDMI_CORE_SYS_INTR2); | ||
924 | DUMPCORE(HDMI_CORE_SYS_INTR3); | ||
925 | DUMPCORE(HDMI_CORE_SYS_INTR4); | ||
926 | DUMPCORE(HDMI_CORE_SYS_UMASK1); | ||
927 | DUMPCORE(HDMI_CORE_SYS_TMDS_CTRL); | ||
928 | |||
929 | DUMPCORE(HDMI_CORE_DDC_ADDR); | ||
930 | DUMPCORE(HDMI_CORE_DDC_SEGM); | ||
931 | DUMPCORE(HDMI_CORE_DDC_OFFSET); | ||
932 | DUMPCORE(HDMI_CORE_DDC_COUNT1); | ||
933 | DUMPCORE(HDMI_CORE_DDC_COUNT2); | ||
934 | DUMPCORE(HDMI_CORE_DDC_STATUS); | ||
935 | DUMPCORE(HDMI_CORE_DDC_CMD); | ||
936 | DUMPCORE(HDMI_CORE_DDC_DATA); | ||
937 | |||
938 | DUMPCOREAV(HDMI_CORE_AV_ACR_CTRL); | ||
939 | DUMPCOREAV(HDMI_CORE_AV_FREQ_SVAL); | ||
940 | DUMPCOREAV(HDMI_CORE_AV_N_SVAL1); | ||
941 | DUMPCOREAV(HDMI_CORE_AV_N_SVAL2); | ||
942 | DUMPCOREAV(HDMI_CORE_AV_N_SVAL3); | ||
943 | DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL1); | ||
944 | DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL2); | ||
945 | DUMPCOREAV(HDMI_CORE_AV_CTS_SVAL3); | ||
946 | DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL1); | ||
947 | DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL2); | ||
948 | DUMPCOREAV(HDMI_CORE_AV_CTS_HVAL3); | ||
949 | DUMPCOREAV(HDMI_CORE_AV_AUD_MODE); | ||
950 | DUMPCOREAV(HDMI_CORE_AV_SPDIF_CTRL); | ||
951 | DUMPCOREAV(HDMI_CORE_AV_HW_SPDIF_FS); | ||
952 | DUMPCOREAV(HDMI_CORE_AV_SWAP_I2S); | ||
953 | DUMPCOREAV(HDMI_CORE_AV_SPDIF_ERTH); | ||
954 | DUMPCOREAV(HDMI_CORE_AV_I2S_IN_MAP); | ||
955 | DUMPCOREAV(HDMI_CORE_AV_I2S_IN_CTRL); | ||
956 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST0); | ||
957 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST1); | ||
958 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST2); | ||
959 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST4); | ||
960 | DUMPCOREAV(HDMI_CORE_AV_I2S_CHST5); | ||
961 | DUMPCOREAV(HDMI_CORE_AV_ASRC); | ||
962 | DUMPCOREAV(HDMI_CORE_AV_I2S_IN_LEN); | ||
963 | DUMPCOREAV(HDMI_CORE_AV_HDMI_CTRL); | ||
964 | DUMPCOREAV(HDMI_CORE_AV_AUDO_TXSTAT); | ||
965 | DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_1); | ||
966 | DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_2); | ||
967 | DUMPCOREAV(HDMI_CORE_AV_AUD_PAR_BUSCLK_3); | ||
968 | DUMPCOREAV(HDMI_CORE_AV_TEST_TXCTRL); | ||
969 | DUMPCOREAV(HDMI_CORE_AV_DPD); | ||
970 | DUMPCOREAV(HDMI_CORE_AV_PB_CTRL1); | ||
971 | DUMPCOREAV(HDMI_CORE_AV_PB_CTRL2); | ||
972 | DUMPCOREAV(HDMI_CORE_AV_AVI_TYPE); | ||
973 | DUMPCOREAV(HDMI_CORE_AV_AVI_VERS); | ||
974 | DUMPCOREAV(HDMI_CORE_AV_AVI_LEN); | ||
975 | DUMPCOREAV(HDMI_CORE_AV_AVI_CHSUM); | ||
976 | |||
977 | for (i = 0; i < HDMI_CORE_AV_AVI_DBYTE_NELEMS; i++) | ||
978 | DUMPCOREAV2(i, HDMI_CORE_AV_AVI_DBYTE); | ||
979 | |||
980 | DUMPCOREAV(HDMI_CORE_AV_SPD_TYPE); | ||
981 | DUMPCOREAV(HDMI_CORE_AV_SPD_VERS); | ||
982 | DUMPCOREAV(HDMI_CORE_AV_SPD_LEN); | ||
983 | DUMPCOREAV(HDMI_CORE_AV_SPD_CHSUM); | ||
984 | |||
985 | for (i = 0; i < HDMI_CORE_AV_SPD_DBYTE_NELEMS; i++) | ||
986 | DUMPCOREAV2(i, HDMI_CORE_AV_SPD_DBYTE); | ||
987 | |||
988 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_TYPE); | ||
989 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_VERS); | ||
990 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_LEN); | ||
991 | DUMPCOREAV(HDMI_CORE_AV_AUDIO_CHSUM); | ||
992 | |||
993 | for (i = 0; i < HDMI_CORE_AV_AUD_DBYTE_NELEMS; i++) | ||
994 | DUMPCOREAV2(i, HDMI_CORE_AV_AUD_DBYTE); | ||
995 | |||
996 | DUMPCOREAV(HDMI_CORE_AV_MPEG_TYPE); | ||
997 | DUMPCOREAV(HDMI_CORE_AV_MPEG_VERS); | ||
998 | DUMPCOREAV(HDMI_CORE_AV_MPEG_LEN); | ||
999 | DUMPCOREAV(HDMI_CORE_AV_MPEG_CHSUM); | ||
1000 | |||
1001 | for (i = 0; i < HDMI_CORE_AV_MPEG_DBYTE_NELEMS; i++) | ||
1002 | DUMPCOREAV2(i, HDMI_CORE_AV_MPEG_DBYTE); | ||
1003 | |||
1004 | for (i = 0; i < HDMI_CORE_AV_GEN_DBYTE_NELEMS; i++) | ||
1005 | DUMPCOREAV2(i, HDMI_CORE_AV_GEN_DBYTE); | ||
1006 | |||
1007 | DUMPCOREAV(HDMI_CORE_AV_CP_BYTE1); | ||
1008 | |||
1009 | for (i = 0; i < HDMI_CORE_AV_GEN2_DBYTE_NELEMS; i++) | ||
1010 | DUMPCOREAV2(i, HDMI_CORE_AV_GEN2_DBYTE); | ||
1011 | |||
1012 | DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID); | ||
1013 | } | ||
1014 | |||
1015 | void ti_hdmi_4xxx_phy_dump(struct hdmi_ip_data *ip_data, struct seq_file *s) | ||
1016 | { | ||
1017 | #define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\ | ||
1018 | hdmi_read_reg(hdmi_phy_base(ip_data), r)) | ||
1019 | |||
1020 | DUMPPHY(HDMI_TXPHY_TX_CTRL); | ||
1021 | DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL); | ||
1022 | DUMPPHY(HDMI_TXPHY_POWER_CTRL); | ||
1023 | DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL); | ||
1024 | } | ||
1025 | |||
1026 | #if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) | ||
1027 | static void ti_hdmi_4xxx_wp_audio_config_format(struct hdmi_ip_data *ip_data, | ||
1028 | struct hdmi_audio_format *aud_fmt) | ||
1029 | { | ||
1030 | u32 r; | ||
1031 | |||
1032 | DSSDBG("Enter hdmi_wp_audio_config_format\n"); | ||
1033 | |||
1034 | r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG); | ||
1035 | r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24); | ||
1036 | r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16); | ||
1037 | r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5); | ||
1038 | r = FLD_MOD(r, aud_fmt->type, 4, 4); | ||
1039 | r = FLD_MOD(r, aud_fmt->justification, 3, 3); | ||
1040 | r = FLD_MOD(r, aud_fmt->sample_order, 2, 2); | ||
1041 | r = FLD_MOD(r, aud_fmt->samples_per_word, 1, 1); | ||
1042 | r = FLD_MOD(r, aud_fmt->sample_size, 0, 0); | ||
1043 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG, r); | ||
1044 | } | ||
1045 | |||
1046 | static void ti_hdmi_4xxx_wp_audio_config_dma(struct hdmi_ip_data *ip_data, | ||
1047 | struct hdmi_audio_dma *aud_dma) | ||
1048 | { | ||
1049 | u32 r; | ||
1050 | |||
1051 | DSSDBG("Enter hdmi_wp_audio_config_dma\n"); | ||
1052 | |||
1053 | r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG2); | ||
1054 | r = FLD_MOD(r, aud_dma->transfer_size, 15, 8); | ||
1055 | r = FLD_MOD(r, aud_dma->block_size, 7, 0); | ||
1056 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CFG2, r); | ||
1057 | |||
1058 | r = hdmi_read_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL); | ||
1059 | r = FLD_MOD(r, aud_dma->mode, 9, 9); | ||
1060 | r = FLD_MOD(r, aud_dma->fifo_threshold, 8, 0); | ||
1061 | hdmi_write_reg(hdmi_wp_base(ip_data), HDMI_WP_AUDIO_CTRL, r); | ||
1062 | } | ||
1063 | |||
1064 | static void ti_hdmi_4xxx_core_audio_config(struct hdmi_ip_data *ip_data, | ||
1065 | struct hdmi_core_audio_config *cfg) | ||
1066 | { | ||
1067 | u32 r; | ||
1068 | void __iomem *av_base = hdmi_av_base(ip_data); | ||
1069 | |||
1070 | /* | ||
1071 | * Parameters for generation of Audio Clock Recovery packets | ||
1072 | */ | ||
1073 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL1, cfg->n, 7, 0); | ||
1074 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL2, cfg->n >> 8, 7, 0); | ||
1075 | REG_FLD_MOD(av_base, HDMI_CORE_AV_N_SVAL3, cfg->n >> 16, 7, 0); | ||
1076 | |||
1077 | if (cfg->cts_mode == HDMI_AUDIO_CTS_MODE_SW) { | ||
1078 | REG_FLD_MOD(av_base, HDMI_CORE_AV_CTS_SVAL1, cfg->cts, 7, 0); | ||
1079 | REG_FLD_MOD(av_base, | ||
1080 | HDMI_CORE_AV_CTS_SVAL2, cfg->cts >> 8, 7, 0); | ||
1081 | REG_FLD_MOD(av_base, | ||
1082 | HDMI_CORE_AV_CTS_SVAL3, cfg->cts >> 16, 7, 0); | ||
1083 | } else { | ||
1084 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_1, | ||
1085 | cfg->aud_par_busclk, 7, 0); | ||
1086 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_2, | ||
1087 | (cfg->aud_par_busclk >> 8), 7, 0); | ||
1088 | REG_FLD_MOD(av_base, HDMI_CORE_AV_AUD_PAR_BUSCLK_3, | ||
1089 | (cfg->aud_par_busclk >> 16), 7, 0); | ||
1090 | } | ||
1091 | |||
1092 | /* Set ACR clock divisor */ | ||
1093 | REG_FLD_MOD(av_base, | ||
1094 | HDMI_CORE_AV_FREQ_SVAL, cfg->mclk_mode, 2, 0); | ||
1095 | |||
1096 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_ACR_CTRL); | ||
1097 | /* | ||
1098 | * Use TMDS clock for ACR packets. For devices that use | ||
1099 | * the MCLK, this is the first part of the MCLK initialization. | ||
1100 | */ | ||
1101 | r = FLD_MOD(r, 0, 2, 2); | ||
1102 | |||
1103 | r = FLD_MOD(r, cfg->en_acr_pkt, 1, 1); | ||
1104 | r = FLD_MOD(r, cfg->cts_mode, 0, 0); | ||
1105 | hdmi_write_reg(av_base, HDMI_CORE_AV_ACR_CTRL, r); | ||
1106 | |||
1107 | /* For devices using MCLK, this completes its initialization. */ | ||
1108 | if (cfg->use_mclk) | ||
1109 | REG_FLD_MOD(av_base, HDMI_CORE_AV_ACR_CTRL, 1, 2, 2); | ||
1110 | |||
1111 | /* Override of SPDIF sample frequency with value in I2S_CHST4 */ | ||
1112 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SPDIF_CTRL, | ||
1113 | cfg->fs_override, 1, 1); | ||
1114 | |||
1115 | /* | ||
1116 | * Set IEC-60958-3 channel status word. It is passed to the IP | ||
1117 | * just as it is received. The user of the driver is responsible | ||
1118 | * for its contents. | ||
1119 | */ | ||
1120 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST0, | ||
1121 | cfg->iec60958_cfg->status[0]); | ||
1122 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST1, | ||
1123 | cfg->iec60958_cfg->status[1]); | ||
1124 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST2, | ||
1125 | cfg->iec60958_cfg->status[2]); | ||
1126 | /* yes, this is correct: status[3] goes to CHST4 register */ | ||
1127 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST4, | ||
1128 | cfg->iec60958_cfg->status[3]); | ||
1129 | /* yes, this is correct: status[4] goes to CHST5 register */ | ||
1130 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_CHST5, | ||
1131 | cfg->iec60958_cfg->status[4]); | ||
1132 | |||
1133 | /* set I2S parameters */ | ||
1134 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL); | ||
1135 | r = FLD_MOD(r, cfg->i2s_cfg.sck_edge_mode, 6, 6); | ||
1136 | r = FLD_MOD(r, cfg->i2s_cfg.vbit, 4, 4); | ||
1137 | r = FLD_MOD(r, cfg->i2s_cfg.justification, 2, 2); | ||
1138 | r = FLD_MOD(r, cfg->i2s_cfg.direction, 1, 1); | ||
1139 | r = FLD_MOD(r, cfg->i2s_cfg.shift, 0, 0); | ||
1140 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_CTRL, r); | ||
1141 | |||
1142 | REG_FLD_MOD(av_base, HDMI_CORE_AV_I2S_IN_LEN, | ||
1143 | cfg->i2s_cfg.in_length_bits, 3, 0); | ||
1144 | |||
1145 | /* Audio channels and mode parameters */ | ||
1146 | REG_FLD_MOD(av_base, HDMI_CORE_AV_HDMI_CTRL, cfg->layout, 2, 1); | ||
1147 | r = hdmi_read_reg(av_base, HDMI_CORE_AV_AUD_MODE); | ||
1148 | r = FLD_MOD(r, cfg->i2s_cfg.active_sds, 7, 4); | ||
1149 | r = FLD_MOD(r, cfg->en_dsd_audio, 3, 3); | ||
1150 | r = FLD_MOD(r, cfg->en_parallel_aud_input, 2, 2); | ||
1151 | r = FLD_MOD(r, cfg->en_spdif, 1, 1); | ||
1152 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_MODE, r); | ||
1153 | |||
1154 | /* Audio channel mappings */ | ||
1155 | /* TODO: Make channel mapping dynamic. For now, map channels | ||
1156 | * in the ALSA order: FL/FR/RL/RR/C/LFE/SL/SR. Remapping is needed as | ||
1157 | * HDMI speaker order is different. See CEA-861 Section 6.6.2. | ||
1158 | */ | ||
1159 | hdmi_write_reg(av_base, HDMI_CORE_AV_I2S_IN_MAP, 0x78); | ||
1160 | REG_FLD_MOD(av_base, HDMI_CORE_AV_SWAP_I2S, 1, 5, 5); | ||
1161 | } | ||
1162 | |||
1163 | static void ti_hdmi_4xxx_core_audio_infoframe_cfg(struct hdmi_ip_data *ip_data, | ||
1164 | struct snd_cea_861_aud_if *info_aud) | ||
1165 | { | ||
1166 | u8 sum = 0, checksum = 0; | ||
1167 | void __iomem *av_base = hdmi_av_base(ip_data); | ||
1168 | |||
1169 | /* | ||
1170 | * Set audio info frame type, version and length as | ||
1171 | * described in HDMI 1.4a Section 8.2.2 specification. | ||
1172 | * Checksum calculation is defined in Section 5.3.5. | ||
1173 | */ | ||
1174 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_TYPE, 0x84); | ||
1175 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_VERS, 0x01); | ||
1176 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUDIO_LEN, 0x0a); | ||
1177 | sum += 0x84 + 0x001 + 0x00a; | ||
1178 | |||
1179 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(0), | ||
1180 | info_aud->db1_ct_cc); | ||
1181 | sum += info_aud->db1_ct_cc; | ||
1182 | |||
1183 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(1), | ||
1184 | info_aud->db2_sf_ss); | ||
1185 | sum += info_aud->db2_sf_ss; | ||
1186 | |||
1187 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(2), info_aud->db3); | ||
1188 | sum += info_aud->db3; | ||
1189 | |||
1190 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(3), info_aud->db4_ca); | ||
1191 | sum += info_aud->db4_ca; | ||
1192 | |||
1193 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(4), | ||
1194 | info_aud->db5_dminh_lsv); | ||
1195 | sum += info_aud->db5_dminh_lsv; | ||
1196 | |||
1197 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(5), 0x00); | ||
1198 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(6), 0x00); | ||
1199 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(7), 0x00); | ||
1200 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(8), 0x00); | ||
1201 | hdmi_write_reg(av_base, HDMI_CORE_AV_AUD_DBYTE(9), 0x00); | ||
1202 | |||
1203 | checksum = 0x100 - sum; | ||
1204 | hdmi_write_reg(av_base, | ||
1205 | HDMI_CORE_AV_AUDIO_CHSUM, checksum); | ||
1206 | |||
1207 | /* | ||
1208 | * TODO: Add MPEG and SPD enable and repeat cfg when EDID parsing | ||
1209 | * is available. | ||
1210 | */ | ||
1211 | } | ||
1212 | |||
1213 | int ti_hdmi_4xxx_audio_config(struct hdmi_ip_data *ip_data, | ||
1214 | struct omap_dss_audio *audio) | ||
1215 | { | ||
1216 | struct hdmi_audio_format audio_format; | ||
1217 | struct hdmi_audio_dma audio_dma; | ||
1218 | struct hdmi_core_audio_config core; | ||
1219 | int err, n, cts, channel_count; | ||
1220 | unsigned int fs_nr; | ||
1221 | bool word_length_16b = false; | ||
1222 | |||
1223 | if (!audio || !audio->iec || !audio->cea || !ip_data) | ||
1224 | return -EINVAL; | ||
1225 | |||
1226 | core.iec60958_cfg = audio->iec; | ||
1227 | /* | ||
1228 | * In the IEC-60958 status word, check if the audio sample word length | ||
1229 | * is 16-bit as several optimizations can be performed in such case. | ||
1230 | */ | ||
1231 | if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24)) | ||
1232 | if (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16) | ||
1233 | word_length_16b = true; | ||
1234 | |||
1235 | /* I2S configuration. See Phillips' specification */ | ||
1236 | if (word_length_16b) | ||
1237 | core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1238 | else | ||
1239 | core.i2s_cfg.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1240 | /* | ||
1241 | * The I2S input word length is twice the lenght given in the IEC-60958 | ||
1242 | * status word. If the word size is greater than | ||
1243 | * 20 bits, increment by one. | ||
1244 | */ | ||
1245 | core.i2s_cfg.in_length_bits = audio->iec->status[4] | ||
1246 | & IEC958_AES4_CON_WORDLEN; | ||
1247 | if (audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) | ||
1248 | core.i2s_cfg.in_length_bits++; | ||
1249 | core.i2s_cfg.sck_edge_mode = HDMI_AUDIO_I2S_SCK_EDGE_RISING; | ||
1250 | core.i2s_cfg.vbit = HDMI_AUDIO_I2S_VBIT_FOR_PCM; | ||
1251 | core.i2s_cfg.direction = HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST; | ||
1252 | core.i2s_cfg.shift = HDMI_AUDIO_I2S_FIRST_BIT_SHIFT; | ||
1253 | |||
1254 | /* convert sample frequency to a number */ | ||
1255 | switch (audio->iec->status[3] & IEC958_AES3_CON_FS) { | ||
1256 | case IEC958_AES3_CON_FS_32000: | ||
1257 | fs_nr = 32000; | ||
1258 | break; | ||
1259 | case IEC958_AES3_CON_FS_44100: | ||
1260 | fs_nr = 44100; | ||
1261 | break; | ||
1262 | case IEC958_AES3_CON_FS_48000: | ||
1263 | fs_nr = 48000; | ||
1264 | break; | ||
1265 | case IEC958_AES3_CON_FS_88200: | ||
1266 | fs_nr = 88200; | ||
1267 | break; | ||
1268 | case IEC958_AES3_CON_FS_96000: | ||
1269 | fs_nr = 96000; | ||
1270 | break; | ||
1271 | case IEC958_AES3_CON_FS_176400: | ||
1272 | fs_nr = 176400; | ||
1273 | break; | ||
1274 | case IEC958_AES3_CON_FS_192000: | ||
1275 | fs_nr = 192000; | ||
1276 | break; | ||
1277 | default: | ||
1278 | return -EINVAL; | ||
1279 | } | ||
1280 | |||
1281 | err = hdmi_compute_acr(fs_nr, &n, &cts); | ||
1282 | |||
1283 | /* Audio clock regeneration settings */ | ||
1284 | core.n = n; | ||
1285 | core.cts = cts; | ||
1286 | if (dss_has_feature(FEAT_HDMI_CTS_SWMODE)) { | ||
1287 | core.aud_par_busclk = 0; | ||
1288 | core.cts_mode = HDMI_AUDIO_CTS_MODE_SW; | ||
1289 | core.use_mclk = dss_has_feature(FEAT_HDMI_AUDIO_USE_MCLK); | ||
1290 | } else { | ||
1291 | core.aud_par_busclk = (((128 * 31) - 1) << 8); | ||
1292 | core.cts_mode = HDMI_AUDIO_CTS_MODE_HW; | ||
1293 | core.use_mclk = true; | ||
1294 | } | ||
1295 | |||
1296 | if (core.use_mclk) | ||
1297 | core.mclk_mode = HDMI_AUDIO_MCLK_128FS; | ||
1298 | |||
1299 | /* Audio channels settings */ | ||
1300 | channel_count = (audio->cea->db1_ct_cc & | ||
1301 | CEA861_AUDIO_INFOFRAME_DB1CC) + 1; | ||
1302 | |||
1303 | switch (channel_count) { | ||
1304 | case 2: | ||
1305 | audio_format.active_chnnls_msk = 0x03; | ||
1306 | break; | ||
1307 | case 3: | ||
1308 | audio_format.active_chnnls_msk = 0x07; | ||
1309 | break; | ||
1310 | case 4: | ||
1311 | audio_format.active_chnnls_msk = 0x0f; | ||
1312 | break; | ||
1313 | case 5: | ||
1314 | audio_format.active_chnnls_msk = 0x1f; | ||
1315 | break; | ||
1316 | case 6: | ||
1317 | audio_format.active_chnnls_msk = 0x3f; | ||
1318 | break; | ||
1319 | case 7: | ||
1320 | audio_format.active_chnnls_msk = 0x7f; | ||
1321 | break; | ||
1322 | case 8: | ||
1323 | audio_format.active_chnnls_msk = 0xff; | ||
1324 | break; | ||
1325 | default: | ||
1326 | return -EINVAL; | ||
1327 | } | ||
1328 | |||
1329 | /* | ||
1330 | * the HDMI IP needs to enable four stereo channels when transmitting | ||
1331 | * more than 2 audio channels | ||
1332 | */ | ||
1333 | if (channel_count == 2) { | ||
1334 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_ONECHANNEL; | ||
1335 | core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN; | ||
1336 | core.layout = HDMI_AUDIO_LAYOUT_2CH; | ||
1337 | } else { | ||
1338 | audio_format.stereo_channels = HDMI_AUDIO_STEREO_FOURCHANNELS; | ||
1339 | core.i2s_cfg.active_sds = HDMI_AUDIO_I2S_SD0_EN | | ||
1340 | HDMI_AUDIO_I2S_SD1_EN | HDMI_AUDIO_I2S_SD2_EN | | ||
1341 | HDMI_AUDIO_I2S_SD3_EN; | ||
1342 | core.layout = HDMI_AUDIO_LAYOUT_8CH; | ||
1343 | } | ||
1344 | |||
1345 | core.en_spdif = false; | ||
1346 | /* use sample frequency from channel status word */ | ||
1347 | core.fs_override = true; | ||
1348 | /* enable ACR packets */ | ||
1349 | core.en_acr_pkt = true; | ||
1350 | /* disable direct streaming digital audio */ | ||
1351 | core.en_dsd_audio = false; | ||
1352 | /* use parallel audio interface */ | ||
1353 | core.en_parallel_aud_input = true; | ||
1354 | |||
1355 | /* DMA settings */ | ||
1356 | if (word_length_16b) | ||
1357 | audio_dma.transfer_size = 0x10; | ||
1358 | else | ||
1359 | audio_dma.transfer_size = 0x20; | ||
1360 | audio_dma.block_size = 0xC0; | ||
1361 | audio_dma.mode = HDMI_AUDIO_TRANSF_DMA; | ||
1362 | audio_dma.fifo_threshold = 0x20; /* in number of samples */ | ||
1363 | |||
1364 | /* audio FIFO format settings */ | ||
1365 | if (word_length_16b) { | ||
1366 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES; | ||
1367 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS; | ||
1368 | audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT; | ||
1369 | } else { | ||
1370 | audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_ONESAMPLE; | ||
1371 | audio_format.sample_size = HDMI_AUDIO_SAMPLE_24BITS; | ||
1372 | audio_format.justification = HDMI_AUDIO_JUSTIFY_RIGHT; | ||
1373 | } | ||
1374 | audio_format.type = HDMI_AUDIO_TYPE_LPCM; | ||
1375 | audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST; | ||
1376 | /* disable start/stop signals of IEC 60958 blocks */ | ||
1377 | audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON; | ||
1378 | |||
1379 | /* configure DMA and audio FIFO format*/ | ||
1380 | ti_hdmi_4xxx_wp_audio_config_dma(ip_data, &audio_dma); | ||
1381 | ti_hdmi_4xxx_wp_audio_config_format(ip_data, &audio_format); | ||
1382 | |||
1383 | /* configure the core*/ | ||
1384 | ti_hdmi_4xxx_core_audio_config(ip_data, &core); | ||
1385 | |||
1386 | /* configure CEA 861 audio infoframe*/ | ||
1387 | ti_hdmi_4xxx_core_audio_infoframe_cfg(ip_data, audio->cea); | ||
1388 | |||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | int ti_hdmi_4xxx_wp_audio_enable(struct hdmi_ip_data *ip_data) | ||
1393 | { | ||
1394 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1395 | HDMI_WP_AUDIO_CTRL, true, 31, 31); | ||
1396 | return 0; | ||
1397 | } | ||
1398 | |||
1399 | void ti_hdmi_4xxx_wp_audio_disable(struct hdmi_ip_data *ip_data) | ||
1400 | { | ||
1401 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1402 | HDMI_WP_AUDIO_CTRL, false, 31, 31); | ||
1403 | } | ||
1404 | |||
1405 | int ti_hdmi_4xxx_audio_start(struct hdmi_ip_data *ip_data) | ||
1406 | { | ||
1407 | REG_FLD_MOD(hdmi_av_base(ip_data), | ||
1408 | HDMI_CORE_AV_AUD_MODE, true, 0, 0); | ||
1409 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1410 | HDMI_WP_AUDIO_CTRL, true, 30, 30); | ||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1414 | void ti_hdmi_4xxx_audio_stop(struct hdmi_ip_data *ip_data) | ||
1415 | { | ||
1416 | REG_FLD_MOD(hdmi_av_base(ip_data), | ||
1417 | HDMI_CORE_AV_AUD_MODE, false, 0, 0); | ||
1418 | REG_FLD_MOD(hdmi_wp_base(ip_data), | ||
1419 | HDMI_WP_AUDIO_CTRL, false, 30, 30); | ||
1420 | } | ||
1421 | |||
1422 | int ti_hdmi_4xxx_audio_get_dma_port(u32 *offset, u32 *size) | ||
1423 | { | ||
1424 | if (!offset || !size) | ||
1425 | return -EINVAL; | ||
1426 | *offset = HDMI_WP_AUDIO_DATA; | ||
1427 | *size = 4; | ||
1428 | return 0; | ||
1429 | } | ||
1430 | #endif | ||
diff --git a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h b/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h deleted file mode 100644 index 8366ae19e82..00000000000 --- a/drivers/video/omap2/dss/ti_hdmi_4xxx_ip.h +++ /dev/null | |||
@@ -1,436 +0,0 @@ | |||
1 | /* | ||
2 | * ti_hdmi_4xxx_ip.h | ||
3 | * | ||
4 | * HDMI header definition for DM81xx, DM38xx, TI OMAP4 etc processors. | ||
5 | * | ||
6 | * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
15 | * more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License along with | ||
18 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
19 | */ | ||
20 | |||
21 | #ifndef _HDMI_TI_4xxx_H_ | ||
22 | #define _HDMI_TI_4xxx_H_ | ||
23 | |||
24 | #include <linux/string.h> | ||
25 | #include <video/omapdss.h> | ||
26 | #include "ti_hdmi.h" | ||
27 | |||
28 | /* HDMI Wrapper */ | ||
29 | |||
30 | #define HDMI_WP_REVISION 0x0 | ||
31 | #define HDMI_WP_SYSCONFIG 0x10 | ||
32 | #define HDMI_WP_IRQSTATUS_RAW 0x24 | ||
33 | #define HDMI_WP_IRQSTATUS 0x28 | ||
34 | #define HDMI_WP_PWR_CTRL 0x40 | ||
35 | #define HDMI_WP_IRQENABLE_SET 0x2C | ||
36 | #define HDMI_WP_VIDEO_CFG 0x50 | ||
37 | #define HDMI_WP_VIDEO_SIZE 0x60 | ||
38 | #define HDMI_WP_VIDEO_TIMING_H 0x68 | ||
39 | #define HDMI_WP_VIDEO_TIMING_V 0x6C | ||
40 | #define HDMI_WP_WP_CLK 0x70 | ||
41 | #define HDMI_WP_AUDIO_CFG 0x80 | ||
42 | #define HDMI_WP_AUDIO_CFG2 0x84 | ||
43 | #define HDMI_WP_AUDIO_CTRL 0x88 | ||
44 | #define HDMI_WP_AUDIO_DATA 0x8C | ||
45 | |||
46 | /* HDMI IP Core System */ | ||
47 | |||
48 | #define HDMI_CORE_SYS_VND_IDL 0x0 | ||
49 | #define HDMI_CORE_SYS_DEV_IDL 0x8 | ||
50 | #define HDMI_CORE_SYS_DEV_IDH 0xC | ||
51 | #define HDMI_CORE_SYS_DEV_REV 0x10 | ||
52 | #define HDMI_CORE_SYS_SRST 0x14 | ||
53 | #define HDMI_CORE_CTRL1 0x20 | ||
54 | #define HDMI_CORE_SYS_SYS_STAT 0x24 | ||
55 | #define HDMI_CORE_SYS_DE_DLY 0xC8 | ||
56 | #define HDMI_CORE_SYS_DE_CTRL 0xCC | ||
57 | #define HDMI_CORE_SYS_DE_TOP 0xD0 | ||
58 | #define HDMI_CORE_SYS_DE_CNTL 0xD8 | ||
59 | #define HDMI_CORE_SYS_DE_CNTH 0xDC | ||
60 | #define HDMI_CORE_SYS_DE_LINL 0xE0 | ||
61 | #define HDMI_CORE_SYS_DE_LINH_1 0xE4 | ||
62 | #define HDMI_CORE_SYS_VID_ACEN 0x124 | ||
63 | #define HDMI_CORE_SYS_VID_MODE 0x128 | ||
64 | #define HDMI_CORE_SYS_INTR_STATE 0x1C0 | ||
65 | #define HDMI_CORE_SYS_INTR1 0x1C4 | ||
66 | #define HDMI_CORE_SYS_INTR2 0x1C8 | ||
67 | #define HDMI_CORE_SYS_INTR3 0x1CC | ||
68 | #define HDMI_CORE_SYS_INTR4 0x1D0 | ||
69 | #define HDMI_CORE_SYS_UMASK1 0x1D4 | ||
70 | #define HDMI_CORE_SYS_TMDS_CTRL 0x208 | ||
71 | |||
72 | #define HDMI_CORE_CTRL1_VEN_FOLLOWVSYNC 0x1 | ||
73 | #define HDMI_CORE_CTRL1_HEN_FOLLOWHSYNC 0x1 | ||
74 | #define HDMI_CORE_CTRL1_BSEL_24BITBUS 0x1 | ||
75 | #define HDMI_CORE_CTRL1_EDGE_RISINGEDGE 0x1 | ||
76 | |||
77 | /* HDMI DDC E-DID */ | ||
78 | #define HDMI_CORE_DDC_ADDR 0x3B4 | ||
79 | #define HDMI_CORE_DDC_SEGM 0x3B8 | ||
80 | #define HDMI_CORE_DDC_OFFSET 0x3BC | ||
81 | #define HDMI_CORE_DDC_COUNT1 0x3C0 | ||
82 | #define HDMI_CORE_DDC_COUNT2 0x3C4 | ||
83 | #define HDMI_CORE_DDC_STATUS 0x3C8 | ||
84 | #define HDMI_CORE_DDC_CMD 0x3CC | ||
85 | #define HDMI_CORE_DDC_DATA 0x3D0 | ||
86 | |||
87 | /* HDMI IP Core Audio Video */ | ||
88 | |||
89 | #define HDMI_CORE_AV_ACR_CTRL 0x4 | ||
90 | #define HDMI_CORE_AV_FREQ_SVAL 0x8 | ||
91 | #define HDMI_CORE_AV_N_SVAL1 0xC | ||
92 | #define HDMI_CORE_AV_N_SVAL2 0x10 | ||
93 | #define HDMI_CORE_AV_N_SVAL3 0x14 | ||
94 | #define HDMI_CORE_AV_CTS_SVAL1 0x18 | ||
95 | #define HDMI_CORE_AV_CTS_SVAL2 0x1C | ||
96 | #define HDMI_CORE_AV_CTS_SVAL3 0x20 | ||
97 | #define HDMI_CORE_AV_CTS_HVAL1 0x24 | ||
98 | #define HDMI_CORE_AV_CTS_HVAL2 0x28 | ||
99 | #define HDMI_CORE_AV_CTS_HVAL3 0x2C | ||
100 | #define HDMI_CORE_AV_AUD_MODE 0x50 | ||
101 | #define HDMI_CORE_AV_SPDIF_CTRL 0x54 | ||
102 | #define HDMI_CORE_AV_HW_SPDIF_FS 0x60 | ||
103 | #define HDMI_CORE_AV_SWAP_I2S 0x64 | ||
104 | #define HDMI_CORE_AV_SPDIF_ERTH 0x6C | ||
105 | #define HDMI_CORE_AV_I2S_IN_MAP 0x70 | ||
106 | #define HDMI_CORE_AV_I2S_IN_CTRL 0x74 | ||
107 | #define HDMI_CORE_AV_I2S_CHST0 0x78 | ||
108 | #define HDMI_CORE_AV_I2S_CHST1 0x7C | ||
109 | #define HDMI_CORE_AV_I2S_CHST2 0x80 | ||
110 | #define HDMI_CORE_AV_I2S_CHST4 0x84 | ||
111 | #define HDMI_CORE_AV_I2S_CHST5 0x88 | ||
112 | #define HDMI_CORE_AV_ASRC 0x8C | ||
113 | #define HDMI_CORE_AV_I2S_IN_LEN 0x90 | ||
114 | #define HDMI_CORE_AV_HDMI_CTRL 0xBC | ||
115 | #define HDMI_CORE_AV_AUDO_TXSTAT 0xC0 | ||
116 | #define HDMI_CORE_AV_AUD_PAR_BUSCLK_1 0xCC | ||
117 | #define HDMI_CORE_AV_AUD_PAR_BUSCLK_2 0xD0 | ||
118 | #define HDMI_CORE_AV_AUD_PAR_BUSCLK_3 0xD4 | ||
119 | #define HDMI_CORE_AV_TEST_TXCTRL 0xF0 | ||
120 | #define HDMI_CORE_AV_DPD 0xF4 | ||
121 | #define HDMI_CORE_AV_PB_CTRL1 0xF8 | ||
122 | #define HDMI_CORE_AV_PB_CTRL2 0xFC | ||
123 | #define HDMI_CORE_AV_AVI_TYPE 0x100 | ||
124 | #define HDMI_CORE_AV_AVI_VERS 0x104 | ||
125 | #define HDMI_CORE_AV_AVI_LEN 0x108 | ||
126 | #define HDMI_CORE_AV_AVI_CHSUM 0x10C | ||
127 | #define HDMI_CORE_AV_AVI_DBYTE(n) (n * 4 + 0x110) | ||
128 | #define HDMI_CORE_AV_SPD_TYPE 0x180 | ||
129 | #define HDMI_CORE_AV_SPD_VERS 0x184 | ||
130 | #define HDMI_CORE_AV_SPD_LEN 0x188 | ||
131 | #define HDMI_CORE_AV_SPD_CHSUM 0x18C | ||
132 | #define HDMI_CORE_AV_SPD_DBYTE(n) (n * 4 + 0x190) | ||
133 | #define HDMI_CORE_AV_AUDIO_TYPE 0x200 | ||
134 | #define HDMI_CORE_AV_AUDIO_VERS 0x204 | ||
135 | #define HDMI_CORE_AV_AUDIO_LEN 0x208 | ||
136 | #define HDMI_CORE_AV_AUDIO_CHSUM 0x20C | ||
137 | #define HDMI_CORE_AV_AUD_DBYTE(n) (n * 4 + 0x210) | ||
138 | #define HDMI_CORE_AV_MPEG_TYPE 0x280 | ||
139 | #define HDMI_CORE_AV_MPEG_VERS 0x284 | ||
140 | #define HDMI_CORE_AV_MPEG_LEN 0x288 | ||
141 | #define HDMI_CORE_AV_MPEG_CHSUM 0x28C | ||
142 | #define HDMI_CORE_AV_MPEG_DBYTE(n) (n * 4 + 0x290) | ||
143 | #define HDMI_CORE_AV_GEN_DBYTE(n) (n * 4 + 0x300) | ||
144 | #define HDMI_CORE_AV_CP_BYTE1 0x37C | ||
145 | #define HDMI_CORE_AV_GEN2_DBYTE(n) (n * 4 + 0x380) | ||
146 | #define HDMI_CORE_AV_CEC_ADDR_ID 0x3FC | ||
147 | |||
148 | #define HDMI_CORE_AV_SPD_DBYTE_ELSIZE 0x4 | ||
149 | #define HDMI_CORE_AV_GEN2_DBYTE_ELSIZE 0x4 | ||
150 | #define HDMI_CORE_AV_MPEG_DBYTE_ELSIZE 0x4 | ||
151 | #define HDMI_CORE_AV_GEN_DBYTE_ELSIZE 0x4 | ||
152 | |||
153 | #define HDMI_CORE_AV_AVI_DBYTE_NELEMS 15 | ||
154 | #define HDMI_CORE_AV_SPD_DBYTE_NELEMS 27 | ||
155 | #define HDMI_CORE_AV_AUD_DBYTE_NELEMS 10 | ||
156 | #define HDMI_CORE_AV_MPEG_DBYTE_NELEMS 27 | ||
157 | #define HDMI_CORE_AV_GEN_DBYTE_NELEMS 31 | ||
158 | #define HDMI_CORE_AV_GEN2_DBYTE_NELEMS 31 | ||
159 | |||
160 | /* PLL */ | ||
161 | |||
162 | #define PLLCTRL_PLL_CONTROL 0x0 | ||
163 | #define PLLCTRL_PLL_STATUS 0x4 | ||
164 | #define PLLCTRL_PLL_GO 0x8 | ||
165 | #define PLLCTRL_CFG1 0xC | ||
166 | #define PLLCTRL_CFG2 0x10 | ||
167 | #define PLLCTRL_CFG3 0x14 | ||
168 | #define PLLCTRL_CFG4 0x20 | ||
169 | |||
170 | /* HDMI PHY */ | ||
171 | |||
172 | #define HDMI_TXPHY_TX_CTRL 0x0 | ||
173 | #define HDMI_TXPHY_DIGITAL_CTRL 0x4 | ||
174 | #define HDMI_TXPHY_POWER_CTRL 0x8 | ||
175 | #define HDMI_TXPHY_PAD_CFG_CTRL 0xC | ||
176 | |||
177 | #define REG_FLD_MOD(base, idx, val, start, end) \ | ||
178 | hdmi_write_reg(base, idx, FLD_MOD(hdmi_read_reg(base, idx),\ | ||
179 | val, start, end)) | ||
180 | #define REG_GET(base, idx, start, end) \ | ||
181 | FLD_GET(hdmi_read_reg(base, idx), start, end) | ||
182 | |||
183 | enum hdmi_phy_pwr { | ||
184 | HDMI_PHYPWRCMD_OFF = 0, | ||
185 | HDMI_PHYPWRCMD_LDOON = 1, | ||
186 | HDMI_PHYPWRCMD_TXON = 2 | ||
187 | }; | ||
188 | |||
189 | enum hdmi_core_inputbus_width { | ||
190 | HDMI_INPUT_8BIT = 0, | ||
191 | HDMI_INPUT_10BIT = 1, | ||
192 | HDMI_INPUT_12BIT = 2 | ||
193 | }; | ||
194 | |||
195 | enum hdmi_core_dither_trunc { | ||
196 | HDMI_OUTPUTTRUNCATION_8BIT = 0, | ||
197 | HDMI_OUTPUTTRUNCATION_10BIT = 1, | ||
198 | HDMI_OUTPUTTRUNCATION_12BIT = 2, | ||
199 | HDMI_OUTPUTDITHER_8BIT = 3, | ||
200 | HDMI_OUTPUTDITHER_10BIT = 4, | ||
201 | HDMI_OUTPUTDITHER_12BIT = 5 | ||
202 | }; | ||
203 | |||
204 | enum hdmi_core_deepcolor_ed { | ||
205 | HDMI_DEEPCOLORPACKECTDISABLE = 0, | ||
206 | HDMI_DEEPCOLORPACKECTENABLE = 1 | ||
207 | }; | ||
208 | |||
209 | enum hdmi_core_packet_mode { | ||
210 | HDMI_PACKETMODERESERVEDVALUE = 0, | ||
211 | HDMI_PACKETMODE24BITPERPIXEL = 4, | ||
212 | HDMI_PACKETMODE30BITPERPIXEL = 5, | ||
213 | HDMI_PACKETMODE36BITPERPIXEL = 6, | ||
214 | HDMI_PACKETMODE48BITPERPIXEL = 7 | ||
215 | }; | ||
216 | |||
217 | enum hdmi_core_tclkselclkmult { | ||
218 | HDMI_FPLL05IDCK = 0, | ||
219 | HDMI_FPLL10IDCK = 1, | ||
220 | HDMI_FPLL20IDCK = 2, | ||
221 | HDMI_FPLL40IDCK = 3 | ||
222 | }; | ||
223 | |||
224 | enum hdmi_core_packet_ctrl { | ||
225 | HDMI_PACKETENABLE = 1, | ||
226 | HDMI_PACKETDISABLE = 0, | ||
227 | HDMI_PACKETREPEATON = 1, | ||
228 | HDMI_PACKETREPEATOFF = 0 | ||
229 | }; | ||
230 | |||
231 | /* INFOFRAME_AVI_ and INFOFRAME_AUDIO_ definitions */ | ||
232 | enum hdmi_core_infoframe { | ||
233 | HDMI_INFOFRAME_AVI_DB1Y_RGB = 0, | ||
234 | HDMI_INFOFRAME_AVI_DB1Y_YUV422 = 1, | ||
235 | HDMI_INFOFRAME_AVI_DB1Y_YUV444 = 2, | ||
236 | HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF = 0, | ||
237 | HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_ON = 1, | ||
238 | HDMI_INFOFRAME_AVI_DB1B_NO = 0, | ||
239 | HDMI_INFOFRAME_AVI_DB1B_VERT = 1, | ||
240 | HDMI_INFOFRAME_AVI_DB1B_HORI = 2, | ||
241 | HDMI_INFOFRAME_AVI_DB1B_VERTHORI = 3, | ||
242 | HDMI_INFOFRAME_AVI_DB1S_0 = 0, | ||
243 | HDMI_INFOFRAME_AVI_DB1S_1 = 1, | ||
244 | HDMI_INFOFRAME_AVI_DB1S_2 = 2, | ||
245 | HDMI_INFOFRAME_AVI_DB2C_NO = 0, | ||
246 | HDMI_INFOFRAME_AVI_DB2C_ITU601 = 1, | ||
247 | HDMI_INFOFRAME_AVI_DB2C_ITU709 = 2, | ||
248 | HDMI_INFOFRAME_AVI_DB2C_EC_EXTENDED = 3, | ||
249 | HDMI_INFOFRAME_AVI_DB2M_NO = 0, | ||
250 | HDMI_INFOFRAME_AVI_DB2M_43 = 1, | ||
251 | HDMI_INFOFRAME_AVI_DB2M_169 = 2, | ||
252 | HDMI_INFOFRAME_AVI_DB2R_SAME = 8, | ||
253 | HDMI_INFOFRAME_AVI_DB2R_43 = 9, | ||
254 | HDMI_INFOFRAME_AVI_DB2R_169 = 10, | ||
255 | HDMI_INFOFRAME_AVI_DB2R_149 = 11, | ||
256 | HDMI_INFOFRAME_AVI_DB3ITC_NO = 0, | ||
257 | HDMI_INFOFRAME_AVI_DB3ITC_YES = 1, | ||
258 | HDMI_INFOFRAME_AVI_DB3EC_XVYUV601 = 0, | ||
259 | HDMI_INFOFRAME_AVI_DB3EC_XVYUV709 = 1, | ||
260 | HDMI_INFOFRAME_AVI_DB3Q_DEFAULT = 0, | ||
261 | HDMI_INFOFRAME_AVI_DB3Q_LR = 1, | ||
262 | HDMI_INFOFRAME_AVI_DB3Q_FR = 2, | ||
263 | HDMI_INFOFRAME_AVI_DB3SC_NO = 0, | ||
264 | HDMI_INFOFRAME_AVI_DB3SC_HORI = 1, | ||
265 | HDMI_INFOFRAME_AVI_DB3SC_VERT = 2, | ||
266 | HDMI_INFOFRAME_AVI_DB3SC_HORIVERT = 3, | ||
267 | HDMI_INFOFRAME_AVI_DB5PR_NO = 0, | ||
268 | HDMI_INFOFRAME_AVI_DB5PR_2 = 1, | ||
269 | HDMI_INFOFRAME_AVI_DB5PR_3 = 2, | ||
270 | HDMI_INFOFRAME_AVI_DB5PR_4 = 3, | ||
271 | HDMI_INFOFRAME_AVI_DB5PR_5 = 4, | ||
272 | HDMI_INFOFRAME_AVI_DB5PR_6 = 5, | ||
273 | HDMI_INFOFRAME_AVI_DB5PR_7 = 6, | ||
274 | HDMI_INFOFRAME_AVI_DB5PR_8 = 7, | ||
275 | HDMI_INFOFRAME_AVI_DB5PR_9 = 8, | ||
276 | HDMI_INFOFRAME_AVI_DB5PR_10 = 9, | ||
277 | }; | ||
278 | |||
279 | enum hdmi_packing_mode { | ||
280 | HDMI_PACK_10b_RGB_YUV444 = 0, | ||
281 | HDMI_PACK_24b_RGB_YUV444_YUV422 = 1, | ||
282 | HDMI_PACK_20b_YUV422 = 2, | ||
283 | HDMI_PACK_ALREADYPACKED = 7 | ||
284 | }; | ||
285 | |||
286 | enum hdmi_core_audio_layout { | ||
287 | HDMI_AUDIO_LAYOUT_2CH = 0, | ||
288 | HDMI_AUDIO_LAYOUT_8CH = 1 | ||
289 | }; | ||
290 | |||
291 | enum hdmi_core_cts_mode { | ||
292 | HDMI_AUDIO_CTS_MODE_HW = 0, | ||
293 | HDMI_AUDIO_CTS_MODE_SW = 1 | ||
294 | }; | ||
295 | |||
296 | enum hdmi_stereo_channels { | ||
297 | HDMI_AUDIO_STEREO_NOCHANNELS = 0, | ||
298 | HDMI_AUDIO_STEREO_ONECHANNEL = 1, | ||
299 | HDMI_AUDIO_STEREO_TWOCHANNELS = 2, | ||
300 | HDMI_AUDIO_STEREO_THREECHANNELS = 3, | ||
301 | HDMI_AUDIO_STEREO_FOURCHANNELS = 4 | ||
302 | }; | ||
303 | |||
304 | enum hdmi_audio_type { | ||
305 | HDMI_AUDIO_TYPE_LPCM = 0, | ||
306 | HDMI_AUDIO_TYPE_IEC = 1 | ||
307 | }; | ||
308 | |||
309 | enum hdmi_audio_justify { | ||
310 | HDMI_AUDIO_JUSTIFY_LEFT = 0, | ||
311 | HDMI_AUDIO_JUSTIFY_RIGHT = 1 | ||
312 | }; | ||
313 | |||
314 | enum hdmi_audio_sample_order { | ||
315 | HDMI_AUDIO_SAMPLE_RIGHT_FIRST = 0, | ||
316 | HDMI_AUDIO_SAMPLE_LEFT_FIRST = 1 | ||
317 | }; | ||
318 | |||
319 | enum hdmi_audio_samples_perword { | ||
320 | HDMI_AUDIO_ONEWORD_ONESAMPLE = 0, | ||
321 | HDMI_AUDIO_ONEWORD_TWOSAMPLES = 1 | ||
322 | }; | ||
323 | |||
324 | enum hdmi_audio_sample_size { | ||
325 | HDMI_AUDIO_SAMPLE_16BITS = 0, | ||
326 | HDMI_AUDIO_SAMPLE_24BITS = 1 | ||
327 | }; | ||
328 | |||
329 | enum hdmi_audio_transf_mode { | ||
330 | HDMI_AUDIO_TRANSF_DMA = 0, | ||
331 | HDMI_AUDIO_TRANSF_IRQ = 1 | ||
332 | }; | ||
333 | |||
334 | enum hdmi_audio_blk_strt_end_sig { | ||
335 | HDMI_AUDIO_BLOCK_SIG_STARTEND_ON = 0, | ||
336 | HDMI_AUDIO_BLOCK_SIG_STARTEND_OFF = 1 | ||
337 | }; | ||
338 | |||
339 | enum hdmi_audio_i2s_config { | ||
340 | HDMI_AUDIO_I2S_MSB_SHIFTED_FIRST = 0, | ||
341 | HDMI_AUDIO_I2S_LSB_SHIFTED_FIRST = 1, | ||
342 | HDMI_AUDIO_I2S_SCK_EDGE_FALLING = 0, | ||
343 | HDMI_AUDIO_I2S_SCK_EDGE_RISING = 1, | ||
344 | HDMI_AUDIO_I2S_VBIT_FOR_PCM = 0, | ||
345 | HDMI_AUDIO_I2S_VBIT_FOR_COMPRESSED = 1, | ||
346 | HDMI_AUDIO_I2S_FIRST_BIT_SHIFT = 0, | ||
347 | HDMI_AUDIO_I2S_FIRST_BIT_NO_SHIFT = 1, | ||
348 | HDMI_AUDIO_I2S_SD0_EN = 1, | ||
349 | HDMI_AUDIO_I2S_SD1_EN = 1 << 1, | ||
350 | HDMI_AUDIO_I2S_SD2_EN = 1 << 2, | ||
351 | HDMI_AUDIO_I2S_SD3_EN = 1 << 3, | ||
352 | }; | ||
353 | |||
354 | enum hdmi_audio_mclk_mode { | ||
355 | HDMI_AUDIO_MCLK_128FS = 0, | ||
356 | HDMI_AUDIO_MCLK_256FS = 1, | ||
357 | HDMI_AUDIO_MCLK_384FS = 2, | ||
358 | HDMI_AUDIO_MCLK_512FS = 3, | ||
359 | HDMI_AUDIO_MCLK_768FS = 4, | ||
360 | HDMI_AUDIO_MCLK_1024FS = 5, | ||
361 | HDMI_AUDIO_MCLK_1152FS = 6, | ||
362 | HDMI_AUDIO_MCLK_192FS = 7 | ||
363 | }; | ||
364 | |||
365 | struct hdmi_core_video_config { | ||
366 | enum hdmi_core_inputbus_width ip_bus_width; | ||
367 | enum hdmi_core_dither_trunc op_dither_truc; | ||
368 | enum hdmi_core_deepcolor_ed deep_color_pkt; | ||
369 | enum hdmi_core_packet_mode pkt_mode; | ||
370 | enum hdmi_core_hdmi_dvi hdmi_dvi; | ||
371 | enum hdmi_core_tclkselclkmult tclk_sel_clkmult; | ||
372 | }; | ||
373 | |||
374 | struct hdmi_core_packet_enable_repeat { | ||
375 | u32 audio_pkt; | ||
376 | u32 audio_pkt_repeat; | ||
377 | u32 avi_infoframe; | ||
378 | u32 avi_infoframe_repeat; | ||
379 | u32 gen_cntrl_pkt; | ||
380 | u32 gen_cntrl_pkt_repeat; | ||
381 | u32 generic_pkt; | ||
382 | u32 generic_pkt_repeat; | ||
383 | }; | ||
384 | |||
385 | struct hdmi_video_format { | ||
386 | enum hdmi_packing_mode packing_mode; | ||
387 | u32 y_res; /* Line per panel */ | ||
388 | u32 x_res; /* pixel per line */ | ||
389 | }; | ||
390 | |||
391 | struct hdmi_audio_format { | ||
392 | enum hdmi_stereo_channels stereo_channels; | ||
393 | u8 active_chnnls_msk; | ||
394 | enum hdmi_audio_type type; | ||
395 | enum hdmi_audio_justify justification; | ||
396 | enum hdmi_audio_sample_order sample_order; | ||
397 | enum hdmi_audio_samples_perword samples_per_word; | ||
398 | enum hdmi_audio_sample_size sample_size; | ||
399 | enum hdmi_audio_blk_strt_end_sig en_sig_blk_strt_end; | ||
400 | }; | ||
401 | |||
402 | struct hdmi_audio_dma { | ||
403 | u8 transfer_size; | ||
404 | u8 block_size; | ||
405 | enum hdmi_audio_transf_mode mode; | ||
406 | u16 fifo_threshold; | ||
407 | }; | ||
408 | |||
409 | struct hdmi_core_audio_i2s_config { | ||
410 | u8 in_length_bits; | ||
411 | u8 justification; | ||
412 | u8 sck_edge_mode; | ||
413 | u8 vbit; | ||
414 | u8 direction; | ||
415 | u8 shift; | ||
416 | u8 active_sds; | ||
417 | }; | ||
418 | |||
419 | struct hdmi_core_audio_config { | ||
420 | struct hdmi_core_audio_i2s_config i2s_cfg; | ||
421 | struct snd_aes_iec958 *iec60958_cfg; | ||
422 | bool fs_override; | ||
423 | u32 n; | ||
424 | u32 cts; | ||
425 | u32 aud_par_busclk; | ||
426 | enum hdmi_core_audio_layout layout; | ||
427 | enum hdmi_core_cts_mode cts_mode; | ||
428 | bool use_mclk; | ||
429 | enum hdmi_audio_mclk_mode mclk_mode; | ||
430 | bool en_acr_pkt; | ||
431 | bool en_dsd_audio; | ||
432 | bool en_parallel_aud_input; | ||
433 | bool en_spdif; | ||
434 | }; | ||
435 | |||
436 | #endif | ||
diff --git a/drivers/video/omap2/dss/venc.c b/drivers/video/omap2/dss/venc.c index 006caf3cb50..173c66430da 100644 --- a/drivers/video/omap2/dss/venc.c +++ b/drivers/video/omap2/dss/venc.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
37 | 37 | ||
38 | #include <video/omapdss.h> | 38 | #include <video/omapdss.h> |
39 | #include <plat/cpu.h> | ||
39 | 40 | ||
40 | #include "dss.h" | 41 | #include "dss.h" |
41 | #include "dss_features.h" | 42 | #include "dss_features.h" |
@@ -271,8 +272,6 @@ const struct omap_video_timings omap_dss_pal_timings = { | |||
271 | .vsw = 5, | 272 | .vsw = 5, |
272 | .vfp = 5, | 273 | .vfp = 5, |
273 | .vbp = 41, | 274 | .vbp = 41, |
274 | |||
275 | .interlace = true, | ||
276 | }; | 275 | }; |
277 | EXPORT_SYMBOL(omap_dss_pal_timings); | 276 | EXPORT_SYMBOL(omap_dss_pal_timings); |
278 | 277 | ||
@@ -286,8 +285,6 @@ const struct omap_video_timings omap_dss_ntsc_timings = { | |||
286 | .vsw = 6, | 285 | .vsw = 6, |
287 | .vfp = 6, | 286 | .vfp = 6, |
288 | .vbp = 31, | 287 | .vbp = 31, |
289 | |||
290 | .interlace = true, | ||
291 | }; | 288 | }; |
292 | EXPORT_SYMBOL(omap_dss_ntsc_timings); | 289 | EXPORT_SYMBOL(omap_dss_ntsc_timings); |
293 | 290 | ||
@@ -298,13 +295,8 @@ static struct { | |||
298 | u32 wss_data; | 295 | u32 wss_data; |
299 | struct regulator *vdda_dac_reg; | 296 | struct regulator *vdda_dac_reg; |
300 | 297 | ||
298 | struct clk *tv_clk; | ||
301 | struct clk *tv_dac_clk; | 299 | struct clk *tv_dac_clk; |
302 | |||
303 | struct omap_video_timings timings; | ||
304 | enum omap_dss_venc_type type; | ||
305 | bool invert_polarity; | ||
306 | |||
307 | struct omap_dss_output output; | ||
308 | } venc; | 300 | } venc; |
309 | 301 | ||
310 | static inline void venc_write_reg(int idx, u32 val) | 302 | static inline void venc_write_reg(int idx, u32 val) |
@@ -410,8 +402,8 @@ static void venc_runtime_put(void) | |||
410 | 402 | ||
411 | DSSDBG("venc_runtime_put\n"); | 403 | DSSDBG("venc_runtime_put\n"); |
412 | 404 | ||
413 | r = pm_runtime_put_sync(&venc.pdev->dev); | 405 | r = pm_runtime_put(&venc.pdev->dev); |
414 | WARN_ON(r < 0 && r != -ENOSYS); | 406 | WARN_ON(r < 0); |
415 | } | 407 | } |
416 | 408 | ||
417 | static const struct venc_config *venc_timings_to_config( | 409 | static const struct venc_config *venc_timings_to_config( |
@@ -424,157 +416,171 @@ static const struct venc_config *venc_timings_to_config( | |||
424 | return &venc_config_ntsc_trm; | 416 | return &venc_config_ntsc_trm; |
425 | 417 | ||
426 | BUG(); | 418 | BUG(); |
427 | return NULL; | ||
428 | } | 419 | } |
429 | 420 | ||
430 | static int venc_power_on(struct omap_dss_device *dssdev) | 421 | static void venc_power_on(struct omap_dss_device *dssdev) |
431 | { | 422 | { |
432 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
433 | u32 l; | 423 | u32 l; |
434 | int r; | ||
435 | |||
436 | r = venc_runtime_get(); | ||
437 | if (r) | ||
438 | goto err0; | ||
439 | 424 | ||
440 | venc_reset(); | 425 | venc_reset(); |
441 | venc_write_config(venc_timings_to_config(&venc.timings)); | 426 | venc_write_config(venc_timings_to_config(&dssdev->panel.timings)); |
442 | 427 | ||
443 | dss_set_venc_output(venc.type); | 428 | dss_set_venc_output(dssdev->phy.venc.type); |
444 | dss_set_dac_pwrdn_bgz(1); | 429 | dss_set_dac_pwrdn_bgz(1); |
445 | 430 | ||
446 | l = 0; | 431 | l = 0; |
447 | 432 | ||
448 | if (venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) | 433 | if (dssdev->phy.venc.type == OMAP_DSS_VENC_TYPE_COMPOSITE) |
449 | l |= 1 << 1; | 434 | l |= 1 << 1; |
450 | else /* S-Video */ | 435 | else /* S-Video */ |
451 | l |= (1 << 0) | (1 << 2); | 436 | l |= (1 << 0) | (1 << 2); |
452 | 437 | ||
453 | if (venc.invert_polarity == false) | 438 | if (dssdev->phy.venc.invert_polarity == false) |
454 | l |= 1 << 3; | 439 | l |= 1 << 3; |
455 | 440 | ||
456 | venc_write_reg(VENC_OUTPUT_CONTROL, l); | 441 | venc_write_reg(VENC_OUTPUT_CONTROL, l); |
457 | 442 | ||
458 | dss_mgr_set_timings(mgr, &venc.timings); | 443 | dispc_set_digit_size(dssdev->panel.timings.x_res, |
444 | dssdev->panel.timings.y_res/2); | ||
459 | 445 | ||
460 | r = regulator_enable(venc.vdda_dac_reg); | 446 | regulator_enable(venc.vdda_dac_reg); |
461 | if (r) | ||
462 | goto err1; | ||
463 | |||
464 | r = dss_mgr_enable(mgr); | ||
465 | if (r) | ||
466 | goto err2; | ||
467 | |||
468 | return 0; | ||
469 | 447 | ||
470 | err2: | 448 | if (dssdev->platform_enable) |
471 | regulator_disable(venc.vdda_dac_reg); | 449 | dssdev->platform_enable(dssdev); |
472 | err1: | ||
473 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | ||
474 | dss_set_dac_pwrdn_bgz(0); | ||
475 | 450 | ||
476 | venc_runtime_put(); | 451 | dssdev->manager->enable(dssdev->manager); |
477 | err0: | ||
478 | return r; | ||
479 | } | 452 | } |
480 | 453 | ||
481 | static void venc_power_off(struct omap_dss_device *dssdev) | 454 | static void venc_power_off(struct omap_dss_device *dssdev) |
482 | { | 455 | { |
483 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
484 | |||
485 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); | 456 | venc_write_reg(VENC_OUTPUT_CONTROL, 0); |
486 | dss_set_dac_pwrdn_bgz(0); | 457 | dss_set_dac_pwrdn_bgz(0); |
487 | 458 | ||
488 | dss_mgr_disable(mgr); | 459 | dssdev->manager->disable(dssdev->manager); |
460 | |||
461 | if (dssdev->platform_disable) | ||
462 | dssdev->platform_disable(dssdev); | ||
489 | 463 | ||
490 | regulator_disable(venc.vdda_dac_reg); | 464 | regulator_disable(venc.vdda_dac_reg); |
465 | } | ||
491 | 466 | ||
492 | venc_runtime_put(); | 467 | |
468 | |||
469 | |||
470 | |||
471 | /* driver */ | ||
472 | static int venc_panel_probe(struct omap_dss_device *dssdev) | ||
473 | { | ||
474 | dssdev->panel.timings = omap_dss_pal_timings; | ||
475 | |||
476 | return 0; | ||
493 | } | 477 | } |
494 | 478 | ||
495 | unsigned long venc_get_pixel_clock(void) | 479 | static void venc_panel_remove(struct omap_dss_device *dssdev) |
496 | { | 480 | { |
497 | /* VENC Pixel Clock in Mhz */ | ||
498 | return 13500000; | ||
499 | } | 481 | } |
500 | 482 | ||
501 | int omapdss_venc_display_enable(struct omap_dss_device *dssdev) | 483 | static int venc_panel_enable(struct omap_dss_device *dssdev) |
502 | { | 484 | { |
503 | struct omap_dss_output *out = dssdev->output; | 485 | int r = 0; |
504 | int r; | ||
505 | 486 | ||
506 | DSSDBG("venc_display_enable\n"); | 487 | DSSDBG("venc_enable_display\n"); |
507 | 488 | ||
508 | mutex_lock(&venc.venc_lock); | 489 | mutex_lock(&venc.venc_lock); |
509 | 490 | ||
510 | if (out == NULL || out->manager == NULL) { | ||
511 | DSSERR("Failed to enable display: no output/manager\n"); | ||
512 | r = -ENODEV; | ||
513 | goto err0; | ||
514 | } | ||
515 | |||
516 | r = omap_dss_start_device(dssdev); | 491 | r = omap_dss_start_device(dssdev); |
517 | if (r) { | 492 | if (r) { |
518 | DSSERR("failed to start device\n"); | 493 | DSSERR("failed to start device\n"); |
519 | goto err0; | 494 | goto err0; |
520 | } | 495 | } |
521 | 496 | ||
522 | if (dssdev->platform_enable) | 497 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { |
523 | dssdev->platform_enable(dssdev); | 498 | r = -EINVAL; |
524 | 499 | goto err1; | |
500 | } | ||
525 | 501 | ||
526 | r = venc_power_on(dssdev); | 502 | r = venc_runtime_get(); |
527 | if (r) | 503 | if (r) |
528 | goto err1; | 504 | goto err1; |
529 | 505 | ||
506 | venc_power_on(dssdev); | ||
507 | |||
530 | venc.wss_data = 0; | 508 | venc.wss_data = 0; |
531 | 509 | ||
532 | mutex_unlock(&venc.venc_lock); | 510 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
533 | 511 | ||
512 | mutex_unlock(&venc.venc_lock); | ||
534 | return 0; | 513 | return 0; |
535 | err1: | 514 | err1: |
536 | if (dssdev->platform_disable) | ||
537 | dssdev->platform_disable(dssdev); | ||
538 | omap_dss_stop_device(dssdev); | 515 | omap_dss_stop_device(dssdev); |
539 | err0: | 516 | err0: |
540 | mutex_unlock(&venc.venc_lock); | 517 | mutex_unlock(&venc.venc_lock); |
518 | |||
541 | return r; | 519 | return r; |
542 | } | 520 | } |
543 | 521 | ||
544 | void omapdss_venc_display_disable(struct omap_dss_device *dssdev) | 522 | static void venc_panel_disable(struct omap_dss_device *dssdev) |
545 | { | 523 | { |
546 | DSSDBG("venc_display_disable\n"); | 524 | DSSDBG("venc_disable_display\n"); |
547 | 525 | ||
548 | mutex_lock(&venc.venc_lock); | 526 | mutex_lock(&venc.venc_lock); |
549 | 527 | ||
528 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) | ||
529 | goto end; | ||
530 | |||
531 | if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) { | ||
532 | /* suspended is the same as disabled with venc */ | ||
533 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
534 | goto end; | ||
535 | } | ||
536 | |||
550 | venc_power_off(dssdev); | 537 | venc_power_off(dssdev); |
551 | 538 | ||
552 | omap_dss_stop_device(dssdev); | 539 | venc_runtime_put(); |
553 | 540 | ||
554 | if (dssdev->platform_disable) | 541 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
555 | dssdev->platform_disable(dssdev); | ||
556 | 542 | ||
543 | omap_dss_stop_device(dssdev); | ||
544 | end: | ||
557 | mutex_unlock(&venc.venc_lock); | 545 | mutex_unlock(&venc.venc_lock); |
558 | } | 546 | } |
559 | 547 | ||
560 | void omapdss_venc_set_timings(struct omap_dss_device *dssdev, | 548 | static int venc_panel_suspend(struct omap_dss_device *dssdev) |
561 | struct omap_video_timings *timings) | ||
562 | { | 549 | { |
563 | DSSDBG("venc_set_timings\n"); | 550 | venc_panel_disable(dssdev); |
551 | return 0; | ||
552 | } | ||
564 | 553 | ||
565 | mutex_lock(&venc.venc_lock); | 554 | static int venc_panel_resume(struct omap_dss_device *dssdev) |
555 | { | ||
556 | return venc_panel_enable(dssdev); | ||
557 | } | ||
558 | |||
559 | static void venc_get_timings(struct omap_dss_device *dssdev, | ||
560 | struct omap_video_timings *timings) | ||
561 | { | ||
562 | *timings = dssdev->panel.timings; | ||
563 | } | ||
564 | |||
565 | static void venc_set_timings(struct omap_dss_device *dssdev, | ||
566 | struct omap_video_timings *timings) | ||
567 | { | ||
568 | DSSDBG("venc_set_timings\n"); | ||
566 | 569 | ||
567 | /* Reset WSS data when the TV standard changes. */ | 570 | /* Reset WSS data when the TV standard changes. */ |
568 | if (memcmp(&venc.timings, timings, sizeof(*timings))) | 571 | if (memcmp(&dssdev->panel.timings, timings, sizeof(*timings))) |
569 | venc.wss_data = 0; | 572 | venc.wss_data = 0; |
570 | 573 | ||
571 | venc.timings = *timings; | 574 | dssdev->panel.timings = *timings; |
572 | 575 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | |
573 | mutex_unlock(&venc.venc_lock); | 576 | /* turn the venc off and on to get new timings to use */ |
577 | venc_panel_disable(dssdev); | ||
578 | venc_panel_enable(dssdev); | ||
579 | } | ||
574 | } | 580 | } |
575 | 581 | ||
576 | int omapdss_venc_check_timings(struct omap_dss_device *dssdev, | 582 | static int venc_check_timings(struct omap_dss_device *dssdev, |
577 | struct omap_video_timings *timings) | 583 | struct omap_video_timings *timings) |
578 | { | 584 | { |
579 | DSSDBG("venc_check_timings\n"); | 585 | DSSDBG("venc_check_timings\n"); |
580 | 586 | ||
@@ -587,13 +593,13 @@ int omapdss_venc_check_timings(struct omap_dss_device *dssdev, | |||
587 | return -EINVAL; | 593 | return -EINVAL; |
588 | } | 594 | } |
589 | 595 | ||
590 | u32 omapdss_venc_get_wss(struct omap_dss_device *dssdev) | 596 | static u32 venc_get_wss(struct omap_dss_device *dssdev) |
591 | { | 597 | { |
592 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ | 598 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ |
593 | return (venc.wss_data >> 8) ^ 0xfffff; | 599 | return (venc.wss_data >> 8) ^ 0xfffff; |
594 | } | 600 | } |
595 | 601 | ||
596 | int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss) | 602 | static int venc_set_wss(struct omap_dss_device *dssdev, u32 wss) |
597 | { | 603 | { |
598 | const struct venc_config *config; | 604 | const struct venc_config *config; |
599 | int r; | 605 | int r; |
@@ -602,7 +608,7 @@ int omapdss_venc_set_wss(struct omap_dss_device *dssdev, u32 wss) | |||
602 | 608 | ||
603 | mutex_lock(&venc.venc_lock); | 609 | mutex_lock(&venc.venc_lock); |
604 | 610 | ||
605 | config = venc_timings_to_config(&venc.timings); | 611 | config = venc_timings_to_config(&dssdev->panel.timings); |
606 | 612 | ||
607 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ | 613 | /* Invert due to VENC_L21_WC_CTL:INV=1 */ |
608 | venc.wss_data = (wss ^ 0xfffff) << 8; | 614 | venc.wss_data = (wss ^ 0xfffff) << 8; |
@@ -622,27 +628,33 @@ err: | |||
622 | return r; | 628 | return r; |
623 | } | 629 | } |
624 | 630 | ||
625 | void omapdss_venc_set_type(struct omap_dss_device *dssdev, | 631 | static struct omap_dss_driver venc_driver = { |
626 | enum omap_dss_venc_type type) | 632 | .probe = venc_panel_probe, |
627 | { | 633 | .remove = venc_panel_remove, |
628 | mutex_lock(&venc.venc_lock); | ||
629 | 634 | ||
630 | venc.type = type; | 635 | .enable = venc_panel_enable, |
636 | .disable = venc_panel_disable, | ||
637 | .suspend = venc_panel_suspend, | ||
638 | .resume = venc_panel_resume, | ||
631 | 639 | ||
632 | mutex_unlock(&venc.venc_lock); | 640 | .get_resolution = omapdss_default_get_resolution, |
633 | } | 641 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, |
634 | 642 | ||
635 | void omapdss_venc_invert_vid_out_polarity(struct omap_dss_device *dssdev, | 643 | .get_timings = venc_get_timings, |
636 | bool invert_polarity) | 644 | .set_timings = venc_set_timings, |
637 | { | 645 | .check_timings = venc_check_timings, |
638 | mutex_lock(&venc.venc_lock); | ||
639 | 646 | ||
640 | venc.invert_polarity = invert_polarity; | 647 | .get_wss = venc_get_wss, |
648 | .set_wss = venc_set_wss, | ||
641 | 649 | ||
642 | mutex_unlock(&venc.venc_lock); | 650 | .driver = { |
643 | } | 651 | .name = "venc", |
652 | .owner = THIS_MODULE, | ||
653 | }, | ||
654 | }; | ||
655 | /* driver end */ | ||
644 | 656 | ||
645 | static int __init venc_init_display(struct omap_dss_device *dssdev) | 657 | int venc_init_display(struct omap_dss_device *dssdev) |
646 | { | 658 | { |
647 | DSSDBG("init_display\n"); | 659 | DSSDBG("init_display\n"); |
648 | 660 | ||
@@ -662,7 +674,7 @@ static int __init venc_init_display(struct omap_dss_device *dssdev) | |||
662 | return 0; | 674 | return 0; |
663 | } | 675 | } |
664 | 676 | ||
665 | static void venc_dump_regs(struct seq_file *s) | 677 | void venc_dump_regs(struct seq_file *s) |
666 | { | 678 | { |
667 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) | 679 | #define DUMPREG(r) seq_printf(s, "%-35s %08x\n", #r, venc_read_reg(r)) |
668 | 680 | ||
@@ -720,10 +732,22 @@ static int venc_get_clocks(struct platform_device *pdev) | |||
720 | { | 732 | { |
721 | struct clk *clk; | 733 | struct clk *clk; |
722 | 734 | ||
735 | clk = clk_get(&pdev->dev, "fck"); | ||
736 | if (IS_ERR(clk)) { | ||
737 | DSSERR("can't get fck\n"); | ||
738 | return PTR_ERR(clk); | ||
739 | } | ||
740 | |||
741 | venc.tv_clk = clk; | ||
742 | |||
723 | if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { | 743 | if (dss_has_feature(FEAT_VENC_REQUIRES_TV_DAC_CLK)) { |
724 | clk = clk_get(&pdev->dev, "tv_dac_clk"); | 744 | if (cpu_is_omap34xx() || cpu_is_omap3630()) |
745 | clk = clk_get(&pdev->dev, "dss_96m_fck"); | ||
746 | else | ||
747 | clk = clk_get(&pdev->dev, "tv_dac_clk"); | ||
725 | if (IS_ERR(clk)) { | 748 | if (IS_ERR(clk)) { |
726 | DSSERR("can't get tv_dac_clk\n"); | 749 | DSSERR("can't get tv_dac_clk\n"); |
750 | clk_put(venc.tv_clk); | ||
727 | return PTR_ERR(clk); | 751 | return PTR_ERR(clk); |
728 | } | 752 | } |
729 | } else { | 753 | } else { |
@@ -737,101 +761,14 @@ static int venc_get_clocks(struct platform_device *pdev) | |||
737 | 761 | ||
738 | static void venc_put_clocks(void) | 762 | static void venc_put_clocks(void) |
739 | { | 763 | { |
764 | if (venc.tv_clk) | ||
765 | clk_put(venc.tv_clk); | ||
740 | if (venc.tv_dac_clk) | 766 | if (venc.tv_dac_clk) |
741 | clk_put(venc.tv_dac_clk); | 767 | clk_put(venc.tv_dac_clk); |
742 | } | 768 | } |
743 | 769 | ||
744 | static struct omap_dss_device * __init venc_find_dssdev(struct platform_device *pdev) | ||
745 | { | ||
746 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | ||
747 | const char *def_disp_name = omapdss_get_default_display_name(); | ||
748 | struct omap_dss_device *def_dssdev; | ||
749 | int i; | ||
750 | |||
751 | def_dssdev = NULL; | ||
752 | |||
753 | for (i = 0; i < pdata->num_devices; ++i) { | ||
754 | struct omap_dss_device *dssdev = pdata->devices[i]; | ||
755 | |||
756 | if (dssdev->type != OMAP_DISPLAY_TYPE_VENC) | ||
757 | continue; | ||
758 | |||
759 | if (def_dssdev == NULL) | ||
760 | def_dssdev = dssdev; | ||
761 | |||
762 | if (def_disp_name != NULL && | ||
763 | strcmp(dssdev->name, def_disp_name) == 0) { | ||
764 | def_dssdev = dssdev; | ||
765 | break; | ||
766 | } | ||
767 | } | ||
768 | |||
769 | return def_dssdev; | ||
770 | } | ||
771 | |||
772 | static void __init venc_probe_pdata(struct platform_device *vencdev) | ||
773 | { | ||
774 | struct omap_dss_device *plat_dssdev; | ||
775 | struct omap_dss_device *dssdev; | ||
776 | int r; | ||
777 | |||
778 | plat_dssdev = venc_find_dssdev(vencdev); | ||
779 | |||
780 | if (!plat_dssdev) | ||
781 | return; | ||
782 | |||
783 | dssdev = dss_alloc_and_init_device(&vencdev->dev); | ||
784 | if (!dssdev) | ||
785 | return; | ||
786 | |||
787 | dss_copy_device_pdata(dssdev, plat_dssdev); | ||
788 | |||
789 | dssdev->channel = OMAP_DSS_CHANNEL_DIGIT; | ||
790 | |||
791 | r = venc_init_display(dssdev); | ||
792 | if (r) { | ||
793 | DSSERR("device %s init failed: %d\n", dssdev->name, r); | ||
794 | dss_put_device(dssdev); | ||
795 | return; | ||
796 | } | ||
797 | |||
798 | r = omapdss_output_set_device(&venc.output, dssdev); | ||
799 | if (r) { | ||
800 | DSSERR("failed to connect output to new device: %s\n", | ||
801 | dssdev->name); | ||
802 | dss_put_device(dssdev); | ||
803 | return; | ||
804 | } | ||
805 | |||
806 | r = dss_add_device(dssdev); | ||
807 | if (r) { | ||
808 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | ||
809 | omapdss_output_unset_device(&venc.output); | ||
810 | dss_put_device(dssdev); | ||
811 | return; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | static void __init venc_init_output(struct platform_device *pdev) | ||
816 | { | ||
817 | struct omap_dss_output *out = &venc.output; | ||
818 | |||
819 | out->pdev = pdev; | ||
820 | out->id = OMAP_DSS_OUTPUT_VENC; | ||
821 | out->type = OMAP_DISPLAY_TYPE_VENC; | ||
822 | |||
823 | dss_register_output(out); | ||
824 | } | ||
825 | |||
826 | static void __exit venc_uninit_output(struct platform_device *pdev) | ||
827 | { | ||
828 | struct omap_dss_output *out = &venc.output; | ||
829 | |||
830 | dss_unregister_output(out); | ||
831 | } | ||
832 | |||
833 | /* VENC HW IP initialisation */ | 770 | /* VENC HW IP initialisation */ |
834 | static int __init omap_venchw_probe(struct platform_device *pdev) | 771 | static int omap_venchw_probe(struct platform_device *pdev) |
835 | { | 772 | { |
836 | u8 rev_id; | 773 | u8 rev_id; |
837 | struct resource *venc_mem; | 774 | struct resource *venc_mem; |
@@ -846,75 +783,65 @@ static int __init omap_venchw_probe(struct platform_device *pdev) | |||
846 | venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); | 783 | venc_mem = platform_get_resource(venc.pdev, IORESOURCE_MEM, 0); |
847 | if (!venc_mem) { | 784 | if (!venc_mem) { |
848 | DSSERR("can't get IORESOURCE_MEM VENC\n"); | 785 | DSSERR("can't get IORESOURCE_MEM VENC\n"); |
849 | return -EINVAL; | 786 | r = -EINVAL; |
787 | goto err_ioremap; | ||
850 | } | 788 | } |
851 | 789 | venc.base = ioremap(venc_mem->start, resource_size(venc_mem)); | |
852 | venc.base = devm_ioremap(&pdev->dev, venc_mem->start, | ||
853 | resource_size(venc_mem)); | ||
854 | if (!venc.base) { | 790 | if (!venc.base) { |
855 | DSSERR("can't ioremap VENC\n"); | 791 | DSSERR("can't ioremap VENC\n"); |
856 | return -ENOMEM; | 792 | r = -ENOMEM; |
793 | goto err_ioremap; | ||
857 | } | 794 | } |
858 | 795 | ||
859 | r = venc_get_clocks(pdev); | 796 | r = venc_get_clocks(pdev); |
860 | if (r) | 797 | if (r) |
861 | return r; | 798 | goto err_get_clk; |
862 | 799 | ||
863 | pm_runtime_enable(&pdev->dev); | 800 | pm_runtime_enable(&pdev->dev); |
864 | 801 | ||
865 | r = venc_runtime_get(); | 802 | r = venc_runtime_get(); |
866 | if (r) | 803 | if (r) |
867 | goto err_runtime_get; | 804 | goto err_get_venc; |
868 | 805 | ||
869 | rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); | 806 | rev_id = (u8)(venc_read_reg(VENC_REV_ID) & 0xff); |
870 | dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); | 807 | dev_dbg(&pdev->dev, "OMAP VENC rev %d\n", rev_id); |
871 | 808 | ||
872 | venc_runtime_put(); | 809 | venc_runtime_put(); |
873 | 810 | ||
874 | r = venc_panel_init(); | 811 | return omap_dss_register_driver(&venc_driver); |
875 | if (r) | ||
876 | goto err_panel_init; | ||
877 | |||
878 | dss_debugfs_create_file("venc", venc_dump_regs); | ||
879 | |||
880 | venc_init_output(pdev); | ||
881 | 812 | ||
882 | venc_probe_pdata(pdev); | 813 | err_get_venc: |
883 | |||
884 | return 0; | ||
885 | |||
886 | err_panel_init: | ||
887 | err_runtime_get: | ||
888 | pm_runtime_disable(&pdev->dev); | 814 | pm_runtime_disable(&pdev->dev); |
889 | venc_put_clocks(); | 815 | venc_put_clocks(); |
816 | err_get_clk: | ||
817 | iounmap(venc.base); | ||
818 | err_ioremap: | ||
890 | return r; | 819 | return r; |
891 | } | 820 | } |
892 | 821 | ||
893 | static int __exit omap_venchw_remove(struct platform_device *pdev) | 822 | static int omap_venchw_remove(struct platform_device *pdev) |
894 | { | 823 | { |
895 | dss_unregister_child_devices(&pdev->dev); | ||
896 | |||
897 | if (venc.vdda_dac_reg != NULL) { | 824 | if (venc.vdda_dac_reg != NULL) { |
898 | regulator_put(venc.vdda_dac_reg); | 825 | regulator_put(venc.vdda_dac_reg); |
899 | venc.vdda_dac_reg = NULL; | 826 | venc.vdda_dac_reg = NULL; |
900 | } | 827 | } |
901 | 828 | omap_dss_unregister_driver(&venc_driver); | |
902 | venc_panel_exit(); | ||
903 | |||
904 | venc_uninit_output(pdev); | ||
905 | 829 | ||
906 | pm_runtime_disable(&pdev->dev); | 830 | pm_runtime_disable(&pdev->dev); |
907 | venc_put_clocks(); | 831 | venc_put_clocks(); |
908 | 832 | ||
833 | iounmap(venc.base); | ||
909 | return 0; | 834 | return 0; |
910 | } | 835 | } |
911 | 836 | ||
912 | static int venc_runtime_suspend(struct device *dev) | 837 | static int venc_runtime_suspend(struct device *dev) |
913 | { | 838 | { |
914 | if (venc.tv_dac_clk) | 839 | if (venc.tv_dac_clk) |
915 | clk_disable_unprepare(venc.tv_dac_clk); | 840 | clk_disable(venc.tv_dac_clk); |
841 | clk_disable(venc.tv_clk); | ||
916 | 842 | ||
917 | dispc_runtime_put(); | 843 | dispc_runtime_put(); |
844 | dss_runtime_put(); | ||
918 | 845 | ||
919 | return 0; | 846 | return 0; |
920 | } | 847 | } |
@@ -923,14 +850,24 @@ static int venc_runtime_resume(struct device *dev) | |||
923 | { | 850 | { |
924 | int r; | 851 | int r; |
925 | 852 | ||
853 | r = dss_runtime_get(); | ||
854 | if (r < 0) | ||
855 | goto err_get_dss; | ||
856 | |||
926 | r = dispc_runtime_get(); | 857 | r = dispc_runtime_get(); |
927 | if (r < 0) | 858 | if (r < 0) |
928 | return r; | 859 | goto err_get_dispc; |
929 | 860 | ||
861 | clk_enable(venc.tv_clk); | ||
930 | if (venc.tv_dac_clk) | 862 | if (venc.tv_dac_clk) |
931 | clk_prepare_enable(venc.tv_dac_clk); | 863 | clk_enable(venc.tv_dac_clk); |
932 | 864 | ||
933 | return 0; | 865 | return 0; |
866 | |||
867 | err_get_dispc: | ||
868 | dss_runtime_put(); | ||
869 | err_get_dss: | ||
870 | return r; | ||
934 | } | 871 | } |
935 | 872 | ||
936 | static const struct dev_pm_ops venc_pm_ops = { | 873 | static const struct dev_pm_ops venc_pm_ops = { |
@@ -939,7 +876,8 @@ static const struct dev_pm_ops venc_pm_ops = { | |||
939 | }; | 876 | }; |
940 | 877 | ||
941 | static struct platform_driver omap_venchw_driver = { | 878 | static struct platform_driver omap_venchw_driver = { |
942 | .remove = __exit_p(omap_venchw_remove), | 879 | .probe = omap_venchw_probe, |
880 | .remove = omap_venchw_remove, | ||
943 | .driver = { | 881 | .driver = { |
944 | .name = "omapdss_venc", | 882 | .name = "omapdss_venc", |
945 | .owner = THIS_MODULE, | 883 | .owner = THIS_MODULE, |
@@ -947,12 +885,18 @@ static struct platform_driver omap_venchw_driver = { | |||
947 | }, | 885 | }, |
948 | }; | 886 | }; |
949 | 887 | ||
950 | int __init venc_init_platform_driver(void) | 888 | int venc_init_platform_driver(void) |
951 | { | 889 | { |
952 | return platform_driver_probe(&omap_venchw_driver, omap_venchw_probe); | 890 | if (cpu_is_omap44xx()) |
891 | return 0; | ||
892 | |||
893 | return platform_driver_register(&omap_venchw_driver); | ||
953 | } | 894 | } |
954 | 895 | ||
955 | void __exit venc_uninit_platform_driver(void) | 896 | void venc_uninit_platform_driver(void) |
956 | { | 897 | { |
957 | platform_driver_unregister(&omap_venchw_driver); | 898 | if (cpu_is_omap44xx()) |
899 | return; | ||
900 | |||
901 | return platform_driver_unregister(&omap_venchw_driver); | ||
958 | } | 902 | } |
diff --git a/drivers/video/omap2/dss/venc_panel.c b/drivers/video/omap2/dss/venc_panel.c deleted file mode 100644 index 0d2b1a0834a..00000000000 --- a/drivers/video/omap2/dss/venc_panel.c +++ /dev/null | |||
@@ -1,232 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009 Nokia Corporation | ||
3 | * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com> | ||
4 | * | ||
5 | * VENC panel driver | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License version 2 as published by | ||
9 | * the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
14 | * more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along with | ||
17 | * this program. If not, see <http://www.gnu.org/licenses/>. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/module.h> | ||
25 | |||
26 | #include <video/omapdss.h> | ||
27 | |||
28 | #include "dss.h" | ||
29 | |||
30 | static struct { | ||
31 | struct mutex lock; | ||
32 | } venc_panel; | ||
33 | |||
34 | static ssize_t display_output_type_show(struct device *dev, | ||
35 | struct device_attribute *attr, char *buf) | ||
36 | { | ||
37 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
38 | const char *ret; | ||
39 | |||
40 | switch (dssdev->phy.venc.type) { | ||
41 | case OMAP_DSS_VENC_TYPE_COMPOSITE: | ||
42 | ret = "composite"; | ||
43 | break; | ||
44 | case OMAP_DSS_VENC_TYPE_SVIDEO: | ||
45 | ret = "svideo"; | ||
46 | break; | ||
47 | default: | ||
48 | return -EINVAL; | ||
49 | } | ||
50 | |||
51 | return snprintf(buf, PAGE_SIZE, "%s\n", ret); | ||
52 | } | ||
53 | |||
54 | static ssize_t display_output_type_store(struct device *dev, | ||
55 | struct device_attribute *attr, const char *buf, size_t size) | ||
56 | { | ||
57 | struct omap_dss_device *dssdev = to_dss_device(dev); | ||
58 | enum omap_dss_venc_type new_type; | ||
59 | |||
60 | if (sysfs_streq("composite", buf)) | ||
61 | new_type = OMAP_DSS_VENC_TYPE_COMPOSITE; | ||
62 | else if (sysfs_streq("svideo", buf)) | ||
63 | new_type = OMAP_DSS_VENC_TYPE_SVIDEO; | ||
64 | else | ||
65 | return -EINVAL; | ||
66 | |||
67 | mutex_lock(&venc_panel.lock); | ||
68 | |||
69 | if (dssdev->phy.venc.type != new_type) { | ||
70 | dssdev->phy.venc.type = new_type; | ||
71 | omapdss_venc_set_type(dssdev, new_type); | ||
72 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) { | ||
73 | omapdss_venc_display_disable(dssdev); | ||
74 | omapdss_venc_display_enable(dssdev); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | mutex_unlock(&venc_panel.lock); | ||
79 | |||
80 | return size; | ||
81 | } | ||
82 | |||
83 | static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR, | ||
84 | display_output_type_show, display_output_type_store); | ||
85 | |||
86 | static int venc_panel_probe(struct omap_dss_device *dssdev) | ||
87 | { | ||
88 | /* set default timings to PAL */ | ||
89 | const struct omap_video_timings default_timings = { | ||
90 | .x_res = 720, | ||
91 | .y_res = 574, | ||
92 | .pixel_clock = 13500, | ||
93 | .hsw = 64, | ||
94 | .hfp = 12, | ||
95 | .hbp = 68, | ||
96 | .vsw = 5, | ||
97 | .vfp = 5, | ||
98 | .vbp = 41, | ||
99 | |||
100 | .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
101 | .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH, | ||
102 | |||
103 | .interlace = true, | ||
104 | }; | ||
105 | |||
106 | mutex_init(&venc_panel.lock); | ||
107 | |||
108 | dssdev->panel.timings = default_timings; | ||
109 | |||
110 | return device_create_file(&dssdev->dev, &dev_attr_output_type); | ||
111 | } | ||
112 | |||
113 | static void venc_panel_remove(struct omap_dss_device *dssdev) | ||
114 | { | ||
115 | device_remove_file(&dssdev->dev, &dev_attr_output_type); | ||
116 | } | ||
117 | |||
118 | static int venc_panel_enable(struct omap_dss_device *dssdev) | ||
119 | { | ||
120 | int r; | ||
121 | |||
122 | dev_dbg(&dssdev->dev, "venc_panel_enable\n"); | ||
123 | |||
124 | mutex_lock(&venc_panel.lock); | ||
125 | |||
126 | if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) { | ||
127 | r = -EINVAL; | ||
128 | goto err; | ||
129 | } | ||
130 | |||
131 | omapdss_venc_set_timings(dssdev, &dssdev->panel.timings); | ||
132 | omapdss_venc_set_type(dssdev, dssdev->phy.venc.type); | ||
133 | omapdss_venc_invert_vid_out_polarity(dssdev, | ||
134 | dssdev->phy.venc.invert_polarity); | ||
135 | |||
136 | r = omapdss_venc_display_enable(dssdev); | ||
137 | if (r) | ||
138 | goto err; | ||
139 | |||
140 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | ||
141 | |||
142 | mutex_unlock(&venc_panel.lock); | ||
143 | |||
144 | return 0; | ||
145 | err: | ||
146 | mutex_unlock(&venc_panel.lock); | ||
147 | |||
148 | return r; | ||
149 | } | ||
150 | |||
151 | static void venc_panel_disable(struct omap_dss_device *dssdev) | ||
152 | { | ||
153 | dev_dbg(&dssdev->dev, "venc_panel_disable\n"); | ||
154 | |||
155 | mutex_lock(&venc_panel.lock); | ||
156 | |||
157 | if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED) | ||
158 | goto end; | ||
159 | |||
160 | omapdss_venc_display_disable(dssdev); | ||
161 | |||
162 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | ||
163 | end: | ||
164 | mutex_unlock(&venc_panel.lock); | ||
165 | } | ||
166 | |||
167 | static void venc_panel_set_timings(struct omap_dss_device *dssdev, | ||
168 | struct omap_video_timings *timings) | ||
169 | { | ||
170 | dev_dbg(&dssdev->dev, "venc_panel_set_timings\n"); | ||
171 | |||
172 | mutex_lock(&venc_panel.lock); | ||
173 | |||
174 | omapdss_venc_set_timings(dssdev, timings); | ||
175 | dssdev->panel.timings = *timings; | ||
176 | |||
177 | mutex_unlock(&venc_panel.lock); | ||
178 | } | ||
179 | |||
180 | static int venc_panel_check_timings(struct omap_dss_device *dssdev, | ||
181 | struct omap_video_timings *timings) | ||
182 | { | ||
183 | dev_dbg(&dssdev->dev, "venc_panel_check_timings\n"); | ||
184 | |||
185 | return omapdss_venc_check_timings(dssdev, timings); | ||
186 | } | ||
187 | |||
188 | static u32 venc_panel_get_wss(struct omap_dss_device *dssdev) | ||
189 | { | ||
190 | dev_dbg(&dssdev->dev, "venc_panel_get_wss\n"); | ||
191 | |||
192 | return omapdss_venc_get_wss(dssdev); | ||
193 | } | ||
194 | |||
195 | static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss) | ||
196 | { | ||
197 | dev_dbg(&dssdev->dev, "venc_panel_set_wss\n"); | ||
198 | |||
199 | return omapdss_venc_set_wss(dssdev, wss); | ||
200 | } | ||
201 | |||
202 | static struct omap_dss_driver venc_driver = { | ||
203 | .probe = venc_panel_probe, | ||
204 | .remove = venc_panel_remove, | ||
205 | |||
206 | .enable = venc_panel_enable, | ||
207 | .disable = venc_panel_disable, | ||
208 | |||
209 | .get_resolution = omapdss_default_get_resolution, | ||
210 | .get_recommended_bpp = omapdss_default_get_recommended_bpp, | ||
211 | |||
212 | .set_timings = venc_panel_set_timings, | ||
213 | .check_timings = venc_panel_check_timings, | ||
214 | |||
215 | .get_wss = venc_panel_get_wss, | ||
216 | .set_wss = venc_panel_set_wss, | ||
217 | |||
218 | .driver = { | ||
219 | .name = "venc", | ||
220 | .owner = THIS_MODULE, | ||
221 | }, | ||
222 | }; | ||
223 | |||
224 | int venc_panel_init(void) | ||
225 | { | ||
226 | return omap_dss_register_driver(&venc_driver); | ||
227 | } | ||
228 | |||
229 | void venc_panel_exit(void) | ||
230 | { | ||
231 | omap_dss_unregister_driver(&venc_driver); | ||
232 | } | ||
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig index 4cb12ce6885..aa33386c81f 100644 --- a/drivers/video/omap2/omapfb/Kconfig +++ b/drivers/video/omap2/omapfb/Kconfig | |||
@@ -1,7 +1,8 @@ | |||
1 | menuconfig FB_OMAP2 | 1 | menuconfig FB_OMAP2 |
2 | tristate "OMAP2+ frame buffer support" | 2 | tristate "OMAP2+ frame buffer support (EXPERIMENTAL)" |
3 | depends on FB && OMAP2_DSS && !DRM_OMAP | 3 | depends on FB && OMAP2_DSS |
4 | 4 | ||
5 | select OMAP2_VRAM | ||
5 | select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 | 6 | select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 |
6 | select FB_CFB_FILLRECT | 7 | select FB_CFB_FILLRECT |
7 | select FB_CFB_COPYAREA | 8 | select FB_CFB_COPYAREA |
diff --git a/drivers/video/omap2/omapfb/omapfb-ioctl.c b/drivers/video/omap2/omapfb/omapfb-ioctl.c index d30b45d7264..6b1ac23dbbd 100644 --- a/drivers/video/omap2/omapfb/omapfb-ioctl.c +++ b/drivers/video/omap2/omapfb/omapfb-ioctl.c | |||
@@ -27,11 +27,10 @@ | |||
27 | #include <linux/mm.h> | 27 | #include <linux/mm.h> |
28 | #include <linux/omapfb.h> | 28 | #include <linux/omapfb.h> |
29 | #include <linux/vmalloc.h> | 29 | #include <linux/vmalloc.h> |
30 | #include <linux/export.h> | ||
31 | #include <linux/sizes.h> | ||
32 | 30 | ||
33 | #include <video/omapdss.h> | 31 | #include <video/omapdss.h> |
34 | #include <video/omapvrfb.h> | 32 | #include <plat/vrfb.h> |
33 | #include <plat/vram.h> | ||
35 | 34 | ||
36 | #include "omapfb.h" | 35 | #include "omapfb.h" |
37 | 36 | ||
@@ -70,7 +69,7 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
70 | 69 | ||
71 | DBG("omapfb_setup_plane\n"); | 70 | DBG("omapfb_setup_plane\n"); |
72 | 71 | ||
73 | if (ofbi->num_overlays == 0) { | 72 | if (ofbi->num_overlays != 1) { |
74 | r = -EINVAL; | 73 | r = -EINVAL; |
75 | goto out; | 74 | goto out; |
76 | } | 75 | } |
@@ -111,22 +110,28 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
111 | set_fb_fix(fbi); | 110 | set_fb_fix(fbi); |
112 | } | 111 | } |
113 | 112 | ||
114 | if (!pi->enabled) { | ||
115 | r = ovl->disable(ovl); | ||
116 | if (r) | ||
117 | goto undo; | ||
118 | } | ||
119 | |||
120 | if (pi->enabled) { | 113 | if (pi->enabled) { |
114 | struct omap_overlay_info info; | ||
115 | |||
121 | r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, | 116 | r = omapfb_setup_overlay(fbi, ovl, pi->pos_x, pi->pos_y, |
122 | pi->out_width, pi->out_height); | 117 | pi->out_width, pi->out_height); |
123 | if (r) | 118 | if (r) |
124 | goto undo; | 119 | goto undo; |
120 | |||
121 | ovl->get_overlay_info(ovl, &info); | ||
122 | |||
123 | if (!info.enabled) { | ||
124 | info.enabled = pi->enabled; | ||
125 | r = ovl->set_overlay_info(ovl, &info); | ||
126 | if (r) | ||
127 | goto undo; | ||
128 | } | ||
125 | } else { | 129 | } else { |
126 | struct omap_overlay_info info; | 130 | struct omap_overlay_info info; |
127 | 131 | ||
128 | ovl->get_overlay_info(ovl, &info); | 132 | ovl->get_overlay_info(ovl, &info); |
129 | 133 | ||
134 | info.enabled = pi->enabled; | ||
130 | info.pos_x = pi->pos_x; | 135 | info.pos_x = pi->pos_x; |
131 | info.pos_y = pi->pos_y; | 136 | info.pos_y = pi->pos_y; |
132 | info.out_width = pi->out_width; | 137 | info.out_width = pi->out_width; |
@@ -140,12 +145,6 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
140 | if (ovl->manager) | 145 | if (ovl->manager) |
141 | ovl->manager->apply(ovl->manager); | 146 | ovl->manager->apply(ovl->manager); |
142 | 147 | ||
143 | if (pi->enabled) { | ||
144 | r = ovl->enable(ovl); | ||
145 | if (r) | ||
146 | goto undo; | ||
147 | } | ||
148 | |||
149 | /* Release the locks in a specific order to keep lockdep happy */ | 148 | /* Release the locks in a specific order to keep lockdep happy */ |
150 | if (old_rg->id > new_rg->id) { | 149 | if (old_rg->id > new_rg->id) { |
151 | omapfb_put_mem_region(old_rg); | 150 | omapfb_put_mem_region(old_rg); |
@@ -185,23 +184,23 @@ static int omapfb_query_plane(struct fb_info *fbi, struct omapfb_plane_info *pi) | |||
185 | { | 184 | { |
186 | struct omapfb_info *ofbi = FB2OFB(fbi); | 185 | struct omapfb_info *ofbi = FB2OFB(fbi); |
187 | 186 | ||
188 | if (ofbi->num_overlays == 0) { | 187 | if (ofbi->num_overlays != 1) { |
189 | memset(pi, 0, sizeof(*pi)); | 188 | memset(pi, 0, sizeof(*pi)); |
190 | } else { | 189 | } else { |
191 | struct omap_overlay *ovl; | 190 | struct omap_overlay *ovl; |
192 | struct omap_overlay_info ovli; | 191 | struct omap_overlay_info *ovli; |
193 | 192 | ||
194 | ovl = ofbi->overlays[0]; | 193 | ovl = ofbi->overlays[0]; |
195 | ovl->get_overlay_info(ovl, &ovli); | 194 | ovli = &ovl->info; |
196 | 195 | ||
197 | pi->pos_x = ovli.pos_x; | 196 | pi->pos_x = ovli->pos_x; |
198 | pi->pos_y = ovli.pos_y; | 197 | pi->pos_y = ovli->pos_y; |
199 | pi->enabled = ovl->is_enabled(ovl); | 198 | pi->enabled = ovli->enabled; |
200 | pi->channel_out = 0; /* xxx */ | 199 | pi->channel_out = 0; /* xxx */ |
201 | pi->mirror = 0; | 200 | pi->mirror = 0; |
202 | pi->mem_idx = get_mem_idx(ofbi); | 201 | pi->mem_idx = get_mem_idx(ofbi); |
203 | pi->out_width = ovli.out_width; | 202 | pi->out_width = ovli->out_width; |
204 | pi->out_height = ovli.out_height; | 203 | pi->out_height = ovli->out_height; |
205 | } | 204 | } |
206 | 205 | ||
207 | return 0; | 206 | return 0; |
@@ -211,27 +210,20 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
211 | { | 210 | { |
212 | struct omapfb_info *ofbi = FB2OFB(fbi); | 211 | struct omapfb_info *ofbi = FB2OFB(fbi); |
213 | struct omapfb2_device *fbdev = ofbi->fbdev; | 212 | struct omapfb2_device *fbdev = ofbi->fbdev; |
214 | struct omap_dss_device *display = fb2display(fbi); | ||
215 | struct omapfb2_mem_region *rg; | 213 | struct omapfb2_mem_region *rg; |
216 | int r = 0, i; | 214 | int r = 0, i; |
217 | size_t size; | 215 | size_t size; |
218 | 216 | ||
219 | if (mi->type != OMAPFB_MEMTYPE_SDRAM) | 217 | if (mi->type > OMAPFB_MEMTYPE_MAX) |
220 | return -EINVAL; | 218 | return -EINVAL; |
221 | 219 | ||
222 | size = PAGE_ALIGN(mi->size); | 220 | size = PAGE_ALIGN(mi->size); |
223 | 221 | ||
224 | if (display && display->driver->sync) | ||
225 | display->driver->sync(display); | ||
226 | |||
227 | rg = ofbi->region; | 222 | rg = ofbi->region; |
228 | 223 | ||
229 | down_write_nested(&rg->lock, rg->id); | 224 | down_write_nested(&rg->lock, rg->id); |
230 | atomic_inc(&rg->lock_count); | 225 | atomic_inc(&rg->lock_count); |
231 | 226 | ||
232 | if (rg->size == size && rg->type == mi->type) | ||
233 | goto out; | ||
234 | |||
235 | if (atomic_read(&rg->map_count)) { | 227 | if (atomic_read(&rg->map_count)) { |
236 | r = -EBUSY; | 228 | r = -EBUSY; |
237 | goto out; | 229 | goto out; |
@@ -245,19 +237,19 @@ static int omapfb_setup_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
245 | continue; | 237 | continue; |
246 | 238 | ||
247 | for (j = 0; j < ofbi2->num_overlays; j++) { | 239 | for (j = 0; j < ofbi2->num_overlays; j++) { |
248 | struct omap_overlay *ovl; | 240 | if (ofbi2->overlays[j]->info.enabled) { |
249 | ovl = ofbi2->overlays[j]; | ||
250 | if (ovl->is_enabled(ovl)) { | ||
251 | r = -EBUSY; | 241 | r = -EBUSY; |
252 | goto out; | 242 | goto out; |
253 | } | 243 | } |
254 | } | 244 | } |
255 | } | 245 | } |
256 | 246 | ||
257 | r = omapfb_realloc_fbmem(fbi, size, mi->type); | 247 | if (rg->size != size || rg->type != mi->type) { |
258 | if (r) { | 248 | r = omapfb_realloc_fbmem(fbi, size, mi->type); |
259 | dev_err(fbdev->dev, "realloc fbmem failed\n"); | 249 | if (r) { |
260 | goto out; | 250 | dev_err(fbdev->dev, "realloc fbmem failed\n"); |
251 | goto out; | ||
252 | } | ||
261 | } | 253 | } |
262 | 254 | ||
263 | out: | 255 | out: |
@@ -283,7 +275,7 @@ static int omapfb_query_mem(struct fb_info *fbi, struct omapfb_mem_info *mi) | |||
283 | return 0; | 275 | return 0; |
284 | } | 276 | } |
285 | 277 | ||
286 | static int omapfb_update_window(struct fb_info *fbi, | 278 | static int omapfb_update_window_nolock(struct fb_info *fbi, |
287 | u32 x, u32 y, u32 w, u32 h) | 279 | u32 x, u32 y, u32 w, u32 h) |
288 | { | 280 | { |
289 | struct omap_dss_device *display = fb2display(fbi); | 281 | struct omap_dss_device *display = fb2display(fbi); |
@@ -303,6 +295,27 @@ static int omapfb_update_window(struct fb_info *fbi, | |||
303 | return display->driver->update(display, x, y, w, h); | 295 | return display->driver->update(display, x, y, w, h); |
304 | } | 296 | } |
305 | 297 | ||
298 | /* This function is exported for SGX driver use */ | ||
299 | int omapfb_update_window(struct fb_info *fbi, | ||
300 | u32 x, u32 y, u32 w, u32 h) | ||
301 | { | ||
302 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
303 | struct omapfb2_device *fbdev = ofbi->fbdev; | ||
304 | int r; | ||
305 | |||
306 | if (!lock_fb_info(fbi)) | ||
307 | return -ENODEV; | ||
308 | omapfb_lock(fbdev); | ||
309 | |||
310 | r = omapfb_update_window_nolock(fbi, x, y, w, h); | ||
311 | |||
312 | omapfb_unlock(fbdev); | ||
313 | unlock_fb_info(fbi); | ||
314 | |||
315 | return r; | ||
316 | } | ||
317 | EXPORT_SYMBOL(omapfb_update_window); | ||
318 | |||
306 | int omapfb_set_update_mode(struct fb_info *fbi, | 319 | int omapfb_set_update_mode(struct fb_info *fbi, |
307 | enum omapfb_update_mode mode) | 320 | enum omapfb_update_mode mode) |
308 | { | 321 | { |
@@ -582,7 +595,6 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
582 | struct omapfb_info *ofbi = FB2OFB(fbi); | 595 | struct omapfb_info *ofbi = FB2OFB(fbi); |
583 | struct omapfb2_device *fbdev = ofbi->fbdev; | 596 | struct omapfb2_device *fbdev = ofbi->fbdev; |
584 | struct omap_dss_device *display = fb2display(fbi); | 597 | struct omap_dss_device *display = fb2display(fbi); |
585 | struct omap_overlay_manager *mgr; | ||
586 | 598 | ||
587 | union { | 599 | union { |
588 | struct omapfb_update_window_old uwnd_o; | 600 | struct omapfb_update_window_old uwnd_o; |
@@ -629,7 +641,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
629 | break; | 641 | break; |
630 | } | 642 | } |
631 | 643 | ||
632 | r = omapfb_update_window(fbi, p.uwnd_o.x, p.uwnd_o.y, | 644 | r = omapfb_update_window_nolock(fbi, p.uwnd_o.x, p.uwnd_o.y, |
633 | p.uwnd_o.width, p.uwnd_o.height); | 645 | p.uwnd_o.width, p.uwnd_o.height); |
634 | break; | 646 | break; |
635 | 647 | ||
@@ -646,7 +658,7 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
646 | break; | 658 | break; |
647 | } | 659 | } |
648 | 660 | ||
649 | r = omapfb_update_window(fbi, p.uwnd.x, p.uwnd.y, | 661 | r = omapfb_update_window_nolock(fbi, p.uwnd.x, p.uwnd.y, |
650 | p.uwnd.width, p.uwnd.height); | 662 | p.uwnd.width, p.uwnd.height); |
651 | break; | 663 | break; |
652 | 664 | ||
@@ -770,14 +782,12 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
770 | 782 | ||
771 | case OMAPFB_WAITFORVSYNC: | 783 | case OMAPFB_WAITFORVSYNC: |
772 | DBG("ioctl WAITFORVSYNC\n"); | 784 | DBG("ioctl WAITFORVSYNC\n"); |
773 | if (!display || !display->output || !display->output->manager) { | 785 | if (!display) { |
774 | r = -EINVAL; | 786 | r = -EINVAL; |
775 | break; | 787 | break; |
776 | } | 788 | } |
777 | 789 | ||
778 | mgr = display->output->manager; | 790 | r = display->manager->wait_for_vsync(display->manager); |
779 | |||
780 | r = mgr->wait_for_vsync(mgr); | ||
781 | break; | 791 | break; |
782 | 792 | ||
783 | case OMAPFB_WAITFORGO: | 793 | case OMAPFB_WAITFORGO: |
@@ -836,15 +846,14 @@ int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg) | |||
836 | break; | 846 | break; |
837 | 847 | ||
838 | case OMAPFB_GET_VRAM_INFO: { | 848 | case OMAPFB_GET_VRAM_INFO: { |
849 | unsigned long vram, free, largest; | ||
850 | |||
839 | DBG("ioctl GET_VRAM_INFO\n"); | 851 | DBG("ioctl GET_VRAM_INFO\n"); |
840 | 852 | ||
841 | /* | 853 | omap_vram_get_info(&vram, &free, &largest); |
842 | * We don't have the ability to get this vram info anymore. | 854 | p.vram_info.total = vram; |
843 | * Fill in something that should keep the applications working. | 855 | p.vram_info.free = free; |
844 | */ | 856 | p.vram_info.largest_free_block = largest; |
845 | p.vram_info.total = SZ_1M * 64; | ||
846 | p.vram_info.free = SZ_1M * 64; | ||
847 | p.vram_info.largest_free_block = SZ_1M * 64; | ||
848 | 857 | ||
849 | if (copy_to_user((void __user *)arg, &p.vram_info, | 858 | if (copy_to_user((void __user *)arg, &p.vram_info, |
850 | sizeof(p.vram_info))) | 859 | sizeof(p.vram_info))) |
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c index ca585ef37f2..602b71a92d3 100644 --- a/drivers/video/omap2/omapfb/omapfb-main.c +++ b/drivers/video/omap2/omapfb/omapfb-main.c | |||
@@ -31,7 +31,8 @@ | |||
31 | #include <linux/omapfb.h> | 31 | #include <linux/omapfb.h> |
32 | 32 | ||
33 | #include <video/omapdss.h> | 33 | #include <video/omapdss.h> |
34 | #include <video/omapvrfb.h> | 34 | #include <plat/vram.h> |
35 | #include <plat/vrfb.h> | ||
35 | 36 | ||
36 | #include "omapfb.h" | 37 | #include "omapfb.h" |
37 | 38 | ||
@@ -42,18 +43,18 @@ | |||
42 | 43 | ||
43 | static char *def_mode; | 44 | static char *def_mode; |
44 | static char *def_vram; | 45 | static char *def_vram; |
45 | static bool def_vrfb; | 46 | static int def_vrfb; |
46 | static int def_rotate; | 47 | static int def_rotate; |
47 | static bool def_mirror; | 48 | static int def_mirror; |
48 | static bool auto_update; | 49 | static bool auto_update; |
49 | static unsigned int auto_update_freq; | 50 | static unsigned int auto_update_freq; |
50 | module_param(auto_update, bool, 0); | 51 | module_param(auto_update, bool, 0); |
51 | module_param(auto_update_freq, uint, 0644); | 52 | module_param(auto_update_freq, uint, 0644); |
52 | 53 | ||
53 | #ifdef DEBUG | 54 | #ifdef DEBUG |
54 | bool omapfb_debug; | 55 | unsigned int omapfb_debug; |
55 | module_param_named(debug, omapfb_debug, bool, 0644); | 56 | module_param_named(debug, omapfb_debug, bool, 0644); |
56 | static bool omapfb_test_pattern; | 57 | static unsigned int omapfb_test_pattern; |
57 | module_param_named(test, omapfb_test_pattern, bool, 0644); | 58 | module_param_named(test, omapfb_test_pattern, bool, 0644); |
58 | #endif | 59 | #endif |
59 | 60 | ||
@@ -178,7 +179,6 @@ static unsigned omapfb_get_vrfb_offset(const struct omapfb_info *ofbi, int rot) | |||
178 | break; | 179 | break; |
179 | default: | 180 | default: |
180 | BUG(); | 181 | BUG(); |
181 | return 0; | ||
182 | } | 182 | } |
183 | 183 | ||
184 | offset *= vrfb->bytespp; | 184 | offset *= vrfb->bytespp; |
@@ -732,12 +732,6 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) | |||
732 | var->lower_margin = timings.vfp; | 732 | var->lower_margin = timings.vfp; |
733 | var->hsync_len = timings.hsw; | 733 | var->hsync_len = timings.hsw; |
734 | var->vsync_len = timings.vsw; | 734 | var->vsync_len = timings.vsw; |
735 | var->sync |= timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH ? | ||
736 | FB_SYNC_HOR_HIGH_ACT : 0; | ||
737 | var->sync |= timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH ? | ||
738 | FB_SYNC_VERT_HIGH_ACT : 0; | ||
739 | var->vmode = timings.interlace ? | ||
740 | FB_VMODE_INTERLACED : FB_VMODE_NONINTERLACED; | ||
741 | } else { | 735 | } else { |
742 | var->pixclock = 0; | 736 | var->pixclock = 0; |
743 | var->left_margin = 0; | 737 | var->left_margin = 0; |
@@ -746,10 +740,12 @@ int check_fb_var(struct fb_info *fbi, struct fb_var_screeninfo *var) | |||
746 | var->lower_margin = 0; | 740 | var->lower_margin = 0; |
747 | var->hsync_len = 0; | 741 | var->hsync_len = 0; |
748 | var->vsync_len = 0; | 742 | var->vsync_len = 0; |
749 | var->sync = 0; | ||
750 | var->vmode = FB_VMODE_NONINTERLACED; | ||
751 | } | 743 | } |
752 | 744 | ||
745 | /* TODO: get these from panel->config */ | ||
746 | var->vmode = FB_VMODE_NONINTERLACED; | ||
747 | var->sync = 0; | ||
748 | |||
753 | return 0; | 749 | return 0; |
754 | } | 750 | } |
755 | 751 | ||
@@ -812,15 +808,19 @@ static unsigned calc_rotation_offset_vrfb(const struct fb_var_screeninfo *var, | |||
812 | static void omapfb_calc_addr(const struct omapfb_info *ofbi, | 808 | static void omapfb_calc_addr(const struct omapfb_info *ofbi, |
813 | const struct fb_var_screeninfo *var, | 809 | const struct fb_var_screeninfo *var, |
814 | const struct fb_fix_screeninfo *fix, | 810 | const struct fb_fix_screeninfo *fix, |
815 | int rotation, u32 *paddr) | 811 | int rotation, u32 *paddr, void __iomem **vaddr) |
816 | { | 812 | { |
817 | u32 data_start_p; | 813 | u32 data_start_p; |
814 | void __iomem *data_start_v; | ||
818 | int offset; | 815 | int offset; |
819 | 816 | ||
820 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | 817 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
821 | data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); | 818 | data_start_p = omapfb_get_region_rot_paddr(ofbi, rotation); |
822 | else | 819 | data_start_v = NULL; |
820 | } else { | ||
823 | data_start_p = omapfb_get_region_paddr(ofbi); | 821 | data_start_p = omapfb_get_region_paddr(ofbi); |
822 | data_start_v = omapfb_get_region_vaddr(ofbi); | ||
823 | } | ||
824 | 824 | ||
825 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | 825 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) |
826 | offset = calc_rotation_offset_vrfb(var, fix, rotation); | 826 | offset = calc_rotation_offset_vrfb(var, fix, rotation); |
@@ -828,14 +828,16 @@ static void omapfb_calc_addr(const struct omapfb_info *ofbi, | |||
828 | offset = calc_rotation_offset_dma(var, fix, rotation); | 828 | offset = calc_rotation_offset_dma(var, fix, rotation); |
829 | 829 | ||
830 | data_start_p += offset; | 830 | data_start_p += offset; |
831 | data_start_v += offset; | ||
831 | 832 | ||
832 | if (offset) | 833 | if (offset) |
833 | DBG("offset %d, %d = %d\n", | 834 | DBG("offset %d, %d = %d\n", |
834 | var->xoffset, var->yoffset, offset); | 835 | var->xoffset, var->yoffset, offset); |
835 | 836 | ||
836 | DBG("paddr %x\n", data_start_p); | 837 | DBG("paddr %x, vaddr %p\n", data_start_p, data_start_v); |
837 | 838 | ||
838 | *paddr = data_start_p; | 839 | *paddr = data_start_p; |
840 | *vaddr = data_start_v; | ||
839 | } | 841 | } |
840 | 842 | ||
841 | /* setup overlay according to the fb */ | 843 | /* setup overlay according to the fb */ |
@@ -848,6 +850,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | |||
848 | struct fb_fix_screeninfo *fix = &fbi->fix; | 850 | struct fb_fix_screeninfo *fix = &fbi->fix; |
849 | enum omap_color_mode mode = 0; | 851 | enum omap_color_mode mode = 0; |
850 | u32 data_start_p = 0; | 852 | u32 data_start_p = 0; |
853 | void __iomem *data_start_v = NULL; | ||
851 | struct omap_overlay_info info; | 854 | struct omap_overlay_info info; |
852 | int xres, yres; | 855 | int xres, yres; |
853 | int screen_width; | 856 | int screen_width; |
@@ -877,7 +880,8 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | |||
877 | } | 880 | } |
878 | 881 | ||
879 | if (ofbi->region->size) | 882 | if (ofbi->region->size) |
880 | omapfb_calc_addr(ofbi, var, fix, rotation, &data_start_p); | 883 | omapfb_calc_addr(ofbi, var, fix, rotation, |
884 | &data_start_p, &data_start_v); | ||
881 | 885 | ||
882 | r = fb_mode_to_dss_mode(var, &mode); | 886 | r = fb_mode_to_dss_mode(var, &mode); |
883 | if (r) { | 887 | if (r) { |
@@ -906,6 +910,7 @@ int omapfb_setup_overlay(struct fb_info *fbi, struct omap_overlay *ovl, | |||
906 | mirror = ofbi->mirror; | 910 | mirror = ofbi->mirror; |
907 | 911 | ||
908 | info.paddr = data_start_p; | 912 | info.paddr = data_start_p; |
913 | info.vaddr = data_start_v; | ||
909 | info.screen_width = screen_width; | 914 | info.screen_width = screen_width; |
910 | info.width = xres; | 915 | info.width = xres; |
911 | info.height = yres; | 916 | info.height = yres; |
@@ -974,20 +979,16 @@ int omapfb_apply_changes(struct fb_info *fbi, int init) | |||
974 | outh = var->yres; | 979 | outh = var->yres; |
975 | } | 980 | } |
976 | } else { | 981 | } else { |
977 | struct omap_overlay_info info; | 982 | outw = ovl->info.out_width; |
978 | ovl->get_overlay_info(ovl, &info); | 983 | outh = ovl->info.out_height; |
979 | outw = info.out_width; | ||
980 | outh = info.out_height; | ||
981 | } | 984 | } |
982 | 985 | ||
983 | if (init) { | 986 | if (init) { |
984 | posx = 0; | 987 | posx = 0; |
985 | posy = 0; | 988 | posy = 0; |
986 | } else { | 989 | } else { |
987 | struct omap_overlay_info info; | 990 | posx = ovl->info.pos_x; |
988 | ovl->get_overlay_info(ovl, &info); | 991 | posy = ovl->info.pos_y; |
989 | posx = info.pos_x; | ||
990 | posy = info.pos_y; | ||
991 | } | 992 | } |
992 | 993 | ||
993 | r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); | 994 | r = omapfb_setup_overlay(fbi, ovl, posx, posy, outw, outh); |
@@ -1126,7 +1127,7 @@ static int omapfb_mmap(struct fb_info *fbi, struct vm_area_struct *vma) | |||
1126 | DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off); | 1127 | DBG("user mmap region start %lx, len %d, off %lx\n", start, len, off); |
1127 | 1128 | ||
1128 | vma->vm_pgoff = off >> PAGE_SHIFT; | 1129 | vma->vm_pgoff = off >> PAGE_SHIFT; |
1129 | /* VM_IO | VM_DONTEXPAND | VM_DONTDUMP are set by remap_pfn_range() */ | 1130 | vma->vm_flags |= VM_IO | VM_RESERVED; |
1130 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); | 1131 | vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); |
1131 | vma->vm_ops = &mmap_user_ops; | 1132 | vma->vm_ops = &mmap_user_ops; |
1132 | vma->vm_private_data = rg; | 1133 | vma->vm_private_data = rg; |
@@ -1191,7 +1192,7 @@ static int _setcolreg(struct fb_info *fbi, u_int regno, u_int red, u_int green, | |||
1191 | break; | 1192 | break; |
1192 | 1193 | ||
1193 | if (regno < 16) { | 1194 | if (regno < 16) { |
1194 | u32 pal; | 1195 | u16 pal; |
1195 | pal = ((red >> (16 - var->red.length)) << | 1196 | pal = ((red >> (16 - var->red.length)) << |
1196 | var->red.offset) | | 1197 | var->red.offset) | |
1197 | ((green >> (16 - var->green.length)) << | 1198 | ((green >> (16 - var->green.length)) << |
@@ -1257,10 +1258,11 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1257 | 1258 | ||
1258 | switch (blank) { | 1259 | switch (blank) { |
1259 | case FB_BLANK_UNBLANK: | 1260 | case FB_BLANK_UNBLANK: |
1260 | if (display->state == OMAP_DSS_DISPLAY_ACTIVE) | 1261 | if (display->state != OMAP_DSS_DISPLAY_SUSPENDED) |
1261 | goto exit; | 1262 | goto exit; |
1262 | 1263 | ||
1263 | r = display->driver->enable(display); | 1264 | if (display->driver->resume) |
1265 | r = display->driver->resume(display); | ||
1264 | 1266 | ||
1265 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && | 1267 | if ((display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) && |
1266 | d->update_mode == OMAPFB_AUTO_UPDATE && | 1268 | d->update_mode == OMAPFB_AUTO_UPDATE && |
@@ -1281,7 +1283,8 @@ static int omapfb_blank(int blank, struct fb_info *fbi) | |||
1281 | if (d->auto_update_work_enabled) | 1283 | if (d->auto_update_work_enabled) |
1282 | omapfb_stop_auto_update(fbdev, display); | 1284 | omapfb_stop_auto_update(fbdev, display); |
1283 | 1285 | ||
1284 | display->driver->disable(display); | 1286 | if (display->driver->suspend) |
1287 | r = display->driver->suspend(display); | ||
1285 | 1288 | ||
1286 | break; | 1289 | break; |
1287 | 1290 | ||
@@ -1332,25 +1335,24 @@ static void omapfb_free_fbmem(struct fb_info *fbi) | |||
1332 | 1335 | ||
1333 | rg = ofbi->region; | 1336 | rg = ofbi->region; |
1334 | 1337 | ||
1335 | if (rg->token == NULL) | ||
1336 | return; | ||
1337 | |||
1338 | WARN_ON(atomic_read(&rg->map_count)); | 1338 | WARN_ON(atomic_read(&rg->map_count)); |
1339 | 1339 | ||
1340 | if (rg->paddr) | ||
1341 | if (omap_vram_free(rg->paddr, rg->size)) | ||
1342 | dev_err(fbdev->dev, "VRAM FREE failed\n"); | ||
1343 | |||
1344 | if (rg->vaddr) | ||
1345 | iounmap(rg->vaddr); | ||
1346 | |||
1340 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | 1347 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { |
1341 | /* unmap the 0 angle rotation */ | 1348 | /* unmap the 0 angle rotation */ |
1342 | if (rg->vrfb.vaddr[0]) { | 1349 | if (rg->vrfb.vaddr[0]) { |
1343 | iounmap(rg->vrfb.vaddr[0]); | 1350 | iounmap(rg->vrfb.vaddr[0]); |
1351 | omap_vrfb_release_ctx(&rg->vrfb); | ||
1344 | rg->vrfb.vaddr[0] = NULL; | 1352 | rg->vrfb.vaddr[0] = NULL; |
1345 | } | 1353 | } |
1346 | |||
1347 | omap_vrfb_release_ctx(&rg->vrfb); | ||
1348 | } | 1354 | } |
1349 | 1355 | ||
1350 | dma_free_attrs(fbdev->dev, rg->size, rg->token, rg->dma_handle, | ||
1351 | &rg->attrs); | ||
1352 | |||
1353 | rg->token = NULL; | ||
1354 | rg->vaddr = NULL; | 1356 | rg->vaddr = NULL; |
1355 | rg->paddr = 0; | 1357 | rg->paddr = 0; |
1356 | rg->alloc = 0; | 1358 | rg->alloc = 0; |
@@ -1385,9 +1387,7 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
1385 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1387 | struct omapfb_info *ofbi = FB2OFB(fbi); |
1386 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1388 | struct omapfb2_device *fbdev = ofbi->fbdev; |
1387 | struct omapfb2_mem_region *rg; | 1389 | struct omapfb2_mem_region *rg; |
1388 | void *token; | 1390 | void __iomem *vaddr; |
1389 | DEFINE_DMA_ATTRS(attrs); | ||
1390 | dma_addr_t dma_handle; | ||
1391 | int r; | 1391 | int r; |
1392 | 1392 | ||
1393 | rg = ofbi->region; | 1393 | rg = ofbi->region; |
@@ -1402,40 +1402,42 @@ static int omapfb_alloc_fbmem(struct fb_info *fbi, unsigned long size, | |||
1402 | 1402 | ||
1403 | size = PAGE_ALIGN(size); | 1403 | size = PAGE_ALIGN(size); |
1404 | 1404 | ||
1405 | dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs); | 1405 | if (!paddr) { |
1406 | 1406 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | |
1407 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) | 1407 | r = omap_vram_alloc(OMAP_VRAM_MEMTYPE_SDRAM, size, &paddr); |
1408 | dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs); | 1408 | } else { |
1409 | 1409 | DBG("reserving %lu bytes at %lx for fb %d\n", size, paddr, | |
1410 | DBG("allocating %lu bytes for fb %d\n", size, ofbi->id); | 1410 | ofbi->id); |
1411 | 1411 | r = omap_vram_reserve(paddr, size); | |
1412 | token = dma_alloc_attrs(fbdev->dev, size, &dma_handle, | 1412 | } |
1413 | GFP_KERNEL, &attrs); | ||
1414 | 1413 | ||
1415 | if (token == NULL) { | 1414 | if (r) { |
1416 | dev_err(fbdev->dev, "failed to allocate framebuffer\n"); | 1415 | dev_err(fbdev->dev, "failed to allocate framebuffer\n"); |
1417 | return -ENOMEM; | 1416 | return -ENOMEM; |
1418 | } | 1417 | } |
1419 | 1418 | ||
1420 | DBG("allocated VRAM paddr %lx, vaddr %p\n", | 1419 | if (ofbi->rotation_type != OMAP_DSS_ROT_VRFB) { |
1421 | (unsigned long)dma_handle, token); | 1420 | vaddr = ioremap_wc(paddr, size); |
1422 | 1421 | ||
1423 | if (ofbi->rotation_type == OMAP_DSS_ROT_VRFB) { | 1422 | if (!vaddr) { |
1423 | dev_err(fbdev->dev, "failed to ioremap framebuffer\n"); | ||
1424 | omap_vram_free(paddr, size); | ||
1425 | return -ENOMEM; | ||
1426 | } | ||
1427 | |||
1428 | DBG("allocated VRAM paddr %lx, vaddr %p\n", paddr, vaddr); | ||
1429 | } else { | ||
1424 | r = omap_vrfb_request_ctx(&rg->vrfb); | 1430 | r = omap_vrfb_request_ctx(&rg->vrfb); |
1425 | if (r) { | 1431 | if (r) { |
1426 | dma_free_attrs(fbdev->dev, size, token, dma_handle, | ||
1427 | &attrs); | ||
1428 | dev_err(fbdev->dev, "vrfb create ctx failed\n"); | 1432 | dev_err(fbdev->dev, "vrfb create ctx failed\n"); |
1429 | return r; | 1433 | return r; |
1430 | } | 1434 | } |
1431 | } | ||
1432 | 1435 | ||
1433 | rg->attrs = attrs; | 1436 | vaddr = NULL; |
1434 | rg->token = token; | 1437 | } |
1435 | rg->dma_handle = dma_handle; | ||
1436 | 1438 | ||
1437 | rg->paddr = (unsigned long)dma_handle; | 1439 | rg->paddr = paddr; |
1438 | rg->vaddr = (void __iomem *)token; | 1440 | rg->vaddr = vaddr; |
1439 | rg->size = size; | 1441 | rg->size = size; |
1440 | rg->alloc = 1; | 1442 | rg->alloc = 1; |
1441 | 1443 | ||
@@ -1490,6 +1492,60 @@ static int omapfb_alloc_fbmem_display(struct fb_info *fbi, unsigned long size, | |||
1490 | return omapfb_alloc_fbmem(fbi, size, paddr); | 1492 | return omapfb_alloc_fbmem(fbi, size, paddr); |
1491 | } | 1493 | } |
1492 | 1494 | ||
1495 | static enum omap_color_mode fb_format_to_dss_mode(enum omapfb_color_format fmt) | ||
1496 | { | ||
1497 | enum omap_color_mode mode; | ||
1498 | |||
1499 | switch (fmt) { | ||
1500 | case OMAPFB_COLOR_RGB565: | ||
1501 | mode = OMAP_DSS_COLOR_RGB16; | ||
1502 | break; | ||
1503 | case OMAPFB_COLOR_YUV422: | ||
1504 | mode = OMAP_DSS_COLOR_YUV2; | ||
1505 | break; | ||
1506 | case OMAPFB_COLOR_CLUT_8BPP: | ||
1507 | mode = OMAP_DSS_COLOR_CLUT8; | ||
1508 | break; | ||
1509 | case OMAPFB_COLOR_CLUT_4BPP: | ||
1510 | mode = OMAP_DSS_COLOR_CLUT4; | ||
1511 | break; | ||
1512 | case OMAPFB_COLOR_CLUT_2BPP: | ||
1513 | mode = OMAP_DSS_COLOR_CLUT2; | ||
1514 | break; | ||
1515 | case OMAPFB_COLOR_CLUT_1BPP: | ||
1516 | mode = OMAP_DSS_COLOR_CLUT1; | ||
1517 | break; | ||
1518 | case OMAPFB_COLOR_RGB444: | ||
1519 | mode = OMAP_DSS_COLOR_RGB12U; | ||
1520 | break; | ||
1521 | case OMAPFB_COLOR_YUY422: | ||
1522 | mode = OMAP_DSS_COLOR_UYVY; | ||
1523 | break; | ||
1524 | case OMAPFB_COLOR_ARGB16: | ||
1525 | mode = OMAP_DSS_COLOR_ARGB16; | ||
1526 | break; | ||
1527 | case OMAPFB_COLOR_RGB24U: | ||
1528 | mode = OMAP_DSS_COLOR_RGB24U; | ||
1529 | break; | ||
1530 | case OMAPFB_COLOR_RGB24P: | ||
1531 | mode = OMAP_DSS_COLOR_RGB24P; | ||
1532 | break; | ||
1533 | case OMAPFB_COLOR_ARGB32: | ||
1534 | mode = OMAP_DSS_COLOR_ARGB32; | ||
1535 | break; | ||
1536 | case OMAPFB_COLOR_RGBA32: | ||
1537 | mode = OMAP_DSS_COLOR_RGBA32; | ||
1538 | break; | ||
1539 | case OMAPFB_COLOR_RGBX32: | ||
1540 | mode = OMAP_DSS_COLOR_RGBX32; | ||
1541 | break; | ||
1542 | default: | ||
1543 | mode = -EINVAL; | ||
1544 | } | ||
1545 | |||
1546 | return mode; | ||
1547 | } | ||
1548 | |||
1493 | static int omapfb_parse_vram_param(const char *param, int max_entries, | 1549 | static int omapfb_parse_vram_param(const char *param, int max_entries, |
1494 | unsigned long *sizes, unsigned long *paddrs) | 1550 | unsigned long *sizes, unsigned long *paddrs) |
1495 | { | 1551 | { |
@@ -1505,7 +1561,7 @@ static int omapfb_parse_vram_param(const char *param, int max_entries, | |||
1505 | 1561 | ||
1506 | fbnum = simple_strtoul(p, &p, 10); | 1562 | fbnum = simple_strtoul(p, &p, 10); |
1507 | 1563 | ||
1508 | if (p == start) | 1564 | if (p == param) |
1509 | return -EINVAL; | 1565 | return -EINVAL; |
1510 | 1566 | ||
1511 | if (*p != ':') | 1567 | if (*p != ':') |
@@ -1529,9 +1585,6 @@ static int omapfb_parse_vram_param(const char *param, int max_entries, | |||
1529 | 1585 | ||
1530 | } | 1586 | } |
1531 | 1587 | ||
1532 | WARN_ONCE(paddr, | ||
1533 | "reserving memory at predefined address not supported\n"); | ||
1534 | |||
1535 | paddrs[fbnum] = paddr; | 1588 | paddrs[fbnum] = paddr; |
1536 | sizes[fbnum] = size; | 1589 | sizes[fbnum] = size; |
1537 | 1590 | ||
@@ -1566,6 +1619,23 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) | |||
1566 | memset(&vram_paddrs, 0, sizeof(vram_paddrs)); | 1619 | memset(&vram_paddrs, 0, sizeof(vram_paddrs)); |
1567 | } | 1620 | } |
1568 | 1621 | ||
1622 | if (fbdev->dev->platform_data) { | ||
1623 | struct omapfb_platform_data *opd; | ||
1624 | opd = fbdev->dev->platform_data; | ||
1625 | for (i = 0; i < opd->mem_desc.region_cnt; ++i) { | ||
1626 | if (!vram_sizes[i]) { | ||
1627 | unsigned long size; | ||
1628 | unsigned long paddr; | ||
1629 | |||
1630 | size = opd->mem_desc.region[i].size; | ||
1631 | paddr = opd->mem_desc.region[i].paddr; | ||
1632 | |||
1633 | vram_sizes[i] = size; | ||
1634 | vram_paddrs[i] = paddr; | ||
1635 | } | ||
1636 | } | ||
1637 | } | ||
1638 | |||
1569 | for (i = 0; i < fbdev->num_fbs; i++) { | 1639 | for (i = 0; i < fbdev->num_fbs; i++) { |
1570 | /* allocate memory automatically only for fb0, or if | 1640 | /* allocate memory automatically only for fb0, or if |
1571 | * excplicitly defined with vram or plat data option */ | 1641 | * excplicitly defined with vram or plat data option */ |
@@ -1593,31 +1663,18 @@ static int omapfb_allocate_all_fbs(struct omapfb2_device *fbdev) | |||
1593 | return 0; | 1663 | return 0; |
1594 | } | 1664 | } |
1595 | 1665 | ||
1596 | static void omapfb_clear_fb(struct fb_info *fbi) | ||
1597 | { | ||
1598 | const struct fb_fillrect rect = { | ||
1599 | .dx = 0, | ||
1600 | .dy = 0, | ||
1601 | .width = fbi->var.xres_virtual, | ||
1602 | .height = fbi->var.yres_virtual, | ||
1603 | .color = 0, | ||
1604 | .rop = ROP_COPY, | ||
1605 | }; | ||
1606 | |||
1607 | cfb_fillrect(fbi, &rect); | ||
1608 | } | ||
1609 | |||
1610 | int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | 1666 | int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) |
1611 | { | 1667 | { |
1612 | struct omapfb_info *ofbi = FB2OFB(fbi); | 1668 | struct omapfb_info *ofbi = FB2OFB(fbi); |
1613 | struct omapfb2_device *fbdev = ofbi->fbdev; | 1669 | struct omapfb2_device *fbdev = ofbi->fbdev; |
1670 | struct omap_dss_device *display = fb2display(fbi); | ||
1614 | struct omapfb2_mem_region *rg = ofbi->region; | 1671 | struct omapfb2_mem_region *rg = ofbi->region; |
1615 | unsigned long old_size = rg->size; | 1672 | unsigned long old_size = rg->size; |
1616 | unsigned long old_paddr = rg->paddr; | 1673 | unsigned long old_paddr = rg->paddr; |
1617 | int old_type = rg->type; | 1674 | int old_type = rg->type; |
1618 | int r; | 1675 | int r; |
1619 | 1676 | ||
1620 | if (type != OMAPFB_MEMTYPE_SDRAM) | 1677 | if (type > OMAPFB_MEMTYPE_MAX) |
1621 | return -EINVAL; | 1678 | return -EINVAL; |
1622 | 1679 | ||
1623 | size = PAGE_ALIGN(size); | 1680 | size = PAGE_ALIGN(size); |
@@ -1625,6 +1682,9 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
1625 | if (old_size == size && old_type == type) | 1682 | if (old_size == size && old_type == type) |
1626 | return 0; | 1683 | return 0; |
1627 | 1684 | ||
1685 | if (display && display->driver->sync) | ||
1686 | display->driver->sync(display); | ||
1687 | |||
1628 | omapfb_free_fbmem(fbi); | 1688 | omapfb_free_fbmem(fbi); |
1629 | 1689 | ||
1630 | if (size == 0) { | 1690 | if (size == 0) { |
@@ -1672,8 +1732,6 @@ int omapfb_realloc_fbmem(struct fb_info *fbi, unsigned long size, int type) | |||
1672 | goto err; | 1732 | goto err; |
1673 | } | 1733 | } |
1674 | 1734 | ||
1675 | omapfb_clear_fb(fbi); | ||
1676 | |||
1677 | return 0; | 1735 | return 0; |
1678 | err: | 1736 | err: |
1679 | omapfb_free_fbmem(fbi); | 1737 | omapfb_free_fbmem(fbi); |
@@ -1775,6 +1833,32 @@ static int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi) | |||
1775 | 1833 | ||
1776 | var->rotate = def_rotate; | 1834 | var->rotate = def_rotate; |
1777 | 1835 | ||
1836 | /* | ||
1837 | * Check if there is a default color format set in the board file, | ||
1838 | * and use this format instead the default deducted from the | ||
1839 | * display bpp. | ||
1840 | */ | ||
1841 | if (fbdev->dev->platform_data) { | ||
1842 | struct omapfb_platform_data *opd; | ||
1843 | int id = ofbi->id; | ||
1844 | |||
1845 | opd = fbdev->dev->platform_data; | ||
1846 | if (opd->mem_desc.region[id].format_used) { | ||
1847 | enum omap_color_mode mode; | ||
1848 | enum omapfb_color_format format; | ||
1849 | |||
1850 | format = opd->mem_desc.region[id].format; | ||
1851 | mode = fb_format_to_dss_mode(format); | ||
1852 | if (mode < 0) { | ||
1853 | r = mode; | ||
1854 | goto err; | ||
1855 | } | ||
1856 | r = dss_mode_to_fb_mode(mode, var); | ||
1857 | if (r < 0) | ||
1858 | goto err; | ||
1859 | } | ||
1860 | } | ||
1861 | |||
1778 | if (display) { | 1862 | if (display) { |
1779 | u16 w, h; | 1863 | u16 w, h; |
1780 | int rotation = (var->rotate + ofbi->rotation[0]) % 4; | 1864 | int rotation = (var->rotate + ofbi->rotation[0]) % 4; |
@@ -1879,6 +1963,7 @@ static void omapfb_free_resources(struct omapfb2_device *fbdev) | |||
1879 | } | 1963 | } |
1880 | 1964 | ||
1881 | dev_set_drvdata(fbdev->dev, NULL); | 1965 | dev_set_drvdata(fbdev->dev, NULL); |
1966 | kfree(fbdev); | ||
1882 | } | 1967 | } |
1883 | 1968 | ||
1884 | static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | 1969 | static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) |
@@ -1957,16 +2042,6 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
1957 | } | 2042 | } |
1958 | } | 2043 | } |
1959 | 2044 | ||
1960 | for (i = 0; i < fbdev->num_fbs; i++) { | ||
1961 | struct fb_info *fbi = fbdev->fbs[i]; | ||
1962 | struct omapfb_info *ofbi = FB2OFB(fbi); | ||
1963 | |||
1964 | if (ofbi->region->size == 0) | ||
1965 | continue; | ||
1966 | |||
1967 | omapfb_clear_fb(fbi); | ||
1968 | } | ||
1969 | |||
1970 | DBG("fb_infos initialized\n"); | 2045 | DBG("fb_infos initialized\n"); |
1971 | 2046 | ||
1972 | for (i = 0; i < fbdev->num_fbs; i++) { | 2047 | for (i = 0; i < fbdev->num_fbs; i++) { |
@@ -2001,8 +2076,6 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
2001 | if (ofbi->num_overlays > 0) { | 2076 | if (ofbi->num_overlays > 0) { |
2002 | struct omap_overlay *ovl = ofbi->overlays[0]; | 2077 | struct omap_overlay *ovl = ofbi->overlays[0]; |
2003 | 2078 | ||
2004 | ovl->manager->apply(ovl->manager); | ||
2005 | |||
2006 | r = omapfb_overlay_enable(ovl, 1); | 2079 | r = omapfb_overlay_enable(ovl, 1); |
2007 | 2080 | ||
2008 | if (r) { | 2081 | if (r) { |
@@ -2019,7 +2092,6 @@ static int omapfb_create_framebuffers(struct omapfb2_device *fbdev) | |||
2019 | } | 2092 | } |
2020 | 2093 | ||
2021 | static int omapfb_mode_to_timings(const char *mode_str, | 2094 | static int omapfb_mode_to_timings(const char *mode_str, |
2022 | struct omap_dss_device *display, | ||
2023 | struct omap_video_timings *timings, u8 *bpp) | 2095 | struct omap_video_timings *timings, u8 *bpp) |
2024 | { | 2096 | { |
2025 | struct fb_info *fbi; | 2097 | struct fb_info *fbi; |
@@ -2073,14 +2145,6 @@ static int omapfb_mode_to_timings(const char *mode_str, | |||
2073 | goto err; | 2145 | goto err; |
2074 | } | 2146 | } |
2075 | 2147 | ||
2076 | if (display->driver->get_timings) { | ||
2077 | display->driver->get_timings(display, timings); | ||
2078 | } else { | ||
2079 | timings->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | ||
2080 | timings->de_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
2081 | timings->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
2082 | } | ||
2083 | |||
2084 | timings->pixel_clock = PICOS2KHZ(var->pixclock); | 2148 | timings->pixel_clock = PICOS2KHZ(var->pixclock); |
2085 | timings->hbp = var->left_margin; | 2149 | timings->hbp = var->left_margin; |
2086 | timings->hfp = var->right_margin; | 2150 | timings->hfp = var->right_margin; |
@@ -2090,13 +2154,6 @@ static int omapfb_mode_to_timings(const char *mode_str, | |||
2090 | timings->vsw = var->vsync_len; | 2154 | timings->vsw = var->vsync_len; |
2091 | timings->x_res = var->xres; | 2155 | timings->x_res = var->xres; |
2092 | timings->y_res = var->yres; | 2156 | timings->y_res = var->yres; |
2093 | timings->hsync_level = var->sync & FB_SYNC_HOR_HIGH_ACT ? | ||
2094 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
2095 | OMAPDSS_SIG_ACTIVE_LOW; | ||
2096 | timings->vsync_level = var->sync & FB_SYNC_VERT_HIGH_ACT ? | ||
2097 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
2098 | OMAPDSS_SIG_ACTIVE_LOW; | ||
2099 | timings->interlace = var->vmode & FB_VMODE_INTERLACED; | ||
2100 | 2157 | ||
2101 | switch (var->bits_per_pixel) { | 2158 | switch (var->bits_per_pixel) { |
2102 | case 16: | 2159 | case 16: |
@@ -2127,7 +2184,7 @@ static int omapfb_set_def_mode(struct omapfb2_device *fbdev, | |||
2127 | struct omap_video_timings timings, temp_timings; | 2184 | struct omap_video_timings timings, temp_timings; |
2128 | struct omapfb_display_data *d; | 2185 | struct omapfb_display_data *d; |
2129 | 2186 | ||
2130 | r = omapfb_mode_to_timings(mode_str, display, &timings, &bpp); | 2187 | r = omapfb_mode_to_timings(mode_str, &timings, &bpp); |
2131 | if (r) | 2188 | if (r) |
2132 | return r; | 2189 | return r; |
2133 | 2190 | ||
@@ -2219,110 +2276,6 @@ static int omapfb_parse_def_modes(struct omapfb2_device *fbdev) | |||
2219 | return r; | 2276 | return r; |
2220 | } | 2277 | } |
2221 | 2278 | ||
2222 | static void fb_videomode_to_omap_timings(struct fb_videomode *m, | ||
2223 | struct omap_dss_device *display, | ||
2224 | struct omap_video_timings *t) | ||
2225 | { | ||
2226 | if (display->driver->get_timings) { | ||
2227 | display->driver->get_timings(display, t); | ||
2228 | } else { | ||
2229 | t->data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE; | ||
2230 | t->de_level = OMAPDSS_SIG_ACTIVE_HIGH; | ||
2231 | t->sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES; | ||
2232 | } | ||
2233 | |||
2234 | t->x_res = m->xres; | ||
2235 | t->y_res = m->yres; | ||
2236 | t->pixel_clock = PICOS2KHZ(m->pixclock); | ||
2237 | t->hsw = m->hsync_len; | ||
2238 | t->hfp = m->right_margin; | ||
2239 | t->hbp = m->left_margin; | ||
2240 | t->vsw = m->vsync_len; | ||
2241 | t->vfp = m->lower_margin; | ||
2242 | t->vbp = m->upper_margin; | ||
2243 | t->hsync_level = m->sync & FB_SYNC_HOR_HIGH_ACT ? | ||
2244 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
2245 | OMAPDSS_SIG_ACTIVE_LOW; | ||
2246 | t->vsync_level = m->sync & FB_SYNC_VERT_HIGH_ACT ? | ||
2247 | OMAPDSS_SIG_ACTIVE_HIGH : | ||
2248 | OMAPDSS_SIG_ACTIVE_LOW; | ||
2249 | t->interlace = m->vmode & FB_VMODE_INTERLACED; | ||
2250 | } | ||
2251 | |||
2252 | static int omapfb_find_best_mode(struct omap_dss_device *display, | ||
2253 | struct omap_video_timings *timings) | ||
2254 | { | ||
2255 | struct fb_monspecs *specs; | ||
2256 | u8 *edid; | ||
2257 | int r, i, best_idx, len; | ||
2258 | |||
2259 | if (!display->driver->read_edid) | ||
2260 | return -ENODEV; | ||
2261 | |||
2262 | len = 0x80 * 2; | ||
2263 | edid = kmalloc(len, GFP_KERNEL); | ||
2264 | if (edid == NULL) | ||
2265 | return -ENOMEM; | ||
2266 | |||
2267 | r = display->driver->read_edid(display, edid, len); | ||
2268 | if (r < 0) | ||
2269 | goto err1; | ||
2270 | |||
2271 | specs = kzalloc(sizeof(*specs), GFP_KERNEL); | ||
2272 | if (specs == NULL) { | ||
2273 | r = -ENOMEM; | ||
2274 | goto err1; | ||
2275 | } | ||
2276 | |||
2277 | fb_edid_to_monspecs(edid, specs); | ||
2278 | |||
2279 | best_idx = -1; | ||
2280 | |||
2281 | for (i = 0; i < specs->modedb_len; ++i) { | ||
2282 | struct fb_videomode *m; | ||
2283 | struct omap_video_timings t; | ||
2284 | |||
2285 | m = &specs->modedb[i]; | ||
2286 | |||
2287 | if (m->pixclock == 0) | ||
2288 | continue; | ||
2289 | |||
2290 | /* skip repeated pixel modes */ | ||
2291 | if (m->xres == 2880 || m->xres == 1440) | ||
2292 | continue; | ||
2293 | |||
2294 | if (m->vmode & FB_VMODE_INTERLACED || | ||
2295 | m->vmode & FB_VMODE_DOUBLE) | ||
2296 | continue; | ||
2297 | |||
2298 | fb_videomode_to_omap_timings(m, display, &t); | ||
2299 | |||
2300 | r = display->driver->check_timings(display, &t); | ||
2301 | if (r == 0) { | ||
2302 | best_idx = i; | ||
2303 | break; | ||
2304 | } | ||
2305 | } | ||
2306 | |||
2307 | if (best_idx == -1) { | ||
2308 | r = -ENOENT; | ||
2309 | goto err2; | ||
2310 | } | ||
2311 | |||
2312 | fb_videomode_to_omap_timings(&specs->modedb[best_idx], display, | ||
2313 | timings); | ||
2314 | |||
2315 | r = 0; | ||
2316 | |||
2317 | err2: | ||
2318 | fb_destroy_modedb(specs->modedb); | ||
2319 | kfree(specs); | ||
2320 | err1: | ||
2321 | kfree(edid); | ||
2322 | |||
2323 | return r; | ||
2324 | } | ||
2325 | |||
2326 | static int omapfb_init_display(struct omapfb2_device *fbdev, | 2279 | static int omapfb_init_display(struct omapfb2_device *fbdev, |
2327 | struct omap_dss_device *dssdev) | 2280 | struct omap_dss_device *dssdev) |
2328 | { | 2281 | { |
@@ -2373,60 +2326,12 @@ static int omapfb_init_display(struct omapfb2_device *fbdev, | |||
2373 | return 0; | 2326 | return 0; |
2374 | } | 2327 | } |
2375 | 2328 | ||
2376 | static int omapfb_init_connections(struct omapfb2_device *fbdev, | 2329 | static int omapfb_probe(struct platform_device *pdev) |
2377 | struct omap_dss_device *def_dssdev) | ||
2378 | { | ||
2379 | int i, r; | ||
2380 | struct omap_overlay_manager *mgr; | ||
2381 | |||
2382 | if (!def_dssdev->output) { | ||
2383 | dev_err(fbdev->dev, "no output for the default display\n"); | ||
2384 | return -EINVAL; | ||
2385 | } | ||
2386 | |||
2387 | for (i = 0; i < fbdev->num_displays; ++i) { | ||
2388 | struct omap_dss_device *dssdev = fbdev->displays[i].dssdev; | ||
2389 | struct omap_dss_output *out = dssdev->output; | ||
2390 | |||
2391 | mgr = omap_dss_get_overlay_manager(dssdev->channel); | ||
2392 | |||
2393 | if (!mgr || !out) | ||
2394 | continue; | ||
2395 | |||
2396 | if (mgr->output) | ||
2397 | mgr->unset_output(mgr); | ||
2398 | |||
2399 | mgr->set_output(mgr, out); | ||
2400 | } | ||
2401 | |||
2402 | mgr = def_dssdev->output->manager; | ||
2403 | |||
2404 | if (!mgr) { | ||
2405 | dev_err(fbdev->dev, "no ovl manager for the default display\n"); | ||
2406 | return -EINVAL; | ||
2407 | } | ||
2408 | |||
2409 | for (i = 0; i < fbdev->num_overlays; i++) { | ||
2410 | struct omap_overlay *ovl = fbdev->overlays[i]; | ||
2411 | |||
2412 | if (ovl->manager) | ||
2413 | ovl->unset_manager(ovl); | ||
2414 | |||
2415 | r = ovl->set_manager(ovl, mgr); | ||
2416 | if (r) | ||
2417 | dev_warn(fbdev->dev, | ||
2418 | "failed to connect overlay %s to manager %s\n", | ||
2419 | ovl->name, mgr->name); | ||
2420 | } | ||
2421 | |||
2422 | return 0; | ||
2423 | } | ||
2424 | |||
2425 | static int __init omapfb_probe(struct platform_device *pdev) | ||
2426 | { | 2330 | { |
2427 | struct omapfb2_device *fbdev = NULL; | 2331 | struct omapfb2_device *fbdev = NULL; |
2428 | int r = 0; | 2332 | int r = 0; |
2429 | int i; | 2333 | int i; |
2334 | struct omap_overlay *ovl; | ||
2430 | struct omap_dss_device *def_display; | 2335 | struct omap_dss_device *def_display; |
2431 | struct omap_dss_device *dssdev; | 2336 | struct omap_dss_device *dssdev; |
2432 | 2337 | ||
@@ -2438,28 +2343,28 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2438 | goto err0; | 2343 | goto err0; |
2439 | } | 2344 | } |
2440 | 2345 | ||
2441 | fbdev = devm_kzalloc(&pdev->dev, sizeof(struct omapfb2_device), | 2346 | fbdev = kzalloc(sizeof(struct omapfb2_device), GFP_KERNEL); |
2442 | GFP_KERNEL); | ||
2443 | if (fbdev == NULL) { | 2347 | if (fbdev == NULL) { |
2444 | r = -ENOMEM; | 2348 | r = -ENOMEM; |
2445 | goto err0; | 2349 | goto err0; |
2446 | } | 2350 | } |
2447 | 2351 | ||
2448 | if (def_vrfb && !omap_vrfb_supported()) { | 2352 | /* TODO : Replace cpu check with omap_has_vrfb once HAS_FEATURE |
2353 | * available for OMAP2 and OMAP3 | ||
2354 | */ | ||
2355 | if (def_vrfb && !cpu_is_omap24xx() && !cpu_is_omap34xx()) { | ||
2449 | def_vrfb = 0; | 2356 | def_vrfb = 0; |
2450 | dev_warn(&pdev->dev, "VRFB is not supported on this hardware, " | 2357 | dev_warn(&pdev->dev, "VRFB is not supported on this hardware, " |
2451 | "ignoring the module parameter vrfb=y\n"); | 2358 | "ignoring the module parameter vrfb=y\n"); |
2452 | } | 2359 | } |
2453 | 2360 | ||
2454 | r = omapdss_compat_init(); | ||
2455 | if (r) | ||
2456 | goto err0; | ||
2457 | 2361 | ||
2458 | mutex_init(&fbdev->mtx); | 2362 | mutex_init(&fbdev->mtx); |
2459 | 2363 | ||
2460 | fbdev->dev = &pdev->dev; | 2364 | fbdev->dev = &pdev->dev; |
2461 | platform_set_drvdata(pdev, fbdev); | 2365 | platform_set_drvdata(pdev, fbdev); |
2462 | 2366 | ||
2367 | r = 0; | ||
2463 | fbdev->num_displays = 0; | 2368 | fbdev->num_displays = 0; |
2464 | dssdev = NULL; | 2369 | dssdev = NULL; |
2465 | for_each_dss_dev(dssdev) { | 2370 | for_each_dss_dev(dssdev) { |
@@ -2468,10 +2373,8 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2468 | omap_dss_get_device(dssdev); | 2373 | omap_dss_get_device(dssdev); |
2469 | 2374 | ||
2470 | if (!dssdev->driver) { | 2375 | if (!dssdev->driver) { |
2471 | dev_warn(&pdev->dev, "no driver for display: %s\n", | 2376 | dev_err(&pdev->dev, "no driver for display\n"); |
2472 | dssdev->name); | 2377 | r = -ENODEV; |
2473 | omap_dss_put_device(dssdev); | ||
2474 | continue; | ||
2475 | } | 2378 | } |
2476 | 2379 | ||
2477 | d = &fbdev->displays[fbdev->num_displays++]; | 2380 | d = &fbdev->displays[fbdev->num_displays++]; |
@@ -2482,6 +2385,9 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2482 | d->update_mode = OMAPFB_AUTO_UPDATE; | 2385 | d->update_mode = OMAPFB_AUTO_UPDATE; |
2483 | } | 2386 | } |
2484 | 2387 | ||
2388 | if (r) | ||
2389 | goto cleanup; | ||
2390 | |||
2485 | if (fbdev->num_displays == 0) { | 2391 | if (fbdev->num_displays == 0) { |
2486 | dev_err(&pdev->dev, "no displays\n"); | 2392 | dev_err(&pdev->dev, "no displays\n"); |
2487 | r = -EINVAL; | 2393 | r = -EINVAL; |
@@ -2496,46 +2402,9 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2496 | for (i = 0; i < fbdev->num_managers; i++) | 2402 | for (i = 0; i < fbdev->num_managers; i++) |
2497 | fbdev->managers[i] = omap_dss_get_overlay_manager(i); | 2403 | fbdev->managers[i] = omap_dss_get_overlay_manager(i); |
2498 | 2404 | ||
2499 | def_display = NULL; | ||
2500 | |||
2501 | for (i = 0; i < fbdev->num_displays; ++i) { | ||
2502 | struct omap_dss_device *dssdev; | ||
2503 | const char *def_name; | ||
2504 | |||
2505 | def_name = omapdss_get_default_display_name(); | ||
2506 | |||
2507 | dssdev = fbdev->displays[i].dssdev; | ||
2508 | |||
2509 | if (def_name == NULL || | ||
2510 | (dssdev->name && strcmp(def_name, dssdev->name) == 0)) { | ||
2511 | def_display = dssdev; | ||
2512 | break; | ||
2513 | } | ||
2514 | } | ||
2515 | |||
2516 | if (def_display == NULL) { | ||
2517 | dev_err(fbdev->dev, "failed to find default display\n"); | ||
2518 | r = -EINVAL; | ||
2519 | goto cleanup; | ||
2520 | } | ||
2521 | |||
2522 | r = omapfb_init_connections(fbdev, def_display); | ||
2523 | if (r) { | ||
2524 | dev_err(fbdev->dev, "failed to init overlay connections\n"); | ||
2525 | goto cleanup; | ||
2526 | } | ||
2527 | |||
2528 | if (def_mode && strlen(def_mode) > 0) { | 2405 | if (def_mode && strlen(def_mode) > 0) { |
2529 | if (omapfb_parse_def_modes(fbdev)) | 2406 | if (omapfb_parse_def_modes(fbdev)) |
2530 | dev_warn(&pdev->dev, "cannot parse default modes\n"); | 2407 | dev_warn(&pdev->dev, "cannot parse default modes\n"); |
2531 | } else if (def_display && def_display->driver->set_timings && | ||
2532 | def_display->driver->check_timings) { | ||
2533 | struct omap_video_timings t; | ||
2534 | |||
2535 | r = omapfb_find_best_mode(def_display, &t); | ||
2536 | |||
2537 | if (r == 0) | ||
2538 | def_display->driver->set_timings(def_display, &t); | ||
2539 | } | 2408 | } |
2540 | 2409 | ||
2541 | r = omapfb_create_framebuffers(fbdev); | 2410 | r = omapfb_create_framebuffers(fbdev); |
@@ -2552,6 +2421,16 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2552 | 2421 | ||
2553 | DBG("mgr->apply'ed\n"); | 2422 | DBG("mgr->apply'ed\n"); |
2554 | 2423 | ||
2424 | /* gfx overlay should be the default one. find a display | ||
2425 | * connected to that, and use it as default display */ | ||
2426 | ovl = omap_dss_get_overlay(0); | ||
2427 | if (ovl->manager && ovl->manager->device) { | ||
2428 | def_display = ovl->manager->device; | ||
2429 | } else { | ||
2430 | dev_warn(&pdev->dev, "cannot find default display\n"); | ||
2431 | def_display = NULL; | ||
2432 | } | ||
2433 | |||
2555 | if (def_display) { | 2434 | if (def_display) { |
2556 | r = omapfb_init_display(fbdev, def_display); | 2435 | r = omapfb_init_display(fbdev, def_display); |
2557 | if (r) { | 2436 | if (r) { |
@@ -2573,13 +2452,12 @@ static int __init omapfb_probe(struct platform_device *pdev) | |||
2573 | 2452 | ||
2574 | cleanup: | 2453 | cleanup: |
2575 | omapfb_free_resources(fbdev); | 2454 | omapfb_free_resources(fbdev); |
2576 | omapdss_compat_uninit(); | ||
2577 | err0: | 2455 | err0: |
2578 | dev_err(&pdev->dev, "failed to setup omapfb\n"); | 2456 | dev_err(&pdev->dev, "failed to setup omapfb\n"); |
2579 | return r; | 2457 | return r; |
2580 | } | 2458 | } |
2581 | 2459 | ||
2582 | static int __exit omapfb_remove(struct platform_device *pdev) | 2460 | static int omapfb_remove(struct platform_device *pdev) |
2583 | { | 2461 | { |
2584 | struct omapfb2_device *fbdev = platform_get_drvdata(pdev); | 2462 | struct omapfb2_device *fbdev = platform_get_drvdata(pdev); |
2585 | 2463 | ||
@@ -2589,13 +2467,12 @@ static int __exit omapfb_remove(struct platform_device *pdev) | |||
2589 | 2467 | ||
2590 | omapfb_free_resources(fbdev); | 2468 | omapfb_free_resources(fbdev); |
2591 | 2469 | ||
2592 | omapdss_compat_uninit(); | ||
2593 | |||
2594 | return 0; | 2470 | return 0; |
2595 | } | 2471 | } |
2596 | 2472 | ||
2597 | static struct platform_driver omapfb_driver = { | 2473 | static struct platform_driver omapfb_driver = { |
2598 | .remove = __exit_p(omapfb_remove), | 2474 | .probe = omapfb_probe, |
2475 | .remove = omapfb_remove, | ||
2599 | .driver = { | 2476 | .driver = { |
2600 | .name = "omapfb", | 2477 | .name = "omapfb", |
2601 | .owner = THIS_MODULE, | 2478 | .owner = THIS_MODULE, |
@@ -2606,7 +2483,7 @@ static int __init omapfb_init(void) | |||
2606 | { | 2483 | { |
2607 | DBG("omapfb_init\n"); | 2484 | DBG("omapfb_init\n"); |
2608 | 2485 | ||
2609 | if (platform_driver_probe(&omapfb_driver, omapfb_probe)) { | 2486 | if (platform_driver_register(&omapfb_driver)) { |
2610 | printk(KERN_ERR "failed to register omapfb driver\n"); | 2487 | printk(KERN_ERR "failed to register omapfb driver\n"); |
2611 | return -ENODEV; | 2488 | return -ENODEV; |
2612 | } | 2489 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb-sysfs.c b/drivers/video/omap2/omapfb/omapfb-sysfs.c index 18fa9e1d003..153bf1aceeb 100644 --- a/drivers/video/omap2/omapfb/omapfb-sysfs.c +++ b/drivers/video/omap2/omapfb/omapfb-sysfs.c | |||
@@ -30,7 +30,7 @@ | |||
30 | #include <linux/omapfb.h> | 30 | #include <linux/omapfb.h> |
31 | 31 | ||
32 | #include <video/omapdss.h> | 32 | #include <video/omapdss.h> |
33 | #include <video/omapvrfb.h> | 33 | #include <plat/vrfb.h> |
34 | 34 | ||
35 | #include "omapfb.h" | 35 | #include "omapfb.h" |
36 | 36 | ||
@@ -104,14 +104,16 @@ static ssize_t store_mirror(struct device *dev, | |||
104 | { | 104 | { |
105 | struct fb_info *fbi = dev_get_drvdata(dev); | 105 | struct fb_info *fbi = dev_get_drvdata(dev); |
106 | struct omapfb_info *ofbi = FB2OFB(fbi); | 106 | struct omapfb_info *ofbi = FB2OFB(fbi); |
107 | bool mirror; | 107 | int mirror; |
108 | int r; | 108 | int r; |
109 | struct fb_var_screeninfo new_var; | 109 | struct fb_var_screeninfo new_var; |
110 | 110 | ||
111 | r = strtobool(buf, &mirror); | 111 | r = kstrtoint(buf, 0, &mirror); |
112 | if (r) | 112 | if (r) |
113 | return r; | 113 | return r; |
114 | 114 | ||
115 | mirror = !!mirror; | ||
116 | |||
115 | if (!lock_fb_info(fbi)) | 117 | if (!lock_fb_info(fbi)) |
116 | return -ENODEV; | 118 | return -ENODEV; |
117 | 119 | ||
@@ -441,7 +443,6 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
441 | struct fb_info *fbi = dev_get_drvdata(dev); | 443 | struct fb_info *fbi = dev_get_drvdata(dev); |
442 | struct omapfb_info *ofbi = FB2OFB(fbi); | 444 | struct omapfb_info *ofbi = FB2OFB(fbi); |
443 | struct omapfb2_device *fbdev = ofbi->fbdev; | 445 | struct omapfb2_device *fbdev = ofbi->fbdev; |
444 | struct omap_dss_device *display = fb2display(fbi); | ||
445 | struct omapfb2_mem_region *rg; | 446 | struct omapfb2_mem_region *rg; |
446 | unsigned long size; | 447 | unsigned long size; |
447 | int r; | 448 | int r; |
@@ -456,9 +457,6 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
456 | if (!lock_fb_info(fbi)) | 457 | if (!lock_fb_info(fbi)) |
457 | return -ENODEV; | 458 | return -ENODEV; |
458 | 459 | ||
459 | if (display && display->driver->sync) | ||
460 | display->driver->sync(display); | ||
461 | |||
462 | rg = ofbi->region; | 460 | rg = ofbi->region; |
463 | 461 | ||
464 | down_write_nested(&rg->lock, rg->id); | 462 | down_write_nested(&rg->lock, rg->id); |
@@ -477,9 +475,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr, | |||
477 | continue; | 475 | continue; |
478 | 476 | ||
479 | for (j = 0; j < ofbi2->num_overlays; j++) { | 477 | for (j = 0; j < ofbi2->num_overlays; j++) { |
480 | struct omap_overlay *ovl; | 478 | if (ofbi2->overlays[j]->info.enabled) { |
481 | ovl = ofbi2->overlays[j]; | ||
482 | if (ovl->is_enabled(ovl)) { | ||
483 | r = -EBUSY; | 479 | r = -EBUSY; |
484 | goto out; | 480 | goto out; |
485 | } | 481 | } |
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h index 623cd872a36..fdf0edeccf4 100644 --- a/drivers/video/omap2/omapfb/omapfb.h +++ b/drivers/video/omap2/omapfb/omapfb.h | |||
@@ -28,13 +28,11 @@ | |||
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | #include <linux/rwsem.h> | 30 | #include <linux/rwsem.h> |
31 | #include <linux/dma-attrs.h> | ||
32 | #include <linux/dma-mapping.h> | ||
33 | 31 | ||
34 | #include <video/omapdss.h> | 32 | #include <video/omapdss.h> |
35 | 33 | ||
36 | #ifdef DEBUG | 34 | #ifdef DEBUG |
37 | extern bool omapfb_debug; | 35 | extern unsigned int omapfb_debug; |
38 | #define DBG(format, ...) \ | 36 | #define DBG(format, ...) \ |
39 | do { \ | 37 | do { \ |
40 | if (omapfb_debug) \ | 38 | if (omapfb_debug) \ |
@@ -51,9 +49,6 @@ extern bool omapfb_debug; | |||
51 | 49 | ||
52 | struct omapfb2_mem_region { | 50 | struct omapfb2_mem_region { |
53 | int id; | 51 | int id; |
54 | struct dma_attrs attrs; | ||
55 | void *token; | ||
56 | dma_addr_t dma_handle; | ||
57 | u32 paddr; | 52 | u32 paddr; |
58 | void __iomem *vaddr; | 53 | void __iomem *vaddr; |
59 | struct vrfb vrfb; | 54 | struct vrfb vrfb; |
@@ -129,6 +124,9 @@ void omapfb_remove_sysfs(struct omapfb2_device *fbdev); | |||
129 | 124 | ||
130 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); | 125 | int omapfb_ioctl(struct fb_info *fbi, unsigned int cmd, unsigned long arg); |
131 | 126 | ||
127 | int omapfb_update_window(struct fb_info *fbi, | ||
128 | u32 x, u32 y, u32 w, u32 h); | ||
129 | |||
132 | int dss_mode_to_fb_mode(enum omap_color_mode dssmode, | 130 | int dss_mode_to_fb_mode(enum omap_color_mode dssmode, |
133 | struct fb_var_screeninfo *var); | 131 | struct fb_var_screeninfo *var); |
134 | 132 | ||
@@ -146,16 +144,15 @@ int omapfb_set_update_mode(struct fb_info *fbi, enum omapfb_update_mode mode); | |||
146 | static inline struct omap_dss_device *fb2display(struct fb_info *fbi) | 144 | static inline struct omap_dss_device *fb2display(struct fb_info *fbi) |
147 | { | 145 | { |
148 | struct omapfb_info *ofbi = FB2OFB(fbi); | 146 | struct omapfb_info *ofbi = FB2OFB(fbi); |
149 | struct omap_overlay *ovl; | 147 | int i; |
150 | 148 | ||
151 | /* XXX: returns the display connected to first attached overlay */ | 149 | /* XXX: returns the display connected to first attached overlay */ |
150 | for (i = 0; i < ofbi->num_overlays; i++) { | ||
151 | if (ofbi->overlays[i]->manager) | ||
152 | return ofbi->overlays[i]->manager->device; | ||
153 | } | ||
152 | 154 | ||
153 | if (ofbi->num_overlays == 0) | 155 | return NULL; |
154 | return NULL; | ||
155 | |||
156 | ovl = ofbi->overlays[0]; | ||
157 | |||
158 | return ovl->get_device(ovl); | ||
159 | } | 156 | } |
160 | 157 | ||
161 | static inline struct omapfb_display_data *get_display_data( | 158 | static inline struct omapfb_display_data *get_display_data( |
@@ -169,7 +166,6 @@ static inline struct omapfb_display_data *get_display_data( | |||
169 | 166 | ||
170 | /* This should never happen */ | 167 | /* This should never happen */ |
171 | BUG(); | 168 | BUG(); |
172 | return NULL; | ||
173 | } | 169 | } |
174 | 170 | ||
175 | static inline void omapfb_lock(struct omapfb2_device *fbdev) | 171 | static inline void omapfb_lock(struct omapfb2_device *fbdev) |
@@ -185,10 +181,13 @@ static inline void omapfb_unlock(struct omapfb2_device *fbdev) | |||
185 | static inline int omapfb_overlay_enable(struct omap_overlay *ovl, | 181 | static inline int omapfb_overlay_enable(struct omap_overlay *ovl, |
186 | int enable) | 182 | int enable) |
187 | { | 183 | { |
188 | if (enable) | 184 | struct omap_overlay_info info; |
189 | return ovl->enable(ovl); | 185 | |
190 | else | 186 | ovl->get_overlay_info(ovl, &info); |
191 | return ovl->disable(ovl); | 187 | if (info.enabled == enable) |
188 | return 0; | ||
189 | info.enabled = enable; | ||
190 | return ovl->set_overlay_info(ovl, &info); | ||
192 | } | 191 | } |
193 | 192 | ||
194 | static inline struct omapfb2_mem_region * | 193 | static inline struct omapfb2_mem_region * |
diff --git a/drivers/video/omap2/vrfb.c b/drivers/video/omap2/vrfb.c index 5d8fdac3b80..fd227160037 100644 --- a/drivers/video/omap2/vrfb.c +++ b/drivers/video/omap2/vrfb.c | |||
@@ -26,9 +26,10 @@ | |||
26 | #include <linux/io.h> | 26 | #include <linux/io.h> |
27 | #include <linux/bitops.h> | 27 | #include <linux/bitops.h> |
28 | #include <linux/mutex.h> | 28 | #include <linux/mutex.h> |
29 | #include <linux/platform_device.h> | ||
30 | 29 | ||
31 | #include <video/omapvrfb.h> | 30 | #include <mach/io.h> |
31 | #include <plat/vrfb.h> | ||
32 | #include <plat/sdrc.h> | ||
32 | 33 | ||
33 | #ifdef DEBUG | 34 | #ifdef DEBUG |
34 | #define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__) | 35 | #define DBG(format, ...) pr_debug("VRFB: " format, ## __VA_ARGS__) |
@@ -36,10 +37,10 @@ | |||
36 | #define DBG(format, ...) | 37 | #define DBG(format, ...) |
37 | #endif | 38 | #endif |
38 | 39 | ||
39 | #define SMS_ROT_CONTROL(context) (0x0 + 0x10 * context) | 40 | #define SMS_ROT_VIRT_BASE(context, rot) \ |
40 | #define SMS_ROT_SIZE(context) (0x4 + 0x10 * context) | 41 | (((context >= 4) ? 0xD0000000 : 0x70000000) \ |
41 | #define SMS_ROT_PHYSICAL_BA(context) (0x8 + 0x10 * context) | 42 | + (0x4000000 * (context)) \ |
42 | #define SMS_ROT_VIRT_BASE(rot) (0x1000000 * (rot)) | 43 | + (0x1000000 * (rot))) |
43 | 44 | ||
44 | #define OMAP_VRFB_SIZE (2048 * 2048 * 4) | 45 | #define OMAP_VRFB_SIZE (2048 * 2048 * 4) |
45 | 46 | ||
@@ -53,16 +54,10 @@ | |||
53 | #define SMS_PW_OFFSET 4 | 54 | #define SMS_PW_OFFSET 4 |
54 | #define SMS_PS_OFFSET 0 | 55 | #define SMS_PS_OFFSET 0 |
55 | 56 | ||
57 | #define VRFB_NUM_CTXS 12 | ||
56 | /* bitmap of reserved contexts */ | 58 | /* bitmap of reserved contexts */ |
57 | static unsigned long ctx_map; | 59 | static unsigned long ctx_map; |
58 | 60 | ||
59 | struct vrfb_ctx { | ||
60 | u32 base; | ||
61 | u32 physical_ba; | ||
62 | u32 control; | ||
63 | u32 size; | ||
64 | }; | ||
65 | |||
66 | static DEFINE_MUTEX(ctx_lock); | 61 | static DEFINE_MUTEX(ctx_lock); |
67 | 62 | ||
68 | /* | 63 | /* |
@@ -71,34 +66,17 @@ static DEFINE_MUTEX(ctx_lock); | |||
71 | * we don't need locking, since no drivers will run until after the wake-up | 66 | * we don't need locking, since no drivers will run until after the wake-up |
72 | * has finished. | 67 | * has finished. |
73 | */ | 68 | */ |
74 | 69 | static struct { | |
75 | static void __iomem *vrfb_base; | 70 | u32 physical_ba; |
76 | 71 | u32 control; | |
77 | static int num_ctxs; | 72 | u32 size; |
78 | static struct vrfb_ctx *ctxs; | 73 | } vrfb_hw_context[VRFB_NUM_CTXS]; |
79 | |||
80 | static bool vrfb_loaded; | ||
81 | |||
82 | static void omap2_sms_write_rot_control(u32 val, unsigned ctx) | ||
83 | { | ||
84 | __raw_writel(val, vrfb_base + SMS_ROT_CONTROL(ctx)); | ||
85 | } | ||
86 | |||
87 | static void omap2_sms_write_rot_size(u32 val, unsigned ctx) | ||
88 | { | ||
89 | __raw_writel(val, vrfb_base + SMS_ROT_SIZE(ctx)); | ||
90 | } | ||
91 | |||
92 | static void omap2_sms_write_rot_physical_ba(u32 val, unsigned ctx) | ||
93 | { | ||
94 | __raw_writel(val, vrfb_base + SMS_ROT_PHYSICAL_BA(ctx)); | ||
95 | } | ||
96 | 74 | ||
97 | static inline void restore_hw_context(int ctx) | 75 | static inline void restore_hw_context(int ctx) |
98 | { | 76 | { |
99 | omap2_sms_write_rot_control(ctxs[ctx].control, ctx); | 77 | omap2_sms_write_rot_control(vrfb_hw_context[ctx].control, ctx); |
100 | omap2_sms_write_rot_size(ctxs[ctx].size, ctx); | 78 | omap2_sms_write_rot_size(vrfb_hw_context[ctx].size, ctx); |
101 | omap2_sms_write_rot_physical_ba(ctxs[ctx].physical_ba, ctx); | 79 | omap2_sms_write_rot_physical_ba(vrfb_hw_context[ctx].physical_ba, ctx); |
102 | } | 80 | } |
103 | 81 | ||
104 | static u32 get_image_width_roundup(u16 width, u8 bytespp) | 82 | static u32 get_image_width_roundup(u16 width, u8 bytespp) |
@@ -202,10 +180,8 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr, | |||
202 | pixel_size_exp = 2; | 180 | pixel_size_exp = 2; |
203 | else if (bytespp == 2) | 181 | else if (bytespp == 2) |
204 | pixel_size_exp = 1; | 182 | pixel_size_exp = 1; |
205 | else { | 183 | else |
206 | BUG(); | 184 | BUG(); |
207 | return; | ||
208 | } | ||
209 | 185 | ||
210 | vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp; | 186 | vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp; |
211 | vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT); | 187 | vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT); |
@@ -219,9 +195,9 @@ void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr, | |||
219 | control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET; | 195 | control |= VRFB_PAGE_WIDTH_EXP << SMS_PW_OFFSET; |
220 | control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET; | 196 | control |= VRFB_PAGE_HEIGHT_EXP << SMS_PH_OFFSET; |
221 | 197 | ||
222 | ctxs[ctx].physical_ba = paddr; | 198 | vrfb_hw_context[ctx].physical_ba = paddr; |
223 | ctxs[ctx].size = size; | 199 | vrfb_hw_context[ctx].size = size; |
224 | ctxs[ctx].control = control; | 200 | vrfb_hw_context[ctx].control = control; |
225 | 201 | ||
226 | omap2_sms_write_rot_physical_ba(paddr, ctx); | 202 | omap2_sms_write_rot_physical_ba(paddr, ctx); |
227 | omap2_sms_write_rot_size(size, ctx); | 203 | omap2_sms_write_rot_size(size, ctx); |
@@ -297,11 +273,11 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) | |||
297 | 273 | ||
298 | mutex_lock(&ctx_lock); | 274 | mutex_lock(&ctx_lock); |
299 | 275 | ||
300 | for (ctx = 0; ctx < num_ctxs; ++ctx) | 276 | for (ctx = 0; ctx < VRFB_NUM_CTXS; ++ctx) |
301 | if ((ctx_map & (1 << ctx)) == 0) | 277 | if ((ctx_map & (1 << ctx)) == 0) |
302 | break; | 278 | break; |
303 | 279 | ||
304 | if (ctx == num_ctxs) { | 280 | if (ctx == VRFB_NUM_CTXS) { |
305 | pr_err("vrfb: no free contexts\n"); | 281 | pr_err("vrfb: no free contexts\n"); |
306 | r = -EBUSY; | 282 | r = -EBUSY; |
307 | goto out; | 283 | goto out; |
@@ -316,7 +292,7 @@ int omap_vrfb_request_ctx(struct vrfb *vrfb) | |||
316 | vrfb->context = ctx; | 292 | vrfb->context = ctx; |
317 | 293 | ||
318 | for (rot = 0; rot < 4; ++rot) { | 294 | for (rot = 0; rot < 4; ++rot) { |
319 | paddr = ctxs[ctx].base + SMS_ROT_VIRT_BASE(rot); | 295 | paddr = SMS_ROT_VIRT_BASE(ctx, rot); |
320 | if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) { | 296 | if (!request_mem_region(paddr, OMAP_VRFB_SIZE, "vrfb")) { |
321 | pr_err("vrfb: failed to reserve VRFB " | 297 | pr_err("vrfb: failed to reserve VRFB " |
322 | "area for ctx %d, rotation %d\n", | 298 | "area for ctx %d, rotation %d\n", |
@@ -337,80 +313,3 @@ out: | |||
337 | return r; | 313 | return r; |
338 | } | 314 | } |
339 | EXPORT_SYMBOL(omap_vrfb_request_ctx); | 315 | EXPORT_SYMBOL(omap_vrfb_request_ctx); |
340 | |||
341 | bool omap_vrfb_supported(void) | ||
342 | { | ||
343 | return vrfb_loaded; | ||
344 | } | ||
345 | EXPORT_SYMBOL(omap_vrfb_supported); | ||
346 | |||
347 | static int __init vrfb_probe(struct platform_device *pdev) | ||
348 | { | ||
349 | struct resource *mem; | ||
350 | int i; | ||
351 | |||
352 | /* first resource is the register res, the rest are vrfb contexts */ | ||
353 | |||
354 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
355 | if (!mem) { | ||
356 | dev_err(&pdev->dev, "can't get vrfb base address\n"); | ||
357 | return -EINVAL; | ||
358 | } | ||
359 | |||
360 | vrfb_base = devm_request_and_ioremap(&pdev->dev, mem); | ||
361 | if (!vrfb_base) { | ||
362 | dev_err(&pdev->dev, "can't ioremap vrfb memory\n"); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | num_ctxs = pdev->num_resources - 1; | ||
367 | |||
368 | ctxs = devm_kzalloc(&pdev->dev, | ||
369 | sizeof(struct vrfb_ctx) * num_ctxs, | ||
370 | GFP_KERNEL); | ||
371 | |||
372 | if (!ctxs) | ||
373 | return -ENOMEM; | ||
374 | |||
375 | for (i = 0; i < num_ctxs; ++i) { | ||
376 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i); | ||
377 | if (!mem) { | ||
378 | dev_err(&pdev->dev, "can't get vrfb ctx %d address\n", | ||
379 | i); | ||
380 | return -EINVAL; | ||
381 | } | ||
382 | |||
383 | ctxs[i].base = mem->start; | ||
384 | } | ||
385 | |||
386 | vrfb_loaded = true; | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static void __exit vrfb_remove(struct platform_device *pdev) | ||
392 | { | ||
393 | vrfb_loaded = false; | ||
394 | } | ||
395 | |||
396 | static struct platform_driver vrfb_driver = { | ||
397 | .driver.name = "omapvrfb", | ||
398 | .remove = __exit_p(vrfb_remove), | ||
399 | }; | ||
400 | |||
401 | static int __init vrfb_init(void) | ||
402 | { | ||
403 | return platform_driver_probe(&vrfb_driver, &vrfb_probe); | ||
404 | } | ||
405 | |||
406 | static void __exit vrfb_exit(void) | ||
407 | { | ||
408 | platform_driver_unregister(&vrfb_driver); | ||
409 | } | ||
410 | |||
411 | module_init(vrfb_init); | ||
412 | module_exit(vrfb_exit); | ||
413 | |||
414 | MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>"); | ||
415 | MODULE_DESCRIPTION("OMAP VRFB"); | ||
416 | MODULE_LICENSE("GPL v2"); | ||