summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drm/nouveau_platform.c76
-rw-r--r--drm/nouveau_platform.h2
-rw-r--r--lib/core/os.h1
3 files changed, 74 insertions, 5 deletions
diff --git a/drm/nouveau_platform.c b/drm/nouveau_platform.c
index 246a824c1..9945c2ec2 100644
--- a/drm/nouveau_platform.c
+++ b/drm/nouveau_platform.c
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/reset.h>
#include <linux/regulator/consumer.h>
#include <soc/tegra/pmc.h>
@@ -90,6 +91,52 @@ static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu)
return 0;
}
+struct nouveau_platform_probe_data {
+ const char *soc;
+ const char *gpu;
+ bool use_ext_firmware;
+};
+
+static const struct firmware *
+nouveau_platform_load_netlist_fw(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ const struct nouveau_platform_probe_data *pdata;
+ const struct firmware *ctxsw_fw;
+ char f[32];
+ int err;
+
+ match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
+ if (!match) {
+ dev_warn(&pdev->dev, "cannot find OF match for device\n");
+ return NULL;
+ }
+ pdata = match->data;
+ if (!pdata) {
+ dev_warn(&pdev->dev, "no probe data for device\n");
+ return NULL;
+ }
+
+ if (!pdata->use_ext_firmware)
+ return NULL;
+
+ err = snprintf(f, sizeof(f), "nvidia/%s/%s_ctxsw.bin", pdata->soc,
+ pdata->gpu);
+ if (err >= sizeof(f)) {
+ dev_err(&pdev->dev, "firmware path too long (max %d)\n",
+ sizeof(f));
+ return ERR_PTR(-ENOSPC);
+ }
+
+ err = request_firmware(&ctxsw_fw, f, &pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "error loading firmware: %d\n", err);
+ return ERR_PTR(err);
+ }
+
+ return ctxsw_fw;
+}
+
static int nouveau_platform_probe(struct platform_device *pdev)
{
struct nouveau_platform_gpu *gpu;
@@ -117,9 +164,13 @@ static int nouveau_platform_probe(struct platform_device *pdev)
if (IS_ERR(gpu->clk_pwr))
return PTR_ERR(gpu->clk_pwr);
+ gpu->ctxsw_fw = nouveau_platform_load_netlist_fw(pdev);
+ if (IS_ERR(gpu->ctxsw_fw))
+ return PTR_ERR(gpu->ctxsw_fw);
+
err = nouveau_platform_power_up(gpu);
if (err)
- return err;
+ goto release_fw;
drm = nouveau_platform_device_create(pdev, &device);
if (IS_ERR(drm)) {
@@ -133,16 +184,22 @@ static int nouveau_platform_probe(struct platform_device *pdev)
if (err < 0)
goto err_unref;
- return 0;
+ /*
+ * we can release the firmware now since it has been consumed during
+ * probe
+ */
+ goto release_fw;
err_unref:
drm_dev_unref(drm);
- return 0;
-
power_down:
nouveau_platform_power_down(gpu);
+release_fw:
+ if (gpu->ctxsw_fw)
+ release_firmware(gpu->ctxsw_fw);
+
return err;
}
@@ -159,8 +216,17 @@ static int nouveau_platform_remove(struct platform_device *pdev)
}
#if IS_ENABLED(CONFIG_OF)
+static struct nouveau_platform_probe_data gk20a_probe_data = {
+ .soc = "tegra124",
+ .gpu = "gk20a",
+ .use_ext_firmware = true,
+};
+
static const struct of_device_id nouveau_platform_match[] = {
- { .compatible = "nvidia,gk20a" },
+ {
+ .compatible = "nvidia,gk20a",
+ .data = &gk20a_probe_data,
+ },
{ }
};
diff --git a/drm/nouveau_platform.h b/drm/nouveau_platform.h
index 91f665049..7fe17d1df 100644
--- a/drm/nouveau_platform.h
+++ b/drm/nouveau_platform.h
@@ -35,6 +35,8 @@ struct nouveau_platform_gpu {
struct clk *clk_pwr;
struct regulator *vdd;
+
+ const struct firmware *ctxsw_fw;
};
struct nouveau_platform_device {
diff --git a/lib/core/os.h b/lib/core/os.h
index 79462eb2c..a00897cd5 100644
--- a/lib/core/os.h
+++ b/lib/core/os.h
@@ -1143,6 +1143,7 @@ clk_get_rate(struct clk *clk)
struct nouveau_platform_gpu {
struct clk *clk;
+ const struct firmware *ctxsw_fw;
};
struct nouveau_platform_device {