Commit 19c800ca authored by Dave Airlie's avatar Dave Airlie

Merge tag 'drm/tegra/for-4.17-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next

drm/tegra: Changes for v4.17-rc1

This fixes mmap() for fbdev devices by providing a custom implementation
based on the KMS variant. This is a fairly exotic case these days, hence
why it is not flagged for stable.

There is also support for dedicating one of the overlay planes to serve
as a hardware cursor on older Tegra that did support hardware cursors
but not RGBA formats for it.

Planes will now also export the IN_FORMATS property by supporting the
various block-linear tiling modifiers for RGBA pixel formats.

Other than that, there's a bit of cleanup of DMA API abuse, use of the
private object infrastructure for global state (rather than subclassing
atomic state objects) and an implementation of ->{begin,end}_cpu_access
callbacks for PRIME exported buffers, which allow users to perform cache
maintenance on these buffers.

* tag 'drm/tegra/for-4.17-rc1' of git://anongit.freedesktop.org/tegra/linux:
  drm/tegra: prime: Implement ->{begin,end}_cpu_access()
  drm/tegra: gem: Map pages via the DMA API
  drm/tegra: hub: Use private object for global state
  drm/tegra: fb: Properly support linear modifier
  drm/tegra: plane: Support format modifiers
  drm/tegra: dc: Dedicate overlay plane to cursor on older Tegra's
  drm/tegra: plane: Make tegra_plane_get_overlap_index() static
  drm/tegra: fb: Implement ->fb_mmap() callback
  drm/tegra: gem: Make __tegra_gem_mmap() available more widely
  drm/tegra: gem: Reshuffle declarations
parents 4f6dd8d6 27e92f1f
...@@ -383,6 +383,12 @@ static const u32 tegra20_primary_formats[] = { ...@@ -383,6 +383,12 @@ static const u32 tegra20_primary_formats[] = {
DRM_FORMAT_XRGB8888, 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[] = { static const u32 tegra114_primary_formats[] = {
DRM_FORMAT_ARGB4444, DRM_FORMAT_ARGB4444,
DRM_FORMAT_ARGB1555, DRM_FORMAT_ARGB1555,
...@@ -430,6 +436,17 @@ static const u32 tegra124_primary_formats[] = { ...@@ -430,6 +436,17 @@ static const u32 tegra124_primary_formats[] = {
DRM_FORMAT_BGRX8888, 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, static int tegra_plane_atomic_check(struct drm_plane *plane,
struct drm_plane_state *state) struct drm_plane_state *state)
{ {
...@@ -596,6 +613,7 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, ...@@ -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; enum drm_plane_type type = DRM_PLANE_TYPE_PRIMARY;
struct tegra_plane *plane; struct tegra_plane *plane;
unsigned int num_formats; unsigned int num_formats;
const u64 *modifiers;
const u32 *formats; const u32 *formats;
int err; int err;
...@@ -610,10 +628,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm, ...@@ -610,10 +628,11 @@ static struct drm_plane *tegra_primary_plane_create(struct drm_device *drm,
num_formats = dc->soc->num_primary_formats; num_formats = dc->soc->num_primary_formats;
formats = dc->soc->primary_formats; formats = dc->soc->primary_formats;
modifiers = dc->soc->modifiers;
err = drm_universal_plane_init(drm, &plane->base, possible_crtcs, err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
&tegra_plane_funcs, formats, &tegra_plane_funcs, formats,
num_formats, NULL, type, NULL); num_formats, modifiers, type, NULL);
if (err < 0) { if (err < 0) {
kfree(plane); kfree(plane);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -864,11 +883,13 @@ static const u32 tegra124_overlay_formats[] = { ...@@ -864,11 +883,13 @@ static const u32 tegra124_overlay_formats[] = {
static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
struct tegra_dc *dc, struct tegra_dc *dc,
unsigned int index) unsigned int index,
bool cursor)
{ {
unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm); unsigned long possible_crtcs = tegra_plane_get_possible_crtcs(drm);
struct tegra_plane *plane; struct tegra_plane *plane;
unsigned int num_formats; unsigned int num_formats;
enum drm_plane_type type;
const u32 *formats; const u32 *formats;
int err; int err;
...@@ -883,10 +904,14 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm, ...@@ -883,10 +904,14 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
num_formats = dc->soc->num_overlay_formats; num_formats = dc->soc->num_overlay_formats;
formats = dc->soc->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, err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
&tegra_plane_funcs, formats, &tegra_plane_funcs, formats,
num_formats, NULL, num_formats, NULL, type, NULL);
DRM_PLANE_TYPE_OVERLAY, NULL);
if (err < 0) { if (err < 0) {
kfree(plane); kfree(plane);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -938,6 +963,7 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, ...@@ -938,6 +963,7 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,
struct tegra_dc *dc) struct tegra_dc *dc)
{ {
struct drm_plane *planes[2], *primary; struct drm_plane *planes[2], *primary;
unsigned int planes_num;
unsigned int i; unsigned int i;
int err; int err;
...@@ -945,8 +971,14 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm, ...@@ -945,8 +971,14 @@ static struct drm_plane *tegra_dc_add_planes(struct drm_device *drm,
if (IS_ERR(primary)) if (IS_ERR(primary))
return primary; return primary;
for (i = 0; i < 2; i++) { if (dc->soc->supports_cursor)
planes[i] = tegra_dc_overlay_plane_create(drm, dc, 1 + i); 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])) { if (IS_ERR(planes[i])) {
err = PTR_ERR(planes[i]); err = PTR_ERR(planes[i]);
...@@ -1704,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc, ...@@ -1704,31 +1736,6 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
drm_crtc_vblank_on(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, static void tegra_crtc_atomic_begin(struct drm_crtc *crtc,
struct drm_crtc_state *old_crtc_state) struct drm_crtc_state *old_crtc_state)
{ {
...@@ -1765,7 +1772,6 @@ static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, ...@@ -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 = { static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
.atomic_check = tegra_crtc_atomic_check,
.atomic_begin = tegra_crtc_atomic_begin, .atomic_begin = tegra_crtc_atomic_begin,
.atomic_flush = tegra_crtc_atomic_flush, .atomic_flush = tegra_crtc_atomic_flush,
.atomic_enable = tegra_crtc_atomic_enable, .atomic_enable = tegra_crtc_atomic_enable,
...@@ -1864,6 +1870,13 @@ static int tegra_dc_init(struct host1x_client *client) ...@@ -1864,6 +1870,13 @@ static int tegra_dc_init(struct host1x_client *client)
err = PTR_ERR(cursor); err = PTR_ERR(cursor);
goto cleanup; 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, err = drm_crtc_init_with_planes(drm, &dc->base, primary, cursor,
...@@ -1954,6 +1967,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = { ...@@ -1954,6 +1967,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
.primary_formats = tegra20_primary_formats, .primary_formats = tegra20_primary_formats,
.num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
.overlay_formats = tegra20_overlay_formats, .overlay_formats = tegra20_overlay_formats,
.modifiers = tegra20_modifiers,
}; };
static const struct tegra_dc_soc_info tegra30_dc_soc_info = { static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
...@@ -1970,6 +1984,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = { ...@@ -1970,6 +1984,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
.primary_formats = tegra20_primary_formats, .primary_formats = tegra20_primary_formats,
.num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats), .num_overlay_formats = ARRAY_SIZE(tegra20_overlay_formats),
.overlay_formats = tegra20_overlay_formats, .overlay_formats = tegra20_overlay_formats,
.modifiers = tegra20_modifiers,
}; };
static const struct tegra_dc_soc_info tegra114_dc_soc_info = { static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
...@@ -1986,6 +2001,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = { ...@@ -1986,6 +2001,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
.primary_formats = tegra114_primary_formats, .primary_formats = tegra114_primary_formats,
.num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
.overlay_formats = tegra114_overlay_formats, .overlay_formats = tegra114_overlay_formats,
.modifiers = tegra20_modifiers,
}; };
static const struct tegra_dc_soc_info tegra124_dc_soc_info = { static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
...@@ -2002,6 +2018,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = { ...@@ -2002,6 +2018,7 @@ static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
.primary_formats = tegra114_primary_formats, .primary_formats = tegra114_primary_formats,
.num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats), .num_overlay_formats = ARRAY_SIZE(tegra124_overlay_formats),
.overlay_formats = tegra114_overlay_formats, .overlay_formats = tegra114_overlay_formats,
.modifiers = tegra124_modifiers,
}; };
static const struct tegra_dc_soc_info tegra210_dc_soc_info = { static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
...@@ -2018,6 +2035,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = { ...@@ -2018,6 +2035,7 @@ static const struct tegra_dc_soc_info tegra210_dc_soc_info = {
.primary_formats = tegra114_primary_formats, .primary_formats = tegra114_primary_formats,
.num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats), .num_overlay_formats = ARRAY_SIZE(tegra114_overlay_formats),
.overlay_formats = tegra114_overlay_formats, .overlay_formats = tegra114_overlay_formats,
.modifiers = tegra124_modifiers,
}; };
static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = { static const struct tegra_windowgroup_soc tegra186_dc_wgrps[] = {
......
...@@ -66,6 +66,7 @@ struct tegra_dc_soc_info { ...@@ -66,6 +66,7 @@ struct tegra_dc_soc_info {
unsigned int num_primary_formats; unsigned int num_primary_formats;
const u32 *overlay_formats; const u32 *overlay_formats;
unsigned int num_overlay_formats; unsigned int num_overlay_formats;
const u64 *modifiers;
}; };
struct tegra_dc { struct tegra_dc {
......
...@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm, ...@@ -42,6 +42,10 @@ static int tegra_atomic_check(struct drm_device *drm,
if (err < 0) if (err < 0)
return err; return err;
err = tegra_display_hub_atomic_check(drm, state);
if (err < 0)
return err;
err = drm_atomic_normalize_zpos(drm, state); err = drm_atomic_normalize_zpos(drm, state);
if (err < 0) if (err < 0)
return err; return err;
...@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm, ...@@ -56,35 +60,6 @@ static int tegra_atomic_check(struct drm_device *drm,
return 0; 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 = { static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
.fb_create = tegra_fb_create, .fb_create = tegra_fb_create,
#ifdef CONFIG_DRM_FBDEV_EMULATION #ifdef CONFIG_DRM_FBDEV_EMULATION
...@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = { ...@@ -92,9 +67,6 @@ static const struct drm_mode_config_funcs tegra_drm_mode_config_funcs = {
#endif #endif
.atomic_check = tegra_atomic_check, .atomic_check = tegra_atomic_check,
.atomic_commit = drm_atomic_helper_commit, .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) static void tegra_atomic_commit_tail(struct drm_atomic_state *old_state)
......
...@@ -42,20 +42,6 @@ struct tegra_fbdev { ...@@ -42,20 +42,6 @@ struct tegra_fbdev {
}; };
#endif #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 tegra_drm {
struct drm_device *drm; struct drm_device *drm;
......
...@@ -55,6 +55,11 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, ...@@ -55,6 +55,11 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
uint64_t modifier = fb->base.modifier; uint64_t modifier = fb->base.modifier;
switch (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: case DRM_FORMAT_MOD_NVIDIA_TEGRA_TILED:
tiling->mode = TEGRA_BO_TILING_MODE_TILED; tiling->mode = TEGRA_BO_TILING_MODE_TILED;
tiling->value = 0; tiling->value = 0;
...@@ -91,9 +96,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer, ...@@ -91,9 +96,7 @@ int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
break; break;
default: default:
/* TODO: handle YUV formats? */ return -EINVAL;
*tiling = fb->planes[0]->tiling;
break;
} }
return 0; return 0;
...@@ -224,12 +227,28 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm, ...@@ -224,12 +227,28 @@ struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
} }
#ifdef CONFIG_DRM_FBDEV_EMULATION #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 = { static struct fb_ops tegra_fb_ops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
DRM_FB_HELPER_DEFAULT_OPS, DRM_FB_HELPER_DEFAULT_OPS,
.fb_fillrect = drm_fb_helper_sys_fillrect, .fb_fillrect = drm_fb_helper_sys_fillrect,
.fb_copyarea = drm_fb_helper_sys_copyarea, .fb_copyarea = drm_fb_helper_sys_copyarea,
.fb_imageblit = drm_fb_helper_sys_imageblit, .fb_imageblit = drm_fb_helper_sys_imageblit,
.fb_mmap = tegra_fb_mmap,
}; };
static int tegra_fbdev_probe(struct drm_fb_helper *helper, static int tegra_fbdev_probe(struct drm_fb_helper *helper,
......
...@@ -203,6 +203,8 @@ static struct tegra_bo *tegra_bo_alloc_object(struct drm_device *drm, ...@@ -203,6 +203,8 @@ static struct tegra_bo *tegra_bo_alloc_object(struct drm_device *drm,
static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo)
{ {
if (bo->pages) { 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); drm_gem_put_pages(&bo->gem, bo->pages, true, true);
sg_free_table(bo->sgt); sg_free_table(bo->sgt);
kfree(bo->sgt); kfree(bo->sgt);
...@@ -213,8 +215,7 @@ static void tegra_bo_free(struct drm_device *drm, struct tegra_bo *bo) ...@@ -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) static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
{ {
struct scatterlist *s; int err;
unsigned int i;
bo->pages = drm_gem_get_pages(&bo->gem); bo->pages = drm_gem_get_pages(&bo->gem);
if (IS_ERR(bo->pages)) if (IS_ERR(bo->pages))
...@@ -223,27 +224,26 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo) ...@@ -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->num_pages = bo->gem.size >> PAGE_SHIFT;
bo->sgt = drm_prime_pages_to_sg(bo->pages, bo->num_pages); 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; goto put_pages;
}
/* err = dma_map_sg(drm->dev, bo->sgt->sgl, bo->sgt->nents,
* Fake up the SG table so that dma_sync_sg_for_device() can be used DMA_BIDIRECTIONAL);
* to flush the pages associated with it. if (err == 0) {
* err = -EFAULT;
* TODO: Replace this by drm_clflash_sg() once it can be implemented goto free_sgt;
* 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);
return 0; return 0;
free_sgt:
sg_free_table(bo->sgt);
kfree(bo->sgt);
put_pages: put_pages:
drm_gem_put_pages(&bo->gem, bo->pages, false, false); 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) 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 = { ...@@ -459,8 +459,7 @@ const struct vm_operations_struct tegra_bo_vm_ops = {
.close = drm_gem_vm_close, .close = drm_gem_vm_close,
}; };
static int tegra_gem_mmap(struct drm_gem_object *gem, int __tegra_gem_mmap(struct drm_gem_object *gem, struct vm_area_struct *vma)
struct vm_area_struct *vma)
{ {
struct tegra_bo *bo = to_tegra_bo(gem); struct tegra_bo *bo = to_tegra_bo(gem);
...@@ -507,7 +506,7 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma) ...@@ -507,7 +506,7 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma)
gem = vma->vm_private_data; gem = vma->vm_private_data;
return tegra_gem_mmap(gem, vma); return __tegra_gem_mmap(gem, vma);
} }
static struct sg_table * static struct sg_table *
...@@ -569,6 +568,34 @@ static void tegra_gem_prime_release(struct dma_buf *buf) ...@@ -569,6 +568,34 @@ static void tegra_gem_prime_release(struct dma_buf *buf)
drm_gem_dmabuf_release(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, static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf,
unsigned long page) unsigned long page)
{ {
...@@ -600,7 +627,7 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma) ...@@ -600,7 +627,7 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
if (err < 0) if (err < 0)
return err; return err;
return tegra_gem_mmap(gem, vma); return __tegra_gem_mmap(gem, vma);
} }
static void *tegra_gem_prime_vmap(struct dma_buf *buf) 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 = { ...@@ -619,6 +646,8 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = {
.map_dma_buf = tegra_gem_prime_map_dma_buf, .map_dma_buf = tegra_gem_prime_map_dma_buf,
.unmap_dma_buf = tegra_gem_prime_unmap_dma_buf, .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf,
.release = tegra_gem_prime_release, .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, .map_atomic = tegra_gem_prime_kmap_atomic,
.unmap_atomic = tegra_gem_prime_kunmap_atomic, .unmap_atomic = tegra_gem_prime_kunmap_atomic,
.map = tegra_gem_prime_kmap, .map = tegra_gem_prime_kmap,
......
...@@ -68,10 +68,11 @@ void tegra_bo_free_object(struct drm_gem_object *gem); ...@@ -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, int tegra_bo_dumb_create(struct drm_file *file, struct drm_device *drm,
struct drm_mode_create_dumb *args); 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; 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 dma_buf *tegra_gem_prime_export(struct drm_device *drm,
struct drm_gem_object *gem, struct drm_gem_object *gem,
int flags); int flags);
......
...@@ -49,6 +49,17 @@ static const u32 tegra_shared_plane_formats[] = { ...@@ -49,6 +49,17 @@ static const u32 tegra_shared_plane_formats[] = {
DRM_FORMAT_YUV422, 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, static inline unsigned int tegra_plane_offset(struct tegra_plane *plane,
unsigned int offset) unsigned int offset)
{ {
...@@ -527,6 +538,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, ...@@ -527,6 +538,7 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
unsigned int possible_crtcs = 0x7; unsigned int possible_crtcs = 0x7;
struct tegra_shared_plane *plane; struct tegra_shared_plane *plane;
unsigned int num_formats; unsigned int num_formats;
const u64 *modifiers;
struct drm_plane *p; struct drm_plane *p;
const u32 *formats; const u32 *formats;
int err; int err;
...@@ -545,10 +557,11 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, ...@@ -545,10 +557,11 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
num_formats = ARRAY_SIZE(tegra_shared_plane_formats); num_formats = ARRAY_SIZE(tegra_shared_plane_formats);
formats = tegra_shared_plane_formats; formats = tegra_shared_plane_formats;
modifiers = tegra_shared_plane_modifiers;
err = drm_universal_plane_init(drm, p, possible_crtcs, err = drm_universal_plane_init(drm, p, possible_crtcs,
&tegra_plane_funcs, formats, &tegra_plane_funcs, formats,
num_formats, NULL, type, NULL); num_formats, modifiers, type, NULL);
if (err < 0) { if (err < 0) {
kfree(plane); kfree(plane);
return ERR_PTR(err); return ERR_PTR(err);
...@@ -560,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, ...@@ -560,6 +573,89 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
return p; 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) static void tegra_display_hub_update(struct tegra_dc *dc)
{ {
u32 value; u32 value;
...@@ -585,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc) ...@@ -585,26 +681,28 @@ static void tegra_display_hub_update(struct tegra_dc *dc)
void tegra_display_hub_atomic_commit(struct drm_device *drm, void tegra_display_hub_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *state) struct drm_atomic_state *state)
{ {
struct tegra_atomic_state *s = to_tegra_atomic_state(state);
struct tegra_drm *tegra = drm->dev_private; struct tegra_drm *tegra = drm->dev_private;
struct tegra_display_hub *hub = tegra->hub; struct tegra_display_hub *hub = tegra->hub;
struct tegra_display_hub_state *hub_state;
struct device *dev = hub->client.dev; struct device *dev = hub->client.dev;
int err; int err;
if (s->clk_disp) { hub_state = tegra_display_hub_get_state(hub, state);
err = clk_set_rate(s->clk_disp, s->rate);
if (hub_state->clk) {
err = clk_set_rate(hub_state->clk, hub_state->rate);
if (err < 0) if (err < 0)
dev_err(dev, "failed to set rate of %pC to %lu Hz\n", 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) if (err < 0)
dev_err(dev, "failed to set parent of %pC to %pC: %d\n", 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) if (hub_state->dc)
tegra_display_hub_update(s->dc); tegra_display_hub_update(hub_state->dc);
} }
static int tegra_display_hub_init(struct host1x_client *client) static int tegra_display_hub_init(struct host1x_client *client)
...@@ -612,6 +710,14 @@ 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 tegra_display_hub *hub = to_tegra_display_hub(client);
struct drm_device *drm = dev_get_drvdata(client->parent); struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private; 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; tegra->hub = hub;
...@@ -623,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client) ...@@ -623,6 +729,7 @@ static int tegra_display_hub_exit(struct host1x_client *client)
struct drm_device *drm = dev_get_drvdata(client->parent); struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private; struct tegra_drm *tegra = drm->dev_private;
drm_atomic_private_obj_fini(&tegra->hub->base);
tegra->hub = NULL; tegra->hub = NULL;
return 0; return 0;
......
...@@ -41,6 +41,7 @@ struct tegra_display_hub_soc { ...@@ -41,6 +41,7 @@ struct tegra_display_hub_soc {
}; };
struct tegra_display_hub { struct tegra_display_hub {
struct drm_private_obj base;
struct host1x_client client; struct host1x_client client;
struct clk *clk_disp; struct clk *clk_disp;
struct clk *clk_dsc; struct clk *clk_dsc;
...@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client) ...@@ -57,6 +58,20 @@ to_tegra_display_hub(struct host1x_client *client)
return container_of(client, struct tegra_display_hub, 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_dc;
struct tegra_plane; struct tegra_plane;
...@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm, ...@@ -68,6 +83,8 @@ struct drm_plane *tegra_shared_plane_create(struct drm_device *drm,
unsigned int wgrp, unsigned int wgrp,
unsigned int index); 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, void tegra_display_hub_atomic_commit(struct drm_device *drm,
struct drm_atomic_state *state); struct drm_atomic_state *state);
......
...@@ -68,6 +68,21 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane, ...@@ -68,6 +68,21 @@ static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
kfree(state); 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 = { const struct drm_plane_funcs tegra_plane_funcs = {
.update_plane = drm_atomic_helper_update_plane, .update_plane = drm_atomic_helper_update_plane,
.disable_plane = drm_atomic_helper_disable_plane, .disable_plane = drm_atomic_helper_disable_plane,
...@@ -75,6 +90,7 @@ const struct drm_plane_funcs tegra_plane_funcs = { ...@@ -75,6 +90,7 @@ const struct drm_plane_funcs tegra_plane_funcs = {
.reset = tegra_plane_reset, .reset = tegra_plane_reset,
.atomic_duplicate_state = tegra_plane_atomic_duplicate_state, .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
.atomic_destroy_state = tegra_plane_atomic_destroy_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, int tegra_plane_state_add(struct tegra_plane *plane,
...@@ -296,8 +312,8 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha) ...@@ -296,8 +312,8 @@ int tegra_plane_format_get_alpha(unsigned int opaque, unsigned int *alpha)
return -EINVAL; return -EINVAL;
} }
unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane, static unsigned int tegra_plane_get_overlap_index(struct tegra_plane *plane,
struct tegra_plane *other) struct tegra_plane *other)
{ {
unsigned int index = 0, i; unsigned int index = 0, i;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment