diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 07:59:23 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-04-02 07:59:23 -0700 |
commit | 320b164abb32db876866a4ff8c2cb710524ac6ea (patch) | |
tree | 1f79119cde6e24c9f1d01fb1e51252bca7c4cdd5 /drivers/gpu/drm/tegra | |
parent | 0adb32858b0bddf4ada5f364a84ed60b196dbcda (diff) | |
parent | 694f54f680f7fd8e9561928fbfc537d9afbc3d79 (diff) |
Merge tag 'drm-for-v4.17' of git://people.freedesktop.org/~airlied/linux
Pull drm updates from Dave Airlie:
"Cannonlake and Vega12 support are probably the two major things. This
pull lacks nouveau, Ben had some unforseen leave and a few other
blockers so we'll see how things look or maybe leave it for this merge
window.
core:
- Device links to handle sound/gpu pm dependency
- Color encoding/range properties
- Plane clipping into plane check helper
- Backlight helpers
- DP TP4 + HBR3 helper support
amdgpu:
- Vega12 support
- Enable DC by default on all supported GPUs
- Powerplay restructuring and cleanup
- DC bandwidth calc updates
- DC backlight on pre-DCE11
- TTM backing store dropping support
- SR-IOV fixes
- Adding "wattman" like functionality
- DC crc support
- Improved DC dual-link handling
amdkfd:
- GPUVM support for dGPU
- KFD events for dGPU
- Enable PCIe atomics for dGPUs
- HSA process eviction support
- Live-lock fixes for process eviction
- VM page table allocation fix for large-bar systems
panel:
- Raydium RM68200
- AUO G104SN02 V2
- KEO TX31D200VM0BAA
- ARM Versatile panels
i915:
- Cannonlake support enabled
- AUX-F port support added
- Icelake base enabling until internal milestone of forcewake support
- Query uAPI interface (used for GPU topology information currently)
- Compressed framebuffer support for sprites
- kmem cache shrinking when GPU is idle
- Avoid boosting GPU when waited item is being processed already
- Avoid retraining LSPCON link unnecessarily
- Decrease request signaling latency
- Deprecation of I915_SET_COLORKEY_NONE
- Kerneldoc and compiler warning cleanup for upcoming CI enforcements
- Full range ycbcr toggling
- HDCP support
i915/gvt:
- Big refactor for shadow ppgtt
- KBL context save/restore via LRI cmd (Weinan)
- Properly unmap dma for guest page (Changbin)
vmwgfx:
- Lots of various improvements
etnaviv:
- Use the drm gpu scheduler
- prep work for GC7000L support
vc4:
- fix alpha blending
- Expose perf counters to userspace
pl111:
- Bandwidth checking/limiting
- Versatile panel support
sun4i:
- A83T HDMI support
- A80 support
- YUV plane support
- H3/H5 HDMI support
omapdrm:
- HPD support for DVI connector
- remove lots of static variables
msm:
- DSI updates from 10nm / SDM845
- fix for race condition with a3xx/a4xx fence completion irq
- some refactoring/prep work for eventual a6xx support (ie. when we
have a userspace)
- a5xx debugfs enhancements
- some mdp5 fixes/cleanups to prepare for eventually merging
writeback
- support (ie. when we have a userspace)
tegra:
- mmap() fixes for fbdev devices
- Overlay plane for hw cursor fix
- dma-buf cache maintenance support
mali-dp:
- YUV->RGB conversion support
rockchip:
- rk3399/chromebook fixes and improvements
rcar-du:
- LVDS support move to drm bridge
- DT bindings for R8A77995
- Driver/DT support for R8A77970
tilcdc:
- DRM panel support"
* tag 'drm-for-v4.17' of git://people.freedesktop.org/~airlied/linux: (1646 commits)
drm/i915: Fix hibernation with ACPI S0 target state
drm/i915/execlists: Use a locked clear_bit() for synchronisation with interrupt
drm/i915: Specify which engines to reset following semaphore/event lockups
drm/i915/dp: Write to SET_POWER dpcd to enable MST hub.
drm/amdkfd: Use ordered workqueue to restore processes
drm/amdgpu: Fix acquiring VM on large-BAR systems
drm/amd/pp: clean header file hwmgr.h
drm/amd/pp: use mlck_table.count for array loop index limit
drm: Fix uabi regression by allowing garbage mode->type from userspace
drm/amdgpu: Add an ATPX quirk for hybrid laptop
drm/amdgpu: fix spelling mistake: "asssert" -> "assert"
drm/amd/pp: Add new asic support in pp_psm.c
drm/amd/pp: Clean up powerplay code on Vega12
drm/amd/pp: Add smu irq handlers for legacy asics
drm/amd/pp: Fix set wrong temperature range on smu7
drm/amdgpu: Don't change preferred domian when fallback GTT v5
drm/vmwgfx: Bump version patchlevel and date
drm/vmwgfx: use monotonic event timestamps
drm/vmwgfx: Unpin the screen object backup buffer when not used
drm/vmwgfx: Stricter count of legacy surface device resources
...
Diffstat (limited to 'drivers/gpu/drm/tegra')
-rw-r--r-- | drivers/gpu/drm/tegra/dc.c | 84 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/dc.h | 1 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.c | 36 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/drm.h | 14 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/fb.c | 25 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.c | 69 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/gem.h | 5 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.c | 125 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/hub.h | 17 | ||||
-rw-r--r-- | drivers/gpu/drm/tegra/plane.c | 28 |
10 files changed, 282 insertions, 122 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index 90b25ce363ca..9f83a65b5ea9 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -383,6 +383,12 @@ static const u32 tegra20_primary_formats[] = { DRM_FORMAT_XRGB8888, }; +static const u64 tegra20_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED, + DRM_FORMAT_MOD_INVALID +}; + static const u32 tegra114_primary_formats[] = { DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB1555, @@ -430,6 +436,17 @@ static const u32 tegra124_primary_formats[] = { DRM_FORMAT_BGRX8888, }; +static const u64 tegra124_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), + DRM_FORMAT_MOD_INVALID +}; + static int tegra_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { @@ -596,6 +613,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY; struct tegra_plane *plane; unsigned int num_formats; + const u64 *modifiers; const u32 *formats; int err; @@ -610,10 +628,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, num_formats = dc->soc->num_primary_formats; formats = dc->soc->primary_formats; + modifiers = dc->soc->modifiers; err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, type, NULL); + num_formats, modifiers, type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -864,11 +883,13 @@ static const u32 tegra124_overlay_formats[] = { static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, struct tegra_dc *dc, - unsigned int index) + unsigned int index, + bool cursor) { unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm); struct tegra_plane *plane; unsigned int num_formats; + enum drm_plane_type type; const u32 *formats; int err; @@ -883,10 +904,14 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, num_formats = dc->soc->num_overlay_formats; formats = dc->soc->overlay_formats; + if (!cursor) + type = DRM_PLANE_TYPE_OVERLAY; + else + type = DRM_PLANE_TYPE_CURSOR; + err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, - DRM_PLANE_TYPE_OVERLAY, NULL); + num_formats, NULL, type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -938,6 +963,7 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc) { struct drm_plane *planes[2], *primary; + unsigned int planes_num; unsigned int i; int err; @@ -945,8 +971,14 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, if (IS_ERR(primary)) return primary; - for (i = 0; i < 2; i++) { - planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i); + if (dc->soc->supports_cursor) + planes_num = 2; + else + planes_num = 1; + + for (i = 0; i < planes_num; i++) { + planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i, + false); if (IS_ERR(planes[i])) { err = PTR_ERR(planes[i]); @@ -1359,7 +1391,7 @@ static u32 tegra_dc_get_vblank_counter(struct drm_crtc *crtc) return host1x_syncpt_read(dc->syncpt); /* fallback to software emulated VBLANK counter */ - return drm_crtc_vblank_count(&dc->base); + return (u32)drm_crtc_vblank_count(&dc->base); } static int tegra_dc_enable_vblank(struct drm_crtc *crtc) @@ -1704,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, drm_crtc_vblank_on(crtc); } -static int tegra_crtc_atomic_check(struct drm_crtc *crtc, - struct drm_crtc_state *state) -{ - struct tegra_atomic_state *s = to_tegra_atomic_state(state->state); - struct tegra_dc_state *tegra = to_dc_state(state); - - /* - * The display hub display clock needs to be fed by the display clock - * with the highest frequency to ensure proper functioning of all the - * displays. - * - * Note that this isn't used before Tegra186, but it doesn't hurt and - * conditionalizing it would make the code less clean. - */ - if (state->active) { - if (!s->clk_disp || tegra->pclk > s->rate) { - s->dc = to_tegra_dc(crtc); - s->clk_disp = s->dc->clk; - s->rate = tegra->pclk; - } - } - - return 0; -} - static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -1765,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, } static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = { - .atomic_check = tegra_crtc_atomic_check, .atomic_begin = tegra_crtc_atomic_begin, .atomic_flush = tegra_crtc_atomic_flush, .atomic_enable = tegra_crtc_atomic_enable, @@ -1864,6 +1870,13 @@ static int tegra_dc_init(struct host1x_client *client) err = PTR_ERR(cursor); goto cleanup; } + } else { + /* dedicate one overlay to mouse cursor */ + cursor = tegra_dc_overlay_plane_create(drm, dc, 2, true); + if (IS_ERR(cursor)) { + err = PTR_ERR(cursor); + goto cleanup; + } } err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor, @@ -1964,6 +1977,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { .primary_formats = tegra20_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), .overlay_formats = tegra20_overlay_formats, + .modifiers = tegra20_modifiers, }; static const struct tegra_dc_soc_info tegra30_dc_soc_info = { @@ -1980,6 +1994,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { .primary_formats = tegra20_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), .overlay_formats = tegra20_overlay_formats, + .modifiers = tegra20_modifiers, }; static const struct tegra_dc_soc_info tegra114_dc_soc_info = { @@ -1996,6 +2011,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { .primary_formats = tegra114_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), .overlay_formats = tegra114_overlay_formats, + .modifiers = tegra20_modifiers, }; static const struct tegra_dc_soc_info tegra124_dc_soc_info = { @@ -2012,6 +2028,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { .primary_formats = tegra124_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats), .overlay_formats = tegra124_overlay_formats, + .modifiers = tegra124_modifiers, }; static const struct tegra_dc_soc_info tegra210_dc_soc_info = { @@ -2028,6 +2045,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = { .primary_formats = tegra114_primary_formats, .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), .overlay_formats = tegra114_overlay_formats, + .modifiers = tegra124_modifiers, }; static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h index 096a81ad6d8d..d2b50d32de4d 100644 --- a/drivers/gpu/drm/tegra/dc.h +++ b/drivers/gpu/drm/tegra/dc.h @@ -66,6 +66,7 @@ struct tegra_dc_soc_info { unsigned int num_primary_formats; const u32 *overlay_formats; unsigned int num_overlay_formats; + const u64 *modifiers; }; struct tegra_dc { diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 7fcf4a242840..7afe2f635f74 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm, if (err < 0) return err; + err = tegra_display_hub_atomic_check(drm, state); + if (err < 0) + return err; + err = drm_atomic_normalize_zpos(drm, state); if (err < 0) return err; @@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm, return 0; } -static struct drm_atomic_state * -tegra_atomic_state_alloc(struct drm_device *drm) -{ - struct tegra_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); - - if (!state || drm_atomic_state_init(drm, &state->base) < 0) { - kfree(state); - return NULL; - } - - return &state->base; -} - -static void tegra_atomic_state_clear(struct drm_atomic_state *state) -{ - struct tegra_atomic_state *tegra = to_tegra_atomic_state(state); - - drm_atomic_state_default_clear(state); - tegra->clk_disp = NULL; - tegra->dc = NULL; - tegra->rate = 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_config_funcs = { .fb_create = tegra_fb_create, #ifdef CONFIG_DRM_FBDEV_EMULATION @@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { #endif .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) diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h index 73b661ce7086..4f41aaec8530 100644 --- a/drivers/gpu/drm/tegra/drm.h +++ b/drivers/gpu/drm/tegra/drm.h @@ -42,20 +42,6 @@ struct tegra_fbdev { }; #endif -struct tegra_atomic_state { - struct drm_atomic_state base; - - struct clk *clk_disp; - struct tegra_dc *dc; - unsigned long rate; -}; - -static inline struct tegra_atomic_state * -to_tegra_atomic_state(struct drm_atomic_state *state) -{ - return container_of(state, struct tegra_atomic_state, base); -} - struct tegra_drm { struct drm_device *drm; diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c index 001cb77e2f59..e69434909a42 100644 --- a/drivers/gpu/drm/tegra/fb.c +++ b/drivers/gpu/drm/tegra/fb.c @@ -55,6 +55,11 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, uint64_t modifier = fb->base.modifier; switch (modifier) { + case DRM_FORMAT_MOD_LINEAR: + tiling->mode = TEGRA_BO_TILING_MODE_PITCH; + tiling->value = 0; + break; + case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED: tiling->mode = TEGRA_BO_TILING_MODE_TILED; tiling->value = 0; @@ -91,9 +96,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, break; default: - /* TODO: handle YUV formats? */ - *tiling = fb->planes[0]->tiling; - break; + return -EINVAL; } return 0; @@ -224,12 +227,28 @@ unreference: } #ifdef CONFIG_DRM_FBDEV_EMULATION +static int tegra_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct drm_fb_helper *helper = info->par; + struct tegra_bo *bo; + int err; + + bo = tegra_fb_get_plane(helper->fb, 0); + + err = drm_gem_mmap_obj(&bo->gem, bo->gem.size, vma); + if (err < 0) + return err; + + return __tegra_gem_mmap(&bo->gem, vma); +} + static struct fb_ops tegra_fb_ops = { .owner = THIS_MODULE, DRM_FB_HELPER_DEFAULT_OPS, .fb_fillrect = drm_fb_helper_sys_fillrect, .fb_copyarea = drm_fb_helper_sys_copyarea, .fb_imageblit = drm_fb_helper_sys_imageblit, + .fb_mmap = tegra_fb_mmap, }; static int tegra_fbdev_probe(struct drm_fb_helper *helper, diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index 49b9bf28f872..8b0b4ff64bb4 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -203,6 +203,8 @@ free: static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) { if (bo->pages) { + dma_unmap_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_BIDIRECTIONAL); drm_gem_put_pages(&bo->gem, bo->pages, true, true); sg_free_table(bo->sgt); kfree(bo->sgt); @@ -213,8 +215,7 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) { - struct scatterlist *s; - unsigned int i; + int err; bo->pages = drm_gem_get_pages(&bo->gem); if (IS_ERR(bo->pages)) @@ -223,27 +224,26 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) bo->num_pages = bo->gem.size >> PAGE_SHIFT; bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); - if (IS_ERR(bo->sgt)) + if (IS_ERR(bo->sgt)) { + err = PTR_ERR(bo->sgt); goto put_pages; + } - /* - * Fake up the SG table so that dma_sync_sg_for_device() can be used - * to flush the pages associated with it. - * - * TODO: Replace this by drm_clflash_sg() once it can be implemented - * without relying on symbols that are not exported. - */ - for_each_sg(bo->sgt->sgl, s, bo->sgt->nents, i) - sg_dma_address(s) = sg_phys(s); - - dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents, - DMA_TO_DEVICE); + err = dma_map_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_BIDIRECTIONAL); + if (err == 0) { + err = -EFAULT; + goto free_sgt; + } return 0; +free_sgt: + sg_free_table(bo->sgt); + kfree(bo->sgt); put_pages: drm_gem_put_pages(&bo->gem, bo->pages, false, false); - return PTR_ERR(bo->sgt); + return err; } static int tegra_bo_alloc(struct drm_device *drm, struct tegra_bo *bo) @@ -459,8 +459,7 @@ const struct vm_operations_struct tegra_bo_vm_ops = { .close = drm_gem_vm_close, }; -static int tegra_gem_mmap(struct drm_gem_object *gem, - struct vm_area_struct *vma) +int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma) { struct tegra_bo *bo = to_tegra_bo(gem); @@ -507,7 +506,7 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) gem = vma->vm_private_data; - return tegra_gem_mmap(gem, vma); + return __tegra_gem_mmap(gem, vma); } static struct sg_table * @@ -569,6 +568,34 @@ static void tegra_gem_prime_release(struct dma_buf *buf) drm_gem_dmabuf_release(buf); } +static int tegra_gem_prime_begin_cpu_access(struct dma_buf *buf, + enum dma_data_direction direction) +{ + struct drm_gem_object *gem = buf->priv; + struct tegra_bo *bo = to_tegra_bo(gem); + struct drm_device *drm = gem->dev; + + if (bo->pages) + dma_sync_sg_for_cpu(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_FROM_DEVICE); + + return 0; +} + +static int tegra_gem_prime_end_cpu_access(struct dma_buf *buf, + enum dma_data_direction direction) +{ + struct drm_gem_object *gem = buf->priv; + struct tegra_bo *bo = to_tegra_bo(gem); + struct drm_device *drm = gem->dev; + + if (bo->pages) + dma_sync_sg_for_device(drm->dev, bo->sgt->sgl, bo->sgt->nents, + DMA_TO_DEVICE); + + return 0; +} + static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf, unsigned long page) { @@ -600,7 +627,7 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) if (err < 0) return err; - return tegra_gem_mmap(gem, vma); + return __tegra_gem_mmap(gem, vma); } static void *tegra_gem_prime_vmap(struct dma_buf *buf) @@ -619,6 +646,8 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = { .map_dma_buf = tegra_gem_prime_map_dma_buf, .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, .release = tegra_gem_prime_release, + .begin_cpu_access = tegra_gem_prime_begin_cpu_access, + .end_cpu_access = tegra_gem_prime_end_cpu_access, .map_atomic = tegra_gem_prime_kmap_atomic, .unmap_atomic = tegra_gem_prime_kunmap_atomic, .map = tegra_gem_prime_kmap, diff --git a/drivers/gpu/drm/tegra/gem.h b/drivers/gpu/drm/tegra/gem.h index 8eb9fd24ef0e..6bd7dd7e55b4 100644 --- a/drivers/gpu/drm/tegra/gem.h +++ b/drivers/gpu/drm/tegra/gem.h @@ -68,10 +68,11 @@ void tegra_bo_free_object(struct drm_gem_object *gem); int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm, struct drm_mode_create_dumb *args); -int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); - extern const struct vm_operations_struct tegra_bo_vm_ops; +int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma); +int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma); + struct dma_buf *tegra_gem_prime_export(struct drm_device *drm, struct drm_gem_object *gem, int flags); diff --git a/drivers/gpu/drm/tegra/hub.c b/drivers/gpu/drm/tegra/hub.c index e10a47d57313..9a3f23d4780f 100644 --- a/drivers/gpu/drm/tegra/hub.c +++ b/drivers/gpu/drm/tegra/hub.c @@ -49,6 +49,17 @@ static const u32 tegra_shared_plane_formats[] = { DRM_FORMAT_YUV422, }; +static const u64 tegra_shared_plane_modifiers[] = { + DRM_FORMAT_MOD_LINEAR, + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(0), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(1), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(2), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(3), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(4), + DRM_FORMAT_MOD_NVIDIA_16BX2_BLOCK(5), + DRM_FORMAT_MOD_INVALID +}; + static inline unsigned int tegra_plane_offset(struct tegra_plane *plane, unsigned int offset) { @@ -527,6 +538,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, unsigned int possible_crtcs = 0x7; struct tegra_shared_plane *plane; unsigned int num_formats; + const u64 *modifiers; struct drm_plane *p; const u32 *formats; int err; @@ -545,10 +557,11 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, num_formats = ARRAY_SIZE(tegra_shared_plane_formats); formats = tegra_shared_plane_formats; + modifiers = tegra_shared_plane_modifiers; err = drm_universal_plane_init(drm, p, possible_crtcs, &tegra_plane_funcs, formats, - num_formats, NULL, type, NULL); + num_formats, modifiers, type, NULL); if (err < 0) { kfree(plane); return ERR_PTR(err); @@ -560,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, return p; } +static struct drm_private_state * +tegra_display_hub_duplicate_state(struct drm_private_obj *obj) +{ + struct tegra_display_hub_state *state; + + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + + return &state->base; +} + +static void tegra_display_hub_destroy_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + struct tegra_display_hub_state *hub_state = + to_tegra_display_hub_state(state); + + kfree(hub_state); +} + +static const struct drm_private_state_funcs tegra_display_hub_state_funcs = { + .atomic_duplicate_state = tegra_display_hub_duplicate_state, + .atomic_destroy_state = tegra_display_hub_destroy_state, +}; + +static struct tegra_display_hub_state * +tegra_display_hub_get_state(struct tegra_display_hub *hub, + struct drm_atomic_state *state) +{ + struct drm_device *drm = dev_get_drvdata(hub->client.parent); + struct drm_private_state *priv; + + WARN_ON(!drm_modeset_is_locked(&drm->mode_config.connection_mutex)); + + priv = drm_atomic_get_private_obj_state(state, &hub->base); + if (IS_ERR(priv)) + return ERR_CAST(priv); + + return to_tegra_display_hub_state(priv); +} + +int tegra_display_hub_atomic_check(struct drm_device *drm, + struct drm_atomic_state *state) +{ + struct tegra_drm *tegra = drm->dev_private; + struct tegra_display_hub_state *hub_state; + struct drm_crtc_state *old, *new; + struct drm_crtc *crtc; + unsigned int i; + + if (!tegra->hub) + return 0; + + hub_state = tegra_display_hub_get_state(tegra->hub, state); + if (IS_ERR(hub_state)) + return PTR_ERR(hub_state); + + /* + * The display hub display clock needs to be fed by the display clock + * with the highest frequency to ensure proper functioning of all the + * displays. + * + * Note that this isn't used before Tegra186, but it doesn't hurt and + * conditionalizing it would make the code less clean. + */ + for_each_oldnew_crtc_in_state(state, crtc, old, new, i) { + struct tegra_dc_state *dc = to_dc_state(new); + + if (new->active) { + if (!hub_state->clk || dc->pclk > hub_state->rate) { + hub_state->dc = to_tegra_dc(dc->base.crtc); + hub_state->clk = hub_state->dc->clk; + hub_state->rate = dc->pclk; + } + } + } + + return 0; +} + static void tegra_display_hub_update(struct tegra_dc *dc) { u32 value; @@ -585,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc) void tegra_display_hub_atomic_commit(struct drm_device *drm, struct drm_atomic_state *state) { - struct tegra_atomic_state *s = to_tegra_atomic_state(state); struct tegra_drm *tegra = drm->dev_private; struct tegra_display_hub *hub = tegra->hub; + struct tegra_display_hub_state *hub_state; struct device *dev = hub->client.dev; int err; - if (s->clk_disp) { - err = clk_set_rate(s->clk_disp, s->rate); + hub_state = tegra_display_hub_get_state(hub, state); + + if (hub_state->clk) { + err = clk_set_rate(hub_state->clk, hub_state->rate); if (err < 0) dev_err(dev, "failed to set rate of %pC to %lu Hz\n", - s->clk_disp, s->rate); + hub_state->clk, hub_state->rate); - err = clk_set_parent(hub->clk_disp, s->clk_disp); + err = clk_set_parent(hub->clk_disp, hub_state->clk); if (err < 0) dev_err(dev, "failed to set parent of %pC to %pC: %d\n", - hub->clk_disp, s->clk_disp, err); + hub->clk_disp, hub_state->clk, err); } - if (s->dc) - tegra_display_hub_update(s->dc); + if (hub_state->dc) + tegra_display_hub_update(hub_state->dc); } static int tegra_display_hub_init(struct host1x_client *client) @@ -612,6 +710,14 @@ static int tegra_display_hub_init(struct host1x_client *client) struct tegra_display_hub *hub = to_tegra_display_hub(client); struct drm_device *drm = dev_get_drvdata(client->parent); struct tegra_drm *tegra = drm->dev_private; + struct tegra_display_hub_state *state; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + drm_atomic_private_obj_init(&hub->base, &state->base, + &tegra_display_hub_state_funcs); tegra->hub = hub; @@ -623,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client) struct drm_device *drm = dev_get_drvdata(client->parent); struct tegra_drm *tegra = drm->dev_private; + drm_atomic_private_obj_fini(&tegra->hub->base); tegra->hub = NULL; return 0; diff --git a/drivers/gpu/drm/tegra/hub.h b/drivers/gpu/drm/tegra/hub.h index 890a47cd05c3..85b8bf41a395 100644 --- a/drivers/gpu/drm/tegra/hub.h +++ b/drivers/gpu/drm/tegra/hub.h @@ -41,6 +41,7 @@ struct tegra_display_hub_soc { }; struct tegra_display_hub { + struct drm_private_obj base; struct host1x_client client; struct clk *clk_disp; struct clk *clk_dsc; @@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client) return container_of(client, struct tegra_display_hub, client); } +struct tegra_display_hub_state { + struct drm_private_state base; + + struct tegra_dc *dc; + unsigned long rate; + struct clk *clk; +}; + +static inline struct tegra_display_hub_state * +to_tegra_display_hub_state(struct drm_private_state *priv) +{ + return container_of(priv, struct tegra_display_hub_state, base); +} + struct tegra_dc; struct tegra_plane; @@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, unsigned int wgrp, unsigned int index); +int tegra_display_hub_atomic_check(struct drm_device *drm, + struct drm_atomic_state *state); void tegra_display_hub_atomic_commit(struct drm_device *drm, struct drm_atomic_state *state); diff --git a/drivers/gpu/drm/tegra/plane.c b/drivers/gpu/drm/tegra/plane.c index 94dac79ac3c9..176ef46c615c 100644 --- a/drivers/gpu/drm/tegra/plane.c +++ b/drivers/gpu/drm/tegra/plane.c @@ -68,6 +68,21 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, kfree(state); } +static bool tegra_plane_format_mod_supported(struct drm_plane *plane, + uint32_t format, + uint64_t modifier) +{ + const struct drm_format_info *info = drm_format_info(format); + + if (modifier == DRM_FORMAT_MOD_LINEAR) + return true; + + if (info->num_planes == 1) + return true; + + return false; +} + const struct drm_plane_funcs tegra_plane_funcs = { .update_plane = drm_atomic_helper_update_plane, .disable_plane = drm_atomic_helper_disable_plane, @@ -75,6 +90,7 @@ const struct drm_plane_funcs tegra_plane_funcs = { .reset = tegra_plane_reset, .atomic_duplicate_state = tegra_plane_atomic_duplicate_state, .atomic_destroy_state = tegra_plane_atomic_destroy_state, + .format_mod_supported = tegra_plane_format_mod_supported, }; int tegra_plane_state_add(struct tegra_plane *plane, @@ -82,7 +98,6 @@ int tegra_plane_state_add(struct tegra_plane *plane, { struct drm_crtc_state *crtc_state; struct tegra_dc_state *tegra; - struct drm_rect clip; int err; /* Propagate errors from allocation or locking failures. */ @@ -90,13 +105,8 @@ int tegra_plane_state_add(struct tegra_plane *plane, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - clip.x1 = 0; - clip.y1 = 0; - clip.x2 = crtc_state->mode.hdisplay; - clip.y2 = crtc_state->mode.vdisplay; - /* Check plane state for visibility and calculate clipping bounds */ - err = drm_atomic_helper_check_plane_state(state, crtc_state, &clip, + err = drm_atomic_helper_check_plane_state(state, crtc_state, 0, INT_MAX, true, true); if (err < 0) return err; @@ -306,8 +316,8 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha) return -EINVAL; } -unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, - struct tegra_plane *other) +static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, + struct tegra_plane *other) { unsigned int index = 0, i; |