aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Reding <treding@nvidia.com>2015-01-28 08:43:05 -0500
committerThierry Reding <treding@nvidia.com>2015-04-02 12:46:21 -0400
commit42e9ce0523699b3f3383b7c5c0bcc2657a77d0ca (patch)
tree6b12a0c8d1152a7ee3e7b670e9236b311a08a8f6
parentb4a20144e0c0a45431695fa5968ce2ed8c9ce6ca (diff)
drm/tegra: dc: Implement hardware VBLANK counter
The display controller on Tegra can use syncpoints to count VBLANK events. syncpoints are 32-bit unsigned integers, so well suited as VBLANK counters. Signed-off-by: Thierry Reding <treding@nvidia.com>
-rw-r--r--drivers/gpu/drm/tegra/dc.c31
-rw-r--r--drivers/gpu/drm/tegra/dc.h7
-rw-r--r--drivers/gpu/drm/tegra/drm.c8
-rw-r--r--drivers/gpu/drm/tegra/drm.h2
4 files changed, 35 insertions, 13 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 8746a9ce6a8f..9e329465ab11 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -906,6 +906,15 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
906 return 0; 906 return 0;
907} 907}
908 908
909u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc)
910{
911 if (dc->syncpt)
912 return host1x_syncpt_read(dc->syncpt);
913
914 /* fallback to software emulated VBLANK counter */
915 return drm_crtc_vblank_count(&dc->base);
916}
917
909void tegra_dc_enable_vblank(struct tegra_dc *dc) 918void tegra_dc_enable_vblank(struct tegra_dc *dc)
910{ 919{
911 unsigned long value, flags; 920 unsigned long value, flags;
@@ -1632,7 +1641,6 @@ static int tegra_dc_init(struct host1x_client *client)
1632 struct tegra_drm *tegra = drm->dev_private; 1641 struct tegra_drm *tegra = drm->dev_private;
1633 struct drm_plane *primary = NULL; 1642 struct drm_plane *primary = NULL;
1634 struct drm_plane *cursor = NULL; 1643 struct drm_plane *cursor = NULL;
1635 unsigned int syncpt;
1636 u32 value; 1644 u32 value;
1637 int err; 1645 int err;
1638 1646
@@ -1701,13 +1709,15 @@ static int tegra_dc_init(struct host1x_client *client)
1701 } 1709 }
1702 1710
1703 /* initialize display controller */ 1711 /* initialize display controller */
1704 if (dc->pipe) 1712 if (dc->syncpt) {
1705 syncpt = SYNCPT_VBLANK1; 1713 u32 syncpt = host1x_syncpt_id(dc->syncpt);
1706 else
1707 syncpt = SYNCPT_VBLANK0;
1708 1714
1709 tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL); 1715 value = SYNCPT_CNTRL_NO_STALL;
1710 tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC); 1716 tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
1717
1718 value = SYNCPT_VSYNC_ENABLE | syncpt;
1719 tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
1720 }
1711 1721
1712 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT; 1722 value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
1713 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE); 1723 tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
@@ -1875,6 +1885,7 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)
1875 1885
1876static int tegra_dc_probe(struct platform_device *pdev) 1886static int tegra_dc_probe(struct platform_device *pdev)
1877{ 1887{
1888 unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
1878 const struct of_device_id *id; 1889 const struct of_device_id *id;
1879 struct resource *regs; 1890 struct resource *regs;
1880 struct tegra_dc *dc; 1891 struct tegra_dc *dc;
@@ -1966,6 +1977,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
1966 return err; 1977 return err;
1967 } 1978 }
1968 1979
1980 dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
1981 if (!dc->syncpt)
1982 dev_warn(&pdev->dev, "failed to allocate syncpoint\n");
1983
1969 platform_set_drvdata(pdev, dc); 1984 platform_set_drvdata(pdev, dc);
1970 1985
1971 return 0; 1986 return 0;
@@ -1976,6 +1991,8 @@ static int tegra_dc_remove(struct platform_device *pdev)
1976 struct tegra_dc *dc = platform_get_drvdata(pdev); 1991 struct tegra_dc *dc = platform_get_drvdata(pdev);
1977 int err; 1992 int err;
1978 1993
1994 host1x_syncpt_free(dc->syncpt);
1995
1979 err = host1x_client_unregister(&dc->client); 1996 err = host1x_client_unregister(&dc->client);
1980 if (err < 0) { 1997 if (err < 0) {
1981 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n", 1998 dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 705c93b00794..55792daabbb5 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -12,6 +12,8 @@
12 12
13#define DC_CMD_GENERAL_INCR_SYNCPT 0x000 13#define DC_CMD_GENERAL_INCR_SYNCPT 0x000
14#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001 14#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL 0x001
15#define SYNCPT_CNTRL_NO_STALL (1 << 8)
16#define SYNCPT_CNTRL_SOFT_RESET (1 << 0)
15#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002 17#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR 0x002
16#define DC_CMD_WIN_A_INCR_SYNCPT 0x008 18#define DC_CMD_WIN_A_INCR_SYNCPT 0x008
17#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009 19#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL 0x009
@@ -23,6 +25,7 @@
23#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019 25#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL 0x019
24#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a 26#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR 0x01a
25#define DC_CMD_CONT_SYNCPT_VSYNC 0x028 27#define DC_CMD_CONT_SYNCPT_VSYNC 0x028
28#define SYNCPT_VSYNC_ENABLE (1 << 8)
26#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031 29#define DC_CMD_DISPLAY_COMMAND_OPTION0 0x031
27#define DC_CMD_DISPLAY_COMMAND 0x032 30#define DC_CMD_DISPLAY_COMMAND 0x032
28#define DISP_CTRL_MODE_STOP (0 << 5) 31#define DISP_CTRL_MODE_STOP (0 << 5)
@@ -438,8 +441,4 @@
438#define DC_WINBUF_BD_UFLOW_STATUS 0xdca 441#define DC_WINBUF_BD_UFLOW_STATUS 0xdca
439#define DC_WINBUF_CD_UFLOW_STATUS 0xfca 442#define DC_WINBUF_CD_UFLOW_STATUS 0xfca
440 443
441/* synchronization points */
442#define SYNCPT_VBLANK0 26
443#define SYNCPT_VBLANK1 27
444
445#endif /* TEGRA_DC_H */ 444#endif /* TEGRA_DC_H */
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index 7ba7e2860ac8..8de17f9e5fe1 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -172,6 +172,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
172 */ 172 */
173 drm->irq_enabled = true; 173 drm->irq_enabled = true;
174 174
175 /* syncpoints are used for full 32-bit hardware VBLANK counters */
176 drm->vblank_disable_immediate = true;
177 drm->max_vblank_count = 0xffffffff;
178
175 err = drm_vblank_init(drm, drm->mode_config.num_crtc); 179 err = drm_vblank_init(drm, drm->mode_config.num_crtc);
176 if (err < 0) 180 if (err < 0)
177 goto device; 181 goto device;
@@ -813,12 +817,12 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
813static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) 817static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
814{ 818{
815 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe); 819 struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
820 struct tegra_dc *dc = to_tegra_dc(crtc);
816 821
817 if (!crtc) 822 if (!crtc)
818 return 0; 823 return 0;
819 824
820 /* TODO: implement real hardware counter using syncpoints */ 825 return tegra_dc_get_vblank_counter(dc);
821 return drm_crtc_vblank_count(crtc);
822} 826}
823 827
824static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) 828static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 8cb2dfeaa957..ded04e3473e9 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -106,6 +106,7 @@ struct tegra_output;
106 106
107struct tegra_dc { 107struct tegra_dc {
108 struct host1x_client client; 108 struct host1x_client client;
109 struct host1x_syncpt *syncpt;
109 struct device *dev; 110 struct device *dev;
110 spinlock_t lock; 111 spinlock_t lock;
111 112
@@ -180,6 +181,7 @@ struct tegra_dc_window {
180}; 181};
181 182
182/* from dc.c */ 183/* from dc.c */
184u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc);
183void tegra_dc_enable_vblank(struct tegra_dc *dc); 185void tegra_dc_enable_vblank(struct tegra_dc *dc);
184void tegra_dc_disable_vblank(struct tegra_dc *dc); 186void tegra_dc_disable_vblank(struct tegra_dc *dc);
185void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); 187void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);