summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2014-10-01 19:05:04 +0900
committerAlexandre Courbot <acourbot@nvidia.com>2014-11-11 18:47:50 +0900
commitd71225db69e0df58377c8c9526a1dadb2d8e0fb6 (patch)
treee471f15dcea6f07d3f3e4442b3d1a48cf93bf92f
parentde84ed71c72797d9caf6fee0ab1c89dd7583ec97 (diff)
downloadnouveau-d71225db69e0df58377c8c9526a1dadb2d8e0fb6.tar.gz
platform: support for netlist firmwares
Netlists released by NVIDIA are made of a single file containing firmwares that can potentially be used across different engines. It therefore makes most sense to load a netlist once before engines are probed and have them duplicate their firmwares so the netlist can be freed at the end of probe. This patch implements this mechanism and adds the lookup data for GK20A. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
-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 aea628eb3..84e0dad6f 100644
--- a/lib/core/os.h
+++ b/lib/core/os.h
@@ -1147,6 +1147,7 @@ clk_get_rate(struct clk *clk)
struct nouveau_platform_gpu {
struct clk *clk;
+ const struct firmware *ctxsw_fw;
};
struct nouveau_platform_device {