diff options
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
-rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 158 |
1 files changed, 114 insertions, 44 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index 8c9b8b3b7f77..769d0828581c 100644 --- a/drivers/video/omap2/dss/hdmi.c +++ b/drivers/video/omap2/dss/hdmi.c | |||
@@ -60,6 +60,7 @@ | |||
60 | static struct { | 60 | static struct { |
61 | struct mutex lock; | 61 | struct mutex lock; |
62 | struct platform_device *pdev; | 62 | struct platform_device *pdev; |
63 | |||
63 | struct hdmi_ip_data ip_data; | 64 | struct hdmi_ip_data ip_data; |
64 | 65 | ||
65 | struct clk *sys_clk; | 66 | struct clk *sys_clk; |
@@ -295,6 +296,12 @@ static const struct hdmi_config vesa_timings[] = { | |||
295 | false, }, | 296 | false, }, |
296 | { 0x55, HDMI_DVI }, | 297 | { 0x55, HDMI_DVI }, |
297 | }, | 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 | }, | ||
298 | }; | 305 | }; |
299 | 306 | ||
300 | static int hdmi_runtime_get(void) | 307 | static int hdmi_runtime_get(void) |
@@ -333,13 +340,17 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) | |||
333 | 340 | ||
334 | DSSDBG("init_display\n"); | 341 | DSSDBG("init_display\n"); |
335 | 342 | ||
336 | dss_init_hdmi_ip_ops(&hdmi.ip_data); | 343 | dss_init_hdmi_ip_ops(&hdmi.ip_data, omapdss_get_version()); |
337 | 344 | ||
338 | if (hdmi.vdda_hdmi_dac_reg == NULL) { | 345 | if (hdmi.vdda_hdmi_dac_reg == NULL) { |
339 | struct regulator *reg; | 346 | struct regulator *reg; |
340 | 347 | ||
341 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); | 348 | reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac"); |
342 | 349 | ||
350 | /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */ | ||
351 | if (IS_ERR(reg)) | ||
352 | reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC"); | ||
353 | |||
343 | if (IS_ERR(reg)) { | 354 | if (IS_ERR(reg)) { |
344 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); | 355 | DSSERR("can't get VDDA_HDMI_DAC regulator\n"); |
345 | return PTR_ERR(reg); | 356 | return PTR_ERR(reg); |
@@ -355,7 +366,7 @@ static int __init hdmi_init_display(struct omap_dss_device *dssdev) | |||
355 | return 0; | 366 | return 0; |
356 | } | 367 | } |
357 | 368 | ||
358 | static void __exit hdmi_uninit_display(struct omap_dss_device *dssdev) | 369 | static void hdmi_uninit_display(struct omap_dss_device *dssdev) |
359 | { | 370 | { |
360 | DSSDBG("uninit_display\n"); | 371 | DSSDBG("uninit_display\n"); |
361 | 372 | ||
@@ -398,7 +409,8 @@ static bool hdmi_timings_compare(struct omap_video_timings *timing1, | |||
398 | { | 409 | { |
399 | int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; | 410 | int timing1_vsync, timing1_hsync, timing2_vsync, timing2_hsync; |
400 | 411 | ||
401 | if ((timing2->pixel_clock == timing1->pixel_clock) && | 412 | if ((DIV_ROUND_CLOSEST(timing2->pixel_clock, 1000) == |
413 | DIV_ROUND_CLOSEST(timing1->pixel_clock, 1000)) && | ||
402 | (timing2->x_res == timing1->x_res) && | 414 | (timing2->x_res == timing1->x_res) && |
403 | (timing2->y_res == timing1->y_res)) { | 415 | (timing2->y_res == timing1->y_res)) { |
404 | 416 | ||
@@ -500,12 +512,9 @@ static void hdmi_compute_pll(struct omap_dss_device *dssdev, int phy, | |||
500 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); | 512 | DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd); |
501 | } | 513 | } |
502 | 514 | ||
503 | static int hdmi_power_on(struct omap_dss_device *dssdev) | 515 | static int hdmi_power_on_core(struct omap_dss_device *dssdev) |
504 | { | 516 | { |
505 | int r; | 517 | int r; |
506 | struct omap_video_timings *p; | ||
507 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
508 | unsigned long phy; | ||
509 | 518 | ||
510 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); | 519 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 1); |
511 | gpio_set_value(hdmi.ls_oe_gpio, 1); | 520 | gpio_set_value(hdmi.ls_oe_gpio, 1); |
@@ -521,6 +530,38 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
521 | if (r) | 530 | if (r) |
522 | goto err_runtime_get; | 531 | goto err_runtime_get; |
523 | 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 | { | ||
556 | int r; | ||
557 | struct omap_video_timings *p; | ||
558 | struct omap_overlay_manager *mgr = dssdev->output->manager; | ||
559 | unsigned long phy; | ||
560 | |||
561 | r = hdmi_power_on_core(dssdev); | ||
562 | if (r) | ||
563 | return r; | ||
564 | |||
524 | dss_mgr_disable(mgr); | 565 | dss_mgr_disable(mgr); |
525 | 566 | ||
526 | p = &hdmi.ip_data.cfg.timings; | 567 | p = &hdmi.ip_data.cfg.timings; |
@@ -548,17 +589,6 @@ static int hdmi_power_on(struct omap_dss_device *dssdev) | |||
548 | 589 | ||
549 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); | 590 | hdmi.ip_data.ops->video_configure(&hdmi.ip_data); |
550 | 591 | ||
551 | /* Make selection of HDMI in DSS */ | ||
552 | dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK); | ||
553 | |||
554 | /* Select the dispc clock source as PRCM clock, to ensure that it is not | ||
555 | * DSI PLL source as the clock selected by DSI PLL might not be | ||
556 | * sufficient for the resolution selected / that can be changed | ||
557 | * dynamically by user. This can be moved to single location , say | ||
558 | * Boardfile. | ||
559 | */ | ||
560 | dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src); | ||
561 | |||
562 | /* bypass TV gamma table */ | 592 | /* bypass TV gamma table */ |
563 | dispc_enable_gamma_table(0); | 593 | dispc_enable_gamma_table(0); |
564 | 594 | ||
@@ -582,16 +612,11 @@ err_vid_enable: | |||
582 | err_phy_enable: | 612 | err_phy_enable: |
583 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 613 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
584 | err_pll_enable: | 614 | err_pll_enable: |
585 | hdmi_runtime_put(); | 615 | hdmi_power_off_core(dssdev); |
586 | err_runtime_get: | ||
587 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
588 | err_vdac_enable: | ||
589 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | ||
590 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
591 | return -EIO; | 616 | return -EIO; |
592 | } | 617 | } |
593 | 618 | ||
594 | static void hdmi_power_off(struct omap_dss_device *dssdev) | 619 | static void hdmi_power_off_full(struct omap_dss_device *dssdev) |
595 | { | 620 | { |
596 | struct omap_overlay_manager *mgr = dssdev->output->manager; | 621 | struct omap_overlay_manager *mgr = dssdev->output->manager; |
597 | 622 | ||
@@ -600,12 +625,8 @@ static void hdmi_power_off(struct omap_dss_device *dssdev) | |||
600 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); | 625 | hdmi.ip_data.ops->video_disable(&hdmi.ip_data); |
601 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); | 626 | hdmi.ip_data.ops->phy_disable(&hdmi.ip_data); |
602 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); | 627 | hdmi.ip_data.ops->pll_disable(&hdmi.ip_data); |
603 | hdmi_runtime_put(); | ||
604 | |||
605 | regulator_disable(hdmi.vdda_hdmi_dac_reg); | ||
606 | 628 | ||
607 | gpio_set_value(hdmi.ct_cp_hpd_gpio, 0); | 629 | hdmi_power_off_core(dssdev); |
608 | gpio_set_value(hdmi.ls_oe_gpio, 0); | ||
609 | } | 630 | } |
610 | 631 | ||
611 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, | 632 | int omapdss_hdmi_display_check_timing(struct omap_dss_device *dssdev, |
@@ -715,7 +736,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | |||
715 | goto err0; | 736 | goto err0; |
716 | } | 737 | } |
717 | 738 | ||
718 | r = hdmi_power_on(dssdev); | 739 | r = hdmi_power_on_full(dssdev); |
719 | if (r) { | 740 | if (r) { |
720 | DSSERR("failed to power on device\n"); | 741 | DSSERR("failed to power on device\n"); |
721 | goto err1; | 742 | goto err1; |
@@ -737,13 +758,48 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
737 | 758 | ||
738 | mutex_lock(&hdmi.lock); | 759 | mutex_lock(&hdmi.lock); |
739 | 760 | ||
740 | hdmi_power_off(dssdev); | 761 | hdmi_power_off_full(dssdev); |
741 | 762 | ||
742 | omap_dss_stop_device(dssdev); | 763 | omap_dss_stop_device(dssdev); |
743 | 764 | ||
744 | mutex_unlock(&hdmi.lock); | 765 | mutex_unlock(&hdmi.lock); |
745 | } | 766 | } |
746 | 767 | ||
768 | int omapdss_hdmi_core_enable(struct omap_dss_device *dssdev) | ||
769 | { | ||
770 | int r = 0; | ||
771 | |||
772 | DSSDBG("ENTER omapdss_hdmi_core_enable\n"); | ||
773 | |||
774 | mutex_lock(&hdmi.lock); | ||
775 | |||
776 | hdmi.ip_data.hpd_gpio = hdmi.hpd_gpio; | ||
777 | |||
778 | r = hdmi_power_on_core(dssdev); | ||
779 | if (r) { | ||
780 | DSSERR("failed to power on device\n"); | ||
781 | goto err0; | ||
782 | } | ||
783 | |||
784 | mutex_unlock(&hdmi.lock); | ||
785 | return 0; | ||
786 | |||
787 | err0: | ||
788 | mutex_unlock(&hdmi.lock); | ||
789 | return r; | ||
790 | } | ||
791 | |||
792 | void omapdss_hdmi_core_disable(struct omap_dss_device *dssdev) | ||
793 | { | ||
794 | DSSDBG("Enter omapdss_hdmi_core_disable\n"); | ||
795 | |||
796 | mutex_lock(&hdmi.lock); | ||
797 | |||
798 | hdmi_power_off_core(dssdev); | ||
799 | |||
800 | mutex_unlock(&hdmi.lock); | ||
801 | } | ||
802 | |||
747 | static int hdmi_get_clocks(struct platform_device *pdev) | 803 | static int hdmi_get_clocks(struct platform_device *pdev) |
748 | { | 804 | { |
749 | struct clk *clk; | 805 | struct clk *clk; |
@@ -912,7 +968,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio) | |||
912 | static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) | 968 | static struct omap_dss_device * __init hdmi_find_dssdev(struct platform_device *pdev) |
913 | { | 969 | { |
914 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 970 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
915 | const char *def_disp_name = dss_get_default_display_name(); | 971 | const char *def_disp_name = omapdss_get_default_display_name(); |
916 | struct omap_dss_device *def_dssdev; | 972 | struct omap_dss_device *def_dssdev; |
917 | int i; | 973 | int i; |
918 | 974 | ||
@@ -970,9 +1026,19 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) | |||
970 | return; | 1026 | return; |
971 | } | 1027 | } |
972 | 1028 | ||
1029 | r = omapdss_output_set_device(&hdmi.output, dssdev); | ||
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 | |||
973 | r = dss_add_device(dssdev); | 1037 | r = dss_add_device(dssdev); |
974 | if (r) { | 1038 | if (r) { |
975 | DSSERR("device %s register failed: %d\n", dssdev->name, r); | 1039 | DSSERR("device %s register failed: %d\n", dssdev->name, r); |
1040 | omapdss_output_unset_device(&hdmi.output); | ||
1041 | hdmi_uninit_display(dssdev); | ||
976 | dss_put_device(dssdev); | 1042 | dss_put_device(dssdev); |
977 | return; | 1043 | return; |
978 | } | 1044 | } |
@@ -999,22 +1065,22 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) | |||
999 | /* HDMI HW IP initialisation */ | 1065 | /* HDMI HW IP initialisation */ |
1000 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | 1066 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) |
1001 | { | 1067 | { |
1002 | struct resource *hdmi_mem; | 1068 | struct resource *res; |
1003 | int r; | 1069 | int r; |
1004 | 1070 | ||
1005 | hdmi.pdev = pdev; | 1071 | hdmi.pdev = pdev; |
1006 | 1072 | ||
1007 | mutex_init(&hdmi.lock); | 1073 | mutex_init(&hdmi.lock); |
1074 | mutex_init(&hdmi.ip_data.lock); | ||
1008 | 1075 | ||
1009 | hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); | 1076 | res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); |
1010 | if (!hdmi_mem) { | 1077 | if (!res) { |
1011 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); | 1078 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); |
1012 | return -EINVAL; | 1079 | return -EINVAL; |
1013 | } | 1080 | } |
1014 | 1081 | ||
1015 | /* Base address taken from platform */ | 1082 | /* Base address taken from platform */ |
1016 | hdmi.ip_data.base_wp = ioremap(hdmi_mem->start, | 1083 | hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res); |
1017 | resource_size(hdmi_mem)); | ||
1018 | if (!hdmi.ip_data.base_wp) { | 1084 | if (!hdmi.ip_data.base_wp) { |
1019 | DSSERR("can't ioremap WP\n"); | 1085 | DSSERR("can't ioremap WP\n"); |
1020 | return -ENOMEM; | 1086 | return -ENOMEM; |
@@ -1022,7 +1088,7 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1022 | 1088 | ||
1023 | r = hdmi_get_clocks(pdev); | 1089 | r = hdmi_get_clocks(pdev); |
1024 | if (r) { | 1090 | if (r) { |
1025 | iounmap(hdmi.ip_data.base_wp); | 1091 | DSSERR("can't get clocks\n"); |
1026 | return r; | 1092 | return r; |
1027 | } | 1093 | } |
1028 | 1094 | ||
@@ -1033,9 +1099,11 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1033 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1099 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
1034 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1100 | hdmi.ip_data.phy_offset = HDMI_PHY; |
1035 | 1101 | ||
1036 | mutex_init(&hdmi.ip_data.lock); | 1102 | r = hdmi_panel_init(); |
1037 | 1103 | if (r) { | |
1038 | hdmi_panel_init(); | 1104 | DSSERR("can't init panel\n"); |
1105 | goto err_panel_init; | ||
1106 | } | ||
1039 | 1107 | ||
1040 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 1108 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
1041 | 1109 | ||
@@ -1044,6 +1112,10 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
1044 | hdmi_probe_pdata(pdev); | 1112 | hdmi_probe_pdata(pdev); |
1045 | 1113 | ||
1046 | return 0; | 1114 | return 0; |
1115 | |||
1116 | err_panel_init: | ||
1117 | hdmi_put_clocks(); | ||
1118 | return r; | ||
1047 | } | 1119 | } |
1048 | 1120 | ||
1049 | static int __exit hdmi_remove_child(struct device *dev, void *data) | 1121 | static int __exit hdmi_remove_child(struct device *dev, void *data) |
@@ -1067,8 +1139,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
1067 | 1139 | ||
1068 | hdmi_put_clocks(); | 1140 | hdmi_put_clocks(); |
1069 | 1141 | ||
1070 | iounmap(hdmi.ip_data.base_wp); | ||
1071 | |||
1072 | return 0; | 1142 | return 0; |
1073 | } | 1143 | } |
1074 | 1144 | ||