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