+static const struct nouveau_mclass
+nouveau_decoder_msvld[] = {
+ { G98_MSVLD, -1 },
+ { IGT21A_MSVLD, -1 },
+ { GT212_MSVLD, -1 },
+ { GF100_MSVLD, -1 },
+ { GK104_MSVLD, -1 },
+ {}
+};
+
+static int
+firmware_present(struct pipe_screen *pscreen, enum pipe_video_profile profile)
+{
+ struct nouveau_screen *screen = nouveau_screen(pscreen);
+ int chipset = screen->device->chipset;
+ int vp3 = chipset < 0xa3 || chipset == 0xaa || chipset == 0xac;
+ int vp5 = chipset >= 0xd0;
+ int ret;
+
+ /* For all chipsets, try to create a BSP objects. Assume that if firmware
+ * is present for it, firmware is also present for VP/PPP */
+ if (!(screen->firmware_info.profiles_checked & 1)) {
+ struct nouveau_object *channel = NULL, *bsp = NULL;
+ struct nv04_fifo nv04_data = {.vram = 0xbeef0201, .gart = 0xbeef0202};
+ struct nvc0_fifo nvc0_args = {};
+ struct nve0_fifo nve0_args = {.engine = NVE0_FIFO_ENGINE_BSP};
+ void *data = NULL;
+ int size;
+
+ if (chipset < 0xc0) {
+ data = &nv04_data;
+ size = sizeof(nv04_data);
+ } else if (chipset < 0xe0) {
+ data = &nvc0_args;
+ size = sizeof(nvc0_args);
+ } else {
+ data = &nve0_args;
+ size = sizeof(nve0_args);
+ }
+
+ /* kepler must have its own channel, so just do this for everyone */
+ nouveau_object_new(&screen->device->object, 0,
+ NOUVEAU_FIFO_CHANNEL_CLASS,
+ data, size, &channel);
+
+ if (channel) {
+ ret = nouveau_object_mclass(channel, nouveau_decoder_msvld);
+ if (ret >= 0)
+ nouveau_object_new(channel, 0, nouveau_decoder_msvld[ret].oclass,
+ NULL, 0, &bsp);
+ if (bsp)
+ screen->firmware_info.profiles_present |= 1;
+ nouveau_object_del(&bsp);
+ nouveau_object_del(&channel);
+ }
+ screen->firmware_info.profiles_checked |= 1;
+ }
+
+ if (!(screen->firmware_info.profiles_present & 1))
+ return 0;
+
+ /* For vp3/vp4 chipsets, make sure that the relevant firmware is present */
+ if (!vp5 && !(screen->firmware_info.profiles_checked & (1 << profile))) {
+ char path[PATH_MAX];
+ struct stat s;
+ if (vp3)
+ vp3_getpath(profile, path);
+ else
+ vp4_getpath(profile, path);
+ ret = stat(path, &s);
+ if (!ret && s.st_size > 1000)
+ screen->firmware_info.profiles_present |= (1 << profile);
+ screen->firmware_info.profiles_checked |= (1 << profile);
+ }
+
+ return vp5 || (screen->firmware_info.profiles_present & (1 << profile));
+}
+