diff options
author | Dave Airlie <airlied@redhat.com> | 2015-04-08 11:13:06 +1000 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2015-04-08 11:13:06 +1000 |
commit | 1ddd36eda1a577837826a8e465ab9d43b024d382 (patch) | |
tree | cf655491cf727e057a5448be043778991c3fd597 /drivers/gpu/drm/tegra/dc.c | |
parent | 67a0375f5e27c1daa50554de7a01fdfa4a9ea0bf (diff) | |
parent | 535a65db484ff4e4654a037f2ea7e1ff21431b77 (diff) | |
download | blackbird-op-linux-1ddd36eda1a577837826a8e465ab9d43b024d382.tar.gz blackbird-op-linux-1ddd36eda1a577837826a8e465ab9d43b024d382.zip |
Merge tag 'drm/tegra/for-4.1-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next
drm/tegra: Changes for v4.1-rc1
Perhaps the most noteworthy change in this set is the implementation of
a hardware VBLANK counter using host1x syncpoints. The SOR registers can
now be dumped via debugfs, which can be useful while debugging. The IOVA
address space maintained by the driver can also be dumped via debugfs.
Other than than, these changes are mostly cleanup work, such as making
register names more consistent or removing unused code (that was left
over after the atomic mode-setting conversion). There's also a fix for
eDP that makes the driver cope with firmware that already initialized
the display (such as the firmware on the Tegra-based Chromebooks).
* tag 'drm/tegra/for-4.1-rc1' of git://anongit.freedesktop.org/tegra/linux:
drm/tegra: sor: Reset during initialization
drm/tegra: gem: Return 64-bit offset for mmap(2)
drm/tegra: hdmi: Name register fields consistently
drm/tegra: hdmi: Resets are synchronous
drm/tegra: dc: Document tegra_dc_state_setup_clock()
drm/tegra: dc: Remove unused callbacks
drm/tegra: dc: Remove unused function
drm/tegra: dc: Use base atomic state helpers
drm/atomic: Add helpers for state-subclassing drivers
drm/tegra: dc: Implement hardware VBLANK counter
gpu: host1x: Export host1x_syncpt_read()
drm/tegra: sor: Dump registers via debugfs
drm/tegra: sor: Registers are 32-bit
drm/tegra: Provide debugfs file for the IOVA space
drm/tegra: dc: Check for valid parent clock
Diffstat (limited to 'drivers/gpu/drm/tegra/dc.c')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 99 |
1 files changed, 57 insertions, 42 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index b7f781573b15..a287e4fec865 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -425,8 +425,8 @@ static void tegra_plane_reset(struct drm_plane *plane) { struct tegra_plane_state *state; - if (plane->state && plane->state->fb) - drm_framebuffer_unreference(plane->state->fb); + if (plane->state) + __drm_atomic_helper_plane_destroy_state(plane, plane->state); kfree(plane->state); plane->state = NULL; @@ -443,12 +443,14 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla struct tegra_plane_state *state = to_tegra_plane_state(plane->state); struct tegra_plane_state *copy; - copy = kmemdup(state, sizeof(*state), GFP_KERNEL); + copy = kmalloc(sizeof(*copy), GFP_KERNEL); if (!copy) return NULL; - if (copy->base.fb) - drm_framebuffer_reference(copy->base.fb); + __drm_atomic_helper_plane_duplicate_state(plane, ©->base); + copy->tiling = state->tiling; + copy->format = state->format; + copy->swap = state->swap; return ©->base; } @@ -456,9 +458,7 @@ static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_pla static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, struct drm_plane_state *state) { - if (state->fb) - drm_framebuffer_unreference(state->fb); - + __drm_atomic_helper_plane_destroy_state(plane, state); kfree(state); } @@ -908,6 +908,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; @@ -995,6 +1004,9 @@ static void tegra_crtc_reset(struct drm_crtc *crtc) { struct tegra_dc_state *state; + if (crtc->state) + __drm_atomic_helper_crtc_destroy_state(crtc, crtc->state); + kfree(crtc->state); crtc->state = NULL; @@ -1011,14 +1023,15 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) struct tegra_dc_state *state = to_dc_state(crtc->state); struct tegra_dc_state *copy; - copy = kmemdup(state, sizeof(*state), GFP_KERNEL); + copy = kmalloc(sizeof(*copy), GFP_KERNEL); if (!copy) return NULL; - copy->base.mode_changed = false; - copy->base.active_changed = false; - copy->base.planes_changed = false; - copy->base.event = NULL; + __drm_atomic_helper_crtc_duplicate_state(crtc, ©->base); + copy->clk = state->clk; + copy->pclk = state->pclk; + copy->div = state->div; + copy->planes = state->planes; return ©->base; } @@ -1026,6 +1039,7 @@ tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc) static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state) { + __drm_atomic_helper_crtc_destroy_state(crtc, state); kfree(state); } @@ -1152,26 +1166,18 @@ static int tegra_dc_set_timings(struct tegra_dc *dc, return 0; } -int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent, - unsigned long pclk, unsigned int div) -{ - u32 value; - int err; - - err = clk_set_parent(dc->clk, parent); - if (err < 0) { - dev_err(dc->dev, "failed to set parent clock: %d\n", err); - return err; - } - - DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk), div); - - value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1; - tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL); - - return 0; -} - +/** + * tegra_dc_state_setup_clock - check clock settings and store them in atomic + * state + * @dc: display controller + * @crtc_state: CRTC atomic state + * @clk: parent clock for display controller + * @pclk: pixel clock + * @div: shift clock divider + * + * Returns: + * 0 on success or a negative error-code on failure. + */ int tegra_dc_state_setup_clock(struct tegra_dc *dc, struct drm_crtc_state *crtc_state, struct clk *clk, unsigned long pclk, @@ -1179,6 +1185,9 @@ int tegra_dc_state_setup_clock(struct tegra_dc *dc, { struct tegra_dc_state *state = to_dc_state(crtc_state); + if (!clk_has_parent(dc->clk, clk)) + return -EINVAL; + state->clk = clk; state->pclk = pclk; state->div = div; @@ -1294,9 +1303,7 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc) static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { .disable = tegra_crtc_disable, .mode_fixup = tegra_crtc_mode_fixup, - .mode_set = drm_helper_crtc_mode_set, .mode_set_nofb = tegra_crtc_mode_set_nofb, - .mode_set_base = drm_helper_crtc_mode_set_base, .prepare = tegra_crtc_prepare, .commit = tegra_crtc_commit, .atomic_check = tegra_crtc_atomic_check, @@ -1631,7 +1638,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; @@ -1700,13 +1706,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); @@ -1874,6 +1882,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; @@ -1965,6 +1974,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; @@ -1975,6 +1988,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", |