Skip to content

Commit

Permalink
drm/tegra: Add Tegra234 support to NVDEC driver
Browse files Browse the repository at this point in the history
Add support for the Tegra234 version of NVDEC to the NVDEC driver.
This version sports a RISC-V controller and requires a few additional
clocks. After firmware has been loaded, the behavior is, however,
backwards compatible.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
  • Loading branch information
Mikko Perttunen authored and Thierry Reding committed Nov 25, 2022
1 parent b7dc179 commit fbc82b9
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 15 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/tegra/drm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
{ .compatible = "nvidia,tegra194-vic", },
{ .compatible = "nvidia,tegra194-nvdec", },
{ .compatible = "nvidia,tegra234-vic", },
{ .compatible = "nvidia,tegra234-nvdec", },
{ /* sentinel */ }
};

Expand Down
140 changes: 125 additions & 15 deletions drivers/gpu/drm/tegra/nvdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <linux/dma-mapping.h>
#include <linux/host1x.h>
#include <linux/iommu.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
Expand All @@ -16,18 +17,21 @@
#include <linux/pm_runtime.h>
#include <linux/reset.h>

#include <soc/tegra/pmc.h>
#include <soc/tegra/mc.h>

#include "drm.h"
#include "falcon.h"
#include "riscv.h"
#include "vic.h"

#define NVDEC_FALCON_DEBUGINFO 0x1094
#define NVDEC_TFBIF_TRANSCFG 0x2c44

struct nvdec_config {
const char *firmware;
unsigned int version;
bool supports_sid;
bool has_riscv;
bool has_extra_clocks;
};

Expand All @@ -40,9 +44,14 @@ struct nvdec {
struct device *dev;
struct clk_bulk_data clks[3];
unsigned int num_clks;
struct reset_control *reset;

/* Platform configuration */
const struct nvdec_config *config;

/* RISC-V specific data */
struct tegra_drm_riscv riscv;
phys_addr_t carveout_base;
};

static inline struct nvdec *to_nvdec(struct tegra_drm_client *client)
Expand All @@ -56,7 +65,7 @@ static inline void nvdec_writel(struct nvdec *nvdec, u32 value,
writel(value, nvdec->regs + offset);
}

static int nvdec_boot(struct nvdec *nvdec)
static int nvdec_boot_falcon(struct nvdec *nvdec)
{
#ifdef CONFIG_IOMMU_API
struct iommu_fwspec *spec = dev_iommu_fwspec_get(nvdec->dev);
Expand Down Expand Up @@ -92,6 +101,64 @@ static int nvdec_boot(struct nvdec *nvdec)
return 0;
}

static int nvdec_wait_debuginfo(struct nvdec *nvdec, const char *phase)
{
int err;
u32 val;

err = readl_poll_timeout(nvdec->regs + NVDEC_FALCON_DEBUGINFO, val, val == 0x0, 10, 100000);
if (err) {
dev_err(nvdec->dev, "failed to boot %s, debuginfo=0x%x\n", phase, val);
return err;
}

return 0;
}

static int nvdec_boot_riscv(struct nvdec *nvdec)
{
int err;

err = reset_control_acquire(nvdec->reset);
if (err)
return err;

nvdec_writel(nvdec, 0xabcd1234, NVDEC_FALCON_DEBUGINFO);

err = tegra_drm_riscv_boot_bootrom(&nvdec->riscv, nvdec->carveout_base, 1,
&nvdec->riscv.bl_desc);
if (err) {
dev_err(nvdec->dev, "failed to execute bootloader\n");
goto release_reset;
}

err = nvdec_wait_debuginfo(nvdec, "bootloader");
if (err)
goto release_reset;

err = reset_control_reset(nvdec->reset);
if (err)
goto release_reset;

nvdec_writel(nvdec, 0xabcd1234, NVDEC_FALCON_DEBUGINFO);

err = tegra_drm_riscv_boot_bootrom(&nvdec->riscv, nvdec->carveout_base, 1,
&nvdec->riscv.os_desc);
if (err) {
dev_err(nvdec->dev, "failed to execute firmware\n");
goto release_reset;
}

err = nvdec_wait_debuginfo(nvdec, "firmware");
if (err)
goto release_reset;

release_reset:
reset_control_release(nvdec->reset);

return err;
}

static int nvdec_init(struct host1x_client *client)
{
struct tegra_drm_client *drm = host1x_to_drm_client(client);
Expand Down Expand Up @@ -191,7 +258,7 @@ static const struct host1x_client_ops nvdec_client_ops = {
.exit = nvdec_exit,
};

static int nvdec_load_firmware(struct nvdec *nvdec)
static int nvdec_load_falcon_firmware(struct nvdec *nvdec)
{
struct host1x_client *client = &nvdec->client.base;
struct tegra_drm *tegra = nvdec->client.drm;
Expand Down Expand Up @@ -254,7 +321,6 @@ static int nvdec_load_firmware(struct nvdec *nvdec)
return err;
}


static __maybe_unused int nvdec_runtime_resume(struct device *dev)
{
struct nvdec *nvdec = dev_get_drvdata(dev);
Expand All @@ -266,13 +332,19 @@ static __maybe_unused int nvdec_runtime_resume(struct device *dev)

usleep_range(10, 20);

err = nvdec_load_firmware(nvdec);
if (err < 0)
goto disable;
if (nvdec->config->has_riscv) {
err = nvdec_boot_riscv(nvdec);
if (err < 0)
goto disable;
} else {
err = nvdec_load_falcon_firmware(nvdec);
if (err < 0)
goto disable;

err = nvdec_boot(nvdec);
if (err < 0)
goto disable;
err = nvdec_boot_falcon(nvdec);
if (err < 0)
goto disable;
}

return 0;

Expand Down Expand Up @@ -348,10 +420,18 @@ static const struct nvdec_config nvdec_t194_config = {
.supports_sid = true,
};

static const struct nvdec_config nvdec_t234_config = {
.version = 0x23,
.supports_sid = true,
.has_riscv = true,
.has_extra_clocks = true,
};

static const struct of_device_id tegra_nvdec_of_match[] = {
{ .compatible = "nvidia,tegra210-nvdec", .data = &nvdec_t210_config },
{ .compatible = "nvidia,tegra186-nvdec", .data = &nvdec_t186_config },
{ .compatible = "nvidia,tegra194-nvdec", .data = &nvdec_t194_config },
{ .compatible = "nvidia,tegra234-nvdec", .data = &nvdec_t234_config },
{ },
};
MODULE_DEVICE_TABLE(of, tegra_nvdec_of_match);
Expand Down Expand Up @@ -410,12 +490,42 @@ static int nvdec_probe(struct platform_device *pdev)
if (err < 0)
host_class = HOST1X_CLASS_NVDEC;

nvdec->falcon.dev = dev;
nvdec->falcon.regs = nvdec->regs;
if (nvdec->config->has_riscv) {
struct tegra_mc *mc;

err = falcon_init(&nvdec->falcon);
if (err < 0)
return err;
mc = devm_tegra_memory_controller_get(dev);
if (IS_ERR(mc)) {
dev_err_probe(dev, PTR_ERR(mc),
"failed to get memory controller handle\n");
return PTR_ERR(mc);
}

err = tegra_mc_get_carveout_info(mc, 1, &nvdec->carveout_base, NULL);
if (err) {
dev_err(dev, "failed to get carveout info: %d\n", err);
return err;
}

nvdec->reset = devm_reset_control_get_exclusive_released(dev, "nvdec");
if (IS_ERR(nvdec->reset)) {
dev_err_probe(dev, PTR_ERR(nvdec->reset), "failed to get reset\n");
return PTR_ERR(nvdec->reset);
}

nvdec->riscv.dev = dev;
nvdec->riscv.regs = nvdec->regs;

err = tegra_drm_riscv_read_descriptors(&nvdec->riscv);
if (err < 0)
return err;
} else {
nvdec->falcon.dev = dev;
nvdec->falcon.regs = nvdec->regs;

err = falcon_init(&nvdec->falcon);
if (err < 0)
return err;
}

platform_set_drvdata(pdev, nvdec);

Expand Down

0 comments on commit fbc82b9

Please sign in to comment.