Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 42e9ce05 authored by Thierry Reding's avatar Thierry Reding
Browse files

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: default avatarThierry Reding <treding@nvidia.com>
parent b4a20144
Loading
Loading
Loading
Loading
+24 −7
Original line number Diff line number Diff line
@@ -906,6 +906,15 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
	return 0;
}

u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc)
{
	if (dc->syncpt)
		return host1x_syncpt_read(dc->syncpt);

	/* fallback to software emulated VBLANK counter */
	return drm_crtc_vblank_count(&dc->base);
}

void tegra_dc_enable_vblank(struct tegra_dc *dc)
{
	unsigned long value, flags;
@@ -1632,7 +1641,6 @@ static int tegra_dc_init(struct host1x_client *client)
	struct tegra_drm *tegra = drm->dev_private;
	struct drm_plane *primary = NULL;
	struct drm_plane *cursor = NULL;
	unsigned int syncpt;
	u32 value;
	int err;

@@ -1701,13 +1709,15 @@ static int tegra_dc_init(struct host1x_client *client)
	}

	/* initialize display controller */
	if (dc->pipe)
		syncpt = SYNCPT_VBLANK1;
	else
		syncpt = SYNCPT_VBLANK0;
	if (dc->syncpt) {
		u32 syncpt = host1x_syncpt_id(dc->syncpt);

	tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
	tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
		value = SYNCPT_CNTRL_NO_STALL;
		tegra_dc_writel(dc, value, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);

		value = SYNCPT_VSYNC_ENABLE | syncpt;
		tegra_dc_writel(dc, value, DC_CMD_CONT_SYNCPT_VSYNC);
	}

	value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
	tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
@@ -1875,6 +1885,7 @@ static int tegra_dc_parse_dt(struct tegra_dc *dc)

static int tegra_dc_probe(struct platform_device *pdev)
{
	unsigned long flags = HOST1X_SYNCPT_CLIENT_MANAGED;
	const struct of_device_id *id;
	struct resource *regs;
	struct tegra_dc *dc;
@@ -1966,6 +1977,10 @@ static int tegra_dc_probe(struct platform_device *pdev)
		return err;
	}

	dc->syncpt = host1x_syncpt_request(&pdev->dev, flags);
	if (!dc->syncpt)
		dev_warn(&pdev->dev, "failed to allocate syncpoint\n");

	platform_set_drvdata(pdev, dc);

	return 0;
@@ -1976,6 +1991,8 @@ static int tegra_dc_remove(struct platform_device *pdev)
	struct tegra_dc *dc = platform_get_drvdata(pdev);
	int err;

	host1x_syncpt_free(dc->syncpt);

	err = host1x_client_unregister(&dc->client);
	if (err < 0) {
		dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
+3 −4
Original line number Diff line number Diff line
@@ -12,6 +12,8 @@

#define DC_CMD_GENERAL_INCR_SYNCPT		0x000
#define DC_CMD_GENERAL_INCR_SYNCPT_CNTRL	0x001
#define  SYNCPT_CNTRL_NO_STALL   (1 << 8)
#define  SYNCPT_CNTRL_SOFT_RESET (1 << 0)
#define DC_CMD_GENERAL_INCR_SYNCPT_ERROR	0x002
#define DC_CMD_WIN_A_INCR_SYNCPT		0x008
#define DC_CMD_WIN_A_INCR_SYNCPT_CNTRL		0x009
@@ -23,6 +25,7 @@
#define DC_CMD_WIN_C_INCR_SYNCPT_CNTRL		0x019
#define DC_CMD_WIN_C_INCR_SYNCPT_ERROR		0x01a
#define DC_CMD_CONT_SYNCPT_VSYNC		0x028
#define  SYNCPT_VSYNC_ENABLE (1 << 8)
#define DC_CMD_DISPLAY_COMMAND_OPTION0		0x031
#define DC_CMD_DISPLAY_COMMAND			0x032
#define DISP_CTRL_MODE_STOP (0 << 5)
@@ -438,8 +441,4 @@
#define DC_WINBUF_BD_UFLOW_STATUS		0xdca
#define DC_WINBUF_CD_UFLOW_STATUS		0xfca

/* synchronization points */
#define SYNCPT_VBLANK0 26
#define SYNCPT_VBLANK1 27

#endif /* TEGRA_DC_H */
+6 −2
Original line number Diff line number Diff line
@@ -172,6 +172,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
	 */
	drm->irq_enabled = true;

	/* syncpoints are used for full 32-bit hardware VBLANK counters */
	drm->vblank_disable_immediate = true;
	drm->max_vblank_count = 0xffffffff;

	err = drm_vblank_init(drm, drm->mode_config.num_crtc);
	if (err < 0)
		goto device;
@@ -813,12 +817,12 @@ static struct drm_crtc *tegra_crtc_from_pipe(struct drm_device *drm,
static u32 tegra_drm_get_vblank_counter(struct drm_device *drm, int pipe)
{
	struct drm_crtc *crtc = tegra_crtc_from_pipe(drm, pipe);
	struct tegra_dc *dc = to_tegra_dc(crtc);

	if (!crtc)
		return 0;

	/* TODO: implement real hardware counter using syncpoints */
	return drm_crtc_vblank_count(crtc);
	return tegra_dc_get_vblank_counter(dc);
}

static int tegra_drm_enable_vblank(struct drm_device *drm, int pipe)
+2 −0
Original line number Diff line number Diff line
@@ -106,6 +106,7 @@ struct tegra_output;

struct tegra_dc {
	struct host1x_client client;
	struct host1x_syncpt *syncpt;
	struct device *dev;
	spinlock_t lock;

@@ -180,6 +181,7 @@ struct tegra_dc_window {
};

/* from dc.c */
u32 tegra_dc_get_vblank_counter(struct tegra_dc *dc);
void tegra_dc_enable_vblank(struct tegra_dc *dc);
void tegra_dc_disable_vblank(struct tegra_dc *dc);
void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);