diff options
author | Thierry Reding <treding@nvidia.com> | 2015-01-28 08:43:05 -0500 |
---|---|---|
committer | Thierry Reding <treding@nvidia.com> | 2015-04-02 12:46:21 -0400 |
commit | 42e9ce0523699b3f3383b7c5c0bcc2657a77d0ca (patch) | |
tree | 6b12a0c8d1152a7ee3e7b670e9236b311a08a8f6 | |
parent | b4a20144e0c0a45431695fa5968ce2ed8c9ce6ca (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.c | 31 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 7 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 8 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 2 |
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 | ||
909 | u32 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 | |||
909 | void tegra_dc_enable_vblank(struct tegra_dc *dc) | 918 | void 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 | ||
1876 | static int tegra_dc_probe(struct platform_device *pdev) | 1886 | static 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, | |||
813 | static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe) | 817 | static 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 | ||
824 | static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe) | 828 | static 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 | ||
107 | struct tegra_dc { | 107 | struct 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 */ |
184 | u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc); | ||
183 | void tegra_dc_enable_vblank(struct tegra_dc *dc); | 185 | void tegra_dc_enable_vblank(struct tegra_dc *dc); |
184 | void tegra_dc_disable_vblank(struct tegra_dc *dc); | 186 | void tegra_dc_disable_vblank(struct tegra_dc *dc); |
185 | void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); | 187 | void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file); |