diff options
-rw-r--r-- | drm/nouveau_platform.c | 76 | ||||
-rw-r--r-- | drm/nouveau_platform.h | 2 | ||||
-rw-r--r-- | lib/core/os.h | 1 |
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 { |