drm/tegra: Changes for v5.6-rc1 This contains a small set of mostly fixes and some minor improvements. Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -1727,6 +1727,7 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, · 1726 unmodified lines | |||
| 1727 | { | 1727 | { |
| 1728 | struct tegra_dc *dc = to_tegra_dc(crtc); | 1728 | struct tegra_dc *dc = to_tegra_dc(crtc); |
| 1729 | u32 value; | 1729 | u32 value; |
| 1730 | int err; | ||
| 1730 | 1731 | ||
| 1731 | if (!tegra_dc_idle(dc)) { | 1732 | if (!tegra_dc_idle(dc)) { |
| 1732 | tegra_dc_stop(dc); | 1733 | tegra_dc_stop(dc); |
| @@ -1773,7 +1774,9 @@ static void tegra_crtc_atomic_disable(struct drm_crtc *crtc, · 40 unmodified lines | |||
| 1773 | 1774 | ||
| 1774 | spin_unlock_irq(&crtc->dev->event_lock); | 1775 | spin_unlock_irq(&crtc->dev->event_lock); |
| 1775 | 1776 | ||
| 1776 | pm_runtime_put_sync(dc->dev); | 1777 | err = host1x_client_suspend(&dc->client); |
| 1778 | if (err < 0) | ||
| 1779 | dev_err(dc->dev, "failed to suspend: %d\n", err); | ||
| 1777 | } | 1780 | } |
| 1778 | 1781 | ||
| 1779 | static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, | 1782 | static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, |
| @@ -1783,8 +1786,13 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, · 3 unmodified lines | |||
| 1783 | struct tegra_dc_state *state = to_dc_state(crtc->state); | 1786 | struct tegra_dc_state *state = to_dc_state(crtc->state); |
| 1784 | struct tegra_dc *dc = to_tegra_dc(crtc); | 1787 | struct tegra_dc *dc = to_tegra_dc(crtc); |
| 1785 | u32 value; | 1788 | u32 value; |
| 1789 | int err; | ||
| 1786 | 1790 | ||
| 1787 | pm_runtime_get_sync(dc->dev); | 1791 | err = host1x_client_resume(&dc->client); |
| 1792 | if (err < 0) { | ||
| 1793 | dev_err(dc->dev, "failed to resume: %d\n", err); | ||
| 1794 | return; | ||
| 1795 | } | ||
| 1788 | 1796 | ||
| 1789 | /* initialize display controller */ | 1797 | /* initialize display controller */ |
| 1790 | if (dc->syncpt) { | 1798 | if (dc->syncpt) { |
| @@ -1996,7 +2004,7 @@ static bool tegra_dc_has_window_groups(struct tegra_dc *dc) · 205 unmodified lines | |||
| 1996 | 2004 | ||
| 1997 | static int tegra_dc_init(struct host1x_client *client) | 2005 | static int tegra_dc_init(struct host1x_client *client) |
| 1998 | { | 2006 | { |
| 1999 | struct drm_device *drm = dev_get_drvdata(client->parent); | 2007 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 2000 | unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; | 2008 | unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; |
| 2001 | struct tegra_dc *dc = host1x_client_to_dc(client); | 2009 | struct tegra_dc *dc = host1x_client_to_dc(client); |
| 2002 | struct tegra_drm *tegra = drm->dev_private; | 2010 | struct tegra_drm *tegra = drm->dev_private; |
| @@ -2012,6 +2020,15 @@ static int tegra_dc_init(struct host1x_client *client) · 9 unmodified lines | |||
| 2012 | if (!tegra_dc_has_window_groups(dc)) | 2020 | if (!tegra_dc_has_window_groups(dc)) |
| 2013 | return 0; | 2021 | return 0; |
| 2014 | 2022 | ||
| 2023 | /* | ||
| 2024 | * Set the display hub as the host1x client parent for the display | ||
| 2025 | * controller. This is needed for the runtime reference counting that | ||
| 2026 | * ensures the display hub is always powered when any of the display | ||
| 2027 | * controllers are. | ||
| 2028 | */ | ||
| 2029 | if (dc->soc->has_nvdisplay) | ||
| 2030 | client->parent = &tegra->hub->client; | ||
| 2031 | |||
| 2015 | dc->syncpt = host1x_syncpt_request(client, flags); | 2032 | dc->syncpt = host1x_syncpt_request(client, flags); |
| 2016 | if (!dc->syncpt) | 2033 | if (!dc->syncpt) |
| 2017 | dev_warn(dc->dev, "failed to allocate syncpoint\n"); | 2034 | dev_warn(dc->dev, "failed to allocate syncpoint\n"); |
| @@ -2077,9 +2094,9 @@ static int tegra_dc_init(struct host1x_client *client) · 59 unmodified lines | |||
| 2077 | 2094 | ||
| 2078 | /* | 2095 | /* |
| 2079 | * Inherit the DMA parameters (such as maximum segment size) from the | 2096 | * Inherit the DMA parameters (such as maximum segment size) from the |
| 2080 | * parent device. | 2097 | * parent host1x device. |
| 2081 | */ | 2098 | */ |
| 2082 | client->dev->dma_parms = client->parent->dma_parms; | 2099 | client->dev->dma_parms = client->host->dma_parms; |
| 2083 | 2100 | ||
| 2084 | return 0; | 2101 | return 0; |
| 2085 | 2102 | ||
| @@ -2121,9 +2138,74 @@ static int tegra_dc_exit(struct host1x_client *client) · 35 unmodified lines | |||
| 2121 | return 0; | 2138 | return 0; |
| 2122 | } | 2139 | } |
| 2123 | 2140 | ||
| 2141 | static int tegra_dc_runtime_suspend(struct host1x_client *client) | ||
| 2142 | { | ||
| 2143 | struct tegra_dc *dc = host1x_client_to_dc(client); | ||
| 2144 | struct device *dev = client->dev; | ||
| 2145 | int err; | ||
| 2146 | |||
| 2147 | err = reset_control_assert(dc->rst); | ||
| 2148 | if (err < 0) { | ||
| 2149 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 2150 | return err; | ||
| 2151 | } | ||
| 2152 | |||
| 2153 | if (dc->soc->has_powergate) | ||
| 2154 | tegra_powergate_power_off(dc->powergate); | ||
| 2155 | |||
| 2156 | clk_disable_unprepare(dc->clk); | ||
| 2157 | pm_runtime_put_sync(dev); | ||
| 2158 | |||
| 2159 | return 0; | ||
| 2160 | } | ||
| 2161 | |||
| 2162 | static int tegra_dc_runtime_resume(struct host1x_client *client) | ||
| 2163 | { | ||
| 2164 | struct tegra_dc *dc = host1x_client_to_dc(client); | ||
| 2165 | struct device *dev = client->dev; | ||
| 2166 | int err; | ||
| 2167 | |||
| 2168 | err = pm_runtime_get_sync(dev); | ||
| 2169 | if (err < 0) { | ||
| 2170 | dev_err(dev, "failed to get runtime PM: %d\n", err); | ||
| 2171 | return err; | ||
| 2172 | } | ||
| 2173 | |||
| 2174 | if (dc->soc->has_powergate) { | ||
| 2175 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | ||
| 2176 | dc->rst); | ||
| 2177 | if (err < 0) { | ||
| 2178 | dev_err(dev, "failed to power partition: %d\n", err); | ||
| 2179 | goto put_rpm; | ||
| 2180 | } | ||
| 2181 | } else { | ||
| 2182 | err = clk_prepare_enable(dc->clk); | ||
| 2183 | if (err < 0) { | ||
| 2184 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
| 2185 | goto put_rpm; | ||
| 2186 | } | ||
| 2187 | |||
| 2188 | err = reset_control_deassert(dc->rst); | ||
| 2189 | if (err < 0) { | ||
| 2190 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
| 2191 | goto disable_clk; | ||
| 2192 | } | ||
| 2193 | } | ||
| 2194 | |||
| 2195 | return 0; | ||
| 2196 | |||
| 2197 | disable_clk: | ||
| 2198 | clk_disable_unprepare(dc->clk); | ||
| 2199 | put_rpm: | ||
| 2200 | pm_runtime_put_sync(dev); | ||
| 2201 | return err; | ||
| 2202 | } | ||
| 2203 | |||
| 2124 | static const struct host1x_client_ops dc_client_ops = { | 2204 | static const struct host1x_client_ops dc_client_ops = { |
| 2125 | .init = tegra_dc_init, | 2205 | .init = tegra_dc_init, |
| 2126 | .exit = tegra_dc_exit, | 2206 | .exit = tegra_dc_exit, |
| 2207 | .suspend = tegra_dc_runtime_suspend, | ||
| 2208 | .resume = tegra_dc_runtime_resume, | ||
| 2127 | }; | 2209 | }; |
| 2128 | 2210 | ||
| 2129 | static const struct tegra_dc_soc_info tegra20_dc_soc_info = { | 2211 | static const struct tegra_dc_soc_info tegra20_dc_soc_info = { |
| @@ -2535,65 +2617,10 @@ static int tegra_dc_remove(struct platform_device *pdev) · 405 unmodified lines | |||
| 2535 | return 0; | 2617 | return 0; |
| 2536 | } | 2618 | } |
| 2537 | 2619 | ||
| 2538 | #ifdef CONFIG_PM | ||
| 2539 | static int tegra_dc_suspend(struct device *dev) | ||
| 2540 | { | ||
| 2541 | struct tegra_dc *dc = dev_get_drvdata(dev); | ||
| 2542 | int err; | ||
| 2543 | |||
| 2544 | err = reset_control_assert(dc->rst); | ||
| 2545 | if (err < 0) { | ||
| 2546 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 2547 | return err; | ||
| 2548 | } | ||
| 2549 | |||
| 2550 | if (dc->soc->has_powergate) | ||
| 2551 | tegra_powergate_power_off(dc->powergate); | ||
| 2552 | |||
| 2553 | clk_disable_unprepare(dc->clk); | ||
| 2554 | |||
| 2555 | return 0; | ||
| 2556 | } | ||
| 2557 | |||
| 2558 | static int tegra_dc_resume(struct device *dev) | ||
| 2559 | { | ||
| 2560 | struct tegra_dc *dc = dev_get_drvdata(dev); | ||
| 2561 | int err; | ||
| 2562 | |||
| 2563 | if (dc->soc->has_powergate) { | ||
| 2564 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | ||
| 2565 | dc->rst); | ||
| 2566 | if (err < 0) { | ||
| 2567 | dev_err(dev, "failed to power partition: %d\n", err); | ||
| 2568 | return err; | ||
| 2569 | } | ||
| 2570 | } else { | ||
| 2571 | err = clk_prepare_enable(dc->clk); | ||
| 2572 | if (err < 0) { | ||
| 2573 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
| 2574 | return err; | ||
| 2575 | } | ||
| 2576 | |||
| 2577 | err = reset_control_deassert(dc->rst); | ||
| 2578 | if (err < 0) { | ||
| 2579 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
| 2580 | return err; | ||
| 2581 | } | ||
| 2582 | } | ||
| 2583 | |||
| 2584 | return 0; | ||
| 2585 | } | ||
| 2586 | #endif | ||
| 2587 | |||
| 2588 | static const struct dev_pm_ops tegra_dc_pm_ops = { | ||
| 2589 | SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL) | ||
| 2590 | }; | ||
| 2591 | |||
| 2592 | struct platform_driver tegra_dc_driver = { | 2620 | struct platform_driver tegra_dc_driver = { |
| 2593 | .driver = { | 2621 | .driver = { |
| 2594 | .name = "tegra-dc", | 2622 | .name = "tegra-dc", |
| 2595 | .of_match_table = tegra_dc_of_match, | 2623 | .of_match_table = tegra_dc_of_match, |
| 2596 | .pm = &tegra_dc_pm_ops, | ||
| 2597 | }, | 2624 | }, |
| 2598 | .probe = tegra_dc_probe, | 2625 | .probe = tegra_dc_probe, |
| 2599 | .remove = tegra_dc_remove, | 2626 | .remove = tegra_dc_remove, |
| @@ -588,7 +588,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev) · 587 unmodified lines | |||
| 588 | /* make sure pads are powered down when not in use */ | 588 | /* make sure pads are powered down when not in use */ |
| 589 | tegra_dpaux_pad_power_down(dpaux); | 589 | tegra_dpaux_pad_power_down(dpaux); |
| 590 | 590 | ||
| 591 | pm_runtime_put(&pdev->dev); | 591 | pm_runtime_put_sync(&pdev->dev); |
| 592 | pm_runtime_disable(&pdev->dev); | 592 | pm_runtime_disable(&pdev->dev); |
| 593 | 593 | ||
| 594 | drm_dp_aux_unregister(&dpaux->aux); | 594 | drm_dp_aux_unregister(&dpaux->aux); |
| @@ -905,7 +905,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, · 904 unmodified lines | |||
| 905 | int host1x_client_iommu_attach(struct host1x_client *client) | 905 | int host1x_client_iommu_attach(struct host1x_client *client) |
| 906 | { | 906 | { |
| 907 | struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev); | 907 | struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev); |
| 908 | struct drm_device *drm = dev_get_drvdata(client->parent); | 908 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 909 | struct tegra_drm *tegra = drm->dev_private; | 909 | struct tegra_drm *tegra = drm->dev_private; |
| 910 | struct iommu_group *group = NULL; | 910 | struct iommu_group *group = NULL; |
| 911 | int err; | 911 | int err; |
| @@ -941,7 +941,7 @@ int host1x_client_iommu_attach(struct host1x_client *client) · 29 unmodified lines | |||
| 941 | 941 | ||
| 942 | void host1x_client_iommu_detach(struct host1x_client *client) | 942 | void host1x_client_iommu_detach(struct host1x_client *client) |
| 943 | { | 943 | { |
| 944 | struct drm_device *drm = dev_get_drvdata(client->parent); | 944 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 945 | struct tegra_drm *tegra = drm->dev_private; | 945 | struct tegra_drm *tegra = drm->dev_private; |
| 946 | struct iommu_domain *domain; | 946 | struct iommu_domain *domain; |
| 947 | 947 | ||
| @@ -144,6 +144,8 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output); · 143 unmodified lines | |||
| 144 | void tegra_output_exit(struct tegra_output *output); | 144 | void tegra_output_exit(struct tegra_output *output); |
| 145 | void tegra_output_find_possible_crtcs(struct tegra_output *output, | 145 | void tegra_output_find_possible_crtcs(struct tegra_output *output, |
| 146 | struct drm_device *drm); | 146 | struct drm_device *drm); |
| 147 | int tegra_output_suspend(struct tegra_output *output); | ||
| 148 | int tegra_output_resume(struct tegra_output *output); | ||
| 147 | 149 | ||
| 148 | int tegra_output_connector_get_modes(struct drm_connector *connector); | 150 | int tegra_output_connector_get_modes(struct drm_connector *connector); |
| 149 | enum drm_connector_status | 151 | enum drm_connector_status |
| @@ -840,7 +840,9 @@ static void tegra_dsi_unprepare(struct tegra_dsi *dsi) · 839 unmodified lines | |||
| 840 | dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n", | 840 | dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n", |
| 841 | err); | 841 | err); |
| 842 | 842 | ||
| 843 | pm_runtime_put(dsi->dev); | 843 | err = host1x_client_suspend(&dsi->client); |
| 844 | if (err < 0) | ||
| 845 | dev_err(dsi->dev, "failed to suspend: %d\n", err); | ||
| 844 | } | 846 | } |
| 845 | 847 | ||
| 846 | static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) | 848 | static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) |
| @@ -882,11 +884,15 @@ static void tegra_dsi_encoder_disable(struct drm_encoder *encoder) · 35 unmodified lines | |||
| 882 | tegra_dsi_unprepare(dsi); | 884 | tegra_dsi_unprepare(dsi); |
| 883 | } | 885 | } |
| 884 | 886 | ||
| 885 | static void tegra_dsi_prepare(struct tegra_dsi *dsi) | 887 | static int tegra_dsi_prepare(struct tegra_dsi *dsi) |
| 886 | { | 888 | { |
| 887 | int err; | 889 | int err; |
| 888 | 890 | ||
| 889 | pm_runtime_get_sync(dsi->dev); | 891 | err = host1x_client_resume(&dsi->client); |
| 892 | if (err < 0) { | ||
| 893 | dev_err(dsi->dev, "failed to resume: %d\n", err); | ||
| 894 | return err; | ||
| 895 | } | ||
| 890 | 896 | ||
| 891 | err = tegra_mipi_enable(dsi->mipi); | 897 | err = tegra_mipi_enable(dsi->mipi); |
| 892 | if (err < 0) | 898 | if (err < 0) |
| @@ -899,6 +905,8 @@ static void tegra_dsi_prepare(struct tegra_dsi *dsi) · 6 unmodified lines | |||
| 899 | 905 | ||
| 900 | if (dsi->slave) | 906 | if (dsi->slave) |
| 901 | tegra_dsi_prepare(dsi->slave); | 907 | tegra_dsi_prepare(dsi->slave); |
| 908 | |||
| 909 | return 0; | ||
| 902 | } | 910 | } |
| 903 | 911 | ||
| 904 | static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) | 912 | static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) |
| @@ -909,8 +917,13 @@ static void tegra_dsi_encoder_enable(struct drm_encoder *encoder) · 4 unmodified lines | |||
| 909 | struct tegra_dsi *dsi = to_dsi(output); | 917 | struct tegra_dsi *dsi = to_dsi(output); |
| 910 | struct tegra_dsi_state *state; | 918 | struct tegra_dsi_state *state; |
| 911 | u32 value; | 919 | u32 value; |
| 920 | int err; | ||
| 912 | 921 | ||
| 913 | tegra_dsi_prepare(dsi); | 922 | err = tegra_dsi_prepare(dsi); |
| 923 | if (err < 0) { | ||
| 924 | dev_err(dsi->dev, "failed to prepare: %d\n", err); | ||
| 925 | return; | ||
| 926 | } | ||
| 914 | 927 | ||
| 915 | state = tegra_dsi_get_state(dsi); | 928 | state = tegra_dsi_get_state(dsi); |
| 916 | 929 | ||
| @@ -1030,7 +1043,7 @@ static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = { · 113 unmodified lines | |||
| 1030 | 1043 | ||
| 1031 | static int tegra_dsi_init(struct host1x_client *client) | 1044 | static int tegra_dsi_init(struct host1x_client *client) |
| 1032 | { | 1045 | { |
| 1033 | struct drm_device *drm = dev_get_drvdata(client->parent); | 1046 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 1034 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); | 1047 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
| 1035 | int err; | 1048 | int err; |
| 1036 | 1049 | ||
| @@ -1075,9 +1088,89 @@ static int tegra_dsi_exit(struct host1x_client *client) · 38 unmodified lines | |||
| 1075 | return 0; | 1088 | return 0; |
| 1076 | } | 1089 | } |
| 1077 | 1090 | ||
| 1091 | static int tegra_dsi_runtime_suspend(struct host1x_client *client) | ||
| 1092 | { | ||
| 1093 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); | ||
| 1094 | struct device *dev = client->dev; | ||
| 1095 | int err; | ||
| 1096 | |||
| 1097 | if (dsi->rst) { | ||
| 1098 | err = reset_control_assert(dsi->rst); | ||
| 1099 | if (err < 0) { | ||
| 1100 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 1101 | return err; | ||
| 1102 | } | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | usleep_range(1000, 2000); | ||
| 1106 | |||
| 1107 | clk_disable_unprepare(dsi->clk_lp); | ||
| 1108 | clk_disable_unprepare(dsi->clk); | ||
| 1109 | |||
| 1110 | regulator_disable(dsi->vdd); | ||
| 1111 | pm_runtime_put_sync(dev); | ||
| 1112 | |||
| 1113 | return 0; | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | static int tegra_dsi_runtime_resume(struct host1x_client *client) | ||
| 1117 | { | ||
| 1118 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); | ||
| 1119 | struct device *dev = client->dev; | ||
| 1120 | int err; | ||
| 1121 | |||
| 1122 | err = pm_runtime_get_sync(dev); | ||
| 1123 | if (err < 0) { | ||
| 1124 | dev_err(dev, "failed to get runtime PM: %d\n", err); | ||
| 1125 | return err; | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | err = regulator_enable(dsi->vdd); | ||
| 1129 | if (err < 0) { | ||
| 1130 | dev_err(dev, "failed to enable VDD supply: %d\n", err); | ||
| 1131 | goto put_rpm; | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | err = clk_prepare_enable(dsi->clk); | ||
| 1135 | if (err < 0) { | ||
| 1136 | dev_err(dev, "cannot enable DSI clock: %d\n", err); | ||
| 1137 | goto disable_vdd; | ||
| 1138 | } | ||
| 1139 | |||
| 1140 | err = clk_prepare_enable(dsi->clk_lp); | ||
| 1141 | if (err < 0) { | ||
| 1142 | dev_err(dev, "cannot enable low-power clock: %d\n", err); | ||
| 1143 | goto disable_clk; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | usleep_range(1000, 2000); | ||
| 1147 | |||
| 1148 | if (dsi->rst) { | ||
| 1149 | err = reset_control_deassert(dsi->rst); | ||
| 1150 | if (err < 0) { | ||
| 1151 | dev_err(dev, "cannot assert reset: %d\n", err); | ||
| 1152 | goto disable_clk_lp; | ||
| 1153 | } | ||
| 1154 | } | ||
| 1155 | |||
| 1156 | return 0; | ||
| 1157 | |||
| 1158 | disable_clk_lp: | ||
| 1159 | clk_disable_unprepare(dsi->clk_lp); | ||
| 1160 | disable_clk: | ||
| 1161 | clk_disable_unprepare(dsi->clk); | ||
| 1162 | disable_vdd: | ||
| 1163 | regulator_disable(dsi->vdd); | ||
| 1164 | put_rpm: | ||
| 1165 | pm_runtime_put_sync(dev); | ||
| 1166 | return err; | ||
| 1167 | } | ||
| 1168 | |||
| 1078 | static const struct host1x_client_ops dsi_client_ops = { | 1169 | static const struct host1x_client_ops dsi_client_ops = { |
| 1079 | .init = tegra_dsi_init, | 1170 | .init = tegra_dsi_init, |
| 1080 | .exit = tegra_dsi_exit, | 1171 | .exit = tegra_dsi_exit, |
| 1172 | .suspend = tegra_dsi_runtime_suspend, | ||
| 1173 | .resume = tegra_dsi_runtime_resume, | ||
| 1081 | }; | 1174 | }; |
| 1082 | 1175 | ||
| 1083 | static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) | 1176 | static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi) |
| @@ -1596,79 +1689,6 @@ static int tegra_dsi_remove(struct platform_device *pdev) · 512 unmodified lines | |||
| 1596 | return 0; | 1689 | return 0; |
| 1597 | } | 1690 | } |
| 1598 | 1691 | ||
| 1599 | #ifdef CONFIG_PM | ||
| 1600 | static int tegra_dsi_suspend(struct device *dev) | ||
| 1601 | { | ||
| 1602 | struct tegra_dsi *dsi = dev_get_drvdata(dev); | ||
| 1603 | int err; | ||
| 1604 | |||
| 1605 | if (dsi->rst) { | ||
| 1606 | err = reset_control_assert(dsi->rst); | ||
| 1607 | if (err < 0) { | ||
| 1608 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 1609 | return err; | ||
| 1610 | } | ||
| 1611 | } | ||
| 1612 | |||
| 1613 | usleep_range(1000, 2000); | ||
| 1614 | |||
| 1615 | clk_disable_unprepare(dsi->clk_lp); | ||
| 1616 | clk_disable_unprepare(dsi->clk); | ||
| 1617 | |||
| 1618 | regulator_disable(dsi->vdd); | ||
| 1619 | |||
| 1620 | return 0; | ||
| 1621 | } | ||
| 1622 | |||
| 1623 | static int tegra_dsi_resume(struct device *dev) | ||
| 1624 | { | ||
| 1625 | struct tegra_dsi *dsi = dev_get_drvdata(dev); | ||
| 1626 | int err; | ||
| 1627 | |||
| 1628 | err = regulator_enable(dsi->vdd); | ||
| 1629 | if (err < 0) { | ||
| 1630 | dev_err(dsi->dev, "failed to enable VDD supply: %d\n", err); | ||
| 1631 | return err; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | err = clk_prepare_enable(dsi->clk); | ||
| 1635 | if (err < 0) { | ||
| 1636 | dev_err(dev, "cannot enable DSI clock: %d\n", err); | ||
| 1637 | goto disable_vdd; | ||
| 1638 | } | ||
| 1639 | |||
| 1640 | err = clk_prepare_enable(dsi->clk_lp); | ||
| 1641 | if (err < 0) { | ||
| 1642 | dev_err(dev, "cannot enable low-power clock: %d\n", err); | ||
| 1643 | goto disable_clk; | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | usleep_range(1000, 2000); | ||
| 1647 | |||
| 1648 | if (dsi->rst) { | ||
| 1649 | err = reset_control_deassert(dsi->rst); | ||
| 1650 | if (err < 0) { | ||
| 1651 | dev_err(dev, "cannot assert reset: %d\n", err); | ||
| 1652 | goto disable_clk_lp; | ||
| 1653 | } | ||
| 1654 | } | ||
| 1655 | |||
| 1656 | return 0; | ||
| 1657 | |||
| 1658 | disable_clk_lp: | ||
| 1659 | clk_disable_unprepare(dsi->clk_lp); | ||
| 1660 | disable_clk: | ||
| 1661 | clk_disable_unprepare(dsi->clk); | ||
| 1662 | disable_vdd: | ||
| 1663 | regulator_disable(dsi->vdd); | ||
| 1664 | return err; | ||
| 1665 | } | ||
| 1666 | #endif | ||
| 1667 | |||
| 1668 | static const struct dev_pm_ops tegra_dsi_pm_ops = { | ||
| 1669 | SET_RUNTIME_PM_OPS(tegra_dsi_suspend, tegra_dsi_resume, NULL) | ||
| 1670 | }; | ||
| 1671 | |||
| 1672 | static const struct of_device_id tegra_dsi_of_match[] = { | 1692 | static const struct of_device_id tegra_dsi_of_match[] = { |
| 1673 | { .compatible = "nvidia,tegra210-dsi", }, | 1693 | { .compatible = "nvidia,tegra210-dsi", }, |
| 1674 | { .compatible = "nvidia,tegra132-dsi", }, | 1694 | { .compatible = "nvidia,tegra132-dsi", }, |
| @@ -1682,7 +1702,6 @@ struct platform_driver tegra_dsi_driver = { · 7 unmodified lines | |||
| 1682 | .driver = { | 1702 | .driver = { |
| 1683 | .name = "tegra-dsi", | 1703 | .name = "tegra-dsi", |
| 1684 | .of_match_table = tegra_dsi_of_match, | 1704 | .of_match_table = tegra_dsi_of_match, |
| 1685 | .pm = &tegra_dsi_pm_ops, | ||
| 1686 | }, | 1705 | }, |
| 1687 | .probe = tegra_dsi_probe, | 1706 | .probe = tegra_dsi_probe, |
| 1688 | .remove = tegra_dsi_remove, | 1707 | .remove = tegra_dsi_remove, |
| @@ -34,7 +34,7 @@ static inline struct gr2d *to_gr2d(struct tegra_drm_client *client) · 33 unmodified lines | |||
| 34 | static int gr2d_init(struct host1x_client *client) | 34 | static int gr2d_init(struct host1x_client *client) |
| 35 | { | 35 | { |
| 36 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | 36 | struct tegra_drm_client *drm = host1x_to_drm_client(client); |
| 37 | struct drm_device *dev = dev_get_drvdata(client->parent); | 37 | struct drm_device *dev = dev_get_drvdata(client->host); |
| 38 | unsigned long flags = HOST1X_SYNCPT_HAS_BASE; | 38 | unsigned long flags = HOST1X_SYNCPT_HAS_BASE; |
| 39 | struct gr2d *gr2d = to_gr2d(drm); | 39 | struct gr2d *gr2d = to_gr2d(drm); |
| 40 | int err; | 40 | int err; |
| @@ -76,7 +76,7 @@ put: · 35 unmodified lines | |||
| 76 | static int gr2d_exit(struct host1x_client *client) | 76 | static int gr2d_exit(struct host1x_client *client) |
| 77 | { | 77 | { |
| 78 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | 78 | struct tegra_drm_client *drm = host1x_to_drm_client(client); |
| 79 | struct drm_device *dev = dev_get_drvdata(client->parent); | 79 | struct drm_device *dev = dev_get_drvdata(client->host); |
| 80 | struct tegra_drm *tegra = dev->dev_private; | 80 | struct tegra_drm *tegra = dev->dev_private; |
| 81 | struct gr2d *gr2d = to_gr2d(drm); | 81 | struct gr2d *gr2d = to_gr2d(drm); |
| 82 | int err; | 82 | int err; |
| @@ -43,7 +43,7 @@ static inline struct gr3d *to_gr3d(struct tegra_drm_client *client) · 42 unmodified lines | |||
| 43 | static int gr3d_init(struct host1x_client *client) | 43 | static int gr3d_init(struct host1x_client *client) |
| 44 | { | 44 | { |
| 45 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | 45 | struct tegra_drm_client *drm = host1x_to_drm_client(client); |
| 46 | struct drm_device *dev = dev_get_drvdata(client->parent); | 46 | struct drm_device *dev = dev_get_drvdata(client->host); |
| 47 | unsigned long flags = HOST1X_SYNCPT_HAS_BASE; | 47 | unsigned long flags = HOST1X_SYNCPT_HAS_BASE; |
| 48 | struct gr3d *gr3d = to_gr3d(drm); | 48 | struct gr3d *gr3d = to_gr3d(drm); |
| 49 | int err; | 49 | int err; |
| @@ -85,7 +85,7 @@ put: · 35 unmodified lines | |||
| 85 | static int gr3d_exit(struct host1x_client *client) | 85 | static int gr3d_exit(struct host1x_client *client) |
| 86 | { | 86 | { |
| 87 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | 87 | struct tegra_drm_client *drm = host1x_to_drm_client(client); |
| 88 | struct drm_device *dev = dev_get_drvdata(client->parent); | 88 | struct drm_device *dev = dev_get_drvdata(client->host); |
| 89 | struct gr3d *gr3d = to_gr3d(drm); | 89 | struct gr3d *gr3d = to_gr3d(drm); |
| 90 | int err; | 90 | int err; |
| 91 | 91 | ||
| @@ -1146,6 +1146,7 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) · 1145 unmodified lines | |||
| 1146 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); | 1146 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
| 1147 | struct tegra_hdmi *hdmi = to_hdmi(output); | 1147 | struct tegra_hdmi *hdmi = to_hdmi(output); |
| 1148 | u32 value; | 1148 | u32 value; |
| 1149 | int err; | ||
| 1149 | 1150 | ||
| 1150 | /* | 1151 | /* |
| 1151 | * The following accesses registers of the display controller, so make | 1152 | * The following accesses registers of the display controller, so make |
| @@ -1171,7 +1172,9 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) · 19 unmodified lines | |||
| 1171 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_ENABLE); | 1172 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_ENABLE); |
| 1172 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_MASK); | 1173 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_MASK); |
| 1173 | 1174 | ||
| 1174 | pm_runtime_put(hdmi->dev); | 1175 | err = host1x_client_suspend(&hdmi->client); |
| 1176 | if (err < 0) | ||
| 1177 | dev_err(hdmi->dev, "failed to suspend: %d\n", err); | ||
| 1175 | } | 1178 | } |
| 1176 | 1179 | ||
| 1177 | static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) | 1180 | static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) |
| @@ -1186,7 +1189,11 @@ static void tegra_hdmi_encoder_enable(struct drm_encoder *encoder) · 8 unmodified lines | |||
| 1186 | u32 value; | 1189 | u32 value; |
| 1187 | int err; | 1190 | int err; |
| 1188 | 1191 | ||
| 1189 | pm_runtime_get_sync(hdmi->dev); | 1192 | err = host1x_client_resume(&hdmi->client); |
| 1193 | if (err < 0) { | ||
| 1194 | dev_err(hdmi->dev, "failed to resume: %d\n", err); | ||
| 1195 | return; | ||
| 1196 | } | ||
| 1190 | 1197 | ||
| 1191 | /* | 1198 | /* |
| 1192 | * Enable and unmask the HDA codec SCRATCH0 register interrupt. This | 1199 | * Enable and unmask the HDA codec SCRATCH0 register interrupt. This |
| @@ -1424,8 +1431,8 @@ static const struct drm_encoder_helper_funcs tegra_hdmi_encoder_helper_funcs = { · 231 unmodified lines | |||
| 1424 | 1431 | ||
| 1425 | static int tegra_hdmi_init(struct host1x_client *client) | 1432 | static int tegra_hdmi_init(struct host1x_client *client) |
| 1426 | { | 1433 | { |
| 1427 | struct drm_device *drm = dev_get_drvdata(client->parent); | ||
| 1428 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | 1434 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); |
| 1435 | struct drm_device *drm = dev_get_drvdata(client->host); | ||
| 1429 | int err; | 1436 | int err; |
| 1430 | 1437 | ||
| 1431 | hdmi->output.dev = client->dev; | 1438 | hdmi->output.dev = client->dev; |
| @@ -1490,9 +1497,66 @@ static int tegra_hdmi_exit(struct host1x_client *client) · 58 unmodified lines | |||
| 1490 | return 0; | 1497 | return 0; |
| 1491 | } | 1498 | } |
| 1492 | 1499 | ||
| 1500 | static int tegra_hdmi_runtime_suspend(struct host1x_client *client) | ||
| 1501 | { | ||
| 1502 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | ||
| 1503 | struct device *dev = client->dev; | ||
| 1504 | int err; | ||
| 1505 | |||
| 1506 | err = reset_control_assert(hdmi->rst); | ||
| 1507 | if (err < 0) { | ||
| 1508 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 1509 | return err; | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | usleep_range(1000, 2000); | ||
| 1513 | |||
| 1514 | clk_disable_unprepare(hdmi->clk); | ||
| 1515 | pm_runtime_put_sync(dev); | ||
| 1516 | |||
| 1517 | return 0; | ||
| 1518 | } | ||
| 1519 | |||
| 1520 | static int tegra_hdmi_runtime_resume(struct host1x_client *client) | ||
| 1521 | { | ||
| 1522 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); | ||
| 1523 | struct device *dev = client->dev; | ||
| 1524 | int err; | ||
| 1525 | |||
| 1526 | err = pm_runtime_get_sync(dev); | ||
| 1527 | if (err < 0) { | ||
| 1528 | dev_err(dev, "failed to get runtime PM: %d\n", err); | ||
| 1529 | return err; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | err = clk_prepare_enable(hdmi->clk); | ||
| 1533 | if (err < 0) { | ||
| 1534 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
| 1535 | goto put_rpm; | ||
| 1536 | } | ||
| 1537 | |||
| 1538 | usleep_range(1000, 2000); | ||
| 1539 | |||
| 1540 | err = reset_control_deassert(hdmi->rst); | ||
| 1541 | if (err < 0) { | ||
| 1542 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
| 1543 | goto disable_clk; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | return 0; | ||
| 1547 | |||
| 1548 | disable_clk: | ||
| 1549 | clk_disable_unprepare(hdmi->clk); | ||
| 1550 | put_rpm: | ||
| 1551 | pm_runtime_put_sync(dev); | ||
| 1552 | return err; | ||
| 1553 | } | ||
| 1554 | |||
| 1493 | static const struct host1x_client_ops hdmi_client_ops = { | 1555 | static const struct host1x_client_ops hdmi_client_ops = { |
| 1494 | .init = tegra_hdmi_init, | 1556 | .init = tegra_hdmi_init, |
| 1495 | .exit = tegra_hdmi_exit, | 1557 | .exit = tegra_hdmi_exit, |
| 1558 | .suspend = tegra_hdmi_runtime_suspend, | ||
| 1559 | .resume = tegra_hdmi_runtime_resume, | ||
| 1496 | }; | 1560 | }; |
| 1497 | 1561 | ||
| 1498 | static const struct tegra_hdmi_config tegra20_hdmi_config = { | 1562 | static const struct tegra_hdmi_config tegra20_hdmi_config = { |
| @@ -1700,58 +1764,10 @@ static int tegra_hdmi_remove(struct platform_device *pdev) · 201 unmodified lines | |||
| 1700 | return 0; | 1764 | return 0; |
| 1701 | } | 1765 | } |
| 1702 | 1766 | ||
| 1703 | #ifdef CONFIG_PM | ||
| 1704 | static int tegra_hdmi_suspend(struct device *dev) | ||
| 1705 | { | ||
| 1706 | struct tegra_hdmi *hdmi = dev_get_drvdata(dev); | ||
| 1707 | int err; | ||
| 1708 | |||
| 1709 | err = reset_control_assert(hdmi->rst); | ||
| 1710 | if (err < 0) { | ||
| 1711 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 1712 | return err; | ||
| 1713 | } | ||
| 1714 | |||
| 1715 | usleep_range(1000, 2000); | ||
| 1716 | |||
| 1717 | clk_disable_unprepare(hdmi->clk); | ||
| 1718 | |||
| 1719 | return 0; | ||
| 1720 | } | ||
| 1721 | |||
| 1722 | static int tegra_hdmi_resume(struct device *dev) | ||
| 1723 | { | ||
| 1724 | struct tegra_hdmi *hdmi = dev_get_drvdata(dev); | ||
| 1725 | int err; | ||
| 1726 | |||
| 1727 | err = clk_prepare_enable(hdmi->clk); | ||
| 1728 | if (err < 0) { | ||
| 1729 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
| 1730 | return err; | ||
| 1731 | } | ||
| 1732 | |||
| 1733 | usleep_range(1000, 2000); | ||
| 1734 | |||
| 1735 | err = reset_control_deassert(hdmi->rst); | ||
| 1736 | if (err < 0) { | ||
| 1737 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
| 1738 | clk_disable_unprepare(hdmi->clk); | ||
| 1739 | return err; | ||
| 1740 | } | ||
| 1741 | |||
| 1742 | return 0; | ||
| 1743 | } | ||
| 1744 | #endif | ||
| 1745 | |||
| 1746 | static const struct dev_pm_ops tegra_hdmi_pm_ops = { | ||
| 1747 | SET_RUNTIME_PM_OPS(tegra_hdmi_suspend, tegra_hdmi_resume, NULL) | ||
| 1748 | }; | ||
| 1749 | |||
| 1750 | struct platform_driver tegra_hdmi_driver = { | 1767 | struct platform_driver tegra_hdmi_driver = { |
| 1751 | .driver = { | 1768 | .driver = { |
| 1752 | .name = "tegra-hdmi", | 1769 | .name = "tegra-hdmi", |
| 1753 | .of_match_table = tegra_hdmi_of_match, | 1770 | .of_match_table = tegra_hdmi_of_match, |
| 1754 | .pm = &tegra_hdmi_pm_ops, | ||
| 1755 | }, | 1771 | }, |
| 1756 | .probe = tegra_hdmi_probe, | 1772 | .probe = tegra_hdmi_probe, |
| 1757 | .remove = tegra_hdmi_remove, | 1773 | .remove = tegra_hdmi_remove, |
| @@ -95,17 +95,25 @@ static inline void tegra_plane_writel(struct tegra_plane *plane, u32 value, · 94 unmodified lines | |||
| 95 | 95 | ||
| 96 | static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp) | 96 | static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp) |
| 97 | { | 97 | { |
| 98 | int err = 0; | ||
| 99 | |||
| 98 | mutex_lock(&wgrp->lock); | 100 | mutex_lock(&wgrp->lock); |
| 99 | 101 | ||
| 100 | if (wgrp->usecount == 0) { | 102 | if (wgrp->usecount == 0) { |
| 101 | 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 | |||
| 102 | reset_control_deassert(wgrp->rst); | 109 | reset_control_deassert(wgrp->rst); |
| 103 | } | 110 | } |
| 104 | 111 | ||
| 105 | wgrp->usecount++; | 112 | wgrp->usecount++; |
| 106 | mutex_unlock(&wgrp->lock); | ||
| 107 | 113 | ||
| 108 | return 0; | 114 | unlock: |
| 115 | mutex_unlock(&wgrp->lock); | ||
| 116 | return err; | ||
| 109 | } | 117 | } |
| 110 | 118 | ||
| 111 | static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) | 119 | static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) |
| @@ -121,7 +129,7 @@ static void tegra_windowgroup_disable(struct tegra_windowgroup *wgrp) · 9 unmodified lines | |||
| 121 | wgrp->index); | 129 | wgrp->index); |
| 122 | } | 130 | } |
| 123 | 131 | ||
| 124 | pm_runtime_put(wgrp->parent); | 132 | host1x_client_suspend(wgrp->parent); |
| 125 | } | 133 | } |
| 126 | 134 | ||
| 127 | wgrp->usecount--; | 135 | wgrp->usecount--; |
| @@ -379,6 +387,7 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, · 251 unmodified lines | |||
| 379 | struct tegra_plane *p = to_tegra_plane(plane); | 387 | struct tegra_plane *p = to_tegra_plane(plane); |
| 380 | struct tegra_dc *dc; | 388 | struct tegra_dc *dc; |
| 381 | u32 value; | 389 | u32 value; |
| 390 | int err; | ||
| 382 | 391 | ||
| 383 | /* rien ne va plus */ | 392 | /* rien ne va plus */ |
| 384 | if (!old_state || !old_state->crtc) | 393 | if (!old_state || !old_state->crtc) |
| @@ -386,6 +395,12 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, · 1 unmodified line | |||
| 386 | 395 | ||
| 387 | dc = to_tegra_dc(old_state->crtc); | 396 | dc = to_tegra_dc(old_state->crtc); |
| 388 | 397 | ||
| 398 | err = host1x_client_resume(&dc->client); | ||
| 399 | if (err < 0) { | ||
| 400 | dev_err(dc->dev, "failed to resume: %d\n", err); | ||
| 401 | return; | ||
| 402 | } | ||
| 403 | |||
| 389 | /* | 404 | /* |
| 390 | * XXX Legacy helpers seem to sometimes call ->atomic_disable() even | 405 | * XXX Legacy helpers seem to sometimes call ->atomic_disable() even |
| 391 | * on planes that are already disabled. Make sure we fallback to the | 406 | * on planes that are already disabled. Make sure we fallback to the |
| @@ -394,15 +409,13 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, · 2 unmodified lines | |||
| 394 | if (WARN_ON(p->dc == NULL)) | 409 | if (WARN_ON(p->dc == NULL)) |
| 395 | p->dc = dc; | 410 | p->dc = dc; |
| 396 | 411 | ||
| 397 | pm_runtime_get_sync(dc->dev); | ||
| 398 | |||
| 399 | value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); | 412 | value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); |
| 400 | value &= ~WIN_ENABLE; | 413 | value &= ~WIN_ENABLE; |
| 401 | tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); | 414 | tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); |
| 402 | 415 | ||
| 403 | tegra_dc_remove_shared_plane(dc, p); | 416 | tegra_dc_remove_shared_plane(dc, p); |
| 404 | 417 | ||
| 405 | pm_runtime_put(dc->dev); | 418 | host1x_client_suspend(&dc->client); |
| 406 | } | 419 | } |
| 407 | 420 | ||
| 408 | static void tegra_shared_plane_atomic_update(struct drm_plane *plane, | 421 | static void tegra_shared_plane_atomic_update(struct drm_plane *plane, |
| @@ -415,6 +428,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, · 6 unmodified lines | |||
| 415 | struct tegra_plane *p = to_tegra_plane(plane); | 428 | struct tegra_plane *p = to_tegra_plane(plane); |
| 416 | dma_addr_t base; | 429 | dma_addr_t base; |
| 417 | u32 value; | 430 | u32 value; |
| 431 | int err; | ||
| 418 | 432 | ||
| 419 | /* rien ne va plus */ | 433 | /* rien ne va plus */ |
| 420 | if (!plane->state->crtc || !plane->state->fb) | 434 | if (!plane->state->crtc || !plane->state->fb) |
| @@ -425,7 +439,11 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, · 4 unmodified lines | |||
| 425 | return; | 439 | return; |
| 426 | } | 440 | } |
| 427 | 441 | ||
| 428 | pm_runtime_get_sync(dc->dev); | 442 | err = host1x_client_resume(&dc->client); |
| 443 | if (err < 0) { | ||
| 444 | dev_err(dc->dev, "failed to resume: %d\n", err); | ||
| 445 | return; | ||
| 446 | } | ||
| 429 | 447 | ||
| 430 | tegra_dc_assign_shared_plane(dc, p); | 448 | tegra_dc_assign_shared_plane(dc, p); |
| 431 | 449 | ||
| @@ -515,7 +533,7 @@ static void tegra_shared_plane_atomic_update(struct drm_plane *plane, · 83 unmodified lines | |||
| 515 | value &= ~CONTROL_CSC_ENABLE; | 533 | value &= ~CONTROL_CSC_ENABLE; |
| 516 | tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL); | 534 | tegra_plane_writel(p, value, DC_WIN_WINDOW_SET_CONTROL); |
| 517 | 535 | ||
| 518 | pm_runtime_put(dc->dev); | 536 | host1x_client_suspend(&dc->client); |
| 519 | } | 537 | } |
| 520 | 538 | ||
| 521 | static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = { | 539 | static const struct drm_plane_helper_funcs tegra_shared_plane_helper_funcs = { |
| @@ -551,7 +569,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, · 29 unmodified lines | |||
| 551 | plane->base.index = index; | 569 | plane->base.index = index; |
| 552 | 570 | ||
| 553 | plane->wgrp = &hub->wgrps[wgrp]; | 571 | plane->wgrp = &hub->wgrps[wgrp]; |
| 554 | plane->wgrp->parent = dc->dev; | 572 | plane->wgrp->parent = &dc->client; |
| 555 | 573 | ||
| 556 | p = &plane->base.base; | 574 | p = &plane->base.base; |
| 557 | 575 | ||
| @@ -656,8 +674,13 @@ int tegra_display_hub_atomic_check(struct drm_device *drm, · 98 unmodified lines | |||
| 656 | static void tegra_display_hub_update(struct tegra_dc *dc) | 674 | static void tegra_display_hub_update(struct tegra_dc *dc) |
| 657 | { | 675 | { |
| 658 | u32 value; | 676 | u32 value; |
| 677 | int err; | ||
| 659 | 678 | ||
| 660 | pm_runtime_get_sync(dc->dev); | 679 | err = host1x_client_resume(&dc->client); |
| 680 | if (err < 0) { | ||
| 681 | dev_err(dc->dev, "failed to resume: %d\n", err); | ||
| 682 | return; | ||
| 683 | } | ||
| 661 | 684 | ||
| 662 | value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL); | 685 | value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL); |
| 663 | value &= ~LATENCY_EVENT; | 686 | value &= ~LATENCY_EVENT; |
| @@ -672,7 +695,7 @@ static void tegra_display_hub_update(struct tegra_dc *dc) · 8 unmodified lines | |||
| 672 | tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL); | 695 | tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL); |
| 673 | tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); | 696 | tegra_dc_readl(dc, DC_CMD_STATE_CONTROL); |
| 674 | 697 | ||
| 675 | pm_runtime_put(dc->dev); | 698 | host1x_client_suspend(&dc->client); |
| 676 | } | 699 | } |
| 677 | 700 | ||
| 678 | void tegra_display_hub_atomic_commit(struct drm_device *drm, | 701 | void tegra_display_hub_atomic_commit(struct drm_device *drm, |
| @@ -705,7 +728,7 @@ void tegra_display_hub_atomic_commit(struct drm_device *drm, · 26 unmodified lines | |||
| 705 | static int tegra_display_hub_init(struct host1x_client *client) | 728 | static int tegra_display_hub_init(struct host1x_client *client) |
| 706 | { | 729 | { |
| 707 | struct tegra_display_hub *hub = to_tegra_display_hub(client); | 730 | struct tegra_display_hub *hub = to_tegra_display_hub(client); |
| 708 | struct drm_device *drm = dev_get_drvdata(client->parent); | 731 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 709 | struct tegra_drm *tegra = drm->dev_private; | 732 | struct tegra_drm *tegra = drm->dev_private; |
| 710 | struct tegra_display_hub_state *state; | 733 | struct tegra_display_hub_state *state; |
| 711 | 734 | ||
| @@ -723,7 +746,7 @@ static int tegra_display_hub_init(struct host1x_client *client) · 11 unmodified lines | |||
| 723 | 746 | ||
| 724 | static int tegra_display_hub_exit(struct host1x_client *client) | 747 | static int tegra_display_hub_exit(struct host1x_client *client) |
| 725 | { | 748 | { |
| 726 | struct drm_device *drm = dev_get_drvdata(client->parent); | 749 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 727 | struct tegra_drm *tegra = drm->dev_private; | 750 | struct tegra_drm *tegra = drm->dev_private; |
| 728 | 751 | ||
| 729 | drm_atomic_private_obj_fini(&tegra->hub->base); | 752 | drm_atomic_private_obj_fini(&tegra->hub->base); |
| @@ -732,9 +755,85 @@ static int tegra_display_hub_exit(struct host1x_client *client) · 2 unmodified lines | |||
| 732 | return 0; | 755 | return 0; |
| 733 | } | 756 | } |
| 734 | 757 | ||
| 758 | static int tegra_display_hub_runtime_suspend(struct host1x_client *client) | ||
| 759 | { | ||
| 760 | struct tegra_display_hub *hub = to_tegra_display_hub(client); | ||
| 761 | struct device *dev = client->dev; | ||
| 762 | unsigned int i = hub->num_heads; | ||
| 763 | int err; | ||
| 764 | |||
| 765 | err = reset_control_assert(hub->rst); | ||
| 766 | if (err < 0) | ||
| 767 | return err; | ||
| 768 | |||
| 769 | while (i--) | ||
| 770 | clk_disable_unprepare(hub->clk_heads[i]); | ||
| 771 | |||
| 772 | clk_disable_unprepare(hub->clk_hub); | ||
| 773 | clk_disable_unprepare(hub->clk_dsc); | ||
| 774 | clk_disable_unprepare(hub->clk_disp); | ||
| 775 | |||
| 776 | pm_runtime_put_sync(dev); | ||
| 777 | |||
| 778 | return 0; | ||
| 779 | } | ||
| 780 | |||
| 781 | static int tegra_display_hub_runtime_resume(struct host1x_client *client) | ||
| 782 | { | ||
| 783 | struct tegra_display_hub *hub = to_tegra_display_hub(client); | ||
| 784 | struct device *dev = client->dev; | ||
| 785 | unsigned int i; | ||
| 786 | int err; | ||
| 787 | |||
| 788 | err = pm_runtime_get_sync(dev); | ||
| 789 | if (err < 0) { | ||
| 790 | dev_err(dev, "failed to get runtime PM: %d\n", err); | ||
| 791 | return err; | ||
| 792 | } | ||
| 793 | |||
| 794 | err = clk_prepare_enable(hub->clk_disp); | ||
| 795 | if (err < 0) | ||
| 796 | goto put_rpm; | ||
| 797 | |||
| 798 | err = clk_prepare_enable(hub->clk_dsc); | ||
| 799 | if (err < 0) | ||
| 800 | goto disable_disp; | ||
| 801 | |||
| 802 | err = clk_prepare_enable(hub->clk_hub); | ||
| 803 | if (err < 0) | ||
| 804 | goto disable_dsc; | ||
| 805 | |||
| 806 | for (i = 0; i < hub->num_heads; i++) { | ||
| 807 | err = clk_prepare_enable(hub->clk_heads[i]); | ||
| 808 | if (err < 0) | ||
| 809 | goto disable_heads; | ||
| 810 | } | ||
| 811 | |||
| 812 | err = reset_control_deassert(hub->rst); | ||
| 813 | if (err < 0) | ||
| 814 | goto disable_heads; | ||
| 815 | |||
| 816 | return 0; | ||
| 817 | |||
| 818 | disable_heads: | ||
| 819 | while (i--) | ||
| 820 | clk_disable_unprepare(hub->clk_heads[i]); | ||
| 821 | |||
| 822 | clk_disable_unprepare(hub->clk_hub); | ||
| 823 | disable_dsc: | ||
| 824 | clk_disable_unprepare(hub->clk_dsc); | ||
| 825 | disable_disp: | ||
| 826 | clk_disable_unprepare(hub->clk_disp); | ||
| 827 | put_rpm: | ||
| 828 | pm_runtime_put_sync(dev); | ||
| 829 | return err; | ||
| 830 | } | ||
| 831 | |||
| 735 | static const struct host1x_client_ops tegra_display_hub_ops = { | 832 | static const struct host1x_client_ops tegra_display_hub_ops = { |
| 736 | .init = tegra_display_hub_init, | 833 | .init = tegra_display_hub_init, |
| 737 | .exit = tegra_display_hub_exit, | 834 | .exit = tegra_display_hub_exit, |
| 835 | .suspend = tegra_display_hub_runtime_suspend, | ||
| 836 | .resume = tegra_display_hub_runtime_resume, | ||
| 738 | }; | 837 | }; |
| 739 | 838 | ||
| 740 | static int tegra_display_hub_probe(struct platform_device *pdev) | 839 | static int tegra_display_hub_probe(struct platform_device *pdev) |
| @@ -851,6 +950,7 @@ static int tegra_display_hub_probe(struct platform_device *pdev) · 110 unmodified lines | |||
| 851 | static int tegra_display_hub_remove(struct platform_device *pdev) | 950 | static int tegra_display_hub_remove(struct platform_device *pdev) |
| 852 | { | 951 | { |
| 853 | struct tegra_display_hub *hub = platform_get_drvdata(pdev); | 952 | struct tegra_display_hub *hub = platform_get_drvdata(pdev); |
| 953 | unsigned int i; | ||
| 854 | int err; | 954 | int err; |
| 855 | 955 | ||
| 856 | err = host1x_client_unregister(&hub->client); | 956 | err = host1x_client_unregister(&hub->client); |
| @@ -859,78 +959,17 @@ static int tegra_display_hub_remove(struct platform_device *pdev) · 2 unmodified lines | |||
| 859 | err); | 959 | err); |
| 860 | } | 960 | } |
| 861 | 961 | ||
| 862 | pm_runtime_disable(&pdev->dev); | 962 | for (i = 0; i < hub->soc->num_wgrps; i++) { |
| 863 | 963 | struct tegra_windowgroup *wgrp = &hub->wgrps[i]; | |
| 864 | return err; | ||
| 865 | } | ||
| 866 | |||
| 867 | static int __maybe_unused tegra_display_hub_suspend(struct device *dev) | ||
| 868 | { | ||
| 869 | struct tegra_display_hub *hub = dev_get_drvdata(dev); | ||
| 870 | unsigned int i = hub->num_heads; | ||
| 871 | int err; | ||
| 872 | |||
| 873 | err = reset_control_assert(hub->rst); | ||
| 874 | if (err < 0) | ||
| 875 | return err; | ||
| 876 | |||
| 877 | while (i--) | ||
| 878 | clk_disable_unprepare(hub->clk_heads[i]); | ||
| 879 | |||
| 880 | clk_disable_unprepare(hub->clk_hub); | ||
| 881 | clk_disable_unprepare(hub->clk_dsc); | ||
| 882 | clk_disable_unprepare(hub->clk_disp); | ||
| 883 | |||
| 884 | return 0; | ||
| 885 | } | ||
| 886 | |||
| 887 | static int __maybe_unused tegra_display_hub_resume(struct device *dev) | ||
| 888 | { | ||
| 889 | struct tegra_display_hub *hub = dev_get_drvdata(dev); | ||
| 890 | unsigned int i; | ||
| 891 | int err; | ||
| 892 | |||
| 893 | err = clk_prepare_enable(hub->clk_disp); | ||
| 894 | if (err < 0) | ||
| 895 | return err; | ||
| 896 | |||
| 897 | err = clk_prepare_enable(hub->clk_dsc); | ||
| 898 | if (err < 0) | ||
| 899 | goto disable_disp; | ||
| 900 | |||
| 901 | err = clk_prepare_enable(hub->clk_hub); | ||
| 902 | if (err < 0) | ||
| 903 | goto disable_dsc; | ||
| 904 | 964 | ||
| 905 | for (i = 0; i < hub->num_heads; i++) { | 965 | mutex_destroy(&wgrp->lock); |
| 906 | err = clk_prepare_enable(hub->clk_heads[i]); | ||
| 907 | if (err < 0) | ||
| 908 | goto disable_heads; | ||
| 909 | } | 966 | } |
| 910 | 967 | ||
| 911 | err = reset_control_deassert(hub->rst); | 968 | pm_runtime_disable(&pdev->dev); |
| 912 | if (err < 0) | ||
| 913 | goto disable_heads; | ||
| 914 | |||
| 915 | return 0; | ||
| 916 | |||
| 917 | disable_heads: | ||
| 918 | while (i--) | ||
| 919 | clk_disable_unprepare(hub->clk_heads[i]); | ||
| 920 | 969 | ||
| 921 | clk_disable_unprepare(hub->clk_hub); | ||
| 922 | disable_dsc: | ||
| 923 | clk_disable_unprepare(hub->clk_dsc); | ||
| 924 | disable_disp: | ||
| 925 | clk_disable_unprepare(hub->clk_disp); | ||
| 926 | return err; | 970 | return err; |
| 927 | } | 971 | } |
| 928 | 972 | ||
| 929 | static const struct dev_pm_ops tegra_display_hub_pm_ops = { | ||
| 930 | SET_RUNTIME_PM_OPS(tegra_display_hub_suspend, | ||
| 931 | tegra_display_hub_resume, NULL) | ||
| 932 | }; | ||
| 933 | |||
| 934 | static const struct tegra_display_hub_soc tegra186_display_hub = { | 973 | static const struct tegra_display_hub_soc tegra186_display_hub = { |
| 935 | .num_wgrps = 6, | 974 | .num_wgrps = 6, |
| 936 | .supports_dsc = true, | 975 | .supports_dsc = true, |
| @@ -958,7 +997,6 @@ struct platform_driver tegra_display_hub_driver = { · 21 unmodified lines | |||
| 958 | .driver = { | 997 | .driver = { |
| 959 | .name = "tegra-display-hub", | 998 | .name = "tegra-display-hub", |
| 960 | .of_match_table = tegra_display_hub_of_match, | 999 | .of_match_table = tegra_display_hub_of_match, |
| 961 | .pm = &tegra_display_hub_pm_ops, | ||
| 962 | }, | 1000 | }, |
| 963 | .probe = tegra_display_hub_probe, | 1001 | .probe = tegra_display_hub_probe, |
| 964 | .remove = tegra_display_hub_remove, | 1002 | .remove = tegra_display_hub_remove, |
| @@ -17,7 +17,7 @@ struct tegra_windowgroup { · 16 unmodified lines | |||
| 17 | struct mutex lock; | 17 | struct mutex lock; |
| 18 | 18 | ||
| 19 | unsigned int index; | 19 | unsigned int index; |
| 20 | struct device *parent; | 20 | struct host1x_client *parent; |
| 21 | struct reset_control *rst; | 21 | struct reset_control *rst; |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| @@ -250,3 +250,19 @@ void tegra_output_find_possible_crtcs(struct tegra_output *output, · 249 unmodified lines | |||
| 250 | 250 | ||
| 251 | output->encoder.possible_crtcs = mask; | 251 | output->encoder.possible_crtcs = mask; |
| 252 | } | 252 | } |
| 253 | |||
| 254 | int tegra_output_suspend(struct tegra_output *output) | ||
| 255 | { | ||
| 256 | if (output->hpd_irq) | ||
| 257 | disable_irq(output->hpd_irq); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | int tegra_output_resume(struct tegra_output *output) | ||
| 263 | { | ||
| 264 | if (output->hpd_irq) | ||
| 265 | enable_irq(output->hpd_irq); | ||
| 266 | |||
| 267 | return 0; | ||
| 268 | } | ||
| @@ -2255,7 +2255,7 @@ static void tegra_sor_hdmi_disable(struct drm_encoder *encoder) · 2254 unmodified lines | |||
| 2255 | if (err < 0) | 2255 | if (err < 0) |
| 2256 | dev_err(sor->dev, "failed to power off I/O pad: %d\n", err); | 2256 | dev_err(sor->dev, "failed to power off I/O pad: %d\n", err); |
| 2257 | 2257 | ||
| 2258 | pm_runtime_put(sor->dev); | 2258 | host1x_client_suspend(&sor->client); |
| 2259 | } | 2259 | } |
| 2260 | 2260 | ||
| 2261 | static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) | 2261 | static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) |
| @@ -2276,7 +2276,11 @@ static void tegra_sor_hdmi_enable(struct drm_encoder *encoder) · 14 unmodified lines | |||
| 2276 | mode = &encoder->crtc->state->adjusted_mode; | 2276 | mode = &encoder->crtc->state->adjusted_mode; |
| 2277 | pclk = mode->clock * 1000; | 2277 | pclk = mode->clock * 1000; |
| 2278 | 2278 | ||
| 2279 | pm_runtime_get_sync(sor->dev); | 2279 | err = host1x_client_resume(&sor->client); |
| 2280 | if (err < 0) { | ||
| 2281 | dev_err(sor->dev, "failed to resume: %d\n", err); | ||
| 2282 | return; | ||
| 2283 | } | ||
| 2280 | 2284 | ||
| 2281 | /* switch to safe parent clock */ | 2285 | /* switch to safe parent clock */ |
| 2282 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | 2286 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); |
| @@ -2722,7 +2726,7 @@ static void tegra_sor_dp_disable(struct drm_encoder *encoder) · 439 unmodified lines | |||
| 2722 | if (output->panel) | 2726 | if (output->panel) |
| 2723 | drm_panel_unprepare(output->panel); | 2727 | drm_panel_unprepare(output->panel); |
| 2724 | 2728 | ||
| 2725 | pm_runtime_put(sor->dev); | 2729 | host1x_client_suspend(&sor->client); |
| 2726 | } | 2730 | } |
| 2727 | 2731 | ||
| 2728 | static void tegra_sor_dp_enable(struct drm_encoder *encoder) | 2732 | static void tegra_sor_dp_enable(struct drm_encoder *encoder) |
| @@ -2742,7 +2746,11 @@ static void tegra_sor_dp_enable(struct drm_encoder *encoder) · 13 unmodified lines | |||
| 2742 | mode = &encoder->crtc->state->adjusted_mode; | 2746 | mode = &encoder->crtc->state->adjusted_mode; |
| 2743 | info = &output->connector.display_info; | 2747 | info = &output->connector.display_info; |
| 2744 | 2748 | ||
| 2745 | pm_runtime_get_sync(sor->dev); | 2749 | err = host1x_client_resume(&sor->client); |
| 2750 | if (err < 0) { | ||
| 2751 | dev_err(sor->dev, "failed to resume: %d\n", err); | ||
| 2752 | return; | ||
| 2753 | } | ||
| 2746 | 2754 | ||
| 2747 | /* switch to safe parent clock */ | 2755 | /* switch to safe parent clock */ |
| 2748 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); | 2756 | err = tegra_sor_set_parent_clock(sor, sor->clk_safe); |
| @@ -3053,7 +3061,7 @@ static const struct tegra_sor_ops tegra_sor_dp_ops = { · 304 unmodified lines | |||
| 3053 | 3061 | ||
| 3054 | static int tegra_sor_init(struct host1x_client *client) | 3062 | static int tegra_sor_init(struct host1x_client *client) |
| 3055 | { | 3063 | { |
| 3056 | struct drm_device *drm = dev_get_drvdata(client->parent); | 3064 | struct drm_device *drm = dev_get_drvdata(client->host); |
| 3057 | const struct drm_encoder_helper_funcs *helpers = NULL; | 3065 | const struct drm_encoder_helper_funcs *helpers = NULL; |
| 3058 | struct tegra_sor *sor = host1x_client_to_sor(client); | 3066 | struct tegra_sor *sor = host1x_client_to_sor(client); |
| 3059 | int connector = DRM_MODE_CONNECTOR_Unknown; | 3067 | int connector = DRM_MODE_CONNECTOR_Unknown; |
| @@ -3190,9 +3198,80 @@ static int tegra_sor_exit(struct host1x_client *client) · 130 unmodified lines | |||
| 3190 | return 0; | 3198 | return 0; |
| 3191 | } | 3199 | } |
| 3192 | 3200 | ||
| 3201 | static int tegra_sor_runtime_suspend(struct host1x_client *client) | ||
| 3202 | { | ||
| 3203 | struct tegra_sor *sor = host1x_client_to_sor(client); | ||
| 3204 | struct device *dev = client->dev; | ||
| 3205 | int err; | ||
| 3206 | |||
| 3207 | if (sor->rst) { | ||
| 3208 | err = reset_control_assert(sor->rst); | ||
| 3209 | if (err < 0) { | ||
| 3210 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 3211 | return err; | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | reset_control_release(sor->rst); | ||
| 3215 | } | ||
| 3216 | |||
| 3217 | usleep_range(1000, 2000); | ||
| 3218 | |||
| 3219 | clk_disable_unprepare(sor->clk); | ||
| 3220 | pm_runtime_put_sync(dev); | ||
| 3221 | |||
| 3222 | return 0; | ||
| 3223 | } | ||
| 3224 | |||
| 3225 | static int tegra_sor_runtime_resume(struct host1x_client *client) | ||
| 3226 | { | ||
| 3227 | struct tegra_sor *sor = host1x_client_to_sor(client); | ||
| 3228 | struct device *dev = client->dev; | ||
| 3229 | int err; | ||
| 3230 | |||
| 3231 | err = pm_runtime_get_sync(dev); | ||
| 3232 | if (err < 0) { | ||
| 3233 | dev_err(dev, "failed to get runtime PM: %d\n", err); | ||
| 3234 | return err; | ||
| 3235 | } | ||
| 3236 | |||
| 3237 | err = clk_prepare_enable(sor->clk); | ||
| 3238 | if (err < 0) { | ||
| 3239 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
| 3240 | goto put_rpm; | ||
| 3241 | } | ||
| 3242 | |||
| 3243 | usleep_range(1000, 2000); | ||
| 3244 | |||
| 3245 | if (sor->rst) { | ||
| 3246 | err = reset_control_acquire(sor->rst); | ||
| 3247 | if (err < 0) { | ||
| 3248 | dev_err(dev, "failed to acquire reset: %d\n", err); | ||
| 3249 | goto disable_clk; | ||
| 3250 | } | ||
| 3251 | |||
| 3252 | err = reset_control_deassert(sor->rst); | ||
| 3253 | if (err < 0) { | ||
| 3254 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
| 3255 | goto release_reset; | ||
| 3256 | } | ||
| 3257 | } | ||
| 3258 | |||
| 3259 | return 0; | ||
| 3260 | |||
| 3261 | release_reset: | ||
| 3262 | reset_control_release(sor->rst); | ||
| 3263 | disable_clk: | ||
| 3264 | clk_disable_unprepare(sor->clk); | ||
| 3265 | put_rpm: | ||
| 3266 | pm_runtime_put_sync(dev); | ||
| 3267 | return err; | ||
| 3268 | } | ||
| 3269 | |||
| 3193 | static const struct host1x_client_ops sor_client_ops = { | 3270 | static const struct host1x_client_ops sor_client_ops = { |
| 3194 | .init = tegra_sor_init, | 3271 | .init = tegra_sor_init, |
| 3195 | .exit = tegra_sor_exit, | 3272 | .exit = tegra_sor_exit, |
| 3273 | .suspend = tegra_sor_runtime_suspend, | ||
| 3274 | .resume = tegra_sor_runtime_resume, | ||
| 3196 | }; | 3275 | }; |
| 3197 | 3276 | ||
| 3198 | static const u8 tegra124_sor_xbar_cfg[5] = { | 3277 | static const u8 tegra124_sor_xbar_cfg[5] = { |
| @@ -3843,10 +3922,9 @@ static int tegra_sor_probe(struct platform_device *pdev) · 644 unmodified lines | |||
| 3843 | if (!sor->clk_pad) { | 3922 | if (!sor->clk_pad) { |
| 3844 | char *name; | 3923 | char *name; |
| 3845 | 3924 | ||
| 3846 | err = pm_runtime_get_sync(&pdev->dev); | 3925 | err = host1x_client_resume(&sor->client); |
| 3847 | if (err < 0) { | 3926 | if (err < 0) { |
| 3848 | dev_err(&pdev->dev, "failed to get runtime PM: %d\n", | 3927 | dev_err(sor->dev, "failed to resume: %d\n", err); |
| 3849 | err); | ||
| 3850 | goto remove; | 3928 | goto remove; |
| 3851 | } | 3929 | } |
| 3852 | 3930 | ||
| @@ -3857,7 +3935,7 @@ static int tegra_sor_probe(struct platform_device *pdev) · 4 unmodified lines | |||
| 3857 | } | 3935 | } |
| 3858 | 3936 | ||
| 3859 | sor->clk_pad = tegra_clk_sor_pad_register(sor, name); | 3937 | sor->clk_pad = tegra_clk_sor_pad_register(sor, name); |
| 3860 | pm_runtime_put(&pdev->dev); | 3938 | host1x_client_suspend(&sor->client); |
| 3861 | } | 3939 | } |
| 3862 | 3940 | ||
| 3863 | if (IS_ERR(sor->clk_pad)) { | 3941 | if (IS_ERR(sor->clk_pad)) { |
| @@ -3913,54 +3991,21 @@ static int tegra_sor_remove(struct platform_device *pdev) · 49 unmodified lines | |||
| 3913 | return 0; | 3991 | return 0; |
| 3914 | } | 3992 | } |
| 3915 | 3993 | ||
| 3916 | static int tegra_sor_runtime_suspend(struct device *dev) | 3994 | static int __maybe_unused tegra_sor_suspend(struct device *dev) |
| 3917 | { | ||
| 3918 | struct tegra_sor *sor = dev_get_drvdata(dev); | ||
| 3919 | int err; | ||
| 3920 | |||
| 3921 | if (sor->rst) { | ||
| 3922 | err = reset_control_assert(sor->rst); | ||
| 3923 | if (err < 0) { | ||
| 3924 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
| 3925 | return err; | ||
| 3926 | } | ||
| 3927 | |||
| 3928 | reset_control_release(sor->rst); | ||
| 3929 | } | ||
| 3930 | |||
| 3931 | usleep_range(1000, 2000); | ||
| 3932 | |||
| 3933 | clk_disable_unprepare(sor->clk); | ||
| 3934 | |||
| 3935 | return 0; | ||
| 3936 | } | ||
| 3937 | |||
| 3938 | static int tegra_sor_runtime_resume(struct device *dev) | ||
| 3939 | { | 3995 | { |
| 3940 | struct tegra_sor *sor = dev_get_drvdata(dev); | 3996 | struct tegra_sor *sor = dev_get_drvdata(dev); |
| 3941 | int err; | 3997 | int err; |
| 3942 | 3998 | ||
| 3943 | err = clk_prepare_enable(sor->clk); | 3999 | err = tegra_output_suspend(&sor->output); |
| 3944 | if (err < 0) { | 4000 | if (err < 0) { |
| 3945 | dev_err(dev, "failed to enable clock: %d\n", err); | 4001 | dev_err(dev, "failed to suspend output: %d\n", err); |
| 3946 | return err; | 4002 | return err; |
| 3947 | } | 4003 | } |
| 3948 | 4004 | ||
| 3949 | usleep_range(1000, 2000); | 4005 | if (sor->hdmi_supply) { |
| 3950 | 4006 | err = regulator_disable(sor->hdmi_supply); | |
| 3951 | if (sor->rst) { | ||
| 3952 | err = reset_control_acquire(sor->rst); | ||
| 3953 | if (err < 0) { | ||
| 3954 | dev_err(dev, "failed to acquire reset: %d\n", err); | ||
| 3955 | clk_disable_unprepare(sor->clk); | ||
| 3956 | return err; | ||
| 3957 | } | ||
| 3958 | |||
| 3959 | err = reset_control_deassert(sor->rst); | ||
| 3960 | if (err < 0) { | 4007 | if (err < 0) { |
| 3961 | dev_err(dev, "failed to deassert reset: %d\n", err); | 4008 | tegra_output_resume(&sor->output); |
| 3962 | reset_control_release(sor->rst); | ||
| 3963 | clk_disable_unprepare(sor->clk); | ||
| 3964 | return err; | 4009 | return err; |
| 3965 | } | 4010 | } |
| 3966 | } | 4011 | } |
| @@ -3968,37 +4013,31 @@ static int tegra_sor_runtime_resume(struct device *dev) · 1 unmodified line | |||
| 3968 | return 0; | 4013 | return 0; |
| 3969 | } | 4014 | } |
| 3970 | 4015 | ||
| 3971 | static int tegra_sor_suspend(struct device *dev) | 4016 | static int __maybe_unused tegra_sor_resume(struct device *dev) |
| 3972 | { | 4017 | { |
| 3973 | struct tegra_sor *sor = dev_get_drvdata(dev); | 4018 | struct tegra_sor *sor = dev_get_drvdata(dev); |
| 3974 | int err; | 4019 | int err; |
| 3975 | 4020 | ||
| 3976 | if (sor->hdmi_supply) { | 4021 | if (sor->hdmi_supply) { |
| 3977 | err = regulator_disable(sor->hdmi_supply); | 4022 | err = regulator_enable(sor->hdmi_supply); |
| 3978 | if (err < 0) | 4023 | if (err < 0) |
| 3979 | return err; | 4024 | return err; |
| 3980 | } | 4025 | } |
| 3981 | 4026 | ||
| 3982 | return 0; | 4027 | err = tegra_output_resume(&sor->output); |
| 3983 | } | 4028 | if (err < 0) { |
| 4029 | dev_err(dev, "failed to resume output: %d\n", err); | ||
| 3984 | 4030 | ||
| 3985 | static int tegra_sor_resume(struct device *dev) | 4031 | if (sor->hdmi_supply) |
| 3986 | { | 4032 | regulator_disable(sor->hdmi_supply); |
| 3987 | struct tegra_sor *sor = dev_get_drvdata(dev); | ||
| 3988 | int err; | ||
| 3989 | 4033 | ||
| 3990 | if (sor->hdmi_supply) { | 4034 | return err; |
| 3991 | err = regulator_enable(sor->hdmi_supply); | ||
| 3992 | if (err < 0) | ||
| 3993 | return err; | ||
| 3994 | } | 4035 | } |
| 3995 | 4036 | ||
| 3996 | return 0; | 4037 | return 0; |
| 3997 | } | 4038 | } |
| 3998 | 4039 | ||
| 3999 | static const struct dev_pm_ops tegra_sor_pm_ops = { | 4040 | static const struct dev_pm_ops tegra_sor_pm_ops = { |
| 4000 | SET_RUNTIME_PM_OPS(tegra_sor_runtime_suspend, tegra_sor_runtime_resume, | ||
| 4001 | NULL) | ||
| 4002 | SET_SYSTEM_SLEEP_PM_OPS(tegra_sor_suspend, tegra_sor_resume) | 4041 | SET_SYSTEM_SLEEP_PM_OPS(tegra_sor_suspend, tegra_sor_resume) |
| 4003 | }; | 4042 | }; |
| 4004 | 4043 | ||
| @@ -161,7 +161,7 @@ static int vic_boot(struct vic *vic) · 160 unmodified lines | |||
| 161 | static int vic_init(struct host1x_client *client) | 161 | static int vic_init(struct host1x_client *client) |
| 162 | { | 162 | { |
| 163 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | 163 | struct tegra_drm_client *drm = host1x_to_drm_client(client); |
| 164 | struct drm_device *dev = dev_get_drvdata(client->parent); | 164 | struct drm_device *dev = dev_get_drvdata(client->host); |
| 165 | struct tegra_drm *tegra = dev->dev_private; | 165 | struct tegra_drm *tegra = dev->dev_private; |
| 166 | struct vic *vic = to_vic(drm); | 166 | struct vic *vic = to_vic(drm); |
| 167 | int err; | 167 | int err; |
| @@ -190,9 +190,9 @@ static int vic_init(struct host1x_client *client) · 22 unmodified lines | |||
| 190 | 190 | ||
| 191 | /* | 191 | /* |
| 192 | * Inherit the DMA parameters (such as maximum segment size) from the | 192 | * Inherit the DMA parameters (such as maximum segment size) from the |
| 193 | * parent device. | 193 | * parent host1x device. |
| 194 | */ | 194 | */ |
| 195 | client->dev->dma_parms = client->parent->dma_parms; | 195 | client->dev->dma_parms = client->host->dma_parms; |
| 196 | 196 | ||
| 197 | return 0; | 197 | return 0; |
| 198 | 198 | ||
| @@ -209,7 +209,7 @@ detach: · 10 unmodified lines | |||
| 209 | static int vic_exit(struct host1x_client *client) | 209 | static int vic_exit(struct host1x_client *client) |
| 210 | { | 210 | { |
| 211 | struct tegra_drm_client *drm = host1x_to_drm_client(client); | 211 | struct tegra_drm_client *drm = host1x_to_drm_client(client); |
| 212 | struct drm_device *dev = dev_get_drvdata(client->parent); | 212 | struct drm_device *dev = dev_get_drvdata(client->host); |
| 213 | struct tegra_drm *tegra = dev->dev_private; | 213 | struct tegra_drm *tegra = dev->dev_private; |
| 214 | struct vic *vic = to_vic(drm); | 214 | struct vic *vic = to_vic(drm); |
| 215 | int err; | 215 | int err; |
| @@ -120,7 +120,7 @@ static void host1x_subdev_register(struct host1x_device *device, · 119 unmodified lines | |||
| 120 | mutex_lock(&device->clients_lock); | 120 | mutex_lock(&device->clients_lock); |
| 121 | list_move_tail(&client->list, &device->clients); | 121 | list_move_tail(&client->list, &device->clients); |
| 122 | list_move_tail(&subdev->list, &device->active); | 122 | list_move_tail(&subdev->list, &device->active); |
| 123 | client->parent = &device->dev; | 123 | client->host = &device->dev; |
| 124 | subdev->client = client; | 124 | subdev->client = client; |
| 125 | mutex_unlock(&device->clients_lock); | 125 | mutex_unlock(&device->clients_lock); |
| 126 | mutex_unlock(&device->subdevs_lock); | 126 | mutex_unlock(&device->subdevs_lock); |
| @@ -156,7 +156,7 @@ static void __host1x_subdev_unregister(struct host1x_device *device, · 29 unmodified lines | |||
| 156 | */ | 156 | */ |
| 157 | mutex_lock(&device->clients_lock); | 157 | mutex_lock(&device->clients_lock); |
| 158 | subdev->client = NULL; | 158 | subdev->client = NULL; |
| 159 | client->parent = NULL; | 159 | client->host = NULL; |
| 160 | list_move_tail(&subdev->list, &device->subdevs); | 160 | list_move_tail(&subdev->list, &device->subdevs); |
| 161 | /* | 161 | /* |
| 162 | * XXX: Perhaps don't do this here, but rather explicitly remove it | 162 | * XXX: Perhaps don't do this here, but rather explicitly remove it |
| @@ -710,6 +710,10 @@ int host1x_client_register(struct host1x_client *client) · 547 unmodified lines | |||
| 710 | struct host1x *host1x; | 710 | struct host1x *host1x; |
| 711 | int err; | 711 | int err; |
| 712 | 712 | ||
| 713 | INIT_LIST_HEAD(&client->list); | ||
| 714 | mutex_init(&client->lock); | ||
| 715 | client->usecount = 0; | ||
| 716 | |||
| 713 | mutex_lock(&devices_lock); | 717 | mutex_lock(&devices_lock); |
| 714 | 718 | ||
| 715 | list_for_each_entry(host1x, &devices, list) { | 719 | list_for_each_entry(host1x, &devices, list) { |
| @@ -768,3 +772,74 @@ int host1x_client_unregister(struct host1x_client *client) · 52 unmodified lines | |||
| 768 | return 0; | 772 | return 0; |
| 769 | } | 773 | } |
| 770 | EXPORT_SYMBOL(host1x_client_unregister); | 774 | EXPORT_SYMBOL(host1x_client_unregister); |
| 775 | |||
| 776 | int host1x_client_suspend(struct host1x_client *client) | ||
| 777 | { | ||
| 778 | int err = 0; | ||
| 779 | |||
| 780 | mutex_lock(&client->lock); | ||
| 781 | |||
| 782 | if (client->usecount == 1) { | ||
| 783 | if (client->ops && client->ops->suspend) { | ||
| 784 | err = client->ops->suspend(client); | ||
| 785 | if (err < 0) | ||
| 786 | goto unlock; | ||
| 787 | } | ||
| 788 | } | ||
| 789 | |||
| 790 | client->usecount--; | ||
| 791 | dev_dbg(client->dev, "use count: %u\n", client->usecount); | ||
| 792 | |||
| 793 | if (client->parent) { | ||
| 794 | err = host1x_client_suspend(client->parent); | ||
| 795 | if (err < 0) | ||
| 796 | goto resume; | ||
| 797 | } | ||
| 798 | |||
| 799 | goto unlock; | ||
| 800 | |||
| 801 | resume: | ||
| 802 | if (client->usecount == 0) | ||
| 803 | if (client->ops && client->ops->resume) | ||
| 804 | client->ops->resume(client); | ||
| 805 | |||
| 806 | client->usecount++; | ||
| 807 | unlock: | ||
| 808 | mutex_unlock(&client->lock); | ||
| 809 | return err; | ||
| 810 | } | ||
| 811 | EXPORT_SYMBOL(host1x_client_suspend); | ||
| 812 | |||
| 813 | int host1x_client_resume(struct host1x_client *client) | ||
| 814 | { | ||
| 815 | int err = 0; | ||
| 816 | |||
| 817 | mutex_lock(&client->lock); | ||
| 818 | |||
| 819 | if (client->parent) { | ||
| 820 | err = host1x_client_resume(client->parent); | ||
| 821 | if (err < 0) | ||
| 822 | goto unlock; | ||
| 823 | } | ||
| 824 | |||
| 825 | if (client->usecount == 0) { | ||
| 826 | if (client->ops && client->ops->resume) { | ||
| 827 | err = client->ops->resume(client); | ||
| 828 | if (err < 0) | ||
| 829 | goto suspend; | ||
| 830 | } | ||
| 831 | } | ||
| 832 | |||
| 833 | client->usecount++; | ||
| 834 | dev_dbg(client->dev, "use count: %u\n", client->usecount); | ||
| 835 | |||
| 836 | goto unlock; | ||
| 837 | |||
| 838 | suspend: | ||
| 839 | if (client->parent) | ||
| 840 | host1x_client_suspend(client->parent); | ||
| 841 | unlock: | ||
| 842 | mutex_unlock(&client->lock); | ||
| 843 | return err; | ||
| 844 | } | ||
| 845 | EXPORT_SYMBOL(host1x_client_resume); | ||
| @@ -339,10 +339,8 @@ static int host1x_probe(struct platform_device *pdev) · 338 unmodified lines | |||
| 339 | } | 339 | } |
| 340 | 340 | ||
| 341 | syncpt_irq = platform_get_irq(pdev, 0); | 341 | syncpt_irq = platform_get_irq(pdev, 0); |
| 342 | if (syncpt_irq < 0) { | 342 | if (syncpt_irq < 0) |
| 343 | dev_err(&pdev->dev, "failed to get IRQ: %d\n", syncpt_irq); | ||
| 344 | return syncpt_irq; | 343 | return syncpt_irq; |
| 345 | } | ||
| 346 | 344 | ||
| 347 | mutex_init(&host->devices_lock); | 345 | mutex_init(&host->devices_lock); |
| 348 | INIT_LIST_HEAD(&host->devices); | 346 | INIT_LIST_HEAD(&host->devices); |
| @@ -421,7 +421,7 @@ int host1x_syncpt_init(struct host1x *host) · 420 unmodified lines | |||
| 421 | struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client, | 421 | struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client, |
| 422 | unsigned long flags) | 422 | unsigned long flags) |
| 423 | { | 423 | { |
| 424 | struct host1x *host = dev_get_drvdata(client->parent->parent); | 424 | struct host1x *host = dev_get_drvdata(client->host->parent); |
| 425 | 425 | ||
| 426 | return host1x_syncpt_alloc(host, client, flags); | 426 | return host1x_syncpt_alloc(host, client, flags); |
| 427 | } | 427 | } |
| @@ -24,16 +24,20 @@ struct iommu_group; · 23 unmodified lines | |||
| 24 | * struct host1x_client_ops - host1x client operations | 24 | * struct host1x_client_ops - host1x client operations |
| 25 | * @init: host1x client initialization code | 25 | * @init: host1x client initialization code |
| 26 | * @exit: host1x client tear down code | 26 | * @exit: host1x client tear down code |
| 27 | * @suspend: host1x client suspend code | ||
| 28 | * @resume: host1x client resume code | ||
| 27 | */ | 29 | */ |
| 28 | struct host1x_client_ops { | 30 | struct host1x_client_ops { |
| 29 | int (*init)(struct host1x_client *client); | 31 | int (*init)(struct host1x_client *client); |
| 30 | int (*exit)(struct host1x_client *client); | 32 | int (*exit)(struct host1x_client *client); |
| 33 | int (*suspend)(struct host1x_client *client); | ||
| 34 | int (*resume)(struct host1x_client *client); | ||
| 31 | }; | 35 | }; |
| 32 | 36 | ||
| 33 | /** | 37 | /** |
| 34 | * struct host1x_client - host1x client structure | 38 | * struct host1x_client - host1x client structure |
| 35 | * @list: list node for the host1x client | 39 | * @list: list node for the host1x client |
| 36 | * @parent: pointer to struct device representing the host1x controller | 40 | * @host: pointer to struct device representing the host1x controller |
| 37 | * @dev: pointer to struct device backing this host1x client | 41 | * @dev: pointer to struct device backing this host1x client |
| 38 | * @group: IOMMU group that this client is a member of | 42 | * @group: IOMMU group that this client is a member of |
| 39 | * @ops: host1x client operations | 43 | * @ops: host1x client operations |
| @@ -44,7 +48,7 @@ struct host1x_client_ops { · 4 unmodified lines | |||
| 44 | */ | 48 | */ |
| 45 | struct host1x_client { | 49 | struct host1x_client { |
| 46 | struct list_head list; | 50 | struct list_head list; |
| 47 | struct device *parent; | 51 | struct device *host; |
| 48 | struct device *dev; | 52 | struct device *dev; |
| 49 | struct iommu_group *group; | 53 | struct iommu_group *group; |
| 50 | 54 | ||
| @@ -55,6 +59,10 @@ struct host1x_client { · 4 unmodified lines | |||
| 55 | 59 | ||
| 56 | struct host1x_syncpt **syncpts; | 60 | struct host1x_syncpt **syncpts; |
| 57 | unsigned int num_syncpts; | 61 | unsigned int num_syncpts; |
| 62 | |||
| 63 | struct host1x_client *parent; | ||
| 64 | unsigned int usecount; | ||
| 65 | struct mutex lock; | ||
| 58 | }; | 66 | }; |
| 59 | 67 | ||
| 60 | /* | 68 | /* |
| @@ -309,6 +317,9 @@ int host1x_device_exit(struct host1x_device *device); · 248 unmodified lines | |||
| 309 | int host1x_client_register(struct host1x_client *client); | 317 | int host1x_client_register(struct host1x_client *client); |
| 310 | int host1x_client_unregister(struct host1x_client *client); | 318 | int host1x_client_unregister(struct host1x_client *client); |
| 311 | 319 | ||
| 320 | int host1x_client_suspend(struct host1x_client *client); | ||
| 321 | int host1x_client_resume(struct host1x_client *client); | ||
| 322 | |||
| 312 | struct tegra_mipi_device; | 323 | struct tegra_mipi_device; |
| 313 | 324 | ||
| 314 | struct tegra_mipi_device *tegra_mipi_request(struct device *device); | 325 | struct tegra_mipi_device *tegra_mipi_request(struct device *device); |