Skip to content

Commit

Permalink
Merge tag 'drm/tegra/for-4.18-rc1' of git://anongit.freedesktop.org/t…
Browse files Browse the repository at this point in the history
…egra/linux into drm-next

drm/tegra: Changes for v4.18-rc1

This set enables IOMMU support in the gr2d and gr3d drivers and adds
support for the zpos property on older Tegra generations. It also
enables scaling filters and incorporates some rework to eliminate a
private wrapper around struct drm_framebuffer.

The remainder is mostly a random assortment of fixes and cleanups, as
well as some preparatory work for destaging the userspace ABI, which
is almost ready and is targetted for v4.19-rc1.

Signed-off-by: Dave Airlie <airlied@redhat.com>

# gpg: Signature made Sat 19 May 2018 08:31:00 AEST
# gpg:                using RSA key DD23ACD77F3EB3A1
# gpg: Can't check signature: public key not found
Link: https://patchwork.freedesktop.org/patch/msgid/20180518224523.30982-1-thierry.reding@gmail.com
  • Loading branch information
Dave Airlie committed May 22, 2018
2 parents ddfd0f4 + 6134534 commit ce234cc
Show file tree
Hide file tree
Showing 28 changed files with 1,138 additions and 538 deletions.
300 changes: 219 additions & 81 deletions drivers/gpu/drm/tegra/dc.c

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions drivers/gpu/drm/tegra/dc.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ struct tegra_dc_soc_info {
bool supports_interlacing;
bool supports_cursor;
bool supports_block_linear;
bool supports_blending;
bool has_legacy_blending;
unsigned int pitch_align;
bool has_powergate;
bool coupled_pm;
Expand All @@ -67,6 +67,8 @@ struct tegra_dc_soc_info {
const u32 *overlay_formats;
unsigned int num_overlay_formats;
const u64 *modifiers;
bool has_win_a_without_filters;
bool has_win_c_without_vert_filter;
};

struct tegra_dc {
Expand All @@ -92,7 +94,7 @@ struct tegra_dc {

const struct tegra_dc_soc_info *soc;

struct iommu_domain *domain;
struct iommu_group *group;
};

static inline struct tegra_dc *
Expand Down Expand Up @@ -553,6 +555,9 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define THREAD_NUM(x) (((x) & 0x1f) << 1)
#define THREAD_GROUP_ENABLE (1 << 0)

#define DC_WIN_H_FILTER_P(p) (0x601 + (p))
#define DC_WIN_V_FILTER_P(p) (0x619 + (p))

#define DC_WIN_CSC_YOF 0x611
#define DC_WIN_CSC_KYRGB 0x612
#define DC_WIN_CSC_KUR 0x613
Expand All @@ -566,6 +571,8 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define H_DIRECTION (1 << 0)
#define V_DIRECTION (1 << 2)
#define COLOR_EXPAND (1 << 6)
#define H_FILTER (1 << 8)
#define V_FILTER (1 << 10)
#define CSC_ENABLE (1 << 18)
#define WIN_ENABLE (1 << 30)

Expand Down
133 changes: 65 additions & 68 deletions drivers/gpu/drm/tegra/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
goto free;
}

err = iova_cache_get();
if (err < 0)
goto domain;

geometry = &tegra->domain->geometry;
gem_start = geometry->aperture_start;
gem_end = geometry->aperture_end - CARVEOUT_SZ;
Expand Down Expand Up @@ -191,11 +195,14 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
drm_mode_config_cleanup(drm);

if (tegra->domain) {
iommu_domain_free(tegra->domain);
drm_mm_takedown(&tegra->mm);
mutex_destroy(&tegra->mm_lock);
drm_mm_takedown(&tegra->mm);
put_iova_domain(&tegra->carveout.domain);
iova_cache_put();
}
domain:
if (tegra->domain)
iommu_domain_free(tegra->domain);
free:
kfree(tegra);
return err;
Expand All @@ -217,10 +224,11 @@ static void tegra_drm_unload(struct drm_device *drm)
return;

if (tegra->domain) {
iommu_domain_free(tegra->domain);
drm_mm_takedown(&tegra->mm);
mutex_destroy(&tegra->mm_lock);
drm_mm_takedown(&tegra->mm);
put_iova_domain(&tegra->carveout.domain);
iova_cache_put();
iommu_domain_free(tegra->domain);
}

kfree(tegra);
Expand Down Expand Up @@ -300,46 +308,15 @@ static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
return 0;
}

static int host1x_waitchk_copy_from_user(struct host1x_waitchk *dest,
struct drm_tegra_waitchk __user *src,
struct drm_file *file)
{
u32 cmdbuf;
int err;

err = get_user(cmdbuf, &src->handle);
if (err < 0)
return err;

err = get_user(dest->offset, &src->offset);
if (err < 0)
return err;

err = get_user(dest->syncpt_id, &src->syncpt);
if (err < 0)
return err;

err = get_user(dest->thresh, &src->thresh);
if (err < 0)
return err;

dest->bo = host1x_bo_lookup(file, cmdbuf);
if (!dest->bo)
return -ENOENT;

return 0;
}

int tegra_drm_submit(struct tegra_drm_context *context,
struct drm_tegra_submit *args, struct drm_device *drm,
struct drm_file *file)
{
struct host1x_client *client = &context->client->base;
unsigned int num_cmdbufs = args->num_cmdbufs;
unsigned int num_relocs = args->num_relocs;
unsigned int num_waitchks = args->num_waitchks;
struct drm_tegra_cmdbuf __user *user_cmdbufs;
struct drm_tegra_reloc __user *user_relocs;
struct drm_tegra_waitchk __user *user_waitchks;
struct drm_tegra_syncpt __user *user_syncpt;
struct drm_tegra_syncpt syncpt;
struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
Expand All @@ -351,7 +328,6 @@ int tegra_drm_submit(struct tegra_drm_context *context,

user_cmdbufs = u64_to_user_ptr(args->cmdbufs);
user_relocs = u64_to_user_ptr(args->relocs);
user_waitchks = u64_to_user_ptr(args->waitchks);
user_syncpt = u64_to_user_ptr(args->syncpts);

/* We don't yet support other than one syncpt_incr struct per submit */
Expand All @@ -363,21 +339,20 @@ int tegra_drm_submit(struct tegra_drm_context *context,
return -EINVAL;

job = host1x_job_alloc(context->channel, args->num_cmdbufs,
args->num_relocs, args->num_waitchks);
args->num_relocs);
if (!job)
return -ENOMEM;

job->num_relocs = args->num_relocs;
job->num_waitchk = args->num_waitchks;
job->client = (u32)args->context;
job->class = context->client->base.class;
job->client = client;
job->class = client->class;
job->serialize = true;

/*
* Track referenced BOs so that they can be unreferenced after the
* submission is complete.
*/
num_refs = num_cmdbufs + num_relocs * 2 + num_waitchks;
num_refs = num_cmdbufs + num_relocs * 2;

refs = kmalloc_array(num_refs, sizeof(*refs), GFP_KERNEL);
if (!refs) {
Expand Down Expand Up @@ -438,13 +413,13 @@ int tegra_drm_submit(struct tegra_drm_context *context,
struct host1x_reloc *reloc;
struct tegra_bo *obj;

err = host1x_reloc_copy_from_user(&job->relocarray[num_relocs],
err = host1x_reloc_copy_from_user(&job->relocs[num_relocs],
&user_relocs[num_relocs], drm,
file);
if (err < 0)
goto fail;

reloc = &job->relocarray[num_relocs];
reloc = &job->relocs[num_relocs];
obj = host1x_to_tegra_bo(reloc->cmdbuf.bo);
refs[num_refs++] = &obj->gem;

Expand All @@ -468,30 +443,6 @@ int tegra_drm_submit(struct tegra_drm_context *context,
}
}

/* copy and resolve waitchks from submit */
while (num_waitchks--) {
struct host1x_waitchk *wait = &job->waitchk[num_waitchks];
struct tegra_bo *obj;

err = host1x_waitchk_copy_from_user(
wait, &user_waitchks[num_waitchks], file);
if (err < 0)
goto fail;

obj = host1x_to_tegra_bo(wait->bo);
refs[num_refs++] = &obj->gem;

/*
* The unaligned offset will cause an unaligned write during
* of the waitchks patching, corrupting the commands stream.
*/
if (wait->offset & 3 ||
wait->offset >= obj->gem.size) {
err = -EINVAL;
goto fail;
}
}

if (copy_from_user(&syncpt, user_syncpt, sizeof(syncpt))) {
err = -EFAULT;
goto fail;
Expand Down Expand Up @@ -1101,6 +1052,52 @@ int tegra_drm_unregister_client(struct tegra_drm *tegra,
return 0;
}

struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client,
bool shared)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private;
struct iommu_group *group = NULL;
int err;

if (tegra->domain) {
group = iommu_group_get(client->dev);
if (!group) {
dev_err(client->dev, "failed to get IOMMU group\n");
return ERR_PTR(-ENODEV);
}

if (!shared || (shared && (group != tegra->group))) {
err = iommu_attach_group(tegra->domain, group);
if (err < 0) {
iommu_group_put(group);
return ERR_PTR(err);
}

if (shared && !tegra->group)
tegra->group = group;
}
}

return group;
}

void host1x_client_iommu_detach(struct host1x_client *client,
struct iommu_group *group)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
struct tegra_drm *tegra = drm->dev_private;

if (group) {
if (group == tegra->group) {
iommu_detach_group(tegra->domain, group);
tegra->group = NULL;
}

iommu_group_put(group);
}
}

void *tegra_drm_alloc(struct tegra_drm *tegra, size_t size, dma_addr_t *dma)
{
struct iova *alloc;
Expand Down
13 changes: 6 additions & 7 deletions drivers/gpu/drm/tegra/drm.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,10 @@

struct reset_control;

struct tegra_fb {
struct drm_framebuffer base;
struct tegra_bo **planes;
unsigned int num_planes;
};

#ifdef CONFIG_DRM_FBDEV_EMULATION
struct tegra_fbdev {
struct drm_fb_helper base;
struct tegra_fb *fb;
struct drm_framebuffer *fb;
};
#endif

Expand Down Expand Up @@ -97,6 +91,7 @@ struct tegra_drm_client {
struct host1x_client base;
struct list_head list;

unsigned int version;
const struct tegra_drm_client_ops *ops;
};

Expand All @@ -110,6 +105,10 @@ int tegra_drm_register_client(struct tegra_drm *tegra,
struct tegra_drm_client *client);
int tegra_drm_unregister_client(struct tegra_drm *tegra,
struct tegra_drm_client *client);
struct iommu_group *host1x_client_iommu_attach(struct host1x_client *client,
bool shared);
void host1x_client_iommu_detach(struct host1x_client *client,
struct iommu_group *group);

int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
int tegra_drm_exit(struct tegra_drm *tegra);
Expand Down
Loading

0 comments on commit ce234cc

Please sign in to comment.