Skip to content

Commit

Permalink
WIP: drm/grate: Add Host1x and DRM drivers with experimental changes
Browse files Browse the repository at this point in the history
The new drivers and UAPI provide all features that are necessary for
implementing of a proper userspace driver. The new driver takes a different
approach in regards to working with sync points by making each submitted job
to take an individual sync point, this solves the problem with the sync point
recovery that old driver suffered from. The new Host1x driver and v2 UAPI are
optimized for performance and minimal resources consumption. The new v2 UAPI
exposes to userspace the HW cmdstream-related features that are necessary
for a proper HW fencing. The staging v1 UAPI is kept functional and all of
current userspace will continue to work with the new driver, note that some
of the never-really-used features of v1 UAPI have been removed (like sync
point increment IOCTL) and will return EPERM.

The goal is to merge new features into the main driver once they are ready.

Key moments of v2 UAPI:
	- Raw sync points are not exposed to userspace.

	- Job descriptors are embedded into the commands stream. Kernel
	  driver parses the stream and patches the descriptors in-place.

	- Commands buffer is copied from userspace via usrptr (no BO
	  allocation and uncached-reading overhead).

	- Channel is not restricted to a single client, thus 3d channel can
	  take a multi-client job that uses 2d / 3d.

	- Supports explicit jobs fencing. DRM sync object and DRM scheduler
	  are utilized to provide the fencing support.

	- Allows to use host1x gather opcode, which is restricted to
	  data-upload usecase only. This allows userspace to pre-allocate
	  a gather buffer, put shaders code / data there, and use two-word
	  "gather" opcode to upload data from the buffer without pushing
	  that data into the commands stream on each submission.

Signed-off-by: Dmitry Osipenko <[email protected]>
  • Loading branch information
digetx committed Jun 18, 2023
1 parent 13c01f1 commit 50b7a58
Show file tree
Hide file tree
Showing 127 changed files with 38,749 additions and 5 deletions.
4 changes: 3 additions & 1 deletion drivers/gpu/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
# drm/tegra depends on host1x, so if both drivers are built-in care must be
# taken to initialize them in the correct order. Link order is the only way
# to ensure this currently.
obj-y += host1x/ drm/ vga/
obj-$(CONFIG_TEGRA_HOST1X) += host1x/
obj-$(CONFIG_GRATE_HOST1X) += host1x-grate/
obj-y += drm/ vga/
obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
obj-$(CONFIG_TRACE_GPU_MEM) += trace/
2 changes: 2 additions & 0 deletions drivers/gpu/drm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ source "drivers/gpu/drm/msm/Kconfig"

source "drivers/gpu/drm/fsl-dcu/Kconfig"

source "drivers/gpu/drm/grate/Kconfig"

source "drivers/gpu/drm/tegra/Kconfig"

source "drivers/gpu/drm/stm/Kconfig"
Expand Down
3 changes: 2 additions & 1 deletion drivers/gpu/drm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ obj-y += tilcdc/
obj-$(CONFIG_DRM_QXL) += qxl/
obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/
obj-$(CONFIG_DRM_MSM) += msm/
obj-$(CONFIG_DRM_TEGRA) += tegra/
obj-$(CONFIG_DRM_TEGRA) += grate/
obj-$(CONFIG_DRM_TEGRA_ORIG) += tegra/
obj-$(CONFIG_DRM_STM) += stm/
obj-$(CONFIG_DRM_STI) += sti/
obj-y += imx/
Expand Down
46 changes: 46 additions & 0 deletions drivers/gpu/drm/grate/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_TEGRA
tristate "NVIDIA Tegra DRM (with experimental changes)"
depends on ARCH_TEGRA || (ARM && COMPILE_TEST)
depends on COMMON_CLK
depends on DRM
depends on OF
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDMI_HELPER
select DRM_DISPLAY_HELPER
select DRM_DP_AUX_BUS
select DRM_KMS_HELPER
select DRM_MIPI_DSI
select DRM_PANEL
select FB_SYS_HELPERS if DRM_FBDEV_EMULATION
select DRM_SCHED
select GRATE_HOST1X
select GRATE_HOST1X_DRV
select INTERCONNECT
select IOMMU_IOVA
select CEC_CORE if CEC_NOTIFIER
select SND_SIMPLE_CARD if SND_SOC_TEGRA20_SPDIF
select SND_SOC_HDMI_CODEC if SND_SOC_TEGRA20_SPDIF
select SND_AUDIO_GRAPH_CARD if SND_SOC_TEGRA20_SPDIF
help
Choose this option if you have an NVIDIA Tegra SoC.

To compile this driver as a module, choose M here: the module
will be called tegra-drm.

if DRM_TEGRA

config DRM_TEGRA_DEBUG
bool "NVIDIA Tegra DRM debug support"
help
Say yes here to enable debugging support.

config DRM_TEGRA_STAGING
bool "Enable HOST1X interface"
depends on STAGING
help
Say yes if HOST1X should be available for userspace DRM users.

If unsure, choose N.

endif
40 changes: 40 additions & 0 deletions drivers/gpu/drm/grate/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# SPDX-License-Identifier: GPL-2.0
ccflags-y := -I $(srctree)/$(src)
ccflags-y += -I $(srctree)/$(src)/uapi
ccflags-y += -I $(srctree)/drivers/gpu/host1x-grate/soc/hw
ccflags-$(CONFIG_DRM_TEGRA_DEBUG) += -DDEBUG

tegra-drm-y := \
drm.o \
gem.o \
fb.o \
dp.o \
hub.o \
plane.o \
dc.o \
output.o \
rgb.o \
hda.o \
hdmi.o \
mipi-phy.o \
dsi.o \
sor.o \
dpaux.o \
gr2d.o \
gr3d.o \
falcon.o \
vic.o \
trace.o \
channel.o \
client.o \
gart.o \
uapi/debug.o \
uapi/job_v1.o \
uapi/job_v2.o \
uapi/patching.o \
uapi/scheduler.o \
uapi/uapi.o

tegra-drm-$(CONFIG_DRM_FBDEV_EMULATION) += fbdev.o

obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o
62 changes: 62 additions & 0 deletions drivers/gpu/drm/grate/channel.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0 */

#include "channel.h"
#include "scheduler.h"

struct tegra_drm_channel *
tegra_drm_open_channel(struct tegra_drm *tegra,
struct tegra_drm_client *drm_client,
u64 pipes_bitmask,
unsigned int num_pushbuf_words,
unsigned int hw_jobs_limit,
unsigned int job_hang_limit,
unsigned int timeout_msecs,
const char *name)
{
struct drm_device *drm = tegra->drm;
struct host1x *host = dev_get_drvdata(drm->dev->parent);
struct host1x_client *client = &drm_client->base;
struct tegra_drm_channel *drm_channel;
int err;

drm_channel = kzalloc(sizeof(*drm_channel), GFP_KERNEL);
if (!drm_channel)
return ERR_PTR(-ENOMEM);

drm_channel->channel = host1x_channel_request(host, client->dev,
num_pushbuf_words);
if (IS_ERR(drm_channel->channel)) {
err = PTR_ERR(drm_channel->channel);
goto err_free_channel;
}

drm_channel->acceptable_pipes = pipes_bitmask;

err = drm_sched_init(&drm_channel->sched,
&tegra_drm_sched_ops,
hw_jobs_limit, job_hang_limit,
msecs_to_jiffies(timeout_msecs / 2),
NULL, NULL, name, drm_client->base.dev);
if (err)
goto err_put_channel;

list_add_tail(&drm_channel->list, &tegra->channels);

return drm_channel;

err_put_channel:
host1x_channel_put(drm_channel->channel);

err_free_channel:
kfree(drm_channel);

return ERR_PTR(err);
}

void tegra_drm_close_channel(struct tegra_drm_channel *drm_channel)
{
drm_sched_fini(&drm_channel->sched);
host1x_channel_put(drm_channel->channel);
list_del(&drm_channel->list);
kfree(drm_channel);
}
40 changes: 40 additions & 0 deletions drivers/gpu/drm/grate/channel.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef __TEGRA_DRM_CHANNEL_H
#define __TEGRA_DRM_CHANNEL_H

#include "drm.h"

#define TEGRA_DRM_PIPE_2D BIT(DRM_TEGRA_PIPE_ID_2D)
#define TEGRA_DRM_PIPE_3D BIT(DRM_TEGRA_PIPE_ID_3D)
#define TEGRA_DRM_PIPE_VIC BIT(DRM_TEGRA_PIPE_ID_VIC)

struct tegra_drm_channel {
struct drm_gpu_scheduler sched;
struct host1x_channel *channel;
struct list_head list;
u64 acceptable_pipes;
};

static inline struct tegra_drm_channel *
to_tegra_drm_channel(struct drm_gpu_scheduler *sched)
{
return container_of(sched, struct tegra_drm_channel, sched);
}

struct tegra_drm;
struct tegra_drm_client;

struct tegra_drm_channel *
tegra_drm_open_channel(struct tegra_drm *tegra,
struct tegra_drm_client *drm_client,
u64 pipes_bitmask,
unsigned int num_pushbuf_words,
unsigned int hw_jobs_limit,
unsigned int job_hang_limit,
unsigned int timeout_msecs,
const char *name);

void tegra_drm_close_channel(struct tegra_drm_channel *drm_channel);

#endif
107 changes: 107 additions & 0 deletions drivers/gpu/drm/grate/client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/* SPDX-License-Identifier: GPL-2.0 */

#include "drm.h"

#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
#include <asm/dma-iommu.h>
#endif

int tegra_drm_register_client(struct tegra_drm *tegra,
struct tegra_drm_client *drm_client)
{
struct drm_device *drm = tegra->drm;
struct host1x *host1x = dev_get_drvdata(drm->dev->parent);
struct host1x_client *client = &drm_client->base;
int err;

drm_client->mlock = host1x_mlock_request(host1x, client->dev);
if (IS_ERR(drm_client->mlock)) {
err = PTR_ERR(drm_client->mlock);
return err;
}

list_add_tail(&drm_client->list, &tegra->clients);
drm_client->drm = tegra;

return 0;
}

void tegra_drm_unregister_client(struct tegra_drm_client *drm_client)
{
host1x_mlock_put(drm_client->mlock);
list_del(&drm_client->list);
drm_client->drm = NULL;
}

struct iommu_group *
tegra_drm_client_iommu_attach(struct tegra_drm_client *drm_client, bool shared)
{
struct host1x_client *client = &drm_client->base;
struct iommu_domain *domain = iommu_get_domain_for_dev(client->dev);
struct drm_device *drm = dev_get_drvdata(client->host);
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) {
if (tegra->has_gart) {
dev_warn(client->dev, "failed to get IOMMU group\n");
dev_warn(client->dev, "please update your device-tree\n");
return 0;
}

dev_err(client->dev, "failed to get IOMMU group\n");
return ERR_PTR(-ENODEV);
}

if (!shared || !tegra->group) {
#if IS_ENABLED(CONFIG_ARM_DMA_USE_IOMMU)
if (client->dev->archdata.mapping) {
struct dma_iommu_mapping *mapping =
to_dma_iommu_mapping(client->dev);
arm_iommu_detach_device(client->dev);
arm_iommu_release_mapping(mapping);
}
#endif
if (domain != tegra->domain) {
err = iommu_attach_group(tegra->domain, group);
if (err < 0) {
iommu_group_put(group);
return ERR_PTR(err);
}

drm_client->detach_iommu = true;
}

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

return group;
}

void tegra_drm_client_iommu_detach(struct tegra_drm_client *drm_client,
struct iommu_group *group,
bool shared)
{
struct host1x_client *client = &drm_client->base;
struct drm_device *drm = dev_get_drvdata(client->host);
struct tegra_drm *tegra = drm->dev_private;

if (group) {
if (!shared || group == tegra->group) {
if (drm_client->detach_iommu) {
iommu_detach_group(tegra->domain, group);
drm_client->detach_iommu = false;
}

if (group == tegra->group)
tegra->group = NULL;
}

iommu_group_put(group);
}
}
52 changes: 52 additions & 0 deletions drivers/gpu/drm/grate/client.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef __TEGRA_DRM_CLIENT_H
#define __TEGRA_DRM_CLIENT_H

#include "drm.h"

struct tegra_drm_job;

struct tegra_drm_client {
struct host1x_client base;
struct host1x_mlock *mlock;
struct tegra_drm *drm;
struct list_head list;
bool detach_iommu;
const unsigned long *addr_regs;
unsigned int num_regs;
u64 pipe;

int (*refine_class)(struct tegra_drm_client *client, u64 pipes,
unsigned int *classid);

int (*prepare_job)(struct tegra_drm_client *client,
struct tegra_drm_job *job);

int (*unprepare_job)(struct tegra_drm_client *client,
struct tegra_drm_job *job);

int (*reset_hw)(struct tegra_drm_client *client);
};

static inline struct tegra_drm_client *
to_tegra_drm_client(struct host1x_client *client)
{
return container_of(client, struct tegra_drm_client, base);
}

struct tegra_drm;

int tegra_drm_register_client(struct tegra_drm *tegra,
struct tegra_drm_client *drm_client);

void tegra_drm_unregister_client(struct tegra_drm_client *drm_client);

struct iommu_group *
tegra_drm_client_iommu_attach(struct tegra_drm_client *drm_client, bool shared);

void tegra_drm_client_iommu_detach(struct tegra_drm_client *drm_client,
struct iommu_group *group,
bool shared);

#endif
Loading

0 comments on commit 50b7a58

Please sign in to comment.