| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2017 NVIDIA CORPORATION. All rights reserved. |
|---|
| 3 | | - * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 6 | | - * published by the Free Software Foundation. |
|---|
| 7 | 4 | */ |
|---|
| 8 | 5 | |
|---|
| 9 | 6 | #include <linux/clk.h> |
|---|
| 7 | +#include <linux/delay.h> |
|---|
| 10 | 8 | #include <linux/host1x.h> |
|---|
| 11 | 9 | #include <linux/module.h> |
|---|
| 12 | 10 | #include <linux/of.h> |
|---|
| .. | .. |
|---|
| 16 | 14 | #include <linux/pm_runtime.h> |
|---|
| 17 | 15 | #include <linux/reset.h> |
|---|
| 18 | 16 | |
|---|
| 19 | | -#include <drm/drmP.h> |
|---|
| 20 | 17 | #include <drm/drm_atomic.h> |
|---|
| 21 | 18 | #include <drm/drm_atomic_helper.h> |
|---|
| 22 | | -#include <drm/drm_crtc_helper.h> |
|---|
| 19 | +#include <drm/drm_fourcc.h> |
|---|
| 20 | +#include <drm/drm_probe_helper.h> |
|---|
| 23 | 21 | |
|---|
| 24 | 22 | #include "drm.h" |
|---|
| 25 | 23 | #include "dc.h" |
|---|
| .. | .. |
|---|
| 97 | 95 | |
|---|
| 98 | 96 | static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp) |
|---|
| 99 | 97 | { |
|---|
| 98 | + int err = 0; |
|---|
| 99 | + |
|---|
| 100 | 100 | mutex_lock(&wgrp->lock); |
|---|
| 101 | 101 | |
|---|
| 102 | 102 | if (wgrp->usecount == 0) { |
|---|
| 103 | | - pm_runtime_get_sync(wgrp->parent); |
|---|
| 103 | + err = host1x_client_resume(wgrp->parent); |
|---|
| 104 | + if (err < 0) { |
|---|
| 105 | + dev_err(wgrp->parent->dev, "failed to resume: %d\n", err); |
|---|
| 106 | + goto unlock; |
|---|
| 107 | + } |
|---|
| 108 | + |
|---|
| 104 | 109 | reset_control_deassert(wgrp->rst); |
|---|
| 105 | 110 | } |
|---|
| 106 | 111 | |
|---|
| 107 | 112 | wgrp->usecount++; |
|---|
| 108 | | - mutex_unlock(&wgrp->lock); |
|---|
| 109 | 113 | |
|---|
| 110 | | - return 0; |
|---|
| 114 | +unlock: |
|---|
| 115 | + mutex_unlock(&wgrp->lock); |
|---|
| 116 | + return err; |
|---|
| 111 | 117 | } |
|---|
| 112 | 118 | |
|---|
| 113 | 119 | static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) |
|---|
| .. | .. |
|---|
| 123 | 129 | wgrp->index); |
|---|
| 124 | 130 | } |
|---|
| 125 | 131 | |
|---|
| 126 | | - pm_runtime_put(wgrp->parent); |
|---|
| 132 | + host1x_client_suspend(wgrp->parent); |
|---|
| 127 | 133 | } |
|---|
| 128 | 134 | |
|---|
| 129 | 135 | wgrp->usecount--; |
|---|
| .. | .. |
|---|
| 385 | 391 | struct tegra_plane *p = to_tegra_plane(plane); |
|---|
| 386 | 392 | struct tegra_dc *dc; |
|---|
| 387 | 393 | u32 value; |
|---|
| 394 | + int err; |
|---|
| 388 | 395 | |
|---|
| 389 | 396 | /* rien ne va plus */ |
|---|
| 390 | 397 | if (!old_state || !old_state->crtc) |
|---|
| 391 | 398 | return; |
|---|
| 392 | 399 | |
|---|
| 393 | 400 | dc = to_tegra_dc(old_state->crtc); |
|---|
| 401 | + |
|---|
| 402 | + err = host1x_client_resume(&dc->client); |
|---|
| 403 | + if (err < 0) { |
|---|
| 404 | + dev_err(dc->dev, "failed to resume: %d\n", err); |
|---|
| 405 | + return; |
|---|
| 406 | + } |
|---|
| 394 | 407 | |
|---|
| 395 | 408 | /* |
|---|
| 396 | 409 | * XXX Legacy helpers seem to sometimes call ->atomic_disable() even |
|---|
| .. | .. |
|---|
| 400 | 413 | if (WARN_ON(p->dc == NULL)) |
|---|
| 401 | 414 | p->dc = dc; |
|---|
| 402 | 415 | |
|---|
| 403 | | - pm_runtime_get_sync(dc->dev); |
|---|
| 404 | | - |
|---|
| 405 | 416 | value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); |
|---|
| 406 | 417 | value &= ~WIN_ENABLE; |
|---|
| 407 | 418 | tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); |
|---|
| 408 | 419 | |
|---|
| 409 | 420 | tegra_dc_remove_shared_plane(dc, p); |
|---|
| 410 | 421 | |
|---|
| 411 | | - pm_runtime_put(dc->dev); |
|---|
| 422 | + host1x_client_suspend(&dc->client); |
|---|
| 412 | 423 | } |
|---|
| 413 | 424 | |
|---|
| 414 | 425 | static void tegra_shared_plane_atomic_update(struct drm_plane *plane, |
|---|
| .. | .. |
|---|
| 419 | 430 | unsigned int zpos = plane->state->normalized_zpos; |
|---|
| 420 | 431 | struct drm_framebuffer *fb = plane->state->fb; |
|---|
| 421 | 432 | struct tegra_plane *p = to_tegra_plane(plane); |
|---|
| 422 | | - struct tegra_bo *bo; |
|---|
| 423 | 433 | dma_addr_t base; |
|---|
| 424 | 434 | u32 value; |
|---|
| 435 | + int err; |
|---|
| 425 | 436 | |
|---|
| 426 | 437 | /* rien ne va plus */ |
|---|
| 427 | 438 | if (!plane->state->crtc || !plane->state->fb) |
|---|
| .. | .. |
|---|
| 432 | 443 | return; |
|---|
| 433 | 444 | } |
|---|
| 434 | 445 | |
|---|
| 435 | | - pm_runtime_get_sync(dc->dev); |
|---|
| 446 | + err = host1x_client_resume(&dc->client); |
|---|
| 447 | + if (err < 0) { |
|---|
| 448 | + dev_err(dc->dev, "failed to resume: %d\n", err); |
|---|
| 449 | + return; |
|---|
| 450 | + } |
|---|
| 436 | 451 | |
|---|
| 437 | 452 | tegra_dc_assign_shared_plane(dc, p); |
|---|
| 438 | 453 | |
|---|
| .. | .. |
|---|
| 462 | 477 | /* disable compression */ |
|---|
| 463 | 478 | tegra_plane_writel(p, 0, DC_WINBUF_CDE_CONTROL); |
|---|
| 464 | 479 | |
|---|
| 465 | | - bo = tegra_fb_get_plane(fb, 0); |
|---|
| 466 | | - base = bo->paddr; |
|---|
| 480 | + base = state->iova[0] + fb->offsets[0]; |
|---|
| 467 | 481 | |
|---|
| 468 | 482 | tegra_plane_writel(p, state->format, DC_WIN_COLOR_DEPTH); |
|---|
| 469 | 483 | tegra_plane_writel(p, 0, DC_WIN_PRECOMP_WGRP_PARAMS); |
|---|
| .. | .. |
|---|
| 523 | 537 | value &= ~CONTROL_CSC_ENABLE; |
|---|
| 524 | 538 | tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL); |
|---|
| 525 | 539 | |
|---|
| 526 | | - pm_runtime_put(dc->dev); |
|---|
| 540 | + host1x_client_suspend(&dc->client); |
|---|
| 527 | 541 | } |
|---|
| 528 | 542 | |
|---|
| 529 | 543 | static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = { |
|---|
| 544 | + .prepare_fb = tegra_plane_prepare_fb, |
|---|
| 545 | + .cleanup_fb = tegra_plane_cleanup_fb, |
|---|
| 530 | 546 | .atomic_check = tegra_shared_plane_atomic_check, |
|---|
| 531 | 547 | .atomic_update = tegra_shared_plane_atomic_update, |
|---|
| 532 | 548 | .atomic_disable = tegra_shared_plane_atomic_disable, |
|---|
| .. | .. |
|---|
| 557 | 573 | plane->base.index = index; |
|---|
| 558 | 574 | |
|---|
| 559 | 575 | plane->wgrp = &hub->wgrps[wgrp]; |
|---|
| 560 | | - plane->wgrp->parent = dc->dev; |
|---|
| 576 | + plane->wgrp->parent = &dc->client; |
|---|
| 561 | 577 | |
|---|
| 562 | 578 | p = &plane->base.base; |
|---|
| 563 | 579 | |
|---|
| .. | .. |
|---|
| 611 | 627 | tegra_display_hub_get_state(struct tegra_display_hub *hub, |
|---|
| 612 | 628 | struct drm_atomic_state *state) |
|---|
| 613 | 629 | { |
|---|
| 614 | | - struct drm_device *drm = dev_get_drvdata(hub->client.parent); |
|---|
| 615 | 630 | struct drm_private_state *priv; |
|---|
| 616 | | - |
|---|
| 617 | | - WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex)); |
|---|
| 618 | 631 | |
|---|
| 619 | 632 | priv = drm_atomic_get_private_obj_state(state, &hub->base); |
|---|
| 620 | 633 | if (IS_ERR(priv)) |
|---|
| .. | .. |
|---|
| 665 | 678 | static void tegra_display_hub_update(struct tegra_dc *dc) |
|---|
| 666 | 679 | { |
|---|
| 667 | 680 | u32 value; |
|---|
| 681 | + int err; |
|---|
| 668 | 682 | |
|---|
| 669 | | - pm_runtime_get_sync(dc->dev); |
|---|
| 683 | + err = host1x_client_resume(&dc->client); |
|---|
| 684 | + if (err < 0) { |
|---|
| 685 | + dev_err(dc->dev, "failed to resume: %d\n", err); |
|---|
| 686 | + return; |
|---|
| 687 | + } |
|---|
| 670 | 688 | |
|---|
| 671 | 689 | value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL); |
|---|
| 672 | 690 | value &= ~LATENCY_EVENT; |
|---|
| .. | .. |
|---|
| 681 | 699 | tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL); |
|---|
| 682 | 700 | tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); |
|---|
| 683 | 701 | |
|---|
| 684 | | - pm_runtime_put(dc->dev); |
|---|
| 702 | + host1x_client_suspend(&dc->client); |
|---|
| 685 | 703 | } |
|---|
| 686 | 704 | |
|---|
| 687 | 705 | void tegra_display_hub_atomic_commit(struct drm_device *drm, |
|---|
| .. | .. |
|---|
| 714 | 732 | static int tegra_display_hub_init(struct host1x_client *client) |
|---|
| 715 | 733 | { |
|---|
| 716 | 734 | struct tegra_display_hub *hub = to_tegra_display_hub(client); |
|---|
| 717 | | - struct drm_device *drm = dev_get_drvdata(client->parent); |
|---|
| 735 | + struct drm_device *drm = dev_get_drvdata(client->host); |
|---|
| 718 | 736 | struct tegra_drm *tegra = drm->dev_private; |
|---|
| 719 | 737 | struct tegra_display_hub_state *state; |
|---|
| 720 | 738 | |
|---|
| .. | .. |
|---|
| 722 | 740 | if (!state) |
|---|
| 723 | 741 | return -ENOMEM; |
|---|
| 724 | 742 | |
|---|
| 725 | | - drm_atomic_private_obj_init(&hub->base, &state->base, |
|---|
| 743 | + drm_atomic_private_obj_init(drm, &hub->base, &state->base, |
|---|
| 726 | 744 | &tegra_display_hub_state_funcs); |
|---|
| 727 | 745 | |
|---|
| 728 | 746 | tegra->hub = hub; |
|---|
| .. | .. |
|---|
| 732 | 750 | |
|---|
| 733 | 751 | static int tegra_display_hub_exit(struct host1x_client *client) |
|---|
| 734 | 752 | { |
|---|
| 735 | | - struct drm_device *drm = dev_get_drvdata(client->parent); |
|---|
| 753 | + struct drm_device *drm = dev_get_drvdata(client->host); |
|---|
| 736 | 754 | struct tegra_drm *tegra = drm->dev_private; |
|---|
| 737 | 755 | |
|---|
| 738 | 756 | drm_atomic_private_obj_fini(&tegra->hub->base); |
|---|
| .. | .. |
|---|
| 741 | 759 | return 0; |
|---|
| 742 | 760 | } |
|---|
| 743 | 761 | |
|---|
| 762 | +static int tegra_display_hub_runtime_suspend(struct host1x_client *client) |
|---|
| 763 | +{ |
|---|
| 764 | + struct tegra_display_hub *hub = to_tegra_display_hub(client); |
|---|
| 765 | + struct device *dev = client->dev; |
|---|
| 766 | + unsigned int i = hub->num_heads; |
|---|
| 767 | + int err; |
|---|
| 768 | + |
|---|
| 769 | + err = reset_control_assert(hub->rst); |
|---|
| 770 | + if (err < 0) |
|---|
| 771 | + return err; |
|---|
| 772 | + |
|---|
| 773 | + while (i--) |
|---|
| 774 | + clk_disable_unprepare(hub->clk_heads[i]); |
|---|
| 775 | + |
|---|
| 776 | + clk_disable_unprepare(hub->clk_hub); |
|---|
| 777 | + clk_disable_unprepare(hub->clk_dsc); |
|---|
| 778 | + clk_disable_unprepare(hub->clk_disp); |
|---|
| 779 | + |
|---|
| 780 | + pm_runtime_put_sync(dev); |
|---|
| 781 | + |
|---|
| 782 | + return 0; |
|---|
| 783 | +} |
|---|
| 784 | + |
|---|
| 785 | +static int tegra_display_hub_runtime_resume(struct host1x_client *client) |
|---|
| 786 | +{ |
|---|
| 787 | + struct tegra_display_hub *hub = to_tegra_display_hub(client); |
|---|
| 788 | + struct device *dev = client->dev; |
|---|
| 789 | + unsigned int i; |
|---|
| 790 | + int err; |
|---|
| 791 | + |
|---|
| 792 | + err = pm_runtime_resume_and_get(dev); |
|---|
| 793 | + if (err < 0) { |
|---|
| 794 | + dev_err(dev, "failed to get runtime PM: %d\n", err); |
|---|
| 795 | + return err; |
|---|
| 796 | + } |
|---|
| 797 | + |
|---|
| 798 | + err = clk_prepare_enable(hub->clk_disp); |
|---|
| 799 | + if (err < 0) |
|---|
| 800 | + goto put_rpm; |
|---|
| 801 | + |
|---|
| 802 | + err = clk_prepare_enable(hub->clk_dsc); |
|---|
| 803 | + if (err < 0) |
|---|
| 804 | + goto disable_disp; |
|---|
| 805 | + |
|---|
| 806 | + err = clk_prepare_enable(hub->clk_hub); |
|---|
| 807 | + if (err < 0) |
|---|
| 808 | + goto disable_dsc; |
|---|
| 809 | + |
|---|
| 810 | + for (i = 0; i < hub->num_heads; i++) { |
|---|
| 811 | + err = clk_prepare_enable(hub->clk_heads[i]); |
|---|
| 812 | + if (err < 0) |
|---|
| 813 | + goto disable_heads; |
|---|
| 814 | + } |
|---|
| 815 | + |
|---|
| 816 | + err = reset_control_deassert(hub->rst); |
|---|
| 817 | + if (err < 0) |
|---|
| 818 | + goto disable_heads; |
|---|
| 819 | + |
|---|
| 820 | + return 0; |
|---|
| 821 | + |
|---|
| 822 | +disable_heads: |
|---|
| 823 | + while (i--) |
|---|
| 824 | + clk_disable_unprepare(hub->clk_heads[i]); |
|---|
| 825 | + |
|---|
| 826 | + clk_disable_unprepare(hub->clk_hub); |
|---|
| 827 | +disable_dsc: |
|---|
| 828 | + clk_disable_unprepare(hub->clk_dsc); |
|---|
| 829 | +disable_disp: |
|---|
| 830 | + clk_disable_unprepare(hub->clk_disp); |
|---|
| 831 | +put_rpm: |
|---|
| 832 | + pm_runtime_put_sync(dev); |
|---|
| 833 | + return err; |
|---|
| 834 | +} |
|---|
| 835 | + |
|---|
| 744 | 836 | static const struct host1x_client_ops tegra_display_hub_ops = { |
|---|
| 745 | 837 | .init = tegra_display_hub_init, |
|---|
| 746 | 838 | .exit = tegra_display_hub_exit, |
|---|
| 839 | + .suspend = tegra_display_hub_runtime_suspend, |
|---|
| 840 | + .resume = tegra_display_hub_runtime_resume, |
|---|
| 747 | 841 | }; |
|---|
| 748 | 842 | |
|---|
| 749 | 843 | static int tegra_display_hub_probe(struct platform_device *pdev) |
|---|
| 750 | 844 | { |
|---|
| 845 | + struct device_node *child = NULL; |
|---|
| 751 | 846 | struct tegra_display_hub *hub; |
|---|
| 847 | + struct clk *clk; |
|---|
| 752 | 848 | unsigned int i; |
|---|
| 753 | 849 | int err; |
|---|
| 754 | 850 | |
|---|
| .. | .. |
|---|
| 764 | 860 | return err; |
|---|
| 765 | 861 | } |
|---|
| 766 | 862 | |
|---|
| 767 | | - hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc"); |
|---|
| 768 | | - if (IS_ERR(hub->clk_dsc)) { |
|---|
| 769 | | - err = PTR_ERR(hub->clk_dsc); |
|---|
| 770 | | - return err; |
|---|
| 863 | + if (hub->soc->supports_dsc) { |
|---|
| 864 | + hub->clk_dsc = devm_clk_get(&pdev->dev, "dsc"); |
|---|
| 865 | + if (IS_ERR(hub->clk_dsc)) { |
|---|
| 866 | + err = PTR_ERR(hub->clk_dsc); |
|---|
| 867 | + return err; |
|---|
| 868 | + } |
|---|
| 771 | 869 | } |
|---|
| 772 | 870 | |
|---|
| 773 | 871 | hub->clk_hub = devm_clk_get(&pdev->dev, "hub"); |
|---|
| .. | .. |
|---|
| 805 | 903 | return err; |
|---|
| 806 | 904 | } |
|---|
| 807 | 905 | |
|---|
| 906 | + hub->num_heads = of_get_child_count(pdev->dev.of_node); |
|---|
| 907 | + |
|---|
| 908 | + hub->clk_heads = devm_kcalloc(&pdev->dev, hub->num_heads, sizeof(clk), |
|---|
| 909 | + GFP_KERNEL); |
|---|
| 910 | + if (!hub->clk_heads) |
|---|
| 911 | + return -ENOMEM; |
|---|
| 912 | + |
|---|
| 913 | + for (i = 0; i < hub->num_heads; i++) { |
|---|
| 914 | + child = of_get_next_child(pdev->dev.of_node, child); |
|---|
| 915 | + if (!child) { |
|---|
| 916 | + dev_err(&pdev->dev, "failed to find node for head %u\n", |
|---|
| 917 | + i); |
|---|
| 918 | + return -ENODEV; |
|---|
| 919 | + } |
|---|
| 920 | + |
|---|
| 921 | + clk = devm_get_clk_from_child(&pdev->dev, child, "dc"); |
|---|
| 922 | + if (IS_ERR(clk)) { |
|---|
| 923 | + dev_err(&pdev->dev, "failed to get clock for head %u\n", |
|---|
| 924 | + i); |
|---|
| 925 | + of_node_put(child); |
|---|
| 926 | + return PTR_ERR(clk); |
|---|
| 927 | + } |
|---|
| 928 | + |
|---|
| 929 | + hub->clk_heads[i] = clk; |
|---|
| 930 | + } |
|---|
| 931 | + |
|---|
| 932 | + of_node_put(child); |
|---|
| 933 | + |
|---|
| 808 | 934 | /* XXX: enable clock across reset? */ |
|---|
| 809 | 935 | err = reset_control_assert(hub->rst); |
|---|
| 810 | 936 | if (err < 0) |
|---|
| .. | .. |
|---|
| 822 | 948 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", |
|---|
| 823 | 949 | err); |
|---|
| 824 | 950 | |
|---|
| 951 | + err = devm_of_platform_populate(&pdev->dev); |
|---|
| 952 | + if (err < 0) |
|---|
| 953 | + goto unregister; |
|---|
| 954 | + |
|---|
| 955 | + return err; |
|---|
| 956 | + |
|---|
| 957 | +unregister: |
|---|
| 958 | + host1x_client_unregister(&hub->client); |
|---|
| 959 | + pm_runtime_disable(&pdev->dev); |
|---|
| 825 | 960 | return err; |
|---|
| 826 | 961 | } |
|---|
| 827 | 962 | |
|---|
| 828 | 963 | static int tegra_display_hub_remove(struct platform_device *pdev) |
|---|
| 829 | 964 | { |
|---|
| 830 | 965 | struct tegra_display_hub *hub = platform_get_drvdata(pdev); |
|---|
| 966 | + unsigned int i; |
|---|
| 831 | 967 | int err; |
|---|
| 832 | 968 | |
|---|
| 833 | 969 | err = host1x_client_unregister(&hub->client); |
|---|
| .. | .. |
|---|
| 836 | 972 | err); |
|---|
| 837 | 973 | } |
|---|
| 838 | 974 | |
|---|
| 975 | + for (i = 0; i < hub->soc->num_wgrps; i++) { |
|---|
| 976 | + struct tegra_windowgroup *wgrp = &hub->wgrps[i]; |
|---|
| 977 | + |
|---|
| 978 | + mutex_destroy(&wgrp->lock); |
|---|
| 979 | + } |
|---|
| 980 | + |
|---|
| 839 | 981 | pm_runtime_disable(&pdev->dev); |
|---|
| 840 | 982 | |
|---|
| 841 | 983 | return err; |
|---|
| 842 | 984 | } |
|---|
| 843 | 985 | |
|---|
| 844 | | -static int __maybe_unused tegra_display_hub_suspend(struct device *dev) |
|---|
| 845 | | -{ |
|---|
| 846 | | - struct tegra_display_hub *hub = dev_get_drvdata(dev); |
|---|
| 847 | | - int err; |
|---|
| 848 | | - |
|---|
| 849 | | - err = reset_control_assert(hub->rst); |
|---|
| 850 | | - if (err < 0) |
|---|
| 851 | | - return err; |
|---|
| 852 | | - |
|---|
| 853 | | - clk_disable_unprepare(hub->clk_hub); |
|---|
| 854 | | - clk_disable_unprepare(hub->clk_dsc); |
|---|
| 855 | | - clk_disable_unprepare(hub->clk_disp); |
|---|
| 856 | | - |
|---|
| 857 | | - return 0; |
|---|
| 858 | | -} |
|---|
| 859 | | - |
|---|
| 860 | | -static int __maybe_unused tegra_display_hub_resume(struct device *dev) |
|---|
| 861 | | -{ |
|---|
| 862 | | - struct tegra_display_hub *hub = dev_get_drvdata(dev); |
|---|
| 863 | | - int err; |
|---|
| 864 | | - |
|---|
| 865 | | - err = clk_prepare_enable(hub->clk_disp); |
|---|
| 866 | | - if (err < 0) |
|---|
| 867 | | - return err; |
|---|
| 868 | | - |
|---|
| 869 | | - err = clk_prepare_enable(hub->clk_dsc); |
|---|
| 870 | | - if (err < 0) |
|---|
| 871 | | - goto disable_disp; |
|---|
| 872 | | - |
|---|
| 873 | | - err = clk_prepare_enable(hub->clk_hub); |
|---|
| 874 | | - if (err < 0) |
|---|
| 875 | | - goto disable_dsc; |
|---|
| 876 | | - |
|---|
| 877 | | - err = reset_control_deassert(hub->rst); |
|---|
| 878 | | - if (err < 0) |
|---|
| 879 | | - goto disable_hub; |
|---|
| 880 | | - |
|---|
| 881 | | - return 0; |
|---|
| 882 | | - |
|---|
| 883 | | -disable_hub: |
|---|
| 884 | | - clk_disable_unprepare(hub->clk_hub); |
|---|
| 885 | | -disable_dsc: |
|---|
| 886 | | - clk_disable_unprepare(hub->clk_dsc); |
|---|
| 887 | | -disable_disp: |
|---|
| 888 | | - clk_disable_unprepare(hub->clk_disp); |
|---|
| 889 | | - return err; |
|---|
| 890 | | -} |
|---|
| 891 | | - |
|---|
| 892 | | -static const struct dev_pm_ops tegra_display_hub_pm_ops = { |
|---|
| 893 | | - SET_RUNTIME_PM_OPS(tegra_display_hub_suspend, |
|---|
| 894 | | - tegra_display_hub_resume, NULL) |
|---|
| 895 | | -}; |
|---|
| 896 | | - |
|---|
| 897 | 986 | static const struct tegra_display_hub_soc tegra186_display_hub = { |
|---|
| 898 | 987 | .num_wgrps = 6, |
|---|
| 988 | + .supports_dsc = true, |
|---|
| 989 | +}; |
|---|
| 990 | + |
|---|
| 991 | +static const struct tegra_display_hub_soc tegra194_display_hub = { |
|---|
| 992 | + .num_wgrps = 6, |
|---|
| 993 | + .supports_dsc = false, |
|---|
| 899 | 994 | }; |
|---|
| 900 | 995 | |
|---|
| 901 | 996 | static const struct of_device_id tegra_display_hub_of_match[] = { |
|---|
| 902 | 997 | { |
|---|
| 998 | + .compatible = "nvidia,tegra194-display", |
|---|
| 999 | + .data = &tegra194_display_hub |
|---|
| 1000 | + }, { |
|---|
| 903 | 1001 | .compatible = "nvidia,tegra186-display", |
|---|
| 904 | 1002 | .data = &tegra186_display_hub |
|---|
| 905 | 1003 | }, { |
|---|
| .. | .. |
|---|
| 912 | 1010 | .driver = { |
|---|
| 913 | 1011 | .name = "tegra-display-hub", |
|---|
| 914 | 1012 | .of_match_table = tegra_display_hub_of_match, |
|---|
| 915 | | - .pm = &tegra_display_hub_pm_ops, |
|---|
| 916 | 1013 | }, |
|---|
| 917 | 1014 | .probe = tegra_display_hub_probe, |
|---|
| 918 | 1015 | .remove = tegra_display_hub_remove, |
|---|