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 | 1728 | struct tegra_dc *dc = to_tegra_dc(crtc); |
| 1729 | 1729 | u32 value; |
| 1730 | + int err; | |
| 1730 | 1731 | |
| 1731 | 1732 | if (!tegra_dc_idle(dc)) { |
| 1732 | 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 | 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 | 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 | 1786 | struct tegra_dc_state *state = to_dc_state(crtc->state); |
| 1784 | 1787 | struct tegra_dc *dc = to_tegra_dc(crtc); |
| 1785 | 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 | 1797 | /* initialize display controller */ |
| 1790 | 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 | 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 | 2008 | unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED; |
| 2001 | 2009 | struct tegra_dc *dc = host1x_client_to_dc(client); |
| 2002 | 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 | 2020 | if (!tegra_dc_has_window_groups(dc)) |
| 2013 | 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 | 2032 | dc->syncpt = host1x_syncpt_request(client, flags); |
| 2016 | 2033 | if (!dc->syncpt) |
| 2017 | 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 | 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 | 2101 | return 0; |
| 2085 | 2102 | |
| @@ -2121,9 +2138,74 @@ static int tegra_dc_exit(struct host1x_client *client) · 35 unmodified lines | ||
| 2121 | 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 | 2204 | static const struct host1x_client_ops dc_client_ops = { |
| 2125 | 2205 | .init = tegra_dc_init, |
| 2126 | 2206 | .exit = tegra_dc_exit, |
| 2207 | + .suspend = tegra_dc_runtime_suspend, | |
| 2208 | + .resume = tegra_dc_runtime_resume, | |
| 2127 | 2209 | }; |
| 2128 | 2210 | |
| 2129 | 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 | 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 | 2620 | struct platform_driver tegra_dc_driver = { |
| 2593 | 2621 | .driver = { |
| 2594 | 2622 | .name = "tegra-dc", |
| 2595 | 2623 | .of_match_table = tegra_dc_of_match, |
| 2596 | − .pm = &tegra_dc_pm_ops, | |
| 2597 | 2624 | }, |
| 2598 | 2625 | .probe = tegra_dc_probe, |
| 2599 | 2626 | .remove = tegra_dc_remove, |
| @@ -588,7 +588,7 @@ static int tegra_dpaux_remove(struct platform_device *pdev) · 587 unmodified lines | ||
| 588 | 588 | /* make sure pads are powered down when not in use */ |
| 589 | 589 | tegra_dpaux_pad_power_down(dpaux); |
| 590 | 590 | |
| 591 | − pm_runtime_put(&pdev->dev); | |
| 591 | + pm_runtime_put_sync(&pdev->dev); | |
| 592 | 592 | pm_runtime_disable(&pdev->dev); |
| 593 | 593 | |
| 594 | 594 | drm_dp_aux_unregister(&dpaux->aux); |
| @@ -905,7 +905,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, · 904 unmodified lines | ||
| 905 | 905 | int host1x_client_iommu_attach(struct host1x_client *client) |
| 906 | 906 | { |
| 907 | 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 | 909 | struct tegra_drm *tegra = drm->dev_private; |
| 910 | 910 | struct iommu_group *group = NULL; |
| 911 | 911 | int err; |
| @@ -941,7 +941,7 @@ int host1x_client_iommu_attach(struct host1x_client *client) · 29 unmodified lines | ||
| 941 | 941 | |
| 942 | 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 | 945 | struct tegra_drm *tegra = drm->dev_private; |
| 946 | 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 | 144 | void tegra_output_exit(struct tegra_output *output); |
| 145 | 145 | void tegra_output_find_possible_crtcs(struct tegra_output *output, |
| 146 | 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 | 150 | int tegra_output_connector_get_modes(struct drm_connector *connector); |
| 149 | 151 | enum drm_connector_status |
| @@ -840,7 +840,9 @@ static void tegra_dsi_unprepare(struct tegra_dsi *dsi) · 839 unmodified lines | ||
| 840 | 840 | dev_err(dsi->dev, "failed to disable MIPI calibration: %d\n", |
| 841 | 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 | 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 | 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 | 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 | 897 | err = tegra_mipi_enable(dsi->mipi); |
| 892 | 898 | if (err < 0) |
| @@ -899,6 +905,8 @@ static void tegra_dsi_prepare(struct tegra_dsi *dsi) · 6 unmodified lines | ||
| 899 | 905 | |
| 900 | 906 | if (dsi->slave) |
| 901 | 907 | tegra_dsi_prepare(dsi->slave); |
| 908 | + | |
| 909 | + return 0; | |
| 902 | 910 | } |
| 903 | 911 | |
| 904 | 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 | 917 | struct tegra_dsi *dsi = to_dsi(output); |
| 910 | 918 | struct tegra_dsi_state *state; |
| 911 | 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 | 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 | 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 | 1047 | struct tegra_dsi *dsi = host1x_client_to_dsi(client); |
| 1035 | 1048 | int err; |
| 1036 | 1049 | |
| @@ -1075,9 +1088,89 @@ static int tegra_dsi_exit(struct host1x_client *client) · 38 unmodified lines | ||
| 1075 | 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 | 1169 | static const struct host1x_client_ops dsi_client_ops = { |
| 1079 | 1170 | .init = tegra_dsi_init, |
| 1080 | 1171 | .exit = tegra_dsi_exit, |
| 1172 | + .suspend = tegra_dsi_runtime_suspend, | |
| 1173 | + .resume = tegra_dsi_runtime_resume, | |
| 1081 | 1174 | }; |
| 1082 | 1175 | |
| 1083 | 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 | 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 | 1692 | static const struct of_device_id tegra_dsi_of_match[] = { |
| 1673 | 1693 | { .compatible = "nvidia,tegra210-dsi", }, |
| 1674 | 1694 | { .compatible = "nvidia,tegra132-dsi", }, |
| @@ -1682,7 +1702,6 @@ struct platform_driver tegra_dsi_driver = { · 7 unmodified lines | ||
| 1682 | 1702 | .driver = { |
| 1683 | 1703 | .name = "tegra-dsi", |
| 1684 | 1704 | .of_match_table = tegra_dsi_of_match, |
| 1685 | − .pm = &tegra_dsi_pm_ops, | |
| 1686 | 1705 | }, |
| 1687 | 1706 | .probe = tegra_dsi_probe, |
| 1688 | 1707 | .remove = tegra_dsi_remove, |
| @@ -34,7 +34,7 @@ static inline struct gr2d *to_gr2d(struct tegra_drm_client *client) · 33 unmodified lines | ||
| 34 | 34 | static int gr2d_init(struct host1x_client *client) |
| 35 | 35 | { |
| 36 | 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 | 38 | unsigned long flags = HOST1X_SYNCPT_HAS_BASE; |
| 39 | 39 | struct gr2d *gr2d = to_gr2d(drm); |
| 40 | 40 | int err; |
| @@ -76,7 +76,7 @@ put: · 35 unmodified lines | ||
| 76 | 76 | static int gr2d_exit(struct host1x_client *client) |
| 77 | 77 | { |
| 78 | 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 | 80 | struct tegra_drm *tegra = dev->dev_private; |
| 81 | 81 | struct gr2d *gr2d = to_gr2d(drm); |
| 82 | 82 | int err; |
| @@ -43,7 +43,7 @@ static inline struct gr3d *to_gr3d(struct tegra_drm_client *client) · 42 unmodified lines | ||
| 43 | 43 | static int gr3d_init(struct host1x_client *client) |
| 44 | 44 | { |
| 45 | 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 | 47 | unsigned long flags = HOST1X_SYNCPT_HAS_BASE; |
| 48 | 48 | struct gr3d *gr3d = to_gr3d(drm); |
| 49 | 49 | int err; |
| @@ -85,7 +85,7 @@ put: · 35 unmodified lines | ||
| 85 | 85 | static int gr3d_exit(struct host1x_client *client) |
| 86 | 86 | { |
| 87 | 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 | 89 | struct gr3d *gr3d = to_gr3d(drm); |
| 90 | 90 | int err; |
| 91 | 91 | |
| @@ -1146,6 +1146,7 @@ static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder) · 1145 unmodified lines | ||
| 1146 | 1146 | struct tegra_dc *dc = to_tegra_dc(encoder->crtc); |
| 1147 | 1147 | struct tegra_hdmi *hdmi = to_hdmi(output); |
| 1148 | 1148 | u32 value; |
| 1149 | + int err; | |
| 1149 | 1150 | |
| 1150 | 1151 | /* |
| 1151 | 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 | 1172 | tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_INT_ENABLE); |
| 1172 | 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 | 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 | 1189 | u32 value; |
| 1187 | 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 | 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 | 1432 | static int tegra_hdmi_init(struct host1x_client *client) |
| 1426 | 1433 | { |
| 1427 | − struct drm_device *drm = dev_get_drvdata(client->parent); | |
| 1428 | 1434 | struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client); |
| 1435 | + struct drm_device *drm = dev_get_drvdata(client->host); | |
| 1429 | 1436 | int err; |
| 1430 | 1437 | |
| 1431 | 1438 | hdmi->output.dev = client->dev; |
| @@ -1490,9 +1497,66 @@ static int tegra_hdmi_exit(struct host1x_client *client) · 58 unmodified lines | ||
| 1490 | 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 | 1555 | static const struct host1x_client_ops hdmi_client_ops = { |
| 1494 | 1556 | .init = tegra_hdmi_init, |
| 1495 | 1557 | .exit = tegra_hdmi_exit, |
| 1558 | + .suspend = tegra_hdmi_runtime_suspend, | |
| 1559 | + .resume = tegra_hdmi_runtime_resume, | |
| 1496 | 1560 | }; |
| 1497 | 1561 | |
| 1498 | 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 | 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 | 1767 | struct platform_driver tegra_hdmi_driver = { |
| 1751 | 1768 | .driver = { |
| 1752 | 1769 | .name = "tegra-hdmi", |
| 1753 | 1770 | .of_match_table = tegra_hdmi_of_match, |
| 1754 | − .pm = &tegra_hdmi_pm_ops, | |
| 1755 | 1771 | }, |
| 1756 | 1772 | .probe = tegra_hdmi_probe, |
| 1757 | 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 | 96 | static int tegra_windowgroup_enable(struct tegra_windowgroup *wgrp) |
| 97 | 97 | { |
| 98 | + int err = 0; | |
| 99 | + | |
| 98 | 100 | mutex_lock(&wgrp->lock); |
| 99 | 101 | |
| 100 | 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 | 109 | reset_control_deassert(wgrp->rst); |
| 103 | 110 | } |
| 104 | 111 | |
| 105 | 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 | 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 | 129 | wgrp->index); |
| 122 | 130 | } |
| 123 | 131 | |
| 124 | − pm_runtime_put(wgrp->parent); | |
| 132 | + host1x_client_suspend(wgrp->parent); | |
| 125 | 133 | } |
| 126 | 134 | |
| 127 | 135 | wgrp->usecount--; |
| @@ -379,6 +387,7 @@ static void tegra_shared_plane_atomic_disable(struct drm_plane *plane, · 251 unmodified lines | ||
| 379 | 387 | struct tegra_plane *p = to_tegra_plane(plane); |
| 380 | 388 | struct tegra_dc *dc; |
| 381 | 389 | u32 value; |
| 390 | + int err; | |
| 382 | 391 | |
| 383 | 392 | /* rien ne va plus */ |
| 384 | 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 | 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 | 405 | * XXX Legacy helpers seem to sometimes call ->atomic_disable() even |
| 391 | 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 | 409 | if (WARN_ON(p->dc == NULL)) |
| 395 | 410 | p->dc = dc; |
| 396 | 411 | |
| 397 | − pm_runtime_get_sync(dc->dev); | |
| 398 | − | |
| 399 | 412 | value = tegra_plane_readl(p, DC_WIN_WIN_OPTIONS); |
| 400 | 413 | value &= ~WIN_ENABLE; |
| 401 | 414 | tegra_plane_writel(p, value, DC_WIN_WIN_OPTIONS); |
| 402 | 415 | |
| 403 | 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 | 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 | 428 | struct tegra_plane *p = to_tegra_plane(plane); |
| 416 | 429 | dma_addr_t base; |
| 417 | 430 | u32 value; |
| 431 | + int err; | |
| 418 | 432 | |
| 419 | 433 | /* rien ne va plus */ |
| 420 | 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 | 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 | 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 | 533 | value &= ~CONTROL_CSC_ENABLE; |
| 516 | 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 | 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 | 569 | plane->base.index = index; |
| 552 | 570 | |
| 553 | 571 | plane->wgrp = &hub->wgrps[wgrp]; |
| 554 | − plane->wgrp->parent = dc->dev; | |
| 572 | + plane->wgrp->parent = &dc->client; | |
| 555 | 573 | |
| 556 | 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 | 674 | static void tegra_display_hub_update(struct tegra_dc *dc) |
| 657 | 675 | { |
| 658 | 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 | 685 | value = tegra_dc_readl(dc, DC_CMD_IHUB_COMMON_MISC_CTL); |
| 663 | 686 | value &= ~LATENCY_EVENT; |
| @@ -672,7 +695,7 @@ static void tegra_display_hub_update(struct tegra_dc *dc) · 8 unmodified lines | ||
| 672 | 695 | tegra_dc_writel(dc, COMMON_ACTREQ, DC_CMD_STATE_CONTROL); |
| 673 | 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 | 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 | 728 | static int tegra_display_hub_init(struct host1x_client *client) |
| 706 | 729 | { |
| 707 | 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 | 732 | struct tegra_drm *tegra = drm->dev_private; |
| 710 | 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 | 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 | 750 | struct tegra_drm *tegra = drm->dev_private; |
| 728 | 751 | |
| 729 | 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 | 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 | 832 | static const struct host1x_client_ops tegra_display_hub_ops = { |
| 736 | 833 | .init = tegra_display_hub_init, |
| 737 | 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 | 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 | 950 | static int tegra_display_hub_remove(struct platform_device *pdev) |
| 852 | 951 | { |
| 853 | 952 | struct tegra_display_hub *hub = platform_get_drvdata(pdev); |
| 953 | + unsigned int i; | |
| 854 | 954 | int err; |
| 855 | 955 | |
| 856 | 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 | 959 | err); |
| 860 | 960 | } |
| 861 | 961 | |
| 862 | − pm_runtime_disable(&pdev->dev); | |
| 863 | − | |
| 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; | |
| 962 | + for (i = 0; i < hub->soc->num_wgrps; i++) { | |
| 963 | + struct tegra_windowgroup *wgrp = &hub->wgrps[i]; | |
| 904 | 964 | |
| 905 | − for (i = 0; i < hub->num_heads; i++) { | |
| 906 | − err = clk_prepare_enable(hub->clk_heads[i]); | |
| 907 | − if (err < 0) | |
| 908 | − goto disable_heads; | |
| 965 | + mutex_destroy(&wgrp->lock); | |
| 909 | 966 | } |
| 910 | 967 | |
| 911 | − err = reset_control_deassert(hub->rst); | |
| 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]); | |
| 968 | + pm_runtime_disable(&pdev->dev); | |
| 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 | 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 | 973 | static const struct tegra_display_hub_soc tegra186_display_hub = { |
| 935 | 974 | .num_wgrps = 6, |
| 936 | 975 | .supports_dsc = true, |
| @@ -958,7 +997,6 @@ struct platform_driver tegra_display_hub_driver = { · 21 unmodified lines | ||
| 958 | 997 | .driver = { |
| 959 | 998 | .name = "tegra-display-hub", |
| 960 | 999 | .of_match_table = tegra_display_hub_of_match, |
| 961 | − .pm = &tegra_display_hub_pm_ops, | |
| 962 | 1000 | }, |
| 963 | 1001 | .probe = tegra_display_hub_probe, |
| 964 | 1002 | .remove = tegra_display_hub_remove, |
| @@ -17,7 +17,7 @@ struct tegra_windowgroup { · 16 unmodified lines | ||
| 17 | 17 | struct mutex lock; |
| 18 | 18 | |
| 19 | 19 | unsigned int index; |
| 20 | − struct device *parent; | |
| 20 | + struct host1x_client *parent; | |
| 21 | 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 | 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 | 2255 | if (err < 0) |
| 2256 | 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 | 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 | 2276 | mode = &encoder->crtc->state->adjusted_mode; |
| 2277 | 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 | 2285 | /* switch to safe parent clock */ |
| 2282 | 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 | 2726 | if (output->panel) |
| 2723 | 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 | 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 | 2746 | mode = &encoder->crtc->state->adjusted_mode; |
| 2743 | 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 | 2755 | /* switch to safe parent clock */ |
| 2748 | 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 | 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 | 3065 | const struct drm_encoder_helper_funcs *helpers = NULL; |
| 3058 | 3066 | struct tegra_sor *sor = host1x_client_to_sor(client); |
| 3059 | 3067 | int connector = DRM_MODE_CONNECTOR_Unknown; |
| @@ -3190,9 +3198,80 @@ static int tegra_sor_exit(struct host1x_client *client) · 130 unmodified lines | ||
| 3190 | 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 | 3270 | static const struct host1x_client_ops sor_client_ops = { |
| 3194 | 3271 | .init = tegra_sor_init, |
| 3195 | 3272 | .exit = tegra_sor_exit, |
| 3273 | + .suspend = tegra_sor_runtime_suspend, | |
| 3274 | + .resume = tegra_sor_runtime_resume, | |
| 3196 | 3275 | }; |
| 3197 | 3276 | |
| 3198 | 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 | 3922 | if (!sor->clk_pad) { |
| 3844 | 3923 | char *name; |
| 3845 | 3924 | |
| 3846 | − err = pm_runtime_get_sync(&pdev->dev); | |
| 3925 | + err = host1x_client_resume(&sor->client); | |
| 3847 | 3926 | if (err < 0) { |
| 3848 | − dev_err(&pdev->dev, "failed to get runtime PM: %d\n", | |
| 3849 | − err); | |
| 3927 | + dev_err(sor->dev, "failed to resume: %d\n", err); | |
| 3850 | 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 | 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 | 3941 | if (IS_ERR(sor->clk_pad)) { |
| @@ -3913,54 +3991,21 @@ static int tegra_sor_remove(struct platform_device *pdev) · 49 unmodified lines | ||
| 3913 | 3991 | return 0; |
| 3914 | 3992 | } |
| 3915 | 3993 | |
| 3916 | −static int tegra_sor_runtime_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) | |
| 3994 | +static int __maybe_unused tegra_sor_suspend(struct device *dev) | |
| 3939 | 3995 | { |
| 3940 | 3996 | struct tegra_sor *sor = dev_get_drvdata(dev); |
| 3941 | 3997 | int err; |
| 3942 | 3998 | |
| 3943 | − err = clk_prepare_enable(sor->clk); | |
| 3999 | + err = tegra_output_suspend(&sor->output); | |
| 3944 | 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 | 4002 | return err; |
| 3947 | 4003 | } |
| 3948 | 4004 | |
| 3949 | − usleep_range(1000, 2000); | |
| 3950 | − | |
| 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); | |
| 4005 | + if (sor->hdmi_supply) { | |
| 4006 | + err = regulator_disable(sor->hdmi_supply); | |
| 3960 | 4007 | if (err < 0) { |
| 3961 | − dev_err(dev, "failed to deassert reset: %d\n", err); | |
| 3962 | − reset_control_release(sor->rst); | |
| 3963 | − clk_disable_unprepare(sor->clk); | |
| 4008 | + tegra_output_resume(&sor->output); | |
| 3964 | 4009 | return err; |
| 3965 | 4010 | } |
| 3966 | 4011 | } |
| @@ -3968,37 +4013,31 @@ static int tegra_sor_runtime_resume(struct device *dev) · 1 unmodified line | ||
| 3968 | 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 | 4018 | struct tegra_sor *sor = dev_get_drvdata(dev); |
| 3974 | 4019 | int err; |
| 3975 | 4020 | |
| 3976 | 4021 | if (sor->hdmi_supply) { |
| 3977 | − err = regulator_disable(sor->hdmi_supply); | |
| 4022 | + err = regulator_enable(sor->hdmi_supply); | |
| 3978 | 4023 | if (err < 0) |
| 3979 | 4024 | return err; |
| 3980 | 4025 | } |
| 3981 | 4026 | |
| 3982 | − return 0; | |
| 3983 | −} | |
| 4027 | + err = tegra_output_resume(&sor->output); | |
| 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) | |
| 3986 | −{ | |
| 3987 | − struct tegra_sor *sor = dev_get_drvdata(dev); | |
| 3988 | − int err; | |
| 4031 | + if (sor->hdmi_supply) | |
| 4032 | + regulator_disable(sor->hdmi_supply); | |
| 3989 | 4033 | |
| 3990 | − if (sor->hdmi_supply) { | |
| 3991 | − err = regulator_enable(sor->hdmi_supply); | |
| 3992 | − if (err < 0) | |
| 3993 | − return err; | |
| 4034 | + return err; | |
| 3994 | 4035 | } |
| 3995 | 4036 | |
| 3996 | 4037 | return 0; |
| 3997 | 4038 | } |
| 3998 | 4039 | |
| 3999 | 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 | 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 | 161 | static int vic_init(struct host1x_client *client) |
| 162 | 162 | { |
| 163 | 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 | 165 | struct tegra_drm *tegra = dev->dev_private; |
| 166 | 166 | struct vic *vic = to_vic(drm); |
| 167 | 167 | int err; |
| @@ -190,9 +190,9 @@ static int vic_init(struct host1x_client *client) · 22 unmodified lines | ||
| 190 | 190 | |
| 191 | 191 | /* |
| 192 | 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 | 197 | return 0; |
| 198 | 198 | |
| @@ -209,7 +209,7 @@ detach: · 10 unmodified lines | ||
| 209 | 209 | static int vic_exit(struct host1x_client *client) |
| 210 | 210 | { |
| 211 | 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 | 213 | struct tegra_drm *tegra = dev->dev_private; |
| 214 | 214 | struct vic *vic = to_vic(drm); |
| 215 | 215 | int err; |
| @@ -120,7 +120,7 @@ static void host1x_subdev_register(struct host1x_device *device, · 119 unmodified lines | ||
| 120 | 120 | mutex_lock(&device->clients_lock); |
| 121 | 121 | list_move_tail(&client->list, &device->clients); |
| 122 | 122 | list_move_tail(&subdev->list, &device->active); |
| 123 | − client->parent = &device->dev; | |
| 123 | + client->host = &device->dev; | |
| 124 | 124 | subdev->client = client; |
| 125 | 125 | mutex_unlock(&device->clients_lock); |
| 126 | 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 | 157 | mutex_lock(&device->clients_lock); |
| 158 | 158 | subdev->client = NULL; |
| 159 | − client->parent = NULL; | |
| 159 | + client->host = NULL; | |
| 160 | 160 | list_move_tail(&subdev->list, &device->subdevs); |
| 161 | 161 | /* |
| 162 | 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 | 710 | struct host1x *host1x; |
| 711 | 711 | int err; |
| 712 | 712 | |
| 713 | + INIT_LIST_HEAD(&client->list); | |
| 714 | + mutex_init(&client->lock); | |
| 715 | + client->usecount = 0; | |
| 716 | + | |
| 713 | 717 | mutex_lock(&devices_lock); |
| 714 | 718 | |
| 715 | 719 | list_for_each_entry(host1x, &devices, list) { |
| @@ -768,3 +772,74 @@ int host1x_client_unregister(struct host1x_client *client) · 52 unmodified lines | ||
| 768 | 772 | return 0; |
| 769 | 773 | } |
| 770 | 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 | 341 | syncpt_irq = platform_get_irq(pdev, 0); |
| 342 | − if (syncpt_irq < 0) { | |
| 343 | − dev_err(&pdev->dev, "failed to get IRQ: %d\n", syncpt_irq); | |
| 342 | + if (syncpt_irq < 0) | |
| 344 | 343 | return syncpt_irq; |
| 345 | − } | |
| 346 | 344 | |
| 347 | 345 | mutex_init(&host->devices_lock); |
| 348 | 346 | INIT_LIST_HEAD(&host->devices); |
| @@ -421,7 +421,7 @@ int host1x_syncpt_init(struct host1x *host) · 420 unmodified lines | ||
| 421 | 421 | struct host1x_syncpt *host1x_syncpt_request(struct host1x_client *client, |
| 422 | 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 | 426 | return host1x_syncpt_alloc(host, client, flags); |
| 427 | 427 | } |
| @@ -24,16 +24,20 @@ struct iommu_group; · 23 unmodified lines | ||
| 24 | 24 | * struct host1x_client_ops - host1x client operations |
| 25 | 25 | * @init: host1x client initialization code |
| 26 | 26 | * @exit: host1x client tear down code |
| 27 | + * @suspend: host1x client suspend code | |
| 28 | + * @resume: host1x client resume code | |
| 27 | 29 | */ |
| 28 | 30 | struct host1x_client_ops { |
| 29 | 31 | int (*init)(struct host1x_client *client); |
| 30 | 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 | 38 | * struct host1x_client - host1x client structure |
| 35 | 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 | 41 | * @dev: pointer to struct device backing this host1x client |
| 38 | 42 | * @group: IOMMU group that this client is a member of |
| 39 | 43 | * @ops: host1x client operations |
| @@ -44,7 +48,7 @@ struct host1x_client_ops { · 4 unmodified lines | ||
| 44 | 48 | */ |
| 45 | 49 | struct host1x_client { |
| 46 | 50 | struct list_head list; |
| 47 | − struct device *parent; | |
| 51 | + struct device *host; | |
| 48 | 52 | struct device *dev; |
| 49 | 53 | struct iommu_group *group; |
| 50 | 54 | |
| @@ -55,6 +59,10 @@ struct host1x_client { · 4 unmodified lines | ||
| 55 | 59 | |
| 56 | 60 | struct host1x_syncpt **syncpts; |
| 57 | 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 | 317 | int host1x_client_register(struct host1x_client *client); |
| 310 | 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 | 323 | struct tegra_mipi_device; |
| 313 | 324 | |
| 314 | 325 | struct tegra_mipi_device *tegra_mipi_request(struct device *device); |