diff options
Diffstat (limited to 'drivers/gpu/drm/tegra/drm.c')
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 177 |
1 files changed, 87 insertions, 90 deletions
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 52552b9b89ef..d50bddb2e447 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -33,97 +33,91 @@ struct tegra_drm_file { struct mutex lock; }; -static void tegra_atomic_schedule(struct tegra_drm *tegra, - struct drm_atomic_state *state) +static int tegra_atomic_check(struct drm_device *drm, + struct drm_atomic_state *state) { - tegra->commit.state = state; - schedule_work(&tegra->commit.work); -} + int err; -static void tegra_atomic_complete(struct tegra_drm *tegra, - struct drm_atomic_state *state) -{ - struct drm_device *drm = tegra->drm; + err = drm_atomic_helper_check_modeset(drm, state); + if (err < 0) + return err; - /* - * Everything below can be run asynchronously without the need to grab - * any modeset locks at all under one condition: It must be guaranteed - * that the asynchronous work has either been cancelled (if the driver - * supports it, which at least requires that the framebuffers get - * cleaned up with drm_atomic_helper_cleanup_planes()) or completed - * before the new state gets committed on the software side with - * drm_atomic_helper_swap_state(). - * - * This scheme allows new atomic state updates to be prepared and - * checked in parallel to the asynchronous completion of the previous - * update. Which is important since compositors need to figure out the - * composition of the next frame right after having submitted the - * current layout. - */ + err = drm_atomic_normalize_zpos(drm, state); + if (err < 0) + return err; - drm_atomic_helper_commit_modeset_disables(drm, state); - drm_atomic_helper_commit_modeset_enables(drm, state); - drm_atomic_helper_commit_planes(drm, state, - DRM_PLANE_COMMIT_ACTIVE_ONLY); + err = drm_atomic_helper_check_planes(drm, state); + if (err < 0) + return err; - drm_atomic_helper_wait_for_vblanks(drm, state); + if (state->legacy_cursor_update) + state->async_update = !drm_atomic_helper_async_check(drm, state); - drm_atomic_helper_cleanup_planes(drm, state); - drm_atomic_state_put(state); + return 0; } -static void tegra_atomic_work(struct work_struct *work) +static struct drm_atomic_state * +tegra_atomic_state_alloc(struct drm_device *drm) { - struct tegra_drm *tegra = container_of(work, struct tegra_drm, - commit.work); + struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state || drm_atomic_state_init(drm, &state->base) < 0) { + kfree(state); + return NULL; + } - tegra_atomic_complete(tegra, tegra->commit.state); + return &state->base; } -static int tegra_atomic_commit(struct drm_device *drm, - struct drm_atomic_state *state, bool nonblock) +static void tegra_atomic_state_clear(struct drm_atomic_state *state) { - struct tegra_drm *tegra = drm->dev_private; - int err; - - err = drm_atomic_helper_prepare_planes(drm, state); - if (err) - return err; + struct tegra_atomic_state *tegra = to_tegra_atomic_state(state); - /* serialize outstanding nonblocking commits */ - mutex_lock(&tegra->commit.lock); - flush_work(&tegra->commit.work); - - /* - * This is the point of no return - everything below never fails except - * when the hw goes bonghits. Which means we can commit the new state on - * the software side now. - */ - - err = drm_atomic_helper_swap_state(state, true); - if (err) { - mutex_unlock(&tegra->commit.lock); - drm_atomic_helper_cleanup_planes(drm, state); - return err; - } - - drm_atomic_state_get(state); - if (nonblock) - tegra_atomic_schedule(tegra, state); - else - tegra_atomic_complete(tegra, state); + drm_atomic_state_default_clear(state); + tegra->clk_disp = NULL; + tegra->dc = NULL; + tegra->rate = 0; +} - mutex_unlock(&tegra->commit.lock); - return 0; +static void tegra_atomic_state_free(struct drm_atomic_state *state) +{ + drm_atomic_state_default_release(state); + kfree(state); } -static const struct drm_mode_config_funcs tegra_drm_mode_funcs = { +static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { .fb_create = tegra_fb_create, #ifdef CONFIG_DRM_FBDEV_EMULATION - .output_poll_changed = tegra_fb_output_poll_changed, + .output_poll_changed = drm_fb_helper_output_poll_changed, #endif - .atomic_check = drm_atomic_helper_check, - .atomic_commit = tegra_atomic_commit, + .atomic_check = tegra_atomic_check, + .atomic_commit = drm_atomic_helper_commit, + .atomic_state_alloc = tegra_atomic_state_alloc, + .atomic_state_clear = tegra_atomic_state_clear, + .atomic_state_free = tegra_atomic_state_free, +}; + +static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state) +{ + struct drm_device *drm = old_state->dev; + struct tegra_drm *tegra = drm->dev_private; + + if (tegra->hub) { + drm_atomic_helper_commit_modeset_disables(drm, old_state); + tegra_display_hub_atomic_commit(drm, old_state); + drm_atomic_helper_commit_planes(drm, old_state, 0); + drm_atomic_helper_commit_modeset_enables(drm, old_state); + drm_atomic_helper_commit_hw_done(old_state); + drm_atomic_helper_wait_for_vblanks(drm, old_state); + drm_atomic_helper_cleanup_planes(drm, old_state); + } else { + drm_atomic_helper_commit_tail_rpm(old_state); + } +} + +static const struct drm_mode_config_helper_funcs +tegra_drm_mode_config_helpers = { + .atomic_commit_tail = tegra_atomic_commit_tail, }; static int tegra_drm_load(struct drm_device *drm, unsigned long flags) @@ -172,9 +166,6 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) mutex_init(&tegra->clients_lock); INIT_LIST_HEAD(&tegra->clients); - mutex_init(&tegra->commit.lock); - INIT_WORK(&tegra->commit.work, tegra_atomic_work); - drm->dev_private = tegra; tegra->drm = drm; @@ -188,7 +179,8 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) drm->mode_config.allow_fb_modifiers = true; - drm->mode_config.funcs = &tegra_drm_mode_funcs; + drm->mode_config.funcs = &tegra_drm_mode_config_funcs; + drm->mode_config.helper_private = &tegra_drm_mode_config_helpers; err = tegra_drm_fb_prepare(drm); if (err < 0) @@ -200,6 +192,12 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) if (err < 0) goto fbdev; + if (tegra->hub) { + err = tegra_display_hub_prepare(tegra->hub); + if (err < 0) + goto device; + } + /* * We don't use the drm_irq_install() helpers provided by the DRM * core, so we need to set this manually in order to allow the @@ -212,16 +210,19 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags) err = drm_vblank_init(drm, drm->mode_config.num_crtc); if (err < 0) - goto device; + goto hub; drm_mode_config_reset(drm); err = tegra_drm_fb_init(drm); if (err < 0) - goto device; + goto hub; return 0; +hub: + if (tegra->hub) + tegra_display_hub_cleanup(tegra->hub); device: host1x_device_exit(device); fbdev: @@ -286,15 +287,6 @@ static void tegra_drm_context_free(struct tegra_drm_context *context) kfree(context); } -static void tegra_drm_lastclose(struct drm_device *drm) -{ -#ifdef CONFIG_DRM_FBDEV_EMULATION - struct tegra_drm *tegra = drm->dev_private; - - tegra_fbdev_restore_mode(tegra->fbdev); -#endif -} - static struct host1x_bo * host1x_bo_lookup(struct drm_file *file, u32 handle) { @@ -660,7 +652,8 @@ static int tegra_syncpt_wait(struct drm_device *drm, void *data, if (!sp) return -EINVAL; - return host1x_syncpt_wait(sp, args->thresh, args->timeout, + return host1x_syncpt_wait(sp, args->thresh, + msecs_to_jiffies(args->timeout), &args->value); } @@ -1100,7 +1093,7 @@ static struct drm_driver tegra_drm_driver = { .unload = tegra_drm_unload, .open = tegra_drm_open, .postclose = tegra_drm_postclose, - .lastclose = tegra_drm_lastclose, + .lastclose = drm_fb_helper_lastclose, #if defined(CONFIG_DEBUG_FS) .debugfs_init = tegra_debugfs_init, @@ -1148,8 +1141,7 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra, return 0; } -void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, - dma_addr_t *dma) +void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *dma) { struct iova *alloc; void *virt; @@ -1317,6 +1309,10 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra210-sor", }, { .compatible = "nvidia,tegra210-sor1", }, { .compatible = "nvidia,tegra210-vic", }, + { .compatible = "nvidia,tegra186-display", }, + { .compatible = "nvidia,tegra186-dc", }, + { .compatible = "nvidia,tegra186-sor", }, + { .compatible = "nvidia,tegra186-sor1", }, { .compatible = "nvidia,tegra186-vic", }, { /* sentinel */ } }; @@ -1332,6 +1328,7 @@ static struct host1x_driver host1x_drm_driver = { }; static struct platform_driver * const drivers[] = { + &tegra_display_hub_driver, &tegra_dc_driver, &tegra_hdmi_driver, &tegra_dsi_driver, |