summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2014-10-01 19:01:23 +0900
committerAlexandre Courbot <acourbot@nvidia.com>2014-11-04 13:13:05 +0900
commitf14f2c1fab29a09dd2e1ee7fd95473ee793a0e07 (patch)
tree15301bc202a470dfacc9538bfb734b771ca5afc2
parent88605fca3ff3ed09d400781edfe8113d2cacd62a (diff)
downloadnouveau-f14f2c1fab29a09dd2e1ee7fd95473ee793a0e07.tar.gz
graph/nvc0: add support for netlist firmwares
NVIDIA is releasing some GPU firmwares for the Tegra SoCs under linux-firmware. The release format is a single file (called a netlist) containing all the firmwares relevant to a GPU, which must thus be extracted. This patch adds support for parsing the netlist and loading the firmwares for the NVC0 family of GPUs, falling back to the previous firmware lookup method is no netlist was already loaded. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
l---------drm/core/engine/graph/netlist.h1
-rw-r--r--nvkm/engine/graph/netlist.h76
-rw-r--r--nvkm/engine/graph/nvc0.c96
3 files changed, 173 insertions, 0 deletions
diff --git a/drm/core/engine/graph/netlist.h b/drm/core/engine/graph/netlist.h
new file mode 120000
index 000000000..8d453e540
--- /dev/null
+++ b/drm/core/engine/graph/netlist.h
@@ -0,0 +1 @@
+../../../../nvkm/engine/graph/netlist.h \ No newline at end of file
diff --git a/nvkm/engine/graph/netlist.h b/nvkm/engine/graph/netlist.h
new file mode 100644
index 000000000..0c1a90986
--- /dev/null
+++ b/nvkm/engine/graph/netlist.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/**
+ * Contains definitions of the structures used to pack NVIDIA
+ * officially-released firmwares.
+ */
+
+#ifndef __GRAPH_NETLIST_H__
+#define __GRAPH_NETLIST_H__
+
+#include <core/os.h>
+
+/* netlist regions */
+#define NETLIST_REGIONID_FECS_UCODE_DATA 0
+#define NETLIST_REGIONID_FECS_UCODE_INST 1
+#define NETLIST_REGIONID_GPCCS_UCODE_DATA 2
+#define NETLIST_REGIONID_GPCCS_UCODE_INST 3
+#define NETLIST_REGIONID_SW_BUNDLE_INIT 4
+#define NETLIST_REGIONID_SW_CTX_LOAD 5
+#define NETLIST_REGIONID_SW_NON_CTX_LOAD 6
+#define NETLIST_REGIONID_SW_METHOD_INIT 7
+#define NETLIST_REGIONID_CTXREG_SYS 8
+#define NETLIST_REGIONID_CTXREG_GPC 9
+#define NETLIST_REGIONID_CTXREG_TPC 10
+#define NETLIST_REGIONID_CTXREG_ZCULL_GPC 11
+#define NETLIST_REGIONID_CTXREG_PM_SYS 12
+#define NETLIST_REGIONID_CTXREG_PM_GPC 13
+#define NETLIST_REGIONID_CTXREG_PM_TPC 14
+#define NETLIST_REGIONID_MAJORV 15
+#define NETLIST_REGIONID_BUFFER_SIZE 16
+#define NETLIST_REGIONID_CTXSW_REG_BASE_INDEX 17
+#define NETLIST_REGIONID_NETLIST_NUM 18
+#define NETLIST_REGIONID_CTXREG_PPC 19
+#define NETLIST_REGIONID_CTXREG_PMPPC 20
+
+struct netlist_region
+{
+ u32 region_id;
+ u32 data_size;
+ u32 data_offset;
+};
+
+struct netlist_image_header
+{
+ u32 version;
+ u32 regions;
+};
+
+struct netlist_image
+{
+ struct netlist_image_header header;
+ struct netlist_region regions[1];
+};
+
+#endif
diff --git a/nvkm/engine/graph/nvc0.c b/nvkm/engine/graph/nvc0.c
index 30fd1dc64..39cee49ce 100644
--- a/nvkm/engine/graph/nvc0.c
+++ b/nvkm/engine/graph/nvc0.c
@@ -24,6 +24,11 @@
#include "nvc0.h"
#include "ctxnvc0.h"
+#include "netlist.h"
+
+#ifdef __KERNEL__
+#include <nouveau_platform.h>
+#endif
/*******************************************************************************
* Zero Bandwidth Clear
@@ -1508,6 +1513,89 @@ nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
return (fuc->data != NULL) ? 0 : -ENOMEM;
}
+static int
+duplicate_netlist_region(const struct firmware *fw,
+ struct netlist_region *region,
+ struct nvc0_graph_fuc *fuc)
+{
+ fuc->size = region->data_size;
+ fuc->data = kmemdup(fw->data + region->data_offset, fuc->size,
+ GFP_KERNEL);
+ if (!fuc->data)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int
+nvc0_graph_ctor_fw_netlist(struct nvc0_graph_priv *priv)
+{
+ struct nouveau_device *device = nv_device(priv);
+ struct nouveau_platform_device *platdev;
+ struct netlist_image *netimage;
+ const struct firmware *fw;
+ const u32 required_fw = BIT(NETLIST_REGIONID_FECS_UCODE_DATA) |
+ BIT(NETLIST_REGIONID_FECS_UCODE_INST) |
+ BIT(NETLIST_REGIONID_GPCCS_UCODE_DATA) |
+ BIT(NETLIST_REGIONID_GPCCS_UCODE_INST);
+ u32 loaded_fw = 0;
+ int i;
+
+ /* Are we a platform device? */
+ if (!device->platformdev)
+ return 0;
+
+ platdev = nv_device_to_platform(device);
+ fw = platdev->gpu->ctxsw_fw;
+ /* No firmware loaded? */
+ if (!fw)
+ return 0;
+
+ netimage = (struct netlist_image *)fw->data;
+ for (i = 0; i < netimage->header.regions; i++) {
+ struct netlist_region region = netimage->regions[i];
+ int err = 0;
+
+ if (loaded_fw & BIT(region.region_id)) {
+ nv_warn(priv, "skipping already loaded fw region\n");
+ continue;
+ }
+
+ switch (region.region_id) {
+ case NETLIST_REGIONID_FECS_UCODE_DATA:
+ err = duplicate_netlist_region(fw, &region,
+ &priv->fuc409d);
+ break;
+ case NETLIST_REGIONID_FECS_UCODE_INST:
+ err = duplicate_netlist_region(fw, &region,
+ &priv->fuc409c);
+ break;
+ case NETLIST_REGIONID_GPCCS_UCODE_DATA:
+ err = duplicate_netlist_region(fw, &region,
+ &priv->fuc41ad);
+ break;
+ case NETLIST_REGIONID_GPCCS_UCODE_INST:
+ err = duplicate_netlist_region(fw, &region,
+ &priv->fuc41ac);
+ break;
+ }
+
+ if (err)
+ return err;
+
+ loaded_fw |= BIT(region.region_id);
+ }
+
+ /* Check that all FWs have been loaded */
+ if ((loaded_fw & required_fw) != required_fw) {
+ nv_error(priv, "firmwares missing from the netlist image!\n");
+ return -EINVAL;
+ }
+
+ priv->firmware = true;
+ return 0;
+}
+
void
nvc0_graph_dtor(struct nouveau_object *object)
{
@@ -1553,6 +1641,14 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
if (use_ext_fw) {
nv_info(priv, "using external firmware\n");
+ /* First look for a netlist blob */
+ ret = nvc0_graph_ctor_fw_netlist(priv);
+ if (ret)
+ return ret;
+ }
+
+ /* Legacy firmware loading if no netlist was present */
+ if (use_ext_fw && !priv->firmware) {
if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||