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
...
This commit is contained in:
+51
-33
@@ -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[] = {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
+49
-20
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
+116
-9
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user