diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 176 |
1 files changed, 106 insertions, 70 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 39940f5b7c91..8495bd01b544 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
11 | #include <linux/debugfs.h> | 11 | #include <linux/debugfs.h> |
12 | #include <linux/iommu.h> | 12 | #include <linux/iommu.h> |
13 | #include <linux/pm_runtime.h> | ||
13 | #include <linux/reset.h> | 14 | #include <linux/reset.h> |
14 | 15 | ||
15 | #include <soc/tegra/pmc.h> | 16 | #include <soc/tegra/pmc.h> |
@@ -1216,6 +1217,8 @@ static void tegra_crtc_disable(struct drm_crtc *crtc) | |||
1216 | 1217 | ||
1217 | tegra_dc_stats_reset(&dc->stats); | 1218 | tegra_dc_stats_reset(&dc->stats); |
1218 | drm_crtc_vblank_off(crtc); | 1219 | drm_crtc_vblank_off(crtc); |
1220 | |||
1221 | pm_runtime_put_sync(dc->dev); | ||
1219 | } | 1222 | } |
1220 | 1223 | ||
1221 | static void tegra_crtc_enable(struct drm_crtc *crtc) | 1224 | static void tegra_crtc_enable(struct drm_crtc *crtc) |
@@ -1225,6 +1228,48 @@ static void tegra_crtc_enable(struct drm_crtc *crtc) | |||
1225 | struct tegra_dc *dc = to_tegra_dc(crtc); | 1228 | struct tegra_dc *dc = to_tegra_dc(crtc); |
1226 | u32 value; | 1229 | u32 value; |
1227 | 1230 | ||
1231 | pm_runtime_get_sync(dc->dev); | ||
1232 | |||
1233 | /* initialize display controller */ | ||
1234 | if (dc->syncpt) { | ||
1235 | u32 syncpt = host1x_syncpt_id(dc->syncpt); | ||
1236 | |||
1237 | value = SYNCPT_CNTRL_NO_STALL; | ||
1238 | tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
1239 | |||
1240 | value = SYNCPT_VSYNC_ENABLE | syncpt; | ||
1241 | tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC); | ||
1242 | } | ||
1243 | |||
1244 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1245 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1246 | tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); | ||
1247 | |||
1248 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1249 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1250 | tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); | ||
1251 | |||
1252 | /* initialize timer */ | ||
1253 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | | ||
1254 | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); | ||
1255 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
1256 | |||
1257 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | | ||
1258 | WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); | ||
1259 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
1260 | |||
1261 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1262 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1263 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
1264 | |||
1265 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1266 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1267 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
1268 | |||
1269 | if (dc->soc->supports_border_color) | ||
1270 | tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR); | ||
1271 | |||
1272 | /* apply PLL and pixel clock changes */ | ||
1228 | tegra_dc_commit_state(dc, state); | 1273 | tegra_dc_commit_state(dc, state); |
1229 | 1274 | ||
1230 | /* program display mode */ | 1275 | /* program display mode */ |
@@ -1685,7 +1730,6 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1685 | struct tegra_drm *tegra = drm->dev_private; | 1730 | struct tegra_drm *tegra = drm->dev_private; |
1686 | struct drm_plane *primary = NULL; | 1731 | struct drm_plane *primary = NULL; |
1687 | struct drm_plane *cursor = NULL; | 1732 | struct drm_plane *cursor = NULL; |
1688 | u32 value; | ||
1689 | int err; | 1733 | int err; |
1690 | 1734 | ||
1691 | dc->syncpt = host1x_syncpt_request(dc->dev, flags); | 1735 | dc->syncpt = host1x_syncpt_request(dc->dev, flags); |
@@ -1755,47 +1799,6 @@ static int tegra_dc_init(struct host1x_client *client) | |||
1755 | goto cleanup; | 1799 | goto cleanup; |
1756 | } | 1800 | } |
1757 | 1801 | ||
1758 | /* initialize display controller */ | ||
1759 | if (dc->syncpt) { | ||
1760 | u32 syncpt = host1x_syncpt_id(dc->syncpt); | ||
1761 | |||
1762 | value = SYNCPT_CNTRL_NO_STALL; | ||
1763 | tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); | ||
1764 | |||
1765 | value = SYNCPT_VSYNC_ENABLE | syncpt; | ||
1766 | tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC); | ||
1767 | } | ||
1768 | |||
1769 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1770 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1771 | tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); | ||
1772 | |||
1773 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1774 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1775 | tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY); | ||
1776 | |||
1777 | /* initialize timer */ | ||
1778 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) | | ||
1779 | WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20); | ||
1780 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY); | ||
1781 | |||
1782 | value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) | | ||
1783 | WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1); | ||
1784 | tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER); | ||
1785 | |||
1786 | value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1787 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1788 | tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE); | ||
1789 | |||
1790 | value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | | ||
1791 | WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT; | ||
1792 | tegra_dc_writel(dc, value, DC_CMD_INT_MASK); | ||
1793 | |||
1794 | if (dc->soc->supports_border_color) | ||
1795 | tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR); | ||
1796 | |||
1797 | tegra_dc_stats_reset(&dc->stats); | ||
1798 | |||
1799 | return 0; | 1802 | return 0; |
1800 | 1803 | ||
1801 | cleanup: | 1804 | cleanup: |
@@ -1987,33 +1990,15 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
1987 | return PTR_ERR(dc->rst); | 1990 | return PTR_ERR(dc->rst); |
1988 | } | 1991 | } |
1989 | 1992 | ||
1993 | reset_control_assert(dc->rst); | ||
1994 | |||
1990 | if (dc->soc->has_powergate) { | 1995 | if (dc->soc->has_powergate) { |
1991 | if (dc->pipe == 0) | 1996 | if (dc->pipe == 0) |
1992 | dc->powergate = TEGRA_POWERGATE_DIS; | 1997 | dc->powergate = TEGRA_POWERGATE_DIS; |
1993 | else | 1998 | else |
1994 | dc->powergate = TEGRA_POWERGATE_DISB; | 1999 | dc->powergate = TEGRA_POWERGATE_DISB; |
1995 | 2000 | ||
1996 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | 2001 | tegra_powergate_power_off(dc->powergate); |
1997 | dc->rst); | ||
1998 | if (err < 0) { | ||
1999 | dev_err(&pdev->dev, "failed to power partition: %d\n", | ||
2000 | err); | ||
2001 | return err; | ||
2002 | } | ||
2003 | } else { | ||
2004 | err = clk_prepare_enable(dc->clk); | ||
2005 | if (err < 0) { | ||
2006 | dev_err(&pdev->dev, "failed to enable clock: %d\n", | ||
2007 | err); | ||
2008 | return err; | ||
2009 | } | ||
2010 | |||
2011 | err = reset_control_deassert(dc->rst); | ||
2012 | if (err < 0) { | ||
2013 | dev_err(&pdev->dev, "failed to deassert reset: %d\n", | ||
2014 | err); | ||
2015 | return err; | ||
2016 | } | ||
2017 | } | 2002 | } |
2018 | 2003 | ||
2019 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 2004 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -2027,16 +2012,19 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
2027 | return -ENXIO; | 2012 | return -ENXIO; |
2028 | } | 2013 | } |
2029 | 2014 | ||
2030 | INIT_LIST_HEAD(&dc->client.list); | ||
2031 | dc->client.ops = &dc_client_ops; | ||
2032 | dc->client.dev = &pdev->dev; | ||
2033 | |||
2034 | err = tegra_dc_rgb_probe(dc); | 2015 | err = tegra_dc_rgb_probe(dc); |
2035 | if (err < 0 && err != -ENODEV) { | 2016 | if (err < 0 && err != -ENODEV) { |
2036 | dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); | 2017 | dev_err(&pdev->dev, "failed to probe RGB output: %d\n", err); |
2037 | return err; | 2018 | return err; |
2038 | } | 2019 | } |
2039 | 2020 | ||
2021 | platform_set_drvdata(pdev, dc); | ||
2022 | pm_runtime_enable(&pdev->dev); | ||
2023 | |||
2024 | INIT_LIST_HEAD(&dc->client.list); | ||
2025 | dc->client.ops = &dc_client_ops; | ||
2026 | dc->client.dev = &pdev->dev; | ||
2027 | |||
2040 | err = host1x_client_register(&dc->client); | 2028 | err = host1x_client_register(&dc->client); |
2041 | if (err < 0) { | 2029 | if (err < 0) { |
2042 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", | 2030 | dev_err(&pdev->dev, "failed to register host1x client: %d\n", |
@@ -2044,8 +2032,6 @@ static int tegra_dc_probe(struct platform_device *pdev) | |||
2044 | return err; | 2032 | return err; |
2045 | } | 2033 | } |
2046 | 2034 | ||
2047 | platform_set_drvdata(pdev, dc); | ||
2048 | |||
2049 | return 0; | 2035 | return 0; |
2050 | } | 2036 | } |
2051 | 2037 | ||
@@ -2067,7 +2053,22 @@ static int tegra_dc_remove(struct platform_device *pdev) | |||
2067 | return err; | 2053 | return err; |
2068 | } | 2054 | } |
2069 | 2055 | ||
2070 | reset_control_assert(dc->rst); | 2056 | pm_runtime_disable(&pdev->dev); |
2057 | |||
2058 | return 0; | ||
2059 | } | ||
2060 | |||
2061 | #ifdef CONFIG_PM | ||
2062 | static int tegra_dc_suspend(struct device *dev) | ||
2063 | { | ||
2064 | struct tegra_dc *dc = dev_get_drvdata(dev); | ||
2065 | int err; | ||
2066 | |||
2067 | err = reset_control_assert(dc->rst); | ||
2068 | if (err < 0) { | ||
2069 | dev_err(dev, "failed to assert reset: %d\n", err); | ||
2070 | return err; | ||
2071 | } | ||
2071 | 2072 | ||
2072 | if (dc->soc->has_powergate) | 2073 | if (dc->soc->has_powergate) |
2073 | tegra_powergate_power_off(dc->powergate); | 2074 | tegra_powergate_power_off(dc->powergate); |
@@ -2077,10 +2078,45 @@ static int tegra_dc_remove(struct platform_device *pdev) | |||
2077 | return 0; | 2078 | return 0; |
2078 | } | 2079 | } |
2079 | 2080 | ||
2081 | static int tegra_dc_resume(struct device *dev) | ||
2082 | { | ||
2083 | struct tegra_dc *dc = dev_get_drvdata(dev); | ||
2084 | int err; | ||
2085 | |||
2086 | if (dc->soc->has_powergate) { | ||
2087 | err = tegra_powergate_sequence_power_up(dc->powergate, dc->clk, | ||
2088 | dc->rst); | ||
2089 | if (err < 0) { | ||
2090 | dev_err(dev, "failed to power partition: %d\n", err); | ||
2091 | return err; | ||
2092 | } | ||
2093 | } else { | ||
2094 | err = clk_prepare_enable(dc->clk); | ||
2095 | if (err < 0) { | ||
2096 | dev_err(dev, "failed to enable clock: %d\n", err); | ||
2097 | return err; | ||
2098 | } | ||
2099 | |||
2100 | err = reset_control_deassert(dc->rst); | ||
2101 | if (err < 0) { | ||
2102 | dev_err(dev, "failed to deassert reset: %d\n", err); | ||
2103 | return err; | ||
2104 | } | ||
2105 | } | ||
2106 | |||
2107 | return 0; | ||
2108 | } | ||
2109 | #endif | ||
2110 | |||
2111 | static const struct dev_pm_ops tegra_dc_pm_ops = { | ||
2112 | SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL) | ||
2113 | }; | ||
2114 | |||
2080 | struct platform_driver tegra_dc_driver = { | 2115 | struct platform_driver tegra_dc_driver = { |
2081 | .driver = { | 2116 | .driver = { |
2082 | .name = "tegra-dc", | 2117 | .name = "tegra-dc", |
2083 | .of_match_table = tegra_dc_of_match, | 2118 | .of_match_table = tegra_dc_of_match, |
2119 | .pm = &tegra_dc_pm_ops, | ||
2084 | }, | 2120 | }, |
2085 | .probe = tegra_dc_probe, | 2121 | .probe = tegra_dc_probe, |
2086 | .remove = tegra_dc_remove, | 2122 | .remove = tegra_dc_remove, |