-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP: drm/grate: Add Host1x and DRM drivers with experimental changes
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
Showing
127 changed files
with
38,749 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.