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-04 13:13:05 +0900
commit524879f4efc9e626fa1862ded6f0a16018ff545d (patch)
tree492db5f494408c53f5eeb2fd963b3f403fbe650d
parentf14f2c1fab29a09dd2e1ee7fd95473ee793a0e07 (diff)
downloadnouveau-524879f4efc9e626fa1862ded6f0a16018ff545d.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 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 {