diff options
Diffstat (limited to 'drivers/video/omap2/dss/hdmi.c')
| -rw-r--r-- | drivers/video/omap2/dss/hdmi.c | 162 |
1 files changed, 117 insertions, 45 deletions
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c index a48a7dd75b33..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, |
| @@ -644,8 +665,10 @@ static void hdmi_dump_regs(struct seq_file *s) | |||
| 644 | { | 665 | { |
| 645 | mutex_lock(&hdmi.lock); | 666 | mutex_lock(&hdmi.lock); |
| 646 | 667 | ||
| 647 | if (hdmi_runtime_get()) | 668 | if (hdmi_runtime_get()) { |
| 669 | mutex_unlock(&hdmi.lock); | ||
| 648 | return; | 670 | return; |
| 671 | } | ||
| 649 | 672 | ||
| 650 | hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); | 673 | hdmi.ip_data.ops->dump_wrapper(&hdmi.ip_data, s); |
| 651 | hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); | 674 | hdmi.ip_data.ops->dump_pll(&hdmi.ip_data, s); |
| @@ -713,7 +736,7 @@ int omapdss_hdmi_display_enable(struct omap_dss_device *dssdev) | |||
| 713 | goto err0; | 736 | goto err0; |
| 714 | } | 737 | } |
| 715 | 738 | ||
| 716 | r = hdmi_power_on(dssdev); | 739 | r = hdmi_power_on_full(dssdev); |
| 717 | if (r) { | 740 | if (r) { |
| 718 | DSSERR("failed to power on device\n"); | 741 | DSSERR("failed to power on device\n"); |
| 719 | goto err1; | 742 | goto err1; |
| @@ -735,13 +758,48 @@ void omapdss_hdmi_display_disable(struct omap_dss_device *dssdev) | |||
| 735 | 758 | ||
| 736 | mutex_lock(&hdmi.lock); | 759 | mutex_lock(&hdmi.lock); |
| 737 | 760 | ||
| 738 | hdmi_power_off(dssdev); | 761 | hdmi_power_off_full(dssdev); |
| 739 | 762 | ||
| 740 | omap_dss_stop_device(dssdev); | 763 | omap_dss_stop_device(dssdev); |
| 741 | 764 | ||
| 742 | mutex_unlock(&hdmi.lock); | 765 | mutex_unlock(&hdmi.lock); |
| 743 | } | 766 | } |
| 744 | 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 | |||
| 745 | static int hdmi_get_clocks(struct platform_device *pdev) | 803 | static int hdmi_get_clocks(struct platform_device *pdev) |
| 746 | { | 804 | { |
| 747 | struct clk *clk; | 805 | struct clk *clk; |
| @@ -910,7 +968,7 @@ int hdmi_audio_config(struct omap_dss_audio *audio) | |||
| 910 | 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) |
| 911 | { | 969 | { |
| 912 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; | 970 | struct omap_dss_board_info *pdata = pdev->dev.platform_data; |
| 913 | const char *def_disp_name = dss_get_default_display_name(); | 971 | const char *def_disp_name = omapdss_get_default_display_name(); |
| 914 | struct omap_dss_device *def_dssdev; | 972 | struct omap_dss_device *def_dssdev; |
| 915 | int i; | 973 | int i; |
| 916 | 974 | ||
| @@ -968,9 +1026,19 @@ static void __init hdmi_probe_pdata(struct platform_device *pdev) | |||
| 968 | return; | 1026 | return; |
| 969 | } | 1027 | } |
| 970 | 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 | |||
| 971 | r = dss_add_device(dssdev); | 1037 | r = dss_add_device(dssdev); |
| 972 | if (r) { | 1038 | if (r) { |
| 973 | 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); | ||
| 974 | dss_put_device(dssdev); | 1042 | dss_put_device(dssdev); |
| 975 | return; | 1043 | return; |
| 976 | } | 1044 | } |
| @@ -997,22 +1065,22 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev) | |||
| 997 | /* HDMI HW IP initialisation */ | 1065 | /* HDMI HW IP initialisation */ |
| 998 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | 1066 | static int __init omapdss_hdmihw_probe(struct platform_device *pdev) |
| 999 | { | 1067 | { |
| 1000 | struct resource *hdmi_mem; | 1068 | struct resource *res; |
| 1001 | int r; | 1069 | int r; |
| 1002 | 1070 | ||
| 1003 | hdmi.pdev = pdev; | 1071 | hdmi.pdev = pdev; |
| 1004 | 1072 | ||
| 1005 | mutex_init(&hdmi.lock); | 1073 | mutex_init(&hdmi.lock); |
| 1074 | mutex_init(&hdmi.ip_data.lock); | ||
| 1006 | 1075 | ||
| 1007 | hdmi_mem = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); | 1076 | res = platform_get_resource(hdmi.pdev, IORESOURCE_MEM, 0); |
| 1008 | if (!hdmi_mem) { | 1077 | if (!res) { |
| 1009 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); | 1078 | DSSERR("can't get IORESOURCE_MEM HDMI\n"); |
| 1010 | return -EINVAL; | 1079 | return -EINVAL; |
| 1011 | } | 1080 | } |
| 1012 | 1081 | ||
| 1013 | /* Base address taken from platform */ | 1082 | /* Base address taken from platform */ |
| 1014 | hdmi.ip_data.base_wp = ioremap(hdmi_mem->start, | 1083 | hdmi.ip_data.base_wp = devm_request_and_ioremap(&pdev->dev, res); |
| 1015 | resource_size(hdmi_mem)); | ||
| 1016 | if (!hdmi.ip_data.base_wp) { | 1084 | if (!hdmi.ip_data.base_wp) { |
| 1017 | DSSERR("can't ioremap WP\n"); | 1085 | DSSERR("can't ioremap WP\n"); |
| 1018 | return -ENOMEM; | 1086 | return -ENOMEM; |
| @@ -1020,7 +1088,7 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 1020 | 1088 | ||
| 1021 | r = hdmi_get_clocks(pdev); | 1089 | r = hdmi_get_clocks(pdev); |
| 1022 | if (r) { | 1090 | if (r) { |
| 1023 | iounmap(hdmi.ip_data.base_wp); | 1091 | DSSERR("can't get clocks\n"); |
| 1024 | return r; | 1092 | return r; |
| 1025 | } | 1093 | } |
| 1026 | 1094 | ||
| @@ -1031,9 +1099,11 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 1031 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; | 1099 | hdmi.ip_data.pll_offset = HDMI_PLLCTRL; |
| 1032 | hdmi.ip_data.phy_offset = HDMI_PHY; | 1100 | hdmi.ip_data.phy_offset = HDMI_PHY; |
| 1033 | 1101 | ||
| 1034 | mutex_init(&hdmi.ip_data.lock); | 1102 | r = hdmi_panel_init(); |
| 1035 | 1103 | if (r) { | |
| 1036 | hdmi_panel_init(); | 1104 | DSSERR("can't init panel\n"); |
| 1105 | goto err_panel_init; | ||
| 1106 | } | ||
| 1037 | 1107 | ||
| 1038 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); | 1108 | dss_debugfs_create_file("hdmi", hdmi_dump_regs); |
| 1039 | 1109 | ||
| @@ -1042,6 +1112,10 @@ static int __init omapdss_hdmihw_probe(struct platform_device *pdev) | |||
| 1042 | hdmi_probe_pdata(pdev); | 1112 | hdmi_probe_pdata(pdev); |
| 1043 | 1113 | ||
| 1044 | return 0; | 1114 | return 0; |
| 1115 | |||
| 1116 | err_panel_init: | ||
| 1117 | hdmi_put_clocks(); | ||
| 1118 | return r; | ||
| 1045 | } | 1119 | } |
| 1046 | 1120 | ||
| 1047 | static int __exit hdmi_remove_child(struct device *dev, void *data) | 1121 | static int __exit hdmi_remove_child(struct device *dev, void *data) |
| @@ -1065,8 +1139,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev) | |||
| 1065 | 1139 | ||
| 1066 | hdmi_put_clocks(); | 1140 | hdmi_put_clocks(); |
| 1067 | 1141 | ||
| 1068 | iounmap(hdmi.ip_data.base_wp); | ||
| 1069 | |||
| 1070 | return 0; | 1142 | return 0; |
| 1071 | } | 1143 | } |
| 1072 | 1144 | ||
