summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2014-10-01 19:05:04 +0900
committerAlexandre Courbot <acourbot@nvidia.com>2014-10-31 11:47:40 +0900
commitfd0f127182cdf90f73dede9bdbe26b76ef5af3ae (patch)
treea9f6eeacd1806008f283f8273614c902034803f5
parent865e9b500fb6f8ae5b61a3e8edb3b23f10de7221 (diff)
downloadnouveau-fd0f127182cdf90f73dede9bdbe26b76ef5af3ae.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 {