aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/tegra/dc.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-07-15 21:23:50 -0400
committerDave Airlie <airlied@redhat.com>2016-07-15 21:23:50 -0400
commit877fa9a42ddc087dc46a3a3aac18db8adde2bdf1 (patch)
treec5189830c8d3fed08e92deda8681f0676aaea8a5 /drivers/gpu/drm/tegra/dc.c
parente2b80bac213cdfd443df9b6e1c769f98d0553c0c (diff)
parent64ea25c3bc86c05c7da6c683b86663f4c90158d6 (diff)
Merge tag 'drm/tegra/for-4.8-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Changes for v4.8-rc1 This set of changes contains a bunch of cleanups to the host1x driver as well as the addition of a pin controller for DPAUX, which is required by boards to configure the DPAUX pads in AUX mode (for DisplayPort) or I2C mode (for HDMI and DDC). Included is also a bit of rework of the SOR driver in preparation to add DisplayPort support as well as some refactoring and cleanup. Finally, all output drivers are converted to runtime PM, which greatly simplifies the handling of clocks and resets. * tag 'drm/tegra/for-4.8-rc1' of git://anongit.freedesktop.org/tegra/linux: (35 commits) drm/tegra: sor: Reject HDMI 2.0 modes drm/tegra: sor: Prepare for generic PM domain support drm/tegra: dsi: Prepare for generic PM domain support drm/tegra: sor: Make XBAR configurable per SoC drm/tegra: sor: Use sor1_src clock to set parent for HDMI dt-bindings: display: tegra: Add source clock for SOR drm/tegra: sor: Implement sor1_brick clock drm/tegra: sor: Implement runtime PM drm/tegra: hdmi: Implement runtime PM drm/tegra: dsi: Implement runtime PM drm/tegra: dc: Implement runtime PM drm/tegra: hdmi: Enable audio over HDMI drm/tegra: sor: Do not support deep color modes drm/tegra: sor: Extract tegra_sor_mode_set() drm/tegra: sor: Split out tegra_sor_apply_config() drm/tegra: sor: Rename tegra_sor_calc_config() drm/tegra: sor: Factor out tegra_sor_set_parent_clock() drm/tegra: dpaux: Add pinctrl support dt-bindings: Add bindings for Tegra DPAUX pinctrl driver drm/tegra: Prepare DPAUX for supporting generic PM domains ...
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r--drivers/gpu/drm/tegra/dc.c176
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
1221static void tegra_crtc_enable(struct drm_crtc *crtc) 1224static 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
1801cleanup: 1804cleanup:
@@ -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
2062static 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
2081static 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
2111static const struct dev_pm_ops tegra_dc_pm_ops = {
2112 SET_RUNTIME_PM_OPS(tegra_dc_suspend, tegra_dc_resume, NULL)
2113};
2114
2080struct platform_driver tegra_dc_driver = { 2115struct 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,