From 1ef6885568617656d35fded33e9dc944734c4728 Mon Sep 17 00:00:00 2001 From: Aaron Kling Date: Thu, 14 Aug 2025 21:18:17 -0500 Subject: [PATCH] drm/tegra: Support Tegra186+ in NVJPG Change-Id: I7bf2c200d4ad9690c4f21a004ecc6dea8065f93e --- drivers/gpu/drm/tegra/drm.c | 3 + drivers/gpu/drm/tegra/nvjpg.c | 141 ++++++++++++++++++++++++++++++++-- 2 files changed, 139 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index c2804c36ee07..f62b2b05f8d0 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -1391,15 +1391,18 @@ static const struct of_device_id host1x_drm_subdevs[] = { { .compatible = "nvidia,tegra186-vic", }, { .compatible = "nvidia,tegra186-nvdec", }, { .compatible = "nvidia,tegra186-nvenc", }, + { .compatible = "nvidia,tegra186-nvjpg", }, { .compatible = "nvidia,tegra194-display", }, { .compatible = "nvidia,tegra194-dc", }, { .compatible = "nvidia,tegra194-sor", }, { .compatible = "nvidia,tegra194-vic", }, { .compatible = "nvidia,tegra194-nvdec", }, { .compatible = "nvidia,tegra194-nvenc", }, + { .compatible = "nvidia,tegra194-nvjpg", }, { .compatible = "nvidia,tegra234-vic", }, { .compatible = "nvidia,tegra234-nvdec", }, { .compatible = "nvidia,tegra234-nvenc", }, + { .compatible = "nvidia,tegra234-nvjpg", }, { /* sentinel */ } }; diff --git a/drivers/gpu/drm/tegra/nvjpg.c b/drivers/gpu/drm/tegra/nvjpg.c index d1beee322232..28dc26999cad 100644 --- a/drivers/gpu/drm/tegra/nvjpg.c +++ b/drivers/gpu/drm/tegra/nvjpg.c @@ -12,10 +12,14 @@ #include "drm.h" #include "falcon.h" +#include "vic.h" + +#define NVJPG_TFBIF_TRANSCFG 0x1444 struct nvjpg_config { const char *firmware; unsigned int version; + bool supports_sid; }; struct nvjpg { @@ -23,6 +27,7 @@ struct nvjpg { void __iomem *regs; struct tegra_drm_client client; + struct host1x_channel *channel; struct device *dev; struct clk *clk; @@ -35,6 +40,12 @@ static inline struct nvjpg *to_nvjpg(struct tegra_drm_client *client) return container_of(client, struct nvjpg, client); } +static inline void nvjpg_writel(struct nvjpg *nvjpg, u32 value, + unsigned int offset) +{ + writel(value, nvjpg->regs + offset); +} + static int nvjpg_init(struct host1x_client *client) { struct tegra_drm_client *drm = host1x_to_drm_client(client); @@ -49,9 +60,21 @@ static int nvjpg_init(struct host1x_client *client) return err; } + nvjpg->channel = host1x_channel_request(client); + if (!nvjpg->channel) { + err = -ENOMEM; + goto detach; + } + + client->syncpts[0] = host1x_syncpt_request(client, 0); + if (!client->syncpts[0]) { + err = -ENOMEM; + goto free_channel; + } + err = tegra_drm_register_client(tegra, drm); if (err < 0) - goto detach; + goto free_syncpt; /* * Inherit the DMA parameters (such as maximum segment size) from the @@ -61,6 +84,10 @@ static int nvjpg_init(struct host1x_client *client) return 0; +free_syncpt: + host1x_syncpt_put(client->syncpts[0]); +free_channel: + host1x_channel_put(nvjpg->channel); detach: host1x_client_iommu_detach(client); @@ -85,8 +112,12 @@ static int nvjpg_exit(struct host1x_client *client) pm_runtime_dont_use_autosuspend(client->dev); pm_runtime_force_suspend(client->dev); + host1x_syncpt_put(client->syncpts[0]); + host1x_channel_put(nvjpg->channel); host1x_client_iommu_detach(client); + nvjpg->channel = NULL; + if (client->group) { dma_unmap_single(nvjpg->dev, nvjpg->falcon.firmware.phys, nvjpg->falcon.firmware.size, DMA_TO_DEVICE); @@ -170,6 +201,34 @@ cleanup: return err; } +static int nvjpg_boot_falcon(struct nvjpg *nvjpg) +{ + u32 stream_id; + int err; + + if (nvjpg->config->supports_sid && tegra_dev_iommu_get_stream_id(nvjpg->dev, &stream_id)) { + u32 value; + + value = TRANSCFG_ATT(1, TRANSCFG_SID_FALCON) | TRANSCFG_ATT(0, TRANSCFG_SID_HW); + nvjpg_writel(nvjpg, value, NVJPG_TFBIF_TRANSCFG); + + nvjpg_writel(nvjpg, stream_id, VIC_THI_STREAMID0); + nvjpg_writel(nvjpg, stream_id, VIC_THI_STREAMID1); + } + + err = falcon_boot(&nvjpg->falcon); + if (err < 0) + return err; + + err = falcon_wait_idle(&nvjpg->falcon); + if (err < 0) { + dev_err(nvjpg->dev, "falcon boot timed out\n"); + return err; + } + + return 0; +} + static __maybe_unused int nvjpg_runtime_resume(struct device *dev) { struct nvjpg *nvjpg = dev_get_drvdata(dev); @@ -185,7 +244,7 @@ static __maybe_unused int nvjpg_runtime_resume(struct device *dev) if (err < 0) goto disable_clk; - err = falcon_boot(&nvjpg->falcon); + err = nvjpg_boot_falcon(nvjpg); if (err < 0) goto disable_clk; @@ -200,31 +259,82 @@ static __maybe_unused int nvjpg_runtime_suspend(struct device *dev) { struct nvjpg *nvjpg = dev_get_drvdata(dev); + host1x_channel_stop(nvjpg->channel); + clk_disable_unprepare(nvjpg->clk); return 0; } +static int nvjpg_open_channel(struct tegra_drm_client *client, + struct tegra_drm_context *context) +{ + struct nvjpg *nvjpg = to_nvjpg(client); + + context->channel = host1x_channel_get(nvjpg->channel); + if (!context->channel) + return -ENOMEM; + + return 0; +} + +static void nvjpg_close_channel(struct tegra_drm_context *context) +{ + host1x_channel_put(context->channel); +} + static int nvjpg_can_use_memory_ctx(struct tegra_drm_client *client, bool *supported) { - *supported = false; + *supported = true; return 0; } static const struct tegra_drm_client_ops nvjpg_ops = { - .get_streamid_offset = NULL, + .open_channel = nvjpg_open_channel, + .close_channel = nvjpg_close_channel, + .submit = tegra_drm_submit, + .get_streamid_offset = tegra_drm_get_streamid_offset_thi, .can_use_memory_ctx = nvjpg_can_use_memory_ctx, }; + #define NVIDIA_TEGRA_210_NVJPG_FIRMWARE "nvidia/tegra210/nvjpg.bin" static const struct nvjpg_config nvjpg_t210_config = { .firmware = NVIDIA_TEGRA_210_NVJPG_FIRMWARE, .version = 0x21, + .supports_sid = false, +}; + +#define NVIDIA_TEGRA_186_NVJPG_FIRMWARE "nvidia/tegra186/nvjpg.bin" + +static const struct nvjpg_config nvjpg_t186_config = { + .firmware = NVIDIA_TEGRA_186_NVJPG_FIRMWARE, + .version = 0x18, + .supports_sid = true, +}; + +#define NVIDIA_TEGRA_194_NVJPG_FIRMWARE "nvidia/tegra194/nvjpg.bin" + +static const struct nvjpg_config nvjpg_t194_config = { + .firmware = NVIDIA_TEGRA_194_NVJPG_FIRMWARE, + .version = 0x19, + .supports_sid = true, +}; + +#define NVIDIA_TEGRA_234_NVJPG_FIRMWARE "nvidia/tegra234/nvjpg.bin" + +static const struct nvjpg_config nvjpg_t234_config = { + .firmware = NVIDIA_TEGRA_234_NVJPG_FIRMWARE, + .version = 0x23, + .supports_sid = true, }; static const struct of_device_id tegra_nvjpg_of_match[] = { { .compatible = "nvidia,tegra210-nvjpg", .data = &nvjpg_t210_config }, + { .compatible = "nvidia,tegra186-nvjpg", .data = &nvjpg_t186_config }, + { .compatible = "nvidia,tegra194-nvjpg", .data = &nvjpg_t194_config }, + { .compatible = "nvidia,tegra234-nvjpg", .data = &nvjpg_t234_config }, { }, }; MODULE_DEVICE_TABLE(of, tegra_nvjpg_of_match); @@ -232,7 +342,9 @@ MODULE_DEVICE_TABLE(of, tegra_nvjpg_of_match); static int nvjpg_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct host1x_syncpt **syncpts; struct nvjpg *nvjpg; + u32 host_class; int err; /* inherit DMA mask from host1x parent */ @@ -248,6 +360,10 @@ static int nvjpg_probe(struct platform_device *pdev) nvjpg->config = of_device_get_match_data(dev); + syncpts = devm_kzalloc(dev, sizeof(*syncpts), GFP_KERNEL); + if (!syncpts) + return -ENOMEM; + nvjpg->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(nvjpg->regs)) return PTR_ERR(nvjpg->regs); @@ -271,12 +387,18 @@ static int nvjpg_probe(struct platform_device *pdev) if (err < 0) return err; + err = of_property_read_u32(dev->of_node, "nvidia,host1x-class", &host_class); + if (err < 0) + host_class = HOST1X_CLASS_NVJPG; + platform_set_drvdata(pdev, nvjpg); INIT_LIST_HEAD(&nvjpg->client.base.list); nvjpg->client.base.ops = &nvjpg_client_ops; nvjpg->client.base.dev = dev; - nvjpg->client.base.class = HOST1X_CLASS_NVJPG; + nvjpg->client.base.class = host_class; + nvjpg->client.base.syncpts = syncpts; + nvjpg->client.base.num_syncpts = 1; nvjpg->dev = dev; INIT_LIST_HEAD(&nvjpg->client.list); @@ -327,3 +449,12 @@ struct platform_driver tegra_nvjpg_driver = { #if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) MODULE_FIRMWARE(NVIDIA_TEGRA_210_NVJPG_FIRMWARE); #endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_186_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_186_NVJPG_FIRMWARE); +#endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_194_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_194_NVJPG_FIRMWARE); +#endif +#if IS_ENABLED(CONFIG_ARCH_TEGRA_234_SOC) +MODULE_FIRMWARE(NVIDIA_TEGRA_234_NVJPG_FIRMWARE); +#endif