Merge remote branch 'keithp/drm-intel-next' of ../drm-next into drm-core-next
authorDave Airlie <airlied@redhat.com>
Fri, 20 May 2011 01:30:02 +0000 (11:30 +1000)
committerDave Airlie <airlied@redhat.com>
Fri, 20 May 2011 01:30:02 +0000 (11:30 +1000)
* 'keithp/drm-intel-next' of ../drm-next:
  drm/i915: initialize gen6 rps work queue on Sandy Bridge and Ivy Bridge
  drm/i915/sdvo: Reorder i2c initialisation before ddc proxy
  drm/i915: FDI link training broken on Ironlake by Ivybridge integration
  drm/i915: enable rc6 by default
  drm/i915: add fbc enable flag, but disable by default
  drm/i915: clean up unused ring_get_irq/ring_put_irq functions
  drm/i915: fix user irq miss in BSD ring on g4x

69 files changed:
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/nouveau/Kconfig
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bios.h
drivers/gpu/drm/nouveau/nouveau_channel.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drv.c
drivers/gpu/drm/nouveau/nouveau_drv.h
drivers/gpu/drm/nouveau/nouveau_grctx.h
drivers/gpu/drm/nouveau/nouveau_mem.c
drivers/gpu/drm/nouveau/nouveau_object.c
drivers/gpu/drm/nouveau/nouveau_perf.c
drivers/gpu/drm/nouveau/nouveau_pm.c
drivers/gpu/drm/nouveau/nouveau_reg.h
drivers/gpu/drm/nouveau/nouveau_state.c
drivers/gpu/drm/nouveau/nouveau_vm.h
drivers/gpu/drm/nouveau/nouveau_volt.c
drivers/gpu/drm/nouveau/nv04_crtc.c
drivers/gpu/drm/nouveau/nv04_graph.c
drivers/gpu/drm/nouveau/nv04_instmem.c
drivers/gpu/drm/nouveau/nv10_graph.c
drivers/gpu/drm/nouveau/nv20_graph.c
drivers/gpu/drm/nouveau/nv40_fifo.c
drivers/gpu/drm/nouveau/nv40_graph.c
drivers/gpu/drm/nouveau/nv40_mpeg.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_calc.c
drivers/gpu/drm/nouveau/nv50_crtc.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/nouveau/nv50_graph.c
drivers/gpu/drm/nouveau/nv50_grctx.c
drivers/gpu/drm/nouveau/nv50_mpeg.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nv50_pm.c
drivers/gpu/drm/nouveau/nv50_vm.c
drivers/gpu/drm/nouveau/nv84_crypt.c
drivers/gpu/drm/nouveau/nva3_copy.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_copy.fuc [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_copy.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nva3_pm.c
drivers/gpu/drm/nouveau/nvc0_copy.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_copy.fuc.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/nvc0_fifo.c
drivers/gpu/drm/nouveau/nvc0_graph.c
drivers/gpu/drm/nouveau/nvc0_graph.h
drivers/gpu/drm/nouveau/nvc0_grctx.c
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_encoders.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/vga/vga_switcheroo.c
drivers/gpu/vga/vgaarb.c
drivers/pci/pci.c
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/mxm-wmi.c [new file with mode: 0644]
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_edid.h
include/drm/drm_fb_helper.h
include/linux/mxm-wmi.h [new file with mode: 0644]
include/linux/pci.h

index adc9358c9bec4a2b1f0d86a7a7ebb32655c36184..0a9357c66ff8703b76123487c8ef8d05b373c136 100644 (file)
@@ -1412,6 +1412,64 @@ end:
 }
 EXPORT_SYMBOL(drm_detect_monitor_audio);
 
+/**
+ * drm_add_display_info - pull display info out if present
+ * @edid: EDID data
+ * @info: display info (attached to connector)
+ *
+ * Grab any available display info and stuff it into the drm_display_info
+ * structure that's part of the connector.  Useful for tracking bpp and
+ * color spaces.
+ */
+static void drm_add_display_info(struct edid *edid,
+                                struct drm_display_info *info)
+{
+       info->width_mm = edid->width_cm * 10;
+       info->height_mm = edid->height_cm * 10;
+
+       /* driver figures it out in this case */
+       info->bpc = 0;
+       info->color_formats = 0;
+
+       /* Only defined for 1.4 with digital displays */
+       if (edid->revision < 4)
+               return;
+
+       if (!(edid->input & DRM_EDID_INPUT_DIGITAL))
+               return;
+
+       switch (edid->input & DRM_EDID_DIGITAL_DEPTH_MASK) {
+       case DRM_EDID_DIGITAL_DEPTH_6:
+               info->bpc = 6;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_8:
+               info->bpc = 8;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_10:
+               info->bpc = 10;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_12:
+               info->bpc = 12;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_14:
+               info->bpc = 14;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_16:
+               info->bpc = 16;
+               break;
+       case DRM_EDID_DIGITAL_DEPTH_UNDEF:
+       default:
+               info->bpc = 0;
+               break;
+       }
+
+       info->color_formats = DRM_COLOR_FORMAT_RGB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB444)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB444;
+       if (info->color_formats & DRM_EDID_FEATURE_RGB_YCRCB422)
+               info->color_formats = DRM_COLOR_FORMAT_YCRCB422;
+}
+
 /**
  * drm_add_edid_modes - add modes from EDID data, if available
  * @connector: connector we're probing
@@ -1460,8 +1518,7 @@ int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid)
        if (quirks & (EDID_QUIRK_PREFER_LARGE_60 | EDID_QUIRK_PREFER_LARGE_75))
                edid_fixup_preferred(connector, quirks);
 
-       connector->display_info.width_mm = edid->width_cm * 10;
-       connector->display_info.height_mm = edid->height_cm * 10;
+       drm_add_display_info(edid, &connector->display_info);
 
        return num_modes;
 }
index 11d7a72c22d9141697697db81b375e15a8a15f0b..802b61ac31390d92b2affaf14f787b75f8caab2f 100644 (file)
@@ -70,174 +70,50 @@ fail:
 }
 EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors);
 
-/**
- * drm_fb_helper_connector_parse_command_line - parse command line for connector
- * @connector - connector to parse line for
- * @mode_option - per connector mode option
- *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
- *
- * This uses the same parameters as the fb modedb.c, except for extra
- *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
- *
- * enable/enable Digital/disable bit at the end
- */
-static bool drm_fb_helper_connector_parse_command_line(struct drm_fb_helper_connector *fb_helper_conn,
-                                                      const char *mode_option)
-{
-       const char *name;
-       unsigned int namelen;
-       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
-       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
-       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
-       int i;
-       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
-       struct drm_connector *connector;
-
-       if (!fb_helper_conn)
-               return false;
-       connector = fb_helper_conn->connector;
-
-       cmdline_mode = &fb_helper_conn->cmdline_mode;
-       if (!mode_option)
-               mode_option = fb_mode_option;
-
-       if (!mode_option) {
-               cmdline_mode->specified = false;
-               return false;
-       }
-
-       name = mode_option;
-       namelen = strlen(name);
-       for (i = namelen-1; i >= 0; i--) {
-               switch (name[i]) {
-               case '@':
-                       namelen = i;
-                       if (!refresh_specified && !bpp_specified &&
-                           !yres_specified) {
-                               refresh = simple_strtol(&name[i+1], NULL, 10);
-                               refresh_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case '-':
-                       namelen = i;
-                       if (!bpp_specified && !yres_specified) {
-                               bpp = simple_strtol(&name[i+1], NULL, 10);
-                               bpp_specified = 1;
-                               if (cvt || rb)
-                                       cvt = 0;
-                       } else
-                               goto done;
-                       break;
-               case 'x':
-                       if (!yres_specified) {
-                               yres = simple_strtol(&name[i+1], NULL, 10);
-                               yres_specified = 1;
-                       } else
-                               goto done;
-               case '0' ... '9':
-                       break;
-               case 'M':
-                       if (!yres_specified)
-                               cvt = 1;
-                       break;
-               case 'R':
-                       if (cvt)
-                               rb = 1;
-                       break;
-               case 'm':
-                       if (!cvt)
-                               margins = 1;
-                       break;
-               case 'i':
-                       if (!cvt)
-                               interlace = 1;
-                       break;
-               case 'e':
-                       force = DRM_FORCE_ON;
-                       break;
-               case 'D':
-                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
-                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
-                               force = DRM_FORCE_ON;
-                       else
-                               force = DRM_FORCE_ON_DIGITAL;
-                       break;
-               case 'd':
-                       force = DRM_FORCE_OFF;
-                       break;
-               default:
-                       goto done;
-               }
-       }
-       if (i < 0 && yres_specified) {
-               xres = simple_strtol(name, NULL, 10);
-               res_specified = 1;
-       }
-done:
-
-       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
-               drm_get_connector_name(connector), xres, yres,
-               (refresh) ? refresh : 60, (rb) ? " reduced blanking" :
-               "", (margins) ? " with margins" : "", (interlace) ?
-               " interlaced" : "");
-
-       if (force) {
-               const char *s;
-               switch (force) {
-               case DRM_FORCE_OFF: s = "OFF"; break;
-               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
-               default:
-               case DRM_FORCE_ON: s = "ON"; break;
-               }
-
-               DRM_INFO("forcing %s connector %s\n",
-                        drm_get_connector_name(connector), s);
-               connector->force = force;
-       }
-
-       if (res_specified) {
-               cmdline_mode->specified = true;
-               cmdline_mode->xres = xres;
-               cmdline_mode->yres = yres;
-       }
-
-       if (refresh_specified) {
-               cmdline_mode->refresh_specified = true;
-               cmdline_mode->refresh = refresh;
-       }
-
-       if (bpp_specified) {
-               cmdline_mode->bpp_specified = true;
-               cmdline_mode->bpp = bpp;
-       }
-       cmdline_mode->rb = rb ? true : false;
-       cmdline_mode->cvt = cvt  ? true : false;
-       cmdline_mode->interlace = interlace ? true : false;
-
-       return true;
-}
-
 static int drm_fb_helper_parse_command_line(struct drm_fb_helper *fb_helper)
 {
        struct drm_fb_helper_connector *fb_helper_conn;
        int i;
 
        for (i = 0; i < fb_helper->connector_count; i++) {
+               struct drm_cmdline_mode *mode;
+               struct drm_connector *connector;
                char *option = NULL;
 
                fb_helper_conn = fb_helper->connector_info[i];
+               connector = fb_helper_conn->connector;
+               mode = &fb_helper_conn->cmdline_mode;
 
                /* do something on return - turn off connector maybe */
-               if (fb_get_options(drm_get_connector_name(fb_helper_conn->connector), &option))
+               if (fb_get_options(drm_get_connector_name(connector), &option))
                        continue;
 
-               drm_fb_helper_connector_parse_command_line(fb_helper_conn, option);
+               if (drm_mode_parse_command_line_for_connector(option,
+                                                             connector,
+                                                             mode)) {
+                       if (mode->force) {
+                               const char *s;
+                               switch (mode->force) {
+                               case DRM_FORCE_OFF: s = "OFF"; break;
+                               case DRM_FORCE_ON_DIGITAL: s = "ON - dig"; break;
+                               default:
+                               case DRM_FORCE_ON: s = "ON"; break;
+                               }
+
+                               DRM_INFO("forcing %s connector %s\n",
+                                        drm_get_connector_name(connector), s);
+                               connector->force = mode->force;
+                       }
+
+                       DRM_DEBUG_KMS("cmdline mode for connector %s %dx%d@%dHz%s%s%s\n",
+                                     drm_get_connector_name(connector),
+                                     mode->xres, mode->yres,
+                                     mode->refresh_specified ? mode->refresh : 60,
+                                     mode->rb ? " reduced blanking" : "",
+                                     mode->margins ? " with margins" : "",
+                                     mode->interlace ?  " interlaced" : "");
+               }
+
        }
        return 0;
 }
@@ -901,7 +777,7 @@ int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper,
        /* first up get a count of crtcs now in use and new min/maxes width/heights */
        for (i = 0; i < fb_helper->connector_count; i++) {
                struct drm_fb_helper_connector *fb_helper_conn = fb_helper->connector_info[i];
-               struct drm_fb_helper_cmdline_mode *cmdline_mode;
+               struct drm_cmdline_mode *cmdline_mode;
 
                cmdline_mode = &fb_helper_conn->cmdline_mode;
 
@@ -1123,7 +999,7 @@ static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_conn
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        cmdline_mode = &fb_connector->cmdline_mode;
        return cmdline_mode->specified;
 }
@@ -1131,7 +1007,7 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
                                                      int width, int height)
 {
-       struct drm_fb_helper_cmdline_mode *cmdline_mode;
+       struct drm_cmdline_mode *cmdline_mode;
        struct drm_display_mode *mode = NULL;
 
        cmdline_mode = &fb_helper_conn->cmdline_mode;
@@ -1163,19 +1039,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
        }
 
 create_mode:
-       if (cmdline_mode->cvt)
-               mode = drm_cvt_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->rb, cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       else
-               mode = drm_gtf_mode(fb_helper_conn->connector->dev,
-                                   cmdline_mode->xres, cmdline_mode->yres,
-                                   cmdline_mode->refresh_specified ? cmdline_mode->refresh : 60,
-                                   cmdline_mode->interlace,
-                                   cmdline_mode->margins);
-       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
+                                                cmdline_mode);
        list_add(&mode->head, &fb_helper_conn->connector->modes);
        return mode;
 }
@@ -1516,17 +1381,33 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 }
 EXPORT_SYMBOL(drm_fb_helper_initial_config);
 
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
+/**
+ * drm_fb_helper_hotplug_event - respond to a hotplug notification by
+ *                               probing all the outputs attached to the fb.
+ * @fb_helper: the drm_fb_helper
+ *
+ * LOCKING:
+ * Called at runtime, must take mode config lock.
+ *
+ * Scan the connectors attached to the fb_helper and try to put together a
+ * setup after *notification of a change in output configuration.
+ *
+ * RETURNS:
+ * 0 on success and a non-zero error code otherwise.
+ */
+int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 {
+       struct drm_device *dev = fb_helper->dev;
        int count = 0;
        u32 max_width, max_height, bpp_sel;
        bool bound = false, crtcs_bound = false;
        struct drm_crtc *crtc;
 
        if (!fb_helper->fb)
-               return false;
+               return 0;
 
-       list_for_each_entry(crtc, &fb_helper->dev->mode_config.crtc_list, head) {
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                if (crtc->fb)
                        crtcs_bound = true;
                if (crtc->fb == fb_helper->fb)
@@ -1535,7 +1416,8 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
 
        if (!bound && crtcs_bound) {
                fb_helper->delayed_hotplug = true;
-               return false;
+               mutex_unlock(&dev->mode_config.mutex);
+               return 0;
        }
        DRM_DEBUG_KMS("\n");
 
@@ -1546,6 +1428,7 @@ bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper)
        count = drm_fb_helper_probe_connector_modes(fb_helper, max_width,
                                                    max_height);
        drm_setup_crtcs(fb_helper);
+       mutex_unlock(&dev->mode_config.mutex);
 
        return drm_fb_helper_single_fb_probe(fb_helper, bpp_sel);
 }
index a1f12cb043deb233484f9a4957300fa475c3a024..2022a5c966bb050d89084a699cc6e6ab8508a026 100644 (file)
@@ -684,10 +684,11 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
         */
        *vblank_time = ns_to_timeval(timeval_to_ns(&raw_time) - delta_ns);
 
-       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %d.%d -> %d.%d [e %d us, %d rep]\n",
-                 crtc, (int) vbl_status, hpos, vpos, raw_time.tv_sec,
-                 raw_time.tv_usec, vblank_time->tv_sec, vblank_time->tv_usec,
-                 (int) duration_ns/1000, i);
+       DRM_DEBUG("crtc %d : v %d p(%d,%d)@ %ld.%ld -> %ld.%ld [e %d us, %d rep]\n",
+                 crtc, (int)vbl_status, hpos, vpos,
+                 (long)raw_time.tv_sec, (long)raw_time.tv_usec,
+                 (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
+                 (int)duration_ns/1000, i);
 
        vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
        if (invbl)
index 25bf87390f53bd86ed3bd32db419f1ecf65de732..c2d32f20e2fb606838f5799b538f57baa765ce9e 100644 (file)
@@ -974,3 +974,159 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
        }
 }
 EXPORT_SYMBOL(drm_mode_connector_list_update);
+
+/**
+ * drm_mode_parse_command_line_for_connector - parse command line for connector
+ * @mode_option - per connector mode option
+ * @connector - connector to parse line for
+ *
+ * This parses the connector specific then generic command lines for
+ * modes and options to configure the connector.
+ *
+ * This uses the same parameters as the fb modedb.c, except for extra
+ *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
+ *
+ * enable/enable Digital/disable bit at the end
+ */
+bool drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                              struct drm_connector *connector,
+                                              struct drm_cmdline_mode *mode)
+{
+       const char *name;
+       unsigned int namelen;
+       int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
+       unsigned int xres = 0, yres = 0, bpp = 32, refresh = 0;
+       int yres_specified = 0, cvt = 0, rb = 0, interlace = 0, margins = 0;
+       int i;
+       enum drm_connector_force force = DRM_FORCE_UNSPECIFIED;
+
+#ifdef CONFIG_FB
+       if (!mode_option)
+               mode_option = fb_mode_option;
+#endif
+
+       if (!mode_option) {
+               mode->specified = false;
+               return false;
+       }
+
+       name = mode_option;
+       namelen = strlen(name);
+       for (i = namelen-1; i >= 0; i--) {
+               switch (name[i]) {
+               case '@':
+                       namelen = i;
+                       if (!refresh_specified && !bpp_specified &&
+                           !yres_specified) {
+                               refresh = simple_strtol(&name[i+1], NULL, 10);
+                               refresh_specified = 1;
+                               if (cvt || rb)
+                                       cvt = 0;
+                       } else
+                               goto done;
+                       break;
+               case '-':
+                       namelen = i;
+                       if (!bpp_specified && !yres_specified) {
+                               bpp = simple_strtol(&name[i+1], NULL, 10);
+                               bpp_specified = 1;
+                               if (cvt || rb)
+                                       cvt = 0;
+                       } else
+                               goto done;
+                       break;
+               case 'x':
+                       if (!yres_specified) {
+                               yres = simple_strtol(&name[i+1], NULL, 10);
+                               yres_specified = 1;
+                       } else
+                               goto done;
+               case '0' ... '9':
+                       break;
+               case 'M':
+                       if (!yres_specified)
+                               cvt = 1;
+                       break;
+               case 'R':
+                       if (cvt)
+                               rb = 1;
+                       break;
+               case 'm':
+                       if (!cvt)
+                               margins = 1;
+                       break;
+               case 'i':
+                       if (!cvt)
+                               interlace = 1;
+                       break;
+               case 'e':
+                       force = DRM_FORCE_ON;
+                       break;
+               case 'D':
+                       if ((connector->connector_type != DRM_MODE_CONNECTOR_DVII) &&
+                           (connector->connector_type != DRM_MODE_CONNECTOR_HDMIB))
+                               force = DRM_FORCE_ON;
+                       else
+                               force = DRM_FORCE_ON_DIGITAL;
+                       break;
+               case 'd':
+                       force = DRM_FORCE_OFF;
+                       break;
+               default:
+                       goto done;
+               }
+       }
+       if (i < 0 && yres_specified) {
+               xres = simple_strtol(name, NULL, 10);
+               res_specified = 1;
+       }
+done:
+       if (res_specified) {
+               mode->specified = true;
+               mode->xres = xres;
+               mode->yres = yres;
+       }
+
+       if (refresh_specified) {
+               mode->refresh_specified = true;
+               mode->refresh = refresh;
+       }
+
+       if (bpp_specified) {
+               mode->bpp_specified = true;
+               mode->bpp = bpp;
+       }
+       mode->rb = rb ? true : false;
+       mode->cvt = cvt  ? true : false;
+       mode->interlace = interlace ? true : false;
+       mode->force = force;
+
+       return true;
+}
+EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
+
+struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd)
+{
+       struct drm_display_mode *mode;
+
+       if (cmd->cvt)
+               mode = drm_cvt_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->rb, cmd->interlace,
+                                   cmd->margins);
+       else
+               mode = drm_gtf_mode(dev,
+                                   cmd->xres, cmd->yres,
+                                   cmd->refresh_specified ? cmd->refresh : 60,
+                                   cmd->interlace,
+                                   cmd->margins);
+       if (!mode)
+               return NULL;
+
+       drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
+       return mode;
+}
+EXPORT_SYMBOL(drm_mode_create_from_cmdline_mode);
index 001273d57f2d689b6b08f9dd8916a10211b427a0..6d7b083c5b776d482d3b0a21f60a43adebd8f66d 100644 (file)
@@ -62,6 +62,26 @@ struct idr drm_minors_idr;
 struct class *drm_class;
 struct proc_dir_entry *drm_proc_root;
 struct dentry *drm_debugfs_root;
+
+int drm_err(const char *func, const char *format, ...)
+{
+       struct va_format vaf;
+       va_list args;
+       int r;
+
+       va_start(args, format);
+
+       vaf.fmt = format;
+       vaf.va = &args;
+
+       r = printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* %pV", func, &vaf);
+
+       va_end(args);
+
+       return r;
+}
+EXPORT_SYMBOL(drm_err);
+
 void drm_ut_debug_printk(unsigned int request_level,
                         const char *prefix,
                         const char *function_name,
@@ -78,6 +98,7 @@ void drm_ut_debug_printk(unsigned int request_level,
        }
 }
 EXPORT_SYMBOL(drm_ut_debug_printk);
+
 static int drm_minor_get_id(struct drm_device *dev, int type)
 {
        int new_id;
index fb5b4d426ae0793baa93836cffe2aaf93c6f9241..927442a11925f990fcb45b5cba763a3cb7d521bc 100644 (file)
@@ -214,9 +214,9 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
            i915_lvds_downclock) {
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = temp_downclock;
-               DRM_DEBUG_KMS("LVDS downclock is found in VBT. ",
-                               "Normal Clock %dKHz, downclock %dKHz\n",
-                               temp_downclock, panel_fixed_mode->clock);
+               DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
+                             "Normal Clock %dKHz, downclock %dKHz\n",
+                             temp_downclock, panel_fixed_mode->clock);
        }
        return;
 }
index 455d88578ea419dbc24701aa7b1f3ffa83725e66..311fffede6f8a3b42cdb131c73115394fc1dfd76 100644 (file)
@@ -3337,11 +3337,11 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
                1000;
        entries_required = DIV_ROUND_UP(entries_required, wm->cacheline_size);
 
-       DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
+       DRM_DEBUG_KMS("FIFO entries required for mode: %ld\n", entries_required);
 
        wm_size = fifo_size - (entries_required + wm->guard_size);
 
-       DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
+       DRM_DEBUG_KMS("FIFO watermark level: %ld\n", wm_size);
 
        /* Don't promote wm_size to unsigned... */
        if (wm_size > (long)wm->max_wm)
@@ -3663,13 +3663,13 @@ static bool g4x_check_srwm(struct drm_device *dev,
                      display_wm, cursor_wm);
 
        if (display_wm > display->max_wm) {
-               DRM_DEBUG_KMS("display watermark is too large(%d), disabling\n",
+               DRM_DEBUG_KMS("display watermark is too large(%d/%ld), disabling\n",
                              display_wm, display->max_wm);
                return false;
        }
 
        if (cursor_wm > cursor->max_wm) {
-               DRM_DEBUG_KMS("cursor watermark is too large(%d), disabling\n",
+               DRM_DEBUG_KMS("cursor watermark is too large(%d/%ld), disabling\n",
                              cursor_wm, cursor->max_wm);
                return false;
        }
index de70959b9ed51371a42eefccba299b76ab738274..ca1639918f57976b852bdcaab751d18402a882ad 100644 (file)
@@ -11,6 +11,8 @@ config DRM_NOUVEAU
        select FRAMEBUFFER_CONSOLE if !EXPERT
        select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
        select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
+       select ACPI_WMI if ACPI
+       select MXM_WMI if ACPI
        help
          Choose this option for open-source nVidia support.
 
index e12c97fd8db89790299836773533827a8d7af3ee..0583677e4581c2faa476f20a8a7a68acee2398b5 100644 (file)
@@ -20,6 +20,8 @@ nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \
              nv40_graph.o nv50_graph.o nvc0_graph.o \
              nv40_grctx.o nv50_grctx.o nvc0_grctx.o \
              nv84_crypt.o \
+             nva3_copy.o nvc0_copy.o \
+             nv40_mpeg.o nv50_mpeg.o \
              nv04_instmem.o nv50_instmem.o nvc0_instmem.o \
              nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \
              nv50_cursor.o nv50_display.o \
index a54238058dc54a5d75cb2bacb5b9467eccb7a8b4..f0d459bb46e4152a2f40c0fa2e0b54311c79a328 100644 (file)
@@ -4,6 +4,8 @@
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/video.h>
+#include <acpi/acpi.h>
+#include <linux/mxm-wmi.h>
 
 #include "drmP.h"
 #include "drm.h"
 
 static struct nouveau_dsm_priv {
        bool dsm_detected;
+       bool optimus_detected;
        acpi_handle dhandle;
        acpi_handle rom_handle;
 } nouveau_dsm_priv;
 
+#define NOUVEAU_DSM_HAS_MUX 0x1
+#define NOUVEAU_DSM_HAS_OPT 0x2
+
 static const char nouveau_dsm_muid[] = {
        0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
        0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
 };
 
+static const char nouveau_op_dsm_muid[] = {
+       0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
+       0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
+};
+
+static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
+{
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_object_list input;
+       union acpi_object params[4];
+       union acpi_object *obj;
+       int err;
+
+       input.count = 4;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_BUFFER;
+       params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
+       params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = 0x00000100;
+       params[2].type = ACPI_TYPE_INTEGER;
+       params[2].integer.value = func;
+       params[3].type = ACPI_TYPE_BUFFER;
+       params[3].buffer.length = 0;
+
+       err = acpi_evaluate_object(handle, "_DSM", &input, &output);
+       if (err) {
+               printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
+               return err;
+       }
+
+       obj = (union acpi_object *)output.pointer;
+
+       if (obj->type == ACPI_TYPE_INTEGER)
+               if (obj->integer.value == 0x80000002) {
+                       return -ENODEV;
+               }
+
+       if (obj->type == ACPI_TYPE_BUFFER) {
+               if (obj->buffer.length == 4 && result) {
+                       *result = 0;
+                       *result |= obj->buffer.pointer[0];
+                       *result |= (obj->buffer.pointer[1] << 8);
+                       *result |= (obj->buffer.pointer[2] << 16);
+                       *result |= (obj->buffer.pointer[3] << 24);
+               }
+       }
+
+       kfree(output.pointer);
+       return 0;
+}
+
 static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 {
        struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -92,6 +150,8 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
 
 static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
 {
+       mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
+       mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
        return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
 }
 
@@ -148,11 +208,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
        .get_client_id = nouveau_dsm_get_client_id,
 };
 
-static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
+static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
 {
        acpi_handle dhandle, nvidia_handle;
        acpi_status status;
-       int ret;
+       int ret, retval = 0;
        uint32_t result;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
@@ -166,11 +226,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
 
        ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
                          NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
-       if (ret < 0)
-               return false;
+       if (ret == 0)
+               retval |= NOUVEAU_DSM_HAS_MUX;
 
-       nouveau_dsm_priv.dhandle = dhandle;
-       return true;
+       ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
+       if (ret == 0)
+               retval |= NOUVEAU_DSM_HAS_OPT;
+
+       if (retval)
+               nouveau_dsm_priv.dhandle = dhandle;
+
+       return retval;
 }
 
 static bool nouveau_dsm_detect(void)
@@ -179,22 +245,42 @@ static bool nouveau_dsm_detect(void)
        struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
        struct pci_dev *pdev = NULL;
        int has_dsm = 0;
+       int has_optimus;
        int vga_count = 0;
+       bool guid_valid;
+       int retval;
+       bool ret = false;
+
+       /* lookup the MXM GUID */
+       guid_valid = mxm_wmi_supported();
 
+       if (guid_valid)
+               printk("MXM: GUID detected in BIOS\n");
+
+       /* now do DSM detection */
        while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
                vga_count++;
 
-               has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
+               retval = nouveau_dsm_pci_probe(pdev);
+               printk("ret val is %d\n", retval);
+               if (retval & NOUVEAU_DSM_HAS_MUX)
+                       has_dsm |= 1;
+               if (retval & NOUVEAU_DSM_HAS_OPT)
+                       has_optimus = 1;
        }
 
-       if (vga_count == 2 && has_dsm) {
+       if (vga_count == 2 && has_dsm && guid_valid) {
                acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
                printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
                       acpi_method_name);
                nouveau_dsm_priv.dsm_detected = true;
-               return true;
+               ret = true;
        }
-       return false;
+
+       if (has_optimus == 1)
+               nouveau_dsm_priv.optimus_detected = true;
+
+       return ret;
 }
 
 void nouveau_register_dsm_handler(void)
@@ -247,7 +333,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
        acpi_status status;
        acpi_handle dhandle, rom_handle;
 
-       if (!nouveau_dsm_priv.dsm_detected)
+       if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
                return false;
 
        dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
index 90aef64b76f277a649cd8e7caf79bfa40851cf3f..729d5fd7c88d246fda09dad22c599efad448623b 100644 (file)
@@ -5049,11 +5049,7 @@ int get_pll_limits(struct drm_device *dev, uint32_t limit_match, struct pll_lims
                pll_lim->vco1.max_n = record[11];
                pll_lim->min_p = record[12];
                pll_lim->max_p = record[13];
-               /* where did this go to?? */
-               if ((entry[0] & 0xf0) == 0x80)
-                       pll_lim->refclk = 27000;
-               else
-                       pll_lim->refclk = 100000;
+               pll_lim->refclk = ROM16(entry[9]) * 1000;
        }
 
        /*
@@ -6035,6 +6031,7 @@ parse_dcb_connector_table(struct nvbios *bios)
                case DCB_CONNECTOR_DVI_I:
                case DCB_CONNECTOR_DVI_D:
                case DCB_CONNECTOR_LVDS:
+               case DCB_CONNECTOR_LVDS_SPWG:
                case DCB_CONNECTOR_DP:
                case DCB_CONNECTOR_eDP:
                case DCB_CONNECTOR_HDMI_0:
index 8a54fa7edf5c18d692ecb2bfc94dfa1696800c43..050c314119dff4c0eb37fb36df860031ba61397c 100644 (file)
@@ -82,6 +82,7 @@ enum dcb_connector_type {
        DCB_CONNECTOR_DVI_I = 0x30,
        DCB_CONNECTOR_DVI_D = 0x31,
        DCB_CONNECTOR_LVDS = 0x40,
+       DCB_CONNECTOR_LVDS_SPWG = 0x41,
        DCB_CONNECTOR_DP = 0x46,
        DCB_CONNECTOR_eDP = 0x47,
        DCB_CONNECTOR_HDMI_0 = 0x60,
index 4cea35c57d15a4582ac0dfbd76add6b9934e9317..a7583a8ddb01f13dba3f12a43d1c263630cb261a 100644 (file)
@@ -268,9 +268,8 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
        unsigned long flags;
+       int i;
 
        /* decrement the refcount, and we're done if there's still refs */
        if (likely(!atomic_dec_and_test(&chan->users))) {
@@ -294,19 +293,12 @@ nouveau_channel_put_unlocked(struct nouveau_channel **pchan)
        /* boot it off the hardware */
        pfifo->reassign(dev, false);
 
-       /* We want to give pgraph a chance to idle and get rid of all
-        * potential errors. We need to do this without the context
-        * switch lock held, otherwise the irq handler is unable to
-        * process them.
-        */
-       if (pgraph->channel(dev) == chan)
-               nouveau_wait_for_idle(dev);
-
        /* destroy the engine specific contexts */
        pfifo->destroy_context(chan);
-       pgraph->destroy_context(chan);
-       if (pcrypt->destroy_context)
-               pcrypt->destroy_context(chan);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (chan->engctx[i])
+                       dev_priv->eng[i]->context_del(chan, i);
+       }
 
        pfifo->reassign(dev, true);
 
@@ -414,7 +406,7 @@ nouveau_ioctl_fifo_alloc(struct drm_device *dev, void *data,
        struct nouveau_channel *chan;
        int ret;
 
-       if (dev_priv->engine.graph.accel_blocked)
+       if (!dev_priv->eng[NVOBJ_ENGINE_GR])
                return -ENODEV;
 
        if (init->fb_ctxdma_handle == ~0 || init->tt_ctxdma_handle == ~0)
index 7ae151109a66f76eb467557f66f055c5ea7cb5c7..1595d0b6e8154544b0149b7053366fbf29baa880 100644 (file)
@@ -442,7 +442,7 @@ nouveau_connector_set_property(struct drm_connector *connector,
                }
 
                /* LVDS always needs gpu scaling */
-               if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS &&
+               if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
                    value == DRM_MODE_SCALE_NONE)
                        return -EINVAL;
 
@@ -650,6 +650,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
                ret = get_slave_funcs(encoder)->get_modes(encoder, connector);
 
        if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS ||
+           nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG ||
            nv_connector->dcb->type == DCB_CONNECTOR_eDP)
                ret += nouveau_connector_scaler_modes_add(connector);
 
@@ -810,6 +811,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                type = DRM_MODE_CONNECTOR_HDMIA;
                break;
        case DCB_CONNECTOR_LVDS:
+       case DCB_CONNECTOR_LVDS_SPWG:
                type = DRM_MODE_CONNECTOR_LVDS;
                funcs = &nouveau_connector_funcs_lvds;
                break;
@@ -838,7 +840,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
        drm_connector_helper_add(connector, &nouveau_connector_helper_funcs);
 
        /* Check if we need dithering enabled */
-       if (dcb->type == DCB_CONNECTOR_LVDS) {
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS) {
                bool dummy, is_24bit = false;
 
                ret = nouveau_bios_parse_lvds_table(dev, 0, &dummy, &is_24bit);
@@ -883,7 +885,7 @@ nouveau_connector_create(struct drm_device *dev, int index)
                                nv_connector->use_dithering ?
                                DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF);
 
-               if (dcb->type != DCB_CONNECTOR_LVDS) {
+               if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) {
                        if (dev_priv->card_type >= NV_50)
                                connector->polled = DRM_CONNECTOR_POLL_HPD;
                        else
index 764c15d537bac897d64eebfc791ba3db401fae67..eb514ea29377aee0f79a5073725b990e39800c7c 100644 (file)
@@ -276,7 +276,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        struct nouveau_fence *fence;
        int ret;
 
-       if (dev_priv->engine.graph.accel_blocked)
+       if (!dev_priv->channel)
                return -ENODEV;
 
        s = kzalloc(sizeof(*s), GFP_KERNEL);
index 155ebdcbf06fe2ab1d41f047733a307dd9656389..02c6f37d8bd78b4685ddd07a87c24a3a2ebd4e3c 100644 (file)
@@ -162,11 +162,10 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct drm_crtc *crtc;
-       int ret, i;
+       int ret, i, e;
 
        if (pm_state.event == PM_EVENT_PRETHAW)
                return 0;
@@ -206,12 +205,17 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
                        nouveau_channel_idle(chan);
        }
 
-       pgraph->fifo_access(dev, false);
-       nouveau_wait_for_idle(dev);
        pfifo->reassign(dev, false);
        pfifo->disable(dev);
        pfifo->unload_context(dev);
-       pgraph->unload_context(dev);
+
+       for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+               if (dev_priv->eng[e]) {
+                       ret = dev_priv->eng[e]->fini(dev, e);
+                       if (ret)
+                               goto out_abort;
+               }
+       }
 
        ret = pinstmem->suspend(dev);
        if (ret) {
@@ -242,9 +246,12 @@ nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state)
 
 out_abort:
        NV_INFO(dev, "Re-enabling acceleration..\n");
+       for (e = e + 1; e < NVOBJ_ENGINE_NR; e++) {
+               if (dev_priv->eng[e])
+                       dev_priv->eng[e]->init(dev, e);
+       }
        pfifo->enable(dev);
        pfifo->reassign(dev, true);
-       pgraph->fifo_access(dev, true);
        return ret;
 }
 
@@ -299,8 +306,10 @@ nouveau_pci_resume(struct pci_dev *pdev)
        engine->mc.init(dev);
        engine->timer.init(dev);
        engine->fb.init(dev);
-       engine->graph.init(dev);
-       engine->crypt.init(dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (dev_priv->eng[i])
+                       dev_priv->eng[i]->init(dev, i);
+       }
        engine->fifo.init(dev);
 
        nouveau_irq_postinstall(dev);
index a76514a209b369880ac8b5ced881bb337a186695..9c56331941e2430cd2dda20ca9c3ab06a6b1c0cf 100644 (file)
@@ -150,13 +150,12 @@ enum nouveau_flags {
 
 #define NVOBJ_ENGINE_SW                0
 #define NVOBJ_ENGINE_GR                1
-#define NVOBJ_ENGINE_PPP       2
-#define NVOBJ_ENGINE_COPY      3
-#define NVOBJ_ENGINE_VP                4
-#define NVOBJ_ENGINE_CRYPT      5
-#define NVOBJ_ENGINE_BSP       6
-#define NVOBJ_ENGINE_DISPLAY   0xcafe0001
-#define NVOBJ_ENGINE_INT       0xdeadbeef
+#define NVOBJ_ENGINE_CRYPT     2
+#define NVOBJ_ENGINE_COPY0     3
+#define NVOBJ_ENGINE_COPY1     4
+#define NVOBJ_ENGINE_MPEG      5
+#define NVOBJ_ENGINE_DISPLAY   15
+#define NVOBJ_ENGINE_NR                16
 
 #define NVOBJ_FLAG_DONT_MAP             (1 << 0)
 #define NVOBJ_FLAG_ZERO_ALLOC          (1 << 1)
@@ -245,11 +244,8 @@ struct nouveau_channel {
        struct nouveau_gpuobj *cache;
        void *fifo_priv;
 
-       /* PGRAPH context */
-       /* XXX may be merge 2 pointers as private data ??? */
-       struct nouveau_gpuobj *ramin_grctx;
-       struct nouveau_gpuobj *crypt_ctx;
-       void *pgraph_ctx;
+       /* Execution engine contexts */
+       void *engctx[NVOBJ_ENGINE_NR];
 
        /* NV50 VM */
        struct nouveau_vm     *vm;
@@ -298,6 +294,18 @@ struct nouveau_channel {
        } debugfs;
 };
 
+struct nouveau_exec_engine {
+       void (*destroy)(struct drm_device *, int engine);
+       int  (*init)(struct drm_device *, int engine);
+       int  (*fini)(struct drm_device *, int engine);
+       int  (*context_new)(struct nouveau_channel *, int engine);
+       void (*context_del)(struct nouveau_channel *, int engine);
+       int  (*object_new)(struct nouveau_channel *, int engine,
+                          u32 handle, u16 class);
+       void (*set_tile_region)(struct drm_device *dev, int i);
+       void (*tlb_flush)(struct drm_device *, int engine);
+};
+
 struct nouveau_instmem_engine {
        void    *priv;
 
@@ -364,30 +372,6 @@ struct nouveau_fifo_engine {
        void (*tlb_flush)(struct drm_device *dev);
 };
 
-struct nouveau_pgraph_engine {
-       bool accel_blocked;
-       bool registered;
-       int grctx_size;
-       void *priv;
-
-       /* NV2x/NV3x context table (0x400780) */
-       struct nouveau_gpuobj *ctx_table;
-
-       int  (*init)(struct drm_device *);
-       void (*takedown)(struct drm_device *);
-
-       void (*fifo_access)(struct drm_device *, bool);
-
-       struct nouveau_channel *(*channel)(struct drm_device *);
-       int  (*create_context)(struct nouveau_channel *);
-       void (*destroy_context)(struct nouveau_channel *);
-       int  (*load_context)(struct nouveau_channel *);
-       int  (*unload_context)(struct drm_device *);
-       void (*tlb_flush)(struct drm_device *dev);
-
-       void (*set_tile_region)(struct drm_device *dev, int i);
-};
-
 struct nouveau_display_engine {
        void *priv;
        int (*early_init)(struct drm_device *);
@@ -426,6 +410,19 @@ struct nouveau_pm_voltage {
        int nr_level;
 };
 
+struct nouveau_pm_memtiming {
+       int id;
+       u32 reg_100220;
+       u32 reg_100224;
+       u32 reg_100228;
+       u32 reg_10022c;
+       u32 reg_100230;
+       u32 reg_100234;
+       u32 reg_100238;
+       u32 reg_10023c;
+       u32 reg_100240;
+};
+
 #define NOUVEAU_PM_MAX_LEVEL 8
 struct nouveau_pm_level {
        struct device_attribute dev_attr;
@@ -436,11 +433,13 @@ struct nouveau_pm_level {
        u32 memory;
        u32 shader;
        u32 unk05;
+       u32 unk0a;
 
        u8 voltage;
        u8 fanspeed;
 
        u16 memscript;
+       struct nouveau_pm_memtiming *timing;
 };
 
 struct nouveau_pm_temp_sensor_constants {
@@ -457,17 +456,6 @@ struct nouveau_pm_threshold_temp {
        s16 fan_boost;
 };
 
-struct nouveau_pm_memtiming {
-       u32 reg_100220;
-       u32 reg_100224;
-       u32 reg_100228;
-       u32 reg_10022c;
-       u32 reg_100230;
-       u32 reg_100234;
-       u32 reg_100238;
-       u32 reg_10023c;
-};
-
 struct nouveau_pm_memtimings {
        bool supported;
        struct nouveau_pm_memtiming *timing;
@@ -499,16 +487,6 @@ struct nouveau_pm_engine {
        int (*temp_get)(struct drm_device *);
 };
 
-struct nouveau_crypt_engine {
-       bool registered;
-
-       int  (*init)(struct drm_device *);
-       void (*takedown)(struct drm_device *);
-       int  (*create_context)(struct nouveau_channel *);
-       void (*destroy_context)(struct nouveau_channel *);
-       void (*tlb_flush)(struct drm_device *dev);
-};
-
 struct nouveau_vram_engine {
        int  (*init)(struct drm_device *);
        int  (*get)(struct drm_device *, u64, u32 align, u32 size_nc,
@@ -523,12 +501,10 @@ struct nouveau_engine {
        struct nouveau_mc_engine      mc;
        struct nouveau_timer_engine   timer;
        struct nouveau_fb_engine      fb;
-       struct nouveau_pgraph_engine  graph;
        struct nouveau_fifo_engine    fifo;
        struct nouveau_display_engine display;
        struct nouveau_gpio_engine    gpio;
        struct nouveau_pm_engine      pm;
-       struct nouveau_crypt_engine   crypt;
        struct nouveau_vram_engine    vram;
 };
 
@@ -637,6 +613,7 @@ struct drm_nouveau_private {
        enum nouveau_card_type card_type;
        /* exact chipset, derived from NV_PMC_BOOT_0 */
        int chipset;
+       int stepping;
        int flags;
 
        void __iomem *mmio;
@@ -647,6 +624,7 @@ struct drm_nouveau_private {
        u32 ramin_base;
        bool ramin_available;
        struct drm_mm ramin_heap;
+       struct nouveau_exec_engine *eng[NVOBJ_ENGINE_NR];
        struct list_head gpuobj_list;
        struct list_head classes;
 
@@ -745,10 +723,6 @@ struct drm_nouveau_private {
        uint32_t crtc_owner;
        uint32_t dac_users[4];
 
-       struct nouveau_suspend_resume {
-               uint32_t *ramin_copy;
-       } susres;
-
        struct backlight_device *backlight;
 
        struct {
@@ -757,8 +731,6 @@ struct drm_nouveau_private {
 
        struct nouveau_fbdev *nfbdev;
        struct apertures_struct *apertures;
-
-       bool powered_down;
 };
 
 static inline struct drm_nouveau_private *
@@ -883,17 +855,27 @@ extern void nouveau_channel_ref(struct nouveau_channel *chan,
 extern void nouveau_channel_idle(struct nouveau_channel *chan);
 
 /* nouveau_object.c */
-#define NVOBJ_CLASS(d,c,e) do {                                                \
+#define NVOBJ_ENGINE_ADD(d, e, p) do {                                         \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = (p);                                 \
+} while (0)
+
+#define NVOBJ_ENGINE_DEL(d, e) do {                                            \
+       struct drm_nouveau_private *dev_priv = (d)->dev_private;               \
+       dev_priv->eng[NVOBJ_ENGINE_##e] = NULL;                                \
+} while (0)
+
+#define NVOBJ_CLASS(d, c, e) do {                                              \
        int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e);        \
        if (ret)                                                               \
                return ret;                                                    \
-} while(0)
+} while (0)
 
-#define NVOBJ_MTHD(d,c,m,e) do {                                               \
+#define NVOBJ_MTHD(d, c, m, e) do {                                            \
        int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e));                 \
        if (ret)                                                               \
                return ret;                                                    \
-} while(0)
+} while (0)
 
 extern int  nouveau_gpuobj_early_init(struct drm_device *);
 extern int  nouveau_gpuobj_init(struct drm_device *);
@@ -903,7 +885,7 @@ extern void nouveau_gpuobj_resume(struct drm_device *dev);
 extern int  nouveau_gpuobj_class_new(struct drm_device *, u32 class, u32 eng);
 extern int  nouveau_gpuobj_mthd_new(struct drm_device *, u32 class, u32 mthd,
                                    int (*exec)(struct nouveau_channel *,
-                                               u32 class, u32 mthd, u32 data));
+                                               u32 class, u32 mthd, u32 data));
 extern int  nouveau_gpuobj_mthd_call(struct nouveau_channel *, u32, u32, u32);
 extern int  nouveau_gpuobj_mthd_call2(struct drm_device *, int, u32, u32, u32);
 extern int nouveau_gpuobj_channel_init(struct nouveau_channel *,
@@ -1137,81 +1119,50 @@ extern int  nvc0_fifo_load_context(struct nouveau_channel *);
 extern int  nvc0_fifo_unload_context(struct drm_device *);
 
 /* nv04_graph.c */
-extern int  nv04_graph_init(struct drm_device *);
-extern void nv04_graph_takedown(struct drm_device *);
+extern int  nv04_graph_create(struct drm_device *);
 extern void nv04_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv04_graph_channel(struct drm_device *);
-extern int  nv04_graph_create_context(struct nouveau_channel *);
-extern void nv04_graph_destroy_context(struct nouveau_channel *);
-extern int  nv04_graph_load_context(struct nouveau_channel *);
-extern int  nv04_graph_unload_context(struct drm_device *);
+extern int  nv04_graph_object_new(struct nouveau_channel *, int, u32, u16);
 extern int  nv04_graph_mthd_page_flip(struct nouveau_channel *chan,
                                      u32 class, u32 mthd, u32 data);
 extern struct nouveau_bitfield nv04_graph_nsource[];
 
 /* nv10_graph.c */
-extern int  nv10_graph_init(struct drm_device *);
-extern void nv10_graph_takedown(struct drm_device *);
+extern int  nv10_graph_create(struct drm_device *);
 extern struct nouveau_channel *nv10_graph_channel(struct drm_device *);
-extern int  nv10_graph_create_context(struct nouveau_channel *);
-extern void nv10_graph_destroy_context(struct nouveau_channel *);
-extern int  nv10_graph_load_context(struct nouveau_channel *);
-extern int  nv10_graph_unload_context(struct drm_device *);
-extern void nv10_graph_set_tile_region(struct drm_device *dev, int i);
 extern struct nouveau_bitfield nv10_graph_intr[];
 extern struct nouveau_bitfield nv10_graph_nstatus[];
 
 /* nv20_graph.c */
-extern int  nv20_graph_create_context(struct nouveau_channel *);
-extern void nv20_graph_destroy_context(struct nouveau_channel *);
-extern int  nv20_graph_load_context(struct nouveau_channel *);
-extern int  nv20_graph_unload_context(struct drm_device *);
-extern int  nv20_graph_init(struct drm_device *);
-extern void nv20_graph_takedown(struct drm_device *);
-extern int  nv30_graph_init(struct drm_device *);
-extern void nv20_graph_set_tile_region(struct drm_device *dev, int i);
+extern int  nv20_graph_create(struct drm_device *);
 
 /* nv40_graph.c */
-extern int  nv40_graph_init(struct drm_device *);
-extern void nv40_graph_takedown(struct drm_device *);
-extern struct nouveau_channel *nv40_graph_channel(struct drm_device *);
-extern int  nv40_graph_create_context(struct nouveau_channel *);
-extern void nv40_graph_destroy_context(struct nouveau_channel *);
-extern int  nv40_graph_load_context(struct nouveau_channel *);
-extern int  nv40_graph_unload_context(struct drm_device *);
+extern int  nv40_graph_create(struct drm_device *);
 extern void nv40_grctx_init(struct nouveau_grctx *);
-extern void nv40_graph_set_tile_region(struct drm_device *dev, int i);
 
 /* nv50_graph.c */
-extern int  nv50_graph_init(struct drm_device *);
-extern void nv50_graph_takedown(struct drm_device *);
-extern void nv50_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nv50_graph_channel(struct drm_device *);
-extern int  nv50_graph_create_context(struct nouveau_channel *);
-extern void nv50_graph_destroy_context(struct nouveau_channel *);
-extern int  nv50_graph_load_context(struct nouveau_channel *);
-extern int  nv50_graph_unload_context(struct drm_device *);
+extern int  nv50_graph_create(struct drm_device *);
 extern int  nv50_grctx_init(struct nouveau_grctx *);
-extern void nv50_graph_tlb_flush(struct drm_device *dev);
-extern void nv84_graph_tlb_flush(struct drm_device *dev);
 extern struct nouveau_enum nv50_data_error_names[];
+extern int  nv50_graph_isr_chid(struct drm_device *dev, u64 inst);
 
 /* nvc0_graph.c */
-extern int  nvc0_graph_init(struct drm_device *);
-extern void nvc0_graph_takedown(struct drm_device *);
-extern void nvc0_graph_fifo_access(struct drm_device *, bool);
-extern struct nouveau_channel *nvc0_graph_channel(struct drm_device *);
-extern int  nvc0_graph_create_context(struct nouveau_channel *);
-extern void nvc0_graph_destroy_context(struct nouveau_channel *);
-extern int  nvc0_graph_load_context(struct nouveau_channel *);
-extern int  nvc0_graph_unload_context(struct drm_device *);
+extern int  nvc0_graph_create(struct drm_device *);
+extern int  nvc0_graph_isr_chid(struct drm_device *dev, u64 inst);
 
 /* nv84_crypt.c */
-extern int  nv84_crypt_init(struct drm_device *dev);
-extern void nv84_crypt_fini(struct drm_device *dev);
-extern int  nv84_crypt_create_context(struct nouveau_channel *);
-extern void nv84_crypt_destroy_context(struct nouveau_channel *);
-extern void nv84_crypt_tlb_flush(struct drm_device *dev);
+extern int  nv84_crypt_create(struct drm_device *);
+
+/* nva3_copy.c */
+extern int  nva3_copy_create(struct drm_device *dev);
+
+/* nvc0_copy.c */
+extern int  nvc0_copy_create(struct drm_device *dev, int engine);
+
+/* nv40_mpeg.c */
+extern int  nv40_mpeg_create(struct drm_device *dev);
+
+/* nv50_mpeg.c */
+extern int  nv50_mpeg_create(struct drm_device *dev);
 
 /* nv04_instmem.c */
 extern int  nv04_instmem_init(struct drm_device *);
@@ -1402,8 +1353,8 @@ bool nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on);
 /* nv50_calc. */
 int nv50_calc_pll(struct drm_device *, struct pll_lims *, int clk,
                  int *N1, int *M1, int *N2, int *M2, int *P);
-int nv50_calc_pll2(struct drm_device *, struct pll_lims *,
-                  int clk, int *N, int *fN, int *M, int *P);
+int nva3_calc_pll(struct drm_device *, struct pll_lims *,
+                 int clk, int *N, int *fN, int *M, int *P);
 
 #ifndef ioread32_native
 #ifdef __BIG_ENDIAN
@@ -1579,6 +1530,13 @@ nv_match_device(struct drm_device *dev, unsigned device,
                dev->pdev->subsystem_device == sub_device;
 }
 
+static inline void *
+nv_engine(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       return (void *)dev_priv->eng[engine];
+}
+
 /* returns 1 if device is one of the nv4x using the 0x4497 object class,
  * helpful to determine a number of other hardware features
  */
index 4a8ad1307fa49403f53e5768488afd7e4b49f8c9..86c2e374e938e644070f533214bbd6038e72eaf3 100644 (file)
@@ -87,10 +87,10 @@ _cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
        cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
                    (state ? 0 : CP_BRA_IF_CLEAR));
 }
-#define cp_bra(c,f,s,n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
 #ifdef CP_BRA_MOD
-#define cp_cal(c,f,s,n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c,f,s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
 #endif
 
 static inline void
@@ -98,14 +98,14 @@ _cp_wait(struct nouveau_grctx *ctx, int flag, int state)
 {
        cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
 }
-#define cp_wait(c,f,s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
 
 static inline void
 _cp_set(struct nouveau_grctx *ctx, int flag, int state)
 {
        cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
 }
-#define cp_set(c,f,s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
 
 static inline void
 cp_pos(struct nouveau_grctx *ctx, int offset)
index 5045f8b921d644088ef4d8345dda673fadfba424..2960f583dc389fac112de1d4ad7ee615a0d6ca31 100644 (file)
@@ -51,8 +51,7 @@ nv10_mem_update_tile_region(struct drm_device *dev,
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       int i = tile - dev_priv->tile.reg;
+       int i = tile - dev_priv->tile.reg, j;
        unsigned long save;
 
        nouveau_fence_unref(&tile->fence);
@@ -70,7 +69,10 @@ nv10_mem_update_tile_region(struct drm_device *dev,
        nouveau_wait_for_idle(dev);
 
        pfb->set_tile_region(dev, i);
-       pgraph->set_tile_region(dev, i);
+       for (j = 0; j < NVOBJ_ENGINE_NR; j++) {
+               if (dev_priv->eng[j] && dev_priv->eng[j]->set_tile_region)
+                       dev_priv->eng[j]->set_tile_region(dev, i);
+       }
 
        pfifo->cache_pull(dev, true);
        pfifo->reassign(dev, true);
@@ -152,8 +154,6 @@ nouveau_mem_vram_fini(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       nouveau_bo_ref(NULL, &dev_priv->vga_ram);
-
        ttm_bo_device_release(&dev_priv->ttm.bdev);
 
        nouveau_ttm_global_release(dev_priv);
@@ -597,10 +597,10 @@ nouveau_mem_timing_init(struct drm_device *dev)
        if (!memtimings->timing)
                return;
 
-       /* Get "some number" from the timing reg for NV_40
+       /* Get "some number" from the timing reg for NV_40 and NV_50
         * Used in calculations later */
-       if(dev_priv->card_type == NV_40) {
-               magic_number = (nv_rd32(dev,0x100228) & 0x0f000000) >> 24;
+       if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) {
+               magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24;
        }
 
        entry = mem + mem[1];
@@ -643,51 +643,68 @@ nouveau_mem_timing_init(struct drm_device *dev)
                /* XXX: I don't trust the -1's and +1's... they must come
                 *      from somewhere! */
                timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 |
-                                     tUNK_18 << 16 |
+                                     max(tUNK_18, (u8) 1) << 16 |
                                      (tUNK_1 + tUNK_19 + 1 + magic_number) << 8;
-               if(dev_priv->chipset == 0xa8) {
+               if (dev_priv->chipset == 0xa8) {
                        timing->reg_100224 |= (tUNK_2 - 1);
                } else {
                        timing->reg_100224 |= (tUNK_2 + 2 - magic_number);
                }
 
                timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10);
-               if(dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) {
+               if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa)
                        timing->reg_100228 |= (tUNK_19 - 1) << 24;
-               }
+               else
+                       timing->reg_100228 |= magic_number << 24;
 
-               if(dev_priv->card_type == NV_40) {
+               if (dev_priv->card_type == NV_40) {
                        /* NV40: don't know what the rest of the regs are..
                         * And don't need to know either */
-                       timing->reg_100228 |= 0x20200000 | magic_number << 24;
-               } else if(dev_priv->card_type >= NV_50) {
-                       /* XXX: reg_10022c */
-                       timing->reg_10022c = tUNK_2 - 1;
+                       timing->reg_100228 |= 0x20200000;
+               } else if (dev_priv->card_type >= NV_50) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
+                               timing->reg_10022c = (0x14 + tUNK_2) << 24 |
+                                                    0x16 << 16 |
+                                                    (tUNK_2 - 1) << 8 |
+                                                    (tUNK_2 - 1);
+                       } else {
+                               /* XXX: reg_10022c for recentish cards */
+                               timing->reg_10022c = tUNK_2 - 1;
+                       }
 
                        timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 |
                                                  tUNK_13 << 8  | tUNK_13);
 
                        timing->reg_100234 = (tRAS << 24 | tRC);
-                       timing->reg_100234 += max(tUNK_10,tUNK_11) << 16;
+                       timing->reg_100234 += max(tUNK_10, tUNK_11) << 16;
 
-                       if(dev_priv->chipset < 0xa3) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
                                timing->reg_100234 |= (tUNK_2 + 2) << 8;
                        } else {
                                /* XXX: +6? */
                                timing->reg_100234 |= (tUNK_19 + 6) << 8;
                        }
 
-                       /* XXX; reg_100238, reg_10023c
-                        * reg_100238: 0x00??????
-                        * reg_10023c: 0x!!??0202 for NV50+ cards (empirical evidence) */
+                       /* XXX; reg_100238
+                        * reg_100238: 0x00?????? */
                        timing->reg_10023c = 0x202;
-                       if(dev_priv->chipset < 0xa3) {
+                       if (dev_priv->chipset < 0x98 ||
+                           (dev_priv->chipset == 0x98 &&
+                            dev_priv->stepping <= 0xa1)) {
                                timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16;
                        } else {
-                               /* currently unknown
+                               /* XXX: reg_10023c
+                                * currently unknown
                                 * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */
                        }
+
+                       /* XXX: reg_100240? */
                }
+               timing->id = i;
 
                NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i,
                         timing->reg_100220, timing->reg_100224,
@@ -695,10 +712,11 @@ nouveau_mem_timing_init(struct drm_device *dev)
                NV_DEBUG(dev, "         230: %08x %08x %08x %08x\n",
                         timing->reg_100230, timing->reg_100234,
                         timing->reg_100238, timing->reg_10023c);
+               NV_DEBUG(dev, "         240: %08x\n", timing->reg_100240);
        }
 
        memtimings->nr_timing = entries;
-       memtimings->supported = true;
+       memtimings->supported = (dev_priv->chipset <= 0x98);
 }
 
 void
index 67a16e01ffa6db3030fd789d500dafd9b03eaf54..8f97016f5b2648a22fbdb1197f6e26168b1851b2 100644 (file)
@@ -361,20 +361,6 @@ nouveau_gpuobj_new_fake(struct drm_device *dev, u32 pinst, u64 vinst,
        return 0;
 }
 
-
-static uint32_t
-nouveau_gpuobj_class_instmem_size(struct drm_device *dev, int class)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       /*XXX: dodgy hack for now */
-       if (dev_priv->card_type >= NV_50)
-               return 24;
-       if (dev_priv->card_type >= NV_40)
-               return 32;
-       return 16;
-}
-
 /*
    DMA objects are used to reference a piece of memory in the
    framebuffer, PCI or AGP address space. Each object is 16 bytes big
@@ -606,11 +592,11 @@ nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base,
    set to 0?
 */
 static int
-nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
-                     struct nouveau_gpuobj **gpuobj_ret)
+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, u32 handle, u16 class)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct nouveau_gpuobj *gpuobj;
+       int ret;
 
        gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL);
        if (!gpuobj)
@@ -624,8 +610,10 @@ nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class,
        spin_lock(&dev_priv->ramin_lock);
        list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list);
        spin_unlock(&dev_priv->ramin_lock);
-       *gpuobj_ret = gpuobj;
-       return 0;
+
+       ret = nouveau_ramht_insert(chan, handle, gpuobj);
+       nouveau_gpuobj_ref(NULL, &gpuobj);
+       return ret;
 }
 
 int
@@ -634,101 +622,30 @@ nouveau_gpuobj_gr_new(struct nouveau_channel *chan, u32 handle, int class)
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
        struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj_class *oc;
-       struct nouveau_gpuobj *gpuobj;
        int ret;
 
        NV_DEBUG(dev, "ch%d class=0x%04x\n", chan->id, class);
 
        list_for_each_entry(oc, &dev_priv->classes, head) {
-               if (oc->id == class)
-                       goto found;
-       }
-
-       NV_ERROR(dev, "illegal object class: 0x%x\n", class);
-       return -EINVAL;
+               struct nouveau_exec_engine *eng = dev_priv->eng[oc->engine];
 
-found:
-       switch (oc->engine) {
-       case NVOBJ_ENGINE_SW:
-               if (dev_priv->card_type < NV_C0) {
-                       ret = nouveau_gpuobj_sw_new(chan, class, &gpuobj);
-                       if (ret)
-                               return ret;
-                       goto insert;
-               }
-               break;
-       case NVOBJ_ENGINE_GR:
-               if ((dev_priv->card_type >= NV_20 && !chan->ramin_grctx) ||
-                   (dev_priv->card_type  < NV_20 && !chan->pgraph_ctx)) {
-                       struct nouveau_pgraph_engine *pgraph =
-                               &dev_priv->engine.graph;
+               if (oc->id != class)
+                       continue;
 
-                       ret = pgraph->create_context(chan);
-                       if (ret)
-                               return ret;
-               }
-               break;
-       case NVOBJ_ENGINE_CRYPT:
-               if (!chan->crypt_ctx) {
-                       struct nouveau_crypt_engine *pcrypt =
-                               &dev_priv->engine.crypt;
+               if (oc->engine == NVOBJ_ENGINE_SW)
+                       return nouveau_gpuobj_sw_new(chan, handle, class);
 
-                       ret = pcrypt->create_context(chan);
+               if (!chan->engctx[oc->engine]) {
+                       ret = eng->context_new(chan, oc->engine);
                        if (ret)
                                return ret;
                }
-               break;
-       }
-
-       /* we're done if this is fermi */
-       if (dev_priv->card_type >= NV_C0)
-               return 0;
-
-       ret = nouveau_gpuobj_new(dev, chan,
-                                nouveau_gpuobj_class_instmem_size(dev, class),
-                                16,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &gpuobj);
-       if (ret) {
-               NV_ERROR(dev, "error creating gpuobj: %d\n", ret);
-               return ret;
-       }
 
-       if (dev_priv->card_type >= NV_50) {
-               nv_wo32(gpuobj,  0, class);
-               nv_wo32(gpuobj, 20, 0x00010000);
-       } else {
-               switch (class) {
-               case NV_CLASS_NULL:
-                       nv_wo32(gpuobj, 0, 0x00001030);
-                       nv_wo32(gpuobj, 4, 0xFFFFFFFF);
-                       break;
-               default:
-                       if (dev_priv->card_type >= NV_40) {
-                               nv_wo32(gpuobj, 0, class);
-#ifdef __BIG_ENDIAN
-                               nv_wo32(gpuobj, 8, 0x01000000);
-#endif
-                       } else {
-#ifdef __BIG_ENDIAN
-                               nv_wo32(gpuobj, 0, class | 0x00080000);
-#else
-                               nv_wo32(gpuobj, 0, class);
-#endif
-                       }
-               }
+               return eng->object_new(chan, oc->engine, handle, class);
        }
-       dev_priv->engine.instmem.flush(dev);
-
-       gpuobj->engine = oc->engine;
-       gpuobj->class  = oc->id;
 
-insert:
-       ret = nouveau_ramht_insert(chan, handle, gpuobj);
-       if (ret)
-               NV_ERROR(dev, "error adding gpuobj to RAMHT: %d\n", ret);
-       nouveau_gpuobj_ref(NULL, &gpuobj);
-       return ret;
+       NV_ERROR(dev, "illegal object class: 0x%x\n", class);
+       return -EINVAL;
 }
 
 static int
@@ -746,9 +663,6 @@ nouveau_gpuobj_channel_init_pramin(struct nouveau_channel *chan)
        size = 0x2000;
        base = 0;
 
-       /* PGRAPH context */
-       size += dev_priv->engine.graph.grctx_size;
-
        if (dev_priv->card_type == NV_50) {
                /* Various fixed table thingos */
                size += 0x1400; /* mostly unknown stuff */
index 670e3cb697ec7664921e1fc87f57fa6fa40cd68e..922fb6b664edda718e2e15f929500a2fe3967d21 100644 (file)
@@ -72,6 +72,68 @@ legacy_perf_init(struct drm_device *dev)
        pm->nr_perflvl = 1;
 }
 
+static struct nouveau_pm_memtiming *
+nouveau_perf_timing(struct drm_device *dev, struct bit_entry *P,
+                   u16 memclk, u8 *entry, u8 recordlen, u8 entries)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_pm_engine *pm = &dev_priv->engine.pm;
+       struct nvbios *bios = &dev_priv->vbios;
+       u8 ramcfg;
+       int i;
+
+       /* perf v2 has a separate "timing map" table, we have to match
+        * the target memory clock to a specific entry, *then* use
+        * ramcfg to select the correct subentry
+        */
+       if (P->version == 2) {
+               u8 *tmap = ROMPTR(bios, P->data[4]);
+               if (!tmap) {
+                       NV_DEBUG(dev, "no timing map pointer\n");
+                       return NULL;
+               }
+
+               if (tmap[0] != 0x10) {
+                       NV_WARN(dev, "timing map 0x%02x unknown\n", tmap[0]);
+                       return NULL;
+               }
+
+               entry = tmap + tmap[1];
+               recordlen = tmap[2] + (tmap[4] * tmap[3]);
+               for (i = 0; i < tmap[5]; i++, entry += recordlen) {
+                       if (memclk >= ROM16(entry[0]) &&
+                           memclk <= ROM16(entry[2]))
+                               break;
+               }
+
+               if (i == tmap[5]) {
+                       NV_WARN(dev, "no match in timing map table\n");
+                       return NULL;
+               }
+
+               entry += tmap[2];
+               recordlen = tmap[3];
+               entries   = tmap[4];
+       }
+
+       ramcfg = (nv_rd32(dev, NV_PEXTDEV_BOOT_0) & 0x0000003c) >> 2;
+       if (bios->ram_restrict_tbl_ptr)
+               ramcfg = bios->data[bios->ram_restrict_tbl_ptr + ramcfg];
+
+       if (ramcfg >= entries) {
+               NV_WARN(dev, "ramcfg strap out of bounds!\n");
+               return NULL;
+       }
+
+       entry += ramcfg * recordlen;
+       if (entry[1] >= pm->memtimings.nr_timing) {
+               NV_WARN(dev, "timingset %d does not exist\n", entry[1]);
+               return NULL;
+       }
+
+       return &pm->memtimings.timing[entry[1]];
+}
+
 void
 nouveau_perf_init(struct drm_device *dev)
 {
@@ -124,6 +186,8 @@ nouveau_perf_init(struct drm_device *dev)
        for (i = 0; i < entries; i++) {
                struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl];
 
+               perflvl->timing = NULL;
+
                if (entry[0] == 0xff) {
                        entry += recordlen;
                        continue;
@@ -174,9 +238,21 @@ nouveau_perf_init(struct drm_device *dev)
 #define subent(n) entry[perf[2] + ((n) * perf[3])]
                        perflvl->fanspeed = 0; /*XXX*/
                        perflvl->voltage = entry[2];
-                       perflvl->core = (ROM16(subent(0)) & 0xfff) * 1000;
-                       perflvl->shader = (ROM16(subent(1)) & 0xfff) * 1000;
-                       perflvl->memory = (ROM16(subent(2)) & 0xfff) * 1000;
+                       if (dev_priv->card_type == NV_50) {
+                               perflvl->core = ROM16(subent(0)) & 0xfff;
+                               perflvl->shader = ROM16(subent(1)) & 0xfff;
+                               perflvl->memory = ROM16(subent(2)) & 0xfff;
+                       } else {
+                               perflvl->shader = ROM16(subent(3)) & 0xfff;
+                               perflvl->core   = perflvl->shader / 2;
+                               perflvl->unk0a  = ROM16(subent(4)) & 0xfff;
+                               perflvl->memory = ROM16(subent(5)) & 0xfff;
+                       }
+
+                       perflvl->core *= 1000;
+                       perflvl->shader *= 1000;
+                       perflvl->memory *= 1000;
+                       perflvl->unk0a *= 1000;
                        break;
                }
 
@@ -190,6 +266,16 @@ nouveau_perf_init(struct drm_device *dev)
                        }
                }
 
+               /* get the corresponding memory timings */
+               if (version > 0x15) {
+                       /* last 3 args are for < 0x40, ignored for >= 0x40 */
+                       perflvl->timing =
+                               nouveau_perf_timing(dev, &P,
+                                                   perflvl->memory / 1000,
+                                                   entry + perf[3],
+                                                   perf[5], perf[4]);
+               }
+
                snprintf(perflvl->name, sizeof(perflvl->name),
                         "performance_level_%d", i);
                perflvl->id = i;
index 4399e2f34db41068dd1769a06af1547b6603a263..da8d994d5e8a3f2b505a7d9fefa9f764a51112df 100644 (file)
@@ -156,7 +156,7 @@ nouveau_pm_perflvl_get(struct drm_device *dev, struct nouveau_pm_level *perflvl)
 static void
 nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
 {
-       char c[16], s[16], v[16], f[16];
+       char c[16], s[16], v[16], f[16], t[16];
 
        c[0] = '\0';
        if (perflvl->core)
@@ -174,8 +174,12 @@ nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len)
        if (perflvl->fanspeed)
                snprintf(f, sizeof(f), " fanspeed %d%%", perflvl->fanspeed);
 
-       snprintf(ptr, len, "memory %dMHz%s%s%s%s\n", perflvl->memory / 1000,
-                c, s, v, f);
+       t[0] = '\0';
+       if (perflvl->timing)
+               snprintf(t, sizeof(t), " timing %d", perflvl->timing->id);
+
+       snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000,
+                c, s, v, f, t);
 }
 
 static ssize_t
@@ -449,7 +453,7 @@ nouveau_hwmon_fini(struct drm_device *dev)
 #endif
 }
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
 static int
 nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data)
 {
@@ -476,10 +480,10 @@ nouveau_pm_init(struct drm_device *dev)
        char info[256];
        int ret, i;
 
+       nouveau_mem_timing_init(dev);
        nouveau_volt_init(dev);
        nouveau_perf_init(dev);
        nouveau_temp_init(dev);
-       nouveau_mem_timing_init(dev);
 
        NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl);
        for (i = 0; i < pm->nr_perflvl; i++) {
@@ -490,6 +494,7 @@ nouveau_pm_init(struct drm_device *dev)
        /* determine current ("boot") performance level */
        ret = nouveau_pm_perflvl_get(dev, &pm->boot);
        if (ret == 0) {
+               strncpy(pm->boot.name, "boot", 4);
                pm->cur = &pm->boot;
 
                nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info));
@@ -507,7 +512,7 @@ nouveau_pm_init(struct drm_device *dev)
 
        nouveau_sysfs_init(dev);
        nouveau_hwmon_init(dev);
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        pm->acpi_nb.notifier_call = nouveau_pm_acpi_event;
        register_acpi_notifier(&pm->acpi_nb);
 #endif
@@ -524,12 +529,12 @@ nouveau_pm_fini(struct drm_device *dev)
        if (pm->cur != &pm->boot)
                nouveau_pm_perflvl_set(dev, &pm->boot);
 
-       nouveau_mem_timing_fini(dev);
        nouveau_temp_fini(dev);
        nouveau_perf_fini(dev);
        nouveau_volt_fini(dev);
+       nouveau_mem_timing_fini(dev);
 
-#ifdef CONFIG_ACPI
+#if defined(CONFIG_ACPI) && defined(CONFIG_POWER_SUPPLY)
        unregister_acpi_notifier(&pm->acpi_nb);
 #endif
        nouveau_hwmon_fini(dev);
index 04e8fb7952692ccfde1524439d12e51a7cd88f64..f18cdfc3400fc00894dd8f40c3e3239114e2a2e5 100644 (file)
 #    define NV50_PCONNECTOR_I2C_PORT_4                      0x0000e240
 #    define NV50_PCONNECTOR_I2C_PORT_5                      0x0000e258
 
-#define NV50_AUXCH_DATA_OUT(i,n)             ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
+#define NV50_AUXCH_DATA_OUT(i, n)            ((n) * 4 + (i) * 0x50 + 0x0000e4c0)
 #define NV50_AUXCH_DATA_OUT__SIZE                                             4
-#define NV50_AUXCH_DATA_IN(i,n)              ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
+#define NV50_AUXCH_DATA_IN(i, n)             ((n) * 4 + (i) * 0x50 + 0x0000e4d0)
 #define NV50_AUXCH_DATA_IN__SIZE                                              4
 #define NV50_AUXCH_ADDR(i)                             ((i) * 0x50 + 0x0000e4e0)
 #define NV50_AUXCH_CTRL(i)                             ((i) * 0x50 + 0x0000e4e4)
 #define NV50_PDISPLAY_SOR_BACKLIGHT                                  0x0061c084
 #define NV50_PDISPLAY_SOR_BACKLIGHT_ENABLE                           0x80000000
 #define NV50_PDISPLAY_SOR_BACKLIGHT_LEVEL                            0x00000fff
-#define NV50_SOR_DP_CTRL(i,l)            (0x0061c10c + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_CTRL(i, l)           (0x0061c10c + (i) * 0x800 + (l) * 0x80)
 #define NV50_SOR_DP_CTRL_ENABLED                                     0x00000001
 #define NV50_SOR_DP_CTRL_ENHANCED_FRAME_ENABLED                      0x00004000
 #define NV50_SOR_DP_CTRL_LANE_MASK                                   0x001f0000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_DISABLED                   0x00000000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_1                          0x01000000
 #define NV50_SOR_DP_CTRL_TRAINING_PATTERN_2                          0x02000000
-#define NV50_SOR_DP_UNK118(i,l)          (0x0061c118 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK120(i,l)          (0x0061c120 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK128(i,l)          (0x0061c128 + (i) * 0x800 + (l) * 0x80)
-#define NV50_SOR_DP_UNK130(i,l)          (0x0061c130 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK118(i, l)         (0x0061c118 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK120(i, l)         (0x0061c120 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK128(i, l)         (0x0061c128 + (i) * 0x800 + (l) * 0x80)
+#define NV50_SOR_DP_UNK130(i, l)         (0x0061c130 + (i) * 0x800 + (l) * 0x80)
 
 #define NV50_PDISPLAY_USER(i)                        ((i) * 0x1000 + 0x00640000)
 #define NV50_PDISPLAY_USER_PUT(i)                    ((i) * 0x1000 + 0x00640000)
index a30adec5beaa7c1149a0089e688fc71832debb7b..38ea662568c1062a6486426408ef5648265e360a 100644 (file)
@@ -65,14 +65,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv04_fb_init;
                engine->fb.takedown             = nv04_fb_takedown;
-               engine->graph.init              = nv04_graph_init;
-               engine->graph.takedown          = nv04_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv04_graph_channel;
-               engine->graph.create_context    = nv04_graph_create_context;
-               engine->graph.destroy_context   = nv04_graph_destroy_context;
-               engine->graph.load_context      = nv04_graph_load_context;
-               engine->graph.unload_context    = nv04_graph_unload_context;
                engine->fifo.channels           = 16;
                engine->fifo.init               = nv04_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -98,8 +90,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -123,15 +113,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv10_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv10_fb_free_tile_region;
-               engine->graph.init              = nv10_graph_init;
-               engine->graph.takedown          = nv10_graph_takedown;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv10_graph_create_context;
-               engine->graph.destroy_context   = nv10_graph_destroy_context;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.load_context      = nv10_graph_load_context;
-               engine->graph.unload_context    = nv10_graph_unload_context;
-               engine->graph.set_tile_region   = nv10_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -157,8 +138,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -182,15 +161,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv10_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv10_fb_free_tile_region;
-               engine->graph.init              = nv20_graph_init;
-               engine->graph.takedown          = nv20_graph_takedown;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv20_graph_create_context;
-               engine->graph.destroy_context   = nv20_graph_destroy_context;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.load_context      = nv20_graph_load_context;
-               engine->graph.unload_context    = nv20_graph_unload_context;
-               engine->graph.set_tile_region   = nv20_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -216,8 +186,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_get            = nv04_pm_clock_get;
                engine->pm.clock_pre            = nv04_pm_clock_pre;
                engine->pm.clock_set            = nv04_pm_clock_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -241,15 +209,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv30_fb_init_tile_region;
                engine->fb.set_tile_region      = nv10_fb_set_tile_region;
                engine->fb.free_tile_region     = nv30_fb_free_tile_region;
-               engine->graph.init              = nv30_graph_init;
-               engine->graph.takedown          = nv20_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv10_graph_channel;
-               engine->graph.create_context    = nv20_graph_create_context;
-               engine->graph.destroy_context   = nv20_graph_destroy_context;
-               engine->graph.load_context      = nv20_graph_load_context;
-               engine->graph.unload_context    = nv20_graph_unload_context;
-               engine->graph.set_tile_region   = nv20_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv10_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -277,8 +236,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.clock_set            = nv04_pm_clock_set;
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -303,15 +260,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->fb.init_tile_region     = nv30_fb_init_tile_region;
                engine->fb.set_tile_region      = nv40_fb_set_tile_region;
                engine->fb.free_tile_region     = nv30_fb_free_tile_region;
-               engine->graph.init              = nv40_graph_init;
-               engine->graph.takedown          = nv40_graph_takedown;
-               engine->graph.fifo_access       = nv04_graph_fifo_access;
-               engine->graph.channel           = nv40_graph_channel;
-               engine->graph.create_context    = nv40_graph_create_context;
-               engine->graph.destroy_context   = nv40_graph_destroy_context;
-               engine->graph.load_context      = nv40_graph_load_context;
-               engine->graph.unload_context    = nv40_graph_unload_context;
-               engine->graph.set_tile_region   = nv40_graph_set_tile_region;
                engine->fifo.channels           = 32;
                engine->fifo.init               = nv40_fifo_init;
                engine->fifo.takedown           = nv04_fifo_fini;
@@ -340,8 +288,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->pm.voltage_get          = nouveau_voltage_gpio_get;
                engine->pm.voltage_set          = nouveau_voltage_gpio_set;
                engine->pm.temp_get             = nv40_temp_get;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nouveau_mem_detect;
                engine->vram.flags_valid        = nouveau_mem_flags_valid;
                break;
@@ -368,19 +314,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nv50_fb_init;
                engine->fb.takedown             = nv50_fb_takedown;
-               engine->graph.init              = nv50_graph_init;
-               engine->graph.takedown          = nv50_graph_takedown;
-               engine->graph.fifo_access       = nv50_graph_fifo_access;
-               engine->graph.channel           = nv50_graph_channel;
-               engine->graph.create_context    = nv50_graph_create_context;
-               engine->graph.destroy_context   = nv50_graph_destroy_context;
-               engine->graph.load_context      = nv50_graph_load_context;
-               engine->graph.unload_context    = nv50_graph_unload_context;
-               if (dev_priv->chipset == 0x50 ||
-                   dev_priv->chipset == 0xac)
-                       engine->graph.tlb_flush = nv50_graph_tlb_flush;
-               else
-                       engine->graph.tlb_flush = nv84_graph_tlb_flush;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nv50_fifo_init;
                engine->fifo.takedown           = nv50_fifo_takedown;
@@ -432,24 +365,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                        engine->pm.temp_get     = nv84_temp_get;
                else
                        engine->pm.temp_get     = nv40_temp_get;
-               switch (dev_priv->chipset) {
-               case 0x84:
-               case 0x86:
-               case 0x92:
-               case 0x94:
-               case 0x96:
-               case 0xa0:
-                       engine->crypt.init      = nv84_crypt_init;
-                       engine->crypt.takedown  = nv84_crypt_fini;
-                       engine->crypt.create_context = nv84_crypt_create_context;
-                       engine->crypt.destroy_context = nv84_crypt_destroy_context;
-                       engine->crypt.tlb_flush = nv84_crypt_tlb_flush;
-                       break;
-               default:
-                       engine->crypt.init      = nouveau_stub_init;
-                       engine->crypt.takedown  = nouveau_stub_takedown;
-                       break;
-               }
                engine->vram.init               = nv50_vram_init;
                engine->vram.get                = nv50_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -472,14 +387,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->timer.takedown          = nv04_timer_takedown;
                engine->fb.init                 = nvc0_fb_init;
                engine->fb.takedown             = nvc0_fb_takedown;
-               engine->graph.init              = nvc0_graph_init;
-               engine->graph.takedown          = nvc0_graph_takedown;
-               engine->graph.fifo_access       = nvc0_graph_fifo_access;
-               engine->graph.channel           = nvc0_graph_channel;
-               engine->graph.create_context    = nvc0_graph_create_context;
-               engine->graph.destroy_context   = nvc0_graph_destroy_context;
-               engine->graph.load_context      = nvc0_graph_load_context;
-               engine->graph.unload_context    = nvc0_graph_unload_context;
                engine->fifo.channels           = 128;
                engine->fifo.init               = nvc0_fifo_init;
                engine->fifo.takedown           = nvc0_fifo_takedown;
@@ -503,8 +410,6 @@ static int nouveau_init_engine_ptrs(struct drm_device *dev)
                engine->gpio.irq_register       = nv50_gpio_irq_register;
                engine->gpio.irq_unregister     = nv50_gpio_irq_unregister;
                engine->gpio.irq_enable         = nv50_gpio_irq_enable;
-               engine->crypt.init              = nouveau_stub_init;
-               engine->crypt.takedown          = nouveau_stub_takedown;
                engine->vram.init               = nvc0_vram_init;
                engine->vram.get                = nvc0_vram_new;
                engine->vram.put                = nv50_vram_del;
@@ -593,7 +498,7 @@ nouveau_card_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine;
-       int ret;
+       int ret, e = 0;
 
        vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
        vga_switcheroo_register_client(dev->pdev, nouveau_switcheroo_set_state,
@@ -658,23 +563,80 @@ nouveau_card_init(struct drm_device *dev)
        if (ret)
                goto out_timer;
 
-       if (nouveau_noaccel)
-               engine->graph.accel_blocked = true;
-       else {
-               /* PGRAPH */
-               ret = engine->graph.init(dev);
-               if (ret)
-                       goto out_fb;
+       switch (dev_priv->card_type) {
+       case NV_04:
+               nv04_graph_create(dev);
+               break;
+       case NV_10:
+               nv10_graph_create(dev);
+               break;
+       case NV_20:
+       case NV_30:
+               nv20_graph_create(dev);
+               break;
+       case NV_40:
+               nv40_graph_create(dev);
+               break;
+       case NV_50:
+               nv50_graph_create(dev);
+               break;
+       case NV_C0:
+               nvc0_graph_create(dev);
+               break;
+       default:
+               break;
+       }
 
-               /* PCRYPT */
-               ret = engine->crypt.init(dev);
-               if (ret)
-                       goto out_graph;
+       switch (dev_priv->chipset) {
+       case 0x84:
+       case 0x86:
+       case 0x92:
+       case 0x94:
+       case 0x96:
+       case 0xa0:
+               nv84_crypt_create(dev);
+               break;
+       }
+
+       switch (dev_priv->card_type) {
+       case NV_50:
+               switch (dev_priv->chipset) {
+               case 0xa3:
+               case 0xa5:
+               case 0xa8:
+               case 0xaf:
+                       nva3_copy_create(dev);
+                       break;
+               }
+               break;
+       case NV_C0:
+               nvc0_copy_create(dev, 0);
+               nvc0_copy_create(dev, 1);
+               break;
+       default:
+               break;
+       }
+
+       if (dev_priv->card_type == NV_40)
+               nv40_mpeg_create(dev);
+       else
+       if (dev_priv->card_type == NV_50 &&
+           (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0))
+               nv50_mpeg_create(dev);
+
+       if (!nouveau_noaccel) {
+               for (e = 0; e < NVOBJ_ENGINE_NR; e++) {
+                       if (dev_priv->eng[e]) {
+                               ret = dev_priv->eng[e]->init(dev, e);
+                               if (ret)
+                                       goto out_engine;
+                       }
+               }
 
                /* PFIFO */
                ret = engine->fifo.init(dev);
                if (ret)
-                       goto out_crypt;
+                       goto out_engine;
        }
 
        ret = engine->display.create(dev);
@@ -691,7 +653,7 @@ nouveau_card_init(struct drm_device *dev)
 
        /* what about PVIDEO/PCRTC/PRAMDAC etc? */
 
-       if (!engine->graph.accel_blocked) {
+       if (dev_priv->eng[NVOBJ_ENGINE_GR]) {
                ret = nouveau_fence_init(dev);
                if (ret)
                        goto out_irq;
@@ -715,13 +677,16 @@ out_vblank:
 out_fifo:
        if (!nouveau_noaccel)
                engine->fifo.takedown(dev);
-out_crypt:
-       if (!nouveau_noaccel)
-               engine->crypt.takedown(dev);
-out_graph:
-       if (!nouveau_noaccel)
-               engine->graph.takedown(dev);
-out_fb:
+out_engine:
+       if (!nouveau_noaccel) {
+               for (e = e - 1; e >= 0; e--) {
+                       if (!dev_priv->eng[e])
+                               continue;
+                       dev_priv->eng[e]->fini(dev, e);
+                       dev_priv->eng[e]->destroy(dev,e );
+               }
+       }
+
        engine->fb.takedown(dev);
 out_timer:
        engine->timer.takedown(dev);
@@ -751,16 +716,21 @@ static void nouveau_card_takedown(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_engine *engine = &dev_priv->engine;
+       int e;
 
-       if (!engine->graph.accel_blocked) {
+       if (dev_priv->channel) {
                nouveau_fence_fini(dev);
                nouveau_channel_put_unlocked(&dev_priv->channel);
        }
 
        if (!nouveau_noaccel) {
                engine->fifo.takedown(dev);
-               engine->crypt.takedown(dev);
-               engine->graph.takedown(dev);
+               for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) {
+                       if (dev_priv->eng[e]) {
+                               dev_priv->eng[e]->fini(dev, e);
+                               dev_priv->eng[e]->destroy(dev,e );
+                       }
+               }
        }
        engine->fb.takedown(dev);
        engine->timer.takedown(dev);
@@ -768,6 +738,11 @@ static void nouveau_card_takedown(struct drm_device *dev)
        engine->mc.takedown(dev);
        engine->display.late_takedown(dev);
 
+       if (dev_priv->vga_ram) {
+               nouveau_bo_unpin(dev_priv->vga_ram);
+               nouveau_bo_ref(NULL, &dev_priv->vga_ram);
+       }
+
        mutex_lock(&dev->struct_mutex);
        ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_VRAM);
        ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT);
@@ -861,7 +836,7 @@ static int nouveau_remove_conflicting_drivers(struct drm_device *dev)
 #ifdef CONFIG_X86
        primary = dev->pdev->resource[PCI_ROM_RESOURCE].flags & IORESOURCE_ROM_SHADOW;
 #endif
-       
+
        remove_conflicting_framebuffers(dev_priv->apertures, "nouveaufb", primary);
        return 0;
 }
@@ -913,11 +888,13 @@ int nouveau_load(struct drm_device *dev, unsigned long flags)
 
        /* Time to determine the card architecture */
        reg0 = nv_rd32(dev, NV03_PMC_BOOT_0);
+       dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */
 
        /* We're dealing with >=NV10 */
        if ((reg0 & 0x0f000000) > 0) {
                /* Bit 27-20 contain the architecture in hex */
                dev_priv->chipset = (reg0 & 0xff00000) >> 20;
+               dev_priv->stepping = (reg0 & 0xff);
        /* NV04 or NV05 */
        } else if ((reg0 & 0xff00fff0) == 0x20004000) {
                if (reg0 & 0x00f00000)
index 2e06b55cfdc1844eb4e1a376890fa35912fb10ca..c48a9fc2b47b41eb870f17a7f9fa95c28a4daa20 100644 (file)
@@ -53,8 +53,7 @@ struct nouveau_vm {
        int refcount;
 
        struct list_head pgd_list;
-       atomic_t pgraph_refs;
-       atomic_t pcrypt_refs;
+       atomic_t engref[16];
 
        struct nouveau_vm_pgt *pgt;
        u32 fpde;
index 04fdc00a67d540324bb8a5ef4ee4fcf0d9b1ecfa..75e872741d9218c91aeb49c46dfd7f3f6268cdf2 100644 (file)
@@ -159,8 +159,16 @@ nouveau_volt_init(struct drm_device *dev)
                headerlen = volt[1];
                recordlen = volt[2];
                entries   = volt[3];
-               vidshift  = hweight8(volt[5]);
                vidmask   = volt[4];
+               /* no longer certain what volt[5] is, if it's related to
+                * the vid shift then it's definitely not a function of
+                * how many bits are set.
+                *
+                * after looking at a number of nva3+ vbios images, they
+                * all seem likely to have a static shift of 2.. lets
+                * go with that for now until proven otherwise.
+                */
+               vidshift  = 2;
                break;
        default:
                NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]);
index 748b9d9c2949df0f24a998e1caf0cfec2f929258..3c78bc81357e0e838ec933e330748d9bd019f661 100644 (file)
@@ -790,8 +790,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
        if (atomic) {
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
-       }
-       else {
+       } else {
                /* If not atomic, we can go ahead and pin, and unpin the
                 * old fb we were passed.
                 */
@@ -944,14 +943,14 @@ nv04_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct drm_gem_object *gem;
        int ret = 0;
 
-       if (width != 64 || height != 64)
-               return -EINVAL;
-
        if (!buffer_handle) {
                nv_crtc->cursor.hide(nv_crtc, true);
                return 0;
        }
 
+       if (width != 64 || height != 64)
+               return -EINVAL;
+
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
                return -ENOENT;
index af75015068d6bd89477d81f5a5b5aabae41c9a3b..3626ee7db3ba5924cfc5dcd5412b1d618203c5f7 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
 #include "nouveau_util.h"
+#include "nouveau_ramht.h"
 
-static int  nv04_graph_register(struct drm_device *dev);
-static void nv04_graph_isr(struct drm_device *dev);
+struct nv04_graph_engine {
+       struct nouveau_exec_engine base;
+};
 
 static uint32_t nv04_graph_ctx_regs[] = {
        0x0040053c,
@@ -350,7 +352,7 @@ struct graph_state {
        uint32_t nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
 };
 
-struct nouveau_channel *
+static struct nouveau_channel *
 nv04_graph_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -365,26 +367,6 @@ nv04_graph_channel(struct drm_device *dev)
        return dev_priv->channels.ptr[chid];
 }
 
-static void
-nv04_graph_context_switch(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_channel *chan = NULL;
-       int chid;
-
-       nouveau_wait_for_idle(dev);
-
-       /* If previous context is valid, we need to save it */
-       pgraph->unload_context(dev);
-
-       /* Load context for next channel */
-       chid = dev_priv->engine.fifo.channel_id(dev);
-       chan = dev_priv->channels.ptr[chid];
-       if (chan)
-               nv04_graph_load_context(chan);
-}
-
 static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
 {
        int i;
@@ -397,48 +379,11 @@ static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg)
        return NULL;
 }
 
-int nv04_graph_create_context(struct nouveau_channel *chan)
-{
-       struct graph_state *pgraph_ctx;
-       NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
-
-       chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
-                                               GFP_KERNEL);
-       if (pgraph_ctx == NULL)
-               return -ENOMEM;
-
-       *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
-       return 0;
-}
-
-void nv04_graph_destroy_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
-
-       /* Free the context resources */
-       kfree(pgraph_ctx);
-       chan->pgraph_ctx = NULL;
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-}
-
-int nv04_graph_load_context(struct nouveau_channel *chan)
+static int
+nv04_graph_load_context(struct nouveau_channel *chan)
 {
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
        uint32_t tmp;
        int i;
 
@@ -456,20 +401,19 @@ int nv04_graph_load_context(struct nouveau_channel *chan)
        return 0;
 }
 
-int
+static int
 nv04_graph_unload_context(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_channel *chan = NULL;
        struct graph_state *ctx;
        uint32_t tmp;
        int i;
 
-       chan = pgraph->channel(dev);
+       chan = nv04_graph_channel(dev);
        if (!chan)
                return 0;
-       ctx = chan->pgraph_ctx;
+       ctx = chan->engctx[NVOBJ_ENGINE_GR];
 
        for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
                ctx->nv04[i] = nv_rd32(dev, nv04_graph_ctx_regs[i]);
@@ -481,23 +425,85 @@ nv04_graph_unload_context(struct drm_device *dev)
        return 0;
 }
 
-int nv04_graph_init(struct drm_device *dev)
+static int
+nv04_graph_context_new(struct nouveau_channel *chan, int engine)
 {
+       struct graph_state *pgraph_ctx;
+       NV_DEBUG(chan->dev, "nv04_graph_context_create %d\n", chan->id);
+
+       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
+       if (pgraph_ctx == NULL)
+               return -ENOMEM;
+
+       *ctx_reg(pgraph_ctx, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+       chan->engctx[engine] = pgraph_ctx;
+       return 0;
+}
+
+static void
+nv04_graph_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
+       struct graph_state *pgraph_ctx = chan->engctx[engine];
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv04_graph_fifo_access(dev, false);
+
+       /* Unload the context if it's the currently active one */
+       if (nv04_graph_channel(dev) == chan)
+               nv04_graph_unload_context(dev);
+
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       /* Free the context resources */
+       kfree(pgraph_ctx);
+       chan->engctx[engine] = NULL;
+}
+
+int
+nv04_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
        int ret;
 
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
+
+#ifdef __BIG_ENDIAN
+       nv_wo32(obj, 0x00, 0x00080000 | class);
+#else
+       nv_wo32(obj, 0x00, class);
+#endif
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static int
+nv04_graph_init(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t tmp;
+
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       ret = nv04_graph_register(dev);
-       if (ret)
-               return ret;
-
        /* Enable PGRAPH interrupts */
-       nouveau_irq_register(dev, 12, nv04_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR, 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -507,7 +513,7 @@ int nv04_graph_init(struct drm_device *dev)
        nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
        nv_wr32(dev, NV04_PGRAPH_DEBUG_0, 0x1231c000);
        /*1231C000 blob, 001 haiku*/
-       //*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+       /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
        nv_wr32(dev, NV04_PGRAPH_DEBUG_1, 0x72111100);
        /*0x72111100 blob , 01 haiku*/
        /*nv_wr32(dev, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
@@ -531,10 +537,12 @@ int nv04_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv04_graph_takedown(struct drm_device *dev)
+static int
+nv04_graph_fini(struct drm_device *dev, int engine)
 {
+       nv04_graph_unload_context(dev);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
+       return 0;
 }
 
 void
@@ -969,13 +977,138 @@ nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan,
        return 1;
 }
 
-static int
-nv04_graph_register(struct drm_device *dev)
+static struct nouveau_bitfield nv04_graph_intr[] = {
+       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+       {}
+};
+
+static struct nouveau_bitfield nv04_graph_nstatus[] = {
+       { NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
+       { NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
+       { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
+       { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
+       {}
+};
+
+struct nouveau_bitfield nv04_graph_nsource[] = {
+       { NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
+       { NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
+       { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
+       { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
+       { NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
+       { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
+       { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
+       { NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
+       { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
+       { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
+       { NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
+       { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
+       { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
+       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
+       {}
+};
+
+static void
+nv04_graph_context_switch(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_channel *chan = NULL;
+       int chid;
 
-       if (dev_priv->engine.graph.registered)
-               return 0;
+       nouveau_wait_for_idle(dev);
+
+       /* If previous context is valid, we need to save it */
+       nv04_graph_unload_context(dev);
+
+       /* Load context for next channel */
+       chid = dev_priv->engine.fifo.channel_id(dev);
+       chan = dev_priv->channels.ptr[chid];
+       if (chan)
+               nv04_graph_load_context(chan);
+}
+
+static void
+nv04_graph_isr(struct drm_device *dev)
+{
+       u32 stat;
+
+       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
+               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
+               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
+               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
+               u32 chid = (addr & 0x0f000000) >> 24;
+               u32 subc = (addr & 0x0000e000) >> 13;
+               u32 mthd = (addr & 0x00001ffc);
+               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
+               u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
+               u32 show = stat;
+
+               if (stat & NV_PGRAPH_INTR_NOTIFY) {
+                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
+                                       show &= ~NV_PGRAPH_INTR_NOTIFY;
+                       }
+               }
+
+               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+                       nv04_graph_context_switch(dev);
+               }
+
+               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
+               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
+
+               if (show && nouveau_ratelimit()) {
+                       NV_INFO(dev, "PGRAPH -");
+                       nouveau_bitfield_print(nv04_graph_intr, show);
+                       printk(" nsource:");
+                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
+                       printk(" nstatus:");
+                       nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
+                       printk("\n");
+                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
+                                    "mthd 0x%04x data 0x%08x\n",
+                               chid, subc, class, mthd, data);
+               }
+       }
+}
+
+static void
+nv04_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv04_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv04_graph_create(struct drm_device *dev)
+{
+       struct nv04_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv04_graph_destroy;
+       pgraph->base.init = nv04_graph_init;
+       pgraph->base.fini = nv04_graph_fini;
+       pgraph->base.context_new = nv04_graph_context_new;
+       pgraph->base.context_del = nv04_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv04_graph_isr);
 
        /* dvd subpicture */
        NVOBJ_CLASS(dev, 0x0038, GR);
@@ -1222,93 +1355,5 @@ nv04_graph_register(struct drm_device *dev)
        NVOBJ_CLASS(dev, 0x506e, SW);
        NVOBJ_MTHD (dev, 0x506e, 0x0150, nv04_graph_mthd_set_ref);
        NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
        return 0;
-};
-
-static struct nouveau_bitfield nv04_graph_intr[] = {
-       { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
-       {}
-};
-
-static struct nouveau_bitfield nv04_graph_nstatus[] =
-{
-       { NV04_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
-       { NV04_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
-       { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
-       { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT,   "PROTECTION_FAULT" },
-       {}
-};
-
-struct nouveau_bitfield nv04_graph_nsource[] =
-{
-       { NV03_PGRAPH_NSOURCE_NOTIFICATION,       "NOTIFICATION" },
-       { NV03_PGRAPH_NSOURCE_DATA_ERROR,         "DATA_ERROR" },
-       { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR,   "PROTECTION_ERROR" },
-       { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION,    "RANGE_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_LIMIT_COLOR,        "LIMIT_COLOR" },
-       { NV03_PGRAPH_NSOURCE_LIMIT_ZETA,         "LIMIT_ZETA" },
-       { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD,       "ILLEGAL_MTHD" },
-       { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION,   "DMA_R_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION,   "DMA_W_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION,   "FORMAT_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION,    "PATCH_EXCEPTION" },
-       { NV03_PGRAPH_NSOURCE_STATE_INVALID,      "STATE_INVALID" },
-       { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY,      "DOUBLE_NOTIFY" },
-       { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE,      "NOTIFY_IN_USE" },
-       { NV03_PGRAPH_NSOURCE_METHOD_CNT,         "METHOD_CNT" },
-       { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION,   "BFR_NOTIFICATION" },
-       { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
-       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A,        "DMA_WIDTH_A" },
-       { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B,        "DMA_WIDTH_B" },
-       {}
-};
-
-static void
-nv04_graph_isr(struct drm_device *dev)
-{
-       u32 stat;
-
-       while ((stat = nv_rd32(dev, NV03_PGRAPH_INTR))) {
-               u32 nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE);
-               u32 nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS);
-               u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR);
-               u32 chid = (addr & 0x0f000000) >> 24;
-               u32 subc = (addr & 0x0000e000) >> 13;
-               u32 mthd = (addr & 0x00001ffc);
-               u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA);
-               u32 class = nv_rd32(dev, 0x400180 + subc * 4) & 0xff;
-               u32 show = stat;
-
-               if (stat & NV_PGRAPH_INTR_NOTIFY) {
-                       if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
-                               if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data))
-                                       show &= ~NV_PGRAPH_INTR_NOTIFY;
-                       }
-               }
-
-               if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
-                       nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
-                       stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
-                       nv04_graph_context_switch(dev);
-               }
-
-               nv_wr32(dev, NV03_PGRAPH_INTR, stat);
-               nv_wr32(dev, NV04_PGRAPH_FIFO, 0x00000001);
-
-               if (show && nouveau_ratelimit()) {
-                       NV_INFO(dev, "PGRAPH -");
-                       nouveau_bitfield_print(nv04_graph_intr, show);
-                       printk(" nsource:");
-                       nouveau_bitfield_print(nv04_graph_nsource, nsource);
-                       printk(" nstatus:");
-                       nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
-                       printk("\n");
-                       NV_INFO(dev, "PGRAPH - ch %d/%d class 0x%04x "
-                                    "mthd 0x%04x data 0x%08x\n",
-                               chid, subc, class, mthd, data);
-               }
-       }
 }
index b8e3edb5c063f2bb2f704485e6336779848c29ac..b8611b9553131b1df7669f394586dc8e4e80abff 100644 (file)
@@ -95,6 +95,9 @@ nv04_instmem_takedown(struct drm_device *dev)
        nouveau_ramht_ref(NULL, &dev_priv->ramht, NULL);
        nouveau_gpuobj_ref(NULL, &dev_priv->ramro);
        nouveau_gpuobj_ref(NULL, &dev_priv->ramfc);
+
+       if (drm_mm_initialized(&dev_priv->ramin_heap))
+               drm_mm_takedown(&dev_priv->ramin_heap);
 }
 
 int
index 8c92edb7bbcd1833dcc2c823f230793b243e86e1..0930c6cb88e079cb6b6d2f4aaca45a55b1c0ca7d 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_util.h"
 
-static int  nv10_graph_register(struct drm_device *);
-static void nv10_graph_isr(struct drm_device *);
-
-#define NV10_FIFO_NUMBER 32
+struct nv10_graph_engine {
+       struct nouveau_exec_engine base;
+};
 
 struct pipe_state {
        uint32_t pipe_0x0000[0x040/4];
@@ -414,9 +413,9 @@ struct graph_state {
 
 static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
 
        PIPE_SAVE(dev, pipe->pipe_0x4400, 0x4400);
        PIPE_SAVE(dev, pipe->pipe_0x0200, 0x0200);
@@ -432,9 +431,9 @@ static void nv10_graph_save_pipe(struct nouveau_channel *chan)
 
 static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *pipe = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
        uint32_t xfmode0, xfmode1;
        int i;
 
@@ -482,9 +481,9 @@ static void nv10_graph_load_pipe(struct nouveau_channel *chan)
 
 static void nv10_graph_create_pipe(struct nouveau_channel *chan)
 {
-       struct drm_device *dev = chan->dev;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct pipe_state *fifo_pipe_state = &pgraph_ctx->pipe_state;
+       struct drm_device *dev = chan->dev;
        uint32_t *fifo_pipe_state_addr;
        int i;
 #define PIPE_INIT(addr) \
@@ -661,8 +660,6 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                                       uint32_t inst)
 {
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
        uint32_t ctx_user, ctx_switch[5];
        int i, subchan = -1;
@@ -711,8 +708,8 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
                0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c);
        nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
        nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
-       pgraph->fifo_access(dev, true);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, true);
+       nv04_graph_fifo_access(dev, false);
 
        /* Restore the FIFO state */
        for (i = 0; i < ARRAY_SIZE(fifo); i++)
@@ -729,11 +726,12 @@ static void nv10_graph_load_dma_vtxbuf(struct nouveau_channel *chan,
        nv_wr32(dev, NV10_PGRAPH_CTX_USER, ctx_user);
 }
 
-int nv10_graph_load_context(struct nouveau_channel *chan)
+static int
+nv10_graph_load_context(struct nouveau_channel *chan)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[NVOBJ_ENGINE_GR];
        uint32_t tmp;
        int i;
 
@@ -757,21 +755,20 @@ int nv10_graph_load_context(struct nouveau_channel *chan)
        return 0;
 }
 
-int
+static int
 nv10_graph_unload_context(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nouveau_channel *chan;
        struct graph_state *ctx;
        uint32_t tmp;
        int i;
 
-       chan = pgraph->channel(dev);
+       chan = nv10_graph_channel(dev);
        if (!chan)
                return 0;
-       ctx = chan->pgraph_ctx;
+       ctx = chan->engctx[NVOBJ_ENGINE_GR];
 
        for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
                ctx->nv10[i] = nv_rd32(dev, nv10_graph_ctx_regs[i]);
@@ -805,7 +802,7 @@ nv10_graph_context_switch(struct drm_device *dev)
        /* Load context for next channel */
        chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
        chan = dev_priv->channels.ptr[chid];
-       if (chan && chan->pgraph_ctx)
+       if (chan && chan->engctx[NVOBJ_ENGINE_GR])
                nv10_graph_load_context(chan);
 }
 
@@ -836,7 +833,8 @@ nv10_graph_channel(struct drm_device *dev)
        return dev_priv->channels.ptr[chid];
 }
 
-int nv10_graph_create_context(struct nouveau_channel *chan)
+static int
+nv10_graph_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -844,11 +842,10 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
 
        NV_DEBUG(dev, "nv10_graph_context_create %d\n", chan->id);
 
-       chan->pgraph_ctx = pgraph_ctx = kzalloc(sizeof(*pgraph_ctx),
-                                               GFP_KERNEL);
+       pgraph_ctx = kzalloc(sizeof(*pgraph_ctx), GFP_KERNEL);
        if (pgraph_ctx == NULL)
                return -ENOMEM;
-
+       chan->engctx[engine] = pgraph_ctx;
 
        NV_WRITE_CTX(0x00400e88, 0x08000000);
        NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
@@ -873,30 +870,30 @@ int nv10_graph_create_context(struct nouveau_channel *chan)
        return 0;
 }
 
-void nv10_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv10_graph_context_del(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct graph_state *pgraph_ctx = chan->pgraph_ctx;
+       struct graph_state *pgraph_ctx = chan->engctx[engine];
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, false);
 
        /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv10_graph_channel(dev) == chan)
+               nv10_graph_unload_context(dev);
+
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
+       chan->engctx[engine] = NULL;
        kfree(pgraph_ctx);
-       chan->pgraph_ctx = NULL;
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
-void
+static void
 nv10_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -907,22 +904,18 @@ nv10_graph_set_tile_region(struct drm_device *dev, int i)
        nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr);
 }
 
-int nv10_graph_init(struct drm_device *dev)
+static int
+nv10_graph_init(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t tmp;
-       int ret, i;
+       u32 tmp;
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) |
                         NV_PMC_ENABLE_PGRAPH);
 
-       ret = nv10_graph_register(dev);
-       if (ret)
-               return ret;
-
-       nouveau_irq_register(dev, 12, nv10_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -963,18 +956,20 @@ int nv10_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv10_graph_takedown(struct drm_device *dev)
+static int
+nv10_graph_fini(struct drm_device *dev, int engine)
 {
+       nv10_graph_unload_context(dev);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
+       return 0;
 }
 
 static int
 nv17_graph_mthd_lma_window(struct nouveau_channel *chan,
                           u32 class, u32 mthd, u32 data)
 {
+       struct graph_state *ctx = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
-       struct graph_state *ctx = chan->pgraph_ctx;
        struct pipe_state *pipe = &ctx->pipe_state;
        uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
        uint32_t xfmode0, xfmode1;
@@ -1061,64 +1056,13 @@ nv17_graph_mthd_lma_enable(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nv10_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
-       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
-       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
-
-       /* celcius */
-       if (dev_priv->chipset <= 0x10) {
-               NVOBJ_CLASS(dev, 0x0056, GR);
-       } else
-       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
-               NVOBJ_CLASS(dev, 0x0096, GR);
-       } else {
-               NVOBJ_CLASS(dev, 0x0099, GR);
-               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
-               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
-       }
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
-
 struct nouveau_bitfield nv10_graph_intr[] = {
        { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
        { NV_PGRAPH_INTR_ERROR,  "ERROR"  },
        {}
 };
 
-struct nouveau_bitfield nv10_graph_nstatus[] =
-{
+struct nouveau_bitfield nv10_graph_nstatus[] = {
        { NV10_PGRAPH_NSTATUS_STATE_IN_USE,       "STATE_IN_USE" },
        { NV10_PGRAPH_NSTATUS_INVALID_STATE,      "INVALID_STATE" },
        { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT,       "BAD_ARGUMENT" },
@@ -1173,3 +1117,73 @@ nv10_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv10_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv10_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+       kfree(pgraph);
+}
+
+int
+nv10_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv10_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv10_graph_destroy;
+       pgraph->base.init = nv10_graph_init;
+       pgraph->base.fini = nv10_graph_fini;
+       pgraph->base.context_new = nv10_graph_context_new;
+       pgraph->base.context_del = nv10_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+       pgraph->base.set_tile_region = nv10_graph_set_tile_region;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv10_graph_isr);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x005f, GR); /* imageblit */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       NVOBJ_CLASS(dev, 0x0052, GR); /* swzsurf */
+       NVOBJ_CLASS(dev, 0x0093, GR); /* surf3d */
+       NVOBJ_CLASS(dev, 0x0094, GR); /* tex_tri */
+       NVOBJ_CLASS(dev, 0x0095, GR); /* multitex_tri */
+
+       /* celcius */
+       if (dev_priv->chipset <= 0x10) {
+               NVOBJ_CLASS(dev, 0x0056, GR);
+       } else
+       if (dev_priv->chipset < 0x17 || dev_priv->chipset == 0x1a) {
+               NVOBJ_CLASS(dev, 0x0096, GR);
+       } else {
+               NVOBJ_CLASS(dev, 0x0099, GR);
+               NVOBJ_MTHD (dev, 0x0099, 0x1638, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x163c, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1640, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1644, nv17_graph_mthd_lma_window);
+               NVOBJ_MTHD (dev, 0x0099, 0x1658, nv17_graph_mthd_lma_enable);
+       }
+
+       return 0;
+}
index 8464b76798d5e4746af344ef260526a4b97fdee9..affc7d7dd0291d1707a6e714eb5e57294fbcc807 100644 (file)
  *
  */
 
+struct nv20_graph_engine {
+       struct nouveau_exec_engine base;
+       struct nouveau_gpuobj *ctxtab;
+       void (*grctx_init)(struct nouveau_gpuobj *);
+       u32 grctx_size;
+       u32 grctx_user;
+};
+
 #define NV20_GRCTX_SIZE (3580*4)
 #define NV25_GRCTX_SIZE (3529*4)
 #define NV2A_GRCTX_SIZE (3500*4)
 #define NV34_GRCTX_SIZE    (18140)
 #define NV35_36_GRCTX_SIZE (22396)
 
-static int nv20_graph_register(struct drm_device *);
-static int nv30_graph_register(struct drm_device *);
-static void nv20_graph_isr(struct drm_device *);
+int
+nv20_graph_unload_context(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_channel *chan;
+       struct nouveau_gpuobj *grctx;
+       u32 tmp;
+
+       chan = nv10_graph_channel(dev);
+       if (!chan)
+               return 0;
+       grctx = chan->engctx[NVOBJ_ENGINE_GR];
+
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, grctx->pinst >> 4);
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
+                    NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
+
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
+       tmp |= (pfifo->channels - 1) << 24;
+       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
+       return 0;
+}
+
+static void
+nv20_graph_rdi(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       int i, writecount = 32;
+       uint32_t rdi_index = 0x2c80000;
+
+       if (dev_priv->chipset == 0x20) {
+               rdi_index = 0x3d0000;
+               writecount = 15;
+       }
+
+       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
+       for (i = 0; i < writecount; i++)
+               nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
+
+       nouveau_wait_for_idle(dev);
+}
 
 static void
-nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv20_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -87,7 +137,7 @@ nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv25_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -146,7 +196,7 @@ nv25_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv2a_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -196,7 +246,7 @@ nv2a_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv30_31_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -254,7 +304,7 @@ nv30_31_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv34_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -312,7 +362,7 @@ nv34_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 static void
-nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
+nv35_36_graph_context_init(struct nouveau_gpuobj *ctx)
 {
        int i;
 
@@ -370,148 +420,57 @@ nv35_36_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx)
 }
 
 int
-nv20_graph_create_context(struct nouveau_channel *chan)
+nv20_graph_context_new(struct nouveau_channel *chan, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *grctx = NULL;
        struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       void (*ctx_init)(struct drm_device *, struct nouveau_gpuobj *);
-       unsigned int idoffs = 0x28;
        int ret;
 
-       switch (dev_priv->chipset) {
-       case 0x20:
-               ctx_init = nv20_graph_context_init;
-               idoffs = 0;
-               break;
-       case 0x25:
-       case 0x28:
-               ctx_init = nv25_graph_context_init;
-               break;
-       case 0x2a:
-               ctx_init = nv2a_graph_context_init;
-               idoffs = 0;
-               break;
-       case 0x30:
-       case 0x31:
-               ctx_init = nv30_31_graph_context_init;
-               break;
-       case 0x34:
-               ctx_init = nv34_graph_context_init;
-               break;
-       case 0x35:
-       case 0x36:
-               ctx_init = nv35_36_graph_context_init;
-               break;
-       default:
-               BUG_ON(1);
-       }
-
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
-                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &grctx);
        if (ret)
                return ret;
 
        /* Initialise default context values */
-       ctx_init(dev, chan->ramin_grctx);
+       pgraph->grctx_init(grctx);
 
        /* nv20: nv_wo32(dev, chan->ramin_grctx->gpuobj, 10, chan->id<<24); */
-       nv_wo32(chan->ramin_grctx, idoffs,
-               (chan->id << 24) | 0x1); /* CTX_USER */
+       /* CTX_USER */
+       nv_wo32(grctx, pgraph->grctx_user, (chan->id << 24) | 0x1);
 
-       nv_wo32(pgraph->ctx_table, chan->id * 4, chan->ramin_grctx->pinst >> 4);
+       nv_wo32(pgraph->ctxtab, chan->id * 4, grctx->pinst >> 4);
+       chan->engctx[engine] = grctx;
        return 0;
 }
 
 void
-nv20_graph_destroy_context(struct nouveau_channel *chan)
+nv20_graph_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
+       nv04_graph_fifo_access(dev, false);
 
        /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv10_graph_channel(dev) == chan)
+               nv20_graph_unload_context(dev);
 
-       pgraph->fifo_access(dev, true);
+       nv04_graph_fifo_access(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
        /* Free the context resources */
-       nv_wo32(pgraph->ctx_table, chan->id * 4, 0);
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
-int
-nv20_graph_load_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       uint32_t inst;
+       nv_wo32(pgraph->ctxtab, chan->id * 4, 0);
 
-       if (!chan->ramin_grctx)
-               return -EINVAL;
-       inst = chan->ramin_grctx->pinst >> 4;
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-                    NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD);
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
-
-       nouveau_wait_for_idle(dev);
-       return 0;
-}
-
-int
-nv20_graph_unload_context(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_channel *chan;
-       uint32_t inst, tmp;
-
-       chan = pgraph->channel(dev);
-       if (!chan)
-               return 0;
-       inst = chan->ramin_grctx->pinst >> 4;
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_XFER,
-                    NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE);
-
-       nouveau_wait_for_idle(dev);
-
-       nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
-       tmp  = nv_rd32(dev, NV10_PGRAPH_CTX_USER) & 0x00ffffff;
-       tmp |= (pfifo->channels - 1) << 24;
-       nv_wr32(dev, NV10_PGRAPH_CTX_USER, tmp);
-       return 0;
+       nouveau_gpuobj_ref(NULL, &grctx);
+       chan->engctx[engine] = NULL;
 }
 
 static void
-nv20_graph_rdi(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       int i, writecount = 32;
-       uint32_t rdi_index = 0x2c80000;
-
-       if (dev_priv->chipset == 0x20) {
-               rdi_index = 0x3d0000;
-               writecount = 15;
-       }
-
-       nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, rdi_index);
-       for (i = 0; i < writecount; i++)
-               nv_wr32(dev, NV10_PGRAPH_RDI_DATA, 0);
-
-       nouveau_wait_for_idle(dev);
-}
-
-void
 nv20_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -536,56 +495,22 @@ nv20_graph_set_tile_region(struct drm_device *dev, int i)
 }
 
 int
-nv20_graph_init(struct drm_device *dev)
+nv20_graph_init(struct drm_device *dev, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        uint32_t tmp, vramsz;
-       int ret, i;
-
-       switch (dev_priv->chipset) {
-       case 0x20:
-               pgraph->grctx_size = NV20_GRCTX_SIZE;
-               break;
-       case 0x25:
-       case 0x28:
-               pgraph->grctx_size = NV25_GRCTX_SIZE;
-               break;
-       case 0x2a:
-               pgraph->grctx_size = NV2A_GRCTX_SIZE;
-               break;
-       default:
-               NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
-               pgraph->accel_blocked = true;
-               return 0;
-       }
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
 
-       if (!pgraph->ctx_table) {
-               /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
-                                        NVOBJ_FLAG_ZERO_ALLOC,
-                                        &pgraph->ctx_table);
-               if (ret)
-                       return ret;
-       }
-
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->pinst >> 4);
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
 
        nv20_graph_rdi(dev);
 
-       ret = nv20_graph_register(dev);
-       if (ret) {
-               nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-               return ret;
-       }
-
-       nouveau_irq_register(dev, 12, nv20_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -657,67 +582,20 @@ nv20_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void
-nv20_graph_takedown(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-
-       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
-
-       nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-}
-
 int
-nv30_graph_init(struct drm_device *dev)
+nv30_graph_init(struct drm_device *dev, int engine)
 {
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       int ret, i;
-
-       switch (dev_priv->chipset) {
-       case 0x30:
-       case 0x31:
-               pgraph->grctx_size = NV30_31_GRCTX_SIZE;
-               break;
-       case 0x34:
-               pgraph->grctx_size = NV34_GRCTX_SIZE;
-               break;
-       case 0x35:
-       case 0x36:
-               pgraph->grctx_size = NV35_36_GRCTX_SIZE;
-               break;
-       default:
-               NV_ERROR(dev, "unknown chipset, disabling acceleration\n");
-               pgraph->accel_blocked = true;
-               return 0;
-       }
+       int i;
 
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) & ~NV_PMC_ENABLE_PGRAPH);
        nv_wr32(dev, NV03_PMC_ENABLE,
                nv_rd32(dev, NV03_PMC_ENABLE) |  NV_PMC_ENABLE_PGRAPH);
 
-       if (!pgraph->ctx_table) {
-               /* Create Context Pointer Table */
-               ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16,
-                                        NVOBJ_FLAG_ZERO_ALLOC,
-                                        &pgraph->ctx_table);
-               if (ret)
-                       return ret;
-       }
-
-       ret = nv30_graph_register(dev);
-       if (ret) {
-               nouveau_gpuobj_ref(NULL, &pgraph->ctx_table);
-               return ret;
-       }
+       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE, pgraph->ctxtab->pinst >> 4);
 
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_TABLE,
-                    pgraph->ctx_table->pinst >> 4);
-
-       nouveau_irq_register(dev, 12, nv20_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -775,85 +653,11 @@ nv30_graph_init(struct drm_device *dev)
        return 0;
 }
 
-static int
-nv20_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
-       NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
-
-       /* kelvin */
-       if (dev_priv->chipset < 0x25)
-               NVOBJ_CLASS(dev, 0x0097, GR);
-       else
-               NVOBJ_CLASS(dev, 0x0597, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
-
-static int
-nv30_graph_register(struct drm_device *dev)
+int
+nv20_graph_fini(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
-
-       /* rankine */
-       if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0397, GR);
-       else
-       if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0697, GR);
-       else
-       if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
-               NVOBJ_CLASS(dev, 0x0497, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
+       nv20_graph_unload_context(dev);
+       nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000);
        return 0;
 }
 
@@ -897,3 +701,135 @@ nv20_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv20_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv20_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+       nouveau_gpuobj_ref(NULL, &pgraph->ctxtab);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv20_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv20_graph_engine *pgraph;
+       int ret;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv20_graph_destroy;
+       pgraph->base.fini = nv20_graph_fini;
+       pgraph->base.context_new = nv20_graph_context_new;
+       pgraph->base.context_del = nv20_graph_context_del;
+       pgraph->base.object_new = nv04_graph_object_new;
+       pgraph->base.set_tile_region = nv20_graph_set_tile_region;
+
+       pgraph->grctx_user = 0x0028;
+       if (dev_priv->card_type == NV_20) {
+               pgraph->base.init = nv20_graph_init;
+               switch (dev_priv->chipset) {
+               case 0x20:
+                       pgraph->grctx_init = nv20_graph_context_init;
+                       pgraph->grctx_size = NV20_GRCTX_SIZE;
+                       pgraph->grctx_user = 0x0000;
+                       break;
+               case 0x25:
+               case 0x28:
+                       pgraph->grctx_init = nv25_graph_context_init;
+                       pgraph->grctx_size = NV25_GRCTX_SIZE;
+                       break;
+               case 0x2a:
+                       pgraph->grctx_init = nv2a_graph_context_init;
+                       pgraph->grctx_size = NV2A_GRCTX_SIZE;
+                       pgraph->grctx_user = 0x0000;
+                       break;
+               default:
+                       NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+                       return 0;
+               }
+       } else {
+               pgraph->base.init = nv30_graph_init;
+               switch (dev_priv->chipset) {
+               case 0x30:
+               case 0x31:
+                       pgraph->grctx_init = nv30_31_graph_context_init;
+                       pgraph->grctx_size = NV30_31_GRCTX_SIZE;
+                       break;
+               case 0x34:
+                       pgraph->grctx_init = nv34_graph_context_init;
+                       pgraph->grctx_size = NV34_GRCTX_SIZE;
+                       break;
+               case 0x35:
+               case 0x36:
+                       pgraph->grctx_init = nv35_36_graph_context_init;
+                       pgraph->grctx_size = NV35_36_GRCTX_SIZE;
+                       break;
+               default:
+                       NV_ERROR(dev, "PGRAPH: unknown chipset\n");
+                       return 0;
+               }
+       }
+
+       /* Create Context Pointer Table */
+       ret = nouveau_gpuobj_new(dev, NULL, 32 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC,
+                                &pgraph->ctxtab);
+       if (ret) {
+               kfree(pgraph);
+               return ret;
+       }
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv20_graph_isr);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       if (dev_priv->card_type == NV_20) {
+               NVOBJ_CLASS(dev, 0x009e, GR); /* swzsurf */
+               NVOBJ_CLASS(dev, 0x0096, GR); /* celcius */
+
+               /* kelvin */
+               if (dev_priv->chipset < 0x25)
+                       NVOBJ_CLASS(dev, 0x0097, GR);
+               else
+                       NVOBJ_CLASS(dev, 0x0597, GR);
+       } else {
+               NVOBJ_CLASS(dev, 0x038a, GR); /* ifc (nv30) */
+               NVOBJ_CLASS(dev, 0x0389, GR); /* sifm (nv30) */
+               NVOBJ_CLASS(dev, 0x0362, GR); /* surf2d (nv30) */
+               NVOBJ_CLASS(dev, 0x039e, GR); /* swzsurf */
+
+               /* rankine */
+               if (0x00000003 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0397, GR);
+               else
+               if (0x00000010 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0697, GR);
+               else
+               if (0x000001e0 & (1 << (dev_priv->chipset & 0x0f)))
+                       NVOBJ_CLASS(dev, 0x0497, GR);
+       }
+
+       return 0;
+}
index 49b9a35a9cd6c79857fab54e69590f3e046cac53..68cb2d991c88c5c865062ed9bc5d88f14c242357 100644 (file)
@@ -115,6 +115,7 @@ nv40_fifo_do_load_context(struct drm_device *dev, int chid)
        nv_wr32(dev, 0x32e8, nv_ri32(dev, fc + 68));
        nv_wr32(dev, 0x2088, nv_ri32(dev, fc + 76));
        nv_wr32(dev, 0x3300, nv_ri32(dev, fc + 80));
+       nv_wr32(dev, 0x330c, nv_ri32(dev, fc + 84));
 
        nv_wr32(dev, NV03_PFIFO_CACHE1_GET, 0);
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUT, 0);
@@ -186,6 +187,7 @@ nv40_fifo_unload_context(struct drm_device *dev)
        tmp |= (nv_rd32(dev, NV04_PFIFO_CACHE1_PUT) << 16);
        nv_wi32(dev, fc + 72, tmp);
 #endif
+       nv_wi32(dev, fc + 84, nv_rd32(dev, 0x330c));
 
        nv40_fifo_do_load_context(dev, pfifo->channels - 1);
        nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH1,
index fceb44c0ec748d2f1499dc6255983339c675c830..5beb01b8ace1387bd04639a7b49be90d28bd4d9f 100644 (file)
 #include "drm.h"
 #include "nouveau_drv.h"
 #include "nouveau_grctx.h"
+#include "nouveau_ramht.h"
 
-static int nv40_graph_register(struct drm_device *);
-static void nv40_graph_isr(struct drm_device *);
+struct nv40_graph_engine {
+       struct nouveau_exec_engine base;
+       u32 grctx_size;
+};
 
-struct nouveau_channel *
+static struct nouveau_channel *
 nv40_graph_channel(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *grctx;
        uint32_t inst;
        int i;
 
@@ -45,74 +49,17 @@ nv40_graph_channel(struct drm_device *dev)
        inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4;
 
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+               if (!dev_priv->channels.ptr[i])
+                       continue;
 
-               if (chan && chan->ramin_grctx &&
-                   chan->ramin_grctx->pinst == inst)
-                       return chan;
+               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
+               if (grctx && grctx->pinst == inst)
+                       return dev_priv->channels.ptr[i];
        }
 
        return NULL;
 }
 
-int
-nv40_graph_create_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_grctx ctx = {};
-       unsigned long flags;
-       int ret;
-
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 16,
-                                NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin_grctx);
-       if (ret)
-               return ret;
-
-       /* Initialise default context values */
-       ctx.dev = chan->dev;
-       ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx;
-       nv40_grctx_init(&ctx);
-
-       nv_wo32(chan->ramin_grctx, 0, chan->ramin_grctx->pinst);
-
-       /* init grctx pointer in ramfc, and on PFIFO if channel is
-        * already active there
-        */
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       nv_wo32(chan->ramfc, 0x38, chan->ramin_grctx->pinst >> 4);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
-       if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
-               nv_wr32(dev, 0x0032e0, chan->ramin_grctx->pinst >> 4);
-       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-       return 0;
-}
-
-void
-nv40_graph_destroy_context(struct nouveau_channel *chan)
-{
-       struct drm_device *dev = chan->dev;
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       unsigned long flags;
-
-       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
-       pgraph->fifo_access(dev, false);
-
-       /* Unload the context if it's the currently active one */
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
-
-       pgraph->fifo_access(dev, true);
-       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
-
-       /* Free the context resources */
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
-}
-
 static int
 nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
 {
@@ -154,57 +101,115 @@ nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save)
        return 0;
 }
 
-/* Restore the context for a specific channel into PGRAPH */
-int
-nv40_graph_load_context(struct nouveau_channel *chan)
+static int
+nv40_graph_unload_context(struct drm_device *dev)
 {
-       struct drm_device *dev = chan->dev;
        uint32_t inst;
        int ret;
 
-       if (!chan->ramin_grctx)
-               return -EINVAL;
-       inst = chan->ramin_grctx->pinst >> 4;
+       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
+               return 0;
+       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+       ret = nv40_graph_transfer_context(dev, inst, 1);
+
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+       return ret;
+}
+
+static int
+nv40_graph_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nv40_graph_engine *pgraph = nv_engine(chan->dev, engine);
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *grctx = NULL;
+       struct nouveau_grctx ctx = {};
+       unsigned long flags;
+       int ret;
 
-       ret = nv40_graph_transfer_context(dev, inst, 0);
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 16,
+                                NVOBJ_FLAG_ZERO_ALLOC, &grctx);
        if (ret)
                return ret;
 
-       /* 0x40032C, no idea of it's exact function.  Could simply be a
-        * record of the currently active PGRAPH context.  It's currently
-        * unknown as to what bit 24 does.  The nv ddx has it set, so we will
-        * set it here too.
-        */
-       nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst);
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR,
-                (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) |
-                 NV40_PGRAPH_CTXCTL_CUR_LOADED);
-       /* 0x32E0 records the instance address of the active FIFO's PGRAPH
-        * context.  If at any time this doesn't match 0x40032C, you will
-        * receive PGRAPH_INTR_CONTEXT_SWITCH
+       /* Initialise default context values */
+       ctx.dev = chan->dev;
+       ctx.mode = NOUVEAU_GRCTX_VALS;
+       ctx.data = grctx;
+       nv40_grctx_init(&ctx);
+
+       nv_wo32(grctx, 0, grctx->vinst);
+
+       /* init grctx pointer in ramfc, and on PFIFO if channel is
+        * already active there
         */
-       nv_wr32(dev, NV40_PFIFO_GRCTX_INSTANCE, inst);
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_wo32(chan->ramfc, 0x38, grctx->vinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+       if ((nv_rd32(dev, 0x003204) & 0x0000001f) == chan->id)
+               nv_wr32(dev, 0x0032e0, grctx->vinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       chan->engctx[engine] = grctx;
        return 0;
 }
 
-int
-nv40_graph_unload_context(struct drm_device *dev)
+static void
+nv40_graph_context_del(struct nouveau_channel *chan, int engine)
 {
-       uint32_t inst;
-       int ret;
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       unsigned long flags;
 
-       inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE;
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv04_graph_fifo_access(dev, false);
 
-       ret = nv40_graph_transfer_context(dev, inst, 1);
+       /* Unload the context if it's the currently active one */
+       if (nv40_graph_channel(dev) == chan)
+               nv40_graph_unload_context(dev);
 
-       nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst);
+       nv04_graph_fifo_access(dev, true);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       /* Free the context resources */
+       nouveau_gpuobj_ref(NULL, &grctx);
+       chan->engctx[engine] = NULL;
+}
+
+int
+nv40_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+#ifndef __BIG_ENDIAN
+       nv_wo32(obj, 0x08, 0x00000000);
+#else
+       nv_wo32(obj, 0x08, 0x01000000);
+#endif
+       nv_wo32(obj, 0x0c, 0x00000000);
+       nv_wo32(obj, 0x10, 0x00000000);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
        return ret;
 }
 
-void
+static void
 nv40_graph_set_tile_region(struct drm_device *dev, int i)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -257,14 +262,14 @@ nv40_graph_set_tile_region(struct drm_device *dev, int i)
  * C51         0x4e
  */
 int
-nv40_graph_init(struct drm_device *dev)
+nv40_graph_init(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv =
-               (struct drm_nouveau_private *)dev->dev_private;
+       struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fb_engine *pfb = &dev_priv->engine.fb;
        struct nouveau_grctx ctx = {};
        uint32_t vramsz, *cp;
-       int ret, i, j;
+       int i, j;
 
        nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) &
                        ~NV_PMC_ENABLE_PGRAPH);
@@ -280,7 +285,7 @@ nv40_graph_init(struct drm_device *dev)
        ctx.data = cp;
        ctx.ctxprog_max = 256;
        nv40_grctx_init(&ctx);
-       dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
+       pgraph->grctx_size = ctx.ctxvals_pos * 4;
 
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
        for (i = 0; i < ctx.ctxprog_len; i++)
@@ -288,14 +293,9 @@ nv40_graph_init(struct drm_device *dev)
 
        kfree(cp);
 
-       ret = nv40_graph_register(dev);
-       if (ret)
-               return ret;
-
        /* No context present currently */
        nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
 
-       nouveau_irq_register(dev, 12, nv40_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR   , 0xFFFFFFFF);
        nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
 
@@ -428,47 +428,10 @@ nv40_graph_init(struct drm_device *dev)
        return 0;
 }
 
-void nv40_graph_takedown(struct drm_device *dev)
-{
-       nouveau_irq_unregister(dev, 12);
-}
-
 static int
-nv40_graph_register(struct drm_device *dev)
+nv40_graph_fini(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
-       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
-       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
-       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
-       NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
-       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
-       NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
-       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
-       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
-       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
-       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
-       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
-       NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
-
-       /* curie */
-       if (nv44_graph_class(dev))
-               NVOBJ_CLASS(dev, 0x4497, GR);
-       else
-               NVOBJ_CLASS(dev, 0x4097, GR);
-
-       /* nvsw */
-       NVOBJ_CLASS(dev, 0x506e, SW);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
-
-       dev_priv->engine.graph.registered = true;
+       nv40_graph_unload_context(dev);
        return 0;
 }
 
@@ -476,17 +439,17 @@ static int
 nv40_graph_isr_chid(struct drm_device *dev, u32 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_channel *chan;
+       struct nouveau_gpuobj *grctx;
        unsigned long flags;
        int i;
 
        spin_lock_irqsave(&dev_priv->channels.lock, flags);
        for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               chan = dev_priv->channels.ptr[i];
-               if (!chan || !chan->ramin_grctx)
+               if (!dev_priv->channels.ptr[i])
                        continue;
+               grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR];
 
-               if (inst == chan->ramin_grctx->pinst)
+               if (grctx && grctx->pinst == inst)
                        break;
        }
        spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
@@ -537,3 +500,63 @@ nv40_graph_isr(struct drm_device *dev)
                }
        }
 }
+
+static void
+nv40_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv40_graph_engine *pgraph = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 12);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(pgraph);
+}
+
+int
+nv40_graph_create(struct drm_device *dev)
+{
+       struct nv40_graph_engine *pgraph;
+
+       pgraph = kzalloc(sizeof(*pgraph), GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       pgraph->base.destroy = nv40_graph_destroy;
+       pgraph->base.init = nv40_graph_init;
+       pgraph->base.fini = nv40_graph_fini;
+       pgraph->base.context_new = nv40_graph_context_new;
+       pgraph->base.context_del = nv40_graph_context_del;
+       pgraph->base.object_new = nv40_graph_object_new;
+       pgraph->base.set_tile_region = nv40_graph_set_tile_region;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       nouveau_irq_register(dev, 12, nv40_graph_isr);
+
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x0039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x004a, GR); /* gdirect */
+       NVOBJ_CLASS(dev, 0x009f, GR); /* imageblit (nv12) */
+       NVOBJ_CLASS(dev, 0x008a, GR); /* ifc */
+       NVOBJ_CLASS(dev, 0x0089, GR); /* sifm */
+       NVOBJ_CLASS(dev, 0x3089, GR); /* sifm (nv40) */
+       NVOBJ_CLASS(dev, 0x0062, GR); /* surf2d */
+       NVOBJ_CLASS(dev, 0x3062, GR); /* surf2d (nv40) */
+       NVOBJ_CLASS(dev, 0x0043, GR); /* rop */
+       NVOBJ_CLASS(dev, 0x0012, GR); /* beta1 */
+       NVOBJ_CLASS(dev, 0x0072, GR); /* beta4 */
+       NVOBJ_CLASS(dev, 0x0019, GR); /* cliprect */
+       NVOBJ_CLASS(dev, 0x0044, GR); /* pattern */
+       NVOBJ_CLASS(dev, 0x309e, GR); /* swzsurf */
+
+       /* curie */
+       if (nv44_graph_class(dev))
+               NVOBJ_CLASS(dev, 0x4497, GR);
+       else
+               NVOBJ_CLASS(dev, 0x4097, GR);
+
+       /* nvsw */
+       NVOBJ_CLASS(dev, 0x506e, SW);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv04_graph_mthd_page_flip);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nv40_mpeg.c b/drivers/gpu/drm/nouveau/nv40_mpeg.c
new file mode 100644 (file)
index 0000000..6d2af29
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv40_mpeg_engine {
+       struct nouveau_exec_engine base;
+};
+
+static int
+nv40_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ctx = NULL;
+       unsigned long flags;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ctx, 0x78, 0x02001ec1);
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000000);
+       if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id)
+               nv_wr32(dev, 0x00330c, ctx->pinst >> 4);
+       nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4);
+       nv_mask(dev, 0x002500, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static void
+nv40_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       unsigned long flags;
+       u32 inst = 0x80000000 | (ctx->pinst >> 4);
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(dev, 0x00b318) == inst)
+               nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       nouveau_gpuobj_ref(NULL, &ctx);
+       chan->engctx[engine] = NULL;
+}
+
+static int
+nv40_mpeg_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 2;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static int
+nv40_mpeg_init(struct drm_device *dev, int engine)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+       int i;
+
+       /* VPE init */
+       nv_mask(dev, 0x000200, 0x00000002, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00000002, 0x00000002);
+       nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+       nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+       for (i = 0; i < dev_priv->engine.fb.num_tiles; i++)
+               pmpeg->base.set_tile_region(dev, i);
+
+       /* PMPEG init */
+       nv_wr32(dev, 0x00b32c, 0x00000000);
+       nv_wr32(dev, 0x00b314, 0x00000100);
+       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b300, 0x02001ec1);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+       nv_wr32(dev, 0x00b100, 0xffffffff);
+       nv_wr32(dev, 0x00b140, 0xffffffff);
+
+       if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+nv40_mpeg_fini(struct drm_device *dev, int engine)
+{
+       /*XXX: context save? */
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       nv_wr32(dev, 0x00b140, 0x00000000);
+       return 0;
+}
+
+static int
+nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data)
+{
+       struct drm_device *dev = chan->dev;
+       u32 inst = data << 4;
+       u32 dma0 = nv_ri32(dev, inst + 0);
+       u32 dma1 = nv_ri32(dev, inst + 4);
+       u32 dma2 = nv_ri32(dev, inst + 8);
+       u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+       u32 size = dma1 + 1;
+
+       /* only allow linear DMA objects */
+       if (!(dma0 & 0x00002000))
+               return -EINVAL;
+
+       if (mthd == 0x0190) {
+               /* DMA_CMD */
+               nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+               nv_wr32(dev, 0x00b334, base);
+               nv_wr32(dev, 0x00b324, size);
+       } else
+       if (mthd == 0x01a0) {
+               /* DMA_DATA */
+               nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+               nv_wr32(dev, 0x00b360, base);
+               nv_wr32(dev, 0x00b364, size);
+       } else {
+               /* DMA_IMAGE, VRAM only */
+               if (dma0 & 0x000c0000)
+                       return -EINVAL;
+
+               nv_wr32(dev, 0x00b370, base);
+               nv_wr32(dev, 0x00b374, size);
+       }
+
+       return 0;
+}
+
+static int
+nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ctx;
+       unsigned long flags;
+       int i;
+
+       spin_lock_irqsave(&dev_priv->channels.lock, flags);
+       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+               if (!dev_priv->channels.ptr[i])
+                       continue;
+
+               ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG];
+               if (ctx && ctx->pinst == inst)
+                       break;
+       }
+       spin_unlock_irqrestore(&dev_priv->channels.lock, flags);
+       return i;
+}
+
+static void
+nv40_vpe_set_tile_region(struct drm_device *dev, int i)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i];
+
+       nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch);
+       nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit);
+       nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+static void
+nv40_mpeg_isr(struct drm_device *dev)
+{
+       u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4;
+       u32 chid = nv40_mpeg_isr_chid(dev, inst);
+       u32 stat = nv_rd32(dev, 0x00b100);
+       u32 type = nv_rd32(dev, 0x00b230);
+       u32 mthd = nv_rd32(dev, 0x00b234);
+       u32 data = nv_rd32(dev, 0x00b238);
+       u32 show = stat;
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_mask(dev, 0x00b308, 0x00000000, 0x00000000);
+                       show &= ~0x01000000;
+               }
+
+               if (type == 0x00000010) {
+                       if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data))
+                               show &= ~0x01000000;
+               }
+       }
+
+       nv_wr32(dev, 0x00b100, stat);
+       nv_wr32(dev, 0x00b230, 0x00000001);
+
+       if (show && nouveau_ratelimit()) {
+               NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       chid, inst, stat, type, mthd, data);
+       }
+}
+
+static void
+nv40_vpe_isr(struct drm_device *dev)
+{
+       if (nv_rd32(dev, 0x00b100))
+               nv40_mpeg_isr(dev);
+
+       if (nv_rd32(dev, 0x00b800)) {
+               u32 stat = nv_rd32(dev, 0x00b800);
+               NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+               nv_wr32(dev, 0xb800, stat);
+       }
+}
+
+static void
+nv40_mpeg_destroy(struct drm_device *dev, int engine)
+{
+       struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 0);
+
+       NVOBJ_ENGINE_DEL(dev, MPEG);
+       kfree(pmpeg);
+}
+
+int
+nv40_mpeg_create(struct drm_device *dev)
+{
+       struct nv40_mpeg_engine *pmpeg;
+
+       pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+       if (!pmpeg)
+               return -ENOMEM;
+
+       pmpeg->base.destroy = nv40_mpeg_destroy;
+       pmpeg->base.init = nv40_mpeg_init;
+       pmpeg->base.fini = nv40_mpeg_fini;
+       pmpeg->base.context_new = nv40_mpeg_context_new;
+       pmpeg->base.context_del = nv40_mpeg_context_del;
+       pmpeg->base.object_new = nv40_mpeg_object_new;
+
+       /* ISR vector, PMC_ENABLE bit,  and TILE regs are shared between
+        * all VPE engines, for this driver's purposes the PMPEG engine
+        * will be treated as the "master" and handle the global VPE
+        * bits too
+        */
+       pmpeg->base.set_tile_region = nv40_vpe_set_tile_region;
+       nouveau_irq_register(dev, 0, nv40_vpe_isr);
+
+       NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+       NVOBJ_CLASS(dev, 0x3174, MPEG);
+       NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma);
+       NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma);
+       NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma);
+
+#if 0
+       NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+       NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+       return 0;
+
+}
index de81151648f831c5a7c97b9491d3670c356276f5..8cf63a8b30cdb96198e8b8be469e48e2c42604a4 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include "drmP.h"
-#include "drm_fixed.h"
 #include "nouveau_drv.h"
 #include "nouveau_hw.h"
 
@@ -47,45 +46,52 @@ nv50_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
 }
 
 int
-nv50_calc_pll2(struct drm_device *dev, struct pll_lims *pll, int clk,
-              int *N, int *fN, int *M, int *P)
+nva3_calc_pll(struct drm_device *dev, struct pll_lims *pll, int clk,
+             int *pN, int *pfN, int *pM, int *P)
 {
-       fixed20_12 fb_div, a, b;
-       u32 refclk = pll->refclk / 10;
-       u32 max_vco_freq = pll->vco1.maxfreq / 10;
-       u32 max_vco_inputfreq = pll->vco1.max_inputfreq / 10;
-       clk /= 10;
+       u32 best_err = ~0, err;
+       int M, lM, hM, N, fN;
 
-       *P = max_vco_freq / clk;
+       *P = pll->vco1.maxfreq / clk;
        if (*P > pll->max_p)
                *P = pll->max_p;
        if (*P < pll->min_p)
                *P = pll->min_p;
 
-       /* *M = floor((refclk + max_vco_inputfreq) / max_vco_inputfreq); */
-       a.full = dfixed_const(refclk + max_vco_inputfreq);
-       b.full = dfixed_const(max_vco_inputfreq);
-       a.full = dfixed_div(a, b);
-       a.full = dfixed_floor(a);
-       *M = dfixed_trunc(a);
+       lM = (pll->refclk + pll->vco1.max_inputfreq) / pll->vco1.max_inputfreq;
+       lM = max(lM, (int)pll->vco1.min_m);
+       hM = (pll->refclk + pll->vco1.min_inputfreq) / pll->vco1.min_inputfreq;
+       hM = min(hM, (int)pll->vco1.max_m);
 
-       /* fb_div = (vco * *M) / refclk; */
-       fb_div.full = dfixed_const(clk * *P);
-       fb_div.full = dfixed_mul(fb_div, a);
-       a.full = dfixed_const(refclk);
-       fb_div.full = dfixed_div(fb_div, a);
+       for (M = lM; M <= hM; M++) {
+               u32 tmp = clk * *P * M;
+               N  = tmp / pll->refclk;
+               fN = tmp % pll->refclk;
+               if (!pfN && fN >= pll->refclk / 2)
+                       N++;
 
-       /* *N = floor(fb_div); */
-       a.full = dfixed_floor(fb_div);
-       *N = dfixed_trunc(fb_div);
+               if (N < pll->vco1.min_n)
+                       continue;
+               if (N > pll->vco1.max_n)
+                       break;
 
-       /* *fN = (fmod(fb_div, 1.0) * 8192) - 4096; */
-       b.full = dfixed_const(8192);
-       a.full = dfixed_mul(a, b);
-       fb_div.full = dfixed_mul(fb_div, b);
-       fb_div.full = fb_div.full - a.full;
-       *fN = dfixed_trunc(fb_div) - 4096;
-       *fN &= 0xffff;
+               err = abs(clk - (pll->refclk * N / M / *P));
+               if (err < best_err) {
+                       best_err = err;
+                       *pN = N;
+                       *pM = M;
+               }
 
-       return clk;
+               if (pfN) {
+                       *pfN = (((fN << 13) / pll->refclk) - 4096) & 0xffff;
+                       return clk;
+               }
+       }
+
+       if (unlikely(best_err == ~0)) {
+               NV_ERROR(dev, "unable to find matching pll values\n");
+               return -EINVAL;
+       }
+
+       return pll->refclk * *pN / *pM / *P;
 }
index a19ccaa025b389508f604f72a10a060d338a32ee..ebabacf38da9ff02ae5f2f0f2503e1ffb3fd0ce5 100644 (file)
@@ -286,7 +286,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, pll.reg + 8, reg2 | (P << 28) | (M2 << 16) | N2);
        } else
        if (dev_priv->chipset < NV_C0) {
-               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
 
@@ -298,7 +298,7 @@ nv50_crtc_set_clock(struct drm_device *dev, int head, int pclk)
                nv_wr32(dev, pll.reg + 4, reg1 | (P << 16) | (M1 << 8) | N1);
                nv_wr32(dev, pll.reg + 8, N2);
        } else {
-               ret = nv50_calc_pll2(dev, &pll, pclk, &N1, &N2, &M1, &P);
+               ret = nva3_calc_pll(dev, &pll, pclk, &N1, &N2, &M1, &P);
                if (ret <= 0)
                        return 0;
 
@@ -349,14 +349,14 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
        struct drm_gem_object *gem;
        int ret = 0, i;
 
-       if (width != 64 || height != 64)
-               return -EINVAL;
-
        if (!buffer_handle) {
                nv_crtc->cursor.hide(nv_crtc, true);
                return 0;
        }
 
+       if (width != 64 || height != 64)
+               return -EINVAL;
+
        gem = drm_gem_object_lookup(dev, file_priv, buffer_handle);
        if (!gem)
                return -ENOENT;
@@ -532,8 +532,7 @@ nv50_crtc_do_mode_set_base(struct drm_crtc *crtc,
        if (atomic) {
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
-       }
-       else {
+       } else {
                /* If not atomic, we can go ahead and pin, and unpin the
                 * old fb we were passed.
                 */
index 75a376cc342a54e4201c978bf8d7a08de21ccd0d..74a3f687270124cdfb32ddd55ce78f9ae70a6157 100644 (file)
@@ -517,13 +517,25 @@ nv50_display_script_select(struct drm_device *dev, struct dcb_entry *dcb,
                        if (bios->fp.if_is_24bit)
                                script |= 0x0200;
                } else {
+                       /* determine number of lvds links */
+                       if (nv_connector && nv_connector->edid &&
+                           nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) {
+                               /* http://www.spwg.org */
+                               if (((u8 *)nv_connector->edid)[121] == 2)
+                                       script |= 0x0100;
+                       } else
                        if (pxclk >= bios->fp.duallink_transition_clk) {
                                script |= 0x0100;
+                       }
+
+                       /* determine panel depth */
+                       if (script & 0x0100) {
                                if (bios->fp.strapless_is_24bit & 2)
                                        script |= 0x0200;
-                       } else
-                       if (bios->fp.strapless_is_24bit & 1)
-                               script |= 0x0200;
+                       } else {
+                               if (bios->fp.strapless_is_24bit & 1)
+                                       script |= 0x0200;
+                       }
 
                        if (nv_connector && nv_connector->edid &&
                            (nv_connector->edid->revision >= 4) &&
index b02a5b1e7d379fb1928467a668b905ddb4fa30b9..e25cbb46789a6780b5cf9611680468a835a09cff 100644 (file)
 #include "nouveau_grctx.h"
 #include "nouveau_dma.h"
 #include "nouveau_vm.h"
+#include "nouveau_ramht.h"
 #include "nv50_evo.h"
 
-static int  nv50_graph_register(struct drm_device *);
-static void nv50_graph_isr(struct drm_device *);
+struct nv50_graph_engine {
+       struct nouveau_exec_engine base;
+       u32 ctxprog[512];
+       u32 ctxprog_size;
+       u32 grctx_size;
+};
+
+static void
+nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
+{
+       const uint32_t mask = 0x00010001;
+
+       if (enabled)
+               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
+       else
+               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
+}
+
+static struct nouveau_channel *
+nv50_graph_channel(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       uint32_t inst;
+       int i;
+
+       /* Be sure we're not in the middle of a context switch or bad things
+        * will happen, such as unloading the wrong pgraph context.
+        */
+       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
+               NV_ERROR(dev, "Ctxprog is still running\n");
+
+       inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+               return NULL;
+       inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
+
+       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
+               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
+
+               if (chan && chan->ramin && chan->ramin->vinst == inst)
+                       return chan;
+       }
+
+       return NULL;
+}
+
+static int
+nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
+{
+       uint32_t fifo = nv_rd32(dev, 0x400500);
+
+       nv_wr32(dev, 0x400500, fifo & ~1);
+       nv_wr32(dev, 0x400784, inst);
+       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
+       nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
+       nv_wr32(dev, 0x400040, 0xffffffff);
+       (void)nv_rd32(dev, 0x400040);
+       nv_wr32(dev, 0x400040, 0x00000000);
+       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
+
+       if (nouveau_wait_for_idle(dev))
+               nv_wr32(dev, 0x40032c, inst | (1<<31));
+       nv_wr32(dev, 0x400500, fifo);
+
+       return 0;
+}
+
+static int
+nv50_graph_unload_context(struct drm_device *dev)
+{
+       uint32_t inst;
+
+       inst  = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
+       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
+               return 0;
+       inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+
+       nouveau_wait_for_idle(dev);
+       nv_wr32(dev, 0x400784, inst);
+       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
+       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
+       nouveau_wait_for_idle(dev);
+
+       nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
+       return 0;
+}
 
 static void
 nv50_graph_init_reset(struct drm_device *dev)
@@ -52,7 +137,6 @@ nv50_graph_init_intr(struct drm_device *dev)
 {
        NV_DEBUG(dev, "\n");
 
-       nouveau_irq_register(dev, 12, nv50_graph_isr);
        nv_wr32(dev, NV03_PGRAPH_INTR, 0xffffffff);
        nv_wr32(dev, 0x400138, 0xffffffff);
        nv_wr32(dev, NV40_PGRAPH_INTR_EN, 0xffffffff);
@@ -135,34 +219,14 @@ nv50_graph_init_zcull(struct drm_device *dev)
 static int
 nv50_graph_init_ctxctl(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_grctx ctx = {};
-       uint32_t *cp;
+       struct nv50_graph_engine *pgraph = nv_engine(dev, NVOBJ_ENGINE_GR);
        int i;
 
        NV_DEBUG(dev, "\n");
 
-       cp = kmalloc(512 * 4, GFP_KERNEL);
-       if (!cp) {
-               NV_ERROR(dev, "failed to allocate ctxprog\n");
-               dev_priv->engine.graph.accel_blocked = true;
-               return 0;
-       }
-
-       ctx.dev = dev;
-       ctx.mode = NOUVEAU_GRCTX_PROG;
-       ctx.data = cp;
-       ctx.ctxprog_max = 512;
-       if (!nv50_grctx_init(&ctx)) {
-               dev_priv->engine.graph.grctx_size = ctx.ctxvals_pos * 4;
-
-               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
-               for (i = 0; i < ctx.ctxprog_len; i++)
-                       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, cp[i]);
-       } else {
-               dev_priv->engine.graph.accel_blocked = true;
-       }
-       kfree(cp);
+       nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_INDEX, 0);
+       for (i = 0; i < pgraph->ctxprog_size; i++)
+               nv_wr32(dev, NV40_PGRAPH_CTXCTL_UCODE_DATA, pgraph->ctxprog[i]);
 
        nv_wr32(dev, 0x40008c, 0x00000004); /* HW_CTX_SWITCH_ENABLED */
        nv_wr32(dev, 0x400320, 4);
@@ -171,8 +235,8 @@ nv50_graph_init_ctxctl(struct drm_device *dev)
        return 0;
 }
 
-int
-nv50_graph_init(struct drm_device *dev)
+static int
+nv50_graph_init(struct drm_device *dev, int engine)
 {
        int ret;
 
@@ -186,105 +250,66 @@ nv50_graph_init(struct drm_device *dev)
        if (ret)
                return ret;
 
-       ret = nv50_graph_register(dev);
-       if (ret)
-               return ret;
        nv50_graph_init_intr(dev);
        return 0;
 }
 
-void
-nv50_graph_takedown(struct drm_device *dev)
+static int
+nv50_graph_fini(struct drm_device *dev, int engine)
 {
        NV_DEBUG(dev, "\n");
+       nv50_graph_unload_context(dev);
        nv_wr32(dev, 0x40013c, 0x00000000);
-       nouveau_irq_unregister(dev, 12);
-}
-
-void
-nv50_graph_fifo_access(struct drm_device *dev, bool enabled)
-{
-       const uint32_t mask = 0x00010001;
-
-       if (enabled)
-               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) | mask);
-       else
-               nv_wr32(dev, 0x400500, nv_rd32(dev, 0x400500) & ~mask);
-}
-
-struct nouveau_channel *
-nv50_graph_channel(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       uint32_t inst;
-       int i;
-
-       /* Be sure we're not in the middle of a context switch or bad things
-        * will happen, such as unloading the wrong pgraph context.
-        */
-       if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000))
-               NV_ERROR(dev, "Ctxprog is still running\n");
-
-       inst = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
-               return NULL;
-       inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12;
-
-       for (i = 0; i < dev_priv->engine.fifo.channels; i++) {
-               struct nouveau_channel *chan = dev_priv->channels.ptr[i];
-
-               if (chan && chan->ramin && chan->ramin->vinst == inst)
-                       return chan;
-       }
-
-       return NULL;
+       return 0;
 }
 
-int
-nv50_graph_create_context(struct nouveau_channel *chan)
+static int
+nv50_graph_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
+       struct nouveau_gpuobj *grctx = NULL;
+       struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
        struct nouveau_grctx ctx = {};
        int hdr, ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0,
+       ret = nouveau_gpuobj_new(dev, NULL, pgraph->grctx_size, 0,
                                 NVOBJ_FLAG_ZERO_ALLOC |
-                                NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx);
+                                NVOBJ_FLAG_ZERO_FREE, &grctx);
        if (ret)
                return ret;
 
        hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        nv_wo32(ramin, hdr + 0x00, 0x00190002);
-       nv_wo32(ramin, hdr + 0x04, chan->ramin_grctx->vinst +
-                                  pgraph->grctx_size - 1);
-       nv_wo32(ramin, hdr + 0x08, chan->ramin_grctx->vinst);
+       nv_wo32(ramin, hdr + 0x04, grctx->vinst + grctx->size - 1);
+       nv_wo32(ramin, hdr + 0x08, grctx->vinst);
        nv_wo32(ramin, hdr + 0x0c, 0);
        nv_wo32(ramin, hdr + 0x10, 0);
        nv_wo32(ramin, hdr + 0x14, 0x00010000);
 
        ctx.dev = chan->dev;
        ctx.mode = NOUVEAU_GRCTX_VALS;
-       ctx.data = chan->ramin_grctx;
+       ctx.data = grctx;
        nv50_grctx_init(&ctx);
 
-       nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12);
+       nv_wo32(grctx, 0x00000, chan->ramin->vinst >> 12);
 
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pgraph_refs);
+
+       atomic_inc(&chan->vm->engref[NVOBJ_ENGINE_GR]);
+       chan->engctx[NVOBJ_ENGINE_GR] = grctx;
        return 0;
 }
 
-void
-nv50_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nv50_graph_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *grctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20;
        unsigned long flags;
@@ -296,72 +321,49 @@ nv50_graph_destroy_context(struct nouveau_channel *chan)
 
        spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
        pfifo->reassign(dev, false);
-       pgraph->fifo_access(dev, false);
+       nv50_graph_fifo_access(dev, false);
 
-       if (pgraph->channel(dev) == chan)
-               pgraph->unload_context(dev);
+       if (nv50_graph_channel(dev) == chan)
+               nv50_graph_unload_context(dev);
 
        for (i = hdr; i < hdr + 24; i += 4)
                nv_wo32(chan->ramin, i, 0);
        dev_priv->engine.instmem.flush(dev);
 
-       pgraph->fifo_access(dev, true);
+       nv50_graph_fifo_access(dev, true);
        pfifo->reassign(dev, true);
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 
-       nouveau_gpuobj_ref(NULL, &chan->ramin_grctx);
+       nouveau_gpuobj_ref(NULL, &grctx);
 
-       atomic_dec(&chan->vm->pgraph_refs);
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
 static int
-nv50_graph_do_load_context(struct drm_device *dev, uint32_t inst)
-{
-       uint32_t fifo = nv_rd32(dev, 0x400500);
-
-       nv_wr32(dev, 0x400500, fifo & ~1);
-       nv_wr32(dev, 0x400784, inst);
-       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x40);
-       nv_wr32(dev, 0x400320, nv_rd32(dev, 0x400320) | 0x11);
-       nv_wr32(dev, 0x400040, 0xffffffff);
-       (void)nv_rd32(dev, 0x400040);
-       nv_wr32(dev, 0x400040, 0x00000000);
-       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 1);
-
-       if (nouveau_wait_for_idle(dev))
-               nv_wr32(dev, 0x40032c, inst | (1<<31));
-       nv_wr32(dev, 0x400500, fifo);
-
-       return 0;
-}
-
-int
-nv50_graph_load_context(struct nouveau_channel *chan)
-{
-       uint32_t inst = chan->ramin->vinst >> 12;
-
-       NV_DEBUG(chan->dev, "ch%d\n", chan->id);
-       return nv50_graph_do_load_context(chan->dev, inst);
-}
-
-int
-nv50_graph_unload_context(struct drm_device *dev)
+nv50_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
-       uint32_t inst;
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
 
-       inst  = nv_rd32(dev, NV50_PGRAPH_CTXCTL_CUR);
-       if (!(inst & NV50_PGRAPH_CTXCTL_CUR_LOADED))
-               return 0;
-       inst &= NV50_PGRAPH_CTXCTL_CUR_INSTANCE;
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 1;
+       obj->class  = class;
 
-       nouveau_wait_for_idle(dev);
-       nv_wr32(dev, 0x400784, inst);
-       nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) | 0x20);
-       nv_wr32(dev, 0x400304, nv_rd32(dev, 0x400304) | 0x01);
-       nouveau_wait_for_idle(dev);
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, NV50_PGRAPH_CTXCTL_CUR, inst);
-       return 0;
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
 static void
@@ -442,68 +444,15 @@ nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nv50_graph_register(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->engine.graph.registered)
-               return 0;
-
-       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
-       NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
-       NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
-       NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
-       NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
-       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
-
-       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
-       NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
-       NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
-
-       /* tesla */
-       if (dev_priv->chipset == 0x50)
-               NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
-       else
-       if (dev_priv->chipset < 0xa0)
-               NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
-       else {
-               switch (dev_priv->chipset) {
-               case 0xa0:
-               case 0xaa:
-               case 0xac:
-                       NVOBJ_CLASS(dev, 0x8397, GR);
-                       break;
-               case 0xa3:
-               case 0xa5:
-               case 0xa8:
-                       NVOBJ_CLASS(dev, 0x8597, GR);
-                       break;
-               case 0xaf:
-                       NVOBJ_CLASS(dev, 0x8697, GR);
-                       break;
-               }
-       }
-
-       /* compute */
-       NVOBJ_CLASS(dev, 0x50c0, GR);
-       if (dev_priv->chipset  > 0xa0 &&
-           dev_priv->chipset != 0xaa &&
-           dev_priv->chipset != 0xac)
-               NVOBJ_CLASS(dev, 0x85c0, GR);
-
-       dev_priv->engine.graph.registered = true;
-       return 0;
-}
 
-void
-nv50_graph_tlb_flush(struct drm_device *dev)
+static void
+nv50_graph_tlb_flush(struct drm_device *dev, int engine)
 {
        nv50_vm_flush_engine(dev, 0);
 }
 
-void
-nv84_graph_tlb_flush(struct drm_device *dev)
+static void
+nv84_graph_tlb_flush(struct drm_device *dev, int engine)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer;
@@ -548,8 +497,7 @@ nv84_graph_tlb_flush(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
 }
 
-static struct nouveau_enum nv50_mp_exec_error_names[] =
-{
+static struct nouveau_enum nv50_mp_exec_error_names[] = {
        { 3, "STACK_UNDERFLOW", NULL },
        { 4, "QUADON_ACTIVE", NULL },
        { 8, "TIMEOUT", NULL },
@@ -663,7 +611,7 @@ nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display)
                        nv_rd32(dev, addr + 0x20);
                        pc = nv_rd32(dev, addr + 0x24);
                        oplow = nv_rd32(dev, addr + 0x70);
-                       ophigh= nv_rd32(dev, addr + 0x74);
+                       ophigh = nv_rd32(dev, addr + 0x74);
                        NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - "
                                        "TP %d MP %d: ", tpid, i);
                        nouveau_enum_print(nv50_mp_exec_error_names, status);
@@ -991,7 +939,7 @@ nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid
        return 1;
 }
 
-static int
+int
 nv50_graph_isr_chid(struct drm_device *dev, u64 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -1073,3 +1021,101 @@ nv50_graph_isr(struct drm_device *dev)
        if (nv_rd32(dev, 0x400824) & (1 << 31))
                nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31));
 }
+
+static void
+nv50_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nv50_graph_engine *pgraph = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+
+       nouveau_irq_unregister(dev, 12);
+       kfree(pgraph);
+}
+
+int
+nv50_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_graph_engine *pgraph;
+       struct nouveau_grctx ctx = {};
+       int ret;
+
+       pgraph = kzalloc(sizeof(*pgraph),GFP_KERNEL);
+       if (!pgraph)
+               return -ENOMEM;
+
+       ctx.dev = dev;
+       ctx.mode = NOUVEAU_GRCTX_PROG;
+       ctx.data = pgraph->ctxprog;
+       ctx.ctxprog_max = ARRAY_SIZE(pgraph->ctxprog);
+
+       ret = nv50_grctx_init(&ctx);
+       if (ret) {
+               NV_ERROR(dev, "PGRAPH: ctxprog build failed\n");
+               kfree(pgraph);
+               return 0;
+       }
+
+       pgraph->grctx_size = ctx.ctxvals_pos * 4;
+       pgraph->ctxprog_size = ctx.ctxprog_len;
+
+       pgraph->base.destroy = nv50_graph_destroy;
+       pgraph->base.init = nv50_graph_init;
+       pgraph->base.fini = nv50_graph_fini;
+       pgraph->base.context_new = nv50_graph_context_new;
+       pgraph->base.context_del = nv50_graph_context_del;
+       pgraph->base.object_new = nv50_graph_object_new;
+       if (dev_priv->chipset == 0x50 || dev_priv->chipset == 0xac)
+               pgraph->base.tlb_flush = nv50_graph_tlb_flush;
+       else
+               pgraph->base.tlb_flush = nv84_graph_tlb_flush;
+
+       nouveau_irq_register(dev, 12, nv50_graph_isr);
+
+       /* NVSW really doesn't live here... */
+       NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */
+       NVOBJ_MTHD (dev, 0x506e, 0x018c, nv50_graph_nvsw_dma_vblsem);
+       NVOBJ_MTHD (dev, 0x506e, 0x0400, nv50_graph_nvsw_vblsem_offset);
+       NVOBJ_MTHD (dev, 0x506e, 0x0404, nv50_graph_nvsw_vblsem_release_val);
+       NVOBJ_MTHD (dev, 0x506e, 0x0408, nv50_graph_nvsw_vblsem_release);
+       NVOBJ_MTHD (dev, 0x506e, 0x0500, nv50_graph_nvsw_mthd_page_flip);
+
+       NVOBJ_ENGINE_ADD(dev, GR, &pgraph->base);
+       NVOBJ_CLASS(dev, 0x0030, GR); /* null */
+       NVOBJ_CLASS(dev, 0x5039, GR); /* m2mf */
+       NVOBJ_CLASS(dev, 0x502d, GR); /* 2d */
+
+       /* tesla */
+       if (dev_priv->chipset == 0x50)
+               NVOBJ_CLASS(dev, 0x5097, GR); /* tesla (nv50) */
+       else
+       if (dev_priv->chipset < 0xa0)
+               NVOBJ_CLASS(dev, 0x8297, GR); /* tesla (nv8x/nv9x) */
+       else {
+               switch (dev_priv->chipset) {
+               case 0xa0:
+               case 0xaa:
+               case 0xac:
+                       NVOBJ_CLASS(dev, 0x8397, GR);
+                       break;
+               case 0xa3:
+               case 0xa5:
+               case 0xa8:
+                       NVOBJ_CLASS(dev, 0x8597, GR);
+                       break;
+               case 0xaf:
+                       NVOBJ_CLASS(dev, 0x8697, GR);
+                       break;
+               }
+       }
+
+       /* compute */
+       NVOBJ_CLASS(dev, 0x50c0, GR);
+       if (dev_priv->chipset  > 0xa0 &&
+           dev_priv->chipset != 0xaa &&
+           dev_priv->chipset != 0xac)
+               NVOBJ_CLASS(dev, 0x85c0, GR);
+
+       return 0;
+}
index 336aab2a24a66ff030b7af629db43f53aaa9ef8e..de9abff12b909122faf612f16a2dfd0ab17d0052 100644 (file)
@@ -747,7 +747,7 @@ nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
                                gr_def(ctx, offset + 0x64, 0x0000001f);
                                gr_def(ctx, offset + 0x68, 0x0000000f);
                                gr_def(ctx, offset + 0x6c, 0x0000000f);
-                       } else if(dev_priv->chipset < 0xa0) {
+                       } else if (dev_priv->chipset < 0xa0) {
                                cp_ctx(ctx, offset + 0x50, 1);
                                cp_ctx(ctx, offset + 0x70, 1);
                        } else {
@@ -924,7 +924,7 @@ nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
                dd_emit(ctx, 1, 0);     /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
        } else {
                dd_emit(ctx, 1, 0);     /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
-       } 
+       }
        dd_emit(ctx, 1, 0xc);           /* 000000ff SEMANTIC_COLOR.BFC0_ID */
        if (dev_priv->chipset != 0x50)
                dd_emit(ctx, 1, 0);     /* 00000001 SEMANTIC_COLOR.CLMP_EN */
@@ -1803,9 +1803,7 @@ nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
                xf_emit(ctx, 1, 0);     /* 1ff */
                xf_emit(ctx, 8, 0);     /* 0? */
                xf_emit(ctx, 9, 0);     /* ffffffff, 7ff */
-       }
-       else
-       {
+       } else {
                xf_emit(ctx, 0xc, 0);   /* RO */
                /* SEEK */
                xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
@@ -2836,7 +2834,7 @@ nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
        xf_emit(ctx, 1, 1);             /* 00000001 DST_LINEAR */
        if (IS_NVA3F(dev_priv->chipset))
                xf_emit(ctx, 1, 1);     /* 0000001f tesla UNK169C */
-       if(dev_priv->chipset == 0x50)
+       if (dev_priv->chipset == 0x50)
                xf_emit(ctx, 1, 0);     /* ff */
        else
                xf_emit(ctx, 3, 0);     /* 1, 7, 3ff */
diff --git a/drivers/gpu/drm/nouveau/nv50_mpeg.c b/drivers/gpu/drm/nouveau/nv50_mpeg.c
new file mode 100644 (file)
index 0000000..1dc5913
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_ramht.h"
+
+struct nv50_mpeg_engine {
+       struct nouveau_exec_engine base;
+};
+
+static inline u32
+CTX_PTR(struct drm_device *dev, u32 offset)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->chipset == 0x50)
+               offset += 0x0260;
+       else
+               offset += 0x0060;
+
+       return offset;
+}
+
+static int
+nv50_mpeg_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 128 * 4, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, CTX_PTR(dev, 0x00), 0x80190002);
+       nv_wo32(ramin, CTX_PTR(dev, 0x04), ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, CTX_PTR(dev, 0x08), ctx->vinst);
+       nv_wo32(ramin, CTX_PTR(dev, 0x0c), 0);
+       nv_wo32(ramin, CTX_PTR(dev, 0x10), 0);
+       nv_wo32(ramin, CTX_PTR(dev, 0x14), 0x00010000);
+
+       nv_wo32(ctx, 0x70, 0x00801ec1);
+       nv_wo32(ctx, 0x7c, 0x0000037c);
+       dev_priv->engine.instmem.flush(dev);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static void
+nv50_mpeg_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       unsigned long flags;
+       u32 inst, i;
+
+       if (!chan->ramin)
+               return;
+
+       inst  = chan->ramin->vinst >> 12;
+       inst |= 0x80000000;
+
+       spin_lock_irqsave(&dev_priv->context_switch_lock, flags);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       if (nv_rd32(dev, 0x00b318) == inst)
+               nv_mask(dev, 0x00b318, 0x80000000, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+       spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags);
+
+       for (i = 0x00; i <= 0x14; i += 4)
+               nv_wo32(chan->ramin, CTX_PTR(dev, i), 0x00000000);
+       nouveau_gpuobj_ref(NULL, &ctx);
+       chan->engctx[engine] = NULL;
+}
+
+static int
+nv50_mpeg_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 2;
+       obj->class  = class;
+
+       nv_wo32(obj, 0x00, class);
+       nv_wo32(obj, 0x04, 0x00000000);
+       nv_wo32(obj, 0x08, 0x00000000);
+       nv_wo32(obj, 0x0c, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
+
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
+}
+
+static void
+nv50_mpeg_tlb_flush(struct drm_device *dev, int engine)
+{
+       nv50_vm_flush_engine(dev, 0x08);
+}
+
+static int
+nv50_mpeg_init(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x00b32c, 0x00000000);
+       nv_wr32(dev, 0x00b314, 0x00000100);
+       nv_wr32(dev, 0x00b0e0, 0x0000001a);
+
+       nv_wr32(dev, 0x00b220, 0x00000044);
+       nv_wr32(dev, 0x00b300, 0x00801ec1);
+       nv_wr32(dev, 0x00b390, 0x00000000);
+       nv_wr32(dev, 0x00b394, 0x00000000);
+       nv_wr32(dev, 0x00b398, 0x00000000);
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001);
+
+       nv_wr32(dev, 0x00b100, 0xffffffff);
+       nv_wr32(dev, 0x00b140, 0xffffffff);
+
+       if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200));
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static int
+nv50_mpeg_fini(struct drm_device *dev, int engine)
+{
+       /*XXX: context save for s/r */
+       nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000);
+       nv_wr32(dev, 0x00b140, 0x00000000);
+       return 0;
+}
+
+static void
+nv50_mpeg_isr(struct drm_device *dev)
+{
+       u32 stat = nv_rd32(dev, 0x00b100);
+       u32 type = nv_rd32(dev, 0x00b230);
+       u32 mthd = nv_rd32(dev, 0x00b234);
+       u32 data = nv_rd32(dev, 0x00b238);
+       u32 show = stat;
+
+       if (stat & 0x01000000) {
+               /* happens on initial binding of the object */
+               if (type == 0x00000020 && mthd == 0x0000) {
+                       nv_wr32(dev, 0x00b308, 0x00000100);
+                       show &= ~0x01000000;
+               }
+       }
+
+       if (show && nouveau_ratelimit()) {
+               NV_INFO(dev, "PMPEG - 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                       stat, type, mthd, data);
+       }
+
+       nv_wr32(dev, 0x00b100, stat);
+       nv_wr32(dev, 0x00b230, 0x00000001);
+       nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nv50_vpe_isr(struct drm_device *dev)
+{
+       if (nv_rd32(dev, 0x00b100))
+               nv50_mpeg_isr(dev);
+
+       if (nv_rd32(dev, 0x00b800)) {
+               u32 stat = nv_rd32(dev, 0x00b800);
+               NV_INFO(dev, "PMSRCH: 0x%08x\n", stat);
+               nv_wr32(dev, 0xb800, stat);
+       }
+}
+
+static void
+nv50_mpeg_destroy(struct drm_device *dev, int engine)
+{
+       struct nv50_mpeg_engine *pmpeg = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 0);
+
+       NVOBJ_ENGINE_DEL(dev, MPEG);
+       kfree(pmpeg);
+}
+
+int
+nv50_mpeg_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nv50_mpeg_engine *pmpeg;
+
+       pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL);
+       if (!pmpeg)
+               return -ENOMEM;
+
+       pmpeg->base.destroy = nv50_mpeg_destroy;
+       pmpeg->base.init = nv50_mpeg_init;
+       pmpeg->base.fini = nv50_mpeg_fini;
+       pmpeg->base.context_new = nv50_mpeg_context_new;
+       pmpeg->base.context_del = nv50_mpeg_context_del;
+       pmpeg->base.object_new = nv50_mpeg_object_new;
+       pmpeg->base.tlb_flush = nv50_mpeg_tlb_flush;
+
+       if (dev_priv->chipset == 0x50) {
+               nouveau_irq_register(dev, 0, nv50_vpe_isr);
+               NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+               NVOBJ_CLASS(dev, 0x3174, MPEG);
+#if 0
+               NVOBJ_ENGINE_ADD(dev, ME, &pme->base);
+               NVOBJ_CLASS(dev, 0x4075, ME);
+#endif
+       } else {
+               nouveau_irq_register(dev, 0, nv50_mpeg_isr);
+               NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base);
+               NVOBJ_CLASS(dev, 0x8274, MPEG);
+       }
+
+       return 0;
+
+}
index 7dbb305d7e63598056678c8e3e20b594c8c25a18..8a2810011bda5e9cd1861d03ecf3482229be20da 100644 (file)
@@ -47,6 +47,21 @@ nv50_pm_clock_get(struct drm_device *dev, u32 id)
 
        reg0 = nv_rd32(dev, pll.reg + 0);
        reg1 = nv_rd32(dev, pll.reg + 4);
+
+       if ((reg0 & 0x80000000) == 0) {
+               if (id == PLL_SHADER) {
+                       NV_DEBUG(dev, "Shader PLL is disabled. "
+                               "Shader clock is twice the core\n");
+                       ret = nv50_pm_clock_get(dev, PLL_CORE);
+                       if (ret > 0)
+                               return ret << 1;
+               } else if (id == PLL_MEMORY) {
+                       NV_DEBUG(dev, "Memory PLL is disabled. "
+                               "Memory clock is equal to the ref_clk\n");
+                       return pll.refclk;
+               }
+       }
+
        P = (reg0 & 0x00070000) >> 16;
        N = (reg1 & 0x0000ff00) >> 8;
        M = (reg1 & 0x000000ff);
index 6c26944907418b0d090d35758b8e22d7ce9de06c..1a0dd491a0e44257dc1eb4dc87005b4b3d18f1dc 100644 (file)
@@ -151,8 +151,7 @@ nv50_vm_flush(struct nouveau_vm *vm)
        struct drm_nouveau_private *dev_priv = vm->dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
+       int i;
 
        pinstmem->flush(vm->dev);
 
@@ -163,11 +162,10 @@ nv50_vm_flush(struct nouveau_vm *vm)
        }
 
        pfifo->tlb_flush(vm->dev);
-
-       if (atomic_read(&vm->pgraph_refs))
-               pgraph->tlb_flush(vm->dev);
-       if (atomic_read(&vm->pcrypt_refs))
-               pcrypt->tlb_flush(vm->dev);
+       for (i = 0; i < NVOBJ_ENGINE_NR; i++) {
+               if (atomic_read(&vm->engref[i]))
+                       dev_priv->eng[i]->tlb_flush(vm->dev, i);
+       }
 }
 
 void
index fabc7fd30b1d9150e7f532f7cf58de8e5f9f247f..75b809a51748e09eaa78cd8e07d5a7b754b3e408 100644 (file)
 #include "nouveau_drv.h"
 #include "nouveau_util.h"
 #include "nouveau_vm.h"
+#include "nouveau_ramht.h"
 
-static void nv84_crypt_isr(struct drm_device *);
+struct nv84_crypt_engine {
+       struct nouveau_exec_engine base;
+};
 
-int
-nv84_crypt_create_context(struct nouveau_channel *chan)
+static int
+nv84_crypt_context_new(struct nouveau_channel *chan, int engine)
 {
        struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx;
        int ret;
 
        NV_DEBUG(dev, "ch%d\n", chan->id);
 
-       ret = nouveau_gpuobj_new(dev, chan, 256, 0,
-                                NVOBJ_FLAG_ZERO_ALLOC | NVOBJ_FLAG_ZERO_FREE,
-                                &chan->crypt_ctx);
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
        if (ret)
                return ret;
 
        nv_wo32(ramin, 0xa0, 0x00190000);
-       nv_wo32(ramin, 0xa4, chan->crypt_ctx->vinst + 0xff);
-       nv_wo32(ramin, 0xa8, chan->crypt_ctx->vinst);
+       nv_wo32(ramin, 0xa4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xa8, ctx->vinst);
        nv_wo32(ramin, 0xac, 0);
        nv_wo32(ramin, 0xb0, 0);
        nv_wo32(ramin, 0xb4, 0);
-
        dev_priv->engine.instmem.flush(dev);
-       atomic_inc(&chan->vm->pcrypt_refs);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
        return 0;
 }
 
-void
-nv84_crypt_destroy_context(struct nouveau_channel *chan)
+static void
+nv84_crypt_context_del(struct nouveau_channel *chan, int engine)
 {
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
        struct drm_device *dev = chan->dev;
        u32 inst;
 
-       if (!chan->crypt_ctx)
-               return;
-
        inst  = (chan->ramin->vinst >> 12);
        inst |= 0x80000000;
 
@@ -80,43 +82,39 @@ nv84_crypt_destroy_context(struct nouveau_channel *chan)
                nv_mask(dev, 0x10218c, 0x80000000, 0x00000000);
        nv_wr32(dev, 0x10200c, 0x00000010);
 
-       nouveau_gpuobj_ref(NULL, &chan->crypt_ctx);
-       atomic_dec(&chan->vm->pcrypt_refs);
-}
+       nouveau_gpuobj_ref(NULL, &ctx);
 
-void
-nv84_crypt_tlb_flush(struct drm_device *dev)
-{
-       nv50_vm_flush_engine(dev, 0x0a);
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = NULL;
 }
 
-int
-nv84_crypt_init(struct drm_device *dev)
+static int
+nv84_crypt_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
+       struct drm_device *dev = chan->dev;
        struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt;
-
-       if (!pcrypt->registered) {
-               NVOBJ_CLASS(dev, 0x74c1, CRYPT);
-               pcrypt->registered = true;
-       }
+       struct nouveau_gpuobj *obj = NULL;
+       int ret;
 
-       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
-       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+       ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj);
+       if (ret)
+               return ret;
+       obj->engine = 5;
+       obj->class  = class;
 
-       nouveau_irq_register(dev, 14, nv84_crypt_isr);
-       nv_wr32(dev, 0x102130, 0xffffffff);
-       nv_wr32(dev, 0x102140, 0xffffffbf);
+       nv_wo32(obj, 0x00, class);
+       dev_priv->engine.instmem.flush(dev);
 
-       nv_wr32(dev, 0x10200c, 0x00000010);
-       return 0;
+       ret = nouveau_ramht_insert(chan, handle, obj);
+       nouveau_gpuobj_ref(NULL, &obj);
+       return ret;
 }
 
-void
-nv84_crypt_fini(struct drm_device *dev)
+static void
+nv84_crypt_tlb_flush(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x102140, 0x00000000);
-       nouveau_irq_unregister(dev, 14);
+       nv50_vm_flush_engine(dev, 0x0a);
 }
 
 static void
@@ -138,3 +136,58 @@ nv84_crypt_isr(struct drm_device *dev)
 
        nv50_fb_vm_trap(dev, show);
 }
+
+static int
+nv84_crypt_fini(struct drm_device *dev, int engine)
+{
+       nv_wr32(dev, 0x102140, 0x00000000);
+       return 0;
+}
+
+static int
+nv84_crypt_init(struct drm_device *dev, int engine)
+{
+       nv_mask(dev, 0x000200, 0x00004000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00004000, 0x00004000);
+
+       nv_wr32(dev, 0x102130, 0xffffffff);
+       nv_wr32(dev, 0x102140, 0xffffffbf);
+
+       nv_wr32(dev, 0x10200c, 0x00000010);
+       return 0;
+}
+
+static void
+nv84_crypt_destroy(struct drm_device *dev, int engine)
+{
+       struct nv84_crypt_engine *pcrypt = nv_engine(dev, engine);
+
+       NVOBJ_ENGINE_DEL(dev, CRYPT);
+
+       nouveau_irq_unregister(dev, 14);
+       kfree(pcrypt);
+}
+
+int
+nv84_crypt_create(struct drm_device *dev)
+{
+       struct nv84_crypt_engine *pcrypt;
+
+       pcrypt = kzalloc(sizeof(*pcrypt), GFP_KERNEL);
+       if (!pcrypt)
+               return -ENOMEM;
+
+       pcrypt->base.destroy = nv84_crypt_destroy;
+       pcrypt->base.init = nv84_crypt_init;
+       pcrypt->base.fini = nv84_crypt_fini;
+       pcrypt->base.context_new = nv84_crypt_context_new;
+       pcrypt->base.context_del = nv84_crypt_context_del;
+       pcrypt->base.object_new = nv84_crypt_object_new;
+       pcrypt->base.tlb_flush = nv84_crypt_tlb_flush;
+
+       nouveau_irq_register(dev, 14, nv84_crypt_isr);
+
+       NVOBJ_ENGINE_ADD(dev, CRYPT, &pcrypt->base);
+       NVOBJ_CLASS (dev, 0x74c1, CRYPT);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.c b/drivers/gpu/drm/nouveau/nva3_copy.c
new file mode 100644 (file)
index 0000000..b86820a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nva3_copy.fuc.h"
+
+struct nva3_copy_engine {
+       struct nouveau_exec_engine base;
+};
+
+static int
+nva3_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       NV_DEBUG(dev, "ch%d\n", chan->id);
+
+       ret = nouveau_gpuobj_new(dev, chan, 256, 0, NVOBJ_FLAG_ZERO_ALLOC |
+                                NVOBJ_FLAG_ZERO_FREE, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, 0xc0, 0x00190000);
+       nv_wo32(ramin, 0xc4, ctx->vinst + ctx->size - 1);
+       nv_wo32(ramin, 0xc8, ctx->vinst);
+       nv_wo32(ramin, 0xcc, 0x00000000);
+       nv_wo32(ramin, 0xd0, 0x00000000);
+       nv_wo32(ramin, 0xd4, 0x00000000);
+       dev_priv->engine.instmem.flush(dev);
+
+       atomic_inc(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static int
+nva3_copy_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+
+       /* fuc engine doesn't need an object, our ramht code does.. */
+       ctx->engine = 3;
+       ctx->class  = class;
+       return nouveau_ramht_insert(chan, handle, ctx);
+}
+
+static void
+nva3_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x40000000;
+
+       /* disable fifo access */
+       nv_wr32(dev, 0x104048, 0x00000000);
+       /* mark channel as unloaded if it's currently active */
+       if (nv_rd32(dev, 0x104050) == inst)
+               nv_mask(dev, 0x104050, 0x40000000, 0x00000000);
+       /* mark next channel as invalid if it's about to be loaded */
+       if (nv_rd32(dev, 0x104054) == inst)
+               nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+       /* restore fifo access */
+       nv_wr32(dev, 0x104048, 0x00000003);
+
+       for (inst = 0xc0; inst <= 0xd4; inst += 4)
+               nv_wo32(chan->ramin, inst, 0x00000000);
+
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       atomic_dec(&chan->vm->engref[engine]);
+       chan->engctx[engine] = ctx;
+}
+
+static void
+nva3_copy_tlb_flush(struct drm_device *dev, int engine)
+{
+       nv50_vm_flush_engine(dev, 0x0d);
+}
+
+static int
+nva3_copy_init(struct drm_device *dev, int engine)
+{
+       int i;
+
+       nv_mask(dev, 0x000200, 0x00002000, 0x00000000);
+       nv_mask(dev, 0x000200, 0x00002000, 0x00002000);
+       nv_wr32(dev, 0x104014, 0xffffffff); /* disable all interrupts */
+
+       /* upload ucode */
+       nv_wr32(dev, 0x1041c0, 0x01000000);
+       for (i = 0; i < sizeof(nva3_pcopy_data) / 4; i++)
+               nv_wr32(dev, 0x1041c4, nva3_pcopy_data[i]);
+
+       nv_wr32(dev, 0x104180, 0x01000000);
+       for (i = 0; i < sizeof(nva3_pcopy_code) / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(dev, 0x104188, i >> 6);
+               nv_wr32(dev, 0x104184, nva3_pcopy_code[i]);
+       }
+
+       /* start it running */
+       nv_wr32(dev, 0x10410c, 0x00000000);
+       nv_wr32(dev, 0x104104, 0x00000000); /* ENTRY */
+       nv_wr32(dev, 0x104100, 0x00000002); /* TRIGGER */
+       return 0;
+}
+
+static int
+nva3_copy_fini(struct drm_device *dev, int engine)
+{
+       nv_mask(dev, 0x104048, 0x00000003, 0x00000000);
+
+       /* trigger fuc context unload */
+       nv_wait(dev, 0x104008, 0x0000000c, 0x00000000);
+       nv_mask(dev, 0x104054, 0x40000000, 0x00000000);
+       nv_wr32(dev, 0x104000, 0x00000008);
+       nv_wait(dev, 0x104008, 0x00000008, 0x00000000);
+
+       nv_wr32(dev, 0x104014, 0xffffffff);
+       return 0;
+}
+
+static struct nouveau_enum nva3_copy_isr_error_name[] = {
+       { 0x0001, "ILLEGAL_MTHD" },
+       { 0x0002, "INVALID_ENUM" },
+       { 0x0003, "INVALID_BITFIELD" },
+       {}
+};
+
+static void
+nva3_copy_isr(struct drm_device *dev)
+{
+       u32 dispatch = nv_rd32(dev, 0x10401c);
+       u32 stat = nv_rd32(dev, 0x104008) & dispatch & ~(dispatch >> 16);
+       u32 inst = nv_rd32(dev, 0x104050) & 0x3fffffff;
+       u32 ssta = nv_rd32(dev, 0x104040) & 0x0000ffff;
+       u32 addr = nv_rd32(dev, 0x104040) >> 16;
+       u32 mthd = (addr & 0x07ff) << 2;
+       u32 subc = (addr & 0x3800) >> 11;
+       u32 data = nv_rd32(dev, 0x104044);
+       int chid = nv50_graph_isr_chid(dev, inst);
+
+       if (stat & 0x00000040) {
+               NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+               nouveau_enum_print(nva3_copy_isr_error_name, ssta);
+               printk("] ch %d [0x%08x] subc %d mthd 0x%04x data 0x%08x\n",
+                       chid, inst, subc, mthd, data);
+               nv_wr32(dev, 0x104004, 0x00000040);
+               stat &= ~0x00000040;
+       }
+
+       if (stat) {
+               NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+               nv_wr32(dev, 0x104004, stat);
+       }
+       nv50_fb_vm_trap(dev, 1);
+}
+
+static void
+nva3_copy_destroy(struct drm_device *dev, int engine)
+{
+       struct nva3_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, 22);
+
+       NVOBJ_ENGINE_DEL(dev, COPY0);
+       kfree(pcopy);
+}
+
+int
+nva3_copy_create(struct drm_device *dev)
+{
+       struct nva3_copy_engine *pcopy;
+
+       pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+       if (!pcopy)
+               return -ENOMEM;
+
+       pcopy->base.destroy = nva3_copy_destroy;
+       pcopy->base.init = nva3_copy_init;
+       pcopy->base.fini = nva3_copy_fini;
+       pcopy->base.context_new = nva3_copy_context_new;
+       pcopy->base.context_del = nva3_copy_context_del;
+       pcopy->base.object_new = nva3_copy_object_new;
+       pcopy->base.tlb_flush = nva3_copy_tlb_flush;
+
+       nouveau_irq_register(dev, 22, nva3_copy_isr);
+
+       NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+       NVOBJ_CLASS(dev, 0x85b5, COPY0);
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc b/drivers/gpu/drm/nouveau/nva3_copy.fuc
new file mode 100644 (file)
index 0000000..eaf35f8
--- /dev/null
@@ -0,0 +1,870 @@
+/* fuc microcode for copy engine on nva3- chipsets
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* To build for nva3:nvc0
+ *    m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
+ *
+ * To build for nvc0-
+ *    m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
+ */
+
+ifdef(`NVA3',
+.section nva3_pcopy_data,
+.section nvc0_pcopy_data
+)
+
+ctx_object:                   .b32 0
+ifdef(`NVA3',
+ctx_dma:
+ctx_dma_query:                .b32 0
+ctx_dma_src:                  .b32 0
+ctx_dma_dst:                  .b32 0
+,)
+.equ ctx_dma_count 3
+ctx_query_address_high:       .b32 0
+ctx_query_address_low:        .b32 0
+ctx_query_counter:            .b32 0
+ctx_src_address_high:         .b32 0
+ctx_src_address_low:          .b32 0
+ctx_src_pitch:                .b32 0
+ctx_src_tile_mode:            .b32 0
+ctx_src_xsize:                .b32 0
+ctx_src_ysize:                .b32 0
+ctx_src_zsize:                .b32 0
+ctx_src_zoff:                 .b32 0
+ctx_src_xoff:                 .b32 0
+ctx_src_yoff:                 .b32 0
+ctx_src_cpp:                  .b32 0
+ctx_dst_address_high:         .b32 0
+ctx_dst_address_low:          .b32 0
+ctx_dst_pitch:                .b32 0
+ctx_dst_tile_mode:            .b32 0
+ctx_dst_xsize:                .b32 0
+ctx_dst_ysize:                .b32 0
+ctx_dst_zsize:                .b32 0
+ctx_dst_zoff:                 .b32 0
+ctx_dst_xoff:                 .b32 0
+ctx_dst_yoff:                 .b32 0
+ctx_dst_cpp:                  .b32 0
+ctx_format:                   .b32 0
+ctx_swz_const0:               .b32 0
+ctx_swz_const1:               .b32 0
+ctx_xcnt:                     .b32 0
+ctx_ycnt:                     .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 ctx_object                     ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + cmd_nop           ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + cmd_pm_trigger    ~0xffffffff
+ifdef(`NVA3', `
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+.b32 0x00010000 + cmd_dma           ~0xffffffff
+',)
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 ctx_src_tile_mode              ~0x00000fff
+.b32 ctx_src_xsize                  ~0x0007ffff
+.b32 ctx_src_ysize                  ~0x00001fff
+.b32 ctx_src_zsize                  ~0x000007ff
+.b32 ctx_src_zoff                   ~0x00000fff
+.b32 ctx_src_xoff                   ~0x0007ffff
+.b32 ctx_src_yoff                   ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 ctx_dst_tile_mode              ~0x00000fff
+.b32 ctx_dst_xsize                  ~0x0007ffff
+.b32 ctx_dst_ysize                  ~0x00001fff
+.b32 ctx_dst_zsize                  ~0x000007ff
+.b32 ctx_dst_zoff                   ~0x00000fff
+.b32 ctx_dst_xoff                   ~0x0007ffff
+.b32 ctx_dst_yoff                   ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + cmd_exec          ~0xffffffff
+.b32 0x00010000 + cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 ctx_src_address_high           ~0x000000ff
+.b32 ctx_src_address_low            ~0xfffffff0
+.b32 ctx_dst_address_high           ~0x000000ff
+.b32 ctx_dst_address_low            ~0xfffffff0
+.b32 ctx_src_pitch                  ~0x0007ffff
+.b32 ctx_dst_pitch                  ~0x0007ffff
+.b32 ctx_xcnt                       ~0x0000ffff
+.b32 ctx_ycnt                       ~0x00001fff
+.b32 ctx_format                     ~0x0333ffff
+.b32 ctx_swz_const0                 ~0xffffffff
+.b32 ctx_swz_const1                 ~0xffffffff
+.b32 ctx_query_address_high         ~0x000000ff
+.b32 ctx_query_address_low          ~0xffffffff
+.b32 ctx_query_counter              ~0xffffffff
+.b16 0x800 0
+
+ifdef(`NVA3',
+.section nva3_pcopy_code,
+.section nvc0_pcopy_code
+)
+
+main:
+   clear b32 $r0
+   mov $sp $r0
+
+   // setup i0 handler and route fifo and ctxswitch to it
+   mov $r1 ih
+   mov $iv0 $r1
+   mov $r1 0x400
+   movw $r2 0xfff3
+   sethi $r2 0
+   iowr I[$r2 + 0x300] $r2
+
+   // enable interrupts
+   or $r2 0xc
+   iowr I[$r1] $r2
+   bset $flags ie0
+
+   // enable fifo access and context switching
+   mov $r1 0x1200
+   mov $r2 3
+   iowr I[$r1] $r2
+
+   // sleep forever, waking for interrupts
+   bset $flags $p0
+   spin:
+      sleep $p0
+      bra spin
+
+// i0 handler
+ih:
+   iord $r1 I[$r0 + 0x200]
+
+   and $r2 $r1 0x00000008
+   bra e ih_no_chsw
+      call chsw
+   ih_no_chsw:
+   and $r2 $r1 0x00000004
+   bra e ih_no_cmd
+      call dispatch
+
+   ih_no_cmd:
+   and $r1 $r1 0x0000000c
+   iowr I[$r0 + 0x100] $r1
+   iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+   mov $r4 0x7700
+   mov $xtargets $r4
+ifdef(`NVA3', `
+   // target 7 hardcoded to ctx dma object
+   mov $xdbase $r0
+', ` // NVC0
+   // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+   mov $r4 0x2100
+   iord $r4 I[$r4 + 0]
+   and $r4 1
+   shl b32 $r4 4
+   add b32 $r4 0x30
+
+   // channel is in vram
+   mov $r15 0x61c
+   shl b32 $r15 6
+   mov $r5 0x114
+   iowrs I[$r15] $r5
+
+   // read 16-byte PCOPYn info, containing context pointer, from channel
+   shl b32 $r5 $r3 4
+   add b32 $r5 2
+   mov $xdbase $r5
+   mov $r5 $sp
+   // get a chunk of stack space, aligned to 256 byte boundary
+   sub b32 $r5 0x100
+   mov $r6 0xff
+   not b32 $r6
+   and $r5 $r6
+   sethi $r5 0x00020000
+   xdld $r4 $r5
+   xdwait
+   sethi $r5 0
+
+   // set context pointer, from within channel VM
+   mov $r14 0
+   iowrs I[$r15] $r14
+   ld b32 $r4 D[$r5 + 0]
+   shr b32 $r4 8
+   ld b32 $r6 D[$r5 + 4]
+   shl b32 $r6 24
+   or $r4 $r6
+   mov $xdbase $r4
+')
+   // 256-byte context, at start of data segment
+   mov b32 $r4 $r0
+   sethi $r4 0x60000
+
+   // swap!
+   bra $p1 swctx_load
+      xdst $r0 $r4
+      bra swctx_done
+   swctx_load:
+      xdld $r0 $r4
+   swctx_done:
+   xdwait
+   ret
+
+chsw:
+   // read current channel
+   mov $r2 0x1400
+   iord $r3 I[$r2]
+
+   // if it's active, unload it and return
+   xbit $r15 $r3 0x1e
+   bra e chsw_no_unload
+      bclr $flags $p1
+      call swctx
+      bclr $r3 0x1e
+      iowr I[$r2] $r3
+      mov $r4 1
+      iowr I[$r2 + 0x200] $r4
+      ret
+
+   // read next channel
+   chsw_no_unload:
+   iord $r3 I[$r2 + 0x100]
+
+   // is there a channel waiting to be loaded?
+   xbit $r13 $r3 0x1e
+   bra e chsw_finish_load
+      bset $flags $p1
+      call swctx
+ifdef(`NVA3',
+      // load dma objects back into TARGET regs
+      mov $r5 ctx_dma
+      mov $r6 ctx_dma_count
+      chsw_load_ctx_dma:
+         ld b32 $r7 D[$r5 + $r6 * 4]
+         add b32 $r8 $r6 0x180
+         shl b32 $r8 8
+         iowr I[$r8] $r7
+         sub b32 $r6 1
+         bra nc chsw_load_ctx_dma
+,)
+
+   chsw_finish_load:
+   mov $r3 2
+   iowr I[$r2 + 0x200] $r3
+   ret
+
+dispatch:
+   // read incoming fifo command
+   mov $r3 0x1900
+   iord $r2 I[$r3 + 0x100]
+   iord $r3 I[$r3 + 0x000]
+   and $r4 $r2 0x7ff
+   // $r2 will be used to store exception data
+   shl b32 $r2 0x10
+
+   // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+   mov $r5 dispatch_table
+   clear b32 $r6
+   clear b32 $r7
+   dispatch_loop:
+      ld b16 $r6 D[$r5 + 0]
+      ld b16 $r7 D[$r5 + 2]
+      add b32 $r5 4
+      cmpu b32 $r4 $r6
+      bra c dispatch_illegal_mthd
+      add b32 $r7 $r6
+      cmpu b32 $r4 $r7
+      bra c dispatch_valid_mthd
+      sub b32 $r7 $r6
+      shl b32 $r7 3
+      add b32 $r5 $r7
+      bra dispatch_loop
+
+   // ensure no bits set in reserved fields, INVALID_BITFIELD
+   dispatch_valid_mthd:
+   sub b32 $r4 $r6
+   shl b32 $r4 3
+   add b32 $r4 $r5
+   ld b32 $r5 D[$r4 + 4]
+   and $r5 $r3
+   cmpu b32 $r5 0
+   bra ne dispatch_invalid_bitfield
+
+   // depending on dispatch flags: execute method, or save data as state
+   ld b16 $r5 D[$r4 + 0]
+   ld b16 $r6 D[$r4 + 2]
+   cmpu b32 $r6 0
+   bra ne dispatch_cmd
+      st b32 D[$r5] $r3
+      bra dispatch_done
+   dispatch_cmd:
+      bclr $flags $p1
+      call $r5
+      bra $p1 dispatch_error
+      bra dispatch_done
+
+   dispatch_invalid_bitfield:
+   or $r2 2
+   dispatch_illegal_mthd:
+   or $r2 1
+
+   // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+   dispatch_error:
+   mov $r4 0x1000
+   iowr I[$r4 + 0x000] $r2
+   iowr I[$r4 + 0x100] $r3
+   mov $r2 0x40
+   iowr I[$r0] $r2
+   hostirq_wait:
+      iord $r2 I[$r0 + 0x200]
+      and $r2 0x40
+      cmpu b32 $r2 0
+      bra ne hostirq_wait
+
+   dispatch_done:
+   mov $r2 0x1d00
+   mov $r3 1
+   iowr I[$r2] $r3
+   ret
+
+// No-operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_nop:
+   ret
+
+// PM_TRIGGER
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_pm_trigger:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x20000
+   iowr I[$r2] $r3
+   ret
+
+ifdef(`NVA3',
+// SET_DMA_* method handler
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_dma:
+   sub b32 $r4 dispatch_dma
+   shr b32 $r4 1
+   bset $r3 0x1e
+   st b32 D[$r4 + ctx_dma] $r3
+   add b32 $r4 0x600
+   shl b32 $r4 6
+   iowr I[$r4] $r3
+   ret
+,)
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+   // zero out a chunk of the stack to store the swizzle into
+   add $sp -0x10
+   st b32 D[$sp + 0x00] $r0
+   st b32 D[$sp + 0x04] $r0
+   st b32 D[$sp + 0x08] $r0
+   st b32 D[$sp + 0x0c] $r0
+
+   // extract cpp, src_ncomp and dst_ncomp from FORMAT
+   ld b32 $r4 D[$r0 + ctx_format]
+   extr $r5 $r4 16:17
+   add b32 $r5 1
+   extr $r6 $r4 20:21
+   add b32 $r6 1
+   extr $r7 $r4 24:25
+   add b32 $r7 1
+
+   // convert FORMAT swizzle mask to hw swizzle mask
+   bclr $flags $p2
+   clear b32 $r8
+   clear b32 $r9
+   ncomp_loop:
+      and $r10 $r4 0xf
+      shr b32 $r4 4
+      clear b32 $r11
+      bpc_loop:
+         cmpu b8 $r10 4
+         bra nc cmp_c0
+            mulu $r12 $r10 $r5
+            add b32 $r12 $r11
+            bset $flags $p2
+            bra bpc_next
+         cmp_c0:
+         bra ne cmp_c1
+            mov $r12 0x10
+            add b32 $r12 $r11
+            bra bpc_next
+         cmp_c1:
+         cmpu b8 $r10 6
+         bra nc cmp_zero
+            mov $r12 0x14
+            add b32 $r12 $r11
+            bra bpc_next
+         cmp_zero:
+            mov $r12 0x80
+         bpc_next:
+         st b8 D[$sp + $r8] $r12
+         add b32 $r8 1
+         add b32 $r11 1
+         cmpu b32 $r11 $r5
+         bra c bpc_loop
+      add b32 $r9 1
+      cmpu b32 $r9 $r7
+      bra c ncomp_loop
+
+   // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+   mulu $r6 $r5
+   st b32 D[$r0 + ctx_src_cpp] $r6
+   ld b32 $r8 D[$r0 + ctx_xcnt]
+   mulu $r6 $r8
+   bra $p2 dst_xcnt
+   clear b32 $r6
+
+   dst_xcnt:
+   mulu $r7 $r5
+   st b32 D[$r0 + ctx_dst_cpp] $r7
+   mulu $r7 $r8
+
+   mov $r5 0x810
+   shl b32 $r5 6
+   iowr I[$r5 + 0x000] $r6
+   iowr I[$r5 + 0x100] $r7
+   add b32 $r5 0x800
+   ld b32 $r6 D[$r0 + ctx_dst_cpp]
+   sub b32 $r6 1
+   shl b32 $r6 8
+   ld b32 $r7 D[$r0 + ctx_src_cpp]
+   sub b32 $r7 1
+   or $r6 $r7
+   iowr I[$r5 + 0x000] $r6
+   add b32 $r5 0x100
+   ld b32 $r6 D[$sp + 0x00]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$sp + 0x04]
+   iowr I[$r5 + 0x100] $r6
+   ld b32 $r6 D[$sp + 0x08]
+   iowr I[$r5 + 0x200] $r6
+   ld b32 $r6 D[$sp + 0x0c]
+   iowr I[$r5 + 0x300] $r6
+   add b32 $r5 0x400
+   ld b32 $r6 D[$r0 + ctx_swz_const0]
+   iowr I[$r5 + 0x000] $r6
+   ld b32 $r6 D[$r0 + ctx_swz_const1]
+   iowr I[$r5 + 0x100] $r6
+   add $sp 0x10
+   ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+//    nTx = round_up(w * cpp, 1 << Tp) >> Tp
+//    nTy = round_up(h, 1 << Th) >> Th
+//    Txo = (x * cpp) & ((1 << Tp) - 1)
+//     Tx = (x * cpp) >> Tp
+//    Tyo = y & ((1 << Th) - 1)
+//     Ty = y >> Th
+//    Tzo = z & ((1 << Td) - 1)
+//     Tz = z >> Td
+//
+//    off  = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+//    off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+//    $r4: hw command (0x104800)
+//    $r5: ctx offset adjustment for src/dst selection
+//    $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+   // translate TILE_MODE into Tp, Th, Td shift values
+   ld b32 $r7 D[$r5 + ctx_src_tile_mode]
+   extr $r9 $r7 8:11
+   extr $r8 $r7 4:7
+ifdef(`NVA3',
+   add b32 $r8 2
+,
+   add b32 $r8 3
+)
+   extr $r7 $r7 0:3
+   cmp b32 $r7 0xe
+   bra ne xtile64
+   mov $r7 4
+   bra xtileok
+   xtile64:
+   xbit $r7 $flags $p2
+   add b32 $r7 17
+   bset $r4 $r7
+   mov $r7 6
+   xtileok:
+
+   // Op = (x * cpp) & ((1 << Tp) - 1)
+   // Tx = (x * cpp) >> Tp
+   ld b32 $r10 D[$r5 + ctx_src_xoff]
+   ld b32 $r11 D[$r5 + ctx_src_cpp]
+   mulu $r10 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   and $r12 $r10 $r11
+   shr b32 $r10 $r7
+
+   // Tyo = y & ((1 << Th) - 1)
+   // Ty  = y >> Th
+   ld b32 $r13 D[$r5 + ctx_src_yoff]
+   mov $r14 1
+   shl b32 $r14 $r8
+   sub b32 $r14 1
+   and $r11 $r13 $r14
+   shr b32 $r13 $r8
+
+   // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+   add b32 $r14 1
+   shl b32 $r15 $r14 12
+   sub b32 $r14 $r11
+   or $r15 $r14
+   xbit $r6 $flags $p2
+   add b32 $r6 0x208
+   shl b32 $r6 8
+   iowr I[$r6 + 0x000] $r15
+
+   // Op += Tyo << Tp
+   shl b32 $r11 $r7
+   add b32 $r12 $r11
+
+   // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+   ld b32 $r15 D[$r5 + ctx_src_xsize]
+   ld b32 $r11 D[$r5 + ctx_src_cpp]
+   mulu $r15 $r11
+   mov $r11 1
+   shl b32 $r11 $r7
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r7
+   push $r15
+
+   // nTy = (h + ((1 << Th) - 1)) >> Th
+   ld b32 $r15 D[$r5 + ctx_src_ysize]
+   mov $r11 1
+   shl b32 $r11 $r8
+   sub b32 $r11 1
+   add b32 $r15 $r11
+   shr b32 $r15 $r8
+   push $r15
+
+   // Tys = Tp + Th
+   // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+   add b32 $r7 $r8
+   sub b32 $r8 2
+   mov $r11 1
+   shl b32 $r11 $r8
+   shl b32 $r11 $r9
+
+   // Tzo = z & ((1 << Td) - 1)
+   // Tz  = z >> Td
+   // Op += Tzo << Tys
+   // Ts  = Tys + Td
+   ld b32 $r8 D[$r5 + ctx_src_zoff]
+   mov $r14 1
+   shl b32 $r14 $r9
+   sub b32 $r14 1
+   and $r15 $r8 $r14
+   shl b32 $r15 $r7
+   add b32 $r12 $r15
+   add b32 $r7 $r9
+   shr b32 $r8 $r9
+
+   // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+   pop $r15
+   pop $r9
+   mulu $r13 $r9
+   add b32 $r10 $r13
+   mulu $r8 $r9
+   mulu $r8 $r15
+   add b32 $r10 $r8
+   shl b32 $r10 $r7
+
+   // PITCH = (nTx - 1) << Ts
+   sub b32 $r9 1
+   shl b32 $r9 $r7
+   iowr I[$r6 + 0x200] $r9
+
+   // SRC_ADDRESS_LOW   = (Ot + Op) & 0xffffffff
+   // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+   ld b32 $r7 D[$r5 + ctx_src_address_low]
+   ld b32 $r8 D[$r5 + ctx_src_address_high]
+   add b32 $r10 $r12
+   add b32 $r7 $r10
+   adc b32 $r8 0
+   shl b32 $r8 16
+   or $r8 $r11
+   sub b32 $r6 0x600
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   iowr I[$r6 + 0x000] $r8
+   ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+   xbit $r6 $flags $p2
+   add b32 $r6 0x202
+   shl b32 $r6 8
+   ld b32 $r7 D[$r5 + ctx_src_address_low]
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + ctx_src_address_high]
+   shl b32 $r7 16
+   iowr I[$r6 + 0x000] $r7
+   add b32 $r6 0x400
+   ld b32 $r7 D[$r5 + ctx_src_pitch]
+   iowr I[$r6 + 0x000] $r7
+   ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+   push $r0
+   push $r1
+   mov $r0 0x800
+   shl b32 $r0 6
+   loop:
+      iord $r1 I[$r0]
+      and $r1 1
+      bra ne loop
+   pop $r1
+   pop $r0
+   ret
+
+cmd_exec_query:
+   // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+   xbit $r4 $r3 13
+   bra ne query_counter
+      call cmd_exec_wait
+      mov $r4 0x80c
+      shl b32 $r4 6
+      ld b32 $r5 D[$r0 + ctx_query_address_low]
+      add b32 $r5 4
+      iowr I[$r4 + 0x000] $r5
+      iowr I[$r4 + 0x100] $r0
+      mov $r5 0xc
+      iowr I[$r4 + 0x200] $r5
+      add b32 $r4 0x400
+      ld b32 $r5 D[$r0 + ctx_query_address_high]
+      shl b32 $r5 16
+      iowr I[$r4 + 0x000] $r5
+      add b32 $r4 0x500
+      mov $r5 0x00000b00
+      sethi $r5 0x00010000
+      iowr I[$r4 + 0x000] $r5
+      mov $r5 0x00004040
+      shl b32 $r5 1
+      sethi $r5 0x80800000
+      iowr I[$r4 + 0x100] $r5
+      mov $r5 0x00001110
+      sethi $r5 0x13120000
+      iowr I[$r4 + 0x200] $r5
+      mov $r5 0x00001514
+      sethi $r5 0x17160000
+      iowr I[$r4 + 0x300] $r5
+      mov $r5 0x00002601
+      sethi $r5 0x00010000
+      mov $r4 0x800
+      shl b32 $r4 6
+      iowr I[$r4 + 0x000] $r5
+
+   // write COUNTER
+   query_counter:
+   call cmd_exec_wait
+   mov $r4 0x80c
+   shl b32 $r4 6
+   ld b32 $r5 D[$r0 + ctx_query_address_low]
+   iowr I[$r4 + 0x000] $r5
+   iowr I[$r4 + 0x100] $r0
+   mov $r5 0x4
+   iowr I[$r4 + 0x200] $r5
+   add b32 $r4 0x400
+   ld b32 $r5 D[$r0 + ctx_query_address_high]
+   shl b32 $r5 16
+   iowr I[$r4 + 0x000] $r5
+   add b32 $r4 0x500
+   mov $r5 0x00000300
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00001110
+   sethi $r5 0x13120000
+   iowr I[$r4 + 0x100] $r5
+   ld b32 $r5 D[$r0 + ctx_query_counter]
+   add b32 $r4 0x500
+   iowr I[$r4 + 0x000] $r5
+   mov $r5 0x00002601
+   sethi $r5 0x00010000
+   mov $r4 0x800
+   shl b32 $r4 6
+   iowr I[$r4 + 0x000] $r5
+   ret
+
+// Execute a copy operation
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//       000002000 QUERY_SHORT
+//       000001000 QUERY
+//       000000100 DST_LINEAR
+//       000000010 SRC_LINEAR
+//       000000001 FORMAT
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_exec:
+   call cmd_exec_wait
+
+   // if format requested, call function to calculate it, otherwise
+   // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+   xbit $r15 $r3 0
+   bra e cmd_exec_no_format
+      call cmd_exec_set_format
+      mov $r4 0x200
+      bra cmd_exec_init_src_surface
+   cmd_exec_no_format:
+      mov $r6 0x810
+      shl b32 $r6 6
+      mov $r7 1
+      st b32 D[$r0 + ctx_src_cpp] $r7
+      st b32 D[$r0 + ctx_dst_cpp] $r7
+      ld b32 $r7 D[$r0 + ctx_xcnt]
+      iowr I[$r6 + 0x000] $r7
+      iowr I[$r6 + 0x100] $r7
+      clear b32 $r4
+
+   cmd_exec_init_src_surface:
+   bclr $flags $p2
+   clear b32 $r5
+   xbit $r15 $r3 4
+   bra e src_tiled
+      call cmd_exec_set_surface_linear
+      bra cmd_exec_init_dst_surface
+   src_tiled:
+      call cmd_exec_set_surface_tiled
+      bset $r4 7
+
+   cmd_exec_init_dst_surface:
+   bset $flags $p2
+   mov $r5 ctx_dst_address_high - ctx_src_address_high
+   xbit $r15 $r3 8
+   bra e dst_tiled
+      call cmd_exec_set_surface_linear
+      bra cmd_exec_kick
+   dst_tiled:
+      call cmd_exec_set_surface_tiled
+      bset $r4 8
+
+   cmd_exec_kick:
+   mov $r5 0x800
+   shl b32 $r5 6
+   ld b32 $r6 D[$r0 + ctx_ycnt]
+   iowr I[$r5 + 0x100] $r6
+   mov $r6 0x0041
+   // SRC_TARGET = 1, DST_TARGET = 2
+   sethi $r6 0x44000000
+   or $r4 $r6
+   iowr I[$r5] $r4
+
+   // if requested, queue up a QUERY write after the copy has completed
+   xbit $r15 $r3 12
+   bra e cmd_exec_done
+      call cmd_exec_query
+
+   cmd_exec_done:
+   ret
+
+// Flush write cache
+//
+// Inputs:
+//    $r1: irqh state
+//    $r2: hostirq state
+//    $r3: data
+//    $r4: dispatch table entry
+// Outputs:
+//    $r1: irqh state
+//    $p1: set on error
+//       $r2: hostirq state
+//       $r3: data
+cmd_wrcache_flush:
+   mov $r2 0x2200
+   clear b32 $r3
+   sethi $r3 0x10000
+   iowr I[$r2] $r3
+   ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nva3_copy.fuc.h b/drivers/gpu/drm/nouveau/nva3_copy.fuc.h
new file mode 100644 (file)
index 0000000..2731de2
--- /dev/null
@@ -0,0 +1,534 @@
+uint32_t nva3_pcopy_data[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00010000,
+       0x00000000,
+       0x00000000,
+       0x00010040,
+       0x00010160,
+       0x00000000,
+       0x00010050,
+       0x00010162,
+       0x00000000,
+       0x00030060,
+       0x00010170,
+       0x00000000,
+       0x00010170,
+       0x00000000,
+       0x00010170,
+       0x00000000,
+       0x00070080,
+       0x00000028,
+       0xfffff000,
+       0x0000002c,
+       0xfff80000,
+       0x00000030,
+       0xffffe000,
+       0x00000034,
+       0xfffff800,
+       0x00000038,
+       0xfffff000,
+       0x0000003c,
+       0xfff80000,
+       0x00000040,
+       0xffffe000,
+       0x00070088,
+       0x00000054,
+       0xfffff000,
+       0x00000058,
+       0xfff80000,
+       0x0000005c,
+       0xffffe000,
+       0x00000060,
+       0xfffff800,
+       0x00000064,
+       0xfffff000,
+       0x00000068,
+       0xfff80000,
+       0x0000006c,
+       0xffffe000,
+       0x000200c0,
+       0x00010492,
+       0x00000000,
+       0x0001051b,
+       0x00000000,
+       0x000e00c3,
+       0x0000001c,
+       0xffffff00,
+       0x00000020,
+       0x0000000f,
+       0x00000048,
+       0xffffff00,
+       0x0000004c,
+       0x0000000f,
+       0x00000024,
+       0xfff80000,
+       0x00000050,
+       0xfff80000,
+       0x00000080,
+       0xffff0000,
+       0x00000084,
+       0xffffe000,
+       0x00000074,
+       0xfccc0000,
+       0x00000078,
+       0x00000000,
+       0x0000007c,
+       0x00000000,
+       0x00000010,
+       0xffffff00,
+       0x00000014,
+       0x00000000,
+       0x00000018,
+       0x00000000,
+       0x00000800,
+};
+
+uint32_t nva3_pcopy_code[] = {
+       0x04fe04bd,
+       0x3517f000,
+       0xf10010fe,
+       0xf1040017,
+       0xf0fff327,
+       0x22d00023,
+       0x0c25f0c0,
+       0xf40012d0,
+       0x17f11031,
+       0x27f01200,
+       0x0012d003,
+       0xf40031f4,
+       0x0ef40028,
+       0x8001cffd,
+       0xf40812c4,
+       0x21f4060b,
+       0x0412c472,
+       0xf4060bf4,
+       0x11c4c321,
+       0x4001d00c,
+       0x47f101f8,
+       0x4bfe7700,
+       0x0007fe00,
+       0xf00204b9,
+       0x01f40643,
+       0x0604fa09,
+       0xfa060ef4,
+       0x03f80504,
+       0x27f100f8,
+       0x23cf1400,
+       0x1e3fc800,
+       0xf4170bf4,
+       0x21f40132,
+       0x1e3af052,
+       0xf00023d0,
+       0x24d00147,
+       0xcf00f880,
+       0x3dc84023,
+       0x220bf41e,
+       0xf40131f4,
+       0x57f05221,
+       0x0367f004,
+       0xa07856bc,
+       0xb6018068,
+       0x87d00884,
+       0x0162b600,
+       0xf0f018f4,
+       0x23d00237,
+       0xf100f880,
+       0xcf190037,
+       0x33cf4032,
+       0xff24e400,
+       0x1024b607,
+       0x010057f1,
+       0x74bd64bd,
+       0x58005658,
+       0x50b60157,
+       0x0446b804,
+       0xbb4d08f4,
+       0x47b80076,
+       0x0f08f404,
+       0xb60276bb,
+       0x57bb0374,
+       0xdf0ef400,
+       0xb60246bb,
+       0x45bb0344,
+       0x01459800,
+       0xb00453fd,
+       0x1bf40054,
+       0x00455820,
+       0xb0014658,
+       0x1bf40064,
+       0x00538009,
+       0xf4300ef4,
+       0x55f90132,
+       0xf40c01f4,
+       0x25f0250e,
+       0x0125f002,
+       0x100047f1,
+       0xd00042d0,
+       0x27f04043,
+       0x0002d040,
+       0xf08002cf,
+       0x24b04024,
+       0xf71bf400,
+       0x1d0027f1,
+       0xd00137f0,
+       0x00f80023,
+       0x27f100f8,
+       0x34bd2200,
+       0xd00233f0,
+       0x00f80023,
+       0x012842b7,
+       0xf00145b6,
+       0x43801e39,
+       0x0040b701,
+       0x0644b606,
+       0xf80043d0,
+       0xf030f400,
+       0xb00001b0,
+       0x01b00101,
+       0x0301b002,
+       0xc71d0498,
+       0x50b63045,
+       0x3446c701,
+       0xc70160b6,
+       0x70b63847,
+       0x0232f401,
+       0x94bd84bd,
+       0xb60f4ac4,
+       0xb4bd0445,
+       0xf404a430,
+       0xa5ff0f18,
+       0x00cbbbc0,
+       0xf40231f4,
+       0x1bf4220e,
+       0x10c7f00c,
+       0xf400cbbb,
+       0xa430160e,
+       0x0c18f406,
+       0xbb14c7f0,
+       0x0ef400cb,
+       0x80c7f107,
+       0x01c83800,
+       0xb60180b6,
+       0xb5b801b0,
+       0xc308f404,
+       0xb80190b6,
+       0x08f40497,
+       0x0065fdb2,
+       0x98110680,
+       0x68fd2008,
+       0x0502f400,
+       0x75fd64bd,
+       0x1c078000,
+       0xf10078fd,
+       0xb6081057,
+       0x56d00654,
+       0x4057d000,
+       0x080050b7,
+       0xb61c0698,
+       0x64b60162,
+       0x11079808,
+       0xfd0172b6,
+       0x56d00567,
+       0x0050b700,
+       0x0060b401,
+       0xb40056d0,
+       0x56d00160,
+       0x0260b440,
+       0xb48056d0,
+       0x56d00360,
+       0x0050b7c0,
+       0x1e069804,
+       0x980056d0,
+       0x56d01f06,
+       0x1030f440,
+       0x579800f8,
+       0x6879c70a,
+       0xb66478c7,
+       0x77c70280,
+       0x0e76b060,
+       0xf0091bf4,
+       0x0ef40477,
+       0x027cf00f,
+       0xfd1170b6,
+       0x77f00947,
+       0x0f5a9806,
+       0xfd115b98,
+       0xb7f000ab,
+       0x04b7bb01,
+       0xff01b2b6,
+       0xa7bbc4ab,
+       0x105d9805,
+       0xbb01e7f0,
+       0xe2b604e8,
+       0xb4deff01,
+       0xb605d8bb,
+       0xef9401e0,
+       0x02ebbb0c,
+       0xf005fefd,
+       0x60b7026c,
+       0x64b60208,
+       0x006fd008,
+       0xbb04b7bb,
+       0x5f9800cb,
+       0x115b980b,
+       0xf000fbfd,
+       0xb7bb01b7,
+       0x01b2b604,
+       0xbb00fbbb,
+       0xf0f905f7,
+       0xf00c5f98,
+       0xb8bb01b7,
+       0x01b2b604,
+       0xbb00fbbb,
+       0xf0f905f8,
+       0xb60078bb,
+       0xb7f00282,
+       0x04b8bb01,
+       0x9804b9bb,
+       0xe7f00e58,
+       0x04e9bb01,
+       0xff01e2b6,
+       0xf7bbf48e,
+       0x00cfbb04,
+       0xbb0079bb,
+       0xf0fc0589,
+       0xd9fd90fc,
+       0x00adbb00,
+       0xfd0089fd,
+       0xa8bb008f,
+       0x04a7bb00,
+       0xbb0192b6,
+       0x69d00497,
+       0x08579880,
+       0xbb075898,
+       0x7abb00ac,
+       0x0081b600,
+       0xfd1084b6,
+       0x62b7058b,
+       0x67d00600,
+       0x0060b700,
+       0x0068d004,
+       0x6cf000f8,
+       0x0260b702,
+       0x0864b602,
+       0xd0085798,
+       0x60b70067,
+       0x57980400,
+       0x1074b607,
+       0xb70067d0,
+       0x98040060,
+       0x67d00957,
+       0xf900f800,
+       0xf110f900,
+       0xb6080007,
+       0x01cf0604,
+       0x0114f000,
+       0xfcfa1bf4,
+       0xf800fc10,
+       0x0d34c800,
+       0xf5701bf4,
+       0xf103ab21,
+       0xb6080c47,
+       0x05980644,
+       0x0450b605,
+       0xd00045d0,
+       0x57f04040,
+       0x8045d00c,
+       0x040040b7,
+       0xb6040598,
+       0x45d01054,
+       0x0040b700,
+       0x0057f105,
+       0x0153f00b,
+       0xf10045d0,
+       0xb6404057,
+       0x53f10154,
+       0x45d08080,
+       0x1057f140,
+       0x1253f111,
+       0x8045d013,
+       0x151457f1,
+       0x171653f1,
+       0xf1c045d0,
+       0xf0260157,
+       0x47f10153,
+       0x44b60800,
+       0x0045d006,
+       0x03ab21f5,
+       0x080c47f1,
+       0x980644b6,
+       0x45d00505,
+       0x4040d000,
+       0xd00457f0,
+       0x40b78045,
+       0x05980400,
+       0x1054b604,
+       0xb70045d0,
+       0xf1050040,
+       0xd0030057,
+       0x57f10045,
+       0x53f11110,
+       0x45d01312,
+       0x06059840,
+       0x050040b7,
+       0xf10045d0,
+       0xf0260157,
+       0x47f10153,
+       0x44b60800,
+       0x0045d006,
+       0x21f500f8,
+       0x3fc803ab,
+       0x0e0bf400,
+       0x018921f5,
+       0x020047f1,
+       0xf11e0ef4,
+       0xb6081067,
+       0x77f00664,
+       0x11078001,
+       0x981c0780,
+       0x67d02007,
+       0x4067d000,
+       0x32f444bd,
+       0xc854bd02,
+       0x0bf4043f,
+       0x8221f50a,
+       0x0a0ef403,
+       0x027621f5,
+       0xf40749f0,
+       0x57f00231,
+       0x083fc82c,
+       0xf50a0bf4,
+       0xf4038221,
+       0x21f50a0e,
+       0x49f00276,
+       0x0057f108,
+       0x0654b608,
+       0xd0210698,
+       0x67f04056,
+       0x0063f141,
+       0x0546fd44,
+       0xc80054d0,
+       0x0bf40c3f,
+       0xc521f507,
+       0xf100f803,
+       0xbd220027,
+       0x0133f034,
+       0xf80023d0,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index dbbafed36406d6609502a0e6ccbeabf0c33dcc66..e4b2b9e934b2733e910ee7f2cab77c6548680857 100644 (file)
 #include "nouveau_bios.h"
 #include "nouveau_pm.h"
 
-/*XXX: boards using limits 0x40 need fixing, the register layout
- *     is correct here, but, there's some other funny magic
- *     that modifies things, so it's not likely we'll set/read
- *     the correct timings yet..  working on it...
+/* This is actually a lot more complex than it appears here, but hopefully
+ * this should be able to deal with what the VBIOS leaves for us..
+ *
+ * If not, well, I'll jump off that bridge when I come to it.
  */
 
 struct nva3_pm_state {
-       struct pll_lims pll;
-       int N, M, P;
+       enum pll_types type;
+       u32 src0;
+       u32 src1;
+       u32 ctrl;
+       u32 coef;
+       u32 old_pnm;
+       u32 new_pnm;
+       u32 new_div;
 };
 
+static int
+nva3_pm_pll_offset(u32 id)
+{
+       static const u32 pll_map[] = {
+               0x00, PLL_CORE,
+               0x01, PLL_SHADER,
+               0x02, PLL_MEMORY,
+               0x00, 0x00
+       };
+       const u32 *map = pll_map;
+
+       while (map[1]) {
+               if (id == map[1])
+                       return map[0];
+               map += 2;
+       }
+
+       return -ENOENT;
+}
+
 int
 nva3_pm_clock_get(struct drm_device *dev, u32 id)
 {
+       u32 src0, src1, ctrl, coef;
        struct pll_lims pll;
-       int P, N, M, ret;
-       u32 reg;
+       int ret, off;
+       int P, N, M;
 
        ret = get_pll_limits(dev, id, &pll);
        if (ret)
                return ret;
 
-       reg = nv_rd32(dev, pll.reg + 4);
-       P = (reg & 0x003f0000) >> 16;
-       N = (reg & 0x0000ff00) >> 8;
-       M = (reg & 0x000000ff);
+       off = nva3_pm_pll_offset(id);
+       if (off < 0)
+               return off;
+
+       src0 = nv_rd32(dev, 0x4120 + (off * 4));
+       src1 = nv_rd32(dev, 0x4160 + (off * 4));
+       ctrl = nv_rd32(dev, pll.reg + 0);
+       coef = nv_rd32(dev, pll.reg + 4);
+       NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                     id, src0, src1, ctrl, coef);
+
+       if (ctrl & 0x00000008) {
+               u32 div = ((src1 & 0x003c0000) >> 18) + 1;
+               return (pll.refclk * 2) / div;
+       }
+
+       P = (coef & 0x003f0000) >> 16;
+       N = (coef & 0x0000ff00) >> 8;
+       M = (coef & 0x000000ff);
        return pll.refclk * N / M / P;
 }
 
@@ -60,36 +102,103 @@ void *
 nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl,
                  u32 id, int khz)
 {
-       struct nva3_pm_state *state;
-       int dummy, ret;
+       struct nva3_pm_state *pll;
+       struct pll_lims limits;
+       int N, M, P, diff;
+       int ret, off;
+
+       ret = get_pll_limits(dev, id, &limits);
+       if (ret < 0)
+               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+
+       off = nva3_pm_pll_offset(id);
+       if (id < 0)
+               return ERR_PTR(-EINVAL);
 
-       state = kzalloc(sizeof(*state), GFP_KERNEL);
-       if (!state)
+
+       pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+       if (!pll)
                return ERR_PTR(-ENOMEM);
+       pll->type = id;
+       pll->src0 = 0x004120 + (off * 4);
+       pll->src1 = 0x004160 + (off * 4);
+       pll->ctrl = limits.reg + 0;
+       pll->coef = limits.reg + 4;
 
-       ret = get_pll_limits(dev, id, &state->pll);
-       if (ret < 0) {
-               kfree(state);
-               return (ret == -ENOENT) ? NULL : ERR_PTR(ret);
+       /* If target clock is within [-2, 3) MHz of a divisor, we'll
+        * use that instead of calculating MNP values
+        */
+       pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16);
+       if (pll->new_div) {
+               diff = khz - ((limits.refclk * 2) / pll->new_div);
+               if (diff < -2000 || diff >= 3000)
+                       pll->new_div = 0;
        }
 
-       ret = nv50_calc_pll2(dev, &state->pll, khz, &state->N, &dummy,
-                            &state->M, &state->P);
-       if (ret < 0) {
-               kfree(state);
-               return ERR_PTR(ret);
+       if (!pll->new_div) {
+               ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P);
+               if (ret < 0)
+                       return ERR_PTR(ret);
+
+               pll->new_pnm = (P << 16) | (N << 8) | M;
+               pll->new_div = 2 - 1;
+       } else {
+               pll->new_pnm = 0;
+               pll->new_div--;
        }
 
-       return state;
+       if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101)
+               pll->old_pnm = nv_rd32(dev, pll->coef);
+       return pll;
 }
 
 void
 nva3_pm_clock_set(struct drm_device *dev, void *pre_state)
 {
-       struct nva3_pm_state *state = pre_state;
-       u32 reg = state->pll.reg;
+       struct nva3_pm_state *pll = pre_state;
+       u32 ctrl = 0;
+
+       /* For the memory clock, NVIDIA will build a "script" describing
+        * the reclocking process and ask PDAEMON to execute it.
+        */
+       if (pll->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x100210, 0);
+               nv_wr32(dev, 0x1002dc, 1);
+               nv_wr32(dev, 0x004018, 0x00001000);
+               ctrl = 0x18000100;
+       }
+
+       if (pll->old_pnm || !pll->new_pnm) {
+               nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 |
+                                                   (pll->new_div << 18));
+               nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+               nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+       }
+
+       if (pll->new_pnm) {
+               nv_mask(dev, pll->src0, 0x00000101, 0x00000101);
+               nv_wr32(dev, pll->coef, pll->new_pnm);
+               nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl);
+               nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000);
+               nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010);
+               nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl);
+               nv_mask(dev, pll->src1, 0x00000100, 0x00000000);
+               nv_mask(dev, pll->src1, 0x00000001, 0x00000000);
+               if (pll->type == PLL_MEMORY)
+                       nv_wr32(dev, 0x4018, 0x10005000);
+       } else {
+               nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000);
+               nv_mask(dev, pll->src0, 0x00000100, 0x00000000);
+               nv_mask(dev, pll->src0, 0x00000001, 0x00000000);
+               if (pll->type == PLL_MEMORY)
+                       nv_wr32(dev, 0x4018, 0x1000d000);
+       }
+
+       if (pll->type == PLL_MEMORY) {
+               nv_wr32(dev, 0x1002dc, 0);
+               nv_wr32(dev, 0x100210, 0x80000000);
+       }
 
-       nv_wr32(dev, reg + 4, (state->P << 16) | (state->N << 8) | state->M);
-       kfree(state);
+       kfree(pll);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.c b/drivers/gpu/drm/nouveau/nvc0_copy.c
new file mode 100644 (file)
index 0000000..208fa7a
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <linux/firmware.h>
+#include "drmP.h"
+#include "nouveau_drv.h"
+#include "nouveau_util.h"
+#include "nouveau_vm.h"
+#include "nouveau_ramht.h"
+#include "nvc0_copy.fuc.h"
+
+struct nvc0_copy_engine {
+       struct nouveau_exec_engine base;
+       u32 irq;
+       u32 pmc;
+       u32 fuc;
+       u32 ctx;
+};
+
+static int
+nvc0_copy_context_new(struct nouveau_channel *chan, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nouveau_gpuobj *ramin = chan->ramin;
+       struct nouveau_gpuobj *ctx = NULL;
+       int ret;
+
+       ret = nouveau_gpuobj_new(dev, NULL, 256, 256,
+                                NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER |
+                                NVOBJ_FLAG_ZERO_ALLOC, &ctx);
+       if (ret)
+               return ret;
+
+       nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst));
+       nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst));
+       dev_priv->engine.instmem.flush(dev);
+
+       chan->engctx[engine] = ctx;
+       return 0;
+}
+
+static int
+nvc0_copy_object_new(struct nouveau_channel *chan, int engine,
+                    u32 handle, u16 class)
+{
+       return 0;
+}
+
+static void
+nvc0_copy_context_del(struct nouveau_channel *chan, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(chan->dev, engine);
+       struct nouveau_gpuobj *ctx = chan->engctx[engine];
+       struct drm_device *dev = chan->dev;
+       u32 inst;
+
+       inst  = (chan->ramin->vinst >> 12);
+       inst |= 0x40000000;
+
+       /* disable fifo access */
+       nv_wr32(dev, pcopy->fuc + 0x048, 0x00000000);
+       /* mark channel as unloaded if it's currently active */
+       if (nv_rd32(dev, pcopy->fuc + 0x050) == inst)
+               nv_mask(dev, pcopy->fuc + 0x050, 0x40000000, 0x00000000);
+       /* mark next channel as invalid if it's about to be loaded */
+       if (nv_rd32(dev, pcopy->fuc + 0x054) == inst)
+               nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+       /* restore fifo access */
+       nv_wr32(dev, pcopy->fuc + 0x048, 0x00000003);
+
+       nv_wo32(chan->ramin, pcopy->ctx + 0, 0x00000000);
+       nv_wo32(chan->ramin, pcopy->ctx + 4, 0x00000000);
+       nouveau_gpuobj_ref(NULL, &ctx);
+
+       chan->engctx[engine] = ctx;
+}
+
+static int
+nvc0_copy_init(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+       int i;
+
+       nv_mask(dev, 0x000200, pcopy->pmc, 0x00000000);
+       nv_mask(dev, 0x000200, pcopy->pmc, pcopy->pmc);
+       nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+
+       nv_wr32(dev, pcopy->fuc + 0x1c0, 0x01000000);
+       for (i = 0; i < sizeof(nvc0_pcopy_data) / 4; i++)
+               nv_wr32(dev, pcopy->fuc + 0x1c4, nvc0_pcopy_data[i]);
+
+       nv_wr32(dev, pcopy->fuc + 0x180, 0x01000000);
+       for (i = 0; i < sizeof(nvc0_pcopy_code) / 4; i++) {
+               if ((i & 0x3f) == 0)
+                       nv_wr32(dev, pcopy->fuc + 0x188, i >> 6);
+               nv_wr32(dev, pcopy->fuc + 0x184, nvc0_pcopy_code[i]);
+       }
+
+       nv_wr32(dev, pcopy->fuc + 0x084, engine - NVOBJ_ENGINE_COPY0);
+       nv_wr32(dev, pcopy->fuc + 0x10c, 0x00000000);
+       nv_wr32(dev, pcopy->fuc + 0x104, 0x00000000); /* ENTRY */
+       nv_wr32(dev, pcopy->fuc + 0x100, 0x00000002); /* TRIGGER */
+       return 0;
+}
+
+static int
+nvc0_copy_fini(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nv_mask(dev, pcopy->fuc + 0x048, 0x00000003, 0x00000000);
+
+       /* trigger fuc context unload */
+       nv_wait(dev, pcopy->fuc + 0x008, 0x0000000c, 0x00000000);
+       nv_mask(dev, pcopy->fuc + 0x054, 0x40000000, 0x00000000);
+       nv_wr32(dev, pcopy->fuc + 0x000, 0x00000008);
+       nv_wait(dev, pcopy->fuc + 0x008, 0x00000008, 0x00000000);
+
+       nv_wr32(dev, pcopy->fuc + 0x014, 0xffffffff);
+       return 0;
+}
+
+static struct nouveau_enum nvc0_copy_isr_error_name[] = {
+       { 0x0001, "ILLEGAL_MTHD" },
+       { 0x0002, "INVALID_ENUM" },
+       { 0x0003, "INVALID_BITFIELD" },
+       {}
+};
+
+static void
+nvc0_copy_isr(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+       u32 disp = nv_rd32(dev, pcopy->fuc + 0x01c);
+       u32 stat = nv_rd32(dev, pcopy->fuc + 0x008) & disp & ~(disp >> 16);
+       u64 inst = (u64)(nv_rd32(dev, pcopy->fuc + 0x050) & 0x0fffffff) << 12;
+       u32 chid = nvc0_graph_isr_chid(dev, inst);
+       u32 ssta = nv_rd32(dev, pcopy->fuc + 0x040) & 0x0000ffff;
+       u32 addr = nv_rd32(dev, pcopy->fuc + 0x040) >> 16;
+       u32 mthd = (addr & 0x07ff) << 2;
+       u32 subc = (addr & 0x3800) >> 11;
+       u32 data = nv_rd32(dev, pcopy->fuc + 0x044);
+
+       if (stat & 0x00000040) {
+               NV_INFO(dev, "PCOPY: DISPATCH_ERROR [");
+               nouveau_enum_print(nvc0_copy_isr_error_name, ssta);
+               printk("] ch %d [0x%010llx] subc %d mthd 0x%04x data 0x%08x\n",
+                       chid, inst, subc, mthd, data);
+               nv_wr32(dev, pcopy->fuc + 0x004, 0x00000040);
+               stat &= ~0x00000040;
+       }
+
+       if (stat) {
+               NV_INFO(dev, "PCOPY: unhandled intr 0x%08x\n", stat);
+               nv_wr32(dev, pcopy->fuc + 0x004, stat);
+       }
+}
+
+static void
+nvc0_copy_isr_0(struct drm_device *dev)
+{
+       nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY0);
+}
+
+static void
+nvc0_copy_isr_1(struct drm_device *dev)
+{
+       nvc0_copy_isr(dev, NVOBJ_ENGINE_COPY1);
+}
+
+static void
+nvc0_copy_destroy(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy = nv_engine(dev, engine);
+
+       nouveau_irq_unregister(dev, pcopy->irq);
+
+       if (engine == NVOBJ_ENGINE_COPY0)
+               NVOBJ_ENGINE_DEL(dev, COPY0);
+       else
+               NVOBJ_ENGINE_DEL(dev, COPY1);
+       kfree(pcopy);
+}
+
+int
+nvc0_copy_create(struct drm_device *dev, int engine)
+{
+       struct nvc0_copy_engine *pcopy;
+
+       pcopy = kzalloc(sizeof(*pcopy), GFP_KERNEL);
+       if (!pcopy)
+               return -ENOMEM;
+
+       pcopy->base.destroy = nvc0_copy_destroy;
+       pcopy->base.init = nvc0_copy_init;
+       pcopy->base.fini = nvc0_copy_fini;
+       pcopy->base.context_new = nvc0_copy_context_new;
+       pcopy->base.context_del = nvc0_copy_context_del;
+       pcopy->base.object_new = nvc0_copy_object_new;
+
+       if (engine == 0) {
+               pcopy->irq = 5;
+               pcopy->pmc = 0x00000040;
+               pcopy->fuc = 0x104000;
+               pcopy->ctx = 0x0230;
+               nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_0);
+               NVOBJ_ENGINE_ADD(dev, COPY0, &pcopy->base);
+               NVOBJ_CLASS(dev, 0x90b5, COPY0);
+       } else {
+               pcopy->irq = 6;
+               pcopy->pmc = 0x00000080;
+               pcopy->fuc = 0x105000;
+               pcopy->ctx = 0x0240;
+               nouveau_irq_register(dev, pcopy->irq, nvc0_copy_isr_1);
+               NVOBJ_ENGINE_ADD(dev, COPY1, &pcopy->base);
+               NVOBJ_CLASS(dev, 0x90b8, COPY1);
+       }
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h b/drivers/gpu/drm/nouveau/nvc0_copy.fuc.h
new file mode 100644 (file)
index 0000000..4199038
--- /dev/null
@@ -0,0 +1,527 @@
+uint32_t nvc0_pcopy_data[] = {
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00010000,
+       0x00000000,
+       0x00000000,
+       0x00010040,
+       0x0001019f,
+       0x00000000,
+       0x00010050,
+       0x000101a1,
+       0x00000000,
+       0x00070080,
+       0x0000001c,
+       0xfffff000,
+       0x00000020,
+       0xfff80000,
+       0x00000024,
+       0xffffe000,
+       0x00000028,
+       0xfffff800,
+       0x0000002c,
+       0xfffff000,
+       0x00000030,
+       0xfff80000,
+       0x00000034,
+       0xffffe000,
+       0x00070088,
+       0x00000048,
+       0xfffff000,
+       0x0000004c,
+       0xfff80000,
+       0x00000050,
+       0xffffe000,
+       0x00000054,
+       0xfffff800,
+       0x00000058,
+       0xfffff000,
+       0x0000005c,
+       0xfff80000,
+       0x00000060,
+       0xffffe000,
+       0x000200c0,
+       0x000104b8,
+       0x00000000,
+       0x00010541,
+       0x00000000,
+       0x000e00c3,
+       0x00000010,
+       0xffffff00,
+       0x00000014,
+       0x0000000f,
+       0x0000003c,
+       0xffffff00,
+       0x00000040,
+       0x0000000f,
+       0x00000018,
+       0xfff80000,
+       0x00000044,
+       0xfff80000,
+       0x00000074,
+       0xffff0000,
+       0x00000078,
+       0xffffe000,
+       0x00000068,
+       0xfccc0000,
+       0x0000006c,
+       0x00000000,
+       0x00000070,
+       0x00000000,
+       0x00000004,
+       0xffffff00,
+       0x00000008,
+       0x00000000,
+       0x0000000c,
+       0x00000000,
+       0x00000800,
+};
+
+uint32_t nvc0_pcopy_code[] = {
+       0x04fe04bd,
+       0x3517f000,
+       0xf10010fe,
+       0xf1040017,
+       0xf0fff327,
+       0x22d00023,
+       0x0c25f0c0,
+       0xf40012d0,
+       0x17f11031,
+       0x27f01200,
+       0x0012d003,
+       0xf40031f4,
+       0x0ef40028,
+       0x8001cffd,
+       0xf40812c4,
+       0x21f4060b,
+       0x0412c4ca,
+       0xf5070bf4,
+       0xc4010221,
+       0x01d00c11,
+       0xf101f840,
+       0xfe770047,
+       0x47f1004b,
+       0x44cf2100,
+       0x0144f000,
+       0xb60444b6,
+       0xf7f13040,
+       0xf4b6061c,
+       0x1457f106,
+       0x00f5d101,
+       0xb6043594,
+       0x57fe0250,
+       0x0145fe00,
+       0x010052b7,
+       0x00ff67f1,
+       0x56fd60bd,
+       0x0253f004,
+       0xf80545fa,
+       0x0053f003,
+       0xd100e7f0,
+       0x549800fe,
+       0x0845b600,
+       0xb6015698,
+       0x46fd1864,
+       0x0047fe05,
+       0xf00204b9,
+       0x01f40643,
+       0x0604fa09,
+       0xfa060ef4,
+       0x03f80504,
+       0x27f100f8,
+       0x23cf1400,
+       0x1e3fc800,
+       0xf4170bf4,
+       0x21f40132,
+       0x1e3af053,
+       0xf00023d0,
+       0x24d00147,
+       0xcf00f880,
+       0x3dc84023,
+       0x090bf41e,
+       0xf40131f4,
+       0x37f05321,
+       0x8023d002,
+       0x37f100f8,
+       0x32cf1900,
+       0x0033cf40,
+       0x07ff24e4,
+       0xf11024b6,
+       0xbd010057,
+       0x5874bd64,
+       0x57580056,
+       0x0450b601,
+       0xf40446b8,
+       0x76bb4d08,
+       0x0447b800,
+       0xbb0f08f4,
+       0x74b60276,
+       0x0057bb03,
+       0xbbdf0ef4,
+       0x44b60246,
+       0x0045bb03,
+       0xfd014598,
+       0x54b00453,
+       0x201bf400,
+       0x58004558,
+       0x64b00146,
+       0x091bf400,
+       0xf4005380,
+       0x32f4300e,
+       0xf455f901,
+       0x0ef40c01,
+       0x0225f025,
+       0xf10125f0,
+       0xd0100047,
+       0x43d00042,
+       0x4027f040,
+       0xcf0002d0,
+       0x24f08002,
+       0x0024b040,
+       0xf1f71bf4,
+       0xf01d0027,
+       0x23d00137,
+       0xf800f800,
+       0x0027f100,
+       0xf034bd22,
+       0x23d00233,
+       0xf400f800,
+       0x01b0f030,
+       0x0101b000,
+       0xb00201b0,
+       0x04980301,
+       0x3045c71a,
+       0xc70150b6,
+       0x60b63446,
+       0x3847c701,
+       0xf40170b6,
+       0x84bd0232,
+       0x4ac494bd,
+       0x0445b60f,
+       0xa430b4bd,
+       0x0f18f404,
+       0xbbc0a5ff,
+       0x31f400cb,
+       0x220ef402,
+       0xf00c1bf4,
+       0xcbbb10c7,
+       0x160ef400,
+       0xf406a430,
+       0xc7f00c18,
+       0x00cbbb14,
+       0xf1070ef4,
+       0x380080c7,
+       0x80b601c8,
+       0x01b0b601,
+       0xf404b5b8,
+       0x90b6c308,
+       0x0497b801,
+       0xfdb208f4,
+       0x06800065,
+       0x1d08980e,
+       0xf40068fd,
+       0x64bd0502,
+       0x800075fd,
+       0x78fd1907,
+       0x1057f100,
+       0x0654b608,
+       0xd00056d0,
+       0x50b74057,
+       0x06980800,
+       0x0162b619,
+       0x980864b6,
+       0x72b60e07,
+       0x0567fd01,
+       0xb70056d0,
+       0xb4010050,
+       0x56d00060,
+       0x0160b400,
+       0xb44056d0,
+       0x56d00260,
+       0x0360b480,
+       0xb7c056d0,
+       0x98040050,
+       0x56d01b06,
+       0x1c069800,
+       0xf44056d0,
+       0x00f81030,
+       0xc7075798,
+       0x78c76879,
+       0x0380b664,
+       0xb06077c7,
+       0x1bf40e76,
+       0x0477f009,
+       0xf00f0ef4,
+       0x70b6027c,
+       0x0947fd11,
+       0x980677f0,
+       0x5b980c5a,
+       0x00abfd0e,
+       0xbb01b7f0,
+       0xb2b604b7,
+       0xc4abff01,
+       0x9805a7bb,
+       0xe7f00d5d,
+       0x04e8bb01,
+       0xff01e2b6,
+       0xd8bbb4de,
+       0x01e0b605,
+       0xbb0cef94,
+       0xfefd02eb,
+       0x026cf005,
+       0x020860b7,
+       0xd00864b6,
+       0xb7bb006f,
+       0x00cbbb04,
+       0x98085f98,
+       0xfbfd0e5b,
+       0x01b7f000,
+       0xb604b7bb,
+       0xfbbb01b2,
+       0x05f7bb00,
+       0x5f98f0f9,
+       0x01b7f009,
+       0xb604b8bb,
+       0xfbbb01b2,
+       0x05f8bb00,
+       0x78bbf0f9,
+       0x0282b600,
+       0xbb01b7f0,
+       0xb9bb04b8,
+       0x0b589804,
+       0xbb01e7f0,
+       0xe2b604e9,
+       0xf48eff01,
+       0xbb04f7bb,
+       0x79bb00cf,
+       0x0589bb00,
+       0x90fcf0fc,
+       0xbb00d9fd,
+       0x89fd00ad,
+       0x008ffd00,
+       0xbb00a8bb,
+       0x92b604a7,
+       0x0497bb01,
+       0x988069d0,
+       0x58980557,
+       0x00acbb04,
+       0xb6007abb,
+       0x84b60081,
+       0x058bfd10,
+       0x060062b7,
+       0xb70067d0,
+       0xd0040060,
+       0x00f80068,
+       0xb7026cf0,
+       0xb6020260,
+       0x57980864,
+       0x0067d005,
+       0x040060b7,
+       0xb6045798,
+       0x67d01074,
+       0x0060b700,
+       0x06579804,
+       0xf80067d0,
+       0xf900f900,
+       0x0007f110,
+       0x0604b608,
+       0xf00001cf,
+       0x1bf40114,
+       0xfc10fcfa,
+       0xc800f800,
+       0x1bf40d34,
+       0xd121f570,
+       0x0c47f103,
+       0x0644b608,
+       0xb6020598,
+       0x45d00450,
+       0x4040d000,
+       0xd00c57f0,
+       0x40b78045,
+       0x05980400,
+       0x1054b601,
+       0xb70045d0,
+       0xf1050040,
+       0xf00b0057,
+       0x45d00153,
+       0x4057f100,
+       0x0154b640,
+       0x808053f1,
+       0xf14045d0,
+       0xf1111057,
+       0xd0131253,
+       0x57f18045,
+       0x53f11514,
+       0x45d01716,
+       0x0157f1c0,
+       0x0153f026,
+       0x080047f1,
+       0xd00644b6,
+       0x21f50045,
+       0x47f103d1,
+       0x44b6080c,
+       0x02059806,
+       0xd00045d0,
+       0x57f04040,
+       0x8045d004,
+       0x040040b7,
+       0xb6010598,
+       0x45d01054,
+       0x0040b700,
+       0x0057f105,
+       0x0045d003,
+       0x111057f1,
+       0x131253f1,
+       0x984045d0,
+       0x40b70305,
+       0x45d00500,
+       0x0157f100,
+       0x0153f026,
+       0x080047f1,
+       0xd00644b6,
+       0x00f80045,
+       0x03d121f5,
+       0xf4003fc8,
+       0x21f50e0b,
+       0x47f101af,
+       0x0ef40200,
+       0x1067f11e,
+       0x0664b608,
+       0x800177f0,
+       0x07800e07,
+       0x1d079819,
+       0xd00067d0,
+       0x44bd4067,
+       0xbd0232f4,
+       0x043fc854,
+       0xf50a0bf4,
+       0xf403a821,
+       0x21f50a0e,
+       0x49f0029c,
+       0x0231f407,
+       0xc82c57f0,
+       0x0bf4083f,
+       0xa821f50a,
+       0x0a0ef403,
+       0x029c21f5,
+       0xf10849f0,
+       0xb6080057,
+       0x06980654,
+       0x4056d01e,
+       0xf14167f0,
+       0xfd440063,
+       0x54d00546,
+       0x0c3fc800,
+       0xf5070bf4,
+       0xf803eb21,
+       0x0027f100,
+       0xf034bd22,
+       0x23d00133,
+       0x0000f800,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index 2886f2726a9e07ebe25eddb484a061fa2990a503..fb4f5943e01b5f947ee3119ef0988eda83b98171 100644 (file)
@@ -37,7 +37,7 @@ struct nvc0_fifo_priv {
 };
 
 struct nvc0_fifo_chan {
-       struct nouveau_bo *user;
+       struct nouveau_gpuobj *user;
        struct nouveau_gpuobj *ramfc;
 };
 
@@ -106,7 +106,7 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
        struct nvc0_fifo_priv *priv = pfifo->priv;
        struct nvc0_fifo_chan *fifoch;
-       u64 ib_virt, user_vinst;
+       u64 ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
        int ret;
 
        chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL);
@@ -115,28 +115,13 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        fifoch = chan->fifo_priv;
 
        /* allocate vram for control regs, map into polling area */
-       ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM,
-                            0, 0, &fifoch->user);
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC, &fifoch->user);
        if (ret)
                goto error;
 
-       ret = nouveau_bo_pin(fifoch->user, TTM_PL_FLAG_VRAM);
-       if (ret) {
-               nouveau_bo_ref(NULL, &fifoch->user);
-               goto error;
-       }
-
-       user_vinst = fifoch->user->bo.mem.start << PAGE_SHIFT;
-
-       ret = nouveau_bo_map(fifoch->user);
-       if (ret) {
-               nouveau_bo_unpin(fifoch->user);
-               nouveau_bo_ref(NULL, &fifoch->user);
-               goto error;
-       }
-
        nouveau_vm_map_at(&priv->user_vma, chan->id * 0x1000,
-                         fifoch->user->bo.mem.mm_node);
+                         *(struct nouveau_mem **)fifoch->user->node);
 
        chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) +
                                priv->user_vma.offset + (chan->id * 0x1000),
@@ -146,20 +131,6 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
                goto error;
        }
 
-       ib_virt = chan->pushbuf_base + chan->dma.ib_base * 4;
-
-       /* zero channel regs */
-       nouveau_bo_wr32(fifoch->user, 0x0040/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0044/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0048/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x004c/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0050/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0058/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x005c/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0060/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x0088/4, 0);
-       nouveau_bo_wr32(fifoch->user, 0x008c/4, 0);
-
        /* ramfc */
        ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst,
                                      chan->ramin->vinst, 0x100,
@@ -167,8 +138,8 @@ nvc0_fifo_create_context(struct nouveau_channel *chan)
        if (ret)
                goto error;
 
-       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(user_vinst));
-       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(user_vinst));
+       nv_wo32(fifoch->ramfc, 0x08, lower_32_bits(fifoch->user->vinst));
+       nv_wo32(fifoch->ramfc, 0x0c, upper_32_bits(fifoch->user->vinst));
        nv_wo32(fifoch->ramfc, 0x10, 0x0000face);
        nv_wo32(fifoch->ramfc, 0x30, 0xfffff902);
        nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt));
@@ -223,11 +194,7 @@ nvc0_fifo_destroy_context(struct nouveau_channel *chan)
                return;
 
        nouveau_gpuobj_ref(NULL, &fifoch->ramfc);
-       if (fifoch->user) {
-               nouveau_bo_unmap(fifoch->user);
-               nouveau_bo_unpin(fifoch->user);
-               nouveau_bo_ref(NULL, &fifoch->user);
-       }
+       nouveau_gpuobj_ref(NULL, &fifoch->user);
        kfree(fifoch);
 }
 
@@ -240,6 +207,21 @@ nvc0_fifo_load_context(struct nouveau_channel *chan)
 int
 nvc0_fifo_unload_context(struct drm_device *dev)
 {
+       int i;
+
+       for (i = 0; i < 128; i++) {
+               if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1))
+                       continue;
+
+               nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000);
+               nv_wr32(dev, 0x002634, i);
+               if (!nv_wait(dev, 0x002634, 0xffffffff, i)) {
+                       NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n",
+                               i, nv_rd32(dev, 0x002634));
+                       return -EBUSY;
+               }
+       }
+
        return 0;
 }
 
@@ -309,6 +291,7 @@ nvc0_fifo_init(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo;
+       struct nouveau_channel *chan;
        struct nvc0_fifo_priv *priv;
        int ret, i;
 
@@ -351,23 +334,74 @@ nvc0_fifo_init(struct drm_device *dev)
        nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
        nv_wr32(dev, 0x002100, 0xffffffff);
        nv_wr32(dev, 0x002140, 0xbfffffff);
+
+       /* restore PFIFO context table */
+       for (i = 0; i < 128; i++) {
+               chan = dev_priv->channels.ptr[i];
+               if (!chan || !chan->fifo_priv)
+                       continue;
+
+               nv_wr32(dev, 0x003000 + (i * 8), 0xc0000000 |
+                                                (chan->ramin->vinst >> 12));
+               nv_wr32(dev, 0x003004 + (i * 8), 0x001f0001);
+       }
+       nvc0_fifo_playlist_update(dev);
+
        return 0;
 }
 
 struct nouveau_enum nvc0_fifo_fault_unit[] = {
-       { 0, "PGRAPH" },
-       { 3, "PEEPHOLE" },
-       { 4, "BAR1" },
-       { 5, "BAR3" },
-       { 7, "PFIFO" },
+       { 0x00, "PGRAPH" },
+       { 0x03, "PEEPHOLE" },
+       { 0x04, "BAR1" },
+       { 0x05, "BAR3" },
+       { 0x07, "PFIFO" },
+       { 0x10, "PBSP" },
+       { 0x11, "PPPP" },
+       { 0x13, "PCOUNTER" },
+       { 0x14, "PVP" },
+       { 0x15, "PCOPY0" },
+       { 0x16, "PCOPY1" },
+       { 0x17, "PDAEMON" },
        {}
 };
 
 struct nouveau_enum nvc0_fifo_fault_reason[] = {
-       { 0, "PT_NOT_PRESENT" },
-       { 1, "PT_TOO_SHORT" },
-       { 2, "PAGE_NOT_PRESENT" },
-       { 3, "VM_LIMIT_EXCEEDED" },
+       { 0x00, "PT_NOT_PRESENT" },
+       { 0x01, "PT_TOO_SHORT" },
+       { 0x02, "PAGE_NOT_PRESENT" },
+       { 0x03, "VM_LIMIT_EXCEEDED" },
+       { 0x04, "NO_CHANNEL" },
+       { 0x05, "PAGE_SYSTEM_ONLY" },
+       { 0x06, "PAGE_READ_ONLY" },
+       { 0x0a, "COMPRESSED_SYSRAM" },
+       { 0x0c, "INVALID_STORAGE_TYPE" },
+       {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
+       { 0x01, "PCOPY0" },
+       { 0x02, "PCOPY1" },
+       { 0x04, "DISPATCH" },
+       { 0x05, "CTXCTL" },
+       { 0x06, "PFIFO" },
+       { 0x07, "BAR_READ" },
+       { 0x08, "BAR_WRITE" },
+       { 0x0b, "PVP" },
+       { 0x0c, "PPPP" },
+       { 0x0d, "PBSP" },
+       { 0x11, "PCOUNTER" },
+       { 0x12, "PDAEMON" },
+       { 0x14, "CCACHE" },
+       { 0x15, "CCACHE_POST" },
+       {}
+};
+
+struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
+       { 0x01, "TEX" },
+       { 0x0c, "ESETUP" },
+       { 0x0e, "CTXCTL" },
+       { 0x0f, "PROP" },
        {}
 };
 
@@ -385,12 +419,20 @@ nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit)
        u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10));
        u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10));
        u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10));
+       u32 client = (stat & 0x00001f00) >> 8;
 
        NV_INFO(dev, "PFIFO: %s fault at 0x%010llx [",
                (stat & 0x00000080) ? "write" : "read", (u64)vahi << 32 | valo);
        nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
        printk("] from ");
        nouveau_enum_print(nvc0_fifo_fault_unit, unit);
+       if (stat & 0x00000040) {
+               printk("/");
+               nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
+       } else {
+               printk("/GPC%d/", (stat & 0x1f000000) >> 24);
+               nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
+       }
        printk(" on channel 0x%010llx\n", (u64)inst << 12);
 }
 
index 3de9b721d8dbe61260af7487ce086fc23acaa758..ca6db204d644711dafcaa8e9eaf2c88deada27ae 100644 (file)
 #include "nouveau_mm.h"
 #include "nvc0_graph.h"
 
-static void nvc0_graph_isr(struct drm_device *);
-static void nvc0_runk140_isr(struct drm_device *);
-static int  nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan);
-
-void
-nvc0_graph_fifo_access(struct drm_device *dev, bool enabled)
+static int
+nvc0_graph_load_context(struct nouveau_channel *chan)
 {
+       struct drm_device *dev = chan->dev;
+
+       nv_wr32(dev, 0x409840, 0x00000030);
+       nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
+       nv_wr32(dev, 0x409504, 0x00000003);
+       if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
+               NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
+
+       return 0;
 }
 
-struct nouveau_channel *
-nvc0_graph_channel(struct drm_device *dev)
+static int
+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
 {
-       return NULL;
+       nv_wr32(dev, 0x409840, 0x00000003);
+       nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
+       nv_wr32(dev, 0x409504, 0x00000009);
+       if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
+               NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
+               return -EBUSY;
+       }
+
+       return 0;
 }
 
 static int
 nvc0_graph_construct_context(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int ret, i;
        u32 *ctx;
@@ -89,9 +102,8 @@ nvc0_graph_construct_context(struct nouveau_channel *chan)
 static int
 nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int i = 0, gpc, tp, ret;
        u32 magic;
@@ -158,29 +170,27 @@ nvc0_graph_create_context_mmio_list(struct nouveau_channel *chan)
        return 0;
 }
 
-int
-nvc0_graph_create_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_context_new(struct nouveau_channel *chan, int engine)
 {
-       struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
+       struct drm_device *dev = chan->dev;
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
        struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv = pgraph->priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, engine);
        struct nvc0_graph_chan *grch;
-       struct drm_device *dev = chan->dev;
        struct nouveau_gpuobj *grctx;
        int ret, i;
 
-       chan->pgraph_ctx = kzalloc(sizeof(*grch), GFP_KERNEL);
-       if (!chan->pgraph_ctx)
+       grch = kzalloc(sizeof(*grch), GFP_KERNEL);
+       if (!grch)
                return -ENOMEM;
-       grch = chan->pgraph_ctx;
+       chan->engctx[NVOBJ_ENGINE_GR] = grch;
 
        ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256,
                                 NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC,
                                 &grch->grctx);
        if (ret)
                goto error;
-       chan->ramin_grctx = grch->grctx;
        grctx = grch->grctx;
 
        ret = nvc0_graph_create_context_mmio_list(chan);
@@ -200,104 +210,49 @@ nvc0_graph_create_context(struct nouveau_channel *chan)
        for (i = 0; i < priv->grctx_size; i += 4)
                nv_wo32(grctx, i, priv->grctx_vals[i / 4]);
 
-        nv_wo32(grctx, 0xf4, 0);
-        nv_wo32(grctx, 0xf8, 0);
-        nv_wo32(grctx, 0x10, grch->mmio_nr);
-        nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
-        nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
-        nv_wo32(grctx, 0x1c, 1);
-        nv_wo32(grctx, 0x20, 0);
-        nv_wo32(grctx, 0x28, 0);
-        nv_wo32(grctx, 0x2c, 0);
+       nv_wo32(grctx, 0xf4, 0);
+       nv_wo32(grctx, 0xf8, 0);
+       nv_wo32(grctx, 0x10, grch->mmio_nr);
+       nv_wo32(grctx, 0x14, lower_32_bits(grch->mmio->vinst));
+       nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->vinst));
+       nv_wo32(grctx, 0x1c, 1);
+       nv_wo32(grctx, 0x20, 0);
+       nv_wo32(grctx, 0x28, 0);
+       nv_wo32(grctx, 0x2c, 0);
        pinstmem->flush(dev);
        return 0;
 
 error:
-       pgraph->destroy_context(chan);
+       priv->base.context_del(chan, engine);
        return ret;
 }
 
-void
-nvc0_graph_destroy_context(struct nouveau_channel *chan)
+static void
+nvc0_graph_context_del(struct nouveau_channel *chan, int engine)
 {
-       struct nvc0_graph_chan *grch;
-
-       grch = chan->pgraph_ctx;
-       chan->pgraph_ctx = NULL;
-       if (!grch)
-               return;
+       struct nvc0_graph_chan *grch = chan->engctx[engine];
 
        nouveau_gpuobj_ref(NULL, &grch->mmio);
        nouveau_gpuobj_ref(NULL, &grch->unk418810);
        nouveau_gpuobj_ref(NULL, &grch->unk40800c);
        nouveau_gpuobj_ref(NULL, &grch->unk408004);
        nouveau_gpuobj_ref(NULL, &grch->grctx);
-       chan->ramin_grctx = NULL;
+       chan->engctx[engine] = NULL;
 }
 
-int
-nvc0_graph_load_context(struct nouveau_channel *chan)
+static int
+nvc0_graph_object_new(struct nouveau_channel *chan, int engine,
+                     u32 handle, u16 class)
 {
-       struct drm_device *dev = chan->dev;
-
-       nv_wr32(dev, 0x409840, 0x00000030);
-       nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12);
-       nv_wr32(dev, 0x409504, 0x00000003);
-       if (!nv_wait(dev, 0x409800, 0x00000010, 0x00000010))
-               NV_ERROR(dev, "PGRAPH: load_ctx timeout\n");
-
        return 0;
 }
 
 static int
-nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan)
+nvc0_graph_fini(struct drm_device *dev, int engine)
 {
-       nv_wr32(dev, 0x409840, 0x00000003);
-       nv_wr32(dev, 0x409500, 0x80000000 | chan >> 12);
-       nv_wr32(dev, 0x409504, 0x00000009);
-       if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000000)) {
-               NV_ERROR(dev, "PGRAPH: unload_ctx timeout\n");
-               return -EBUSY;
-       }
-
        return 0;
 }
 
-int
-nvc0_graph_unload_context(struct drm_device *dev)
-{
-       u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12;
-       return nvc0_graph_unload_context_to(dev, inst);
-}
-
-static void
-nvc0_graph_destroy(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv;
-
-       priv = pgraph->priv;
-       if (!priv)
-               return;
-
-       nouveau_irq_unregister(dev, 12);
-       nouveau_irq_unregister(dev, 25);
-
-       nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
-       nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
-       if (priv->grctx_vals)
-               kfree(priv->grctx_vals);
-       kfree(priv);
-}
-
-void
-nvc0_graph_takedown(struct drm_device *dev)
-{
-       nvc0_graph_destroy(dev);
-}
-
 static int
 nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
                          u32 class, u32 mthd, u32 data)
@@ -306,119 +261,10 @@ nvc0_graph_mthd_page_flip(struct nouveau_channel *chan,
        return 0;
 }
 
-static int
-nvc0_graph_create(struct drm_device *dev)
-{
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv;
-       int ret, gpc, i;
-
-       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-       pgraph->priv = priv;
-
-       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
-       if (ret)
-               goto error;
-
-       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
-       if (ret)
-               goto error;
-
-       for (i = 0; i < 0x1000; i += 4) {
-               nv_wo32(priv->unk4188b4, i, 0x00000010);
-               nv_wo32(priv->unk4188b8, i, 0x00000010);
-       }
-
-       priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
-       priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
-       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
-               priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
-               priv->tp_total += priv->tp_nr[gpc];
-       }
-
-       /*XXX: these need figuring out... */
-       switch (dev_priv->chipset) {
-       case 0xc0:
-               if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
-                       priv->magic_not_rop_nr = 0x07;
-                       /* filled values up to tp_total, the rest 0 */
-                       priv->magicgpc980[0]   = 0x22111000;
-                       priv->magicgpc980[1]   = 0x00000233;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x000ba2e9;
-               } else
-               if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
-                       priv->magic_not_rop_nr = 0x05;
-                       priv->magicgpc980[0]   = 0x11110000;
-                       priv->magicgpc980[1]   = 0x00233222;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x00092493;
-               } else
-               if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
-                       priv->magic_not_rop_nr = 0x06;
-                       priv->magicgpc980[0]   = 0x11110000;
-                       priv->magicgpc980[1]   = 0x03332222;
-                       priv->magicgpc980[2]   = 0x00000000;
-                       priv->magicgpc980[3]   = 0x00000000;
-                       priv->magicgpc918      = 0x00088889;
-               }
-               break;
-       case 0xc3: /* 450, 4/0/0/0, 2 */
-               priv->magic_not_rop_nr = 0x03;
-               priv->magicgpc980[0]   = 0x00003210;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00200000;
-               break;
-       case 0xc4: /* 460, 3/4/0/0, 4 */
-               priv->magic_not_rop_nr = 0x01;
-               priv->magicgpc980[0]   = 0x02321100;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00124925;
-               break;
-       }
-
-       if (!priv->magic_not_rop_nr) {
-               NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
-                        priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
-                        priv->tp_nr[3], priv->rop_nr);
-               /* use 0xc3's values... */
-               priv->magic_not_rop_nr = 0x03;
-               priv->magicgpc980[0]   = 0x00003210;
-               priv->magicgpc980[1]   = 0x00000000;
-               priv->magicgpc980[2]   = 0x00000000;
-               priv->magicgpc980[3]   = 0x00000000;
-               priv->magicgpc918      = 0x00200000;
-       }
-
-       nouveau_irq_register(dev, 12, nvc0_graph_isr);
-       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
-       NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
-       NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
-       NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
-       NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
-       NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
-       return 0;
-
-error:
-       nvc0_graph_destroy(dev);
-       return ret;
-}
-
 static void
 nvc0_graph_init_obj418880(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
-       struct nvc0_graph_priv *priv = pgraph->priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int i;
 
        nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000);
@@ -449,35 +295,42 @@ nvc0_graph_init_regs(struct drm_device *dev)
 static void
 nvc0_graph_init_gpc_0(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       int gpc;
-       
-       //      TP      ROP UNKVAL(magic_not_rop_nr)
-       // 450: 4/0/0/0 2        3
-       // 460: 3/4/0/0 4        1
-       // 465: 3/4/4/0 4        7
-       // 470: 3/3/4/4 5        5
-       // 480: 3/4/4/4 6        6
-
-       // magicgpc918
-       // 450: 00200000 00000000001000000000000000000000
-       // 460: 00124925 00000000000100100100100100100101
-       // 465: 000ba2e9 00000000000010111010001011101001
-       // 470: 00092493 00000000000010010010010010010011
-       // 480: 00088889 00000000000010001000100010001001
-
-       /* filled values up to tp_total, remainder 0 */
-       // 450: 00003210 00000000 00000000 00000000
-       // 460: 02321100 00000000 00000000 00000000
-       // 465: 22111000 00000233 00000000 00000000
-       // 470: 11110000 00233222 00000000 00000000
-       // 480: 11110000 03332222 00000000 00000000
-       
-       nv_wr32(dev, GPC_BCAST(0x0980), priv->magicgpc980[0]);
-       nv_wr32(dev, GPC_BCAST(0x0984), priv->magicgpc980[1]);
-       nv_wr32(dev, GPC_BCAST(0x0988), priv->magicgpc980[2]);
-       nv_wr32(dev, GPC_BCAST(0x098c), priv->magicgpc980[3]);
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
+       u32 data[TP_MAX / 8];
+       u8  tpnr[GPC_MAX];
+       int i, gpc, tpc;
+
+       /*
+        *      TP      ROP UNKVAL(magic_not_rop_nr)
+        * 450: 4/0/0/0 2        3
+        * 460: 3/4/0/0 4        1
+        * 465: 3/4/4/0 4        7
+        * 470: 3/3/4/4 5        5
+        * 480: 3/4/4/4 6        6
+        *
+        * magicgpc918
+        * 450: 00200000 00000000001000000000000000000000
+        * 460: 00124925 00000000000100100100100100100101
+        * 465: 000ba2e9 00000000000010111010001011101001
+        * 470: 00092493 00000000000010010010010010010011
+        * 480: 00088889 00000000000010001000100010001001
+        */
+
+       memset(data, 0x00, sizeof(data));
+       memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr));
+       for (i = 0, gpc = -1; i < priv->tp_total; i++) {
+               do {
+                       gpc = (gpc + 1) % priv->gpc_nr;
+               } while (!tpnr[gpc]);
+               tpc = priv->tp_nr[gpc] - tpnr[gpc]--;
+
+               data[i / 8] |= tpc << ((i % 8) * 4);
+       }
+
+       nv_wr32(dev, GPC_BCAST(0x0980), data[0]);
+       nv_wr32(dev, GPC_BCAST(0x0984), data[1]);
+       nv_wr32(dev, GPC_BCAST(0x0988), data[2]);
+       nv_wr32(dev, GPC_BCAST(0x098c), data[3]);
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
                nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 |
@@ -509,8 +362,7 @@ nvc0_graph_init_units(struct drm_device *dev)
 static void
 nvc0_graph_init_gpc_1(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int gpc, tp;
 
        for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
@@ -535,8 +387,7 @@ nvc0_graph_init_gpc_1(struct drm_device *dev)
 static void
 nvc0_graph_init_rop(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        int rop;
 
        for (rop = 0; rop < priv->rop_nr; rop++) {
@@ -547,62 +398,36 @@ nvc0_graph_init_rop(struct drm_device *dev)
        }
 }
 
-static int
-nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base,
-                const char *code_fw, const char *data_fw)
+static void
+nvc0_graph_init_fuc(struct drm_device *dev, u32 fuc_base,
+                   struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
 {
-       const struct firmware *fw;
-       char name[32];
-       int ret, i;
-
-       snprintf(name, sizeof(name), "nouveau/%s", data_fw);
-       ret = request_firmware(&fw, name, &dev->pdev->dev);
-       if (ret) {
-               NV_ERROR(dev, "failed to load %s\n", data_fw);
-               return ret;
-       }
+       int i;
 
        nv_wr32(dev, fuc_base + 0x01c0, 0x01000000);
-       for (i = 0; i < fw->size / 4; i++)
-               nv_wr32(dev, fuc_base + 0x01c4, ((u32 *)fw->data)[i]);
-       release_firmware(fw);
-
-       snprintf(name, sizeof(name), "nouveau/%s", code_fw);
-       ret = request_firmware(&fw, name, &dev->pdev->dev);
-       if (ret) {
-               NV_ERROR(dev, "failed to load %s\n", code_fw);
-               return ret;
-       }
+       for (i = 0; i < data->size / 4; i++)
+               nv_wr32(dev, fuc_base + 0x01c4, data->data[i]);
 
        nv_wr32(dev, fuc_base + 0x0180, 0x01000000);
-       for (i = 0; i < fw->size / 4; i++) {
+       for (i = 0; i < code->size / 4; i++) {
                if ((i & 0x3f) == 0)
                        nv_wr32(dev, fuc_base + 0x0188, i >> 6);
-               nv_wr32(dev, fuc_base + 0x0184, ((u32 *)fw->data)[i]);
+               nv_wr32(dev, fuc_base + 0x0184, code->data[i]);
        }
-       release_firmware(fw);
-
-       return 0;
 }
 
 static int
 nvc0_graph_init_ctxctl(struct drm_device *dev)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
+       struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR);
        u32 r000260;
-       int ret;
 
        /* load fuc microcode */
        r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000);
-       ret = nvc0_fuc_load_fw(dev, 0x409000, "fuc409c", "fuc409d");
-       if (ret == 0)
-               ret = nvc0_fuc_load_fw(dev, 0x41a000, "fuc41ac", "fuc41ad");
+       nvc0_graph_init_fuc(dev, 0x409000, &priv->fuc409c, &priv->fuc409d);
+       nvc0_graph_init_fuc(dev, 0x41a000, &priv->fuc41ac, &priv->fuc41ad);
        nv_wr32(dev, 0x000260, r000260);
 
-       if (ret)
-               return ret;
-
        /* start both of them running */
        nv_wr32(dev, 0x409840, 0xffffffff);
        nv_wr32(dev, 0x41a10c, 0x00000000);
@@ -644,41 +469,19 @@ nvc0_graph_init_ctxctl(struct drm_device *dev)
        return 0;
 }
 
-int
-nvc0_graph_init(struct drm_device *dev)
+static int
+nvc0_graph_init(struct drm_device *dev, int engine)
 {
-       struct drm_nouveau_private *dev_priv = dev->dev_private;
-       struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph;
        int ret;
 
-       dev_priv->engine.graph.accel_blocked = true;
-
-       switch (dev_priv->chipset) {
-       case 0xc0:
-       case 0xc3:
-       case 0xc4:
-               break;
-       default:
-               NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
-               if (nouveau_noaccel != 0)
-                       return 0;
-               break;
-       }
-
        nv_mask(dev, 0x000200, 0x18001000, 0x00000000);
        nv_mask(dev, 0x000200, 0x18001000, 0x18001000);
 
-       if (!pgraph->priv) {
-               ret = nvc0_graph_create(dev);
-               if (ret)
-                       return ret;
-       }
-
        nvc0_graph_init_obj418880(dev);
        nvc0_graph_init_regs(dev);
-       //nvc0_graph_init_unitplemented_magics(dev);
+       /*nvc0_graph_init_unitplemented_magics(dev);*/
        nvc0_graph_init_gpc_0(dev);
-       //nvc0_graph_init_unitplemented_c242(dev);
+       /*nvc0_graph_init_unitplemented_c242(dev);*/
 
        nv_wr32(dev, 0x400500, 0x00010001);
        nv_wr32(dev, 0x400100, 0xffffffff);
@@ -697,12 +500,13 @@ nvc0_graph_init(struct drm_device *dev)
        nv_wr32(dev, 0x400054, 0x34ce3464);
 
        ret = nvc0_graph_init_ctxctl(dev);
-       if (ret == 0)
-               dev_priv->engine.graph.accel_blocked = false;
+       if (ret)
+               return ret;
+
        return 0;
 }
 
-static int
+int
 nvc0_graph_isr_chid(struct drm_device *dev, u64 inst)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
@@ -806,3 +610,187 @@ nvc0_runk140_isr(struct drm_device *dev)
                units &= ~(1 << unit);
        }
 }
+
+static int
+nvc0_graph_create_fw(struct drm_device *dev, const char *fwname,
+                    struct nvc0_graph_fuc *fuc)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       const struct firmware *fw;
+       char f[32];
+       int ret;
+
+       snprintf(f, sizeof(f), "nouveau/nv%02x_%s", dev_priv->chipset, fwname);
+       ret = request_firmware(&fw, f, &dev->pdev->dev);
+       if (ret) {
+               snprintf(f, sizeof(f), "nouveau/%s", fwname);
+               ret = request_firmware(&fw, f, &dev->pdev->dev);
+               if (ret) {
+                       NV_ERROR(dev, "failed to load %s\n", fwname);
+                       return ret;
+               }
+       }
+
+       fuc->size = fw->size;
+       fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+       release_firmware(fw);
+       return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+static void
+nvc0_graph_destroy_fw(struct nvc0_graph_fuc *fuc)
+{
+       if (fuc->data) {
+               kfree(fuc->data);
+               fuc->data = NULL;
+       }
+}
+
+static void
+nvc0_graph_destroy(struct drm_device *dev, int engine)
+{
+       struct nvc0_graph_priv *priv = nv_engine(dev, engine);
+
+       nvc0_graph_destroy_fw(&priv->fuc409c);
+       nvc0_graph_destroy_fw(&priv->fuc409d);
+       nvc0_graph_destroy_fw(&priv->fuc41ac);
+       nvc0_graph_destroy_fw(&priv->fuc41ad);
+
+       nouveau_irq_unregister(dev, 12);
+       nouveau_irq_unregister(dev, 25);
+
+       nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
+       nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
+
+       if (priv->grctx_vals)
+               kfree(priv->grctx_vals);
+
+       NVOBJ_ENGINE_DEL(dev, GR);
+       kfree(priv);
+}
+
+int
+nvc0_graph_create(struct drm_device *dev)
+{
+       struct drm_nouveau_private *dev_priv = dev->dev_private;
+       struct nvc0_graph_priv *priv;
+       int ret, gpc, i;
+
+       switch (dev_priv->chipset) {
+       case 0xc0:
+       case 0xc3:
+       case 0xc4:
+               break;
+       default:
+               NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n");
+               return 0;
+       }
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base.destroy = nvc0_graph_destroy;
+       priv->base.init = nvc0_graph_init;
+       priv->base.fini = nvc0_graph_fini;
+       priv->base.context_new = nvc0_graph_context_new;
+       priv->base.context_del = nvc0_graph_context_del;
+       priv->base.object_new = nvc0_graph_object_new;
+
+       NVOBJ_ENGINE_ADD(dev, GR, &priv->base);
+       nouveau_irq_register(dev, 12, nvc0_graph_isr);
+       nouveau_irq_register(dev, 25, nvc0_runk140_isr);
+
+       if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) ||
+           nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) ||
+           nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) ||
+           nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) {
+               ret = 0;
+               goto error;
+       }
+
+
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4);
+       if (ret)
+               goto error;
+
+       ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b8);
+       if (ret)
+               goto error;
+
+       for (i = 0; i < 0x1000; i += 4) {
+               nv_wo32(priv->unk4188b4, i, 0x00000010);
+               nv_wo32(priv->unk4188b8, i, 0x00000010);
+       }
+
+       priv->gpc_nr  =  nv_rd32(dev, 0x409604) & 0x0000001f;
+       priv->rop_nr = (nv_rd32(dev, 0x409604) & 0x001f0000) >> 16;
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               priv->tp_nr[gpc] = nv_rd32(dev, GPC_UNIT(gpc, 0x2608));
+               priv->tp_total += priv->tp_nr[gpc];
+       }
+
+       /*XXX: these need figuring out... */
+       switch (dev_priv->chipset) {
+       case 0xc0:
+               if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */
+                       priv->magic_not_rop_nr = 0x07;
+                       /* filled values up to tp_total, the rest 0 */
+                       priv->magicgpc918      = 0x000ba2e9;
+               } else
+               if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */
+                       priv->magic_not_rop_nr = 0x05;
+                       priv->magicgpc918      = 0x00092493;
+               } else
+               if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */
+                       priv->magic_not_rop_nr = 0x06;
+                       priv->magicgpc918      = 0x00088889;
+               }
+               break;
+       case 0xc3: /* 450, 4/0/0/0, 2 */
+               priv->magic_not_rop_nr = 0x03;
+               priv->magicgpc918      = 0x00200000;
+               break;
+       case 0xc4: /* 460, 3/4/0/0, 4 */
+               priv->magic_not_rop_nr = 0x01;
+               priv->magicgpc918      = 0x00124925;
+               break;
+       }
+
+       if (!priv->magic_not_rop_nr) {
+               NV_ERROR(dev, "PGRAPH: unknown config: %d/%d/%d/%d, %d\n",
+                        priv->tp_nr[0], priv->tp_nr[1], priv->tp_nr[2],
+                        priv->tp_nr[3], priv->rop_nr);
+               /* use 0xc3's values... */
+               priv->magic_not_rop_nr = 0x03;
+               priv->magicgpc918      = 0x00200000;
+       }
+
+       NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */
+       NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */
+       NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip);
+       NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */
+       NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */
+       return 0;
+
+error:
+       nvc0_graph_destroy(dev, NVOBJ_ENGINE_GR);
+       return ret;
+}
+
+MODULE_FIRMWARE("nouveau/nvc0_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc0_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc0_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc3_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc3_fuc41ad");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409c");
+MODULE_FIRMWARE("nouveau/nvc4_fuc409d");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ac");
+MODULE_FIRMWARE("nouveau/nvc4_fuc41ad");
+MODULE_FIRMWARE("nouveau/fuc409c");
+MODULE_FIRMWARE("nouveau/fuc409d");
+MODULE_FIRMWARE("nouveau/fuc41ac");
+MODULE_FIRMWARE("nouveau/fuc41ad");
index 40e26f9c56c44c0af8a9dcaed0d0ac64872db5d8..f5d184e0689df4bad0f99ce792167c1c8ea960f9 100644 (file)
 #define GPC_MAX 4
 #define TP_MAX 32
 
-#define ROP_BCAST(r)   (0x408800 + (r))
-#define ROP_UNIT(u,r)  (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r)   (0x418000 + (r))
-#define GPC_UNIT(t,r)  (0x500000 + (t) * 0x8000 + (r))
-#define TP_UNIT(t,m,r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+#define ROP_BCAST(r)     (0x408800 + (r))
+#define ROP_UNIT(u, r)   (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r)     (0x418000 + (r))
+#define GPC_UNIT(t, r)   (0x500000 + (t) * 0x8000 + (r))
+#define TP_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct nvc0_graph_fuc {
+       u32 *data;
+       u32  size;
+};
 
 struct nvc0_graph_priv {
+       struct nouveau_exec_engine base;
+
+       struct nvc0_graph_fuc fuc409c;
+       struct nvc0_graph_fuc fuc409d;
+       struct nvc0_graph_fuc fuc41ac;
+       struct nvc0_graph_fuc fuc41ad;
+
        u8 gpc_nr;
        u8 rop_nr;
        u8 tp_nr[GPC_MAX];
@@ -46,15 +58,14 @@ struct nvc0_graph_priv {
        struct nouveau_gpuobj *unk4188b8;
 
        u8  magic_not_rop_nr;
-       u32 magicgpc980[4];
        u32 magicgpc918;
 };
 
 struct nvc0_graph_chan {
        struct nouveau_gpuobj *grctx;
-       struct nouveau_gpuobj *unk408004; // 0x418810 too
-       struct nouveau_gpuobj *unk40800c; // 0x419004 too
-       struct nouveau_gpuobj *unk418810; // 0x419848 too
+       struct nouveau_gpuobj *unk408004; /* 0x418810 too */
+       struct nouveau_gpuobj *unk40800c; /* 0x419004 too */
+       struct nouveau_gpuobj *unk418810; /* 0x419848 too */
        struct nouveau_gpuobj *mmio;
        int mmio_nr;
 };
index f880ff776db8562842142ebbc5482632e9ff2ecd..6df066114133dfc4beb9c1c142ce0391b15ab527 100644 (file)
@@ -1623,7 +1623,7 @@ nvc0_grctx_generate_rop(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       // ROPC_BROADCAST
+       /* ROPC_BROADCAST */
        nv_wr32(dev, 0x408800, 0x02802a3c);
        nv_wr32(dev, 0x408804, 0x00000040);
        nv_wr32(dev, 0x408808, 0x0003e00d);
@@ -1647,7 +1647,7 @@ nvc0_grctx_generate_gpc(struct drm_device *dev)
 {
        int i;
 
-       // GPC_BROADCAST
+       /* GPC_BROADCAST */
        nv_wr32(dev, 0x418380, 0x00000016);
        nv_wr32(dev, 0x418400, 0x38004e00);
        nv_wr32(dev, 0x418404, 0x71e0ffff);
@@ -1728,7 +1728,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
 {
        struct drm_nouveau_private *dev_priv = dev->dev_private;
 
-       // GPC_BROADCAST.TP_BROADCAST
+       /* GPC_BROADCAST.TP_BROADCAST */
        nv_wr32(dev, 0x419848, 0x00000000);
        nv_wr32(dev, 0x419864, 0x0000012a);
        nv_wr32(dev, 0x419888, 0x00000000);
@@ -1741,7 +1741,7 @@ nvc0_grctx_generate_tp(struct drm_device *dev)
        nv_wr32(dev, 0x419a1c, 0x00000000);
        nv_wr32(dev, 0x419a20, 0x00000800);
        if (dev_priv->chipset != 0xc0)
-               nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3
+               nv_wr32(dev, 0x00419ac4, 0x0007f440); /* 0xc3 */
        nv_wr32(dev, 0x419b00, 0x0a418820);
        nv_wr32(dev, 0x419b04, 0x062080e6);
        nv_wr32(dev, 0x419b08, 0x020398a4);
@@ -1797,8 +1797,8 @@ int
 nvc0_grctx_generate(struct nouveau_channel *chan)
 {
        struct drm_nouveau_private *dev_priv = chan->dev->dev_private;
-       struct nvc0_graph_priv *priv = dev_priv->engine.graph.priv;
-       struct nvc0_graph_chan *grch = chan->pgraph_ctx;
+       struct nvc0_graph_priv *priv = nv_engine(chan->dev, NVOBJ_ENGINE_GR);
+       struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR];
        struct drm_device *dev = chan->dev;
        int i, gpc, tp, id;
        u32 r000260, tmp;
@@ -1912,13 +1912,13 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                for (i = 1; i < 7; i++)
                        data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
 
-               // GPC_BROADCAST
+               /* GPC_BROADCAST */
                nv_wr32(dev, 0x418bb8, (priv->tp_total << 8) |
                                        priv->magic_not_rop_nr);
                for (i = 0; i < 6; i++)
                        nv_wr32(dev, 0x418b08 + (i * 4), data[i]);
 
-               // GPC_BROADCAST.TP_BROADCAST
+               /* GPC_BROADCAST.TP_BROADCAST */
                nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) |
                                       priv->magic_not_rop_nr |
                                       data2[0]);
@@ -1926,7 +1926,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                for (i = 0; i < 6; i++)
                        nv_wr32(dev, 0x419b00 + (i * 4), data[i]);
 
-               // UNK78xx
+               /* UNK78xx */
                nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) |
                                        priv->magic_not_rop_nr);
                for (i = 0; i < 6; i++)
@@ -1944,7 +1944,7 @@ nvc0_grctx_generate(struct nouveau_channel *chan)
                gpc = -1;
                for (i = 0, gpc = -1; i < 32; i++) {
                        int ltp = i * (priv->tp_total - 1) / 32;
-                       
+
                        do {
                                gpc = (gpc + 1) % priv->gpc_nr;
                        } while (!tpnr[gpc]);
index 8caf546c8e92f189d6576939081b7afa1a7a33c2..5b991f7c6e2add24f1b4290b270cf1d44282915f 100644 (file)
@@ -505,12 +505,18 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
         * DDC_VGA           = RADEON_GPIO_VGA_DDC
         * DDC_LCD           = RADEON_GPIOPAD_MASK
         * DDC_GPIO          = RADEON_MDGPIO_MASK
-        * r1xx/r2xx
+        * r1xx
         * DDC_MONID         = RADEON_GPIO_MONID
         * DDC_CRT2          = RADEON_GPIO_CRT2_DDC
-        * r3xx
+        * r200
         * DDC_MONID         = RADEON_GPIO_MONID
         * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * r300/r350
+        * DDC_MONID         = RADEON_GPIO_DVI_DDC
+        * DDC_CRT2          = RADEON_GPIO_DVI_DDC
+        * rv2xx/rv3xx
+        * DDC_MONID         = RADEON_GPIO_MONID
+        * DDC_CRT2          = RADEON_GPIO_MONID
         * rs3xx/rs4xx
         * DDC_MONID         = RADEON_GPIOPAD_MASK
         * DDC_CRT2          = RADEON_GPIO_MONID
@@ -537,17 +543,26 @@ static struct radeon_i2c_bus_rec combios_setup_i2c_bus(struct radeon_device *rde
                    rdev->family == CHIP_RS400 ||
                    rdev->family == CHIP_RS480)
                        ddc_line = RADEON_GPIOPAD_MASK;
-               else
+               else if (rdev->family == CHIP_R300 ||
+                        rdev->family == CHIP_R350) {
+                       ddc_line = RADEON_GPIO_DVI_DDC;
+                       ddc = DDC_DVI;
+               } else
                        ddc_line = RADEON_GPIO_MONID;
                break;
        case DDC_CRT2:
-               if (rdev->family == CHIP_RS300 ||
-                   rdev->family == CHIP_RS400 ||
-                   rdev->family == CHIP_RS480)
-                       ddc_line = RADEON_GPIO_MONID;
-               else if (rdev->family >= CHIP_R300) {
+               if (rdev->family == CHIP_R200 ||
+                   rdev->family == CHIP_R300 ||
+                   rdev->family == CHIP_R350) {
                        ddc_line = RADEON_GPIO_DVI_DDC;
                        ddc = DDC_DVI;
+               } else if (rdev->family == CHIP_RS300 ||
+                          rdev->family == CHIP_RS400 ||
+                          rdev->family == CHIP_RS480)
+                       ddc_line = RADEON_GPIO_MONID;
+               else if (rdev->family >= CHIP_RV350) {
+                       ddc_line = RADEON_GPIO_MONID;
+                       ddc = DDC_MONID;
                } else
                        ddc_line = RADEON_GPIO_CRT2_DDC;
                break;
@@ -709,26 +724,42 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
        struct drm_device *dev = rdev->ddev;
        struct radeon_i2c_bus_rec i2c;
 
+       /* actual hw pads
+        * r1xx/rs2xx/rs3xx
+        * 0x60, 0x64, 0x68, 0x6c, gpiopads, mm
+        * r200
+        * 0x60, 0x64, 0x68, mm
+        * r300/r350
+        * 0x60, 0x64, mm
+        * rv2xx/rv3xx/rs4xx
+        * 0x60, 0x64, 0x68, gpiopads, mm
+        */
 
+       /* 0x60 */
        i2c = combios_setup_i2c_bus(rdev, DDC_DVI, 0, 0);
        rdev->i2c_bus[0] = radeon_i2c_create(dev, &i2c, "DVI_DDC");
-
+       /* 0x64 */
        i2c = combios_setup_i2c_bus(rdev, DDC_VGA, 0, 0);
        rdev->i2c_bus[1] = radeon_i2c_create(dev, &i2c, "VGA_DDC");
 
+       /* mm i2c */
        i2c.valid = true;
        i2c.hw_capable = true;
        i2c.mm_i2c = true;
        i2c.i2c_id = 0xa0;
        rdev->i2c_bus[2] = radeon_i2c_create(dev, &i2c, "MM_I2C");
 
-       if (rdev->family == CHIP_RS300 ||
-           rdev->family == CHIP_RS400 ||
-           rdev->family == CHIP_RS480) {
+       if (rdev->family == CHIP_R300 ||
+           rdev->family == CHIP_R350) {
+               /* only 2 sw i2c pads */
+       } else if (rdev->family == CHIP_RS300 ||
+                  rdev->family == CHIP_RS400 ||
+                  rdev->family == CHIP_RS480) {
                u16 offset;
                u8 id, blocks, clk, data;
                int i;
 
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
 
@@ -740,6 +771,7 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
                                if (id == 136) {
                                        clk = RBIOS8(offset + 3 + (i * 5) + 3);
                                        data = RBIOS8(offset + 3 + (i * 5) + 4);
+                                       /* gpiopad */
                                        i2c = combios_setup_i2c_bus(rdev, DDC_MONID,
                                                                    (1 << clk), (1 << data));
                                        rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "GPIOPAD_MASK");
@@ -747,14 +779,15 @@ void radeon_combios_i2c_init(struct radeon_device *rdev)
                                }
                        }
                }
-
-       } else if (rdev->family >= CHIP_R300) {
+       } else if (rdev->family >= CHIP_R200) {
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
        } else {
+               /* 0x68 */
                i2c = combios_setup_i2c_bus(rdev, DDC_MONID, 0, 0);
                rdev->i2c_bus[3] = radeon_i2c_create(dev, &i2c, "MONID");
-
+               /* 0x6c */
                i2c = combios_setup_i2c_bus(rdev, DDC_CRT2, 0, 0);
                rdev->i2c_bus[4] = radeon_i2c_create(dev, &i2c, "CRT2_DDC");
        }
@@ -2504,6 +2537,12 @@ bool radeon_get_legacy_connector_info_from_bios(struct drm_device *dev)
        return true;
 }
 
+static const char *thermal_controller_names[] = {
+       "NONE",
+       "lm63",
+       "adm1032",
+};
+
 void radeon_combios_get_power_modes(struct radeon_device *rdev)
 {
        struct drm_device *dev = rdev->ddev;
@@ -2524,6 +2563,54 @@ void radeon_combios_get_power_modes(struct radeon_device *rdev)
                return;
        }
 
+       /* check for a thermal chip */
+       offset = combios_get_table_offset(dev, COMBIOS_OVERDRIVE_INFO_TABLE);
+       if (offset) {
+               u8 thermal_controller = 0, gpio = 0, i2c_addr = 0, clk_bit = 0, data_bit = 0;
+               struct radeon_i2c_bus_rec i2c_bus;
+
+               rev = RBIOS8(offset);
+
+               if (rev == 0) {
+                       thermal_controller = RBIOS8(offset + 3);
+                       gpio = RBIOS8(offset + 4) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 5);
+               } else if (rev == 1) {
+                       thermal_controller = RBIOS8(offset + 4);
+                       gpio = RBIOS8(offset + 5) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 6);
+               } else if (rev == 2) {
+                       thermal_controller = RBIOS8(offset + 4);
+                       gpio = RBIOS8(offset + 5) & 0x3f;
+                       i2c_addr = RBIOS8(offset + 6);
+                       clk_bit = RBIOS8(offset + 0xa);
+                       data_bit = RBIOS8(offset + 0xb);
+               }
+               if ((thermal_controller > 0) && (thermal_controller < 3)) {
+                       DRM_INFO("Possible %s thermal controller at 0x%02x\n",
+                                thermal_controller_names[thermal_controller],
+                                i2c_addr >> 1);
+                       if (gpio == DDC_LCD) {
+                               /* MM i2c */
+                               i2c_bus.valid = true;
+                               i2c_bus.hw_capable = true;
+                               i2c_bus.mm_i2c = true;
+                               i2c_bus.i2c_id = 0xa0;
+                       } else if (gpio == DDC_GPIO)
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 1 << clk_bit, 1 << data_bit);
+                       else
+                               i2c_bus = combios_setup_i2c_bus(rdev, gpio, 0, 0);
+                       rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus);
+                       if (rdev->pm.i2c_bus) {
+                               struct i2c_board_info info = { };
+                               const char *name = thermal_controller_names[thermal_controller];
+                               info.addr = i2c_addr >> 1;
+                               strlcpy(info.type, name, sizeof(info.type));
+                               i2c_new_device(&rdev->pm.i2c_bus->adapter, &info);
+                       }
+               }
+       }
+
        if (rdev->flags & RADEON_IS_MOBILITY) {
                offset = combios_get_table_offset(dev, COMBIOS_POWERPLAY_INFO_TABLE);
                if (offset) {
index bdbab5c43bdc05f3305155d35303ab1bfdf25a5e..06719340edcb4c87055bb18f652d143d2710ca21 100644 (file)
@@ -1087,8 +1087,9 @@ void radeon_compute_pll_legacy(struct radeon_pll *pll,
        *frac_fb_div_p = best_frac_feedback_div;
        *ref_div_p = best_ref_div;
        *post_div_p = best_post_div;
-       DRM_DEBUG_KMS("%d %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
-                     freq, best_freq / 1000, best_feedback_div, best_frac_feedback_div,
+       DRM_DEBUG_KMS("%lld %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     (long long)freq,
+                     best_freq / 1000, best_feedback_div, best_frac_feedback_div,
                      best_ref_div, best_post_div);
 
 }
index b4274883227fee64e283f39934050cefa6d36cde..99477480b98b3f277977c3849abeff8c6daaf244 100644 (file)
@@ -2116,8 +2116,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
-                       if (ASIC_IS_AVIVO(rdev))
-                               radeon_encoder->underscan_type = UNDERSCAN_AUTO;
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
@@ -2150,8 +2148,6 @@ radeon_add_atom_encoder(struct drm_device *dev,
                } else {
                        drm_encoder_init(dev, encoder, &radeon_atom_enc_funcs, DRM_MODE_ENCODER_TMDS);
                        radeon_encoder->enc_priv = radeon_atombios_set_dig_info(radeon_encoder);
-                       if (ASIC_IS_AVIVO(rdev))
-                               radeon_encoder->underscan_type = UNDERSCAN_AUTO;
                }
                drm_encoder_helper_add(encoder, &radeon_atom_dig_helper_funcs);
                break;
index 983cbac75af0159d493c7b81dbe2da1fd90866e6..781196db792f15ff919df30323cf37c5aca4ab63 100644 (file)
@@ -888,6 +888,7 @@ struct radeon_i2c_chan *radeon_i2c_create(struct drm_device *dev,
 
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
        i2c->dev = dev;
        i2c_set_adapdata(&i2c->adapter, i2c);
        if (rec->mm_i2c ||
@@ -947,6 +948,7 @@ struct radeon_i2c_chan *radeon_i2c_create_dp(struct drm_device *dev,
 
        i2c->rec = *rec;
        i2c->adapter.owner = THIS_MODULE;
+       i2c->adapter.class = I2C_CLASS_DDC;
        i2c->dev = dev;
        snprintf(i2c->adapter.name, sizeof(i2c->adapter.name),
                 "Radeon aux bus %s", name);
index e01cacba685f771f0f82a660b1e1bc21cd0b40e8..f0f244d2943849c1436bbcde741bc3390ebada61 100644 (file)
@@ -215,7 +215,6 @@ static int vga_switchoff(struct vga_switcheroo_client *client)
 /* stage one happens before delay */
 static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
 {
-       int ret;
        int i;
        struct vga_switcheroo_client *active = NULL;
 
@@ -231,11 +230,6 @@ static int vga_switchto_stage1(struct vga_switcheroo_client *new_client)
        if (!active)
                return 0;
 
-       /* power up the first device */
-       ret = pci_enable_device(new_client->pdev);
-       if (ret)
-               return ret;
-
        if (new_client->pwr_state == VGA_SWITCHEROO_OFF)
                vga_switchon(new_client);
 
index be8d4cb5861cbce7999a2c09bc7305c1ba3b558f..8a1021f2e319e1f1918fadd25550bf9e1a7c4b84 100644 (file)
@@ -61,7 +61,7 @@ struct vga_device {
        unsigned int mem_lock_cnt;      /* legacy MEM lock count */
        unsigned int io_norm_cnt;       /* normal IO count */
        unsigned int mem_norm_cnt;      /* normal MEM count */
-
+       bool bridge_has_one_vga;
        /* allow IRQ enable/disable hook */
        void *cookie;
        void (*irq_set_state)(void *cookie, bool enable);
@@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
        unsigned int wants, legacy_wants, match;
        struct vga_device *conflict;
        unsigned int pci_bits;
+       u32 flags = 0;
+
        /* Account for "normal" resources to lock. If we decode the legacy,
         * counterpart, we need to request it as well
         */
@@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
                /* looks like he doesn't have a lock, we can steal
                 * them from him
                 */
-               vga_irq_set_state(conflict, false);
 
+               flags = 0;
                pci_bits = 0;
-               if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-                       pci_bits |= PCI_COMMAND_MEMORY;
-               if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-                       pci_bits |= PCI_COMMAND_IO;
 
-               pci_set_vga_state(conflict->pdev, false, pci_bits,
-                                 change_bridge);
+               if (!conflict->bridge_has_one_vga) {
+                       vga_irq_set_state(conflict, false);
+                       flags |= PCI_VGA_STATE_CHANGE_DECODES;
+                       if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                               pci_bits |= PCI_COMMAND_MEMORY;
+                       if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                               pci_bits |= PCI_COMMAND_IO;
+               }
+
+               if (change_bridge)
+                       flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+               pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
                conflict->owns &= ~lwants;
                /* If he also owned non-legacy, that is no longer the case */
                if (lwants & VGA_RSRC_LEGACY_MEM)
@@ -261,14 +270,24 @@ enable_them:
         * also have in "decodes". We can lock resources we don't decode but
         * not own them.
         */
+       flags = 0;
        pci_bits = 0;
-       if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
-               pci_bits |= PCI_COMMAND_MEMORY;
-       if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
-               pci_bits |= PCI_COMMAND_IO;
-       pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
 
-       vga_irq_set_state(vgadev, true);
+       if (!vgadev->bridge_has_one_vga) {
+               flags |= PCI_VGA_STATE_CHANGE_DECODES;
+               if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
+                       pci_bits |= PCI_COMMAND_MEMORY;
+               if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
+                       pci_bits |= PCI_COMMAND_IO;
+       }
+       if (!!(wants & VGA_RSRC_LEGACY_MASK))
+               flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
+
+       pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
+
+       if (!vgadev->bridge_has_one_vga) {
+               vga_irq_set_state(vgadev, true);
+       }
        vgadev->owns |= (wants & vgadev->decodes);
 lock_them:
        vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
@@ -421,6 +440,62 @@ bail:
 }
 EXPORT_SYMBOL(vga_put);
 
+/* Rules for using a bridge to control a VGA descendant decoding:
+   if a bridge has only one VGA descendant then it can be used
+   to control the VGA routing for that device.
+   It should always use the bridge closest to the device to control it.
+   If a bridge has a direct VGA descendant, but also have a sub-bridge
+   VGA descendant then we cannot use that bridge to control the direct VGA descendant.
+   So for every device we register, we need to iterate all its parent bridges
+   so we can invalidate any devices using them properly.
+*/
+static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
+{
+       struct vga_device *same_bridge_vgadev;
+       struct pci_bus *new_bus, *bus;
+       struct pci_dev *new_bridge, *bridge;
+
+       vgadev->bridge_has_one_vga = true;
+
+       if (list_empty(&vga_list))
+               return;
+
+       /* okay iterate the new devices bridge hierarachy */
+       new_bus = vgadev->pdev->bus;
+       while (new_bus) {
+               new_bridge = new_bus->self;
+
+               if (new_bridge) {
+                       /* go through list of devices already registered */
+                       list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
+                               bus = same_bridge_vgadev->pdev->bus;
+                               bridge = bus->self;
+
+                               /* see if the share a bridge with this device */
+                               if (new_bridge == bridge) {
+                                       /* if their direct parent bridge is the same
+                                          as any bridge of this device then it can't be used
+                                          for that device */
+                                       same_bridge_vgadev->bridge_has_one_vga = false;
+                               }
+
+                               /* now iterate the previous devices bridge hierarchy */
+                               /* if the new devices parent bridge is in the other devices
+                                  hierarchy then we can't use it to control this device */
+                               while (bus) {
+                                       bridge = bus->self;
+                                       if (bridge) {
+                                               if (bridge == vgadev->pdev->bus->self)
+                                                       vgadev->bridge_has_one_vga = false;
+                                       }
+                                       bus = bus->parent;
+                               }
+                       }
+               }
+               new_bus = new_bus->parent;
+       }
+}
+
 /*
  * Currently, we assume that the "initial" setup of the system is
  * not sane, that is we come up with conflicting devices and let
@@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
                vga_default = pci_dev_get(pdev);
 #endif
 
+       vga_arbiter_check_bridge_sharing(vgadev);
+
        /* Add to the list */
        list_add(&vgadev->list, &vga_list);
        vga_count++;
@@ -1222,6 +1299,7 @@ static int __init vga_arb_device_init(void)
 {
        int rc;
        struct pci_dev *pdev;
+       struct vga_device *vgadev;
 
        rc = misc_register(&vga_arb_device);
        if (rc < 0)
@@ -1238,6 +1316,13 @@ static int __init vga_arb_device_init(void)
                vga_arbiter_add_pci_device(pdev);
 
        pr_info("vgaarb: loaded\n");
+
+       list_for_each_entry(vgadev, &vga_list, list) {
+               if (vgadev->bridge_has_one_vga)
+                       pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
+               else
+                       pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
+       }
        return rc;
 }
 subsys_initcall(vga_arb_device_init);
index 2472e7177b4b5af6ddc813913fb193c47fef984d..a339237f4f96b331d707a613499e43d391c8e0de 100644 (file)
@@ -2875,31 +2875,34 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
  * @dev: the PCI device
  * @decode: true = enable decoding, false = disable decoding
  * @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
- * @change_bridge: traverse ancestors and change bridges
+ * @change_bridge_flags: traverse ancestors and change bridges
+ * CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
  */
 int pci_set_vga_state(struct pci_dev *dev, bool decode,
-                     unsigned int command_bits, bool change_bridge)
+                     unsigned int command_bits, u32 flags)
 {
        struct pci_bus *bus;
        struct pci_dev *bridge;
        u16 cmd;
        int rc;
 
-       WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
+       WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
 
        /* ARCH specific VGA enables */
-       rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge);
+       rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
        if (rc)
                return rc;
 
-       pci_read_config_word(dev, PCI_COMMAND, &cmd);
-       if (decode == true)
-               cmd |= command_bits;
-       else
-               cmd &= ~command_bits;
-       pci_write_config_word(dev, PCI_COMMAND, cmd);
+       if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
+               pci_read_config_word(dev, PCI_COMMAND, &cmd);
+               if (decode == true)
+                       cmd |= command_bits;
+               else
+                       cmd &= ~command_bits;
+               pci_write_config_word(dev, PCI_COMMAND, cmd);
+       }
 
-       if (change_bridge == false)
+       if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
                return 0;
 
        bus = dev->bus;
index 0485e394712aa4645cc695230f2dcaaca1664af3..006c6d5c78052a3a6866e3f7e872a0c21cb1b16e 100644 (file)
@@ -753,4 +753,11 @@ config SAMSUNG_LAPTOP
          To compile this driver as a module, choose M here: the module
          will be called samsung-laptop.
 
+config MXM_WMI
+       tristate "WMI support for MXM Laptop Graphics"
+       depends on ACPI_WMI
+       ---help---
+          MXM is a standard for laptop graphics cards, the WMI interface
+         is required for switchable nvidia graphics machines
+
 endif # X86_PLATFORM_DEVICES
index 029e8861d086d19cbc5c28bafb15a449717a0af4..a7ab3bc7b3a182cefb4eefa38f5d0263dfe37a23 100644 (file)
@@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK)      += xo15-ebook.o
 obj-$(CONFIG_IBM_RTL)          += ibm_rtl.o
 obj-$(CONFIG_SAMSUNG_LAPTOP)   += samsung-laptop.o
 obj-$(CONFIG_INTEL_MFLD_THERMAL)       += intel_mid_thermal.o
+obj-$(CONFIG_MXM_WMI)          += mxm-wmi.o
diff --git a/drivers/platform/x86/mxm-wmi.c b/drivers/platform/x86/mxm-wmi.c
new file mode 100644 (file)
index 0000000..0aea63b
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("Dave Airlie");
+MODULE_DESCRIPTION("MXM WMI Driver");
+MODULE_LICENSE("GPL");
+
+#define MXM_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
+MODULE_ALIAS("wmi:"MXM_WMMX_GUID);
+
+#define MXM_WMMX_FUNC_MXDS 0x5344584D /* "MXDS" */
+#define MXM_WMMX_FUNC_MXMX 0x53445344 /* "MXMX" */
+
+struct mxds_args {
+       u32 func;
+       u32 args;
+       u32 xarg;
+};
+
+int mxm_wmi_call_mxds(int adapter)
+{
+       struct mxds_args args = {
+               .func = MXM_WMMX_FUNC_MXDS,
+               .args = 0,
+               .xarg = 1,
+       };
+       struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       printk("calling mux switch %d\n", adapter);
+
+       status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+                                    &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       printk("mux switched %d\n", status);
+       return 0;
+                           
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxds);
+
+int mxm_wmi_call_mxmx(int adapter)
+{
+       struct mxds_args args = {
+               .func = MXM_WMMX_FUNC_MXMX,
+               .args = 0,
+               .xarg = 1,
+       };
+       struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
+       struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
+       acpi_status status;
+
+       printk("calling mux switch %d\n", adapter);
+
+       status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
+                                    &output);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       printk("mux mutex set switched %d\n", status);
+       return 0;
+                           
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_call_mxmx);
+
+bool mxm_wmi_supported(void)
+{
+       bool guid_valid;
+       guid_valid = wmi_has_guid(MXM_WMMX_GUID);
+       return guid_valid;
+}
+EXPORT_SYMBOL_GPL(mxm_wmi_supported);
+
+static int __init mxm_wmi_init(void)
+{
+       return 0;
+}
+
+static void __exit mxm_wmi_exit(void)
+{
+}
+
+module_init(mxm_wmi_init);
+module_exit(mxm_wmi_exit);
index 202424d17ed7c1924ae5d26936369dc110564e44..738b3a5faa1294215479ddf88e99c2c523dfa72c 100644 (file)
@@ -122,10 +122,14 @@ struct drm_device;
  * using the DRM_DEBUG_KMS and DRM_DEBUG.
  */
 
-extern void drm_ut_debug_printk(unsigned int request_level,
+extern __attribute__((format (printf, 4, 5)))
+void drm_ut_debug_printk(unsigned int request_level,
                                const char *prefix,
                                const char *function_name,
                                const char *format, ...);
+extern __attribute__((format (printf, 2, 3)))
+int drm_err(const char *func, const char *format, ...);
+
 /***********************************************************************/
 /** \name DRM template customization defaults */
 /*@{*/
@@ -181,21 +185,11 @@ extern void drm_ut_debug_printk(unsigned int request_level,
  * \param fmt printf() like format string.
  * \param arg arguments
  */
-#define DRM_ERROR(fmt, arg...) \
-       printk(KERN_ERR "[" DRM_NAME ":%s] *ERROR* " fmt , __func__ , ##arg)
-
-/**
- * Memory error output.
- *
- * \param area memory area where the error occurred.
- * \param fmt printf() like format string.
- * \param arg arguments
- */
-#define DRM_MEM_ERROR(area, fmt, arg...) \
-       printk(KERN_ERR "[" DRM_NAME ":%s:%s] *ERROR* " fmt , __func__, \
-              drm_mem_stats[area].name , ##arg)
+#define DRM_ERROR(fmt, ...)                            \
+       drm_err(__func__, fmt, ##__VA_ARGS__)
 
-#define DRM_INFO(fmt, arg...)  printk(KERN_INFO "[" DRM_NAME "] " fmt , ##arg)
+#define DRM_INFO(fmt, ...)                             \
+       printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
 
 /**
  * Debug output.
@@ -1000,6 +994,22 @@ struct drm_minor {
        struct drm_mode_group mode_group;
 };
 
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+
 struct drm_pending_vblank_event {
        struct drm_pending_event base;
        int pipe;
@@ -1395,6 +1405,15 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
                                                 struct drm_crtc *refcrtc);
 extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
 
+extern bool
+drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                         struct drm_connector *connector,
+                                         struct drm_cmdline_mode *mode);
+
+extern struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd);
+
 /* Modesetting support */
 extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
 extern void drm_vblank_post_modeset(struct drm_device *dev, int crtc);
index d94684b7ba3462ab8e62a0460b3ca06bd3fe9662..9573e0ce312080caf9bcbcb72cd804e2ed200871 100644 (file)
@@ -183,7 +183,9 @@ enum subpixel_order {
        SubPixelNone,
 };
 
-
+#define DRM_COLOR_FORMAT_RGB444                (1<<0)
+#define DRM_COLOR_FORMAT_YCRCB444      (1<<1)
+#define DRM_COLOR_FORMAT_YCRCB422      (1<<2)
 /*
  * Describes a given display (e.g. CRT or flat panel) and its limitations.
  */
@@ -198,8 +200,10 @@ struct drm_display_info {
        unsigned int min_vfreq, max_vfreq;
        unsigned int min_hfreq, max_hfreq;
        unsigned int pixel_clock;
+       unsigned int bpc;
 
        enum subpixel_order subpixel_order;
+       u32 color_formats;
 
        char *raw_edid; /* if any */
 };
index 5881fad91faa29ef3d446a75b7e22280ca0dd270..eacb415b309a2c72e20928b4d0faecbff905d132 100644 (file)
@@ -155,12 +155,35 @@ struct detailed_timing {
 #define DRM_EDID_INPUT_SEPARATE_SYNCS  (1 << 3)
 #define DRM_EDID_INPUT_BLANK_TO_BLACK  (1 << 4)
 #define DRM_EDID_INPUT_VIDEO_LEVEL     (3 << 5)
-#define DRM_EDID_INPUT_DIGITAL         (1 << 7) /* bits below must be zero if set */
+#define DRM_EDID_INPUT_DIGITAL         (1 << 7)
+#define DRM_EDID_DIGITAL_DEPTH_MASK    (7 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_UNDEF   (0 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_6       (1 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_8       (2 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_10      (3 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_12      (4 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_14      (5 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_16      (6 << 4)
+#define DRM_EDID_DIGITAL_DEPTH_RSVD    (7 << 4)
+#define DRM_EDID_DIGITAL_TYPE_UNDEF    (0)
+#define DRM_EDID_DIGITAL_TYPE_DVI      (1)
+#define DRM_EDID_DIGITAL_TYPE_HDMI_A   (2)
+#define DRM_EDID_DIGITAL_TYPE_HDMI_B   (3)
+#define DRM_EDID_DIGITAL_TYPE_MDDI     (4)
+#define DRM_EDID_DIGITAL_TYPE_DP       (5)
 
 #define DRM_EDID_FEATURE_DEFAULT_GTF      (1 << 0)
 #define DRM_EDID_FEATURE_PREFERRED_TIMING (1 << 1)
 #define DRM_EDID_FEATURE_STANDARD_COLOR   (1 << 2)
+/* If analog */
 #define DRM_EDID_FEATURE_DISPLAY_TYPE     (3 << 3) /* 00=mono, 01=rgb, 10=non-rgb, 11=unknown */
+/* If digital */
+#define DRM_EDID_FEATURE_COLOR_MASK      (3 << 3)
+#define DRM_EDID_FEATURE_RGB             (0 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB444    (1 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB422    (2 << 3)
+#define DRM_EDID_FEATURE_RGB_YCRCB       (3 << 3) /* both 4:4:4 and 4:2:2 */
+
 #define DRM_EDID_FEATURE_PM_ACTIVE_OFF    (1 << 5)
 #define DRM_EDID_FEATURE_PM_SUSPEND       (1 << 6)
 #define DRM_EDID_FEATURE_PM_STANDBY       (1 << 7)
index ade09d7b427100da6057cb04c7e43d484c84ac25..6e3076ad646e99debaecdc315affe494b52f2f28 100644 (file)
@@ -40,20 +40,6 @@ struct drm_fb_helper_crtc {
        struct drm_display_mode *desired_mode;
 };
 
-/* mode specified on the command line */
-struct drm_fb_helper_cmdline_mode {
-       bool specified;
-       bool refresh_specified;
-       bool bpp_specified;
-       int xres, yres;
-       int bpp;
-       int refresh;
-       bool rb;
-       bool interlace;
-       bool cvt;
-       bool margins;
-};
-
 struct drm_fb_helper_surface_size {
        u32 fb_width;
        u32 fb_height;
@@ -74,8 +60,8 @@ struct drm_fb_helper_funcs {
 };
 
 struct drm_fb_helper_connector {
-       struct drm_fb_helper_cmdline_mode cmdline_mode;
        struct drm_connector *connector;
+       struct drm_cmdline_mode cmdline_mode;
 };
 
 struct drm_fb_helper {
@@ -127,7 +113,7 @@ void drm_fb_helper_fill_fix(struct fb_info *info, uint32_t pitch,
 
 int drm_fb_helper_setcmap(struct fb_cmap *cmap, struct fb_info *info);
 
-bool drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
+int drm_fb_helper_hotplug_event(struct drm_fb_helper *fb_helper);
 bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_debug_enter(struct fb_info *info);
diff --git a/include/linux/mxm-wmi.h b/include/linux/mxm-wmi.h
new file mode 100644 (file)
index 0000000..617a295
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * MXM WMI driver
+ *
+ * Copyright(C) 2010 Red Hat.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef MXM_WMI_H
+#define MXM_WMI_H
+
+/* discrete adapters */
+#define MXM_MXDS_ADAPTER_0 0x0
+#define MXM_MXDS_ADAPTER_1 0x0
+/* integrated adapter */
+#define MXM_MXDS_ADAPTER_IGD 0x10
+int mxm_wmi_call_mxds(int adapter);
+int mxm_wmi_call_mxmx(int adapter);
+bool mxm_wmi_supported(void);
+
+#endif
index 96f70d7e058dd043716ae216e3918567923f28bb..f2e57b2e6a8116dc7da8bdf0200d2a4c067fa6ec 100644 (file)
@@ -915,8 +915,11 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
 int pci_cfg_space_size(struct pci_dev *dev);
 unsigned char pci_bus_max_busnr(struct pci_bus *bus);
 
+#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
+#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
+
 int pci_set_vga_state(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge);
+                     unsigned int command_bits, u32 flags);
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 
 #include <linux/pci-dma.h>
@@ -1061,7 +1064,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 
 /* some architectures require additional setup to direct VGA traffic */
 typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
-                     unsigned int command_bits, bool change_bridge);
+                     unsigned int command_bits, u32 flags);
 extern void pci_register_set_vga_state(arch_set_vga_state_t func);
 
 #else /* CONFIG_PCI is not enabled */