From a3aaf06e79578fd8874fbb47900cd58630f5cc87 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Tue, 22 Feb 2011 02:31:15 +0100 Subject: [PATCH] linux: update nouveau patch Signed-off-by: Stephan Raue --- ...drm_nouveau_upstream-20110111.patch.ignore | 29027 ---------------- ...c5-110-drm_nouveau_upstream-20110222.patch | 4649 +++ 2 files changed, 4649 insertions(+), 29027 deletions(-) delete mode 100644 packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110111.patch.ignore create mode 100644 packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110222.patch diff --git a/packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110111.patch.ignore b/packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110111.patch.ignore deleted file mode 100644 index db7c4af7f5..0000000000 --- a/packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110111.patch.ignore +++ /dev/null @@ -1,29027 +0,0 @@ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/drm_crtc_helper.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/drm_crtc_helper.c ---- linux-2.6.37-rc3/drivers/gpu/drm/drm_crtc_helper.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/drm_crtc_helper.c 2011-01-07 14:22:17.000000000 +0100 -@@ -336,7 +336,7 @@ - struct drm_framebuffer *old_fb) - { - struct drm_device *dev = crtc->dev; -- struct drm_display_mode *adjusted_mode, saved_mode; -+ struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode; - struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; - struct drm_encoder_helper_funcs *encoder_funcs; - int saved_x, saved_y; -@@ -350,6 +350,7 @@ - if (!crtc->enabled) - return true; - -+ saved_hwmode = crtc->hwmode; - saved_mode = crtc->mode; - saved_x = crtc->x; - saved_y = crtc->y; -@@ -427,11 +428,21 @@ - - } - -+ /* Store real post-adjustment hardware mode. */ -+ crtc->hwmode = *adjusted_mode; -+ -+ /* Calculate and store various constants which -+ * are later needed by vblank and swap-completion -+ * timestamping. They are derived from true hwmode. -+ */ -+ drm_calc_timestamping_constants(crtc); -+ - /* XXX free adjustedmode */ - drm_mode_destroy(dev, adjusted_mode); - /* FIXME: add subpixel order */ - done: - if (!ret) { -+ crtc->hwmode = saved_hwmode; - crtc->mode = saved_mode; - crtc->x = saved_x; - crtc->y = saved_y; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/drm_irq.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/drm_irq.c ---- linux-2.6.37-rc3/drivers/gpu/drm/drm_irq.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/drm_irq.c 2011-01-07 14:22:17.000000000 +0100 -@@ -40,6 +40,22 @@ - #include - - #include -+ -+/* Access macro for slots in vblank timestamp ringbuffer. */ -+#define vblanktimestamp(dev, crtc, count) ( \ -+ (dev)->_vblank_time[(crtc) * DRM_VBLANKTIME_RBSIZE + \ -+ ((count) % DRM_VBLANKTIME_RBSIZE)]) -+ -+/* Retry timestamp calculation up to 3 times to satisfy -+ * drm_timestamp_precision before giving up. -+ */ -+#define DRM_TIMESTAMP_MAXRETRIES 3 -+ -+/* Threshold in nanoseconds for detection of redundant -+ * vblank irq in drm_handle_vblank(). 1 msec should be ok. -+ */ -+#define DRM_REDUNDANT_VBLIRQ_THRESH_NS 1000000 -+ - /** - * Get interrupt from bus id. - * -@@ -77,6 +93,87 @@ - return 0; - } - -+/* -+ * Clear vblank timestamp buffer for a crtc. -+ */ -+static void clear_vblank_timestamps(struct drm_device *dev, int crtc) -+{ -+ memset(&dev->_vblank_time[crtc * DRM_VBLANKTIME_RBSIZE], 0, -+ DRM_VBLANKTIME_RBSIZE * sizeof(struct timeval)); -+} -+ -+/* -+ * Disable vblank irq's on crtc, make sure that last vblank count -+ * of hardware and corresponding consistent software vblank counter -+ * are preserved, even if there are any spurious vblank irq's after -+ * disable. -+ */ -+static void vblank_disable_and_save(struct drm_device *dev, int crtc) -+{ -+ unsigned long irqflags; -+ u32 vblcount; -+ s64 diff_ns; -+ int vblrc; -+ struct timeval tvblank; -+ -+ /* Prevent vblank irq processing while disabling vblank irqs, -+ * so no updates of timestamps or count can happen after we've -+ * disabled. Needed to prevent races in case of delayed irq's. -+ * Disable preemption, so vblank_time_lock is held as short as -+ * possible, even under a kernel with PREEMPT_RT patches. -+ */ -+ preempt_disable(); -+ spin_lock_irqsave(&dev->vblank_time_lock, irqflags); -+ -+ dev->driver->disable_vblank(dev, crtc); -+ dev->vblank_enabled[crtc] = 0; -+ -+ /* No further vblank irq's will be processed after -+ * this point. Get current hardware vblank count and -+ * vblank timestamp, repeat until they are consistent. -+ * -+ * FIXME: There is still a race condition here and in -+ * drm_update_vblank_count() which can cause off-by-one -+ * reinitialization of software vblank counter. If gpu -+ * vblank counter doesn't increment exactly at the leading -+ * edge of a vblank interval, then we can lose 1 count if -+ * we happen to execute between start of vblank and the -+ * delayed gpu counter increment. -+ */ -+ do { -+ dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); -+ vblrc = drm_get_last_vbltimestamp(dev, crtc, &tvblank, 0); -+ } while (dev->last_vblank[crtc] != dev->driver->get_vblank_counter(dev, crtc)); -+ -+ /* Compute time difference to stored timestamp of last vblank -+ * as updated by last invocation of drm_handle_vblank() in vblank irq. -+ */ -+ vblcount = atomic_read(&dev->_vblank_count[crtc]); -+ diff_ns = timeval_to_ns(&tvblank) - -+ timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); -+ -+ /* If there is at least 1 msec difference between the last stored -+ * timestamp and tvblank, then we are currently executing our -+ * disable inside a new vblank interval, the tvblank timestamp -+ * corresponds to this new vblank interval and the irq handler -+ * for this vblank didn't run yet and won't run due to our disable. -+ * Therefore we need to do the job of drm_handle_vblank() and -+ * increment the vblank counter by one to account for this vblank. -+ * -+ * Skip this step if there isn't any high precision timestamp -+ * available. In that case we can't account for this and just -+ * hope for the best. -+ */ -+ if ((vblrc > 0) && (abs(diff_ns) > 1000000)) -+ atomic_inc(&dev->_vblank_count[crtc]); -+ -+ /* Invalidate all timestamps while vblank irq's are off. */ -+ clear_vblank_timestamps(dev, crtc); -+ -+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); -+ preempt_enable(); -+} -+ - static void vblank_disable_fn(unsigned long arg) - { - struct drm_device *dev = (struct drm_device *)arg; -@@ -91,10 +188,7 @@ - if (atomic_read(&dev->vblank_refcount[i]) == 0 && - dev->vblank_enabled[i]) { - DRM_DEBUG("disabling vblank on crtc %d\n", i); -- dev->last_vblank[i] = -- dev->driver->get_vblank_counter(dev, i); -- dev->driver->disable_vblank(dev, i); -- dev->vblank_enabled[i] = 0; -+ vblank_disable_and_save(dev, i); - } - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } -@@ -117,6 +211,7 @@ - kfree(dev->last_vblank); - kfree(dev->last_vblank_wait); - kfree(dev->vblank_inmodeset); -+ kfree(dev->_vblank_time); - - dev->num_crtcs = 0; - } -@@ -129,6 +224,8 @@ - setup_timer(&dev->vblank_disable_timer, vblank_disable_fn, - (unsigned long)dev); - spin_lock_init(&dev->vbl_lock); -+ spin_lock_init(&dev->vblank_time_lock); -+ - dev->num_crtcs = num_crtcs; - - dev->vbl_queue = kmalloc(sizeof(wait_queue_head_t) * num_crtcs, -@@ -161,6 +258,19 @@ - if (!dev->vblank_inmodeset) - goto err; - -+ dev->_vblank_time = kcalloc(num_crtcs * DRM_VBLANKTIME_RBSIZE, -+ sizeof(struct timeval), GFP_KERNEL); -+ if (!dev->_vblank_time) -+ goto err; -+ -+ DRM_INFO("Supports vblank timestamp caching Rev 1 (10.10.2010).\n"); -+ -+ /* Driver specific high-precision vblank timestamping supported? */ -+ if (dev->driver->get_vblank_timestamp) -+ DRM_INFO("Driver supports precise vblank timestamp query.\n"); -+ else -+ DRM_INFO("No driver support for vblank timestamp query.\n"); -+ - /* Zero per-crtc vblank stuff */ - for (i = 0; i < num_crtcs; i++) { - init_waitqueue_head(&dev->vbl_queue[i]); -@@ -279,7 +389,7 @@ - * - * Calls the driver's \c drm_driver_irq_uninstall() function, and stops the irq. - */ --int drm_irq_uninstall(struct drm_device * dev) -+int drm_irq_uninstall(struct drm_device *dev) - { - unsigned long irqflags; - int irq_enabled, i; -@@ -335,7 +445,9 @@ - { - struct drm_control *ctl = data; - -- /* if we haven't irq we fallback for compatibility reasons - this used to be a separate function in drm_dma.h */ -+ /* if we haven't irq we fallback for compatibility reasons - -+ * this used to be a separate function in drm_dma.h -+ */ - - - switch (ctl->func) { -@@ -360,6 +472,287 @@ - } - - /** -+ * drm_calc_timestamping_constants - Calculate and -+ * store various constants which are later needed by -+ * vblank and swap-completion timestamping, e.g, by -+ * drm_calc_vbltimestamp_from_scanoutpos(). -+ * They are derived from crtc's true scanout timing, -+ * so they take things like panel scaling or other -+ * adjustments into account. -+ * -+ * @crtc drm_crtc whose timestamp constants should be updated. -+ * -+ */ -+void drm_calc_timestamping_constants(struct drm_crtc *crtc) -+{ -+ s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0; -+ u64 dotclock; -+ -+ /* Dot clock in Hz: */ -+ dotclock = (u64) crtc->hwmode.clock * 1000; -+ -+ /* Valid dotclock? */ -+ if (dotclock > 0) { -+ /* Convert scanline length in pixels and video dot clock to -+ * line duration, frame duration and pixel duration in -+ * nanoseconds: -+ */ -+ pixeldur_ns = (s64) div64_u64(1000000000, dotclock); -+ linedur_ns = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal * -+ 1000000000), dotclock); -+ framedur_ns = (s64) crtc->hwmode.crtc_vtotal * linedur_ns; -+ } else -+ DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n", -+ crtc->base.id); -+ -+ crtc->pixeldur_ns = pixeldur_ns; -+ crtc->linedur_ns = linedur_ns; -+ crtc->framedur_ns = framedur_ns; -+ -+ DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n", -+ crtc->base.id, crtc->hwmode.crtc_htotal, -+ crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay); -+ DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n", -+ crtc->base.id, (int) dotclock/1000, (int) framedur_ns, -+ (int) linedur_ns, (int) pixeldur_ns); -+} -+EXPORT_SYMBOL(drm_calc_timestamping_constants); -+ -+/** -+ * drm_calc_vbltimestamp_from_scanoutpos - helper routine for kms -+ * drivers. Implements calculation of exact vblank timestamps from -+ * given drm_display_mode timings and current video scanout position -+ * of a crtc. This can be called from within get_vblank_timestamp() -+ * implementation of a kms driver to implement the actual timestamping. -+ * -+ * Should return timestamps conforming to the OML_sync_control OpenML -+ * extension specification. The timestamp corresponds to the end of -+ * the vblank interval, aka start of scanout of topmost-leftmost display -+ * pixel in the following video frame. -+ * -+ * Requires support for optional dev->driver->get_scanout_position() -+ * in kms driver, plus a bit of setup code to provide a drm_display_mode -+ * that corresponds to the true scanout timing. -+ * -+ * The current implementation only handles standard video modes. It -+ * returns as no operation if a doublescan or interlaced video mode is -+ * active. Higher level code is expected to handle this. -+ * -+ * @dev: DRM device. -+ * @crtc: Which crtc's vblank timestamp to retrieve. -+ * @max_error: Desired maximum allowable error in timestamps (nanosecs). -+ * On return contains true maximum error of timestamp. -+ * @vblank_time: Pointer to struct timeval which should receive the timestamp. -+ * @flags: Flags to pass to driver: -+ * 0 = Default. -+ * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. -+ * @refcrtc: drm_crtc* of crtc which defines scanout timing. -+ * -+ * Returns negative value on error, failure or if not supported in current -+ * video mode: -+ * -+ * -EINVAL - Invalid crtc. -+ * -EAGAIN - Temporary unavailable, e.g., called before initial modeset. -+ * -ENOTSUPP - Function not supported in current display mode. -+ * -EIO - Failed, e.g., due to failed scanout position query. -+ * -+ * Returns or'ed positive status flags on success: -+ * -+ * DRM_VBLANKTIME_SCANOUTPOS_METHOD - Signal this method used for timestamping. -+ * DRM_VBLANKTIME_INVBL - Timestamp taken while scanout was in vblank interval. -+ * -+ */ -+int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc, -+ int *max_error, -+ struct timeval *vblank_time, -+ unsigned flags, -+ struct drm_crtc *refcrtc) -+{ -+ struct timeval stime, raw_time; -+ struct drm_display_mode *mode; -+ int vbl_status, vtotal, vdisplay; -+ int vpos, hpos, i; -+ s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns; -+ bool invbl; -+ -+ if (crtc < 0 || crtc >= dev->num_crtcs) { -+ DRM_ERROR("Invalid crtc %d\n", crtc); -+ return -EINVAL; -+ } -+ -+ /* Scanout position query not supported? Should not happen. */ -+ if (!dev->driver->get_scanout_position) { -+ DRM_ERROR("Called from driver w/o get_scanout_position()!?\n"); -+ return -EIO; -+ } -+ -+ mode = &refcrtc->hwmode; -+ vtotal = mode->crtc_vtotal; -+ vdisplay = mode->crtc_vdisplay; -+ -+ /* Durations of frames, lines, pixels in nanoseconds. */ -+ framedur_ns = refcrtc->framedur_ns; -+ linedur_ns = refcrtc->linedur_ns; -+ pixeldur_ns = refcrtc->pixeldur_ns; -+ -+ /* If mode timing undefined, just return as no-op: -+ * Happens during initial modesetting of a crtc. -+ */ -+ if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) { -+ DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc); -+ return -EAGAIN; -+ } -+ -+ /* Don't know yet how to handle interlaced or -+ * double scan modes. Just no-op for now. -+ */ -+ if (mode->flags & (DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLSCAN)) { -+ DRM_DEBUG("crtc %d: Noop due to unsupported mode.\n", crtc); -+ return -ENOTSUPP; -+ } -+ -+ /* Get current scanout position with system timestamp. -+ * Repeat query up to DRM_TIMESTAMP_MAXRETRIES times -+ * if single query takes longer than max_error nanoseconds. -+ * -+ * This guarantees a tight bound on maximum error if -+ * code gets preempted or delayed for some reason. -+ */ -+ for (i = 0; i < DRM_TIMESTAMP_MAXRETRIES; i++) { -+ /* Disable preemption to make it very likely to -+ * succeed in the first iteration even on PREEMPT_RT kernel. -+ */ -+ preempt_disable(); -+ -+ /* Get system timestamp before query. */ -+ do_gettimeofday(&stime); -+ -+ /* Get vertical and horizontal scanout pos. vpos, hpos. */ -+ vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos, &hpos); -+ -+ /* Get system timestamp after query. */ -+ do_gettimeofday(&raw_time); -+ -+ preempt_enable(); -+ -+ /* Return as no-op if scanout query unsupported or failed. */ -+ if (!(vbl_status & DRM_SCANOUTPOS_VALID)) { -+ DRM_DEBUG("crtc %d : scanoutpos query failed [%d].\n", -+ crtc, vbl_status); -+ return -EIO; -+ } -+ -+ duration_ns = timeval_to_ns(&raw_time) - timeval_to_ns(&stime); -+ -+ /* Accept result with < max_error nsecs timing uncertainty. */ -+ if (duration_ns <= (s64) *max_error) -+ break; -+ } -+ -+ /* Noisy system timing? */ -+ if (i == DRM_TIMESTAMP_MAXRETRIES) { -+ DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n", -+ crtc, (int) duration_ns/1000, *max_error/1000, i); -+ } -+ -+ /* Return upper bound of timestamp precision error. */ -+ *max_error = (int) duration_ns; -+ -+ /* Check if in vblank area: -+ * vpos is >=0 in video scanout area, but negative -+ * within vblank area, counting down the number of lines until -+ * start of scanout. -+ */ -+ invbl = vbl_status & DRM_SCANOUTPOS_INVBL; -+ -+ /* Convert scanout position into elapsed time at raw_time query -+ * since start of scanout at first display scanline. delta_ns -+ * can be negative if start of scanout hasn't happened yet. -+ */ -+ delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns; -+ -+ /* Is vpos outside nominal vblank area, but less than -+ * 1/100 of a frame height away from start of vblank? -+ * If so, assume this isn't a massively delayed vblank -+ * interrupt, but a vblank interrupt that fired a few -+ * microseconds before true start of vblank. Compensate -+ * by adding a full frame duration to the final timestamp. -+ * Happens, e.g., on ATI R500, R600. -+ * -+ * We only do this if DRM_CALLED_FROM_VBLIRQ. -+ */ -+ if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl && -+ ((vdisplay - vpos) < vtotal / 100)) { -+ delta_ns = delta_ns - framedur_ns; -+ -+ /* Signal this correction as "applied". */ -+ vbl_status |= 0x8; -+ } -+ -+ /* Subtract time delta from raw timestamp to get final -+ * vblank_time timestamp for end of vblank. -+ */ -+ *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); -+ -+ vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD; -+ if (invbl) -+ vbl_status |= DRM_VBLANKTIME_INVBL; -+ -+ return vbl_status; -+} -+EXPORT_SYMBOL(drm_calc_vbltimestamp_from_scanoutpos); -+ -+/** -+ * drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent -+ * vblank interval. -+ * -+ * @dev: DRM device -+ * @crtc: which crtc's vblank timestamp to retrieve -+ * @tvblank: Pointer to target struct timeval which should receive the timestamp -+ * @flags: Flags to pass to driver: -+ * 0 = Default. -+ * DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler. -+ * -+ * Fetches the system timestamp corresponding to the time of the most recent -+ * vblank interval on specified crtc. May call into kms-driver to -+ * compute the timestamp with a high-precision GPU specific method. -+ * -+ * Returns zero if timestamp originates from uncorrected do_gettimeofday() -+ * call, i.e., it isn't very precisely locked to the true vblank. -+ * -+ * Returns non-zero if timestamp is considered to be very precise. -+ */ -+u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, -+ struct timeval *tvblank, unsigned flags) -+{ -+ int ret = 0; -+ -+ /* Define requested maximum error on timestamps (nanoseconds). */ -+ int max_error = (int) drm_timestamp_precision * 1000; -+ -+ /* Query driver if possible and precision timestamping enabled. */ -+ if (dev->driver->get_vblank_timestamp && (max_error > 0)) { -+ ret = dev->driver->get_vblank_timestamp(dev, crtc, &max_error, -+ tvblank, flags); -+ if (ret > 0) -+ return (u32) ret; -+ } -+ -+ /* GPU high precision timestamp query unsupported or failed. -+ * Return gettimeofday timestamp as best estimate. -+ */ -+ do_gettimeofday(tvblank); -+ -+ return 0; -+} -+EXPORT_SYMBOL(drm_get_last_vbltimestamp); -+ -+/** - * drm_vblank_count - retrieve "cooked" vblank counter value - * @dev: DRM device - * @crtc: which counter to retrieve -@@ -375,6 +768,40 @@ - EXPORT_SYMBOL(drm_vblank_count); - - /** -+ * drm_vblank_count_and_time - retrieve "cooked" vblank counter value -+ * and the system timestamp corresponding to that vblank counter value. -+ * -+ * @dev: DRM device -+ * @crtc: which counter to retrieve -+ * @vblanktime: Pointer to struct timeval to receive the vblank timestamp. -+ * -+ * Fetches the "cooked" vblank count value that represents the number of -+ * vblank events since the system was booted, including lost events due to -+ * modesetting activity. Returns corresponding system timestamp of the time -+ * of the vblank interval that corresponds to the current value vblank counter -+ * value. -+ */ -+u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, -+ struct timeval *vblanktime) -+{ -+ u32 cur_vblank; -+ -+ /* Read timestamp from slot of _vblank_time ringbuffer -+ * that corresponds to current vblank count. Retry if -+ * count has incremented during readout. This works like -+ * a seqlock. -+ */ -+ do { -+ cur_vblank = atomic_read(&dev->_vblank_count[crtc]); -+ *vblanktime = vblanktimestamp(dev, crtc, cur_vblank); -+ smp_rmb(); -+ } while (cur_vblank != atomic_read(&dev->_vblank_count[crtc])); -+ -+ return cur_vblank; -+} -+EXPORT_SYMBOL(drm_vblank_count_and_time); -+ -+/** - * drm_update_vblank_count - update the master vblank counter - * @dev: DRM device - * @crtc: counter to update -@@ -392,7 +819,8 @@ - */ - static void drm_update_vblank_count(struct drm_device *dev, int crtc) - { -- u32 cur_vblank, diff; -+ u32 cur_vblank, diff, tslot, rc; -+ struct timeval t_vblank; - - /* - * Interrupts were disabled prior to this call, so deal with counter -@@ -400,8 +828,18 @@ - * NOTE! It's possible we lost a full dev->max_vblank_count events - * here if the register is small or we had vblank interrupts off for - * a long time. -+ * -+ * We repeat the hardware vblank counter & timestamp query until -+ * we get consistent results. This to prevent races between gpu -+ * updating its hardware counter while we are retrieving the -+ * corresponding vblank timestamp. - */ -- cur_vblank = dev->driver->get_vblank_counter(dev, crtc); -+ do { -+ cur_vblank = dev->driver->get_vblank_counter(dev, crtc); -+ rc = drm_get_last_vbltimestamp(dev, crtc, &t_vblank, 0); -+ } while (cur_vblank != dev->driver->get_vblank_counter(dev, crtc)); -+ -+ /* Deal with counter wrap */ - diff = cur_vblank - dev->last_vblank[crtc]; - if (cur_vblank < dev->last_vblank[crtc]) { - diff += dev->max_vblank_count; -@@ -413,6 +851,16 @@ - DRM_DEBUG("enabling vblank interrupts on crtc %d, missed %d\n", - crtc, diff); - -+ /* Reinitialize corresponding vblank timestamp if high-precision query -+ * available. Skip this step if query unsupported or failed. Will -+ * reinitialize delayed at next vblank interrupt in that case. -+ */ -+ if (rc) { -+ tslot = atomic_read(&dev->_vblank_count[crtc]) + diff; -+ vblanktimestamp(dev, crtc, tslot) = t_vblank; -+ smp_wmb(); -+ } -+ - atomic_add(diff, &dev->_vblank_count[crtc]); - } - -@@ -429,15 +877,27 @@ - */ - int drm_vblank_get(struct drm_device *dev, int crtc) - { -- unsigned long irqflags; -+ unsigned long irqflags, irqflags2; - int ret = 0; - - spin_lock_irqsave(&dev->vbl_lock, irqflags); - /* Going from 0->1 means we have to enable interrupts again */ - if (atomic_add_return(1, &dev->vblank_refcount[crtc]) == 1) { -+ /* Disable preemption while holding vblank_time_lock. Do -+ * it explicitely to guard against PREEMPT_RT kernel. -+ */ -+ preempt_disable(); -+ spin_lock_irqsave(&dev->vblank_time_lock, irqflags2); - if (!dev->vblank_enabled[crtc]) { -+ /* Enable vblank irqs under vblank_time_lock protection. -+ * All vblank count & timestamp updates are held off -+ * until we are done reinitializing master counter and -+ * timestamps. Filtercode in drm_handle_vblank() will -+ * prevent double-accounting of same vblank interval. -+ */ - ret = dev->driver->enable_vblank(dev, crtc); -- DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", crtc, ret); -+ DRM_DEBUG("enabling vblank on crtc %d, ret: %d\n", -+ crtc, ret); - if (ret) - atomic_dec(&dev->vblank_refcount[crtc]); - else { -@@ -445,6 +905,8 @@ - drm_update_vblank_count(dev, crtc); - } - } -+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags2); -+ preempt_enable(); - } else { - if (!dev->vblank_enabled[crtc]) { - atomic_dec(&dev->vblank_refcount[crtc]); -@@ -463,15 +925,17 @@ - * @crtc: which counter to give up - * - * Release ownership of a given vblank counter, turning off interrupts -- * if possible. -+ * if possible. Disable interrupts after drm_vblank_offdelay milliseconds. - */ - void drm_vblank_put(struct drm_device *dev, int crtc) - { -- BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0); -+ BUG_ON(atomic_read(&dev->vblank_refcount[crtc]) == 0); - - /* Last user schedules interrupt disable */ -- if (atomic_dec_and_test(&dev->vblank_refcount[crtc])) -- mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ); -+ if (atomic_dec_and_test(&dev->vblank_refcount[crtc]) && -+ (drm_vblank_offdelay > 0)) -+ mod_timer(&dev->vblank_disable_timer, -+ jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000)); - } - EXPORT_SYMBOL(drm_vblank_put); - -@@ -480,10 +944,8 @@ - unsigned long irqflags; - - spin_lock_irqsave(&dev->vbl_lock, irqflags); -- dev->driver->disable_vblank(dev, crtc); -+ vblank_disable_and_save(dev, crtc); - DRM_WAKEUP(&dev->vbl_queue[crtc]); -- dev->vblank_enabled[crtc] = 0; -- dev->last_vblank[crtc] = dev->driver->get_vblank_counter(dev, crtc); - spin_unlock_irqrestore(&dev->vbl_lock, irqflags); - } - EXPORT_SYMBOL(drm_vblank_off); -@@ -599,7 +1061,6 @@ - e->base.file_priv = file_priv; - e->base.destroy = (void (*) (struct drm_pending_event *)) kfree; - -- do_gettimeofday(&now); - spin_lock_irqsave(&dev->event_lock, flags); - - if (file_priv->event_space < sizeof e->event) { -@@ -609,7 +1070,8 @@ - } - - file_priv->event_space -= sizeof e->event; -- seq = drm_vblank_count(dev, pipe); -+ seq = drm_vblank_count_and_time(dev, pipe, &now); -+ - if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) && - (seq - vblwait->request.sequence) <= (1 << 23)) { - vblwait->request.sequence = seq + 1; -@@ -718,11 +1180,10 @@ - if (ret != -EINTR) { - struct timeval now; - -- do_gettimeofday(&now); -- -+ vblwait->reply.sequence = drm_vblank_count_and_time(dev, crtc, &now); - vblwait->reply.tval_sec = now.tv_sec; - vblwait->reply.tval_usec = now.tv_usec; -- vblwait->reply.sequence = drm_vblank_count(dev, crtc); -+ - DRM_DEBUG("returning %d to client\n", - vblwait->reply.sequence); - } else { -@@ -741,8 +1202,7 @@ - unsigned long flags; - unsigned int seq; - -- do_gettimeofday(&now); -- seq = drm_vblank_count(dev, crtc); -+ seq = drm_vblank_count_and_time(dev, crtc, &now); - - spin_lock_irqsave(&dev->event_lock, flags); - -@@ -780,11 +1240,64 @@ - */ - void drm_handle_vblank(struct drm_device *dev, int crtc) - { -+ u32 vblcount; -+ s64 diff_ns; -+ struct timeval tvblank; -+ unsigned long irqflags; -+ - if (!dev->num_crtcs) - return; - -- atomic_inc(&dev->_vblank_count[crtc]); -+ /* Need timestamp lock to prevent concurrent execution with -+ * vblank enable/disable, as this would cause inconsistent -+ * or corrupted timestamps and vblank counts. -+ */ -+ spin_lock_irqsave(&dev->vblank_time_lock, irqflags); -+ -+ /* Vblank irq handling disabled. Nothing to do. */ -+ if (!dev->vblank_enabled[crtc]) { -+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); -+ return; -+ } -+ -+ /* Fetch corresponding timestamp for this vblank interval from -+ * driver and store it in proper slot of timestamp ringbuffer. -+ */ -+ -+ /* Get current timestamp and count. */ -+ vblcount = atomic_read(&dev->_vblank_count[crtc]); -+ drm_get_last_vbltimestamp(dev, crtc, &tvblank, DRM_CALLED_FROM_VBLIRQ); -+ -+ /* Compute time difference to timestamp of last vblank */ -+ diff_ns = timeval_to_ns(&tvblank) - -+ timeval_to_ns(&vblanktimestamp(dev, crtc, vblcount)); -+ -+ /* Update vblank timestamp and count if at least -+ * DRM_REDUNDANT_VBLIRQ_THRESH_NS nanoseconds -+ * difference between last stored timestamp and current -+ * timestamp. A smaller difference means basically -+ * identical timestamps. Happens if this vblank has -+ * been already processed and this is a redundant call, -+ * e.g., due to spurious vblank interrupts. We need to -+ * ignore those for accounting. -+ */ -+ if (abs(diff_ns) > DRM_REDUNDANT_VBLIRQ_THRESH_NS) { -+ /* Store new timestamp in ringbuffer. */ -+ vblanktimestamp(dev, crtc, vblcount + 1) = tvblank; -+ smp_wmb(); -+ -+ /* Increment cooked vblank count. This also atomically commits -+ * the timestamp computed above. -+ */ -+ atomic_inc(&dev->_vblank_count[crtc]); -+ } else { -+ DRM_DEBUG("crtc %d: Redundant vblirq ignored. diff_ns = %d\n", -+ crtc, (int) diff_ns); -+ } -+ - DRM_WAKEUP(&dev->vbl_queue[crtc]); - drm_handle_vblank_events(dev, crtc); -+ -+ spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags); - } - EXPORT_SYMBOL(drm_handle_vblank); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/drm_stub.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/drm_stub.c ---- linux-2.6.37-rc3/drivers/gpu/drm/drm_stub.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/drm_stub.c 2011-01-07 14:22:17.000000000 +0100 -@@ -40,12 +40,22 @@ - unsigned int drm_debug = 0; /* 1 to enable debug output */ - EXPORT_SYMBOL(drm_debug); - -+unsigned int drm_vblank_offdelay = 5000; /* Default to 5000 msecs. */ -+EXPORT_SYMBOL(drm_vblank_offdelay); -+ -+unsigned int drm_timestamp_precision = 20; /* Default to 20 usecs. */ -+EXPORT_SYMBOL(drm_timestamp_precision); -+ - MODULE_AUTHOR(CORE_AUTHOR); - MODULE_DESCRIPTION(CORE_DESC); - MODULE_LICENSE("GPL and additional rights"); - MODULE_PARM_DESC(debug, "Enable debug output"); -+MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs]"); -+MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]"); - - module_param_named(debug, drm_debug, int, 0600); -+module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600); -+module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600); - - struct idr drm_minors_idr; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/Kconfig linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/Kconfig ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/Kconfig 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/Kconfig 2011-01-07 14:22:17.000000000 +0100 -@@ -10,7 +10,7 @@ - select FB - select FRAMEBUFFER_CONSOLE if !EMBEDDED - select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT -- select ACPI_VIDEO if ACPI -+ select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT - help - Choose this option for open-source nVidia support. - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/Makefile linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/Makefile ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/Makefile 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/Makefile 2011-01-07 14:22:17.000000000 +0100 -@@ -5,27 +5,32 @@ - ccflags-y := -Iinclude/drm - nouveau-y := nouveau_drv.o nouveau_state.o nouveau_channel.o nouveau_mem.o \ - nouveau_object.o nouveau_irq.o nouveau_notifier.o \ -- nouveau_sgdma.o nouveau_dma.o \ -+ nouveau_sgdma.o nouveau_dma.o nouveau_util.o \ - nouveau_bo.o nouveau_fence.o nouveau_gem.o nouveau_ttm.o \ - nouveau_hw.o nouveau_calc.o nouveau_bios.o nouveau_i2c.o \ - nouveau_display.o nouveau_connector.o nouveau_fbcon.o \ - nouveau_dp.o nouveau_ramht.o \ - nouveau_pm.o nouveau_volt.o nouveau_perf.o nouveau_temp.o \ -+ nouveau_mm.o nouveau_vm.o \ - nv04_timer.o \ - nv04_mc.o nv40_mc.o nv50_mc.o \ - nv04_fb.o nv10_fb.o nv30_fb.o nv40_fb.o nv50_fb.o nvc0_fb.o \ - nv04_fifo.o nv10_fifo.o nv40_fifo.o nv50_fifo.o nvc0_fifo.o \ - nv04_graph.o nv10_graph.o nv20_graph.o \ - nv40_graph.o nv50_graph.o nvc0_graph.o \ -- nv40_grctx.o nv50_grctx.o \ -+ nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ -+ nv84_crypt.o \ - nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ -- nv50_crtc.o nv50_dac.o nv50_sor.o \ -- nv50_cursor.o nv50_display.o nv50_fbcon.o \ -+ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ -+ nv50_cursor.o nv50_display.o \ - nv04_dac.o nv04_dfp.o nv04_tv.o nv17_tv.o nv17_tv_modes.o \ -- nv04_crtc.o nv04_display.o nv04_cursor.o nv04_fbcon.o \ -+ nv04_crtc.o nv04_display.o nv04_cursor.o \ -+ nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o \ - nv10_gpio.o nv50_gpio.o \ - nv50_calc.o \ -- nv04_pm.o nv50_pm.o nva3_pm.o -+ nv04_pm.o nv50_pm.o nva3_pm.o \ -+ nv50_vram.o nvc0_vram.o \ -+ nv50_vm.o nvc0_vm.o - - nouveau-$(CONFIG_DRM_NOUVEAU_DEBUG) += nouveau_debugfs.o - nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_bios.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_bios.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_bios.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-01-07 14:22:17.000000000 +0100 -@@ -6053,52 +6053,17 @@ - return entry; - } - --static void fabricate_vga_output(struct dcb_table *dcb, int i2c, int heads) -+static void fabricate_dcb_output(struct dcb_table *dcb, int type, int i2c, -+ int heads, int or) - { - struct dcb_entry *entry = new_dcb_entry(dcb); - -- entry->type = 0; -+ entry->type = type; - entry->i2c_index = i2c; - entry->heads = heads; -- entry->location = DCB_LOC_ON_CHIP; -- entry->or = 1; --} -- --static void fabricate_dvi_i_output(struct dcb_table *dcb, bool twoHeads) --{ -- struct dcb_entry *entry = new_dcb_entry(dcb); -- -- entry->type = 2; -- entry->i2c_index = LEGACY_I2C_PANEL; -- entry->heads = twoHeads ? 3 : 1; -- entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */ -- entry->or = 1; /* means |0x10 gets set on CRE_LCD__INDEX */ -- entry->duallink_possible = false; /* SiI164 and co. are single link */ -- --#if 0 -- /* -- * For dvi-a either crtc probably works, but my card appears to only -- * support dvi-d. "nvidia" still attempts to program it for dvi-a, -- * doing the full fp output setup (program 0x6808.. fp dimension regs, -- * setting 0x680848 to 0x10000111 to enable, maybe setting 0x680880); -- * the monitor picks up the mode res ok and lights up, but no pixel -- * data appears, so the board manufacturer probably connected up the -- * sync lines, but missed the video traces / components -- * -- * with this introduction, dvi-a left as an exercise for the reader. -- */ -- fabricate_vga_output(dcb, LEGACY_I2C_PANEL, entry->heads); --#endif --} -- --static void fabricate_tv_output(struct dcb_table *dcb, bool twoHeads) --{ -- struct dcb_entry *entry = new_dcb_entry(dcb); -- -- entry->type = 1; -- entry->i2c_index = LEGACY_I2C_TV; -- entry->heads = twoHeads ? 3 : 1; -- entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */ -+ if (type != OUTPUT_ANALOG) -+ entry->location = !DCB_LOC_ON_CHIP; /* ie OFF CHIP */ -+ entry->or = or; - } - - static bool -@@ -6365,8 +6330,36 @@ - return true; - } - -+static void -+fabricate_dcb_encoder_table(struct drm_device *dev, struct nvbios *bios) -+{ -+ struct dcb_table *dcb = &bios->dcb; -+ int all_heads = (nv_two_heads(dev) ? 3 : 1); -+ -+#ifdef __powerpc__ -+ /* Apple iMac G4 NV17 */ -+ if (of_machine_is_compatible("PowerMac4,5")) { -+ fabricate_dcb_output(dcb, OUTPUT_TMDS, 0, all_heads, 1); -+ fabricate_dcb_output(dcb, OUTPUT_ANALOG, 1, all_heads, 2); -+ return; -+ } -+#endif -+ -+ /* Make up some sane defaults */ -+ fabricate_dcb_output(dcb, OUTPUT_ANALOG, LEGACY_I2C_CRT, 1, 1); -+ -+ if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) -+ fabricate_dcb_output(dcb, OUTPUT_TV, LEGACY_I2C_TV, -+ all_heads, 0); -+ -+ else if (bios->tmds.output0_script_ptr || -+ bios->tmds.output1_script_ptr) -+ fabricate_dcb_output(dcb, OUTPUT_TMDS, LEGACY_I2C_PANEL, -+ all_heads, 1); -+} -+ - static int --parse_dcb_table(struct drm_device *dev, struct nvbios *bios, bool twoHeads) -+parse_dcb_table(struct drm_device *dev, struct nvbios *bios) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct dcb_table *dcb = &bios->dcb; -@@ -6386,12 +6379,7 @@ - - /* this situation likely means a really old card, pre DCB */ - if (dcbptr == 0x0) { -- NV_INFO(dev, "Assuming a CRT output exists\n"); -- fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1); -- -- if (nv04_tv_identify(dev, bios->legacy.i2c_indices.tv) >= 0) -- fabricate_tv_output(dcb, twoHeads); -- -+ fabricate_dcb_encoder_table(dev, bios); - return 0; - } - -@@ -6451,21 +6439,7 @@ - */ - NV_TRACEWARN(dev, "No useful information in BIOS output table; " - "adding all possible outputs\n"); -- fabricate_vga_output(dcb, LEGACY_I2C_CRT, 1); -- -- /* -- * Attempt to detect TV before DVI because the test -- * for the former is more accurate and it rules the -- * latter out. -- */ -- if (nv04_tv_identify(dev, -- bios->legacy.i2c_indices.tv) >= 0) -- fabricate_tv_output(dcb, twoHeads); -- -- else if (bios->tmds.output0_script_ptr || -- bios->tmds.output1_script_ptr) -- fabricate_dvi_i_output(dcb, twoHeads); -- -+ fabricate_dcb_encoder_table(dev, bios); - return 0; - } - -@@ -6859,7 +6833,7 @@ - if (ret) - return ret; - -- ret = parse_dcb_table(dev, bios, nv_two_heads(dev)); -+ ret = parse_dcb_table(dev, bios); - if (ret) - return ret; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_bo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_bo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_bo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_bo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -32,6 +32,8 @@ - #include "nouveau_drm.h" - #include "nouveau_drv.h" - #include "nouveau_dma.h" -+#include "nouveau_mm.h" -+#include "nouveau_vm.h" - - #include - #include -@@ -46,82 +48,51 @@ - if (unlikely(nvbo->gem)) - DRM_ERROR("bo %p still attached to GEM object\n", bo); - -- if (nvbo->tile) -- nv10_mem_expire_tiling(dev, nvbo->tile, NULL); -- -+ nv10_mem_put_tile_region(dev, nvbo->tile, NULL); -+ nouveau_vm_put(&nvbo->vma); - kfree(nvbo); - } - - static void --nouveau_bo_fixup_align(struct drm_device *dev, -- uint32_t tile_mode, uint32_t tile_flags, -- int *align, int *size) -+nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, int *size, -+ int *page_shift) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- -- /* -- * Some of the tile_flags have a periodic structure of N*4096 bytes, -- * align to to that as well as the page size. Align the size to the -- * appropriate boundaries. This does imply that sizes are rounded up -- * 3-7 pages, so be aware of this and do not waste memory by allocating -- * many small buffers. -- */ -- if (dev_priv->card_type == NV_50) { -- uint32_t block_size = dev_priv->vram_size >> 15; -- int i; -- -- switch (tile_flags) { -- case 0x1800: -- case 0x2800: -- case 0x4800: -- case 0x7a00: -- if (is_power_of_2(block_size)) { -- for (i = 1; i < 10; i++) { -- *align = 12 * i * block_size; -- if (!(*align % 65536)) -- break; -- } -- } else { -- for (i = 1; i < 10; i++) { -- *align = 8 * i * block_size; -- if (!(*align % 65536)) -- break; -- } -- } -- *size = roundup(*size, *align); -- break; -- default: -- break; -- } -+ struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); - -- } else { -- if (tile_mode) { -+ if (dev_priv->card_type < NV_50) { -+ if (nvbo->tile_mode) { - if (dev_priv->chipset >= 0x40) { - *align = 65536; -- *size = roundup(*size, 64 * tile_mode); -+ *size = roundup(*size, 64 * nvbo->tile_mode); - - } else if (dev_priv->chipset >= 0x30) { - *align = 32768; -- *size = roundup(*size, 64 * tile_mode); -+ *size = roundup(*size, 64 * nvbo->tile_mode); - - } else if (dev_priv->chipset >= 0x20) { - *align = 16384; -- *size = roundup(*size, 64 * tile_mode); -+ *size = roundup(*size, 64 * nvbo->tile_mode); - - } else if (dev_priv->chipset >= 0x10) { - *align = 16384; -- *size = roundup(*size, 32 * tile_mode); -+ *size = roundup(*size, 32 * nvbo->tile_mode); - } - } -+ } else { -+ if (likely(dev_priv->chan_vm)) { -+ if (*size > 256 * 1024) -+ *page_shift = dev_priv->chan_vm->lpg_shift; -+ else -+ *page_shift = dev_priv->chan_vm->spg_shift; -+ } else { -+ *page_shift = 12; -+ } -+ -+ *size = roundup(*size, (1 << *page_shift)); -+ *align = max((1 << *page_shift), *align); - } - -- /* ALIGN works only on powers of two. */ - *size = roundup(*size, PAGE_SIZE); -- -- if (dev_priv->card_type == NV_50) { -- *size = roundup(*size, 65536); -- *align = max(65536, *align); -- } - } - - int -@@ -132,7 +103,7 @@ - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_bo *nvbo; -- int ret = 0; -+ int ret = 0, page_shift = 0; - - nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); - if (!nvbo) -@@ -145,10 +116,18 @@ - nvbo->tile_flags = tile_flags; - nvbo->bo.bdev = &dev_priv->ttm.bdev; - -- nouveau_bo_fixup_align(dev, tile_mode, nouveau_bo_tile_layout(nvbo), -- &align, &size); -+ nouveau_bo_fixup_align(nvbo, &align, &size, &page_shift); - align >>= PAGE_SHIFT; - -+ if (!nvbo->no_vm && dev_priv->chan_vm) { -+ ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, -+ NV_MEM_ACCESS_RW, &nvbo->vma); -+ if (ret) { -+ kfree(nvbo); -+ return ret; -+ } -+ } -+ - nouveau_bo_placement_set(nvbo, flags, 0); - - nvbo->channel = chan; -@@ -161,6 +140,11 @@ - } - nvbo->channel = NULL; - -+ if (nvbo->vma.node) { -+ if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) -+ nvbo->bo.offset = nvbo->vma.offset; -+ } -+ - *pnvbo = nvbo; - return 0; - } -@@ -244,7 +228,7 @@ - - nouveau_bo_placement_set(nvbo, memtype, 0); - -- ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false); -+ ret = nouveau_bo_validate(nvbo, false, false, false); - if (ret == 0) { - switch (bo->mem.mem_type) { - case TTM_PL_VRAM: -@@ -280,7 +264,7 @@ - - nouveau_bo_placement_set(nvbo, bo->mem.placement, 0); - -- ret = ttm_bo_validate(bo, &nvbo->placement, false, false, false); -+ ret = nouveau_bo_validate(nvbo, false, false, false); - if (ret == 0) { - switch (bo->mem.mem_type) { - case TTM_PL_VRAM: -@@ -319,6 +303,25 @@ - ttm_bo_kunmap(&nvbo->kmap); - } - -+int -+nouveau_bo_validate(struct nouveau_bo *nvbo, bool interruptible, -+ bool no_wait_reserve, bool no_wait_gpu) -+{ -+ int ret; -+ -+ ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, interruptible, -+ no_wait_reserve, no_wait_gpu); -+ if (ret) -+ return ret; -+ -+ if (nvbo->vma.node) { -+ if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) -+ nvbo->bo.offset = nvbo->vma.offset; -+ } -+ -+ return 0; -+} -+ - u16 - nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index) - { -@@ -410,37 +413,40 @@ - man->default_caching = TTM_PL_FLAG_CACHED; - break; - case TTM_PL_VRAM: -- man->func = &ttm_bo_manager_func; -+ if (dev_priv->card_type >= NV_50) { -+ man->func = &nouveau_vram_manager; -+ man->io_reserve_fastpath = false; -+ man->use_io_reserve_lru = true; -+ } else { -+ man->func = &ttm_bo_manager_func; -+ } - man->flags = TTM_MEMTYPE_FLAG_FIXED | - TTM_MEMTYPE_FLAG_MAPPABLE; - man->available_caching = TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_WC; - man->default_caching = TTM_PL_FLAG_WC; -- if (dev_priv->card_type == NV_50) -- man->gpu_offset = 0x40000000; -- else -- man->gpu_offset = 0; - break; - case TTM_PL_TT: - man->func = &ttm_bo_manager_func; - switch (dev_priv->gart_info.type) { - case NOUVEAU_GART_AGP: - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; -- man->available_caching = TTM_PL_FLAG_UNCACHED; -- man->default_caching = TTM_PL_FLAG_UNCACHED; -+ man->available_caching = TTM_PL_FLAG_UNCACHED | -+ TTM_PL_FLAG_WC; -+ man->default_caching = TTM_PL_FLAG_WC; - break; - case NOUVEAU_GART_SGDMA: - man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | - TTM_MEMTYPE_FLAG_CMA; - man->available_caching = TTM_PL_MASK_CACHING; - man->default_caching = TTM_PL_FLAG_CACHED; -+ man->gpu_offset = dev_priv->gart_info.aper_base; - break; - default: - NV_ERROR(dev, "Unknown GART type: %d\n", - dev_priv->gart_info.type); - return -EINVAL; - } -- man->gpu_offset = dev_priv->vm_gart_base; - break; - default: - NV_ERROR(dev, "Unsupported memory type %u\n", (unsigned)type); -@@ -485,16 +491,9 @@ - if (ret) - return ret; - -- if (nvbo->channel) { -- ret = nouveau_fence_sync(fence, nvbo->channel); -- if (ret) -- goto out; -- } -- - ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, NULL, evict, - no_wait_reserve, no_wait_gpu, new_mem); --out: -- nouveau_fence_unref((void *)&fence); -+ nouveau_fence_unref(&fence); - return ret; - } - -@@ -516,6 +515,58 @@ - } - - static int -+nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, -+ struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) -+{ -+ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); -+ struct nouveau_bo *nvbo = nouveau_bo(bo); -+ u64 src_offset = old_mem->start << PAGE_SHIFT; -+ u64 dst_offset = new_mem->start << PAGE_SHIFT; -+ u32 page_count = new_mem->num_pages; -+ int ret; -+ -+ if (!nvbo->no_vm) { -+ if (old_mem->mem_type == TTM_PL_VRAM) -+ src_offset = nvbo->vma.offset; -+ else -+ src_offset += dev_priv->gart_info.aper_base; -+ -+ if (new_mem->mem_type == TTM_PL_VRAM) -+ dst_offset = nvbo->vma.offset; -+ else -+ dst_offset += dev_priv->gart_info.aper_base; -+ } -+ -+ page_count = new_mem->num_pages; -+ while (page_count) { -+ int line_count = (page_count > 2047) ? 2047 : page_count; -+ -+ ret = RING_SPACE(chan, 12); -+ if (ret) -+ return ret; -+ -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0238, 2); -+ OUT_RING (chan, upper_32_bits(dst_offset)); -+ OUT_RING (chan, lower_32_bits(dst_offset)); -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x030c, 6); -+ OUT_RING (chan, upper_32_bits(src_offset)); -+ OUT_RING (chan, lower_32_bits(src_offset)); -+ OUT_RING (chan, PAGE_SIZE); /* src_pitch */ -+ OUT_RING (chan, PAGE_SIZE); /* dst_pitch */ -+ OUT_RING (chan, PAGE_SIZE); /* line_length */ -+ OUT_RING (chan, line_count); -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0300, 1); -+ OUT_RING (chan, 0x00100110); -+ -+ page_count -= line_count; -+ src_offset += (PAGE_SIZE * line_count); -+ dst_offset += (PAGE_SIZE * line_count); -+ } -+ -+ return 0; -+} -+ -+static int - nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, - struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) - { -@@ -529,14 +580,14 @@ - dst_offset = new_mem->start << PAGE_SHIFT; - if (!nvbo->no_vm) { - if (old_mem->mem_type == TTM_PL_VRAM) -- src_offset += dev_priv->vm_vram_base; -+ src_offset = nvbo->vma.offset; - else -- src_offset += dev_priv->vm_gart_base; -+ src_offset += dev_priv->gart_info.aper_base; - - if (new_mem->mem_type == TTM_PL_VRAM) -- dst_offset += dev_priv->vm_vram_base; -+ dst_offset = nvbo->vma.offset; - else -- dst_offset += dev_priv->vm_gart_base; -+ dst_offset += dev_priv->gart_info.aper_base; - } - - ret = RING_SPACE(chan, 3); -@@ -683,17 +734,27 @@ - int ret; - - chan = nvbo->channel; -- if (!chan || nvbo->no_vm) -+ if (!chan || nvbo->no_vm) { - chan = dev_priv->channel; -+ mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX); -+ } - - if (dev_priv->card_type < NV_50) - ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem); - else -+ if (dev_priv->card_type < NV_C0) - ret = nv50_bo_move_m2mf(chan, bo, &bo->mem, new_mem); -- if (ret) -- return ret; -+ else -+ ret = nvc0_bo_move_m2mf(chan, bo, &bo->mem, new_mem); -+ if (ret == 0) { -+ ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict, -+ no_wait_reserve, -+ no_wait_gpu, new_mem); -+ } - -- return nouveau_bo_move_accel_cleanup(chan, nvbo, evict, no_wait_reserve, no_wait_gpu, new_mem); -+ if (chan == dev_priv->channel) -+ mutex_unlock(&chan->mutex); -+ return ret; - } - - static int -@@ -771,7 +832,6 @@ - struct drm_device *dev = dev_priv->dev; - struct nouveau_bo *nvbo = nouveau_bo(bo); - uint64_t offset; -- int ret; - - if (nvbo->no_vm || new_mem->mem_type != TTM_PL_VRAM) { - /* Nothing to do. */ -@@ -781,18 +841,12 @@ - - offset = new_mem->start << PAGE_SHIFT; - -- if (dev_priv->card_type == NV_50) { -- ret = nv50_mem_vm_bind_linear(dev, -- offset + dev_priv->vm_vram_base, -- new_mem->size, -- nouveau_bo_tile_layout(nvbo), -- offset); -- if (ret) -- return ret; -- -+ if (dev_priv->chan_vm) { -+ nouveau_vm_map(&nvbo->vma, new_mem->mm_node); - } else if (dev_priv->card_type >= NV_10) { - *new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size, -- nvbo->tile_mode); -+ nvbo->tile_mode, -+ nvbo->tile_flags); - } - - return 0; -@@ -808,9 +862,7 @@ - - if (dev_priv->card_type >= NV_10 && - dev_priv->card_type < NV_50) { -- if (*old_tile) -- nv10_mem_expire_tiling(dev, *old_tile, bo->sync_obj); -- -+ nv10_mem_put_tile_region(dev, *old_tile, bo->sync_obj); - *old_tile = new_tile; - } - } -@@ -879,6 +931,7 @@ - struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; - struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev); - struct drm_device *dev = dev_priv->dev; -+ int ret; - - mem->bus.addr = NULL; - mem->bus.offset = 0; -@@ -901,9 +954,40 @@ - #endif - break; - case TTM_PL_VRAM: -- mem->bus.offset = mem->start << PAGE_SHIFT; -+ { -+ struct nouveau_vram *vram = mem->mm_node; -+ u8 page_shift; -+ -+ if (!dev_priv->bar1_vm) { -+ mem->bus.offset = mem->start << PAGE_SHIFT; -+ mem->bus.base = pci_resource_start(dev->pdev, 1); -+ mem->bus.is_iomem = true; -+ break; -+ } -+ -+ if (dev_priv->card_type == NV_C0) -+ page_shift = vram->page_shift; -+ else -+ page_shift = 12; -+ -+ ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, -+ page_shift, NV_MEM_ACCESS_RW, -+ &vram->bar_vma); -+ if (ret) -+ return ret; -+ -+ nouveau_vm_map(&vram->bar_vma, vram); -+ if (ret) { -+ nouveau_vm_put(&vram->bar_vma); -+ return ret; -+ } -+ -+ mem->bus.offset = vram->bar_vma.offset; -+ if (dev_priv->card_type == NV_50) /*XXX*/ -+ mem->bus.offset -= 0x0020000000ULL; - mem->bus.base = pci_resource_start(dev->pdev, 1); - mem->bus.is_iomem = true; -+ } - break; - default: - return -EINVAL; -@@ -914,6 +998,17 @@ - static void - nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) - { -+ struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev); -+ struct nouveau_vram *vram = mem->mm_node; -+ -+ if (!dev_priv->bar1_vm || mem->mem_type != TTM_PL_VRAM) -+ return; -+ -+ if (!vram->bar_vma.node) -+ return; -+ -+ nouveau_vm_unmap(&vram->bar_vma); -+ nouveau_vm_put(&vram->bar_vma); - } - - static int -@@ -939,7 +1034,23 @@ - nvbo->placement.fpfn = 0; - nvbo->placement.lpfn = dev_priv->fb_mappable_pages; - nouveau_bo_placement_set(nvbo, TTM_PL_VRAM, 0); -- return ttm_bo_validate(bo, &nvbo->placement, false, true, false); -+ return nouveau_bo_validate(nvbo, false, true, false); -+} -+ -+void -+nouveau_bo_fence(struct nouveau_bo *nvbo, struct nouveau_fence *fence) -+{ -+ struct nouveau_fence *old_fence; -+ -+ if (likely(fence)) -+ nouveau_fence_ref(fence); -+ -+ spin_lock(&nvbo->bo.bdev->fence_lock); -+ old_fence = nvbo->bo.sync_obj; -+ nvbo->bo.sync_obj = fence; -+ spin_unlock(&nvbo->bo.bdev->fence_lock); -+ -+ nouveau_fence_unref(&old_fence); - } - - struct ttm_bo_driver nouveau_bo_driver = { -@@ -949,11 +1060,11 @@ - .evict_flags = nouveau_bo_evict_flags, - .move = nouveau_bo_move, - .verify_access = nouveau_bo_verify_access, -- .sync_obj_signaled = nouveau_fence_signalled, -- .sync_obj_wait = nouveau_fence_wait, -- .sync_obj_flush = nouveau_fence_flush, -- .sync_obj_unref = nouveau_fence_unref, -- .sync_obj_ref = nouveau_fence_ref, -+ .sync_obj_signaled = __nouveau_fence_signalled, -+ .sync_obj_wait = __nouveau_fence_wait, -+ .sync_obj_flush = __nouveau_fence_flush, -+ .sync_obj_unref = __nouveau_fence_unref, -+ .sync_obj_ref = __nouveau_fence_ref, - .fault_reserve_notify = &nouveau_ttm_fault_reserve_notify, - .io_mem_reserve = &nouveau_ttm_io_mem_reserve, - .io_mem_free = &nouveau_ttm_io_mem_free, -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_channel.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_channel.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_channel.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-01-07 14:22:17.000000000 +0100 -@@ -38,23 +38,28 @@ - int ret; - - if (dev_priv->card_type >= NV_50) { -- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, -- dev_priv->vm_end, NV_DMA_ACCESS_RO, -- NV_DMA_TARGET_AGP, &pushbuf); -+ if (dev_priv->card_type < NV_C0) { -+ ret = nouveau_gpuobj_dma_new(chan, -+ NV_CLASS_DMA_IN_MEMORY, 0, -+ (1ULL << 40), -+ NV_MEM_ACCESS_RO, -+ NV_MEM_TARGET_VM, -+ &pushbuf); -+ } - chan->pushbuf_base = pb->bo.offset; - } else - if (pb->bo.mem.mem_type == TTM_PL_TT) { -- ret = nouveau_gpuobj_gart_dma_new(chan, 0, -- dev_priv->gart_info.aper_size, -- NV_DMA_ACCESS_RO, &pushbuf, -- NULL); -+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, -+ dev_priv->gart_info.aper_size, -+ NV_MEM_ACCESS_RO, -+ NV_MEM_TARGET_GART, &pushbuf); - chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; - } else - if (dev_priv->card_type != NV_04) { - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, 0, - dev_priv->fb_available_size, -- NV_DMA_ACCESS_RO, -- NV_DMA_TARGET_VIDMEM, &pushbuf); -+ NV_MEM_ACCESS_RO, -+ NV_MEM_TARGET_VRAM, &pushbuf); - chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; - } else { - /* NV04 cmdbuf hack, from original ddx.. not sure of it's -@@ -62,17 +67,16 @@ - * VRAM. - */ - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -- pci_resource_start(dev->pdev, -- 1), -+ pci_resource_start(dev->pdev, 1), - dev_priv->fb_available_size, -- NV_DMA_ACCESS_RO, -- NV_DMA_TARGET_PCI, &pushbuf); -+ NV_MEM_ACCESS_RO, -+ NV_MEM_TARGET_PCI, &pushbuf); - chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; - } - - nouveau_gpuobj_ref(pushbuf, &chan->pushbuf); - nouveau_gpuobj_ref(NULL, &pushbuf); -- return 0; -+ return ret; - } - - static struct nouveau_bo * -@@ -100,6 +104,13 @@ - return NULL; - } - -+ ret = nouveau_bo_map(pushbuf); -+ if (ret) { -+ nouveau_bo_unpin(pushbuf); -+ nouveau_bo_ref(NULL, &pushbuf); -+ return NULL; -+ } -+ - return pushbuf; - } - -@@ -107,74 +118,59 @@ - int - nouveau_channel_alloc(struct drm_device *dev, struct nouveau_channel **chan_ret, - struct drm_file *file_priv, -- uint32_t vram_handle, uint32_t tt_handle) -+ uint32_t vram_handle, uint32_t gart_handle) - { - 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; -- int channel, user; -+ unsigned long flags; - int ret; - -- /* -- * Alright, here is the full story -- * Nvidia cards have multiple hw fifo contexts (praise them for that, -- * no complicated crash-prone context switches) -- * We allocate a new context for each app and let it write to it -- * directly (woo, full userspace command submission !) -- * When there are no more contexts, you lost -- */ -- for (channel = 0; channel < pfifo->channels; channel++) { -- if (dev_priv->fifos[channel] == NULL) -+ /* allocate and lock channel structure */ -+ chan = kzalloc(sizeof(*chan), GFP_KERNEL); -+ if (!chan) -+ return -ENOMEM; -+ chan->dev = dev; -+ chan->file_priv = file_priv; -+ chan->vram_handle = vram_handle; -+ chan->gart_handle = gart_handle; -+ -+ kref_init(&chan->ref); -+ atomic_set(&chan->users, 1); -+ mutex_init(&chan->mutex); -+ mutex_lock(&chan->mutex); -+ -+ /* allocate hw channel id */ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); -+ for (chan->id = 0; chan->id < pfifo->channels; chan->id++) { -+ if (!dev_priv->channels.ptr[chan->id]) { -+ nouveau_channel_ref(chan, &dev_priv->channels.ptr[chan->id]); - break; -+ } - } -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - -- /* no more fifos. you lost. */ -- if (channel == pfifo->channels) -- return -EINVAL; -+ if (chan->id == pfifo->channels) { -+ mutex_unlock(&chan->mutex); -+ kfree(chan); -+ return -ENODEV; -+ } - -- dev_priv->fifos[channel] = kzalloc(sizeof(struct nouveau_channel), -- GFP_KERNEL); -- if (!dev_priv->fifos[channel]) -- return -ENOMEM; -- chan = dev_priv->fifos[channel]; -+ NV_DEBUG(dev, "initialising channel %d\n", chan->id); - INIT_LIST_HEAD(&chan->nvsw.vbl_wait); -+ INIT_LIST_HEAD(&chan->nvsw.flip); - INIT_LIST_HEAD(&chan->fence.pending); -- chan->dev = dev; -- chan->id = channel; -- chan->file_priv = file_priv; -- chan->vram_handle = vram_handle; -- chan->gart_handle = tt_handle; -- -- NV_INFO(dev, "Allocating FIFO number %d\n", channel); - - /* Allocate DMA push buffer */ - chan->pushbuf_bo = nouveau_channel_user_pushbuf_alloc(dev); - if (!chan->pushbuf_bo) { - ret = -ENOMEM; - NV_ERROR(dev, "pushbuf %d\n", ret); -- nouveau_channel_free(chan); -+ nouveau_channel_put(&chan); - return ret; - } - - nouveau_dma_pre_init(chan); -- -- /* Locate channel's user control regs */ -- if (dev_priv->card_type < NV_40) -- user = NV03_USER(channel); -- else -- if (dev_priv->card_type < NV_50) -- user = NV40_USER(channel); -- else -- user = NV50_USER(channel); -- -- chan->user = ioremap(pci_resource_start(dev->pdev, 0) + user, -- PAGE_SIZE); -- if (!chan->user) { -- NV_ERROR(dev, "ioremap of regs failed.\n"); -- nouveau_channel_free(chan); -- return -ENOMEM; -- } - chan->user_put = 0x40; - chan->user_get = 0x44; - -@@ -182,15 +178,15 @@ - ret = nouveau_notifier_init_channel(chan); - if (ret) { - NV_ERROR(dev, "ntfy %d\n", ret); -- nouveau_channel_free(chan); -+ nouveau_channel_put(&chan); - return ret; - } - - /* Setup channel's default objects */ -- ret = nouveau_gpuobj_channel_init(chan, vram_handle, tt_handle); -+ ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); - if (ret) { - NV_ERROR(dev, "gpuobj %d\n", ret); -- nouveau_channel_free(chan); -+ nouveau_channel_put(&chan); - return ret; - } - -@@ -198,24 +194,17 @@ - ret = nouveau_channel_pushbuf_ctxdma_init(chan); - if (ret) { - NV_ERROR(dev, "pbctxdma %d\n", ret); -- nouveau_channel_free(chan); -+ nouveau_channel_put(&chan); - return ret; - } - - /* disable the fifo caches */ - pfifo->reassign(dev, false); - -- /* Create a graphics context for new channel */ -- ret = pgraph->create_context(chan); -- if (ret) { -- nouveau_channel_free(chan); -- return ret; -- } -- - /* Construct inital RAMFC for new channel */ - ret = pfifo->create_context(chan); - if (ret) { -- nouveau_channel_free(chan); -+ nouveau_channel_put(&chan); - return ret; - } - -@@ -225,83 +214,111 @@ - if (!ret) - ret = nouveau_fence_channel_init(chan); - if (ret) { -- nouveau_channel_free(chan); -+ nouveau_channel_put(&chan); - return ret; - } - - nouveau_debugfs_channel_init(chan); - -- NV_INFO(dev, "%s: initialised FIFO %d\n", __func__, channel); -+ NV_DEBUG(dev, "channel %d initialised\n", chan->id); - *chan_ret = chan; - return 0; - } - --/* stops a fifo */ -+struct nouveau_channel * -+nouveau_channel_get_unlocked(struct nouveau_channel *ref) -+{ -+ struct nouveau_channel *chan = NULL; -+ -+ if (likely(ref && atomic_inc_not_zero(&ref->users))) -+ nouveau_channel_ref(ref, &chan); -+ -+ return chan; -+} -+ -+struct nouveau_channel * -+nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan; -+ unsigned long flags; -+ -+ if (unlikely(id < 0 || id >= NOUVEAU_MAX_CHANNEL_NR)) -+ return ERR_PTR(-EINVAL); -+ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); -+ chan = nouveau_channel_get_unlocked(dev_priv->channels.ptr[id]); -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ -+ if (unlikely(!chan)) -+ return ERR_PTR(-EINVAL); -+ -+ if (unlikely(file_priv && chan->file_priv != file_priv)) { -+ nouveau_channel_put_unlocked(&chan); -+ return ERR_PTR(-EINVAL); -+ } -+ -+ mutex_lock(&chan->mutex); -+ return chan; -+} -+ - void --nouveau_channel_free(struct nouveau_channel *chan) -+nouveau_channel_put_unlocked(struct nouveau_channel **pchan) - { -+ struct nouveau_channel *chan = *pchan; - 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; -+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; -+ struct nouveau_crypt_engine *pcrypt = &dev_priv->engine.crypt; - unsigned long flags; -- int ret; - -- NV_INFO(dev, "%s: freeing fifo %d\n", __func__, chan->id); -+ /* decrement the refcount, and we're done if there's still refs */ -+ if (likely(!atomic_dec_and_test(&chan->users))) { -+ nouveau_channel_ref(NULL, pchan); -+ return; -+ } - -+ /* noone wants the channel anymore */ -+ NV_DEBUG(dev, "freeing channel %d\n", chan->id); - nouveau_debugfs_channel_fini(chan); - -- /* Give outstanding push buffers a chance to complete */ -- nouveau_fence_update(chan); -- if (chan->fence.sequence != chan->fence.sequence_ack) { -- struct nouveau_fence *fence = NULL; -- -- ret = nouveau_fence_new(chan, &fence, true); -- if (ret == 0) { -- ret = nouveau_fence_wait(fence, NULL, false, false); -- nouveau_fence_unref((void *)&fence); -- } -- -- if (ret) -- NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); -- } -+ /* give it chance to idle */ -+ nouveau_channel_idle(chan); - -- /* Ensure all outstanding fences are signaled. They should be if the -+ /* ensure all outstanding fences are signaled. they should be if the - * above attempts at idling were OK, but if we failed this'll tell TTM - * we're done with the buffers. - */ - nouveau_fence_channel_fini(chan); - -- /* This will prevent pfifo from switching channels. */ -+ /* 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 before the lock, otherwise the irq handler -- * is unable to process them. -+ /* 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); - -- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -- -- pgraph->fifo_access(dev, false); -- if (pgraph->channel(dev) == chan) -- pgraph->unload_context(dev); -- pgraph->destroy_context(chan); -- pgraph->fifo_access(dev, true); -- -- if (pfifo->channel_id(dev) == chan->id) { -- pfifo->disable(dev); -- pfifo->unload_context(dev); -- pfifo->enable(dev); -- } -+ /* destroy the engine specific contexts */ - pfifo->destroy_context(chan); -+ pgraph->destroy_context(chan); -+ if (pcrypt->destroy_context) -+ pcrypt->destroy_context(chan); - - pfifo->reassign(dev, true); - -- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ /* aside from its resources, the channel should now be dead, -+ * remove it from the channel list -+ */ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); -+ nouveau_channel_ref(NULL, &dev_priv->channels.ptr[chan->id]); -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - -- /* Release the channel's resources */ -+ /* destroy any resources the channel owned */ - nouveau_gpuobj_ref(NULL, &chan->pushbuf); - if (chan->pushbuf_bo) { - nouveau_bo_unmap(chan->pushbuf_bo); -@@ -310,44 +327,80 @@ - } - nouveau_gpuobj_channel_takedown(chan); - nouveau_notifier_takedown_channel(chan); -- if (chan->user) -- iounmap(chan->user); - -- dev_priv->fifos[chan->id] = NULL; -+ nouveau_channel_ref(NULL, pchan); -+} -+ -+void -+nouveau_channel_put(struct nouveau_channel **pchan) -+{ -+ mutex_unlock(&(*pchan)->mutex); -+ nouveau_channel_put_unlocked(pchan); -+} -+ -+static void -+nouveau_channel_del(struct kref *ref) -+{ -+ struct nouveau_channel *chan = -+ container_of(ref, struct nouveau_channel, ref); -+ - kfree(chan); - } - -+void -+nouveau_channel_ref(struct nouveau_channel *chan, -+ struct nouveau_channel **pchan) -+{ -+ if (chan) -+ kref_get(&chan->ref); -+ -+ if (*pchan) -+ kref_put(&(*pchan)->ref, nouveau_channel_del); -+ -+ *pchan = chan; -+} -+ -+void -+nouveau_channel_idle(struct nouveau_channel *chan) -+{ -+ struct drm_device *dev = chan->dev; -+ struct nouveau_fence *fence = NULL; -+ int ret; -+ -+ nouveau_fence_update(chan); -+ -+ if (chan->fence.sequence != chan->fence.sequence_ack) { -+ ret = nouveau_fence_new(chan, &fence, true); -+ if (!ret) { -+ ret = nouveau_fence_wait(fence, false, false); -+ nouveau_fence_unref(&fence); -+ } -+ -+ if (ret) -+ NV_ERROR(dev, "Failed to idle channel %d.\n", chan->id); -+ } -+} -+ - /* cleans up all the fifos from file_priv */ - void - nouveau_channel_cleanup(struct drm_device *dev, struct drm_file *file_priv) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_engine *engine = &dev_priv->engine; -+ struct nouveau_channel *chan; - int i; - - NV_DEBUG(dev, "clearing FIFO enables from file_priv\n"); - for (i = 0; i < engine->fifo.channels; i++) { -- struct nouveau_channel *chan = dev_priv->fifos[i]; -+ chan = nouveau_channel_get(dev, file_priv, i); -+ if (IS_ERR(chan)) -+ continue; - -- if (chan && chan->file_priv == file_priv) -- nouveau_channel_free(chan); -+ atomic_dec(&chan->users); -+ nouveau_channel_put(&chan); - } - } - --int --nouveau_channel_owner(struct drm_device *dev, struct drm_file *file_priv, -- int channel) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_engine *engine = &dev_priv->engine; -- -- if (channel >= engine->fifo.channels) -- return 0; -- if (dev_priv->fifos[channel] == NULL) -- return 0; -- -- return (dev_priv->fifos[channel]->file_priv == file_priv); --} - - /*********************************** - * ioctls wrapping the functions -@@ -383,36 +436,44 @@ - else - init->pushbuf_domains = NOUVEAU_GEM_DOMAIN_GART; - -- init->subchan[0].handle = NvM2MF; -- if (dev_priv->card_type < NV_50) -- init->subchan[0].grclass = 0x0039; -- else -- init->subchan[0].grclass = 0x5039; -- init->subchan[1].handle = NvSw; -- init->subchan[1].grclass = NV_SW; -- init->nr_subchan = 2; -+ if (dev_priv->card_type < NV_C0) { -+ init->subchan[0].handle = NvM2MF; -+ if (dev_priv->card_type < NV_50) -+ init->subchan[0].grclass = 0x0039; -+ else -+ init->subchan[0].grclass = 0x5039; -+ init->subchan[1].handle = NvSw; -+ init->subchan[1].grclass = NV_SW; -+ init->nr_subchan = 2; -+ } else { -+ init->subchan[0].handle = 0x9039; -+ init->subchan[0].grclass = 0x9039; -+ init->nr_subchan = 1; -+ } - - /* Named memory object area */ - ret = drm_gem_handle_create(file_priv, chan->notifier_bo->gem, - &init->notifier_handle); -- if (ret) { -- nouveau_channel_free(chan); -- return ret; -- } - -- return 0; -+ if (ret == 0) -+ atomic_inc(&chan->users); /* userspace reference */ -+ nouveau_channel_put(&chan); -+ return ret; - } - - static int - nouveau_ioctl_fifo_free(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { -- struct drm_nouveau_channel_free *cfree = data; -+ struct drm_nouveau_channel_free *req = data; - struct nouveau_channel *chan; - -- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(cfree->channel, file_priv, chan); -+ chan = nouveau_channel_get(dev, file_priv, req->channel); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); - -- nouveau_channel_free(chan); -+ atomic_dec(&chan->users); -+ nouveau_channel_put(&chan); - return 0; - } - -@@ -421,18 +482,18 @@ - ***********************************/ - - struct drm_ioctl_desc nouveau_ioctls[] = { -- DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -- DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_AUTH), -- DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GETPARAM, nouveau_ioctl_getparam, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_SETPARAM, nouveau_ioctl_setparam, DRM_UNLOCKED|DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_ALLOC, nouveau_ioctl_fifo_alloc, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_CHANNEL_FREE, nouveau_ioctl_fifo_free, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GROBJ_ALLOC, nouveau_ioctl_grobj_alloc, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_NOTIFIEROBJ_ALLOC, nouveau_ioctl_notifier_alloc, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GPUOBJ_FREE, nouveau_ioctl_gpuobj_free, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_NEW, nouveau_gem_ioctl_new, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_PUSHBUF, nouveau_gem_ioctl_pushbuf, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_PREP, nouveau_gem_ioctl_cpu_prep, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_CPU_FINI, nouveau_gem_ioctl_cpu_fini, DRM_UNLOCKED|DRM_AUTH), -+ DRM_IOCTL_DEF_DRV(NOUVEAU_GEM_INFO, nouveau_gem_ioctl_info, DRM_UNLOCKED|DRM_AUTH), - }; - - int nouveau_max_ioctl = DRM_ARRAY_SIZE(nouveau_ioctls); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_connector.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_connector.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_connector.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-01-07 14:22:17.000000000 +0100 -@@ -37,6 +37,8 @@ - #include "nouveau_connector.h" - #include "nouveau_hw.h" - -+static void nouveau_connector_hotplug(void *, int); -+ - static struct nouveau_encoder * - find_encoder_by_type(struct drm_connector *connector, int type) - { -@@ -94,22 +96,30 @@ - } - - static void --nouveau_connector_destroy(struct drm_connector *drm_connector) -+nouveau_connector_destroy(struct drm_connector *connector) - { -- struct nouveau_connector *nv_connector = -- nouveau_connector(drm_connector); -+ struct nouveau_connector *nv_connector = nouveau_connector(connector); -+ struct drm_nouveau_private *dev_priv; -+ struct nouveau_gpio_engine *pgpio; - struct drm_device *dev; - - if (!nv_connector) - return; - - dev = nv_connector->base.dev; -+ dev_priv = dev->dev_private; - NV_DEBUG_KMS(dev, "\n"); - -+ pgpio = &dev_priv->engine.gpio; -+ if (pgpio->irq_unregister) { -+ pgpio->irq_unregister(dev, nv_connector->dcb->gpio_tag, -+ nouveau_connector_hotplug, connector); -+ } -+ - kfree(nv_connector->edid); -- drm_sysfs_connector_remove(drm_connector); -- drm_connector_cleanup(drm_connector); -- kfree(drm_connector); -+ drm_sysfs_connector_remove(connector); -+ drm_connector_cleanup(connector); -+ kfree(connector); - } - - static struct nouveau_i2c_chan * -@@ -760,6 +770,7 @@ - { - const struct drm_connector_funcs *funcs = &nouveau_connector_funcs; - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; - struct nouveau_connector *nv_connector = NULL; - struct dcb_connector_table_entry *dcb = NULL; - struct drm_connector *connector; -@@ -876,6 +887,11 @@ - break; - } - -+ if (pgpio->irq_register) { -+ pgpio->irq_register(dev, nv_connector->dcb->gpio_tag, -+ nouveau_connector_hotplug, connector); -+ } -+ - drm_sysfs_connector_add(connector); - dcb->drm = connector; - return dcb->drm; -@@ -886,3 +902,29 @@ - return ERR_PTR(ret); - - } -+ -+static void -+nouveau_connector_hotplug(void *data, int plugged) -+{ -+ struct drm_connector *connector = data; -+ struct drm_device *dev = connector->dev; -+ -+ NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", -+ drm_get_connector_name(connector)); -+ -+ if (connector->encoder && connector->encoder->crtc && -+ connector->encoder->crtc->enabled) { -+ struct nouveau_encoder *nv_encoder = nouveau_encoder(connector->encoder); -+ struct drm_encoder_helper_funcs *helper = -+ connector->encoder->helper_private; -+ -+ if (nv_encoder->dcb->type == OUTPUT_DP) { -+ if (plugged) -+ helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); -+ else -+ helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); -+ } -+ } -+ -+ drm_helper_hpd_irq_event(dev); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_display.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_display.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_display.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_display.c 2011-01-07 14:22:17.000000000 +0100 -@@ -29,6 +29,9 @@ - #include "nouveau_drv.h" - #include "nouveau_fb.h" - #include "nouveau_fbcon.h" -+#include "nouveau_hw.h" -+#include "nouveau_crtc.h" -+#include "nouveau_dma.h" - - static void - nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) -@@ -104,3 +107,207 @@ - .output_poll_changed = nouveau_fbcon_output_poll_changed, - }; - -+int -+nouveau_vblank_enable(struct drm_device *dev, int crtc) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ if (dev_priv->card_type >= NV_50) -+ nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, 0, -+ NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc)); -+ else -+ NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, -+ NV_PCRTC_INTR_0_VBLANK); -+ -+ return 0; -+} -+ -+void -+nouveau_vblank_disable(struct drm_device *dev, int crtc) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ if (dev_priv->card_type >= NV_50) -+ nv_mask(dev, NV50_PDISPLAY_INTR_EN_1, -+ NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(crtc), 0); -+ else -+ NVWriteCRTC(dev, crtc, NV_PCRTC_INTR_EN_0, 0); -+} -+ -+static int -+nouveau_page_flip_reserve(struct nouveau_bo *old_bo, -+ struct nouveau_bo *new_bo) -+{ -+ int ret; -+ -+ ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); -+ if (ret) -+ return ret; -+ -+ ret = ttm_bo_reserve(&new_bo->bo, false, false, false, 0); -+ if (ret) -+ goto fail; -+ -+ ret = ttm_bo_reserve(&old_bo->bo, false, false, false, 0); -+ if (ret) -+ goto fail_unreserve; -+ -+ return 0; -+ -+fail_unreserve: -+ ttm_bo_unreserve(&new_bo->bo); -+fail: -+ nouveau_bo_unpin(new_bo); -+ return ret; -+} -+ -+static void -+nouveau_page_flip_unreserve(struct nouveau_bo *old_bo, -+ struct nouveau_bo *new_bo, -+ struct nouveau_fence *fence) -+{ -+ nouveau_bo_fence(new_bo, fence); -+ ttm_bo_unreserve(&new_bo->bo); -+ -+ nouveau_bo_fence(old_bo, fence); -+ ttm_bo_unreserve(&old_bo->bo); -+ -+ nouveau_bo_unpin(old_bo); -+} -+ -+static int -+nouveau_page_flip_emit(struct nouveau_channel *chan, -+ struct nouveau_bo *old_bo, -+ struct nouveau_bo *new_bo, -+ struct nouveau_page_flip_state *s, -+ struct nouveau_fence **pfence) -+{ -+ struct drm_device *dev = chan->dev; -+ unsigned long flags; -+ int ret; -+ -+ /* Queue it to the pending list */ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ list_add_tail(&s->head, &chan->nvsw.flip); -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ /* Synchronize with the old framebuffer */ -+ ret = nouveau_fence_sync(old_bo->bo.sync_obj, chan); -+ if (ret) -+ goto fail; -+ -+ /* Emit the pageflip */ -+ ret = RING_SPACE(chan, 2); -+ if (ret) -+ goto fail; -+ -+ BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); -+ OUT_RING(chan, 0); -+ FIRE_RING(chan); -+ -+ ret = nouveau_fence_new(chan, pfence, true); -+ if (ret) -+ goto fail; -+ -+ return 0; -+fail: -+ spin_lock_irqsave(&dev->event_lock, flags); -+ list_del(&s->head); -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ return ret; -+} -+ -+int -+nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, -+ struct drm_pending_vblank_event *event) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo; -+ struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo; -+ struct nouveau_page_flip_state *s; -+ struct nouveau_channel *chan; -+ struct nouveau_fence *fence; -+ int ret; -+ -+ if (dev_priv->engine.graph.accel_blocked) -+ return -ENODEV; -+ -+ s = kzalloc(sizeof(*s), GFP_KERNEL); -+ if (!s) -+ return -ENOMEM; -+ -+ /* Don't let the buffers go away while we flip */ -+ ret = nouveau_page_flip_reserve(old_bo, new_bo); -+ if (ret) -+ goto fail_free; -+ -+ /* Initialize a page flip struct */ -+ *s = (struct nouveau_page_flip_state) -+ { { }, s->event, nouveau_crtc(crtc)->index, -+ fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y, -+ new_bo->bo.offset }; -+ -+ /* Choose the channel the flip will be handled in */ -+ chan = nouveau_fence_channel(new_bo->bo.sync_obj); -+ if (!chan) -+ chan = nouveau_channel_get_unlocked(dev_priv->channel); -+ mutex_lock(&chan->mutex); -+ -+ /* Emit a page flip */ -+ ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); -+ nouveau_channel_put(&chan); -+ if (ret) -+ goto fail_unreserve; -+ -+ /* Update the crtc struct and cleanup */ -+ crtc->fb = fb; -+ -+ nouveau_page_flip_unreserve(old_bo, new_bo, fence); -+ nouveau_fence_unref(&fence); -+ return 0; -+ -+fail_unreserve: -+ nouveau_page_flip_unreserve(old_bo, new_bo, NULL); -+fail_free: -+ kfree(s); -+ return ret; -+} -+ -+int -+nouveau_finish_page_flip(struct nouveau_channel *chan, -+ struct nouveau_page_flip_state *ps) -+{ -+ struct drm_device *dev = chan->dev; -+ struct nouveau_page_flip_state *s; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ -+ if (list_empty(&chan->nvsw.flip)) { -+ NV_ERROR(dev, "Unexpected pageflip in channel %d.\n", chan->id); -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ return -EINVAL; -+ } -+ -+ s = list_first_entry(&chan->nvsw.flip, -+ struct nouveau_page_flip_state, head); -+ if (s->event) { -+ struct drm_pending_vblank_event *e = s->event; -+ struct timeval now; -+ -+ do_gettimeofday(&now); -+ e->event.sequence = 0; -+ e->event.tv_sec = now.tv_sec; -+ e->event.tv_usec = now.tv_usec; -+ list_add_tail(&e->base.link, &e->base.file_priv->event_list); -+ wake_up_interruptible(&e->base.file_priv->event_wait); -+ } -+ -+ list_del(&s->head); -+ *ps = *s; -+ kfree(s); -+ -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ return 0; -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_dma.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_dma.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_dma.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_dma.c 2011-01-07 14:22:17.000000000 +0100 -@@ -36,7 +36,7 @@ - struct drm_nouveau_private *dev_priv = chan->dev->dev_private; - struct nouveau_bo *pushbuf = chan->pushbuf_bo; - -- if (dev_priv->card_type == NV_50) { -+ if (dev_priv->card_type >= NV_50) { - const int ib_size = pushbuf->bo.mem.size / 2; - - chan->dma.ib_base = (pushbuf->bo.mem.size - ib_size) >> 2; -@@ -59,17 +59,26 @@ - { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *obj = NULL; - int ret, i; - -- /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ -- ret = nouveau_gpuobj_gr_new(chan, dev_priv->card_type < NV_50 ? -- 0x0039 : 0x5039, &obj); -- if (ret) -- return ret; -+ if (dev_priv->card_type >= NV_C0) { -+ ret = nouveau_gpuobj_gr_new(chan, 0x9039, 0x9039); -+ if (ret) -+ return ret; -+ -+ ret = RING_SPACE(chan, 2); -+ if (ret) -+ return ret; -+ -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0000, 1); -+ OUT_RING (chan, 0x00009039); -+ FIRE_RING (chan); -+ return 0; -+ } - -- ret = nouveau_ramht_insert(chan, NvM2MF, obj); -- nouveau_gpuobj_ref(NULL, &obj); -+ /* Create NV_MEMORY_TO_MEMORY_FORMAT for buffer moves */ -+ ret = nouveau_gpuobj_gr_new(chan, NvM2MF, dev_priv->card_type < NV_50 ? -+ 0x0039 : 0x5039); - if (ret) - return ret; - -@@ -78,11 +87,6 @@ - if (ret) - return ret; - -- /* Map push buffer */ -- ret = nouveau_bo_map(chan->pushbuf_bo); -- if (ret) -- return ret; -- - /* Insert NOPS for NOUVEAU_DMA_SKIPS */ - ret = RING_SPACE(chan, NOUVEAU_DMA_SKIPS); - if (ret) -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_dma.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_dma.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_dma.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_dma.h 2011-01-07 14:22:17.000000000 +0100 -@@ -77,7 +77,8 @@ - /* G80+ display objects */ - NvEvoVRAM = 0x01000000, - NvEvoFB16 = 0x01000001, -- NvEvoFB32 = 0x01000002 -+ NvEvoFB32 = 0x01000002, -+ NvEvoVRAM_LP = 0x01000003 - }; - - #define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 -@@ -125,6 +126,12 @@ - OUT_RINGp(struct nouveau_channel *chan, const void *data, unsigned nr_dwords); - - static inline void -+BEGIN_NVC0(struct nouveau_channel *chan, int op, int subc, int mthd, int size) -+{ -+ OUT_RING(chan, (op << 28) | (size << 16) | (subc << 13) | (mthd >> 2)); -+} -+ -+static inline void - BEGIN_RING(struct nouveau_channel *chan, int subc, int mthd, int size) - { - OUT_RING(chan, (subc << 13) | (size << 18) | mthd); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_dp.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_dp.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_dp.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_dp.c 2011-01-07 14:22:17.000000000 +0100 -@@ -279,7 +279,7 @@ - struct bit_displayport_encoder_table *dpe; - int dpe_headerlen; - uint8_t config[4], status[3]; -- bool cr_done, cr_max_vs, eq_done; -+ bool cr_done, cr_max_vs, eq_done, hpd_state; - int ret = 0, i, tries, voltage; - - NV_DEBUG_KMS(dev, "link training!!\n"); -@@ -297,7 +297,7 @@ - /* disable hotplug detect, this flips around on some panels during - * link training. - */ -- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); -+ hpd_state = pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, false); - - if (dpe->script0) { - NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); -@@ -439,7 +439,7 @@ - } - - /* re-enable hotplug detect */ -- pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, true); -+ pgpio->irq_enable(dev, nv_connector->dcb->gpio_tag, hpd_state); - - return eq_done; - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_drv.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_drv.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_drv.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_drv.c 2011-01-07 14:22:17.000000000 +0100 -@@ -115,6 +115,10 @@ - int nouveau_perflvl_wr; - module_param_named(perflvl_wr, nouveau_perflvl_wr, int, 0400); - -+MODULE_PARM_DESC(msi, "Enable MSI (default: off)\n"); -+int nouveau_msi; -+module_param_named(msi, nouveau_msi, int, 0400); -+ - int nouveau_fbpercrtc; - #if 0 - module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); -@@ -193,23 +197,10 @@ - - NV_INFO(dev, "Idling channels...\n"); - for (i = 0; i < pfifo->channels; i++) { -- struct nouveau_fence *fence = NULL; -- -- chan = dev_priv->fifos[i]; -- if (!chan || (dev_priv->card_type >= NV_50 && -- chan == dev_priv->fifos[0])) -- continue; -- -- ret = nouveau_fence_new(chan, &fence, true); -- if (ret == 0) { -- ret = nouveau_fence_wait(fence, NULL, false, false); -- nouveau_fence_unref((void *)&fence); -- } -+ chan = dev_priv->channels.ptr[i]; - -- if (ret) { -- NV_ERROR(dev, "Failed to idle channel %d for suspend\n", -- chan->id); -- } -+ if (chan && chan->pushbuf_bo) -+ nouveau_channel_idle(chan); - } - - pgraph->fifo_access(dev, false); -@@ -219,17 +210,17 @@ - pfifo->unload_context(dev); - pgraph->unload_context(dev); - -- NV_INFO(dev, "Suspending GPU objects...\n"); -- ret = nouveau_gpuobj_suspend(dev); -+ ret = pinstmem->suspend(dev); - if (ret) { - NV_ERROR(dev, "... failed: %d\n", ret); - goto out_abort; - } - -- ret = pinstmem->suspend(dev); -+ NV_INFO(dev, "Suspending GPU objects...\n"); -+ ret = nouveau_gpuobj_suspend(dev); - if (ret) { - NV_ERROR(dev, "... failed: %d\n", ret); -- nouveau_gpuobj_suspend_cleanup(dev); -+ pinstmem->resume(dev); - goto out_abort; - } - -@@ -294,17 +285,18 @@ - } - } - -+ NV_INFO(dev, "Restoring GPU objects...\n"); -+ nouveau_gpuobj_resume(dev); -+ - NV_INFO(dev, "Reinitialising engines...\n"); - engine->instmem.resume(dev); - engine->mc.init(dev); - engine->timer.init(dev); - engine->fb.init(dev); - engine->graph.init(dev); -+ engine->crypt.init(dev); - engine->fifo.init(dev); - -- NV_INFO(dev, "Restoring GPU objects...\n"); -- nouveau_gpuobj_resume(dev); -- - nouveau_irq_postinstall(dev); - - /* Re-write SKIPS, they'll have been lost over the suspend */ -@@ -313,7 +305,7 @@ - int j; - - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- chan = dev_priv->fifos[i]; -+ chan = dev_priv->channels.ptr[i]; - if (!chan || !chan->pushbuf_bo) - continue; - -@@ -347,13 +339,11 @@ - - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); -+ u32 offset = nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT; - -- nv_crtc->cursor.set_offset(nv_crtc, -- nv_crtc->cursor.nvbo->bo.offset - -- dev_priv->vm_vram_base); -- -+ nv_crtc->cursor.set_offset(nv_crtc, offset); - nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x, -- nv_crtc->cursor_saved_y); -+ nv_crtc->cursor_saved_y); - } - - /* Force CLUT to get re-loaded during modeset */ -@@ -393,6 +383,9 @@ - .irq_postinstall = nouveau_irq_postinstall, - .irq_uninstall = nouveau_irq_uninstall, - .irq_handler = nouveau_irq_handler, -+ .get_vblank_counter = drm_vblank_count, -+ .enable_vblank = nouveau_vblank_enable, -+ .disable_vblank = nouveau_vblank_disable, - .reclaim_buffers = drm_core_reclaim_buffers, - .ioctls = nouveau_ioctls, - .fops = { -@@ -403,6 +396,7 @@ - .mmap = nouveau_ttm_mmap, - .poll = drm_poll, - .fasync = drm_fasync, -+ .read = drm_read, - #if defined(CONFIG_COMPAT) - .compat_ioctl = nouveau_compat_ioctl, - #endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_drv.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_drv.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_drv.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-01-07 14:22:17.000000000 +0100 -@@ -54,22 +54,37 @@ - #include "nouveau_drm.h" - #include "nouveau_reg.h" - #include "nouveau_bios.h" -+#include "nouveau_util.h" -+ - struct nouveau_grctx; -+struct nouveau_vram; -+#include "nouveau_vm.h" - - #define MAX_NUM_DCB_ENTRIES 16 - - #define NOUVEAU_MAX_CHANNEL_NR 128 - #define NOUVEAU_MAX_TILE_NR 15 - --#define NV50_VM_MAX_VRAM (2*1024*1024*1024ULL) --#define NV50_VM_BLOCK (512*1024*1024ULL) --#define NV50_VM_VRAM_NR (NV50_VM_MAX_VRAM / NV50_VM_BLOCK) -+struct nouveau_vram { -+ struct drm_device *dev; -+ -+ struct nouveau_vma bar_vma; -+ u8 page_shift; -+ -+ struct list_head regions; -+ u32 memtype; -+ u64 offset; -+ u64 size; -+}; - - struct nouveau_tile_reg { -- struct nouveau_fence *fence; -- uint32_t addr; -- uint32_t size; - bool used; -+ uint32_t addr; -+ uint32_t limit; -+ uint32_t pitch; -+ uint32_t zcomp; -+ struct drm_mm_node *tag_mem; -+ struct nouveau_fence *fence; - }; - - struct nouveau_bo { -@@ -88,6 +103,7 @@ - - struct nouveau_channel *channel; - -+ struct nouveau_vma vma; - bool mappable; - bool no_vm; - -@@ -96,7 +112,6 @@ - struct nouveau_tile_reg *tile; - - struct drm_gem_object *gem; -- struct drm_file *cpu_filp; - int pin_refcnt; - }; - -@@ -133,20 +148,28 @@ - - #define NVOBJ_ENGINE_SW 0 - #define NVOBJ_ENGINE_GR 1 --#define NVOBJ_ENGINE_DISPLAY 2 -+#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_FLAG_DONT_MAP (1 << 0) - #define NVOBJ_FLAG_ZERO_ALLOC (1 << 1) - #define NVOBJ_FLAG_ZERO_FREE (1 << 2) -+#define NVOBJ_FLAG_VM (1 << 3) -+ -+#define NVOBJ_CINST_GLOBAL 0xdeadbeef -+ - struct nouveau_gpuobj { - struct drm_device *dev; - struct kref refcount; - struct list_head list; - -- struct drm_mm_node *im_pramin; -- struct nouveau_bo *im_backing; -- uint32_t *im_backing_suspend; -- int im_bound; -+ void *node; -+ u32 *suspend; - - uint32_t flags; - -@@ -162,10 +185,29 @@ - void *priv; - }; - -+struct nouveau_page_flip_state { -+ struct list_head head; -+ struct drm_pending_vblank_event *event; -+ int crtc, bpp, pitch, x, y; -+ uint64_t offset; -+}; -+ -+enum nouveau_channel_mutex_class { -+ NOUVEAU_UCHANNEL_MUTEX, -+ NOUVEAU_KCHANNEL_MUTEX -+}; -+ - struct nouveau_channel { - struct drm_device *dev; - int id; - -+ /* references to the channel data structure */ -+ struct kref ref; -+ /* users of the hardware channel resources, the hardware -+ * context will be kicked off when it reaches zero. */ -+ atomic_t users; -+ struct mutex mutex; -+ - /* owner of this fifo */ - struct drm_file *file_priv; - /* mapping of the fifo itself */ -@@ -198,16 +240,17 @@ - /* PFIFO context */ - struct nouveau_gpuobj *ramfc; - 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; - - /* NV50 VM */ -+ struct nouveau_vm *vm; - struct nouveau_gpuobj *vm_pd; -- struct nouveau_gpuobj *vm_gart_pt; -- struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; - - /* Objects */ - struct nouveau_gpuobj *ramin; /* Private instmem */ -@@ -238,9 +281,11 @@ - - struct { - struct nouveau_gpuobj *vblsem; -+ uint32_t vblsem_head; - uint32_t vblsem_offset; - uint32_t vblsem_rval; - struct list_head vbl_wait; -+ struct list_head flip; - } nvsw; - - struct { -@@ -258,11 +303,11 @@ - int (*suspend)(struct drm_device *dev); - void (*resume)(struct drm_device *dev); - -- int (*populate)(struct drm_device *, struct nouveau_gpuobj *, -- uint32_t *size); -- void (*clear)(struct drm_device *, struct nouveau_gpuobj *); -- int (*bind)(struct drm_device *, struct nouveau_gpuobj *); -- int (*unbind)(struct drm_device *, struct nouveau_gpuobj *); -+ int (*get)(struct nouveau_gpuobj *, u32 size, u32 align); -+ void (*put)(struct nouveau_gpuobj *); -+ int (*map)(struct nouveau_gpuobj *); -+ void (*unmap)(struct nouveau_gpuobj *); -+ - void (*flush)(struct drm_device *); - }; - -@@ -279,15 +324,21 @@ - - struct nouveau_fb_engine { - int num_tiles; -+ struct drm_mm tag_heap; -+ void *priv; - - int (*init)(struct drm_device *dev); - void (*takedown)(struct drm_device *dev); - -- void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch); -+ void (*init_tile_region)(struct drm_device *dev, int i, -+ uint32_t addr, uint32_t size, -+ uint32_t pitch, uint32_t flags); -+ void (*set_tile_region)(struct drm_device *dev, int i); -+ void (*free_tile_region)(struct drm_device *dev, int i); - }; - - struct nouveau_fifo_engine { -+ void *priv; - int channels; - - struct nouveau_gpuobj *playlist[2]; -@@ -310,22 +361,11 @@ - void (*tlb_flush)(struct drm_device *dev); - }; - --struct nouveau_pgraph_object_method { -- int id; -- int (*exec)(struct nouveau_channel *chan, int grclass, int mthd, -- uint32_t data); --}; -- --struct nouveau_pgraph_object_class { -- int id; -- bool software; -- struct nouveau_pgraph_object_method *methods; --}; -- - struct nouveau_pgraph_engine { -- struct nouveau_pgraph_object_class *grclass; - bool accel_blocked; -+ bool registered; - int grctx_size; -+ void *priv; - - /* NV2x/NV3x context table (0x400780) */ - struct nouveau_gpuobj *ctx_table; -@@ -342,8 +382,7 @@ - int (*unload_context)(struct drm_device *); - void (*tlb_flush)(struct drm_device *dev); - -- void (*set_region_tiling)(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch); -+ void (*set_tile_region)(struct drm_device *dev, int i); - }; - - struct nouveau_display_engine { -@@ -355,13 +394,19 @@ - }; - - struct nouveau_gpio_engine { -+ void *priv; -+ - int (*init)(struct drm_device *); - void (*takedown)(struct drm_device *); - - int (*get)(struct drm_device *, enum dcb_gpio_tag); - int (*set)(struct drm_device *, enum dcb_gpio_tag, int state); - -- void (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); -+ int (*irq_register)(struct drm_device *, enum dcb_gpio_tag, -+ void (*)(void *, int), void *); -+ void (*irq_unregister)(struct drm_device *, enum dcb_gpio_tag, -+ void (*)(void *, int), void *); -+ bool (*irq_enable)(struct drm_device *, enum dcb_gpio_tag, bool on); - }; - - struct nouveau_pm_voltage_level { -@@ -437,6 +482,7 @@ - struct nouveau_pm_level *cur; - - struct device *hwmon; -+ struct notifier_block acpi_nb; - - int (*clock_get)(struct drm_device *, u32 id); - void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *, -@@ -449,6 +495,25 @@ - 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, -+ u32 type, struct nouveau_vram **); -+ void (*put)(struct drm_device *, struct nouveau_vram **); -+ -+ bool (*flags_valid)(struct drm_device *, u32 tile_flags); -+}; -+ - struct nouveau_engine { - struct nouveau_instmem_engine instmem; - struct nouveau_mc_engine mc; -@@ -459,6 +524,8 @@ - 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; - }; - - struct nouveau_pll_vals { -@@ -577,18 +644,15 @@ - bool ramin_available; - struct drm_mm ramin_heap; - struct list_head gpuobj_list; -+ struct list_head classes; - - struct nouveau_bo *vga_ram; - -+ /* interrupt handling */ -+ void (*irq_handler[32])(struct drm_device *); -+ bool msi_enabled; - struct workqueue_struct *wq; - struct work_struct irq_work; -- struct work_struct hpd_work; -- -- struct { -- spinlock_t lock; -- uint32_t hpd0_bits; -- uint32_t hpd1_bits; -- } hpd_state; - - struct list_head vbl_waiting; - -@@ -605,8 +669,10 @@ - struct nouveau_bo *bo; - } fence; - -- int fifo_alloc_count; -- struct nouveau_channel *fifos[NOUVEAU_MAX_CHANNEL_NR]; -+ struct { -+ spinlock_t lock; -+ struct nouveau_channel *ptr[NOUVEAU_MAX_CHANNEL_NR]; -+ } channels; - - struct nouveau_engine engine; - struct nouveau_channel *channel; -@@ -632,12 +698,14 @@ - uint64_t aper_free; - - struct nouveau_gpuobj *sg_ctxdma; -- struct page *sg_dummy_page; -- dma_addr_t sg_dummy_bus; -+ struct nouveau_vma vma; - } gart_info; - - /* nv10-nv40 tiling regions */ -- struct nouveau_tile_reg tile[NOUVEAU_MAX_TILE_NR]; -+ struct { -+ struct nouveau_tile_reg reg[NOUVEAU_MAX_TILE_NR]; -+ spinlock_t lock; -+ } tile; - - /* VRAM/fb configuration */ - uint64_t vram_size; -@@ -650,14 +718,12 @@ - uint64_t fb_aper_free; - int fb_mtrr; - -+ /* BAR control (NV50-) */ -+ struct nouveau_vm *bar1_vm; -+ struct nouveau_vm *bar3_vm; -+ - /* G8x/G9x virtual address space */ -- uint64_t vm_gart_base; -- uint64_t vm_gart_size; -- uint64_t vm_vram_base; -- uint64_t vm_vram_size; -- uint64_t vm_end; -- struct nouveau_gpuobj *vm_vram_pt[NV50_VM_VRAM_NR]; -- int vm_vram_pt_nr; -+ struct nouveau_vm *chan_vm; - - struct nvbios vbios; - -@@ -674,6 +740,7 @@ - struct backlight_device *backlight; - - struct nouveau_channel *evo; -+ u32 evo_alloc; - struct { - struct dcb_entry *dcb; - u16 script; -@@ -719,16 +786,6 @@ - return 0; - } - --#define NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(id, cl, ch) do { \ -- struct drm_nouveau_private *nv = dev->dev_private; \ -- if (!nouveau_channel_owner(dev, (cl), (id))) { \ -- NV_ERROR(dev, "pid %d doesn't own channel %d\n", \ -- DRM_CURRENTPID, (id)); \ -- return -EPERM; \ -- } \ -- (ch) = nv->fifos[(id)]; \ --} while (0) -- - /* nouveau_drv.c */ - extern int nouveau_agpmode; - extern int nouveau_duallink; -@@ -748,6 +805,7 @@ - extern int nouveau_override_conntype; - extern char *nouveau_perflvl; - extern int nouveau_perflvl_wr; -+extern int nouveau_msi; - - extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); - extern int nouveau_pci_resume(struct pci_dev *pdev); -@@ -762,8 +820,10 @@ - struct drm_file *); - extern int nouveau_ioctl_setparam(struct drm_device *, void *data, - struct drm_file *); --extern bool nouveau_wait_until(struct drm_device *, uint64_t timeout, -- uint32_t reg, uint32_t mask, uint32_t val); -+extern bool nouveau_wait_eq(struct drm_device *, uint64_t timeout, -+ uint32_t reg, uint32_t mask, uint32_t val); -+extern bool nouveau_wait_ne(struct drm_device *, uint64_t timeout, -+ uint32_t reg, uint32_t mask, uint32_t val); - extern bool nouveau_wait_for_idle(struct drm_device *); - extern int nouveau_card_init(struct drm_device *); - -@@ -775,18 +835,18 @@ - extern int nouveau_mem_init_agp(struct drm_device *); - extern int nouveau_mem_reset_agp(struct drm_device *); - extern void nouveau_mem_close(struct drm_device *); --extern struct nouveau_tile_reg *nv10_mem_set_tiling(struct drm_device *dev, -- uint32_t addr, -- uint32_t size, -- uint32_t pitch); --extern void nv10_mem_expire_tiling(struct drm_device *dev, -- struct nouveau_tile_reg *tile, -- struct nouveau_fence *fence); --extern int nv50_mem_vm_bind_linear(struct drm_device *, uint64_t virt, -- uint32_t size, uint32_t flags, -- uint64_t phys); --extern void nv50_mem_vm_unbind(struct drm_device *, uint64_t virt, -- uint32_t size); -+extern int nouveau_mem_detect(struct drm_device *); -+extern bool nouveau_mem_flags_valid(struct drm_device *, u32 tile_flags); -+extern struct nouveau_tile_reg *nv10_mem_set_tiling( -+ struct drm_device *dev, uint32_t addr, uint32_t size, -+ uint32_t pitch, uint32_t flags); -+extern void nv10_mem_put_tile_region(struct drm_device *dev, -+ struct nouveau_tile_reg *tile, -+ struct nouveau_fence *fence); -+extern const struct ttm_mem_type_manager_func nouveau_vram_manager; -+ -+/* nvc0_vram.c */ -+extern const struct ttm_mem_type_manager_func nvc0_vram_manager; - - /* nouveau_notifier.c */ - extern int nouveau_notifier_init_channel(struct nouveau_channel *); -@@ -803,21 +863,44 @@ - extern struct drm_ioctl_desc nouveau_ioctls[]; - extern int nouveau_max_ioctl; - extern void nouveau_channel_cleanup(struct drm_device *, struct drm_file *); --extern int nouveau_channel_owner(struct drm_device *, struct drm_file *, -- int channel); - extern int nouveau_channel_alloc(struct drm_device *dev, - struct nouveau_channel **chan, - struct drm_file *file_priv, - uint32_t fb_ctxdma, uint32_t tt_ctxdma); --extern void nouveau_channel_free(struct nouveau_channel *); -+extern struct nouveau_channel * -+nouveau_channel_get_unlocked(struct nouveau_channel *); -+extern struct nouveau_channel * -+nouveau_channel_get(struct drm_device *, struct drm_file *, int id); -+extern void nouveau_channel_put_unlocked(struct nouveau_channel **); -+extern void nouveau_channel_put(struct nouveau_channel **); -+extern void nouveau_channel_ref(struct nouveau_channel *chan, -+ struct nouveau_channel **pchan); -+extern void nouveau_channel_idle(struct nouveau_channel *chan); - - /* nouveau_object.c */ -+#define NVOBJ_CLASS(d,c,e) do { \ -+ int ret = nouveau_gpuobj_class_new((d), (c), NVOBJ_ENGINE_##e); \ -+ if (ret) \ -+ return ret; \ -+} while(0) -+ -+#define NVOBJ_MTHD(d,c,m,e) do { \ -+ int ret = nouveau_gpuobj_mthd_new((d), (c), (m), (e)); \ -+ if (ret) \ -+ return ret; \ -+} while(0) -+ - extern int nouveau_gpuobj_early_init(struct drm_device *); - extern int nouveau_gpuobj_init(struct drm_device *); - extern void nouveau_gpuobj_takedown(struct drm_device *); - extern int nouveau_gpuobj_suspend(struct drm_device *dev); --extern void nouveau_gpuobj_suspend_cleanup(struct drm_device *dev); - 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)); -+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 *, - uint32_t vram_h, uint32_t tt_h); - extern void nouveau_gpuobj_channel_takedown(struct nouveau_channel *); -@@ -832,21 +915,25 @@ - extern int nouveau_gpuobj_dma_new(struct nouveau_channel *, int class, - uint64_t offset, uint64_t size, int access, - int target, struct nouveau_gpuobj **); --extern int nouveau_gpuobj_gart_dma_new(struct nouveau_channel *, -- uint64_t offset, uint64_t size, -- int access, struct nouveau_gpuobj **, -- uint32_t *o_ret); --extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, int class, -- struct nouveau_gpuobj **); --extern int nouveau_gpuobj_sw_new(struct nouveau_channel *, int class, -- struct nouveau_gpuobj **); -+extern int nouveau_gpuobj_gr_new(struct nouveau_channel *, u32 handle, int class); -+extern int nv50_gpuobj_dma_new(struct nouveau_channel *, int class, u64 base, -+ u64 size, int target, int access, u32 type, -+ u32 comp, struct nouveau_gpuobj **pobj); -+extern void nv50_gpuobj_dma_init(struct nouveau_gpuobj *, u32 offset, -+ int class, u64 base, u64 size, int target, -+ int access, u32 type, u32 comp); - extern int nouveau_ioctl_grobj_alloc(struct drm_device *, void *data, - struct drm_file *); - extern int nouveau_ioctl_gpuobj_free(struct drm_device *, void *data, - struct drm_file *); - - /* nouveau_irq.c */ -+extern int nouveau_irq_init(struct drm_device *); -+extern void nouveau_irq_fini(struct drm_device *); - extern irqreturn_t nouveau_irq_handler(DRM_IRQ_ARGS); -+extern void nouveau_irq_register(struct drm_device *, int status_bit, -+ void (*)(struct drm_device *)); -+extern void nouveau_irq_unregister(struct drm_device *, int status_bit); - extern void nouveau_irq_preinstall(struct drm_device *); - extern int nouveau_irq_postinstall(struct drm_device *); - extern void nouveau_irq_uninstall(struct drm_device *); -@@ -854,8 +941,8 @@ - /* nouveau_sgdma.c */ - extern int nouveau_sgdma_init(struct drm_device *); - extern void nouveau_sgdma_takedown(struct drm_device *); --extern int nouveau_sgdma_get_page(struct drm_device *, uint32_t offset, -- uint32_t *page); -+extern uint32_t nouveau_sgdma_get_physical(struct drm_device *, -+ uint32_t offset); - extern struct ttm_backend *nouveau_sgdma_init_ttm(struct drm_device *); - - /* nouveau_debugfs.c */ -@@ -966,18 +1053,25 @@ - /* nv10_fb.c */ - extern int nv10_fb_init(struct drm_device *); - extern void nv10_fb_takedown(struct drm_device *); --extern void nv10_fb_set_region_tiling(struct drm_device *, int, uint32_t, -- uint32_t, uint32_t); -+extern void nv10_fb_init_tile_region(struct drm_device *dev, int i, -+ uint32_t addr, uint32_t size, -+ uint32_t pitch, uint32_t flags); -+extern void nv10_fb_set_tile_region(struct drm_device *dev, int i); -+extern void nv10_fb_free_tile_region(struct drm_device *dev, int i); - - /* nv30_fb.c */ - extern int nv30_fb_init(struct drm_device *); - extern void nv30_fb_takedown(struct drm_device *); -+extern void nv30_fb_init_tile_region(struct drm_device *dev, int i, -+ uint32_t addr, uint32_t size, -+ uint32_t pitch, uint32_t flags); -+extern void nv30_fb_free_tile_region(struct drm_device *dev, int i); - - /* nv40_fb.c */ - extern int nv40_fb_init(struct drm_device *); - extern void nv40_fb_takedown(struct drm_device *); --extern void nv40_fb_set_region_tiling(struct drm_device *, int, uint32_t, -- uint32_t, uint32_t); -+extern void nv40_fb_set_tile_region(struct drm_device *dev, int i); -+ - /* nv50_fb.c */ - extern int nv50_fb_init(struct drm_device *); - extern void nv50_fb_takedown(struct drm_device *); -@@ -989,6 +1083,7 @@ - - /* nv04_fifo.c */ - extern int nv04_fifo_init(struct drm_device *); -+extern void nv04_fifo_fini(struct drm_device *); - extern void nv04_fifo_disable(struct drm_device *); - extern void nv04_fifo_enable(struct drm_device *); - extern bool nv04_fifo_reassign(struct drm_device *, bool); -@@ -998,19 +1093,18 @@ - extern void nv04_fifo_destroy_context(struct nouveau_channel *); - extern int nv04_fifo_load_context(struct nouveau_channel *); - extern int nv04_fifo_unload_context(struct drm_device *); -+extern void nv04_fifo_isr(struct drm_device *); - - /* nv10_fifo.c */ - extern int nv10_fifo_init(struct drm_device *); - extern int nv10_fifo_channel_id(struct drm_device *); - extern int nv10_fifo_create_context(struct nouveau_channel *); --extern void nv10_fifo_destroy_context(struct nouveau_channel *); - extern int nv10_fifo_load_context(struct nouveau_channel *); - extern int nv10_fifo_unload_context(struct drm_device *); - - /* nv40_fifo.c */ - extern int nv40_fifo_init(struct drm_device *); - extern int nv40_fifo_create_context(struct nouveau_channel *); --extern void nv40_fifo_destroy_context(struct nouveau_channel *); - extern int nv40_fifo_load_context(struct nouveau_channel *); - extern int nv40_fifo_unload_context(struct drm_device *); - -@@ -1038,7 +1132,6 @@ - extern int nvc0_fifo_unload_context(struct drm_device *); - - /* nv04_graph.c */ --extern struct nouveau_pgraph_object_class nv04_graph_grclass[]; - extern int nv04_graph_init(struct drm_device *); - extern void nv04_graph_takedown(struct drm_device *); - extern void nv04_graph_fifo_access(struct drm_device *, bool); -@@ -1047,10 +1140,11 @@ - 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 void nv04_graph_context_switch(struct drm_device *); -+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 struct nouveau_pgraph_object_class nv10_graph_grclass[]; - extern int nv10_graph_init(struct drm_device *); - extern void nv10_graph_takedown(struct drm_device *); - extern struct nouveau_channel *nv10_graph_channel(struct drm_device *); -@@ -1058,13 +1152,11 @@ - 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_context_switch(struct drm_device *); --extern void nv10_graph_set_region_tiling(struct drm_device *, int, uint32_t, -- uint32_t, uint32_t); -+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 struct nouveau_pgraph_object_class nv20_graph_grclass[]; --extern struct nouveau_pgraph_object_class nv30_graph_grclass[]; - 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 *); -@@ -1072,11 +1164,9 @@ - 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_region_tiling(struct drm_device *, int, uint32_t, -- uint32_t, uint32_t); -+extern void nv20_graph_set_tile_region(struct drm_device *dev, int i); - - /* nv40_graph.c */ --extern struct nouveau_pgraph_object_class nv40_graph_grclass[]; - 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 *); -@@ -1085,11 +1175,9 @@ - extern int nv40_graph_load_context(struct nouveau_channel *); - extern int nv40_graph_unload_context(struct drm_device *); - extern void nv40_grctx_init(struct nouveau_grctx *); --extern void nv40_graph_set_region_tiling(struct drm_device *, int, uint32_t, -- uint32_t, uint32_t); -+extern void nv40_graph_set_tile_region(struct drm_device *dev, int i); - - /* nv50_graph.c */ --extern struct nouveau_pgraph_object_class nv50_graph_grclass[]; - 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); -@@ -1098,10 +1186,10 @@ - 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 void nv50_graph_context_switch(struct drm_device *); - extern int nv50_grctx_init(struct nouveau_grctx *); - extern void nv50_graph_tlb_flush(struct drm_device *dev); - extern void nv86_graph_tlb_flush(struct drm_device *dev); -+extern struct nouveau_enum nv50_data_error_names[]; - - /* nvc0_graph.c */ - extern int nvc0_graph_init(struct drm_device *); -@@ -1113,16 +1201,22 @@ - extern int nvc0_graph_load_context(struct nouveau_channel *); - extern int nvc0_graph_unload_context(struct drm_device *); - -+/* 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); -+ - /* nv04_instmem.c */ - extern int nv04_instmem_init(struct drm_device *); - extern void nv04_instmem_takedown(struct drm_device *); - extern int nv04_instmem_suspend(struct drm_device *); - extern void nv04_instmem_resume(struct drm_device *); --extern int nv04_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, -- uint32_t *size); --extern void nv04_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); --extern int nv04_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); --extern int nv04_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); -+extern int nv04_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); -+extern void nv04_instmem_put(struct nouveau_gpuobj *); -+extern int nv04_instmem_map(struct nouveau_gpuobj *); -+extern void nv04_instmem_unmap(struct nouveau_gpuobj *); - extern void nv04_instmem_flush(struct drm_device *); - - /* nv50_instmem.c */ -@@ -1130,26 +1224,18 @@ - extern void nv50_instmem_takedown(struct drm_device *); - extern int nv50_instmem_suspend(struct drm_device *); - extern void nv50_instmem_resume(struct drm_device *); --extern int nv50_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, -- uint32_t *size); --extern void nv50_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); --extern int nv50_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); --extern int nv50_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); -+extern int nv50_instmem_get(struct nouveau_gpuobj *, u32 size, u32 align); -+extern void nv50_instmem_put(struct nouveau_gpuobj *); -+extern int nv50_instmem_map(struct nouveau_gpuobj *); -+extern void nv50_instmem_unmap(struct nouveau_gpuobj *); - extern void nv50_instmem_flush(struct drm_device *); - extern void nv84_instmem_flush(struct drm_device *); --extern void nv50_vm_flush(struct drm_device *, int engine); - - /* nvc0_instmem.c */ - extern int nvc0_instmem_init(struct drm_device *); - extern void nvc0_instmem_takedown(struct drm_device *); - extern int nvc0_instmem_suspend(struct drm_device *); - extern void nvc0_instmem_resume(struct drm_device *); --extern int nvc0_instmem_populate(struct drm_device *, struct nouveau_gpuobj *, -- uint32_t *size); --extern void nvc0_instmem_clear(struct drm_device *, struct nouveau_gpuobj *); --extern int nvc0_instmem_bind(struct drm_device *, struct nouveau_gpuobj *); --extern int nvc0_instmem_unbind(struct drm_device *, struct nouveau_gpuobj *); --extern void nvc0_instmem_flush(struct drm_device *); - - /* nv04_mc.c */ - extern int nv04_mc_init(struct drm_device *); -@@ -1219,6 +1305,9 @@ - extern void nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val); - extern u32 nouveau_bo_rd32(struct nouveau_bo *nvbo, unsigned index); - extern void nouveau_bo_wr32(struct nouveau_bo *nvbo, unsigned index, u32 val); -+extern void nouveau_bo_fence(struct nouveau_bo *, struct nouveau_fence *); -+extern int nouveau_bo_validate(struct nouveau_bo *, bool interruptible, -+ bool no_wait_reserve, bool no_wait_gpu); - - /* nouveau_fence.c */ - struct nouveau_fence; -@@ -1234,12 +1323,35 @@ - void (*work)(void *priv, bool signalled), - void *priv); - struct nouveau_channel *nouveau_fence_channel(struct nouveau_fence *); --extern bool nouveau_fence_signalled(void *obj, void *arg); --extern int nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); -+ -+extern bool __nouveau_fence_signalled(void *obj, void *arg); -+extern int __nouveau_fence_wait(void *obj, void *arg, bool lazy, bool intr); -+extern int __nouveau_fence_flush(void *obj, void *arg); -+extern void __nouveau_fence_unref(void **obj); -+extern void *__nouveau_fence_ref(void *obj); -+ -+static inline bool nouveau_fence_signalled(struct nouveau_fence *obj) -+{ -+ return __nouveau_fence_signalled(obj, NULL); -+} -+static inline int -+nouveau_fence_wait(struct nouveau_fence *obj, bool lazy, bool intr) -+{ -+ return __nouveau_fence_wait(obj, NULL, lazy, intr); -+} - extern int nouveau_fence_sync(struct nouveau_fence *, struct nouveau_channel *); --extern int nouveau_fence_flush(void *obj, void *arg); --extern void nouveau_fence_unref(void **obj); --extern void *nouveau_fence_ref(void *obj); -+static inline int nouveau_fence_flush(struct nouveau_fence *obj) -+{ -+ return __nouveau_fence_flush(obj, NULL); -+} -+static inline void nouveau_fence_unref(struct nouveau_fence **obj) -+{ -+ __nouveau_fence_unref((void **)obj); -+} -+static inline struct nouveau_fence *nouveau_fence_ref(struct nouveau_fence *obj) -+{ -+ return __nouveau_fence_ref(obj); -+} - - /* nouveau_gem.c */ - extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, -@@ -1259,15 +1371,28 @@ - extern int nouveau_gem_ioctl_info(struct drm_device *, void *, - struct drm_file *); - -+/* nouveau_display.c */ -+int nouveau_vblank_enable(struct drm_device *dev, int crtc); -+void nouveau_vblank_disable(struct drm_device *dev, int crtc); -+int nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, -+ struct drm_pending_vblank_event *event); -+int nouveau_finish_page_flip(struct nouveau_channel *, -+ struct nouveau_page_flip_state *); -+ - /* nv10_gpio.c */ - int nv10_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); - int nv10_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); - - /* nv50_gpio.c */ - int nv50_gpio_init(struct drm_device *dev); -+void nv50_gpio_fini(struct drm_device *dev); - int nv50_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); - int nv50_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); --void nv50_gpio_irq_enable(struct drm_device *, enum dcb_gpio_tag, bool on); -+int nv50_gpio_irq_register(struct drm_device *, enum dcb_gpio_tag, -+ void (*)(void *, int), void *); -+void nv50_gpio_irq_unregister(struct drm_device *, enum dcb_gpio_tag, -+ void (*)(void *, int), void *); -+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, -@@ -1334,7 +1459,9 @@ - } - - #define nv_wait(dev, reg, mask, val) \ -- nouveau_wait_until(dev, 2000000000ULL, (reg), (mask), (val)) -+ nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) -+#define nv_wait_ne(dev, reg, mask, val) \ -+ nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) - - /* PRAMIN access */ - static inline u32 nv_ri32(struct drm_device *dev, unsigned offset) -@@ -1447,6 +1574,23 @@ - dev->pdev->subsystem_device == sub_device; - } - -+/* memory type/access flags, do not match hardware values */ -+#define NV_MEM_ACCESS_RO 1 -+#define NV_MEM_ACCESS_WO 2 -+#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO) -+#define NV_MEM_ACCESS_SYS 4 -+#define NV_MEM_ACCESS_VM 8 -+ -+#define NV_MEM_TARGET_VRAM 0 -+#define NV_MEM_TARGET_PCI 1 -+#define NV_MEM_TARGET_PCI_NOSNOOP 2 -+#define NV_MEM_TARGET_VM 3 -+#define NV_MEM_TARGET_GART 4 -+ -+#define NV_MEM_TYPE_VM 0x7f -+#define NV_MEM_COMP_VM 0x03 -+ -+/* NV_SW object class */ - #define NV_SW 0x0000506e - #define NV_SW_DMA_SEMAPHORE 0x00000060 - #define NV_SW_SEMAPHORE_OFFSET 0x00000064 -@@ -1457,5 +1601,6 @@ - #define NV_SW_VBLSEM_OFFSET 0x00000400 - #define NV_SW_VBLSEM_RELEASE_VALUE 0x00000404 - #define NV_SW_VBLSEM_RELEASE 0x00000408 -+#define NV_SW_PAGE_FLIP 0x00000500 - - #endif /* __NOUVEAU_DRV_H__ */ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_fbcon.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_fbcon.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2011-01-07 14:22:17.000000000 +0100 -@@ -49,6 +49,102 @@ - #include "nouveau_fbcon.h" - #include "nouveau_dma.h" - -+static void -+nouveau_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int ret; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return; -+ -+ ret = -ENODEV; -+ if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && -+ mutex_trylock(&dev_priv->channel->mutex)) { -+ if (dev_priv->card_type < NV_50) -+ ret = nv04_fbcon_fillrect(info, rect); -+ else -+ if (dev_priv->card_type < NV_C0) -+ ret = nv50_fbcon_fillrect(info, rect); -+ else -+ ret = nvc0_fbcon_fillrect(info, rect); -+ mutex_unlock(&dev_priv->channel->mutex); -+ } -+ -+ if (ret == 0) -+ return; -+ -+ if (ret != -ENODEV) -+ nouveau_fbcon_gpu_lockup(info); -+ cfb_fillrect(info, rect); -+} -+ -+static void -+nouveau_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *image) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int ret; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return; -+ -+ ret = -ENODEV; -+ if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && -+ mutex_trylock(&dev_priv->channel->mutex)) { -+ if (dev_priv->card_type < NV_50) -+ ret = nv04_fbcon_copyarea(info, image); -+ else -+ if (dev_priv->card_type < NV_C0) -+ ret = nv50_fbcon_copyarea(info, image); -+ else -+ ret = nvc0_fbcon_copyarea(info, image); -+ mutex_unlock(&dev_priv->channel->mutex); -+ } -+ -+ if (ret == 0) -+ return; -+ -+ if (ret != -ENODEV) -+ nouveau_fbcon_gpu_lockup(info); -+ cfb_copyarea(info, image); -+} -+ -+static void -+nouveau_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int ret; -+ -+ if (info->state != FBINFO_STATE_RUNNING) -+ return; -+ -+ ret = -ENODEV; -+ if (!in_interrupt() && !(info->flags & FBINFO_HWACCEL_DISABLED) && -+ mutex_trylock(&dev_priv->channel->mutex)) { -+ if (dev_priv->card_type < NV_50) -+ ret = nv04_fbcon_imageblit(info, image); -+ else -+ if (dev_priv->card_type < NV_C0) -+ ret = nv50_fbcon_imageblit(info, image); -+ else -+ ret = nvc0_fbcon_imageblit(info, image); -+ mutex_unlock(&dev_priv->channel->mutex); -+ } -+ -+ if (ret == 0) -+ return; -+ -+ if (ret != -ENODEV) -+ nouveau_fbcon_gpu_lockup(info); -+ cfb_imageblit(info, image); -+} -+ - static int - nouveau_fbcon_sync(struct fb_info *info) - { -@@ -58,22 +154,36 @@ - struct nouveau_channel *chan = dev_priv->channel; - int ret, i; - -- if (!chan || !chan->accel_done || -+ if (!chan || !chan->accel_done || in_interrupt() || - info->state != FBINFO_STATE_RUNNING || - info->flags & FBINFO_HWACCEL_DISABLED) - return 0; - -- if (RING_SPACE(chan, 4)) { -+ if (!mutex_trylock(&chan->mutex)) -+ return 0; -+ -+ ret = RING_SPACE(chan, 4); -+ if (ret) { -+ mutex_unlock(&chan->mutex); - nouveau_fbcon_gpu_lockup(info); - return 0; - } - -- BEGIN_RING(chan, 0, 0x0104, 1); -- OUT_RING(chan, 0); -- BEGIN_RING(chan, 0, 0x0100, 1); -- OUT_RING(chan, 0); -+ if (dev_priv->card_type >= NV_C0) { -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x010c, 1); -+ OUT_RING (chan, 0); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0100, 1); -+ OUT_RING (chan, 0); -+ } else { -+ BEGIN_RING(chan, 0, 0x0104, 1); -+ OUT_RING (chan, 0); -+ BEGIN_RING(chan, 0, 0x0100, 1); -+ OUT_RING (chan, 0); -+ } -+ - nouveau_bo_wr32(chan->notifier_bo, chan->m2mf_ntfy + 3, 0xffffffff); - FIRE_RING(chan); -+ mutex_unlock(&chan->mutex); - - ret = -EBUSY; - for (i = 0; i < 100000; i++) { -@@ -97,9 +207,9 @@ - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, -- .fb_fillrect = cfb_fillrect, -- .fb_copyarea = cfb_copyarea, -- .fb_imageblit = cfb_imageblit, -+ .fb_fillrect = nouveau_fbcon_fillrect, -+ .fb_copyarea = nouveau_fbcon_copyarea, -+ .fb_imageblit = nouveau_fbcon_imageblit, - .fb_sync = nouveau_fbcon_sync, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, -@@ -108,29 +218,13 @@ - .fb_debug_leave = drm_fb_helper_debug_leave, - }; - --static struct fb_ops nv04_fbcon_ops = { -+static struct fb_ops nouveau_fbcon_sw_ops = { - .owner = THIS_MODULE, - .fb_check_var = drm_fb_helper_check_var, - .fb_set_par = drm_fb_helper_set_par, -- .fb_fillrect = nv04_fbcon_fillrect, -- .fb_copyarea = nv04_fbcon_copyarea, -- .fb_imageblit = nv04_fbcon_imageblit, -- .fb_sync = nouveau_fbcon_sync, -- .fb_pan_display = drm_fb_helper_pan_display, -- .fb_blank = drm_fb_helper_blank, -- .fb_setcmap = drm_fb_helper_setcmap, -- .fb_debug_enter = drm_fb_helper_debug_enter, -- .fb_debug_leave = drm_fb_helper_debug_leave, --}; -- --static struct fb_ops nv50_fbcon_ops = { -- .owner = THIS_MODULE, -- .fb_check_var = drm_fb_helper_check_var, -- .fb_set_par = drm_fb_helper_set_par, -- .fb_fillrect = nv50_fbcon_fillrect, -- .fb_copyarea = nv50_fbcon_copyarea, -- .fb_imageblit = nv50_fbcon_imageblit, -- .fb_sync = nouveau_fbcon_sync, -+ .fb_fillrect = cfb_fillrect, -+ .fb_copyarea = cfb_copyarea, -+ .fb_imageblit = cfb_imageblit, - .fb_pan_display = drm_fb_helper_pan_display, - .fb_blank = drm_fb_helper_blank, - .fb_setcmap = drm_fb_helper_setcmap, -@@ -257,9 +351,9 @@ - FBINFO_HWACCEL_FILLRECT | - FBINFO_HWACCEL_IMAGEBLIT; - info->flags |= FBINFO_CAN_FORCE_OUTPUT; -- info->fbops = &nouveau_fbcon_ops; -- info->fix.smem_start = dev->mode_config.fb_base + nvbo->bo.offset - -- dev_priv->vm_vram_base; -+ info->fbops = &nouveau_fbcon_sw_ops; -+ info->fix.smem_start = dev->mode_config.fb_base + -+ (nvbo->bo.mem.start << PAGE_SHIFT); - info->fix.smem_len = size; - - info->screen_base = nvbo_kmap_obj_iovirtual(nouveau_fb->nvbo); -@@ -285,19 +379,20 @@ - info->pixmap.flags = FB_PIXMAP_SYSTEM; - info->pixmap.scan_align = 1; - -+ mutex_unlock(&dev->struct_mutex); -+ - if (dev_priv->channel && !nouveau_nofbaccel) { -- switch (dev_priv->card_type) { -- case NV_C0: -- break; -- case NV_50: -- nv50_fbcon_accel_init(info); -- info->fbops = &nv50_fbcon_ops; -- break; -- default: -- nv04_fbcon_accel_init(info); -- info->fbops = &nv04_fbcon_ops; -- break; -- }; -+ ret = -ENODEV; -+ if (dev_priv->card_type < NV_50) -+ ret = nv04_fbcon_accel_init(info); -+ else -+ if (dev_priv->card_type < NV_C0) -+ ret = nv50_fbcon_accel_init(info); -+ else -+ ret = nvc0_fbcon_accel_init(info); -+ -+ if (ret == 0) -+ info->fbops = &nouveau_fbcon_ops; - } - - nouveau_fbcon_zfill(dev, nfbdev); -@@ -308,7 +403,6 @@ - nouveau_fb->base.height, - nvbo->bo.offset, nvbo); - -- mutex_unlock(&dev->struct_mutex); - vga_switcheroo_client_fb_set(dev->pdev, info); - return 0; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_fbcon.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_fbcon.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_fbcon.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_fbcon.h 2011-01-07 14:22:17.000000000 +0100 -@@ -40,15 +40,21 @@ - - void nouveau_fbcon_restore(void); - --void nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); --void nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); --void nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); -+int nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -+int nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -+int nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); - int nv04_fbcon_accel_init(struct fb_info *info); --void nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); --void nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); --void nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); -+ -+int nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -+int nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -+int nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); - int nv50_fbcon_accel_init(struct fb_info *info); - -+int nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect); -+int nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region); -+int nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image); -+int nvc0_fbcon_accel_init(struct fb_info *info); -+ - void nouveau_fbcon_gpu_lockup(struct fb_info *info); - - int nouveau_fbcon_init(struct drm_device *dev); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_fence.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_fence.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_fence.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_fence.c 2011-01-07 14:22:17.000000000 +0100 -@@ -32,7 +32,8 @@ - #include "nouveau_dma.h" - - #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) --#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17) -+#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \ -+ nouveau_private(dev)->card_type < NV_C0) - - struct nouveau_fence { - struct nouveau_channel *channel; -@@ -64,6 +65,7 @@ - struct nouveau_fence *fence = - container_of(ref, struct nouveau_fence, refcount); - -+ nouveau_channel_ref(NULL, &fence->channel); - kfree(fence); - } - -@@ -76,14 +78,17 @@ - - spin_lock(&chan->fence.lock); - -- if (USE_REFCNT(dev)) -- sequence = nvchan_rd32(chan, 0x48); -- else -- sequence = atomic_read(&chan->fence.last_sequence_irq); -- -- if (chan->fence.sequence_ack == sequence) -- goto out; -- chan->fence.sequence_ack = sequence; -+ /* Fetch the last sequence if the channel is still up and running */ -+ if (likely(!list_empty(&chan->fence.pending))) { -+ if (USE_REFCNT(dev)) -+ sequence = nvchan_rd32(chan, 0x48); -+ else -+ sequence = atomic_read(&chan->fence.last_sequence_irq); -+ -+ if (chan->fence.sequence_ack == sequence) -+ goto out; -+ chan->fence.sequence_ack = sequence; -+ } - - list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { - sequence = fence->sequence; -@@ -113,13 +118,13 @@ - if (!fence) - return -ENOMEM; - kref_init(&fence->refcount); -- fence->channel = chan; -+ nouveau_channel_ref(chan, &fence->channel); - - if (emit) - ret = nouveau_fence_emit(fence); - - if (ret) -- nouveau_fence_unref((void *)&fence); -+ nouveau_fence_unref(&fence); - *pfence = fence; - return ret; - } -@@ -127,7 +132,7 @@ - struct nouveau_channel * - nouveau_fence_channel(struct nouveau_fence *fence) - { -- return fence ? fence->channel : NULL; -+ return fence ? nouveau_channel_get_unlocked(fence->channel) : NULL; - } - - int -@@ -135,6 +140,7 @@ - { - struct nouveau_channel *chan = fence->channel; - struct drm_device *dev = chan->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; - int ret; - - ret = RING_SPACE(chan, 2); -@@ -155,8 +161,15 @@ - list_add_tail(&fence->entry, &chan->fence.pending); - spin_unlock(&chan->fence.lock); - -- BEGIN_RING(chan, NvSubSw, USE_REFCNT(dev) ? 0x0050 : 0x0150, 1); -- OUT_RING(chan, fence->sequence); -+ if (USE_REFCNT(dev)) { -+ if (dev_priv->card_type < NV_C0) -+ BEGIN_RING(chan, NvSubSw, 0x0050, 1); -+ else -+ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0050, 1); -+ } else { -+ BEGIN_RING(chan, NvSubSw, 0x0150, 1); -+ } -+ OUT_RING (chan, fence->sequence); - FIRE_RING(chan); - - return 0; -@@ -182,7 +195,7 @@ - } - - void --nouveau_fence_unref(void **sync_obj) -+__nouveau_fence_unref(void **sync_obj) - { - struct nouveau_fence *fence = nouveau_fence(*sync_obj); - -@@ -192,7 +205,7 @@ - } - - void * --nouveau_fence_ref(void *sync_obj) -+__nouveau_fence_ref(void *sync_obj) - { - struct nouveau_fence *fence = nouveau_fence(sync_obj); - -@@ -201,7 +214,7 @@ - } - - bool --nouveau_fence_signalled(void *sync_obj, void *sync_arg) -+__nouveau_fence_signalled(void *sync_obj, void *sync_arg) - { - struct nouveau_fence *fence = nouveau_fence(sync_obj); - struct nouveau_channel *chan = fence->channel; -@@ -214,13 +227,14 @@ - } - - int --nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) -+__nouveau_fence_wait(void *sync_obj, void *sync_arg, bool lazy, bool intr) - { - unsigned long timeout = jiffies + (3 * DRM_HZ); -+ unsigned long sleep_time = jiffies + 1; - int ret = 0; - - while (1) { -- if (nouveau_fence_signalled(sync_obj, sync_arg)) -+ if (__nouveau_fence_signalled(sync_obj, sync_arg)) - break; - - if (time_after_eq(jiffies, timeout)) { -@@ -230,7 +244,7 @@ - - __set_current_state(intr ? TASK_INTERRUPTIBLE - : TASK_UNINTERRUPTIBLE); -- if (lazy) -+ if (lazy && time_after_eq(jiffies, sleep_time)) - schedule_timeout(1); - - if (intr && signal_pending(current)) { -@@ -368,7 +382,7 @@ - - kref_get(&sema->ref); - nouveau_fence_work(fence, semaphore_work, sema); -- nouveau_fence_unref((void *)&fence); -+ nouveau_fence_unref(&fence); - - return 0; - } -@@ -380,33 +394,49 @@ - struct nouveau_channel *chan = nouveau_fence_channel(fence); - struct drm_device *dev = wchan->dev; - struct nouveau_semaphore *sema; -- int ret; -+ int ret = 0; - -- if (likely(!fence || chan == wchan || -- nouveau_fence_signalled(fence, NULL))) -- return 0; -+ if (likely(!chan || chan == wchan || -+ nouveau_fence_signalled(fence))) -+ goto out; - - sema = alloc_semaphore(dev); - if (!sema) { - /* Early card or broken userspace, fall back to - * software sync. */ -- return nouveau_fence_wait(fence, NULL, false, false); -+ ret = nouveau_fence_wait(fence, true, false); -+ goto out; -+ } -+ -+ /* try to take chan's mutex, if we can't take it right away -+ * we have to fallback to software sync to prevent locking -+ * order issues -+ */ -+ if (!mutex_trylock(&chan->mutex)) { -+ ret = nouveau_fence_wait(fence, true, false); -+ goto out_unref; - } - - /* Make wchan wait until it gets signalled */ - ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); - if (ret) -- goto out; -+ goto out_unlock; - - /* Signal the semaphore from chan */ - ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); --out: -+ -+out_unlock: -+ mutex_unlock(&chan->mutex); -+out_unref: - kref_put(&sema->ref, free_semaphore); -+out: -+ if (chan) -+ nouveau_channel_put_unlocked(&chan); - return ret; - } - - int --nouveau_fence_flush(void *sync_obj, void *sync_arg) -+__nouveau_fence_flush(void *sync_obj, void *sync_arg) - { - return 0; - } -@@ -420,30 +450,27 @@ - int ret; - - /* Create an NV_SW object for various sync purposes */ -- ret = nouveau_gpuobj_sw_new(chan, NV_SW, &obj); -- if (ret) -- return ret; -- -- ret = nouveau_ramht_insert(chan, NvSw, obj); -- nouveau_gpuobj_ref(NULL, &obj); -+ ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); - if (ret) - return ret; - -- ret = RING_SPACE(chan, 2); -- if (ret) -- return ret; -- BEGIN_RING(chan, NvSubSw, 0, 1); -- OUT_RING(chan, NvSw); -+ /* we leave subchannel empty for nvc0 */ -+ if (dev_priv->card_type < NV_C0) { -+ ret = RING_SPACE(chan, 2); -+ if (ret) -+ return ret; -+ BEGIN_RING(chan, NvSubSw, 0, 1); -+ OUT_RING(chan, NvSw); -+ } - - /* Create a DMA object for the shared cross-channel sync area. */ - if (USE_SEMA(dev)) { -- struct drm_mm_node *mem = dev_priv->fence.bo->bo.mem.mm_node; -+ struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; - - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - mem->start << PAGE_SHIFT, -- mem->size << PAGE_SHIFT, -- NV_DMA_ACCESS_RW, -- NV_DMA_TARGET_VIDMEM, &obj); -+ mem->size, NV_MEM_ACCESS_RW, -+ NV_MEM_TARGET_VRAM, &obj); - if (ret) - return ret; - -@@ -473,6 +500,8 @@ - { - struct nouveau_fence *tmp, *fence; - -+ spin_lock(&chan->fence.lock); -+ - list_for_each_entry_safe(fence, tmp, &chan->fence.pending, entry) { - fence->signalled = true; - list_del(&fence->entry); -@@ -482,6 +511,8 @@ - - kref_put(&fence->refcount, nouveau_fence_del); - } -+ -+ spin_unlock(&chan->fence.lock); - } - - int -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_gem.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_gem.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_gem.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_gem.c 2011-01-07 14:22:17.000000000 +0100 -@@ -48,9 +48,6 @@ - return; - nvbo->gem = NULL; - -- if (unlikely(nvbo->cpu_filp)) -- ttm_bo_synccpu_write_release(bo); -- - if (unlikely(nvbo->pin_refcnt)) { - nvbo->pin_refcnt = 1; - nouveau_bo_unpin(nvbo); -@@ -106,32 +103,6 @@ - return 0; - } - --static bool --nouveau_gem_tile_flags_valid(struct drm_device *dev, uint32_t tile_flags) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- -- if (dev_priv->card_type >= NV_50) { -- switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { -- case 0x0000: -- case 0x1800: -- case 0x2800: -- case 0x4800: -- case 0x7000: -- case 0x7400: -- case 0x7a00: -- case 0xe000: -- return true; -- } -- } else { -- if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) -- return true; -- } -- -- NV_ERROR(dev, "bad page flags: 0x%08x\n", tile_flags); -- return false; --} -- - int - nouveau_gem_ioctl_new(struct drm_device *dev, void *data, - struct drm_file *file_priv) -@@ -146,11 +117,6 @@ - if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) - dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; - -- if (req->channel_hint) { -- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel_hint, -- file_priv, chan); -- } -- - if (req->info.domain & NOUVEAU_GEM_DOMAIN_VRAM) - flags |= TTM_PL_FLAG_VRAM; - if (req->info.domain & NOUVEAU_GEM_DOMAIN_GART) -@@ -158,13 +124,23 @@ - if (!flags || req->info.domain & NOUVEAU_GEM_DOMAIN_CPU) - flags |= TTM_PL_FLAG_SYSTEM; - -- if (!nouveau_gem_tile_flags_valid(dev, req->info.tile_flags)) -+ if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) { -+ NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags); - return -EINVAL; -+ } -+ -+ if (req->channel_hint) { -+ chan = nouveau_channel_get(dev, file_priv, req->channel_hint); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); -+ } - - ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags, - req->info.tile_mode, req->info.tile_flags, false, - (req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE), - &nvbo); -+ if (chan) -+ nouveau_channel_put(&chan); - if (ret) - return ret; - -@@ -231,15 +207,8 @@ - - list_for_each_safe(entry, tmp, list) { - nvbo = list_entry(entry, struct nouveau_bo, entry); -- if (likely(fence)) { -- struct nouveau_fence *prev_fence; - -- spin_lock(&nvbo->bo.lock); -- prev_fence = nvbo->bo.sync_obj; -- nvbo->bo.sync_obj = nouveau_fence_ref(fence); -- spin_unlock(&nvbo->bo.lock); -- nouveau_fence_unref((void *)&prev_fence); -- } -+ nouveau_bo_fence(nvbo, fence); - - if (unlikely(nvbo->validate_mapped)) { - ttm_bo_kunmap(&nvbo->kmap); -@@ -299,14 +268,15 @@ - return -EINVAL; - } - -- ret = ttm_bo_reserve(&nvbo->bo, false, false, true, sequence); -+ ret = ttm_bo_reserve(&nvbo->bo, true, false, true, sequence); - if (ret) { - validate_fini(op, NULL); -- if (ret == -EAGAIN) -- ret = ttm_bo_wait_unreserved(&nvbo->bo, false); -+ if (unlikely(ret == -EAGAIN)) -+ ret = ttm_bo_wait_unreserved(&nvbo->bo, true); - drm_gem_object_unreference_unlocked(gem); -- if (ret) { -- NV_ERROR(dev, "fail reserve\n"); -+ if (unlikely(ret)) { -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "fail reserve\n"); - return ret; - } - goto retry; -@@ -331,25 +301,6 @@ - validate_fini(op, NULL); - return -EINVAL; - } -- -- if (unlikely(atomic_read(&nvbo->bo.cpu_writers) > 0)) { -- validate_fini(op, NULL); -- -- if (nvbo->cpu_filp == file_priv) { -- NV_ERROR(dev, "bo %p mapped by process trying " -- "to validate it!\n", nvbo); -- return -EINVAL; -- } -- -- mutex_unlock(&drm_global_mutex); -- ret = ttm_bo_wait_cpu(&nvbo->bo, false); -- mutex_lock(&drm_global_mutex); -- if (ret) { -- NV_ERROR(dev, "fail wait_cpu\n"); -- return ret; -- } -- goto retry; -- } - } - - return 0; -@@ -383,11 +334,11 @@ - } - - nvbo->channel = (b->read_domains & (1 << 31)) ? NULL : chan; -- ret = ttm_bo_validate(&nvbo->bo, &nvbo->placement, -- false, false, false); -+ ret = nouveau_bo_validate(nvbo, true, false, false); - nvbo->channel = NULL; - if (unlikely(ret)) { -- NV_ERROR(dev, "fail ttm_validate\n"); -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "fail ttm_validate\n"); - return ret; - } - -@@ -439,13 +390,15 @@ - - ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); - if (unlikely(ret)) { -- NV_ERROR(dev, "validate_init\n"); -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "validate_init\n"); - return ret; - } - - ret = validate_list(chan, &op->vram_list, pbbo, user_buffers); - if (unlikely(ret < 0)) { -- NV_ERROR(dev, "validate vram_list\n"); -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "validate vram_list\n"); - validate_fini(op, NULL); - return ret; - } -@@ -453,7 +406,8 @@ - - ret = validate_list(chan, &op->gart_list, pbbo, user_buffers); - if (unlikely(ret < 0)) { -- NV_ERROR(dev, "validate gart_list\n"); -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "validate gart_list\n"); - validate_fini(op, NULL); - return ret; - } -@@ -461,7 +415,8 @@ - - ret = validate_list(chan, &op->both_list, pbbo, user_buffers); - if (unlikely(ret < 0)) { -- NV_ERROR(dev, "validate both_list\n"); -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "validate both_list\n"); - validate_fini(op, NULL); - return ret; - } -@@ -557,9 +512,9 @@ - data |= r->vor; - } - -- spin_lock(&nvbo->bo.lock); -+ spin_lock(&nvbo->bo.bdev->fence_lock); - ret = ttm_bo_wait(&nvbo->bo, false, false, false); -- spin_unlock(&nvbo->bo.lock); -+ spin_unlock(&nvbo->bo.bdev->fence_lock); - if (ret) { - NV_ERROR(dev, "reloc wait_idle failed: %d\n", ret); - break; -@@ -585,7 +540,9 @@ - struct nouveau_fence *fence = NULL; - int i, j, ret = 0, do_reloc = 0; - -- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(req->channel, file_priv, chan); -+ chan = nouveau_channel_get(dev, file_priv, req->channel); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); - - req->vram_available = dev_priv->fb_aper_free; - req->gart_available = dev_priv->gart_info.aper_free; -@@ -595,28 +552,34 @@ - if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { - NV_ERROR(dev, "pushbuf push count exceeds limit: %d max %d\n", - req->nr_push, NOUVEAU_GEM_MAX_PUSH); -+ nouveau_channel_put(&chan); - return -EINVAL; - } - - if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { - NV_ERROR(dev, "pushbuf bo count exceeds limit: %d max %d\n", - req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); -+ nouveau_channel_put(&chan); - return -EINVAL; - } - - if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { - NV_ERROR(dev, "pushbuf reloc count exceeds limit: %d max %d\n", - req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); -+ nouveau_channel_put(&chan); - return -EINVAL; - } - - push = u_memcpya(req->push, req->nr_push, sizeof(*push)); -- if (IS_ERR(push)) -+ if (IS_ERR(push)) { -+ nouveau_channel_put(&chan); - return PTR_ERR(push); -+ } - - bo = u_memcpya(req->buffers, req->nr_buffers, sizeof(*bo)); - if (IS_ERR(bo)) { - kfree(push); -+ nouveau_channel_put(&chan); - return PTR_ERR(bo); - } - -@@ -639,7 +602,8 @@ - ret = nouveau_gem_pushbuf_validate(chan, file_priv, bo, req->buffers, - req->nr_buffers, &op, &do_reloc); - if (ret) { -- NV_ERROR(dev, "validate: %d\n", ret); -+ if (ret != -ERESTARTSYS) -+ NV_ERROR(dev, "validate: %d\n", ret); - goto out; - } - -@@ -732,7 +696,7 @@ - - out: - validate_fini(&op, fence); -- nouveau_fence_unref((void**)&fence); -+ nouveau_fence_unref(&fence); - kfree(bo); - kfree(push); - -@@ -750,6 +714,7 @@ - req->suffix1 = 0x00000000; - } - -+ nouveau_channel_put(&chan); - return ret; - } - -@@ -781,26 +746,9 @@ - return -ENOENT; - nvbo = nouveau_gem_object(gem); - -- if (nvbo->cpu_filp) { -- if (nvbo->cpu_filp == file_priv) -- goto out; -- -- ret = ttm_bo_wait_cpu(&nvbo->bo, no_wait); -- if (ret) -- goto out; -- } -- -- if (req->flags & NOUVEAU_GEM_CPU_PREP_NOBLOCK) { -- spin_lock(&nvbo->bo.lock); -- ret = ttm_bo_wait(&nvbo->bo, false, false, no_wait); -- spin_unlock(&nvbo->bo.lock); -- } else { -- ret = ttm_bo_synccpu_write_grab(&nvbo->bo, no_wait); -- if (ret == 0) -- nvbo->cpu_filp = file_priv; -- } -- --out: -+ spin_lock(&nvbo->bo.bdev->fence_lock); -+ ret = ttm_bo_wait(&nvbo->bo, true, true, no_wait); -+ spin_unlock(&nvbo->bo.bdev->fence_lock); - drm_gem_object_unreference_unlocked(gem); - return ret; - } -@@ -809,26 +757,7 @@ - nouveau_gem_ioctl_cpu_fini(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { -- struct drm_nouveau_gem_cpu_prep *req = data; -- struct drm_gem_object *gem; -- struct nouveau_bo *nvbo; -- int ret = -EINVAL; -- -- gem = drm_gem_object_lookup(dev, file_priv, req->handle); -- if (!gem) -- return -ENOENT; -- nvbo = nouveau_gem_object(gem); -- -- if (nvbo->cpu_filp != file_priv) -- goto out; -- nvbo->cpu_filp = NULL; -- -- ttm_bo_synccpu_write_release(&nvbo->bo); -- ret = 0; -- --out: -- drm_gem_object_unreference_unlocked(gem); -- return ret; -+ return 0; - } - - int -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_hw.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_hw.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_hw.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_hw.c 2011-01-07 14:22:17.000000000 +0100 -@@ -953,7 +953,7 @@ - NVWriteCRTC(dev, head, NV_PCRTC_850, regp->crtc_850); - - reg900 = NVReadRAMDAC(dev, head, NV_PRAMDAC_900); -- if (regp->crtc_cfg == NV_PCRTC_CONFIG_START_ADDRESS_HSYNC) -+ if (regp->crtc_cfg == NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC) - NVWriteRAMDAC(dev, head, NV_PRAMDAC_900, reg900 | 0x10000); - else - NVWriteRAMDAC(dev, head, NV_PRAMDAC_900, reg900 & ~0x10000); -@@ -999,8 +999,8 @@ - if (dev_priv->card_type == NV_10) { - /* Not waiting for vertical retrace before modifying - CRE_53/CRE_54 causes lockups. */ -- nouveau_wait_until(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); -- nouveau_wait_until(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); -+ nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); -+ nouveau_wait_eq(dev, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); - } - - wr_cio_state(dev, head, regp, NV_CIO_CRE_53); -@@ -1017,8 +1017,9 @@ - - NVWriteCRTC(dev, head, NV_PCRTC_START, regp->fb_start); - -- /* Setting 1 on this value gives you interrupts for every vblank period. */ -- NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, 0); -+ /* Enable vblank interrupts. */ -+ NVWriteCRTC(dev, head, NV_PCRTC_INTR_EN_0, -+ (dev->vblank_enabled[head] ? 1 : 0)); - NVWriteCRTC(dev, head, NV_PCRTC_INTR_0, NV_PCRTC_INTR_0_VBLANK); - } - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_irq.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_irq.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_irq.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_irq.c 2011-01-07 14:22:17.000000000 +0100 -@@ -36,18 +36,7 @@ - #include "nouveau_drv.h" - #include "nouveau_reg.h" - #include "nouveau_ramht.h" --#include -- --/* needed for hotplug irq */ --#include "nouveau_connector.h" --#include "nv50_display.h" -- --static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); -- --static int nouveau_ratelimit(void) --{ -- return __ratelimit(&nouveau_ratelimit_state); --} -+#include "nouveau_util.h" - - void - nouveau_irq_preinstall(struct drm_device *dev) -@@ -57,19 +46,19 @@ - /* Master disable */ - nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); - -- if (dev_priv->card_type >= NV_50) { -- INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); -- INIT_WORK(&dev_priv->hpd_work, nv50_display_irq_hotplug_bh); -- spin_lock_init(&dev_priv->hpd_state.lock); -- INIT_LIST_HEAD(&dev_priv->vbl_waiting); -- } -+ INIT_LIST_HEAD(&dev_priv->vbl_waiting); - } - - int - nouveau_irq_postinstall(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ - /* Master enable */ - nv_wr32(dev, NV03_PMC_INTR_EN_0, NV_PMC_INTR_EN_0_MASTER_ENABLE); -+ if (dev_priv->msi_enabled) -+ nv_wr08(dev, 0x00088068, 0xff); -+ - return 0; - } - -@@ -80,1178 +69,83 @@ - nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); - } - --static int --nouveau_call_method(struct nouveau_channel *chan, int class, int mthd, int data) --{ -- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -- struct nouveau_pgraph_object_method *grm; -- struct nouveau_pgraph_object_class *grc; -- -- grc = dev_priv->engine.graph.grclass; -- while (grc->id) { -- if (grc->id == class) -- break; -- grc++; -- } -- -- if (grc->id != class || !grc->methods) -- return -ENOENT; -- -- grm = grc->methods; -- while (grm->id) { -- if (grm->id == mthd) -- return grm->exec(chan, class, mthd, data); -- grm++; -- } -- -- return -ENOENT; --} -- --static bool --nouveau_fifo_swmthd(struct nouveau_channel *chan, uint32_t addr, uint32_t data) --{ -- struct drm_device *dev = chan->dev; -- const int subc = (addr >> 13) & 0x7; -- const int mthd = addr & 0x1ffc; -- -- if (mthd == 0x0000) { -- struct nouveau_gpuobj *gpuobj; -- -- gpuobj = nouveau_ramht_find(chan, data); -- if (!gpuobj) -- return false; -- -- if (gpuobj->engine != NVOBJ_ENGINE_SW) -- return false; -- -- chan->sw_subchannel[subc] = gpuobj->class; -- nv_wr32(dev, NV04_PFIFO_CACHE1_ENGINE, nv_rd32(dev, -- NV04_PFIFO_CACHE1_ENGINE) & ~(0xf << subc * 4)); -- return true; -- } -- -- /* hw object */ -- if (nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE) & (1 << (subc*4))) -- return false; -- -- if (nouveau_call_method(chan, chan->sw_subchannel[subc], mthd, data)) -- return false; -- -- return true; --} -- --static void --nouveau_fifo_irq_handler(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_engine *engine = &dev_priv->engine; -- uint32_t status, reassign; -- int cnt = 0; -- -- reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; -- while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { -- struct nouveau_channel *chan = NULL; -- uint32_t chid, get; -- -- nv_wr32(dev, NV03_PFIFO_CACHES, 0); -- -- chid = engine->fifo.channel_id(dev); -- if (chid >= 0 && chid < engine->fifo.channels) -- chan = dev_priv->fifos[chid]; -- get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); -- -- if (status & NV_PFIFO_INTR_CACHE_ERROR) { -- uint32_t mthd, data; -- int ptr; -- -- /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before -- * wrapping on my G80 chips, but CACHE1 isn't big -- * enough for this much data.. Tests show that it -- * wraps around to the start at GET=0x800.. No clue -- * as to why.. -- */ -- ptr = (get & 0x7ff) >> 2; -- -- if (dev_priv->card_type < NV_40) { -- mthd = nv_rd32(dev, -- NV04_PFIFO_CACHE1_METHOD(ptr)); -- data = nv_rd32(dev, -- NV04_PFIFO_CACHE1_DATA(ptr)); -- } else { -- mthd = nv_rd32(dev, -- NV40_PFIFO_CACHE1_METHOD(ptr)); -- data = nv_rd32(dev, -- NV40_PFIFO_CACHE1_DATA(ptr)); -- } -- -- if (!chan || !nouveau_fifo_swmthd(chan, mthd, data)) { -- NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " -- "Mthd 0x%04x Data 0x%08x\n", -- chid, (mthd >> 13) & 7, mthd & 0x1ffc, -- data); -- } -- -- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); -- nv_wr32(dev, NV03_PFIFO_INTR_0, -- NV_PFIFO_INTR_CACHE_ERROR); -- -- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, -- nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); -- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); -- nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, -- nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); -- nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); -- -- nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, -- nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); -- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); -- -- status &= ~NV_PFIFO_INTR_CACHE_ERROR; -- } -- -- if (status & NV_PFIFO_INTR_DMA_PUSHER) { -- u32 dma_get = nv_rd32(dev, 0x003244); -- u32 dma_put = nv_rd32(dev, 0x003240); -- u32 push = nv_rd32(dev, 0x003220); -- u32 state = nv_rd32(dev, 0x003228); -- -- if (dev_priv->card_type == NV_50) { -- u32 ho_get = nv_rd32(dev, 0x003328); -- u32 ho_put = nv_rd32(dev, 0x003320); -- u32 ib_get = nv_rd32(dev, 0x003334); -- u32 ib_put = nv_rd32(dev, 0x003330); -- -- if (nouveau_ratelimit()) -- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " -- "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " -- "State 0x%08x Push 0x%08x\n", -- chid, ho_get, dma_get, ho_put, -- dma_put, ib_get, ib_put, state, -- push); -- -- /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ -- nv_wr32(dev, 0x003364, 0x00000000); -- if (dma_get != dma_put || ho_get != ho_put) { -- nv_wr32(dev, 0x003244, dma_put); -- nv_wr32(dev, 0x003328, ho_put); -- } else -- if (ib_get != ib_put) { -- nv_wr32(dev, 0x003334, ib_put); -- } -- } else { -- NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " -- "Put 0x%08x State 0x%08x Push 0x%08x\n", -- chid, dma_get, dma_put, state, push); -- -- if (dma_get != dma_put) -- nv_wr32(dev, 0x003244, dma_put); -- } -- -- nv_wr32(dev, 0x003228, 0x00000000); -- nv_wr32(dev, 0x003220, 0x00000001); -- nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); -- status &= ~NV_PFIFO_INTR_DMA_PUSHER; -- } -- -- if (status & NV_PFIFO_INTR_SEMAPHORE) { -- uint32_t sem; -- -- status &= ~NV_PFIFO_INTR_SEMAPHORE; -- nv_wr32(dev, NV03_PFIFO_INTR_0, -- NV_PFIFO_INTR_SEMAPHORE); -- -- sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); -- nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); -- -- nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); -- nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); -- } -- -- if (dev_priv->card_type == NV_50) { -- if (status & 0x00000010) { -- nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); -- status &= ~0x00000010; -- nv_wr32(dev, 0x002100, 0x00000010); -- } -- } -- -- if (status) { -- if (nouveau_ratelimit()) -- NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", -- status, chid); -- nv_wr32(dev, NV03_PFIFO_INTR_0, status); -- status = 0; -- } -- -- nv_wr32(dev, NV03_PFIFO_CACHES, reassign); -- } -- -- if (status) { -- NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); -- nv_wr32(dev, 0x2140, 0); -- nv_wr32(dev, 0x140, 0); -- } -- -- nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); --} -- --struct nouveau_bitfield_names { -- uint32_t mask; -- const char *name; --}; -- --static struct nouveau_bitfield_names nstatus_names[] = --{ -- { 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" } --}; -- --static struct nouveau_bitfield_names nstatus_names_nv10[] = --{ -- { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" }, -- { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" }, -- { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" }, -- { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" } --}; -- --static struct nouveau_bitfield_names nsource_names[] = --{ -- { 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 --nouveau_print_bitfield_names_(uint32_t value, -- const struct nouveau_bitfield_names *namelist, -- const int namelist_len) --{ -- /* -- * Caller must have already printed the KERN_* log level for us. -- * Also the caller is responsible for adding the newline. -- */ -- int i; -- for (i = 0; i < namelist_len; ++i) { -- uint32_t mask = namelist[i].mask; -- if (value & mask) { -- printk(" %s", namelist[i].name); -- value &= ~mask; -- } -- } -- if (value) -- printk(" (unknown bits 0x%08x)", value); --} --#define nouveau_print_bitfield_names(val, namelist) \ -- nouveau_print_bitfield_names_((val), (namelist), ARRAY_SIZE(namelist)) -- --struct nouveau_enum_names { -- uint32_t value; -- const char *name; --}; -- --static void --nouveau_print_enum_names_(uint32_t value, -- const struct nouveau_enum_names *namelist, -- const int namelist_len) --{ -- /* -- * Caller must have already printed the KERN_* log level for us. -- * Also the caller is responsible for adding the newline. -- */ -- int i; -- for (i = 0; i < namelist_len; ++i) { -- if (value == namelist[i].value) { -- printk("%s", namelist[i].name); -- return; -- } -- } -- printk("unknown value 0x%08x", value); --} --#define nouveau_print_enum_names(val, namelist) \ -- nouveau_print_enum_names_((val), (namelist), ARRAY_SIZE(namelist)) -- --static int --nouveau_graph_chid_from_grctx(struct drm_device *dev) -+irqreturn_t -+nouveau_irq_handler(DRM_IRQ_ARGS) - { -+ struct drm_device *dev = (struct drm_device *)arg; - struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t inst; -+ unsigned long flags; -+ u32 stat; - int i; - -- if (dev_priv->card_type < NV_40) -- return dev_priv->engine.fifo.channels; -- else -- if (dev_priv->card_type < NV_50) { -- inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 4; -- -- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- struct nouveau_channel *chan = dev_priv->fifos[i]; -- -- if (!chan || !chan->ramin_grctx) -- continue; -- -- if (inst == chan->ramin_grctx->pinst) -- break; -- } -- } else { -- inst = (nv_rd32(dev, 0x40032c) & 0xfffff) << 12; -- -- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- struct nouveau_channel *chan = dev_priv->fifos[i]; -- -- if (!chan || !chan->ramin) -- continue; -- -- if (inst == chan->ramin->vinst) -- break; -- } -- } -- -- -- return i; --} -- --static int --nouveau_graph_trapped_channel(struct drm_device *dev, int *channel_ret) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_engine *engine = &dev_priv->engine; -- int channel; -- -- if (dev_priv->card_type < NV_10) -- channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0xf; -- else -- if (dev_priv->card_type < NV_40) -- channel = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; -- else -- channel = nouveau_graph_chid_from_grctx(dev); -- -- if (channel >= engine->fifo.channels || !dev_priv->fifos[channel]) { -- NV_ERROR(dev, "AIII, invalid/inactive channel id %d\n", channel); -- return -EINVAL; -- } -- -- *channel_ret = channel; -- return 0; --} -- --struct nouveau_pgraph_trap { -- int channel; -- int class; -- int subc, mthd, size; -- uint32_t data, data2; -- uint32_t nsource, nstatus; --}; -- --static void --nouveau_graph_trap_info(struct drm_device *dev, -- struct nouveau_pgraph_trap *trap) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t address; -- -- trap->nsource = trap->nstatus = 0; -- if (dev_priv->card_type < NV_50) { -- trap->nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); -- trap->nstatus = nv_rd32(dev, NV03_PGRAPH_NSTATUS); -- } -- -- if (nouveau_graph_trapped_channel(dev, &trap->channel)) -- trap->channel = -1; -- address = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); -- -- trap->mthd = address & 0x1FFC; -- trap->data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); -- if (dev_priv->card_type < NV_10) { -- trap->subc = (address >> 13) & 0x7; -- } else { -- trap->subc = (address >> 16) & 0x7; -- trap->data2 = nv_rd32(dev, NV10_PGRAPH_TRAPPED_DATA_HIGH); -- } -- -- if (dev_priv->card_type < NV_10) -- trap->class = nv_rd32(dev, 0x400180 + trap->subc*4) & 0xFF; -- else if (dev_priv->card_type < NV_40) -- trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFF; -- else if (dev_priv->card_type < NV_50) -- trap->class = nv_rd32(dev, 0x400160 + trap->subc*4) & 0xFFFF; -- else -- trap->class = nv_rd32(dev, 0x400814); --} -- --static void --nouveau_graph_dump_trap_info(struct drm_device *dev, const char *id, -- struct nouveau_pgraph_trap *trap) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t nsource = trap->nsource, nstatus = trap->nstatus; -- -- if (dev_priv->card_type < NV_50) { -- NV_INFO(dev, "%s - nSource:", id); -- nouveau_print_bitfield_names(nsource, nsource_names); -- printk(", nStatus:"); -- if (dev_priv->card_type < NV_10) -- nouveau_print_bitfield_names(nstatus, nstatus_names); -- else -- nouveau_print_bitfield_names(nstatus, nstatus_names_nv10); -- printk("\n"); -- } -- -- NV_INFO(dev, "%s - Ch %d/%d Class 0x%04x Mthd 0x%04x " -- "Data 0x%08x:0x%08x\n", -- id, trap->channel, trap->subc, -- trap->class, trap->mthd, -- trap->data2, trap->data); --} -- --static int --nouveau_pgraph_intr_swmthd(struct drm_device *dev, -- struct nouveau_pgraph_trap *trap) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- -- if (trap->channel < 0 || -- trap->channel >= dev_priv->engine.fifo.channels || -- !dev_priv->fifos[trap->channel]) -- return -ENODEV; -- -- return nouveau_call_method(dev_priv->fifos[trap->channel], -- trap->class, trap->mthd, trap->data); --} -- --static inline void --nouveau_pgraph_intr_notify(struct drm_device *dev, uint32_t nsource) --{ -- struct nouveau_pgraph_trap trap; -- int unhandled = 0; -+ stat = nv_rd32(dev, NV03_PMC_INTR_0); -+ if (!stat) -+ return IRQ_NONE; - -- nouveau_graph_trap_info(dev, &trap); -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ for (i = 0; i < 32 && stat; i++) { -+ if (!(stat & (1 << i)) || !dev_priv->irq_handler[i]) -+ continue; - -- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { -- if (nouveau_pgraph_intr_swmthd(dev, &trap)) -- unhandled = 1; -- } else { -- unhandled = 1; -+ dev_priv->irq_handler[i](dev); -+ stat &= ~(1 << i); - } - -- if (unhandled) -- nouveau_graph_dump_trap_info(dev, "PGRAPH_NOTIFY", &trap); --} -- -- --static inline void --nouveau_pgraph_intr_error(struct drm_device *dev, uint32_t nsource) --{ -- struct nouveau_pgraph_trap trap; -- int unhandled = 0; -- -- nouveau_graph_trap_info(dev, &trap); -- trap.nsource = nsource; -- -- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { -- if (nouveau_pgraph_intr_swmthd(dev, &trap)) -- unhandled = 1; -- } else if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { -- uint32_t v = nv_rd32(dev, 0x402000); -- nv_wr32(dev, 0x402000, v); -- -- /* dump the error anyway for now: it's useful for -- Gallium development */ -- unhandled = 1; -- } else { -- unhandled = 1; -- } -+ if (dev_priv->msi_enabled) -+ nv_wr08(dev, 0x00088068, 0xff); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - -- if (unhandled && nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, "PGRAPH_ERROR", &trap); -+ if (stat && nouveau_ratelimit()) -+ NV_ERROR(dev, "PMC - unhandled INTR 0x%08x\n", stat); -+ return IRQ_HANDLED; - } - --static inline void --nouveau_pgraph_intr_context_switch(struct drm_device *dev) -+int -+nouveau_irq_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_engine *engine = &dev_priv->engine; -- uint32_t chid; -- -- chid = engine->fifo.channel_id(dev); -- NV_DEBUG(dev, "PGRAPH context switch interrupt channel %x\n", chid); -- -- switch (dev_priv->card_type) { -- case NV_04: -- nv04_graph_context_switch(dev); -- break; -- case NV_10: -- nv10_graph_context_switch(dev); -- break; -- default: -- NV_ERROR(dev, "Context switch not implemented\n"); -- break; -- } --} -- --static void --nouveau_pgraph_irq_handler(struct drm_device *dev) --{ -- uint32_t status; -- -- while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { -- uint32_t nsource = nv_rd32(dev, NV03_PGRAPH_NSOURCE); -- -- if (status & NV_PGRAPH_INTR_NOTIFY) { -- nouveau_pgraph_intr_notify(dev, nsource); -- -- status &= ~NV_PGRAPH_INTR_NOTIFY; -- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_NOTIFY); -- } -- -- if (status & NV_PGRAPH_INTR_ERROR) { -- nouveau_pgraph_intr_error(dev, nsource); -- -- status &= ~NV_PGRAPH_INTR_ERROR; -- nv_wr32(dev, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_ERROR); -- } -- -- if (status & NV_PGRAPH_INTR_CONTEXT_SWITCH) { -- status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; -- nv_wr32(dev, NV03_PGRAPH_INTR, -- NV_PGRAPH_INTR_CONTEXT_SWITCH); -+ int ret; - -- nouveau_pgraph_intr_context_switch(dev); -+ if (nouveau_msi != 0 && dev_priv->card_type >= NV_50) { -+ ret = pci_enable_msi(dev->pdev); -+ if (ret == 0) { -+ NV_INFO(dev, "enabled MSI\n"); -+ dev_priv->msi_enabled = true; - } -- -- if (status) { -- NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", status); -- nv_wr32(dev, NV03_PGRAPH_INTR, status); -- } -- -- if ((nv_rd32(dev, NV04_PGRAPH_FIFO) & (1 << 0)) == 0) -- nv_wr32(dev, NV04_PGRAPH_FIFO, 1); - } - -- nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); -+ return drm_irq_install(dev); - } - --static struct nouveau_enum_names nv50_mp_exec_error_names[] = --{ -- { 3, "STACK_UNDERFLOW" }, -- { 4, "QUADON_ACTIVE" }, -- { 8, "TIMEOUT" }, -- { 0x10, "INVALID_OPCODE" }, -- { 0x40, "BREAKPOINT" }, --}; -- --static void --nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t units = nv_rd32(dev, 0x1540); -- uint32_t addr, mp10, status, pc, oplow, ophigh; -- int i; -- int mps = 0; -- for (i = 0; i < 4; i++) { -- if (!(units & 1 << (i+24))) -- continue; -- if (dev_priv->chipset < 0xa0) -- addr = 0x408200 + (tpid << 12) + (i << 7); -- else -- addr = 0x408100 + (tpid << 11) + (i << 7); -- mp10 = nv_rd32(dev, addr + 0x10); -- status = nv_rd32(dev, addr + 0x14); -- if (!status) -- continue; -- if (display) { -- nv_rd32(dev, addr + 0x20); -- pc = nv_rd32(dev, addr + 0x24); -- oplow = nv_rd32(dev, addr + 0x70); -- ophigh= nv_rd32(dev, addr + 0x74); -- NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - " -- "TP %d MP %d: ", tpid, i); -- nouveau_print_enum_names(status, -- nv50_mp_exec_error_names); -- printk(" at %06x warp %d, opcode %08x %08x\n", -- pc&0xffffff, pc >> 24, -- oplow, ophigh); -- } -- nv_wr32(dev, addr + 0x10, mp10); -- nv_wr32(dev, addr + 0x14, 0); -- mps++; -- } -- if (!mps && display) -- NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " -- "No MPs claiming errors?\n", tpid); --} -- --static void --nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, -- uint32_t ustatus_new, int display, const char *name) -+void -+nouveau_irq_fini(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- int tps = 0; -- uint32_t units = nv_rd32(dev, 0x1540); -- int i, r; -- uint32_t ustatus_addr, ustatus; -- for (i = 0; i < 16; i++) { -- if (!(units & (1 << i))) -- continue; -- if (dev_priv->chipset < 0xa0) -- ustatus_addr = ustatus_old + (i << 12); -- else -- ustatus_addr = ustatus_new + (i << 11); -- ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; -- if (!ustatus) -- continue; -- tps++; -- switch (type) { -- case 6: /* texture error... unknown for now */ -- nv50_fb_vm_trap(dev, display, name); -- if (display) { -- NV_ERROR(dev, "magic set %d:\n", i); -- for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) -- NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, -- nv_rd32(dev, r)); -- } -- break; -- case 7: /* MP error */ -- if (ustatus & 0x00010000) { -- nv50_pgraph_mp_trap(dev, i, display); -- ustatus &= ~0x00010000; -- } -- break; -- case 8: /* TPDMA error */ -- { -- uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); -- uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); -- uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); -- uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); -- uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); -- uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); -- uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); -- nv50_fb_vm_trap(dev, display, name); -- /* 2d engine destination */ -- if (ustatus & 0x00000010) { -- if (display) { -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", -- i, e14, e10); -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", -- i, e0c, e18, e1c, e20, e24); -- } -- ustatus &= ~0x00000010; -- } -- /* Render target */ -- if (ustatus & 0x00000040) { -- if (display) { -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", -- i, e14, e10); -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", -- i, e0c, e18, e1c, e20, e24); -- } -- ustatus &= ~0x00000040; -- } -- /* CUDA memory: l[], g[] or stack. */ -- if (ustatus & 0x00000080) { -- if (display) { -- if (e18 & 0x80000000) { -- /* g[] read fault? */ -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", -- i, e14, e10 | ((e18 >> 24) & 0x1f)); -- e18 &= ~0x1f000000; -- } else if (e18 & 0xc) { -- /* g[] write fault? */ -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", -- i, e14, e10 | ((e18 >> 7) & 0x1f)); -- e18 &= ~0x00000f80; -- } else { -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", -- i, e14, e10); -- } -- NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", -- i, e0c, e18, e1c, e20, e24); -- } -- ustatus &= ~0x00000080; -- } -- } -- break; -- } -- if (ustatus) { -- if (display) -- NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); -- } -- nv_wr32(dev, ustatus_addr, 0xc0000000); -- } -- -- if (!tps && display) -- NV_INFO(dev, "%s - No TPs claiming errors?\n", name); --} -- --static void --nv50_pgraph_trap_handler(struct drm_device *dev) --{ -- struct nouveau_pgraph_trap trap; -- uint32_t status = nv_rd32(dev, 0x400108); -- uint32_t ustatus; -- int display = nouveau_ratelimit(); -- -- -- if (!status && display) { -- nouveau_graph_trap_info(dev, &trap); -- nouveau_graph_dump_trap_info(dev, "PGRAPH_TRAP", &trap); -- NV_INFO(dev, "PGRAPH_TRAP - no units reporting traps?\n"); -- } -- -- /* DISPATCH: Relays commands to other units and handles NOTIFY, -- * COND, QUERY. If you get a trap from it, the command is still stuck -- * in DISPATCH and you need to do something about it. */ -- if (status & 0x001) { -- ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; -- if (!ustatus && display) { -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); -- } -- -- /* Known to be triggered by screwed up NOTIFY and COND... */ -- if (ustatus & 0x00000001) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_FAULT"); -- nv_wr32(dev, 0x400500, 0); -- if (nv_rd32(dev, 0x400808) & 0x80000000) { -- if (display) { -- if (nouveau_graph_trapped_channel(dev, &trap.channel)) -- trap.channel = -1; -- trap.class = nv_rd32(dev, 0x400814); -- trap.mthd = nv_rd32(dev, 0x400808) & 0x1ffc; -- trap.subc = (nv_rd32(dev, 0x400808) >> 16) & 0x7; -- trap.data = nv_rd32(dev, 0x40080c); -- trap.data2 = nv_rd32(dev, 0x400810); -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_TRAP_DISPATCH_FAULT", &trap); -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400808: %08x\n", nv_rd32(dev, 0x400808)); -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - 400848: %08x\n", nv_rd32(dev, 0x400848)); -- } -- nv_wr32(dev, 0x400808, 0); -- } else if (display) { -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_FAULT - No stuck command?\n"); -- } -- nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); -- nv_wr32(dev, 0x400848, 0); -- ustatus &= ~0x00000001; -- } -- if (ustatus & 0x00000002) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_DISPATCH_QUERY"); -- nv_wr32(dev, 0x400500, 0); -- if (nv_rd32(dev, 0x40084c) & 0x80000000) { -- if (display) { -- if (nouveau_graph_trapped_channel(dev, &trap.channel)) -- trap.channel = -1; -- trap.class = nv_rd32(dev, 0x400814); -- trap.mthd = nv_rd32(dev, 0x40084c) & 0x1ffc; -- trap.subc = (nv_rd32(dev, 0x40084c) >> 16) & 0x7; -- trap.data = nv_rd32(dev, 0x40085c); -- trap.data2 = 0; -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_TRAP_DISPATCH_QUERY", &trap); -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - 40084c: %08x\n", nv_rd32(dev, 0x40084c)); -- } -- nv_wr32(dev, 0x40084c, 0); -- } else if (display) { -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH_QUERY - No stuck command?\n"); -- } -- ustatus &= ~0x00000002; -- } -- if (ustatus && display) -- NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - Unhandled ustatus 0x%08x\n", ustatus); -- nv_wr32(dev, 0x400804, 0xc0000000); -- nv_wr32(dev, 0x400108, 0x001); -- status &= ~0x001; -- } -- -- /* TRAPs other than dispatch use the "normal" trap regs. */ -- if (status && display) { -- nouveau_graph_trap_info(dev, &trap); -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_TRAP", &trap); -- } -- -- /* M2MF: Memory to memory copy engine. */ -- if (status & 0x002) { -- ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; -- if (!ustatus && display) { -- NV_INFO(dev, "PGRAPH_TRAP_M2MF - no ustatus?\n"); -- } -- if (ustatus & 0x00000001) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_NOTIFY"); -- ustatus &= ~0x00000001; -- } -- if (ustatus & 0x00000002) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_IN"); -- ustatus &= ~0x00000002; -- } -- if (ustatus & 0x00000004) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_M2MF_OUT"); -- ustatus &= ~0x00000004; -- } -- NV_INFO (dev, "PGRAPH_TRAP_M2MF - %08x %08x %08x %08x\n", -- nv_rd32(dev, 0x406804), -- nv_rd32(dev, 0x406808), -- nv_rd32(dev, 0x40680c), -- nv_rd32(dev, 0x406810)); -- if (ustatus && display) -- NV_INFO(dev, "PGRAPH_TRAP_M2MF - Unhandled ustatus 0x%08x\n", ustatus); -- /* No sane way found yet -- just reset the bugger. */ -- nv_wr32(dev, 0x400040, 2); -- nv_wr32(dev, 0x400040, 0); -- nv_wr32(dev, 0x406800, 0xc0000000); -- nv_wr32(dev, 0x400108, 0x002); -- status &= ~0x002; -- } -- -- /* VFETCH: Fetches data from vertex buffers. */ -- if (status & 0x004) { -- ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; -- if (!ustatus && display) { -- NV_INFO(dev, "PGRAPH_TRAP_VFETCH - no ustatus?\n"); -- } -- if (ustatus & 0x00000001) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_VFETCH_FAULT"); -- NV_INFO (dev, "PGRAPH_TRAP_VFETCH_FAULT - %08x %08x %08x %08x\n", -- nv_rd32(dev, 0x400c00), -- nv_rd32(dev, 0x400c08), -- nv_rd32(dev, 0x400c0c), -- nv_rd32(dev, 0x400c10)); -- ustatus &= ~0x00000001; -- } -- if (ustatus && display) -- NV_INFO(dev, "PGRAPH_TRAP_VFETCH - Unhandled ustatus 0x%08x\n", ustatus); -- nv_wr32(dev, 0x400c04, 0xc0000000); -- nv_wr32(dev, 0x400108, 0x004); -- status &= ~0x004; -- } -- -- /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ -- if (status & 0x008) { -- ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; -- if (!ustatus && display) { -- NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - no ustatus?\n"); -- } -- if (ustatus & 0x00000001) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_STRMOUT_FAULT"); -- NV_INFO (dev, "PGRAPH_TRAP_STRMOUT_FAULT - %08x %08x %08x %08x\n", -- nv_rd32(dev, 0x401804), -- nv_rd32(dev, 0x401808), -- nv_rd32(dev, 0x40180c), -- nv_rd32(dev, 0x401810)); -- ustatus &= ~0x00000001; -- } -- if (ustatus && display) -- NV_INFO(dev, "PGRAPH_TRAP_STRMOUT - Unhandled ustatus 0x%08x\n", ustatus); -- /* No sane way found yet -- just reset the bugger. */ -- nv_wr32(dev, 0x400040, 0x80); -- nv_wr32(dev, 0x400040, 0); -- nv_wr32(dev, 0x401800, 0xc0000000); -- nv_wr32(dev, 0x400108, 0x008); -- status &= ~0x008; -- } -- -- /* CCACHE: Handles code and c[] caches and fills them. */ -- if (status & 0x010) { -- ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; -- if (!ustatus && display) { -- NV_INFO(dev, "PGRAPH_TRAP_CCACHE - no ustatus?\n"); -- } -- if (ustatus & 0x00000001) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_CCACHE_FAULT"); -- NV_INFO (dev, "PGRAPH_TRAP_CCACHE_FAULT - %08x %08x %08x %08x %08x %08x %08x\n", -- nv_rd32(dev, 0x405800), -- nv_rd32(dev, 0x405804), -- nv_rd32(dev, 0x405808), -- nv_rd32(dev, 0x40580c), -- nv_rd32(dev, 0x405810), -- nv_rd32(dev, 0x405814), -- nv_rd32(dev, 0x40581c)); -- ustatus &= ~0x00000001; -- } -- if (ustatus && display) -- NV_INFO(dev, "PGRAPH_TRAP_CCACHE - Unhandled ustatus 0x%08x\n", ustatus); -- nv_wr32(dev, 0x405018, 0xc0000000); -- nv_wr32(dev, 0x400108, 0x010); -- status &= ~0x010; -- } -- -- /* Unknown, not seen yet... 0x402000 is the only trap status reg -- * remaining, so try to handle it anyway. Perhaps related to that -- * unknown DMA slot on tesla? */ -- if (status & 0x20) { -- nv50_fb_vm_trap(dev, display, "PGRAPH_TRAP_UNKC04"); -- ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; -- if (display) -- NV_INFO(dev, "PGRAPH_TRAP_UNKC04 - Unhandled ustatus 0x%08x\n", ustatus); -- nv_wr32(dev, 0x402000, 0xc0000000); -- /* no status modifiction on purpose */ -- } -- -- /* TEXTURE: CUDA texturing units */ -- if (status & 0x040) { -- nv50_pgraph_tp_trap (dev, 6, 0x408900, 0x408600, display, -- "PGRAPH_TRAP_TEXTURE"); -- nv_wr32(dev, 0x400108, 0x040); -- status &= ~0x040; -- } -- -- /* MP: CUDA execution engines. */ -- if (status & 0x080) { -- nv50_pgraph_tp_trap (dev, 7, 0x408314, 0x40831c, display, -- "PGRAPH_TRAP_MP"); -- nv_wr32(dev, 0x400108, 0x080); -- status &= ~0x080; -- } -- -- /* TPDMA: Handles TP-initiated uncached memory accesses: -- * l[], g[], stack, 2d surfaces, render targets. */ -- if (status & 0x100) { -- nv50_pgraph_tp_trap (dev, 8, 0x408e08, 0x408708, display, -- "PGRAPH_TRAP_TPDMA"); -- nv_wr32(dev, 0x400108, 0x100); -- status &= ~0x100; -- } - -- if (status) { -- if (display) -- NV_INFO(dev, "PGRAPH_TRAP - Unknown trap 0x%08x\n", -- status); -- nv_wr32(dev, 0x400108, status); -- } -+ drm_irq_uninstall(dev); -+ if (dev_priv->msi_enabled) -+ pci_disable_msi(dev->pdev); - } - --/* There must be a *lot* of these. Will take some time to gather them up. */ --static struct nouveau_enum_names nv50_data_error_names[] = --{ -- { 4, "INVALID_VALUE" }, -- { 5, "INVALID_ENUM" }, -- { 8, "INVALID_OBJECT" }, -- { 0xc, "INVALID_BITFIELD" }, -- { 0x28, "MP_NO_REG_SPACE" }, -- { 0x2b, "MP_BLOCK_SIZE_MISMATCH" }, --}; -- --static void --nv50_pgraph_irq_handler(struct drm_device *dev) --{ -- struct nouveau_pgraph_trap trap; -- int unhandled = 0; -- uint32_t status; -- -- while ((status = nv_rd32(dev, NV03_PGRAPH_INTR))) { -- /* NOTIFY: You've set a NOTIFY an a command and it's done. */ -- if (status & 0x00000001) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_NOTIFY", &trap); -- status &= ~0x00000001; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000001); -- } -- -- /* COMPUTE_QUERY: Purpose and exact cause unknown, happens -- * when you write 0x200 to 0x50c0 method 0x31c. */ -- if (status & 0x00000002) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_COMPUTE_QUERY", &trap); -- status &= ~0x00000002; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000002); -- } -- -- /* Unknown, never seen: 0x4 */ -- -- /* ILLEGAL_MTHD: You used a wrong method for this class. */ -- if (status & 0x00000010) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_pgraph_intr_swmthd(dev, &trap)) -- unhandled = 1; -- if (unhandled && nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_ILLEGAL_MTHD", &trap); -- status &= ~0x00000010; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000010); -- } -- -- /* ILLEGAL_CLASS: You used a wrong class. */ -- if (status & 0x00000020) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_ILLEGAL_CLASS", &trap); -- status &= ~0x00000020; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000020); -- } -- -- /* DOUBLE_NOTIFY: You tried to set a NOTIFY on another NOTIFY. */ -- if (status & 0x00000040) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_DOUBLE_NOTIFY", &trap); -- status &= ~0x00000040; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00000040); -- } -- -- /* CONTEXT_SWITCH: PGRAPH needs us to load a new context */ -- if (status & 0x00001000) { -- nv_wr32(dev, 0x400500, 0x00000000); -- nv_wr32(dev, NV03_PGRAPH_INTR, -- NV_PGRAPH_INTR_CONTEXT_SWITCH); -- nv_wr32(dev, NV40_PGRAPH_INTR_EN, nv_rd32(dev, -- NV40_PGRAPH_INTR_EN) & -- ~NV_PGRAPH_INTR_CONTEXT_SWITCH); -- nv_wr32(dev, 0x400500, 0x00010001); -- -- nv50_graph_context_switch(dev); -- -- status &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; -- } -- -- /* BUFFER_NOTIFY: Your m2mf transfer finished */ -- if (status & 0x00010000) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_BUFFER_NOTIFY", &trap); -- status &= ~0x00010000; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00010000); -- } -- -- /* DATA_ERROR: Invalid value for this method, or invalid -- * state in current PGRAPH context for this operation */ -- if (status & 0x00100000) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) { -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_DATA_ERROR", &trap); -- NV_INFO (dev, "PGRAPH_DATA_ERROR - "); -- nouveau_print_enum_names(nv_rd32(dev, 0x400110), -- nv50_data_error_names); -- printk("\n"); -- } -- status &= ~0x00100000; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00100000); -- } -- -- /* TRAP: Something bad happened in the middle of command -- * execution. Has a billion types, subtypes, and even -- * subsubtypes. */ -- if (status & 0x00200000) { -- nv50_pgraph_trap_handler(dev); -- status &= ~0x00200000; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x00200000); -- } -- -- /* Unknown, never seen: 0x00400000 */ -- -- /* SINGLE_STEP: Happens on every method if you turned on -- * single stepping in 40008c */ -- if (status & 0x01000000) { -- nouveau_graph_trap_info(dev, &trap); -- if (nouveau_ratelimit()) -- nouveau_graph_dump_trap_info(dev, -- "PGRAPH_SINGLE_STEP", &trap); -- status &= ~0x01000000; -- nv_wr32(dev, NV03_PGRAPH_INTR, 0x01000000); -- } -- -- /* 0x02000000 happens when you pause a ctxprog... -- * but the only way this can happen that I know is by -- * poking the relevant MMIO register, and we don't -- * do that. */ -- -- if (status) { -- NV_INFO(dev, "Unhandled PGRAPH_INTR - 0x%08x\n", -- status); -- nv_wr32(dev, NV03_PGRAPH_INTR, status); -- } -- -- { -- const int isb = (1 << 16) | (1 << 0); -- -- if ((nv_rd32(dev, 0x400500) & isb) != isb) -- nv_wr32(dev, 0x400500, -- nv_rd32(dev, 0x400500) | isb); -- } -- } -- -- nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PGRAPH_PENDING); -- if (nv_rd32(dev, 0x400824) & (1 << 31)) -- nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); --} -- --static void --nouveau_crtc_irq_handler(struct drm_device *dev, int crtc) -+void -+nouveau_irq_register(struct drm_device *dev, int status_bit, -+ void (*handler)(struct drm_device *)) - { -- if (crtc & 1) -- nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ unsigned long flags; - -- if (crtc & 2) -- nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ dev_priv->irq_handler[status_bit] = handler; -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - } - --irqreturn_t --nouveau_irq_handler(DRM_IRQ_ARGS) -+void -+nouveau_irq_unregister(struct drm_device *dev, int status_bit) - { -- struct drm_device *dev = (struct drm_device *)arg; - struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t status; - unsigned long flags; - -- status = nv_rd32(dev, NV03_PMC_INTR_0); -- if (!status) -- return IRQ_NONE; -- - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -- -- if (status & NV_PMC_INTR_0_PFIFO_PENDING) { -- nouveau_fifo_irq_handler(dev); -- status &= ~NV_PMC_INTR_0_PFIFO_PENDING; -- } -- -- if (status & NV_PMC_INTR_0_PGRAPH_PENDING) { -- if (dev_priv->card_type >= NV_50) -- nv50_pgraph_irq_handler(dev); -- else -- nouveau_pgraph_irq_handler(dev); -- -- status &= ~NV_PMC_INTR_0_PGRAPH_PENDING; -- } -- -- if (status & NV_PMC_INTR_0_CRTCn_PENDING) { -- nouveau_crtc_irq_handler(dev, (status>>24)&3); -- status &= ~NV_PMC_INTR_0_CRTCn_PENDING; -- } -- -- if (status & (NV_PMC_INTR_0_NV50_DISPLAY_PENDING | -- NV_PMC_INTR_0_NV50_I2C_PENDING)) { -- nv50_display_irq_handler(dev); -- status &= ~(NV_PMC_INTR_0_NV50_DISPLAY_PENDING | -- NV_PMC_INTR_0_NV50_I2C_PENDING); -- } -- -- if (status) -- NV_ERROR(dev, "Unhandled PMC INTR status bits 0x%08x\n", status); -- -+ dev_priv->irq_handler[status_bit] = NULL; - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -- -- return IRQ_HANDLED; - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_mem.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_mem.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_mem.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-01-07 14:22:17.000000000 +0100 -@@ -36,183 +36,112 @@ - - #include "nouveau_drv.h" - #include "nouveau_pm.h" -+#include "nouveau_mm.h" -+#include "nouveau_vm.h" - - /* - * NV10-NV40 tiling helpers - */ - - static void --nv10_mem_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch) -+nv10_mem_update_tile_region(struct drm_device *dev, -+ struct nouveau_tile_reg *tile, uint32_t addr, -+ uint32_t size, uint32_t pitch, uint32_t flags) - { - 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; -- struct nouveau_tile_reg *tile = &dev_priv->tile[i]; -+ int i = tile - dev_priv->tile.reg; -+ unsigned long save; - -- tile->addr = addr; -- tile->size = size; -- tile->used = !!pitch; -- nouveau_fence_unref((void **)&tile->fence); -+ nouveau_fence_unref(&tile->fence); - -+ if (tile->pitch) -+ pfb->free_tile_region(dev, i); -+ -+ if (pitch) -+ pfb->init_tile_region(dev, i, addr, size, pitch, flags); -+ -+ spin_lock_irqsave(&dev_priv->context_switch_lock, save); - pfifo->reassign(dev, false); - pfifo->cache_pull(dev, false); - - nouveau_wait_for_idle(dev); - -- pgraph->set_region_tiling(dev, i, addr, size, pitch); -- pfb->set_region_tiling(dev, i, addr, size, pitch); -+ pfb->set_tile_region(dev, i); -+ pgraph->set_tile_region(dev, i); - - pfifo->cache_pull(dev, true); - pfifo->reassign(dev, true); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, save); - } - --struct nouveau_tile_reg * --nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, -- uint32_t pitch) -+static struct nouveau_tile_reg * -+nv10_mem_get_tile_region(struct drm_device *dev, int i) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; -- struct nouveau_tile_reg *found = NULL; -- unsigned long i, flags; -- -- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -- -- for (i = 0; i < pfb->num_tiles; i++) { -- struct nouveau_tile_reg *tile = &dev_priv->tile[i]; -- -- if (tile->used) -- /* Tile region in use. */ -- continue; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - -- if (tile->fence && -- !nouveau_fence_signalled(tile->fence, NULL)) -- /* Pending tile region. */ -- continue; -- -- if (max(tile->addr, addr) < -- min(tile->addr + tile->size, addr + size)) -- /* Kill an intersecting tile region. */ -- nv10_mem_set_region_tiling(dev, i, 0, 0, 0); -- -- if (pitch && !found) { -- /* Free tile region. */ -- nv10_mem_set_region_tiling(dev, i, addr, size, pitch); -- found = tile; -- } -- } -+ spin_lock(&dev_priv->tile.lock); - -- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ if (!tile->used && -+ (!tile->fence || nouveau_fence_signalled(tile->fence))) -+ tile->used = true; -+ else -+ tile = NULL; - -- return found; -+ spin_unlock(&dev_priv->tile.lock); -+ return tile; - } - - void --nv10_mem_expire_tiling(struct drm_device *dev, struct nouveau_tile_reg *tile, -- struct nouveau_fence *fence) --{ -- if (fence) { -- /* Mark it as pending. */ -- tile->fence = fence; -- nouveau_fence_ref(fence); -- } -- -- tile->used = false; --} -- --/* -- * NV50 VM helpers -- */ --int --nv50_mem_vm_bind_linear(struct drm_device *dev, uint64_t virt, uint32_t size, -- uint32_t flags, uint64_t phys) -+nv10_mem_put_tile_region(struct drm_device *dev, struct nouveau_tile_reg *tile, -+ struct nouveau_fence *fence) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *pgt; -- unsigned block; -- int i; -- -- virt = ((virt - dev_priv->vm_vram_base) >> 16) << 1; -- size = (size >> 16) << 1; -- -- phys |= ((uint64_t)flags << 32); -- phys |= 1; -- if (dev_priv->vram_sys_base) { -- phys += dev_priv->vram_sys_base; -- phys |= 0x30; -- } - -- while (size) { -- unsigned offset_h = upper_32_bits(phys); -- unsigned offset_l = lower_32_bits(phys); -- unsigned pte, end; -- -- for (i = 7; i >= 0; i--) { -- block = 1 << (i + 1); -- if (size >= block && !(virt & (block - 1))) -- break; -+ if (tile) { -+ spin_lock(&dev_priv->tile.lock); -+ if (fence) { -+ /* Mark it as pending. */ -+ tile->fence = fence; -+ nouveau_fence_ref(fence); - } -- offset_l |= (i << 7); -- -- phys += block << 15; -- size -= block; - -- while (block) { -- pgt = dev_priv->vm_vram_pt[virt >> 14]; -- pte = virt & 0x3ffe; -- -- end = pte + block; -- if (end > 16384) -- end = 16384; -- block -= (end - pte); -- virt += (end - pte); -- -- while (pte < end) { -- nv_wo32(pgt, (pte * 4) + 0, offset_l); -- nv_wo32(pgt, (pte * 4) + 4, offset_h); -- pte += 2; -- } -- } -+ tile->used = false; -+ spin_unlock(&dev_priv->tile.lock); - } -- -- dev_priv->engine.instmem.flush(dev); -- dev_priv->engine.fifo.tlb_flush(dev); -- dev_priv->engine.graph.tlb_flush(dev); -- nv50_vm_flush(dev, 6); -- return 0; - } - --void --nv50_mem_vm_unbind(struct drm_device *dev, uint64_t virt, uint32_t size) -+struct nouveau_tile_reg * -+nv10_mem_set_tiling(struct drm_device *dev, uint32_t addr, uint32_t size, -+ uint32_t pitch, uint32_t flags) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *pgt; -- unsigned pages, pte, end; -- -- virt -= dev_priv->vm_vram_base; -- pages = (size >> 16) << 1; -+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; -+ struct nouveau_tile_reg *tile, *found = NULL; -+ int i; - -- while (pages) { -- pgt = dev_priv->vm_vram_pt[virt >> 29]; -- pte = (virt & 0x1ffe0000ULL) >> 15; -+ for (i = 0; i < pfb->num_tiles; i++) { -+ tile = nv10_mem_get_tile_region(dev, i); - -- end = pte + pages; -- if (end > 16384) -- end = 16384; -- pages -= (end - pte); -- virt += (end - pte) << 15; -+ if (pitch && !found) { -+ found = tile; -+ continue; - -- while (pte < end) { -- nv_wo32(pgt, (pte * 4), 0); -- pte++; -+ } else if (tile && tile->pitch) { -+ /* Kill an unused tile region. */ -+ nv10_mem_update_tile_region(dev, tile, 0, 0, 0, 0); - } -+ -+ nv10_mem_put_tile_region(dev, tile, NULL); - } - -- dev_priv->engine.instmem.flush(dev); -- dev_priv->engine.fifo.tlb_flush(dev); -- dev_priv->engine.graph.tlb_flush(dev); -- nv50_vm_flush(dev, 6); -+ if (found) -+ nv10_mem_update_tile_region(dev, found, addr, size, -+ pitch, flags); -+ return found; - } - - /* -@@ -312,62 +241,7 @@ - return 0; - } - --static void --nv50_vram_preinit(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- int i, parts, colbits, rowbitsa, rowbitsb, banks; -- u64 rowsize, predicted; -- u32 r0, r4, rt, ru; -- -- r0 = nv_rd32(dev, 0x100200); -- r4 = nv_rd32(dev, 0x100204); -- rt = nv_rd32(dev, 0x100250); -- ru = nv_rd32(dev, 0x001540); -- NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); -- -- for (i = 0, parts = 0; i < 8; i++) { -- if (ru & (0x00010000 << i)) -- parts++; -- } -- -- colbits = (r4 & 0x0000f000) >> 12; -- rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; -- rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; -- banks = ((r4 & 0x01000000) ? 8 : 4); -- -- rowsize = parts * banks * (1 << colbits) * 8; -- predicted = rowsize << rowbitsa; -- if (r0 & 0x00000004) -- predicted += rowsize << rowbitsb; -- -- if (predicted != dev_priv->vram_size) { -- NV_WARN(dev, "memory controller reports %dMiB VRAM\n", -- (u32)(dev_priv->vram_size >> 20)); -- NV_WARN(dev, "we calculated %dMiB VRAM\n", -- (u32)(predicted >> 20)); -- } -- -- dev_priv->vram_rblock_size = rowsize >> 12; -- if (rt & 1) -- dev_priv->vram_rblock_size *= 3; -- -- NV_DEBUG(dev, "rblock %lld bytes\n", -- (u64)dev_priv->vram_rblock_size << 12); --} -- --static void --nvaa_vram_preinit(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- -- /* To our knowledge, there's no large scale reordering of pages -- * that occurs on IGP chipsets. -- */ -- dev_priv->vram_rblock_size = 1; --} -- --static int -+int - nouveau_mem_detect(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -381,33 +255,6 @@ - if (dev_priv->card_type < NV_50) { - dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); - dev_priv->vram_size &= NV10_PFB_FIFO_DATA_RAM_AMOUNT_MB_MASK; -- } else -- if (dev_priv->card_type < NV_C0) { -- dev_priv->vram_size = nv_rd32(dev, NV04_PFB_FIFO_DATA); -- dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; -- dev_priv->vram_size &= 0xffffffff00ll; -- -- switch (dev_priv->chipset) { -- case 0xaa: -- case 0xac: -- case 0xaf: -- dev_priv->vram_sys_base = nv_rd32(dev, 0x100e10); -- dev_priv->vram_sys_base <<= 12; -- nvaa_vram_preinit(dev); -- break; -- default: -- nv50_vram_preinit(dev); -- break; -- } -- } else { -- dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; -- dev_priv->vram_size *= nv_rd32(dev, 0x121c74); -- } -- -- NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -- if (dev_priv->vram_sys_base) { -- NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", -- dev_priv->vram_sys_base); - } - - if (dev_priv->vram_size) -@@ -415,6 +262,15 @@ - return -ENOMEM; - } - -+bool -+nouveau_mem_flags_valid(struct drm_device *dev, u32 tile_flags) -+{ -+ if (!(tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK)) -+ return true; -+ -+ return false; -+} -+ - #if __OS_HAS_AGP - static unsigned long - get_agp_mode(struct drm_device *dev, unsigned long mode) -@@ -547,10 +403,6 @@ - if (ret) - return ret; - -- ret = nouveau_mem_detect(dev); -- if (ret) -- return ret; -- - dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); - - ret = nouveau_ttm_global_init(dev_priv); -@@ -566,13 +418,6 @@ - return ret; - } - -- dev_priv->fb_available_size = dev_priv->vram_size; -- dev_priv->fb_mappable_pages = dev_priv->fb_available_size; -- if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) -- dev_priv->fb_mappable_pages = -- pci_resource_len(dev->pdev, 1); -- dev_priv->fb_mappable_pages >>= PAGE_SHIFT; -- - /* reserve space at end of VRAM for PRAMIN */ - if (dev_priv->chipset == 0x40 || dev_priv->chipset == 0x47 || - dev_priv->chipset == 0x49 || dev_priv->chipset == 0x4b) -@@ -583,6 +428,22 @@ - else - dev_priv->ramin_rsvd_vram = (512 * 1024); - -+ ret = dev_priv->engine.vram.init(dev); -+ if (ret) -+ return ret; -+ -+ NV_INFO(dev, "Detected %dMiB VRAM\n", (int)(dev_priv->vram_size >> 20)); -+ if (dev_priv->vram_sys_base) { -+ NV_INFO(dev, "Stolen system memory at: 0x%010llx\n", -+ dev_priv->vram_sys_base); -+ } -+ -+ dev_priv->fb_available_size = dev_priv->vram_size; -+ dev_priv->fb_mappable_pages = dev_priv->fb_available_size; -+ if (dev_priv->fb_mappable_pages > pci_resource_len(dev->pdev, 1)) -+ dev_priv->fb_mappable_pages = pci_resource_len(dev->pdev, 1); -+ dev_priv->fb_mappable_pages >>= PAGE_SHIFT; -+ - dev_priv->fb_available_size -= dev_priv->ramin_rsvd_vram; - dev_priv->fb_aper_free = dev_priv->fb_available_size; - -@@ -799,3 +660,118 @@ - - kfree(mem->timing); - } -+ -+static int -+nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long p_size) -+{ -+ struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); -+ struct nouveau_mm *mm; -+ u32 b_size; -+ int ret; -+ -+ p_size = (p_size << PAGE_SHIFT) >> 12; -+ b_size = dev_priv->vram_rblock_size >> 12; -+ -+ ret = nouveau_mm_init(&mm, 0, p_size, b_size); -+ if (ret) -+ return ret; -+ -+ man->priv = mm; -+ return 0; -+} -+ -+static int -+nouveau_vram_manager_fini(struct ttm_mem_type_manager *man) -+{ -+ struct nouveau_mm *mm = man->priv; -+ int ret; -+ -+ ret = nouveau_mm_fini(&mm); -+ if (ret) -+ return ret; -+ -+ man->priv = NULL; -+ return 0; -+} -+ -+static void -+nouveau_vram_manager_del(struct ttm_mem_type_manager *man, -+ struct ttm_mem_reg *mem) -+{ -+ struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); -+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; -+ struct drm_device *dev = dev_priv->dev; -+ -+ vram->put(dev, (struct nouveau_vram **)&mem->mm_node); -+} -+ -+static int -+nouveau_vram_manager_new(struct ttm_mem_type_manager *man, -+ struct ttm_buffer_object *bo, -+ struct ttm_placement *placement, -+ struct ttm_mem_reg *mem) -+{ -+ struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); -+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; -+ struct drm_device *dev = dev_priv->dev; -+ struct nouveau_bo *nvbo = nouveau_bo(bo); -+ struct nouveau_vram *node; -+ u32 size_nc = 0; -+ int ret; -+ -+ if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) -+ size_nc = 1 << nvbo->vma.node->type; -+ -+ ret = vram->get(dev, mem->num_pages << PAGE_SHIFT, -+ mem->page_alignment << PAGE_SHIFT, size_nc, -+ (nvbo->tile_flags >> 8) & 0xff, &node); -+ if (ret) -+ return ret; -+ -+ node->page_shift = 12; -+ if (nvbo->vma.node) -+ node->page_shift = nvbo->vma.node->type; -+ -+ mem->mm_node = node; -+ mem->start = node->offset >> PAGE_SHIFT; -+ return 0; -+} -+ -+void -+nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) -+{ -+ struct nouveau_mm *mm = man->priv; -+ struct nouveau_mm_node *r; -+ u64 total = 0, ttotal[3] = {}, tused[3] = {}, tfree[3] = {}; -+ int i; -+ -+ mutex_lock(&mm->mutex); -+ list_for_each_entry(r, &mm->nodes, nl_entry) { -+ printk(KERN_DEBUG "%s %s-%d: 0x%010llx 0x%010llx\n", -+ prefix, r->free ? "free" : "used", r->type, -+ ((u64)r->offset << 12), -+ (((u64)r->offset + r->length) << 12)); -+ total += r->length; -+ ttotal[r->type] += r->length; -+ if (r->free) -+ tfree[r->type] += r->length; -+ else -+ tused[r->type] += r->length; -+ } -+ mutex_unlock(&mm->mutex); -+ -+ printk(KERN_DEBUG "%s total: 0x%010llx\n", prefix, total << 12); -+ for (i = 0; i < 3; i++) { -+ printk(KERN_DEBUG "%s type %d: 0x%010llx, " -+ "used 0x%010llx, free 0x%010llx\n", prefix, -+ i, ttotal[i] << 12, tused[i] << 12, tfree[i] << 12); -+ } -+} -+ -+const struct ttm_mem_type_manager_func nouveau_vram_manager = { -+ nouveau_vram_manager_init, -+ nouveau_vram_manager_fini, -+ nouveau_vram_manager_new, -+ nouveau_vram_manager_del, -+ nouveau_vram_manager_debug -+}; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_mm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_mm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_mm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_mm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,271 @@ -+/* -+ * Copyright 2010 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_mm.h" -+ -+static inline void -+region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) -+{ -+ list_del(&a->nl_entry); -+ list_del(&a->fl_entry); -+ kfree(a); -+} -+ -+static struct nouveau_mm_node * -+region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) -+{ -+ struct nouveau_mm_node *b; -+ -+ if (a->length == size) -+ return a; -+ -+ b = kmalloc(sizeof(*b), GFP_KERNEL); -+ if (unlikely(b == NULL)) -+ return NULL; -+ -+ b->offset = a->offset; -+ b->length = size; -+ b->free = a->free; -+ b->type = a->type; -+ a->offset += size; -+ a->length -= size; -+ list_add_tail(&b->nl_entry, &a->nl_entry); -+ if (b->free) -+ list_add_tail(&b->fl_entry, &a->fl_entry); -+ return b; -+} -+ -+static struct nouveau_mm_node * -+nouveau_mm_merge(struct nouveau_mm *rmm, struct nouveau_mm_node *this) -+{ -+ struct nouveau_mm_node *prev, *next; -+ -+ /* try to merge with free adjacent entries of same type */ -+ prev = list_entry(this->nl_entry.prev, struct nouveau_mm_node, nl_entry); -+ if (this->nl_entry.prev != &rmm->nodes) { -+ if (prev->free && prev->type == this->type) { -+ prev->length += this->length; -+ region_put(rmm, this); -+ this = prev; -+ } -+ } -+ -+ next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); -+ if (this->nl_entry.next != &rmm->nodes) { -+ if (next->free && next->type == this->type) { -+ next->offset = this->offset; -+ next->length += this->length; -+ region_put(rmm, this); -+ this = next; -+ } -+ } -+ -+ return this; -+} -+ -+void -+nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) -+{ -+ u32 block_s, block_l; -+ -+ this->free = true; -+ list_add(&this->fl_entry, &rmm->free); -+ this = nouveau_mm_merge(rmm, this); -+ -+ /* any entirely free blocks now? we'll want to remove typing -+ * on them now so they can be use for any memory allocation -+ */ -+ block_s = roundup(this->offset, rmm->block_size); -+ if (block_s + rmm->block_size > this->offset + this->length) -+ return; -+ -+ /* split off any still-typed region at the start */ -+ if (block_s != this->offset) { -+ if (!region_split(rmm, this, block_s - this->offset)) -+ return; -+ } -+ -+ /* split off the soon-to-be-untyped block(s) */ -+ block_l = rounddown(this->length, rmm->block_size); -+ if (block_l != this->length) { -+ this = region_split(rmm, this, block_l); -+ if (!this) -+ return; -+ } -+ -+ /* mark as having no type, and retry merge with any adjacent -+ * untyped blocks -+ */ -+ this->type = 0; -+ nouveau_mm_merge(rmm, this); -+} -+ -+int -+nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, -+ u32 align, struct nouveau_mm_node **pnode) -+{ -+ struct nouveau_mm_node *this, *tmp, *next; -+ u32 splitoff, avail, alloc; -+ -+ list_for_each_entry_safe(this, tmp, &rmm->free, fl_entry) { -+ next = list_entry(this->nl_entry.next, struct nouveau_mm_node, nl_entry); -+ if (this->nl_entry.next == &rmm->nodes) -+ next = NULL; -+ -+ /* skip wrongly typed blocks */ -+ if (this->type && this->type != type) -+ continue; -+ -+ /* account for alignment */ -+ splitoff = this->offset & (align - 1); -+ if (splitoff) -+ splitoff = align - splitoff; -+ -+ if (this->length <= splitoff) -+ continue; -+ -+ /* determine total memory available from this, and -+ * the next block (if appropriate) -+ */ -+ avail = this->length; -+ if (next && next->free && (!next->type || next->type == type)) -+ avail += next->length; -+ -+ avail -= splitoff; -+ -+ /* determine allocation size */ -+ if (size_nc) { -+ alloc = min(avail, size); -+ alloc = rounddown(alloc, size_nc); -+ if (alloc == 0) -+ continue; -+ } else { -+ alloc = size; -+ if (avail < alloc) -+ continue; -+ } -+ -+ /* untyped block, split off a chunk that's a multiple -+ * of block_size and type it -+ */ -+ if (!this->type) { -+ u32 block = roundup(alloc + splitoff, rmm->block_size); -+ if (this->length < block) -+ continue; -+ -+ this = region_split(rmm, this, block); -+ if (!this) -+ return -ENOMEM; -+ -+ this->type = type; -+ } -+ -+ /* stealing memory from adjacent block */ -+ if (alloc > this->length) { -+ u32 amount = alloc - (this->length - splitoff); -+ -+ if (!next->type) { -+ amount = roundup(amount, rmm->block_size); -+ -+ next = region_split(rmm, next, amount); -+ if (!next) -+ return -ENOMEM; -+ -+ next->type = type; -+ } -+ -+ this->length += amount; -+ next->offset += amount; -+ next->length -= amount; -+ if (!next->length) { -+ list_del(&next->nl_entry); -+ list_del(&next->fl_entry); -+ kfree(next); -+ } -+ } -+ -+ if (splitoff) { -+ if (!region_split(rmm, this, splitoff)) -+ return -ENOMEM; -+ } -+ -+ this = region_split(rmm, this, alloc); -+ if (this == NULL) -+ return -ENOMEM; -+ -+ this->free = false; -+ list_del(&this->fl_entry); -+ *pnode = this; -+ return 0; -+ } -+ -+ return -ENOMEM; -+} -+ -+int -+nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) -+{ -+ struct nouveau_mm *rmm; -+ struct nouveau_mm_node *heap; -+ -+ heap = kzalloc(sizeof(*heap), GFP_KERNEL); -+ if (!heap) -+ return -ENOMEM; -+ heap->free = true; -+ heap->offset = roundup(offset, block); -+ heap->length = rounddown(offset + length, block) - heap->offset; -+ -+ rmm = kzalloc(sizeof(*rmm), GFP_KERNEL); -+ if (!rmm) { -+ kfree(heap); -+ return -ENOMEM; -+ } -+ rmm->block_size = block; -+ mutex_init(&rmm->mutex); -+ INIT_LIST_HEAD(&rmm->nodes); -+ INIT_LIST_HEAD(&rmm->free); -+ list_add(&heap->nl_entry, &rmm->nodes); -+ list_add(&heap->fl_entry, &rmm->free); -+ -+ *prmm = rmm; -+ return 0; -+} -+ -+int -+nouveau_mm_fini(struct nouveau_mm **prmm) -+{ -+ struct nouveau_mm *rmm = *prmm; -+ struct nouveau_mm_node *heap = -+ list_first_entry(&rmm->nodes, struct nouveau_mm_node, nl_entry); -+ -+ if (!list_is_singular(&rmm->nodes)) -+ return -EBUSY; -+ -+ kfree(heap); -+ kfree(rmm); -+ *prmm = NULL; -+ return 0; -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_mm.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_mm.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_mm.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_mm.h 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,67 @@ -+/* -+ * Copyright 2010 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 -+ */ -+ -+#ifndef __NOUVEAU_REGION_H__ -+#define __NOUVEAU_REGION_H__ -+ -+struct nouveau_mm_node { -+ struct list_head nl_entry; -+ struct list_head fl_entry; -+ struct list_head rl_entry; -+ -+ bool free; -+ int type; -+ -+ u32 offset; -+ u32 length; -+}; -+ -+struct nouveau_mm { -+ struct list_head nodes; -+ struct list_head free; -+ -+ struct mutex mutex; -+ -+ u32 block_size; -+}; -+ -+int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block); -+int nouveau_mm_fini(struct nouveau_mm **); -+int nouveau_mm_pre(struct nouveau_mm *); -+int nouveau_mm_get(struct nouveau_mm *, int type, u32 size, u32 size_nc, -+ u32 align, struct nouveau_mm_node **); -+void nouveau_mm_put(struct nouveau_mm *, struct nouveau_mm_node *); -+ -+int nv50_vram_init(struct drm_device *); -+int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, -+ u32 memtype, struct nouveau_vram **); -+void nv50_vram_del(struct drm_device *, struct nouveau_vram **); -+bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); -+ -+int nvc0_vram_init(struct drm_device *); -+int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin, -+ u32 memtype, struct nouveau_vram **); -+bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags); -+ -+#endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_notifier.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_notifier.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_notifier.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_notifier.c 2011-01-07 14:22:17.000000000 +0100 -@@ -99,7 +99,6 @@ - int size, uint32_t *b_offset) - { - struct drm_device *dev = chan->dev; -- struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *nobj = NULL; - struct drm_mm_node *mem; - uint32_t offset; -@@ -113,31 +112,15 @@ - return -ENOMEM; - } - -- offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; -- if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) { -- target = NV_DMA_TARGET_VIDMEM; -- } else -- if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_TT) { -- if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA && -- dev_priv->card_type < NV_50) { -- ret = nouveau_sgdma_get_page(dev, offset, &offset); -- if (ret) -- return ret; -- target = NV_DMA_TARGET_PCI; -- } else { -- target = NV_DMA_TARGET_AGP; -- if (dev_priv->card_type >= NV_50) -- offset += dev_priv->vm_gart_base; -- } -- } else { -- NV_ERROR(dev, "Bad DMA target, mem_type %d!\n", -- chan->notifier_bo->bo.mem.mem_type); -- return -EINVAL; -- } -+ if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) -+ target = NV_MEM_TARGET_VRAM; -+ else -+ target = NV_MEM_TARGET_GART; -+ offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; - offset += mem->start; - - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset, -- mem->size, NV_DMA_ACCESS_RW, target, -+ mem->size, NV_MEM_ACCESS_RW, target, - &nobj); - if (ret) { - drm_mm_put_block(mem); -@@ -181,15 +164,20 @@ - nouveau_ioctl_notifier_alloc(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_nouveau_notifierobj_alloc *na = data; - struct nouveau_channel *chan; - int ret; - -- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(na->channel, file_priv, chan); -+ /* completely unnecessary for these chipsets... */ -+ if (unlikely(dev_priv->card_type >= NV_C0)) -+ return -EINVAL; - -- ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); -- if (ret) -- return ret; -+ chan = nouveau_channel_get(dev, file_priv, na->channel); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); - -- return 0; -+ ret = nouveau_notifier_alloc(chan, na->handle, na->size, &na->offset); -+ nouveau_channel_put(&chan); -+ return ret; - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_object.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_object.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_object.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_object.c 2011-01-07 14:22:17.000000000 +0100 -@@ -35,6 +35,102 @@ - #include "nouveau_drv.h" - #include "nouveau_drm.h" - #include "nouveau_ramht.h" -+#include "nouveau_vm.h" -+ -+struct nouveau_gpuobj_method { -+ struct list_head head; -+ u32 mthd; -+ int (*exec)(struct nouveau_channel *, u32 class, u32 mthd, u32 data); -+}; -+ -+struct nouveau_gpuobj_class { -+ struct list_head head; -+ struct list_head methods; -+ u32 id; -+ u32 engine; -+}; -+ -+int -+nouveau_gpuobj_class_new(struct drm_device *dev, u32 class, u32 engine) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj_class *oc; -+ -+ oc = kzalloc(sizeof(*oc), GFP_KERNEL); -+ if (!oc) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&oc->methods); -+ oc->id = class; -+ oc->engine = engine; -+ list_add(&oc->head, &dev_priv->classes); -+ return 0; -+} -+ -+int -+nouveau_gpuobj_mthd_new(struct drm_device *dev, u32 class, u32 mthd, -+ int (*exec)(struct nouveau_channel *, u32, u32, u32)) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj_method *om; -+ struct nouveau_gpuobj_class *oc; -+ -+ list_for_each_entry(oc, &dev_priv->classes, head) { -+ if (oc->id == class) -+ goto found; -+ } -+ -+ return -EINVAL; -+ -+found: -+ om = kzalloc(sizeof(*om), GFP_KERNEL); -+ if (!om) -+ return -ENOMEM; -+ -+ om->mthd = mthd; -+ om->exec = exec; -+ list_add(&om->head, &oc->methods); -+ return 0; -+} -+ -+int -+nouveau_gpuobj_mthd_call(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) -+{ -+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -+ struct nouveau_gpuobj_method *om; -+ struct nouveau_gpuobj_class *oc; -+ -+ list_for_each_entry(oc, &dev_priv->classes, head) { -+ if (oc->id != class) -+ continue; -+ -+ list_for_each_entry(om, &oc->methods, head) { -+ if (om->mthd == mthd) -+ return om->exec(chan, class, mthd, data); -+ } -+ } -+ -+ return -ENOENT; -+} -+ -+int -+nouveau_gpuobj_mthd_call2(struct drm_device *dev, int chid, -+ u32 class, u32 mthd, u32 data) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan = NULL; -+ unsigned long flags; -+ int ret = -EINVAL; -+ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); -+ if (chid > 0 && chid < dev_priv->engine.fifo.channels) -+ chan = dev_priv->channels.ptr[chid]; -+ if (chan) -+ ret = nouveau_gpuobj_mthd_call(chan, class, mthd, data); -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ return ret; -+} - - /* NVidia uses context objects to drive drawing operations. - -@@ -73,17 +169,14 @@ - struct nouveau_gpuobj **gpuobj_ret) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_engine *engine = &dev_priv->engine; -+ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; - struct nouveau_gpuobj *gpuobj; - struct drm_mm_node *ramin = NULL; -- int ret; -+ int ret, i; - - NV_DEBUG(dev, "ch%d size=%u align=%d flags=0x%08x\n", - chan ? chan->id : -1, size, align, flags); - -- if (!dev_priv || !gpuobj_ret || *gpuobj_ret != NULL) -- return -EINVAL; -- - gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); - if (!gpuobj) - return -ENOMEM; -@@ -98,88 +191,41 @@ - spin_unlock(&dev_priv->ramin_lock); - - if (chan) { -- NV_DEBUG(dev, "channel heap\n"); -- - ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0); - if (ramin) - ramin = drm_mm_get_block(ramin, size, align); -- - if (!ramin) { - nouveau_gpuobj_ref(NULL, &gpuobj); - return -ENOMEM; - } -- } else { -- NV_DEBUG(dev, "global heap\n"); -- -- /* allocate backing pages, sets vinst */ -- ret = engine->instmem.populate(dev, gpuobj, &size); -- if (ret) { -- nouveau_gpuobj_ref(NULL, &gpuobj); -- return ret; -- } - -- /* try and get aperture space */ -- do { -- if (drm_mm_pre_get(&dev_priv->ramin_heap)) -- return -ENOMEM; -- -- spin_lock(&dev_priv->ramin_lock); -- ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, -- align, 0); -- if (ramin == NULL) { -- spin_unlock(&dev_priv->ramin_lock); -- nouveau_gpuobj_ref(NULL, &gpuobj); -- return -ENOMEM; -- } -- -- ramin = drm_mm_get_block_atomic(ramin, size, align); -- spin_unlock(&dev_priv->ramin_lock); -- } while (ramin == NULL); -- -- /* on nv50 it's ok to fail, we have a fallback path */ -- if (!ramin && dev_priv->card_type < NV_50) { -- nouveau_gpuobj_ref(NULL, &gpuobj); -- return -ENOMEM; -- } -- } -+ gpuobj->pinst = chan->ramin->pinst; -+ if (gpuobj->pinst != ~0) -+ gpuobj->pinst += ramin->start; - -- /* if we got a chunk of the aperture, map pages into it */ -- gpuobj->im_pramin = ramin; -- if (!chan && gpuobj->im_pramin && dev_priv->ramin_available) { -- ret = engine->instmem.bind(dev, gpuobj); -+ gpuobj->cinst = ramin->start; -+ gpuobj->vinst = ramin->start + chan->ramin->vinst; -+ gpuobj->node = ramin; -+ } else { -+ ret = instmem->get(gpuobj, size, align); - if (ret) { - nouveau_gpuobj_ref(NULL, &gpuobj); - return ret; - } -- } -- -- /* calculate the various different addresses for the object */ -- if (chan) { -- gpuobj->pinst = chan->ramin->pinst; -- if (gpuobj->pinst != ~0) -- gpuobj->pinst += gpuobj->im_pramin->start; - -- if (dev_priv->card_type < NV_50) { -- gpuobj->cinst = gpuobj->pinst; -- } else { -- gpuobj->cinst = gpuobj->im_pramin->start; -- gpuobj->vinst = gpuobj->im_pramin->start + -- chan->ramin->vinst; -- } -- } else { -- if (gpuobj->im_pramin) -- gpuobj->pinst = gpuobj->im_pramin->start; -- else -+ ret = -ENOSYS; -+ if (!(flags & NVOBJ_FLAG_DONT_MAP)) -+ ret = instmem->map(gpuobj); -+ if (ret) - gpuobj->pinst = ~0; -- gpuobj->cinst = 0xdeadbeef; -+ -+ gpuobj->cinst = NVOBJ_CINST_GLOBAL; - } - - if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { -- int i; -- - for (i = 0; i < gpuobj->size; i += 4) - nv_wo32(gpuobj, i, 0); -- engine->instmem.flush(dev); -+ instmem->flush(dev); - } - - -@@ -195,6 +241,7 @@ - NV_DEBUG(dev, "\n"); - - INIT_LIST_HEAD(&dev_priv->gpuobj_list); -+ INIT_LIST_HEAD(&dev_priv->classes); - spin_lock_init(&dev_priv->ramin_lock); - dev_priv->ramin_base = ~0; - -@@ -205,9 +252,20 @@ - nouveau_gpuobj_takedown(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj_method *om, *tm; -+ struct nouveau_gpuobj_class *oc, *tc; - - NV_DEBUG(dev, "\n"); - -+ list_for_each_entry_safe(oc, tc, &dev_priv->classes, head) { -+ list_for_each_entry_safe(om, tm, &oc->methods, head) { -+ list_del(&om->head); -+ kfree(om); -+ } -+ list_del(&oc->head); -+ kfree(oc); -+ } -+ - BUG_ON(!list_empty(&dev_priv->gpuobj_list)); - } - -@@ -219,26 +277,34 @@ - container_of(ref, struct nouveau_gpuobj, refcount); - struct drm_device *dev = gpuobj->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_engine *engine = &dev_priv->engine; -+ struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; - int i; - - NV_DEBUG(dev, "gpuobj %p\n", gpuobj); - -- if (gpuobj->im_pramin && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { -+ if (gpuobj->node && (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE)) { - for (i = 0; i < gpuobj->size; i += 4) - nv_wo32(gpuobj, i, 0); -- engine->instmem.flush(dev); -+ instmem->flush(dev); - } - - if (gpuobj->dtor) - gpuobj->dtor(dev, gpuobj); - -- if (gpuobj->im_backing) -- engine->instmem.clear(dev, gpuobj); -+ if (gpuobj->cinst == NVOBJ_CINST_GLOBAL) { -+ if (gpuobj->node) { -+ instmem->unmap(gpuobj); -+ instmem->put(gpuobj); -+ } -+ } else { -+ if (gpuobj->node) { -+ spin_lock(&dev_priv->ramin_lock); -+ drm_mm_put_block(gpuobj->node); -+ spin_unlock(&dev_priv->ramin_lock); -+ } -+ } - - spin_lock(&dev_priv->ramin_lock); -- if (gpuobj->im_pramin) -- drm_mm_put_block(gpuobj->im_pramin); - list_del(&gpuobj->list); - spin_unlock(&dev_priv->ramin_lock); - -@@ -278,7 +344,7 @@ - kref_init(&gpuobj->refcount); - gpuobj->size = size; - gpuobj->pinst = pinst; -- gpuobj->cinst = 0xdeadbeef; -+ gpuobj->cinst = NVOBJ_CINST_GLOBAL; - gpuobj->vinst = vinst; - - if (gpuobj->flags & NVOBJ_FLAG_ZERO_ALLOC) { -@@ -335,113 +401,150 @@ - The method below creates a DMA object in instance RAM and returns a handle - to it that can be used to set up context objects. - */ --int --nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, -- uint64_t offset, uint64_t size, int access, -- int target, struct nouveau_gpuobj **gpuobj) --{ -- struct drm_device *dev = chan->dev; -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; -- int ret; - -- NV_DEBUG(dev, "ch%d class=0x%04x offset=0x%llx size=0x%llx\n", -- chan->id, class, offset, size); -- NV_DEBUG(dev, "access=%d target=%d\n", access, target); -+void -+nv50_gpuobj_dma_init(struct nouveau_gpuobj *obj, u32 offset, int class, -+ u64 base, u64 size, int target, int access, -+ u32 type, u32 comp) -+{ -+ struct drm_nouveau_private *dev_priv = obj->dev->dev_private; -+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; -+ u32 flags0; -+ -+ flags0 = (comp << 29) | (type << 22) | class; -+ flags0 |= 0x00100000; -+ -+ switch (access) { -+ case NV_MEM_ACCESS_RO: flags0 |= 0x00040000; break; -+ case NV_MEM_ACCESS_RW: -+ case NV_MEM_ACCESS_WO: flags0 |= 0x00080000; break; -+ default: -+ break; -+ } - - switch (target) { -- case NV_DMA_TARGET_AGP: -- offset += dev_priv->gart_info.aper_base; -+ case NV_MEM_TARGET_VRAM: -+ flags0 |= 0x00010000; -+ break; -+ case NV_MEM_TARGET_PCI: -+ flags0 |= 0x00020000; -+ break; -+ case NV_MEM_TARGET_PCI_NOSNOOP: -+ flags0 |= 0x00030000; - break; -+ case NV_MEM_TARGET_GART: -+ base += dev_priv->gart_info.aper_base; - default: -+ flags0 &= ~0x00100000; - break; - } - -- 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; -- } -+ /* convert to base + limit */ -+ size = (base + size) - 1; - -- if (dev_priv->card_type < NV_50) { -- uint32_t frame, adjust, pte_flags = 0; -+ nv_wo32(obj, offset + 0x00, flags0); -+ nv_wo32(obj, offset + 0x04, lower_32_bits(size)); -+ nv_wo32(obj, offset + 0x08, lower_32_bits(base)); -+ nv_wo32(obj, offset + 0x0c, upper_32_bits(size) << 24 | -+ upper_32_bits(base)); -+ nv_wo32(obj, offset + 0x10, 0x00000000); -+ nv_wo32(obj, offset + 0x14, 0x00000000); - -- if (access != NV_DMA_ACCESS_RO) -- pte_flags |= (1<<1); -- adjust = offset & 0x00000fff; -- frame = offset & ~0x00000fff; -- -- nv_wo32(*gpuobj, 0, ((1<<12) | (1<<13) | (adjust << 20) | -- (access << 14) | (target << 16) | -- class)); -- nv_wo32(*gpuobj, 4, size - 1); -- nv_wo32(*gpuobj, 8, frame | pte_flags); -- nv_wo32(*gpuobj, 12, frame | pte_flags); -- } else { -- uint64_t limit = offset + size - 1; -- uint32_t flags0, flags5; -- -- if (target == NV_DMA_TARGET_VIDMEM) { -- flags0 = 0x00190000; -- flags5 = 0x00010000; -- } else { -- flags0 = 0x7fc00000; -- flags5 = 0x00080000; -- } -+ pinstmem->flush(obj->dev); -+} - -- nv_wo32(*gpuobj, 0, flags0 | class); -- nv_wo32(*gpuobj, 4, lower_32_bits(limit)); -- nv_wo32(*gpuobj, 8, lower_32_bits(offset)); -- nv_wo32(*gpuobj, 12, ((upper_32_bits(limit) & 0xff) << 24) | -- (upper_32_bits(offset) & 0xff)); -- nv_wo32(*gpuobj, 20, flags5); -- } -+int -+nv50_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, u64 size, -+ int target, int access, u32 type, u32 comp, -+ struct nouveau_gpuobj **pobj) -+{ -+ struct drm_device *dev = chan->dev; -+ int ret; - -- instmem->flush(dev); -+ ret = nouveau_gpuobj_new(dev, chan, 24, 16, NVOBJ_FLAG_ZERO_FREE, pobj); -+ if (ret) -+ return ret; - -- (*gpuobj)->engine = NVOBJ_ENGINE_SW; -- (*gpuobj)->class = class; -+ nv50_gpuobj_dma_init(*pobj, 0, class, base, size, target, -+ access, type, comp); - return 0; - } - - int --nouveau_gpuobj_gart_dma_new(struct nouveau_channel *chan, -- uint64_t offset, uint64_t size, int access, -- struct nouveau_gpuobj **gpuobj, -- uint32_t *o_ret) -+nouveau_gpuobj_dma_new(struct nouveau_channel *chan, int class, u64 base, -+ u64 size, int access, int target, -+ struct nouveau_gpuobj **pobj) - { -+ 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_gpuobj *obj; -+ u32 flags0, flags2; - int ret; - -- if (dev_priv->gart_info.type == NOUVEAU_GART_AGP || -- (dev_priv->card_type >= NV_50 && -- dev_priv->gart_info.type == NOUVEAU_GART_SGDMA)) { -- ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -- offset + dev_priv->vm_gart_base, -- size, access, NV_DMA_TARGET_AGP, -- gpuobj); -- if (o_ret) -- *o_ret = 0; -- } else -- if (dev_priv->gart_info.type == NOUVEAU_GART_SGDMA) { -- nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, gpuobj); -- if (offset & ~0xffffffffULL) { -- NV_ERROR(dev, "obj offset exceeds 32-bits\n"); -- return -EINVAL; -- } -- if (o_ret) -- *o_ret = (uint32_t)offset; -- ret = (*gpuobj != NULL) ? 0 : -EINVAL; -- } else { -- NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type); -- return -EINVAL; -+ if (dev_priv->card_type >= NV_50) { -+ u32 comp = (target == NV_MEM_TARGET_VM) ? NV_MEM_COMP_VM : 0; -+ u32 type = (target == NV_MEM_TARGET_VM) ? NV_MEM_TYPE_VM : 0; -+ -+ return nv50_gpuobj_dma_new(chan, class, base, size, -+ target, access, type, comp, pobj); - } - -- return ret; -+ if (target == NV_MEM_TARGET_GART) { -+ if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) { -+ target = NV_MEM_TARGET_PCI_NOSNOOP; -+ base += dev_priv->gart_info.aper_base; -+ } else -+ if (base != 0) { -+ base = nouveau_sgdma_get_physical(dev, base); -+ target = NV_MEM_TARGET_PCI; -+ } else { -+ nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj); -+ return 0; -+ } -+ } -+ -+ flags0 = class; -+ flags0 |= 0x00003000; /* PT present, PT linear */ -+ flags2 = 0; -+ -+ switch (target) { -+ case NV_MEM_TARGET_PCI: -+ flags0 |= 0x00020000; -+ break; -+ case NV_MEM_TARGET_PCI_NOSNOOP: -+ flags0 |= 0x00030000; -+ break; -+ default: -+ break; -+ } -+ -+ switch (access) { -+ case NV_MEM_ACCESS_RO: -+ flags0 |= 0x00004000; -+ break; -+ case NV_MEM_ACCESS_WO: -+ flags0 |= 0x00008000; -+ default: -+ flags2 |= 0x00000002; -+ break; -+ } -+ -+ flags0 |= (base & 0x00000fff) << 20; -+ flags2 |= (base & 0xfffff000); -+ -+ ret = nouveau_gpuobj_new(dev, chan, 16, 16, NVOBJ_FLAG_ZERO_FREE, &obj); -+ if (ret) -+ return ret; -+ -+ nv_wo32(obj, 0x00, flags0); -+ nv_wo32(obj, 0x04, size - 1); -+ nv_wo32(obj, 0x08, flags2); -+ nv_wo32(obj, 0x0c, flags2); -+ -+ obj->engine = NVOBJ_ENGINE_SW; -+ obj->class = class; -+ *pobj = obj; -+ return 0; - } - - /* Context objects in the instance RAM have the following structure. -@@ -495,82 +598,130 @@ - entry[5]: - set to 0? - */ -+static int -+nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, -+ struct nouveau_gpuobj **gpuobj_ret) -+{ -+ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; -+ struct nouveau_gpuobj *gpuobj; -+ -+ gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); -+ if (!gpuobj) -+ return -ENOMEM; -+ gpuobj->dev = chan->dev; -+ gpuobj->engine = NVOBJ_ENGINE_SW; -+ gpuobj->class = class; -+ kref_init(&gpuobj->refcount); -+ gpuobj->cinst = 0x40; -+ -+ 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; -+} -+ - int --nouveau_gpuobj_gr_new(struct nouveau_channel *chan, int class, -- struct nouveau_gpuobj **gpuobj) -+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 drm_nouveau_private *dev_priv = dev->dev_private; -+ 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; -+ -+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; -+ -+ 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; -+ -+ ret = pcrypt->create_context(chan); -+ 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); -+ &gpuobj); - if (ret) { -- NV_ERROR(dev, "Error creating gpuobj: %d\n", 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); -+ 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); -+ nv_wo32(gpuobj, 0, 0x00001030); -+ nv_wo32(gpuobj, 4, 0xFFFFFFFF); - break; - default: - if (dev_priv->card_type >= NV_40) { -- nv_wo32(*gpuobj, 0, class); -+ nv_wo32(gpuobj, 0, class); - #ifdef __BIG_ENDIAN -- nv_wo32(*gpuobj, 8, 0x01000000); -+ nv_wo32(gpuobj, 8, 0x01000000); - #endif - } else { - #ifdef __BIG_ENDIAN -- nv_wo32(*gpuobj, 0, class | 0x00080000); -+ nv_wo32(gpuobj, 0, class | 0x00080000); - #else -- nv_wo32(*gpuobj, 0, class); -+ nv_wo32(gpuobj, 0, class); - #endif - } - } - } - dev_priv->engine.instmem.flush(dev); - -- (*gpuobj)->engine = NVOBJ_ENGINE_GR; -- (*gpuobj)->class = class; -- return 0; --} -- --int --nouveau_gpuobj_sw_new(struct nouveau_channel *chan, int class, -- struct nouveau_gpuobj **gpuobj_ret) --{ -- struct drm_nouveau_private *dev_priv; -- struct nouveau_gpuobj *gpuobj; -- -- if (!chan || !gpuobj_ret || *gpuobj_ret != NULL) -- return -EINVAL; -- dev_priv = chan->dev->dev_private; -+ gpuobj->engine = oc->engine; -+ gpuobj->class = oc->id; - -- gpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL); -- if (!gpuobj) -- return -ENOMEM; -- gpuobj->dev = chan->dev; -- gpuobj->engine = NVOBJ_ENGINE_SW; -- gpuobj->class = class; -- kref_init(&gpuobj->refcount); -- gpuobj->cinst = 0x40; -- -- 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; -+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; - } - - static int -@@ -585,7 +736,7 @@ - NV_DEBUG(dev, "ch%d\n", chan->id); - - /* Base amount for object storage (4KiB enough?) */ -- size = 0x1000; -+ size = 0x2000; - base = 0; - - /* PGRAPH context */ -@@ -624,12 +775,30 @@ - { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_instmem_engine *instmem = &dev_priv->engine.instmem; - struct nouveau_gpuobj *vram = NULL, *tt = NULL; -- int ret, i; -+ int ret; - - NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); - -+ if (dev_priv->card_type == NV_C0) { -+ struct nouveau_vm *vm = dev_priv->chan_vm; -+ struct nouveau_vm_pgd *vpgd; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, -+ &chan->ramin); -+ if (ret) -+ return ret; -+ -+ nouveau_vm_ref(vm, &chan->vm, NULL); -+ -+ vpgd = list_first_entry(&vm->pgd_list, struct nouveau_vm_pgd, head); -+ nv_wo32(chan->ramin, 0x0200, lower_32_bits(vpgd->obj->vinst)); -+ nv_wo32(chan->ramin, 0x0204, upper_32_bits(vpgd->obj->vinst)); -+ nv_wo32(chan->ramin, 0x0208, 0xffffffff); -+ nv_wo32(chan->ramin, 0x020c, 0x000000ff); -+ return 0; -+ } -+ - /* Allocate a chunk of memory for per-channel object storage */ - ret = nouveau_gpuobj_channel_init_pramin(chan); - if (ret) { -@@ -639,14 +808,12 @@ - - /* NV50 VM - * - Allocate per-channel page-directory -- * - Map GART and VRAM into the channel's address space at the -- * locations determined during init. -+ * - Link with shared channel VM - */ -- if (dev_priv->card_type >= NV_50) { -+ if (dev_priv->chan_vm) { - u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; - u64 vm_vinst = chan->ramin->vinst + pgd_offs; - u32 vm_pinst = chan->ramin->pinst; -- u32 pde; - - if (vm_pinst != ~0) - vm_pinst += pgd_offs; -@@ -655,29 +822,8 @@ - 0, &chan->vm_pd); - if (ret) - return ret; -- for (i = 0; i < 0x4000; i += 8) { -- nv_wo32(chan->vm_pd, i + 0, 0x00000000); -- nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe); -- } -- -- nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, -- &chan->vm_gart_pt); -- pde = (dev_priv->vm_gart_base / (512*1024*1024)) * 8; -- nv_wo32(chan->vm_pd, pde + 0, chan->vm_gart_pt->vinst | 3); -- nv_wo32(chan->vm_pd, pde + 4, 0x00000000); -- -- pde = (dev_priv->vm_vram_base / (512*1024*1024)) * 8; -- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { -- nouveau_gpuobj_ref(dev_priv->vm_vram_pt[i], -- &chan->vm_vram_pt[i]); -- -- nv_wo32(chan->vm_pd, pde + 0, -- chan->vm_vram_pt[i]->vinst | 0x61); -- nv_wo32(chan->vm_pd, pde + 4, 0x00000000); -- pde += 8; -- } - -- instmem->flush(dev); -+ nouveau_vm_ref(dev_priv->chan_vm, &chan->vm, chan->vm_pd); - } - - /* RAMHT */ -@@ -700,9 +846,8 @@ - /* VRAM ctxdma */ - if (dev_priv->card_type >= NV_50) { - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -- 0, dev_priv->vm_end, -- NV_DMA_ACCESS_RW, -- NV_DMA_TARGET_AGP, &vram); -+ 0, (1ULL << 40), NV_MEM_ACCESS_RW, -+ NV_MEM_TARGET_VM, &vram); - if (ret) { - NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); - return ret; -@@ -710,8 +855,8 @@ - } else { - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->fb_available_size, -- NV_DMA_ACCESS_RW, -- NV_DMA_TARGET_VIDMEM, &vram); -+ NV_MEM_ACCESS_RW, -+ NV_MEM_TARGET_VRAM, &vram); - if (ret) { - NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); - return ret; -@@ -728,21 +873,13 @@ - /* TT memory ctxdma */ - if (dev_priv->card_type >= NV_50) { - ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -- 0, dev_priv->vm_end, -- NV_DMA_ACCESS_RW, -- NV_DMA_TARGET_AGP, &tt); -- if (ret) { -- NV_ERROR(dev, "Error creating VRAM ctxdma: %d\n", ret); -- return ret; -- } -- } else -- if (dev_priv->gart_info.type != NOUVEAU_GART_NONE) { -- ret = nouveau_gpuobj_gart_dma_new(chan, 0, -- dev_priv->gart_info.aper_size, -- NV_DMA_ACCESS_RW, &tt, NULL); -+ 0, (1ULL << 40), NV_MEM_ACCESS_RW, -+ NV_MEM_TARGET_VM, &tt); - } else { -- NV_ERROR(dev, "Invalid GART type %d\n", dev_priv->gart_info.type); -- ret = -EINVAL; -+ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, -+ 0, dev_priv->gart_info.aper_size, -+ NV_MEM_ACCESS_RW, -+ NV_MEM_TARGET_GART, &tt); - } - - if (ret) { -@@ -763,21 +900,14 @@ - void - nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) - { -- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; - struct drm_device *dev = chan->dev; -- int i; - - NV_DEBUG(dev, "ch%d\n", chan->id); - -- if (!chan->ramht) -- return; -- - nouveau_ramht_ref(NULL, &chan->ramht, chan); - -+ nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); - nouveau_gpuobj_ref(NULL, &chan->vm_pd); -- nouveau_gpuobj_ref(NULL, &chan->vm_gart_pt); -- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) -- nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); - - if (chan->ramin_heap.free_stack.next) - drm_mm_takedown(&chan->ramin_heap); -@@ -791,147 +921,91 @@ - struct nouveau_gpuobj *gpuobj; - int i; - -- if (dev_priv->card_type < NV_50) { -- dev_priv->susres.ramin_copy = vmalloc(dev_priv->ramin_rsvd_vram); -- if (!dev_priv->susres.ramin_copy) -- return -ENOMEM; -- -- for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4) -- dev_priv->susres.ramin_copy[i/4] = nv_ri32(dev, i); -- return 0; -- } -- - list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { -- if (!gpuobj->im_backing) -+ if (gpuobj->cinst != NVOBJ_CINST_GLOBAL) - continue; - -- gpuobj->im_backing_suspend = vmalloc(gpuobj->size); -- if (!gpuobj->im_backing_suspend) { -+ gpuobj->suspend = vmalloc(gpuobj->size); -+ if (!gpuobj->suspend) { - nouveau_gpuobj_resume(dev); - return -ENOMEM; - } - - for (i = 0; i < gpuobj->size; i += 4) -- gpuobj->im_backing_suspend[i/4] = nv_ro32(gpuobj, i); -+ gpuobj->suspend[i/4] = nv_ro32(gpuobj, i); - } - - return 0; - } - - void --nouveau_gpuobj_suspend_cleanup(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *gpuobj; -- -- if (dev_priv->card_type < NV_50) { -- vfree(dev_priv->susres.ramin_copy); -- dev_priv->susres.ramin_copy = NULL; -- return; -- } -- -- list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { -- if (!gpuobj->im_backing_suspend) -- continue; -- -- vfree(gpuobj->im_backing_suspend); -- gpuobj->im_backing_suspend = NULL; -- } --} -- --void - nouveau_gpuobj_resume(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *gpuobj; - int i; - -- if (dev_priv->card_type < NV_50) { -- for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4) -- nv_wi32(dev, i, dev_priv->susres.ramin_copy[i/4]); -- nouveau_gpuobj_suspend_cleanup(dev); -- return; -- } -- - list_for_each_entry(gpuobj, &dev_priv->gpuobj_list, list) { -- if (!gpuobj->im_backing_suspend) -+ if (!gpuobj->suspend) - continue; - - for (i = 0; i < gpuobj->size; i += 4) -- nv_wo32(gpuobj, i, gpuobj->im_backing_suspend[i/4]); -- dev_priv->engine.instmem.flush(dev); -+ nv_wo32(gpuobj, i, gpuobj->suspend[i/4]); -+ -+ vfree(gpuobj->suspend); -+ gpuobj->suspend = NULL; - } - -- nouveau_gpuobj_suspend_cleanup(dev); -+ dev_priv->engine.instmem.flush(dev); - } - - int nouveau_ioctl_grobj_alloc(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; - struct drm_nouveau_grobj_alloc *init = data; -- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; -- struct nouveau_pgraph_object_class *grc; -- struct nouveau_gpuobj *gr = NULL; - struct nouveau_channel *chan; - int ret; - -- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(init->channel, file_priv, chan); -- - if (init->handle == ~0) - return -EINVAL; - -- grc = pgraph->grclass; -- while (grc->id) { -- if (grc->id == init->class) -- break; -- grc++; -- } -+ chan = nouveau_channel_get(dev, file_priv, init->channel); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); - -- if (!grc->id) { -- NV_ERROR(dev, "Illegal object class: 0x%x\n", init->class); -- return -EPERM; -+ if (nouveau_ramht_find(chan, init->handle)) { -+ ret = -EEXIST; -+ goto out; - } - -- if (nouveau_ramht_find(chan, init->handle)) -- return -EEXIST; -- -- if (!grc->software) -- ret = nouveau_gpuobj_gr_new(chan, grc->id, &gr); -- else -- ret = nouveau_gpuobj_sw_new(chan, grc->id, &gr); -+ ret = nouveau_gpuobj_gr_new(chan, init->handle, init->class); - if (ret) { - NV_ERROR(dev, "Error creating object: %d (%d/0x%08x)\n", - ret, init->channel, init->handle); -- return ret; - } - -- ret = nouveau_ramht_insert(chan, init->handle, gr); -- nouveau_gpuobj_ref(NULL, &gr); -- if (ret) { -- NV_ERROR(dev, "Error referencing object: %d (%d/0x%08x)\n", -- ret, init->channel, init->handle); -- return ret; -- } -- -- return 0; -+out: -+ nouveau_channel_put(&chan); -+ return ret; - } - - int nouveau_ioctl_gpuobj_free(struct drm_device *dev, void *data, - struct drm_file *file_priv) - { - struct drm_nouveau_gpuobj_free *objfree = data; -- struct nouveau_gpuobj *gpuobj; - struct nouveau_channel *chan; -+ int ret; - -- NOUVEAU_GET_USER_CHANNEL_WITH_RETURN(objfree->channel, file_priv, chan); -+ chan = nouveau_channel_get(dev, file_priv, objfree->channel); -+ if (IS_ERR(chan)) -+ return PTR_ERR(chan); - -- gpuobj = nouveau_ramht_find(chan, objfree->handle); -- if (!gpuobj) -- return -ENOENT; -+ /* Synchronize with the user channel */ -+ nouveau_channel_idle(chan); - -- nouveau_ramht_remove(chan, objfree->handle); -- return 0; -+ ret = nouveau_ramht_remove(chan, objfree->handle); -+ nouveau_channel_put(&chan); -+ return ret; - } - - u32 -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_pm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_pm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_pm.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -27,6 +27,10 @@ - #include "nouveau_drv.h" - #include "nouveau_pm.h" - -+#ifdef CONFIG_ACPI -+#include -+#endif -+#include - #include - #include - -@@ -418,8 +422,7 @@ - return ret; - } - dev_set_drvdata(hwmon_dev, dev); -- ret = sysfs_create_group(&hwmon_dev->kobj, -- &hwmon_attrgroup); -+ ret = sysfs_create_group(&dev->pdev->dev.kobj, &hwmon_attrgroup); - if (ret) { - NV_ERROR(dev, - "Unable to create hwmon sysfs file: %d\n", ret); -@@ -446,6 +449,25 @@ - #endif - } - -+#ifdef CONFIG_ACPI -+static int -+nouveau_pm_acpi_event(struct notifier_block *nb, unsigned long val, void *data) -+{ -+ struct drm_nouveau_private *dev_priv = -+ container_of(nb, struct drm_nouveau_private, engine.pm.acpi_nb); -+ struct drm_device *dev = dev_priv->dev; -+ struct acpi_bus_event *entry = (struct acpi_bus_event *)data; -+ -+ if (strcmp(entry->device_class, "ac_adapter") == 0) { -+ bool ac = power_supply_is_system_supplied(); -+ -+ NV_DEBUG(dev, "power supply changed: %s\n", ac ? "AC" : "DC"); -+ } -+ -+ return NOTIFY_OK; -+} -+#endif -+ - int - nouveau_pm_init(struct drm_device *dev) - { -@@ -485,6 +507,10 @@ - - nouveau_sysfs_init(dev); - nouveau_hwmon_init(dev); -+#ifdef CONFIG_ACPI -+ pm->acpi_nb.notifier_call = nouveau_pm_acpi_event; -+ register_acpi_notifier(&pm->acpi_nb); -+#endif - - return 0; - } -@@ -503,6 +529,9 @@ - nouveau_perf_fini(dev); - nouveau_volt_fini(dev); - -+#ifdef CONFIG_ACPI -+ unregister_acpi_notifier(&pm->acpi_nb); -+#endif - nouveau_hwmon_fini(dev); - nouveau_sysfs_fini(dev); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_ramht.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_ramht.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_ramht.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_ramht.c 2011-01-07 14:22:17.000000000 +0100 -@@ -104,17 +104,17 @@ - nouveau_gpuobj_ref(gpuobj, &entry->gpuobj); - - if (dev_priv->card_type < NV_40) { -- ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->cinst >> 4) | -+ ctx = NV_RAMHT_CONTEXT_VALID | (gpuobj->pinst >> 4) | - (chan->id << NV_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (gpuobj->engine << NV_RAMHT_CONTEXT_ENGINE_SHIFT); - } else - if (dev_priv->card_type < NV_50) { -- ctx = (gpuobj->cinst >> 4) | -+ ctx = (gpuobj->pinst >> 4) | - (chan->id << NV40_RAMHT_CONTEXT_CHANNEL_SHIFT) | - (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); - } else { - if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { -- ctx = (gpuobj->cinst << 10) | 2; -+ ctx = (gpuobj->cinst << 10) | chan->id; - } else { - ctx = (gpuobj->cinst >> 4) | - ((gpuobj->engine << -@@ -214,18 +214,19 @@ - spin_unlock_irqrestore(&chan->ramht->lock, flags); - } - --void -+int - nouveau_ramht_remove(struct nouveau_channel *chan, u32 handle) - { - struct nouveau_ramht_entry *entry; - - entry = nouveau_ramht_remove_entry(chan, handle); - if (!entry) -- return; -+ return -ENOENT; - - nouveau_ramht_remove_hash(chan, entry->handle); - nouveau_gpuobj_ref(NULL, &entry->gpuobj); - kfree(entry); -+ return 0; - } - - struct nouveau_gpuobj * -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_ramht.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_ramht.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_ramht.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_ramht.h 2011-01-07 14:22:17.000000000 +0100 -@@ -48,7 +48,7 @@ - - extern int nouveau_ramht_insert(struct nouveau_channel *, u32 handle, - struct nouveau_gpuobj *); --extern void nouveau_ramht_remove(struct nouveau_channel *, u32 handle); -+extern int nouveau_ramht_remove(struct nouveau_channel *, u32 handle); - extern struct nouveau_gpuobj * - nouveau_ramht_find(struct nouveau_channel *chan, u32 handle); - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_reg.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_reg.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_reg.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_reg.h 2011-01-07 14:22:17.000000000 +0100 -@@ -45,6 +45,11 @@ - # define NV04_PFB_REF_CMD_REFRESH (1 << 0) - #define NV04_PFB_PRE 0x001002d4 - # define NV04_PFB_PRE_CMD_PRECHARGE (1 << 0) -+#define NV20_PFB_ZCOMP(i) (0x00100300 + 4*(i)) -+# define NV20_PFB_ZCOMP_MODE_32 (4 << 24) -+# define NV20_PFB_ZCOMP_EN (1 << 31) -+# define NV25_PFB_ZCOMP_MODE_16 (1 << 20) -+# define NV25_PFB_ZCOMP_MODE_32 (2 << 20) - #define NV10_PFB_CLOSE_PAGE2 0x0010033c - #define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i)) - #define NV40_PFB_TILE(i) (0x00100600 + (i*16)) -@@ -74,17 +79,6 @@ - # define NV40_RAMHT_CONTEXT_ENGINE_SHIFT 20 - # define NV40_RAMHT_CONTEXT_INSTANCE_SHIFT 0 - --/* DMA object defines */ --#define NV_DMA_ACCESS_RW 0 --#define NV_DMA_ACCESS_RO 1 --#define NV_DMA_ACCESS_WO 2 --#define NV_DMA_TARGET_VIDMEM 0 --#define NV_DMA_TARGET_PCI 2 --#define NV_DMA_TARGET_AGP 3 --/* The following is not a real value used by the card, it's changed by -- * nouveau_object_dma_create */ --#define NV_DMA_TARGET_PCI_NONLINEAR 8 -- - /* Some object classes we care about in the drm */ - #define NV_CLASS_DMA_FROM_MEMORY 0x00000002 - #define NV_CLASS_DMA_TO_MEMORY 0x00000003 -@@ -332,6 +326,7 @@ - #define NV04_PGRAPH_BSWIZZLE5 0x004006A0 - #define NV03_PGRAPH_STATUS 0x004006B0 - #define NV04_PGRAPH_STATUS 0x00400700 -+# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000 - #define NV04_PGRAPH_TRAPPED_ADDR 0x00400704 - #define NV04_PGRAPH_TRAPPED_DATA 0x00400708 - #define NV04_PGRAPH_SURFACE 0x0040070C -@@ -378,6 +373,7 @@ - #define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16)) - #define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16)) - #define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16)) -+#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i)) - #define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16)) - #define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16)) - #define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16)) -@@ -714,31 +710,32 @@ - #define NV50_PDISPLAY_INTR_1_CLK_UNK10 0x00000010 - #define NV50_PDISPLAY_INTR_1_CLK_UNK20 0x00000020 - #define NV50_PDISPLAY_INTR_1_CLK_UNK40 0x00000040 --#define NV50_PDISPLAY_INTR_EN 0x0061002c --#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC 0x0000000c --#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(n) (1 << ((n) + 2)) --#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_0 0x00000004 --#define NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_1 0x00000008 --#define NV50_PDISPLAY_INTR_EN_CLK_UNK10 0x00000010 --#define NV50_PDISPLAY_INTR_EN_CLK_UNK20 0x00000020 --#define NV50_PDISPLAY_INTR_EN_CLK_UNK40 0x00000040 -+#define NV50_PDISPLAY_INTR_EN_0 0x00610028 -+#define NV50_PDISPLAY_INTR_EN_1 0x0061002c -+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC 0x0000000c -+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_(n) (1 << ((n) + 2)) -+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_0 0x00000004 -+#define NV50_PDISPLAY_INTR_EN_1_VBLANK_CRTC_1 0x00000008 -+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 0x00000010 -+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 0x00000020 -+#define NV50_PDISPLAY_INTR_EN_1_CLK_UNK40 0x00000040 - #define NV50_PDISPLAY_UNK30_CTRL 0x00610030 - #define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK0 0x00000200 - #define NV50_PDISPLAY_UNK30_CTRL_UPDATE_VCLK1 0x00000400 - #define NV50_PDISPLAY_UNK30_CTRL_PENDING 0x80000000 --#define NV50_PDISPLAY_TRAPPED_ADDR 0x00610080 --#define NV50_PDISPLAY_TRAPPED_DATA 0x00610084 --#define NV50_PDISPLAY_CHANNEL_STAT(i) ((i) * 0x10 + 0x00610200) --#define NV50_PDISPLAY_CHANNEL_STAT_DMA 0x00000010 --#define NV50_PDISPLAY_CHANNEL_STAT_DMA_DISABLED 0x00000000 --#define NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED 0x00000010 --#define NV50_PDISPLAY_CHANNEL_DMA_CB(i) ((i) * 0x10 + 0x00610204) --#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION 0x00000002 --#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM 0x00000000 --#define NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_SYSTEM 0x00000002 --#define NV50_PDISPLAY_CHANNEL_DMA_CB_VALID 0x00000001 --#define NV50_PDISPLAY_CHANNEL_UNK2(i) ((i) * 0x10 + 0x00610208) --#define NV50_PDISPLAY_CHANNEL_UNK3(i) ((i) * 0x10 + 0x0061020c) -+#define NV50_PDISPLAY_TRAPPED_ADDR(i) ((i) * 0x08 + 0x00610080) -+#define NV50_PDISPLAY_TRAPPED_DATA(i) ((i) * 0x08 + 0x00610084) -+#define NV50_PDISPLAY_EVO_CTRL(i) ((i) * 0x10 + 0x00610200) -+#define NV50_PDISPLAY_EVO_CTRL_DMA 0x00000010 -+#define NV50_PDISPLAY_EVO_CTRL_DMA_DISABLED 0x00000000 -+#define NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED 0x00000010 -+#define NV50_PDISPLAY_EVO_DMA_CB(i) ((i) * 0x10 + 0x00610204) -+#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION 0x00000002 -+#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM 0x00000000 -+#define NV50_PDISPLAY_EVO_DMA_CB_LOCATION_SYSTEM 0x00000002 -+#define NV50_PDISPLAY_EVO_DMA_CB_VALID 0x00000001 -+#define NV50_PDISPLAY_EVO_UNK2(i) ((i) * 0x10 + 0x00610208) -+#define NV50_PDISPLAY_EVO_HASH_TAG(i) ((i) * 0x10 + 0x0061020c) - - #define NV50_PDISPLAY_CURSOR 0x00610270 - #define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i) ((i) * 0x10 + 0x00610270) -@@ -746,15 +743,11 @@ - #define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS 0x00030000 - #define NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS_ACTIVE 0x00010000 - --#define NV50_PDISPLAY_CTRL_STATE 0x00610300 --#define NV50_PDISPLAY_CTRL_STATE_PENDING 0x80000000 --#define NV50_PDISPLAY_CTRL_STATE_METHOD 0x00001ffc --#define NV50_PDISPLAY_CTRL_STATE_ENABLE 0x00000001 --#define NV50_PDISPLAY_CTRL_VAL 0x00610304 --#define NV50_PDISPLAY_UNK_380 0x00610380 --#define NV50_PDISPLAY_RAM_AMOUNT 0x00610384 --#define NV50_PDISPLAY_UNK_388 0x00610388 --#define NV50_PDISPLAY_UNK_38C 0x0061038c -+#define NV50_PDISPLAY_PIO_CTRL 0x00610300 -+#define NV50_PDISPLAY_PIO_CTRL_PENDING 0x80000000 -+#define NV50_PDISPLAY_PIO_CTRL_MTHD 0x00001ffc -+#define NV50_PDISPLAY_PIO_CTRL_ENABLED 0x00000001 -+#define NV50_PDISPLAY_PIO_DATA 0x00610304 - - #define NV50_PDISPLAY_CRTC_P(i, r) ((i) * 0x540 + NV50_PDISPLAY_CRTC_##r) - #define NV50_PDISPLAY_CRTC_C(i, r) (4 + (i) * 0x540 + NV50_PDISPLAY_CRTC_##r) -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_sgdma.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_sgdma.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_sgdma.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_sgdma.c 2011-01-07 14:22:17.000000000 +0100 -@@ -14,7 +14,7 @@ - dma_addr_t *pages; - unsigned nr_pages; - -- unsigned pte_start; -+ u64 offset; - bool bound; - }; - -@@ -74,18 +74,6 @@ - } - } - --static inline unsigned --nouveau_sgdma_pte(struct drm_device *dev, uint64_t offset) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- unsigned pte = (offset >> NV_CTXDMA_PAGE_SHIFT); -- -- if (dev_priv->card_type < NV_50) -- return pte + 2; -- -- return pte << 1; --} -- - static int - nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) - { -@@ -97,32 +85,17 @@ - - NV_DEBUG(dev, "pg=0x%lx\n", mem->start); - -- pte = nouveau_sgdma_pte(nvbe->dev, mem->start << PAGE_SHIFT); -- nvbe->pte_start = pte; -+ nvbe->offset = mem->start << PAGE_SHIFT; -+ pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2; - for (i = 0; i < nvbe->nr_pages; i++) { - dma_addr_t dma_offset = nvbe->pages[i]; - uint32_t offset_l = lower_32_bits(dma_offset); -- uint32_t offset_h = upper_32_bits(dma_offset); -- -- for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { -- if (dev_priv->card_type < NV_50) { -- nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3); -- pte += 1; -- } else { -- nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 0x21); -- nv_wo32(gpuobj, (pte * 4) + 4, offset_h & 0xff); -- pte += 2; -- } - -+ for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) { -+ nv_wo32(gpuobj, (pte * 4) + 0, offset_l | 3); - dma_offset += NV_CTXDMA_PAGE_SIZE; - } - } -- dev_priv->engine.instmem.flush(nvbe->dev); -- -- if (dev_priv->card_type == NV_50) { -- dev_priv->engine.fifo.tlb_flush(dev); -- dev_priv->engine.graph.tlb_flush(dev); -- } - - nvbe->bound = true; - return 0; -@@ -142,28 +115,10 @@ - if (!nvbe->bound) - return 0; - -- pte = nvbe->pte_start; -+ pte = (nvbe->offset >> NV_CTXDMA_PAGE_SHIFT) + 2; - for (i = 0; i < nvbe->nr_pages; i++) { -- dma_addr_t dma_offset = dev_priv->gart_info.sg_dummy_bus; -- -- for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++) { -- if (dev_priv->card_type < NV_50) { -- nv_wo32(gpuobj, (pte * 4) + 0, dma_offset | 3); -- pte += 1; -- } else { -- nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); -- nv_wo32(gpuobj, (pte * 4) + 4, 0x00000000); -- pte += 2; -- } -- -- dma_offset += NV_CTXDMA_PAGE_SIZE; -- } -- } -- dev_priv->engine.instmem.flush(nvbe->dev); -- -- if (dev_priv->card_type == NV_50) { -- dev_priv->engine.fifo.tlb_flush(dev); -- dev_priv->engine.graph.tlb_flush(dev); -+ for (j = 0; j < PAGE_SIZE / NV_CTXDMA_PAGE_SIZE; j++, pte++) -+ nv_wo32(gpuobj, (pte * 4) + 0, 0x00000000); - } - - nvbe->bound = false; -@@ -186,6 +141,35 @@ - } - } - -+static int -+nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) -+{ -+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; -+ -+ nvbe->offset = mem->start << PAGE_SHIFT; -+ -+ nouveau_vm_map_sg(&dev_priv->gart_info.vma, nvbe->offset, -+ nvbe->nr_pages << PAGE_SHIFT, nvbe->pages); -+ nvbe->bound = true; -+ return 0; -+} -+ -+static int -+nv50_sgdma_unbind(struct ttm_backend *be) -+{ -+ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; -+ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; -+ -+ if (!nvbe->bound) -+ return 0; -+ -+ nouveau_vm_unmap_at(&dev_priv->gart_info.vma, nvbe->offset, -+ nvbe->nr_pages << PAGE_SHIFT); -+ nvbe->bound = false; -+ return 0; -+} -+ - static struct ttm_backend_func nouveau_sgdma_backend = { - .populate = nouveau_sgdma_populate, - .clear = nouveau_sgdma_clear, -@@ -194,23 +178,30 @@ - .destroy = nouveau_sgdma_destroy - }; - -+static struct ttm_backend_func nv50_sgdma_backend = { -+ .populate = nouveau_sgdma_populate, -+ .clear = nouveau_sgdma_clear, -+ .bind = nv50_sgdma_bind, -+ .unbind = nv50_sgdma_unbind, -+ .destroy = nouveau_sgdma_destroy -+}; -+ - struct ttm_backend * - nouveau_sgdma_init_ttm(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_sgdma_be *nvbe; - -- if (!dev_priv->gart_info.sg_ctxdma) -- return NULL; -- - nvbe = kzalloc(sizeof(*nvbe), GFP_KERNEL); - if (!nvbe) - return NULL; - - nvbe->dev = dev; - -- nvbe->backend.func = &nouveau_sgdma_backend; -- -+ if (dev_priv->card_type < NV_50) -+ nvbe->backend.func = &nouveau_sgdma_backend; -+ else -+ nvbe->backend.func = &nv50_sgdma_backend; - return &nvbe->backend; - } - -@@ -218,7 +209,6 @@ - nouveau_sgdma_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct pci_dev *pdev = dev->pdev; - struct nouveau_gpuobj *gpuobj = NULL; - uint32_t aper_size, obj_size; - int i, ret; -@@ -231,68 +221,40 @@ - - obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; - obj_size += 8; /* ctxdma header */ -- } else { -- /* 1 entire VM page table */ -- aper_size = (512 * 1024 * 1024); -- obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 8; -- } -- -- ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, -- NVOBJ_FLAG_ZERO_ALLOC | -- NVOBJ_FLAG_ZERO_FREE, &gpuobj); -- if (ret) { -- NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); -- return ret; -- } - -- dev_priv->gart_info.sg_dummy_page = -- alloc_page(GFP_KERNEL|__GFP_DMA32|__GFP_ZERO); -- if (!dev_priv->gart_info.sg_dummy_page) { -- nouveau_gpuobj_ref(NULL, &gpuobj); -- return -ENOMEM; -- } -- -- set_bit(PG_locked, &dev_priv->gart_info.sg_dummy_page->flags); -- dev_priv->gart_info.sg_dummy_bus = -- pci_map_page(pdev, dev_priv->gart_info.sg_dummy_page, 0, -- PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -- if (pci_dma_mapping_error(pdev, dev_priv->gart_info.sg_dummy_bus)) { -- nouveau_gpuobj_ref(NULL, &gpuobj); -- return -EFAULT; -- } -+ ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, -+ NVOBJ_FLAG_ZERO_ALLOC | -+ NVOBJ_FLAG_ZERO_FREE, &gpuobj); -+ if (ret) { -+ NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); -+ return ret; -+ } - -- if (dev_priv->card_type < NV_50) { -- /* special case, allocated from global instmem heap so -- * cinst is invalid, we use it on all channels though so -- * cinst needs to be valid, set it the same as pinst -- */ -- gpuobj->cinst = gpuobj->pinst; -- -- /* Maybe use NV_DMA_TARGET_AGP for PCIE? NVIDIA do this, and -- * confirmed to work on c51. Perhaps means NV_DMA_TARGET_PCIE -- * on those cards? */ - nv_wo32(gpuobj, 0, NV_CLASS_DMA_IN_MEMORY | - (1 << 12) /* PT present */ | - (0 << 13) /* PT *not* linear */ | -- (NV_DMA_ACCESS_RW << 14) | -- (NV_DMA_TARGET_PCI << 16)); -+ (0 << 14) /* RW */ | -+ (2 << 16) /* PCI */); - nv_wo32(gpuobj, 4, aper_size - 1); -- for (i = 2; i < 2 + (aper_size >> 12); i++) { -- nv_wo32(gpuobj, i * 4, -- dev_priv->gart_info.sg_dummy_bus | 3); -- } -- } else { -- for (i = 0; i < obj_size; i += 8) { -- nv_wo32(gpuobj, i + 0, 0x00000000); -- nv_wo32(gpuobj, i + 4, 0x00000000); -- } -+ for (i = 2; i < 2 + (aper_size >> 12); i++) -+ nv_wo32(gpuobj, i * 4, 0x00000000); -+ -+ dev_priv->gart_info.sg_ctxdma = gpuobj; -+ dev_priv->gart_info.aper_base = 0; -+ dev_priv->gart_info.aper_size = aper_size; -+ } else -+ if (dev_priv->chan_vm) { -+ ret = nouveau_vm_get(dev_priv->chan_vm, 512 * 1024 * 1024, -+ 12, NV_MEM_ACCESS_RW, -+ &dev_priv->gart_info.vma); -+ if (ret) -+ return ret; -+ -+ dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset; -+ dev_priv->gart_info.aper_size = 512 * 1024 * 1024; - } -- dev_priv->engine.instmem.flush(dev); - - dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; -- dev_priv->gart_info.aper_base = 0; -- dev_priv->gart_info.aper_size = aper_size; -- dev_priv->gart_info.sg_ctxdma = gpuobj; - return 0; - } - -@@ -301,31 +263,19 @@ - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - -- if (dev_priv->gart_info.sg_dummy_page) { -- pci_unmap_page(dev->pdev, dev_priv->gart_info.sg_dummy_bus, -- NV_CTXDMA_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -- unlock_page(dev_priv->gart_info.sg_dummy_page); -- __free_page(dev_priv->gart_info.sg_dummy_page); -- dev_priv->gart_info.sg_dummy_page = NULL; -- dev_priv->gart_info.sg_dummy_bus = 0; -- } -- - nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma); -+ nouveau_vm_put(&dev_priv->gart_info.vma); - } - --int --nouveau_sgdma_get_page(struct drm_device *dev, uint32_t offset, uint32_t *page) -+uint32_t -+nouveau_sgdma_get_physical(struct drm_device *dev, uint32_t offset) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_gpuobj *gpuobj = dev_priv->gart_info.sg_ctxdma; -- int pte; -+ int pte = (offset >> NV_CTXDMA_PAGE_SHIFT) + 2; - -- pte = (offset >> NV_CTXDMA_PAGE_SHIFT) << 2; -- if (dev_priv->card_type < NV_50) { -- *page = nv_ro32(gpuobj, (pte + 8)) & ~NV_CTXDMA_PAGE_MASK; -- return 0; -- } -+ BUG_ON(dev_priv->card_type >= NV_50); - -- NV_ERROR(dev, "Unimplemented on NV50\n"); -- return -EINVAL; -+ return (nv_ro32(gpuobj, 4 * pte) & ~NV_CTXDMA_PAGE_MASK) | -+ (offset & NV_CTXDMA_PAGE_MASK); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_state.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_state.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_state.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_state.c 2011-01-07 14:22:17.000000000 +0100 -@@ -53,10 +53,10 @@ - engine->instmem.takedown = nv04_instmem_takedown; - engine->instmem.suspend = nv04_instmem_suspend; - engine->instmem.resume = nv04_instmem_resume; -- engine->instmem.populate = nv04_instmem_populate; -- engine->instmem.clear = nv04_instmem_clear; -- engine->instmem.bind = nv04_instmem_bind; -- engine->instmem.unbind = nv04_instmem_unbind; -+ engine->instmem.get = nv04_instmem_get; -+ engine->instmem.put = nv04_instmem_put; -+ engine->instmem.map = nv04_instmem_map; -+ engine->instmem.unmap = nv04_instmem_unmap; - engine->instmem.flush = nv04_instmem_flush; - engine->mc.init = nv04_mc_init; - engine->mc.takedown = nv04_mc_takedown; -@@ -65,7 +65,6 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv04_fb_init; - engine->fb.takedown = nv04_fb_takedown; -- engine->graph.grclass = nv04_graph_grclass; - engine->graph.init = nv04_graph_init; - engine->graph.takedown = nv04_graph_takedown; - engine->graph.fifo_access = nv04_graph_fifo_access; -@@ -76,7 +75,7 @@ - engine->graph.unload_context = nv04_graph_unload_context; - engine->fifo.channels = 16; - engine->fifo.init = nv04_fifo_init; -- engine->fifo.takedown = nouveau_stub_takedown; -+ engine->fifo.takedown = nv04_fifo_fini; - engine->fifo.disable = nv04_fifo_disable; - engine->fifo.enable = nv04_fifo_enable; - engine->fifo.reassign = nv04_fifo_reassign; -@@ -99,16 +98,20 @@ - 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; - case 0x10: - engine->instmem.init = nv04_instmem_init; - engine->instmem.takedown = nv04_instmem_takedown; - engine->instmem.suspend = nv04_instmem_suspend; - engine->instmem.resume = nv04_instmem_resume; -- engine->instmem.populate = nv04_instmem_populate; -- engine->instmem.clear = nv04_instmem_clear; -- engine->instmem.bind = nv04_instmem_bind; -- engine->instmem.unbind = nv04_instmem_unbind; -+ engine->instmem.get = nv04_instmem_get; -+ engine->instmem.put = nv04_instmem_put; -+ engine->instmem.map = nv04_instmem_map; -+ engine->instmem.unmap = nv04_instmem_unmap; - engine->instmem.flush = nv04_instmem_flush; - engine->mc.init = nv04_mc_init; - engine->mc.takedown = nv04_mc_takedown; -@@ -117,8 +120,9 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv10_fb_init; - engine->fb.takedown = nv10_fb_takedown; -- engine->fb.set_region_tiling = nv10_fb_set_region_tiling; -- engine->graph.grclass = nv10_graph_grclass; -+ 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; -@@ -127,17 +131,17 @@ - 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_region_tiling = nv10_graph_set_region_tiling; -+ engine->graph.set_tile_region = nv10_graph_set_tile_region; - engine->fifo.channels = 32; - engine->fifo.init = nv10_fifo_init; -- engine->fifo.takedown = nouveau_stub_takedown; -+ engine->fifo.takedown = nv04_fifo_fini; - engine->fifo.disable = nv04_fifo_disable; - engine->fifo.enable = nv04_fifo_enable; - engine->fifo.reassign = nv04_fifo_reassign; - engine->fifo.cache_pull = nv04_fifo_cache_pull; - engine->fifo.channel_id = nv10_fifo_channel_id; - engine->fifo.create_context = nv10_fifo_create_context; -- engine->fifo.destroy_context = nv10_fifo_destroy_context; -+ engine->fifo.destroy_context = nv04_fifo_destroy_context; - engine->fifo.load_context = nv10_fifo_load_context; - engine->fifo.unload_context = nv10_fifo_unload_context; - engine->display.early_init = nv04_display_early_init; -@@ -153,16 +157,20 @@ - 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; - case 0x20: - engine->instmem.init = nv04_instmem_init; - engine->instmem.takedown = nv04_instmem_takedown; - engine->instmem.suspend = nv04_instmem_suspend; - engine->instmem.resume = nv04_instmem_resume; -- engine->instmem.populate = nv04_instmem_populate; -- engine->instmem.clear = nv04_instmem_clear; -- engine->instmem.bind = nv04_instmem_bind; -- engine->instmem.unbind = nv04_instmem_unbind; -+ engine->instmem.get = nv04_instmem_get; -+ engine->instmem.put = nv04_instmem_put; -+ engine->instmem.map = nv04_instmem_map; -+ engine->instmem.unmap = nv04_instmem_unmap; - engine->instmem.flush = nv04_instmem_flush; - engine->mc.init = nv04_mc_init; - engine->mc.takedown = nv04_mc_takedown; -@@ -171,8 +179,9 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv10_fb_init; - engine->fb.takedown = nv10_fb_takedown; -- engine->fb.set_region_tiling = nv10_fb_set_region_tiling; -- engine->graph.grclass = nv20_graph_grclass; -+ 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; -@@ -181,17 +190,17 @@ - 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_region_tiling = nv20_graph_set_region_tiling; -+ engine->graph.set_tile_region = nv20_graph_set_tile_region; - engine->fifo.channels = 32; - engine->fifo.init = nv10_fifo_init; -- engine->fifo.takedown = nouveau_stub_takedown; -+ engine->fifo.takedown = nv04_fifo_fini; - engine->fifo.disable = nv04_fifo_disable; - engine->fifo.enable = nv04_fifo_enable; - engine->fifo.reassign = nv04_fifo_reassign; - engine->fifo.cache_pull = nv04_fifo_cache_pull; - engine->fifo.channel_id = nv10_fifo_channel_id; - engine->fifo.create_context = nv10_fifo_create_context; -- engine->fifo.destroy_context = nv10_fifo_destroy_context; -+ engine->fifo.destroy_context = nv04_fifo_destroy_context; - engine->fifo.load_context = nv10_fifo_load_context; - engine->fifo.unload_context = nv10_fifo_unload_context; - engine->display.early_init = nv04_display_early_init; -@@ -207,16 +216,20 @@ - 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; - case 0x30: - engine->instmem.init = nv04_instmem_init; - engine->instmem.takedown = nv04_instmem_takedown; - engine->instmem.suspend = nv04_instmem_suspend; - engine->instmem.resume = nv04_instmem_resume; -- engine->instmem.populate = nv04_instmem_populate; -- engine->instmem.clear = nv04_instmem_clear; -- engine->instmem.bind = nv04_instmem_bind; -- engine->instmem.unbind = nv04_instmem_unbind; -+ engine->instmem.get = nv04_instmem_get; -+ engine->instmem.put = nv04_instmem_put; -+ engine->instmem.map = nv04_instmem_map; -+ engine->instmem.unmap = nv04_instmem_unmap; - engine->instmem.flush = nv04_instmem_flush; - engine->mc.init = nv04_mc_init; - engine->mc.takedown = nv04_mc_takedown; -@@ -225,8 +238,9 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv30_fb_init; - engine->fb.takedown = nv30_fb_takedown; -- engine->fb.set_region_tiling = nv10_fb_set_region_tiling; -- engine->graph.grclass = nv30_graph_grclass; -+ 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; -@@ -235,17 +249,17 @@ - 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_region_tiling = nv20_graph_set_region_tiling; -+ engine->graph.set_tile_region = nv20_graph_set_tile_region; - engine->fifo.channels = 32; - engine->fifo.init = nv10_fifo_init; -- engine->fifo.takedown = nouveau_stub_takedown; -+ engine->fifo.takedown = nv04_fifo_fini; - engine->fifo.disable = nv04_fifo_disable; - engine->fifo.enable = nv04_fifo_enable; - engine->fifo.reassign = nv04_fifo_reassign; - engine->fifo.cache_pull = nv04_fifo_cache_pull; - engine->fifo.channel_id = nv10_fifo_channel_id; - engine->fifo.create_context = nv10_fifo_create_context; -- engine->fifo.destroy_context = nv10_fifo_destroy_context; -+ engine->fifo.destroy_context = nv04_fifo_destroy_context; - engine->fifo.load_context = nv10_fifo_load_context; - engine->fifo.unload_context = nv10_fifo_unload_context; - engine->display.early_init = nv04_display_early_init; -@@ -263,6 +277,10 @@ - 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; - case 0x40: - case 0x60: -@@ -270,10 +288,10 @@ - engine->instmem.takedown = nv04_instmem_takedown; - engine->instmem.suspend = nv04_instmem_suspend; - engine->instmem.resume = nv04_instmem_resume; -- engine->instmem.populate = nv04_instmem_populate; -- engine->instmem.clear = nv04_instmem_clear; -- engine->instmem.bind = nv04_instmem_bind; -- engine->instmem.unbind = nv04_instmem_unbind; -+ engine->instmem.get = nv04_instmem_get; -+ engine->instmem.put = nv04_instmem_put; -+ engine->instmem.map = nv04_instmem_map; -+ engine->instmem.unmap = nv04_instmem_unmap; - engine->instmem.flush = nv04_instmem_flush; - engine->mc.init = nv40_mc_init; - engine->mc.takedown = nv40_mc_takedown; -@@ -282,8 +300,9 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv40_fb_init; - engine->fb.takedown = nv40_fb_takedown; -- engine->fb.set_region_tiling = nv40_fb_set_region_tiling; -- engine->graph.grclass = nv40_graph_grclass; -+ 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; -@@ -292,17 +311,17 @@ - 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_region_tiling = nv40_graph_set_region_tiling; -+ engine->graph.set_tile_region = nv40_graph_set_tile_region; - engine->fifo.channels = 32; - engine->fifo.init = nv40_fifo_init; -- engine->fifo.takedown = nouveau_stub_takedown; -+ engine->fifo.takedown = nv04_fifo_fini; - engine->fifo.disable = nv04_fifo_disable; - engine->fifo.enable = nv04_fifo_enable; - engine->fifo.reassign = nv04_fifo_reassign; - engine->fifo.cache_pull = nv04_fifo_cache_pull; - engine->fifo.channel_id = nv10_fifo_channel_id; - engine->fifo.create_context = nv40_fifo_create_context; -- engine->fifo.destroy_context = nv40_fifo_destroy_context; -+ engine->fifo.destroy_context = nv04_fifo_destroy_context; - engine->fifo.load_context = nv40_fifo_load_context; - engine->fifo.unload_context = nv40_fifo_unload_context; - engine->display.early_init = nv04_display_early_init; -@@ -321,6 +340,10 @@ - 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; - case 0x50: - case 0x80: /* gotta love NVIDIA's consistency.. */ -@@ -330,10 +353,10 @@ - engine->instmem.takedown = nv50_instmem_takedown; - engine->instmem.suspend = nv50_instmem_suspend; - engine->instmem.resume = nv50_instmem_resume; -- engine->instmem.populate = nv50_instmem_populate; -- engine->instmem.clear = nv50_instmem_clear; -- engine->instmem.bind = nv50_instmem_bind; -- engine->instmem.unbind = nv50_instmem_unbind; -+ engine->instmem.get = nv50_instmem_get; -+ engine->instmem.put = nv50_instmem_put; -+ engine->instmem.map = nv50_instmem_map; -+ engine->instmem.unmap = nv50_instmem_unmap; - if (dev_priv->chipset == 0x50) - engine->instmem.flush = nv50_instmem_flush; - else -@@ -345,7 +368,6 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nv50_fb_init; - engine->fb.takedown = nv50_fb_takedown; -- engine->graph.grclass = nv50_graph_grclass; - engine->graph.init = nv50_graph_init; - engine->graph.takedown = nv50_graph_takedown; - engine->graph.fifo_access = nv50_graph_fifo_access; -@@ -381,24 +403,32 @@ - engine->display.init = nv50_display_init; - engine->display.destroy = nv50_display_destroy; - engine->gpio.init = nv50_gpio_init; -- engine->gpio.takedown = nouveau_stub_takedown; -+ engine->gpio.takedown = nv50_gpio_fini; - engine->gpio.get = nv50_gpio_get; - engine->gpio.set = nv50_gpio_set; -+ engine->gpio.irq_register = nv50_gpio_irq_register; -+ engine->gpio.irq_unregister = nv50_gpio_irq_unregister; - engine->gpio.irq_enable = nv50_gpio_irq_enable; - switch (dev_priv->chipset) { -- case 0xa3: -- case 0xa5: -- case 0xa8: -- case 0xaf: -- engine->pm.clock_get = nva3_pm_clock_get; -- engine->pm.clock_pre = nva3_pm_clock_pre; -- engine->pm.clock_set = nva3_pm_clock_set; -- break; -- default: -+ case 0x84: -+ case 0x86: -+ case 0x92: -+ case 0x94: -+ case 0x96: -+ case 0x98: -+ case 0xa0: -+ case 0xaa: -+ case 0xac: -+ case 0x50: - engine->pm.clock_get = nv50_pm_clock_get; - engine->pm.clock_pre = nv50_pm_clock_pre; - engine->pm.clock_set = nv50_pm_clock_set; - break; -+ default: -+ engine->pm.clock_get = nva3_pm_clock_get; -+ engine->pm.clock_pre = nva3_pm_clock_pre; -+ engine->pm.clock_set = nva3_pm_clock_set; -+ break; - } - engine->pm.voltage_get = nouveau_voltage_gpio_get; - engine->pm.voltage_set = nouveau_voltage_gpio_set; -@@ -406,17 +436,39 @@ - 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; -+ engine->vram.flags_valid = nv50_vram_flags_valid; - break; - case 0xC0: - engine->instmem.init = nvc0_instmem_init; - engine->instmem.takedown = nvc0_instmem_takedown; - engine->instmem.suspend = nvc0_instmem_suspend; - engine->instmem.resume = nvc0_instmem_resume; -- engine->instmem.populate = nvc0_instmem_populate; -- engine->instmem.clear = nvc0_instmem_clear; -- engine->instmem.bind = nvc0_instmem_bind; -- engine->instmem.unbind = nvc0_instmem_unbind; -- engine->instmem.flush = nvc0_instmem_flush; -+ engine->instmem.get = nv50_instmem_get; -+ engine->instmem.put = nv50_instmem_put; -+ engine->instmem.map = nv50_instmem_map; -+ engine->instmem.unmap = nv50_instmem_unmap; -+ engine->instmem.flush = nv84_instmem_flush; - engine->mc.init = nv50_mc_init; - engine->mc.takedown = nv50_mc_takedown; - engine->timer.init = nv04_timer_init; -@@ -424,7 +476,6 @@ - engine->timer.takedown = nv04_timer_takedown; - engine->fb.init = nvc0_fb_init; - engine->fb.takedown = nvc0_fb_takedown; -- engine->graph.grclass = NULL; //nvc0_graph_grclass; - engine->graph.init = nvc0_graph_init; - engine->graph.takedown = nvc0_graph_takedown; - engine->graph.fifo_access = nvc0_graph_fifo_access; -@@ -453,7 +504,15 @@ - engine->gpio.takedown = nouveau_stub_takedown; - engine->gpio.get = nv50_gpio_get; - engine->gpio.set = nv50_gpio_set; -+ 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; -+ engine->vram.flags_valid = nvc0_vram_flags_valid; - break; - default: - NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); -@@ -493,9 +552,13 @@ - if (ret) - return ret; - -+ /* no dma objects on fermi... */ -+ if (dev_priv->card_type >= NV_C0) -+ goto out_done; -+ - ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, - 0, dev_priv->vram_size, -- NV_DMA_ACCESS_RW, NV_DMA_TARGET_VIDMEM, -+ NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM, - &gpuobj); - if (ret) - goto out_err; -@@ -505,9 +568,10 @@ - if (ret) - goto out_err; - -- ret = nouveau_gpuobj_gart_dma_new(dev_priv->channel, 0, -- dev_priv->gart_info.aper_size, -- NV_DMA_ACCESS_RW, &gpuobj, NULL); -+ ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, -+ 0, dev_priv->gart_info.aper_size, -+ NV_MEM_ACCESS_RW, NV_MEM_TARGET_GART, -+ &gpuobj); - if (ret) - goto out_err; - -@@ -516,11 +580,12 @@ - if (ret) - goto out_err; - -+out_done: -+ mutex_unlock(&dev_priv->channel->mutex); - return 0; - - out_err: -- nouveau_channel_free(dev_priv->channel); -- dev_priv->channel = NULL; -+ nouveau_channel_put(&dev_priv->channel); - return ret; - } - -@@ -567,6 +632,8 @@ - if (ret) - goto out; - engine = &dev_priv->engine; -+ spin_lock_init(&dev_priv->channels.lock); -+ spin_lock_init(&dev_priv->tile.lock); - spin_lock_init(&dev_priv->context_switch_lock); - - /* Make the CRTCs and I2C buses accessible */ -@@ -625,26 +692,28 @@ - if (ret) - goto out_fb; - -+ /* PCRYPT */ -+ ret = engine->crypt.init(dev); -+ if (ret) -+ goto out_graph; -+ - /* PFIFO */ - ret = engine->fifo.init(dev); - if (ret) -- goto out_graph; -+ goto out_crypt; - } - - ret = engine->display.create(dev); - if (ret) - goto out_fifo; - -- /* this call irq_preinstall, register irq handler and -- * call irq_postinstall -- */ -- ret = drm_irq_install(dev); -+ ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1); - if (ret) -- goto out_display; -+ goto out_vblank; - -- ret = drm_vblank_init(dev, 0); -+ ret = nouveau_irq_init(dev); - if (ret) -- goto out_irq; -+ goto out_vblank; - - /* what about PVIDEO/PCRTC/PRAMDAC etc? */ - -@@ -669,12 +738,16 @@ - out_fence: - nouveau_fence_fini(dev); - out_irq: -- drm_irq_uninstall(dev); --out_display: -+ nouveau_irq_fini(dev); -+out_vblank: -+ drm_vblank_cleanup(dev); - engine->display.destroy(dev); - 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); -@@ -713,12 +786,12 @@ - - if (!engine->graph.accel_blocked) { - nouveau_fence_fini(dev); -- nouveau_channel_free(dev_priv->channel); -- dev_priv->channel = NULL; -+ nouveau_channel_put_unlocked(&dev_priv->channel); - } - - if (!nouveau_noaccel) { - engine->fifo.takedown(dev); -+ engine->crypt.takedown(dev); - engine->graph.takedown(dev); - } - engine->fb.takedown(dev); -@@ -737,7 +810,8 @@ - nouveau_gpuobj_takedown(dev); - nouveau_mem_vram_fini(dev); - -- drm_irq_uninstall(dev); -+ nouveau_irq_fini(dev); -+ drm_vblank_cleanup(dev); - - nouveau_pm_fini(dev); - nouveau_bios_takedown(dev); -@@ -1024,21 +1098,6 @@ - else - getparam->value = NV_PCI; - break; -- case NOUVEAU_GETPARAM_FB_PHYSICAL: -- getparam->value = dev_priv->fb_phys; -- break; -- case NOUVEAU_GETPARAM_AGP_PHYSICAL: -- getparam->value = dev_priv->gart_info.aper_base; -- break; -- case NOUVEAU_GETPARAM_PCI_PHYSICAL: -- if (dev->sg) { -- getparam->value = (unsigned long)dev->sg->virtual; -- } else { -- NV_ERROR(dev, "Requested PCIGART address, " -- "while no PCIGART was created\n"); -- return -EINVAL; -- } -- break; - case NOUVEAU_GETPARAM_FB_SIZE: - getparam->value = dev_priv->fb_available_size; - break; -@@ -1046,7 +1105,7 @@ - getparam->value = dev_priv->gart_info.aper_size; - break; - case NOUVEAU_GETPARAM_VM_VRAM_BASE: -- getparam->value = dev_priv->vm_vram_base; -+ getparam->value = 0; /* deprecated */ - break; - case NOUVEAU_GETPARAM_PTIMER_TIME: - getparam->value = dev_priv->engine.timer.read(dev); -@@ -1054,6 +1113,9 @@ - case NOUVEAU_GETPARAM_HAS_BO_USAGE: - getparam->value = 1; - break; -+ case NOUVEAU_GETPARAM_HAS_PAGEFLIP: -+ getparam->value = (dev_priv->card_type < NV_50); -+ break; - case NOUVEAU_GETPARAM_GRAPH_UNITS: - /* NV40 and NV50 versions are quite different, but register - * address is the same. User is supposed to know the card -@@ -1087,8 +1149,9 @@ - } - - /* Wait until (value(reg) & mask) == val, up until timeout has hit */ --bool nouveau_wait_until(struct drm_device *dev, uint64_t timeout, -- uint32_t reg, uint32_t mask, uint32_t val) -+bool -+nouveau_wait_eq(struct drm_device *dev, uint64_t timeout, -+ uint32_t reg, uint32_t mask, uint32_t val) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; -@@ -1102,10 +1165,33 @@ - return false; - } - -+/* Wait until (value(reg) & mask) != val, up until timeout has hit */ -+bool -+nouveau_wait_ne(struct drm_device *dev, uint64_t timeout, -+ uint32_t reg, uint32_t mask, uint32_t val) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; -+ uint64_t start = ptimer->read(dev); -+ -+ do { -+ if ((nv_rd32(dev, reg) & mask) != val) -+ return true; -+ } while (ptimer->read(dev) - start < timeout); -+ -+ return false; -+} -+ - /* Waits for PGRAPH to go completely idle */ - bool nouveau_wait_for_idle(struct drm_device *dev) - { -- if (!nv_wait(dev, NV04_PGRAPH_STATUS, 0xffffffff, 0x00000000)) { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ uint32_t mask = ~0; -+ -+ if (dev_priv->card_type == NV_40) -+ mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL; -+ -+ if (!nv_wait(dev, NV04_PGRAPH_STATUS, mask, 0)) { - NV_ERROR(dev, "PGRAPH idle timed out with status 0x%08x\n", - nv_rd32(dev, NV04_PGRAPH_STATUS)); - return false; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_util.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_util.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_util.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_util.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,69 @@ -+/* -+ * Copyright (C) 2010 Nouveau Project -+ * -+ * All Rights Reserved. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. -+ * -+ */ -+ -+#include -+ -+#include "nouveau_util.h" -+ -+static DEFINE_RATELIMIT_STATE(nouveau_ratelimit_state, 3 * HZ, 20); -+ -+void -+nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value) -+{ -+ while (bf->name) { -+ if (value & bf->mask) { -+ printk(" %s", bf->name); -+ value &= ~bf->mask; -+ } -+ -+ bf++; -+ } -+ -+ if (value) -+ printk(" (unknown bits 0x%08x)", value); -+} -+ -+void -+nouveau_enum_print(const struct nouveau_enum *en, u32 value) -+{ -+ while (en->name) { -+ if (value == en->value) { -+ printk("%s", en->name); -+ return; -+ } -+ -+ en++; -+ } -+ -+ printk("(unknown enum 0x%08x)", value); -+} -+ -+int -+nouveau_ratelimit(void) -+{ -+ return __ratelimit(&nouveau_ratelimit_state); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_util.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_util.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_util.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_util.h 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,45 @@ -+/* -+ * Copyright (C) 2010 Nouveau Project -+ * -+ * All Rights Reserved. -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining -+ * a copy of this software and associated documentation files (the -+ * "Software"), to deal in the Software without restriction, including -+ * without limitation the rights to use, copy, modify, merge, publish, -+ * distribute, sublicense, and/or sell copies of the Software, and to -+ * permit persons to whom the Software is furnished to do so, subject to -+ * the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the -+ * next paragraph) 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 OWNER(S) AND/OR ITS SUPPLIERS 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. -+ * -+ */ -+ -+#ifndef __NOUVEAU_UTIL_H__ -+#define __NOUVEAU_UTIL_H__ -+ -+struct nouveau_bitfield { -+ u32 mask; -+ const char *name; -+}; -+ -+struct nouveau_enum { -+ u32 value; -+ const char *name; -+}; -+ -+void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value); -+void nouveau_enum_print(const struct nouveau_enum *, u32 value); -+int nouveau_ratelimit(void); -+ -+#endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_vm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_vm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_vm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_vm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,439 @@ -+/* -+ * Copyright 2010 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_mm.h" -+#include "nouveau_vm.h" -+ -+void -+nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) -+{ -+ struct nouveau_vm *vm = vma->vm; -+ struct nouveau_mm_node *r; -+ int big = vma->node->type != vm->spg_shift; -+ u32 offset = vma->node->offset + (delta >> 12); -+ u32 bits = vma->node->type - 12; -+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde; -+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits; -+ u32 max = 1 << (vm->pgt_bits - bits); -+ u32 end, len; -+ -+ list_for_each_entry(r, &vram->regions, rl_entry) { -+ u64 phys = (u64)r->offset << 12; -+ u32 num = r->length >> bits; -+ -+ while (num) { -+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; -+ -+ end = (pte + num); -+ if (unlikely(end >= max)) -+ end = max; -+ len = end - pte; -+ -+ vm->map(vma, pgt, vram, pte, len, phys); -+ -+ num -= len; -+ pte += len; -+ if (unlikely(end >= max)) { -+ pde++; -+ pte = 0; -+ } -+ } -+ } -+ -+ vm->flush(vm); -+} -+ -+void -+nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_vram *vram) -+{ -+ nouveau_vm_map_at(vma, 0, vram); -+} -+ -+void -+nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, -+ dma_addr_t *list) -+{ -+ struct nouveau_vm *vm = vma->vm; -+ int big = vma->node->type != vm->spg_shift; -+ u32 offset = vma->node->offset + (delta >> 12); -+ u32 bits = vma->node->type - 12; -+ u32 num = length >> vma->node->type; -+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde; -+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits; -+ u32 max = 1 << (vm->pgt_bits - bits); -+ u32 end, len; -+ -+ while (num) { -+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; -+ -+ end = (pte + num); -+ if (unlikely(end >= max)) -+ end = max; -+ len = end - pte; -+ -+ vm->map_sg(vma, pgt, pte, list, len); -+ -+ num -= len; -+ pte += len; -+ list += len; -+ if (unlikely(end >= max)) { -+ pde++; -+ pte = 0; -+ } -+ } -+ -+ vm->flush(vm); -+} -+ -+void -+nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length) -+{ -+ struct nouveau_vm *vm = vma->vm; -+ int big = vma->node->type != vm->spg_shift; -+ u32 offset = vma->node->offset + (delta >> 12); -+ u32 bits = vma->node->type - 12; -+ u32 num = length >> vma->node->type; -+ u32 pde = (offset >> vm->pgt_bits) - vm->fpde; -+ u32 pte = (offset & ((1 << vm->pgt_bits) - 1)) >> bits; -+ u32 max = 1 << (vm->pgt_bits - bits); -+ u32 end, len; -+ -+ while (num) { -+ struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big]; -+ -+ end = (pte + num); -+ if (unlikely(end >= max)) -+ end = max; -+ len = end - pte; -+ -+ vm->unmap(pgt, pte, len); -+ -+ num -= len; -+ pte += len; -+ if (unlikely(end >= max)) { -+ pde++; -+ pte = 0; -+ } -+ } -+ -+ vm->flush(vm); -+} -+ -+void -+nouveau_vm_unmap(struct nouveau_vma *vma) -+{ -+ nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12); -+} -+ -+static void -+nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde) -+{ -+ struct nouveau_vm_pgd *vpgd; -+ struct nouveau_vm_pgt *vpgt; -+ struct nouveau_gpuobj *pgt; -+ u32 pde; -+ -+ for (pde = fpde; pde <= lpde; pde++) { -+ vpgt = &vm->pgt[pde - vm->fpde]; -+ if (--vpgt->refcount[big]) -+ continue; -+ -+ pgt = vpgt->obj[big]; -+ vpgt->obj[big] = NULL; -+ -+ list_for_each_entry(vpgd, &vm->pgd_list, head) { -+ vm->map_pgt(vpgd->obj, pde, vpgt->obj); -+ } -+ -+ mutex_unlock(&vm->mm->mutex); -+ nouveau_gpuobj_ref(NULL, &pgt); -+ mutex_lock(&vm->mm->mutex); -+ } -+} -+ -+static int -+nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type) -+{ -+ struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; -+ struct nouveau_vm_pgd *vpgd; -+ struct nouveau_gpuobj *pgt; -+ int big = (type != vm->spg_shift); -+ u32 pgt_size; -+ int ret; -+ -+ pgt_size = (1 << (vm->pgt_bits + 12)) >> type; -+ pgt_size *= 8; -+ -+ mutex_unlock(&vm->mm->mutex); -+ ret = nouveau_gpuobj_new(vm->dev, NULL, pgt_size, 0x1000, -+ NVOBJ_FLAG_ZERO_ALLOC, &pgt); -+ mutex_lock(&vm->mm->mutex); -+ if (unlikely(ret)) -+ return ret; -+ -+ /* someone beat us to filling the PDE while we didn't have the lock */ -+ if (unlikely(vpgt->refcount[big]++)) { -+ mutex_unlock(&vm->mm->mutex); -+ nouveau_gpuobj_ref(NULL, &pgt); -+ mutex_lock(&vm->mm->mutex); -+ return 0; -+ } -+ -+ vpgt->obj[big] = pgt; -+ list_for_each_entry(vpgd, &vm->pgd_list, head) { -+ vm->map_pgt(vpgd->obj, pde, vpgt->obj); -+ } -+ -+ return 0; -+} -+ -+int -+nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift, -+ u32 access, struct nouveau_vma *vma) -+{ -+ u32 align = (1 << page_shift) >> 12; -+ u32 msize = size >> 12; -+ u32 fpde, lpde, pde; -+ int ret; -+ -+ mutex_lock(&vm->mm->mutex); -+ ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node); -+ if (unlikely(ret != 0)) { -+ mutex_unlock(&vm->mm->mutex); -+ return ret; -+ } -+ -+ fpde = (vma->node->offset >> vm->pgt_bits); -+ lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; -+ for (pde = fpde; pde <= lpde; pde++) { -+ struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; -+ int big = (vma->node->type != vm->spg_shift); -+ -+ if (likely(vpgt->refcount[big])) { -+ vpgt->refcount[big]++; -+ continue; -+ } -+ -+ ret = nouveau_vm_map_pgt(vm, pde, vma->node->type); -+ if (ret) { -+ if (pde != fpde) -+ nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1); -+ nouveau_mm_put(vm->mm, vma->node); -+ mutex_unlock(&vm->mm->mutex); -+ vma->node = NULL; -+ return ret; -+ } -+ } -+ mutex_unlock(&vm->mm->mutex); -+ -+ vma->vm = vm; -+ vma->offset = (u64)vma->node->offset << 12; -+ vma->access = access; -+ return 0; -+} -+ -+void -+nouveau_vm_put(struct nouveau_vma *vma) -+{ -+ struct nouveau_vm *vm = vma->vm; -+ u32 fpde, lpde; -+ -+ if (unlikely(vma->node == NULL)) -+ return; -+ fpde = (vma->node->offset >> vm->pgt_bits); -+ lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; -+ -+ mutex_lock(&vm->mm->mutex); -+ nouveau_vm_unmap_pgt(vm, vma->node->type != vm->spg_shift, fpde, lpde); -+ nouveau_mm_put(vm->mm, vma->node); -+ vma->node = NULL; -+ mutex_unlock(&vm->mm->mutex); -+} -+ -+int -+nouveau_vm_new(struct drm_device *dev, u64 offset, u64 length, u64 mm_offset, -+ struct nouveau_vm **pvm) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_vm *vm; -+ u64 mm_length = (offset + length) - mm_offset; -+ u32 block, pgt_bits; -+ int ret; -+ -+ vm = kzalloc(sizeof(*vm), GFP_KERNEL); -+ if (!vm) -+ return -ENOMEM; -+ -+ if (dev_priv->card_type == NV_50) { -+ vm->map_pgt = nv50_vm_map_pgt; -+ vm->map = nv50_vm_map; -+ vm->map_sg = nv50_vm_map_sg; -+ vm->unmap = nv50_vm_unmap; -+ vm->flush = nv50_vm_flush; -+ vm->spg_shift = 12; -+ vm->lpg_shift = 16; -+ -+ pgt_bits = 29; -+ block = (1 << pgt_bits); -+ if (length < block) -+ block = length; -+ -+ } else -+ if (dev_priv->card_type == NV_C0) { -+ vm->map_pgt = nvc0_vm_map_pgt; -+ vm->map = nvc0_vm_map; -+ vm->map_sg = nvc0_vm_map_sg; -+ vm->unmap = nvc0_vm_unmap; -+ vm->flush = nvc0_vm_flush; -+ vm->spg_shift = 12; -+ vm->lpg_shift = 17; -+ pgt_bits = 27; -+ -+ /* Should be 4096 everywhere, this is a hack that's -+ * currently necessary to avoid an elusive bug that -+ * causes corruption when mixing small/large pages -+ */ -+ if (length < (1ULL << 40)) -+ block = 4096; -+ else { -+ block = (1 << pgt_bits); -+ if (length < block) -+ block = length; -+ } -+ } else { -+ kfree(vm); -+ return -ENOSYS; -+ } -+ -+ vm->fpde = offset >> pgt_bits; -+ vm->lpde = (offset + length - 1) >> pgt_bits; -+ vm->pgt = kcalloc(vm->lpde - vm->fpde + 1, sizeof(*vm->pgt), GFP_KERNEL); -+ if (!vm->pgt) { -+ kfree(vm); -+ return -ENOMEM; -+ } -+ -+ INIT_LIST_HEAD(&vm->pgd_list); -+ vm->dev = dev; -+ vm->refcount = 1; -+ vm->pgt_bits = pgt_bits - 12; -+ -+ ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12, -+ block >> 12); -+ if (ret) { -+ kfree(vm); -+ return ret; -+ } -+ -+ *pvm = vm; -+ return 0; -+} -+ -+static int -+nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) -+{ -+ struct nouveau_vm_pgd *vpgd; -+ int i; -+ -+ if (!pgd) -+ return 0; -+ -+ vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL); -+ if (!vpgd) -+ return -ENOMEM; -+ -+ nouveau_gpuobj_ref(pgd, &vpgd->obj); -+ -+ mutex_lock(&vm->mm->mutex); -+ for (i = vm->fpde; i <= vm->lpde; i++) -+ vm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); -+ list_add(&vpgd->head, &vm->pgd_list); -+ mutex_unlock(&vm->mm->mutex); -+ return 0; -+} -+ -+static void -+nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) -+{ -+ struct nouveau_vm_pgd *vpgd, *tmp; -+ -+ if (!pgd) -+ return; -+ -+ mutex_lock(&vm->mm->mutex); -+ list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { -+ if (vpgd->obj != pgd) -+ continue; -+ -+ list_del(&vpgd->head); -+ nouveau_gpuobj_ref(NULL, &vpgd->obj); -+ kfree(vpgd); -+ } -+ mutex_unlock(&vm->mm->mutex); -+} -+ -+static void -+nouveau_vm_del(struct nouveau_vm *vm) -+{ -+ struct nouveau_vm_pgd *vpgd, *tmp; -+ -+ list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { -+ nouveau_vm_unlink(vm, vpgd->obj); -+ } -+ WARN_ON(nouveau_mm_fini(&vm->mm) != 0); -+ -+ kfree(vm->pgt); -+ kfree(vm); -+} -+ -+int -+nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr, -+ struct nouveau_gpuobj *pgd) -+{ -+ struct nouveau_vm *vm; -+ int ret; -+ -+ vm = ref; -+ if (vm) { -+ ret = nouveau_vm_link(vm, pgd); -+ if (ret) -+ return ret; -+ -+ vm->refcount++; -+ } -+ -+ vm = *ptr; -+ *ptr = ref; -+ -+ if (vm) { -+ nouveau_vm_unlink(vm, pgd); -+ -+ if (--vm->refcount == 0) -+ nouveau_vm_del(vm); -+ } -+ -+ return 0; -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_vm.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_vm.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nouveau_vm.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,113 @@ -+/* -+ * Copyright 2010 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 -+ */ -+ -+#ifndef __NOUVEAU_VM_H__ -+#define __NOUVEAU_VM_H__ -+ -+#include "drmP.h" -+ -+#include "nouveau_drv.h" -+#include "nouveau_mm.h" -+ -+struct nouveau_vm_pgt { -+ struct nouveau_gpuobj *obj[2]; -+ u32 refcount[2]; -+}; -+ -+struct nouveau_vm_pgd { -+ struct list_head head; -+ struct nouveau_gpuobj *obj; -+}; -+ -+struct nouveau_vma { -+ struct nouveau_vm *vm; -+ struct nouveau_mm_node *node; -+ u64 offset; -+ u32 access; -+}; -+ -+struct nouveau_vm { -+ struct drm_device *dev; -+ struct nouveau_mm *mm; -+ int refcount; -+ -+ struct list_head pgd_list; -+ atomic_t pgraph_refs; -+ atomic_t pcrypt_refs; -+ -+ struct nouveau_vm_pgt *pgt; -+ u32 fpde; -+ u32 lpde; -+ -+ u32 pgt_bits; -+ u8 spg_shift; -+ u8 lpg_shift; -+ -+ void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde, -+ struct nouveau_gpuobj *pgt[2]); -+ void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *, -+ struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); -+ void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *, -+ u32 pte, dma_addr_t *, u32 cnt); -+ void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt); -+ void (*flush)(struct nouveau_vm *); -+}; -+ -+/* nouveau_vm.c */ -+int nouveau_vm_new(struct drm_device *, u64 offset, u64 length, u64 mm_offset, -+ struct nouveau_vm **); -+int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **, -+ struct nouveau_gpuobj *pgd); -+int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift, -+ u32 access, struct nouveau_vma *); -+void nouveau_vm_put(struct nouveau_vma *); -+void nouveau_vm_map(struct nouveau_vma *, struct nouveau_vram *); -+void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_vram *); -+void nouveau_vm_unmap(struct nouveau_vma *); -+void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length); -+void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, -+ dma_addr_t *); -+ -+/* nv50_vm.c */ -+void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, -+ struct nouveau_gpuobj *pgt[2]); -+void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, -+ struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); -+void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, -+ u32 pte, dma_addr_t *, u32 cnt); -+void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); -+void nv50_vm_flush(struct nouveau_vm *); -+void nv50_vm_flush_engine(struct drm_device *, int engine); -+ -+/* nvc0_vm.c */ -+void nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, -+ struct nouveau_gpuobj *pgt[2]); -+void nvc0_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, -+ struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); -+void nvc0_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, -+ u32 pte, dma_addr_t *, u32 cnt); -+void nvc0_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); -+void nvc0_vm_flush(struct nouveau_vm *); -+ -+#endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_crtc.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_crtc.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_crtc.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-01-07 14:22:17.000000000 +0100 -@@ -551,7 +551,10 @@ - if (dev_priv->card_type >= NV_30) - regp->gpio_ext = NVReadCRTC(dev, 0, NV_PCRTC_GPIO_EXT); - -- regp->crtc_cfg = NV_PCRTC_CONFIG_START_ADDRESS_HSYNC; -+ if (dev_priv->card_type >= NV_10) -+ regp->crtc_cfg = NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC; -+ else -+ regp->crtc_cfg = NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC; - - /* Some misc regs */ - if (dev_priv->card_type == NV_40) { -@@ -669,6 +672,7 @@ - if (nv_two_heads(dev)) - NVSetOwner(dev, nv_crtc->index); - -+ drm_vblank_pre_modeset(dev, nv_crtc->index); - funcs->dpms(crtc, DRM_MODE_DPMS_OFF); - - NVBlankScreen(dev, nv_crtc->index, true); -@@ -701,6 +705,7 @@ - #endif - - funcs->dpms(crtc, DRM_MODE_DPMS_ON); -+ drm_vblank_post_modeset(dev, nv_crtc->index); - } - - static void nv_crtc_destroy(struct drm_crtc *crtc) -@@ -986,6 +991,7 @@ - .cursor_move = nv04_crtc_cursor_move, - .gamma_set = nv_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, -+ .page_flip = nouveau_crtc_page_flip, - .destroy = nv_crtc_destroy, - }; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_dac.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_dac.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_dac.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_dac.c 2011-01-07 14:22:17.000000000 +0100 -@@ -74,14 +74,14 @@ - * use a 10ms timeout (guards against crtc being inactive, in - * which case blank state would never change) - */ -- if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, -- 0x00000001, 0x00000000)) -+ if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, -+ 0x00000001, 0x00000000)) - return -EBUSY; -- if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, -- 0x00000001, 0x00000001)) -+ if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, -+ 0x00000001, 0x00000001)) - return -EBUSY; -- if (!nouveau_wait_until(dev, 10000000, NV_PRMCIO_INP0__COLOR, -- 0x00000001, 0x00000000)) -+ if (!nouveau_wait_eq(dev, 10000000, NV_PRMCIO_INP0__COLOR, -+ 0x00000001, 0x00000000)) - return -EBUSY; - - udelay(100); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_display.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_display.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_display.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_display.c 2011-01-07 14:22:17.000000000 +0100 -@@ -32,6 +32,9 @@ - #include "nouveau_encoder.h" - #include "nouveau_connector.h" - -+static void nv04_vblank_crtc0_isr(struct drm_device *); -+static void nv04_vblank_crtc1_isr(struct drm_device *); -+ - static void - nv04_display_store_initial_head_owner(struct drm_device *dev) - { -@@ -197,6 +200,8 @@ - func->save(encoder); - } - -+ nouveau_irq_register(dev, 24, nv04_vblank_crtc0_isr); -+ nouveau_irq_register(dev, 25, nv04_vblank_crtc1_isr); - return 0; - } - -@@ -208,6 +213,9 @@ - - NV_DEBUG_KMS(dev, "\n"); - -+ nouveau_irq_unregister(dev, 24); -+ nouveau_irq_unregister(dev, 25); -+ - /* Turn every CRTC off. */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { - struct drm_mode_set modeset = { -@@ -258,3 +266,16 @@ - return 0; - } - -+static void -+nv04_vblank_crtc0_isr(struct drm_device *dev) -+{ -+ nv_wr32(dev, NV_CRTC0_INTSTAT, NV_CRTC_INTR_VBLANK); -+ drm_handle_vblank(dev, 0); -+} -+ -+static void -+nv04_vblank_crtc1_isr(struct drm_device *dev) -+{ -+ nv_wr32(dev, NV_CRTC1_INTSTAT, NV_CRTC_INTR_VBLANK); -+ drm_handle_vblank(dev, 1); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_fbcon.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_fbcon.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_fbcon.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_fbcon.c 2011-01-07 14:22:17.000000000 +0100 -@@ -28,52 +28,39 @@ - #include "nouveau_ramht.h" - #include "nouveau_fbcon.h" - --void -+int - nv04_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) - { - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->channel; -+ int ret; - -- if (info->state != FBINFO_STATE_RUNNING) -- return; -- -- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 4)) { -- nouveau_fbcon_gpu_lockup(info); -- } -- -- if (info->flags & FBINFO_HWACCEL_DISABLED) { -- cfb_copyarea(info, region); -- return; -- } -+ ret = RING_SPACE(chan, 4); -+ if (ret) -+ return ret; - - BEGIN_RING(chan, NvSubImageBlit, 0x0300, 3); - OUT_RING(chan, (region->sy << 16) | region->sx); - OUT_RING(chan, (region->dy << 16) | region->dx); - OUT_RING(chan, (region->height << 16) | region->width); - FIRE_RING(chan); -+ return 0; - } - --void -+int - nv04_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) - { - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->channel; -+ int ret; - -- if (info->state != FBINFO_STATE_RUNNING) -- return; -- -- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 7)) { -- nouveau_fbcon_gpu_lockup(info); -- } -- -- if (info->flags & FBINFO_HWACCEL_DISABLED) { -- cfb_fillrect(info, rect); -- return; -- } -+ ret = RING_SPACE(chan, 7); -+ if (ret) -+ return ret; - - BEGIN_RING(chan, NvSubGdiRect, 0x02fc, 1); - OUT_RING(chan, (rect->rop != ROP_COPY) ? 1 : 3); -@@ -87,9 +74,10 @@ - OUT_RING(chan, (rect->dx << 16) | rect->dy); - OUT_RING(chan, (rect->width << 16) | rect->height); - FIRE_RING(chan); -+ return 0; - } - --void -+int - nv04_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) - { - struct nouveau_fbdev *nfbdev = info->par; -@@ -101,23 +89,14 @@ - uint32_t dsize; - uint32_t width; - uint32_t *data = (uint32_t *)image->data; -+ int ret; - -- if (info->state != FBINFO_STATE_RUNNING) -- return; -- -- if (image->depth != 1) { -- cfb_imageblit(info, image); -- return; -- } -- -- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 8)) { -- nouveau_fbcon_gpu_lockup(info); -- } -+ if (image->depth != 1) -+ return -ENODEV; - -- if (info->flags & FBINFO_HWACCEL_DISABLED) { -- cfb_imageblit(info, image); -- return; -- } -+ ret = RING_SPACE(chan, 8); -+ if (ret) -+ return ret; - - width = ALIGN(image->width, 8); - dsize = ALIGN(width * image->height, 32) >> 5; -@@ -144,11 +123,9 @@ - while (dsize) { - int iter_len = dsize > 128 ? 128 : dsize; - -- if (RING_SPACE(chan, iter_len + 1)) { -- nouveau_fbcon_gpu_lockup(info); -- cfb_imageblit(info, image); -- return; -- } -+ ret = RING_SPACE(chan, iter_len + 1); -+ if (ret) -+ return ret; - - BEGIN_RING(chan, NvSubGdiRect, 0x0c00, iter_len); - OUT_RINGp(chan, data, iter_len); -@@ -157,22 +134,7 @@ - } - - FIRE_RING(chan); --} -- --static int --nv04_fbcon_grobj_new(struct drm_device *dev, int class, uint32_t handle) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *obj = NULL; -- int ret; -- -- ret = nouveau_gpuobj_gr_new(dev_priv->channel, class, &obj); -- if (ret) -- return ret; -- -- ret = nouveau_ramht_insert(dev_priv->channel, handle, obj); -- nouveau_gpuobj_ref(NULL, &obj); -- return ret; -+ return 0; - } - - int -@@ -214,29 +176,31 @@ - return -EINVAL; - } - -- ret = nv04_fbcon_grobj_new(dev, dev_priv->card_type >= NV_10 ? -- 0x0062 : 0x0042, NvCtxSurf2D); -+ ret = nouveau_gpuobj_gr_new(chan, NvCtxSurf2D, -+ dev_priv->card_type >= NV_10 ? -+ 0x0062 : 0x0042); - if (ret) - return ret; - -- ret = nv04_fbcon_grobj_new(dev, 0x0019, NvClipRect); -+ ret = nouveau_gpuobj_gr_new(chan, NvClipRect, 0x0019); - if (ret) - return ret; - -- ret = nv04_fbcon_grobj_new(dev, 0x0043, NvRop); -+ ret = nouveau_gpuobj_gr_new(chan, NvRop, 0x0043); - if (ret) - return ret; - -- ret = nv04_fbcon_grobj_new(dev, 0x0044, NvImagePatt); -+ ret = nouveau_gpuobj_gr_new(chan, NvImagePatt, 0x0044); - if (ret) - return ret; - -- ret = nv04_fbcon_grobj_new(dev, 0x004a, NvGdiRect); -+ ret = nouveau_gpuobj_gr_new(chan, NvGdiRect, 0x004a); - if (ret) - return ret; - -- ret = nv04_fbcon_grobj_new(dev, dev_priv->chipset >= 0x11 ? -- 0x009f : 0x005f, NvImageBlit); -+ ret = nouveau_gpuobj_gr_new(chan, NvImageBlit, -+ dev_priv->chipset >= 0x11 ? -+ 0x009f : 0x005f); - if (ret) - return ret; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_fifo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_fifo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_fifo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_fifo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -28,6 +28,7 @@ - #include "drm.h" - #include "nouveau_drv.h" - #include "nouveau_ramht.h" -+#include "nouveau_util.h" - - #define NV04_RAMFC(c) (dev_priv->ramfc->pinst + ((c) * NV04_RAMFC__SIZE)) - #define NV04_RAMFC__SIZE 32 -@@ -128,6 +129,11 @@ - if (ret) - return ret; - -+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) + -+ NV03_USER(chan->id), PAGE_SIZE); -+ if (!chan->user) -+ return -ENOMEM; -+ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - - /* Setup initial state */ -@@ -151,10 +157,31 @@ - nv04_fifo_destroy_context(struct nouveau_channel *chan) - { - struct drm_device *dev = chan->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; -+ unsigned long flags; - -- nv_wr32(dev, NV04_PFIFO_MODE, -- nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ pfifo->reassign(dev, false); - -+ /* Unload the context if it's the currently active one */ -+ if (pfifo->channel_id(dev) == chan->id) { -+ pfifo->disable(dev); -+ pfifo->unload_context(dev); -+ pfifo->enable(dev); -+ } -+ -+ /* Keep it from being rescheduled */ -+ nv_mask(dev, NV04_PFIFO_MODE, 1 << chan->id, 0); -+ -+ pfifo->reassign(dev, true); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ -+ /* Free the channel resources */ -+ if (chan->user) { -+ iounmap(chan->user); -+ chan->user = NULL; -+ } - nouveau_gpuobj_ref(NULL, &chan->ramfc); - } - -@@ -208,7 +235,7 @@ - if (chid < 0 || chid >= dev_priv->engine.fifo.channels) - return 0; - -- chan = dev_priv->fifos[chid]; -+ chan = dev_priv->channels.ptr[chid]; - if (!chan) { - NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid); - return -EINVAL; -@@ -267,6 +294,7 @@ - static void - nv04_fifo_init_intr(struct drm_device *dev) - { -+ nouveau_irq_register(dev, 8, nv04_fifo_isr); - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xffffffff); - } -@@ -289,7 +317,7 @@ - pfifo->reassign(dev, true); - - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- if (dev_priv->fifos[i]) { -+ if (dev_priv->channels.ptr[i]) { - uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE); - nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i)); - } -@@ -298,3 +326,207 @@ - return 0; - } - -+void -+nv04_fifo_fini(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x2140, 0x00000000); -+ nouveau_irq_unregister(dev, 8); -+} -+ -+static bool -+nouveau_fifo_swmthd(struct drm_device *dev, u32 chid, u32 addr, u32 data) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan = NULL; -+ struct nouveau_gpuobj *obj; -+ unsigned long flags; -+ const int subc = (addr >> 13) & 0x7; -+ const int mthd = addr & 0x1ffc; -+ bool handled = false; -+ u32 engine; -+ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); -+ if (likely(chid >= 0 && chid < dev_priv->engine.fifo.channels)) -+ chan = dev_priv->channels.ptr[chid]; -+ if (unlikely(!chan)) -+ goto out; -+ -+ switch (mthd) { -+ case 0x0000: /* bind object to subchannel */ -+ obj = nouveau_ramht_find(chan, data); -+ if (unlikely(!obj || obj->engine != NVOBJ_ENGINE_SW)) -+ break; -+ -+ chan->sw_subchannel[subc] = obj->class; -+ engine = 0x0000000f << (subc * 4); -+ -+ nv_mask(dev, NV04_PFIFO_CACHE1_ENGINE, engine, 0x00000000); -+ handled = true; -+ break; -+ default: -+ engine = nv_rd32(dev, NV04_PFIFO_CACHE1_ENGINE); -+ if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) -+ break; -+ -+ if (!nouveau_gpuobj_mthd_call(chan, chan->sw_subchannel[subc], -+ mthd, data)) -+ handled = true; -+ break; -+ } -+ -+out: -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ return handled; -+} -+ -+void -+nv04_fifo_isr(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_engine *engine = &dev_priv->engine; -+ uint32_t status, reassign; -+ int cnt = 0; -+ -+ reassign = nv_rd32(dev, NV03_PFIFO_CACHES) & 1; -+ while ((status = nv_rd32(dev, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) { -+ uint32_t chid, get; -+ -+ nv_wr32(dev, NV03_PFIFO_CACHES, 0); -+ -+ chid = engine->fifo.channel_id(dev); -+ get = nv_rd32(dev, NV03_PFIFO_CACHE1_GET); -+ -+ if (status & NV_PFIFO_INTR_CACHE_ERROR) { -+ uint32_t mthd, data; -+ int ptr; -+ -+ /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before -+ * wrapping on my G80 chips, but CACHE1 isn't big -+ * enough for this much data.. Tests show that it -+ * wraps around to the start at GET=0x800.. No clue -+ * as to why.. -+ */ -+ ptr = (get & 0x7ff) >> 2; -+ -+ if (dev_priv->card_type < NV_40) { -+ mthd = nv_rd32(dev, -+ NV04_PFIFO_CACHE1_METHOD(ptr)); -+ data = nv_rd32(dev, -+ NV04_PFIFO_CACHE1_DATA(ptr)); -+ } else { -+ mthd = nv_rd32(dev, -+ NV40_PFIFO_CACHE1_METHOD(ptr)); -+ data = nv_rd32(dev, -+ NV40_PFIFO_CACHE1_DATA(ptr)); -+ } -+ -+ if (!nouveau_fifo_swmthd(dev, chid, mthd, data)) { -+ NV_INFO(dev, "PFIFO_CACHE_ERROR - Ch %d/%d " -+ "Mthd 0x%04x Data 0x%08x\n", -+ chid, (mthd >> 13) & 7, mthd & 0x1ffc, -+ data); -+ } -+ -+ nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, 0); -+ nv_wr32(dev, NV03_PFIFO_INTR_0, -+ NV_PFIFO_INTR_CACHE_ERROR); -+ -+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, -+ nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) & ~1); -+ nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); -+ nv_wr32(dev, NV03_PFIFO_CACHE1_PUSH0, -+ nv_rd32(dev, NV03_PFIFO_CACHE1_PUSH0) | 1); -+ nv_wr32(dev, NV04_PFIFO_CACHE1_HASH, 0); -+ -+ nv_wr32(dev, NV04_PFIFO_CACHE1_DMA_PUSH, -+ nv_rd32(dev, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); -+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); -+ -+ status &= ~NV_PFIFO_INTR_CACHE_ERROR; -+ } -+ -+ if (status & NV_PFIFO_INTR_DMA_PUSHER) { -+ u32 dma_get = nv_rd32(dev, 0x003244); -+ u32 dma_put = nv_rd32(dev, 0x003240); -+ u32 push = nv_rd32(dev, 0x003220); -+ u32 state = nv_rd32(dev, 0x003228); -+ -+ if (dev_priv->card_type == NV_50) { -+ u32 ho_get = nv_rd32(dev, 0x003328); -+ u32 ho_put = nv_rd32(dev, 0x003320); -+ u32 ib_get = nv_rd32(dev, 0x003334); -+ u32 ib_put = nv_rd32(dev, 0x003330); -+ -+ if (nouveau_ratelimit()) -+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " -+ "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " -+ "State 0x%08x Push 0x%08x\n", -+ chid, ho_get, dma_get, ho_put, -+ dma_put, ib_get, ib_put, state, -+ push); -+ -+ /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ -+ nv_wr32(dev, 0x003364, 0x00000000); -+ if (dma_get != dma_put || ho_get != ho_put) { -+ nv_wr32(dev, 0x003244, dma_put); -+ nv_wr32(dev, 0x003328, ho_put); -+ } else -+ if (ib_get != ib_put) { -+ nv_wr32(dev, 0x003334, ib_put); -+ } -+ } else { -+ NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " -+ "Put 0x%08x State 0x%08x Push 0x%08x\n", -+ chid, dma_get, dma_put, state, push); -+ -+ if (dma_get != dma_put) -+ nv_wr32(dev, 0x003244, dma_put); -+ } -+ -+ nv_wr32(dev, 0x003228, 0x00000000); -+ nv_wr32(dev, 0x003220, 0x00000001); -+ nv_wr32(dev, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); -+ status &= ~NV_PFIFO_INTR_DMA_PUSHER; -+ } -+ -+ if (status & NV_PFIFO_INTR_SEMAPHORE) { -+ uint32_t sem; -+ -+ status &= ~NV_PFIFO_INTR_SEMAPHORE; -+ nv_wr32(dev, NV03_PFIFO_INTR_0, -+ NV_PFIFO_INTR_SEMAPHORE); -+ -+ sem = nv_rd32(dev, NV10_PFIFO_CACHE1_SEMAPHORE); -+ nv_wr32(dev, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); -+ -+ nv_wr32(dev, NV03_PFIFO_CACHE1_GET, get + 4); -+ nv_wr32(dev, NV04_PFIFO_CACHE1_PULL0, 1); -+ } -+ -+ if (dev_priv->card_type == NV_50) { -+ if (status & 0x00000010) { -+ nv50_fb_vm_trap(dev, 1, "PFIFO_BAR_FAULT"); -+ status &= ~0x00000010; -+ nv_wr32(dev, 0x002100, 0x00000010); -+ } -+ } -+ -+ if (status) { -+ if (nouveau_ratelimit()) -+ NV_INFO(dev, "PFIFO_INTR 0x%08x - Ch %d\n", -+ status, chid); -+ nv_wr32(dev, NV03_PFIFO_INTR_0, status); -+ status = 0; -+ } -+ -+ nv_wr32(dev, NV03_PFIFO_CACHES, reassign); -+ } -+ -+ if (status) { -+ NV_INFO(dev, "PFIFO still angry after %d spins, halt\n", cnt); -+ nv_wr32(dev, 0x2140, 0); -+ nv_wr32(dev, 0x140, 0); -+ } -+ -+ nv_wr32(dev, NV03_PMC_INTR_0, NV_PMC_INTR_0_PFIFO_PENDING); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_graph.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_graph.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_graph.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_graph.c 2011-01-07 14:22:17.000000000 +0100 -@@ -26,6 +26,11 @@ - #include "drm.h" - #include "nouveau_drm.h" - #include "nouveau_drv.h" -+#include "nouveau_hw.h" -+#include "nouveau_util.h" -+ -+static int nv04_graph_register(struct drm_device *dev); -+static void nv04_graph_isr(struct drm_device *dev); - - static uint32_t nv04_graph_ctx_regs[] = { - 0x0040053c, -@@ -357,10 +362,10 @@ - if (chid >= dev_priv->engine.fifo.channels) - return NULL; - -- return dev_priv->fifos[chid]; -+ return dev_priv->channels.ptr[chid]; - } - --void -+static void - nv04_graph_context_switch(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -368,7 +373,6 @@ - struct nouveau_channel *chan = NULL; - int chid; - -- pgraph->fifo_access(dev, false); - nouveau_wait_for_idle(dev); - - /* If previous context is valid, we need to save it */ -@@ -376,11 +380,9 @@ - - /* Load context for next channel */ - chid = dev_priv->engine.fifo.channel_id(dev); -- chan = dev_priv->fifos[chid]; -+ chan = dev_priv->channels.ptr[chid]; - if (chan) - nv04_graph_load_context(chan); -- -- pgraph->fifo_access(dev, true); - } - - static uint32_t *ctx_reg(struct graph_state *ctx, uint32_t reg) -@@ -412,10 +414,25 @@ - - 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) -@@ -468,13 +485,19 @@ - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t tmp; -+ int ret; - - 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); - -@@ -510,6 +533,8 @@ - - void nv04_graph_takedown(struct drm_device *dev) - { -+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); -+ nouveau_irq_unregister(dev, 12); - } - - void -@@ -524,13 +549,27 @@ - } - - static int --nv04_graph_mthd_set_ref(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_set_ref(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - atomic_set(&chan->fence.last_sequence_irq, data); - return 0; - } - -+int -+nv04_graph_mthd_page_flip(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) -+{ -+ struct drm_device *dev = chan->dev; -+ struct nouveau_page_flip_state s; -+ -+ if (!nouveau_finish_page_flip(chan, &s)) -+ nv_set_crtc_base(dev, s.crtc, -+ s.offset + s.y * s.pitch + s.x * s.bpp / 8); -+ -+ return 0; -+} -+ - /* - * Software methods, why they are needed, and how they all work: - * -@@ -606,12 +645,12 @@ - */ - - static void --nv04_graph_set_ctx1(struct nouveau_channel *chan, uint32_t mask, uint32_t value) -+nv04_graph_set_ctx1(struct nouveau_channel *chan, u32 mask, u32 value) - { - struct drm_device *dev = chan->dev; -- uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; -+ u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; - int subc = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; -- uint32_t tmp; -+ u32 tmp; - - tmp = nv_ri32(dev, instance); - tmp &= ~mask; -@@ -623,11 +662,11 @@ - } - - static void --nv04_graph_set_ctx_val(struct nouveau_channel *chan, uint32_t mask, uint32_t value) -+nv04_graph_set_ctx_val(struct nouveau_channel *chan, u32 mask, u32 value) - { - struct drm_device *dev = chan->dev; -- uint32_t instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; -- uint32_t tmp, ctx1; -+ u32 instance = (nv_rd32(dev, NV04_PGRAPH_CTX_SWITCH4) & 0xffff) << 4; -+ u32 tmp, ctx1; - int class, op, valid = 1; - - ctx1 = nv_ri32(dev, instance); -@@ -672,13 +711,13 @@ - } - - static int --nv04_graph_mthd_set_operation(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_set_operation(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - if (data > 5) - return 1; - /* Old versions of the objects only accept first three operations. */ -- if (data > 2 && grclass < 0x40) -+ if (data > 2 && class < 0x40) - return 1; - nv04_graph_set_ctx1(chan, 0x00038000, data << 15); - /* changing operation changes set of objects needed for validation */ -@@ -687,8 +726,8 @@ - } - - static int --nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_surf3d_clip_h(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - uint32_t min = data & 0xffff, max; - uint32_t w = data >> 16; -@@ -706,8 +745,8 @@ - } - - static int --nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_surf3d_clip_v(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - uint32_t min = data & 0xffff, max; - uint32_t w = data >> 16; -@@ -725,8 +764,8 @@ - } - - static int --nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_surf2d(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -742,8 +781,8 @@ - } - - static int --nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -763,8 +802,8 @@ - } - - static int --nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_nv01_patt(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -778,8 +817,8 @@ - } - - static int --nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_nv04_patt(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -793,8 +832,8 @@ - } - - static int --nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_rop(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -808,8 +847,8 @@ - } - - static int --nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_beta1(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -823,8 +862,8 @@ - } - - static int --nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_beta4(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -838,8 +877,8 @@ - } - - static int --nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_surf_dst(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -853,8 +892,8 @@ - } - - static int --nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_surf_src(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -868,8 +907,8 @@ - } - - static int --nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_surf_color(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -883,8 +922,8 @@ - } - - static int --nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_surf_zeta(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -898,8 +937,8 @@ - } - - static int --nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_clip(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -913,8 +952,8 @@ - } - - static int --nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv04_graph_mthd_bind_chroma(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - switch (nv_ri32(chan->dev, data << 4) & 0xff) { - case 0x30: -@@ -930,194 +969,346 @@ - return 1; - } - --static struct nouveau_pgraph_object_method nv04_graph_mthds_sw[] = { -- { 0x0150, nv04_graph_mthd_set_ref }, -- {} --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_gdirect[] = { -- { 0x0184, nv04_graph_mthd_bind_nv01_patt }, -- { 0x0188, nv04_graph_mthd_bind_rop }, -- { 0x018c, nv04_graph_mthd_bind_beta1 }, -- { 0x0190, nv04_graph_mthd_bind_surf_dst }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_gdirect[] = { -- { 0x0188, nv04_graph_mthd_bind_nv04_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_beta4 }, -- { 0x0198, nv04_graph_mthd_bind_surf2d }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_imageblit[] = { -- { 0x0184, nv04_graph_mthd_bind_chroma }, -- { 0x0188, nv04_graph_mthd_bind_clip }, -- { 0x018c, nv04_graph_mthd_bind_nv01_patt }, -- { 0x0190, nv04_graph_mthd_bind_rop }, -- { 0x0194, nv04_graph_mthd_bind_beta1 }, -- { 0x0198, nv04_graph_mthd_bind_surf_dst }, -- { 0x019c, nv04_graph_mthd_bind_surf_src }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_imageblit_ifc[] = { -- { 0x0184, nv04_graph_mthd_bind_chroma }, -- { 0x0188, nv04_graph_mthd_bind_clip }, -- { 0x018c, nv04_graph_mthd_bind_nv04_patt }, -- { 0x0190, nv04_graph_mthd_bind_rop }, -- { 0x0194, nv04_graph_mthd_bind_beta1 }, -- { 0x0198, nv04_graph_mthd_bind_beta4 }, -- { 0x019c, nv04_graph_mthd_bind_surf2d }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_iifc[] = { -- { 0x0188, nv04_graph_mthd_bind_chroma }, -- { 0x018c, nv04_graph_mthd_bind_clip }, -- { 0x0190, nv04_graph_mthd_bind_nv04_patt }, -- { 0x0194, nv04_graph_mthd_bind_rop }, -- { 0x0198, nv04_graph_mthd_bind_beta1 }, -- { 0x019c, nv04_graph_mthd_bind_beta4 }, -- { 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf }, -- { 0x03e4, nv04_graph_mthd_set_operation }, -- {}, --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_ifc[] = { -- { 0x0184, nv04_graph_mthd_bind_chroma }, -- { 0x0188, nv04_graph_mthd_bind_clip }, -- { 0x018c, nv04_graph_mthd_bind_nv01_patt }, -- { 0x0190, nv04_graph_mthd_bind_rop }, -- { 0x0194, nv04_graph_mthd_bind_beta1 }, -- { 0x0198, nv04_graph_mthd_bind_surf_dst }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -- --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_sifc[] = { -- { 0x0184, nv04_graph_mthd_bind_chroma }, -- { 0x0188, nv04_graph_mthd_bind_nv01_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_surf_dst }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -+static int -+nv04_graph_register(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; - --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_sifc[] = { -- { 0x0184, nv04_graph_mthd_bind_chroma }, -- { 0x0188, nv04_graph_mthd_bind_nv04_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_beta4 }, -- { 0x0198, nv04_graph_mthd_bind_surf2d }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -+ if (dev_priv->engine.graph.registered) -+ return 0; - --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_sifm[] = { -- { 0x0188, nv04_graph_mthd_bind_nv01_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_surf_dst }, -- { 0x0304, nv04_graph_mthd_set_operation }, -- {}, --}; -+ /* dvd subpicture */ -+ NVOBJ_CLASS(dev, 0x0038, GR); - --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_sifm[] = { -- { 0x0188, nv04_graph_mthd_bind_nv04_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_beta4 }, -- { 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf }, -- { 0x0304, nv04_graph_mthd_set_operation }, -- {}, --}; -+ /* m2mf */ -+ NVOBJ_CLASS(dev, 0x0039, GR); - --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv01_shape[] = { -- { 0x0184, nv04_graph_mthd_bind_clip }, -- { 0x0188, nv04_graph_mthd_bind_nv01_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_surf_dst }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, --}; -+ /* nv03 gdirect */ -+ NVOBJ_CLASS(dev, 0x004b, GR); -+ NVOBJ_MTHD (dev, 0x004b, 0x0184, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x004b, 0x0188, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x004b, 0x018c, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x004b, 0x0190, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x004b, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 gdirect */ -+ NVOBJ_CLASS(dev, 0x004a, GR); -+ NVOBJ_MTHD (dev, 0x004a, 0x0188, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x004a, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x004a, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x004a, 0x0194, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x004a, 0x0198, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x004a, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv01 imageblit */ -+ NVOBJ_CLASS(dev, 0x001f, GR); -+ NVOBJ_MTHD (dev, 0x001f, 0x0184, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x001f, 0x0188, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x001f, 0x018c, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x001f, 0x0190, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x001f, 0x0194, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x001f, 0x0198, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x001f, 0x019c, nv04_graph_mthd_bind_surf_src); -+ NVOBJ_MTHD (dev, 0x001f, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 imageblit */ -+ NVOBJ_CLASS(dev, 0x005f, GR); -+ NVOBJ_MTHD (dev, 0x005f, 0x0184, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x005f, 0x0188, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x005f, 0x018c, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x005f, 0x0190, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x005f, 0x0194, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x005f, 0x0198, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x005f, 0x019c, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x005f, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 iifc */ -+ NVOBJ_CLASS(dev, 0x0060, GR); -+ NVOBJ_MTHD (dev, 0x0060, 0x0188, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x0060, 0x018c, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x0060, 0x0190, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x0060, 0x0194, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0060, 0x0198, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0060, 0x019c, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x0060, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf); -+ NVOBJ_MTHD (dev, 0x0060, 0x03e4, nv04_graph_mthd_set_operation); -+ -+ /* nv05 iifc */ -+ NVOBJ_CLASS(dev, 0x0064, GR); -+ -+ /* nv01 ifc */ -+ NVOBJ_CLASS(dev, 0x0021, GR); -+ NVOBJ_MTHD (dev, 0x0021, 0x0184, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x0021, 0x0188, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x0021, 0x018c, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x0021, 0x0190, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0021, 0x0194, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0021, 0x0198, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x0021, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 ifc */ -+ NVOBJ_CLASS(dev, 0x0061, GR); -+ NVOBJ_MTHD (dev, 0x0061, 0x0184, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x0061, 0x0188, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x0061, 0x018c, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x0061, 0x0190, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0061, 0x0194, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0061, 0x0198, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x0061, 0x019c, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x0061, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv05 ifc */ -+ NVOBJ_CLASS(dev, 0x0065, GR); -+ -+ /* nv03 sifc */ -+ NVOBJ_CLASS(dev, 0x0036, GR); -+ NVOBJ_MTHD (dev, 0x0036, 0x0184, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x0036, 0x0188, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x0036, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0036, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0036, 0x0194, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x0036, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 sifc */ -+ NVOBJ_CLASS(dev, 0x0076, GR); -+ NVOBJ_MTHD (dev, 0x0076, 0x0184, nv04_graph_mthd_bind_chroma); -+ NVOBJ_MTHD (dev, 0x0076, 0x0188, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x0076, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0076, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0076, 0x0194, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x0076, 0x0198, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x0076, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv05 sifc */ -+ NVOBJ_CLASS(dev, 0x0066, GR); -+ -+ /* nv03 sifm */ -+ NVOBJ_CLASS(dev, 0x0037, GR); -+ NVOBJ_MTHD (dev, 0x0037, 0x0188, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x0037, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0037, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0037, 0x0194, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x0037, 0x0304, nv04_graph_mthd_set_operation); -+ -+ /* nv04 sifm */ -+ NVOBJ_CLASS(dev, 0x0077, GR); -+ NVOBJ_MTHD (dev, 0x0077, 0x0188, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x0077, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x0077, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x0077, 0x0194, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x0077, 0x0198, nv04_graph_mthd_bind_surf2d_swzsurf); -+ NVOBJ_MTHD (dev, 0x0077, 0x0304, nv04_graph_mthd_set_operation); -+ -+ /* null */ -+ NVOBJ_CLASS(dev, 0x0030, GR); -+ -+ /* surf2d */ -+ NVOBJ_CLASS(dev, 0x0042, GR); -+ -+ /* rop */ -+ NVOBJ_CLASS(dev, 0x0043, GR); -+ -+ /* beta1 */ -+ NVOBJ_CLASS(dev, 0x0012, GR); -+ -+ /* beta4 */ -+ NVOBJ_CLASS(dev, 0x0072, GR); -+ -+ /* cliprect */ -+ NVOBJ_CLASS(dev, 0x0019, GR); -+ -+ /* nv01 pattern */ -+ NVOBJ_CLASS(dev, 0x0018, GR); -+ -+ /* nv04 pattern */ -+ NVOBJ_CLASS(dev, 0x0044, GR); -+ -+ /* swzsurf */ -+ NVOBJ_CLASS(dev, 0x0052, GR); -+ -+ /* surf3d */ -+ NVOBJ_CLASS(dev, 0x0053, GR); -+ NVOBJ_MTHD (dev, 0x0053, 0x02f8, nv04_graph_mthd_surf3d_clip_h); -+ NVOBJ_MTHD (dev, 0x0053, 0x02fc, nv04_graph_mthd_surf3d_clip_v); -+ -+ /* nv03 tex_tri */ -+ NVOBJ_CLASS(dev, 0x0048, GR); -+ NVOBJ_MTHD (dev, 0x0048, 0x0188, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x0048, 0x018c, nv04_graph_mthd_bind_surf_color); -+ NVOBJ_MTHD (dev, 0x0048, 0x0190, nv04_graph_mthd_bind_surf_zeta); -+ -+ /* tex_tri */ -+ NVOBJ_CLASS(dev, 0x0054, GR); -+ -+ /* multitex_tri */ -+ NVOBJ_CLASS(dev, 0x0055, GR); -+ -+ /* nv01 chroma */ -+ NVOBJ_CLASS(dev, 0x0017, GR); -+ -+ /* nv04 chroma */ -+ NVOBJ_CLASS(dev, 0x0057, GR); -+ -+ /* surf_dst */ -+ NVOBJ_CLASS(dev, 0x0058, GR); -+ -+ /* surf_src */ -+ NVOBJ_CLASS(dev, 0x0059, GR); -+ -+ /* surf_color */ -+ NVOBJ_CLASS(dev, 0x005a, GR); -+ -+ /* surf_zeta */ -+ NVOBJ_CLASS(dev, 0x005b, GR); -+ -+ /* nv01 line */ -+ NVOBJ_CLASS(dev, 0x001c, GR); -+ NVOBJ_MTHD (dev, 0x001c, 0x0184, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x001c, 0x0188, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x001c, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x001c, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x001c, 0x0194, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x001c, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 line */ -+ NVOBJ_CLASS(dev, 0x005c, GR); -+ NVOBJ_MTHD (dev, 0x005c, 0x0184, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x005c, 0x0188, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x005c, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x005c, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x005c, 0x0194, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x005c, 0x0198, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x005c, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv01 tri */ -+ NVOBJ_CLASS(dev, 0x001d, GR); -+ NVOBJ_MTHD (dev, 0x001d, 0x0184, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x001d, 0x0188, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x001d, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x001d, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x001d, 0x0194, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x001d, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 tri */ -+ NVOBJ_CLASS(dev, 0x005d, GR); -+ NVOBJ_MTHD (dev, 0x005d, 0x0184, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x005d, 0x0188, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x005d, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x005d, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x005d, 0x0194, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x005d, 0x0198, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x005d, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv01 rect */ -+ NVOBJ_CLASS(dev, 0x001e, GR); -+ NVOBJ_MTHD (dev, 0x001e, 0x0184, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x001e, 0x0188, nv04_graph_mthd_bind_nv01_patt); -+ NVOBJ_MTHD (dev, 0x001e, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x001e, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x001e, 0x0194, nv04_graph_mthd_bind_surf_dst); -+ NVOBJ_MTHD (dev, 0x001e, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nv04 rect */ -+ NVOBJ_CLASS(dev, 0x005e, GR); -+ NVOBJ_MTHD (dev, 0x005e, 0x0184, nv04_graph_mthd_bind_clip); -+ NVOBJ_MTHD (dev, 0x005e, 0x0188, nv04_graph_mthd_bind_nv04_patt); -+ NVOBJ_MTHD (dev, 0x005e, 0x018c, nv04_graph_mthd_bind_rop); -+ NVOBJ_MTHD (dev, 0x005e, 0x0190, nv04_graph_mthd_bind_beta1); -+ NVOBJ_MTHD (dev, 0x005e, 0x0194, nv04_graph_mthd_bind_beta4); -+ NVOBJ_MTHD (dev, 0x005e, 0x0198, nv04_graph_mthd_bind_surf2d); -+ NVOBJ_MTHD (dev, 0x005e, 0x02fc, nv04_graph_mthd_set_operation); -+ -+ /* nvsw */ -+ 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); - --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv04_shape[] = { -- { 0x0184, nv04_graph_mthd_bind_clip }, -- { 0x0188, nv04_graph_mthd_bind_nv04_patt }, -- { 0x018c, nv04_graph_mthd_bind_rop }, -- { 0x0190, nv04_graph_mthd_bind_beta1 }, -- { 0x0194, nv04_graph_mthd_bind_beta4 }, -- { 0x0198, nv04_graph_mthd_bind_surf2d }, -- { 0x02fc, nv04_graph_mthd_set_operation }, -- {}, -+ dev_priv->engine.graph.registered = true; -+ return 0; - }; - --static struct nouveau_pgraph_object_method nv04_graph_mthds_nv03_tex_tri[] = { -- { 0x0188, nv04_graph_mthd_bind_clip }, -- { 0x018c, nv04_graph_mthd_bind_surf_color }, -- { 0x0190, nv04_graph_mthd_bind_surf_zeta }, -- {}, -+static struct nouveau_bitfield nv04_graph_intr[] = { -+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, -+ {} - }; - --static struct nouveau_pgraph_object_method nv04_graph_mthds_surf3d[] = { -- { 0x02f8, nv04_graph_mthd_surf3d_clip_h }, -- { 0x02fc, nv04_graph_mthd_surf3d_clip_v }, -- {}, -+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_pgraph_object_class nv04_graph_grclass[] = { -- { 0x0038, false, NULL }, /* dvd subpicture */ -- { 0x0039, false, NULL }, /* m2mf */ -- { 0x004b, false, nv04_graph_mthds_nv03_gdirect }, /* nv03 gdirect */ -- { 0x004a, false, nv04_graph_mthds_nv04_gdirect }, /* nv04 gdirect */ -- { 0x001f, false, nv04_graph_mthds_nv01_imageblit }, /* nv01 imageblit */ -- { 0x005f, false, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 imageblit */ -- { 0x0060, false, nv04_graph_mthds_nv04_iifc }, /* nv04 iifc */ -- { 0x0064, false, NULL }, /* nv05 iifc */ -- { 0x0021, false, nv04_graph_mthds_nv01_ifc }, /* nv01 ifc */ -- { 0x0061, false, nv04_graph_mthds_nv04_imageblit_ifc }, /* nv04 ifc */ -- { 0x0065, false, NULL }, /* nv05 ifc */ -- { 0x0036, false, nv04_graph_mthds_nv03_sifc }, /* nv03 sifc */ -- { 0x0076, false, nv04_graph_mthds_nv04_sifc }, /* nv04 sifc */ -- { 0x0066, false, NULL }, /* nv05 sifc */ -- { 0x0037, false, nv04_graph_mthds_nv03_sifm }, /* nv03 sifm */ -- { 0x0077, false, nv04_graph_mthds_nv04_sifm }, /* nv04 sifm */ -- { 0x0030, false, NULL }, /* null */ -- { 0x0042, false, NULL }, /* surf2d */ -- { 0x0043, false, NULL }, /* rop */ -- { 0x0012, false, NULL }, /* beta1 */ -- { 0x0072, false, NULL }, /* beta4 */ -- { 0x0019, false, NULL }, /* cliprect */ -- { 0x0018, false, NULL }, /* nv01 pattern */ -- { 0x0044, false, NULL }, /* nv04 pattern */ -- { 0x0052, false, NULL }, /* swzsurf */ -- { 0x0053, false, nv04_graph_mthds_surf3d }, /* surf3d */ -- { 0x0048, false, nv04_graph_mthds_nv03_tex_tri }, /* nv03 tex_tri */ -- { 0x0054, false, NULL }, /* tex_tri */ -- { 0x0055, false, NULL }, /* multitex_tri */ -- { 0x0017, false, NULL }, /* nv01 chroma */ -- { 0x0057, false, NULL }, /* nv04 chroma */ -- { 0x0058, false, NULL }, /* surf_dst */ -- { 0x0059, false, NULL }, /* surf_src */ -- { 0x005a, false, NULL }, /* surf_color */ -- { 0x005b, false, NULL }, /* surf_zeta */ -- { 0x001c, false, nv04_graph_mthds_nv01_shape }, /* nv01 line */ -- { 0x005c, false, nv04_graph_mthds_nv04_shape }, /* nv04 line */ -- { 0x001d, false, nv04_graph_mthds_nv01_shape }, /* nv01 tri */ -- { 0x005d, false, nv04_graph_mthds_nv04_shape }, /* nv04 tri */ -- { 0x001e, false, nv04_graph_mthds_nv01_shape }, /* nv01 rect */ -- { 0x005e, false, nv04_graph_mthds_nv04_shape }, /* nv04 rect */ -- { 0x506e, true, nv04_graph_mthds_sw }, -+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); -+ } -+ } -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_instmem.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_instmem.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv04_instmem.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv04_instmem.c 2011-01-07 14:22:17.000000000 +0100 -@@ -98,42 +98,66 @@ - } - - int --nv04_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, -- uint32_t *sz) -+nv04_instmem_suspend(struct drm_device *dev) - { - return 0; - } - - void --nv04_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+nv04_instmem_resume(struct drm_device *dev) - { - } - - int --nv04_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+nv04_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) - { -- return 0; --} -+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; -+ struct drm_mm_node *ramin = NULL; - --int --nv04_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) --{ -+ do { -+ if (drm_mm_pre_get(&dev_priv->ramin_heap)) -+ return -ENOMEM; -+ -+ spin_lock(&dev_priv->ramin_lock); -+ ramin = drm_mm_search_free(&dev_priv->ramin_heap, size, align, 0); -+ if (ramin == NULL) { -+ spin_unlock(&dev_priv->ramin_lock); -+ return -ENOMEM; -+ } -+ -+ ramin = drm_mm_get_block_atomic(ramin, size, align); -+ spin_unlock(&dev_priv->ramin_lock); -+ } while (ramin == NULL); -+ -+ gpuobj->node = ramin; -+ gpuobj->vinst = ramin->start; - return 0; - } - - void --nv04_instmem_flush(struct drm_device *dev) -+nv04_instmem_put(struct nouveau_gpuobj *gpuobj) - { -+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; -+ -+ spin_lock(&dev_priv->ramin_lock); -+ drm_mm_put_block(gpuobj->node); -+ gpuobj->node = NULL; -+ spin_unlock(&dev_priv->ramin_lock); - } - - int --nv04_instmem_suspend(struct drm_device *dev) -+nv04_instmem_map(struct nouveau_gpuobj *gpuobj) - { -+ gpuobj->pinst = gpuobj->vinst; - return 0; - } - - void --nv04_instmem_resume(struct drm_device *dev) -+nv04_instmem_unmap(struct nouveau_gpuobj *gpuobj) - { - } - -+void -+nv04_instmem_flush(struct drm_device *dev) -+{ -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv10_fb.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv10_fb.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv10_fb.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv10_fb.c 2011-01-07 14:22:17.000000000 +0100 -@@ -3,23 +3,109 @@ - #include "nouveau_drv.h" - #include "nouveau_drm.h" - -+static struct drm_mm_node * -+nv20_fb_alloc_tag(struct drm_device *dev, uint32_t size) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; -+ struct drm_mm_node *mem; -+ int ret; -+ -+ ret = drm_mm_pre_get(&pfb->tag_heap); -+ if (ret) -+ return NULL; -+ -+ spin_lock(&dev_priv->tile.lock); -+ mem = drm_mm_search_free(&pfb->tag_heap, size, 0, 0); -+ if (mem) -+ mem = drm_mm_get_block_atomic(mem, size, 0); -+ spin_unlock(&dev_priv->tile.lock); -+ -+ return mem; -+} -+ -+static void -+nv20_fb_free_tag(struct drm_device *dev, struct drm_mm_node *mem) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ spin_lock(&dev_priv->tile.lock); -+ drm_mm_put_block(mem); -+ spin_unlock(&dev_priv->tile.lock); -+} -+ -+void -+nv10_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, -+ uint32_t size, uint32_t pitch, uint32_t flags) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; -+ int bpp = (flags & NOUVEAU_GEM_TILE_32BPP ? 32 : 16); -+ -+ tile->addr = addr; -+ tile->limit = max(1u, addr + size) - 1; -+ tile->pitch = pitch; -+ -+ if (dev_priv->card_type == NV_20) { -+ if (flags & NOUVEAU_GEM_TILE_ZETA) { -+ /* -+ * Allocate some of the on-die tag memory, -+ * used to store Z compression meta-data (most -+ * likely just a bitmap determining if a given -+ * tile is compressed or not). -+ */ -+ tile->tag_mem = nv20_fb_alloc_tag(dev, size / 256); -+ -+ if (tile->tag_mem) { -+ /* Enable Z compression */ -+ if (dev_priv->chipset >= 0x25) -+ tile->zcomp = tile->tag_mem->start | -+ (bpp == 16 ? -+ NV25_PFB_ZCOMP_MODE_16 : -+ NV25_PFB_ZCOMP_MODE_32); -+ else -+ tile->zcomp = tile->tag_mem->start | -+ NV20_PFB_ZCOMP_EN | -+ (bpp == 16 ? 0 : -+ NV20_PFB_ZCOMP_MODE_32); -+ } -+ -+ tile->addr |= 3; -+ } else { -+ tile->addr |= 1; -+ } -+ -+ } else { -+ tile->addr |= 1 << 31; -+ } -+} -+ - void --nv10_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch) -+nv10_fb_free_tile_region(struct drm_device *dev, int i) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t limit = max(1u, addr + size) - 1; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - -- if (pitch) { -- if (dev_priv->card_type >= NV_20) -- addr |= 1; -- else -- addr |= 1 << 31; -+ if (tile->tag_mem) { -+ nv20_fb_free_tag(dev, tile->tag_mem); -+ tile->tag_mem = NULL; - } - -- nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); -- nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); -- nv_wr32(dev, NV10_PFB_TILE(i), addr); -+ tile->addr = tile->limit = tile->pitch = tile->zcomp = 0; -+} -+ -+void -+nv10_fb_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, NV10_PFB_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); -+ -+ if (dev_priv->card_type == NV_20) -+ nv_wr32(dev, NV20_PFB_ZCOMP(i), tile->zcomp); - } - - int -@@ -31,9 +117,14 @@ - - pfb->num_tiles = NV10_PFB_TILE__SIZE; - -+ if (dev_priv->card_type == NV_20) -+ drm_mm_init(&pfb->tag_heap, 0, -+ (dev_priv->chipset >= 0x25 ? -+ 64 * 1024 : 32 * 1024)); -+ - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) -- pfb->set_region_tiling(dev, i, 0, 0, 0); -+ pfb->set_tile_region(dev, i); - - return 0; - } -@@ -41,4 +132,13 @@ - void - nv10_fb_takedown(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; -+ int i; -+ -+ for (i = 0; i < pfb->num_tiles; i++) -+ pfb->free_tile_region(dev, i); -+ -+ if (dev_priv->card_type == NV_20) -+ drm_mm_takedown(&pfb->tag_heap); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv10_fifo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv10_fifo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv10_fifo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv10_fifo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -53,6 +53,11 @@ - if (ret) - return ret; - -+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) + -+ NV03_USER(chan->id), PAGE_SIZE); -+ if (!chan->user) -+ return -ENOMEM; -+ - /* Fill entries that are seen filled in dumps of nvidia driver just - * after channel's is put into DMA mode - */ -@@ -73,17 +78,6 @@ - return 0; - } - --void --nv10_fifo_destroy_context(struct nouveau_channel *chan) --{ -- struct drm_device *dev = chan->dev; -- -- nv_wr32(dev, NV04_PFIFO_MODE, -- nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); -- -- nouveau_gpuobj_ref(NULL, &chan->ramfc); --} -- - static void - nv10_fifo_do_load_context(struct drm_device *dev, int chid) - { -@@ -219,6 +213,7 @@ - static void - nv10_fifo_init_intr(struct drm_device *dev) - { -+ nouveau_irq_register(dev, 8, nv04_fifo_isr); - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xffffffff); - } -@@ -241,7 +236,7 @@ - pfifo->reassign(dev, true); - - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- if (dev_priv->fifos[i]) { -+ if (dev_priv->channels.ptr[i]) { - uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE); - nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i)); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv10_graph.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv10_graph.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv10_graph.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv10_graph.c 2011-01-07 14:22:17.000000000 +0100 -@@ -26,6 +26,10 @@ - #include "drm.h" - #include "nouveau_drm.h" - #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 - -@@ -786,15 +790,13 @@ - return 0; - } - --void -+static void - nv10_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; - -- pgraph->fifo_access(dev, false); - nouveau_wait_for_idle(dev); - - /* If previous context is valid, we need to save it */ -@@ -802,11 +804,9 @@ - - /* Load context for next channel */ - chid = (nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; -- chan = dev_priv->fifos[chid]; -+ chan = dev_priv->channels.ptr[chid]; - if (chan && chan->pgraph_ctx) - nv10_graph_load_context(chan); -- -- pgraph->fifo_access(dev, true); - } - - #define NV_WRITE_CTX(reg, val) do { \ -@@ -833,7 +833,7 @@ - if (chid >= dev_priv->engine.fifo.channels) - return NULL; - -- return dev_priv->fifos[chid]; -+ return dev_priv->channels.ptr[chid]; - } - - int nv10_graph_create_context(struct nouveau_channel *chan) -@@ -875,37 +875,54 @@ - - void nv10_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); - } - - void --nv10_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch) -+nv10_graph_set_tile_region(struct drm_device *dev, int i) - { -- uint32_t limit = max(1u, addr + size) - 1; -- -- if (pitch) -- addr |= 1 << 31; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - -- nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), limit); -- nv_wr32(dev, NV10_PGRAPH_TSIZE(i), pitch); -- nv_wr32(dev, NV10_PGRAPH_TILE(i), addr); -+ nv_wr32(dev, NV10_PGRAPH_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV10_PGRAPH_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV10_PGRAPH_TILE(i), tile->addr); - } - - int nv10_graph_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t tmp; -- int i; -+ int ret, 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); - -@@ -928,7 +945,7 @@ - - /* Turn all the tiling regions off. */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) -- nv10_graph_set_region_tiling(dev, i, 0, 0, 0); -+ nv10_graph_set_tile_region(dev, i); - - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); - nv_wr32(dev, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); -@@ -948,17 +965,17 @@ - - void nv10_graph_takedown(struct drm_device *dev) - { -+ nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); -+ nouveau_irq_unregister(dev, 12); - } - - static int --nv17_graph_mthd_lma_window(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv17_graph_mthd_lma_window(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - struct drm_device *dev = chan->dev; - struct graph_state *ctx = chan->pgraph_ctx; - struct pipe_state *pipe = &ctx->pipe_state; -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - uint32_t pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; - uint32_t xfmode0, xfmode1; - int i; -@@ -1025,18 +1042,14 @@ - - nouveau_wait_for_idle(dev); - -- pgraph->fifo_access(dev, true); -- - return 0; - } - - static int --nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv17_graph_mthd_lma_enable(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - struct drm_device *dev = chan->dev; -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - - nouveau_wait_for_idle(dev); - -@@ -1045,40 +1058,118 @@ - nv_wr32(dev, 0x004006b0, - nv_rd32(dev, 0x004006b0) | 0x8 << 24); - -- pgraph->fifo_access(dev, true); -+ 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; - } - --static struct nouveau_pgraph_object_method nv17_graph_celsius_mthds[] = { -- { 0x1638, nv17_graph_mthd_lma_window }, -- { 0x163c, nv17_graph_mthd_lma_window }, -- { 0x1640, nv17_graph_mthd_lma_window }, -- { 0x1644, nv17_graph_mthd_lma_window }, -- { 0x1658, nv17_graph_mthd_lma_enable }, -+struct nouveau_bitfield nv10_graph_intr[] = { -+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" }, -+ { NV_PGRAPH_INTR_ERROR, "ERROR" }, - {} - }; - --struct nouveau_pgraph_object_class nv10_graph_grclass[] = { -- { 0x0030, false, NULL }, /* null */ -- { 0x0039, false, NULL }, /* m2mf */ -- { 0x004a, false, NULL }, /* gdirect */ -- { 0x005f, false, NULL }, /* imageblit */ -- { 0x009f, false, NULL }, /* imageblit (nv12) */ -- { 0x008a, false, NULL }, /* ifc */ -- { 0x0089, false, NULL }, /* sifm */ -- { 0x0062, false, NULL }, /* surf2d */ -- { 0x0043, false, NULL }, /* rop */ -- { 0x0012, false, NULL }, /* beta1 */ -- { 0x0072, false, NULL }, /* beta4 */ -- { 0x0019, false, NULL }, /* cliprect */ -- { 0x0044, false, NULL }, /* pattern */ -- { 0x0052, false, NULL }, /* swzsurf */ -- { 0x0093, false, NULL }, /* surf3d */ -- { 0x0094, false, NULL }, /* tex_tri */ -- { 0x0095, false, NULL }, /* multitex_tri */ -- { 0x0056, false, NULL }, /* celcius (nv10) */ -- { 0x0096, false, NULL }, /* celcius (nv11) */ -- { 0x0099, false, nv17_graph_celsius_mthds }, /* celcius (nv17) */ -+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" }, -+ { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" }, - {} - }; -+ -+static void -+nv10_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 & 0x01f00000) >> 20; -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 mthd = (addr & 0x00001ffc); -+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); -+ u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff; -+ u32 show = stat; -+ -+ if (stat & NV_PGRAPH_INTR_ERROR) { -+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { -+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) -+ show &= ~NV_PGRAPH_INTR_ERROR; -+ } -+ } -+ -+ 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; -+ nv10_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(nv10_graph_intr, show); -+ printk(" nsource:"); -+ nouveau_bitfield_print(nv04_graph_nsource, nsource); -+ printk(" nstatus:"); -+ nouveau_bitfield_print(nv10_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); -+ } -+ } -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv20_graph.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv20_graph.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv20_graph.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv20_graph.c 2011-01-07 14:22:17.000000000 +0100 -@@ -32,6 +32,10 @@ - #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 *); -+ - static void - nv20_graph_context_init(struct drm_device *dev, struct nouveau_gpuobj *ctx) - { -@@ -425,9 +429,21 @@ - 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; - -- nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); -+ 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 */ - nv_wo32(pgraph->ctx_table, chan->id * 4, 0); -+ nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); - } - - int -@@ -496,24 +512,27 @@ - } - - void --nv20_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch) -+nv20_graph_set_tile_region(struct drm_device *dev, int i) - { -- uint32_t limit = max(1u, addr + size) - 1; -- -- if (pitch) -- addr |= 1; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - -- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); -- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); -- nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); -+ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); - - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); -- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, limit); -+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->limit); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); -- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, pitch); -+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->pitch); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); -- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, addr); -+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->addr); -+ -+ if (dev_priv->card_type == NV_20) { -+ nv_wr32(dev, NV20_PGRAPH_ZCOMP(i), tile->zcomp); -+ nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); -+ nv_wr32(dev, NV10_PGRAPH_RDI_DATA, tile->zcomp); -+ } - } - - int -@@ -560,6 +579,13 @@ - - 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); - -@@ -571,16 +597,17 @@ - nv_wr32(dev, 0x40009C , 0x00000040); - - if (dev_priv->chipset >= 0x25) { -- nv_wr32(dev, 0x400890, 0x00080000); -+ nv_wr32(dev, 0x400890, 0x00a8cfff); - nv_wr32(dev, 0x400610, 0x304B1FB6); -- nv_wr32(dev, 0x400B80, 0x18B82880); -+ nv_wr32(dev, 0x400B80, 0x1cbd3883); - nv_wr32(dev, 0x400B84, 0x44000000); - nv_wr32(dev, 0x400098, 0x40000080); - nv_wr32(dev, 0x400B88, 0x000000ff); -+ - } else { -- nv_wr32(dev, 0x400880, 0x00080000); /* 0x0008c7df */ -+ nv_wr32(dev, 0x400880, 0x0008c7df); - nv_wr32(dev, 0x400094, 0x00000005); -- nv_wr32(dev, 0x400B80, 0x45CAA208); /* 0x45eae20e */ -+ nv_wr32(dev, 0x400B80, 0x45eae20e); - nv_wr32(dev, 0x400B84, 0x24000000); - nv_wr32(dev, 0x400098, 0x00000040); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00E00038); -@@ -591,14 +618,8 @@ - - /* Turn all the tiling regions off. */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) -- nv20_graph_set_region_tiling(dev, i, 0, 0, 0); -+ nv20_graph_set_tile_region(dev, i); - -- for (i = 0; i < 8; i++) { -- nv_wr32(dev, 0x400980 + i * 4, nv_rd32(dev, 0x100300 + i * 4)); -- nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA0090 + i * 4); -- nv_wr32(dev, NV10_PGRAPH_RDI_DATA, -- nv_rd32(dev, 0x100300 + i * 4)); -- } - nv_wr32(dev, 0x4009a0, nv_rd32(dev, 0x100324)); - nv_wr32(dev, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); - nv_wr32(dev, NV10_PGRAPH_RDI_DATA, nv_rd32(dev, 0x100324)); -@@ -642,6 +663,9 @@ - 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); - } - -@@ -684,9 +708,16 @@ - 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->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); - -@@ -724,7 +755,7 @@ - - /* Turn all the tiling regions off. */ - for (i = 0; i < NV10_PFB_TILE__SIZE; i++) -- nv20_graph_set_region_tiling(dev, i, 0, 0, 0); -+ nv20_graph_set_tile_region(dev, i); - - nv_wr32(dev, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(dev, NV10_PGRAPH_STATE , 0xFFFFFFFF); -@@ -744,46 +775,125 @@ - return 0; - } - --struct nouveau_pgraph_object_class nv20_graph_grclass[] = { -- { 0x0030, false, NULL }, /* null */ -- { 0x0039, false, NULL }, /* m2mf */ -- { 0x004a, false, NULL }, /* gdirect */ -- { 0x009f, false, NULL }, /* imageblit (nv12) */ -- { 0x008a, false, NULL }, /* ifc */ -- { 0x0089, false, NULL }, /* sifm */ -- { 0x0062, false, NULL }, /* surf2d */ -- { 0x0043, false, NULL }, /* rop */ -- { 0x0012, false, NULL }, /* beta1 */ -- { 0x0072, false, NULL }, /* beta4 */ -- { 0x0019, false, NULL }, /* cliprect */ -- { 0x0044, false, NULL }, /* pattern */ -- { 0x009e, false, NULL }, /* swzsurf */ -- { 0x0096, false, NULL }, /* celcius */ -- { 0x0097, false, NULL }, /* kelvin (nv20) */ -- { 0x0597, false, NULL }, /* kelvin (nv25) */ -- {} --}; -- --struct nouveau_pgraph_object_class nv30_graph_grclass[] = { -- { 0x0030, false, NULL }, /* null */ -- { 0x0039, false, NULL }, /* m2mf */ -- { 0x004a, false, NULL }, /* gdirect */ -- { 0x009f, false, NULL }, /* imageblit (nv12) */ -- { 0x008a, false, NULL }, /* ifc */ -- { 0x038a, false, NULL }, /* ifc (nv30) */ -- { 0x0089, false, NULL }, /* sifm */ -- { 0x0389, false, NULL }, /* sifm (nv30) */ -- { 0x0062, false, NULL }, /* surf2d */ -- { 0x0362, false, NULL }, /* surf2d (nv30) */ -- { 0x0043, false, NULL }, /* rop */ -- { 0x0012, false, NULL }, /* beta1 */ -- { 0x0072, false, NULL }, /* beta4 */ -- { 0x0019, false, NULL }, /* cliprect */ -- { 0x0044, false, NULL }, /* pattern */ -- { 0x039e, false, NULL }, /* swzsurf */ -- { 0x0397, false, NULL }, /* rankine (nv30) */ -- { 0x0497, false, NULL }, /* rankine (nv35) */ -- { 0x0697, false, NULL }, /* rankine (nv34) */ -- {} --}; -+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) -+{ -+ 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; -+ return 0; -+} -+ -+static void -+nv20_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 & 0x01f00000) >> 20; -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 mthd = (addr & 0x00001ffc); -+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); -+ u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xfff; -+ u32 show = stat; -+ -+ if (stat & NV_PGRAPH_INTR_ERROR) { -+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { -+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) -+ show &= ~NV_PGRAPH_INTR_ERROR; -+ } -+ } -+ -+ 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(nv10_graph_intr, show); -+ printk(" nsource:"); -+ nouveau_bitfield_print(nv04_graph_nsource, nsource); -+ printk(" nstatus:"); -+ nouveau_bitfield_print(nv10_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); -+ } -+ } -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv30_fb.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv30_fb.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv30_fb.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv30_fb.c 2011-01-07 14:22:17.000000000 +0100 -@@ -29,6 +29,27 @@ - #include "nouveau_drv.h" - #include "nouveau_drm.h" - -+void -+nv30_fb_init_tile_region(struct drm_device *dev, int i, uint32_t addr, -+ uint32_t size, uint32_t pitch, uint32_t flags) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; -+ -+ tile->addr = addr | 1; -+ tile->limit = max(1u, addr + size) - 1; -+ tile->pitch = pitch; -+} -+ -+void -+nv30_fb_free_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]; -+ -+ tile->addr = tile->limit = tile->pitch = 0; -+} -+ - static int - calc_bias(struct drm_device *dev, int k, int i, int j) - { -@@ -65,7 +86,7 @@ - - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) -- pfb->set_region_tiling(dev, i, 0, 0, 0); -+ pfb->set_tile_region(dev, i); - - /* Init the memory timing regs at 0x10037c/0x1003ac */ - if (dev_priv->chipset == 0x30 || -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv40_fb.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv40_fb.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv40_fb.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv40_fb.c 2011-01-07 14:22:17.000000000 +0100 -@@ -4,26 +4,22 @@ - #include "nouveau_drm.h" - - void --nv40_fb_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch) -+nv40_fb_set_tile_region(struct drm_device *dev, int i) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t limit = max(1u, addr + size) - 1; -- -- if (pitch) -- addr |= 1; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - switch (dev_priv->chipset) { - case 0x40: -- nv_wr32(dev, NV10_PFB_TLIMIT(i), limit); -- nv_wr32(dev, NV10_PFB_TSIZE(i), pitch); -- nv_wr32(dev, NV10_PFB_TILE(i), addr); -+ nv_wr32(dev, NV10_PFB_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV10_PFB_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV10_PFB_TILE(i), tile->addr); - break; - - default: -- nv_wr32(dev, NV40_PFB_TLIMIT(i), limit); -- nv_wr32(dev, NV40_PFB_TSIZE(i), pitch); -- nv_wr32(dev, NV40_PFB_TILE(i), addr); -+ nv_wr32(dev, NV40_PFB_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV40_PFB_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV40_PFB_TILE(i), tile->addr); - break; - } - } -@@ -64,7 +60,7 @@ - - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) -- pfb->set_region_tiling(dev, i, 0, 0, 0); -+ pfb->set_tile_region(dev, i); - - return 0; - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv40_fifo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv40_fifo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv40_fifo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv40_fifo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -47,6 +47,11 @@ - if (ret) - return ret; - -+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) + -+ NV40_USER(chan->id), PAGE_SIZE); -+ if (!chan->user) -+ return -ENOMEM; -+ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - - nv_wi32(dev, fc + 0, chan->pushbuf_base); -@@ -59,7 +64,6 @@ - NV_PFIFO_CACHE1_BIG_ENDIAN | - #endif - 0x30000000 /* no idea.. */); -- nv_wi32(dev, fc + 56, chan->ramin_grctx->pinst >> 4); - nv_wi32(dev, fc + 60, 0x0001FFFF); - - /* enable the fifo dma operation */ -@@ -70,17 +74,6 @@ - return 0; - } - --void --nv40_fifo_destroy_context(struct nouveau_channel *chan) --{ -- struct drm_device *dev = chan->dev; -- -- nv_wr32(dev, NV04_PFIFO_MODE, -- nv_rd32(dev, NV04_PFIFO_MODE) & ~(1 << chan->id)); -- -- nouveau_gpuobj_ref(NULL, &chan->ramfc); --} -- - static void - nv40_fifo_do_load_context(struct drm_device *dev, int chid) - { -@@ -279,6 +272,7 @@ - static void - nv40_fifo_init_intr(struct drm_device *dev) - { -+ nouveau_irq_register(dev, 8, nv04_fifo_isr); - nv_wr32(dev, 0x002100, 0xffffffff); - nv_wr32(dev, 0x002140, 0xffffffff); - } -@@ -301,7 +295,7 @@ - pfifo->reassign(dev, true); - - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- if (dev_priv->fifos[i]) { -+ if (dev_priv->channels.ptr[i]) { - uint32_t mode = nv_rd32(dev, NV04_PFIFO_MODE); - nv_wr32(dev, NV04_PFIFO_MODE, mode | (1 << i)); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv40_graph.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv40_graph.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv40_graph.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv40_graph.c 2011-01-07 14:22:17.000000000 +0100 -@@ -29,6 +29,9 @@ - #include "nouveau_drv.h" - #include "nouveau_grctx.h" - -+static int nv40_graph_register(struct drm_device *); -+static void nv40_graph_isr(struct drm_device *); -+ - struct nouveau_channel * - nv40_graph_channel(struct drm_device *dev) - { -@@ -42,7 +45,7 @@ - inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4; - - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- struct nouveau_channel *chan = dev_priv->fifos[i]; -+ struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - - if (chan && chan->ramin_grctx && - chan->ramin_grctx->pinst == inst) -@@ -59,6 +62,7 @@ - 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, -@@ -73,12 +77,39 @@ - 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); - } - -@@ -174,43 +205,39 @@ - } - - void --nv40_graph_set_region_tiling(struct drm_device *dev, int i, uint32_t addr, -- uint32_t size, uint32_t pitch) -+nv40_graph_set_tile_region(struct drm_device *dev, int i) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t limit = max(1u, addr + size) - 1; -- -- if (pitch) -- addr |= 1; -+ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; - - switch (dev_priv->chipset) { - case 0x44: - case 0x4a: - case 0x4e: -- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); -- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); -- nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); -+ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); - break; - - case 0x46: - case 0x47: - case 0x49: - case 0x4b: -- nv_wr32(dev, NV47_PGRAPH_TSIZE(i), pitch); -- nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), limit); -- nv_wr32(dev, NV47_PGRAPH_TILE(i), addr); -- nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); -- nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); -- nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); -+ nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); -+ nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); -+ nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); -+ nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); - break; - - default: -- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), pitch); -- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), limit); -- nv_wr32(dev, NV20_PGRAPH_TILE(i), addr); -- nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), pitch); -- nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), limit); -- nv_wr32(dev, NV40_PGRAPH_TILE1(i), addr); -+ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); -+ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); -+ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); -+ nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); -+ nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); -+ nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); - break; - } - } -@@ -232,7 +259,7 @@ - struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; - struct nouveau_grctx ctx = {}; - uint32_t vramsz, *cp; -- int i, j; -+ int ret, i, j; - - nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & - ~NV_PMC_ENABLE_PGRAPH); -@@ -256,9 +283,14 @@ - - 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); - -@@ -347,7 +379,7 @@ - - /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->num_tiles; i++) -- nv40_graph_set_region_tiling(dev, i, 0, 0, 0); -+ nv40_graph_set_tile_region(dev, i); - - /* begin RAM config */ - vramsz = pci_resource_len(dev->pdev, 0) - 1; -@@ -390,26 +422,111 @@ - - void nv40_graph_takedown(struct drm_device *dev) - { -+ nouveau_irq_unregister(dev, 12); -+} -+ -+static int -+nv40_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, 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 (dev_priv->chipset >= 0x60 || -+ 0x00005450 & (1 << (dev_priv->chipset & 0x0f))) -+ 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; -+ return 0; -+} -+ -+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; -+ 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) -+ continue; -+ -+ if (inst == chan->ramin_grctx->pinst) -+ break; -+ } -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ return i; - } - --struct nouveau_pgraph_object_class nv40_graph_grclass[] = { -- { 0x0030, false, NULL }, /* null */ -- { 0x0039, false, NULL }, /* m2mf */ -- { 0x004a, false, NULL }, /* gdirect */ -- { 0x009f, false, NULL }, /* imageblit (nv12) */ -- { 0x008a, false, NULL }, /* ifc */ -- { 0x0089, false, NULL }, /* sifm */ -- { 0x3089, false, NULL }, /* sifm (nv40) */ -- { 0x0062, false, NULL }, /* surf2d */ -- { 0x3062, false, NULL }, /* surf2d (nv40) */ -- { 0x0043, false, NULL }, /* rop */ -- { 0x0012, false, NULL }, /* beta1 */ -- { 0x0072, false, NULL }, /* beta4 */ -- { 0x0019, false, NULL }, /* cliprect */ -- { 0x0044, false, NULL }, /* pattern */ -- { 0x309e, false, NULL }, /* swzsurf */ -- { 0x4097, false, NULL }, /* curie (nv40) */ -- { 0x4497, false, NULL }, /* curie (nv44) */ -- {} --}; -+static void -+nv40_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 inst = (nv_rd32(dev, 0x40032c) & 0x000fffff) << 4; -+ u32 chid = nv40_graph_isr_chid(dev, inst); -+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 mthd = (addr & 0x00001ffc); -+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); -+ u32 class = nv_rd32(dev, 0x400160 + subc * 4) & 0xffff; -+ u32 show = stat; -+ -+ if (stat & NV_PGRAPH_INTR_ERROR) { -+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { -+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) -+ show &= ~NV_PGRAPH_INTR_ERROR; -+ } else -+ if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { -+ nv_mask(dev, 0x402000, 0, 0); -+ } -+ } -+ -+ 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(nv10_graph_intr, show); -+ printk(" nsource:"); -+ nouveau_bitfield_print(nv04_graph_nsource, nsource); -+ printk(" nstatus:"); -+ nouveau_bitfield_print(nv10_graph_nstatus, nstatus); -+ printk("\n"); -+ NV_INFO(dev, "PGRAPH - ch %d (0x%08x) subc %d " -+ "class 0x%04x mthd 0x%04x data 0x%08x\n", -+ chid, inst, subc, class, mthd, data); -+ } -+ } -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_crtc.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_crtc.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_crtc.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-01-07 14:22:17.000000000 +0100 -@@ -115,15 +115,16 @@ - OUT_RING(evo, 0); - BEGIN_RING(evo, 0, NV50_EVO_CRTC(index, FB_DMA), 1); - if (dev_priv->chipset != 0x50) -- if (nv_crtc->fb.tile_flags == 0x7a00) -+ if (nv_crtc->fb.tile_flags == 0x7a00 || -+ nv_crtc->fb.tile_flags == 0xfe00) - OUT_RING(evo, NvEvoFB32); - else - if (nv_crtc->fb.tile_flags == 0x7000) - OUT_RING(evo, NvEvoFB16); - else -- OUT_RING(evo, NvEvoVRAM); -+ OUT_RING(evo, NvEvoVRAM_LP); - else -- OUT_RING(evo, NvEvoVRAM); -+ OUT_RING(evo, NvEvoVRAM_LP); - } - - nv_crtc->fb.blanked = blanked; -@@ -345,7 +346,6 @@ - uint32_t buffer_handle, uint32_t width, uint32_t height) - { - struct drm_device *dev = crtc->dev; -- struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nouveau_bo *cursor = NULL; - struct drm_gem_object *gem; -@@ -374,8 +374,7 @@ - - nouveau_bo_unmap(cursor); - -- nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset - -- dev_priv->vm_vram_base); -+ nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT); - nv_crtc->cursor.show(nv_crtc, true); - - out: -@@ -437,6 +436,7 @@ - .cursor_move = nv50_crtc_cursor_move, - .gamma_set = nv50_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, -+ .page_flip = nouveau_crtc_page_flip, - .destroy = nv50_crtc_destroy, - }; - -@@ -453,6 +453,7 @@ - - NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); - -+ drm_vblank_pre_modeset(dev, nv_crtc->index); - nv50_crtc_blank(nv_crtc, true); - } - -@@ -468,6 +469,7 @@ - NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); - - nv50_crtc_blank(nv_crtc, false); -+ drm_vblank_post_modeset(dev, nv_crtc->index); - - ret = RING_SPACE(evo, 2); - if (ret) { -@@ -545,7 +547,7 @@ - return -EINVAL; - } - -- nv_crtc->fb.offset = fb->nvbo->bo.offset - dev_priv->vm_vram_base; -+ nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT; - nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); - nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; - if (!nv_crtc->fb.blanked && dev_priv->chipset != 0x50) { -@@ -554,13 +556,14 @@ - return ret; - - BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1); -- if (nv_crtc->fb.tile_flags == 0x7a00) -+ if (nv_crtc->fb.tile_flags == 0x7a00 || -+ nv_crtc->fb.tile_flags == 0xfe00) - OUT_RING(evo, NvEvoFB32); - else - if (nv_crtc->fb.tile_flags == 0x7000) - OUT_RING(evo, NvEvoFB16); - else -- OUT_RING(evo, NvEvoVRAM); -+ OUT_RING(evo, NvEvoVRAM_LP); - } - - ret = RING_SPACE(evo, 12); -@@ -574,8 +577,10 @@ - if (!nv_crtc->fb.tile_flags) { - OUT_RING(evo, drm_fb->pitch | (1 << 20)); - } else { -- OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | -- fb->nvbo->tile_mode); -+ u32 tile_mode = fb->nvbo->tile_mode; -+ if (dev_priv->card_type >= NV_C0) -+ tile_mode >>= 4; -+ OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | tile_mode); - } - if (dev_priv->chipset == 0x50) - OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_display.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_display.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_display.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_display.c 2011-01-07 14:22:17.000000000 +0100 -@@ -33,6 +33,8 @@ - #include "nouveau_ramht.h" - #include "drm_crtc_helper.h" - -+static void nv50_display_isr(struct drm_device *); -+ - static inline int - nv50_sor_nr(struct drm_device *dev) - { -@@ -46,159 +48,6 @@ - return 4; - } - --static void --nv50_evo_channel_del(struct nouveau_channel **pchan) --{ -- struct nouveau_channel *chan = *pchan; -- -- if (!chan) -- return; -- *pchan = NULL; -- -- nouveau_gpuobj_channel_takedown(chan); -- nouveau_bo_unmap(chan->pushbuf_bo); -- nouveau_bo_ref(NULL, &chan->pushbuf_bo); -- -- if (chan->user) -- iounmap(chan->user); -- -- kfree(chan); --} -- --static int --nv50_evo_dmaobj_new(struct nouveau_channel *evo, uint32_t class, uint32_t name, -- uint32_t tile_flags, uint32_t magic_flags, -- uint32_t offset, uint32_t limit) --{ -- struct drm_nouveau_private *dev_priv = evo->dev->dev_private; -- struct drm_device *dev = evo->dev; -- struct nouveau_gpuobj *obj = NULL; -- int ret; -- -- ret = nouveau_gpuobj_new(dev, evo, 6*4, 32, 0, &obj); -- if (ret) -- return ret; -- obj->engine = NVOBJ_ENGINE_DISPLAY; -- -- nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); -- nv_wo32(obj, 4, limit); -- nv_wo32(obj, 8, offset); -- nv_wo32(obj, 12, 0x00000000); -- nv_wo32(obj, 16, 0x00000000); -- if (dev_priv->card_type < NV_C0) -- nv_wo32(obj, 20, 0x00010000); -- else -- nv_wo32(obj, 20, 0x00020000); -- dev_priv->engine.instmem.flush(dev); -- -- ret = nouveau_ramht_insert(evo, name, obj); -- nouveau_gpuobj_ref(NULL, &obj); -- if (ret) { -- return ret; -- } -- -- return 0; --} -- --static int --nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pchan) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_gpuobj *ramht = NULL; -- struct nouveau_channel *chan; -- int ret; -- -- chan = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); -- if (!chan) -- return -ENOMEM; -- *pchan = chan; -- -- chan->id = -1; -- chan->dev = dev; -- chan->user_get = 4; -- chan->user_put = 0; -- -- ret = nouveau_gpuobj_new(dev, NULL, 32768, 0x1000, -- NVOBJ_FLAG_ZERO_ALLOC, &chan->ramin); -- if (ret) { -- NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- ret = drm_mm_init(&chan->ramin_heap, 0, 32768); -- if (ret) { -- NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- ret = nouveau_gpuobj_new(dev, chan, 4096, 16, 0, &ramht); -- if (ret) { -- NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- ret = nouveau_ramht_new(dev, ramht, &chan->ramht); -- nouveau_gpuobj_ref(NULL, &ramht); -- if (ret) { -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- if (dev_priv->chipset != 0x50) { -- ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB16, 0x70, 0x19, -- 0, 0xffffffff); -- if (ret) { -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- -- ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoFB32, 0x7a, 0x19, -- 0, 0xffffffff); -- if (ret) { -- nv50_evo_channel_del(pchan); -- return ret; -- } -- } -- -- ret = nv50_evo_dmaobj_new(chan, 0x3d, NvEvoVRAM, 0, 0x19, -- 0, dev_priv->vram_size); -- if (ret) { -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, -- false, true, &chan->pushbuf_bo); -- if (ret == 0) -- ret = nouveau_bo_pin(chan->pushbuf_bo, TTM_PL_FLAG_VRAM); -- if (ret) { -- NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret); -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- ret = nouveau_bo_map(chan->pushbuf_bo); -- if (ret) { -- NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret); -- nv50_evo_channel_del(pchan); -- return ret; -- } -- -- chan->user = ioremap(pci_resource_start(dev->pdev, 0) + -- NV50_PDISPLAY_USER(0), PAGE_SIZE); -- if (!chan->user) { -- NV_ERROR(dev, "Error mapping EVO control regs.\n"); -- nv50_evo_channel_del(pchan); -- return -ENOMEM; -- } -- -- return 0; --} -- - int - nv50_display_early_init(struct drm_device *dev) - { -@@ -214,17 +63,16 @@ - nv50_display_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; - struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -- struct nouveau_channel *evo = dev_priv->evo; - struct drm_connector *connector; -- uint32_t val, ram_amount; -- uint64_t start; -+ struct nouveau_channel *evo; - int ret, i; -+ u32 val; - - NV_DEBUG_KMS(dev, "\n"); - - nv_wr32(dev, 0x00610184, nv_rd32(dev, 0x00614004)); -+ - /* - * I think the 0x006101XX range is some kind of main control area - * that enables things. -@@ -240,16 +88,19 @@ - val = nv_rd32(dev, 0x0061610c + (i * 0x800)); - nv_wr32(dev, 0x0061019c + (i * 0x10), val); - } -+ - /* DAC */ - for (i = 0; i < 3; i++) { - val = nv_rd32(dev, 0x0061a000 + (i * 0x800)); - nv_wr32(dev, 0x006101d0 + (i * 0x04), val); - } -+ - /* SOR */ - for (i = 0; i < nv50_sor_nr(dev); i++) { - val = nv_rd32(dev, 0x0061c000 + (i * 0x800)); - nv_wr32(dev, 0x006101e0 + (i * 0x04), val); - } -+ - /* EXT */ - for (i = 0; i < 3; i++) { - val = nv_rd32(dev, 0x0061e000 + (i * 0x800)); -@@ -262,17 +113,6 @@ - nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL1(i), 0x00000001); - } - -- /* This used to be in crtc unblank, but seems out of place there. */ -- nv_wr32(dev, NV50_PDISPLAY_UNK_380, 0); -- /* RAM is clamped to 256 MiB. */ -- ram_amount = dev_priv->vram_size; -- NV_DEBUG_KMS(dev, "ram_amount %d\n", ram_amount); -- if (ram_amount > 256*1024*1024) -- ram_amount = 256*1024*1024; -- nv_wr32(dev, NV50_PDISPLAY_RAM_AMOUNT, ram_amount - 1); -- nv_wr32(dev, NV50_PDISPLAY_UNK_388, 0x150000); -- nv_wr32(dev, NV50_PDISPLAY_UNK_38C, 0); -- - /* The precise purpose is unknown, i suspect it has something to do - * with text mode. - */ -@@ -287,37 +127,6 @@ - } - } - -- /* taken from nv bug #12637, attempts to un-wedge the hw if it's -- * stuck in some unspecified state -- */ -- start = ptimer->read(dev); -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x2b00); -- while ((val = nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))) & 0x1e0000) { -- if ((val & 0x9f0000) == 0x20000) -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), -- val | 0x800000); -- -- if ((val & 0x3f0000) == 0x30000) -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), -- val | 0x200000); -- -- if (ptimer->read(dev) - start > 1000000000ULL) { -- NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) != 0\n"); -- NV_ERROR(dev, "0x610200 = 0x%08x\n", val); -- return -EBUSY; -- } -- } -- -- nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, NV50_PDISPLAY_CTRL_STATE_ENABLE); -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1000b03); -- if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), -- 0x40000000, 0x40000000)) { -- NV_ERROR(dev, "timeout: (0x610200 & 0x40000000) == 0x40000000\n"); -- NV_ERROR(dev, "0x610200 = 0x%08x\n", -- nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); -- return -EBUSY; -- } -- - for (i = 0; i < 2; i++) { - nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0x2000); - if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), -@@ -341,39 +150,31 @@ - } - } - -- nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); -+ nv_wr32(dev, NV50_PDISPLAY_PIO_CTRL, 0x00000000); -+ nv_mask(dev, NV50_PDISPLAY_INTR_0, 0x00000000, 0x00000000); -+ nv_wr32(dev, NV50_PDISPLAY_INTR_EN_0, 0x00000000); -+ nv_mask(dev, NV50_PDISPLAY_INTR_1, 0x00000000, 0x00000000); -+ nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, -+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK10 | -+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK20 | -+ NV50_PDISPLAY_INTR_EN_1_CLK_UNK40); -+ -+ /* enable hotplug interrupts */ -+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -+ struct nouveau_connector *conn = nouveau_connector(connector); - -- /* initialise fifo */ -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_DMA_CB(0), -- ((evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT) >> 8) | -- NV50_PDISPLAY_CHANNEL_DMA_CB_LOCATION_VRAM | -- NV50_PDISPLAY_CHANNEL_DMA_CB_VALID); -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK2(0), 0x00010000); -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_UNK3(0), 0x00000002); -- if (!nv_wait(dev, 0x610200, 0x80000000, 0x00000000)) { -- NV_ERROR(dev, "timeout: (0x610200 & 0x80000000) == 0\n"); -- NV_ERROR(dev, "0x610200 = 0x%08x\n", nv_rd32(dev, 0x610200)); -- return -EBUSY; -- } -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), -- (nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0)) & ~0x00000003) | -- NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); -- nv_wr32(dev, NV50_PDISPLAY_USER_PUT(0), 0); -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x01000003 | -- NV50_PDISPLAY_CHANNEL_STAT_DMA_ENABLED); -- nv_wr32(dev, 0x610300, nv_rd32(dev, 0x610300) & ~1); -- -- evo->dma.max = (4096/4) - 2; -- evo->dma.put = 0; -- evo->dma.cur = evo->dma.put; -- evo->dma.free = evo->dma.max - evo->dma.cur; -+ if (conn->dcb->gpio_tag == 0xff) -+ continue; - -- ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS); -+ pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); -+ } -+ -+ ret = nv50_evo_init(dev); - if (ret) - return ret; -+ evo = dev_priv->evo; - -- for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) -- OUT_RING(evo, 0); -+ nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); - - ret = RING_SPACE(evo, 11); - if (ret) -@@ -393,21 +194,6 @@ - if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) - NV_ERROR(dev, "evo pushbuf stalled\n"); - -- /* enable clock change interrupts. */ -- nv_wr32(dev, 0x610028, 0x00010001); -- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, (NV50_PDISPLAY_INTR_EN_CLK_UNK10 | -- NV50_PDISPLAY_INTR_EN_CLK_UNK20 | -- NV50_PDISPLAY_INTR_EN_CLK_UNK40)); -- -- /* enable hotplug interrupts */ -- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -- struct nouveau_connector *conn = nouveau_connector(connector); -- -- if (conn->dcb->gpio_tag == 0xff) -- continue; -- -- pgpio->irq_enable(dev, conn->dcb->gpio_tag, true); -- } - - return 0; - } -@@ -452,13 +238,7 @@ - } - } - -- nv_wr32(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0); -- nv_wr32(dev, NV50_PDISPLAY_CTRL_STATE, 0); -- if (!nv_wait(dev, NV50_PDISPLAY_CHANNEL_STAT(0), 0x1e0000, 0)) { -- NV_ERROR(dev, "timeout: (0x610200 & 0x1e0000) == 0\n"); -- NV_ERROR(dev, "0x610200 = 0x%08x\n", -- nv_rd32(dev, NV50_PDISPLAY_CHANNEL_STAT(0))); -- } -+ nv50_evo_fini(dev); - - for (i = 0; i < 3; i++) { - if (!nv_wait(dev, NV50_PDISPLAY_SOR_DPMS_STATE(i), -@@ -470,7 +250,7 @@ - } - - /* disable interrupts. */ -- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, 0x00000000); -+ nv_wr32(dev, NV50_PDISPLAY_INTR_EN_1, 0x00000000); - - /* disable hotplug interrupts */ - nv_wr32(dev, 0xe054, 0xffffffff); -@@ -508,13 +288,6 @@ - - dev->mode_config.fb_base = dev_priv->fb_phys; - -- /* Create EVO channel */ -- ret = nv50_evo_channel_new(dev, &dev_priv->evo); -- if (ret) { -- NV_ERROR(dev, "Error creating EVO channel: %d\n", ret); -- return ret; -- } -- - /* Create CRTC objects */ - for (i = 0; i < 2; i++) - nv50_crtc_create(dev, i); -@@ -557,6 +330,9 @@ - } - } - -+ INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); -+ nouveau_irq_register(dev, 26, nv50_display_isr); -+ - ret = nv50_display_init(dev); - if (ret) { - nv50_display_destroy(dev); -@@ -569,14 +345,12 @@ - void - nv50_display_destroy(struct drm_device *dev) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- - NV_DEBUG_KMS(dev, "\n"); - - drm_mode_config_cleanup(dev); - - nv50_display_disable(dev); -- nv50_evo_channel_del(&dev_priv->evo); -+ nouveau_irq_unregister(dev, 26); - } - - static u16 -@@ -660,32 +434,32 @@ - nv50_display_vblank_crtc_handler(struct drm_device *dev, int crtc) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_channel *chan; -- struct list_head *entry, *tmp; -+ struct nouveau_channel *chan, *tmp; - -- list_for_each_safe(entry, tmp, &dev_priv->vbl_waiting) { -- chan = list_entry(entry, struct nouveau_channel, nvsw.vbl_wait); -+ list_for_each_entry_safe(chan, tmp, &dev_priv->vbl_waiting, -+ nvsw.vbl_wait) { -+ if (chan->nvsw.vblsem_head != crtc) -+ continue; - - nouveau_bo_wr32(chan->notifier_bo, chan->nvsw.vblsem_offset, - chan->nvsw.vblsem_rval); - list_del(&chan->nvsw.vbl_wait); -+ drm_vblank_put(dev, crtc); - } -+ -+ drm_handle_vblank(dev, crtc); - } - - static void - nv50_display_vblank_handler(struct drm_device *dev, uint32_t intr) - { -- intr &= NV50_PDISPLAY_INTR_1_VBLANK_CRTC; -- - if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_0) - nv50_display_vblank_crtc_handler(dev, 0); - - if (intr & NV50_PDISPLAY_INTR_1_VBLANK_CRTC_1) - nv50_display_vblank_crtc_handler(dev, 1); - -- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev, -- NV50_PDISPLAY_INTR_EN) & ~intr); -- nv_wr32(dev, NV50_PDISPLAY_INTR_1, intr); -+ nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_VBLANK_CRTC); - } - - static void -@@ -1011,108 +785,31 @@ - static void - nv50_display_error_handler(struct drm_device *dev) - { -- uint32_t addr, data; -- -- nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000); -- addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR); -- data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA); -- -- NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x (0x%04x 0x%02x)\n", -- 0, addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf); -- -- nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR, 0x90000000); --} -- --void --nv50_display_irq_hotplug_bh(struct work_struct *work) --{ -- struct drm_nouveau_private *dev_priv = -- container_of(work, struct drm_nouveau_private, hpd_work); -- struct drm_device *dev = dev_priv->dev; -- struct drm_connector *connector; -- const uint32_t gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 }; -- uint32_t unplug_mask, plug_mask, change_mask; -- uint32_t hpd0, hpd1; -- -- spin_lock_irq(&dev_priv->hpd_state.lock); -- hpd0 = dev_priv->hpd_state.hpd0_bits; -- dev_priv->hpd_state.hpd0_bits = 0; -- hpd1 = dev_priv->hpd_state.hpd1_bits; -- dev_priv->hpd_state.hpd1_bits = 0; -- spin_unlock_irq(&dev_priv->hpd_state.lock); -- -- hpd0 &= nv_rd32(dev, 0xe050); -- if (dev_priv->chipset >= 0x90) -- hpd1 &= nv_rd32(dev, 0xe070); -- -- plug_mask = (hpd0 & 0x0000ffff) | (hpd1 << 16); -- unplug_mask = (hpd0 >> 16) | (hpd1 & 0xffff0000); -- change_mask = plug_mask | unplug_mask; -- -- list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -- struct drm_encoder_helper_funcs *helper; -- struct nouveau_connector *nv_connector = -- nouveau_connector(connector); -- struct nouveau_encoder *nv_encoder; -- struct dcb_gpio_entry *gpio; -- uint32_t reg; -- bool plugged; -- -- if (!nv_connector->dcb) -- continue; -- -- gpio = nouveau_bios_gpio_entry(dev, nv_connector->dcb->gpio_tag); -- if (!gpio || !(change_mask & (1 << gpio->line))) -- continue; -+ u32 channels = (nv_rd32(dev, NV50_PDISPLAY_INTR_0) & 0x001f0000) >> 16; -+ u32 addr, data; -+ int chid; -+ -+ for (chid = 0; chid < 5; chid++) { -+ if (!(channels & (1 << chid))) -+ continue; -+ -+ nv_wr32(dev, NV50_PDISPLAY_INTR_0, 0x00010000 << chid); -+ addr = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid)); -+ data = nv_rd32(dev, NV50_PDISPLAY_TRAPPED_DATA(chid)); -+ NV_ERROR(dev, "EvoCh %d Mthd 0x%04x Data 0x%08x " -+ "(0x%04x 0x%02x)\n", chid, -+ addr & 0xffc, data, addr >> 16, (addr >> 12) & 0xf); - -- reg = nv_rd32(dev, gpio_reg[gpio->line >> 3]); -- plugged = !!(reg & (4 << ((gpio->line & 7) << 2))); -- NV_INFO(dev, "%splugged %s\n", plugged ? "" : "un", -- drm_get_connector_name(connector)) ; -- -- if (!connector->encoder || !connector->encoder->crtc || -- !connector->encoder->crtc->enabled) -- continue; -- nv_encoder = nouveau_encoder(connector->encoder); -- helper = connector->encoder->helper_private; -- -- if (nv_encoder->dcb->type != OUTPUT_DP) -- continue; -- -- if (plugged) -- helper->dpms(connector->encoder, DRM_MODE_DPMS_ON); -- else -- helper->dpms(connector->encoder, DRM_MODE_DPMS_OFF); -+ nv_wr32(dev, NV50_PDISPLAY_TRAPPED_ADDR(chid), 0x90000000); - } -- -- drm_helper_hpd_irq_event(dev); - } - --void --nv50_display_irq_handler(struct drm_device *dev) -+static void -+nv50_display_isr(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - uint32_t delayed = 0; - -- if (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_HOTPLUG) { -- uint32_t hpd0_bits, hpd1_bits = 0; -- -- hpd0_bits = nv_rd32(dev, 0xe054); -- nv_wr32(dev, 0xe054, hpd0_bits); -- -- if (dev_priv->chipset >= 0x90) { -- hpd1_bits = nv_rd32(dev, 0xe074); -- nv_wr32(dev, 0xe074, hpd1_bits); -- } -- -- spin_lock(&dev_priv->hpd_state.lock); -- dev_priv->hpd_state.hpd0_bits |= hpd0_bits; -- dev_priv->hpd_state.hpd1_bits |= hpd1_bits; -- spin_unlock(&dev_priv->hpd_state.lock); -- -- queue_work(dev_priv->wq, &dev_priv->hpd_work); -- } -- - while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { - uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); - uint32_t intr1 = nv_rd32(dev, NV50_PDISPLAY_INTR_1); -@@ -1123,9 +820,9 @@ - if (!intr0 && !(intr1 & ~delayed)) - break; - -- if (intr0 & 0x00010000) { -+ if (intr0 & 0x001f0000) { - nv50_display_error_handler(dev); -- intr0 &= ~0x00010000; -+ intr0 &= ~0x001f0000; - } - - if (intr1 & NV50_PDISPLAY_INTR_1_VBLANK_CRTC) { -@@ -1156,4 +853,3 @@ - } - } - } -- -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_display.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_display.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_display.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_display.h 2011-01-07 14:22:17.000000000 +0100 -@@ -35,9 +35,7 @@ - #include "nouveau_crtc.h" - #include "nv50_evo.h" - --void nv50_display_irq_handler(struct drm_device *dev); - void nv50_display_irq_handler_bh(struct work_struct *work); --void nv50_display_irq_hotplug_bh(struct work_struct *work); - int nv50_display_early_init(struct drm_device *dev); - void nv50_display_late_takedown(struct drm_device *dev); - int nv50_display_create(struct drm_device *dev); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_evo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_evo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_evo.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_evo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,345 @@ -+/* -+ * Copyright 2010 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_dma.h" -+#include "nouveau_ramht.h" -+ -+static void -+nv50_evo_channel_del(struct nouveau_channel **pevo) -+{ -+ struct drm_nouveau_private *dev_priv; -+ struct nouveau_channel *evo = *pevo; -+ -+ if (!evo) -+ return; -+ *pevo = NULL; -+ -+ dev_priv = evo->dev->dev_private; -+ dev_priv->evo_alloc &= ~(1 << evo->id); -+ -+ nouveau_gpuobj_channel_takedown(evo); -+ nouveau_bo_unmap(evo->pushbuf_bo); -+ nouveau_bo_ref(NULL, &evo->pushbuf_bo); -+ -+ if (evo->user) -+ iounmap(evo->user); -+ -+ kfree(evo); -+} -+ -+int -+nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, -+ u32 tile_flags, u32 magic_flags, u32 offset, u32 limit, -+ u32 flags5) -+{ -+ struct drm_nouveau_private *dev_priv = evo->dev->dev_private; -+ struct drm_device *dev = evo->dev; -+ struct nouveau_gpuobj *obj = NULL; -+ int ret; -+ -+ ret = nouveau_gpuobj_new(dev, dev_priv->evo, 6*4, 32, 0, &obj); -+ if (ret) -+ return ret; -+ obj->engine = NVOBJ_ENGINE_DISPLAY; -+ -+ nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); -+ nv_wo32(obj, 4, limit); -+ nv_wo32(obj, 8, offset); -+ nv_wo32(obj, 12, 0x00000000); -+ nv_wo32(obj, 16, 0x00000000); -+ nv_wo32(obj, 20, flags5); -+ dev_priv->engine.instmem.flush(dev); -+ -+ ret = nouveau_ramht_insert(evo, name, obj); -+ nouveau_gpuobj_ref(NULL, &obj); -+ if (ret) { -+ return ret; -+ } -+ -+ return 0; -+} -+ -+static int -+nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pevo) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *evo; -+ int ret; -+ -+ evo = kzalloc(sizeof(struct nouveau_channel), GFP_KERNEL); -+ if (!evo) -+ return -ENOMEM; -+ *pevo = evo; -+ -+ for (evo->id = 0; evo->id < 5; evo->id++) { -+ if (dev_priv->evo_alloc & (1 << evo->id)) -+ continue; -+ -+ dev_priv->evo_alloc |= (1 << evo->id); -+ break; -+ } -+ -+ if (evo->id == 5) { -+ kfree(evo); -+ return -ENODEV; -+ } -+ -+ evo->dev = dev; -+ evo->user_get = 4; -+ evo->user_put = 0; -+ -+ ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, -+ false, true, &evo->pushbuf_bo); -+ if (ret == 0) -+ ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM); -+ if (ret) { -+ NV_ERROR(dev, "Error creating EVO DMA push buffer: %d\n", ret); -+ nv50_evo_channel_del(pevo); -+ return ret; -+ } -+ -+ ret = nouveau_bo_map(evo->pushbuf_bo); -+ if (ret) { -+ NV_ERROR(dev, "Error mapping EVO DMA push buffer: %d\n", ret); -+ nv50_evo_channel_del(pevo); -+ return ret; -+ } -+ -+ evo->user = ioremap(pci_resource_start(dev->pdev, 0) + -+ NV50_PDISPLAY_USER(evo->id), PAGE_SIZE); -+ if (!evo->user) { -+ NV_ERROR(dev, "Error mapping EVO control regs.\n"); -+ nv50_evo_channel_del(pevo); -+ return -ENOMEM; -+ } -+ -+ /* bind primary evo channel's ramht to the channel */ -+ if (dev_priv->evo && evo != dev_priv->evo) -+ nouveau_ramht_ref(dev_priv->evo->ramht, &evo->ramht, NULL); -+ -+ return 0; -+} -+ -+static int -+nv50_evo_channel_init(struct nouveau_channel *evo) -+{ -+ struct drm_device *dev = evo->dev; -+ int id = evo->id, ret, i; -+ u64 pushbuf = evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT; -+ u32 tmp; -+ -+ tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)); -+ if ((tmp & 0x009f0000) == 0x00020000) -+ nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00800000); -+ -+ tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)); -+ if ((tmp & 0x003f0000) == 0x00030000) -+ nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), tmp | 0x00600000); -+ -+ /* initialise fifo */ -+ nv_wr32(dev, NV50_PDISPLAY_EVO_DMA_CB(id), pushbuf >> 8 | -+ NV50_PDISPLAY_EVO_DMA_CB_LOCATION_VRAM | -+ NV50_PDISPLAY_EVO_DMA_CB_VALID); -+ nv_wr32(dev, NV50_PDISPLAY_EVO_UNK2(id), 0x00010000); -+ nv_wr32(dev, NV50_PDISPLAY_EVO_HASH_TAG(id), id); -+ nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), NV50_PDISPLAY_EVO_CTRL_DMA, -+ NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); -+ -+ nv_wr32(dev, NV50_PDISPLAY_USER_PUT(id), 0x00000000); -+ nv_wr32(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x01000003 | -+ NV50_PDISPLAY_EVO_CTRL_DMA_ENABLED); -+ if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x80000000, 0x00000000)) { -+ NV_ERROR(dev, "EvoCh %d init timeout: 0x%08x\n", id, -+ nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); -+ return -EBUSY; -+ } -+ -+ /* enable error reporting on the channel */ -+ nv_mask(dev, 0x610028, 0x00000000, 0x00010001 << id); -+ -+ evo->dma.max = (4096/4) - 2; -+ evo->dma.put = 0; -+ evo->dma.cur = evo->dma.put; -+ evo->dma.free = evo->dma.max - evo->dma.cur; -+ -+ ret = RING_SPACE(evo, NOUVEAU_DMA_SKIPS); -+ if (ret) -+ return ret; -+ -+ for (i = 0; i < NOUVEAU_DMA_SKIPS; i++) -+ OUT_RING(evo, 0); -+ -+ return 0; -+} -+ -+static void -+nv50_evo_channel_fini(struct nouveau_channel *evo) -+{ -+ struct drm_device *dev = evo->dev; -+ int id = evo->id; -+ -+ nv_mask(dev, 0x610028, 0x00010001 << id, 0x00000000); -+ nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00001010, 0x00001000); -+ nv_wr32(dev, NV50_PDISPLAY_INTR_0, (1 << id)); -+ nv_mask(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x00000003, 0x00000000); -+ if (!nv_wait(dev, NV50_PDISPLAY_EVO_CTRL(id), 0x001e0000, 0x00000000)) { -+ NV_ERROR(dev, "EvoCh %d takedown timeout: 0x%08x\n", id, -+ nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id))); -+ } -+} -+ -+static int -+nv50_evo_create(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj *ramht = NULL; -+ struct nouveau_channel *evo; -+ int ret; -+ -+ /* create primary evo channel, the one we use for modesetting -+ * purporses -+ */ -+ ret = nv50_evo_channel_new(dev, &dev_priv->evo); -+ if (ret) -+ return ret; -+ evo = dev_priv->evo; -+ -+ /* setup object management on it, any other evo channel will -+ * use this also as there's no per-channel support on the -+ * hardware -+ */ -+ ret = nouveau_gpuobj_new(dev, NULL, 32768, 65536, -+ NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin); -+ if (ret) { -+ NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = drm_mm_init(&evo->ramin_heap, 0, 32768); -+ if (ret) { -+ NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = nouveau_gpuobj_new(dev, evo, 4096, 16, 0, &ramht); -+ if (ret) { -+ NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = nouveau_ramht_new(dev, ramht, &evo->ramht); -+ nouveau_gpuobj_ref(NULL, &ramht); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ /* create some default objects for the scanout memtypes we support */ -+ if (dev_priv->card_type >= NV_C0) { -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0xfe, 0x19, -+ 0, 0xffffffff, 0x00000000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, -+ 0, dev_priv->vram_size, 0x00020000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19, -+ 0, dev_priv->vram_size, 0x00000000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ } else -+ if (dev_priv->chipset != 0x50) { -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19, -+ 0, 0xffffffff, 0x00010000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0x7a, 0x19, -+ 0, 0xffffffff, 0x00010000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, -+ 0, dev_priv->vram_size, 0x00010000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ -+ ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19, -+ 0, dev_priv->vram_size, 0x00010000); -+ if (ret) { -+ nv50_evo_channel_del(&dev_priv->evo); -+ return ret; -+ } -+ } -+ -+ return 0; -+} -+ -+int -+nv50_evo_init(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int ret; -+ -+ if (!dev_priv->evo) { -+ ret = nv50_evo_create(dev); -+ if (ret) -+ return ret; -+ } -+ -+ return nv50_evo_channel_init(dev_priv->evo); -+} -+ -+void -+nv50_evo_fini(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ if (dev_priv->evo) { -+ nv50_evo_channel_fini(dev_priv->evo); -+ nv50_evo_channel_del(&dev_priv->evo); -+ } -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_evo.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_evo.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_evo.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_evo.h 2011-01-07 14:22:17.000000000 +0100 -@@ -24,6 +24,15 @@ - * - */ - -+#ifndef __NV50_EVO_H__ -+#define __NV50_EVO_H__ -+ -+int nv50_evo_init(struct drm_device *dev); -+void nv50_evo_fini(struct drm_device *dev); -+int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name, -+ u32 tile_flags, u32 magic_flags, -+ u32 offset, u32 limit); -+ - #define NV50_EVO_UPDATE 0x00000080 - #define NV50_EVO_UNK84 0x00000084 - #define NV50_EVO_UNK84_NOTIFY 0x40000000 -@@ -111,3 +120,4 @@ - #define NV50_EVO_CRTC_SCALE_RES1 0x000008d8 - #define NV50_EVO_CRTC_SCALE_RES2 0x000008dc - -+#endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_fb.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_fb.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_fb.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_fb.c 2011-01-07 14:22:17.000000000 +0100 -@@ -3,30 +3,75 @@ - #include "nouveau_drv.h" - #include "nouveau_drm.h" - -+struct nv50_fb_priv { -+ struct page *r100c08_page; -+ dma_addr_t r100c08; -+}; -+ -+static int -+nv50_fb_create(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nv50_fb_priv *priv; -+ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); -+ if (!priv->r100c08_page) { -+ kfree(priv); -+ return -ENOMEM; -+ } -+ -+ priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0, -+ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); -+ if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) { -+ __free_page(priv->r100c08_page); -+ kfree(priv); -+ return -EFAULT; -+ } -+ -+ dev_priv->engine.fb.priv = priv; -+ return 0; -+} -+ - int - nv50_fb_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nv50_fb_priv *priv; -+ int ret; -+ -+ if (!dev_priv->engine.fb.priv) { -+ ret = nv50_fb_create(dev); -+ if (ret) -+ return ret; -+ } -+ priv = dev_priv->engine.fb.priv; - - /* Not a clue what this is exactly. Without pointing it at a - * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) - * cause IOMMU "read from address 0" errors (rh#561267) - */ -- nv_wr32(dev, 0x100c08, dev_priv->gart_info.sg_dummy_bus >> 8); -+ nv_wr32(dev, 0x100c08, priv->r100c08 >> 8); - - /* This is needed to get meaningful information from 100c90 - * on traps. No idea what these values mean exactly. */ - switch (dev_priv->chipset) { - case 0x50: -- nv_wr32(dev, 0x100c90, 0x0707ff); -+ nv_wr32(dev, 0x100c90, 0x000707ff); - break; - case 0xa3: - case 0xa5: - case 0xa8: -- nv_wr32(dev, 0x100c90, 0x0d0fff); -+ nv_wr32(dev, 0x100c90, 0x000d0fff); -+ break; -+ case 0xaf: -+ nv_wr32(dev, 0x100c90, 0x089d1fff); - break; - default: -- nv_wr32(dev, 0x100c90, 0x1d07ff); -+ nv_wr32(dev, 0x100c90, 0x001d07ff); - break; - } - -@@ -36,12 +81,25 @@ - void - nv50_fb_takedown(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nv50_fb_priv *priv; -+ -+ priv = dev_priv->engine.fb.priv; -+ if (!priv) -+ return; -+ dev_priv->engine.fb.priv = NULL; -+ -+ pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE, -+ PCI_DMA_BIDIRECTIONAL); -+ __free_page(priv->r100c08_page); -+ kfree(priv); - } - - void - nv50_fb_vm_trap(struct drm_device *dev, int display, const char *name) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ unsigned long flags; - u32 trap[6], idx, chinst; - int i, ch; - -@@ -60,8 +118,10 @@ - return; - - chinst = (trap[2] << 16) | trap[1]; -+ -+ spin_lock_irqsave(&dev_priv->channels.lock, flags); - for (ch = 0; ch < dev_priv->engine.fifo.channels; ch++) { -- struct nouveau_channel *chan = dev_priv->fifos[ch]; -+ struct nouveau_channel *chan = dev_priv->channels.ptr[ch]; - - if (!chan || !chan->ramin) - continue; -@@ -69,6 +129,7 @@ - if (chinst == chan->ramin->vinst >> 12) - break; - } -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); - - NV_INFO(dev, "%s - VM: Trapped %s at %02x%04x%04x status %08x " - "channel %d (0x%08x)\n", -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_fbcon.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_fbcon.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_fbcon.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_fbcon.c 2011-01-07 14:22:17.000000000 +0100 -@@ -1,29 +1,46 @@ -+/* -+ * Copyright 2010 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_dma.h" - #include "nouveau_ramht.h" - #include "nouveau_fbcon.h" -+#include "nouveau_mm.h" - --void -+int - nv50_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) - { - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->channel; -+ int ret; - -- if (info->state != FBINFO_STATE_RUNNING) -- return; -- -- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && -- RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11)) { -- nouveau_fbcon_gpu_lockup(info); -- } -- -- if (info->flags & FBINFO_HWACCEL_DISABLED) { -- cfb_fillrect(info, rect); -- return; -- } -+ ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11); -+ if (ret) -+ return ret; - - if (rect->rop != ROP_COPY) { - BEGIN_RING(chan, NvSub2D, 0x02ac, 1); -@@ -45,27 +62,21 @@ - OUT_RING(chan, 3); - } - FIRE_RING(chan); -+ return 0; - } - --void -+int - nv50_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) - { - struct nouveau_fbdev *nfbdev = info->par; - struct drm_device *dev = nfbdev->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->channel; -+ int ret; - -- if (info->state != FBINFO_STATE_RUNNING) -- return; -- -- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 12)) { -- nouveau_fbcon_gpu_lockup(info); -- } -- -- if (info->flags & FBINFO_HWACCEL_DISABLED) { -- cfb_copyarea(info, region); -- return; -- } -+ ret = RING_SPACE(chan, 12); -+ if (ret) -+ return ret; - - BEGIN_RING(chan, NvSub2D, 0x0110, 1); - OUT_RING(chan, 0); -@@ -80,9 +91,10 @@ - OUT_RING(chan, 0); - OUT_RING(chan, region->sy); - FIRE_RING(chan); -+ return 0; - } - --void -+int - nv50_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) - { - struct nouveau_fbdev *nfbdev = info->par; -@@ -92,23 +104,14 @@ - uint32_t width, dwords, *data = (uint32_t *)image->data; - uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); - uint32_t *palette = info->pseudo_palette; -+ int ret; - -- if (info->state != FBINFO_STATE_RUNNING) -- return; -- -- if (image->depth != 1) { -- cfb_imageblit(info, image); -- return; -- } -+ if (image->depth != 1) -+ return -ENODEV; - -- if (!(info->flags & FBINFO_HWACCEL_DISABLED) && RING_SPACE(chan, 11)) { -- nouveau_fbcon_gpu_lockup(info); -- } -- -- if (info->flags & FBINFO_HWACCEL_DISABLED) { -- cfb_imageblit(info, image); -- return; -- } -+ ret = RING_SPACE(chan, 11); -+ if (ret) -+ return ret; - - width = ALIGN(image->width, 32); - dwords = (width * image->height) >> 5; -@@ -134,11 +137,9 @@ - while (dwords) { - int push = dwords > 2047 ? 2047 : dwords; - -- if (RING_SPACE(chan, push + 1)) { -- nouveau_fbcon_gpu_lockup(info); -- cfb_imageblit(info, image); -- return; -- } -+ ret = RING_SPACE(chan, push + 1); -+ if (ret) -+ return ret; - - dwords -= push; - -@@ -148,6 +149,7 @@ - } - - FIRE_RING(chan); -+ return 0; - } - - int -@@ -157,12 +159,9 @@ - struct drm_device *dev = nfbdev->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nouveau_channel *chan = dev_priv->channel; -- struct nouveau_gpuobj *eng2d = NULL; -- uint64_t fb; -+ struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo; - int ret, format; - -- fb = info->fix.smem_start - dev_priv->fb_phys + dev_priv->vm_vram_base; -- - switch (info->var.bits_per_pixel) { - case 8: - format = 0xf3; -@@ -190,12 +189,7 @@ - return -EINVAL; - } - -- ret = nouveau_gpuobj_gr_new(dev_priv->channel, 0x502d, &eng2d); -- if (ret) -- return ret; -- -- ret = nouveau_ramht_insert(dev_priv->channel, Nv2D, eng2d); -- nouveau_gpuobj_ref(NULL, &eng2d); -+ ret = nouveau_gpuobj_gr_new(dev_priv->channel, Nv2D, 0x502d); - if (ret) - return ret; - -@@ -253,8 +247,8 @@ - OUT_RING(chan, info->fix.line_length); - OUT_RING(chan, info->var.xres_virtual); - OUT_RING(chan, info->var.yres_virtual); -- OUT_RING(chan, upper_32_bits(fb)); -- OUT_RING(chan, lower_32_bits(fb)); -+ OUT_RING(chan, upper_32_bits(nvbo->vma.offset)); -+ OUT_RING(chan, lower_32_bits(nvbo->vma.offset)); - BEGIN_RING(chan, NvSub2D, 0x0230, 2); - OUT_RING(chan, format); - OUT_RING(chan, 1); -@@ -262,8 +256,8 @@ - OUT_RING(chan, info->fix.line_length); - OUT_RING(chan, info->var.xres_virtual); - OUT_RING(chan, info->var.yres_virtual); -- OUT_RING(chan, upper_32_bits(fb)); -- OUT_RING(chan, lower_32_bits(fb)); -+ OUT_RING(chan, upper_32_bits(nvbo->vma.offset)); -+ OUT_RING(chan, lower_32_bits(nvbo->vma.offset)); - - return 0; - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_fifo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_fifo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_fifo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_fifo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -28,6 +28,7 @@ - #include "drm.h" - #include "nouveau_drv.h" - #include "nouveau_ramht.h" -+#include "nouveau_vm.h" - - static void - nv50_fifo_playlist_update(struct drm_device *dev) -@@ -44,7 +45,8 @@ - - /* We never schedule channel 0 or 127 */ - for (i = 1, nr = 0; i < 127; i++) { -- if (dev_priv->fifos[i] && dev_priv->fifos[i]->ramfc) { -+ if (dev_priv->channels.ptr[i] && -+ dev_priv->channels.ptr[i]->ramfc) { - nv_wo32(cur, (nr * 4), i); - nr++; - } -@@ -60,7 +62,7 @@ - nv50_fifo_channel_enable(struct drm_device *dev, int channel) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_channel *chan = dev_priv->fifos[channel]; -+ struct nouveau_channel *chan = dev_priv->channels.ptr[channel]; - uint32_t inst; - - NV_DEBUG(dev, "ch%d\n", channel); -@@ -105,6 +107,7 @@ - { - NV_DEBUG(dev, "\n"); - -+ nouveau_irq_register(dev, 8, nv04_fifo_isr); - nv_wr32(dev, NV03_PFIFO_INTR_0, 0xFFFFFFFF); - nv_wr32(dev, NV03_PFIFO_INTR_EN_0, 0xFFFFFFFF); - } -@@ -118,7 +121,7 @@ - NV_DEBUG(dev, "\n"); - - for (i = 0; i < NV50_PFIFO_CTX_TABLE__SIZE; i++) { -- if (dev_priv->fifos[i]) -+ if (dev_priv->channels.ptr[i]) - nv50_fifo_channel_enable(dev, i); - else - nv50_fifo_channel_disable(dev, i); -@@ -206,6 +209,9 @@ - if (!pfifo->playlist[0]) - return; - -+ nv_wr32(dev, 0x2140, 0x00000000); -+ nouveau_irq_unregister(dev, 8); -+ - nouveau_gpuobj_ref(NULL, &pfifo->playlist[0]); - nouveau_gpuobj_ref(NULL, &pfifo->playlist[1]); - } -@@ -256,6 +262,11 @@ - } - ramfc = chan->ramfc; - -+ chan->user = ioremap(pci_resource_start(dev->pdev, 0) + -+ NV50_USER(chan->id), PAGE_SIZE); -+ if (!chan->user) -+ return -ENOMEM; -+ - spin_lock_irqsave(&dev_priv->context_switch_lock, flags); - - nv_wo32(ramfc, 0x48, chan->pushbuf->cinst >> 4); -@@ -291,10 +302,23 @@ - nv50_fifo_destroy_context(struct nouveau_channel *chan) - { - 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_gpuobj *ramfc = NULL; -+ unsigned long flags; - - NV_DEBUG(dev, "ch%d\n", chan->id); - -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ pfifo->reassign(dev, false); -+ -+ /* Unload the context if it's the currently active one */ -+ if (pfifo->channel_id(dev) == chan->id) { -+ pfifo->disable(dev); -+ pfifo->unload_context(dev); -+ pfifo->enable(dev); -+ } -+ - /* This will ensure the channel is seen as disabled. */ - nouveau_gpuobj_ref(chan->ramfc, &ramfc); - nouveau_gpuobj_ref(NULL, &chan->ramfc); -@@ -305,6 +329,14 @@ - nv50_fifo_channel_disable(dev, 127); - nv50_fifo_playlist_update(dev); - -+ pfifo->reassign(dev, true); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ -+ /* Free the channel resources */ -+ if (chan->user) { -+ iounmap(chan->user); -+ chan->user = NULL; -+ } - nouveau_gpuobj_ref(NULL, &ramfc); - nouveau_gpuobj_ref(NULL, &chan->cache); - } -@@ -392,7 +424,7 @@ - if (chid < 1 || chid >= dev_priv->engine.fifo.channels - 1) - return 0; - -- chan = dev_priv->fifos[chid]; -+ chan = dev_priv->channels.ptr[chid]; - if (!chan) { - NV_ERROR(dev, "Inactive channel on PFIFO: %d\n", chid); - return -EINVAL; -@@ -467,5 +499,5 @@ - void - nv50_fifo_tlb_flush(struct drm_device *dev) - { -- nv50_vm_flush(dev, 5); -+ nv50_vm_flush_engine(dev, 5); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_gpio.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_gpio.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_gpio.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_gpio.c 2011-01-07 14:22:17.000000000 +0100 -@@ -26,6 +26,28 @@ - #include "nouveau_drv.h" - #include "nouveau_hw.h" - -+#include "nv50_display.h" -+ -+static void nv50_gpio_isr(struct drm_device *dev); -+static void nv50_gpio_isr_bh(struct work_struct *work); -+ -+struct nv50_gpio_priv { -+ struct list_head handlers; -+ spinlock_t lock; -+}; -+ -+struct nv50_gpio_handler { -+ struct drm_device *dev; -+ struct list_head head; -+ struct work_struct work; -+ bool inhibit; -+ -+ struct dcb_gpio_entry *gpio; -+ -+ void (*handler)(void *data, int state); -+ void *data; -+}; -+ - static int - nv50_gpio_location(struct dcb_gpio_entry *gpio, uint32_t *reg, uint32_t *shift) - { -@@ -75,29 +97,123 @@ - return 0; - } - -+int -+nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, -+ void (*handler)(void *, int), void *data) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nv50_gpio_priv *priv = pgpio->priv; -+ struct nv50_gpio_handler *gpioh; -+ struct dcb_gpio_entry *gpio; -+ unsigned long flags; -+ -+ gpio = nouveau_bios_gpio_entry(dev, tag); -+ if (!gpio) -+ return -ENOENT; -+ -+ gpioh = kzalloc(sizeof(*gpioh), GFP_KERNEL); -+ if (!gpioh) -+ return -ENOMEM; -+ -+ INIT_WORK(&gpioh->work, nv50_gpio_isr_bh); -+ gpioh->dev = dev; -+ gpioh->gpio = gpio; -+ gpioh->handler = handler; -+ gpioh->data = data; -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ list_add(&gpioh->head, &priv->handlers); -+ spin_unlock_irqrestore(&priv->lock, flags); -+ return 0; -+} -+ - void --nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) -+nv50_gpio_irq_unregister(struct drm_device *dev, enum dcb_gpio_tag tag, -+ void (*handler)(void *, int), void *data) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nv50_gpio_priv *priv = pgpio->priv; -+ struct nv50_gpio_handler *gpioh, *tmp; - struct dcb_gpio_entry *gpio; -- u32 reg, mask; -+ unsigned long flags; - - gpio = nouveau_bios_gpio_entry(dev, tag); -- if (!gpio) { -- NV_ERROR(dev, "gpio tag 0x%02x not found\n", tag); -+ if (!gpio) - return; -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ list_for_each_entry_safe(gpioh, tmp, &priv->handlers, head) { -+ if (gpioh->gpio != gpio || -+ gpioh->handler != handler || -+ gpioh->data != data) -+ continue; -+ list_del(&gpioh->head); -+ kfree(gpioh); - } -+ spin_unlock_irqrestore(&priv->lock, flags); -+} -+ -+bool -+nv50_gpio_irq_enable(struct drm_device *dev, enum dcb_gpio_tag tag, bool on) -+{ -+ struct dcb_gpio_entry *gpio; -+ u32 reg, mask; -+ -+ gpio = nouveau_bios_gpio_entry(dev, tag); -+ if (!gpio) -+ return false; - - reg = gpio->line < 16 ? 0xe050 : 0xe070; - mask = 0x00010001 << (gpio->line & 0xf); - - nv_wr32(dev, reg + 4, mask); -- nv_mask(dev, reg + 0, mask, on ? mask : 0); -+ reg = nv_mask(dev, reg + 0, mask, on ? mask : 0); -+ return (reg & mask) == mask; -+} -+ -+static int -+nv50_gpio_create(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nv50_gpio_priv *priv; -+ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&priv->handlers); -+ spin_lock_init(&priv->lock); -+ pgpio->priv = priv; -+ return 0; -+} -+ -+static void -+nv50_gpio_destroy(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ -+ kfree(pgpio->priv); -+ pgpio->priv = NULL; - } - - int - nv50_gpio_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nv50_gpio_priv *priv; -+ int ret; -+ -+ if (!pgpio->priv) { -+ ret = nv50_gpio_create(dev); -+ if (ret) -+ return ret; -+ } -+ priv = pgpio->priv; - - /* disable, and ack any pending gpio interrupts */ - nv_wr32(dev, 0xe050, 0x00000000); -@@ -107,5 +223,77 @@ - nv_wr32(dev, 0xe074, 0xffffffff); - } - -+ nouveau_irq_register(dev, 21, nv50_gpio_isr); - return 0; - } -+ -+void -+nv50_gpio_fini(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ nv_wr32(dev, 0xe050, 0x00000000); -+ if (dev_priv->chipset >= 0x90) -+ nv_wr32(dev, 0xe070, 0x00000000); -+ nouveau_irq_unregister(dev, 21); -+ -+ nv50_gpio_destroy(dev); -+} -+ -+static void -+nv50_gpio_isr_bh(struct work_struct *work) -+{ -+ struct nv50_gpio_handler *gpioh = -+ container_of(work, struct nv50_gpio_handler, work); -+ struct drm_nouveau_private *dev_priv = gpioh->dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nv50_gpio_priv *priv = pgpio->priv; -+ unsigned long flags; -+ int state; -+ -+ state = pgpio->get(gpioh->dev, gpioh->gpio->tag); -+ if (state < 0) -+ return; -+ -+ gpioh->handler(gpioh->data, state); -+ -+ spin_lock_irqsave(&priv->lock, flags); -+ gpioh->inhibit = false; -+ spin_unlock_irqrestore(&priv->lock, flags); -+} -+ -+static void -+nv50_gpio_isr(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; -+ struct nv50_gpio_priv *priv = pgpio->priv; -+ struct nv50_gpio_handler *gpioh; -+ u32 intr0, intr1 = 0; -+ u32 hi, lo, ch; -+ -+ intr0 = nv_rd32(dev, 0xe054) & nv_rd32(dev, 0xe050); -+ if (dev_priv->chipset >= 0x90) -+ intr1 = nv_rd32(dev, 0xe074) & nv_rd32(dev, 0xe070); -+ -+ hi = (intr0 & 0x0000ffff) | (intr1 << 16); -+ lo = (intr0 >> 16) | (intr1 & 0xffff0000); -+ ch = hi | lo; -+ -+ nv_wr32(dev, 0xe054, intr0); -+ if (dev_priv->chipset >= 0x90) -+ nv_wr32(dev, 0xe074, intr1); -+ -+ spin_lock(&priv->lock); -+ list_for_each_entry(gpioh, &priv->handlers, head) { -+ if (!(ch & (1 << gpioh->gpio->line))) -+ continue; -+ -+ if (gpioh->inhibit) -+ continue; -+ gpioh->inhibit = true; -+ -+ queue_work(dev_priv->wq, &gpioh->work); -+ } -+ spin_unlock(&priv->lock); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_graph.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_graph.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_graph.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_graph.c 2011-01-07 14:22:17.000000000 +0100 -@@ -29,6 +29,12 @@ - #include "nouveau_drv.h" - #include "nouveau_ramht.h" - #include "nouveau_grctx.h" -+#include "nouveau_dma.h" -+#include "nouveau_vm.h" -+#include "nv50_evo.h" -+ -+static int nv50_graph_register(struct drm_device *); -+static void nv50_graph_isr(struct drm_device *); - - static void - nv50_graph_init_reset(struct drm_device *dev) -@@ -46,6 +52,7 @@ - { - 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); -@@ -145,12 +152,15 @@ - nv50_graph_init_reset(dev); - nv50_graph_init_regs__nv(dev); - nv50_graph_init_regs(dev); -- nv50_graph_init_intr(dev); - - ret = nv50_graph_init_ctxctl(dev); - if (ret) - return ret; - -+ ret = nv50_graph_register(dev); -+ if (ret) -+ return ret; -+ nv50_graph_init_intr(dev); - return 0; - } - -@@ -158,6 +168,8 @@ - nv50_graph_takedown(struct drm_device *dev) - { - NV_DEBUG(dev, "\n"); -+ nv_wr32(dev, 0x40013c, 0x00000000); -+ nouveau_irq_unregister(dev, 12); - } - - void -@@ -190,7 +202,7 @@ - inst = (inst & NV50_PGRAPH_CTXCTL_CUR_INSTANCE) << 12; - - for (i = 0; i < dev_priv->engine.fifo.channels; i++) { -- struct nouveau_channel *chan = dev_priv->fifos[i]; -+ struct nouveau_channel *chan = dev_priv->channels.ptr[i]; - - if (chan && chan->ramin && chan->ramin->vinst == inst) - return chan; -@@ -211,7 +223,7 @@ - - NV_DEBUG(dev, "ch%d\n", chan->id); - -- ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0x1000, -+ ret = nouveau_gpuobj_new(dev, chan, pgraph->grctx_size, 0, - NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_ZERO_FREE, &chan->ramin_grctx); - if (ret) -@@ -234,6 +246,7 @@ - nv_wo32(chan->ramin_grctx, 0x00000, chan->ramin->vinst >> 12); - - dev_priv->engine.instmem.flush(dev); -+ atomic_inc(&chan->vm->pgraph_refs); - return 0; - } - -@@ -242,18 +255,31 @@ - { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_pgraph_engine *pgraph = &dev_priv->engine.graph; - int i, hdr = (dev_priv->chipset == 0x50) ? 0x200 : 0x20; -+ unsigned long flags; - - NV_DEBUG(dev, "ch%d\n", chan->id); - - if (!chan->ramin) - return; - -+ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); -+ pgraph->fifo_access(dev, false); -+ -+ if (pgraph->channel(dev) == chan) -+ pgraph->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); -+ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); -+ - nouveau_gpuobj_ref(NULL, &chan->ramin_grctx); -+ -+ atomic_dec(&chan->vm->pgraph_refs); - } - - static int -@@ -306,7 +332,7 @@ - return 0; - } - --void -+static void - nv50_graph_context_switch(struct drm_device *dev) - { - uint32_t inst; -@@ -322,8 +348,8 @@ - } - - static int --nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv50_graph_nvsw_dma_vblsem(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - struct nouveau_gpuobj *gpuobj; - -@@ -340,8 +366,8 @@ - } - - static int --nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv50_graph_nvsw_vblsem_offset(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - if (nouveau_notifier_offset(chan->nvsw.vblsem, &data)) - return -ERANGE; -@@ -351,16 +377,16 @@ - } - - static int --nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv50_graph_nvsw_vblsem_release_val(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - chan->nvsw.vblsem_rval = data; - return 0; - } - - static int --nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, int grclass, -- int mthd, uint32_t data) -+nv50_graph_nvsw_vblsem_release(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) - { - struct drm_device *dev = chan->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -@@ -368,45 +394,85 @@ - if (!chan->nvsw.vblsem || chan->nvsw.vblsem_offset == ~0 || data > 1) - return -EINVAL; - -- if (!(nv_rd32(dev, NV50_PDISPLAY_INTR_EN) & -- NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data))) { -- nv_wr32(dev, NV50_PDISPLAY_INTR_1, -- NV50_PDISPLAY_INTR_1_VBLANK_CRTC_(data)); -- nv_wr32(dev, NV50_PDISPLAY_INTR_EN, nv_rd32(dev, -- NV50_PDISPLAY_INTR_EN) | -- NV50_PDISPLAY_INTR_EN_VBLANK_CRTC_(data)); -- } -+ drm_vblank_get(dev, data); - -+ chan->nvsw.vblsem_head = data; - list_add(&chan->nvsw.vbl_wait, &dev_priv->vbl_waiting); -+ - return 0; - } - --static struct nouveau_pgraph_object_method nv50_graph_nvsw_methods[] = { -- { 0x018c, nv50_graph_nvsw_dma_vblsem }, -- { 0x0400, nv50_graph_nvsw_vblsem_offset }, -- { 0x0404, nv50_graph_nvsw_vblsem_release_val }, -- { 0x0408, nv50_graph_nvsw_vblsem_release }, -- {} --}; -+static int -+nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan, -+ u32 class, u32 mthd, u32 data) -+{ -+ struct nouveau_page_flip_state s; - --struct nouveau_pgraph_object_class nv50_graph_grclass[] = { -- { 0x506e, true, nv50_graph_nvsw_methods }, /* nvsw */ -- { 0x0030, false, NULL }, /* null */ -- { 0x5039, false, NULL }, /* m2mf */ -- { 0x502d, false, NULL }, /* 2d */ -- { 0x50c0, false, NULL }, /* compute */ -- { 0x85c0, false, NULL }, /* compute (nva3, nva5, nva8) */ -- { 0x5097, false, NULL }, /* tesla (nv50) */ -- { 0x8297, false, NULL }, /* tesla (nv8x/nv9x) */ -- { 0x8397, false, NULL }, /* tesla (nva0, nvaa, nvac) */ -- { 0x8597, false, NULL }, /* tesla (nva3, nva5, nva8) */ -- {} --}; -+ if (!nouveau_finish_page_flip(chan, &s)) { -+ /* XXX - Do something here */ -+ } -+ -+ 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) - { -- nv50_vm_flush(dev, 0); -+ nv50_vm_flush_engine(dev, 0); - } - - void -@@ -449,8 +515,535 @@ - nv_rd32(dev, 0x400384), nv_rd32(dev, 0x400388)); - } - -- nv50_vm_flush(dev, 0); -+ nv50_vm_flush_engine(dev, 0); - - nv_mask(dev, 0x400500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); - } -+ -+static struct nouveau_enum nv50_mp_exec_error_names[] = -+{ -+ { 3, "STACK_UNDERFLOW" }, -+ { 4, "QUADON_ACTIVE" }, -+ { 8, "TIMEOUT" }, -+ { 0x10, "INVALID_OPCODE" }, -+ { 0x40, "BREAKPOINT" }, -+ {} -+}; -+ -+static struct nouveau_bitfield nv50_graph_trap_m2mf[] = { -+ { 0x00000001, "NOTIFY" }, -+ { 0x00000002, "IN" }, -+ { 0x00000004, "OUT" }, -+ {} -+}; -+ -+static struct nouveau_bitfield nv50_graph_trap_vfetch[] = { -+ { 0x00000001, "FAULT" }, -+ {} -+}; -+ -+static struct nouveau_bitfield nv50_graph_trap_strmout[] = { -+ { 0x00000001, "FAULT" }, -+ {} -+}; -+ -+static struct nouveau_bitfield nv50_graph_trap_ccache[] = { -+ { 0x00000001, "FAULT" }, -+ {} -+}; -+ -+/* There must be a *lot* of these. Will take some time to gather them up. */ -+struct nouveau_enum nv50_data_error_names[] = { -+ { 0x00000003, "INVALID_QUERY_OR_TEXTURE" }, -+ { 0x00000004, "INVALID_VALUE" }, -+ { 0x00000005, "INVALID_ENUM" }, -+ { 0x00000008, "INVALID_OBJECT" }, -+ { 0x00000009, "READ_ONLY_OBJECT" }, -+ { 0x0000000a, "SUPERVISOR_OBJECT" }, -+ { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT" }, -+ { 0x0000000c, "INVALID_BITFIELD" }, -+ { 0x0000000d, "BEGIN_END_ACTIVE" }, -+ { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT" }, -+ { 0x0000000f, "VIEWPORT_ID_NEEDS_GP" }, -+ { 0x00000010, "RT_DOUBLE_BIND" }, -+ { 0x00000011, "RT_TYPES_MISMATCH" }, -+ { 0x00000012, "RT_LINEAR_WITH_ZETA" }, -+ { 0x00000015, "FP_TOO_FEW_REGS" }, -+ { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH" }, -+ { 0x00000017, "RT_LINEAR_WITH_MSAA" }, -+ { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT" }, -+ { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT" }, -+ { 0x0000001a, "RT_INVALID_ALIGNMENT" }, -+ { 0x0000001b, "SAMPLER_OVER_LIMIT" }, -+ { 0x0000001c, "TEXTURE_OVER_LIMIT" }, -+ { 0x0000001e, "GP_TOO_MANY_OUTPUTS" }, -+ { 0x0000001f, "RT_BPP128_WITH_MS8" }, -+ { 0x00000021, "Z_OUT_OF_BOUNDS" }, -+ { 0x00000023, "XY_OUT_OF_BOUNDS" }, -+ { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED" }, -+ { 0x00000028, "CP_NO_REG_SPACE_STRIPED" }, -+ { 0x00000029, "CP_NO_REG_SPACE_PACKED" }, -+ { 0x0000002a, "CP_NOT_ENOUGH_WARPS" }, -+ { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH" }, -+ { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS" }, -+ { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS" }, -+ { 0x0000002e, "CP_NO_BLOCKDIM_LATCH" }, -+ { 0x00000031, "ENG2D_FORMAT_MISMATCH" }, -+ { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP" }, -+ { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT" }, -+ { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT" }, -+ { 0x00000046, "LAYER_ID_NEEDS_GP" }, -+ { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT" }, -+ { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT" }, -+ {} -+}; -+ -+static struct nouveau_bitfield nv50_graph_intr[] = { -+ { 0x00000001, "NOTIFY" }, -+ { 0x00000002, "COMPUTE_QUERY" }, -+ { 0x00000010, "ILLEGAL_MTHD" }, -+ { 0x00000020, "ILLEGAL_CLASS" }, -+ { 0x00000040, "DOUBLE_NOTIFY" }, -+ { 0x00001000, "CONTEXT_SWITCH" }, -+ { 0x00010000, "BUFFER_NOTIFY" }, -+ { 0x00100000, "DATA_ERROR" }, -+ { 0x00200000, "TRAP" }, -+ { 0x01000000, "SINGLE_STEP" }, -+ {} -+}; -+ -+static void -+nv50_pgraph_mp_trap(struct drm_device *dev, int tpid, int display) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ uint32_t units = nv_rd32(dev, 0x1540); -+ uint32_t addr, mp10, status, pc, oplow, ophigh; -+ int i; -+ int mps = 0; -+ for (i = 0; i < 4; i++) { -+ if (!(units & 1 << (i+24))) -+ continue; -+ if (dev_priv->chipset < 0xa0) -+ addr = 0x408200 + (tpid << 12) + (i << 7); -+ else -+ addr = 0x408100 + (tpid << 11) + (i << 7); -+ mp10 = nv_rd32(dev, addr + 0x10); -+ status = nv_rd32(dev, addr + 0x14); -+ if (!status) -+ continue; -+ if (display) { -+ nv_rd32(dev, addr + 0x20); -+ pc = nv_rd32(dev, addr + 0x24); -+ oplow = nv_rd32(dev, addr + 0x70); -+ 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); -+ printk(" at %06x warp %d, opcode %08x %08x\n", -+ pc&0xffffff, pc >> 24, -+ oplow, ophigh); -+ } -+ nv_wr32(dev, addr + 0x10, mp10); -+ nv_wr32(dev, addr + 0x14, 0); -+ mps++; -+ } -+ if (!mps && display) -+ NV_INFO(dev, "PGRAPH_TRAP_MP_EXEC - TP %d: " -+ "No MPs claiming errors?\n", tpid); -+} -+ -+static void -+nv50_pgraph_tp_trap(struct drm_device *dev, int type, uint32_t ustatus_old, -+ uint32_t ustatus_new, int display, const char *name) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int tps = 0; -+ uint32_t units = nv_rd32(dev, 0x1540); -+ int i, r; -+ uint32_t ustatus_addr, ustatus; -+ for (i = 0; i < 16; i++) { -+ if (!(units & (1 << i))) -+ continue; -+ if (dev_priv->chipset < 0xa0) -+ ustatus_addr = ustatus_old + (i << 12); -+ else -+ ustatus_addr = ustatus_new + (i << 11); -+ ustatus = nv_rd32(dev, ustatus_addr) & 0x7fffffff; -+ if (!ustatus) -+ continue; -+ tps++; -+ switch (type) { -+ case 6: /* texture error... unknown for now */ -+ nv50_fb_vm_trap(dev, display, name); -+ if (display) { -+ NV_ERROR(dev, "magic set %d:\n", i); -+ for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) -+ NV_ERROR(dev, "\t0x%08x: 0x%08x\n", r, -+ nv_rd32(dev, r)); -+ } -+ break; -+ case 7: /* MP error */ -+ if (ustatus & 0x00010000) { -+ nv50_pgraph_mp_trap(dev, i, display); -+ ustatus &= ~0x00010000; -+ } -+ break; -+ case 8: /* TPDMA error */ -+ { -+ uint32_t e0c = nv_rd32(dev, ustatus_addr + 4); -+ uint32_t e10 = nv_rd32(dev, ustatus_addr + 8); -+ uint32_t e14 = nv_rd32(dev, ustatus_addr + 0xc); -+ uint32_t e18 = nv_rd32(dev, ustatus_addr + 0x10); -+ uint32_t e1c = nv_rd32(dev, ustatus_addr + 0x14); -+ uint32_t e20 = nv_rd32(dev, ustatus_addr + 0x18); -+ uint32_t e24 = nv_rd32(dev, ustatus_addr + 0x1c); -+ nv50_fb_vm_trap(dev, display, name); -+ /* 2d engine destination */ -+ if (ustatus & 0x00000010) { -+ if (display) { -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n", -+ i, e14, e10); -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", -+ i, e0c, e18, e1c, e20, e24); -+ } -+ ustatus &= ~0x00000010; -+ } -+ /* Render target */ -+ if (ustatus & 0x00000040) { -+ if (display) { -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n", -+ i, e14, e10); -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", -+ i, e0c, e18, e1c, e20, e24); -+ } -+ ustatus &= ~0x00000040; -+ } -+ /* CUDA memory: l[], g[] or stack. */ -+ if (ustatus & 0x00000080) { -+ if (display) { -+ if (e18 & 0x80000000) { -+ /* g[] read fault? */ -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n", -+ i, e14, e10 | ((e18 >> 24) & 0x1f)); -+ e18 &= ~0x1f000000; -+ } else if (e18 & 0xc) { -+ /* g[] write fault? */ -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n", -+ i, e14, e10 | ((e18 >> 7) & 0x1f)); -+ e18 &= ~0x00000f80; -+ } else { -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n", -+ i, e14, e10); -+ } -+ NV_INFO(dev, "PGRAPH_TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", -+ i, e0c, e18, e1c, e20, e24); -+ } -+ ustatus &= ~0x00000080; -+ } -+ } -+ break; -+ } -+ if (ustatus) { -+ if (display) -+ NV_INFO(dev, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); -+ } -+ nv_wr32(dev, ustatus_addr, 0xc0000000); -+ } -+ -+ if (!tps && display) -+ NV_INFO(dev, "%s - No TPs claiming errors?\n", name); -+} -+ -+static int -+nv50_pgraph_trap_handler(struct drm_device *dev, u32 display, u64 inst, u32 chid) -+{ -+ u32 status = nv_rd32(dev, 0x400108); -+ u32 ustatus; -+ -+ if (!status && display) { -+ NV_INFO(dev, "PGRAPH - TRAP: no units reporting traps?\n"); -+ return 1; -+ } -+ -+ /* DISPATCH: Relays commands to other units and handles NOTIFY, -+ * COND, QUERY. If you get a trap from it, the command is still stuck -+ * in DISPATCH and you need to do something about it. */ -+ if (status & 0x001) { -+ ustatus = nv_rd32(dev, 0x400804) & 0x7fffffff; -+ if (!ustatus && display) { -+ NV_INFO(dev, "PGRAPH_TRAP_DISPATCH - no ustatus?\n"); -+ } -+ -+ nv_wr32(dev, 0x400500, 0x00000000); -+ -+ /* Known to be triggered by screwed up NOTIFY and COND... */ -+ if (ustatus & 0x00000001) { -+ u32 addr = nv_rd32(dev, 0x400808); -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 mthd = (addr & 0x00001ffc); -+ u32 datal = nv_rd32(dev, 0x40080c); -+ u32 datah = nv_rd32(dev, 0x400810); -+ u32 class = nv_rd32(dev, 0x400814); -+ u32 r848 = nv_rd32(dev, 0x400848); -+ -+ NV_INFO(dev, "PGRAPH - TRAP DISPATCH_FAULT\n"); -+ if (display && (addr & 0x80000000)) { -+ NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " -+ "subc %d class 0x%04x mthd 0x%04x " -+ "data 0x%08x%08x " -+ "400808 0x%08x 400848 0x%08x\n", -+ chid, inst, subc, class, mthd, datah, -+ datal, addr, r848); -+ } else -+ if (display) { -+ NV_INFO(dev, "PGRAPH - no stuck command?\n"); -+ } -+ -+ nv_wr32(dev, 0x400808, 0); -+ nv_wr32(dev, 0x4008e8, nv_rd32(dev, 0x4008e8) & 3); -+ nv_wr32(dev, 0x400848, 0); -+ ustatus &= ~0x00000001; -+ } -+ -+ if (ustatus & 0x00000002) { -+ u32 addr = nv_rd32(dev, 0x40084c); -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 mthd = (addr & 0x00001ffc); -+ u32 data = nv_rd32(dev, 0x40085c); -+ u32 class = nv_rd32(dev, 0x400814); -+ -+ NV_INFO(dev, "PGRAPH - TRAP DISPATCH_QUERY\n"); -+ if (display && (addr & 0x80000000)) { -+ NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) " -+ "subc %d class 0x%04x mthd 0x%04x " -+ "data 0x%08x 40084c 0x%08x\n", -+ chid, inst, subc, class, mthd, -+ data, addr); -+ } else -+ if (display) { -+ NV_INFO(dev, "PGRAPH - no stuck command?\n"); -+ } -+ -+ nv_wr32(dev, 0x40084c, 0); -+ ustatus &= ~0x00000002; -+ } -+ -+ if (ustatus && display) { -+ NV_INFO(dev, "PGRAPH - TRAP_DISPATCH (unknown " -+ "0x%08x)\n", ustatus); -+ } -+ -+ nv_wr32(dev, 0x400804, 0xc0000000); -+ nv_wr32(dev, 0x400108, 0x001); -+ status &= ~0x001; -+ if (!status) -+ return 0; -+ } -+ -+ /* M2MF: Memory to memory copy engine. */ -+ if (status & 0x002) { -+ u32 ustatus = nv_rd32(dev, 0x406800) & 0x7fffffff; -+ if (display) { -+ NV_INFO(dev, "PGRAPH - TRAP_M2MF"); -+ nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus); -+ printk("\n"); -+ NV_INFO(dev, "PGRAPH - TRAP_M2MF %08x %08x %08x %08x\n", -+ nv_rd32(dev, 0x406804), nv_rd32(dev, 0x406808), -+ nv_rd32(dev, 0x40680c), nv_rd32(dev, 0x406810)); -+ -+ } -+ -+ /* No sane way found yet -- just reset the bugger. */ -+ nv_wr32(dev, 0x400040, 2); -+ nv_wr32(dev, 0x400040, 0); -+ nv_wr32(dev, 0x406800, 0xc0000000); -+ nv_wr32(dev, 0x400108, 0x002); -+ status &= ~0x002; -+ } -+ -+ /* VFETCH: Fetches data from vertex buffers. */ -+ if (status & 0x004) { -+ u32 ustatus = nv_rd32(dev, 0x400c04) & 0x7fffffff; -+ if (display) { -+ NV_INFO(dev, "PGRAPH - TRAP_VFETCH"); -+ nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus); -+ printk("\n"); -+ NV_INFO(dev, "PGRAPH - TRAP_VFETCH %08x %08x %08x %08x\n", -+ nv_rd32(dev, 0x400c00), nv_rd32(dev, 0x400c08), -+ nv_rd32(dev, 0x400c0c), nv_rd32(dev, 0x400c10)); -+ } -+ -+ nv_wr32(dev, 0x400c04, 0xc0000000); -+ nv_wr32(dev, 0x400108, 0x004); -+ status &= ~0x004; -+ } -+ -+ /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ -+ if (status & 0x008) { -+ ustatus = nv_rd32(dev, 0x401800) & 0x7fffffff; -+ if (display) { -+ NV_INFO(dev, "PGRAPH - TRAP_STRMOUT"); -+ nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus); -+ printk("\n"); -+ NV_INFO(dev, "PGRAPH - TRAP_STRMOUT %08x %08x %08x %08x\n", -+ nv_rd32(dev, 0x401804), nv_rd32(dev, 0x401808), -+ nv_rd32(dev, 0x40180c), nv_rd32(dev, 0x401810)); -+ -+ } -+ -+ /* No sane way found yet -- just reset the bugger. */ -+ nv_wr32(dev, 0x400040, 0x80); -+ nv_wr32(dev, 0x400040, 0); -+ nv_wr32(dev, 0x401800, 0xc0000000); -+ nv_wr32(dev, 0x400108, 0x008); -+ status &= ~0x008; -+ } -+ -+ /* CCACHE: Handles code and c[] caches and fills them. */ -+ if (status & 0x010) { -+ ustatus = nv_rd32(dev, 0x405018) & 0x7fffffff; -+ if (display) { -+ NV_INFO(dev, "PGRAPH - TRAP_CCACHE"); -+ nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus); -+ printk("\n"); -+ NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" -+ " %08x %08x %08x\n", -+ nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), -+ nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), -+ nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), -+ nv_rd32(dev, 0x40581c)); -+ -+ } -+ -+ nv_wr32(dev, 0x405018, 0xc0000000); -+ nv_wr32(dev, 0x400108, 0x010); -+ status &= ~0x010; -+ } -+ -+ /* Unknown, not seen yet... 0x402000 is the only trap status reg -+ * remaining, so try to handle it anyway. Perhaps related to that -+ * unknown DMA slot on tesla? */ -+ if (status & 0x20) { -+ ustatus = nv_rd32(dev, 0x402000) & 0x7fffffff; -+ if (display) -+ NV_INFO(dev, "PGRAPH - TRAP_UNKC04 0x%08x\n", ustatus); -+ nv_wr32(dev, 0x402000, 0xc0000000); -+ /* no status modifiction on purpose */ -+ } -+ -+ /* TEXTURE: CUDA texturing units */ -+ if (status & 0x040) { -+ nv50_pgraph_tp_trap(dev, 6, 0x408900, 0x408600, display, -+ "PGRAPH - TRAP_TEXTURE"); -+ nv_wr32(dev, 0x400108, 0x040); -+ status &= ~0x040; -+ } -+ -+ /* MP: CUDA execution engines. */ -+ if (status & 0x080) { -+ nv50_pgraph_tp_trap(dev, 7, 0x408314, 0x40831c, display, -+ "PGRAPH - TRAP_MP"); -+ nv_wr32(dev, 0x400108, 0x080); -+ status &= ~0x080; -+ } -+ -+ /* TPDMA: Handles TP-initiated uncached memory accesses: -+ * l[], g[], stack, 2d surfaces, render targets. */ -+ if (status & 0x100) { -+ nv50_pgraph_tp_trap(dev, 8, 0x408e08, 0x408708, display, -+ "PGRAPH - TRAP_TPDMA"); -+ nv_wr32(dev, 0x400108, 0x100); -+ status &= ~0x100; -+ } -+ -+ if (status) { -+ if (display) -+ NV_INFO(dev, "PGRAPH - TRAP: unknown 0x%08x\n", status); -+ nv_wr32(dev, 0x400108, status); -+ } -+ -+ return 1; -+} -+ -+static int -+nv50_graph_isr_chid(struct drm_device *dev, u64 inst) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan; -+ 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) -+ continue; -+ -+ if (inst == chan->ramin->vinst) -+ break; -+ } -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ return i; -+} -+ -+static void -+nv50_graph_isr(struct drm_device *dev) -+{ -+ u32 stat; -+ -+ while ((stat = nv_rd32(dev, 0x400100))) { -+ u64 inst = (u64)(nv_rd32(dev, 0x40032c) & 0x0fffffff) << 12; -+ u32 chid = nv50_graph_isr_chid(dev, inst); -+ u32 addr = nv_rd32(dev, NV04_PGRAPH_TRAPPED_ADDR); -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 mthd = (addr & 0x00001ffc); -+ u32 data = nv_rd32(dev, NV04_PGRAPH_TRAPPED_DATA); -+ u32 class = nv_rd32(dev, 0x400814); -+ u32 show = stat; -+ -+ if (stat & 0x00000010) { -+ if (!nouveau_gpuobj_mthd_call2(dev, chid, class, -+ mthd, data)) -+ show &= ~0x00000010; -+ } -+ -+ if (stat & 0x00001000) { -+ nv_wr32(dev, 0x400500, 0x00000000); -+ nv_wr32(dev, 0x400100, 0x00001000); -+ nv_mask(dev, 0x40013c, 0x00001000, 0x00000000); -+ nv50_graph_context_switch(dev); -+ stat &= ~0x00001000; -+ show &= ~0x00001000; -+ } -+ -+ show = (show && nouveau_ratelimit()) ? show : 0; -+ -+ if (show & 0x00100000) { -+ u32 ecode = nv_rd32(dev, 0x400110); -+ NV_INFO(dev, "PGRAPH - DATA_ERROR "); -+ nouveau_enum_print(nv50_data_error_names, ecode); -+ printk("\n"); -+ } -+ -+ if (stat & 0x00200000) { -+ if (!nv50_pgraph_trap_handler(dev, show, inst, chid)) -+ show &= ~0x00200000; -+ } -+ -+ nv_wr32(dev, 0x400100, stat); -+ nv_wr32(dev, 0x400500, 0x00010001); -+ -+ if (show) { -+ NV_INFO(dev, "PGRAPH -"); -+ nouveau_bitfield_print(nv50_graph_intr, show); -+ printk("\n"); -+ NV_INFO(dev, "PGRAPH - ch %d (0x%010llx) subc %d " -+ "class 0x%04x mthd 0x%04x data 0x%08x\n", -+ chid, inst, subc, class, mthd, data); -+ } -+ } -+ -+ if (nv_rd32(dev, 0x400824) & (1 << 31)) -+ nv_wr32(dev, 0x400824, nv_rd32(dev, 0x400824) & ~(1 << 31)); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_instmem.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_instmem.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_instmem.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_instmem.c 2011-01-07 14:22:17.000000000 +0100 -@@ -27,14 +27,20 @@ - - #include "drmP.h" - #include "drm.h" -+ - #include "nouveau_drv.h" -+#include "nouveau_vm.h" -+ -+#define BAR1_VM_BASE 0x0020000000ULL -+#define BAR1_VM_SIZE pci_resource_len(dev->pdev, 1) -+#define BAR3_VM_BASE 0x0000000000ULL -+#define BAR3_VM_SIZE pci_resource_len(dev->pdev, 3) - - struct nv50_instmem_priv { - uint32_t save1700[5]; /* 0x1700->0x1710 */ - -- struct nouveau_gpuobj *pramin_pt; -- struct nouveau_gpuobj *pramin_bar; -- struct nouveau_gpuobj *fb_bar; -+ struct nouveau_gpuobj *bar1_dmaobj; -+ struct nouveau_gpuobj *bar3_dmaobj; - }; - - static void -@@ -48,6 +54,7 @@ - return; - - nouveau_gpuobj_ref(NULL, &chan->ramfc); -+ nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); - nouveau_gpuobj_ref(NULL, &chan->vm_pd); - if (chan->ramin_heap.free_stack.next) - drm_mm_takedown(&chan->ramin_heap); -@@ -56,14 +63,14 @@ - } - - static int --nv50_channel_new(struct drm_device *dev, u32 size, -+nv50_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, - struct nouveau_channel **pchan) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - u32 pgd = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; - u32 fc = (dev_priv->chipset == 0x50) ? 0x0000 : 0x4200; - struct nouveau_channel *chan; -- int ret; -+ int ret, i; - - chan = kzalloc(sizeof(*chan), GFP_KERNEL); - if (!chan) -@@ -92,6 +99,17 @@ - return ret; - } - -+ for (i = 0; i < 0x4000; i += 8) { -+ nv_wo32(chan->vm_pd, i + 0, 0x00000000); -+ nv_wo32(chan->vm_pd, i + 4, 0xdeadcafe); -+ } -+ -+ ret = nouveau_vm_ref(vm, &chan->vm, chan->vm_pd); -+ if (ret) { -+ nv50_channel_del(&chan); -+ return ret; -+ } -+ - ret = nouveau_gpuobj_new_fake(dev, chan->ramin->pinst == ~0 ? ~0 : - chan->ramin->pinst + fc, - chan->ramin->vinst + fc, 0x100, -@@ -111,6 +129,7 @@ - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_instmem_priv *priv; - struct nouveau_channel *chan; -+ struct nouveau_vm *vm; - int ret, i; - u32 tmp; - -@@ -127,112 +146,87 @@ - ret = drm_mm_init(&dev_priv->ramin_heap, 0, dev_priv->ramin_size); - if (ret) { - NV_ERROR(dev, "Failed to init RAMIN heap\n"); -- return -ENOMEM; -+ goto error; - } - -- /* we need a channel to plug into the hw to control the BARs */ -- ret = nv50_channel_new(dev, 128*1024, &dev_priv->fifos[0]); -+ /* BAR3 */ -+ ret = nouveau_vm_new(dev, BAR3_VM_BASE, BAR3_VM_SIZE, BAR3_VM_BASE, -+ &dev_priv->bar3_vm); - if (ret) -- return ret; -- chan = dev_priv->fifos[127] = dev_priv->fifos[0]; -+ goto error; - -- /* allocate page table for PRAMIN BAR */ -- ret = nouveau_gpuobj_new(dev, chan, (dev_priv->ramin_size >> 12) * 8, -- 0x1000, NVOBJ_FLAG_ZERO_ALLOC, -- &priv->pramin_pt); -+ ret = nouveau_gpuobj_new(dev, NULL, (BAR3_VM_SIZE >> 12) * 8, -+ 0x1000, NVOBJ_FLAG_DONT_MAP | -+ NVOBJ_FLAG_ZERO_ALLOC, -+ &dev_priv->bar3_vm->pgt[0].obj[0]); - if (ret) -- return ret; -+ goto error; -+ dev_priv->bar3_vm->pgt[0].refcount[0] = 1; - -- nv_wo32(chan->vm_pd, 0x0000, priv->pramin_pt->vinst | 0x63); -- nv_wo32(chan->vm_pd, 0x0004, 0); -+ nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); - -- /* DMA object for PRAMIN BAR */ -- ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->pramin_bar); -+ ret = nv50_channel_new(dev, 128 * 1024, dev_priv->bar3_vm, &chan); - if (ret) -- return ret; -- nv_wo32(priv->pramin_bar, 0x00, 0x7fc00000); -- nv_wo32(priv->pramin_bar, 0x04, dev_priv->ramin_size - 1); -- nv_wo32(priv->pramin_bar, 0x08, 0x00000000); -- nv_wo32(priv->pramin_bar, 0x0c, 0x00000000); -- nv_wo32(priv->pramin_bar, 0x10, 0x00000000); -- nv_wo32(priv->pramin_bar, 0x14, 0x00000000); -+ goto error; -+ dev_priv->channels.ptr[0] = dev_priv->channels.ptr[127] = chan; - -- /* map channel into PRAMIN, gpuobj didn't do it for us */ -- ret = nv50_instmem_bind(dev, chan->ramin); -+ ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR3_VM_BASE, BAR3_VM_SIZE, -+ NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM, -+ NV_MEM_TYPE_VM, NV_MEM_COMP_VM, -+ &priv->bar3_dmaobj); - if (ret) -- return ret; -+ goto error; - -- /* poke regs... */ - nv_wr32(dev, 0x001704, 0x00000000 | (chan->ramin->vinst >> 12)); - nv_wr32(dev, 0x001704, 0x40000000 | (chan->ramin->vinst >> 12)); -- nv_wr32(dev, 0x00170c, 0x80000000 | (priv->pramin_bar->cinst >> 4)); -- -- tmp = nv_ri32(dev, 0); -- nv_wi32(dev, 0, ~tmp); -- if (nv_ri32(dev, 0) != ~tmp) { -- NV_ERROR(dev, "PRAMIN readback failed\n"); -- return -EIO; -- } -- nv_wi32(dev, 0, tmp); -+ nv_wr32(dev, 0x00170c, 0x80000000 | (priv->bar3_dmaobj->cinst >> 4)); - -+ dev_priv->engine.instmem.flush(dev); - dev_priv->ramin_available = true; - -- /* Determine VM layout */ -- dev_priv->vm_gart_base = roundup(NV50_VM_BLOCK, NV50_VM_BLOCK); -- dev_priv->vm_gart_size = NV50_VM_BLOCK; -- -- dev_priv->vm_vram_base = dev_priv->vm_gart_base + dev_priv->vm_gart_size; -- dev_priv->vm_vram_size = dev_priv->vram_size; -- if (dev_priv->vm_vram_size > NV50_VM_MAX_VRAM) -- dev_priv->vm_vram_size = NV50_VM_MAX_VRAM; -- dev_priv->vm_vram_size = roundup(dev_priv->vm_vram_size, NV50_VM_BLOCK); -- dev_priv->vm_vram_pt_nr = dev_priv->vm_vram_size / NV50_VM_BLOCK; -- -- dev_priv->vm_end = dev_priv->vm_vram_base + dev_priv->vm_vram_size; -- -- NV_DEBUG(dev, "NV50VM: GART 0x%016llx-0x%016llx\n", -- dev_priv->vm_gart_base, -- dev_priv->vm_gart_base + dev_priv->vm_gart_size - 1); -- NV_DEBUG(dev, "NV50VM: VRAM 0x%016llx-0x%016llx\n", -- dev_priv->vm_vram_base, -- dev_priv->vm_vram_base + dev_priv->vm_vram_size - 1); -- -- /* VRAM page table(s), mapped into VM at +1GiB */ -- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) { -- ret = nouveau_gpuobj_new(dev, NULL, NV50_VM_BLOCK / 0x10000 * 8, -- 0, NVOBJ_FLAG_ZERO_ALLOC, -- &chan->vm_vram_pt[i]); -- if (ret) { -- NV_ERROR(dev, "Error creating VRAM PGT: %d\n", ret); -- dev_priv->vm_vram_pt_nr = i; -- return ret; -- } -- dev_priv->vm_vram_pt[i] = chan->vm_vram_pt[i]; -- -- nv_wo32(chan->vm_pd, 0x10 + (i*8), -- chan->vm_vram_pt[i]->vinst | 0x61); -- nv_wo32(chan->vm_pd, 0x14 + (i*8), 0); -+ tmp = nv_ro32(chan->ramin, 0); -+ nv_wo32(chan->ramin, 0, ~tmp); -+ if (nv_ro32(chan->ramin, 0) != ~tmp) { -+ NV_ERROR(dev, "PRAMIN readback failed\n"); -+ ret = -EIO; -+ goto error; - } -+ nv_wo32(chan->ramin, 0, tmp); - -- /* DMA object for FB BAR */ -- ret = nouveau_gpuobj_new(dev, chan, 6*4, 16, 0, &priv->fb_bar); -+ /* BAR1 */ -+ ret = nouveau_vm_new(dev, BAR1_VM_BASE, BAR1_VM_SIZE, BAR1_VM_BASE, &vm); - if (ret) -- return ret; -- nv_wo32(priv->fb_bar, 0x00, 0x7fc00000); -- nv_wo32(priv->fb_bar, 0x04, 0x40000000 + -- pci_resource_len(dev->pdev, 1) - 1); -- nv_wo32(priv->fb_bar, 0x08, 0x40000000); -- nv_wo32(priv->fb_bar, 0x0c, 0x00000000); -- nv_wo32(priv->fb_bar, 0x10, 0x00000000); -- nv_wo32(priv->fb_bar, 0x14, 0x00000000); -+ goto error; - -- dev_priv->engine.instmem.flush(dev); -+ ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, chan->vm_pd); -+ if (ret) -+ goto error; -+ nouveau_vm_ref(NULL, &vm, NULL); -+ -+ ret = nv50_gpuobj_dma_new(chan, 0x0000, BAR1_VM_BASE, BAR1_VM_SIZE, -+ NV_MEM_TARGET_VM, NV_MEM_ACCESS_VM, -+ NV_MEM_TYPE_VM, NV_MEM_COMP_VM, -+ &priv->bar1_dmaobj); -+ if (ret) -+ goto error; - -- nv_wr32(dev, 0x001708, 0x80000000 | (priv->fb_bar->cinst >> 4)); -+ nv_wr32(dev, 0x001708, 0x80000000 | (priv->bar1_dmaobj->cinst >> 4)); - for (i = 0; i < 8; i++) - nv_wr32(dev, 0x1900 + (i*4), 0); - -+ /* Create shared channel VM, space is reserved at the beginning -+ * to catch "NULL pointer" references -+ */ -+ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL, -+ &dev_priv->chan_vm); -+ if (ret) -+ return ret; -+ - return 0; -+ -+error: -+ nv50_instmem_takedown(dev); -+ return ret; - } - - void -@@ -240,7 +234,7 @@ - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; -- struct nouveau_channel *chan = dev_priv->fifos[0]; -+ struct nouveau_channel *chan = dev_priv->channels.ptr[0]; - int i; - - NV_DEBUG(dev, "\n"); -@@ -250,23 +244,23 @@ - - dev_priv->ramin_available = false; - -- /* Restore state from before init */ -+ nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL); -+ - for (i = 0x1700; i <= 0x1710; i += 4) - nv_wr32(dev, i, priv->save1700[(i - 0x1700) / 4]); - -- nouveau_gpuobj_ref(NULL, &priv->fb_bar); -- nouveau_gpuobj_ref(NULL, &priv->pramin_bar); -- nouveau_gpuobj_ref(NULL, &priv->pramin_pt); -- -- /* Destroy dummy channel */ -- if (chan) { -- for (i = 0; i < dev_priv->vm_vram_pt_nr; i++) -- nouveau_gpuobj_ref(NULL, &chan->vm_vram_pt[i]); -- dev_priv->vm_vram_pt_nr = 0; -+ nouveau_gpuobj_ref(NULL, &priv->bar3_dmaobj); -+ nouveau_gpuobj_ref(NULL, &priv->bar1_dmaobj); - -- nv50_channel_del(&dev_priv->fifos[0]); -- dev_priv->fifos[127] = NULL; -- } -+ nouveau_vm_ref(NULL, &dev_priv->bar1_vm, chan->vm_pd); -+ dev_priv->channels.ptr[127] = 0; -+ nv50_channel_del(&dev_priv->channels.ptr[0]); -+ -+ nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); -+ nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); -+ -+ if (dev_priv->ramin_heap.free_stack.next) -+ drm_mm_takedown(&dev_priv->ramin_heap); - - dev_priv->engine.instmem.priv = NULL; - kfree(priv); -@@ -276,16 +270,8 @@ - nv50_instmem_suspend(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nouveau_channel *chan = dev_priv->fifos[0]; -- struct nouveau_gpuobj *ramin = chan->ramin; -- int i; - -- ramin->im_backing_suspend = vmalloc(ramin->size); -- if (!ramin->im_backing_suspend) -- return -ENOMEM; -- -- for (i = 0; i < ramin->size; i += 4) -- ramin->im_backing_suspend[i/4] = nv_ri32(dev, i); -+ dev_priv->ramin_available = false; - return 0; - } - -@@ -294,146 +280,121 @@ - { - struct drm_nouveau_private *dev_priv = dev->dev_private; - struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; -- struct nouveau_channel *chan = dev_priv->fifos[0]; -- struct nouveau_gpuobj *ramin = chan->ramin; -+ struct nouveau_channel *chan = dev_priv->channels.ptr[0]; - int i; - -- dev_priv->ramin_available = false; -- dev_priv->ramin_base = ~0; -- for (i = 0; i < ramin->size; i += 4) -- nv_wo32(ramin, i, ramin->im_backing_suspend[i/4]); -- dev_priv->ramin_available = true; -- vfree(ramin->im_backing_suspend); -- ramin->im_backing_suspend = NULL; -- - /* Poke the relevant regs, and pray it works :) */ - nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12)); - nv_wr32(dev, NV50_PUNK_UNK1710, 0); - nv_wr32(dev, NV50_PUNK_BAR_CFG_BASE, (chan->ramin->vinst >> 12) | - NV50_PUNK_BAR_CFG_BASE_VALID); -- nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->fb_bar->cinst >> 4) | -+ nv_wr32(dev, NV50_PUNK_BAR1_CTXDMA, (priv->bar1_dmaobj->cinst >> 4) | - NV50_PUNK_BAR1_CTXDMA_VALID); -- nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->pramin_bar->cinst >> 4) | -+ nv_wr32(dev, NV50_PUNK_BAR3_CTXDMA, (priv->bar3_dmaobj->cinst >> 4) | - NV50_PUNK_BAR3_CTXDMA_VALID); - - for (i = 0; i < 8; i++) - nv_wr32(dev, 0x1900 + (i*4), 0); -+ -+ dev_priv->ramin_available = true; - } - -+struct nv50_gpuobj_node { -+ struct nouveau_vram *vram; -+ struct nouveau_vma chan_vma; -+ u32 align; -+}; -+ -+ - int --nv50_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, -- uint32_t *sz) -+nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) - { -+ struct drm_device *dev = gpuobj->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; -+ struct nv50_gpuobj_node *node = NULL; - int ret; - -- if (gpuobj->im_backing) -- return -EINVAL; -+ node = kzalloc(sizeof(*node), GFP_KERNEL); -+ if (!node) -+ return -ENOMEM; -+ node->align = align; - -- *sz = ALIGN(*sz, 4096); -- if (*sz == 0) -- return -EINVAL; -+ size = (size + 4095) & ~4095; -+ align = max(align, (u32)4096); - -- ret = nouveau_bo_new(dev, NULL, *sz, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, -- true, false, &gpuobj->im_backing); -+ ret = vram->get(dev, size, align, 0, 0, &node->vram); - if (ret) { -- NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); -+ kfree(node); - return ret; - } - -- ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); -- if (ret) { -- NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); -- nouveau_bo_ref(NULL, &gpuobj->im_backing); -- return ret; -+ gpuobj->vinst = node->vram->offset; -+ -+ if (gpuobj->flags & NVOBJ_FLAG_VM) { -+ ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, -+ NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, -+ &node->chan_vma); -+ if (ret) { -+ vram->put(dev, &node->vram); -+ kfree(node); -+ return ret; -+ } -+ -+ nouveau_vm_map(&node->chan_vma, node->vram); -+ gpuobj->vinst = node->chan_vma.offset; - } - -- gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; -+ gpuobj->size = size; -+ gpuobj->node = node; - return 0; - } - - void --nv50_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+nv50_instmem_put(struct nouveau_gpuobj *gpuobj) - { -+ struct drm_device *dev = gpuobj->dev; - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; -+ struct nv50_gpuobj_node *node; -+ -+ node = gpuobj->node; -+ gpuobj->node = NULL; - -- if (gpuobj && gpuobj->im_backing) { -- if (gpuobj->im_bound) -- dev_priv->engine.instmem.unbind(dev, gpuobj); -- nouveau_bo_unpin(gpuobj->im_backing); -- nouveau_bo_ref(NULL, &gpuobj->im_backing); -- gpuobj->im_backing = NULL; -+ if (node->chan_vma.node) { -+ nouveau_vm_unmap(&node->chan_vma); -+ nouveau_vm_put(&node->chan_vma); - } -+ vram->put(dev, &node->vram); -+ kfree(node); - } - - int --nv50_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+nv50_instmem_map(struct nouveau_gpuobj *gpuobj) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; -- struct nouveau_gpuobj *pramin_pt = priv->pramin_pt; -- uint32_t pte, pte_end; -- uint64_t vram; -- -- if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) -- return -EINVAL; -- -- NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", -- gpuobj->im_pramin->start, gpuobj->im_pramin->size); -- -- pte = (gpuobj->im_pramin->start >> 12) << 1; -- pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; -- vram = gpuobj->vinst; -- -- NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", -- gpuobj->im_pramin->start, pte, pte_end); -- NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); -- -- vram |= 1; -- if (dev_priv->vram_sys_base) { -- vram += dev_priv->vram_sys_base; -- vram |= 0x30; -- } -- -- while (pte < pte_end) { -- nv_wo32(pramin_pt, (pte * 4) + 0, lower_32_bits(vram)); -- nv_wo32(pramin_pt, (pte * 4) + 4, upper_32_bits(vram)); -- vram += 0x1000; -- pte += 2; -- } -- dev_priv->engine.instmem.flush(dev); -+ struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; -+ struct nv50_gpuobj_node *node = gpuobj->node; -+ int ret; - -- nv50_vm_flush(dev, 6); -+ ret = nouveau_vm_get(dev_priv->bar3_vm, gpuobj->size, 12, -+ NV_MEM_ACCESS_RW, &node->vram->bar_vma); -+ if (ret) -+ return ret; - -- gpuobj->im_bound = 1; -+ nouveau_vm_map(&node->vram->bar_vma, node->vram); -+ gpuobj->pinst = node->vram->bar_vma.offset; - return 0; - } - --int --nv50_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+void -+nv50_instmem_unmap(struct nouveau_gpuobj *gpuobj) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- struct nv50_instmem_priv *priv = dev_priv->engine.instmem.priv; -- uint32_t pte, pte_end; -- -- if (gpuobj->im_bound == 0) -- return -EINVAL; -+ struct nv50_gpuobj_node *node = gpuobj->node; - -- /* can happen during late takedown */ -- if (unlikely(!dev_priv->ramin_available)) -- return 0; -- -- pte = (gpuobj->im_pramin->start >> 12) << 1; -- pte_end = ((gpuobj->im_pramin->size >> 12) << 1) + pte; -- -- while (pte < pte_end) { -- nv_wo32(priv->pramin_pt, (pte * 4) + 0, 0x00000000); -- nv_wo32(priv->pramin_pt, (pte * 4) + 4, 0x00000000); -- pte += 2; -+ if (node->vram->bar_vma.node) { -+ nouveau_vm_unmap(&node->vram->bar_vma); -+ nouveau_vm_put(&node->vram->bar_vma); - } -- dev_priv->engine.instmem.flush(dev); -- -- gpuobj->im_bound = 0; -- return 0; - } - - void -@@ -452,11 +413,3 @@ - NV_ERROR(dev, "PRAMIN flush timeout\n"); - } - --void --nv50_vm_flush(struct drm_device *dev, int engine) --{ -- nv_wr32(dev, 0x100c80, (engine << 16) | 1); -- if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) -- NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); --} -- -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_vm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_vm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_vm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_vm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,180 @@ -+/* -+ * Copyright 2010 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_vm.h" -+ -+void -+nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, -+ struct nouveau_gpuobj *pgt[2]) -+{ -+ struct drm_nouveau_private *dev_priv = pgd->dev->dev_private; -+ u64 phys = 0xdeadcafe00000000ULL; -+ u32 coverage = 0; -+ -+ if (pgt[0]) { -+ phys = 0x00000003 | pgt[0]->vinst; /* present, 4KiB pages */ -+ coverage = (pgt[0]->size >> 3) << 12; -+ } else -+ if (pgt[1]) { -+ phys = 0x00000001 | pgt[1]->vinst; /* present */ -+ coverage = (pgt[1]->size >> 3) << 16; -+ } -+ -+ if (phys & 1) { -+ if (dev_priv->vram_sys_base) { -+ phys += dev_priv->vram_sys_base; -+ phys |= 0x30; -+ } -+ -+ if (coverage <= 32 * 1024 * 1024) -+ phys |= 0x60; -+ else if (coverage <= 64 * 1024 * 1024) -+ phys |= 0x40; -+ else if (coverage < 128 * 1024 * 1024) -+ phys |= 0x20; -+ } -+ -+ nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); -+ nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); -+} -+ -+static inline u64 -+nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, -+ u64 phys, u32 memtype, u32 target) -+{ -+ struct drm_nouveau_private *dev_priv = pgt->dev->dev_private; -+ -+ phys |= 1; /* present */ -+ phys |= (u64)memtype << 40; -+ -+ /* IGPs don't have real VRAM, re-target to stolen system memory */ -+ if (target == 0 && dev_priv->vram_sys_base) { -+ phys += dev_priv->vram_sys_base; -+ target = 3; -+ } -+ -+ phys |= target << 4; -+ -+ if (vma->access & NV_MEM_ACCESS_SYS) -+ phys |= (1 << 6); -+ -+ if (!(vma->access & NV_MEM_ACCESS_WO)) -+ phys |= (1 << 3); -+ -+ return phys; -+} -+ -+void -+nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, -+ struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) -+{ -+ u32 block; -+ int i; -+ -+ phys = nv50_vm_addr(vma, pgt, phys, mem->memtype, 0); -+ pte <<= 3; -+ cnt <<= 3; -+ -+ while (cnt) { -+ u32 offset_h = upper_32_bits(phys); -+ u32 offset_l = lower_32_bits(phys); -+ -+ for (i = 7; i >= 0; i--) { -+ block = 1 << (i + 3); -+ if (cnt >= block && !(pte & (block - 1))) -+ break; -+ } -+ offset_l |= (i << 7); -+ -+ phys += block << (vma->node->type - 3); -+ cnt -= block; -+ -+ while (block) { -+ nv_wo32(pgt, pte + 0, offset_l); -+ nv_wo32(pgt, pte + 4, offset_h); -+ pte += 8; -+ block -= 8; -+ } -+ } -+} -+ -+void -+nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, -+ u32 pte, dma_addr_t *list, u32 cnt) -+{ -+ pte <<= 3; -+ while (cnt--) { -+ u64 phys = nv50_vm_addr(vma, pgt, (u64)*list++, 0, 2); -+ nv_wo32(pgt, pte + 0, lower_32_bits(phys)); -+ nv_wo32(pgt, pte + 4, upper_32_bits(phys)); -+ pte += 8; -+ } -+} -+ -+void -+nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) -+{ -+ pte <<= 3; -+ while (cnt--) { -+ nv_wo32(pgt, pte + 0, 0x00000000); -+ nv_wo32(pgt, pte + 4, 0x00000000); -+ pte += 8; -+ } -+} -+ -+void -+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; -+ -+ pinstmem->flush(vm->dev); -+ -+ /* BAR */ -+ if (vm != dev_priv->chan_vm) { -+ nv50_vm_flush_engine(vm->dev, 6); -+ return; -+ } -+ -+ 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); -+} -+ -+void -+nv50_vm_flush_engine(struct drm_device *dev, int engine) -+{ -+ nv_wr32(dev, 0x100c80, (engine << 16) | 1); -+ if (!nv_wait(dev, 0x100c80, 0x00000001, 0x00000000)) -+ NV_ERROR(dev, "vm flush timeout: engine %d\n", engine); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_vram.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_vram.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv50_vram.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv50_vram.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,190 @@ -+/* -+ * Copyright 2010 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_mm.h" -+ -+static int types[0x80] = { -+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, -+ 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0, -+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0, -+ 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, -+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2, -+ 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 -+}; -+ -+bool -+nv50_vram_flags_valid(struct drm_device *dev, u32 tile_flags) -+{ -+ int type = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8; -+ -+ if (likely(type < ARRAY_SIZE(types) && types[type])) -+ return true; -+ return false; -+} -+ -+void -+nv50_vram_del(struct drm_device *dev, struct nouveau_vram **pvram) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; -+ struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; -+ struct nouveau_mm *mm = man->priv; -+ struct nouveau_mm_node *this; -+ struct nouveau_vram *vram; -+ -+ vram = *pvram; -+ *pvram = NULL; -+ if (unlikely(vram == NULL)) -+ return; -+ -+ mutex_lock(&mm->mutex); -+ while (!list_empty(&vram->regions)) { -+ this = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); -+ -+ list_del(&this->rl_entry); -+ nouveau_mm_put(mm, this); -+ } -+ mutex_unlock(&mm->mutex); -+ -+ kfree(vram); -+} -+ -+int -+nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, -+ u32 type, struct nouveau_vram **pvram) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; -+ struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; -+ struct nouveau_mm *mm = man->priv; -+ struct nouveau_mm_node *r; -+ struct nouveau_vram *vram; -+ int ret; -+ -+ if (!types[type]) -+ return -EINVAL; -+ size >>= 12; -+ align >>= 12; -+ size_nc >>= 12; -+ -+ vram = kzalloc(sizeof(*vram), GFP_KERNEL); -+ if (!vram) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&vram->regions); -+ vram->dev = dev_priv->dev; -+ vram->memtype = type; -+ vram->size = size; -+ -+ mutex_lock(&mm->mutex); -+ do { -+ ret = nouveau_mm_get(mm, types[type], size, size_nc, align, &r); -+ if (ret) { -+ mutex_unlock(&mm->mutex); -+ nv50_vram_del(dev, &vram); -+ return ret; -+ } -+ -+ list_add_tail(&r->rl_entry, &vram->regions); -+ size -= r->length; -+ } while (size); -+ mutex_unlock(&mm->mutex); -+ -+ r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); -+ vram->offset = (u64)r->offset << 12; -+ *pvram = vram; -+ return 0; -+} -+ -+static u32 -+nv50_vram_rblock(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ int i, parts, colbits, rowbitsa, rowbitsb, banks; -+ u64 rowsize, predicted; -+ u32 r0, r4, rt, ru, rblock_size; -+ -+ r0 = nv_rd32(dev, 0x100200); -+ r4 = nv_rd32(dev, 0x100204); -+ rt = nv_rd32(dev, 0x100250); -+ ru = nv_rd32(dev, 0x001540); -+ NV_DEBUG(dev, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt, ru); -+ -+ for (i = 0, parts = 0; i < 8; i++) { -+ if (ru & (0x00010000 << i)) -+ parts++; -+ } -+ -+ colbits = (r4 & 0x0000f000) >> 12; -+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; -+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8; -+ banks = ((r4 & 0x01000000) ? 8 : 4); -+ -+ rowsize = parts * banks * (1 << colbits) * 8; -+ predicted = rowsize << rowbitsa; -+ if (r0 & 0x00000004) -+ predicted += rowsize << rowbitsb; -+ -+ if (predicted != dev_priv->vram_size) { -+ NV_WARN(dev, "memory controller reports %dMiB VRAM\n", -+ (u32)(dev_priv->vram_size >> 20)); -+ NV_WARN(dev, "we calculated %dMiB VRAM\n", -+ (u32)(predicted >> 20)); -+ } -+ -+ rblock_size = rowsize; -+ if (rt & 1) -+ rblock_size *= 3; -+ -+ NV_DEBUG(dev, "rblock %d bytes\n", rblock_size); -+ return rblock_size; -+} -+ -+int -+nv50_vram_init(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ dev_priv->vram_size = nv_rd32(dev, 0x10020c); -+ dev_priv->vram_size |= (dev_priv->vram_size & 0xff) << 32; -+ dev_priv->vram_size &= 0xffffffff00ULL; -+ -+ switch (dev_priv->chipset) { -+ case 0xaa: -+ case 0xac: -+ case 0xaf: -+ dev_priv->vram_sys_base = (u64)nv_rd32(dev, 0x100e10) << 12; -+ dev_priv->vram_rblock_size = 4096; -+ break; -+ default: -+ dev_priv->vram_rblock_size = nv50_vram_rblock(dev); -+ break; -+ } -+ -+ return 0; -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv84_crypt.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv84_crypt.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nv84_crypt.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nv84_crypt.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,140 @@ -+/* -+ * Copyright 2010 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_util.h" -+#include "nouveau_vm.h" -+ -+static void nv84_crypt_isr(struct drm_device *); -+ -+int -+nv84_crypt_create_context(struct nouveau_channel *chan) -+{ -+ struct drm_device *dev = chan->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_gpuobj *ramin = chan->ramin; -+ 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); -+ 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, 0xac, 0); -+ nv_wo32(ramin, 0xb0, 0); -+ nv_wo32(ramin, 0xb4, 0); -+ -+ dev_priv->engine.instmem.flush(dev); -+ atomic_inc(&chan->vm->pcrypt_refs); -+ return 0; -+} -+ -+void -+nv84_crypt_destroy_context(struct nouveau_channel *chan) -+{ -+ struct drm_device *dev = chan->dev; -+ u32 inst; -+ -+ if (!chan->crypt_ctx) -+ return; -+ -+ inst = (chan->ramin->vinst >> 12); -+ inst |= 0x80000000; -+ -+ /* mark context as invalid if still on the hardware, not -+ * doing this causes issues the next time PCRYPT is used, -+ * unsurprisingly :) -+ */ -+ nv_wr32(dev, 0x10200c, 0x00000000); -+ if (nv_rd32(dev, 0x102188) == inst) -+ nv_mask(dev, 0x102188, 0x80000000, 0x00000000); -+ if (nv_rd32(dev, 0x10218c) == inst) -+ nv_mask(dev, 0x10218c, 0x80000000, 0x00000000); -+ nv_wr32(dev, 0x10200c, 0x00000010); -+ -+ nouveau_gpuobj_ref(NULL, &chan->crypt_ctx); -+ atomic_dec(&chan->vm->pcrypt_refs); -+} -+ -+void -+nv84_crypt_tlb_flush(struct drm_device *dev) -+{ -+ nv50_vm_flush_engine(dev, 0x0a); -+} -+ -+int -+nv84_crypt_init(struct drm_device *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; -+ } -+ -+ nv_mask(dev, 0x000200, 0x00004000, 0x00000000); -+ nv_mask(dev, 0x000200, 0x00004000, 0x00004000); -+ -+ nouveau_irq_register(dev, 14, nv84_crypt_isr); -+ nv_wr32(dev, 0x102130, 0xffffffff); -+ nv_wr32(dev, 0x102140, 0xffffffbf); -+ -+ nv_wr32(dev, 0x10200c, 0x00000010); -+ return 0; -+} -+ -+void -+nv84_crypt_fini(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x102140, 0x00000000); -+ nouveau_irq_unregister(dev, 14); -+} -+ -+static void -+nv84_crypt_isr(struct drm_device *dev) -+{ -+ u32 stat = nv_rd32(dev, 0x102130); -+ u32 mthd = nv_rd32(dev, 0x102190); -+ u32 data = nv_rd32(dev, 0x102194); -+ u32 inst = nv_rd32(dev, 0x102188) & 0x7fffffff; -+ int show = nouveau_ratelimit(); -+ -+ if (show) { -+ NV_INFO(dev, "PCRYPT_INTR: 0x%08x 0x%08x 0x%08x 0x%08x\n", -+ stat, mthd, data, inst); -+ } -+ -+ nv_wr32(dev, 0x102130, stat); -+ nv_wr32(dev, 0x10200c, 0x10); -+ -+ nv50_fb_vm_trap(dev, show, "PCRYPT"); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_fbcon.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_fbcon.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_fbcon.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_fbcon.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,269 @@ -+/* -+ * Copyright 2010 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_dma.h" -+#include "nouveau_ramht.h" -+#include "nouveau_fbcon.h" -+#include "nouveau_mm.h" -+ -+int -+nvc0_fbcon_fillrect(struct fb_info *info, const struct fb_fillrect *rect) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan = dev_priv->channel; -+ int ret; -+ -+ ret = RING_SPACE(chan, rect->rop == ROP_COPY ? 7 : 11); -+ if (ret) -+ return ret; -+ -+ if (rect->rop != ROP_COPY) { -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); -+ OUT_RING (chan, 1); -+ } -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0588, 1); -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) -+ OUT_RING (chan, ((uint32_t *)info->pseudo_palette)[rect->color]); -+ else -+ OUT_RING (chan, rect->color); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0600, 4); -+ OUT_RING (chan, rect->dx); -+ OUT_RING (chan, rect->dy); -+ OUT_RING (chan, rect->dx + rect->width); -+ OUT_RING (chan, rect->dy + rect->height); -+ if (rect->rop != ROP_COPY) { -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); -+ OUT_RING (chan, 3); -+ } -+ FIRE_RING(chan); -+ return 0; -+} -+ -+int -+nvc0_fbcon_copyarea(struct fb_info *info, const struct fb_copyarea *region) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan = dev_priv->channel; -+ int ret; -+ -+ ret = RING_SPACE(chan, 12); -+ if (ret) -+ return ret; -+ -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0110, 1); -+ OUT_RING (chan, 0); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x08b0, 4); -+ OUT_RING (chan, region->dx); -+ OUT_RING (chan, region->dy); -+ OUT_RING (chan, region->width); -+ OUT_RING (chan, region->height); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x08d0, 4); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, region->sx); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, region->sy); -+ FIRE_RING(chan); -+ return 0; -+} -+ -+int -+nvc0_fbcon_imageblit(struct fb_info *info, const struct fb_image *image) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan = dev_priv->channel; -+ uint32_t width, dwords, *data = (uint32_t *)image->data; -+ uint32_t mask = ~(~0 >> (32 - info->var.bits_per_pixel)); -+ uint32_t *palette = info->pseudo_palette; -+ int ret; -+ -+ if (image->depth != 1) -+ return -ENODEV; -+ -+ ret = RING_SPACE(chan, 11); -+ if (ret) -+ return ret; -+ -+ width = ALIGN(image->width, 32); -+ dwords = (width * image->height) >> 5; -+ -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0814, 2); -+ if (info->fix.visual == FB_VISUAL_TRUECOLOR || -+ info->fix.visual == FB_VISUAL_DIRECTCOLOR) { -+ OUT_RING (chan, palette[image->bg_color] | mask); -+ OUT_RING (chan, palette[image->fg_color] | mask); -+ } else { -+ OUT_RING (chan, image->bg_color); -+ OUT_RING (chan, image->fg_color); -+ } -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0838, 2); -+ OUT_RING (chan, image->width); -+ OUT_RING (chan, image->height); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0850, 4); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, image->dx); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, image->dy); -+ -+ while (dwords) { -+ int push = dwords > 2047 ? 2047 : dwords; -+ -+ ret = RING_SPACE(chan, push + 1); -+ if (ret) -+ return ret; -+ -+ dwords -= push; -+ -+ BEGIN_NVC0(chan, 6, NvSub2D, 0x0860, push); -+ OUT_RINGp(chan, data, push); -+ data += push; -+ } -+ -+ FIRE_RING(chan); -+ return 0; -+} -+ -+int -+nvc0_fbcon_accel_init(struct fb_info *info) -+{ -+ struct nouveau_fbdev *nfbdev = info->par; -+ struct drm_device *dev = nfbdev->dev; -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan = dev_priv->channel; -+ struct nouveau_bo *nvbo = nfbdev->nouveau_fb.nvbo; -+ int ret, format; -+ -+ ret = nouveau_gpuobj_gr_new(chan, 0x902d, 0x902d); -+ if (ret) -+ return ret; -+ -+ switch (info->var.bits_per_pixel) { -+ case 8: -+ format = 0xf3; -+ break; -+ case 15: -+ format = 0xf8; -+ break; -+ case 16: -+ format = 0xe8; -+ break; -+ case 32: -+ switch (info->var.transp.length) { -+ case 0: /* depth 24 */ -+ case 8: /* depth 32, just use 24.. */ -+ format = 0xe6; -+ break; -+ case 2: /* depth 30 */ -+ format = 0xd1; -+ break; -+ default: -+ return -EINVAL; -+ } -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ ret = RING_SPACE(chan, 60); -+ if (ret) { -+ WARN_ON(1); -+ nouveau_fbcon_gpu_lockup(info); -+ return ret; -+ } -+ -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0000, 1); -+ OUT_RING (chan, 0x0000902d); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0104, 2); -+ OUT_RING (chan, upper_32_bits(chan->notifier_bo->bo.offset)); -+ OUT_RING (chan, lower_32_bits(chan->notifier_bo->bo.offset)); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0290, 1); -+ OUT_RING (chan, 0); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0888, 1); -+ OUT_RING (chan, 1); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02ac, 1); -+ OUT_RING (chan, 3); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02a0, 1); -+ OUT_RING (chan, 0x55); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x08c0, 4); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0580, 2); -+ OUT_RING (chan, 4); -+ OUT_RING (chan, format); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x02e8, 2); -+ OUT_RING (chan, 2); -+ OUT_RING (chan, 1); -+ -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0804, 1); -+ OUT_RING (chan, format); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0800, 1); -+ OUT_RING (chan, 1); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0808, 3); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x081c, 1); -+ OUT_RING (chan, 1); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0840, 4); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0200, 10); -+ OUT_RING (chan, format); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, info->fix.line_length); -+ OUT_RING (chan, info->var.xres_virtual); -+ OUT_RING (chan, info->var.yres_virtual); -+ OUT_RING (chan, upper_32_bits(nvbo->vma.offset)); -+ OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); -+ BEGIN_NVC0(chan, 2, NvSub2D, 0x0230, 10); -+ OUT_RING (chan, format); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, 1); -+ OUT_RING (chan, 0); -+ OUT_RING (chan, info->fix.line_length); -+ OUT_RING (chan, info->var.xres_virtual); -+ OUT_RING (chan, info->var.yres_virtual); -+ OUT_RING (chan, upper_32_bits(nvbo->vma.offset)); -+ OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); -+ FIRE_RING (chan); -+ -+ return 0; -+} -+ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_fifo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_fifo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_fifo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -25,6 +25,49 @@ - #include "drmP.h" - - #include "nouveau_drv.h" -+#include "nouveau_mm.h" -+ -+static void nvc0_fifo_isr(struct drm_device *); -+ -+struct nvc0_fifo_priv { -+ struct nouveau_gpuobj *playlist[2]; -+ int cur_playlist; -+ struct nouveau_vma user_vma; -+ int spoon_nr; -+}; -+ -+struct nvc0_fifo_chan { -+ struct nouveau_bo *user; -+ struct nouveau_gpuobj *ramfc; -+}; -+ -+static void -+nvc0_fifo_playlist_update(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; -+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; -+ struct nvc0_fifo_priv *priv = pfifo->priv; -+ struct nouveau_gpuobj *cur; -+ int i, p; -+ -+ cur = priv->playlist[priv->cur_playlist]; -+ priv->cur_playlist = !priv->cur_playlist; -+ -+ for (i = 0, p = 0; i < 128; i++) { -+ if (!(nv_rd32(dev, 0x3004 + (i * 8)) & 1)) -+ continue; -+ nv_wo32(cur, p + 0, i); -+ nv_wo32(cur, p + 4, 0x00000004); -+ p += 8; -+ } -+ pinstmem->flush(dev); -+ -+ nv_wr32(dev, 0x002270, cur->vinst >> 12); -+ nv_wr32(dev, 0x002274, 0x01f00000 | (p >> 3)); -+ if (!nv_wait(dev, 0x00227c, 0x00100000, 0x00000000)) -+ NV_ERROR(dev, "PFIFO - playlist update failed\n"); -+} - - void - nvc0_fifo_disable(struct drm_device *dev) -@@ -57,12 +100,135 @@ - int - nvc0_fifo_create_context(struct nouveau_channel *chan) - { -+ 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_fifo_engine *pfifo = &dev_priv->engine.fifo; -+ struct nvc0_fifo_priv *priv = pfifo->priv; -+ struct nvc0_fifo_chan *fifoch; -+ u64 ib_virt, user_vinst; -+ int ret; -+ -+ chan->fifo_priv = kzalloc(sizeof(*fifoch), GFP_KERNEL); -+ if (!chan->fifo_priv) -+ return -ENOMEM; -+ 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, true, true, &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); -+ -+ chan->user = ioremap_wc(pci_resource_start(dev->pdev, 1) + -+ priv->user_vma.offset + (chan->id * 0x1000), -+ PAGE_SIZE); -+ if (!chan->user) { -+ ret = -ENOMEM; -+ 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, -+ NVOBJ_FLAG_ZERO_ALLOC, &fifoch->ramfc); -+ 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, 0x10, 0x0000face); -+ nv_wo32(fifoch->ramfc, 0x30, 0xfffff902); -+ nv_wo32(fifoch->ramfc, 0x48, lower_32_bits(ib_virt)); -+ nv_wo32(fifoch->ramfc, 0x4c, drm_order(chan->dma.ib_max + 1) << 16 | -+ upper_32_bits(ib_virt)); -+ nv_wo32(fifoch->ramfc, 0x54, 0x00000002); -+ nv_wo32(fifoch->ramfc, 0x84, 0x20400000); -+ nv_wo32(fifoch->ramfc, 0x94, 0x30000001); -+ nv_wo32(fifoch->ramfc, 0x9c, 0x00000100); -+ nv_wo32(fifoch->ramfc, 0xa4, 0x1f1f1f1f); -+ nv_wo32(fifoch->ramfc, 0xa8, 0x1f1f1f1f); -+ nv_wo32(fifoch->ramfc, 0xac, 0x0000001f); -+ nv_wo32(fifoch->ramfc, 0xb8, 0xf8000000); -+ nv_wo32(fifoch->ramfc, 0xf8, 0x10003080); /* 0x002310 */ -+ nv_wo32(fifoch->ramfc, 0xfc, 0x10000010); /* 0x002350 */ -+ pinstmem->flush(dev); -+ -+ nv_wr32(dev, 0x003000 + (chan->id * 8), 0xc0000000 | -+ (chan->ramin->vinst >> 12)); -+ nv_wr32(dev, 0x003004 + (chan->id * 8), 0x001f0001); -+ nvc0_fifo_playlist_update(dev); - return 0; -+ -+error: -+ pfifo->destroy_context(chan); -+ return ret; - } - - void - nvc0_fifo_destroy_context(struct nouveau_channel *chan) - { -+ struct drm_device *dev = chan->dev; -+ struct nvc0_fifo_chan *fifoch; -+ -+ nv_mask(dev, 0x003004 + (chan->id * 8), 0x00000001, 0x00000000); -+ nv_wr32(dev, 0x002634, chan->id); -+ if (!nv_wait(dev, 0x0002634, 0xffffffff, chan->id)) -+ NV_WARN(dev, "0x2634 != chid: 0x%08x\n", nv_rd32(dev, 0x2634)); -+ -+ nvc0_fifo_playlist_update(dev); -+ -+ nv_wr32(dev, 0x003000 + (chan->id * 8), 0x00000000); -+ -+ if (chan->user) { -+ iounmap(chan->user); -+ chan->user = NULL; -+ } -+ -+ fifoch = chan->fifo_priv; -+ chan->fifo_priv = NULL; -+ if (!fifoch) -+ 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); -+ } -+ kfree(fifoch); - } - - int -@@ -77,14 +243,213 @@ - return 0; - } - -+static void -+nvc0_fifo_destroy(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; -+ struct nvc0_fifo_priv *priv; -+ -+ priv = pfifo->priv; -+ if (!priv) -+ return; -+ -+ nouveau_vm_put(&priv->user_vma); -+ nouveau_gpuobj_ref(NULL, &priv->playlist[1]); -+ nouveau_gpuobj_ref(NULL, &priv->playlist[0]); -+ kfree(priv); -+} -+ - void - nvc0_fifo_takedown(struct drm_device *dev) - { -+ nv_wr32(dev, 0x002140, 0x00000000); -+ nvc0_fifo_destroy(dev); -+} -+ -+static int -+nvc0_fifo_create(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; -+ struct nvc0_fifo_priv *priv; -+ int ret; -+ -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ pfifo->priv = priv; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0, -+ &priv->playlist[0]); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0x1000, 0, -+ &priv->playlist[1]); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_vm_get(dev_priv->bar1_vm, pfifo->channels * 0x1000, -+ 12, NV_MEM_ACCESS_RW, &priv->user_vma); -+ if (ret) -+ goto error; -+ -+ nouveau_irq_register(dev, 8, nvc0_fifo_isr); -+ NVOBJ_CLASS(dev, 0x506e, SW); /* nvsw */ -+ return 0; -+ -+error: -+ nvc0_fifo_destroy(dev); -+ return ret; - } - - int - 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 nvc0_fifo_priv *priv; -+ int ret, i; -+ -+ if (!pfifo->priv) { -+ ret = nvc0_fifo_create(dev); -+ if (ret) -+ return ret; -+ } -+ priv = pfifo->priv; -+ -+ /* reset PFIFO, enable all available PSUBFIFO areas */ -+ nv_mask(dev, 0x000200, 0x00000100, 0x00000000); -+ nv_mask(dev, 0x000200, 0x00000100, 0x00000100); -+ nv_wr32(dev, 0x000204, 0xffffffff); -+ nv_wr32(dev, 0x002204, 0xffffffff); -+ -+ priv->spoon_nr = hweight32(nv_rd32(dev, 0x002204)); -+ NV_DEBUG(dev, "PFIFO: %d subfifo(s)\n", priv->spoon_nr); -+ -+ /* assign engines to subfifos */ -+ if (priv->spoon_nr >= 3) { -+ nv_wr32(dev, 0x002208, ~(1 << 0)); /* PGRAPH */ -+ nv_wr32(dev, 0x00220c, ~(1 << 1)); /* PVP */ -+ nv_wr32(dev, 0x002210, ~(1 << 1)); /* PPP */ -+ nv_wr32(dev, 0x002214, ~(1 << 1)); /* PBSP */ -+ nv_wr32(dev, 0x002218, ~(1 << 2)); /* PCE0 */ -+ nv_wr32(dev, 0x00221c, ~(1 << 1)); /* PCE1 */ -+ } -+ -+ /* PSUBFIFO[n] */ -+ for (i = 0; i < 3; i++) { -+ nv_mask(dev, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); -+ nv_wr32(dev, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ -+ nv_wr32(dev, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTR_EN */ -+ } -+ -+ nv_mask(dev, 0x002200, 0x00000001, 0x00000001); -+ nv_wr32(dev, 0x002254, 0x10000000 | priv->user_vma.offset >> 12); -+ -+ nv_wr32(dev, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */ -+ nv_wr32(dev, 0x002100, 0xffffffff); -+ nv_wr32(dev, 0x002140, 0xbfffffff); - return 0; - } - -+struct nouveau_enum nvc0_fifo_fault_unit[] = { -+ { 0, "PGRAPH" }, -+ { 3, "PEEPHOLE" }, -+ { 4, "BAR1" }, -+ { 5, "BAR3" }, -+ { 7, "PFIFO" }, -+ {} -+}; -+ -+struct nouveau_enum nvc0_fifo_fault_reason[] = { -+ { 0, "PT_NOT_PRESENT" }, -+ { 1, "PT_TOO_SHORT" }, -+ { 2, "PAGE_NOT_PRESENT" }, -+ { 3, "VM_LIMIT_EXCEEDED" }, -+ {} -+}; -+ -+struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = { -+/* { 0x00008000, "" } seen with null ib push */ -+ { 0x00200000, "ILLEGAL_MTHD" }, -+ { 0x00800000, "EMPTY_SUBC" }, -+ {} -+}; -+ -+static void -+nvc0_fifo_isr_vm_fault(struct drm_device *dev, int unit) -+{ -+ u32 inst = nv_rd32(dev, 0x2800 + (unit * 0x10)); -+ u32 valo = nv_rd32(dev, 0x2804 + (unit * 0x10)); -+ u32 vahi = nv_rd32(dev, 0x2808 + (unit * 0x10)); -+ u32 stat = nv_rd32(dev, 0x280c + (unit * 0x10)); -+ -+ 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); -+ printk(" on channel 0x%010llx\n", (u64)inst << 12); -+} -+ -+static void -+nvc0_fifo_isr_subfifo_intr(struct drm_device *dev, int unit) -+{ -+ u32 stat = nv_rd32(dev, 0x040108 + (unit * 0x2000)); -+ u32 addr = nv_rd32(dev, 0x0400c0 + (unit * 0x2000)); -+ u32 data = nv_rd32(dev, 0x0400c4 + (unit * 0x2000)); -+ u32 chid = nv_rd32(dev, 0x040120 + (unit * 0x2000)) & 0x7f; -+ u32 subc = (addr & 0x00070000); -+ u32 mthd = (addr & 0x00003ffc); -+ -+ NV_INFO(dev, "PSUBFIFO %d:", unit); -+ nouveau_bitfield_print(nvc0_fifo_subfifo_intr, stat); -+ NV_INFO(dev, "PSUBFIFO %d: ch %d subc %d mthd 0x%04x data 0x%08x\n", -+ unit, chid, subc, mthd, data); -+ -+ nv_wr32(dev, 0x0400c0 + (unit * 0x2000), 0x80600008); -+ nv_wr32(dev, 0x040108 + (unit * 0x2000), stat); -+} -+ -+static void -+nvc0_fifo_isr(struct drm_device *dev) -+{ -+ u32 stat = nv_rd32(dev, 0x002100); -+ -+ if (stat & 0x10000000) { -+ u32 units = nv_rd32(dev, 0x00259c); -+ u32 u = units; -+ -+ while (u) { -+ int i = ffs(u) - 1; -+ nvc0_fifo_isr_vm_fault(dev, i); -+ u &= ~(1 << i); -+ } -+ -+ nv_wr32(dev, 0x00259c, units); -+ stat &= ~0x10000000; -+ } -+ -+ if (stat & 0x20000000) { -+ u32 units = nv_rd32(dev, 0x0025a0); -+ u32 u = units; -+ -+ while (u) { -+ int i = ffs(u) - 1; -+ nvc0_fifo_isr_subfifo_intr(dev, i); -+ u &= ~(1 << i); -+ } -+ -+ nv_wr32(dev, 0x0025a0, units); -+ stat &= ~0x20000000; -+ } -+ -+ if (stat) { -+ NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); -+ nv_wr32(dev, 0x002100, stat); -+ } -+ -+ nv_wr32(dev, 0x2140, 0); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_graph.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_graph.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_graph.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-01-07 14:22:17.000000000 +0100 -@@ -22,9 +22,16 @@ - * Authors: Ben Skeggs - */ - -+#include -+ - #include "drmP.h" - - #include "nouveau_drv.h" -+#include "nouveau_mm.h" -+#include "nvc0_graph.h" -+ -+static void nvc0_graph_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) -@@ -37,39 +44,735 @@ - return NULL; - } - -+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 drm_device *dev = chan->dev; -+ int ret, i; -+ u32 *ctx; -+ -+ ctx = kmalloc(priv->grctx_size, GFP_KERNEL); -+ if (!ctx) -+ return -ENOMEM; -+ -+ nvc0_graph_load_context(chan); -+ -+ nv_wo32(grch->grctx, 0x1c, 1); -+ nv_wo32(grch->grctx, 0x20, 0); -+ nv_wo32(grch->grctx, 0x28, 0); -+ nv_wo32(grch->grctx, 0x2c, 0); -+ dev_priv->engine.instmem.flush(dev); -+ -+ ret = nvc0_grctx_generate(chan); -+ if (ret) { -+ kfree(ctx); -+ return ret; -+ } -+ -+ ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst); -+ if (ret) { -+ kfree(ctx); -+ return ret; -+ } -+ -+ for (i = 0; i < priv->grctx_size; i += 4) -+ ctx[i / 4] = nv_ro32(grch->grctx, i); -+ -+ priv->grctx_vals = ctx; -+ return 0; -+} -+ -+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 drm_device *dev = chan->dev; -+ int i = 0, gpc, tp, ret; -+ u32 magic; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x2000, 256, NVOBJ_FLAG_VM, -+ &grch->unk408004); -+ if (ret) -+ return ret; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 256, NVOBJ_FLAG_VM, -+ &grch->unk40800c); -+ if (ret) -+ return ret; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, NVOBJ_FLAG_VM, -+ &grch->unk418810); -+ if (ret) -+ return ret; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0, NVOBJ_FLAG_VM, -+ &grch->mmio); -+ if (ret) -+ return ret; -+ -+ -+ nv_wo32(grch->mmio, i++ * 4, 0x00408004); -+ nv_wo32(grch->mmio, i++ * 4, grch->unk408004->vinst >> 8); -+ nv_wo32(grch->mmio, i++ * 4, 0x00408008); -+ nv_wo32(grch->mmio, i++ * 4, 0x80000018); -+ -+ nv_wo32(grch->mmio, i++ * 4, 0x0040800c); -+ nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8); -+ nv_wo32(grch->mmio, i++ * 4, 0x00408010); -+ nv_wo32(grch->mmio, i++ * 4, 0x80000000); -+ -+ nv_wo32(grch->mmio, i++ * 4, 0x00418810); -+ nv_wo32(grch->mmio, i++ * 4, 0x80000000 | grch->unk418810->vinst >> 12); -+ nv_wo32(grch->mmio, i++ * 4, 0x00419848); -+ nv_wo32(grch->mmio, i++ * 4, 0x10000000 | grch->unk418810->vinst >> 12); -+ -+ nv_wo32(grch->mmio, i++ * 4, 0x00419004); -+ nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8); -+ nv_wo32(grch->mmio, i++ * 4, 0x00419008); -+ nv_wo32(grch->mmio, i++ * 4, 0x00000000); -+ -+ nv_wo32(grch->mmio, i++ * 4, 0x00418808); -+ nv_wo32(grch->mmio, i++ * 4, grch->unk408004->vinst >> 8); -+ nv_wo32(grch->mmio, i++ * 4, 0x0041880c); -+ nv_wo32(grch->mmio, i++ * 4, 0x80000018); -+ -+ magic = 0x02180000; -+ nv_wo32(grch->mmio, i++ * 4, 0x00405830); -+ nv_wo32(grch->mmio, i++ * 4, magic); -+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { -+ for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x02fc) { -+ u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800); -+ nv_wo32(grch->mmio, i++ * 4, reg); -+ nv_wo32(grch->mmio, i++ * 4, magic); -+ } -+ } -+ -+ grch->mmio_nr = i / 2; -+ return 0; -+} -+ - int - nvc0_graph_create_context(struct nouveau_channel *chan) - { -+ struct drm_nouveau_private *dev_priv = chan->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_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) -+ return -ENOMEM; -+ grch = chan->pgraph_ctx; -+ -+ 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); -+ if (ret) -+ goto error; -+ -+ nv_wo32(chan->ramin, 0x0210, lower_32_bits(grctx->vinst) | 4); -+ nv_wo32(chan->ramin, 0x0214, upper_32_bits(grctx->vinst)); -+ pinstmem->flush(dev); -+ -+ if (!priv->grctx_vals) { -+ ret = nvc0_graph_construct_context(chan); -+ if (ret) -+ goto error; -+ } -+ -+ 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); -+ pinstmem->flush(dev); - return 0; -+ -+error: -+ pgraph->destroy_context(chan); -+ return ret; - } - - void - nvc0_graph_destroy_context(struct nouveau_channel *chan) - { -+ struct nvc0_graph_chan *grch; -+ -+ grch = chan->pgraph_ctx; -+ chan->pgraph_ctx = NULL; -+ if (!grch) -+ return; -+ -+ 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; - } - - 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; -+} -+ -+static int -+nvc0_graph_unload_context_to(struct drm_device *dev, u64 chan) -+{ -+ 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) - { -- return 0; -+ 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_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_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); -+ NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ -+ NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ -+ 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; -+ int i; -+ -+ nv_wr32(dev, GPC_BCAST(0x0880), 0x00000000); -+ nv_wr32(dev, GPC_BCAST(0x08a4), 0x00000000); -+ for (i = 0; i < 4; i++) -+ nv_wr32(dev, GPC_BCAST(0x0888) + (i * 4), 0x00000000); -+ nv_wr32(dev, GPC_BCAST(0x08b4), priv->unk4188b4->vinst >> 8); -+ nv_wr32(dev, GPC_BCAST(0x08b8), priv->unk4188b8->vinst >> 8); -+} -+ -+static void -+nvc0_graph_init_regs(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x400080, 0x003083c2); -+ nv_wr32(dev, 0x400088, 0x00006fe7); -+ nv_wr32(dev, 0x40008c, 0x00000000); -+ nv_wr32(dev, 0x400090, 0x00000030); -+ nv_wr32(dev, 0x40013c, 0x013901f7); -+ nv_wr32(dev, 0x400140, 0x00000100); -+ nv_wr32(dev, 0x400144, 0x00000000); -+ nv_wr32(dev, 0x400148, 0x00000110); -+ nv_wr32(dev, 0x400138, 0x00000000); -+ nv_wr32(dev, 0x400130, 0x00000000); -+ nv_wr32(dev, 0x400134, 0x00000000); -+ nv_wr32(dev, 0x400124, 0x00000002); -+} -+ -+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]); -+ -+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0914), priv->magic_not_rop_nr << 8 | -+ priv->tp_nr[gpc]); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0910), 0x00040000 | priv->tp_total); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0918), priv->magicgpc918); -+ } -+ -+ nv_wr32(dev, GPC_BCAST(0x1bd4), priv->magicgpc918); -+ nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr); -+} -+ -+static void -+nvc0_graph_init_units(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x409c24, 0x000f0000); -+ nv_wr32(dev, 0x404000, 0xc0000000); /* DISPATCH */ -+ nv_wr32(dev, 0x404600, 0xc0000000); /* M2MF */ -+ nv_wr32(dev, 0x408030, 0xc0000000); -+ nv_wr32(dev, 0x40601c, 0xc0000000); -+ nv_wr32(dev, 0x404490, 0xc0000000); /* MACRO */ -+ nv_wr32(dev, 0x406018, 0xc0000000); -+ nv_wr32(dev, 0x405840, 0xc0000000); -+ nv_wr32(dev, 0x405844, 0x00ffffff); -+ nv_mask(dev, 0x419cc0, 0x00000008, 0x00000008); -+ nv_mask(dev, 0x419eb4, 0x00001000, 0x00001000); -+} -+ -+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; -+ int gpc, tp; -+ -+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0420), 0xc0000000); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0900), 0xc0000000); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x1028), 0xc0000000); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0824), 0xc0000000); -+ for (tp = 0; tp < priv->tp_nr[gpc]; tp++) { -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x508), 0xffffffff); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x50c), 0xffffffff); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x224), 0xc0000000); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x48c), 0xc0000000); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x084), 0xc0000000); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0xe44), 0x001ffffe); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0xe4c), 0x0000000f); -+ } -+ nv_wr32(dev, GPC_UNIT(gpc, 0x2c90), 0xffffffff); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x2c94), 0xffffffff); -+ } -+} -+ -+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; -+ int rop; -+ -+ for (rop = 0; rop < priv->rop_nr; rop++) { -+ nv_wr32(dev, ROP_UNIT(rop, 0x144), 0xc0000000); -+ nv_wr32(dev, ROP_UNIT(rop, 0x070), 0xc0000000); -+ nv_wr32(dev, ROP_UNIT(rop, 0x204), 0xffffffff); -+ nv_wr32(dev, ROP_UNIT(rop, 0x208), 0xffffffff); -+ } -+} -+ -+static int -+nvc0_fuc_load_fw(struct drm_device *dev, u32 fuc_base, -+ const char *code_fw, const char *data_fw) -+{ -+ 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; -+ } -+ -+ 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; -+ } -+ -+ nv_wr32(dev, fuc_base + 0x0180, 0x01000000); -+ for (i = 0; i < fw->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]); -+ } -+ 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; -+ 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"); -+ nv_wr32(dev, 0x000260, r000260); -+ -+ if (ret) -+ return ret; -+ -+ /* start both of them running */ -+ nv_wr32(dev, 0x409840, 0xffffffff); -+ nv_wr32(dev, 0x41a10c, 0x00000000); -+ nv_wr32(dev, 0x40910c, 0x00000000); -+ nv_wr32(dev, 0x41a100, 0x00000002); -+ nv_wr32(dev, 0x409100, 0x00000002); -+ if (!nv_wait(dev, 0x409800, 0x00000001, 0x00000001)) -+ NV_INFO(dev, "0x409800 wait failed\n"); -+ -+ nv_wr32(dev, 0x409840, 0xffffffff); -+ nv_wr32(dev, 0x409500, 0x7fffffff); -+ nv_wr32(dev, 0x409504, 0x00000021); -+ -+ nv_wr32(dev, 0x409840, 0xffffffff); -+ nv_wr32(dev, 0x409500, 0x00000000); -+ nv_wr32(dev, 0x409504, 0x00000010); -+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { -+ NV_ERROR(dev, "fuc09 req 0x10 timeout\n"); -+ return -EBUSY; -+ } -+ priv->grctx_size = nv_rd32(dev, 0x409800); -+ -+ nv_wr32(dev, 0x409840, 0xffffffff); -+ nv_wr32(dev, 0x409500, 0x00000000); -+ nv_wr32(dev, 0x409504, 0x00000016); -+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { -+ NV_ERROR(dev, "fuc09 req 0x16 timeout\n"); -+ return -EBUSY; -+ } -+ -+ nv_wr32(dev, 0x409840, 0xffffffff); -+ nv_wr32(dev, 0x409500, 0x00000000); -+ nv_wr32(dev, 0x409504, 0x00000025); -+ if (!nv_wait_ne(dev, 0x409800, 0xffffffff, 0x00000000)) { -+ NV_ERROR(dev, "fuc09 req 0x25 timeout\n"); -+ return -EBUSY; -+ } -+ -+ return 0; - } - - int - nvc0_graph_init(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; -+ - 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; -+ } -+ priv = pgraph->priv; -+ -+ nvc0_graph_init_obj418880(dev); -+ nvc0_graph_init_regs(dev); -+ //nvc0_graph_init_unitplemented_magics(dev); -+ nvc0_graph_init_gpc_0(dev); -+ //nvc0_graph_init_unitplemented_c242(dev); -+ -+ nv_wr32(dev, 0x400500, 0x00010001); -+ nv_wr32(dev, 0x400100, 0xffffffff); -+ nv_wr32(dev, 0x40013c, 0xffffffff); -+ -+ nvc0_graph_init_units(dev); -+ nvc0_graph_init_gpc_1(dev); -+ nvc0_graph_init_rop(dev); -+ -+ nv_wr32(dev, 0x400108, 0xffffffff); -+ nv_wr32(dev, 0x400138, 0xffffffff); -+ nv_wr32(dev, 0x400118, 0xffffffff); -+ nv_wr32(dev, 0x400130, 0xffffffff); -+ nv_wr32(dev, 0x40011c, 0xffffffff); -+ nv_wr32(dev, 0x400134, 0xffffffff); -+ nv_wr32(dev, 0x400054, 0x34ce3464); -+ -+ ret = nvc0_graph_init_ctxctl(dev); -+ if (ret == 0) -+ dev_priv->engine.graph.accel_blocked = false; - return 0; - } - -+static int -+nvc0_graph_isr_chid(struct drm_device *dev, u64 inst) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nouveau_channel *chan; -+ 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) -+ continue; -+ -+ if (inst == chan->ramin->vinst) -+ break; -+ } -+ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); -+ return i; -+} -+ -+static void -+nvc0_graph_isr(struct drm_device *dev) -+{ -+ u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; -+ u32 chid = nvc0_graph_isr_chid(dev, inst); -+ u32 stat = nv_rd32(dev, 0x400100); -+ u32 addr = nv_rd32(dev, 0x400704); -+ u32 mthd = (addr & 0x00003ffc); -+ u32 subc = (addr & 0x00070000) >> 16; -+ u32 data = nv_rd32(dev, 0x400708); -+ u32 code = nv_rd32(dev, 0x400110); -+ u32 class = nv_rd32(dev, 0x404200 + (subc * 4)); -+ -+ if (stat & 0x00000010) { -+ NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] subc %d " -+ "class 0x%04x mthd 0x%04x data 0x%08x\n", -+ chid, inst, subc, class, mthd, data); -+ nv_wr32(dev, 0x400100, 0x00000010); -+ stat &= ~0x00000010; -+ } -+ -+ if (stat & 0x00000020) { -+ NV_INFO(dev, "PGRAPH: ILLEGAL_CLASS ch %d [0x%010llx] subc %d " -+ "class 0x%04x mthd 0x%04x data 0x%08x\n", -+ chid, inst, subc, class, mthd, data); -+ nv_wr32(dev, 0x400100, 0x00000020); -+ stat &= ~0x00000020; -+ } -+ -+ if (stat & 0x00100000) { -+ NV_INFO(dev, "PGRAPH: DATA_ERROR ["); -+ nouveau_enum_print(nv50_data_error_names, code); -+ printk("] ch %d [0x%010llx] subc %d class 0x%04x " -+ "mthd 0x%04x data 0x%08x\n", -+ chid, inst, subc, class, mthd, data); -+ nv_wr32(dev, 0x400100, 0x00100000); -+ stat &= ~0x00100000; -+ } -+ -+ if (stat & 0x00200000) { -+ u32 trap = nv_rd32(dev, 0x400108); -+ NV_INFO(dev, "PGRAPH: TRAP ch %d status 0x%08x\n", chid, trap); -+ nv_wr32(dev, 0x400108, trap); -+ nv_wr32(dev, 0x400100, 0x00200000); -+ stat &= ~0x00200000; -+ } -+ -+ if (stat & 0x00080000) { -+ u32 ustat = nv_rd32(dev, 0x409c18); -+ -+ NV_INFO(dev, "PGRAPH: CTXCTRL ustat 0x%08x\n", ustat); -+ -+ nv_wr32(dev, 0x409c20, ustat); -+ nv_wr32(dev, 0x400100, 0x00080000); -+ stat &= ~0x00080000; -+ } -+ -+ if (stat) { -+ NV_INFO(dev, "PGRAPH: unknown stat 0x%08x\n", stat); -+ nv_wr32(dev, 0x400100, stat); -+ } -+ -+ nv_wr32(dev, 0x400500, 0x00010001); -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_graph.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_graph.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_graph.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_graph.h 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,64 @@ -+/* -+ * Copyright 2010 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 -+ */ -+ -+#ifndef __NVC0_GRAPH_H__ -+#define __NVC0_GRAPH_H__ -+ -+#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)) -+ -+struct nvc0_graph_priv { -+ u8 gpc_nr; -+ u8 rop_nr; -+ u8 tp_nr[GPC_MAX]; -+ u8 tp_total; -+ -+ u32 grctx_size; -+ u32 *grctx_vals; -+ struct nouveau_gpuobj *unk4188b4; -+ 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 *mmio; -+ int mmio_nr; -+}; -+ -+int nvc0_grctx_generate(struct nouveau_channel *); -+ -+#endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_grctx.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_grctx.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_grctx.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_grctx.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,2874 @@ -+/* -+ * Copyright 2010 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_mm.h" -+#include "nvc0_graph.h" -+ -+static void -+nv_icmd(struct drm_device *dev, u32 icmd, u32 data) -+{ -+ nv_wr32(dev, 0x400204, data); -+ nv_wr32(dev, 0x400200, icmd); -+ while (nv_rd32(dev, 0x400700) & 2) {} -+} -+ -+static void -+nv_mthd(struct drm_device *dev, u32 class, u32 mthd, u32 data) -+{ -+ nv_wr32(dev, 0x40448c, data); -+ nv_wr32(dev, 0x404488, 0x80000000 | (mthd << 14) | class); -+} -+ -+static void -+nvc0_grctx_generate_9097(struct drm_device *dev) -+{ -+ nv_mthd(dev, 0x9097, 0x0800, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0840, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0880, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x08c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0900, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0940, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0980, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x09c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0804, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0844, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0884, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x08c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0904, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0944, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0984, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x09c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0808, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x0848, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x0888, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x08c8, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x0908, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x0948, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x0988, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x09c8, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x080c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x084c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x088c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x08cc, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x090c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x094c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x098c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x09cc, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x0810, 0x000000cf); -+ nv_mthd(dev, 0x9097, 0x0850, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0890, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x08d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0910, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0950, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0990, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x09d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0814, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0854, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0894, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x08d4, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0914, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0954, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0994, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x09d4, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0818, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0858, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0898, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x08d8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0918, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0958, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0998, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x09d8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x081c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x085c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x089c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x08dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x091c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x095c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x099c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x09dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0820, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0860, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x08a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x08e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0920, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0960, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x09a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x09e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2700, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2720, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2740, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2760, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2780, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2704, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2724, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2744, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2764, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2784, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2708, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2728, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2748, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2768, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2788, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x270c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x272c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x274c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x276c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x278c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x27ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2710, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x2730, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x2750, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x2770, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x2790, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x27b0, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x27d0, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x27f0, 0x00014000); -+ nv_mthd(dev, 0x9097, 0x2714, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x2734, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x2754, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x2774, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x2794, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x27b4, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x27d4, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x27f4, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x1c00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ca0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cb0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cc0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cd0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ce0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cf0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c24, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c34, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c64, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c94, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ca4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cb4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cc4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cd4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ce4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cf4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c18, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c28, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c38, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c58, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c68, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c78, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c98, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ca8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cb8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cc8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cd8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ce8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cf8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c0c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c1c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c2c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c3c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c4c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c5c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c6c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c7c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1c9c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cbc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ccc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cdc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1cfc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1da0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1db0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dc0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dd0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1de0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1df0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d24, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d34, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d64, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d94, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1da4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1db4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dc4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dd4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1de4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1df4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d18, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d28, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d38, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d58, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d68, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d78, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d98, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1da8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1db8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dc8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dd8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1de8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1df8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d0c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d1c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d2c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d3c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d4c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d5c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d6c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d7c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1d9c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dbc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dcc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ddc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1dfc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f18, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f28, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f38, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f58, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f68, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f78, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f0c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f1c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f24, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f2c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f34, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f3c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f4c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f5c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f64, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f6c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f7c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f98, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fa0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fa8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fb0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fb8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fc0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fc8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fd0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fd8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fe0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fe8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ff0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ff8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f94, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1f9c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fa4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fb4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fbc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fc4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fcc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fd4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fdc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fe4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1fec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ff4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1ffc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2200, 0x00000022); -+ nv_mthd(dev, 0x9097, 0x2210, 0x00000022); -+ nv_mthd(dev, 0x9097, 0x2220, 0x00000022); -+ nv_mthd(dev, 0x9097, 0x2230, 0x00000022); -+ nv_mthd(dev, 0x9097, 0x2240, 0x00000022); -+ nv_mthd(dev, 0x9097, 0x2000, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2040, 0x00000011); -+ nv_mthd(dev, 0x9097, 0x2080, 0x00000020); -+ nv_mthd(dev, 0x9097, 0x20c0, 0x00000030); -+ nv_mthd(dev, 0x9097, 0x2100, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x2140, 0x00000051); -+ nv_mthd(dev, 0x9097, 0x200c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x204c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x208c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x20cc, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x210c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x214c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x2010, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2050, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2090, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x20d0, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x2110, 0x00000003); -+ nv_mthd(dev, 0x9097, 0x2150, 0x00000004); -+ nv_mthd(dev, 0x9097, 0x0380, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0384, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0388, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x038c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x03ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0700, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0710, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0720, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0730, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0704, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0714, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0724, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0734, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0708, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0718, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0728, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0738, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2800, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2804, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2808, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x280c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2810, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2814, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2818, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x281c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2820, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2824, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2828, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x282c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2830, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2834, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2838, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x283c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2840, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2844, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2848, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x284c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2850, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2854, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2858, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x285c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2860, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2864, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2868, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x286c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2870, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2874, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2878, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x287c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2880, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2884, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2888, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x288c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2890, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2894, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2898, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x289c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28b0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28b4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28b8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28d4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28d8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28f0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x28fc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2900, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2904, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2908, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x290c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2910, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2914, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2918, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x291c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2920, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2924, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2928, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x292c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2930, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2934, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2938, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x293c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2940, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2944, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2948, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x294c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2950, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2954, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2958, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x295c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2960, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2964, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2968, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x296c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2970, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2974, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2978, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x297c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2980, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2984, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2988, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x298c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2990, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2994, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2998, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x299c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29b0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29b4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29b8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29d4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29d8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29f0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x29fc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0aa0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ac0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ae0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ba0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bc0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0be0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a24, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a64, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0aa4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ac4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ae4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b24, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b64, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ba4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bc4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0be4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a28, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a68, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0aa8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ac8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ae8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b28, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b68, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ba8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bc8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0be8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a0c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a2c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a4c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a6c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0aac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0acc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0aec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b0c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b2c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b4c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b6c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bcc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ab0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ad0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0af0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bb0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bd0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bf0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a34, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0a94, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ab4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ad4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0af4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b34, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0b94, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bb4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bd4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0bf4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ca0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cb0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cc0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cd0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ce0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cf0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c24, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c34, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c64, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c94, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ca4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cb4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cc4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cd4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ce4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cf4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c18, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c28, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c38, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c58, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c68, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c78, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c98, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ca8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cb8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cc8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cd8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ce8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0cf8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0c0c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c1c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c2c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c3c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c4c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c5c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c6c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c7c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c8c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0c9c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0cac, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0cbc, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0ccc, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0cdc, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0cec, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0cfc, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0d00, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d08, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d10, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d18, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d20, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d28, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d30, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d38, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d04, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d0c, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d14, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d1c, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d24, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d2c, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d34, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d3c, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e00, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e20, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e30, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e60, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e70, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ea0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0eb0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ec0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ed0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ee0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ef0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0e04, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e14, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e24, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e34, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e44, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e54, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e64, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e74, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e84, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e94, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ea4, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0eb4, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ec4, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ed4, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ee4, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ef4, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e08, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e18, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e28, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e38, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e48, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e58, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e68, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e78, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e88, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0e98, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ea8, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0eb8, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ec8, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ed8, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ee8, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0ef8, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d40, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d48, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d50, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d58, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d44, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d4c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d5c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1e00, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e20, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e40, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e60, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e80, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ea0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ec0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ee0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e04, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e24, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e44, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e64, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e84, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ea4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ec4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ee4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e08, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e28, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e48, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e68, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e88, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1ea8, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1ec8, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1ee8, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e0c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e2c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e4c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e6c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e8c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1eac, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ecc, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1eec, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e10, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e30, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e50, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e70, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e90, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1eb0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ed0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ef0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e14, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e34, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e54, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e74, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e94, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1eb4, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1ed4, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1ef4, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1e18, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e38, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e58, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e78, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1e98, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1eb8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ed8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1ef8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x3400, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3404, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3408, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x340c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3410, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3414, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3418, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x341c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3420, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3424, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3428, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x342c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3430, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3434, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3438, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x343c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3440, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3444, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3448, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x344c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3450, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3454, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3458, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x345c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3460, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3464, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3468, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x346c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3470, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3474, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3478, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x347c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3480, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3484, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3488, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x348c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3490, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3494, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3498, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x349c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34b0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34b4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34b8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34d4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34d8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34f0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x34fc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3500, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3504, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3508, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x350c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3510, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3514, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3518, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x351c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3520, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3524, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3528, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x352c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3530, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3534, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3538, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x353c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3540, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3544, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3548, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x354c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3550, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3554, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3558, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x355c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3560, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3564, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3568, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x356c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3570, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3574, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3578, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x357c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3580, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3584, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3588, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x358c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3590, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3594, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x3598, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x359c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35b0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35b4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35b8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35d4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35d8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35f0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x35fc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x030c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1944, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1514, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d68, 0x0000ffff); -+ nv_mthd(dev, 0x9097, 0x121c, 0x0fac6881); -+ nv_mthd(dev, 0x9097, 0x0fac, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1538, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0fe0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0fe4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0fe8, 0x00000014); -+ nv_mthd(dev, 0x9097, 0x0fec, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x0ff0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x179c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1228, 0x00000400); -+ nv_mthd(dev, 0x9097, 0x122c, 0x00000300); -+ nv_mthd(dev, 0x9097, 0x1230, 0x00010001); -+ nv_mthd(dev, 0x9097, 0x07f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x15b4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x15cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1534, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0fb0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x15d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x153c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x16b4, 0x00000003); -+ nv_mthd(dev, 0x9097, 0x0fbc, 0x0000ffff); -+ nv_mthd(dev, 0x9097, 0x0fc0, 0x0000ffff); -+ nv_mthd(dev, 0x9097, 0x0fc4, 0x0000ffff); -+ nv_mthd(dev, 0x9097, 0x0fc8, 0x0000ffff); -+ nv_mthd(dev, 0x9097, 0x0df8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0dfc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1948, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1970, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x161c, 0x000009f0); -+ nv_mthd(dev, 0x9097, 0x0dcc, 0x00000010); -+ nv_mthd(dev, 0x9097, 0x163c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x15e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1160, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1164, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1168, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x116c, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1170, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1174, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1178, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x117c, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1180, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1184, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1188, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x118c, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1190, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1194, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1198, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x119c, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11a0, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11a4, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11a8, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11ac, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11b0, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11b4, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11b8, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11bc, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11c0, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11c4, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11c8, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11cc, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11d0, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11d4, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11d8, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x11dc, 0x25e00040); -+ nv_mthd(dev, 0x9097, 0x1880, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1884, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1888, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x188c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1890, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1894, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1898, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x189c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18b0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18b4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18b8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18d0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18d4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18d8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18e0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18f0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x18fc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x17c8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x17cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x17d0, 0x000000ff); -+ nv_mthd(dev, 0x9097, 0x17d4, 0xffffffff); -+ nv_mthd(dev, 0x9097, 0x17d8, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x17dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x15f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x15f8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1434, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1438, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d74, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0dec, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x13a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1318, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1644, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0748, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0de8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1648, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x12a4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1120, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1124, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1128, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x112c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1118, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x164c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1658, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1910, 0x00000290); -+ nv_mthd(dev, 0x9097, 0x1518, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x165c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1520, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1604, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1570, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x13b0, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x13b4, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x020c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1670, 0x30201000); -+ nv_mthd(dev, 0x9097, 0x1674, 0x70605040); -+ nv_mthd(dev, 0x9097, 0x1678, 0xb8a89888); -+ nv_mthd(dev, 0x9097, 0x167c, 0xf8e8d8c8); -+ nv_mthd(dev, 0x9097, 0x166c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1680, 0x00ffff00); -+ nv_mthd(dev, 0x9097, 0x12d0, 0x00000003); -+ nv_mthd(dev, 0x9097, 0x12d4, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1684, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1688, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0dac, 0x00001b02); -+ nv_mthd(dev, 0x9097, 0x0db0, 0x00001b02); -+ nv_mthd(dev, 0x9097, 0x0db4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x168c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x15bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x156c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x187c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1110, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0dc0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0dc4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0dc8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1234, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1690, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x12ac, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x02c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0790, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0794, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0798, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x079c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x07a0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x077c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1000, 0x00000010); -+ nv_mthd(dev, 0x9097, 0x10fc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1290, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0218, 0x00000010); -+ nv_mthd(dev, 0x9097, 0x12d8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x12dc, 0x00000010); -+ nv_mthd(dev, 0x9097, 0x0d94, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x155c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1560, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1564, 0x00001fff); -+ nv_mthd(dev, 0x9097, 0x1574, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1578, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x157c, 0x003fffff); -+ nv_mthd(dev, 0x9097, 0x1354, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1664, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1610, 0x00000012); -+ nv_mthd(dev, 0x9097, 0x1608, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x160c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x162c, 0x00000003); -+ nv_mthd(dev, 0x9097, 0x0210, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0320, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0324, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0328, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x032c, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0330, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0334, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0338, 0x3f800000); -+ nv_mthd(dev, 0x9097, 0x0750, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0760, 0x39291909); -+ nv_mthd(dev, 0x9097, 0x0764, 0x79695949); -+ nv_mthd(dev, 0x9097, 0x0768, 0xb9a99989); -+ nv_mthd(dev, 0x9097, 0x076c, 0xf9e9d9c9); -+ nv_mthd(dev, 0x9097, 0x0770, 0x30201000); -+ nv_mthd(dev, 0x9097, 0x0774, 0x70605040); -+ nv_mthd(dev, 0x9097, 0x0778, 0x00009080); -+ nv_mthd(dev, 0x9097, 0x0780, 0x39291909); -+ nv_mthd(dev, 0x9097, 0x0784, 0x79695949); -+ nv_mthd(dev, 0x9097, 0x0788, 0xb9a99989); -+ nv_mthd(dev, 0x9097, 0x078c, 0xf9e9d9c9); -+ nv_mthd(dev, 0x9097, 0x07d0, 0x30201000); -+ nv_mthd(dev, 0x9097, 0x07d4, 0x70605040); -+ nv_mthd(dev, 0x9097, 0x07d8, 0x00009080); -+ nv_mthd(dev, 0x9097, 0x037c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0740, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0744, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x2600, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1918, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x191c, 0x00000900); -+ nv_mthd(dev, 0x9097, 0x1920, 0x00000405); -+ nv_mthd(dev, 0x9097, 0x1308, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1924, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x13ac, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x192c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x193c, 0x00002c1c); -+ nv_mthd(dev, 0x9097, 0x0d7c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x02c0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1510, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1940, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ff4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0ff8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x194c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1950, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1968, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1590, 0x0000003f); -+ nv_mthd(dev, 0x9097, 0x07e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x07ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x07f0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x07f4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x196c, 0x00000011); -+ nv_mthd(dev, 0x9097, 0x197c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0fcc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0fd0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x02d8, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x1980, 0x00000080); -+ nv_mthd(dev, 0x9097, 0x1504, 0x00000080); -+ nv_mthd(dev, 0x9097, 0x1984, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0300, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x13a8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x12ec, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1310, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1314, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1380, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1384, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1388, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x138c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1390, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1394, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x139c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1398, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1594, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1598, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x159c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x15a0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x15a4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x0f54, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f58, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f5c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x19bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f9c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0fa0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x12cc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x12e8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x130c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1360, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1364, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1368, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x136c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1370, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1374, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1378, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x137c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x133c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1340, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1344, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1348, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x134c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1350, 0x00000002); -+ nv_mthd(dev, 0x9097, 0x1358, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x12e4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x131c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1320, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1324, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1328, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x19c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1140, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x19c4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x19c8, 0x00001500); -+ nv_mthd(dev, 0x9097, 0x135c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x19e0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19e4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19e8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19ec, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19f0, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19f4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19f8, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19fc, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x19cc, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x15b8, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a00, 0x00001111); -+ nv_mthd(dev, 0x9097, 0x1a04, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a08, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a0c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a10, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a14, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a18, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1a1c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d6c, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x0d70, 0xffff0000); -+ nv_mthd(dev, 0x9097, 0x10f8, 0x00001010); -+ nv_mthd(dev, 0x9097, 0x0d80, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d84, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d88, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d8c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0d90, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0da0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1508, 0x80000000); -+ nv_mthd(dev, 0x9097, 0x150c, 0x40000000); -+ nv_mthd(dev, 0x9097, 0x1668, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0318, 0x00000008); -+ nv_mthd(dev, 0x9097, 0x031c, 0x00000008); -+ nv_mthd(dev, 0x9097, 0x0d9c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x07dc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x074c, 0x00000055); -+ nv_mthd(dev, 0x9097, 0x1420, 0x00000003); -+ nv_mthd(dev, 0x9097, 0x17bc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x17c0, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x17c4, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1008, 0x00000008); -+ nv_mthd(dev, 0x9097, 0x100c, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x1010, 0x0000012c); -+ nv_mthd(dev, 0x9097, 0x0d60, 0x00000040); -+ nv_mthd(dev, 0x9097, 0x075c, 0x00000003); -+ nv_mthd(dev, 0x9097, 0x1018, 0x00000020); -+ nv_mthd(dev, 0x9097, 0x101c, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1020, 0x00000020); -+ nv_mthd(dev, 0x9097, 0x1024, 0x00000001); -+ nv_mthd(dev, 0x9097, 0x1444, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x1448, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x144c, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0360, 0x20164010); -+ nv_mthd(dev, 0x9097, 0x0364, 0x00000020); -+ nv_mthd(dev, 0x9097, 0x0368, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0de4, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0204, 0x00000006); -+ nv_mthd(dev, 0x9097, 0x0208, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x02cc, 0x003fffff); -+ nv_mthd(dev, 0x9097, 0x02d0, 0x00000c48); -+ nv_mthd(dev, 0x9097, 0x1220, 0x00000005); -+ nv_mthd(dev, 0x9097, 0x0fdc, 0x00000000); -+ nv_mthd(dev, 0x9097, 0x0f98, 0x00300008); -+ nv_mthd(dev, 0x9097, 0x1284, 0x04000080); -+ nv_mthd(dev, 0x9097, 0x1450, 0x00300008); -+ nv_mthd(dev, 0x9097, 0x1454, 0x04000080); -+ nv_mthd(dev, 0x9097, 0x0214, 0x00000000); -+ /* in trace, right after 0x90c0, not here */ -+ nv_mthd(dev, 0x9097, 0x3410, 0x80002006); -+} -+ -+static void -+nvc0_grctx_generate_902d(struct drm_device *dev) -+{ -+ nv_mthd(dev, 0x902d, 0x0200, 0x000000cf); -+ nv_mthd(dev, 0x902d, 0x0204, 0x00000001); -+ nv_mthd(dev, 0x902d, 0x0208, 0x00000020); -+ nv_mthd(dev, 0x902d, 0x020c, 0x00000001); -+ nv_mthd(dev, 0x902d, 0x0210, 0x00000000); -+ nv_mthd(dev, 0x902d, 0x0214, 0x00000080); -+ nv_mthd(dev, 0x902d, 0x0218, 0x00000100); -+ nv_mthd(dev, 0x902d, 0x021c, 0x00000100); -+ nv_mthd(dev, 0x902d, 0x0220, 0x00000000); -+ nv_mthd(dev, 0x902d, 0x0224, 0x00000000); -+ nv_mthd(dev, 0x902d, 0x0230, 0x000000cf); -+ nv_mthd(dev, 0x902d, 0x0234, 0x00000001); -+ nv_mthd(dev, 0x902d, 0x0238, 0x00000020); -+ nv_mthd(dev, 0x902d, 0x023c, 0x00000001); -+ nv_mthd(dev, 0x902d, 0x0244, 0x00000080); -+ nv_mthd(dev, 0x902d, 0x0248, 0x00000100); -+ nv_mthd(dev, 0x902d, 0x024c, 0x00000100); -+} -+ -+static void -+nvc0_grctx_generate_9039(struct drm_device *dev) -+{ -+ nv_mthd(dev, 0x9039, 0x030c, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x0310, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x0314, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x0320, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x0238, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x023c, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x0318, 0x00000000); -+ nv_mthd(dev, 0x9039, 0x031c, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_90c0(struct drm_device *dev) -+{ -+ nv_mthd(dev, 0x90c0, 0x270c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x272c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x274c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x276c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x278c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x27ac, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x27cc, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x27ec, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x030c, 0x00000001); -+ nv_mthd(dev, 0x90c0, 0x1944, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0758, 0x00000100); -+ nv_mthd(dev, 0x90c0, 0x02c4, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0790, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0794, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0798, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x079c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x07a0, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x077c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0204, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0208, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x020c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0214, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x024c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x0d94, 0x00000001); -+ nv_mthd(dev, 0x90c0, 0x1608, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x160c, 0x00000000); -+ nv_mthd(dev, 0x90c0, 0x1664, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_dispatch(struct drm_device *dev) -+{ -+ int i; -+ -+ nv_wr32(dev, 0x404004, 0x00000000); -+ nv_wr32(dev, 0x404008, 0x00000000); -+ nv_wr32(dev, 0x40400c, 0x00000000); -+ nv_wr32(dev, 0x404010, 0x00000000); -+ nv_wr32(dev, 0x404014, 0x00000000); -+ nv_wr32(dev, 0x404018, 0x00000000); -+ nv_wr32(dev, 0x40401c, 0x00000000); -+ nv_wr32(dev, 0x404020, 0x00000000); -+ nv_wr32(dev, 0x404024, 0x00000000); -+ nv_wr32(dev, 0x404028, 0x00000000); -+ nv_wr32(dev, 0x40402c, 0x00000000); -+ nv_wr32(dev, 0x404044, 0x00000000); -+ nv_wr32(dev, 0x404094, 0x00000000); -+ nv_wr32(dev, 0x404098, 0x00000000); -+ nv_wr32(dev, 0x40409c, 0x00000000); -+ nv_wr32(dev, 0x4040a0, 0x00000000); -+ nv_wr32(dev, 0x4040a4, 0x00000000); -+ nv_wr32(dev, 0x4040a8, 0x00000000); -+ nv_wr32(dev, 0x4040ac, 0x00000000); -+ nv_wr32(dev, 0x4040b0, 0x00000000); -+ nv_wr32(dev, 0x4040b4, 0x00000000); -+ nv_wr32(dev, 0x4040b8, 0x00000000); -+ nv_wr32(dev, 0x4040bc, 0x00000000); -+ nv_wr32(dev, 0x4040c0, 0x00000000); -+ nv_wr32(dev, 0x4040c4, 0x00000000); -+ nv_wr32(dev, 0x4040c8, 0xf0000087); -+ nv_wr32(dev, 0x4040d4, 0x00000000); -+ nv_wr32(dev, 0x4040d8, 0x00000000); -+ nv_wr32(dev, 0x4040dc, 0x00000000); -+ nv_wr32(dev, 0x4040e0, 0x00000000); -+ nv_wr32(dev, 0x4040e4, 0x00000000); -+ nv_wr32(dev, 0x4040e8, 0x00001000); -+ nv_wr32(dev, 0x4040f8, 0x00000000); -+ nv_wr32(dev, 0x404130, 0x00000000); -+ nv_wr32(dev, 0x404134, 0x00000000); -+ nv_wr32(dev, 0x404138, 0x20000040); -+ nv_wr32(dev, 0x404150, 0x0000002e); -+ nv_wr32(dev, 0x404154, 0x00000400); -+ nv_wr32(dev, 0x404158, 0x00000200); -+ nv_wr32(dev, 0x404164, 0x00000055); -+ nv_wr32(dev, 0x404168, 0x00000000); -+ nv_wr32(dev, 0x404174, 0x00000000); -+ nv_wr32(dev, 0x404178, 0x00000000); -+ nv_wr32(dev, 0x40417c, 0x00000000); -+ for (i = 0; i < 8; i++) -+ nv_wr32(dev, 0x404200 + (i * 4), 0x00000000); /* subc */ -+} -+ -+static void -+nvc0_grctx_generate_macro(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x404404, 0x00000000); -+ nv_wr32(dev, 0x404408, 0x00000000); -+ nv_wr32(dev, 0x40440c, 0x00000000); -+ nv_wr32(dev, 0x404410, 0x00000000); -+ nv_wr32(dev, 0x404414, 0x00000000); -+ nv_wr32(dev, 0x404418, 0x00000000); -+ nv_wr32(dev, 0x40441c, 0x00000000); -+ nv_wr32(dev, 0x404420, 0x00000000); -+ nv_wr32(dev, 0x404424, 0x00000000); -+ nv_wr32(dev, 0x404428, 0x00000000); -+ nv_wr32(dev, 0x40442c, 0x00000000); -+ nv_wr32(dev, 0x404430, 0x00000000); -+ nv_wr32(dev, 0x404434, 0x00000000); -+ nv_wr32(dev, 0x404438, 0x00000000); -+ nv_wr32(dev, 0x404460, 0x00000000); -+ nv_wr32(dev, 0x404464, 0x00000000); -+ nv_wr32(dev, 0x404468, 0x00ffffff); -+ nv_wr32(dev, 0x40446c, 0x00000000); -+ nv_wr32(dev, 0x404480, 0x00000001); -+ nv_wr32(dev, 0x404498, 0x00000001); -+} -+ -+static void -+nvc0_grctx_generate_m2mf(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x404604, 0x00000015); -+ nv_wr32(dev, 0x404608, 0x00000000); -+ nv_wr32(dev, 0x40460c, 0x00002e00); -+ nv_wr32(dev, 0x404610, 0x00000100); -+ nv_wr32(dev, 0x404618, 0x00000000); -+ nv_wr32(dev, 0x40461c, 0x00000000); -+ nv_wr32(dev, 0x404620, 0x00000000); -+ nv_wr32(dev, 0x404624, 0x00000000); -+ nv_wr32(dev, 0x404628, 0x00000000); -+ nv_wr32(dev, 0x40462c, 0x00000000); -+ nv_wr32(dev, 0x404630, 0x00000000); -+ nv_wr32(dev, 0x404634, 0x00000000); -+ nv_wr32(dev, 0x404638, 0x00000004); -+ nv_wr32(dev, 0x40463c, 0x00000000); -+ nv_wr32(dev, 0x404640, 0x00000000); -+ nv_wr32(dev, 0x404644, 0x00000000); -+ nv_wr32(dev, 0x404648, 0x00000000); -+ nv_wr32(dev, 0x40464c, 0x00000000); -+ nv_wr32(dev, 0x404650, 0x00000000); -+ nv_wr32(dev, 0x404654, 0x00000000); -+ nv_wr32(dev, 0x404658, 0x00000000); -+ nv_wr32(dev, 0x40465c, 0x007f0100); -+ nv_wr32(dev, 0x404660, 0x00000000); -+ nv_wr32(dev, 0x404664, 0x00000000); -+ nv_wr32(dev, 0x404668, 0x00000000); -+ nv_wr32(dev, 0x40466c, 0x00000000); -+ nv_wr32(dev, 0x404670, 0x00000000); -+ nv_wr32(dev, 0x404674, 0x00000000); -+ nv_wr32(dev, 0x404678, 0x00000000); -+ nv_wr32(dev, 0x40467c, 0x00000002); -+ nv_wr32(dev, 0x404680, 0x00000000); -+ nv_wr32(dev, 0x404684, 0x00000000); -+ nv_wr32(dev, 0x404688, 0x00000000); -+ nv_wr32(dev, 0x40468c, 0x00000000); -+ nv_wr32(dev, 0x404690, 0x00000000); -+ nv_wr32(dev, 0x404694, 0x00000000); -+ nv_wr32(dev, 0x404698, 0x00000000); -+ nv_wr32(dev, 0x40469c, 0x00000000); -+ nv_wr32(dev, 0x4046a0, 0x007f0080); -+ nv_wr32(dev, 0x4046a4, 0x00000000); -+ nv_wr32(dev, 0x4046a8, 0x00000000); -+ nv_wr32(dev, 0x4046ac, 0x00000000); -+ nv_wr32(dev, 0x4046b0, 0x00000000); -+ nv_wr32(dev, 0x4046b4, 0x00000000); -+ nv_wr32(dev, 0x4046b8, 0x00000000); -+ nv_wr32(dev, 0x4046bc, 0x00000000); -+ nv_wr32(dev, 0x4046c0, 0x00000000); -+ nv_wr32(dev, 0x4046c4, 0x00000000); -+ nv_wr32(dev, 0x4046c8, 0x00000000); -+ nv_wr32(dev, 0x4046cc, 0x00000000); -+ nv_wr32(dev, 0x4046d0, 0x00000000); -+ nv_wr32(dev, 0x4046d4, 0x00000000); -+ nv_wr32(dev, 0x4046d8, 0x00000000); -+ nv_wr32(dev, 0x4046dc, 0x00000000); -+ nv_wr32(dev, 0x4046e0, 0x00000000); -+ nv_wr32(dev, 0x4046e4, 0x00000000); -+ nv_wr32(dev, 0x4046e8, 0x00000000); -+ nv_wr32(dev, 0x4046f0, 0x00000000); -+ nv_wr32(dev, 0x4046f4, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_unk47xx(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x404700, 0x00000000); -+ nv_wr32(dev, 0x404704, 0x00000000); -+ nv_wr32(dev, 0x404708, 0x00000000); -+ nv_wr32(dev, 0x40470c, 0x00000000); -+ nv_wr32(dev, 0x404710, 0x00000000); -+ nv_wr32(dev, 0x404714, 0x00000000); -+ nv_wr32(dev, 0x404718, 0x00000000); -+ nv_wr32(dev, 0x40471c, 0x00000000); -+ nv_wr32(dev, 0x404720, 0x00000000); -+ nv_wr32(dev, 0x404724, 0x00000000); -+ nv_wr32(dev, 0x404728, 0x00000000); -+ nv_wr32(dev, 0x40472c, 0x00000000); -+ nv_wr32(dev, 0x404730, 0x00000000); -+ nv_wr32(dev, 0x404734, 0x00000100); -+ nv_wr32(dev, 0x404738, 0x00000000); -+ nv_wr32(dev, 0x40473c, 0x00000000); -+ nv_wr32(dev, 0x404740, 0x00000000); -+ nv_wr32(dev, 0x404744, 0x00000000); -+ nv_wr32(dev, 0x404748, 0x00000000); -+ nv_wr32(dev, 0x40474c, 0x00000000); -+ nv_wr32(dev, 0x404750, 0x00000000); -+ nv_wr32(dev, 0x404754, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_shaders(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x405800, 0x078000bf); -+ nv_wr32(dev, 0x405830, 0x02180000); -+ nv_wr32(dev, 0x405834, 0x00000000); -+ nv_wr32(dev, 0x405838, 0x00000000); -+ nv_wr32(dev, 0x405854, 0x00000000); -+ nv_wr32(dev, 0x405870, 0x00000001); -+ nv_wr32(dev, 0x405874, 0x00000001); -+ nv_wr32(dev, 0x405878, 0x00000001); -+ nv_wr32(dev, 0x40587c, 0x00000001); -+ nv_wr32(dev, 0x405a00, 0x00000000); -+ nv_wr32(dev, 0x405a04, 0x00000000); -+ nv_wr32(dev, 0x405a18, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_unk60xx(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x406020, 0x000103c1); -+ nv_wr32(dev, 0x406028, 0x00000001); -+ nv_wr32(dev, 0x40602c, 0x00000001); -+ nv_wr32(dev, 0x406030, 0x00000001); -+ nv_wr32(dev, 0x406034, 0x00000001); -+} -+ -+static void -+nvc0_grctx_generate_unk64xx(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x4064a8, 0x00000000); -+ nv_wr32(dev, 0x4064ac, 0x00003fff); -+ nv_wr32(dev, 0x4064b4, 0x00000000); -+ nv_wr32(dev, 0x4064b8, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_tpbus(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x407804, 0x00000023); -+ nv_wr32(dev, 0x40780c, 0x0a418820); -+ nv_wr32(dev, 0x407810, 0x062080e6); -+ nv_wr32(dev, 0x407814, 0x020398a4); -+ nv_wr32(dev, 0x407818, 0x0e629062); -+ nv_wr32(dev, 0x40781c, 0x0a418820); -+ nv_wr32(dev, 0x407820, 0x000000e6); -+ nv_wr32(dev, 0x4078bc, 0x00000103); -+} -+ -+static void -+nvc0_grctx_generate_ccache(struct drm_device *dev) -+{ -+ nv_wr32(dev, 0x408000, 0x00000000); -+ nv_wr32(dev, 0x408004, 0x00000000); -+ nv_wr32(dev, 0x408008, 0x00000018); -+ nv_wr32(dev, 0x40800c, 0x00000000); -+ nv_wr32(dev, 0x408010, 0x00000000); -+ nv_wr32(dev, 0x408014, 0x00000069); -+ nv_wr32(dev, 0x408018, 0xe100e100); -+ nv_wr32(dev, 0x408064, 0x00000000); -+} -+ -+static void -+nvc0_grctx_generate_rop(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ // ROPC_BROADCAST -+ nv_wr32(dev, 0x408800, 0x02802a3c); -+ nv_wr32(dev, 0x408804, 0x00000040); -+ nv_wr32(dev, 0x408808, 0x0003e00d); -+ switch (dev_priv->chipset) { -+ case 0xc0: -+ nv_wr32(dev, 0x408900, 0x0080b801); -+ break; -+ case 0xc3: -+ case 0xc4: -+ nv_wr32(dev, 0x408900, 0x3080b801); -+ break; -+ } -+ nv_wr32(dev, 0x408904, 0x02000001); -+ nv_wr32(dev, 0x408908, 0x00c80929); -+ nv_wr32(dev, 0x40890c, 0x00000000); -+ nv_wr32(dev, 0x408980, 0x0000011d); -+} -+ -+static void -+nvc0_grctx_generate_gpc(struct drm_device *dev) -+{ -+ int i; -+ -+ // GPC_BROADCAST -+ nv_wr32(dev, 0x418380, 0x00000016); -+ nv_wr32(dev, 0x418400, 0x38004e00); -+ nv_wr32(dev, 0x418404, 0x71e0ffff); -+ nv_wr32(dev, 0x418408, 0x00000000); -+ nv_wr32(dev, 0x41840c, 0x00001008); -+ nv_wr32(dev, 0x418410, 0x0fff0fff); -+ nv_wr32(dev, 0x418414, 0x00200fff); -+ nv_wr32(dev, 0x418450, 0x00000000); -+ nv_wr32(dev, 0x418454, 0x00000000); -+ nv_wr32(dev, 0x418458, 0x00000000); -+ nv_wr32(dev, 0x41845c, 0x00000000); -+ nv_wr32(dev, 0x418460, 0x00000000); -+ nv_wr32(dev, 0x418464, 0x00000000); -+ nv_wr32(dev, 0x418468, 0x00000001); -+ nv_wr32(dev, 0x41846c, 0x00000000); -+ nv_wr32(dev, 0x418470, 0x00000000); -+ nv_wr32(dev, 0x418600, 0x0000001f); -+ nv_wr32(dev, 0x418684, 0x0000000f); -+ nv_wr32(dev, 0x418700, 0x00000002); -+ nv_wr32(dev, 0x418704, 0x00000080); -+ nv_wr32(dev, 0x418708, 0x00000000); -+ nv_wr32(dev, 0x41870c, 0x07c80000); -+ nv_wr32(dev, 0x418710, 0x00000000); -+ nv_wr32(dev, 0x418800, 0x0006860a); -+ nv_wr32(dev, 0x418808, 0x00000000); -+ nv_wr32(dev, 0x41880c, 0x00000000); -+ nv_wr32(dev, 0x418810, 0x00000000); -+ nv_wr32(dev, 0x418828, 0x00008442); -+ nv_wr32(dev, 0x418830, 0x00000001); -+ nv_wr32(dev, 0x4188d8, 0x00000008); -+ nv_wr32(dev, 0x4188e0, 0x01000000); -+ nv_wr32(dev, 0x4188e8, 0x00000000); -+ nv_wr32(dev, 0x4188ec, 0x00000000); -+ nv_wr32(dev, 0x4188f0, 0x00000000); -+ nv_wr32(dev, 0x4188f4, 0x00000000); -+ nv_wr32(dev, 0x4188f8, 0x00000000); -+ nv_wr32(dev, 0x4188fc, 0x00100000); -+ nv_wr32(dev, 0x41891c, 0x00ff00ff); -+ nv_wr32(dev, 0x418924, 0x00000000); -+ nv_wr32(dev, 0x418928, 0x00ffff00); -+ nv_wr32(dev, 0x41892c, 0x0000ff00); -+ for (i = 0; i < 8; i++) { -+ nv_wr32(dev, 0x418a00 + (i * 0x20), 0x00000000); -+ nv_wr32(dev, 0x418a04 + (i * 0x20), 0x00000000); -+ nv_wr32(dev, 0x418a08 + (i * 0x20), 0x00000000); -+ nv_wr32(dev, 0x418a0c + (i * 0x20), 0x00010000); -+ nv_wr32(dev, 0x418a10 + (i * 0x20), 0x00000000); -+ nv_wr32(dev, 0x418a14 + (i * 0x20), 0x00000000); -+ nv_wr32(dev, 0x418a18 + (i * 0x20), 0x00000000); -+ } -+ nv_wr32(dev, 0x418b00, 0x00000000); -+ nv_wr32(dev, 0x418b08, 0x0a418820); -+ nv_wr32(dev, 0x418b0c, 0x062080e6); -+ nv_wr32(dev, 0x418b10, 0x020398a4); -+ nv_wr32(dev, 0x418b14, 0x0e629062); -+ nv_wr32(dev, 0x418b18, 0x0a418820); -+ nv_wr32(dev, 0x418b1c, 0x000000e6); -+ nv_wr32(dev, 0x418bb8, 0x00000103); -+ nv_wr32(dev, 0x418c08, 0x00000001); -+ nv_wr32(dev, 0x418c10, 0x00000000); -+ nv_wr32(dev, 0x418c14, 0x00000000); -+ nv_wr32(dev, 0x418c18, 0x00000000); -+ nv_wr32(dev, 0x418c1c, 0x00000000); -+ nv_wr32(dev, 0x418c20, 0x00000000); -+ nv_wr32(dev, 0x418c24, 0x00000000); -+ nv_wr32(dev, 0x418c28, 0x00000000); -+ nv_wr32(dev, 0x418c2c, 0x00000000); -+ nv_wr32(dev, 0x418c80, 0x20200004); -+ nv_wr32(dev, 0x418c8c, 0x00000001); -+ nv_wr32(dev, 0x419000, 0x00000780); -+ nv_wr32(dev, 0x419004, 0x00000000); -+ nv_wr32(dev, 0x419008, 0x00000000); -+ nv_wr32(dev, 0x419014, 0x00000004); -+} -+ -+static void -+nvc0_grctx_generate_tp(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ // GPC_BROADCAST.TP_BROADCAST -+ nv_wr32(dev, 0x419848, 0x00000000); -+ nv_wr32(dev, 0x419864, 0x0000012a); -+ nv_wr32(dev, 0x419888, 0x00000000); -+ nv_wr32(dev, 0x419a00, 0x000001f0); -+ nv_wr32(dev, 0x419a04, 0x00000001); -+ nv_wr32(dev, 0x419a08, 0x00000023); -+ nv_wr32(dev, 0x419a0c, 0x00020000); -+ nv_wr32(dev, 0x419a10, 0x00000000); -+ nv_wr32(dev, 0x419a14, 0x00000200); -+ nv_wr32(dev, 0x419a1c, 0x00000000); -+ nv_wr32(dev, 0x419a20, 0x00000800); -+ if (dev_priv->chipset != 0xc0) -+ nv_wr32(dev, 0x00419ac4, 0x0007f440); // 0xc3 -+ nv_wr32(dev, 0x419b00, 0x0a418820); -+ nv_wr32(dev, 0x419b04, 0x062080e6); -+ nv_wr32(dev, 0x419b08, 0x020398a4); -+ nv_wr32(dev, 0x419b0c, 0x0e629062); -+ nv_wr32(dev, 0x419b10, 0x0a418820); -+ nv_wr32(dev, 0x419b14, 0x000000e6); -+ nv_wr32(dev, 0x419bd0, 0x00900103); -+ nv_wr32(dev, 0x419be0, 0x00000001); -+ nv_wr32(dev, 0x419be4, 0x00000000); -+ nv_wr32(dev, 0x419c00, 0x00000002); -+ nv_wr32(dev, 0x419c04, 0x00000006); -+ nv_wr32(dev, 0x419c08, 0x00000002); -+ nv_wr32(dev, 0x419c20, 0x00000000); -+ nv_wr32(dev, 0x419cbc, 0x28137606); -+ nv_wr32(dev, 0x419ce8, 0x00000000); -+ nv_wr32(dev, 0x419cf4, 0x00000183); -+ nv_wr32(dev, 0x419d20, 0x02180000); -+ nv_wr32(dev, 0x419d24, 0x00001fff); -+ nv_wr32(dev, 0x419e04, 0x00000000); -+ nv_wr32(dev, 0x419e08, 0x00000000); -+ nv_wr32(dev, 0x419e0c, 0x00000000); -+ nv_wr32(dev, 0x419e10, 0x00000002); -+ nv_wr32(dev, 0x419e44, 0x001beff2); -+ nv_wr32(dev, 0x419e48, 0x00000000); -+ nv_wr32(dev, 0x419e4c, 0x0000000f); -+ nv_wr32(dev, 0x419e50, 0x00000000); -+ nv_wr32(dev, 0x419e54, 0x00000000); -+ nv_wr32(dev, 0x419e58, 0x00000000); -+ nv_wr32(dev, 0x419e5c, 0x00000000); -+ nv_wr32(dev, 0x419e60, 0x00000000); -+ nv_wr32(dev, 0x419e64, 0x00000000); -+ nv_wr32(dev, 0x419e68, 0x00000000); -+ nv_wr32(dev, 0x419e6c, 0x00000000); -+ nv_wr32(dev, 0x419e70, 0x00000000); -+ nv_wr32(dev, 0x419e74, 0x00000000); -+ nv_wr32(dev, 0x419e78, 0x00000000); -+ nv_wr32(dev, 0x419e7c, 0x00000000); -+ nv_wr32(dev, 0x419e80, 0x00000000); -+ nv_wr32(dev, 0x419e84, 0x00000000); -+ nv_wr32(dev, 0x419e88, 0x00000000); -+ nv_wr32(dev, 0x419e8c, 0x00000000); -+ nv_wr32(dev, 0x419e90, 0x00000000); -+ nv_wr32(dev, 0x419e98, 0x00000000); -+ if (dev_priv->chipset != 0xc0) -+ nv_wr32(dev, 0x419ee0, 0x00011110); -+ nv_wr32(dev, 0x419f50, 0x00000000); -+ nv_wr32(dev, 0x419f54, 0x00000000); -+ if (dev_priv->chipset != 0xc0) -+ nv_wr32(dev, 0x419f58, 0x00000000); -+} -+ -+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 drm_device *dev = chan->dev; -+ int i, gpc, tp, id; -+ u32 r000260, tmp; -+ -+ r000260 = nv_rd32(dev, 0x000260); -+ nv_wr32(dev, 0x000260, r000260 & ~1); -+ nv_wr32(dev, 0x400208, 0x00000000); -+ -+ nvc0_grctx_generate_dispatch(dev); -+ nvc0_grctx_generate_macro(dev); -+ nvc0_grctx_generate_m2mf(dev); -+ nvc0_grctx_generate_unk47xx(dev); -+ nvc0_grctx_generate_shaders(dev); -+ nvc0_grctx_generate_unk60xx(dev); -+ nvc0_grctx_generate_unk64xx(dev); -+ nvc0_grctx_generate_tpbus(dev); -+ nvc0_grctx_generate_ccache(dev); -+ nvc0_grctx_generate_rop(dev); -+ nvc0_grctx_generate_gpc(dev); -+ nvc0_grctx_generate_tp(dev); -+ -+ nv_wr32(dev, 0x404154, 0x00000000); -+ -+ /* fuc "mmio list" writes */ -+ for (i = 0; i < grch->mmio_nr * 8; i += 8) { -+ u32 reg = nv_ro32(grch->mmio, i + 0); -+ nv_wr32(dev, reg, nv_ro32(grch->mmio, i + 4)); -+ } -+ -+ for (tp = 0, id = 0; tp < 4; tp++) { -+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) { -+ if (tp <= priv->tp_nr[gpc]) { -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x698), id); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x4e8), id); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c10 + tp * 4), id); -+ nv_wr32(dev, TP_UNIT(gpc, tp, 0x088), id); -+ id++; -+ } -+ -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c08), priv->tp_nr[gpc]); -+ nv_wr32(dev, GPC_UNIT(gpc, 0x0c8c), priv->tp_nr[gpc]); -+ } -+ } -+ -+ tmp = 0; -+ for (i = 0; i < priv->gpc_nr; i++) -+ tmp |= priv->tp_nr[i] << (i * 4); -+ nv_wr32(dev, 0x406028, tmp); -+ nv_wr32(dev, 0x405870, tmp); -+ -+ nv_wr32(dev, 0x40602c, 0x00000000); -+ nv_wr32(dev, 0x405874, 0x00000000); -+ nv_wr32(dev, 0x406030, 0x00000000); -+ nv_wr32(dev, 0x405878, 0x00000000); -+ nv_wr32(dev, 0x406034, 0x00000000); -+ nv_wr32(dev, 0x40587c, 0x00000000); -+ -+ if (1) { -+ const u8 chipset_tp_max[] = { 16, 0, 0, 4, 8 }; -+ u8 max = chipset_tp_max[dev_priv->chipset & 0x0f]; -+ u8 tpnr[GPC_MAX]; -+ u8 data[32]; -+ -+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); -+ memset(data, 0x1f, sizeof(data)); -+ -+ gpc = -1; -+ for (tp = 0; tp < priv->tp_total; tp++) { -+ do { -+ gpc = (gpc + 1) % priv->gpc_nr; -+ } while (!tpnr[gpc]); -+ tpnr[gpc]--; -+ data[tp] = gpc; -+ } -+ -+ for (i = 0; i < max / 4; i++) -+ nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]); -+ } -+ -+ if (1) { -+ u32 data[6] = {}, data2[2] = {}; -+ u8 tpnr[GPC_MAX]; -+ u8 shift, ntpcv; -+ -+ /* calculate first set of magics */ -+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); -+ -+ for (tp = 0; tp < priv->tp_total; tp++) { -+ do { -+ gpc = (gpc + 1) % priv->gpc_nr; -+ } while (!tpnr[gpc]); -+ tpnr[gpc]--; -+ -+ data[tp / 6] |= gpc << ((tp % 6) * 5); -+ } -+ -+ for (; tp < 32; tp++) -+ data[tp / 6] |= 7 << ((tp % 6) * 5); -+ -+ /* and the second... */ -+ shift = 0; -+ ntpcv = priv->tp_total; -+ while (!(ntpcv & (1 << 4))) { -+ ntpcv <<= 1; -+ shift++; -+ } -+ -+ data2[0] = (ntpcv << 16); -+ data2[0] |= (shift << 21); -+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24); -+ for (i = 1; i < 7; i++) -+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); -+ -+ // 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 -+ nv_wr32(dev, 0x419bd0, (priv->tp_total << 8) | -+ priv->magic_not_rop_nr | -+ data2[0]); -+ nv_wr32(dev, 0x419be4, data2[1]); -+ for (i = 0; i < 6; i++) -+ nv_wr32(dev, 0x419b00 + (i * 4), data[i]); -+ -+ // UNK78xx -+ nv_wr32(dev, 0x4078bc, (priv->tp_total << 8) | -+ priv->magic_not_rop_nr); -+ for (i = 0; i < 6; i++) -+ nv_wr32(dev, 0x40780c + (i * 4), data[i]); -+ } -+ -+ if (1) { -+ u32 tp_mask = 0, tp_set = 0; -+ u8 tpnr[GPC_MAX]; -+ -+ memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); -+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) -+ tp_mask |= ((1 << priv->tp_nr[gpc]) - 1) << (gpc * 8); -+ -+ 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]); -+ tp = priv->tp_nr[gpc] - tpnr[gpc]--; -+ -+ tp_set |= 1 << ((gpc * 8) + tp); -+ -+ do { -+ nv_wr32(dev, 0x406800 + (i * 0x20), tp_set); -+ tp_set ^= tp_mask; -+ nv_wr32(dev, 0x406c00 + (i * 0x20), tp_set); -+ tp_set ^= tp_mask; -+ } while (ltp == (++i * (priv->tp_total - 1) / 32)); -+ i--; -+ } -+ } -+ -+ nv_wr32(dev, 0x400208, 0x80000000); -+ -+ nv_icmd(dev, 0x00001000, 0x00000004); -+ nv_icmd(dev, 0x000000a9, 0x0000ffff); -+ nv_icmd(dev, 0x00000038, 0x0fac6881); -+ nv_icmd(dev, 0x0000003d, 0x00000001); -+ nv_icmd(dev, 0x000000e8, 0x00000400); -+ nv_icmd(dev, 0x000000e9, 0x00000400); -+ nv_icmd(dev, 0x000000ea, 0x00000400); -+ nv_icmd(dev, 0x000000eb, 0x00000400); -+ nv_icmd(dev, 0x000000ec, 0x00000400); -+ nv_icmd(dev, 0x000000ed, 0x00000400); -+ nv_icmd(dev, 0x000000ee, 0x00000400); -+ nv_icmd(dev, 0x000000ef, 0x00000400); -+ nv_icmd(dev, 0x00000078, 0x00000300); -+ nv_icmd(dev, 0x00000079, 0x00000300); -+ nv_icmd(dev, 0x0000007a, 0x00000300); -+ nv_icmd(dev, 0x0000007b, 0x00000300); -+ nv_icmd(dev, 0x0000007c, 0x00000300); -+ nv_icmd(dev, 0x0000007d, 0x00000300); -+ nv_icmd(dev, 0x0000007e, 0x00000300); -+ nv_icmd(dev, 0x0000007f, 0x00000300); -+ nv_icmd(dev, 0x00000050, 0x00000011); -+ nv_icmd(dev, 0x00000058, 0x00000008); -+ nv_icmd(dev, 0x00000059, 0x00000008); -+ nv_icmd(dev, 0x0000005a, 0x00000008); -+ nv_icmd(dev, 0x0000005b, 0x00000008); -+ nv_icmd(dev, 0x0000005c, 0x00000008); -+ nv_icmd(dev, 0x0000005d, 0x00000008); -+ nv_icmd(dev, 0x0000005e, 0x00000008); -+ nv_icmd(dev, 0x0000005f, 0x00000008); -+ nv_icmd(dev, 0x00000208, 0x00000001); -+ nv_icmd(dev, 0x00000209, 0x00000001); -+ nv_icmd(dev, 0x0000020a, 0x00000001); -+ nv_icmd(dev, 0x0000020b, 0x00000001); -+ nv_icmd(dev, 0x0000020c, 0x00000001); -+ nv_icmd(dev, 0x0000020d, 0x00000001); -+ nv_icmd(dev, 0x0000020e, 0x00000001); -+ nv_icmd(dev, 0x0000020f, 0x00000001); -+ nv_icmd(dev, 0x00000081, 0x00000001); -+ nv_icmd(dev, 0x00000085, 0x00000004); -+ nv_icmd(dev, 0x00000088, 0x00000400); -+ nv_icmd(dev, 0x00000090, 0x00000300); -+ nv_icmd(dev, 0x00000098, 0x00001001); -+ nv_icmd(dev, 0x000000e3, 0x00000001); -+ nv_icmd(dev, 0x000000da, 0x00000001); -+ nv_icmd(dev, 0x000000f8, 0x00000003); -+ nv_icmd(dev, 0x000000fa, 0x00000001); -+ nv_icmd(dev, 0x0000009f, 0x0000ffff); -+ nv_icmd(dev, 0x000000a0, 0x0000ffff); -+ nv_icmd(dev, 0x000000a1, 0x0000ffff); -+ nv_icmd(dev, 0x000000a2, 0x0000ffff); -+ nv_icmd(dev, 0x000000b1, 0x00000001); -+ nv_icmd(dev, 0x000000b2, 0x00000000); -+ nv_icmd(dev, 0x000000b3, 0x00000000); -+ nv_icmd(dev, 0x000000b4, 0x00000000); -+ nv_icmd(dev, 0x000000b5, 0x00000000); -+ nv_icmd(dev, 0x000000b6, 0x00000000); -+ nv_icmd(dev, 0x000000b7, 0x00000000); -+ nv_icmd(dev, 0x000000b8, 0x00000000); -+ nv_icmd(dev, 0x000000b9, 0x00000000); -+ nv_icmd(dev, 0x000000ba, 0x00000000); -+ nv_icmd(dev, 0x000000bb, 0x00000000); -+ nv_icmd(dev, 0x000000bc, 0x00000000); -+ nv_icmd(dev, 0x000000bd, 0x00000000); -+ nv_icmd(dev, 0x000000be, 0x00000000); -+ nv_icmd(dev, 0x000000bf, 0x00000000); -+ nv_icmd(dev, 0x000000c0, 0x00000000); -+ nv_icmd(dev, 0x000000c1, 0x00000000); -+ nv_icmd(dev, 0x000000c2, 0x00000000); -+ nv_icmd(dev, 0x000000c3, 0x00000000); -+ nv_icmd(dev, 0x000000c4, 0x00000000); -+ nv_icmd(dev, 0x000000c5, 0x00000000); -+ nv_icmd(dev, 0x000000c6, 0x00000000); -+ nv_icmd(dev, 0x000000c7, 0x00000000); -+ nv_icmd(dev, 0x000000c8, 0x00000000); -+ nv_icmd(dev, 0x000000c9, 0x00000000); -+ nv_icmd(dev, 0x000000ca, 0x00000000); -+ nv_icmd(dev, 0x000000cb, 0x00000000); -+ nv_icmd(dev, 0x000000cc, 0x00000000); -+ nv_icmd(dev, 0x000000cd, 0x00000000); -+ nv_icmd(dev, 0x000000ce, 0x00000000); -+ nv_icmd(dev, 0x000000cf, 0x00000000); -+ nv_icmd(dev, 0x000000d0, 0x00000000); -+ nv_icmd(dev, 0x000000d1, 0x00000000); -+ nv_icmd(dev, 0x000000d2, 0x00000000); -+ nv_icmd(dev, 0x000000d3, 0x00000000); -+ nv_icmd(dev, 0x000000d4, 0x00000000); -+ nv_icmd(dev, 0x000000d5, 0x00000000); -+ nv_icmd(dev, 0x000000d6, 0x00000000); -+ nv_icmd(dev, 0x000000d7, 0x00000000); -+ nv_icmd(dev, 0x000000d8, 0x00000000); -+ nv_icmd(dev, 0x000000d9, 0x00000000); -+ nv_icmd(dev, 0x00000210, 0x00000040); -+ nv_icmd(dev, 0x00000211, 0x00000040); -+ nv_icmd(dev, 0x00000212, 0x00000040); -+ nv_icmd(dev, 0x00000213, 0x00000040); -+ nv_icmd(dev, 0x00000214, 0x00000040); -+ nv_icmd(dev, 0x00000215, 0x00000040); -+ nv_icmd(dev, 0x00000216, 0x00000040); -+ nv_icmd(dev, 0x00000217, 0x00000040); -+ nv_icmd(dev, 0x00000218, 0x0000c080); -+ nv_icmd(dev, 0x00000219, 0x0000c080); -+ nv_icmd(dev, 0x0000021a, 0x0000c080); -+ nv_icmd(dev, 0x0000021b, 0x0000c080); -+ nv_icmd(dev, 0x0000021c, 0x0000c080); -+ nv_icmd(dev, 0x0000021d, 0x0000c080); -+ nv_icmd(dev, 0x0000021e, 0x0000c080); -+ nv_icmd(dev, 0x0000021f, 0x0000c080); -+ nv_icmd(dev, 0x000000ad, 0x0000013e); -+ nv_icmd(dev, 0x000000e1, 0x00000010); -+ nv_icmd(dev, 0x00000290, 0x00000000); -+ nv_icmd(dev, 0x00000291, 0x00000000); -+ nv_icmd(dev, 0x00000292, 0x00000000); -+ nv_icmd(dev, 0x00000293, 0x00000000); -+ nv_icmd(dev, 0x00000294, 0x00000000); -+ nv_icmd(dev, 0x00000295, 0x00000000); -+ nv_icmd(dev, 0x00000296, 0x00000000); -+ nv_icmd(dev, 0x00000297, 0x00000000); -+ nv_icmd(dev, 0x00000298, 0x00000000); -+ nv_icmd(dev, 0x00000299, 0x00000000); -+ nv_icmd(dev, 0x0000029a, 0x00000000); -+ nv_icmd(dev, 0x0000029b, 0x00000000); -+ nv_icmd(dev, 0x0000029c, 0x00000000); -+ nv_icmd(dev, 0x0000029d, 0x00000000); -+ nv_icmd(dev, 0x0000029e, 0x00000000); -+ nv_icmd(dev, 0x0000029f, 0x00000000); -+ nv_icmd(dev, 0x000003b0, 0x00000000); -+ nv_icmd(dev, 0x000003b1, 0x00000000); -+ nv_icmd(dev, 0x000003b2, 0x00000000); -+ nv_icmd(dev, 0x000003b3, 0x00000000); -+ nv_icmd(dev, 0x000003b4, 0x00000000); -+ nv_icmd(dev, 0x000003b5, 0x00000000); -+ nv_icmd(dev, 0x000003b6, 0x00000000); -+ nv_icmd(dev, 0x000003b7, 0x00000000); -+ nv_icmd(dev, 0x000003b8, 0x00000000); -+ nv_icmd(dev, 0x000003b9, 0x00000000); -+ nv_icmd(dev, 0x000003ba, 0x00000000); -+ nv_icmd(dev, 0x000003bb, 0x00000000); -+ nv_icmd(dev, 0x000003bc, 0x00000000); -+ nv_icmd(dev, 0x000003bd, 0x00000000); -+ nv_icmd(dev, 0x000003be, 0x00000000); -+ nv_icmd(dev, 0x000003bf, 0x00000000); -+ nv_icmd(dev, 0x000002a0, 0x00000000); -+ nv_icmd(dev, 0x000002a1, 0x00000000); -+ nv_icmd(dev, 0x000002a2, 0x00000000); -+ nv_icmd(dev, 0x000002a3, 0x00000000); -+ nv_icmd(dev, 0x000002a4, 0x00000000); -+ nv_icmd(dev, 0x000002a5, 0x00000000); -+ nv_icmd(dev, 0x000002a6, 0x00000000); -+ nv_icmd(dev, 0x000002a7, 0x00000000); -+ nv_icmd(dev, 0x000002a8, 0x00000000); -+ nv_icmd(dev, 0x000002a9, 0x00000000); -+ nv_icmd(dev, 0x000002aa, 0x00000000); -+ nv_icmd(dev, 0x000002ab, 0x00000000); -+ nv_icmd(dev, 0x000002ac, 0x00000000); -+ nv_icmd(dev, 0x000002ad, 0x00000000); -+ nv_icmd(dev, 0x000002ae, 0x00000000); -+ nv_icmd(dev, 0x000002af, 0x00000000); -+ nv_icmd(dev, 0x00000420, 0x00000000); -+ nv_icmd(dev, 0x00000421, 0x00000000); -+ nv_icmd(dev, 0x00000422, 0x00000000); -+ nv_icmd(dev, 0x00000423, 0x00000000); -+ nv_icmd(dev, 0x00000424, 0x00000000); -+ nv_icmd(dev, 0x00000425, 0x00000000); -+ nv_icmd(dev, 0x00000426, 0x00000000); -+ nv_icmd(dev, 0x00000427, 0x00000000); -+ nv_icmd(dev, 0x00000428, 0x00000000); -+ nv_icmd(dev, 0x00000429, 0x00000000); -+ nv_icmd(dev, 0x0000042a, 0x00000000); -+ nv_icmd(dev, 0x0000042b, 0x00000000); -+ nv_icmd(dev, 0x0000042c, 0x00000000); -+ nv_icmd(dev, 0x0000042d, 0x00000000); -+ nv_icmd(dev, 0x0000042e, 0x00000000); -+ nv_icmd(dev, 0x0000042f, 0x00000000); -+ nv_icmd(dev, 0x000002b0, 0x00000000); -+ nv_icmd(dev, 0x000002b1, 0x00000000); -+ nv_icmd(dev, 0x000002b2, 0x00000000); -+ nv_icmd(dev, 0x000002b3, 0x00000000); -+ nv_icmd(dev, 0x000002b4, 0x00000000); -+ nv_icmd(dev, 0x000002b5, 0x00000000); -+ nv_icmd(dev, 0x000002b6, 0x00000000); -+ nv_icmd(dev, 0x000002b7, 0x00000000); -+ nv_icmd(dev, 0x000002b8, 0x00000000); -+ nv_icmd(dev, 0x000002b9, 0x00000000); -+ nv_icmd(dev, 0x000002ba, 0x00000000); -+ nv_icmd(dev, 0x000002bb, 0x00000000); -+ nv_icmd(dev, 0x000002bc, 0x00000000); -+ nv_icmd(dev, 0x000002bd, 0x00000000); -+ nv_icmd(dev, 0x000002be, 0x00000000); -+ nv_icmd(dev, 0x000002bf, 0x00000000); -+ nv_icmd(dev, 0x00000430, 0x00000000); -+ nv_icmd(dev, 0x00000431, 0x00000000); -+ nv_icmd(dev, 0x00000432, 0x00000000); -+ nv_icmd(dev, 0x00000433, 0x00000000); -+ nv_icmd(dev, 0x00000434, 0x00000000); -+ nv_icmd(dev, 0x00000435, 0x00000000); -+ nv_icmd(dev, 0x00000436, 0x00000000); -+ nv_icmd(dev, 0x00000437, 0x00000000); -+ nv_icmd(dev, 0x00000438, 0x00000000); -+ nv_icmd(dev, 0x00000439, 0x00000000); -+ nv_icmd(dev, 0x0000043a, 0x00000000); -+ nv_icmd(dev, 0x0000043b, 0x00000000); -+ nv_icmd(dev, 0x0000043c, 0x00000000); -+ nv_icmd(dev, 0x0000043d, 0x00000000); -+ nv_icmd(dev, 0x0000043e, 0x00000000); -+ nv_icmd(dev, 0x0000043f, 0x00000000); -+ nv_icmd(dev, 0x000002c0, 0x00000000); -+ nv_icmd(dev, 0x000002c1, 0x00000000); -+ nv_icmd(dev, 0x000002c2, 0x00000000); -+ nv_icmd(dev, 0x000002c3, 0x00000000); -+ nv_icmd(dev, 0x000002c4, 0x00000000); -+ nv_icmd(dev, 0x000002c5, 0x00000000); -+ nv_icmd(dev, 0x000002c6, 0x00000000); -+ nv_icmd(dev, 0x000002c7, 0x00000000); -+ nv_icmd(dev, 0x000002c8, 0x00000000); -+ nv_icmd(dev, 0x000002c9, 0x00000000); -+ nv_icmd(dev, 0x000002ca, 0x00000000); -+ nv_icmd(dev, 0x000002cb, 0x00000000); -+ nv_icmd(dev, 0x000002cc, 0x00000000); -+ nv_icmd(dev, 0x000002cd, 0x00000000); -+ nv_icmd(dev, 0x000002ce, 0x00000000); -+ nv_icmd(dev, 0x000002cf, 0x00000000); -+ nv_icmd(dev, 0x000004d0, 0x00000000); -+ nv_icmd(dev, 0x000004d1, 0x00000000); -+ nv_icmd(dev, 0x000004d2, 0x00000000); -+ nv_icmd(dev, 0x000004d3, 0x00000000); -+ nv_icmd(dev, 0x000004d4, 0x00000000); -+ nv_icmd(dev, 0x000004d5, 0x00000000); -+ nv_icmd(dev, 0x000004d6, 0x00000000); -+ nv_icmd(dev, 0x000004d7, 0x00000000); -+ nv_icmd(dev, 0x000004d8, 0x00000000); -+ nv_icmd(dev, 0x000004d9, 0x00000000); -+ nv_icmd(dev, 0x000004da, 0x00000000); -+ nv_icmd(dev, 0x000004db, 0x00000000); -+ nv_icmd(dev, 0x000004dc, 0x00000000); -+ nv_icmd(dev, 0x000004dd, 0x00000000); -+ nv_icmd(dev, 0x000004de, 0x00000000); -+ nv_icmd(dev, 0x000004df, 0x00000000); -+ nv_icmd(dev, 0x00000720, 0x00000000); -+ nv_icmd(dev, 0x00000721, 0x00000000); -+ nv_icmd(dev, 0x00000722, 0x00000000); -+ nv_icmd(dev, 0x00000723, 0x00000000); -+ nv_icmd(dev, 0x00000724, 0x00000000); -+ nv_icmd(dev, 0x00000725, 0x00000000); -+ nv_icmd(dev, 0x00000726, 0x00000000); -+ nv_icmd(dev, 0x00000727, 0x00000000); -+ nv_icmd(dev, 0x00000728, 0x00000000); -+ nv_icmd(dev, 0x00000729, 0x00000000); -+ nv_icmd(dev, 0x0000072a, 0x00000000); -+ nv_icmd(dev, 0x0000072b, 0x00000000); -+ nv_icmd(dev, 0x0000072c, 0x00000000); -+ nv_icmd(dev, 0x0000072d, 0x00000000); -+ nv_icmd(dev, 0x0000072e, 0x00000000); -+ nv_icmd(dev, 0x0000072f, 0x00000000); -+ nv_icmd(dev, 0x000008c0, 0x00000000); -+ nv_icmd(dev, 0x000008c1, 0x00000000); -+ nv_icmd(dev, 0x000008c2, 0x00000000); -+ nv_icmd(dev, 0x000008c3, 0x00000000); -+ nv_icmd(dev, 0x000008c4, 0x00000000); -+ nv_icmd(dev, 0x000008c5, 0x00000000); -+ nv_icmd(dev, 0x000008c6, 0x00000000); -+ nv_icmd(dev, 0x000008c7, 0x00000000); -+ nv_icmd(dev, 0x000008c8, 0x00000000); -+ nv_icmd(dev, 0x000008c9, 0x00000000); -+ nv_icmd(dev, 0x000008ca, 0x00000000); -+ nv_icmd(dev, 0x000008cb, 0x00000000); -+ nv_icmd(dev, 0x000008cc, 0x00000000); -+ nv_icmd(dev, 0x000008cd, 0x00000000); -+ nv_icmd(dev, 0x000008ce, 0x00000000); -+ nv_icmd(dev, 0x000008cf, 0x00000000); -+ nv_icmd(dev, 0x00000890, 0x00000000); -+ nv_icmd(dev, 0x00000891, 0x00000000); -+ nv_icmd(dev, 0x00000892, 0x00000000); -+ nv_icmd(dev, 0x00000893, 0x00000000); -+ nv_icmd(dev, 0x00000894, 0x00000000); -+ nv_icmd(dev, 0x00000895, 0x00000000); -+ nv_icmd(dev, 0x00000896, 0x00000000); -+ nv_icmd(dev, 0x00000897, 0x00000000); -+ nv_icmd(dev, 0x00000898, 0x00000000); -+ nv_icmd(dev, 0x00000899, 0x00000000); -+ nv_icmd(dev, 0x0000089a, 0x00000000); -+ nv_icmd(dev, 0x0000089b, 0x00000000); -+ nv_icmd(dev, 0x0000089c, 0x00000000); -+ nv_icmd(dev, 0x0000089d, 0x00000000); -+ nv_icmd(dev, 0x0000089e, 0x00000000); -+ nv_icmd(dev, 0x0000089f, 0x00000000); -+ nv_icmd(dev, 0x000008e0, 0x00000000); -+ nv_icmd(dev, 0x000008e1, 0x00000000); -+ nv_icmd(dev, 0x000008e2, 0x00000000); -+ nv_icmd(dev, 0x000008e3, 0x00000000); -+ nv_icmd(dev, 0x000008e4, 0x00000000); -+ nv_icmd(dev, 0x000008e5, 0x00000000); -+ nv_icmd(dev, 0x000008e6, 0x00000000); -+ nv_icmd(dev, 0x000008e7, 0x00000000); -+ nv_icmd(dev, 0x000008e8, 0x00000000); -+ nv_icmd(dev, 0x000008e9, 0x00000000); -+ nv_icmd(dev, 0x000008ea, 0x00000000); -+ nv_icmd(dev, 0x000008eb, 0x00000000); -+ nv_icmd(dev, 0x000008ec, 0x00000000); -+ nv_icmd(dev, 0x000008ed, 0x00000000); -+ nv_icmd(dev, 0x000008ee, 0x00000000); -+ nv_icmd(dev, 0x000008ef, 0x00000000); -+ nv_icmd(dev, 0x000008a0, 0x00000000); -+ nv_icmd(dev, 0x000008a1, 0x00000000); -+ nv_icmd(dev, 0x000008a2, 0x00000000); -+ nv_icmd(dev, 0x000008a3, 0x00000000); -+ nv_icmd(dev, 0x000008a4, 0x00000000); -+ nv_icmd(dev, 0x000008a5, 0x00000000); -+ nv_icmd(dev, 0x000008a6, 0x00000000); -+ nv_icmd(dev, 0x000008a7, 0x00000000); -+ nv_icmd(dev, 0x000008a8, 0x00000000); -+ nv_icmd(dev, 0x000008a9, 0x00000000); -+ nv_icmd(dev, 0x000008aa, 0x00000000); -+ nv_icmd(dev, 0x000008ab, 0x00000000); -+ nv_icmd(dev, 0x000008ac, 0x00000000); -+ nv_icmd(dev, 0x000008ad, 0x00000000); -+ nv_icmd(dev, 0x000008ae, 0x00000000); -+ nv_icmd(dev, 0x000008af, 0x00000000); -+ nv_icmd(dev, 0x000008f0, 0x00000000); -+ nv_icmd(dev, 0x000008f1, 0x00000000); -+ nv_icmd(dev, 0x000008f2, 0x00000000); -+ nv_icmd(dev, 0x000008f3, 0x00000000); -+ nv_icmd(dev, 0x000008f4, 0x00000000); -+ nv_icmd(dev, 0x000008f5, 0x00000000); -+ nv_icmd(dev, 0x000008f6, 0x00000000); -+ nv_icmd(dev, 0x000008f7, 0x00000000); -+ nv_icmd(dev, 0x000008f8, 0x00000000); -+ nv_icmd(dev, 0x000008f9, 0x00000000); -+ nv_icmd(dev, 0x000008fa, 0x00000000); -+ nv_icmd(dev, 0x000008fb, 0x00000000); -+ nv_icmd(dev, 0x000008fc, 0x00000000); -+ nv_icmd(dev, 0x000008fd, 0x00000000); -+ nv_icmd(dev, 0x000008fe, 0x00000000); -+ nv_icmd(dev, 0x000008ff, 0x00000000); -+ nv_icmd(dev, 0x0000094c, 0x000000ff); -+ nv_icmd(dev, 0x0000094d, 0xffffffff); -+ nv_icmd(dev, 0x0000094e, 0x00000002); -+ nv_icmd(dev, 0x000002ec, 0x00000001); -+ nv_icmd(dev, 0x00000303, 0x00000001); -+ nv_icmd(dev, 0x000002e6, 0x00000001); -+ nv_icmd(dev, 0x00000466, 0x00000052); -+ nv_icmd(dev, 0x00000301, 0x3f800000); -+ nv_icmd(dev, 0x00000304, 0x30201000); -+ nv_icmd(dev, 0x00000305, 0x70605040); -+ nv_icmd(dev, 0x00000306, 0xb8a89888); -+ nv_icmd(dev, 0x00000307, 0xf8e8d8c8); -+ nv_icmd(dev, 0x0000030a, 0x00ffff00); -+ nv_icmd(dev, 0x0000030b, 0x0000001a); -+ nv_icmd(dev, 0x0000030c, 0x00000001); -+ nv_icmd(dev, 0x00000318, 0x00000001); -+ nv_icmd(dev, 0x00000340, 0x00000000); -+ nv_icmd(dev, 0x00000375, 0x00000001); -+ nv_icmd(dev, 0x00000351, 0x00000100); -+ nv_icmd(dev, 0x0000037d, 0x00000006); -+ nv_icmd(dev, 0x000003a0, 0x00000002); -+ nv_icmd(dev, 0x000003aa, 0x00000001); -+ nv_icmd(dev, 0x000003a9, 0x00000001); -+ nv_icmd(dev, 0x00000380, 0x00000001); -+ nv_icmd(dev, 0x00000360, 0x00000040); -+ nv_icmd(dev, 0x00000366, 0x00000000); -+ nv_icmd(dev, 0x00000367, 0x00000000); -+ nv_icmd(dev, 0x00000368, 0x00001fff); -+ nv_icmd(dev, 0x00000370, 0x00000000); -+ nv_icmd(dev, 0x00000371, 0x00000000); -+ nv_icmd(dev, 0x00000372, 0x003fffff); -+ nv_icmd(dev, 0x0000037a, 0x00000012); -+ nv_icmd(dev, 0x000005e0, 0x00000022); -+ nv_icmd(dev, 0x000005e1, 0x00000022); -+ nv_icmd(dev, 0x000005e2, 0x00000022); -+ nv_icmd(dev, 0x000005e3, 0x00000022); -+ nv_icmd(dev, 0x000005e4, 0x00000022); -+ nv_icmd(dev, 0x00000619, 0x00000003); -+ nv_icmd(dev, 0x00000811, 0x00000003); -+ nv_icmd(dev, 0x00000812, 0x00000004); -+ nv_icmd(dev, 0x00000813, 0x00000006); -+ nv_icmd(dev, 0x00000814, 0x00000008); -+ nv_icmd(dev, 0x00000815, 0x0000000b); -+ nv_icmd(dev, 0x00000800, 0x00000001); -+ nv_icmd(dev, 0x00000801, 0x00000001); -+ nv_icmd(dev, 0x00000802, 0x00000001); -+ nv_icmd(dev, 0x00000803, 0x00000001); -+ nv_icmd(dev, 0x00000804, 0x00000001); -+ nv_icmd(dev, 0x00000805, 0x00000001); -+ nv_icmd(dev, 0x00000632, 0x00000001); -+ nv_icmd(dev, 0x00000633, 0x00000002); -+ nv_icmd(dev, 0x00000634, 0x00000003); -+ nv_icmd(dev, 0x00000635, 0x00000004); -+ nv_icmd(dev, 0x00000654, 0x3f800000); -+ nv_icmd(dev, 0x00000657, 0x3f800000); -+ nv_icmd(dev, 0x00000655, 0x3f800000); -+ nv_icmd(dev, 0x00000656, 0x3f800000); -+ nv_icmd(dev, 0x000006cd, 0x3f800000); -+ nv_icmd(dev, 0x000007f5, 0x3f800000); -+ nv_icmd(dev, 0x000007dc, 0x39291909); -+ nv_icmd(dev, 0x000007dd, 0x79695949); -+ nv_icmd(dev, 0x000007de, 0xb9a99989); -+ nv_icmd(dev, 0x000007df, 0xf9e9d9c9); -+ nv_icmd(dev, 0x000007e8, 0x00003210); -+ nv_icmd(dev, 0x000007e9, 0x00007654); -+ nv_icmd(dev, 0x000007ea, 0x00000098); -+ nv_icmd(dev, 0x000007ec, 0x39291909); -+ nv_icmd(dev, 0x000007ed, 0x79695949); -+ nv_icmd(dev, 0x000007ee, 0xb9a99989); -+ nv_icmd(dev, 0x000007ef, 0xf9e9d9c9); -+ nv_icmd(dev, 0x000007f0, 0x00003210); -+ nv_icmd(dev, 0x000007f1, 0x00007654); -+ nv_icmd(dev, 0x000007f2, 0x00000098); -+ nv_icmd(dev, 0x000005a5, 0x00000001); -+ nv_icmd(dev, 0x00000980, 0x00000000); -+ nv_icmd(dev, 0x00000981, 0x00000000); -+ nv_icmd(dev, 0x00000982, 0x00000000); -+ nv_icmd(dev, 0x00000983, 0x00000000); -+ nv_icmd(dev, 0x00000984, 0x00000000); -+ nv_icmd(dev, 0x00000985, 0x00000000); -+ nv_icmd(dev, 0x00000986, 0x00000000); -+ nv_icmd(dev, 0x00000987, 0x00000000); -+ nv_icmd(dev, 0x00000988, 0x00000000); -+ nv_icmd(dev, 0x00000989, 0x00000000); -+ nv_icmd(dev, 0x0000098a, 0x00000000); -+ nv_icmd(dev, 0x0000098b, 0x00000000); -+ nv_icmd(dev, 0x0000098c, 0x00000000); -+ nv_icmd(dev, 0x0000098d, 0x00000000); -+ nv_icmd(dev, 0x0000098e, 0x00000000); -+ nv_icmd(dev, 0x0000098f, 0x00000000); -+ nv_icmd(dev, 0x00000990, 0x00000000); -+ nv_icmd(dev, 0x00000991, 0x00000000); -+ nv_icmd(dev, 0x00000992, 0x00000000); -+ nv_icmd(dev, 0x00000993, 0x00000000); -+ nv_icmd(dev, 0x00000994, 0x00000000); -+ nv_icmd(dev, 0x00000995, 0x00000000); -+ nv_icmd(dev, 0x00000996, 0x00000000); -+ nv_icmd(dev, 0x00000997, 0x00000000); -+ nv_icmd(dev, 0x00000998, 0x00000000); -+ nv_icmd(dev, 0x00000999, 0x00000000); -+ nv_icmd(dev, 0x0000099a, 0x00000000); -+ nv_icmd(dev, 0x0000099b, 0x00000000); -+ nv_icmd(dev, 0x0000099c, 0x00000000); -+ nv_icmd(dev, 0x0000099d, 0x00000000); -+ nv_icmd(dev, 0x0000099e, 0x00000000); -+ nv_icmd(dev, 0x0000099f, 0x00000000); -+ nv_icmd(dev, 0x000009a0, 0x00000000); -+ nv_icmd(dev, 0x000009a1, 0x00000000); -+ nv_icmd(dev, 0x000009a2, 0x00000000); -+ nv_icmd(dev, 0x000009a3, 0x00000000); -+ nv_icmd(dev, 0x000009a4, 0x00000000); -+ nv_icmd(dev, 0x000009a5, 0x00000000); -+ nv_icmd(dev, 0x000009a6, 0x00000000); -+ nv_icmd(dev, 0x000009a7, 0x00000000); -+ nv_icmd(dev, 0x000009a8, 0x00000000); -+ nv_icmd(dev, 0x000009a9, 0x00000000); -+ nv_icmd(dev, 0x000009aa, 0x00000000); -+ nv_icmd(dev, 0x000009ab, 0x00000000); -+ nv_icmd(dev, 0x000009ac, 0x00000000); -+ nv_icmd(dev, 0x000009ad, 0x00000000); -+ nv_icmd(dev, 0x000009ae, 0x00000000); -+ nv_icmd(dev, 0x000009af, 0x00000000); -+ nv_icmd(dev, 0x000009b0, 0x00000000); -+ nv_icmd(dev, 0x000009b1, 0x00000000); -+ nv_icmd(dev, 0x000009b2, 0x00000000); -+ nv_icmd(dev, 0x000009b3, 0x00000000); -+ nv_icmd(dev, 0x000009b4, 0x00000000); -+ nv_icmd(dev, 0x000009b5, 0x00000000); -+ nv_icmd(dev, 0x000009b6, 0x00000000); -+ nv_icmd(dev, 0x000009b7, 0x00000000); -+ nv_icmd(dev, 0x000009b8, 0x00000000); -+ nv_icmd(dev, 0x000009b9, 0x00000000); -+ nv_icmd(dev, 0x000009ba, 0x00000000); -+ nv_icmd(dev, 0x000009bb, 0x00000000); -+ nv_icmd(dev, 0x000009bc, 0x00000000); -+ nv_icmd(dev, 0x000009bd, 0x00000000); -+ nv_icmd(dev, 0x000009be, 0x00000000); -+ nv_icmd(dev, 0x000009bf, 0x00000000); -+ nv_icmd(dev, 0x000009c0, 0x00000000); -+ nv_icmd(dev, 0x000009c1, 0x00000000); -+ nv_icmd(dev, 0x000009c2, 0x00000000); -+ nv_icmd(dev, 0x000009c3, 0x00000000); -+ nv_icmd(dev, 0x000009c4, 0x00000000); -+ nv_icmd(dev, 0x000009c5, 0x00000000); -+ nv_icmd(dev, 0x000009c6, 0x00000000); -+ nv_icmd(dev, 0x000009c7, 0x00000000); -+ nv_icmd(dev, 0x000009c8, 0x00000000); -+ nv_icmd(dev, 0x000009c9, 0x00000000); -+ nv_icmd(dev, 0x000009ca, 0x00000000); -+ nv_icmd(dev, 0x000009cb, 0x00000000); -+ nv_icmd(dev, 0x000009cc, 0x00000000); -+ nv_icmd(dev, 0x000009cd, 0x00000000); -+ nv_icmd(dev, 0x000009ce, 0x00000000); -+ nv_icmd(dev, 0x000009cf, 0x00000000); -+ nv_icmd(dev, 0x000009d0, 0x00000000); -+ nv_icmd(dev, 0x000009d1, 0x00000000); -+ nv_icmd(dev, 0x000009d2, 0x00000000); -+ nv_icmd(dev, 0x000009d3, 0x00000000); -+ nv_icmd(dev, 0x000009d4, 0x00000000); -+ nv_icmd(dev, 0x000009d5, 0x00000000); -+ nv_icmd(dev, 0x000009d6, 0x00000000); -+ nv_icmd(dev, 0x000009d7, 0x00000000); -+ nv_icmd(dev, 0x000009d8, 0x00000000); -+ nv_icmd(dev, 0x000009d9, 0x00000000); -+ nv_icmd(dev, 0x000009da, 0x00000000); -+ nv_icmd(dev, 0x000009db, 0x00000000); -+ nv_icmd(dev, 0x000009dc, 0x00000000); -+ nv_icmd(dev, 0x000009dd, 0x00000000); -+ nv_icmd(dev, 0x000009de, 0x00000000); -+ nv_icmd(dev, 0x000009df, 0x00000000); -+ nv_icmd(dev, 0x000009e0, 0x00000000); -+ nv_icmd(dev, 0x000009e1, 0x00000000); -+ nv_icmd(dev, 0x000009e2, 0x00000000); -+ nv_icmd(dev, 0x000009e3, 0x00000000); -+ nv_icmd(dev, 0x000009e4, 0x00000000); -+ nv_icmd(dev, 0x000009e5, 0x00000000); -+ nv_icmd(dev, 0x000009e6, 0x00000000); -+ nv_icmd(dev, 0x000009e7, 0x00000000); -+ nv_icmd(dev, 0x000009e8, 0x00000000); -+ nv_icmd(dev, 0x000009e9, 0x00000000); -+ nv_icmd(dev, 0x000009ea, 0x00000000); -+ nv_icmd(dev, 0x000009eb, 0x00000000); -+ nv_icmd(dev, 0x000009ec, 0x00000000); -+ nv_icmd(dev, 0x000009ed, 0x00000000); -+ nv_icmd(dev, 0x000009ee, 0x00000000); -+ nv_icmd(dev, 0x000009ef, 0x00000000); -+ nv_icmd(dev, 0x000009f0, 0x00000000); -+ nv_icmd(dev, 0x000009f1, 0x00000000); -+ nv_icmd(dev, 0x000009f2, 0x00000000); -+ nv_icmd(dev, 0x000009f3, 0x00000000); -+ nv_icmd(dev, 0x000009f4, 0x00000000); -+ nv_icmd(dev, 0x000009f5, 0x00000000); -+ nv_icmd(dev, 0x000009f6, 0x00000000); -+ nv_icmd(dev, 0x000009f7, 0x00000000); -+ nv_icmd(dev, 0x000009f8, 0x00000000); -+ nv_icmd(dev, 0x000009f9, 0x00000000); -+ nv_icmd(dev, 0x000009fa, 0x00000000); -+ nv_icmd(dev, 0x000009fb, 0x00000000); -+ nv_icmd(dev, 0x000009fc, 0x00000000); -+ nv_icmd(dev, 0x000009fd, 0x00000000); -+ nv_icmd(dev, 0x000009fe, 0x00000000); -+ nv_icmd(dev, 0x000009ff, 0x00000000); -+ nv_icmd(dev, 0x00000468, 0x00000004); -+ nv_icmd(dev, 0x0000046c, 0x00000001); -+ nv_icmd(dev, 0x00000470, 0x00000000); -+ nv_icmd(dev, 0x00000471, 0x00000000); -+ nv_icmd(dev, 0x00000472, 0x00000000); -+ nv_icmd(dev, 0x00000473, 0x00000000); -+ nv_icmd(dev, 0x00000474, 0x00000000); -+ nv_icmd(dev, 0x00000475, 0x00000000); -+ nv_icmd(dev, 0x00000476, 0x00000000); -+ nv_icmd(dev, 0x00000477, 0x00000000); -+ nv_icmd(dev, 0x00000478, 0x00000000); -+ nv_icmd(dev, 0x00000479, 0x00000000); -+ nv_icmd(dev, 0x0000047a, 0x00000000); -+ nv_icmd(dev, 0x0000047b, 0x00000000); -+ nv_icmd(dev, 0x0000047c, 0x00000000); -+ nv_icmd(dev, 0x0000047d, 0x00000000); -+ nv_icmd(dev, 0x0000047e, 0x00000000); -+ nv_icmd(dev, 0x0000047f, 0x00000000); -+ nv_icmd(dev, 0x00000480, 0x00000000); -+ nv_icmd(dev, 0x00000481, 0x00000000); -+ nv_icmd(dev, 0x00000482, 0x00000000); -+ nv_icmd(dev, 0x00000483, 0x00000000); -+ nv_icmd(dev, 0x00000484, 0x00000000); -+ nv_icmd(dev, 0x00000485, 0x00000000); -+ nv_icmd(dev, 0x00000486, 0x00000000); -+ nv_icmd(dev, 0x00000487, 0x00000000); -+ nv_icmd(dev, 0x00000488, 0x00000000); -+ nv_icmd(dev, 0x00000489, 0x00000000); -+ nv_icmd(dev, 0x0000048a, 0x00000000); -+ nv_icmd(dev, 0x0000048b, 0x00000000); -+ nv_icmd(dev, 0x0000048c, 0x00000000); -+ nv_icmd(dev, 0x0000048d, 0x00000000); -+ nv_icmd(dev, 0x0000048e, 0x00000000); -+ nv_icmd(dev, 0x0000048f, 0x00000000); -+ nv_icmd(dev, 0x00000490, 0x00000000); -+ nv_icmd(dev, 0x00000491, 0x00000000); -+ nv_icmd(dev, 0x00000492, 0x00000000); -+ nv_icmd(dev, 0x00000493, 0x00000000); -+ nv_icmd(dev, 0x00000494, 0x00000000); -+ nv_icmd(dev, 0x00000495, 0x00000000); -+ nv_icmd(dev, 0x00000496, 0x00000000); -+ nv_icmd(dev, 0x00000497, 0x00000000); -+ nv_icmd(dev, 0x00000498, 0x00000000); -+ nv_icmd(dev, 0x00000499, 0x00000000); -+ nv_icmd(dev, 0x0000049a, 0x00000000); -+ nv_icmd(dev, 0x0000049b, 0x00000000); -+ nv_icmd(dev, 0x0000049c, 0x00000000); -+ nv_icmd(dev, 0x0000049d, 0x00000000); -+ nv_icmd(dev, 0x0000049e, 0x00000000); -+ nv_icmd(dev, 0x0000049f, 0x00000000); -+ nv_icmd(dev, 0x000004a0, 0x00000000); -+ nv_icmd(dev, 0x000004a1, 0x00000000); -+ nv_icmd(dev, 0x000004a2, 0x00000000); -+ nv_icmd(dev, 0x000004a3, 0x00000000); -+ nv_icmd(dev, 0x000004a4, 0x00000000); -+ nv_icmd(dev, 0x000004a5, 0x00000000); -+ nv_icmd(dev, 0x000004a6, 0x00000000); -+ nv_icmd(dev, 0x000004a7, 0x00000000); -+ nv_icmd(dev, 0x000004a8, 0x00000000); -+ nv_icmd(dev, 0x000004a9, 0x00000000); -+ nv_icmd(dev, 0x000004aa, 0x00000000); -+ nv_icmd(dev, 0x000004ab, 0x00000000); -+ nv_icmd(dev, 0x000004ac, 0x00000000); -+ nv_icmd(dev, 0x000004ad, 0x00000000); -+ nv_icmd(dev, 0x000004ae, 0x00000000); -+ nv_icmd(dev, 0x000004af, 0x00000000); -+ nv_icmd(dev, 0x000004b0, 0x00000000); -+ nv_icmd(dev, 0x000004b1, 0x00000000); -+ nv_icmd(dev, 0x000004b2, 0x00000000); -+ nv_icmd(dev, 0x000004b3, 0x00000000); -+ nv_icmd(dev, 0x000004b4, 0x00000000); -+ nv_icmd(dev, 0x000004b5, 0x00000000); -+ nv_icmd(dev, 0x000004b6, 0x00000000); -+ nv_icmd(dev, 0x000004b7, 0x00000000); -+ nv_icmd(dev, 0x000004b8, 0x00000000); -+ nv_icmd(dev, 0x000004b9, 0x00000000); -+ nv_icmd(dev, 0x000004ba, 0x00000000); -+ nv_icmd(dev, 0x000004bb, 0x00000000); -+ nv_icmd(dev, 0x000004bc, 0x00000000); -+ nv_icmd(dev, 0x000004bd, 0x00000000); -+ nv_icmd(dev, 0x000004be, 0x00000000); -+ nv_icmd(dev, 0x000004bf, 0x00000000); -+ nv_icmd(dev, 0x000004c0, 0x00000000); -+ nv_icmd(dev, 0x000004c1, 0x00000000); -+ nv_icmd(dev, 0x000004c2, 0x00000000); -+ nv_icmd(dev, 0x000004c3, 0x00000000); -+ nv_icmd(dev, 0x000004c4, 0x00000000); -+ nv_icmd(dev, 0x000004c5, 0x00000000); -+ nv_icmd(dev, 0x000004c6, 0x00000000); -+ nv_icmd(dev, 0x000004c7, 0x00000000); -+ nv_icmd(dev, 0x000004c8, 0x00000000); -+ nv_icmd(dev, 0x000004c9, 0x00000000); -+ nv_icmd(dev, 0x000004ca, 0x00000000); -+ nv_icmd(dev, 0x000004cb, 0x00000000); -+ nv_icmd(dev, 0x000004cc, 0x00000000); -+ nv_icmd(dev, 0x000004cd, 0x00000000); -+ nv_icmd(dev, 0x000004ce, 0x00000000); -+ nv_icmd(dev, 0x000004cf, 0x00000000); -+ nv_icmd(dev, 0x00000510, 0x3f800000); -+ nv_icmd(dev, 0x00000511, 0x3f800000); -+ nv_icmd(dev, 0x00000512, 0x3f800000); -+ nv_icmd(dev, 0x00000513, 0x3f800000); -+ nv_icmd(dev, 0x00000514, 0x3f800000); -+ nv_icmd(dev, 0x00000515, 0x3f800000); -+ nv_icmd(dev, 0x00000516, 0x3f800000); -+ nv_icmd(dev, 0x00000517, 0x3f800000); -+ nv_icmd(dev, 0x00000518, 0x3f800000); -+ nv_icmd(dev, 0x00000519, 0x3f800000); -+ nv_icmd(dev, 0x0000051a, 0x3f800000); -+ nv_icmd(dev, 0x0000051b, 0x3f800000); -+ nv_icmd(dev, 0x0000051c, 0x3f800000); -+ nv_icmd(dev, 0x0000051d, 0x3f800000); -+ nv_icmd(dev, 0x0000051e, 0x3f800000); -+ nv_icmd(dev, 0x0000051f, 0x3f800000); -+ nv_icmd(dev, 0x00000520, 0x000002b6); -+ nv_icmd(dev, 0x00000529, 0x00000001); -+ nv_icmd(dev, 0x00000530, 0xffff0000); -+ nv_icmd(dev, 0x00000531, 0xffff0000); -+ nv_icmd(dev, 0x00000532, 0xffff0000); -+ nv_icmd(dev, 0x00000533, 0xffff0000); -+ nv_icmd(dev, 0x00000534, 0xffff0000); -+ nv_icmd(dev, 0x00000535, 0xffff0000); -+ nv_icmd(dev, 0x00000536, 0xffff0000); -+ nv_icmd(dev, 0x00000537, 0xffff0000); -+ nv_icmd(dev, 0x00000538, 0xffff0000); -+ nv_icmd(dev, 0x00000539, 0xffff0000); -+ nv_icmd(dev, 0x0000053a, 0xffff0000); -+ nv_icmd(dev, 0x0000053b, 0xffff0000); -+ nv_icmd(dev, 0x0000053c, 0xffff0000); -+ nv_icmd(dev, 0x0000053d, 0xffff0000); -+ nv_icmd(dev, 0x0000053e, 0xffff0000); -+ nv_icmd(dev, 0x0000053f, 0xffff0000); -+ nv_icmd(dev, 0x00000585, 0x0000003f); -+ nv_icmd(dev, 0x00000576, 0x00000003); -+ nv_icmd(dev, 0x00000586, 0x00000040); -+ nv_icmd(dev, 0x00000582, 0x00000080); -+ nv_icmd(dev, 0x00000583, 0x00000080); -+ nv_icmd(dev, 0x000005c2, 0x00000001); -+ nv_icmd(dev, 0x00000638, 0x00000001); -+ nv_icmd(dev, 0x00000639, 0x00000001); -+ nv_icmd(dev, 0x0000063a, 0x00000002); -+ nv_icmd(dev, 0x0000063b, 0x00000001); -+ nv_icmd(dev, 0x0000063c, 0x00000001); -+ nv_icmd(dev, 0x0000063d, 0x00000002); -+ nv_icmd(dev, 0x0000063e, 0x00000001); -+ nv_icmd(dev, 0x000008b8, 0x00000001); -+ nv_icmd(dev, 0x000008b9, 0x00000001); -+ nv_icmd(dev, 0x000008ba, 0x00000001); -+ nv_icmd(dev, 0x000008bb, 0x00000001); -+ nv_icmd(dev, 0x000008bc, 0x00000001); -+ nv_icmd(dev, 0x000008bd, 0x00000001); -+ nv_icmd(dev, 0x000008be, 0x00000001); -+ nv_icmd(dev, 0x000008bf, 0x00000001); -+ nv_icmd(dev, 0x00000900, 0x00000001); -+ nv_icmd(dev, 0x00000901, 0x00000001); -+ nv_icmd(dev, 0x00000902, 0x00000001); -+ nv_icmd(dev, 0x00000903, 0x00000001); -+ nv_icmd(dev, 0x00000904, 0x00000001); -+ nv_icmd(dev, 0x00000905, 0x00000001); -+ nv_icmd(dev, 0x00000906, 0x00000001); -+ nv_icmd(dev, 0x00000907, 0x00000001); -+ nv_icmd(dev, 0x00000908, 0x00000002); -+ nv_icmd(dev, 0x00000909, 0x00000002); -+ nv_icmd(dev, 0x0000090a, 0x00000002); -+ nv_icmd(dev, 0x0000090b, 0x00000002); -+ nv_icmd(dev, 0x0000090c, 0x00000002); -+ nv_icmd(dev, 0x0000090d, 0x00000002); -+ nv_icmd(dev, 0x0000090e, 0x00000002); -+ nv_icmd(dev, 0x0000090f, 0x00000002); -+ nv_icmd(dev, 0x00000910, 0x00000001); -+ nv_icmd(dev, 0x00000911, 0x00000001); -+ nv_icmd(dev, 0x00000912, 0x00000001); -+ nv_icmd(dev, 0x00000913, 0x00000001); -+ nv_icmd(dev, 0x00000914, 0x00000001); -+ nv_icmd(dev, 0x00000915, 0x00000001); -+ nv_icmd(dev, 0x00000916, 0x00000001); -+ nv_icmd(dev, 0x00000917, 0x00000001); -+ nv_icmd(dev, 0x00000918, 0x00000001); -+ nv_icmd(dev, 0x00000919, 0x00000001); -+ nv_icmd(dev, 0x0000091a, 0x00000001); -+ nv_icmd(dev, 0x0000091b, 0x00000001); -+ nv_icmd(dev, 0x0000091c, 0x00000001); -+ nv_icmd(dev, 0x0000091d, 0x00000001); -+ nv_icmd(dev, 0x0000091e, 0x00000001); -+ nv_icmd(dev, 0x0000091f, 0x00000001); -+ nv_icmd(dev, 0x00000920, 0x00000002); -+ nv_icmd(dev, 0x00000921, 0x00000002); -+ nv_icmd(dev, 0x00000922, 0x00000002); -+ nv_icmd(dev, 0x00000923, 0x00000002); -+ nv_icmd(dev, 0x00000924, 0x00000002); -+ nv_icmd(dev, 0x00000925, 0x00000002); -+ nv_icmd(dev, 0x00000926, 0x00000002); -+ nv_icmd(dev, 0x00000927, 0x00000002); -+ nv_icmd(dev, 0x00000928, 0x00000001); -+ nv_icmd(dev, 0x00000929, 0x00000001); -+ nv_icmd(dev, 0x0000092a, 0x00000001); -+ nv_icmd(dev, 0x0000092b, 0x00000001); -+ nv_icmd(dev, 0x0000092c, 0x00000001); -+ nv_icmd(dev, 0x0000092d, 0x00000001); -+ nv_icmd(dev, 0x0000092e, 0x00000001); -+ nv_icmd(dev, 0x0000092f, 0x00000001); -+ nv_icmd(dev, 0x00000648, 0x00000001); -+ nv_icmd(dev, 0x00000649, 0x00000001); -+ nv_icmd(dev, 0x0000064a, 0x00000001); -+ nv_icmd(dev, 0x0000064b, 0x00000001); -+ nv_icmd(dev, 0x0000064c, 0x00000001); -+ nv_icmd(dev, 0x0000064d, 0x00000001); -+ nv_icmd(dev, 0x0000064e, 0x00000001); -+ nv_icmd(dev, 0x0000064f, 0x00000001); -+ nv_icmd(dev, 0x00000650, 0x00000001); -+ nv_icmd(dev, 0x00000658, 0x0000000f); -+ nv_icmd(dev, 0x000007ff, 0x0000000a); -+ nv_icmd(dev, 0x0000066a, 0x40000000); -+ nv_icmd(dev, 0x0000066b, 0x10000000); -+ nv_icmd(dev, 0x0000066c, 0xffff0000); -+ nv_icmd(dev, 0x0000066d, 0xffff0000); -+ nv_icmd(dev, 0x000007af, 0x00000008); -+ nv_icmd(dev, 0x000007b0, 0x00000008); -+ nv_icmd(dev, 0x000007f6, 0x00000001); -+ nv_icmd(dev, 0x000006b2, 0x00000055); -+ nv_icmd(dev, 0x000007ad, 0x00000003); -+ nv_icmd(dev, 0x00000937, 0x00000001); -+ nv_icmd(dev, 0x00000971, 0x00000008); -+ nv_icmd(dev, 0x00000972, 0x00000040); -+ nv_icmd(dev, 0x00000973, 0x0000012c); -+ nv_icmd(dev, 0x0000097c, 0x00000040); -+ nv_icmd(dev, 0x00000979, 0x00000003); -+ nv_icmd(dev, 0x00000975, 0x00000020); -+ nv_icmd(dev, 0x00000976, 0x00000001); -+ nv_icmd(dev, 0x00000977, 0x00000020); -+ nv_icmd(dev, 0x00000978, 0x00000001); -+ nv_icmd(dev, 0x00000957, 0x00000003); -+ nv_icmd(dev, 0x0000095e, 0x20164010); -+ nv_icmd(dev, 0x0000095f, 0x00000020); -+ nv_icmd(dev, 0x00000683, 0x00000006); -+ nv_icmd(dev, 0x00000685, 0x003fffff); -+ nv_icmd(dev, 0x00000687, 0x00000c48); -+ nv_icmd(dev, 0x000006a0, 0x00000005); -+ nv_icmd(dev, 0x00000840, 0x00300008); -+ nv_icmd(dev, 0x00000841, 0x04000080); -+ nv_icmd(dev, 0x00000842, 0x00300008); -+ nv_icmd(dev, 0x00000843, 0x04000080); -+ nv_icmd(dev, 0x00000818, 0x00000000); -+ nv_icmd(dev, 0x00000819, 0x00000000); -+ nv_icmd(dev, 0x0000081a, 0x00000000); -+ nv_icmd(dev, 0x0000081b, 0x00000000); -+ nv_icmd(dev, 0x0000081c, 0x00000000); -+ nv_icmd(dev, 0x0000081d, 0x00000000); -+ nv_icmd(dev, 0x0000081e, 0x00000000); -+ nv_icmd(dev, 0x0000081f, 0x00000000); -+ nv_icmd(dev, 0x00000848, 0x00000000); -+ nv_icmd(dev, 0x00000849, 0x00000000); -+ nv_icmd(dev, 0x0000084a, 0x00000000); -+ nv_icmd(dev, 0x0000084b, 0x00000000); -+ nv_icmd(dev, 0x0000084c, 0x00000000); -+ nv_icmd(dev, 0x0000084d, 0x00000000); -+ nv_icmd(dev, 0x0000084e, 0x00000000); -+ nv_icmd(dev, 0x0000084f, 0x00000000); -+ nv_icmd(dev, 0x00000850, 0x00000000); -+ nv_icmd(dev, 0x00000851, 0x00000000); -+ nv_icmd(dev, 0x00000852, 0x00000000); -+ nv_icmd(dev, 0x00000853, 0x00000000); -+ nv_icmd(dev, 0x00000854, 0x00000000); -+ nv_icmd(dev, 0x00000855, 0x00000000); -+ nv_icmd(dev, 0x00000856, 0x00000000); -+ nv_icmd(dev, 0x00000857, 0x00000000); -+ nv_icmd(dev, 0x00000738, 0x00000000); -+ nv_icmd(dev, 0x000006aa, 0x00000001); -+ nv_icmd(dev, 0x000006ab, 0x00000002); -+ nv_icmd(dev, 0x000006ac, 0x00000080); -+ nv_icmd(dev, 0x000006ad, 0x00000100); -+ nv_icmd(dev, 0x000006ae, 0x00000100); -+ nv_icmd(dev, 0x000006b1, 0x00000011); -+ nv_icmd(dev, 0x000006bb, 0x000000cf); -+ nv_icmd(dev, 0x000006ce, 0x2a712488); -+ nv_icmd(dev, 0x00000739, 0x4085c000); -+ nv_icmd(dev, 0x0000073a, 0x00000080); -+ nv_icmd(dev, 0x00000786, 0x80000100); -+ nv_icmd(dev, 0x0000073c, 0x00010100); -+ nv_icmd(dev, 0x0000073d, 0x02800000); -+ nv_icmd(dev, 0x00000787, 0x000000cf); -+ nv_icmd(dev, 0x0000078c, 0x00000008); -+ nv_icmd(dev, 0x00000792, 0x00000001); -+ nv_icmd(dev, 0x00000794, 0x00000001); -+ nv_icmd(dev, 0x00000795, 0x00000001); -+ nv_icmd(dev, 0x00000796, 0x00000001); -+ nv_icmd(dev, 0x00000797, 0x000000cf); -+ nv_icmd(dev, 0x00000836, 0x00000001); -+ nv_icmd(dev, 0x0000079a, 0x00000002); -+ nv_icmd(dev, 0x00000833, 0x04444480); -+ nv_icmd(dev, 0x000007a1, 0x00000001); -+ nv_icmd(dev, 0x000007a3, 0x00000001); -+ nv_icmd(dev, 0x000007a4, 0x00000001); -+ nv_icmd(dev, 0x000007a5, 0x00000001); -+ nv_icmd(dev, 0x00000831, 0x00000004); -+ nv_icmd(dev, 0x0000080c, 0x00000002); -+ nv_icmd(dev, 0x0000080d, 0x00000100); -+ nv_icmd(dev, 0x0000080e, 0x00000100); -+ nv_icmd(dev, 0x0000080f, 0x00000001); -+ nv_icmd(dev, 0x00000823, 0x00000002); -+ nv_icmd(dev, 0x00000824, 0x00000100); -+ nv_icmd(dev, 0x00000825, 0x00000100); -+ nv_icmd(dev, 0x00000826, 0x00000001); -+ nv_icmd(dev, 0x0000095d, 0x00000001); -+ nv_icmd(dev, 0x0000082b, 0x00000004); -+ nv_icmd(dev, 0x00000942, 0x00010001); -+ nv_icmd(dev, 0x00000943, 0x00000001); -+ nv_icmd(dev, 0x00000944, 0x00000022); -+ nv_icmd(dev, 0x000007c5, 0x00010001); -+ nv_icmd(dev, 0x00000834, 0x00000001); -+ nv_icmd(dev, 0x000007c7, 0x00000001); -+ nv_icmd(dev, 0x0000c1b0, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b1, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b2, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b3, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b4, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b5, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b6, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b7, 0x0000000f); -+ nv_icmd(dev, 0x0000c1b8, 0x0fac6881); -+ nv_icmd(dev, 0x0000c1b9, 0x00fac688); -+ nv_icmd(dev, 0x0001e100, 0x00000001); -+ nv_icmd(dev, 0x00001000, 0x00000002); -+ nv_icmd(dev, 0x000006aa, 0x00000001); -+ nv_icmd(dev, 0x000006ad, 0x00000100); -+ nv_icmd(dev, 0x000006ae, 0x00000100); -+ nv_icmd(dev, 0x000006b1, 0x00000011); -+ nv_icmd(dev, 0x0000078c, 0x00000008); -+ nv_icmd(dev, 0x00000792, 0x00000001); -+ nv_icmd(dev, 0x00000794, 0x00000001); -+ nv_icmd(dev, 0x00000795, 0x00000001); -+ nv_icmd(dev, 0x00000796, 0x00000001); -+ nv_icmd(dev, 0x00000797, 0x000000cf); -+ nv_icmd(dev, 0x0000079a, 0x00000002); -+ nv_icmd(dev, 0x00000833, 0x04444480); -+ nv_icmd(dev, 0x000007a1, 0x00000001); -+ nv_icmd(dev, 0x000007a3, 0x00000001); -+ nv_icmd(dev, 0x000007a4, 0x00000001); -+ nv_icmd(dev, 0x000007a5, 0x00000001); -+ nv_icmd(dev, 0x00000831, 0x00000004); -+ nv_icmd(dev, 0x0001e100, 0x00000001); -+ nv_icmd(dev, 0x00001000, 0x00000014); -+ nv_icmd(dev, 0x00000351, 0x00000100); -+ nv_icmd(dev, 0x00000957, 0x00000003); -+ nv_icmd(dev, 0x0000095d, 0x00000001); -+ nv_icmd(dev, 0x0000082b, 0x00000004); -+ nv_icmd(dev, 0x00000942, 0x00010001); -+ nv_icmd(dev, 0x00000943, 0x00000001); -+ nv_icmd(dev, 0x000007c5, 0x00010001); -+ nv_icmd(dev, 0x00000834, 0x00000001); -+ nv_icmd(dev, 0x000007c7, 0x00000001); -+ nv_icmd(dev, 0x0001e100, 0x00000001); -+ nv_icmd(dev, 0x00001000, 0x00000001); -+ nv_icmd(dev, 0x0000080c, 0x00000002); -+ nv_icmd(dev, 0x0000080d, 0x00000100); -+ nv_icmd(dev, 0x0000080e, 0x00000100); -+ nv_icmd(dev, 0x0000080f, 0x00000001); -+ nv_icmd(dev, 0x00000823, 0x00000002); -+ nv_icmd(dev, 0x00000824, 0x00000100); -+ nv_icmd(dev, 0x00000825, 0x00000100); -+ nv_icmd(dev, 0x00000826, 0x00000001); -+ nv_icmd(dev, 0x0001e100, 0x00000001); -+ nv_wr32(dev, 0x400208, 0x00000000); -+ nv_wr32(dev, 0x404154, 0x00000400); -+ -+ nvc0_grctx_generate_9097(dev); -+ nvc0_grctx_generate_902d(dev); -+ nvc0_grctx_generate_9039(dev); -+ nvc0_grctx_generate_90c0(dev); -+ -+ nv_wr32(dev, 0x000260, r000260); -+ return 0; -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_instmem.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_instmem.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_instmem.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_instmem.c 2011-01-07 14:22:17.000000000 +0100 -@@ -25,206 +25,207 @@ - #include "drmP.h" - - #include "nouveau_drv.h" -+#include "nouveau_vm.h" -+ -+struct nvc0_instmem_priv { -+ struct nouveau_gpuobj *bar1_pgd; -+ struct nouveau_channel *bar1; -+ struct nouveau_gpuobj *bar3_pgd; -+ struct nouveau_channel *bar3; -+ struct nouveau_gpuobj *chan_pgd; -+}; - - int --nvc0_instmem_populate(struct drm_device *dev, struct nouveau_gpuobj *gpuobj, -- uint32_t *size) -+nvc0_instmem_suspend(struct drm_device *dev) - { -- int ret; -- -- *size = ALIGN(*size, 4096); -- if (*size == 0) -- return -EINVAL; -- -- ret = nouveau_bo_new(dev, NULL, *size, 0, TTM_PL_FLAG_VRAM, 0, 0x0000, -- true, false, &gpuobj->im_backing); -- if (ret) { -- NV_ERROR(dev, "error getting PRAMIN backing pages: %d\n", ret); -- return ret; -- } -- -- ret = nouveau_bo_pin(gpuobj->im_backing, TTM_PL_FLAG_VRAM); -- if (ret) { -- NV_ERROR(dev, "error pinning PRAMIN backing VRAM: %d\n", ret); -- nouveau_bo_ref(NULL, &gpuobj->im_backing); -- return ret; -- } -+ struct drm_nouveau_private *dev_priv = dev->dev_private; - -- gpuobj->vinst = gpuobj->im_backing->bo.mem.start << PAGE_SHIFT; -+ dev_priv->ramin_available = false; - return 0; - } - - void --nvc0_instmem_clear(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+nvc0_instmem_resume(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; - -- if (gpuobj && gpuobj->im_backing) { -- if (gpuobj->im_bound) -- dev_priv->engine.instmem.unbind(dev, gpuobj); -- nouveau_bo_unpin(gpuobj->im_backing); -- nouveau_bo_ref(NULL, &gpuobj->im_backing); -- gpuobj->im_backing = NULL; -- } -+ nv_mask(dev, 0x100c80, 0x00000001, 0x00000000); -+ nv_wr32(dev, 0x001704, 0x80000000 | priv->bar1->ramin->vinst >> 12); -+ nv_wr32(dev, 0x001714, 0xc0000000 | priv->bar3->ramin->vinst >> 12); -+ dev_priv->ramin_available = true; - } - --int --nvc0_instmem_bind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+static void -+nvc0_channel_del(struct nouveau_channel **pchan) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t pte, pte_end; -- uint64_t vram; -+ struct nouveau_channel *chan; - -- if (!gpuobj->im_backing || !gpuobj->im_pramin || gpuobj->im_bound) -- return -EINVAL; -+ chan = *pchan; -+ *pchan = NULL; -+ if (!chan) -+ return; - -- NV_DEBUG(dev, "st=0x%lx sz=0x%lx\n", -- gpuobj->im_pramin->start, gpuobj->im_pramin->size); -- -- pte = gpuobj->im_pramin->start >> 12; -- pte_end = (gpuobj->im_pramin->size >> 12) + pte; -- vram = gpuobj->vinst; -- -- NV_DEBUG(dev, "pramin=0x%lx, pte=%d, pte_end=%d\n", -- gpuobj->im_pramin->start, pte, pte_end); -- NV_DEBUG(dev, "first vram page: 0x%010llx\n", gpuobj->vinst); -- -- while (pte < pte_end) { -- nv_wr32(dev, 0x702000 + (pte * 8), (vram >> 8) | 1); -- nv_wr32(dev, 0x702004 + (pte * 8), 0); -- vram += 4096; -- pte++; -- } -- dev_priv->engine.instmem.flush(dev); -- -- if (1) { -- u32 chan = nv_rd32(dev, 0x1700) << 16; -- nv_wr32(dev, 0x100cb8, (chan + 0x1000) >> 8); -- nv_wr32(dev, 0x100cbc, 0x80000005); -- } -- -- gpuobj->im_bound = 1; -- return 0; -+ nouveau_vm_ref(NULL, &chan->vm, NULL); -+ if (chan->ramin_heap.free_stack.next) -+ drm_mm_takedown(&chan->ramin_heap); -+ nouveau_gpuobj_ref(NULL, &chan->ramin); -+ kfree(chan); - } - --int --nvc0_instmem_unbind(struct drm_device *dev, struct nouveau_gpuobj *gpuobj) -+static int -+nvc0_channel_new(struct drm_device *dev, u32 size, struct nouveau_vm *vm, -+ struct nouveau_channel **pchan, -+ struct nouveau_gpuobj *pgd, u64 vm_size) - { -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- uint32_t pte, pte_end; -+ struct nouveau_channel *chan; -+ int ret; - -- if (gpuobj->im_bound == 0) -- return -EINVAL; -+ chan = kzalloc(sizeof(*chan), GFP_KERNEL); -+ if (!chan) -+ return -ENOMEM; -+ chan->dev = dev; - -- pte = gpuobj->im_pramin->start >> 12; -- pte_end = (gpuobj->im_pramin->size >> 12) + pte; -- while (pte < pte_end) { -- nv_wr32(dev, 0x702000 + (pte * 8), 0); -- nv_wr32(dev, 0x702004 + (pte * 8), 0); -- pte++; -+ ret = nouveau_gpuobj_new(dev, NULL, size, 0x1000, 0, &chan->ramin); -+ if (ret) { -+ nvc0_channel_del(&chan); -+ return ret; - } -- dev_priv->engine.instmem.flush(dev); - -- gpuobj->im_bound = 0; -- return 0; --} -- --void --nvc0_instmem_flush(struct drm_device *dev) --{ -- nv_wr32(dev, 0x070000, 1); -- if (!nv_wait(dev, 0x070000, 0x00000002, 0x00000000)) -- NV_ERROR(dev, "PRAMIN flush timeout\n"); --} -+ ret = drm_mm_init(&chan->ramin_heap, 0x1000, size - 0x1000); -+ if (ret) { -+ nvc0_channel_del(&chan); -+ return ret; -+ } - --int --nvc0_instmem_suspend(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- u32 *buf; -- int i; -+ ret = nouveau_vm_ref(vm, &chan->vm, NULL); -+ if (ret) { -+ nvc0_channel_del(&chan); -+ return ret; -+ } - -- dev_priv->susres.ramin_copy = vmalloc(65536); -- if (!dev_priv->susres.ramin_copy) -- return -ENOMEM; -- buf = dev_priv->susres.ramin_copy; -+ nv_wo32(chan->ramin, 0x0200, lower_32_bits(pgd->vinst)); -+ nv_wo32(chan->ramin, 0x0204, upper_32_bits(pgd->vinst)); -+ nv_wo32(chan->ramin, 0x0208, lower_32_bits(vm_size - 1)); -+ nv_wo32(chan->ramin, 0x020c, upper_32_bits(vm_size - 1)); - -- for (i = 0; i < 65536; i += 4) -- buf[i/4] = nv_rd32(dev, NV04_PRAMIN + i); -+ *pchan = chan; - return 0; - } - --void --nvc0_instmem_resume(struct drm_device *dev) --{ -- struct drm_nouveau_private *dev_priv = dev->dev_private; -- u32 *buf = dev_priv->susres.ramin_copy; -- u64 chan; -- int i; -- -- chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; -- nv_wr32(dev, 0x001700, chan >> 16); -- -- for (i = 0; i < 65536; i += 4) -- nv_wr32(dev, NV04_PRAMIN + i, buf[i/4]); -- vfree(dev_priv->susres.ramin_copy); -- dev_priv->susres.ramin_copy = NULL; -- -- nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); --} -- - int - nvc0_instmem_init(struct drm_device *dev) - { - struct drm_nouveau_private *dev_priv = dev->dev_private; -- u64 chan, pgt3, imem, lim3 = dev_priv->ramin_size - 1; -- int ret, i; -- -- dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; -- chan = dev_priv->vram_size - dev_priv->ramin_rsvd_vram; -- imem = 4096 + 4096 + 32768; -- -- nv_wr32(dev, 0x001700, chan >> 16); -- -- /* channel setup */ -- nv_wr32(dev, 0x700200, lower_32_bits(chan + 0x1000)); -- nv_wr32(dev, 0x700204, upper_32_bits(chan + 0x1000)); -- nv_wr32(dev, 0x700208, lower_32_bits(lim3)); -- nv_wr32(dev, 0x70020c, upper_32_bits(lim3)); -- -- /* point pgd -> pgt */ -- nv_wr32(dev, 0x701000, 0); -- nv_wr32(dev, 0x701004, ((chan + 0x2000) >> 8) | 1); -- -- /* point pgt -> physical vram for channel */ -- pgt3 = 0x2000; -- for (i = 0; i < dev_priv->ramin_rsvd_vram; i += 4096, pgt3 += 8) { -- nv_wr32(dev, 0x700000 + pgt3, ((chan + i) >> 8) | 1); -- nv_wr32(dev, 0x700004 + pgt3, 0); -- } -+ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; -+ struct pci_dev *pdev = dev->pdev; -+ struct nvc0_instmem_priv *priv; -+ struct nouveau_vm *vm = NULL; -+ int ret; - -- /* clear rest of pgt */ -- for (; i < dev_priv->ramin_size; i += 4096, pgt3 += 8) { -- nv_wr32(dev, 0x700000 + pgt3, 0); -- nv_wr32(dev, 0x700004 + pgt3, 0); -- } -+ priv = kzalloc(sizeof(*priv), GFP_KERNEL); -+ if (!priv) -+ return -ENOMEM; -+ pinstmem->priv = priv; - -- /* point bar3 at the channel */ -- nv_wr32(dev, 0x001714, 0xc0000000 | (chan >> 12)); -+ /* BAR3 VM */ -+ ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 3), 0, -+ &dev_priv->bar3_vm); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, -+ (pci_resource_len(pdev, 3) >> 12) * 8, 0, -+ NVOBJ_FLAG_DONT_MAP | -+ NVOBJ_FLAG_ZERO_ALLOC, -+ &dev_priv->bar3_vm->pgt[0].obj[0]); -+ if (ret) -+ goto error; -+ dev_priv->bar3_vm->pgt[0].refcount[0] = 1; -+ -+ nv50_instmem_map(dev_priv->bar3_vm->pgt[0].obj[0]); -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, -+ NVOBJ_FLAG_ZERO_ALLOC, &priv->bar3_pgd); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_vm_ref(dev_priv->bar3_vm, &vm, priv->bar3_pgd); -+ if (ret) -+ goto error; -+ nouveau_vm_ref(NULL, &vm, NULL); -+ -+ ret = nvc0_channel_new(dev, 8192, dev_priv->bar3_vm, &priv->bar3, -+ priv->bar3_pgd, pci_resource_len(dev->pdev, 3)); -+ if (ret) -+ goto error; -+ -+ /* BAR1 VM */ -+ ret = nouveau_vm_new(dev, 0, pci_resource_len(pdev, 1), 0, &vm); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, -+ NVOBJ_FLAG_ZERO_ALLOC, &priv->bar1_pgd); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_vm_ref(vm, &dev_priv->bar1_vm, priv->bar1_pgd); -+ if (ret) -+ goto error; -+ nouveau_vm_ref(NULL, &vm, NULL); -+ -+ ret = nvc0_channel_new(dev, 8192, dev_priv->bar1_vm, &priv->bar1, -+ priv->bar1_pgd, pci_resource_len(dev->pdev, 1)); -+ if (ret) -+ goto error; -+ -+ /* channel vm */ -+ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &vm); -+ if (ret) -+ goto error; -+ -+ ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 0, &priv->chan_pgd); -+ if (ret) -+ goto error; - -- /* Global PRAMIN heap */ -- ret = drm_mm_init(&dev_priv->ramin_heap, imem, -- dev_priv->ramin_size - imem); -- if (ret) { -- NV_ERROR(dev, "Failed to init RAMIN heap\n"); -- return -ENOMEM; -- } -+ nouveau_vm_ref(vm, &dev_priv->chan_vm, priv->chan_pgd); -+ nouveau_vm_ref(NULL, &vm, NULL); - -+ nvc0_instmem_resume(dev); - return 0; -+error: -+ nvc0_instmem_takedown(dev); -+ return ret; - } - - void - nvc0_instmem_takedown(struct drm_device *dev) - { -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct nvc0_instmem_priv *priv = dev_priv->engine.instmem.priv; -+ struct nouveau_vm *vm = NULL; -+ -+ nvc0_instmem_suspend(dev); -+ -+ nv_wr32(dev, 0x1704, 0x00000000); -+ nv_wr32(dev, 0x1714, 0x00000000); -+ -+ nouveau_vm_ref(NULL, &dev_priv->chan_vm, priv->chan_pgd); -+ nouveau_gpuobj_ref(NULL, &priv->chan_pgd); -+ -+ nvc0_channel_del(&priv->bar1); -+ nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); -+ nouveau_gpuobj_ref(NULL, &priv->bar1_pgd); -+ -+ nvc0_channel_del(&priv->bar3); -+ nouveau_vm_ref(dev_priv->bar3_vm, &vm, NULL); -+ nouveau_vm_ref(NULL, &vm, priv->bar3_pgd); -+ nouveau_gpuobj_ref(NULL, &priv->bar3_pgd); -+ nouveau_gpuobj_ref(NULL, &dev_priv->bar3_vm->pgt[0].obj[0]); -+ nouveau_vm_ref(NULL, &dev_priv->bar3_vm, NULL); -+ -+ dev_priv->engine.instmem.priv = NULL; -+ kfree(priv); - } - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_vm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_vm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_vm.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_vm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,123 @@ -+/* -+ * Copyright 2010 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_vm.h" -+ -+void -+nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 index, -+ struct nouveau_gpuobj *pgt[2]) -+{ -+ u32 pde[2] = { 0, 0 }; -+ -+ if (pgt[0]) -+ pde[1] = 0x00000001 | (pgt[0]->vinst >> 8); -+ if (pgt[1]) -+ pde[0] = 0x00000001 | (pgt[1]->vinst >> 8); -+ -+ nv_wo32(pgd, (index * 8) + 0, pde[0]); -+ nv_wo32(pgd, (index * 8) + 4, pde[1]); -+} -+ -+static inline u64 -+nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) -+{ -+ phys >>= 8; -+ -+ phys |= 0x00000001; /* present */ -+// if (vma->access & NV_MEM_ACCESS_SYS) -+// phys |= 0x00000002; -+ -+ phys |= ((u64)target << 32); -+ phys |= ((u64)memtype << 36); -+ -+ return phys; -+} -+ -+void -+nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, -+ struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) -+{ -+ u32 next = 1 << (vma->node->type - 8); -+ -+ phys = nvc0_vm_addr(vma, phys, mem->memtype, 0); -+ pte <<= 3; -+ while (cnt--) { -+ nv_wo32(pgt, pte + 0, lower_32_bits(phys)); -+ nv_wo32(pgt, pte + 4, upper_32_bits(phys)); -+ phys += next; -+ pte += 8; -+ } -+} -+ -+void -+nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, -+ u32 pte, dma_addr_t *list, u32 cnt) -+{ -+ pte <<= 3; -+ while (cnt--) { -+ u64 phys = nvc0_vm_addr(vma, *list++, 0, 5); -+ nv_wo32(pgt, pte + 0, lower_32_bits(phys)); -+ nv_wo32(pgt, pte + 4, upper_32_bits(phys)); -+ pte += 8; -+ } -+} -+ -+void -+nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt) -+{ -+ pte <<= 3; -+ while (cnt--) { -+ nv_wo32(pgt, pte + 0, 0x00000000); -+ nv_wo32(pgt, pte + 4, 0x00000000); -+ pte += 8; -+ } -+} -+ -+void -+nvc0_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 drm_device *dev = vm->dev; -+ struct nouveau_vm_pgd *vpgd; -+ u32 r100c80, engine; -+ -+ pinstmem->flush(vm->dev); -+ -+ if (vm == dev_priv->chan_vm) -+ engine = 1; -+ else -+ engine = 5; -+ -+ list_for_each_entry(vpgd, &vm->pgd_list, head) { -+ r100c80 = nv_rd32(dev, 0x100c80); -+ nv_wr32(dev, 0x100cb8, vpgd->obj->vinst >> 8); -+ nv_wr32(dev, 0x100cbc, 0x80000000 | engine); -+ if (!nv_wait(dev, 0x100c80, 0xffffffff, r100c80)) -+ NV_ERROR(dev, "vm flush timeout eng %d\n", engine); -+ } -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_vram.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_vram.c ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvc0_vram.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvc0_vram.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,99 @@ -+/* -+ * Copyright 2010 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_mm.h" -+ -+bool -+nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) -+{ -+ switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { -+ case 0x0000: -+ case 0xfe00: -+ case 0xdb00: -+ case 0x1100: -+ return true; -+ default: -+ break; -+ } -+ -+ return false; -+} -+ -+int -+nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, -+ u32 type, struct nouveau_vram **pvram) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; -+ struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; -+ struct nouveau_mm *mm = man->priv; -+ struct nouveau_mm_node *r; -+ struct nouveau_vram *vram; -+ int ret; -+ -+ size >>= 12; -+ align >>= 12; -+ ncmin >>= 12; -+ -+ vram = kzalloc(sizeof(*vram), GFP_KERNEL); -+ if (!vram) -+ return -ENOMEM; -+ -+ INIT_LIST_HEAD(&vram->regions); -+ vram->dev = dev_priv->dev; -+ vram->memtype = type; -+ vram->size = size; -+ -+ mutex_lock(&mm->mutex); -+ do { -+ ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r); -+ if (ret) { -+ mutex_unlock(&mm->mutex); -+ nv50_vram_del(dev, &vram); -+ return ret; -+ } -+ -+ list_add_tail(&r->rl_entry, &vram->regions); -+ size -= r->length; -+ } while (size); -+ mutex_unlock(&mm->mutex); -+ -+ r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); -+ vram->offset = (u64)r->offset << 12; -+ *pvram = vram; -+ return 0; -+} -+ -+int -+nvc0_vram_init(struct drm_device *dev) -+{ -+ struct drm_nouveau_private *dev_priv = dev->dev_private; -+ -+ dev_priv->vram_size = nv_rd32(dev, 0x10f20c) << 20; -+ dev_priv->vram_size *= nv_rd32(dev, 0x121c74); -+ dev_priv->vram_rblock_size = 4096; -+ return 0; -+} -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvreg.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvreg.h ---- linux-2.6.37-rc3/drivers/gpu/drm/nouveau/nvreg.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/nouveau/nvreg.h 2011-01-07 14:22:17.000000000 +0100 -@@ -153,7 +153,8 @@ - #define NV_PCRTC_START 0x00600800 - #define NV_PCRTC_CONFIG 0x00600804 - # define NV_PCRTC_CONFIG_START_ADDRESS_NON_VGA (1 << 0) --# define NV_PCRTC_CONFIG_START_ADDRESS_HSYNC (2 << 0) -+# define NV04_PCRTC_CONFIG_START_ADDRESS_HSYNC (4 << 0) -+# define NV10_PCRTC_CONFIG_START_ADDRESS_HSYNC (2 << 0) - #define NV_PCRTC_CURSOR_CONFIG 0x00600810 - # define NV_PCRTC_CURSOR_CONFIG_ENABLE_ENABLE (1 << 0) - # define NV_PCRTC_CURSOR_CONFIG_DOUBLE_SCAN_ENABLE (1 << 4) -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/atombios.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/atombios.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/atombios.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/atombios.h 2011-01-07 14:22:17.000000000 +0100 -@@ -73,8 +73,18 @@ - #define ATOM_PPLL1 0 - #define ATOM_PPLL2 1 - #define ATOM_DCPLL 2 -+#define ATOM_PPLL0 2 -+#define ATOM_EXT_PLL1 8 -+#define ATOM_EXT_PLL2 9 -+#define ATOM_EXT_CLOCK 10 - #define ATOM_PPLL_INVALID 0xFF - -+#define ENCODER_REFCLK_SRC_P1PLL 0 -+#define ENCODER_REFCLK_SRC_P2PLL 1 -+#define ENCODER_REFCLK_SRC_DCPLL 2 -+#define ENCODER_REFCLK_SRC_EXTCLK 3 -+#define ENCODER_REFCLK_SRC_INVALID 0xFF -+ - #define ATOM_SCALER1 0 - #define ATOM_SCALER2 1 - -@@ -192,6 +202,9 @@ - /*Image can't be updated, while Driver needs to carry the new table! */ - }ATOM_COMMON_TABLE_HEADER; - -+/****************************************************************************/ -+// Structure stores the ROM header. -+/****************************************************************************/ - typedef struct _ATOM_ROM_HEADER - { - ATOM_COMMON_TABLE_HEADER sHeader; -@@ -221,6 +234,9 @@ - #define USHORT void* - #endif - -+/****************************************************************************/ -+// Structures used in Command.mtb -+/****************************************************************************/ - typedef struct _ATOM_MASTER_LIST_OF_COMMAND_TABLES{ - USHORT ASIC_Init; //Function Table, used by various SW components,latest version 1.1 - USHORT GetDisplaySurfaceSize; //Atomic Table, Used by Bios when enabling HW ICON -@@ -312,6 +328,7 @@ - #define SetUniphyInstance ASIC_StaticPwrMgtStatusChange - #define HPDInterruptService ReadHWAssistedI2CStatus - #define EnableVGA_Access GetSCLKOverMCLKRatio -+#define GetDispObjectInfo EnableYUV - - typedef struct _ATOM_MASTER_COMMAND_TABLE - { -@@ -357,6 +374,24 @@ - /****************************************************************************/ - #define COMPUTE_MEMORY_PLL_PARAM 1 - #define COMPUTE_ENGINE_PLL_PARAM 2 -+#define ADJUST_MC_SETTING_PARAM 3 -+ -+/****************************************************************************/ -+// Structures used by AdjustMemoryControllerTable -+/****************************************************************************/ -+typedef struct _ATOM_ADJUST_MEMORY_CLOCK_FREQ -+{ -+#if ATOM_BIG_ENDIAN -+ ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block -+ ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0] -+ ULONG ulClockFreq:24; -+#else -+ ULONG ulClockFreq:24; -+ ULONG ulMemoryModuleNumber:7; // BYTE_3[6:0] -+ ULONG ulPointerReturnFlag:1; // BYTE_3[7]=1 - Return the pointer to the right Data Block; BYTE_3[7]=0 - Program the right Data Block -+#endif -+}ATOM_ADJUST_MEMORY_CLOCK_FREQ; -+#define POINTER_RETURN_FLAG 0x80 - - typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS - { -@@ -440,6 +475,26 @@ - #endif - }COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4; - -+typedef struct _COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5 -+{ -+ union -+ { -+ ATOM_COMPUTE_CLOCK_FREQ ulClock; //Input Parameter -+ ATOM_S_MPLL_FB_DIVIDER ulFbDiv; //Output Parameter -+ }; -+ UCHAR ucRefDiv; //Output Parameter -+ UCHAR ucPostDiv; //Output Parameter -+ union -+ { -+ UCHAR ucCntlFlag; //Output Flags -+ UCHAR ucInputFlag; //Input Flags. ucInputFlag[0] - Strobe(1)/Performance(0) mode -+ }; -+ UCHAR ucReserved; -+}COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V5; -+ -+// ucInputFlag -+#define ATOM_PLL_INPUT_FLAG_PLL_STROBE_MODE_EN 1 // 1-StrobeMode, 0-PerformanceMode -+ - typedef struct _DYNAMICE_MEMORY_SETTINGS_PARAMETER - { - ATOM_COMPUTE_CLOCK_FREQ ulClock; -@@ -583,6 +638,7 @@ - #define ATOM_ENCODER_CONFIG_DPLINKRATE_MASK 0x01 - #define ATOM_ENCODER_CONFIG_DPLINKRATE_1_62GHZ 0x00 - #define ATOM_ENCODER_CONFIG_DPLINKRATE_2_70GHZ 0x01 -+#define ATOM_ENCODER_CONFIG_DPLINKRATE_5_40GHZ 0x02 - #define ATOM_ENCODER_CONFIG_LINK_SEL_MASK 0x04 - #define ATOM_ENCODER_CONFIG_LINKA 0x00 - #define ATOM_ENCODER_CONFIG_LINKB 0x04 -@@ -608,6 +664,9 @@ - #define ATOM_ENCODER_MODE_TV 13 - #define ATOM_ENCODER_MODE_CV 14 - #define ATOM_ENCODER_MODE_CRT 15 -+#define ATOM_ENCODER_MODE_DVO 16 -+#define ATOM_ENCODER_MODE_DP_SST ATOM_ENCODER_MODE_DP // For DP1.2 -+#define ATOM_ENCODER_MODE_DP_MST 5 // For DP1.2 - - typedef struct _ATOM_DIG_ENCODER_CONFIG_V2 - { -@@ -661,6 +720,7 @@ - #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_START 0x08 - #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN1 0x09 - #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN2 0x0a -+#define ATOM_ENCODER_CMD_DP_LINK_TRAINING_PATTERN3 0x13 - #define ATOM_ENCODER_CMD_DP_LINK_TRAINING_COMPLETE 0x0b - #define ATOM_ENCODER_CMD_DP_VIDEO_OFF 0x0c - #define ATOM_ENCODER_CMD_DP_VIDEO_ON 0x0d -@@ -671,24 +731,34 @@ - #define ATOM_ENCODER_STATUS_LINK_TRAINING_COMPLETE 0x10 - #define ATOM_ENCODER_STATUS_LINK_TRAINING_INCOMPLETE 0x00 - -+//ucTableFormatRevision=1 -+//ucTableContentRevision=3 - // Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver - typedef struct _ATOM_DIG_ENCODER_CONFIG_V3 - { - #if ATOM_BIG_ENDIAN - UCHAR ucReserved1:1; -- UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F -+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) - UCHAR ucReserved:3; - UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz - #else - UCHAR ucDPLinkRate:1; // =0: 1.62Ghz, =1: 2.7Ghz - UCHAR ucReserved:3; -- UCHAR ucDigSel:3; // =0: DIGA/B/C/D/E/F -+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) - UCHAR ucReserved1:1; - #endif - }ATOM_DIG_ENCODER_CONFIG_V3; - -+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03 -+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00 -+#define ATOM_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01 - #define ATOM_ENCODER_CONFIG_V3_ENCODER_SEL 0x70 -- -+#define ATOM_ENCODER_CONFIG_V3_DIG0_ENCODER 0x00 -+#define ATOM_ENCODER_CONFIG_V3_DIG1_ENCODER 0x10 -+#define ATOM_ENCODER_CONFIG_V3_DIG2_ENCODER 0x20 -+#define ATOM_ENCODER_CONFIG_V3_DIG3_ENCODER 0x30 -+#define ATOM_ENCODER_CONFIG_V3_DIG4_ENCODER 0x40 -+#define ATOM_ENCODER_CONFIG_V3_DIG5_ENCODER 0x50 - - typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V3 - { -@@ -707,6 +777,56 @@ - UCHAR ucReserved; - }DIG_ENCODER_CONTROL_PARAMETERS_V3; - -+//ucTableFormatRevision=1 -+//ucTableContentRevision=4 -+// start from NI -+// Following function ENABLE sub-function will be used by driver when TMDS/HDMI/LVDS is used, disable function will be used by driver -+typedef struct _ATOM_DIG_ENCODER_CONFIG_V4 -+{ -+#if ATOM_BIG_ENDIAN -+ UCHAR ucReserved1:1; -+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) -+ UCHAR ucReserved:2; -+ UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version -+#else -+ UCHAR ucDPLinkRate:2; // =0: 1.62Ghz, =1: 2.7Ghz, 2=5.4Ghz <= Changed comparing to previous version -+ UCHAR ucReserved:2; -+ UCHAR ucDigSel:3; // =0/1/2/3/4/5: DIG0/1/2/3/4/5 (In register spec also refered as DIGA/B/C/D/E/F) -+ UCHAR ucReserved1:1; -+#endif -+}ATOM_DIG_ENCODER_CONFIG_V4; -+ -+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_MASK 0x03 -+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_1_62GHZ 0x00 -+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_2_70GHZ 0x01 -+#define ATOM_ENCODER_CONFIG_V4_DPLINKRATE_5_40GHZ 0x02 -+#define ATOM_ENCODER_CONFIG_V4_ENCODER_SEL 0x70 -+#define ATOM_ENCODER_CONFIG_V4_DIG0_ENCODER 0x00 -+#define ATOM_ENCODER_CONFIG_V4_DIG1_ENCODER 0x10 -+#define ATOM_ENCODER_CONFIG_V4_DIG2_ENCODER 0x20 -+#define ATOM_ENCODER_CONFIG_V4_DIG3_ENCODER 0x30 -+#define ATOM_ENCODER_CONFIG_V4_DIG4_ENCODER 0x40 -+#define ATOM_ENCODER_CONFIG_V4_DIG5_ENCODER 0x50 -+ -+typedef struct _DIG_ENCODER_CONTROL_PARAMETERS_V4 -+{ -+ USHORT usPixelClock; // in 10KHz; for bios convenient -+ union{ -+ ATOM_DIG_ENCODER_CONFIG_V4 acConfig; -+ UCHAR ucConfig; -+ }; -+ UCHAR ucAction; -+ UCHAR ucEncoderMode; -+ // =0: DP encoder -+ // =1: LVDS encoder -+ // =2: DVI encoder -+ // =3: HDMI encoder -+ // =4: SDVO encoder -+ // =5: DP audio -+ UCHAR ucLaneNum; // how many lanes to enable -+ UCHAR ucBitPerColor; // only valid for DP mode when ucAction = ATOM_ENCODER_CMD_SETUP -+ UCHAR ucHPD_ID; // HPD ID (1-6). =0 means to skip HDP programming. New comparing to previous version -+}DIG_ENCODER_CONTROL_PARAMETERS_V4; - - // define ucBitPerColor: - #define PANEL_BPC_UNDEFINE 0x00 -@@ -893,6 +1013,7 @@ - #endif - }ATOM_DIG_TRANSMITTER_CONFIG_V3; - -+ - typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 - { - union -@@ -936,6 +1057,149 @@ - #define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER2 0x40 //CD - #define ATOM_TRANSMITTER_CONFIG_V3_TRANSMITTER3 0x80 //EF - -+ -+/****************************************************************************/ -+// Structures used by UNIPHYTransmitterControlTable V1.4 -+// ASIC Families: NI -+// ucTableFormatRevision=1 -+// ucTableContentRevision=4 -+/****************************************************************************/ -+typedef struct _ATOM_DP_VS_MODE_V4 -+{ -+ UCHAR ucLaneSel; -+ union -+ { -+ UCHAR ucLaneSet; -+ struct { -+#if ATOM_BIG_ENDIAN -+ UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4 -+ UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level -+ UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level -+#else -+ UCHAR ucVOLTAGE_SWING:3; //Bit[2:0] Voltage Swing Level -+ UCHAR ucPRE_EMPHASIS:3; //Bit[5:3] Pre-emphasis Level -+ UCHAR ucPOST_CURSOR2:2; //Bit[7:6] Post Cursor2 Level <= New in V4 -+#endif -+ }; -+ }; -+}ATOM_DP_VS_MODE_V4; -+ -+typedef struct _ATOM_DIG_TRANSMITTER_CONFIG_V4 -+{ -+#if ATOM_BIG_ENDIAN -+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) -+ // =1 Dig Transmitter 2 ( Uniphy CD ) -+ // =2 Dig Transmitter 3 ( Uniphy EF ) -+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New -+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F -+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E -+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F -+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) -+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector -+#else -+ UCHAR fDualLinkConnector:1; //bit0=1: Dual Link DVI connector -+ UCHAR fCoherentMode:1; //bit1=1: Coherent Mode ( for DVI/HDMI mode ) -+ UCHAR ucLinkSel:1; //bit2=0: Uniphy LINKA or C or E when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is A or C or E -+ // =1: Uniphy LINKB or D or F when fDualLinkConnector=0. when fDualLinkConnector=1, it means master link of dual link is B or D or F -+ UCHAR ucEncoderSel:1; //bit3=0: Data/Clk path source from DIGA/C/E. =1: Data/clk path source from DIGB/D/F -+ UCHAR ucRefClkSource:2; //bit5:4: PPLL1 =0, PPLL2=1, DCPLL=2, EXT_CLK=3 <= New -+ UCHAR ucTransmitterSel:2; //bit7:6: =0 Dig Transmitter 1 ( Uniphy AB ) -+ // =1 Dig Transmitter 2 ( Uniphy CD ) -+ // =2 Dig Transmitter 3 ( Uniphy EF ) -+#endif -+}ATOM_DIG_TRANSMITTER_CONFIG_V4; -+ -+typedef struct _DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 -+{ -+ union -+ { -+ USHORT usPixelClock; // in 10KHz; for bios convenient -+ USHORT usInitInfo; // when init uniphy,lower 8bit is used for connector type defined in objectid.h -+ ATOM_DP_VS_MODE_V4 asMode; // DP Voltage swing mode Redefined comparing to previous version -+ }; -+ union -+ { -+ ATOM_DIG_TRANSMITTER_CONFIG_V4 acConfig; -+ UCHAR ucConfig; -+ }; -+ UCHAR ucAction; // define as ATOM_TRANSMITER_ACTION_XXX -+ UCHAR ucLaneNum; -+ UCHAR ucReserved[3]; -+}DIG_TRANSMITTER_CONTROL_PARAMETERS_V4; -+ -+//ucConfig -+//Bit0 -+#define ATOM_TRANSMITTER_CONFIG_V4_DUAL_LINK_CONNECTOR 0x01 -+//Bit1 -+#define ATOM_TRANSMITTER_CONFIG_V4_COHERENT 0x02 -+//Bit2 -+#define ATOM_TRANSMITTER_CONFIG_V4_LINK_SEL_MASK 0x04 -+#define ATOM_TRANSMITTER_CONFIG_V4_LINKA 0x00 -+#define ATOM_TRANSMITTER_CONFIG_V4_LINKB 0x04 -+// Bit3 -+#define ATOM_TRANSMITTER_CONFIG_V4_ENCODER_SEL_MASK 0x08 -+#define ATOM_TRANSMITTER_CONFIG_V4_DIG1_ENCODER 0x00 -+#define ATOM_TRANSMITTER_CONFIG_V4_DIG2_ENCODER 0x08 -+// Bit5:4 -+#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SEL_MASK 0x30 -+#define ATOM_TRANSMITTER_CONFIG_V4_P1PLL 0x00 -+#define ATOM_TRANSMITTER_CONFIG_V4_P2PLL 0x10 -+#define ATOM_TRANSMITTER_CONFIG_V4_DCPLL 0x20 // New in _V4 -+#define ATOM_TRANSMITTER_CONFIG_V4_REFCLK_SRC_EXT 0x30 // Changed comparing to V3 -+// Bit7:6 -+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER_SEL_MASK 0xC0 -+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER1 0x00 //AB -+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER2 0x40 //CD -+#define ATOM_TRANSMITTER_CONFIG_V4_TRANSMITTER3 0x80 //EF -+ -+ -+/****************************************************************************/ -+// Structures used by ExternalEncoderControlTable V1.3 -+// ASIC Families: Evergreen, Llano, NI -+// ucTableFormatRevision=1 -+// ucTableContentRevision=3 -+/****************************************************************************/ -+ -+typedef struct _EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 -+{ -+ union{ -+ USHORT usPixelClock; // pixel clock in 10Khz, valid when ucAction=SETUP/ENABLE_OUTPUT -+ USHORT usConnectorId; // connector id, valid when ucAction = INIT -+ }; -+ UCHAR ucConfig; // indicate which encoder, and DP link rate when ucAction = SETUP/ENABLE_OUTPUT -+ UCHAR ucAction; // -+ UCHAR ucEncoderMode; // encoder mode, only used when ucAction = SETUP/ENABLE_OUTPUT -+ UCHAR ucLaneNum; // lane number, only used when ucAction = SETUP/ENABLE_OUTPUT -+ UCHAR ucBitPerColor; // output bit per color, only valid when ucAction = SETUP/ENABLE_OUTPUT and ucEncodeMode= DP -+ UCHAR ucReserved; -+}EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3; -+ -+// ucAction -+#define EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT 0x00 -+#define EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT 0x01 -+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT 0x07 -+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP 0x0f -+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF 0x10 -+#define EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING 0x11 -+#define EXTERNAL_ENCODER_ACTION_V3_DACLOAD_DETECTION 0x12 -+ -+// ucConfig -+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_MASK 0x03 -+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_1_62GHZ 0x00 -+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ 0x01 -+#define EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ 0x02 -+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER_SEL_MASK 0x70 -+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER1 0x00 -+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER2 0x10 -+#define EXTERNAL_ENCODER_CONFIG_V3_ENCODER3 0x20 -+ -+typedef struct _EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 -+{ -+ EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 sExtEncoder; -+ ULONG ulReserved[2]; -+}EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3; -+ -+ - /****************************************************************************/ - // Structures used by DAC1OuputControlTable - // DAC2OuputControlTable -@@ -1142,6 +1406,7 @@ - #define PIXEL_CLOCK_V4_MISC_SS_ENABLE 0x10 - #define PIXEL_CLOCK_V4_MISC_COHERENT_MODE 0x20 - -+ - typedef struct _PIXEL_CLOCK_PARAMETERS_V3 - { - USHORT usPixelClock; // in 10kHz unit; for bios convenient = (RefClk*FB_Div)/(Ref_Div*Post_Div) -@@ -1202,6 +1467,55 @@ - #define PIXEL_CLOCK_V5_MISC_HDMI_32BPP 0x08 - #define PIXEL_CLOCK_V5_MISC_REF_DIV_SRC 0x10 - -+typedef struct _CRTC_PIXEL_CLOCK_FREQ -+{ -+#if ATOM_BIG_ENDIAN -+ ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to -+ // drive the pixel clock. not used for DCPLL case. -+ ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing. -+ // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version. -+#else -+ ULONG ulPixelClock:24; // target the pixel clock to drive the CRTC timing. -+ // 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to previous version. -+ ULONG ucCRTC:8; // ATOM_CRTC1~6, indicate the CRTC controller to -+ // drive the pixel clock. not used for DCPLL case. -+#endif -+}CRTC_PIXEL_CLOCK_FREQ; -+ -+typedef struct _PIXEL_CLOCK_PARAMETERS_V6 -+{ -+ union{ -+ CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq; // pixel clock and CRTC id frequency -+ ULONG ulDispEngClkFreq; // dispclk frequency -+ }; -+ USHORT usFbDiv; // feedback divider integer part. -+ UCHAR ucPostDiv; // post divider. -+ UCHAR ucRefDiv; // Reference divider -+ UCHAR ucPpll; // ATOM_PPLL1/ATOM_PPLL2/ATOM_DCPLL -+ UCHAR ucTransmitterID; // ASIC encoder id defined in objectId.h, -+ // indicate which graphic encoder will be used. -+ UCHAR ucEncoderMode; // Encoder mode: -+ UCHAR ucMiscInfo; // bit[0]= Force program PPLL -+ // bit[1]= when VGA timing is used. -+ // bit[3:2]= HDMI panel bit depth: =0: 24bpp =1:30bpp, =2:32bpp -+ // bit[4]= RefClock source for PPLL. -+ // =0: XTLAIN( default mode ) -+ // =1: other external clock source, which is pre-defined -+ // by VBIOS depend on the feature required. -+ // bit[7:5]: reserved. -+ ULONG ulFbDivDecFrac; // 20 bit feedback divider decimal fraction part, range from 1~999999 ( 0.000001 to 0.999999 ) -+ -+}PIXEL_CLOCK_PARAMETERS_V6; -+ -+#define PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL 0x01 -+#define PIXEL_CLOCK_V6_MISC_VGA_MODE 0x02 -+#define PIXEL_CLOCK_V6_MISC_HDMI_BPP_MASK 0x0c -+#define PIXEL_CLOCK_V6_MISC_HDMI_24BPP 0x00 -+#define PIXEL_CLOCK_V6_MISC_HDMI_36BPP 0x04 -+#define PIXEL_CLOCK_V6_MISC_HDMI_30BPP 0x08 -+#define PIXEL_CLOCK_V6_MISC_HDMI_48BPP 0x0c -+#define PIXEL_CLOCK_V6_MISC_REF_DIV_SRC 0x10 -+ - typedef struct _GET_DISP_PLL_STATUS_INPUT_PARAMETERS_V2 - { - PIXEL_CLOCK_PARAMETERS_V3 sDispClkInput; -@@ -1241,10 +1555,11 @@ - typedef struct _ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3 - { - USHORT usPixelClock; // target pixel clock -- UCHAR ucTransmitterID; // transmitter id defined in objectid.h -+ UCHAR ucTransmitterID; // GPU transmitter id defined in objectid.h - UCHAR ucEncodeMode; // encoder mode: CRT, LVDS, DP, TMDS or HDMI - UCHAR ucDispPllConfig; // display pll configure parameter defined as following DISPPLL_CONFIG_XXXX -- UCHAR ucReserved[3]; -+ UCHAR ucExtTransmitterID; // external encoder id. -+ UCHAR ucReserved[2]; - }ADJUST_DISPLAY_PLL_INPUT_PARAMETERS_V3; - - // usDispPllConfig v1.2 for RoadRunner -@@ -1358,6 +1673,7 @@ - /**************************************************************************/ - #define SPEED_FAN_CONTROL_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS - -+ - /****************************************************************************/ - // Structures used by PowerConnectorDetectionTable - /****************************************************************************/ -@@ -1438,6 +1754,31 @@ - #define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK 0x0F00 - #define ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT 8 - -+// Used by DCE5.0 -+ typedef struct _ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 -+{ -+ USHORT usSpreadSpectrumAmountFrac; // SS_AMOUNT_DSFRAC New in DCE5.0 -+ UCHAR ucSpreadSpectrumType; // Bit[0]: 0-Down Spread,1-Center Spread. -+ // Bit[1]: 1-Ext. 0-Int. -+ // Bit[3:2]: =0 P1PLL =1 P2PLL =2 DCPLL -+ // Bits[7:4] reserved -+ UCHAR ucEnable; // ATOM_ENABLE or ATOM_DISABLE -+ USHORT usSpreadSpectrumAmount; // Includes SS_AMOUNT_FBDIV[7:0] and SS_AMOUNT_NFRAC_SLIP[11:8] -+ USHORT usSpreadSpectrumStep; // SS_STEP_SIZE_DSFRAC -+}ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3; -+ -+#define ATOM_PPLL_SS_TYPE_V3_DOWN_SPREAD 0x00 -+#define ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD 0x01 -+#define ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD 0x02 -+#define ATOM_PPLL_SS_TYPE_V3_PPLL_SEL_MASK 0x0c -+#define ATOM_PPLL_SS_TYPE_V3_P1PLL 0x00 -+#define ATOM_PPLL_SS_TYPE_V3_P2PLL 0x04 -+#define ATOM_PPLL_SS_TYPE_V3_DCPLL 0x08 -+#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK 0x00FF -+#define ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT 0 -+#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK 0x0F00 -+#define ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT 8 -+ - #define ENABLE_SPREAD_SPECTRUM_ON_PPLL_PS_ALLOCATION ENABLE_SPREAD_SPECTRUM_ON_PPLL - - /**************************************************************************/ -@@ -1706,7 +2047,7 @@ - USHORT StandardVESA_Timing; // Only used by Bios - USHORT FirmwareInfo; // Shared by various SW components,latest version 1.4 - USHORT DAC_Info; // Will be obsolete from R600 -- USHORT LVDS_Info; // Shared by various SW components,latest version 1.1 -+ USHORT LCD_Info; // Shared by various SW components,latest version 1.3, was called LVDS_Info - USHORT TMDS_Info; // Will be obsolete from R600 - USHORT AnalogTV_Info; // Shared by various SW components,latest version 1.1 - USHORT SupportedDevicesInfo; // Will be obsolete from R600 -@@ -1736,12 +2077,16 @@ - USHORT PowerSourceInfo; // Shared by various SW components, latest versoin 1.1 - }ATOM_MASTER_LIST_OF_DATA_TABLES; - -+// For backward compatible -+#define LVDS_Info LCD_Info -+ - typedef struct _ATOM_MASTER_DATA_TABLE - { - ATOM_COMMON_TABLE_HEADER sHeader; - ATOM_MASTER_LIST_OF_DATA_TABLES ListOfDataTables; - }ATOM_MASTER_DATA_TABLE; - -+ - /****************************************************************************/ - // Structure used in MultimediaCapabilityInfoTable - /****************************************************************************/ -@@ -1776,6 +2121,7 @@ - UCHAR ucVideoInput4Info;// Video Input 4 Type (1:0) F/B setting (2) physical connector ID (5:3) reserved (7:6) - }ATOM_MULTIMEDIA_CONFIG_INFO; - -+ - /****************************************************************************/ - // Structures used in FirmwareInfoTable - /****************************************************************************/ -@@ -2031,8 +2377,47 @@ - UCHAR ucReserved4[3]; - }ATOM_FIRMWARE_INFO_V2_1; - -+//the structure below to be used from NI -+//ucTableFormatRevision=2 -+//ucTableContentRevision=2 -+typedef struct _ATOM_FIRMWARE_INFO_V2_2 -+{ -+ ATOM_COMMON_TABLE_HEADER sHeader; -+ ULONG ulFirmwareRevision; -+ ULONG ulDefaultEngineClock; //In 10Khz unit -+ ULONG ulDefaultMemoryClock; //In 10Khz unit -+ ULONG ulReserved[2]; -+ ULONG ulReserved1; //Was ulMaxEngineClockPLL_Output; //In 10Khz unit* -+ ULONG ulReserved2; //Was ulMaxMemoryClockPLL_Output; //In 10Khz unit* -+ ULONG ulMaxPixelClockPLL_Output; //In 10Khz unit -+ ULONG ulBinaryAlteredInfo; //Was ulASICMaxEngineClock ? -+ ULONG ulDefaultDispEngineClkFreq; //In 10Khz unit. This is the frequency before DCDTO, corresponding to usBootUpVDDCVoltage. -+ UCHAR ucReserved3; //Was ucASICMaxTemperature; -+ UCHAR ucMinAllowedBL_Level; -+ USHORT usBootUpVDDCVoltage; //In MV unit -+ USHORT usLcdMinPixelClockPLL_Output; // In MHz unit -+ USHORT usLcdMaxPixelClockPLL_Output; // In MHz unit -+ ULONG ulReserved4; //Was ulAsicMaximumVoltage -+ ULONG ulMinPixelClockPLL_Output; //In 10Khz unit -+ ULONG ulReserved5; //Was usMinEngineClockPLL_Input and usMaxEngineClockPLL_Input -+ ULONG ulReserved6; //Was usMinEngineClockPLL_Output and usMinMemoryClockPLL_Input -+ ULONG ulReserved7; //Was usMaxMemoryClockPLL_Input and usMinMemoryClockPLL_Output -+ USHORT usReserved11; //Was usMaxPixelClock; //In 10Khz unit, Max. Pclk used only for DAC -+ USHORT usMinPixelClockPLL_Input; //In 10Khz unit -+ USHORT usMaxPixelClockPLL_Input; //In 10Khz unit -+ USHORT usBootUpVDDCIVoltage; //In unit of mv; Was usMinPixelClockPLL_Output; -+ ATOM_FIRMWARE_CAPABILITY_ACCESS usFirmwareCapability; -+ USHORT usCoreReferenceClock; //In 10Khz unit -+ USHORT usMemoryReferenceClock; //In 10Khz unit -+ USHORT usUniphyDPModeExtClkFreq; //In 10Khz unit, if it is 0, In DP Mode Uniphy Input clock from internal PPLL, otherwise Input clock from external Spread clock -+ UCHAR ucMemoryModule_ID; //Indicate what is the board design -+ UCHAR ucReserved9[3]; -+ USHORT usBootUpMVDDCVoltage; //In unit of mv; Was usMinPixelClockPLL_Output; -+ USHORT usReserved12; -+ ULONG ulReserved10[3]; // New added comparing to previous version -+}ATOM_FIRMWARE_INFO_V2_2; - --#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_1 -+#define ATOM_FIRMWARE_INFO_LAST ATOM_FIRMWARE_INFO_V2_2 - - /****************************************************************************/ - // Structures used in IntegratedSystemInfoTable -@@ -2212,7 +2597,7 @@ - ucDockingPinBit: which bit in this register to read the pin status; - ucDockingPinPolarity:Polarity of the pin when docked; - --ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, other bits reserved for now and must be 0x0 -+ulCPUCapInfo: [7:0]=1:Griffin;[7:0]=2:Greyhound;[7:0]=3:K8, [7:0]=4:Pharaoh, other bits reserved for now and must be 0x0 - - usNumberOfCyclesInPeriod:Indicate how many cycles when PWM duty is 100%. - -@@ -2250,6 +2635,14 @@ - usMinDownStreamHTLinkWidth: same as above. - */ - -+// ATOM_INTEGRATED_SYSTEM_INFO::ulCPUCapInfo - CPU type definition -+#define INTEGRATED_SYSTEM_INFO__UNKNOWN_CPU 0 -+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GRIFFIN 1 -+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__GREYHOUND 2 -+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__K8 3 -+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH 4 -+ -+#define INTEGRATED_SYSTEM_INFO__AMD_CPU__MAX_CODE INTEGRATED_SYSTEM_INFO__AMD_CPU__PHARAOH // this deff reflects max defined CPU code - - #define SYSTEM_CONFIG_POWEREXPRESS_ENABLE 0x00000001 - #define SYSTEM_CONFIG_RUN_AT_OVERDRIVE_ENGINE 0x00000002 -@@ -2778,8 +3171,88 @@ - #define PANEL_RANDOM_DITHER 0x80 - #define PANEL_RANDOM_DITHER_MASK 0x80 - -+#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 // no need to change this -+ -+/****************************************************************************/ -+// Structures used by LCD_InfoTable V1.3 Note: previous version was called ATOM_LVDS_INFO_V12 -+// ASIC Families: NI -+// ucTableFormatRevision=1 -+// ucTableContentRevision=3 -+/****************************************************************************/ -+typedef struct _ATOM_LCD_INFO_V13 -+{ -+ ATOM_COMMON_TABLE_HEADER sHeader; -+ ATOM_DTD_FORMAT sLCDTiming; -+ USHORT usExtInfoTableOffset; -+ USHORT usSupportedRefreshRate; //Refer to panel info table in ATOMBIOS extension Spec. -+ ULONG ulReserved0; -+ UCHAR ucLCD_Misc; // Reorganized in V13 -+ // Bit0: {=0:single, =1:dual}, -+ // Bit1: {=0:LDI format for RGB888, =1 FPDI format for RGB888} // was {=0:666RGB, =1:888RGB}, -+ // Bit3:2: {Grey level} -+ // Bit6:4 Color Bit Depth definition (see below definition in EDID V1.4 @BYTE 14h) -+ // Bit7 Reserved. was for ATOM_PANEL_MISC_API_ENABLED, still need it? -+ UCHAR ucPanelDefaultRefreshRate; -+ UCHAR ucPanelIdentification; -+ UCHAR ucSS_Id; -+ USHORT usLCDVenderID; -+ USHORT usLCDProductID; -+ UCHAR ucLCDPanel_SpecialHandlingCap; // Reorganized in V13 -+ // Bit0: Once DAL sees this CAP is set, it will read EDID from LCD on its own -+ // Bit1: See LCDPANEL_CAP_DRR_SUPPORTED -+ // Bit2: a quick reference whether an embadded panel (LCD1 ) is LVDS (0) or eDP (1) -+ // Bit7-3: Reserved -+ UCHAR ucPanelInfoSize; // start from ATOM_DTD_FORMAT to end of panel info, include ExtInfoTable -+ USHORT usBacklightPWM; // Backlight PWM in Hz. New in _V13 -+ -+ UCHAR ucPowerSequenceDIGONtoDE_in4Ms; -+ UCHAR ucPowerSequenceDEtoVARY_BL_in4Ms; -+ UCHAR ucPowerSequenceDEtoDIGON_in4Ms; -+ UCHAR ucPowerSequenceVARY_BLtoDE_in4Ms; -+ -+ UCHAR ucOffDelay_in4Ms; -+ UCHAR ucPowerSequenceVARY_BLtoBLON_in4Ms; -+ UCHAR ucPowerSequenceBLONtoVARY_BL_in4Ms; -+ UCHAR ucReserved1; -+ -+ ULONG ulReserved[4]; -+}ATOM_LCD_INFO_V13; -+ -+#define ATOM_LCD_INFO_LAST ATOM_LCD_INFO_V13 -+ -+//Definitions for ucLCD_Misc -+#define ATOM_PANEL_MISC_V13_DUAL 0x00000001 -+#define ATOM_PANEL_MISC_V13_FPDI 0x00000002 -+#define ATOM_PANEL_MISC_V13_GREY_LEVEL 0x0000000C -+#define ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT 2 -+#define ATOM_PANEL_MISC_V13_COLOR_BIT_DEPTH_MASK 0x70 -+#define ATOM_PANEL_MISC_V13_6BIT_PER_COLOR 0x10 -+#define ATOM_PANEL_MISC_V13_8BIT_PER_COLOR 0x20 -+ -+//Color Bit Depth definition in EDID V1.4 @BYTE 14h -+//Bit 6 5 4 -+ // 0 0 0 - Color bit depth is undefined -+ // 0 0 1 - 6 Bits per Primary Color -+ // 0 1 0 - 8 Bits per Primary Color -+ // 0 1 1 - 10 Bits per Primary Color -+ // 1 0 0 - 12 Bits per Primary Color -+ // 1 0 1 - 14 Bits per Primary Color -+ // 1 1 0 - 16 Bits per Primary Color -+ // 1 1 1 - Reserved -+ -+//Definitions for ucLCDPanel_SpecialHandlingCap: -+ -+//Once DAL sees this CAP is set, it will read EDID from LCD on its own instead of using sLCDTiming in ATOM_LVDS_INFO_V12. -+//Other entries in ATOM_LVDS_INFO_V12 are still valid/useful to DAL -+#define LCDPANEL_CAP_V13_READ_EDID 0x1 // = LCDPANEL_CAP_READ_EDID no change comparing to previous version - --#define ATOM_LVDS_INFO_LAST ATOM_LVDS_INFO_V12 -+//If a design supports DRR (dynamic refresh rate) on internal panels (LVDS or EDP), this cap is set in ucLCDPanel_SpecialHandlingCap together -+//with multiple supported refresh rates@usSupportedRefreshRate. This cap should not be set when only slow refresh rate is supported (static -+//refresh rate switch by SW. This is only valid from ATOM_LVDS_INFO_V12 -+#define LCDPANEL_CAP_V13_DRR_SUPPORTED 0x2 // = LCDPANEL_CAP_DRR_SUPPORTED no change comparing to previous version -+ -+//Use this cap bit for a quick reference whether an embadded panel (LCD1 ) is LVDS or eDP. -+#define LCDPANEL_CAP_V13_eDP 0x4 // = LCDPANEL_CAP_eDP no change comparing to previous version - - typedef struct _ATOM_PATCH_RECORD_MODE - { -@@ -2944,9 +3417,9 @@ - #define MAX_DTD_MODE_IN_VRAM 6 - #define ATOM_DTD_MODE_SUPPORT_TBL_SIZE (MAX_DTD_MODE_IN_VRAM*28) //28= (SIZEOF ATOM_DTD_FORMAT) - #define ATOM_STD_MODE_SUPPORT_TBL_SIZE 32*8 //32 is a predefined number,8= (SIZEOF ATOM_STD_FORMAT) --#define DFP_ENCODER_TYPE_OFFSET 0x80 --#define DP_ENCODER_LANE_NUM_OFFSET 0x84 --#define DP_ENCODER_LINK_RATE_OFFSET 0x88 -+//20 bytes for Encoder Type and DPCD in STD EDID area -+#define DFP_ENCODER_TYPE_OFFSET (ATOM_EDID_RAW_DATASIZE + ATOM_DTD_MODE_SUPPORT_TBL_SIZE + ATOM_STD_MODE_SUPPORT_TBL_SIZE - 20) -+#define ATOM_DP_DPCD_OFFSET (DFP_ENCODER_TYPE_OFFSET + 4 ) - - #define ATOM_HWICON1_SURFACE_ADDR 0 - #define ATOM_HWICON2_SURFACE_ADDR (ATOM_HWICON1_SURFACE_ADDR + ATOM_HWICON_SURFACE_SIZE) -@@ -2997,14 +3470,16 @@ - #define ATOM_DFP5_DTD_MODE_TBL_ADDR (ATOM_DFP5_EDID_ADDR + ATOM_EDID_RAW_DATASIZE) - #define ATOM_DFP5_STD_MODE_TBL_ADDR (ATOM_DFP5_DTD_MODE_TBL_ADDR + ATOM_DTD_MODE_SUPPORT_TBL_SIZE) - --#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR+ATOM_STD_MODE_SUPPORT_TBL_SIZE) -+#define ATOM_DP_TRAINING_TBL_ADDR (ATOM_DFP5_STD_MODE_TBL_ADDR + ATOM_STD_MODE_SUPPORT_TBL_SIZE) - --#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR+256) --#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START+512 -+#define ATOM_STACK_STORAGE_START (ATOM_DP_TRAINING_TBL_ADDR + 1024) -+#define ATOM_STACK_STORAGE_END ATOM_STACK_STORAGE_START + 512 - - //The size below is in Kb! - #define ATOM_VRAM_RESERVE_SIZE ((((ATOM_STACK_STORAGE_END - ATOM_HWICON1_SURFACE_ADDR)>>10)+4)&0xFFFC) - -+#define ATOM_VRAM_RESERVE_V2_SIZE 32 -+ - #define ATOM_VRAM_OPERATION_FLAGS_MASK 0xC0000000L - #define ATOM_VRAM_OPERATION_FLAGS_SHIFT 30 - #define ATOM_VRAM_BLOCK_NEEDS_NO_RESERVATION 0x1 -@@ -3206,6 +3681,15 @@ - USHORT usGraphicObjIds[1]; //1st Encoder Obj source from GPU to last Graphic Obj destinate to connector. - }ATOM_DISPLAY_OBJECT_PATH; - -+typedef struct _ATOM_DISPLAY_EXTERNAL_OBJECT_PATH -+{ -+ USHORT usDeviceTag; //supported device -+ USHORT usSize; //the size of ATOM_DISPLAY_OBJECT_PATH -+ USHORT usConnObjectId; //Connector Object ID -+ USHORT usGPUObjectId; //GPU ID -+ USHORT usGraphicObjIds[2]; //usGraphicObjIds[0]= GPU internal encoder, usGraphicObjIds[1]= external encoder -+}ATOM_DISPLAY_EXTERNAL_OBJECT_PATH; -+ - typedef struct _ATOM_DISPLAY_OBJECT_PATH_TABLE - { - UCHAR ucNumOfDispPath; -@@ -3261,6 +3745,47 @@ - #define EXT_AUXDDC_LUTINDEX_7 7 - #define MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES (EXT_AUXDDC_LUTINDEX_7+1) - -+//ucChannelMapping are defined as following -+//for DP connector, eDP, DP to VGA/LVDS -+//Bit[1:0]: Define which pin connect to DP connector DP_Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+//Bit[3:2]: Define which pin connect to DP connector DP_Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+//Bit[5:4]: Define which pin connect to DP connector DP_Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+//Bit[7:6]: Define which pin connect to DP connector DP_Lane3, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+typedef struct _ATOM_DP_CONN_CHANNEL_MAPPING -+{ -+#if ATOM_BIG_ENDIAN -+ UCHAR ucDP_Lane3_Source:2; -+ UCHAR ucDP_Lane2_Source:2; -+ UCHAR ucDP_Lane1_Source:2; -+ UCHAR ucDP_Lane0_Source:2; -+#else -+ UCHAR ucDP_Lane0_Source:2; -+ UCHAR ucDP_Lane1_Source:2; -+ UCHAR ucDP_Lane2_Source:2; -+ UCHAR ucDP_Lane3_Source:2; -+#endif -+}ATOM_DP_CONN_CHANNEL_MAPPING; -+ -+//for DVI/HDMI, in dual link case, both links have to have same mapping. -+//Bit[1:0]: Define which pin connect to DVI connector data Lane2, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+//Bit[3:2]: Define which pin connect to DVI connector data Lane1, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+//Bit[5:4]: Define which pin connect to DVI connector data Lane0, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+//Bit[7:6]: Define which pin connect to DVI connector clock lane, =0: source from GPU pin TX0, =1: from GPU pin TX1, =2: from GPU pin TX2, =3 from GPU pin TX3 -+typedef struct _ATOM_DVI_CONN_CHANNEL_MAPPING -+{ -+#if ATOM_BIG_ENDIAN -+ UCHAR ucDVI_CLK_Source:2; -+ UCHAR ucDVI_DATA0_Source:2; -+ UCHAR ucDVI_DATA1_Source:2; -+ UCHAR ucDVI_DATA2_Source:2; -+#else -+ UCHAR ucDVI_DATA2_Source:2; -+ UCHAR ucDVI_DATA1_Source:2; -+ UCHAR ucDVI_DATA0_Source:2; -+ UCHAR ucDVI_CLK_Source:2; -+#endif -+}ATOM_DVI_CONN_CHANNEL_MAPPING; -+ - typedef struct _EXT_DISPLAY_PATH - { - USHORT usDeviceTag; //A bit vector to show what devices are supported -@@ -3269,7 +3794,13 @@ - UCHAR ucExtAUXDDCLutIndex; //An index into external AUX/DDC channel LUT - UCHAR ucExtHPDPINLutIndex; //An index into external HPD pin LUT - USHORT usExtEncoderObjId; //external encoder object id -- USHORT usReserved[3]; -+ union{ -+ UCHAR ucChannelMapping; // if ucChannelMapping=0, using default one to one mapping -+ ATOM_DP_CONN_CHANNEL_MAPPING asDPMapping; -+ ATOM_DVI_CONN_CHANNEL_MAPPING asDVIMapping; -+ }; -+ UCHAR ucReserved; -+ USHORT usReserved[2]; - }EXT_DISPLAY_PATH; - - #define NUMBER_OF_UCHAR_FOR_GUID 16 -@@ -3281,7 +3812,8 @@ - UCHAR ucGuid [NUMBER_OF_UCHAR_FOR_GUID]; // a GUID is a 16 byte long string - EXT_DISPLAY_PATH sPath[MAX_NUMBER_OF_EXT_DISPLAY_PATH]; // total of fixed 7 entries. - UCHAR ucChecksum; // a simple Checksum of the sum of whole structure equal to 0x0. -- UCHAR Reserved [7]; // for potential expansion -+ UCHAR uc3DStereoPinId; // use for eDP panel -+ UCHAR Reserved [6]; // for potential expansion - }ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO; - - //Related definitions, all records are differnt but they have a commond header -@@ -3311,10 +3843,11 @@ - #define ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE 17 //This is for the case when connectors are not known to object table - #define ATOM_OBJECT_LINK_RECORD_TYPE 18 //Once this record is present under one object, it indicats the oobject is linked to another obj described by the record - #define ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE 19 -+#define ATOM_ENCODER_CAP_RECORD_TYPE 20 - - - //Must be updated when new record type is added,equal to that record definition! --#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_CONNECTOR_REMOTE_CAP_RECORD_TYPE -+#define ATOM_MAX_OBJECT_RECORD_NUMBER ATOM_ENCODER_CAP_RECORD_TYPE - - typedef struct _ATOM_I2C_RECORD - { -@@ -3441,6 +3974,26 @@ - UCHAR ucPadding[2]; - }ATOM_ENCODER_DVO_CF_RECORD; - -+// Bit maps for ATOM_ENCODER_CAP_RECORD.ucEncoderCap -+#define ATOM_ENCODER_CAP_RECORD_HBR2 0x01 // DP1.2 HBR2 is supported by this path -+ -+typedef struct _ATOM_ENCODER_CAP_RECORD -+{ -+ ATOM_COMMON_RECORD_HEADER sheader; -+ union { -+ USHORT usEncoderCap; -+ struct { -+#if ATOM_BIG_ENDIAN -+ USHORT usReserved:15; // Bit1-15 may be defined for other capability in future -+ USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability. -+#else -+ USHORT usHBR2Cap:1; // Bit0 is for DP1.2 HBR2 capability. -+ USHORT usReserved:15; // Bit1-15 may be defined for other capability in future -+#endif -+ }; -+ }; -+}ATOM_ENCODER_CAP_RECORD; -+ - // value for ATOM_CONNECTOR_CF_RECORD.ucConnectedDvoBundle - #define ATOM_CONNECTOR_CF_RECORD_CONNECTED_UPPER12BITBUNDLEA 1 - #define ATOM_CONNECTOR_CF_RECORD_CONNECTED_LOWER12BITBUNDLEB 2 -@@ -3580,6 +4133,11 @@ - #define VOLTAGE_CONTROL_ID_DAC 0x02 //I2C control, used for R5xx/R6xx MVDDC,MVDDQ or VDDCI - #define VOLTAGE_CONTROL_ID_VT116xM 0x03 //I2C control, used for R6xx Core Voltage - #define VOLTAGE_CONTROL_ID_DS4402 0x04 -+#define VOLTAGE_CONTROL_ID_UP6266 0x05 -+#define VOLTAGE_CONTROL_ID_SCORPIO 0x06 -+#define VOLTAGE_CONTROL_ID_VT1556M 0x07 -+#define VOLTAGE_CONTROL_ID_CHL822x 0x08 -+#define VOLTAGE_CONTROL_ID_VT1586M 0x09 - - typedef struct _ATOM_VOLTAGE_OBJECT - { -@@ -3670,66 +4228,157 @@ - #define POWER_SENSOR_GPIO 0x01 - #define POWER_SENSOR_I2C 0x02 - -+typedef struct _ATOM_CLK_VOLT_CAPABILITY -+{ -+ ULONG ulVoltageIndex; // The Voltage Index indicated by FUSE, same voltage index shared with SCLK DPM fuse table -+ ULONG ulMaximumSupportedCLK; // Maximum clock supported with specified voltage index, unit in 10kHz -+}ATOM_CLK_VOLT_CAPABILITY; -+ -+typedef struct _ATOM_AVAILABLE_SCLK_LIST -+{ -+ ULONG ulSupportedSCLK; // Maximum clock supported with specified voltage index, unit in 10kHz -+ USHORT usVoltageIndex; // The Voltage Index indicated by FUSE for specified SCLK -+ USHORT usVoltageID; // The Voltage ID indicated by FUSE for specified SCLK -+}ATOM_AVAILABLE_SCLK_LIST; -+ -+// ATOM_INTEGRATED_SYSTEM_INFO_V6 ulSystemConfig cap definition -+#define ATOM_IGP_INFO_V6_SYSTEM_CONFIG__PCIE_POWER_GATING_ENABLE 1 // refer to ulSystemConfig bit[0] -+ -+// this IntegrateSystemInfoTable is used for Liano/Ontario APU - typedef struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 - { - ATOM_COMMON_TABLE_HEADER sHeader; - ULONG ulBootUpEngineClock; - ULONG ulDentistVCOFreq; - ULONG ulBootUpUMAClock; -- ULONG ulReserved1[8]; -+ ATOM_CLK_VOLT_CAPABILITY sDISPCLK_Voltage[4]; - ULONG ulBootUpReqDisplayVector; - ULONG ulOtherDisplayMisc; - ULONG ulGPUCapInfo; -- ULONG ulReserved2[3]; -+ ULONG ulSB_MMIO_Base_Addr; -+ USHORT usRequestedPWMFreqInHz; -+ UCHAR ucHtcTmpLmt; -+ UCHAR ucHtcHystLmt; -+ ULONG ulMinEngineClock; - ULONG ulSystemConfig; - ULONG ulCPUCapInfo; -- USHORT usMaxNBVoltage; -- USHORT usMinNBVoltage; -- USHORT usBootUpNBVoltage; -- USHORT usExtDispConnInfoOffset; -- UCHAR ucHtcTmpLmt; -- UCHAR ucTjOffset; -+ USHORT usNBP0Voltage; -+ USHORT usNBP1Voltage; -+ USHORT usBootUpNBVoltage; -+ USHORT usExtDispConnInfoOffset; -+ USHORT usPanelRefreshRateRange; - UCHAR ucMemoryType; - UCHAR ucUMAChannelNumber; - ULONG ulCSR_M3_ARB_CNTL_DEFAULT[10]; - ULONG ulCSR_M3_ARB_CNTL_UVD[10]; - ULONG ulCSR_M3_ARB_CNTL_FS3D[10]; -- ULONG ulReserved3[42]; -+ ATOM_AVAILABLE_SCLK_LIST sAvail_SCLK[5]; -+ ULONG ulGMCRestoreResetTime; -+ ULONG ulMinimumNClk; -+ ULONG ulIdleNClk; -+ ULONG ulDDR_DLL_PowerUpTime; -+ ULONG ulDDR_PLL_PowerUpTime; -+ USHORT usPCIEClkSSPercentage; -+ USHORT usPCIEClkSSType; -+ USHORT usLvdsSSPercentage; -+ USHORT usLvdsSSpreadRateIn10Hz; -+ USHORT usHDMISSPercentage; -+ USHORT usHDMISSpreadRateIn10Hz; -+ USHORT usDVISSPercentage; -+ USHORT usDVISSpreadRateIn10Hz; -+ ULONG ulReserved3[21]; - ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO sExtDispConnInfo; - }ATOM_INTEGRATED_SYSTEM_INFO_V6; - -+// ulGPUCapInfo -+#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__TMDSHDMI_COHERENT_SINGLEPLL_MODE 0x01 -+#define INTEGRATED_SYSTEM_INFO_V6_GPUCAPINFO__DISABLE_AUX_HW_MODE_DETECTION 0x08 -+ -+// ulOtherDisplayMisc -+#define INTEGRATED_SYSTEM_INFO__GET_EDID_CALLBACK_FUNC_SUPPORT 0x01 -+ -+ - /********************************************************************************************************************** --// ATOM_INTEGRATED_SYSTEM_INFO_V6 Description --//ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. --//ulDentistVCOFreq: Dentist VCO clock in 10kHz unit. --//ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit. --//ulReserved1[8] Reserved by now, must be 0x0. --//ulBootUpReqDisplayVector VBIOS boot up display IDs --// ATOM_DEVICE_CRT1_SUPPORT 0x0001 --// ATOM_DEVICE_CRT2_SUPPORT 0x0010 --// ATOM_DEVICE_DFP1_SUPPORT 0x0008 --// ATOM_DEVICE_DFP6_SUPPORT 0x0040 --// ATOM_DEVICE_DFP2_SUPPORT 0x0080 --// ATOM_DEVICE_DFP3_SUPPORT 0x0200 --// ATOM_DEVICE_DFP4_SUPPORT 0x0400 --// ATOM_DEVICE_DFP5_SUPPORT 0x0800 --// ATOM_DEVICE_LCD1_SUPPORT 0x0002 --//ulOtherDisplayMisc Other display related flags, not defined yet. --//ulGPUCapInfo TBD --//ulReserved2[3] must be 0x0 for the reserved. --//ulSystemConfig TBD --//ulCPUCapInfo TBD --//usMaxNBVoltage High NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse. --//usMinNBVoltage Low NB voltage in unit of mv, calculated using current VDDNB (D24F2xDC) and VDDNB offset fuse. --//usBootUpNBVoltage Boot up NB voltage in unit of mv. --//ucHtcTmpLmt Bit [22:16] of D24F3x64 Thermal Control (HTC) Register. --//ucTjOffset Bit [28:22] of D24F3xE4 Thermtrip Status Register,may not be needed. --//ucMemoryType [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved. --//ucUMAChannelNumber System memory channel numbers. --//usExtDispConnectionInfoOffset ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO offset relative to beginning of this table. --//ulCSR_M3_ARB_CNTL_DEFAULT[10] Arrays with values for CSR M3 arbiter for default --//ulCSR_M3_ARB_CNTL_UVD[10] Arrays with values for CSR M3 arbiter for UVD playback. --//ulCSR_M3_ARB_CNTL_FS3D[10] Arrays with values for CSR M3 arbiter for Full Screen 3D applications. -+ ATOM_INTEGRATED_SYSTEM_INFO_V6 Description -+ulBootUpEngineClock: VBIOS bootup Engine clock frequency, in 10kHz unit. if it is equal 0, then VBIOS use pre-defined bootup engine clock -+ulDentistVCOFreq: Dentist VCO clock in 10kHz unit. -+ulBootUpUMAClock: System memory boot up clock frequency in 10Khz unit. -+sDISPCLK_Voltage: Report Display clock voltage requirement. -+ -+ulBootUpReqDisplayVector: VBIOS boot up display IDs, following are supported devices in Liano/Ontaio projects: -+ ATOM_DEVICE_CRT1_SUPPORT 0x0001 -+ ATOM_DEVICE_CRT2_SUPPORT 0x0010 -+ ATOM_DEVICE_DFP1_SUPPORT 0x0008 -+ ATOM_DEVICE_DFP6_SUPPORT 0x0040 -+ ATOM_DEVICE_DFP2_SUPPORT 0x0080 -+ ATOM_DEVICE_DFP3_SUPPORT 0x0200 -+ ATOM_DEVICE_DFP4_SUPPORT 0x0400 -+ ATOM_DEVICE_DFP5_SUPPORT 0x0800 -+ ATOM_DEVICE_LCD1_SUPPORT 0x0002 -+ulOtherDisplayMisc: Other display related flags, not defined yet. -+ulGPUCapInfo: bit[0]=0: TMDS/HDMI Coherent Mode use cascade PLL mode. -+ =1: TMDS/HDMI Coherent Mode use signel PLL mode. -+ bit[3]=0: Enable HW AUX mode detection logic -+ =1: Disable HW AUX mode dettion logic -+ulSB_MMIO_Base_Addr: Physical Base address to SB MMIO space. Driver needs to initialize it for SMU usage. -+ -+usRequestedPWMFreqInHz: When it's set to 0x0 by SBIOS: the LCD BackLight is not controlled by GPU(SW). -+ Any attempt to change BL using VBIOS function or enable VariBri from PP table is not effective since ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==0; -+ -+ When it's set to a non-zero frequency, the BackLight is controlled by GPU (SW) in one of two ways below: -+ 1. SW uses the GPU BL PWM output to control the BL, in chis case, this non-zero frequency determines what freq GPU should use; -+ VBIOS will set up proper PWM frequency and ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1,as the result, -+ Changing BL using VBIOS function is functional in both driver and non-driver present environment; -+ and enabling VariBri under the driver environment from PP table is optional. -+ -+ 2. SW uses other means to control BL (like DPCD),this non-zero frequency serves as a flag only indicating -+ that BL control from GPU is expected. -+ VBIOS will NOT set up PWM frequency but make ATOM_BIOS_INFO_BL_CONTROLLED_BY_GPU==1 -+ Changing BL using VBIOS function could be functional in both driver and non-driver present environment,but -+ it's per platform -+ and enabling VariBri under the driver environment from PP table is optional. -+ -+ucHtcTmpLmt: Refer to D18F3x64 bit[22:16], HtcTmpLmt. -+ Threshold on value to enter HTC_active state. -+ucHtcHystLmt: Refer to D18F3x64 bit[27:24], HtcHystLmt. -+ To calculate threshold off value to exit HTC_active state, which is Threshold on vlaue minus ucHtcHystLmt. -+ulMinEngineClock: Minimum SCLK allowed in 10kHz unit. This is calculated based on WRCK Fuse settings. -+ulSystemConfig: Bit[0]=0: PCIE Power Gating Disabled -+ =1: PCIE Power Gating Enabled -+ Bit[1]=0: DDR-DLL shut-down feature disabled. -+ 1: DDR-DLL shut-down feature enabled. -+ Bit[2]=0: DDR-PLL Power down feature disabled. -+ 1: DDR-PLL Power down feature enabled. -+ulCPUCapInfo: TBD -+usNBP0Voltage: VID for voltage on NB P0 State -+usNBP1Voltage: VID for voltage on NB P1 State -+usBootUpNBVoltage: Voltage Index of GNB voltage configured by SBIOS, which is suffcient to support VBIOS DISPCLK requirement. -+usExtDispConnInfoOffset: Offset to sExtDispConnInfo inside the structure -+usPanelRefreshRateRange: Bit vector for LCD supported refresh rate range. If DRR is requestd by the platform, at least two bits need to be set -+ to indicate a range. -+ SUPPORTED_LCD_REFRESHRATE_30Hz 0x0004 -+ SUPPORTED_LCD_REFRESHRATE_40Hz 0x0008 -+ SUPPORTED_LCD_REFRESHRATE_50Hz 0x0010 -+ SUPPORTED_LCD_REFRESHRATE_60Hz 0x0020 -+ucMemoryType: [3:0]=1:DDR1;=2:DDR2;=3:DDR3.[7:4] is reserved. -+ucUMAChannelNumber: System memory channel numbers. -+ulCSR_M3_ARB_CNTL_DEFAULT[10]: Arrays with values for CSR M3 arbiter for default -+ulCSR_M3_ARB_CNTL_UVD[10]: Arrays with values for CSR M3 arbiter for UVD playback. -+ulCSR_M3_ARB_CNTL_FS3D[10]: Arrays with values for CSR M3 arbiter for Full Screen 3D applications. -+sAvail_SCLK[5]: Arrays to provide availabe list of SLCK and corresponding voltage, order from low to high -+ulGMCRestoreResetTime: GMC power restore and GMC reset time to calculate data reconnection latency. Unit in ns. -+ulMinimumNClk: Minimum NCLK speed among all NB-Pstates to calcualte data reconnection latency. Unit in 10kHz. -+ulIdleNClk: NCLK speed while memory runs in self-refresh state. Unit in 10kHz. -+ulDDR_DLL_PowerUpTime: DDR PHY DLL power up time. Unit in ns. -+ulDDR_PLL_PowerUpTime: DDR PHY PLL power up time. Unit in ns. -+usPCIEClkSSPercentage: PCIE Clock Spred Spectrum Percentage in unit 0.01%; 100 mean 1%. -+usPCIEClkSSType: PCIE Clock Spred Spectrum Type. 0 for Down spread(default); 1 for Center spread. -+usLvdsSSPercentage: LVDS panel ( not include eDP ) Spread Spectrum Percentage in unit of 0.01%, =0, use VBIOS default setting. -+usLvdsSSpreadRateIn10Hz: LVDS panel ( not include eDP ) Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. -+usHDMISSPercentage: HDMI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. -+usHDMISSpreadRateIn10Hz: HDMI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. -+usDVISSPercentage: DVI Spread Spectrum Percentage in unit 0.01%; 100 mean 1%, =0, use VBIOS default setting. -+usDVISSpreadRateIn10Hz: DVI Spread Spectrum frequency in unit of 10Hz, =0, use VBIOS default setting. - **********************************************************************************************************************/ - - /**************************************************************************/ -@@ -3790,6 +4439,7 @@ - #define ASIC_INTERNAL_SS_ON_LVDS 6 - #define ASIC_INTERNAL_SS_ON_DP 7 - #define ASIC_INTERNAL_SS_ON_DCPLL 8 -+#define ASIC_EXTERNAL_SS_ON_DP_CLOCK 9 - - typedef struct _ATOM_ASIC_SS_ASSIGNMENT_V2 - { -@@ -3903,6 +4553,7 @@ - #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_AC 1 - #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_DC 2 - #define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LITEAC 3 -+#define ATOM_S0_SYSTEM_POWER_STATE_VALUE_LIT2AC 4 - - //Byte aligned defintion for BIOS usage - #define ATOM_S0_CRT1_MONOb0 0x01 -@@ -4529,7 +5180,8 @@ - #define INDEX_ACCESS_RANGE_BEGIN (VALUE_DWORD + 1) - #define INDEX_ACCESS_RANGE_END (INDEX_ACCESS_RANGE_BEGIN + 1) - #define VALUE_INDEX_ACCESS_SINGLE (INDEX_ACCESS_RANGE_END + 1) -- -+//#define ACCESS_MCIODEBUGIND 0x40 //defined in BIOS code -+#define ACCESS_PLACEHOLDER 0x80 - - typedef struct _ATOM_MC_INIT_PARAM_TABLE - { -@@ -4554,6 +5206,10 @@ - #define _32Mx32 0x33 - #define _64Mx8 0x41 - #define _64Mx16 0x42 -+#define _64Mx32 0x43 -+#define _128Mx8 0x51 -+#define _128Mx16 0x52 -+#define _256Mx8 0x61 - - #define SAMSUNG 0x1 - #define INFINEON 0x2 -@@ -4569,10 +5225,11 @@ - #define QIMONDA INFINEON - #define PROMOS MOSEL - #define KRETON INFINEON -+#define ELIXIR NANYA - - /////////////Support for GDDR5 MC uCode to reside in upper 64K of ROM///////////// - --#define UCODE_ROM_START_ADDRESS 0x1c000 -+#define UCODE_ROM_START_ADDRESS 0x1b800 - #define UCODE_SIGNATURE 0x4375434d // 'MCuC' - MC uCode - - //uCode block header for reference -@@ -4903,7 +5560,34 @@ - ATOM_MEMORY_TIMING_FORMAT_V2 asMemTiming[5];//Memory Timing block sort from lower clock to higher clock - }ATOM_VRAM_MODULE_V6; - -- -+typedef struct _ATOM_VRAM_MODULE_V7 -+{ -+// Design Specific Values -+ ULONG ulChannelMapCfg; // mmMC_SHARED_CHREMAP -+ USHORT usModuleSize; // Size of ATOM_VRAM_MODULE_V7 -+ USHORT usPrivateReserved; // MC_ARB_RAMCFG (includes NOOFBANK,NOOFRANKS,NOOFROWS,NOOFCOLS) -+ USHORT usReserved; -+ UCHAR ucExtMemoryID; // Current memory module ID -+ UCHAR ucMemoryType; // MEM_TYPE_DDR2/DDR3/GDDR3/GDDR5 -+ UCHAR ucChannelNum; // Number of mem. channels supported in this module -+ UCHAR ucChannelWidth; // CHANNEL_16BIT/CHANNEL_32BIT/CHANNEL_64BIT -+ UCHAR ucDensity; // _8Mx32, _16Mx32, _16Mx16, _32Mx16 -+ UCHAR ucReserve; // Former container for Mx_FLAGS like DBI_AC_MODE_ENABLE_ASIC for GDDR4. Not used now. -+ UCHAR ucMisc; // RANK_OF_THISMEMORY etc. -+ UCHAR ucVREFI; // Not used. -+ UCHAR ucNPL_RT; // Round trip delay (MC_SEQ_CAS_TIMING [28:24]:TCL=CL+NPL_RT-2). Always 2. -+ UCHAR ucPreamble; // [7:4] Write Preamble, [3:0] Read Preamble -+ UCHAR ucMemorySize; // Total memory size in unit of 16MB for CONFIG_MEMSIZE - bit[23:0] zeros -+ UCHAR ucReserved[3]; -+// Memory Module specific values -+ USHORT usEMRS2Value; // EMRS2/MR2 Value. -+ USHORT usEMRS3Value; // EMRS3/MR3 Value. -+ UCHAR ucMemoryVenderID; // [7:4] Revision, [3:0] Vendor code -+ UCHAR ucRefreshRateFactor; // [1:0]=RefreshFactor (00=8ms, 01=16ms, 10=32ms,11=64ms) -+ UCHAR ucFIFODepth; // FIFO depth can be detected during vendor detection, here is hardcoded per memory -+ UCHAR ucCDR_Bandwidth; // [0:3]=Read CDR bandwidth, [4:7] - Write CDR Bandwidth -+ char strMemPNString[20]; // part number end with '0'. -+}ATOM_VRAM_MODULE_V7; - - typedef struct _ATOM_VRAM_INFO_V2 - { -@@ -4942,6 +5626,20 @@ - // ATOM_INIT_REG_BLOCK aMemAdjust; - }ATOM_VRAM_INFO_V4; - -+typedef struct _ATOM_VRAM_INFO_HEADER_V2_1 -+{ -+ ATOM_COMMON_TABLE_HEADER sHeader; -+ USHORT usMemAdjustTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory vendor specific MC adjust setting -+ USHORT usMemClkPatchTblOffset; // offset of ATOM_INIT_REG_BLOCK structure for memory clock specific MC setting -+ USHORT usReserved[4]; -+ UCHAR ucNumOfVRAMModule; // indicate number of VRAM module -+ UCHAR ucMemoryClkPatchTblVer; // version of memory AC timing register list -+ UCHAR ucVramModuleVer; // indicate ATOM_VRAM_MODUE version -+ UCHAR ucReserved; -+ ATOM_VRAM_MODULE_V7 aVramInfo[ATOM_MAX_NUMBER_OF_VRAM_MODULE]; // just for allocation, real number of blocks is in ucNumOfVRAMModule; -+}ATOM_VRAM_INFO_HEADER_V2_1; -+ -+ - typedef struct _ATOM_VRAM_GPIO_DETECTION_INFO - { - ATOM_COMMON_TABLE_HEADER sHeader; -@@ -5182,6 +5880,16 @@ - UCHAR ucReserved; - }ASIC_TRANSMITTER_INFO; - -+#define ASIC_TRANSMITTER_INFO_CONFIG__DVO_SDR_MODE 0x01 -+#define ASIC_TRANSMITTER_INFO_CONFIG__COHERENT_MODE 0x02 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODEROBJ_ID_MASK 0xc4 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_A 0x00 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_B 0x04 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_C 0x40 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_D 0x44 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_E 0x80 -+#define ASIC_TRANSMITTER_INFO_CONFIG__ENCODER_F 0x84 -+ - typedef struct _ASIC_ENCODER_INFO - { - UCHAR ucEncoderID; -@@ -5284,6 +5992,28 @@ - /* /obselete */ - #define DP_ENCODER_SERVICE_PS_ALLOCATION WRITE_ONE_BYTE_HW_I2C_DATA_PARAMETERS - -+ -+typedef struct _DP_ENCODER_SERVICE_PARAMETERS_V2 -+{ -+ USHORT usExtEncoderObjId; // External Encoder Object Id, output parameter only, use when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION -+ UCHAR ucAuxId; -+ UCHAR ucAction; -+ UCHAR ucSinkType; // Iput and Output parameters. -+ UCHAR ucHPDId; // Input parameter, used when ucAction = DP_SERVICE_V2_ACTION_DET_EXT_CONNECTION -+ UCHAR ucReserved[2]; -+}DP_ENCODER_SERVICE_PARAMETERS_V2; -+ -+typedef struct _DP_ENCODER_SERVICE_PS_ALLOCATION_V2 -+{ -+ DP_ENCODER_SERVICE_PARAMETERS_V2 asDPServiceParam; -+ PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 asAuxParam; -+}DP_ENCODER_SERVICE_PS_ALLOCATION_V2; -+ -+// ucAction -+#define DP_SERVICE_V2_ACTION_GET_SINK_TYPE 0x01 -+#define DP_SERVICE_V2_ACTION_DET_LCD_CONNECTION 0x02 -+ -+ - // DP_TRAINING_TABLE - #define DPCD_SET_LINKRATE_LANENUM_PATTERN1_TBL_ADDR ATOM_DP_TRAINING_TBL_ADDR - #define DPCD_SET_SS_CNTL_TBL_ADDR (ATOM_DP_TRAINING_TBL_ADDR + 8 ) -@@ -5339,6 +6069,7 @@ - #define SELECT_DCIO_IMPCAL 4 - #define SELECT_DCIO_DIG 6 - #define SELECT_CRTC_PIXEL_RATE 7 -+#define SELECT_VGA_BLK 8 - - /****************************************************************************/ - //Portion VI: Definitinos for vbios MC scratch registers that driver used -@@ -5744,7 +6475,17 @@ - #define ATOM_PP_THERMALCONTROLLER_ADT7473 9 - #define ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO 11 - #define ATOM_PP_THERMALCONTROLLER_EVERGREEN 12 -+#define ATOM_PP_THERMALCONTROLLER_EMC2103 13 /* 0x0D */ // Only fan control will be implemented, do NOT show this in PPGen. -+#define ATOM_PP_THERMALCONTROLLER_SUMO 14 /* 0x0E */ // Sumo type, used internally -+#define ATOM_PP_THERMALCONTROLLER_NISLANDS 15 -+ -+// Thermal controller 'combo type' to use an external controller for Fan control and an internal controller for thermal. -+// We probably should reserve the bit 0x80 for this use. -+// To keep the number of these types low we should also use the same code for all ASICs (i.e. do not distinguish RV6xx and RV7xx Internal here). -+// The driver can pick the correct internal controller based on the ASIC. -+ - #define ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL 0x89 // ADT7473 Fan Control + Internal Thermal Controller -+#define ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL 0x8D // EMC2103 Fan Control + Internal Thermal Controller - - typedef struct _ATOM_PPLIB_STATE - { -@@ -5841,6 +6582,29 @@ - USHORT usExtendendedHeaderOffset; - } ATOM_PPLIB_POWERPLAYTABLE3, *LPATOM_PPLIB_POWERPLAYTABLE3; - -+typedef struct _ATOM_PPLIB_POWERPLAYTABLE4 -+{ -+ ATOM_PPLIB_POWERPLAYTABLE3 basicTable3; -+ ULONG ulGoldenPPID; // PPGen use only -+ ULONG ulGoldenRevision; // PPGen use only -+ USHORT usVddcDependencyOnSCLKOffset; -+ USHORT usVddciDependencyOnMCLKOffset; -+ USHORT usVddcDependencyOnMCLKOffset; -+ USHORT usMaxClockVoltageOnDCOffset; -+ USHORT usReserved[2]; -+} ATOM_PPLIB_POWERPLAYTABLE4, *LPATOM_PPLIB_POWERPLAYTABLE4; -+ -+typedef struct _ATOM_PPLIB_POWERPLAYTABLE5 -+{ -+ ATOM_PPLIB_POWERPLAYTABLE4 basicTable4; -+ ULONG ulTDPLimit; -+ ULONG ulNearTDPLimit; -+ ULONG ulSQRampingThreshold; -+ USHORT usCACLeakageTableOffset; // Points to ATOM_PPLIB_CAC_Leakage_Table -+ ULONG ulCACLeakage; // TBD, this parameter is still under discussion. Change to ulReserved if not needed. -+ ULONG ulReserved; -+} ATOM_PPLIB_POWERPLAYTABLE5, *LPATOM_PPLIB_POWERPLAYTABLE5; -+ - //// ATOM_PPLIB_NONCLOCK_INFO::usClassification - #define ATOM_PPLIB_CLASSIFICATION_UI_MASK 0x0007 - #define ATOM_PPLIB_CLASSIFICATION_UI_SHIFT 0 -@@ -5864,6 +6628,10 @@ - #define ATOM_PPLIB_CLASSIFICATION_HDSTATE 0x4000 - #define ATOM_PPLIB_CLASSIFICATION_SDSTATE 0x8000 - -+//// ATOM_PPLIB_NONCLOCK_INFO::usClassification2 -+#define ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2 0x0001 -+#define ATOM_PPLIB_CLASSIFICATION2_ULV 0x0002 -+ - //// ATOM_PPLIB_NONCLOCK_INFO::ulCapsAndSettings - #define ATOM_PPLIB_SINGLE_DISPLAY_ONLY 0x00000001 - #define ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK 0x00000002 -@@ -5896,9 +6664,21 @@ - #define ATOM_PPLIB_M3ARB_MASK 0x00060000 - #define ATOM_PPLIB_M3ARB_SHIFT 17 - -+#define ATOM_PPLIB_ENABLE_DRR 0x00080000 -+ -+// remaining 16 bits are reserved -+typedef struct _ATOM_PPLIB_THERMAL_STATE -+{ -+ UCHAR ucMinTemperature; -+ UCHAR ucMaxTemperature; -+ UCHAR ucThermalAction; -+}ATOM_PPLIB_THERMAL_STATE, *LPATOM_PPLIB_THERMAL_STATE; -+ - // Contained in an array starting at the offset - // in ATOM_PPLIB_POWERPLAYTABLE::usNonClockInfoArrayOffset. - // referenced from ATOM_PPLIB_STATE_INFO::ucNonClockStateIndex -+#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 -+#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 - typedef struct _ATOM_PPLIB_NONCLOCK_INFO - { - USHORT usClassification; -@@ -5906,15 +6686,15 @@ - UCHAR ucMaxTemperature; - ULONG ulCapsAndSettings; - UCHAR ucRequiredPower; -- UCHAR ucUnused1[3]; -+ USHORT usClassification2; -+ ULONG ulVCLK; -+ ULONG ulDCLK; -+ UCHAR ucUnused[5]; - } ATOM_PPLIB_NONCLOCK_INFO; - - // Contained in an array starting at the offset - // in ATOM_PPLIB_POWERPLAYTABLE::usClockInfoArrayOffset. - // referenced from ATOM_PPLIB_STATE::ucClockStateIndices --#define ATOM_PPLIB_NONCLOCKINFO_VER1 12 --#define ATOM_PPLIB_NONCLOCKINFO_VER2 24 -- - typedef struct _ATOM_PPLIB_R600_CLOCK_INFO - { - USHORT usEngineClockLow; -@@ -5985,6 +6765,93 @@ - #define ATOM_PPLIB_RS780_HTLINKFREQ_LOW 1 - #define ATOM_PPLIB_RS780_HTLINKFREQ_HIGH 2 - -+typedef struct _ATOM_PPLIB_SUMO_CLOCK_INFO{ -+ USHORT usEngineClockLow; //clockfrequency & 0xFFFF. The unit is in 10khz -+ UCHAR ucEngineClockHigh; //clockfrequency >> 16. -+ UCHAR vddcIndex; //2-bit vddc index; -+ UCHAR leakage; //please use 8-bit absolute value, not the 6-bit % value -+ //please initalize to 0 -+ UCHAR rsv; -+ //please initalize to 0 -+ USHORT rsv1; -+ //please initialize to 0s -+ ULONG rsv2[2]; -+}ATOM_PPLIB_SUMO_CLOCK_INFO; -+ -+ -+ -+typedef struct _ATOM_PPLIB_STATE_V2 -+{ -+ //number of valid dpm levels in this state; Driver uses it to calculate the whole -+ //size of the state: sizeof(ATOM_PPLIB_STATE_V2) + (ucNumDPMLevels - 1) * sizeof(UCHAR) -+ UCHAR ucNumDPMLevels; -+ -+ //a index to the array of nonClockInfos -+ UCHAR nonClockInfoIndex; -+ /** -+ * Driver will read the first ucNumDPMLevels in this array -+ */ -+ UCHAR clockInfoIndex[1]; -+} ATOM_PPLIB_STATE_V2; -+ -+typedef struct StateArray{ -+ //how many states we have -+ UCHAR ucNumEntries; -+ -+ ATOM_PPLIB_STATE_V2 states[1]; -+}StateArray; -+ -+ -+typedef struct ClockInfoArray{ -+ //how many clock levels we have -+ UCHAR ucNumEntries; -+ -+ //sizeof(ATOM_PPLIB_SUMO_CLOCK_INFO) -+ UCHAR ucEntrySize; -+ -+ //this is for Sumo -+ ATOM_PPLIB_SUMO_CLOCK_INFO clockInfo[1]; -+}ClockInfoArray; -+ -+typedef struct NonClockInfoArray{ -+ -+ //how many non-clock levels we have. normally should be same as number of states -+ UCHAR ucNumEntries; -+ //sizeof(ATOM_PPLIB_NONCLOCK_INFO) -+ UCHAR ucEntrySize; -+ -+ ATOM_PPLIB_NONCLOCK_INFO nonClockInfo[1]; -+}NonClockInfoArray; -+ -+typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Record -+{ -+ USHORT usClockLow; -+ UCHAR ucClockHigh; -+ USHORT usVoltage; -+}ATOM_PPLIB_Clock_Voltage_Dependency_Record; -+ -+typedef struct _ATOM_PPLIB_Clock_Voltage_Dependency_Table -+{ -+ UCHAR ucNumEntries; // Number of entries. -+ ATOM_PPLIB_Clock_Voltage_Dependency_Record entries[1]; // Dynamically allocate entries. -+}ATOM_PPLIB_Clock_Voltage_Dependency_Table; -+ -+typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Record -+{ -+ USHORT usSclkLow; -+ UCHAR ucSclkHigh; -+ USHORT usMclkLow; -+ UCHAR ucMclkHigh; -+ USHORT usVddc; -+ USHORT usVddci; -+}ATOM_PPLIB_Clock_Voltage_Limit_Record; -+ -+typedef struct _ATOM_PPLIB_Clock_Voltage_Limit_Table -+{ -+ UCHAR ucNumEntries; // Number of entries. -+ ATOM_PPLIB_Clock_Voltage_Limit_Record entries[1]; // Dynamically allocate entries. -+}ATOM_PPLIB_Clock_Voltage_Limit_Table; -+ - /**************************************************************************/ - - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreen_blit_kms.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreen_blit_kms.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreen_blit_kms.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreen_blit_kms.c 2011-01-07 14:22:17.000000000 +0100 -@@ -147,7 +147,8 @@ - radeon_ring_write(rdev, 0); - radeon_ring_write(rdev, SQ_TEX_VTX_VALID_BUFFER << 30); - -- if (rdev->family == CHIP_CEDAR) -+ if ((rdev->family == CHIP_CEDAR) || -+ (rdev->family == CHIP_PALM)) - cp_set_surface_sync(rdev, - PACKET3_TC_ACTION_ENA, 48, gpu_addr); - else -@@ -331,9 +332,31 @@ - num_hs_stack_entries = 85; - num_ls_stack_entries = 85; - break; -+ case CHIP_PALM: -+ num_ps_gprs = 93; -+ num_vs_gprs = 46; -+ num_temp_gprs = 4; -+ num_gs_gprs = 31; -+ num_es_gprs = 31; -+ num_hs_gprs = 23; -+ num_ls_gprs = 23; -+ num_ps_threads = 96; -+ num_vs_threads = 16; -+ num_gs_threads = 16; -+ num_es_threads = 16; -+ num_hs_threads = 16; -+ num_ls_threads = 16; -+ num_ps_stack_entries = 42; -+ num_vs_stack_entries = 42; -+ num_gs_stack_entries = 42; -+ num_es_stack_entries = 42; -+ num_hs_stack_entries = 42; -+ num_ls_stack_entries = 42; -+ break; - } - -- if (rdev->family == CHIP_CEDAR) -+ if ((rdev->family == CHIP_CEDAR) || -+ (rdev->family == CHIP_PALM)) - sq_config = 0; - else - sq_config = VC_ENABLE; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreen.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreen.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreen.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreen.c 2011-01-07 14:22:17.000000000 +0100 -@@ -40,6 +40,61 @@ - static void evergreen_gpu_init(struct radeon_device *rdev); - void evergreen_fini(struct radeon_device *rdev); - -+void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; -+ u32 tmp; -+ -+ /* make sure flip is at vb rather than hb */ -+ tmp = RREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); -+ tmp &= ~EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN; -+ WREG32(EVERGREEN_GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); -+ -+ /* set pageflip to happen anywhere in vblank interval */ -+ WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); -+ -+ /* enable the pflip int */ -+ radeon_irq_kms_pflip_irq_get(rdev, crtc); -+} -+ -+void evergreen_post_page_flip(struct radeon_device *rdev, int crtc) -+{ -+ /* disable the pflip int */ -+ radeon_irq_kms_pflip_irq_put(rdev, crtc); -+} -+ -+u32 evergreen_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; -+ u32 tmp = RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset); -+ -+ /* Lock the graphics update lock */ -+ tmp |= EVERGREEN_GRPH_UPDATE_LOCK; -+ WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); -+ -+ /* update the scanout addresses */ -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, -+ upper_32_bits(crtc_base)); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -+ (u32)crtc_base); -+ -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + radeon_crtc->crtc_offset, -+ upper_32_bits(crtc_base)); -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -+ (u32)crtc_base); -+ -+ /* Wait for update_pending to go high. */ -+ while (!(RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING)); -+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); -+ -+ /* Unlock the lock, so double-buffering can take place inside vblank */ -+ tmp &= ~EVERGREEN_GRPH_UPDATE_LOCK; -+ WREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); -+ -+ /* Return current update_pending status: */ -+ return RREG32(EVERGREEN_GRPH_UPDATE + radeon_crtc->crtc_offset) & EVERGREEN_GRPH_SURFACE_UPDATE_PENDING; -+} -+ - /* get temperature in millidegrees */ - u32 evergreen_get_temp(struct radeon_device *rdev) - { -@@ -57,6 +112,14 @@ - return actual_temp * 1000; - } - -+u32 sumo_get_temp(struct radeon_device *rdev) -+{ -+ u32 temp = RREG32(CG_THERMAL_STATUS) & 0xff; -+ u32 actual_temp = (temp >> 1) & 0xff; -+ -+ return actual_temp * 1000; -+} -+ - void evergreen_pm_misc(struct radeon_device *rdev) - { - int req_ps_idx = rdev->pm.requested_power_state_index; -@@ -888,31 +951,39 @@ - save->vga_hdp_control = RREG32(VGA_HDP_CONTROL); - save->crtc_control[0] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET); - save->crtc_control[1] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); -- save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); -- save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); -- save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); -- save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ save->crtc_control[2] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET); -+ save->crtc_control[3] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET); -+ save->crtc_control[4] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET); -+ save->crtc_control[5] = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); -+ } - - /* Stop all video */ - WREG32(VGA_RENDER_CONTROL, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); -+ } - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ } - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ } - - WREG32(D1VGA_CONTROL, 0); - WREG32(D2VGA_CONTROL, 0); -@@ -942,41 +1013,43 @@ - WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC1_REGISTER_OFFSET, - (u32)rdev->mc.vram_start); - -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, -- upper_32_bits(rdev->mc.vram_start)); -- WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -- WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, -- (u32)rdev->mc.vram_start); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC2_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC2_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC3_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC3_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC4_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC4_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS_HIGH + EVERGREEN_CRTC5_REGISTER_OFFSET, -+ upper_32_bits(rdev->mc.vram_start)); -+ WREG32(EVERGREEN_GRPH_PRIMARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ WREG32(EVERGREEN_GRPH_SECONDARY_SURFACE_ADDRESS + EVERGREEN_CRTC5_REGISTER_OFFSET, -+ (u32)rdev->mc.vram_start); -+ } - - WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH, upper_32_bits(rdev->mc.vram_start)); - WREG32(EVERGREEN_VGA_MEMORY_BASE_ADDRESS, (u32)rdev->mc.vram_start); -@@ -992,22 +1065,28 @@ - WREG32(EVERGREEN_D6VGA_CONTROL, save->vga_control[5]); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 1); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 1); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 1); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 1); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 1); -+ } - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, save->crtc_control[0]); - WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, save->crtc_control[1]); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); -- WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, save->crtc_control[2]); -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, save->crtc_control[3]); -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, save->crtc_control[4]); -+ WREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, save->crtc_control[5]); -+ } - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -- WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -+ WREG32(EVERGREEN_CRTC_UPDATE_LOCK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ } - WREG32(VGA_RENDER_CONTROL, save->vga_render_control); - } - -@@ -1055,6 +1134,12 @@ - rdev->mc.vram_end >> 12); - } - WREG32(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR, 0); -+ if (rdev->flags & RADEON_IS_IGP) { -+ tmp = RREG32(MC_FUS_VM_FB_OFFSET) & 0x000FFFFF; -+ tmp |= ((rdev->mc.vram_end >> 20) & 0xF) << 24; -+ tmp |= ((rdev->mc.vram_start >> 20) & 0xF) << 20; -+ WREG32(MC_FUS_VM_FB_OFFSET, tmp); -+ } - tmp = ((rdev->mc.vram_end >> 24) & 0xFFFF) << 16; - tmp |= ((rdev->mc.vram_start >> 24) & 0xFFFF); - WREG32(MC_VM_FB_LOCATION, tmp); -@@ -1283,6 +1368,7 @@ - switch (rdev->family) { - case CHIP_CEDAR: - case CHIP_REDWOOD: -+ case CHIP_PALM: - force_no_swizzle = false; - break; - case CHIP_CYPRESS: -@@ -1382,6 +1468,43 @@ - return backend_map; - } - -+static void evergreen_program_channel_remap(struct radeon_device *rdev) -+{ -+ u32 tcp_chan_steer_lo, tcp_chan_steer_hi, mc_shared_chremap, tmp; -+ -+ tmp = RREG32(MC_SHARED_CHMAP); -+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { -+ case 0: -+ case 1: -+ case 2: -+ case 3: -+ default: -+ /* default mapping */ -+ mc_shared_chremap = 0x00fac688; -+ break; -+ } -+ -+ switch (rdev->family) { -+ case CHIP_HEMLOCK: -+ case CHIP_CYPRESS: -+ tcp_chan_steer_lo = 0x54763210; -+ tcp_chan_steer_hi = 0x0000ba98; -+ break; -+ case CHIP_JUNIPER: -+ case CHIP_REDWOOD: -+ case CHIP_CEDAR: -+ case CHIP_PALM: -+ default: -+ tcp_chan_steer_lo = 0x76543210; -+ tcp_chan_steer_hi = 0x0000ba98; -+ break; -+ } -+ -+ WREG32(TCP_CHAN_STEER_LO, tcp_chan_steer_lo); -+ WREG32(TCP_CHAN_STEER_HI, tcp_chan_steer_hi); -+ WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); -+} -+ - static void evergreen_gpu_init(struct radeon_device *rdev) - { - u32 cc_rb_backend_disable = 0; -@@ -1493,6 +1616,27 @@ - rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; - rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; - break; -+ case CHIP_PALM: -+ rdev->config.evergreen.num_ses = 1; -+ rdev->config.evergreen.max_pipes = 2; -+ rdev->config.evergreen.max_tile_pipes = 2; -+ rdev->config.evergreen.max_simds = 2; -+ rdev->config.evergreen.max_backends = 1 * rdev->config.evergreen.num_ses; -+ rdev->config.evergreen.max_gprs = 256; -+ rdev->config.evergreen.max_threads = 192; -+ rdev->config.evergreen.max_gs_threads = 16; -+ rdev->config.evergreen.max_stack_entries = 256; -+ rdev->config.evergreen.sx_num_of_sets = 4; -+ rdev->config.evergreen.sx_max_export_size = 128; -+ rdev->config.evergreen.sx_max_export_pos_size = 32; -+ rdev->config.evergreen.sx_max_export_smx_size = 96; -+ rdev->config.evergreen.max_hw_contexts = 4; -+ rdev->config.evergreen.sq_num_cf_insts = 1; -+ -+ rdev->config.evergreen.sc_prim_fifo_size = 0x40; -+ rdev->config.evergreen.sc_hiz_tile_fifo_size = 0x30; -+ rdev->config.evergreen.sc_earlyz_tile_fifo_size = 0x130; -+ break; - } - - /* Initialize HDP */ -@@ -1685,6 +1829,8 @@ - WREG32(DMIF_ADDR_CONFIG, gb_addr_config); - WREG32(HDP_ADDR_CONFIG, gb_addr_config); - -+ evergreen_program_channel_remap(rdev); -+ - num_shader_engines = ((RREG32(GB_ADDR_CONFIG) & NUM_SHADER_ENGINES(3)) >> 12) + 1; - grbm_gfx_index = INSTANCE_BROADCAST_WRITES; - -@@ -1767,9 +1913,15 @@ - GS_PRIO(2) | - ES_PRIO(3)); - -- if (rdev->family == CHIP_CEDAR) -+ switch (rdev->family) { -+ case CHIP_CEDAR: -+ case CHIP_PALM: - /* no vertex cache */ - sq_config &= ~VC_ENABLE; -+ break; -+ default: -+ break; -+ } - - sq_lds_resource_mgmt = RREG32(SQ_LDS_RESOURCE_MGMT); - -@@ -1781,10 +1933,15 @@ - sq_gpr_resource_mgmt_3 = NUM_HS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32); - sq_gpr_resource_mgmt_3 |= NUM_LS_GPRS((rdev->config.evergreen.max_gprs - (4 * 2)) * 3 / 32); - -- if (rdev->family == CHIP_CEDAR) -+ switch (rdev->family) { -+ case CHIP_CEDAR: -+ case CHIP_PALM: - ps_thread_count = 96; -- else -+ break; -+ default: - ps_thread_count = 128; -+ break; -+ } - - sq_thread_resource_mgmt = NUM_PS_THREADS(ps_thread_count); - sq_thread_resource_mgmt |= NUM_VS_THREADS((((rdev->config.evergreen.max_threads - ps_thread_count) / 6) / 8) * 8); -@@ -1815,10 +1972,15 @@ - WREG32(PA_SC_FORCE_EOV_MAX_CNTS, (FORCE_EOV_MAX_CLK_CNT(4095) | - FORCE_EOV_MAX_REZ_CNT(255))); - -- if (rdev->family == CHIP_CEDAR) -+ switch (rdev->family) { -+ case CHIP_CEDAR: -+ case CHIP_PALM: - vgt_cache_invalidation = CACHE_INVALIDATION(TC_ONLY); -- else -+ break; -+ default: - vgt_cache_invalidation = CACHE_INVALIDATION(VC_AND_TC); -+ break; -+ } - vgt_cache_invalidation |= AUTO_INVLD_EN(ES_AND_GS_AUTO); - WREG32(VGT_CACHE_INVALIDATION, vgt_cache_invalidation); - -@@ -1902,12 +2064,18 @@ - rdev->mc.aper_base = pci_resource_start(rdev->pdev, 0); - rdev->mc.aper_size = pci_resource_len(rdev->pdev, 0); - /* Setup GPU memory space */ -- /* size in MB on evergreen */ -- rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; -- rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; -+ if (rdev->flags & RADEON_IS_IGP) { -+ /* size in bytes on fusion */ -+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE); -+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); -+ } else { -+ /* size in MB on evergreen */ -+ rdev->mc.mc_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; -+ rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE) * 1024 * 1024; -+ } - rdev->mc.visible_vram_size = rdev->mc.aper_size; - rdev->mc.active_vram_size = rdev->mc.visible_vram_size; -- r600_vram_gtt_location(rdev, &rdev->mc); -+ r700_vram_gtt_location(rdev, &rdev->mc); - radeon_update_bandwidth_info(rdev); - - return 0; -@@ -2024,17 +2192,21 @@ - WREG32(GRBM_INT_CNTL, 0); - WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); -- WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -- WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -- WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -- WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -+ WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -+ WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -+ WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ } - - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, 0); - WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, 0); -- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -- WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, 0); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, 0); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, 0); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0); -+ } - - WREG32(DACA_AUTODETECT_INT_CONTROL, 0); - WREG32(DACB_AUTODETECT_INT_CONTROL, 0); -@@ -2060,6 +2232,7 @@ - u32 crtc1 = 0, crtc2 = 0, crtc3 = 0, crtc4 = 0, crtc5 = 0, crtc6 = 0; - u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6; - u32 grbm_int_cntl = 0; -+ u32 grph1 = 0, grph2 = 0, grph3 = 0, grph4 = 0, grph5 = 0, grph6 = 0; - - if (!rdev->irq.installed) { - WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); -@@ -2085,27 +2258,33 @@ - cp_int_cntl |= RB_INT_ENABLE; - cp_int_cntl |= TIME_STAMP_INT_ENABLE; - } -- if (rdev->irq.crtc_vblank_int[0]) { -+ if (rdev->irq.crtc_vblank_int[0] || -+ rdev->irq.pflip[0]) { - DRM_DEBUG("evergreen_irq_set: vblank 0\n"); - crtc1 |= VBLANK_INT_MASK; - } -- if (rdev->irq.crtc_vblank_int[1]) { -+ if (rdev->irq.crtc_vblank_int[1] || -+ rdev->irq.pflip[1]) { - DRM_DEBUG("evergreen_irq_set: vblank 1\n"); - crtc2 |= VBLANK_INT_MASK; - } -- if (rdev->irq.crtc_vblank_int[2]) { -+ if (rdev->irq.crtc_vblank_int[2] || -+ rdev->irq.pflip[2]) { - DRM_DEBUG("evergreen_irq_set: vblank 2\n"); - crtc3 |= VBLANK_INT_MASK; - } -- if (rdev->irq.crtc_vblank_int[3]) { -+ if (rdev->irq.crtc_vblank_int[3] || -+ rdev->irq.pflip[3]) { - DRM_DEBUG("evergreen_irq_set: vblank 3\n"); - crtc4 |= VBLANK_INT_MASK; - } -- if (rdev->irq.crtc_vblank_int[4]) { -+ if (rdev->irq.crtc_vblank_int[4] || -+ rdev->irq.pflip[4]) { - DRM_DEBUG("evergreen_irq_set: vblank 4\n"); - crtc5 |= VBLANK_INT_MASK; - } -- if (rdev->irq.crtc_vblank_int[5]) { -+ if (rdev->irq.crtc_vblank_int[5] || -+ rdev->irq.pflip[5]) { - DRM_DEBUG("evergreen_irq_set: vblank 5\n"); - crtc6 |= VBLANK_INT_MASK; - } -@@ -2143,10 +2322,19 @@ - - WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, crtc1); - WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, crtc2); -- WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); -- WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); -- WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); -- WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); -+ if (!(rdev->flags & RADEON_IS_IGP)) { -+ WREG32(INT_MASK + EVERGREEN_CRTC2_REGISTER_OFFSET, crtc3); -+ WREG32(INT_MASK + EVERGREEN_CRTC3_REGISTER_OFFSET, crtc4); -+ WREG32(INT_MASK + EVERGREEN_CRTC4_REGISTER_OFFSET, crtc5); -+ WREG32(INT_MASK + EVERGREEN_CRTC5_REGISTER_OFFSET, crtc6); -+ } -+ -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET, grph1); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET, grph2); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET, grph3); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET, grph4); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET, grph5); -+ WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, grph6); - - WREG32(DC_HPD1_INT_CONTROL, hpd1); - WREG32(DC_HPD2_INT_CONTROL, hpd2); -@@ -2158,79 +2346,92 @@ - return 0; - } - --static inline void evergreen_irq_ack(struct radeon_device *rdev, -- u32 *disp_int, -- u32 *disp_int_cont, -- u32 *disp_int_cont2, -- u32 *disp_int_cont3, -- u32 *disp_int_cont4, -- u32 *disp_int_cont5) -+static inline void evergreen_irq_ack(struct radeon_device *rdev) - { - u32 tmp; - -- *disp_int = RREG32(DISP_INTERRUPT_STATUS); -- *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); -- *disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); -- *disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); -- *disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); -- *disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); -+ rdev->irq.stat_regs.evergreen.disp_int = RREG32(DISP_INTERRUPT_STATUS); -+ rdev->irq.stat_regs.evergreen.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); -+ rdev->irq.stat_regs.evergreen.disp_int_cont2 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE2); -+ rdev->irq.stat_regs.evergreen.disp_int_cont3 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE3); -+ rdev->irq.stat_regs.evergreen.disp_int_cont4 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE4); -+ rdev->irq.stat_regs.evergreen.disp_int_cont5 = RREG32(DISP_INTERRUPT_STATUS_CONTINUE5); -+ rdev->irq.stat_regs.evergreen.d1grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET); -+ rdev->irq.stat_regs.evergreen.d2grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET); -+ rdev->irq.stat_regs.evergreen.d3grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET); -+ rdev->irq.stat_regs.evergreen.d4grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET); -+ rdev->irq.stat_regs.evergreen.d5grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET); -+ rdev->irq.stat_regs.evergreen.d6grph_int = RREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET); -+ -+ if (rdev->irq.stat_regs.evergreen.d1grph_int & GRPH_PFLIP_INT_OCCURRED) -+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.evergreen.d2grph_int & GRPH_PFLIP_INT_OCCURRED) -+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.evergreen.d3grph_int & GRPH_PFLIP_INT_OCCURRED) -+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.evergreen.d4grph_int & GRPH_PFLIP_INT_OCCURRED) -+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.evergreen.d5grph_int & GRPH_PFLIP_INT_OCCURRED) -+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.evergreen.d6grph_int & GRPH_PFLIP_INT_OCCURRED) -+ WREG32(GRPH_INT_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, GRPH_PFLIP_INT_CLEAR); - -- if (*disp_int & LB_D1_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VBLANK_ACK); -- if (*disp_int & LB_D1_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET, VLINE_ACK); - -- if (*disp_int_cont & LB_D2_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VBLANK_ACK); -- if (*disp_int_cont & LB_D2_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET, VLINE_ACK); - -- if (*disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VBLANK_ACK); -- if (*disp_int_cont2 & LB_D3_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET, VLINE_ACK); - -- if (*disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VBLANK_ACK); -- if (*disp_int_cont3 & LB_D4_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET, VLINE_ACK); - -- if (*disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VBLANK_ACK); -- if (*disp_int_cont4 & LB_D5_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET, VLINE_ACK); - -- if (*disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) - WREG32(VBLANK_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VBLANK_ACK); -- if (*disp_int_cont5 & LB_D6_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) - WREG32(VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET, VLINE_ACK); - -- if (*disp_int & DC_HPD1_INTERRUPT) { -+ if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { - tmp = RREG32(DC_HPD1_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD1_INT_CONTROL, tmp); - } -- if (*disp_int_cont & DC_HPD2_INTERRUPT) { -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { - tmp = RREG32(DC_HPD2_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD2_INT_CONTROL, tmp); - } -- if (*disp_int_cont2 & DC_HPD3_INTERRUPT) { -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { - tmp = RREG32(DC_HPD3_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD3_INT_CONTROL, tmp); - } -- if (*disp_int_cont3 & DC_HPD4_INTERRUPT) { -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { - tmp = RREG32(DC_HPD4_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD4_INT_CONTROL, tmp); - } -- if (*disp_int_cont4 & DC_HPD5_INTERRUPT) { -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { - tmp = RREG32(DC_HPD5_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD5_INT_CONTROL, tmp); - } -- if (*disp_int_cont5 & DC_HPD6_INTERRUPT) { -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { - tmp = RREG32(DC_HPD5_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD6_INT_CONTROL, tmp); -@@ -2239,14 +2440,10 @@ - - void evergreen_irq_disable(struct radeon_device *rdev) - { -- u32 disp_int, disp_int_cont, disp_int_cont2; -- u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; -- - r600_disable_interrupts(rdev); - /* Wait and acknowledge irq */ - mdelay(1); -- evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, -- &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); -+ evergreen_irq_ack(rdev); - evergreen_disable_interrupt_state(rdev); - } - -@@ -2286,8 +2483,6 @@ - u32 rptr = rdev->ih.rptr; - u32 src_id, src_data; - u32 ring_index; -- u32 disp_int, disp_int_cont, disp_int_cont2; -- u32 disp_int_cont3, disp_int_cont4, disp_int_cont5; - unsigned long flags; - bool queue_hotplug = false; - -@@ -2308,8 +2503,7 @@ - - restart_ih: - /* display interrupts */ -- evergreen_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2, -- &disp_int_cont3, &disp_int_cont4, &disp_int_cont5); -+ evergreen_irq_ack(rdev); - - rdev->ih.wptr = wptr; - while (rptr != wptr) { -@@ -2322,17 +2516,21 @@ - case 1: /* D1 vblank/vline */ - switch (src_data) { - case 0: /* D1 vblank */ -- if (disp_int & LB_D1_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 0); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int &= ~LB_D1_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[0]) { -+ drm_handle_vblank(rdev->ddev, 0); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[0]) -+ radeon_crtc_handle_flip(rdev, 0); -+ rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); - } - break; - case 1: /* D1 vline */ -- if (disp_int & LB_D1_VLINE_INTERRUPT) { -- disp_int &= ~LB_D1_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int & LB_D1_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } - break; -@@ -2344,17 +2542,21 @@ - case 2: /* D2 vblank/vline */ - switch (src_data) { - case 0: /* D2 vblank */ -- if (disp_int_cont & LB_D2_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 1); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[1]) { -+ drm_handle_vblank(rdev->ddev, 1); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[1]) -+ radeon_crtc_handle_flip(rdev, 1); -+ rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); - } - break; - case 1: /* D2 vline */ -- if (disp_int_cont & LB_D2_VLINE_INTERRUPT) { -- disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & LB_D2_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } - break; -@@ -2366,17 +2568,21 @@ - case 3: /* D3 vblank/vline */ - switch (src_data) { - case 0: /* D3 vblank */ -- if (disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 2); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[2]) { -+ drm_handle_vblank(rdev->ddev, 2); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[2]) -+ radeon_crtc_handle_flip(rdev, 2); -+ rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D3 vblank\n"); - } - break; - case 1: /* D3 vline */ -- if (disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { -- disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & LB_D3_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~LB_D3_VLINE_INTERRUPT; - DRM_DEBUG("IH: D3 vline\n"); - } - break; -@@ -2388,17 +2594,21 @@ - case 4: /* D4 vblank/vline */ - switch (src_data) { - case 0: /* D4 vblank */ -- if (disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 3); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[3]) { -+ drm_handle_vblank(rdev->ddev, 3); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[3]) -+ radeon_crtc_handle_flip(rdev, 3); -+ rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D4 vblank\n"); - } - break; - case 1: /* D4 vline */ -- if (disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { -- disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & LB_D4_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~LB_D4_VLINE_INTERRUPT; - DRM_DEBUG("IH: D4 vline\n"); - } - break; -@@ -2410,17 +2620,21 @@ - case 5: /* D5 vblank/vline */ - switch (src_data) { - case 0: /* D5 vblank */ -- if (disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 4); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[4]) { -+ drm_handle_vblank(rdev->ddev, 4); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[4]) -+ radeon_crtc_handle_flip(rdev, 4); -+ rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D5 vblank\n"); - } - break; - case 1: /* D5 vline */ -- if (disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { -- disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & LB_D5_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~LB_D5_VLINE_INTERRUPT; - DRM_DEBUG("IH: D5 vline\n"); - } - break; -@@ -2432,17 +2646,21 @@ - case 6: /* D6 vblank/vline */ - switch (src_data) { - case 0: /* D6 vblank */ -- if (disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 5); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[5]) { -+ drm_handle_vblank(rdev->ddev, 5); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[5]) -+ radeon_crtc_handle_flip(rdev, 5); -+ rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D6 vblank\n"); - } - break; - case 1: /* D6 vline */ -- if (disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { -- disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & LB_D6_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~LB_D6_VLINE_INTERRUPT; - DRM_DEBUG("IH: D6 vline\n"); - } - break; -@@ -2454,43 +2672,43 @@ - case 42: /* HPD hotplug */ - switch (src_data) { - case 0: -- if (disp_int & DC_HPD1_INTERRUPT) { -- disp_int &= ~DC_HPD1_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int & DC_HPD1_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } - break; - case 1: -- if (disp_int_cont & DC_HPD2_INTERRUPT) { -- disp_int_cont &= ~DC_HPD2_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont & DC_HPD2_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } - break; - case 2: -- if (disp_int_cont2 & DC_HPD3_INTERRUPT) { -- disp_int_cont2 &= ~DC_HPD3_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont2 & DC_HPD3_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont2 &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } - break; - case 3: -- if (disp_int_cont3 & DC_HPD4_INTERRUPT) { -- disp_int_cont3 &= ~DC_HPD4_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont3 & DC_HPD4_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont3 &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } - break; - case 4: -- if (disp_int_cont4 & DC_HPD5_INTERRUPT) { -- disp_int_cont4 &= ~DC_HPD5_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont4 & DC_HPD5_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont4 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } - break; - case 5: -- if (disp_int_cont5 & DC_HPD6_INTERRUPT) { -- disp_int_cont5 &= ~DC_HPD6_INTERRUPT; -+ if (rdev->irq.stat_regs.evergreen.disp_int_cont5 & DC_HPD6_INTERRUPT) { -+ rdev->irq.stat_regs.evergreen.disp_int_cont5 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } -@@ -2666,12 +2884,16 @@ - u32 reg; - - /* first check CRTCs */ -- reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | -- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | -- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | -- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | -- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | -- RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); -+ if (rdev->flags & RADEON_IS_IGP) -+ reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); -+ else -+ reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC3_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC4_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET); - if (reg & EVERGREEN_CRTC_MASTER_EN) - return true; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreend.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreend.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreend.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreend.h 2011-01-07 14:22:17.000000000 +0100 -@@ -164,11 +164,13 @@ - #define SE_SC_BUSY (1 << 29) - #define SE_DB_BUSY (1 << 30) - #define SE_CB_BUSY (1 << 31) -- -+/* evergreen */ - #define CG_MULT_THERMAL_STATUS 0x740 - #define ASIC_T(x) ((x) << 16) - #define ASIC_T_MASK 0x7FF0000 - #define ASIC_T_SHIFT 16 -+/* APU */ -+#define CG_THERMAL_STATUS 0x678 - - #define HDP_HOST_PATH_CNTL 0x2C00 - #define HDP_NONSURFACE_BASE 0x2C04 -@@ -180,6 +182,7 @@ - #define MC_SHARED_CHMAP 0x2004 - #define NOOFCHAN_SHIFT 12 - #define NOOFCHAN_MASK 0x00003000 -+#define MC_SHARED_CHREMAP 0x2008 - - #define MC_ARB_RAMCFG 0x2760 - #define NOOFBANK_SHIFT 0 -@@ -199,6 +202,7 @@ - #define MC_VM_AGP_BOT 0x202C - #define MC_VM_AGP_BASE 0x2030 - #define MC_VM_FB_LOCATION 0x2024 -+#define MC_FUS_VM_FB_OFFSET 0x2898 - #define MC_VM_MB_L1_TLB0_CNTL 0x2234 - #define MC_VM_MB_L1_TLB1_CNTL 0x2238 - #define MC_VM_MB_L1_TLB2_CNTL 0x223C -@@ -348,6 +352,9 @@ - #define SYNC_WALKER (1 << 25) - #define SYNC_ALIGNER (1 << 26) - -+#define TCP_CHAN_STEER_LO 0x960c -+#define TCP_CHAN_STEER_HI 0x9610 -+ - #define VGT_CACHE_INVALIDATION 0x88C4 - #define CACHE_INVALIDATION(x) ((x) << 0) - #define VC_ONLY 0 -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreen_reg.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreen_reg.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/evergreen_reg.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/evergreen_reg.h 2011-01-07 14:22:17.000000000 +0100 -@@ -105,6 +105,11 @@ - #define EVERGREEN_GRPH_Y_START 0x6830 - #define EVERGREEN_GRPH_X_END 0x6834 - #define EVERGREEN_GRPH_Y_END 0x6838 -+#define EVERGREEN_GRPH_UPDATE 0x6844 -+# define EVERGREEN_GRPH_SURFACE_UPDATE_PENDING (1 << 2) -+# define EVERGREEN_GRPH_UPDATE_LOCK (1 << 16) -+#define EVERGREEN_GRPH_FLIP_CONTROL 0x6848 -+# define EVERGREEN_GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0) - - /* CUR blocks at 0x6998, 0x7598, 0x10198, 0x10d98, 0x11998, 0x12598 */ - #define EVERGREEN_CUR_CONTROL 0x6998 -@@ -178,6 +183,7 @@ - # define EVERGREEN_CRTC_DISP_READ_REQUEST_DISABLE (1 << 24) - #define EVERGREEN_CRTC_STATUS 0x6e8c - #define EVERGREEN_CRTC_STATUS_POSITION 0x6e90 -+#define EVERGREEN_MASTER_UPDATE_MODE 0x6ef8 - #define EVERGREEN_CRTC_UPDATE_LOCK 0x6ed4 - - #define EVERGREEN_DC_GPIO_HPD_MASK 0x64b0 -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/Makefile linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/Makefile ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/Makefile 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/Makefile 2011-01-07 14:22:17.000000000 +0100 -@@ -65,10 +65,13 @@ - rs400.o rs600.o rs690.o rv515.o r520.o r600.o rv770.o radeon_test.o \ - r200.o radeon_legacy_tv.o r600_cs.o r600_blit.o r600_blit_shaders.o \ - r600_blit_kms.o radeon_pm.o atombios_dp.o r600_audio.o r600_hdmi.o \ -- evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o -+ evergreen.o evergreen_cs.o evergreen_blit_shaders.o evergreen_blit_kms.o \ -+ radeon_trace_points.o - - radeon-$(CONFIG_COMPAT) += radeon_ioc32.o - radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o - radeon-$(CONFIG_ACPI) += radeon_acpi.o - - obj-$(CONFIG_DRM_RADEON)+= radeon.o -+ -+CFLAGS_radeon_trace_points.o := -I$(src) -\ Kein Zeilenumbruch am Dateiende. -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/ObjectID.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/ObjectID.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/ObjectID.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/ObjectID.h 2011-01-07 14:22:17.000000000 +0100 -@@ -37,6 +37,8 @@ - #define GRAPH_OBJECT_TYPE_CONNECTOR 0x3 - #define GRAPH_OBJECT_TYPE_ROUTER 0x4 - /* deleted */ -+#define GRAPH_OBJECT_TYPE_DISPLAY_PATH 0x6 -+#define GRAPH_OBJECT_TYPE_GENERIC 0x7 - - /****************************************************/ - /* Encoder Object ID Definition */ -@@ -64,6 +66,9 @@ - #define ENCODER_OBJECT_ID_VT1623 0x10 - #define ENCODER_OBJECT_ID_HDMI_SI1930 0x11 - #define ENCODER_OBJECT_ID_HDMI_INTERNAL 0x12 -+#define ENCODER_OBJECT_ID_ALMOND 0x22 -+#define ENCODER_OBJECT_ID_TRAVIS 0x23 -+#define ENCODER_OBJECT_ID_NUTMEG 0x22 - /* Kaleidoscope (KLDSCP) Class Display Hardware (internal) */ - #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1 0x13 - #define ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1 0x14 -@@ -108,6 +113,7 @@ - #define CONNECTOR_OBJECT_ID_DISPLAYPORT 0x13 - #define CONNECTOR_OBJECT_ID_eDP 0x14 - #define CONNECTOR_OBJECT_ID_MXM 0x15 -+#define CONNECTOR_OBJECT_ID_LVDS_eDP 0x16 - - /* deleted */ - -@@ -124,6 +130,7 @@ - #define GENERIC_OBJECT_ID_GLSYNC 0x01 - #define GENERIC_OBJECT_ID_PX2_NON_DRIVABLE 0x02 - #define GENERIC_OBJECT_ID_MXM_OPM 0x03 -+#define GENERIC_OBJECT_ID_STEREO_PIN 0x04 //This object could show up from Misc Object table, it follows ATOM_OBJECT format, and contains one ATOM_OBJECT_GPIO_CNTL_RECORD for the stereo pin - - /****************************************************/ - /* Graphics Object ENUM ID Definition */ -@@ -360,6 +367,26 @@ - GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ - ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO << OBJECT_ID_SHIFT) - -+#define ENCODER_ALMOND_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ -+ ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT) -+ -+#define ENCODER_ALMOND_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ -+ ENCODER_OBJECT_ID_ALMOND << OBJECT_ID_SHIFT) -+ -+#define ENCODER_TRAVIS_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ -+ ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT) -+ -+#define ENCODER_TRAVIS_ENUM_ID2 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ -+ ENCODER_OBJECT_ID_TRAVIS << OBJECT_ID_SHIFT) -+ -+#define ENCODER_NUTMEG_ENUM_ID1 ( GRAPH_OBJECT_TYPE_ENCODER << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ -+ ENCODER_OBJECT_ID_NUTMEG << OBJECT_ID_SHIFT) -+ - /****************************************************/ - /* Connector Object ID definition - Shared with BIOS */ - /****************************************************/ -@@ -421,6 +448,14 @@ - GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ - CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) - -+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID3 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID3 << ENUM_ID_SHIFT |\ -+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) -+ -+#define CONNECTOR_SINGLE_LINK_DVI_D_ENUM_ID4 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID4 << ENUM_ID_SHIFT |\ -+ CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D << OBJECT_ID_SHIFT) -+ - #define CONNECTOR_DUAL_LINK_DVI_D_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ - GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ - CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D << OBJECT_ID_SHIFT) -@@ -512,6 +547,7 @@ - #define CONNECTOR_7PIN_DIN_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ - GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ - CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) -+ - #define CONNECTOR_7PIN_DIN_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ - GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ - CONNECTOR_OBJECT_ID_7PIN_DIN << OBJECT_ID_SHIFT) -@@ -593,6 +629,14 @@ - GRAPH_OBJECT_ENUM_ID7 << ENUM_ID_SHIFT |\ - CONNECTOR_OBJECT_ID_MXM << OBJECT_ID_SHIFT) //Mapping to MXM_DAC - -+#define CONNECTOR_LVDS_eDP_ENUM_ID1 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ -+ CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT) -+ -+#define CONNECTOR_LVDS_eDP_ENUM_ID2 ( GRAPH_OBJECT_TYPE_CONNECTOR << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID2 << ENUM_ID_SHIFT |\ -+ CONNECTOR_OBJECT_ID_LVDS_eDP << OBJECT_ID_SHIFT) -+ - /****************************************************/ - /* Router Object ID definition - Shared with BIOS */ - /****************************************************/ -@@ -621,6 +665,10 @@ - GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ - GENERIC_OBJECT_ID_MXM_OPM << OBJECT_ID_SHIFT) - -+#define GENERICOBJECT_STEREO_PIN_ENUM_ID1 (GRAPH_OBJECT_TYPE_GENERIC << OBJECT_TYPE_SHIFT |\ -+ GRAPH_OBJECT_ENUM_ID1 << ENUM_ID_SHIFT |\ -+ GENERIC_OBJECT_ID_STEREO_PIN << OBJECT_ID_SHIFT) -+ - /****************************************************/ - /* Object Cap definition - Shared with BIOS */ - /****************************************************/ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/r100.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r100.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/r100.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r100.c 2011-01-07 14:22:17.000000000 +0100 -@@ -68,6 +68,56 @@ - * r100,rv100,rs100,rv200,rs200,r200,rv250,rs300,rv280 - */ - -+void r100_pre_page_flip(struct radeon_device *rdev, int crtc) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; -+ u32 tmp; -+ -+ /* make sure flip is at vb rather than hb */ -+ tmp = RREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset); -+ tmp &= ~RADEON_CRTC_OFFSET_FLIP_CNTL; -+ /* make sure pending bit is asserted */ -+ tmp |= RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN; -+ WREG32(RADEON_CRTC_OFFSET_CNTL + radeon_crtc->crtc_offset, tmp); -+ -+ /* set pageflip to happen as late as possible in the vblank interval. -+ * same field for crtc1/2 -+ */ -+ tmp = RREG32(RADEON_CRTC_GEN_CNTL); -+ tmp &= ~RADEON_CRTC_VSTAT_MODE_MASK; -+ WREG32(RADEON_CRTC_GEN_CNTL, tmp); -+ -+ /* enable the pflip int */ -+ radeon_irq_kms_pflip_irq_get(rdev, crtc); -+} -+ -+void r100_post_page_flip(struct radeon_device *rdev, int crtc) -+{ -+ /* disable the pflip int */ -+ radeon_irq_kms_pflip_irq_put(rdev, crtc); -+} -+ -+u32 r100_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; -+ u32 tmp = ((u32)crtc_base) | RADEON_CRTC_OFFSET__OFFSET_LOCK; -+ -+ /* Lock the graphics update lock */ -+ /* update the scanout addresses */ -+ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); -+ -+ /* Wait for update_pending to go high. */ -+ while (!(RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET)); -+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); -+ -+ /* Unlock the lock, so double-buffering can take place inside vblank */ -+ tmp &= ~RADEON_CRTC_OFFSET__OFFSET_LOCK; -+ WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, tmp); -+ -+ /* Return current update_pending status: */ -+ return RREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset) & RADEON_CRTC_OFFSET__GUI_TRIG_OFFSET; -+} -+ - void r100_pm_get_dynpm_state(struct radeon_device *rdev) - { - int i; -@@ -526,10 +576,12 @@ - if (rdev->irq.gui_idle) { - tmp |= RADEON_GUI_IDLE_MASK; - } -- if (rdev->irq.crtc_vblank_int[0]) { -+ if (rdev->irq.crtc_vblank_int[0] || -+ rdev->irq.pflip[0]) { - tmp |= RADEON_CRTC_VBLANK_MASK; - } -- if (rdev->irq.crtc_vblank_int[1]) { -+ if (rdev->irq.crtc_vblank_int[1] || -+ rdev->irq.pflip[1]) { - tmp |= RADEON_CRTC2_VBLANK_MASK; - } - if (rdev->irq.hpd[0]) { -@@ -600,14 +652,22 @@ - } - /* Vertical blank interrupts */ - if (status & RADEON_CRTC_VBLANK_STAT) { -- drm_handle_vblank(rdev->ddev, 0); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -+ if (rdev->irq.crtc_vblank_int[0]) { -+ drm_handle_vblank(rdev->ddev, 0); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[0]) -+ radeon_crtc_handle_flip(rdev, 0); - } - if (status & RADEON_CRTC2_VBLANK_STAT) { -- drm_handle_vblank(rdev->ddev, 1); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -+ if (rdev->irq.crtc_vblank_int[1]) { -+ drm_handle_vblank(rdev->ddev, 1); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[1]) -+ radeon_crtc_handle_flip(rdev, 1); - } - if (status & RADEON_FP_DETECT_STAT) { - queue_hotplug = true; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/r500_reg.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r500_reg.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/r500_reg.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r500_reg.h 2011-01-07 14:22:17.000000000 +0100 -@@ -355,6 +355,8 @@ - #define AVIVO_D1CRTC_FRAME_COUNT 0x60a4 - #define AVIVO_D1CRTC_STEREO_CONTROL 0x60c4 - -+#define AVIVO_D1MODE_MASTER_UPDATE_MODE 0x60e4 -+ - /* master controls */ - #define AVIVO_DC_CRTC_MASTER_EN 0x60f8 - #define AVIVO_DC_CRTC_TV_CONTROL 0x60fc -@@ -409,8 +411,10 @@ - #define AVIVO_D1GRPH_X_END 0x6134 - #define AVIVO_D1GRPH_Y_END 0x6138 - #define AVIVO_D1GRPH_UPDATE 0x6144 -+# define AVIVO_D1GRPH_SURFACE_UPDATE_PENDING (1 << 2) - # define AVIVO_D1GRPH_UPDATE_LOCK (1 << 16) - #define AVIVO_D1GRPH_FLIP_CONTROL 0x6148 -+# define AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN (1 << 0) - - #define AVIVO_D1CUR_CONTROL 0x6400 - # define AVIVO_D1CURSOR_EN (1 << 0) -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/r600.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r600.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/r600.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r600.c 2011-01-07 14:22:17.000000000 +0100 -@@ -83,6 +83,9 @@ - MODULE_FIRMWARE("radeon/CYPRESS_pfp.bin"); - MODULE_FIRMWARE("radeon/CYPRESS_me.bin"); - MODULE_FIRMWARE("radeon/CYPRESS_rlc.bin"); -+MODULE_FIRMWARE("radeon/PALM_pfp.bin"); -+MODULE_FIRMWARE("radeon/PALM_me.bin"); -+MODULE_FIRMWARE("radeon/SUMO_rlc.bin"); - - int r600_debugfs_mc_info_init(struct radeon_device *rdev); - -@@ -1161,7 +1164,7 @@ - * Note: GTT start, end, size should be initialized before calling this - * function on AGP platform. - */ --void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) -+static void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) - { - u64 size_bf, size_af; - -@@ -1998,6 +2001,10 @@ - chip_name = "CYPRESS"; - rlc_chip_name = "CYPRESS"; - break; -+ case CHIP_PALM: -+ chip_name = "PALM"; -+ rlc_chip_name = "SUMO"; -+ break; - default: BUG(); - } - -@@ -2863,6 +2870,8 @@ - WREG32(CP_INT_CNTL, CNTX_BUSY_INT_ENABLE | CNTX_EMPTY_INT_ENABLE); - WREG32(GRBM_INT_CNTL, 0); - WREG32(DxMODE_INT_MASK, 0); -+ WREG32(D1GRPH_INTERRUPT_CONTROL, 0); -+ WREG32(D2GRPH_INTERRUPT_CONTROL, 0); - if (ASIC_IS_DCE3(rdev)) { - WREG32(DCE3_DACA_AUTODETECT_INT_CONTROL, 0); - WREG32(DCE3_DACB_AUTODETECT_INT_CONTROL, 0); -@@ -2987,6 +2996,7 @@ - u32 hpd1, hpd2, hpd3, hpd4 = 0, hpd5 = 0, hpd6 = 0; - u32 grbm_int_cntl = 0; - u32 hdmi1, hdmi2; -+ u32 d1grph = 0, d2grph = 0; - - if (!rdev->irq.installed) { - WARN(1, "Can't enable IRQ/MSI because no handler is installed\n"); -@@ -3023,11 +3033,13 @@ - cp_int_cntl |= RB_INT_ENABLE; - cp_int_cntl |= TIME_STAMP_INT_ENABLE; - } -- if (rdev->irq.crtc_vblank_int[0]) { -+ if (rdev->irq.crtc_vblank_int[0] || -+ rdev->irq.pflip[0]) { - DRM_DEBUG("r600_irq_set: vblank 0\n"); - mode_int |= D1MODE_VBLANK_INT_MASK; - } -- if (rdev->irq.crtc_vblank_int[1]) { -+ if (rdev->irq.crtc_vblank_int[1] || -+ rdev->irq.pflip[1]) { - DRM_DEBUG("r600_irq_set: vblank 1\n"); - mode_int |= D2MODE_VBLANK_INT_MASK; - } -@@ -3070,6 +3082,8 @@ - - WREG32(CP_INT_CNTL, cp_int_cntl); - WREG32(DxMODE_INT_MASK, mode_int); -+ WREG32(D1GRPH_INTERRUPT_CONTROL, d1grph); -+ WREG32(D2GRPH_INTERRUPT_CONTROL, d2grph); - WREG32(GRBM_INT_CNTL, grbm_int_cntl); - WREG32(R600_HDMI_BLOCK1 + R600_HDMI_CNTL, hdmi1); - if (ASIC_IS_DCE3(rdev)) { -@@ -3092,32 +3106,35 @@ - return 0; - } - --static inline void r600_irq_ack(struct radeon_device *rdev, -- u32 *disp_int, -- u32 *disp_int_cont, -- u32 *disp_int_cont2) -+static inline void r600_irq_ack(struct radeon_device *rdev) - { - u32 tmp; - - if (ASIC_IS_DCE3(rdev)) { -- *disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS); -- *disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE); -- *disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2); -- } else { -- *disp_int = RREG32(DISP_INTERRUPT_STATUS); -- *disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); -- *disp_int_cont2 = 0; -- } -- -- if (*disp_int & LB_D1_VBLANK_INTERRUPT) -+ rdev->irq.stat_regs.r600.disp_int = RREG32(DCE3_DISP_INTERRUPT_STATUS); -+ rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE); -+ rdev->irq.stat_regs.r600.disp_int_cont2 = RREG32(DCE3_DISP_INTERRUPT_STATUS_CONTINUE2); -+ } else { -+ rdev->irq.stat_regs.r600.disp_int = RREG32(DISP_INTERRUPT_STATUS); -+ rdev->irq.stat_regs.r600.disp_int_cont = RREG32(DISP_INTERRUPT_STATUS_CONTINUE); -+ rdev->irq.stat_regs.r600.disp_int_cont2 = 0; -+ } -+ rdev->irq.stat_regs.r600.d1grph_int = RREG32(D1GRPH_INTERRUPT_STATUS); -+ rdev->irq.stat_regs.r600.d2grph_int = RREG32(D2GRPH_INTERRUPT_STATUS); -+ -+ if (rdev->irq.stat_regs.r600.d1grph_int & DxGRPH_PFLIP_INT_OCCURRED) -+ WREG32(D1GRPH_INTERRUPT_STATUS, DxGRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.r600.d2grph_int & DxGRPH_PFLIP_INT_OCCURRED) -+ WREG32(D2GRPH_INTERRUPT_STATUS, DxGRPH_PFLIP_INT_CLEAR); -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) - WREG32(D1MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK); -- if (*disp_int & LB_D1_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) - WREG32(D1MODE_VLINE_STATUS, DxMODE_VLINE_ACK); -- if (*disp_int & LB_D2_VBLANK_INTERRUPT) -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) - WREG32(D2MODE_VBLANK_STATUS, DxMODE_VBLANK_ACK); -- if (*disp_int & LB_D2_VLINE_INTERRUPT) -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) - WREG32(D2MODE_VLINE_STATUS, DxMODE_VLINE_ACK); -- if (*disp_int & DC_HPD1_INTERRUPT) { -+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { - if (ASIC_IS_DCE3(rdev)) { - tmp = RREG32(DC_HPD1_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; -@@ -3128,7 +3145,7 @@ - WREG32(DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp); - } - } -- if (*disp_int & DC_HPD2_INTERRUPT) { -+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { - if (ASIC_IS_DCE3(rdev)) { - tmp = RREG32(DC_HPD2_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; -@@ -3139,7 +3156,7 @@ - WREG32(DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp); - } - } -- if (*disp_int_cont & DC_HPD3_INTERRUPT) { -+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { - if (ASIC_IS_DCE3(rdev)) { - tmp = RREG32(DC_HPD3_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; -@@ -3150,18 +3167,18 @@ - WREG32(DC_HOT_PLUG_DETECT3_INT_CONTROL, tmp); - } - } -- if (*disp_int_cont & DC_HPD4_INTERRUPT) { -+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { - tmp = RREG32(DC_HPD4_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD4_INT_CONTROL, tmp); - } - if (ASIC_IS_DCE32(rdev)) { -- if (*disp_int_cont2 & DC_HPD5_INTERRUPT) { -+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { - tmp = RREG32(DC_HPD5_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD5_INT_CONTROL, tmp); - } -- if (*disp_int_cont2 & DC_HPD6_INTERRUPT) { -+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { - tmp = RREG32(DC_HPD5_INT_CONTROL); - tmp |= DC_HPDx_INT_ACK; - WREG32(DC_HPD6_INT_CONTROL, tmp); -@@ -3183,12 +3200,10 @@ - - void r600_irq_disable(struct radeon_device *rdev) - { -- u32 disp_int, disp_int_cont, disp_int_cont2; -- - r600_disable_interrupts(rdev); - /* Wait and acknowledge irq */ - mdelay(1); -- r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2); -+ r600_irq_ack(rdev); - r600_disable_interrupt_state(rdev); - } - -@@ -3251,7 +3266,7 @@ - u32 wptr = r600_get_ih_wptr(rdev); - u32 rptr = rdev->ih.rptr; - u32 src_id, src_data; -- u32 ring_index, disp_int, disp_int_cont, disp_int_cont2; -+ u32 ring_index; - unsigned long flags; - bool queue_hotplug = false; - -@@ -3272,7 +3287,7 @@ - - restart_ih: - /* display interrupts */ -- r600_irq_ack(rdev, &disp_int, &disp_int_cont, &disp_int_cont2); -+ r600_irq_ack(rdev); - - rdev->ih.wptr = wptr; - while (rptr != wptr) { -@@ -3285,17 +3300,21 @@ - case 1: /* D1 vblank/vline */ - switch (src_data) { - case 0: /* D1 vblank */ -- if (disp_int & LB_D1_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 0); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int &= ~LB_D1_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[0]) { -+ drm_handle_vblank(rdev->ddev, 0); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[0]) -+ radeon_crtc_handle_flip(rdev, 0); -+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D1 vblank\n"); - } - break; - case 1: /* D1 vline */ -- if (disp_int & LB_D1_VLINE_INTERRUPT) { -- disp_int &= ~LB_D1_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D1_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D1_VLINE_INTERRUPT; - DRM_DEBUG("IH: D1 vline\n"); - } - break; -@@ -3307,17 +3326,21 @@ - case 5: /* D2 vblank/vline */ - switch (src_data) { - case 0: /* D2 vblank */ -- if (disp_int & LB_D2_VBLANK_INTERRUPT) { -- drm_handle_vblank(rdev->ddev, 1); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- disp_int &= ~LB_D2_VBLANK_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VBLANK_INTERRUPT) { -+ if (rdev->irq.crtc_vblank_int[1]) { -+ drm_handle_vblank(rdev->ddev, 1); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[1]) -+ radeon_crtc_handle_flip(rdev, 1); -+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VBLANK_INTERRUPT; - DRM_DEBUG("IH: D2 vblank\n"); - } - break; - case 1: /* D1 vline */ -- if (disp_int & LB_D2_VLINE_INTERRUPT) { -- disp_int &= ~LB_D2_VLINE_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int & LB_D2_VLINE_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int &= ~LB_D2_VLINE_INTERRUPT; - DRM_DEBUG("IH: D2 vline\n"); - } - break; -@@ -3329,43 +3352,43 @@ - case 19: /* HPD/DAC hotplug */ - switch (src_data) { - case 0: -- if (disp_int & DC_HPD1_INTERRUPT) { -- disp_int &= ~DC_HPD1_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD1_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD1_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD1\n"); - } - break; - case 1: -- if (disp_int & DC_HPD2_INTERRUPT) { -- disp_int &= ~DC_HPD2_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int & DC_HPD2_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int &= ~DC_HPD2_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD2\n"); - } - break; - case 4: -- if (disp_int_cont & DC_HPD3_INTERRUPT) { -- disp_int_cont &= ~DC_HPD3_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD3_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD3_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD3\n"); - } - break; - case 5: -- if (disp_int_cont & DC_HPD4_INTERRUPT) { -- disp_int_cont &= ~DC_HPD4_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int_cont & DC_HPD4_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int_cont &= ~DC_HPD4_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD4\n"); - } - break; - case 10: -- if (disp_int_cont2 & DC_HPD5_INTERRUPT) { -- disp_int_cont2 &= ~DC_HPD5_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD5_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD5_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD5\n"); - } - break; - case 12: -- if (disp_int_cont2 & DC_HPD6_INTERRUPT) { -- disp_int_cont2 &= ~DC_HPD6_INTERRUPT; -+ if (rdev->irq.stat_regs.r600.disp_int_cont2 & DC_HPD6_INTERRUPT) { -+ rdev->irq.stat_regs.r600.disp_int_cont2 &= ~DC_HPD6_INTERRUPT; - queue_hotplug = true; - DRM_DEBUG("IH: HPD6\n"); - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/r600d.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r600d.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/r600d.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/r600d.h 2011-01-07 14:22:17.000000000 +0100 -@@ -728,6 +728,15 @@ - /* DCE 3.2 */ - # define DC_HPDx_EN (1 << 28) - -+#define D1GRPH_INTERRUPT_STATUS 0x6158 -+#define D2GRPH_INTERRUPT_STATUS 0x6958 -+# define DxGRPH_PFLIP_INT_OCCURRED (1 << 0) -+# define DxGRPH_PFLIP_INT_CLEAR (1 << 8) -+#define D1GRPH_INTERRUPT_CONTROL 0x615c -+#define D2GRPH_INTERRUPT_CONTROL 0x695c -+# define DxGRPH_PFLIP_INT_MASK (1 << 0) -+# define DxGRPH_PFLIP_INT_TYPE (1 << 8) -+ - /* - * PM4 - */ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_asic.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_asic.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_asic.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_asic.c 2011-01-07 14:22:17.000000000 +0100 -@@ -171,6 +171,9 @@ - .pm_finish = &r100_pm_finish, - .pm_init_profile = &r100_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &r100_pre_page_flip, -+ .page_flip = &r100_page_flip, -+ .post_page_flip = &r100_post_page_flip, - }; - - static struct radeon_asic r200_asic = { -@@ -215,6 +218,9 @@ - .pm_finish = &r100_pm_finish, - .pm_init_profile = &r100_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &r100_pre_page_flip, -+ .page_flip = &r100_page_flip, -+ .post_page_flip = &r100_post_page_flip, - }; - - static struct radeon_asic r300_asic = { -@@ -260,6 +266,9 @@ - .pm_finish = &r100_pm_finish, - .pm_init_profile = &r100_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &r100_pre_page_flip, -+ .page_flip = &r100_page_flip, -+ .post_page_flip = &r100_post_page_flip, - }; - - static struct radeon_asic r300_asic_pcie = { -@@ -304,6 +313,9 @@ - .pm_finish = &r100_pm_finish, - .pm_init_profile = &r100_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &r100_pre_page_flip, -+ .page_flip = &r100_page_flip, -+ .post_page_flip = &r100_post_page_flip, - }; - - static struct radeon_asic r420_asic = { -@@ -349,6 +361,9 @@ - .pm_finish = &r100_pm_finish, - .pm_init_profile = &r420_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &r100_pre_page_flip, -+ .page_flip = &r100_page_flip, -+ .post_page_flip = &r100_post_page_flip, - }; - - static struct radeon_asic rs400_asic = { -@@ -394,6 +409,9 @@ - .pm_finish = &r100_pm_finish, - .pm_init_profile = &r100_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &r100_pre_page_flip, -+ .page_flip = &r100_page_flip, -+ .post_page_flip = &r100_post_page_flip, - }; - - static struct radeon_asic rs600_asic = { -@@ -439,6 +457,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &r420_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rs600_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic rs690_asic = { -@@ -484,6 +505,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &r420_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rs600_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic rv515_asic = { -@@ -529,6 +553,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &r420_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rs600_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic r520_asic = { -@@ -574,6 +601,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &r420_pm_init_profile, - .pm_get_dynpm_state = &r100_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rs600_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic r600_asic = { -@@ -618,6 +648,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &r600_pm_init_profile, - .pm_get_dynpm_state = &r600_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rs600_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic rs780_asic = { -@@ -662,6 +695,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &rs780_pm_init_profile, - .pm_get_dynpm_state = &r600_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rs600_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic rv770_asic = { -@@ -706,6 +742,9 @@ - .pm_finish = &rs600_pm_finish, - .pm_init_profile = &r600_pm_init_profile, - .pm_get_dynpm_state = &r600_pm_get_dynpm_state, -+ .pre_page_flip = &rs600_pre_page_flip, -+ .page_flip = &rv770_page_flip, -+ .post_page_flip = &rs600_post_page_flip, - }; - - static struct radeon_asic evergreen_asic = { -@@ -749,6 +788,52 @@ - .pm_finish = &evergreen_pm_finish, - .pm_init_profile = &r600_pm_init_profile, - .pm_get_dynpm_state = &r600_pm_get_dynpm_state, -+ .pre_page_flip = &evergreen_pre_page_flip, -+ .page_flip = &evergreen_page_flip, -+ .post_page_flip = &evergreen_post_page_flip, -+}; -+ -+static struct radeon_asic sumo_asic = { -+ .init = &evergreen_init, -+ .fini = &evergreen_fini, -+ .suspend = &evergreen_suspend, -+ .resume = &evergreen_resume, -+ .cp_commit = &r600_cp_commit, -+ .gpu_is_lockup = &evergreen_gpu_is_lockup, -+ .asic_reset = &evergreen_asic_reset, -+ .vga_set_state = &r600_vga_set_state, -+ .gart_tlb_flush = &evergreen_pcie_gart_tlb_flush, -+ .gart_set_page = &rs600_gart_set_page, -+ .ring_test = &r600_ring_test, -+ .ring_ib_execute = &r600_ring_ib_execute, -+ .irq_set = &evergreen_irq_set, -+ .irq_process = &evergreen_irq_process, -+ .get_vblank_counter = &evergreen_get_vblank_counter, -+ .fence_ring_emit = &r600_fence_ring_emit, -+ .cs_parse = &evergreen_cs_parse, -+ .copy_blit = &evergreen_copy_blit, -+ .copy_dma = &evergreen_copy_blit, -+ .copy = &evergreen_copy_blit, -+ .get_engine_clock = &radeon_atom_get_engine_clock, -+ .set_engine_clock = &radeon_atom_set_engine_clock, -+ .get_memory_clock = NULL, -+ .set_memory_clock = NULL, -+ .get_pcie_lanes = NULL, -+ .set_pcie_lanes = NULL, -+ .set_clock_gating = NULL, -+ .set_surface_reg = r600_set_surface_reg, -+ .clear_surface_reg = r600_clear_surface_reg, -+ .bandwidth_update = &evergreen_bandwidth_update, -+ .hpd_init = &evergreen_hpd_init, -+ .hpd_fini = &evergreen_hpd_fini, -+ .hpd_sense = &evergreen_hpd_sense, -+ .hpd_set_polarity = &evergreen_hpd_set_polarity, -+ .gui_idle = &r600_gui_idle, -+ .pm_misc = &evergreen_pm_misc, -+ .pm_prepare = &evergreen_pm_prepare, -+ .pm_finish = &evergreen_pm_finish, -+ .pm_init_profile = &rs780_pm_init_profile, -+ .pm_get_dynpm_state = &r600_pm_get_dynpm_state, - }; - - int radeon_asic_init(struct radeon_device *rdev) -@@ -835,6 +920,9 @@ - case CHIP_HEMLOCK: - rdev->asic = &evergreen_asic; - break; -+ case CHIP_PALM: -+ rdev->asic = &sumo_asic; -+ break; - default: - /* FIXME: not supported yet */ - return -EINVAL; -@@ -849,7 +937,9 @@ - if (rdev->flags & RADEON_SINGLE_CRTC) - rdev->num_crtc = 1; - else { -- if (ASIC_IS_DCE4(rdev)) -+ if (ASIC_IS_DCE41(rdev)) -+ rdev->num_crtc = 2; -+ else if (ASIC_IS_DCE4(rdev)) - rdev->num_crtc = 6; - else - rdev->num_crtc = 2; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_asic.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_asic.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_asic.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_asic.h 2011-01-07 14:22:17.000000000 +0100 -@@ -130,6 +130,9 @@ - extern void r100_pm_finish(struct radeon_device *rdev); - extern void r100_pm_init_profile(struct radeon_device *rdev); - extern void r100_pm_get_dynpm_state(struct radeon_device *rdev); -+extern void r100_pre_page_flip(struct radeon_device *rdev, int crtc); -+extern u32 r100_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); -+extern void r100_post_page_flip(struct radeon_device *rdev, int crtc); - - /* - * r200,rv250,rs300,rv280 -@@ -205,6 +208,9 @@ - extern void rs600_pm_misc(struct radeon_device *rdev); - extern void rs600_pm_prepare(struct radeon_device *rdev); - extern void rs600_pm_finish(struct radeon_device *rdev); -+extern void rs600_pre_page_flip(struct radeon_device *rdev, int crtc); -+extern u32 rs600_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); -+extern void rs600_post_page_flip(struct radeon_device *rdev, int crtc); - - /* - * rs690,rs740 -@@ -287,6 +293,7 @@ - int rv770_suspend(struct radeon_device *rdev); - int rv770_resume(struct radeon_device *rdev); - extern void rv770_pm_misc(struct radeon_device *rdev); -+extern u32 rv770_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); - - /* - * evergreen -@@ -314,5 +321,8 @@ - extern void evergreen_pm_misc(struct radeon_device *rdev); - extern void evergreen_pm_prepare(struct radeon_device *rdev); - extern void evergreen_pm_finish(struct radeon_device *rdev); -+extern void evergreen_pre_page_flip(struct radeon_device *rdev, int crtc); -+extern u32 evergreen_page_flip(struct radeon_device *rdev, int crtc, u64 crtc_base); -+extern void evergreen_post_page_flip(struct radeon_device *rdev, int crtc); - - #endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_atombios.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_atombios.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_atombios.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_atombios.c 2011-01-07 14:22:17.000000000 +0100 -@@ -1321,6 +1321,43 @@ - return false; - } - -+static void radeon_atombios_get_igp_ss_overrides(struct radeon_device *rdev, -+ struct radeon_atom_ss *ss, -+ int id) -+{ -+ struct radeon_mode_info *mode_info = &rdev->mode_info; -+ int index = GetIndexIntoMasterTable(DATA, IntegratedSystemInfo); -+ u16 data_offset, size; -+ struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *igp_info; -+ u8 frev, crev; -+ u16 percentage = 0, rate = 0; -+ -+ /* get any igp specific overrides */ -+ if (atom_parse_data_header(mode_info->atom_context, index, &size, -+ &frev, &crev, &data_offset)) { -+ igp_info = (struct _ATOM_INTEGRATED_SYSTEM_INFO_V6 *) -+ (mode_info->atom_context->bios + data_offset); -+ switch (id) { -+ case ASIC_INTERNAL_SS_ON_TMDS: -+ percentage = le16_to_cpu(igp_info->usDVISSPercentage); -+ rate = le16_to_cpu(igp_info->usDVISSpreadRateIn10Hz); -+ break; -+ case ASIC_INTERNAL_SS_ON_HDMI: -+ percentage = le16_to_cpu(igp_info->usHDMISSPercentage); -+ rate = le16_to_cpu(igp_info->usHDMISSpreadRateIn10Hz); -+ break; -+ case ASIC_INTERNAL_SS_ON_LVDS: -+ percentage = le16_to_cpu(igp_info->usLvdsSSPercentage); -+ rate = le16_to_cpu(igp_info->usLvdsSSpreadRateIn10Hz); -+ break; -+ } -+ if (percentage) -+ ss->percentage = percentage; -+ if (rate) -+ ss->rate = rate; -+ } -+} -+ - union asic_ss_info { - struct _ATOM_ASIC_INTERNAL_SS_INFO info; - struct _ATOM_ASIC_INTERNAL_SS_INFO_V2 info_2; -@@ -1385,6 +1422,8 @@ - le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadSpectrumPercentage); - ss->type = ss_info->info_3.asSpreadSpectrum[i].ucSpreadSpectrumMode; - ss->rate = le16_to_cpu(ss_info->info_3.asSpreadSpectrum[i].usSpreadRateIn10Hz); -+ if (rdev->flags & RADEON_IS_IGP) -+ radeon_atombios_get_igp_ss_overrides(rdev, ss, id); - return true; - } - } -@@ -1724,495 +1763,600 @@ - "RV6xx", - "RV770", - "adt7473", -+ "NONE", - "External GPIO", - "Evergreen", -- "adt7473 with internal", -- -+ "emc2103", -+ "Sumo", - }; - - union power_info { - struct _ATOM_POWERPLAY_INFO info; - struct _ATOM_POWERPLAY_INFO_V2 info_2; - struct _ATOM_POWERPLAY_INFO_V3 info_3; -- struct _ATOM_PPLIB_POWERPLAYTABLE info_4; -+ struct _ATOM_PPLIB_POWERPLAYTABLE pplib; -+ struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2; -+ struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3; - }; - --void radeon_atombios_get_power_modes(struct radeon_device *rdev) -+union pplib_clock_info { -+ struct _ATOM_PPLIB_R600_CLOCK_INFO r600; -+ struct _ATOM_PPLIB_RS780_CLOCK_INFO rs780; -+ struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO evergreen; -+ struct _ATOM_PPLIB_SUMO_CLOCK_INFO sumo; -+}; -+ -+union pplib_power_state { -+ struct _ATOM_PPLIB_STATE v1; -+ struct _ATOM_PPLIB_STATE_V2 v2; -+}; -+ -+static void radeon_atombios_parse_misc_flags_1_3(struct radeon_device *rdev, -+ int state_index, -+ u32 misc, u32 misc2) -+{ -+ rdev->pm.power_state[state_index].misc = misc; -+ rdev->pm.power_state[state_index].misc2 = misc2; -+ /* order matters! */ -+ if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_POWERSAVE; -+ if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_BATTERY; -+ if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_BATTERY; -+ if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_BALANCED; -+ if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_PERFORMANCE; -+ rdev->pm.power_state[state_index].flags &= -+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -+ } -+ if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_BALANCED; -+ if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_DEFAULT; -+ rdev->pm.default_power_state_index = state_index; -+ rdev->pm.power_state[state_index].default_clock_mode = -+ &rdev->pm.power_state[state_index].clock_info[0]; -+ } else if (state_index == 0) { -+ rdev->pm.power_state[state_index].clock_info[0].flags |= -+ RADEON_PM_MODE_NO_DISPLAY; -+ } -+} -+ -+static int radeon_atombios_parse_power_table_1_3(struct radeon_device *rdev) - { - struct radeon_mode_info *mode_info = &rdev->mode_info; -+ u32 misc, misc2 = 0; -+ int num_modes = 0, i; -+ int state_index = 0; -+ struct radeon_i2c_bus_rec i2c_bus; -+ union power_info *power_info; - int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); -- u16 data_offset; -+ u16 data_offset; - u8 frev, crev; -- u32 misc, misc2 = 0, sclk, mclk; -- union power_info *power_info; -- struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; -- struct _ATOM_PPLIB_STATE *power_state; -- int num_modes = 0, i, j; -- int state_index = 0, mode_index = 0; -- struct radeon_i2c_bus_rec i2c_bus; -- -- rdev->pm.default_power_state_index = -1; - -- if (atom_parse_data_header(mode_info->atom_context, index, NULL, -- &frev, &crev, &data_offset)) { -- power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); -- if (frev < 4) { -- /* add the i2c bus for thermal/fan chip */ -- if (power_info->info.ucOverdriveThermalController > 0) { -- DRM_INFO("Possible %s thermal controller at 0x%02x\n", -- thermal_controller_names[power_info->info.ucOverdriveThermalController], -- power_info->info.ucOverdriveControllerAddress >> 1); -- i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); -- 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[power_info->info. -- ucOverdriveThermalController]; -- info.addr = power_info->info.ucOverdriveControllerAddress >> 1; -- strlcpy(info.type, name, sizeof(info.type)); -- i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); -- } -+ if (!atom_parse_data_header(mode_info->atom_context, index, NULL, -+ &frev, &crev, &data_offset)) -+ return state_index; -+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); -+ -+ /* add the i2c bus for thermal/fan chip */ -+ if (power_info->info.ucOverdriveThermalController > 0) { -+ DRM_INFO("Possible %s thermal controller at 0x%02x\n", -+ thermal_controller_names[power_info->info.ucOverdriveThermalController], -+ power_info->info.ucOverdriveControllerAddress >> 1); -+ i2c_bus = radeon_lookup_i2c_gpio(rdev, power_info->info.ucOverdriveI2cLine); -+ 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[power_info->info. -+ ucOverdriveThermalController]; -+ info.addr = power_info->info.ucOverdriveControllerAddress >> 1; -+ strlcpy(info.type, name, sizeof(info.type)); -+ i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); -+ } -+ } -+ num_modes = power_info->info.ucNumOfPowerModeEntries; -+ if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) -+ num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; -+ /* last mode is usually default, array is low to high */ -+ for (i = 0; i < num_modes; i++) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; -+ switch (frev) { -+ case 1: -+ rdev->pm.power_state[state_index].num_clock_modes = 1; -+ rdev->pm.power_state[state_index].clock_info[0].mclk = -+ le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); -+ rdev->pm.power_state[state_index].clock_info[0].sclk = -+ le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); -+ /* skip invalid modes */ -+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || -+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) -+ continue; -+ rdev->pm.power_state[state_index].pcie_lanes = -+ power_info->info.asPowerPlayInfo[i].ucNumPciELanes; -+ misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); -+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || -+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = -+ VOLTAGE_GPIO; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = -+ radeon_lookup_gpio(rdev, -+ power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); -+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) -+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -+ true; -+ else -+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -+ false; -+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = -+ VOLTAGE_VDDC; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = -+ power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; - } -- num_modes = power_info->info.ucNumOfPowerModeEntries; -- if (num_modes > ATOM_MAX_NUMBEROF_POWER_BLOCK) -- num_modes = ATOM_MAX_NUMBEROF_POWER_BLOCK; -- /* last mode is usually default, array is low to high */ -- for (i = 0; i < num_modes; i++) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = VOLTAGE_NONE; -- switch (frev) { -- case 1: -- rdev->pm.power_state[state_index].num_clock_modes = 1; -- rdev->pm.power_state[state_index].clock_info[0].mclk = -- le16_to_cpu(power_info->info.asPowerPlayInfo[i].usMemoryClock); -- rdev->pm.power_state[state_index].clock_info[0].sclk = -- le16_to_cpu(power_info->info.asPowerPlayInfo[i].usEngineClock); -- /* skip invalid modes */ -- if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || -- (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) -- continue; -- rdev->pm.power_state[state_index].pcie_lanes = -- power_info->info.asPowerPlayInfo[i].ucNumPciELanes; -- misc = le32_to_cpu(power_info->info.asPowerPlayInfo[i].ulMiscInfo); -- if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || -- (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = -- VOLTAGE_GPIO; -- rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = -- radeon_lookup_gpio(rdev, -- power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex); -- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) -- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -- true; -- else -- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -- false; -- } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = -- VOLTAGE_VDDC; -- rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = -- power_info->info.asPowerPlayInfo[i].ucVoltageDropIndex; -- } -- rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- rdev->pm.power_state[state_index].misc = misc; -- /* order matters! */ -- if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_POWERSAVE; -- if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BALANCED; -- if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_PERFORMANCE; -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- } -- if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_DEFAULT; -- rdev->pm.default_power_state_index = state_index; -- rdev->pm.power_state[state_index].default_clock_mode = -- &rdev->pm.power_state[state_index].clock_info[0]; -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- } else if (state_index == 0) { -- rdev->pm.power_state[state_index].clock_info[0].flags |= -- RADEON_PM_MODE_NO_DISPLAY; -- } -- state_index++; -- break; -- case 2: -- rdev->pm.power_state[state_index].num_clock_modes = 1; -- rdev->pm.power_state[state_index].clock_info[0].mclk = -- le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); -- rdev->pm.power_state[state_index].clock_info[0].sclk = -- le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); -- /* skip invalid modes */ -- if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || -- (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) -- continue; -- rdev->pm.power_state[state_index].pcie_lanes = -- power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; -- misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); -- misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); -- if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || -- (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = -- VOLTAGE_GPIO; -- rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = -- radeon_lookup_gpio(rdev, -- power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); -- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) -- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -- true; -- else -- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -- false; -- } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = -- VOLTAGE_VDDC; -- rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = -- power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; -- } -- rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- rdev->pm.power_state[state_index].misc = misc; -- rdev->pm.power_state[state_index].misc2 = misc2; -- /* order matters! */ -- if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_POWERSAVE; -- if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BALANCED; -- if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_PERFORMANCE; -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- } -- if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BALANCED; -- if (misc2 & ATOM_PM_MISCINFO2_MULTI_DISPLAY_SUPPORT) -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_DEFAULT; -- rdev->pm.default_power_state_index = state_index; -- rdev->pm.power_state[state_index].default_clock_mode = -- &rdev->pm.power_state[state_index].clock_info[0]; -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- } else if (state_index == 0) { -- rdev->pm.power_state[state_index].clock_info[0].flags |= -- RADEON_PM_MODE_NO_DISPLAY; -- } -- state_index++; -- break; -- case 3: -- rdev->pm.power_state[state_index].num_clock_modes = 1; -- rdev->pm.power_state[state_index].clock_info[0].mclk = -- le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); -- rdev->pm.power_state[state_index].clock_info[0].sclk = -- le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); -- /* skip invalid modes */ -- if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || -- (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) -- continue; -- rdev->pm.power_state[state_index].pcie_lanes = -- power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; -- misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); -- misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); -- if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || -- (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = -- VOLTAGE_GPIO; -- rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = -- radeon_lookup_gpio(rdev, -- power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); -- if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) -- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -- true; -- else -- rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -- false; -- } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.type = -- VOLTAGE_VDDC; -- rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = -- power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; -- if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { -- rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = -- true; -- rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = -- power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; -- } -- } -- rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- rdev->pm.power_state[state_index].misc = misc; -- rdev->pm.power_state[state_index].misc2 = misc2; -- /* order matters! */ -- if (misc & ATOM_PM_MISCINFO_POWER_SAVING_MODE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_POWERSAVE; -- if (misc & ATOM_PM_MISCINFO_DEFAULT_DC_STATE_ENTRY_TRUE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- if (misc & ATOM_PM_MISCINFO_DEFAULT_LOW_DC_STATE_ENTRY_TRUE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- if (misc & ATOM_PM_MISCINFO_LOAD_BALANCE_EN) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BALANCED; -- if (misc & ATOM_PM_MISCINFO_3D_ACCELERATION_EN) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_PERFORMANCE; -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- } -- if (misc2 & ATOM_PM_MISCINFO2_SYSTEM_AC_LITE_MODE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BALANCED; -- if (misc & ATOM_PM_MISCINFO_DRIVER_DEFAULT_MODE) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_DEFAULT; -- rdev->pm.default_power_state_index = state_index; -- rdev->pm.power_state[state_index].default_clock_mode = -- &rdev->pm.power_state[state_index].clock_info[0]; -- } else if (state_index == 0) { -- rdev->pm.power_state[state_index].clock_info[0].flags |= -- RADEON_PM_MODE_NO_DISPLAY; -- } -- state_index++; -- break; -- } -+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -+ radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, 0); -+ state_index++; -+ break; -+ case 2: -+ rdev->pm.power_state[state_index].num_clock_modes = 1; -+ rdev->pm.power_state[state_index].clock_info[0].mclk = -+ le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMemoryClock); -+ rdev->pm.power_state[state_index].clock_info[0].sclk = -+ le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulEngineClock); -+ /* skip invalid modes */ -+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || -+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) -+ continue; -+ rdev->pm.power_state[state_index].pcie_lanes = -+ power_info->info_2.asPowerPlayInfo[i].ucNumPciELanes; -+ misc = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo); -+ misc2 = le32_to_cpu(power_info->info_2.asPowerPlayInfo[i].ulMiscInfo2); -+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || -+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = -+ VOLTAGE_GPIO; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = -+ radeon_lookup_gpio(rdev, -+ power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex); -+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) -+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -+ true; -+ else -+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -+ false; -+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = -+ VOLTAGE_VDDC; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = -+ power_info->info_2.asPowerPlayInfo[i].ucVoltageDropIndex; - } -- /* last mode is usually default */ -- if (rdev->pm.default_power_state_index == -1) { -- rdev->pm.power_state[state_index - 1].type = -- POWER_STATE_TYPE_DEFAULT; -- rdev->pm.default_power_state_index = state_index - 1; -- rdev->pm.power_state[state_index - 1].default_clock_mode = -- &rdev->pm.power_state[state_index - 1].clock_info[0]; -- rdev->pm.power_state[state_index].flags &= -- ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- rdev->pm.power_state[state_index].misc = 0; -- rdev->pm.power_state[state_index].misc2 = 0; -+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -+ radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); -+ state_index++; -+ break; -+ case 3: -+ rdev->pm.power_state[state_index].num_clock_modes = 1; -+ rdev->pm.power_state[state_index].clock_info[0].mclk = -+ le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMemoryClock); -+ rdev->pm.power_state[state_index].clock_info[0].sclk = -+ le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulEngineClock); -+ /* skip invalid modes */ -+ if ((rdev->pm.power_state[state_index].clock_info[0].mclk == 0) || -+ (rdev->pm.power_state[state_index].clock_info[0].sclk == 0)) -+ continue; -+ rdev->pm.power_state[state_index].pcie_lanes = -+ power_info->info_3.asPowerPlayInfo[i].ucNumPciELanes; -+ misc = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo); -+ misc2 = le32_to_cpu(power_info->info_3.asPowerPlayInfo[i].ulMiscInfo2); -+ if ((misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_SUPPORT) || -+ (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH)) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = -+ VOLTAGE_GPIO; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.gpio = -+ radeon_lookup_gpio(rdev, -+ power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex); -+ if (misc & ATOM_PM_MISCINFO_VOLTAGE_DROP_ACTIVE_HIGH) -+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -+ true; -+ else -+ rdev->pm.power_state[state_index].clock_info[0].voltage.active_high = -+ false; -+ } else if (misc & ATOM_PM_MISCINFO_PROGRAM_VOLTAGE) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.type = -+ VOLTAGE_VDDC; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddc_id = -+ power_info->info_3.asPowerPlayInfo[i].ucVoltageDropIndex; -+ if (misc2 & ATOM_PM_MISCINFO2_VDDCI_DYNAMIC_VOLTAGE_EN) { -+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_enabled = -+ true; -+ rdev->pm.power_state[state_index].clock_info[0].voltage.vddci_id = -+ power_info->info_3.asPowerPlayInfo[i].ucVDDCI_VoltageDropIndex; -+ } - } -+ rdev->pm.power_state[state_index].flags = RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -+ radeon_atombios_parse_misc_flags_1_3(rdev, state_index, misc, misc2); -+ state_index++; -+ break; -+ } -+ } -+ /* last mode is usually default */ -+ if (rdev->pm.default_power_state_index == -1) { -+ rdev->pm.power_state[state_index - 1].type = -+ POWER_STATE_TYPE_DEFAULT; -+ rdev->pm.default_power_state_index = state_index - 1; -+ rdev->pm.power_state[state_index - 1].default_clock_mode = -+ &rdev->pm.power_state[state_index - 1].clock_info[0]; -+ rdev->pm.power_state[state_index].flags &= -+ ~RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -+ rdev->pm.power_state[state_index].misc = 0; -+ rdev->pm.power_state[state_index].misc2 = 0; -+ } -+ return state_index; -+} -+ -+static void radeon_atombios_add_pplib_thermal_controller(struct radeon_device *rdev, -+ ATOM_PPLIB_THERMALCONTROLLER *controller) -+{ -+ struct radeon_i2c_bus_rec i2c_bus; -+ -+ /* add the i2c bus for thermal/fan chip */ -+ if (controller->ucType > 0) { -+ if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { -+ DRM_INFO("Internal thermal controller %s fan control\n", -+ (controller->ucFanParameters & -+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -+ rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; -+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { -+ DRM_INFO("Internal thermal controller %s fan control\n", -+ (controller->ucFanParameters & -+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -+ rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; -+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { -+ DRM_INFO("Internal thermal controller %s fan control\n", -+ (controller->ucFanParameters & -+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -+ rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; -+ } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) { -+ DRM_INFO("Internal thermal controller %s fan control\n", -+ (controller->ucFanParameters & -+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -+ rdev->pm.int_thermal_type = THERMAL_TYPE_SUMO; -+ } else if ((controller->ucType == -+ ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || -+ (controller->ucType == -+ ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) || -+ (controller->ucType == -+ ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL)) { -+ DRM_INFO("Special thermal controller config\n"); - } else { -- int fw_index = GetIndexIntoMasterTable(DATA, FirmwareInfo); -- uint8_t fw_frev, fw_crev; -- uint16_t fw_data_offset, vddc = 0; -- union firmware_info *firmware_info; -- ATOM_PPLIB_THERMALCONTROLLER *controller = &power_info->info_4.sThermalController; -- -- if (atom_parse_data_header(mode_info->atom_context, fw_index, NULL, -- &fw_frev, &fw_crev, &fw_data_offset)) { -- firmware_info = -- (union firmware_info *)(mode_info->atom_context->bios + -- fw_data_offset); -- vddc = firmware_info->info_14.usBootUpVDDCVoltage; -+ DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", -+ pp_lib_thermal_controller_names[controller->ucType], -+ controller->ucI2cAddress >> 1, -+ (controller->ucFanParameters & -+ ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -+ i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); -+ rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); -+ if (rdev->pm.i2c_bus) { -+ struct i2c_board_info info = { }; -+ const char *name = pp_lib_thermal_controller_names[controller->ucType]; -+ info.addr = controller->ucI2cAddress >> 1; -+ strlcpy(info.type, name, sizeof(info.type)); -+ i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); - } -+ } -+ } -+} - -- /* add the i2c bus for thermal/fan chip */ -- if (controller->ucType > 0) { -- if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) { -- DRM_INFO("Internal thermal controller %s fan control\n", -- (controller->ucFanParameters & -- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -- rdev->pm.int_thermal_type = THERMAL_TYPE_RV6XX; -- } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) { -- DRM_INFO("Internal thermal controller %s fan control\n", -- (controller->ucFanParameters & -- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -- rdev->pm.int_thermal_type = THERMAL_TYPE_RV770; -- } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) { -- DRM_INFO("Internal thermal controller %s fan control\n", -- (controller->ucFanParameters & -- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -- rdev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN; -- } else if ((controller->ucType == -- ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) || -- (controller->ucType == -- ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL)) { -- DRM_INFO("Special thermal controller config\n"); -- } else { -- DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n", -- pp_lib_thermal_controller_names[controller->ucType], -- controller->ucI2cAddress >> 1, -- (controller->ucFanParameters & -- ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with"); -- i2c_bus = radeon_lookup_i2c_gpio(rdev, controller->ucI2cLine); -- rdev->pm.i2c_bus = radeon_i2c_lookup(rdev, &i2c_bus); -- if (rdev->pm.i2c_bus) { -- struct i2c_board_info info = { }; -- const char *name = pp_lib_thermal_controller_names[controller->ucType]; -- info.addr = controller->ucI2cAddress >> 1; -- strlcpy(info.type, name, sizeof(info.type)); -- i2c_new_device(&rdev->pm.i2c_bus->adapter, &info); -- } -+static u16 radeon_atombios_get_default_vddc(struct radeon_device *rdev) -+{ -+ struct radeon_mode_info *mode_info = &rdev->mode_info; -+ int index = GetIndexIntoMasterTable(DATA, FirmwareInfo); -+ u8 frev, crev; -+ u16 data_offset; -+ union firmware_info *firmware_info; -+ u16 vddc = 0; - -- } -- } -- /* first mode is usually default, followed by low to high */ -- for (i = 0; i < power_info->info_4.ucNumStates; i++) { -- mode_index = 0; -- power_state = (struct _ATOM_PPLIB_STATE *) -- (mode_info->atom_context->bios + -- data_offset + -- le16_to_cpu(power_info->info_4.usStateArrayOffset) + -- i * power_info->info_4.ucStateEntrySize); -- non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) -- (mode_info->atom_context->bios + -- data_offset + -- le16_to_cpu(power_info->info_4.usNonClockInfoArrayOffset) + -- (power_state->ucNonClockStateIndex * -- power_info->info_4.ucNonClockSize)); -- for (j = 0; j < (power_info->info_4.ucStateEntrySize - 1); j++) { -- if (rdev->flags & RADEON_IS_IGP) { -- struct _ATOM_PPLIB_RS780_CLOCK_INFO *clock_info = -- (struct _ATOM_PPLIB_RS780_CLOCK_INFO *) -- (mode_info->atom_context->bios + -- data_offset + -- le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + -- (power_state->ucClockStateIndices[j] * -- power_info->info_4.ucClockInfoSize)); -- sclk = le16_to_cpu(clock_info->usLowEngineClockLow); -- sclk |= clock_info->ucLowEngineClockHigh << 16; -- rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -- /* skip invalid modes */ -- if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) -- continue; -- /* voltage works differently on IGPs */ -- mode_index++; -- } else if (ASIC_IS_DCE4(rdev)) { -- struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *clock_info = -- (struct _ATOM_PPLIB_EVERGREEN_CLOCK_INFO *) -- (mode_info->atom_context->bios + -- data_offset + -- le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + -- (power_state->ucClockStateIndices[j] * -- power_info->info_4.ucClockInfoSize)); -- sclk = le16_to_cpu(clock_info->usEngineClockLow); -- sclk |= clock_info->ucEngineClockHigh << 16; -- mclk = le16_to_cpu(clock_info->usMemoryClockLow); -- mclk |= clock_info->ucMemoryClockHigh << 16; -- rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; -- rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -- /* skip invalid modes */ -- if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || -- (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) -- continue; -- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = -- VOLTAGE_SW; -- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = -- clock_info->usVDDC; -- /* XXX usVDDCI */ -- mode_index++; -- } else { -- struct _ATOM_PPLIB_R600_CLOCK_INFO *clock_info = -- (struct _ATOM_PPLIB_R600_CLOCK_INFO *) -- (mode_info->atom_context->bios + -- data_offset + -- le16_to_cpu(power_info->info_4.usClockInfoArrayOffset) + -- (power_state->ucClockStateIndices[j] * -- power_info->info_4.ucClockInfoSize)); -- sclk = le16_to_cpu(clock_info->usEngineClockLow); -- sclk |= clock_info->ucEngineClockHigh << 16; -- mclk = le16_to_cpu(clock_info->usMemoryClockLow); -- mclk |= clock_info->ucMemoryClockHigh << 16; -- rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; -- rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -- /* skip invalid modes */ -- if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || -- (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) -- continue; -- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = -- VOLTAGE_SW; -- rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = -- clock_info->usVDDC; -- mode_index++; -- } -- } -- rdev->pm.power_state[state_index].num_clock_modes = mode_index; -- if (mode_index) { -- misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); -- misc2 = le16_to_cpu(non_clock_info->usClassification); -- rdev->pm.power_state[state_index].misc = misc; -- rdev->pm.power_state[state_index].misc2 = misc2; -- rdev->pm.power_state[state_index].pcie_lanes = -- ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> -- ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; -- switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { -- case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BATTERY; -- break; -- case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_BALANCED; -- break; -- case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_PERFORMANCE; -- break; -- case ATOM_PPLIB_CLASSIFICATION_UI_NONE: -- if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_PERFORMANCE; -- break; -- } -- rdev->pm.power_state[state_index].flags = 0; -- if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) -- rdev->pm.power_state[state_index].flags |= -- RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -- if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { -- rdev->pm.power_state[state_index].type = -- POWER_STATE_TYPE_DEFAULT; -- rdev->pm.default_power_state_index = state_index; -- rdev->pm.power_state[state_index].default_clock_mode = -- &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; -- /* patch the table values with the default slck/mclk from firmware info */ -- for (j = 0; j < mode_index; j++) { -- rdev->pm.power_state[state_index].clock_info[j].mclk = -- rdev->clock.default_mclk; -- rdev->pm.power_state[state_index].clock_info[j].sclk = -- rdev->clock.default_sclk; -- if (vddc) -- rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = -- vddc; -- } -- } -- state_index++; -- } -- } -- /* if multiple clock modes, mark the lowest as no display */ -- for (i = 0; i < state_index; i++) { -- if (rdev->pm.power_state[i].num_clock_modes > 1) -- rdev->pm.power_state[i].clock_info[0].flags |= -- RADEON_PM_MODE_NO_DISPLAY; -- } -- /* first mode is usually default */ -- if (rdev->pm.default_power_state_index == -1) { -- rdev->pm.power_state[0].type = -- POWER_STATE_TYPE_DEFAULT; -- rdev->pm.default_power_state_index = 0; -- rdev->pm.power_state[0].default_clock_mode = -- &rdev->pm.power_state[0].clock_info[0]; -- } -+ if (atom_parse_data_header(mode_info->atom_context, index, NULL, -+ &frev, &crev, &data_offset)) { -+ firmware_info = -+ (union firmware_info *)(mode_info->atom_context->bios + -+ data_offset); -+ vddc = firmware_info->info_14.usBootUpVDDCVoltage; -+ } -+ -+ return vddc; -+} -+ -+static void radeon_atombios_parse_pplib_non_clock_info(struct radeon_device *rdev, -+ int state_index, int mode_index, -+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info) -+{ -+ int j; -+ u32 misc = le32_to_cpu(non_clock_info->ulCapsAndSettings); -+ u32 misc2 = le16_to_cpu(non_clock_info->usClassification); -+ u16 vddc = radeon_atombios_get_default_vddc(rdev); -+ -+ rdev->pm.power_state[state_index].misc = misc; -+ rdev->pm.power_state[state_index].misc2 = misc2; -+ rdev->pm.power_state[state_index].pcie_lanes = -+ ((misc & ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> -+ ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; -+ switch (misc2 & ATOM_PPLIB_CLASSIFICATION_UI_MASK) { -+ case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY: -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_BATTERY; -+ break; -+ case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED: -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_BALANCED; -+ break; -+ case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE: -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_PERFORMANCE; -+ break; -+ case ATOM_PPLIB_CLASSIFICATION_UI_NONE: -+ if (misc2 & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_PERFORMANCE; -+ break; -+ } -+ rdev->pm.power_state[state_index].flags = 0; -+ if (misc & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) -+ rdev->pm.power_state[state_index].flags |= -+ RADEON_PM_STATE_SINGLE_DISPLAY_ONLY; -+ if (misc2 & ATOM_PPLIB_CLASSIFICATION_BOOT) { -+ rdev->pm.power_state[state_index].type = -+ POWER_STATE_TYPE_DEFAULT; -+ rdev->pm.default_power_state_index = state_index; -+ rdev->pm.power_state[state_index].default_clock_mode = -+ &rdev->pm.power_state[state_index].clock_info[mode_index - 1]; -+ /* patch the table values with the default slck/mclk from firmware info */ -+ for (j = 0; j < mode_index; j++) { -+ rdev->pm.power_state[state_index].clock_info[j].mclk = -+ rdev->clock.default_mclk; -+ rdev->pm.power_state[state_index].clock_info[j].sclk = -+ rdev->clock.default_sclk; -+ if (vddc) -+ rdev->pm.power_state[state_index].clock_info[j].voltage.voltage = -+ vddc; -+ } -+ } -+} -+ -+static bool radeon_atombios_parse_pplib_clock_info(struct radeon_device *rdev, -+ int state_index, int mode_index, -+ union pplib_clock_info *clock_info) -+{ -+ u32 sclk, mclk; -+ -+ if (rdev->flags & RADEON_IS_IGP) { -+ if (rdev->family >= CHIP_PALM) { -+ sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow); -+ sclk |= clock_info->sumo.ucEngineClockHigh << 16; -+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -+ } else { -+ sclk = le16_to_cpu(clock_info->rs780.usLowEngineClockLow); -+ sclk |= clock_info->rs780.ucLowEngineClockHigh << 16; -+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -+ } -+ } else if (ASIC_IS_DCE4(rdev)) { -+ sclk = le16_to_cpu(clock_info->evergreen.usEngineClockLow); -+ sclk |= clock_info->evergreen.ucEngineClockHigh << 16; -+ mclk = le16_to_cpu(clock_info->evergreen.usMemoryClockLow); -+ mclk |= clock_info->evergreen.ucMemoryClockHigh << 16; -+ rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; -+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = -+ VOLTAGE_SW; -+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = -+ clock_info->evergreen.usVDDC; -+ } else { -+ sclk = le16_to_cpu(clock_info->r600.usEngineClockLow); -+ sclk |= clock_info->r600.ucEngineClockHigh << 16; -+ mclk = le16_to_cpu(clock_info->r600.usMemoryClockLow); -+ mclk |= clock_info->r600.ucMemoryClockHigh << 16; -+ rdev->pm.power_state[state_index].clock_info[mode_index].mclk = mclk; -+ rdev->pm.power_state[state_index].clock_info[mode_index].sclk = sclk; -+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.type = -+ VOLTAGE_SW; -+ rdev->pm.power_state[state_index].clock_info[mode_index].voltage.voltage = -+ clock_info->r600.usVDDC; -+ } -+ -+ if (rdev->flags & RADEON_IS_IGP) { -+ /* skip invalid modes */ -+ if (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0) -+ return false; -+ } else { -+ /* skip invalid modes */ -+ if ((rdev->pm.power_state[state_index].clock_info[mode_index].mclk == 0) || -+ (rdev->pm.power_state[state_index].clock_info[mode_index].sclk == 0)) -+ return false; -+ } -+ return true; -+} -+ -+static int radeon_atombios_parse_power_table_4_5(struct radeon_device *rdev) -+{ -+ struct radeon_mode_info *mode_info = &rdev->mode_info; -+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; -+ union pplib_power_state *power_state; -+ int i, j; -+ int state_index = 0, mode_index = 0; -+ union pplib_clock_info *clock_info; -+ bool valid; -+ union power_info *power_info; -+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); -+ u16 data_offset; -+ u8 frev, crev; -+ -+ if (!atom_parse_data_header(mode_info->atom_context, index, NULL, -+ &frev, &crev, &data_offset)) -+ return state_index; -+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); -+ -+ radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); -+ /* first mode is usually default, followed by low to high */ -+ for (i = 0; i < power_info->pplib.ucNumStates; i++) { -+ mode_index = 0; -+ power_state = (union pplib_power_state *) -+ (mode_info->atom_context->bios + data_offset + -+ le16_to_cpu(power_info->pplib.usStateArrayOffset) + -+ i * power_info->pplib.ucStateEntrySize); -+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) -+ (mode_info->atom_context->bios + data_offset + -+ le16_to_cpu(power_info->pplib.usNonClockInfoArrayOffset) + -+ (power_state->v1.ucNonClockStateIndex * -+ power_info->pplib.ucNonClockSize)); -+ for (j = 0; j < (power_info->pplib.ucStateEntrySize - 1); j++) { -+ clock_info = (union pplib_clock_info *) -+ (mode_info->atom_context->bios + data_offset + -+ le16_to_cpu(power_info->pplib.usClockInfoArrayOffset) + -+ (power_state->v1.ucClockStateIndices[j] * -+ power_info->pplib.ucClockInfoSize)); -+ valid = radeon_atombios_parse_pplib_clock_info(rdev, -+ state_index, mode_index, -+ clock_info); -+ if (valid) -+ mode_index++; -+ } -+ rdev->pm.power_state[state_index].num_clock_modes = mode_index; -+ if (mode_index) { -+ radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, -+ non_clock_info); -+ state_index++; -+ } -+ } -+ /* if multiple clock modes, mark the lowest as no display */ -+ for (i = 0; i < state_index; i++) { -+ if (rdev->pm.power_state[i].num_clock_modes > 1) -+ rdev->pm.power_state[i].clock_info[0].flags |= -+ RADEON_PM_MODE_NO_DISPLAY; -+ } -+ /* first mode is usually default */ -+ if (rdev->pm.default_power_state_index == -1) { -+ rdev->pm.power_state[0].type = -+ POWER_STATE_TYPE_DEFAULT; -+ rdev->pm.default_power_state_index = 0; -+ rdev->pm.power_state[0].default_clock_mode = -+ &rdev->pm.power_state[0].clock_info[0]; -+ } -+ return state_index; -+} -+ -+static int radeon_atombios_parse_power_table_6(struct radeon_device *rdev) -+{ -+ struct radeon_mode_info *mode_info = &rdev->mode_info; -+ struct _ATOM_PPLIB_NONCLOCK_INFO *non_clock_info; -+ union pplib_power_state *power_state; -+ int i, j, non_clock_array_index, clock_array_index; -+ int state_index = 0, mode_index = 0; -+ union pplib_clock_info *clock_info; -+ struct StateArray *state_array; -+ struct ClockInfoArray *clock_info_array; -+ struct NonClockInfoArray *non_clock_info_array; -+ bool valid; -+ union power_info *power_info; -+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); -+ u16 data_offset; -+ u8 frev, crev; -+ -+ if (!atom_parse_data_header(mode_info->atom_context, index, NULL, -+ &frev, &crev, &data_offset)) -+ return state_index; -+ power_info = (union power_info *)(mode_info->atom_context->bios + data_offset); -+ -+ radeon_atombios_add_pplib_thermal_controller(rdev, &power_info->pplib.sThermalController); -+ state_array = (struct StateArray *) -+ (mode_info->atom_context->bios + data_offset + -+ power_info->pplib.usStateArrayOffset); -+ clock_info_array = (struct ClockInfoArray *) -+ (mode_info->atom_context->bios + data_offset + -+ power_info->pplib.usClockInfoArrayOffset); -+ non_clock_info_array = (struct NonClockInfoArray *) -+ (mode_info->atom_context->bios + data_offset + -+ power_info->pplib.usNonClockInfoArrayOffset); -+ for (i = 0; i < state_array->ucNumEntries; i++) { -+ mode_index = 0; -+ power_state = (union pplib_power_state *)&state_array->states[i]; -+ /* XXX this might be an inagua bug... */ -+ non_clock_array_index = i; /* power_state->v2.nonClockInfoIndex */ -+ non_clock_info = (struct _ATOM_PPLIB_NONCLOCK_INFO *) -+ &non_clock_info_array->nonClockInfo[non_clock_array_index]; -+ for (j = 0; j < power_state->v2.ucNumDPMLevels; j++) { -+ clock_array_index = power_state->v2.clockInfoIndex[j]; -+ /* XXX this might be an inagua bug... */ -+ if (clock_array_index >= clock_info_array->ucNumEntries) -+ continue; -+ clock_info = (union pplib_clock_info *) -+ &clock_info_array->clockInfo[clock_array_index]; -+ valid = radeon_atombios_parse_pplib_clock_info(rdev, -+ state_index, mode_index, -+ clock_info); -+ if (valid) -+ mode_index++; -+ } -+ rdev->pm.power_state[state_index].num_clock_modes = mode_index; -+ if (mode_index) { -+ radeon_atombios_parse_pplib_non_clock_info(rdev, state_index, mode_index, -+ non_clock_info); -+ state_index++; -+ } -+ } -+ /* if multiple clock modes, mark the lowest as no display */ -+ for (i = 0; i < state_index; i++) { -+ if (rdev->pm.power_state[i].num_clock_modes > 1) -+ rdev->pm.power_state[i].clock_info[0].flags |= -+ RADEON_PM_MODE_NO_DISPLAY; -+ } -+ /* first mode is usually default */ -+ if (rdev->pm.default_power_state_index == -1) { -+ rdev->pm.power_state[0].type = -+ POWER_STATE_TYPE_DEFAULT; -+ rdev->pm.default_power_state_index = 0; -+ rdev->pm.power_state[0].default_clock_mode = -+ &rdev->pm.power_state[0].clock_info[0]; -+ } -+ return state_index; -+} -+ -+void radeon_atombios_get_power_modes(struct radeon_device *rdev) -+{ -+ struct radeon_mode_info *mode_info = &rdev->mode_info; -+ int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); -+ u16 data_offset; -+ u8 frev, crev; -+ int state_index = 0; -+ -+ rdev->pm.default_power_state_index = -1; -+ -+ if (atom_parse_data_header(mode_info->atom_context, index, NULL, -+ &frev, &crev, &data_offset)) { -+ switch (frev) { -+ case 1: -+ case 2: -+ case 3: -+ state_index = radeon_atombios_parse_power_table_1_3(rdev); -+ break; -+ case 4: -+ case 5: -+ state_index = radeon_atombios_parse_power_table_4_5(rdev); -+ break; -+ case 6: -+ state_index = radeon_atombios_parse_power_table_6(rdev); -+ break; -+ default: -+ break; - } - } else { - /* add the default mode */ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_cs.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_cs.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_cs.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_cs.c 2011-01-07 14:22:17.000000000 +0100 -@@ -77,13 +77,13 @@ - p->relocs_ptr[i] = &p->relocs[i]; - p->relocs[i].robj = p->relocs[i].gobj->driver_private; - p->relocs[i].lobj.bo = p->relocs[i].robj; -- p->relocs[i].lobj.rdomain = r->read_domains; - p->relocs[i].lobj.wdomain = r->write_domain; -+ p->relocs[i].lobj.rdomain = r->read_domains; -+ p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo; - p->relocs[i].handle = r->handle; - p->relocs[i].flags = r->flags; -- INIT_LIST_HEAD(&p->relocs[i].lobj.list); - radeon_bo_list_add_object(&p->relocs[i].lobj, -- &p->validated); -+ &p->validated); - } - } - return radeon_bo_list_validate(&p->validated); -@@ -189,10 +189,13 @@ - { - unsigned i; - -- if (!error && parser->ib) { -- radeon_bo_list_fence(&parser->validated, parser->ib->fence); -- } -- radeon_bo_list_unreserve(&parser->validated); -+ -+ if (!error && parser->ib) -+ ttm_eu_fence_buffer_objects(&parser->validated, -+ parser->ib->fence); -+ else -+ ttm_eu_backoff_reservation(&parser->validated); -+ - if (parser->relocs != NULL) { - for (i = 0; i < parser->nrelocs; i++) { - if (parser->relocs[i].gobj) -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_device.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_device.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_device.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_device.c 2011-01-07 14:22:17.000000000 +0100 -@@ -81,6 +81,7 @@ - "JUNIPER", - "CYPRESS", - "HEMLOCK", -+ "PALM", - "LAST", - }; - -@@ -335,7 +336,12 @@ - uint32_t reg; - - /* first check CRTCs */ -- if (ASIC_IS_DCE4(rdev)) { -+ if (ASIC_IS_DCE41(rdev)) { -+ reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | -+ RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET); -+ if (reg & EVERGREEN_CRTC_MASTER_EN) -+ return true; -+ } else if (ASIC_IS_DCE4(rdev)) { - reg = RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC0_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC1_REGISTER_OFFSET) | - RREG32(EVERGREEN_CRTC_CONTROL + EVERGREEN_CRTC2_REGISTER_OFFSET) | -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_display.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_display.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_display.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_display.c 2011-01-07 14:22:17.000000000 +0100 -@@ -183,12 +183,272 @@ - kfree(radeon_crtc); - } - -+/* -+ * Handle unpin events outside the interrupt handler proper. -+ */ -+static void radeon_unpin_work_func(struct work_struct *__work) -+{ -+ struct radeon_unpin_work *work = -+ container_of(__work, struct radeon_unpin_work, work); -+ int r; -+ -+ /* unpin of the old buffer */ -+ r = radeon_bo_reserve(work->old_rbo, false); -+ if (likely(r == 0)) { -+ r = radeon_bo_unpin(work->old_rbo); -+ if (unlikely(r != 0)) { -+ DRM_ERROR("failed to unpin buffer after flip\n"); -+ } -+ radeon_bo_unreserve(work->old_rbo); -+ } else -+ DRM_ERROR("failed to reserve buffer after flip\n"); -+ kfree(work); -+} -+ -+void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; -+ struct radeon_unpin_work *work; -+ struct drm_pending_vblank_event *e; -+ struct timeval now; -+ unsigned long flags; -+ u32 update_pending; -+ int vpos, hpos; -+ -+ spin_lock_irqsave(&rdev->ddev->event_lock, flags); -+ work = radeon_crtc->unpin_work; -+ if (work == NULL || -+ !radeon_fence_signaled(work->fence)) { -+ spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); -+ return; -+ } -+ /* New pageflip, or just completion of a previous one? */ -+ if (!radeon_crtc->deferred_flip_completion) { -+ /* do the flip (mmio) */ -+ update_pending = radeon_page_flip(rdev, crtc_id, work->new_crtc_base); -+ } else { -+ /* This is just a completion of a flip queued in crtc -+ * at last invocation. Make sure we go directly to -+ * completion routine. -+ */ -+ update_pending = 0; -+ radeon_crtc->deferred_flip_completion = 0; -+ } -+ -+ /* Has the pageflip already completed in crtc, or is it certain -+ * to complete in this vblank? -+ */ -+ if (update_pending && -+ (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, -+ &vpos, &hpos)) && -+ (vpos >=0) && -+ (vpos < (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100)) { -+ /* crtc didn't flip in this target vblank interval, -+ * but flip is pending in crtc. It will complete it -+ * in next vblank interval, so complete the flip at -+ * next vblank irq. -+ */ -+ radeon_crtc->deferred_flip_completion = 1; -+ spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); -+ return; -+ } -+ -+ /* Pageflip (will be) certainly completed in this vblank. Clean up. */ -+ radeon_crtc->unpin_work = NULL; -+ -+ /* wakeup userspace */ -+ if (work->event) { -+ e = work->event; -+ e->event.sequence = drm_vblank_count_and_time(rdev->ddev, crtc_id, &now); -+ e->event.tv_sec = now.tv_sec; -+ e->event.tv_usec = now.tv_usec; -+ list_add_tail(&e->base.link, &e->base.file_priv->event_list); -+ wake_up_interruptible(&e->base.file_priv->event_wait); -+ } -+ spin_unlock_irqrestore(&rdev->ddev->event_lock, flags); -+ -+ drm_vblank_put(rdev->ddev, radeon_crtc->crtc_id); -+ radeon_fence_unref(&work->fence); -+ radeon_post_page_flip(work->rdev, work->crtc_id); -+ schedule_work(&work->work); -+} -+ -+static int radeon_crtc_page_flip(struct drm_crtc *crtc, -+ struct drm_framebuffer *fb, -+ struct drm_pending_vblank_event *event) -+{ -+ struct drm_device *dev = crtc->dev; -+ struct radeon_device *rdev = dev->dev_private; -+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc); -+ struct radeon_framebuffer *old_radeon_fb; -+ struct radeon_framebuffer *new_radeon_fb; -+ struct drm_gem_object *obj; -+ struct radeon_bo *rbo; -+ struct radeon_fence *fence; -+ struct radeon_unpin_work *work; -+ unsigned long flags; -+ u32 tiling_flags, pitch_pixels; -+ u64 base; -+ int r; -+ -+ work = kzalloc(sizeof *work, GFP_KERNEL); -+ if (work == NULL) -+ return -ENOMEM; -+ -+ r = radeon_fence_create(rdev, &fence); -+ if (unlikely(r != 0)) { -+ kfree(work); -+ DRM_ERROR("flip queue: failed to create fence.\n"); -+ return -ENOMEM; -+ } -+ work->event = event; -+ work->rdev = rdev; -+ work->crtc_id = radeon_crtc->crtc_id; -+ work->fence = radeon_fence_ref(fence); -+ old_radeon_fb = to_radeon_framebuffer(crtc->fb); -+ new_radeon_fb = to_radeon_framebuffer(fb); -+ /* schedule unpin of the old buffer */ -+ obj = old_radeon_fb->obj; -+ rbo = obj->driver_private; -+ work->old_rbo = rbo; -+ INIT_WORK(&work->work, radeon_unpin_work_func); -+ -+ /* We borrow the event spin lock for protecting unpin_work */ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ if (radeon_crtc->unpin_work) { -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ kfree(work); -+ radeon_fence_unref(&fence); -+ -+ DRM_DEBUG_DRIVER("flip queue: crtc already busy\n"); -+ return -EBUSY; -+ } -+ radeon_crtc->unpin_work = work; -+ radeon_crtc->deferred_flip_completion = 0; -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ /* pin the new buffer */ -+ obj = new_radeon_fb->obj; -+ rbo = obj->driver_private; -+ -+ DRM_DEBUG_DRIVER("flip-ioctl() cur_fbo = %p, cur_bbo = %p\n", -+ work->old_rbo, rbo); -+ -+ r = radeon_bo_reserve(rbo, false); -+ if (unlikely(r != 0)) { -+ DRM_ERROR("failed to reserve new rbo buffer before flip\n"); -+ goto pflip_cleanup; -+ } -+ r = radeon_bo_pin(rbo, RADEON_GEM_DOMAIN_VRAM, &base); -+ if (unlikely(r != 0)) { -+ radeon_bo_unreserve(rbo); -+ r = -EINVAL; -+ DRM_ERROR("failed to pin new rbo buffer before flip\n"); -+ goto pflip_cleanup; -+ } -+ radeon_bo_get_tiling_flags(rbo, &tiling_flags, NULL); -+ radeon_bo_unreserve(rbo); -+ -+ if (!ASIC_IS_AVIVO(rdev)) { -+ /* crtc offset is from display base addr not FB location */ -+ base -= radeon_crtc->legacy_display_base_addr; -+ pitch_pixels = fb->pitch / (fb->bits_per_pixel / 8); -+ -+ if (tiling_flags & RADEON_TILING_MACRO) { -+ if (ASIC_IS_R300(rdev)) { -+ base &= ~0x7ff; -+ } else { -+ int byteshift = fb->bits_per_pixel >> 4; -+ int tile_addr = (((crtc->y >> 3) * pitch_pixels + crtc->x) >> (8 - byteshift)) << 11; -+ base += tile_addr + ((crtc->x << byteshift) % 256) + ((crtc->y % 8) << 8); -+ } -+ } else { -+ int offset = crtc->y * pitch_pixels + crtc->x; -+ switch (fb->bits_per_pixel) { -+ case 8: -+ default: -+ offset *= 1; -+ break; -+ case 15: -+ case 16: -+ offset *= 2; -+ break; -+ case 24: -+ offset *= 3; -+ break; -+ case 32: -+ offset *= 4; -+ break; -+ } -+ base += offset; -+ } -+ base &= ~7; -+ } -+ -+ spin_lock_irqsave(&dev->event_lock, flags); -+ work->new_crtc_base = base; -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ -+ /* update crtc fb */ -+ crtc->fb = fb; -+ -+ r = drm_vblank_get(dev, radeon_crtc->crtc_id); -+ if (r) { -+ DRM_ERROR("failed to get vblank before flip\n"); -+ goto pflip_cleanup1; -+ } -+ -+ /* 32 ought to cover us */ -+ r = radeon_ring_lock(rdev, 32); -+ if (r) { -+ DRM_ERROR("failed to lock the ring before flip\n"); -+ goto pflip_cleanup2; -+ } -+ -+ /* emit the fence */ -+ radeon_fence_emit(rdev, fence); -+ /* set the proper interrupt */ -+ radeon_pre_page_flip(rdev, radeon_crtc->crtc_id); -+ /* fire the ring */ -+ radeon_ring_unlock_commit(rdev); -+ -+ return 0; -+ -+pflip_cleanup2: -+ drm_vblank_put(dev, radeon_crtc->crtc_id); -+ -+pflip_cleanup1: -+ r = radeon_bo_reserve(rbo, false); -+ if (unlikely(r != 0)) { -+ DRM_ERROR("failed to reserve new rbo in error path\n"); -+ goto pflip_cleanup; -+ } -+ r = radeon_bo_unpin(rbo); -+ if (unlikely(r != 0)) { -+ radeon_bo_unreserve(rbo); -+ r = -EINVAL; -+ DRM_ERROR("failed to unpin new rbo in error path\n"); -+ goto pflip_cleanup; -+ } -+ radeon_bo_unreserve(rbo); -+ -+pflip_cleanup: -+ spin_lock_irqsave(&dev->event_lock, flags); -+ radeon_crtc->unpin_work = NULL; -+ spin_unlock_irqrestore(&dev->event_lock, flags); -+ radeon_fence_unref(&fence); -+ kfree(work); -+ -+ return r; -+} -+ - static const struct drm_crtc_funcs radeon_crtc_funcs = { - .cursor_set = radeon_crtc_cursor_set, - .cursor_move = radeon_crtc_cursor_move, - .gamma_set = radeon_crtc_gamma_set, - .set_config = drm_crtc_helper_set_config, - .destroy = radeon_crtc_destroy, -+ .page_flip = radeon_crtc_page_flip, - }; - - static void radeon_crtc_init(struct drm_device *dev, int index) -@@ -225,7 +485,7 @@ - radeon_legacy_init_crtc(dev, radeon_crtc); - } - --static const char *encoder_names[34] = { -+static const char *encoder_names[36] = { - "NONE", - "INTERNAL_LVDS", - "INTERNAL_TMDS1", -@@ -260,6 +520,8 @@ - "INTERNAL_KLDSCP_LVTMA", - "INTERNAL_UNIPHY1", - "INTERNAL_UNIPHY2", -+ "NUTMEG", -+ "TRAVIS", - }; - - static const char *connector_names[15] = { -@@ -1019,7 +1281,7 @@ - /* - * Retrieve current video scanout position of crtc on a given gpu. - * -- * \param rdev Device to query. -+ * \param dev Device to query. - * \param crtc Crtc to query. - * \param *vpos Location where vertical scanout position should be stored. - * \param *hpos Location where horizontal scanout position should go. -@@ -1031,72 +1293,74 @@ - * - * \return Flags, or'ed together as follows: - * -- * RADEON_SCANOUTPOS_VALID = Query successfull. -- * RADEON_SCANOUTPOS_INVBL = Inside vblank. -- * RADEON_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of -+ * DRM_SCANOUTPOS_VALID = Query successfull. -+ * DRM_SCANOUTPOS_INVBL = Inside vblank. -+ * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of - * this flag means that returned position may be offset by a constant but - * unknown small number of scanlines wrt. real scanout position. - * - */ --int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos) -+int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos) - { - u32 stat_crtc = 0, vbl = 0, position = 0; - int vbl_start, vbl_end, vtotal, ret = 0; - bool in_vbl = true; - -+ struct radeon_device *rdev = dev->dev_private; -+ - if (ASIC_IS_DCE4(rdev)) { - if (crtc == 0) { - vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + - EVERGREEN_CRTC0_REGISTER_OFFSET); - position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + - EVERGREEN_CRTC0_REGISTER_OFFSET); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 1) { - vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + - EVERGREEN_CRTC1_REGISTER_OFFSET); - position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + - EVERGREEN_CRTC1_REGISTER_OFFSET); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 2) { - vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + - EVERGREEN_CRTC2_REGISTER_OFFSET); - position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + - EVERGREEN_CRTC2_REGISTER_OFFSET); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 3) { - vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + - EVERGREEN_CRTC3_REGISTER_OFFSET); - position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + - EVERGREEN_CRTC3_REGISTER_OFFSET); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 4) { - vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + - EVERGREEN_CRTC4_REGISTER_OFFSET); - position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + - EVERGREEN_CRTC4_REGISTER_OFFSET); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 5) { - vbl = RREG32(EVERGREEN_CRTC_V_BLANK_START_END + - EVERGREEN_CRTC5_REGISTER_OFFSET); - position = RREG32(EVERGREEN_CRTC_STATUS_POSITION + - EVERGREEN_CRTC5_REGISTER_OFFSET); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - } else if (ASIC_IS_AVIVO(rdev)) { - if (crtc == 0) { - vbl = RREG32(AVIVO_D1CRTC_V_BLANK_START_END); - position = RREG32(AVIVO_D1CRTC_STATUS_POSITION); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 1) { - vbl = RREG32(AVIVO_D2CRTC_V_BLANK_START_END); - position = RREG32(AVIVO_D2CRTC_STATUS_POSITION); -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - } else { - /* Pre-AVIVO: Different encoding of scanout pos and vblank interval. */ -@@ -1112,7 +1376,7 @@ - if (!(stat_crtc & 1)) - in_vbl = false; - -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - if (crtc == 1) { - vbl = (RREG32(RADEON_CRTC2_V_TOTAL_DISP) & -@@ -1122,7 +1386,7 @@ - if (!(stat_crtc & 1)) - in_vbl = false; - -- ret |= RADEON_SCANOUTPOS_VALID; -+ ret |= DRM_SCANOUTPOS_VALID; - } - } - -@@ -1133,13 +1397,13 @@ - /* Valid vblank area boundaries from gpu retrieved? */ - if (vbl > 0) { - /* Yes: Decode. */ -- ret |= RADEON_SCANOUTPOS_ACCURATE; -+ ret |= DRM_SCANOUTPOS_ACCURATE; - vbl_start = vbl & 0x1fff; - vbl_end = (vbl >> 16) & 0x1fff; - } - else { - /* No: Fake something reasonable which gives at least ok results. */ -- vbl_start = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vdisplay; -+ vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay; - vbl_end = 0; - } - -@@ -1155,7 +1419,7 @@ - - /* Inside "upper part" of vblank area? Apply corrective offset if so: */ - if (in_vbl && (*vpos >= vbl_start)) { -- vtotal = rdev->mode_info.crtcs[crtc]->base.mode.crtc_vtotal; -+ vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal; - *vpos = *vpos - vtotal; - } - -@@ -1164,7 +1428,7 @@ - - /* In vblank? */ - if (in_vbl) -- ret |= RADEON_SCANOUTPOS_INVBL; -+ ret |= DRM_SCANOUTPOS_INVBL; - - return ret; - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_drv.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_drv.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_drv.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_drv.c 2011-01-07 14:22:17.000000000 +0100 -@@ -48,9 +48,10 @@ - * - 2.5.0 - add get accel 2 to work around ddx breakage for evergreen - * - 2.6.0 - add tiling config query (r6xx+), add initial HiZ support (r300->r500) - * 2.7.0 - fixups for r600 2D tiling support. (no external ABI change), add eg dyn gpr regs -+ * 2.8.0 - pageflip support - */ - #define KMS_DRIVER_MAJOR 2 --#define KMS_DRIVER_MINOR 7 -+#define KMS_DRIVER_MINOR 8 - #define KMS_DRIVER_PATCHLEVEL 0 - int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); - int radeon_driver_unload_kms(struct drm_device *dev); -@@ -66,6 +67,10 @@ - u32 radeon_get_vblank_counter_kms(struct drm_device *dev, int crtc); - int radeon_enable_vblank_kms(struct drm_device *dev, int crtc); - void radeon_disable_vblank_kms(struct drm_device *dev, int crtc); -+int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, -+ int *max_error, -+ struct timeval *vblank_time, -+ unsigned flags); - void radeon_driver_irq_preinstall_kms(struct drm_device *dev); - int radeon_driver_irq_postinstall_kms(struct drm_device *dev); - void radeon_driver_irq_uninstall_kms(struct drm_device *dev); -@@ -74,6 +79,8 @@ - struct drm_file *file_priv); - int radeon_gem_object_init(struct drm_gem_object *obj); - void radeon_gem_object_free(struct drm_gem_object *obj); -+extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, -+ int *vpos, int *hpos); - extern struct drm_ioctl_desc radeon_ioctls_kms[]; - extern int radeon_max_kms_ioctl; - int radeon_mmap(struct file *filp, struct vm_area_struct *vma); -@@ -277,6 +284,8 @@ - .get_vblank_counter = radeon_get_vblank_counter_kms, - .enable_vblank = radeon_enable_vblank_kms, - .disable_vblank = radeon_disable_vblank_kms, -+ .get_vblank_timestamp = radeon_get_vblank_timestamp_kms, -+ .get_scanout_position = radeon_get_crtc_scanoutpos, - #if defined(CONFIG_DEBUG_FS) - .debugfs_init = radeon_debugfs_init, - .debugfs_cleanup = radeon_debugfs_cleanup, -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_encoders.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_encoders.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_encoders.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_encoders.c 2011-01-07 14:22:17.000000000 +0100 -@@ -713,7 +713,7 @@ - * DIG1/2 can drive UNIPHY0/1/2 link A or link B - * - * DCE 4.0 -- * - 3 DIG transmitter blocks UNPHY0/1/2 (links A and B). -+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). - * Supports up to 6 digital outputs - * - 6 DIG encoder blocks. - * - DIG to PHY mapping is hardcoded -@@ -724,6 +724,12 @@ - * DIG5 drives UNIPHY2 link A, A+B - * DIG6 drives UNIPHY2 link B - * -+ * DCE 4.1 -+ * - 3 DIG transmitter blocks UNIPHY0/1/2 (links A and B). -+ * Supports up to 6 digital outputs -+ * - 2 DIG encoder blocks. -+ * DIG1/2 can drive UNIPHY0/1/2 link A or link B -+ * - * Routing - * crtc -> dig encoder -> UNIPHY/LVTMA (1 or 2 links) - * Examples: -@@ -904,9 +910,15 @@ - else - args.v3.ucLaneNum = 4; - -- if (dig->linkb) { -- args.v3.acConfig.ucLinkSel = 1; -- args.v3.acConfig.ucEncoderSel = 1; -+ if (ASIC_IS_DCE41(rdev)) { -+ args.v3.acConfig.ucEncoderSel = dig->dig_encoder; -+ if (dig->linkb) -+ args.v3.acConfig.ucLinkSel = 1; -+ } else { -+ if (dig->linkb) { -+ args.v3.acConfig.ucLinkSel = 1; -+ args.v3.acConfig.ucEncoderSel = 1; -+ } - } - - /* Select the PLL for the PHY -@@ -1044,6 +1056,7 @@ - - union external_encoder_control { - EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION v1; -+ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 v3; - }; - - static void -@@ -1054,6 +1067,7 @@ - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; - struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); -+ struct radeon_encoder *ext_radeon_encoder = to_radeon_encoder(ext_encoder); - union external_encoder_control args; - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); - int index = GetIndexIntoMasterTable(COMMAND, ExternalEncoderControl); -@@ -1061,6 +1075,7 @@ - int dp_clock = 0; - int dp_lane_count = 0; - int connector_object_id = 0; -+ u32 ext_enum = (ext_radeon_encoder->encoder_enum & ENUM_ID_MASK) >> ENUM_ID_SHIFT; - - if (connector) { - struct radeon_connector *radeon_connector = to_radeon_connector(connector); -@@ -1099,6 +1114,37 @@ - else - args.v1.sDigEncoder.ucLaneNum = 4; - break; -+ case 3: -+ args.v3.sExtEncoder.ucAction = action; -+ if (action == EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT) -+ args.v3.sExtEncoder.usConnectorId = connector_object_id; -+ else -+ args.v3.sExtEncoder.usPixelClock = cpu_to_le16(radeon_encoder->pixel_clock / 10); -+ args.v3.sExtEncoder.ucEncoderMode = atombios_get_encoder_mode(encoder); -+ -+ if (args.v3.sExtEncoder.ucEncoderMode == ATOM_ENCODER_MODE_DP) { -+ if (dp_clock == 270000) -+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_2_70GHZ; -+ else if (dp_clock == 540000) -+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_DPLINKRATE_5_40GHZ; -+ args.v3.sExtEncoder.ucLaneNum = dp_lane_count; -+ } else if (radeon_encoder->pixel_clock > 165000) -+ args.v3.sExtEncoder.ucLaneNum = 8; -+ else -+ args.v3.sExtEncoder.ucLaneNum = 4; -+ switch (ext_enum) { -+ case GRAPH_OBJECT_ENUM_ID1: -+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER1; -+ break; -+ case GRAPH_OBJECT_ENUM_ID2: -+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER2; -+ break; -+ case GRAPH_OBJECT_ENUM_ID3: -+ args.v3.sExtEncoder.ucConfig |= EXTERNAL_ENCODER_CONFIG_V3_ENCODER3; -+ break; -+ } -+ args.v3.sExtEncoder.ucBitPerColor = PANEL_8BIT_PER_COLOR; -+ break; - default: - DRM_ERROR("Unknown table version: %d, %d\n", frev, crev); - return; -@@ -1289,12 +1335,18 @@ - switch (mode) { - case DRM_MODE_DPMS_ON: - default: -- action = ATOM_ENABLE; -+ if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) -+ action = EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT; -+ else -+ action = ATOM_ENABLE; - break; - case DRM_MODE_DPMS_STANDBY: - case DRM_MODE_DPMS_SUSPEND: - case DRM_MODE_DPMS_OFF: -- action = ATOM_DISABLE; -+ if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) -+ action = EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT; -+ else -+ action = ATOM_DISABLE; - break; - } - atombios_external_encoder_setup(encoder, ext_encoder, action); -@@ -1483,6 +1535,11 @@ - struct radeon_encoder_atom_dig *dig; - uint32_t dig_enc_in_use = 0; - -+ /* on DCE41 and encoder can driver any phy so just crtc id */ -+ if (ASIC_IS_DCE41(rdev)) { -+ return radeon_crtc->crtc_id; -+ } -+ - if (ASIC_IS_DCE4(rdev)) { - dig = radeon_encoder->enc_priv; - switch (radeon_encoder->encoder_id) { -@@ -1610,7 +1667,13 @@ - } - - if (ext_encoder) { -- atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); -+ if (ASIC_IS_DCE41(rdev) && (rdev->flags & RADEON_IS_IGP)) { -+ atombios_external_encoder_setup(encoder, ext_encoder, -+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_INIT); -+ atombios_external_encoder_setup(encoder, ext_encoder, -+ EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP); -+ } else -+ atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE); - } - - atombios_apply_encoder_quirks(encoder, adjusted_mode); -@@ -2029,6 +2092,8 @@ - case ENCODER_OBJECT_ID_TITFP513: - case ENCODER_OBJECT_ID_VT1623: - case ENCODER_OBJECT_ID_HDMI_SI1930: -+ case ENCODER_OBJECT_ID_TRAVIS: -+ case ENCODER_OBJECT_ID_NUTMEG: - /* these are handled by the primary encoders */ - radeon_encoder->is_ext_encoder = true; - if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_family.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_family.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_family.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_family.h 2011-01-07 14:22:17.000000000 +0100 -@@ -80,6 +80,7 @@ - CHIP_JUNIPER, - CHIP_CYPRESS, - CHIP_HEMLOCK, -+ CHIP_PALM, - CHIP_LAST, - }; - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_fence.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_fence.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_fence.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_fence.c 2011-01-07 14:22:17.000000000 +0100 -@@ -38,6 +38,7 @@ - #include "drm.h" - #include "radeon_reg.h" - #include "radeon.h" -+#include "radeon_trace.h" - - int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence *fence) - { -@@ -57,6 +58,7 @@ - } else - radeon_fence_ring_emit(rdev, fence); - -+ trace_radeon_fence_emit(rdev->ddev, fence->seq); - fence->emited = true; - list_del(&fence->list); - list_add_tail(&fence->list, &rdev->fence_drv.emited); -@@ -213,6 +215,7 @@ - retry: - /* save current sequence used to check for GPU lockup */ - seq = rdev->fence_drv.last_seq; -+ trace_radeon_fence_wait_begin(rdev->ddev, seq); - if (intr) { - radeon_irq_kms_sw_irq_get(rdev); - r = wait_event_interruptible_timeout(rdev->fence_drv.queue, -@@ -227,6 +230,7 @@ - radeon_fence_signaled(fence), timeout); - radeon_irq_kms_sw_irq_put(rdev); - } -+ trace_radeon_fence_wait_end(rdev->ddev, seq); - if (unlikely(!radeon_fence_signaled(fence))) { - /* we were interrupted for some reason and fence isn't - * isn't signaled yet, resume wait -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon.h 2011-01-07 14:22:17.000000000 +0100 -@@ -69,6 +69,7 @@ - #include - #include - #include -+#include - - #include "radeon_family.h" - #include "radeon_mode.h" -@@ -180,6 +181,7 @@ - extern u32 rv6xx_get_temp(struct radeon_device *rdev); - extern u32 rv770_get_temp(struct radeon_device *rdev); - extern u32 evergreen_get_temp(struct radeon_device *rdev); -+extern u32 sumo_get_temp(struct radeon_device *rdev); - - /* - * Fences. -@@ -259,13 +261,12 @@ - }; - - struct radeon_bo_list { -- struct list_head list; -+ struct ttm_validate_buffer tv; - struct radeon_bo *bo; - uint64_t gpu_offset; - unsigned rdomain; - unsigned wdomain; - u32 tiling_flags; -- bool reserved; - }; - - /* -@@ -377,11 +378,56 @@ - /* - * IRQS. - */ -+ -+struct radeon_unpin_work { -+ struct work_struct work; -+ struct radeon_device *rdev; -+ int crtc_id; -+ struct radeon_fence *fence; -+ struct drm_pending_vblank_event *event; -+ struct radeon_bo *old_rbo; -+ u64 new_crtc_base; -+}; -+ -+struct r500_irq_stat_regs { -+ u32 disp_int; -+}; -+ -+struct r600_irq_stat_regs { -+ u32 disp_int; -+ u32 disp_int_cont; -+ u32 disp_int_cont2; -+ u32 d1grph_int; -+ u32 d2grph_int; -+}; -+ -+struct evergreen_irq_stat_regs { -+ u32 disp_int; -+ u32 disp_int_cont; -+ u32 disp_int_cont2; -+ u32 disp_int_cont3; -+ u32 disp_int_cont4; -+ u32 disp_int_cont5; -+ u32 d1grph_int; -+ u32 d2grph_int; -+ u32 d3grph_int; -+ u32 d4grph_int; -+ u32 d5grph_int; -+ u32 d6grph_int; -+}; -+ -+union radeon_irq_stat_regs { -+ struct r500_irq_stat_regs r500; -+ struct r600_irq_stat_regs r600; -+ struct evergreen_irq_stat_regs evergreen; -+}; -+ - struct radeon_irq { - bool installed; - bool sw_int; - /* FIXME: use a define max crtc rather than hardcode it */ - bool crtc_vblank_int[6]; -+ bool pflip[6]; - wait_queue_head_t vblank_queue; - /* FIXME: use defines for max hpd/dacs */ - bool hpd[6]; -@@ -392,12 +438,17 @@ - bool hdmi[2]; - spinlock_t sw_lock; - int sw_refcount; -+ union radeon_irq_stat_regs stat_regs; -+ spinlock_t pflip_lock[6]; -+ int pflip_refcount[6]; - }; - - int radeon_irq_kms_init(struct radeon_device *rdev); - void radeon_irq_kms_fini(struct radeon_device *rdev); - void radeon_irq_kms_sw_irq_get(struct radeon_device *rdev); - void radeon_irq_kms_sw_irq_put(struct radeon_device *rdev); -+void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc); -+void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc); - - /* - * CP & ring. -@@ -687,6 +738,7 @@ - THERMAL_TYPE_RV6XX, - THERMAL_TYPE_RV770, - THERMAL_TYPE_EVERGREEN, -+ THERMAL_TYPE_SUMO, - }; - - struct radeon_voltage { -@@ -881,6 +933,10 @@ - void (*pm_finish)(struct radeon_device *rdev); - void (*pm_init_profile)(struct radeon_device *rdev); - void (*pm_get_dynpm_state)(struct radeon_device *rdev); -+ /* pageflipping */ -+ void (*pre_page_flip)(struct radeon_device *rdev, int crtc); -+ u32 (*page_flip)(struct radeon_device *rdev, int crtc, u64 crtc_base); -+ void (*post_page_flip)(struct radeon_device *rdev, int crtc); - }; - - /* -@@ -1269,6 +1325,7 @@ - #define ASIC_IS_DCE3(rdev) ((rdev->family >= CHIP_RV620)) - #define ASIC_IS_DCE32(rdev) ((rdev->family >= CHIP_RV730)) - #define ASIC_IS_DCE4(rdev) ((rdev->family >= CHIP_CEDAR)) -+#define ASIC_IS_DCE41(rdev) ((rdev->family >= CHIP_PALM)) - - /* - * BIOS helpers. -@@ -1344,6 +1401,9 @@ - #define radeon_pm_finish(rdev) (rdev)->asic->pm_finish((rdev)) - #define radeon_pm_init_profile(rdev) (rdev)->asic->pm_init_profile((rdev)) - #define radeon_pm_get_dynpm_state(rdev) (rdev)->asic->pm_get_dynpm_state((rdev)) -+#define radeon_pre_page_flip(rdev, crtc) rdev->asic->pre_page_flip((rdev), (crtc)) -+#define radeon_page_flip(rdev, crtc, base) rdev->asic->page_flip((rdev), (crtc), (base)) -+#define radeon_post_page_flip(rdev, crtc) rdev->asic->post_page_flip((rdev), (crtc)) - - /* Common functions */ - /* AGP */ -@@ -1432,7 +1492,6 @@ - struct drm_display_mode *mode2); - - /* r600, rv610, rv630, rv620, rv635, rv670, rs780, rs880 */ --extern void r600_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); - extern bool r600_card_posted(struct radeon_device *rdev); - extern void r600_cp_stop(struct radeon_device *rdev); - extern int r600_cp_start(struct radeon_device *rdev); -@@ -1478,6 +1537,7 @@ - extern int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder); - extern void r600_hdmi_update_audio_settings(struct drm_encoder *encoder); - -+extern void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc); - extern void r700_cp_stop(struct radeon_device *rdev); - extern void r700_cp_fini(struct radeon_device *rdev); - extern void evergreen_disable_interrupt_state(struct radeon_device *rdev); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_irq_kms.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_irq_kms.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_irq_kms.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_irq_kms.c 2011-01-07 14:22:17.000000000 +0100 -@@ -71,8 +71,10 @@ - rdev->irq.gui_idle = false; - for (i = 0; i < rdev->num_crtc; i++) - rdev->irq.crtc_vblank_int[i] = false; -- for (i = 0; i < 6; i++) -+ for (i = 0; i < 6; i++) { - rdev->irq.hpd[i] = false; -+ rdev->irq.pflip[i] = false; -+ } - radeon_irq_set(rdev); - /* Clear bits */ - radeon_irq_process(rdev); -@@ -101,8 +103,10 @@ - rdev->irq.gui_idle = false; - for (i = 0; i < rdev->num_crtc; i++) - rdev->irq.crtc_vblank_int[i] = false; -- for (i = 0; i < 6; i++) -+ for (i = 0; i < 6; i++) { - rdev->irq.hpd[i] = false; -+ rdev->irq.pflip[i] = false; -+ } - radeon_irq_set(rdev); - } - -@@ -121,7 +125,7 @@ - * chips. Disable MSI on them for now. - */ - if ((rdev->family >= CHIP_RV380) && -- (!(rdev->flags & RADEON_IS_IGP)) && -+ ((!(rdev->flags & RADEON_IS_IGP)) || (rdev->family >= CHIP_PALM)) && - (!(rdev->flags & RADEON_IS_AGP))) { - int ret = pci_enable_msi(rdev->pdev); - if (!ret) { -@@ -175,3 +179,34 @@ - spin_unlock_irqrestore(&rdev->irq.sw_lock, irqflags); - } - -+void radeon_irq_kms_pflip_irq_get(struct radeon_device *rdev, int crtc) -+{ -+ unsigned long irqflags; -+ -+ if (crtc < 0 || crtc >= rdev->num_crtc) -+ return; -+ -+ spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags); -+ if (rdev->ddev->irq_enabled && (++rdev->irq.pflip_refcount[crtc] == 1)) { -+ rdev->irq.pflip[crtc] = true; -+ radeon_irq_set(rdev); -+ } -+ spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags); -+} -+ -+void radeon_irq_kms_pflip_irq_put(struct radeon_device *rdev, int crtc) -+{ -+ unsigned long irqflags; -+ -+ if (crtc < 0 || crtc >= rdev->num_crtc) -+ return; -+ -+ spin_lock_irqsave(&rdev->irq.pflip_lock[crtc], irqflags); -+ BUG_ON(rdev->ddev->irq_enabled && rdev->irq.pflip_refcount[crtc] <= 0); -+ if (rdev->ddev->irq_enabled && (--rdev->irq.pflip_refcount[crtc] == 0)) { -+ rdev->irq.pflip[crtc] = false; -+ radeon_irq_set(rdev); -+ } -+ spin_unlock_irqrestore(&rdev->irq.pflip_lock[crtc], irqflags); -+} -+ -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_kms.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_kms.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_kms.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_kms.c 2011-01-07 14:22:17.000000000 +0100 -@@ -277,6 +277,27 @@ - radeon_irq_set(rdev); - } - -+int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, -+ int *max_error, -+ struct timeval *vblank_time, -+ unsigned flags) -+{ -+ struct drm_crtc *drmcrtc; -+ struct radeon_device *rdev = dev->dev_private; -+ -+ if (crtc < 0 || crtc >= dev->num_crtcs) { -+ DRM_ERROR("Invalid crtc %d\n", crtc); -+ return -EINVAL; -+ } -+ -+ /* Get associated drm_crtc: */ -+ drmcrtc = &rdev->mode_info.crtcs[crtc]->base; -+ -+ /* Helper routine in DRM core does all the work: */ -+ return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, -+ vblank_time, flags, -+ drmcrtc); -+} - - /* - * IOCTL. -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_mode.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_mode.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_mode.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_mode.h 2011-01-07 14:22:17.000000000 +0100 -@@ -277,6 +277,9 @@ - fixed20_12 hsc; - struct drm_display_mode native_mode; - int pll_id; -+ /* page flipping */ -+ struct radeon_unpin_work *unpin_work; -+ int deferred_flip_completion; - }; - - struct radeon_encoder_primary_dac { -@@ -442,10 +445,6 @@ - struct drm_gem_object *obj; - }; - --/* radeon_get_crtc_scanoutpos() return flags */ --#define RADEON_SCANOUTPOS_VALID (1 << 0) --#define RADEON_SCANOUTPOS_INVBL (1 << 1) --#define RADEON_SCANOUTPOS_ACCURATE (1 << 2) - - extern enum radeon_tv_std - radeon_combios_get_tv_info(struct radeon_device *rdev); -@@ -562,7 +561,8 @@ - extern int radeon_crtc_cursor_move(struct drm_crtc *crtc, - int x, int y); - --extern int radeon_get_crtc_scanoutpos(struct radeon_device *rdev, int crtc, int *vpos, int *hpos); -+extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, -+ int *vpos, int *hpos); - - extern bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev); - extern struct edid * -@@ -662,4 +662,7 @@ - bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj); - - void radeon_fb_output_poll_changed(struct radeon_device *rdev); -+ -+void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id); -+ - #endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_object.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_object.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_object.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_object.c 2011-01-07 14:22:17.000000000 +0100 -@@ -34,6 +34,7 @@ - #include - #include "radeon_drm.h" - #include "radeon.h" -+#include "radeon_trace.h" - - - int radeon_ttm_init(struct radeon_device *rdev); -@@ -137,6 +138,7 @@ - list_add_tail(&bo->list, &rdev->gem.objects); - mutex_unlock(&bo->rdev->gem.mutex); - } -+ trace_radeon_bo_create(bo); - return 0; - } - -@@ -293,34 +295,9 @@ - struct list_head *head) - { - if (lobj->wdomain) { -- list_add(&lobj->list, head); -+ list_add(&lobj->tv.head, head); - } else { -- list_add_tail(&lobj->list, head); -- } --} -- --int radeon_bo_list_reserve(struct list_head *head) --{ -- struct radeon_bo_list *lobj; -- int r; -- -- list_for_each_entry(lobj, head, list){ -- r = radeon_bo_reserve(lobj->bo, false); -- if (unlikely(r != 0)) -- return r; -- lobj->reserved = true; -- } -- return 0; --} -- --void radeon_bo_list_unreserve(struct list_head *head) --{ -- struct radeon_bo_list *lobj; -- -- list_for_each_entry(lobj, head, list) { -- /* only unreserve object we successfully reserved */ -- if (lobj->reserved && radeon_bo_is_reserved(lobj->bo)) -- radeon_bo_unreserve(lobj->bo); -+ list_add_tail(&lobj->tv.head, head); - } - } - -@@ -331,14 +308,11 @@ - u32 domain; - int r; - -- list_for_each_entry(lobj, head, list) { -- lobj->reserved = false; -- } -- r = radeon_bo_list_reserve(head); -+ r = ttm_eu_reserve_buffers(head); - if (unlikely(r != 0)) { - return r; - } -- list_for_each_entry(lobj, head, list) { -+ list_for_each_entry(lobj, head, tv.head) { - bo = lobj->bo; - if (!bo->pin_count) { - domain = lobj->wdomain ? lobj->wdomain : lobj->rdomain; -@@ -361,25 +335,6 @@ - return 0; - } - --void radeon_bo_list_fence(struct list_head *head, void *fence) --{ -- struct radeon_bo_list *lobj; -- struct radeon_bo *bo; -- struct radeon_fence *old_fence = NULL; -- -- list_for_each_entry(lobj, head, list) { -- bo = lobj->bo; -- spin_lock(&bo->tbo.lock); -- old_fence = (struct radeon_fence *)bo->tbo.sync_obj; -- bo->tbo.sync_obj = radeon_fence_ref(fence); -- bo->tbo.sync_obj_arg = NULL; -- spin_unlock(&bo->tbo.lock); -- if (old_fence) { -- radeon_fence_unref(&old_fence); -- } -- } --} -- - int radeon_bo_fbdev_mmap(struct radeon_bo *bo, - struct vm_area_struct *vma) - { -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_object.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_object.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_object.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_object.h 2011-01-07 14:22:17.000000000 +0100 -@@ -126,12 +126,12 @@ - r = ttm_bo_reserve(&bo->tbo, true, no_wait, false, 0); - if (unlikely(r != 0)) - return r; -- spin_lock(&bo->tbo.lock); -+ spin_lock(&bo->tbo.bdev->fence_lock); - if (mem_type) - *mem_type = bo->tbo.mem.mem_type; - if (bo->tbo.sync_obj) - r = ttm_bo_wait(&bo->tbo, true, true, no_wait); -- spin_unlock(&bo->tbo.lock); -+ spin_unlock(&bo->tbo.bdev->fence_lock); - ttm_bo_unreserve(&bo->tbo); - return r; - } -@@ -152,10 +152,7 @@ - extern void radeon_bo_fini(struct radeon_device *rdev); - extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj, - struct list_head *head); --extern int radeon_bo_list_reserve(struct list_head *head); --extern void radeon_bo_list_unreserve(struct list_head *head); - extern int radeon_bo_list_validate(struct list_head *head); --extern void radeon_bo_list_fence(struct list_head *head, void *fence); - extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo, - struct vm_area_struct *vma); - extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo, -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_pm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_pm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_pm.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_pm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -449,6 +449,9 @@ - case THERMAL_TYPE_EVERGREEN: - temp = evergreen_get_temp(rdev); - break; -+ case THERMAL_TYPE_SUMO: -+ temp = sumo_get_temp(rdev); -+ break; - default: - temp = 0; - break; -@@ -487,6 +490,7 @@ - case THERMAL_TYPE_RV6XX: - case THERMAL_TYPE_RV770: - case THERMAL_TYPE_EVERGREEN: -+ case THERMAL_TYPE_SUMO: - rdev->pm.int_hwmon_dev = hwmon_device_register(rdev->dev); - if (IS_ERR(rdev->pm.int_hwmon_dev)) { - err = PTR_ERR(rdev->pm.int_hwmon_dev); -@@ -720,9 +724,9 @@ - */ - for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) { - if (rdev->pm.active_crtcs & (1 << crtc)) { -- vbl_status = radeon_get_crtc_scanoutpos(rdev, crtc, &vpos, &hpos); -- if ((vbl_status & RADEON_SCANOUTPOS_VALID) && -- !(vbl_status & RADEON_SCANOUTPOS_INVBL)) -+ vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos); -+ if ((vbl_status & DRM_SCANOUTPOS_VALID) && -+ !(vbl_status & DRM_SCANOUTPOS_INVBL)) - in_vbl = false; - } - } -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_reg.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_reg.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_reg.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_reg.h 2011-01-07 14:22:17.000000000 +0100 -@@ -422,6 +422,7 @@ - # define RADEON_CRTC_CSYNC_EN (1 << 4) - # define RADEON_CRTC_ICON_EN (1 << 15) - # define RADEON_CRTC_CUR_EN (1 << 16) -+# define RADEON_CRTC_VSTAT_MODE_MASK (3 << 17) - # define RADEON_CRTC_CUR_MODE_MASK (7 << 20) - # define RADEON_CRTC_CUR_MODE_SHIFT 20 - # define RADEON_CRTC_CUR_MODE_MONO 0 -@@ -509,6 +510,8 @@ - # define RADEON_CRTC_TILE_EN (1 << 15) - # define RADEON_CRTC_OFFSET_FLIP_CNTL (1 << 16) - # define RADEON_CRTC_STEREO_OFFSET_EN (1 << 17) -+# define RADEON_CRTC_GUI_TRIG_OFFSET_LEFT_EN (1 << 28) -+# define RADEON_CRTC_GUI_TRIG_OFFSET_RIGHT_EN (1 << 29) - - #define R300_CRTC_TILE_X0_Y0 0x0350 - #define R300_CRTC2_TILE_X0_Y0 0x0358 -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_trace.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_trace.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_trace.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_trace.h 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,82 @@ -+#if !defined(_RADEON_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -+#define _RADEON_TRACE_H_ -+ -+#include -+#include -+#include -+ -+#include -+ -+#undef TRACE_SYSTEM -+#define TRACE_SYSTEM radeon -+#define TRACE_SYSTEM_STRING __stringify(TRACE_SYSTEM) -+#define TRACE_INCLUDE_FILE radeon_trace -+ -+TRACE_EVENT(radeon_bo_create, -+ TP_PROTO(struct radeon_bo *bo), -+ TP_ARGS(bo), -+ TP_STRUCT__entry( -+ __field(struct radeon_bo *, bo) -+ __field(u32, pages) -+ ), -+ -+ TP_fast_assign( -+ __entry->bo = bo; -+ __entry->pages = bo->tbo.num_pages; -+ ), -+ TP_printk("bo=%p, pages=%u", __entry->bo, __entry->pages) -+); -+ -+DECLARE_EVENT_CLASS(radeon_fence_request, -+ -+ TP_PROTO(struct drm_device *dev, u32 seqno), -+ -+ TP_ARGS(dev, seqno), -+ -+ TP_STRUCT__entry( -+ __field(u32, dev) -+ __field(u32, seqno) -+ ), -+ -+ TP_fast_assign( -+ __entry->dev = dev->primary->index; -+ __entry->seqno = seqno; -+ ), -+ -+ TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno) -+); -+ -+DEFINE_EVENT(radeon_fence_request, radeon_fence_emit, -+ -+ TP_PROTO(struct drm_device *dev, u32 seqno), -+ -+ TP_ARGS(dev, seqno) -+); -+ -+DEFINE_EVENT(radeon_fence_request, radeon_fence_retire, -+ -+ TP_PROTO(struct drm_device *dev, u32 seqno), -+ -+ TP_ARGS(dev, seqno) -+); -+ -+DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin, -+ -+ TP_PROTO(struct drm_device *dev, u32 seqno), -+ -+ TP_ARGS(dev, seqno) -+); -+ -+DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_end, -+ -+ TP_PROTO(struct drm_device *dev, u32 seqno), -+ -+ TP_ARGS(dev, seqno) -+); -+ -+#endif -+ -+/* This part must be outside protection */ -+#undef TRACE_INCLUDE_PATH -+#define TRACE_INCLUDE_PATH . -+#include -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_trace_points.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_trace_points.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/radeon_trace_points.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/radeon_trace_points.c 2011-01-07 14:22:17.000000000 +0100 -@@ -0,0 +1,9 @@ -+/* Copyright Red Hat Inc 2010. -+ * Author : Dave Airlie -+ */ -+#include -+#include "radeon_drm.h" -+#include "radeon.h" -+ -+#define CREATE_TRACE_POINTS -+#include "radeon_trace.h" -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/rs600.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/rs600.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/rs600.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/rs600.c 2011-01-07 14:22:17.000000000 +0100 -@@ -46,6 +46,56 @@ - void rs600_gpu_init(struct radeon_device *rdev); - int rs600_mc_wait_for_idle(struct radeon_device *rdev); - -+void rs600_pre_page_flip(struct radeon_device *rdev, int crtc) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc]; -+ u32 tmp; -+ -+ /* make sure flip is at vb rather than hb */ -+ tmp = RREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset); -+ tmp &= ~AVIVO_D1GRPH_SURFACE_UPDATE_H_RETRACE_EN; -+ WREG32(AVIVO_D1GRPH_FLIP_CONTROL + radeon_crtc->crtc_offset, tmp); -+ -+ /* set pageflip to happen anywhere in vblank interval */ -+ WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0); -+ -+ /* enable the pflip int */ -+ radeon_irq_kms_pflip_irq_get(rdev, crtc); -+} -+ -+void rs600_post_page_flip(struct radeon_device *rdev, int crtc) -+{ -+ /* disable the pflip int */ -+ radeon_irq_kms_pflip_irq_put(rdev, crtc); -+} -+ -+u32 rs600_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; -+ u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); -+ -+ /* Lock the graphics update lock */ -+ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; -+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); -+ -+ /* update the scanout addresses */ -+ WREG32(AVIVO_D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -+ (u32)crtc_base); -+ WREG32(AVIVO_D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -+ (u32)crtc_base); -+ -+ /* Wait for update_pending to go high. */ -+ while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); -+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); -+ -+ /* Unlock the lock, so double-buffering can take place inside vblank */ -+ tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; -+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); -+ -+ /* Return current update_pending status: */ -+ return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; -+} -+ - void rs600_pm_misc(struct radeon_device *rdev) - { - int requested_index = rdev->pm.requested_power_state_index; -@@ -515,10 +565,12 @@ - if (rdev->irq.gui_idle) { - tmp |= S_000040_GUI_IDLE(1); - } -- if (rdev->irq.crtc_vblank_int[0]) { -+ if (rdev->irq.crtc_vblank_int[0] || -+ rdev->irq.pflip[0]) { - mode_int |= S_006540_D1MODE_VBLANK_INT_MASK(1); - } -- if (rdev->irq.crtc_vblank_int[1]) { -+ if (rdev->irq.crtc_vblank_int[1] || -+ rdev->irq.pflip[1]) { - mode_int |= S_006540_D2MODE_VBLANK_INT_MASK(1); - } - if (rdev->irq.hpd[0]) { -@@ -534,7 +586,7 @@ - return 0; - } - --static inline uint32_t rs600_irq_ack(struct radeon_device *rdev, u32 *r500_disp_int) -+static inline u32 rs600_irq_ack(struct radeon_device *rdev) - { - uint32_t irqs = RREG32(R_000044_GEN_INT_STATUS); - uint32_t irq_mask = S_000044_SW_INT(1); -@@ -547,27 +599,27 @@ - } - - if (G_000044_DISPLAY_INT_STAT(irqs)) { -- *r500_disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); -- if (G_007EDC_LB_D1_VBLANK_INTERRUPT(*r500_disp_int)) { -+ rdev->irq.stat_regs.r500.disp_int = RREG32(R_007EDC_DISP_INTERRUPT_STATUS); -+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - WREG32(R_006534_D1MODE_VBLANK_STATUS, - S_006534_D1MODE_VBLANK_ACK(1)); - } -- if (G_007EDC_LB_D2_VBLANK_INTERRUPT(*r500_disp_int)) { -+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - WREG32(R_006D34_D2MODE_VBLANK_STATUS, - S_006D34_D2MODE_VBLANK_ACK(1)); - } -- if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(*r500_disp_int)) { -+ if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - tmp = RREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL); - tmp |= S_007D08_DC_HOT_PLUG_DETECT1_INT_ACK(1); - WREG32(R_007D08_DC_HOT_PLUG_DETECT1_INT_CONTROL, tmp); - } -- if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(*r500_disp_int)) { -+ if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - tmp = RREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL); - tmp |= S_007D18_DC_HOT_PLUG_DETECT2_INT_ACK(1); - WREG32(R_007D18_DC_HOT_PLUG_DETECT2_INT_CONTROL, tmp); - } - } else { -- *r500_disp_int = 0; -+ rdev->irq.stat_regs.r500.disp_int = 0; - } - - if (irqs) { -@@ -578,32 +630,30 @@ - - void rs600_irq_disable(struct radeon_device *rdev) - { -- u32 tmp; -- - WREG32(R_000040_GEN_INT_CNTL, 0); - WREG32(R_006540_DxMODE_INT_MASK, 0); - /* Wait and acknowledge irq */ - mdelay(1); -- rs600_irq_ack(rdev, &tmp); -+ rs600_irq_ack(rdev); - } - - int rs600_irq_process(struct radeon_device *rdev) - { -- uint32_t status, msi_rearm; -- uint32_t r500_disp_int; -+ u32 status, msi_rearm; - bool queue_hotplug = false; - - /* reset gui idle ack. the status bit is broken */ - rdev->irq.gui_idle_acked = false; - -- status = rs600_irq_ack(rdev, &r500_disp_int); -- if (!status && !r500_disp_int) { -+ status = rs600_irq_ack(rdev); -+ if (!status && !rdev->irq.stat_regs.r500.disp_int) { - return IRQ_NONE; - } -- while (status || r500_disp_int) { -+ while (status || rdev->irq.stat_regs.r500.disp_int) { - /* SW interrupt */ -- if (G_000044_SW_INT(status)) -+ if (G_000044_SW_INT(status)) { - radeon_fence_process(rdev); -+ } - /* GUI idle */ - if (G_000040_GUI_IDLE(status)) { - rdev->irq.gui_idle_acked = true; -@@ -611,25 +661,33 @@ - wake_up(&rdev->irq.idle_queue); - } - /* Vertical blank interrupts */ -- if (G_007EDC_LB_D1_VBLANK_INTERRUPT(r500_disp_int)) { -- drm_handle_vblank(rdev->ddev, 0); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -- } -- if (G_007EDC_LB_D2_VBLANK_INTERRUPT(r500_disp_int)) { -- drm_handle_vblank(rdev->ddev, 1); -- rdev->pm.vblank_sync = true; -- wake_up(&rdev->irq.vblank_queue); -+ if (G_007EDC_LB_D1_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { -+ if (rdev->irq.crtc_vblank_int[0]) { -+ drm_handle_vblank(rdev->ddev, 0); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[0]) -+ radeon_crtc_handle_flip(rdev, 0); -+ } -+ if (G_007EDC_LB_D2_VBLANK_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { -+ if (rdev->irq.crtc_vblank_int[1]) { -+ drm_handle_vblank(rdev->ddev, 1); -+ rdev->pm.vblank_sync = true; -+ wake_up(&rdev->irq.vblank_queue); -+ } -+ if (rdev->irq.pflip[1]) -+ radeon_crtc_handle_flip(rdev, 1); - } -- if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(r500_disp_int)) { -+ if (G_007EDC_DC_HOT_PLUG_DETECT1_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - queue_hotplug = true; - DRM_DEBUG("HPD1\n"); - } -- if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(r500_disp_int)) { -+ if (G_007EDC_DC_HOT_PLUG_DETECT2_INTERRUPT(rdev->irq.stat_regs.r500.disp_int)) { - queue_hotplug = true; - DRM_DEBUG("HPD2\n"); - } -- status = rs600_irq_ack(rdev, &r500_disp_int); -+ status = rs600_irq_ack(rdev); - } - /* reset gui idle ack. the status bit is broken */ - rdev->irq.gui_idle_acked = false; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/rv770.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/rv770.c ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/rv770.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/rv770.c 2011-01-07 14:22:17.000000000 +0100 -@@ -42,6 +42,40 @@ - static void rv770_gpu_init(struct radeon_device *rdev); - void rv770_fini(struct radeon_device *rdev); - -+u32 rv770_page_flip(struct radeon_device *rdev, int crtc_id, u64 crtc_base) -+{ -+ struct radeon_crtc *radeon_crtc = rdev->mode_info.crtcs[crtc_id]; -+ u32 tmp = RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset); -+ -+ /* Lock the graphics update lock */ -+ tmp |= AVIVO_D1GRPH_UPDATE_LOCK; -+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); -+ -+ /* update the scanout addresses */ -+ if (radeon_crtc->crtc_id) { -+ WREG32(D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); -+ WREG32(D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); -+ } else { -+ WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); -+ WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH, upper_32_bits(crtc_base)); -+ } -+ WREG32(D1GRPH_SECONDARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -+ (u32)crtc_base); -+ WREG32(D1GRPH_PRIMARY_SURFACE_ADDRESS + radeon_crtc->crtc_offset, -+ (u32)crtc_base); -+ -+ /* Wait for update_pending to go high. */ -+ while (!(RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING)); -+ DRM_DEBUG("Update pending now high. Unlocking vupdate_lock.\n"); -+ -+ /* Unlock the lock, so double-buffering can take place inside vblank */ -+ tmp &= ~AVIVO_D1GRPH_UPDATE_LOCK; -+ WREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset, tmp); -+ -+ /* Return current update_pending status: */ -+ return RREG32(AVIVO_D1GRPH_UPDATE + radeon_crtc->crtc_offset) & AVIVO_D1GRPH_SURFACE_UPDATE_PENDING; -+} -+ - /* get temperature in millidegrees */ - u32 rv770_get_temp(struct radeon_device *rdev) - { -@@ -489,6 +523,49 @@ - return backend_map; - } - -+static void rv770_program_channel_remap(struct radeon_device *rdev) -+{ -+ u32 tcp_chan_steer, mc_shared_chremap, tmp; -+ bool force_no_swizzle; -+ -+ switch (rdev->family) { -+ case CHIP_RV770: -+ case CHIP_RV730: -+ force_no_swizzle = false; -+ break; -+ case CHIP_RV710: -+ case CHIP_RV740: -+ default: -+ force_no_swizzle = true; -+ break; -+ } -+ -+ tmp = RREG32(MC_SHARED_CHMAP); -+ switch ((tmp & NOOFCHAN_MASK) >> NOOFCHAN_SHIFT) { -+ case 0: -+ case 1: -+ default: -+ /* default mapping */ -+ mc_shared_chremap = 0x00fac688; -+ break; -+ case 2: -+ case 3: -+ if (force_no_swizzle) -+ mc_shared_chremap = 0x00fac688; -+ else -+ mc_shared_chremap = 0x00bbc298; -+ break; -+ } -+ -+ if (rdev->family == CHIP_RV740) -+ tcp_chan_steer = 0x00ef2a60; -+ else -+ tcp_chan_steer = 0x00fac688; -+ -+ WREG32(TCP_CHAN_STEER, tcp_chan_steer); -+ WREG32(MC_SHARED_CHREMAP, mc_shared_chremap); -+} -+ - static void rv770_gpu_init(struct radeon_device *rdev) - { - int i, j, num_qd_pipes; -@@ -688,6 +765,8 @@ - WREG32(DCP_TILING_CONFIG, (gb_tiling_config & 0xffff)); - WREG32(HDP_TILING_CONFIG, (gb_tiling_config & 0xffff)); - -+ rv770_program_channel_remap(rdev); -+ - WREG32(CC_RB_BACKEND_DISABLE, cc_rb_backend_disable); - WREG32(CC_GC_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); - WREG32(GC_USER_SHADER_PIPE_CONFIG, cc_gc_shader_pipe_config); -@@ -956,6 +1035,45 @@ - radeon_bo_unref(&rdev->vram_scratch.robj); - } - -+void r700_vram_gtt_location(struct radeon_device *rdev, struct radeon_mc *mc) -+{ -+ u64 size_bf, size_af; -+ -+ if (mc->mc_vram_size > 0xE0000000) { -+ /* leave room for at least 512M GTT */ -+ dev_warn(rdev->dev, "limiting VRAM\n"); -+ mc->real_vram_size = 0xE0000000; -+ mc->mc_vram_size = 0xE0000000; -+ } -+ if (rdev->flags & RADEON_IS_AGP) { -+ size_bf = mc->gtt_start; -+ size_af = 0xFFFFFFFF - mc->gtt_end + 1; -+ if (size_bf > size_af) { -+ if (mc->mc_vram_size > size_bf) { -+ dev_warn(rdev->dev, "limiting VRAM\n"); -+ mc->real_vram_size = size_bf; -+ mc->mc_vram_size = size_bf; -+ } -+ mc->vram_start = mc->gtt_start - mc->mc_vram_size; -+ } else { -+ if (mc->mc_vram_size > size_af) { -+ dev_warn(rdev->dev, "limiting VRAM\n"); -+ mc->real_vram_size = size_af; -+ mc->mc_vram_size = size_af; -+ } -+ mc->vram_start = mc->gtt_end; -+ } -+ mc->vram_end = mc->vram_start + mc->mc_vram_size - 1; -+ dev_info(rdev->dev, "VRAM: %lluM 0x%08llX - 0x%08llX (%lluM used)\n", -+ mc->mc_vram_size >> 20, mc->vram_start, -+ mc->vram_end, mc->real_vram_size >> 20); -+ } else { -+ radeon_vram_location(rdev, &rdev->mc, 0); -+ rdev->mc.gtt_base_align = 0; -+ radeon_gtt_location(rdev, mc); -+ } -+} -+ - int rv770_mc_init(struct radeon_device *rdev) - { - u32 tmp; -@@ -996,7 +1114,7 @@ - rdev->mc.real_vram_size = RREG32(CONFIG_MEMSIZE); - rdev->mc.visible_vram_size = rdev->mc.aper_size; - rdev->mc.active_vram_size = rdev->mc.visible_vram_size; -- r600_vram_gtt_location(rdev, &rdev->mc); -+ r700_vram_gtt_location(rdev, &rdev->mc); - radeon_update_bandwidth_info(rdev); - - return 0; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/radeon/rv770d.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/rv770d.h ---- linux-2.6.37-rc3/drivers/gpu/drm/radeon/rv770d.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/radeon/rv770d.h 2011-01-07 14:22:17.000000000 +0100 -@@ -138,6 +138,7 @@ - #define MC_SHARED_CHMAP 0x2004 - #define NOOFCHAN_SHIFT 12 - #define NOOFCHAN_MASK 0x00003000 -+#define MC_SHARED_CHREMAP 0x2008 - - #define MC_ARB_RAMCFG 0x2760 - #define NOOFBANK_SHIFT 0 -@@ -303,6 +304,7 @@ - #define BILINEAR_PRECISION_8_BIT (1 << 31) - - #define TCP_CNTL 0x9610 -+#define TCP_CHAN_STEER 0x9614 - - #define VGT_CACHE_INVALIDATION 0x88C4 - #define CACHE_INVALIDATION(x) ((x)<<0) -@@ -351,4 +353,11 @@ - - #define SRBM_STATUS 0x0E50 - -+#define D1GRPH_PRIMARY_SURFACE_ADDRESS 0x6110 -+#define D1GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6914 -+#define D2GRPH_PRIMARY_SURFACE_ADDRESS_HIGH 0x6114 -+#define D1GRPH_SECONDARY_SURFACE_ADDRESS 0x6118 -+#define D1GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x691c -+#define D2GRPH_SECONDARY_SURFACE_ADDRESS_HIGH 0x611c -+ - #endif -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_bo.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_bo.c ---- linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_bo.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_bo.c 2011-01-07 14:22:17.000000000 +0100 -@@ -169,7 +169,7 @@ - } - EXPORT_SYMBOL(ttm_bo_wait_unreserved); - --static void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) -+void ttm_bo_add_to_lru(struct ttm_buffer_object *bo) - { - struct ttm_bo_device *bdev = bo->bdev; - struct ttm_mem_type_manager *man; -@@ -191,11 +191,7 @@ - } - } - --/** -- * Call with the lru_lock held. -- */ -- --static int ttm_bo_del_from_lru(struct ttm_buffer_object *bo) -+int ttm_bo_del_from_lru(struct ttm_buffer_object *bo) - { - int put_count = 0; - -@@ -227,9 +223,18 @@ - /** - * Deadlock avoidance for multi-bo reserving. - */ -- if (use_sequence && bo->seq_valid && -- (sequence - bo->val_seq < (1 << 31))) { -- return -EAGAIN; -+ if (use_sequence && bo->seq_valid) { -+ /** -+ * We've already reserved this one. -+ */ -+ if (unlikely(sequence == bo->val_seq)) -+ return -EDEADLK; -+ /** -+ * Already reserved by a thread that will not back -+ * off for us. We need to back off. -+ */ -+ if (unlikely(sequence - bo->val_seq < (1 << 31))) -+ return -EAGAIN; - } - - if (no_wait) -@@ -267,6 +272,13 @@ - BUG(); - } - -+void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, -+ bool never_free) -+{ -+ kref_sub(&bo->list_kref, count, -+ (never_free) ? ttm_bo_ref_bug : ttm_bo_release_list); -+} -+ - int ttm_bo_reserve(struct ttm_buffer_object *bo, - bool interruptible, - bool no_wait, bool use_sequence, uint32_t sequence) -@@ -282,20 +294,24 @@ - put_count = ttm_bo_del_from_lru(bo); - spin_unlock(&glob->lru_lock); - -- while (put_count--) -- kref_put(&bo->list_kref, ttm_bo_ref_bug); -+ ttm_bo_list_ref_sub(bo, put_count, true); - - return ret; - } - -+void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo) -+{ -+ ttm_bo_add_to_lru(bo); -+ atomic_set(&bo->reserved, 0); -+ wake_up_all(&bo->event_queue); -+} -+ - void ttm_bo_unreserve(struct ttm_buffer_object *bo) - { - struct ttm_bo_global *glob = bo->glob; - - spin_lock(&glob->lru_lock); -- ttm_bo_add_to_lru(bo); -- atomic_set(&bo->reserved, 0); -- wake_up_all(&bo->event_queue); -+ ttm_bo_unreserve_locked(bo); - spin_unlock(&glob->lru_lock); - } - EXPORT_SYMBOL(ttm_bo_unreserve); -@@ -362,8 +378,13 @@ - int ret = 0; - - if (old_is_pci || new_is_pci || -- ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) -- ttm_bo_unmap_virtual(bo); -+ ((mem->placement & bo->mem.placement & TTM_PL_MASK_CACHING) == 0)) { -+ ret = ttm_mem_io_lock(old_man, true); -+ if (unlikely(ret != 0)) -+ goto out_err; -+ ttm_bo_unmap_virtual_locked(bo); -+ ttm_mem_io_unlock(old_man); -+ } - - /* - * Create and bind a ttm if required. -@@ -416,11 +437,9 @@ - } - - if (bo->mem.mm_node) { -- spin_lock(&bo->lock); - bo->offset = (bo->mem.start << PAGE_SHIFT) + - bdev->man[bo->mem.mem_type].gpu_offset; - bo->cur_placement = bo->mem.placement; -- spin_unlock(&bo->lock); - } else - bo->offset = 0; - -@@ -452,7 +471,6 @@ - ttm_tt_destroy(bo->ttm); - bo->ttm = NULL; - } -- - ttm_bo_mem_put(bo, &bo->mem); - - atomic_set(&bo->reserved, 0); -@@ -474,14 +492,14 @@ - int put_count; - int ret; - -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - (void) ttm_bo_wait(bo, false, false, true); - if (!bo->sync_obj) { - - spin_lock(&glob->lru_lock); - - /** -- * Lock inversion between bo::reserve and bo::lock here, -+ * Lock inversion between bo:reserve and bdev::fence_lock here, - * but that's OK, since we're only trylocking. - */ - -@@ -490,14 +508,13 @@ - if (unlikely(ret == -EBUSY)) - goto queue; - -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - put_count = ttm_bo_del_from_lru(bo); - - spin_unlock(&glob->lru_lock); - ttm_bo_cleanup_memtype_use(bo); - -- while (put_count--) -- kref_put(&bo->list_kref, ttm_bo_ref_bug); -+ ttm_bo_list_ref_sub(bo, put_count, true); - - return; - } else { -@@ -512,7 +529,7 @@ - kref_get(&bo->list_kref); - list_add_tail(&bo->ddestroy, &bdev->ddestroy); - spin_unlock(&glob->lru_lock); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - - if (sync_obj) { - driver->sync_obj_flush(sync_obj, sync_obj_arg); -@@ -537,14 +554,15 @@ - bool no_wait_reserve, - bool no_wait_gpu) - { -+ struct ttm_bo_device *bdev = bo->bdev; - struct ttm_bo_global *glob = bo->glob; - int put_count; - int ret = 0; - - retry: -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - - if (unlikely(ret != 0)) - return ret; -@@ -580,8 +598,7 @@ - spin_unlock(&glob->lru_lock); - ttm_bo_cleanup_memtype_use(bo); - -- while (put_count--) -- kref_put(&bo->list_kref, ttm_bo_ref_bug); -+ ttm_bo_list_ref_sub(bo, put_count, true); - - return 0; - } -@@ -652,6 +669,7 @@ - struct ttm_buffer_object *bo = - container_of(kref, struct ttm_buffer_object, kref); - struct ttm_bo_device *bdev = bo->bdev; -+ struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; - - if (likely(bo->vm_node != NULL)) { - rb_erase(&bo->vm_rb, &bdev->addr_space_rb); -@@ -659,6 +677,9 @@ - bo->vm_node = NULL; - } - write_unlock(&bdev->vm_lock); -+ ttm_mem_io_lock(man, false); -+ ttm_mem_io_free_vm(bo); -+ ttm_mem_io_unlock(man); - ttm_bo_cleanup_refs_or_queue(bo); - kref_put(&bo->list_kref, ttm_bo_release_list); - write_lock(&bdev->vm_lock); -@@ -698,9 +719,9 @@ - struct ttm_placement placement; - int ret = 0; - -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - - if (unlikely(ret != 0)) { - if (ret != -ERESTARTSYS) { -@@ -715,7 +736,8 @@ - - evict_mem = bo->mem; - evict_mem.mm_node = NULL; -- evict_mem.bus.io_reserved = false; -+ evict_mem.bus.io_reserved_vm = false; -+ evict_mem.bus.io_reserved_count = 0; - - placement.fpfn = 0; - placement.lpfn = 0; -@@ -802,8 +824,7 @@ - - BUG_ON(ret != 0); - -- while (put_count--) -- kref_put(&bo->list_kref, ttm_bo_ref_bug); -+ ttm_bo_list_ref_sub(bo, put_count, true); - - ret = ttm_bo_evict(bo, interruptible, no_wait_reserve, no_wait_gpu); - ttm_bo_unreserve(bo); -@@ -1036,6 +1057,7 @@ - { - int ret = 0; - struct ttm_mem_reg mem; -+ struct ttm_bo_device *bdev = bo->bdev; - - BUG_ON(!atomic_read(&bo->reserved)); - -@@ -1044,15 +1066,16 @@ - * Have the driver move function wait for idle when necessary, - * instead of doing it here. - */ -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, interruptible, no_wait_gpu); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - if (ret) - return ret; - mem.num_pages = bo->num_pages; - mem.size = mem.num_pages << PAGE_SHIFT; - mem.page_alignment = bo->mem.page_alignment; -- mem.bus.io_reserved = false; -+ mem.bus.io_reserved_vm = false; -+ mem.bus.io_reserved_count = 0; - /* - * Determine where to move the buffer. - */ -@@ -1163,7 +1186,6 @@ - } - bo->destroy = destroy; - -- spin_lock_init(&bo->lock); - kref_init(&bo->kref); - kref_init(&bo->list_kref); - atomic_set(&bo->cpu_writers, 0); -@@ -1172,6 +1194,7 @@ - INIT_LIST_HEAD(&bo->lru); - INIT_LIST_HEAD(&bo->ddestroy); - INIT_LIST_HEAD(&bo->swap); -+ INIT_LIST_HEAD(&bo->io_reserve_lru); - bo->bdev = bdev; - bo->glob = bdev->glob; - bo->type = type; -@@ -1181,7 +1204,8 @@ - bo->mem.num_pages = bo->num_pages; - bo->mem.mm_node = NULL; - bo->mem.page_alignment = page_alignment; -- bo->mem.bus.io_reserved = false; -+ bo->mem.bus.io_reserved_vm = false; -+ bo->mem.bus.io_reserved_count = 0; - bo->buffer_start = buffer_start & PAGE_MASK; - bo->priv_flags = 0; - bo->mem.placement = (TTM_PL_FLAG_SYSTEM | TTM_PL_FLAG_CACHED); -@@ -1355,6 +1379,10 @@ - BUG_ON(type >= TTM_NUM_MEM_TYPES); - man = &bdev->man[type]; - BUG_ON(man->has_type); -+ man->io_reserve_fastpath = true; -+ man->use_io_reserve_lru = false; -+ mutex_init(&man->io_reserve_mutex); -+ INIT_LIST_HEAD(&man->io_reserve_lru); - - ret = bdev->driver->init_mem_type(bdev, type, man); - if (ret) -@@ -1527,7 +1555,8 @@ - bdev->dev_mapping = NULL; - bdev->glob = glob; - bdev->need_dma32 = need_dma32; -- -+ bdev->val_seq = 0; -+ spin_lock_init(&bdev->fence_lock); - mutex_lock(&glob->device_list_mutex); - list_add_tail(&bdev->device_list, &glob->device_list); - mutex_unlock(&glob->device_list_mutex); -@@ -1561,7 +1590,7 @@ - return true; - } - --void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) -+void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo) - { - struct ttm_bo_device *bdev = bo->bdev; - loff_t offset = (loff_t) bo->addr_space_offset; -@@ -1570,8 +1599,20 @@ - if (!bdev->dev_mapping) - return; - unmap_mapping_range(bdev->dev_mapping, offset, holelen, 1); -- ttm_mem_io_free(bdev, &bo->mem); -+ ttm_mem_io_free_vm(bo); -+} -+ -+void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo) -+{ -+ struct ttm_bo_device *bdev = bo->bdev; -+ struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; -+ -+ ttm_mem_io_lock(man, false); -+ ttm_bo_unmap_virtual_locked(bo); -+ ttm_mem_io_unlock(man); - } -+ -+ - EXPORT_SYMBOL(ttm_bo_unmap_virtual); - - static void ttm_bo_vm_insert_rb(struct ttm_buffer_object *bo) -@@ -1651,6 +1692,7 @@ - bool lazy, bool interruptible, bool no_wait) - { - struct ttm_bo_driver *driver = bo->bdev->driver; -+ struct ttm_bo_device *bdev = bo->bdev; - void *sync_obj; - void *sync_obj_arg; - int ret = 0; -@@ -1664,9 +1706,9 @@ - void *tmp_obj = bo->sync_obj; - bo->sync_obj = NULL; - clear_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - driver->sync_obj_unref(&tmp_obj); -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - continue; - } - -@@ -1675,29 +1717,29 @@ - - sync_obj = driver->sync_obj_ref(bo->sync_obj); - sync_obj_arg = bo->sync_obj_arg; -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - ret = driver->sync_obj_wait(sync_obj, sync_obj_arg, - lazy, interruptible); - if (unlikely(ret != 0)) { - driver->sync_obj_unref(&sync_obj); -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - return ret; - } -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - if (likely(bo->sync_obj == sync_obj && - bo->sync_obj_arg == sync_obj_arg)) { - void *tmp_obj = bo->sync_obj; - bo->sync_obj = NULL; - clear_bit(TTM_BO_PRIV_FLAG_MOVING, - &bo->priv_flags); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - driver->sync_obj_unref(&sync_obj); - driver->sync_obj_unref(&tmp_obj); -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - } else { -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - driver->sync_obj_unref(&sync_obj); -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - } - } - return 0; -@@ -1706,6 +1748,7 @@ - - int ttm_bo_synccpu_write_grab(struct ttm_buffer_object *bo, bool no_wait) - { -+ struct ttm_bo_device *bdev = bo->bdev; - int ret = 0; - - /* -@@ -1715,9 +1758,9 @@ - ret = ttm_bo_reserve(bo, true, no_wait, false, 0); - if (unlikely(ret != 0)) - return ret; -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - ret = ttm_bo_wait(bo, false, true, no_wait); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - if (likely(ret == 0)) - atomic_inc(&bo->cpu_writers); - ttm_bo_unreserve(bo); -@@ -1783,16 +1826,15 @@ - put_count = ttm_bo_del_from_lru(bo); - spin_unlock(&glob->lru_lock); - -- while (put_count--) -- kref_put(&bo->list_kref, ttm_bo_ref_bug); -+ ttm_bo_list_ref_sub(bo, put_count, true); - - /** - * Wait for GPU, then move to system cached. - */ - -- spin_lock(&bo->lock); -+ spin_lock(&bo->bdev->fence_lock); - ret = ttm_bo_wait(bo, false, false, false); -- spin_unlock(&bo->lock); -+ spin_unlock(&bo->bdev->fence_lock); - - if (unlikely(ret != 0)) - goto out; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_bo_util.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_bo_util.c ---- linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_bo_util.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_bo_util.c 2011-01-07 14:22:17.000000000 +0100 -@@ -75,37 +75,123 @@ - } - EXPORT_SYMBOL(ttm_bo_move_ttm); - --int ttm_mem_io_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) -+int ttm_mem_io_lock(struct ttm_mem_type_manager *man, bool interruptible) - { -- int ret; -+ if (likely(man->io_reserve_fastpath)) -+ return 0; -+ -+ if (interruptible) -+ return mutex_lock_interruptible(&man->io_reserve_mutex); -+ -+ mutex_lock(&man->io_reserve_mutex); -+ return 0; -+} - -- if (!mem->bus.io_reserved) { -- mem->bus.io_reserved = true; -+void ttm_mem_io_unlock(struct ttm_mem_type_manager *man) -+{ -+ if (likely(man->io_reserve_fastpath)) -+ return; -+ -+ mutex_unlock(&man->io_reserve_mutex); -+} -+ -+static int ttm_mem_io_evict(struct ttm_mem_type_manager *man) -+{ -+ struct ttm_buffer_object *bo; -+ -+ if (!man->use_io_reserve_lru || list_empty(&man->io_reserve_lru)) -+ return -EAGAIN; -+ -+ bo = list_first_entry(&man->io_reserve_lru, -+ struct ttm_buffer_object, -+ io_reserve_lru); -+ list_del_init(&bo->io_reserve_lru); -+ ttm_bo_unmap_virtual_locked(bo); -+ -+ return 0; -+} -+ -+static int ttm_mem_io_reserve(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem) -+{ -+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; -+ int ret = 0; -+ -+ if (!bdev->driver->io_mem_reserve) -+ return 0; -+ if (likely(man->io_reserve_fastpath)) -+ return bdev->driver->io_mem_reserve(bdev, mem); -+ -+ if (bdev->driver->io_mem_reserve && -+ mem->bus.io_reserved_count++ == 0) { -+retry: - ret = bdev->driver->io_mem_reserve(bdev, mem); -+ if (ret == -EAGAIN) { -+ ret = ttm_mem_io_evict(man); -+ if (ret == 0) -+ goto retry; -+ } -+ } -+ return ret; -+} -+ -+static void ttm_mem_io_free(struct ttm_bo_device *bdev, -+ struct ttm_mem_reg *mem) -+{ -+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; -+ -+ if (likely(man->io_reserve_fastpath)) -+ return; -+ -+ if (bdev->driver->io_mem_reserve && -+ --mem->bus.io_reserved_count == 0 && -+ bdev->driver->io_mem_free) -+ bdev->driver->io_mem_free(bdev, mem); -+ -+} -+ -+int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo) -+{ -+ struct ttm_mem_reg *mem = &bo->mem; -+ int ret; -+ -+ if (!mem->bus.io_reserved_vm) { -+ struct ttm_mem_type_manager *man = -+ &bo->bdev->man[mem->mem_type]; -+ -+ ret = ttm_mem_io_reserve(bo->bdev, mem); - if (unlikely(ret != 0)) - return ret; -+ mem->bus.io_reserved_vm = true; -+ if (man->use_io_reserve_lru) -+ list_add_tail(&bo->io_reserve_lru, -+ &man->io_reserve_lru); - } - return 0; - } - --void ttm_mem_io_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) -+void ttm_mem_io_free_vm(struct ttm_buffer_object *bo) - { -- if (bdev->driver->io_mem_reserve) { -- if (mem->bus.io_reserved) { -- mem->bus.io_reserved = false; -- bdev->driver->io_mem_free(bdev, mem); -- } -+ struct ttm_mem_reg *mem = &bo->mem; -+ -+ if (mem->bus.io_reserved_vm) { -+ mem->bus.io_reserved_vm = false; -+ list_del_init(&bo->io_reserve_lru); -+ ttm_mem_io_free(bo->bdev, mem); - } - } - - int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem, - void **virtual) - { -+ struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; - int ret; - void *addr; - - *virtual = NULL; -+ (void) ttm_mem_io_lock(man, false); - ret = ttm_mem_io_reserve(bdev, mem); -+ ttm_mem_io_unlock(man); - if (ret || !mem->bus.is_iomem) - return ret; - -@@ -117,7 +203,9 @@ - else - addr = ioremap_nocache(mem->bus.base + mem->bus.offset, mem->bus.size); - if (!addr) { -+ (void) ttm_mem_io_lock(man, false); - ttm_mem_io_free(bdev, mem); -+ ttm_mem_io_unlock(man); - return -ENOMEM; - } - } -@@ -134,7 +222,9 @@ - - if (virtual && mem->bus.addr == NULL) - iounmap(virtual); -+ (void) ttm_mem_io_lock(man, false); - ttm_mem_io_free(bdev, mem); -+ ttm_mem_io_unlock(man); - } - - static int ttm_copy_io_page(void *dst, void *src, unsigned long page) -@@ -231,7 +321,7 @@ - struct ttm_mem_type_manager *man = &bdev->man[new_mem->mem_type]; - struct ttm_tt *ttm = bo->ttm; - struct ttm_mem_reg *old_mem = &bo->mem; -- struct ttm_mem_reg old_copy = *old_mem; -+ struct ttm_mem_reg old_copy; - void *old_iomap; - void *new_iomap; - int ret; -@@ -280,8 +370,7 @@ - } - mb(); - out2: -- ttm_bo_free_old_node(bo); -- -+ old_copy = *old_mem; - *old_mem = *new_mem; - new_mem->mm_node = NULL; - -@@ -292,9 +381,10 @@ - } - - out1: -- ttm_mem_reg_iounmap(bdev, new_mem, new_iomap); -+ ttm_mem_reg_iounmap(bdev, old_mem, new_iomap); - out: - ttm_mem_reg_iounmap(bdev, &old_copy, old_iomap); -+ ttm_bo_mem_put(bo, &old_copy); - return ret; - } - EXPORT_SYMBOL(ttm_bo_move_memcpy); -@@ -337,11 +427,11 @@ - * TODO: Explicit member copy would probably be better here. - */ - -- spin_lock_init(&fbo->lock); - init_waitqueue_head(&fbo->event_queue); - INIT_LIST_HEAD(&fbo->ddestroy); - INIT_LIST_HEAD(&fbo->lru); - INIT_LIST_HEAD(&fbo->swap); -+ INIT_LIST_HEAD(&fbo->io_reserve_lru); - fbo->vm_node = NULL; - atomic_set(&fbo->cpu_writers, 0); - -@@ -453,6 +543,8 @@ - unsigned long start_page, unsigned long num_pages, - struct ttm_bo_kmap_obj *map) - { -+ struct ttm_mem_type_manager *man = -+ &bo->bdev->man[bo->mem.mem_type]; - unsigned long offset, size; - int ret; - -@@ -467,7 +559,9 @@ - if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC)) - return -EPERM; - #endif -+ (void) ttm_mem_io_lock(man, false); - ret = ttm_mem_io_reserve(bo->bdev, &bo->mem); -+ ttm_mem_io_unlock(man); - if (ret) - return ret; - if (!bo->mem.bus.is_iomem) { -@@ -482,12 +576,15 @@ - - void ttm_bo_kunmap(struct ttm_bo_kmap_obj *map) - { -+ struct ttm_buffer_object *bo = map->bo; -+ struct ttm_mem_type_manager *man = -+ &bo->bdev->man[bo->mem.mem_type]; -+ - if (!map->virtual) - return; - switch (map->bo_kmap_type) { - case ttm_bo_map_iomap: - iounmap(map->virtual); -- ttm_mem_io_free(map->bo->bdev, &map->bo->mem); - break; - case ttm_bo_map_vmap: - vunmap(map->virtual); -@@ -500,6 +597,9 @@ - default: - BUG(); - } -+ (void) ttm_mem_io_lock(man, false); -+ ttm_mem_io_free(map->bo->bdev, &map->bo->mem); -+ ttm_mem_io_unlock(man); - map->virtual = NULL; - map->page = NULL; - } -@@ -520,7 +620,7 @@ - struct ttm_buffer_object *ghost_obj; - void *tmp_obj = NULL; - -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - if (bo->sync_obj) { - tmp_obj = bo->sync_obj; - bo->sync_obj = NULL; -@@ -529,7 +629,7 @@ - bo->sync_obj_arg = sync_obj_arg; - if (evict) { - ret = ttm_bo_wait(bo, false, false, false); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - if (tmp_obj) - driver->sync_obj_unref(&tmp_obj); - if (ret) -@@ -552,7 +652,7 @@ - */ - - set_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - if (tmp_obj) - driver->sync_obj_unref(&tmp_obj); - -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_bo_vm.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_bo_vm.c ---- linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_bo_vm.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_bo_vm.c 2011-01-07 14:22:17.000000000 +0100 -@@ -83,6 +83,8 @@ - int i; - unsigned long address = (unsigned long)vmf->virtual_address; - int retval = VM_FAULT_NOPAGE; -+ struct ttm_mem_type_manager *man = -+ &bdev->man[bo->mem.mem_type]; - - /* - * Work around locking order reversal in fault / nopfn -@@ -118,24 +120,28 @@ - * move. - */ - -- spin_lock(&bo->lock); -+ spin_lock(&bdev->fence_lock); - if (test_bit(TTM_BO_PRIV_FLAG_MOVING, &bo->priv_flags)) { - ret = ttm_bo_wait(bo, false, true, false); -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - if (unlikely(ret != 0)) { - retval = (ret != -ERESTARTSYS) ? - VM_FAULT_SIGBUS : VM_FAULT_NOPAGE; - goto out_unlock; - } - } else -- spin_unlock(&bo->lock); -+ spin_unlock(&bdev->fence_lock); - -- -- ret = ttm_mem_io_reserve(bdev, &bo->mem); -- if (ret) { -- retval = VM_FAULT_SIGBUS; -+ ret = ttm_mem_io_lock(man, true); -+ if (unlikely(ret != 0)) { -+ retval = VM_FAULT_NOPAGE; - goto out_unlock; - } -+ ret = ttm_mem_io_reserve_vm(bo); -+ if (unlikely(ret != 0)) { -+ retval = VM_FAULT_SIGBUS; -+ goto out_io_unlock; -+ } - - page_offset = ((address - vma->vm_start) >> PAGE_SHIFT) + - bo->vm_node->start - vma->vm_pgoff; -@@ -144,7 +150,7 @@ - - if (unlikely(page_offset >= bo->num_pages)) { - retval = VM_FAULT_SIGBUS; -- goto out_unlock; -+ goto out_io_unlock; - } - - /* -@@ -182,7 +188,7 @@ - page = ttm_tt_get_page(ttm, page_offset); - if (unlikely(!page && i == 0)) { - retval = VM_FAULT_OOM; -- goto out_unlock; -+ goto out_io_unlock; - } else if (unlikely(!page)) { - break; - } -@@ -200,14 +206,15 @@ - else if (unlikely(ret != 0)) { - retval = - (ret == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS; -- goto out_unlock; -+ goto out_io_unlock; - } - - address += PAGE_SIZE; - if (unlikely(++page_offset >= page_last)) - break; - } -- -+out_io_unlock: -+ ttm_mem_io_unlock(man); - out_unlock: - ttm_bo_unreserve(bo); - return retval; -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_execbuf_util.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_execbuf_util.c ---- linux-2.6.37-rc3/drivers/gpu/drm/ttm/ttm_execbuf_util.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/ttm/ttm_execbuf_util.c 2011-01-07 14:22:17.000000000 +0100 -@@ -32,7 +32,7 @@ - #include - #include - --void ttm_eu_backoff_reservation(struct list_head *list) -+static void ttm_eu_backoff_reservation_locked(struct list_head *list) - { - struct ttm_validate_buffer *entry; - -@@ -41,10 +41,77 @@ - if (!entry->reserved) - continue; - -+ if (entry->removed) { -+ ttm_bo_add_to_lru(bo); -+ entry->removed = false; -+ -+ } - entry->reserved = false; -- ttm_bo_unreserve(bo); -+ atomic_set(&bo->reserved, 0); -+ wake_up_all(&bo->event_queue); -+ } -+} -+ -+static void ttm_eu_del_from_lru_locked(struct list_head *list) -+{ -+ struct ttm_validate_buffer *entry; -+ -+ list_for_each_entry(entry, list, head) { -+ struct ttm_buffer_object *bo = entry->bo; -+ if (!entry->reserved) -+ continue; -+ -+ if (!entry->removed) { -+ entry->put_count = ttm_bo_del_from_lru(bo); -+ entry->removed = true; -+ } -+ } -+} -+ -+static void ttm_eu_list_ref_sub(struct list_head *list) -+{ -+ struct ttm_validate_buffer *entry; -+ -+ list_for_each_entry(entry, list, head) { -+ struct ttm_buffer_object *bo = entry->bo; -+ -+ if (entry->put_count) { -+ ttm_bo_list_ref_sub(bo, entry->put_count, true); -+ entry->put_count = 0; -+ } - } - } -+ -+static int ttm_eu_wait_unreserved_locked(struct list_head *list, -+ struct ttm_buffer_object *bo) -+{ -+ struct ttm_bo_global *glob = bo->glob; -+ int ret; -+ -+ ttm_eu_del_from_lru_locked(list); -+ spin_unlock(&glob->lru_lock); -+ ret = ttm_bo_wait_unreserved(bo, true); -+ spin_lock(&glob->lru_lock); -+ if (unlikely(ret != 0)) -+ ttm_eu_backoff_reservation_locked(list); -+ return ret; -+} -+ -+ -+void ttm_eu_backoff_reservation(struct list_head *list) -+{ -+ struct ttm_validate_buffer *entry; -+ struct ttm_bo_global *glob; -+ -+ if (list_empty(list)) -+ return; -+ -+ entry = list_first_entry(list, struct ttm_validate_buffer, head); -+ glob = entry->bo->glob; -+ spin_lock(&glob->lru_lock); -+ ttm_eu_backoff_reservation_locked(list); -+ spin_unlock(&glob->lru_lock); -+} - EXPORT_SYMBOL(ttm_eu_backoff_reservation); - - /* -@@ -59,37 +126,76 @@ - * buffers in different orders. - */ - --int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq) -+int ttm_eu_reserve_buffers(struct list_head *list) - { -+ struct ttm_bo_global *glob; - struct ttm_validate_buffer *entry; - int ret; -+ uint32_t val_seq; -+ -+ if (list_empty(list)) -+ return 0; -+ -+ list_for_each_entry(entry, list, head) { -+ entry->reserved = false; -+ entry->put_count = 0; -+ entry->removed = false; -+ } -+ -+ entry = list_first_entry(list, struct ttm_validate_buffer, head); -+ glob = entry->bo->glob; - - retry: -+ spin_lock(&glob->lru_lock); -+ val_seq = entry->bo->bdev->val_seq++; -+ - list_for_each_entry(entry, list, head) { - struct ttm_buffer_object *bo = entry->bo; - -- entry->reserved = false; -- ret = ttm_bo_reserve(bo, true, false, true, val_seq); -- if (ret != 0) { -- ttm_eu_backoff_reservation(list); -- if (ret == -EAGAIN) { -- ret = ttm_bo_wait_unreserved(bo, true); -- if (unlikely(ret != 0)) -- return ret; -- goto retry; -- } else -+retry_this_bo: -+ ret = ttm_bo_reserve_locked(bo, true, true, true, val_seq); -+ switch (ret) { -+ case 0: -+ break; -+ case -EBUSY: -+ ret = ttm_eu_wait_unreserved_locked(list, bo); -+ if (unlikely(ret != 0)) { -+ spin_unlock(&glob->lru_lock); -+ ttm_eu_list_ref_sub(list); - return ret; -+ } -+ goto retry_this_bo; -+ case -EAGAIN: -+ ttm_eu_backoff_reservation_locked(list); -+ spin_unlock(&glob->lru_lock); -+ ttm_eu_list_ref_sub(list); -+ ret = ttm_bo_wait_unreserved(bo, true); -+ if (unlikely(ret != 0)) -+ return ret; -+ goto retry; -+ default: -+ ttm_eu_backoff_reservation_locked(list); -+ spin_unlock(&glob->lru_lock); -+ ttm_eu_list_ref_sub(list); -+ return ret; - } - - entry->reserved = true; - if (unlikely(atomic_read(&bo->cpu_writers) > 0)) { -- ttm_eu_backoff_reservation(list); -+ ttm_eu_backoff_reservation_locked(list); -+ spin_unlock(&glob->lru_lock); -+ ttm_eu_list_ref_sub(list); - ret = ttm_bo_wait_cpu(bo, false); - if (ret) - return ret; - goto retry; - } - } -+ -+ ttm_eu_del_from_lru_locked(list); -+ spin_unlock(&glob->lru_lock); -+ ttm_eu_list_ref_sub(list); -+ - return 0; - } - EXPORT_SYMBOL(ttm_eu_reserve_buffers); -@@ -97,21 +203,36 @@ - void ttm_eu_fence_buffer_objects(struct list_head *list, void *sync_obj) - { - struct ttm_validate_buffer *entry; -+ struct ttm_buffer_object *bo; -+ struct ttm_bo_global *glob; -+ struct ttm_bo_device *bdev; -+ struct ttm_bo_driver *driver; -+ -+ if (list_empty(list)) -+ return; -+ -+ bo = list_first_entry(list, struct ttm_validate_buffer, head)->bo; -+ bdev = bo->bdev; -+ driver = bdev->driver; -+ glob = bo->glob; - -- list_for_each_entry(entry, list, head) { -- struct ttm_buffer_object *bo = entry->bo; -- struct ttm_bo_driver *driver = bo->bdev->driver; -- void *old_sync_obj; -+ spin_lock(&bdev->fence_lock); -+ spin_lock(&glob->lru_lock); - -- spin_lock(&bo->lock); -- old_sync_obj = bo->sync_obj; -+ list_for_each_entry(entry, list, head) { -+ bo = entry->bo; -+ entry->old_sync_obj = bo->sync_obj; - bo->sync_obj = driver->sync_obj_ref(sync_obj); - bo->sync_obj_arg = entry->new_sync_obj_arg; -- spin_unlock(&bo->lock); -- ttm_bo_unreserve(bo); -+ ttm_bo_unreserve_locked(bo); - entry->reserved = false; -- if (old_sync_obj) -- driver->sync_obj_unref(&old_sync_obj); -+ } -+ spin_unlock(&glob->lru_lock); -+ spin_unlock(&bdev->fence_lock); -+ -+ list_for_each_entry(entry, list, head) { -+ if (entry->old_sync_obj) -+ driver->sync_obj_unref(&entry->old_sync_obj); - } - } - EXPORT_SYMBOL(ttm_eu_fence_buffer_objects); -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h ---- linux-2.6.37-rc3/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h 2011-01-07 14:22:17.000000000 +0100 -@@ -264,7 +264,6 @@ - */ - - struct vmw_sw_context ctx; -- uint32_t val_seq; - struct mutex cmdbuf_mutex; - - /** -diff -Naur linux-2.6.37-rc3/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c ---- linux-2.6.37-rc3/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c 2011-01-07 14:22:17.000000000 +0100 -@@ -653,8 +653,7 @@ - ret = vmw_cmd_check_all(dev_priv, sw_context, cmd, arg->command_size); - if (unlikely(ret != 0)) - goto out_err; -- ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes, -- dev_priv->val_seq++); -+ ret = ttm_eu_reserve_buffers(&sw_context->validate_nodes); - if (unlikely(ret != 0)) - goto out_err; - -diff -Naur linux-2.6.37-rc3/include/drm/drm_crtc.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/drm_crtc.h ---- linux-2.6.37-rc3/include/drm/drm_crtc.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/drm_crtc.h 2011-01-07 14:22:17.000000000 +0100 -@@ -351,8 +351,14 @@ - - bool enabled; - -+ /* Requested mode from modesetting. */ - struct drm_display_mode mode; - -+ /* Programmed mode in hw, after adjustments for encoders, -+ * crtc, panel scaling etc. Needed for timestamping etc. -+ */ -+ struct drm_display_mode hwmode; -+ - int x, y; - const struct drm_crtc_funcs *funcs; - -@@ -360,6 +366,9 @@ - uint32_t gamma_size; - uint16_t *gamma_store; - -+ /* Constants needed for precise vblank and swap timestamping. */ -+ s64 framedur_ns, linedur_ns, pixeldur_ns; -+ - /* if you are using the helper */ - void *helper_private; - }; -diff -Naur linux-2.6.37-rc3/include/drm/drm_pciids.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/drm_pciids.h ---- linux-2.6.37-rc3/include/drm/drm_pciids.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/drm_pciids.h 2011-01-07 14:22:17.000000000 +0100 -@@ -419,6 +419,10 @@ - {0x1002, 0x9713, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ - {0x1002, 0x9714, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ - {0x1002, 0x9715, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS880|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9802, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9803, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9804, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ -+ {0x1002, 0x9805, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_PALM|RADEON_NEW_MEMMAP|RADEON_IS_IGP}, \ - {0, 0, 0} - - #define r128_PCI_IDS \ -diff -Naur linux-2.6.37-rc3/include/drm/drmP.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/drmP.h ---- linux-2.6.37-rc3/include/drm/drmP.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/drmP.h 2011-01-07 14:22:17.000000000 +0100 -@@ -683,6 +683,21 @@ - void *driver_priv; /**< Private structure for driver to use */ - }; - -+/* Size of ringbuffer for vblank timestamps. Just double-buffer -+ * in initial implementation. -+ */ -+#define DRM_VBLANKTIME_RBSIZE 2 -+ -+/* Flags and return codes for get_vblank_timestamp() driver function. */ -+#define DRM_CALLED_FROM_VBLIRQ 1 -+#define DRM_VBLANKTIME_SCANOUTPOS_METHOD (1 << 0) -+#define DRM_VBLANKTIME_INVBL (1 << 1) -+ -+/* get_scanout_position() return flags */ -+#define DRM_SCANOUTPOS_VALID (1 << 0) -+#define DRM_SCANOUTPOS_INVBL (1 << 1) -+#define DRM_SCANOUTPOS_ACCURATE (1 << 2) -+ - /** - * DRM driver structure. This structure represent the common code for - * a family of cards. There will one drm_device for each card present -@@ -760,6 +775,68 @@ - */ - int (*device_is_agp) (struct drm_device *dev); - -+ /** -+ * Called by vblank timestamping code. -+ * -+ * Return the current display scanout position from a crtc. -+ * -+ * \param dev DRM device. -+ * \param crtc Id of the crtc to query. -+ * \param *vpos Target location for current vertical scanout position. -+ * \param *hpos Target location for current horizontal scanout position. -+ * -+ * Returns vpos as a positive number while in active scanout area. -+ * Returns vpos as a negative number inside vblank, counting the number -+ * of scanlines to go until end of vblank, e.g., -1 means "one scanline -+ * until start of active scanout / end of vblank." -+ * -+ * \return Flags, or'ed together as follows: -+ * -+ * DRM_SCANOUTPOS_VALID = Query successfull. -+ * DRM_SCANOUTPOS_INVBL = Inside vblank. -+ * DRM_SCANOUTPOS_ACCURATE = Returned position is accurate. A lack of -+ * this flag means that returned position may be offset by a constant -+ * but unknown small number of scanlines wrt. real scanout position. -+ * -+ */ -+ int (*get_scanout_position) (struct drm_device *dev, int crtc, -+ int *vpos, int *hpos); -+ -+ /** -+ * Called by \c drm_get_last_vbltimestamp. Should return a precise -+ * timestamp when the most recent VBLANK interval ended or will end. -+ * -+ * Specifically, the timestamp in @vblank_time should correspond as -+ * closely as possible to the time when the first video scanline of -+ * the video frame after the end of VBLANK will start scanning out, -+ * the time immmediately after end of the VBLANK interval. If the -+ * @crtc is currently inside VBLANK, this will be a time in the future. -+ * If the @crtc is currently scanning out a frame, this will be the -+ * past start time of the current scanout. This is meant to adhere -+ * to the OpenML OML_sync_control extension specification. -+ * -+ * \param dev dev DRM device handle. -+ * \param crtc crtc for which timestamp should be returned. -+ * \param *max_error Maximum allowable timestamp error in nanoseconds. -+ * Implementation should strive to provide timestamp -+ * with an error of at most *max_error nanoseconds. -+ * Returns true upper bound on error for timestamp. -+ * \param *vblank_time Target location for returned vblank timestamp. -+ * \param flags 0 = Defaults, no special treatment needed. -+ * \param DRM_CALLED_FROM_VBLIRQ = Function is called from vblank -+ * irq handler. Some drivers need to apply some workarounds -+ * for gpu-specific vblank irq quirks if flag is set. -+ * -+ * \returns -+ * Zero if timestamping isn't supported in current display mode or a -+ * negative number on failure. A positive status code on success, -+ * which describes how the vblank_time timestamp was computed. -+ */ -+ int (*get_vblank_timestamp) (struct drm_device *dev, int crtc, -+ int *max_error, -+ struct timeval *vblank_time, -+ unsigned flags); -+ - /* these have to be filled in */ - - irqreturn_t(*irq_handler) (DRM_IRQ_ARGS); -@@ -983,6 +1060,8 @@ - - wait_queue_head_t *vbl_queue; /**< VBLANK wait queue */ - atomic_t *_vblank_count; /**< number of VBLANK interrupts (driver must alloc the right number of counters) */ -+ struct timeval *_vblank_time; /**< timestamp of current vblank_count (drivers must alloc right number of fields) */ -+ spinlock_t vblank_time_lock; /**< Protects vblank count and time updates during vblank enable/disable */ - spinlock_t vbl_lock; - atomic_t *vblank_refcount; /* number of users of vblank interruptsper crtc */ - u32 *last_vblank; /* protected by dev->vbl_lock, used */ -@@ -1284,11 +1363,22 @@ - struct drm_file *filp); - extern int drm_vblank_wait(struct drm_device *dev, unsigned int *vbl_seq); - extern u32 drm_vblank_count(struct drm_device *dev, int crtc); -+extern u32 drm_vblank_count_and_time(struct drm_device *dev, int crtc, -+ struct timeval *vblanktime); - extern void drm_handle_vblank(struct drm_device *dev, int crtc); - extern int drm_vblank_get(struct drm_device *dev, int crtc); - extern void drm_vblank_put(struct drm_device *dev, int crtc); - extern void drm_vblank_off(struct drm_device *dev, int crtc); - extern void drm_vblank_cleanup(struct drm_device *dev); -+extern u32 drm_get_last_vbltimestamp(struct drm_device *dev, int crtc, -+ struct timeval *tvblank, unsigned flags); -+extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, -+ int crtc, int *max_error, -+ struct timeval *vblank_time, -+ unsigned flags, -+ struct drm_crtc *refcrtc); -+extern void drm_calc_timestamping_constants(struct drm_crtc *crtc); -+ - /* 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); -@@ -1340,6 +1430,9 @@ - extern int drm_put_minor(struct drm_minor **minor); - extern unsigned int drm_debug; - -+extern unsigned int drm_vblank_offdelay; -+extern unsigned int drm_timestamp_precision; -+ - extern struct class *drm_class; - extern struct proc_dir_entry *drm_proc_root; - extern struct dentry *drm_debugfs_root; -diff -Naur linux-2.6.37-rc3/include/drm/nouveau_drm.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/nouveau_drm.h ---- linux-2.6.37-rc3/include/drm/nouveau_drm.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/nouveau_drm.h 2011-01-07 14:22:17.000000000 +0100 -@@ -71,16 +71,14 @@ - #define NOUVEAU_GETPARAM_PCI_VENDOR 3 - #define NOUVEAU_GETPARAM_PCI_DEVICE 4 - #define NOUVEAU_GETPARAM_BUS_TYPE 5 --#define NOUVEAU_GETPARAM_FB_PHYSICAL 6 --#define NOUVEAU_GETPARAM_AGP_PHYSICAL 7 - #define NOUVEAU_GETPARAM_FB_SIZE 8 - #define NOUVEAU_GETPARAM_AGP_SIZE 9 --#define NOUVEAU_GETPARAM_PCI_PHYSICAL 10 - #define NOUVEAU_GETPARAM_CHIPSET_ID 11 - #define NOUVEAU_GETPARAM_VM_VRAM_BASE 12 - #define NOUVEAU_GETPARAM_GRAPH_UNITS 13 - #define NOUVEAU_GETPARAM_PTIMER_TIME 14 - #define NOUVEAU_GETPARAM_HAS_BO_USAGE 15 -+#define NOUVEAU_GETPARAM_HAS_PAGEFLIP 16 - struct drm_nouveau_getparam { - uint64_t param; - uint64_t value; -@@ -171,7 +169,6 @@ - }; - - #define NOUVEAU_GEM_CPU_PREP_NOWAIT 0x00000001 --#define NOUVEAU_GEM_CPU_PREP_NOBLOCK 0x00000002 - #define NOUVEAU_GEM_CPU_PREP_WRITE 0x00000004 - struct drm_nouveau_gem_cpu_prep { - uint32_t handle; -diff -Naur linux-2.6.37-rc3/include/drm/ttm/ttm_bo_api.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/ttm/ttm_bo_api.h ---- linux-2.6.37-rc3/include/drm/ttm/ttm_bo_api.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/ttm/ttm_bo_api.h 2011-01-07 14:22:17.000000000 +0100 -@@ -74,6 +74,8 @@ - * @is_iomem: is this io memory ? - * @size: size in byte - * @offset: offset from the base address -+ * @io_reserved_vm: The VM system has a refcount in @io_reserved_count -+ * @io_reserved_count: Refcounting the numbers of callers to ttm_mem_io_reserve - * - * Structure indicating the bus placement of an object. - */ -@@ -83,7 +85,8 @@ - unsigned long size; - unsigned long offset; - bool is_iomem; -- bool io_reserved; -+ bool io_reserved_vm; -+ uint64_t io_reserved_count; - }; - - -@@ -154,7 +157,6 @@ - * keeps one refcount. When this refcount reaches zero, - * the object is destroyed. - * @event_queue: Queue for processes waiting on buffer object status change. -- * @lock: spinlock protecting mostly synchronization members. - * @mem: structure describing current placement. - * @persistant_swap_storage: Usually the swap storage is deleted for buffers - * pinned in physical memory. If this behaviour is not desired, this member -@@ -213,7 +215,6 @@ - struct kref kref; - struct kref list_kref; - wait_queue_head_t event_queue; -- spinlock_t lock; - - /** - * Members protected by the bo::reserved lock. -@@ -237,6 +238,7 @@ - struct list_head lru; - struct list_head ddestroy; - struct list_head swap; -+ struct list_head io_reserve_lru; - uint32_t val_seq; - bool seq_valid; - -@@ -248,10 +250,10 @@ - atomic_t reserved; - - /** -- * Members protected by the bo::lock -+ * Members protected by struct buffer_object_device::fence_lock - * In addition, setting sync_obj to anything else - * than NULL requires bo::reserved to be held. This allows for -- * checking NULL while reserved but not holding bo::lock. -+ * checking NULL while reserved but not holding the mentioned lock. - */ - - void *sync_obj_arg; -@@ -364,6 +366,44 @@ - */ - extern void ttm_bo_unref(struct ttm_buffer_object **bo); - -+ -+/** -+ * ttm_bo_list_ref_sub -+ * -+ * @bo: The buffer object. -+ * @count: The number of references with which to decrease @bo::list_kref; -+ * @never_free: The refcount should not reach zero with this operation. -+ * -+ * Release @count lru list references to this buffer object. -+ */ -+extern void ttm_bo_list_ref_sub(struct ttm_buffer_object *bo, int count, -+ bool never_free); -+ -+/** -+ * ttm_bo_add_to_lru -+ * -+ * @bo: The buffer object. -+ * -+ * Add this bo to the relevant mem type lru and, if it's backed by -+ * system pages (ttms) to the swap list. -+ * This function must be called with struct ttm_bo_global::lru_lock held, and -+ * is typically called immediately prior to unreserving a bo. -+ */ -+extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo); -+ -+/** -+ * ttm_bo_del_from_lru -+ * -+ * @bo: The buffer object. -+ * -+ * Remove this bo from all lru lists used to lookup and reserve an object. -+ * This function must be called with struct ttm_bo_global::lru_lock held, -+ * and is usually called just immediately after the bo has been reserved to -+ * avoid recursive reservation from lru lists. -+ */ -+extern int ttm_bo_del_from_lru(struct ttm_buffer_object *bo); -+ -+ - /** - * ttm_bo_lock_delayed_workqueue - * -diff -Naur linux-2.6.37-rc3/include/drm/ttm/ttm_bo_driver.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/ttm/ttm_bo_driver.h ---- linux-2.6.37-rc3/include/drm/ttm/ttm_bo_driver.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/ttm/ttm_bo_driver.h 2011-01-07 14:22:17.000000000 +0100 -@@ -179,30 +179,6 @@ - #define TTM_MEMTYPE_FLAG_MAPPABLE (1 << 1) /* Memory mappable */ - #define TTM_MEMTYPE_FLAG_CMA (1 << 3) /* Can't map aperture */ - --/** -- * struct ttm_mem_type_manager -- * -- * @has_type: The memory type has been initialized. -- * @use_type: The memory type is enabled. -- * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory -- * managed by this memory type. -- * @gpu_offset: If used, the GPU offset of the first managed page of -- * fixed memory or the first managed location in an aperture. -- * @size: Size of the managed region. -- * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, -- * as defined in ttm_placement_common.h -- * @default_caching: The default caching policy used for a buffer object -- * placed in this memory type if the user doesn't provide one. -- * @manager: The range manager used for this memory type. FIXME: If the aperture -- * has a page size different from the underlying system, the granularity -- * of this manager should take care of this. But the range allocating code -- * in ttm_bo.c needs to be modified for this. -- * @lru: The lru list for this memory type. -- * -- * This structure is used to identify and manage memory types for a device. -- * It's set up by the ttm_bo_driver::init_mem_type method. -- */ -- - struct ttm_mem_type_manager; - - struct ttm_mem_type_manager_func { -@@ -287,6 +263,36 @@ - void (*debug)(struct ttm_mem_type_manager *man, const char *prefix); - }; - -+/** -+ * struct ttm_mem_type_manager -+ * -+ * @has_type: The memory type has been initialized. -+ * @use_type: The memory type is enabled. -+ * @flags: TTM_MEMTYPE_XX flags identifying the traits of the memory -+ * managed by this memory type. -+ * @gpu_offset: If used, the GPU offset of the first managed page of -+ * fixed memory or the first managed location in an aperture. -+ * @size: Size of the managed region. -+ * @available_caching: A mask of available caching types, TTM_PL_FLAG_XX, -+ * as defined in ttm_placement_common.h -+ * @default_caching: The default caching policy used for a buffer object -+ * placed in this memory type if the user doesn't provide one. -+ * @func: structure pointer implementing the range manager. See above -+ * @priv: Driver private closure for @func. -+ * @io_reserve_mutex: Mutex optionally protecting shared io_reserve structures -+ * @use_io_reserve_lru: Use an lru list to try to unreserve io_mem_regions -+ * reserved by the TTM vm system. -+ * @io_reserve_lru: Optional lru list for unreserving io mem regions. -+ * @io_reserve_fastpath: Only use bdev::driver::io_mem_reserve to obtain -+ * static information. bdev::driver::io_mem_free is never used. -+ * @lru: The lru list for this memory type. -+ * -+ * This structure is used to identify and manage memory types for a device. -+ * It's set up by the ttm_bo_driver::init_mem_type method. -+ */ -+ -+ -+ - struct ttm_mem_type_manager { - struct ttm_bo_device *bdev; - -@@ -303,6 +309,15 @@ - uint32_t default_caching; - const struct ttm_mem_type_manager_func *func; - void *priv; -+ struct mutex io_reserve_mutex; -+ bool use_io_reserve_lru; -+ bool io_reserve_fastpath; -+ -+ /* -+ * Protected by @io_reserve_mutex: -+ */ -+ -+ struct list_head io_reserve_lru; - - /* - * Protected by the global->lru_lock. -@@ -510,9 +525,12 @@ - * - * @driver: Pointer to a struct ttm_bo_driver struct setup by the driver. - * @man: An array of mem_type_managers. -+ * @fence_lock: Protects the synchronizing members on *all* bos belonging -+ * to this device. - * @addr_space_mm: Range manager for the device address space. - * lru_lock: Spinlock that protects the buffer+device lru lists and - * ddestroy lists. -+ * @val_seq: Current validation sequence. - * @nice_mode: Try nicely to wait for buffer idle when cleaning a manager. - * If a GPU lockup has been detected, this is forced to 0. - * @dev_mapping: A pointer to the struct address_space representing the -@@ -531,6 +549,7 @@ - struct ttm_bo_driver *driver; - rwlock_t vm_lock; - struct ttm_mem_type_manager man[TTM_NUM_MEM_TYPES]; -+ spinlock_t fence_lock; - /* - * Protected by the vm lock. - */ -@@ -541,6 +560,7 @@ - * Protected by the global:lru lock. - */ - struct list_head ddestroy; -+ uint32_t val_seq; - - /* - * Protected by load / firstopen / lastclose /unload sync. -@@ -753,31 +773,6 @@ - - extern int ttm_bo_wait_cpu(struct ttm_buffer_object *bo, bool no_wait); - --/** -- * ttm_bo_pci_offset - Get the PCI offset for the buffer object memory. -- * -- * @bo Pointer to a struct ttm_buffer_object. -- * @bus_base On return the base of the PCI region -- * @bus_offset On return the byte offset into the PCI region -- * @bus_size On return the byte size of the buffer object or zero if -- * the buffer object memory is not accessible through a PCI region. -- * -- * Returns: -- * -EINVAL if the buffer object is currently not mappable. -- * 0 otherwise. -- */ -- --extern int ttm_bo_pci_offset(struct ttm_bo_device *bdev, -- struct ttm_mem_reg *mem, -- unsigned long *bus_base, -- unsigned long *bus_offset, -- unsigned long *bus_size); -- --extern int ttm_mem_io_reserve(struct ttm_bo_device *bdev, -- struct ttm_mem_reg *mem); --extern void ttm_mem_io_free(struct ttm_bo_device *bdev, -- struct ttm_mem_reg *mem); -- - extern void ttm_bo_global_release(struct drm_global_reference *ref); - extern int ttm_bo_global_init(struct drm_global_reference *ref); - -@@ -810,6 +805,22 @@ - extern void ttm_bo_unmap_virtual(struct ttm_buffer_object *bo); - - /** -+ * ttm_bo_unmap_virtual -+ * -+ * @bo: tear down the virtual mappings for this BO -+ * -+ * The caller must take ttm_mem_io_lock before calling this function. -+ */ -+extern void ttm_bo_unmap_virtual_locked(struct ttm_buffer_object *bo); -+ -+extern int ttm_mem_io_reserve_vm(struct ttm_buffer_object *bo); -+extern void ttm_mem_io_free_vm(struct ttm_buffer_object *bo); -+extern int ttm_mem_io_lock(struct ttm_mem_type_manager *man, -+ bool interruptible); -+extern void ttm_mem_io_unlock(struct ttm_mem_type_manager *man); -+ -+ -+/** - * ttm_bo_reserve: - * - * @bo: A pointer to a struct ttm_buffer_object. -@@ -859,11 +870,44 @@ - * try again. (only if use_sequence == 1). - * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by - * a signal. Release all buffer reservations and return to user-space. -+ * -EBUSY: The function needed to sleep, but @no_wait was true -+ * -EDEADLK: Bo already reserved using @sequence. This error code will only -+ * be returned if @use_sequence is set to true. - */ - extern int ttm_bo_reserve(struct ttm_buffer_object *bo, - bool interruptible, - bool no_wait, bool use_sequence, uint32_t sequence); - -+ -+/** -+ * ttm_bo_reserve_locked: -+ * -+ * @bo: A pointer to a struct ttm_buffer_object. -+ * @interruptible: Sleep interruptible if waiting. -+ * @no_wait: Don't sleep while trying to reserve, rather return -EBUSY. -+ * @use_sequence: If @bo is already reserved, Only sleep waiting for -+ * it to become unreserved if @sequence < (@bo)->sequence. -+ * -+ * Must be called with struct ttm_bo_global::lru_lock held, -+ * and will not remove reserved buffers from the lru lists. -+ * The function may release the LRU spinlock if it needs to sleep. -+ * Otherwise identical to ttm_bo_reserve. -+ * -+ * Returns: -+ * -EAGAIN: The reservation may cause a deadlock. -+ * Release all buffer reservations, wait for @bo to become unreserved and -+ * try again. (only if use_sequence == 1). -+ * -ERESTARTSYS: A wait for the buffer to become unreserved was interrupted by -+ * a signal. Release all buffer reservations and return to user-space. -+ * -EBUSY: The function needed to sleep, but @no_wait was true -+ * -EDEADLK: Bo already reserved using @sequence. This error code will only -+ * be returned if @use_sequence is set to true. -+ */ -+extern int ttm_bo_reserve_locked(struct ttm_buffer_object *bo, -+ bool interruptible, -+ bool no_wait, bool use_sequence, -+ uint32_t sequence); -+ - /** - * ttm_bo_unreserve - * -@@ -874,6 +918,16 @@ - extern void ttm_bo_unreserve(struct ttm_buffer_object *bo); - - /** -+ * ttm_bo_unreserve_locked -+ * -+ * @bo: A pointer to a struct ttm_buffer_object. -+ * -+ * Unreserve a previous reservation of @bo. -+ * Needs to be called with struct ttm_bo_global::lru_lock held. -+ */ -+extern void ttm_bo_unreserve_locked(struct ttm_buffer_object *bo); -+ -+/** - * ttm_bo_wait_unreserved - * - * @bo: A pointer to a struct ttm_buffer_object. -diff -Naur linux-2.6.37-rc3/include/drm/ttm/ttm_execbuf_util.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/ttm/ttm_execbuf_util.h ---- linux-2.6.37-rc3/include/drm/ttm/ttm_execbuf_util.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/drm/ttm/ttm_execbuf_util.h 2011-01-07 14:22:17.000000000 +0100 -@@ -41,7 +41,10 @@ - * @bo: refcounted buffer object pointer. - * @new_sync_obj_arg: New sync_obj_arg for @bo, to be used once - * adding a new sync object. -- * @reservied: Indicates whether @bo has been reserved for validation. -+ * @reserved: Indicates whether @bo has been reserved for validation. -+ * @removed: Indicates whether @bo has been removed from lru lists. -+ * @put_count: Number of outstanding references on bo::list_kref. -+ * @old_sync_obj: Pointer to a sync object about to be unreferenced - */ - - struct ttm_validate_buffer { -@@ -49,6 +52,9 @@ - struct ttm_buffer_object *bo; - void *new_sync_obj_arg; - bool reserved; -+ bool removed; -+ int put_count; -+ void *old_sync_obj; - }; - - /** -@@ -66,7 +72,6 @@ - * function ttm_eu_reserve_buffers - * - * @list: thread private list of ttm_validate_buffer structs. -- * @val_seq: A unique sequence number. - * - * Tries to reserve bos pointed to by the list entries for validation. - * If the function returns 0, all buffers are marked as "unfenced", -@@ -88,7 +93,7 @@ - * has failed. - */ - --extern int ttm_eu_reserve_buffers(struct list_head *list, uint32_t val_seq); -+extern int ttm_eu_reserve_buffers(struct list_head *list); - - /** - * function ttm_eu_fence_buffer_objects. -diff -Naur linux-2.6.37-rc3/include/linux/kref.h linux-2.6.37-rc3.drm-nouveau-next-20110111/include/linux/kref.h ---- linux-2.6.37-rc3/include/linux/kref.h 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/include/linux/kref.h 2011-01-07 14:22:17.000000000 +0100 -@@ -24,5 +24,7 @@ - void kref_init(struct kref *kref); - void kref_get(struct kref *kref); - int kref_put(struct kref *kref, void (*release) (struct kref *kref)); -+int kref_sub(struct kref *kref, unsigned int count, -+ void (*release) (struct kref *kref)); - - #endif /* _KREF_H_ */ -diff -Naur linux-2.6.37-rc3/lib/kref.c linux-2.6.37-rc3.drm-nouveau-next-20110111/lib/kref.c ---- linux-2.6.37-rc3/lib/kref.c 2010-11-22 00:18:56.000000000 +0100 -+++ linux-2.6.37-rc3.drm-nouveau-next-20110111/lib/kref.c 2011-01-07 14:22:17.000000000 +0100 -@@ -62,6 +62,36 @@ - return 0; - } - -+ -+/** -+ * kref_sub - subtract a number of refcounts for object. -+ * @kref: object. -+ * @count: Number of recounts to subtract. -+ * @release: pointer to the function that will clean up the object when the -+ * last reference to the object is released. -+ * This pointer is required, and it is not acceptable to pass kfree -+ * in as this function. -+ * -+ * Subtract @count from the refcount, and if 0, call release(). -+ * Return 1 if the object was removed, otherwise return 0. Beware, if this -+ * function returns 0, you still can not count on the kref from remaining in -+ * memory. Only use the return value if you want to see if the kref is now -+ * gone, not present. -+ */ -+int kref_sub(struct kref *kref, unsigned int count, -+ void (*release)(struct kref *kref)) -+{ -+ WARN_ON(release == NULL); -+ WARN_ON(release == (void (*)(struct kref *))kfree); -+ -+ if (atomic_sub_and_test((int) count, &kref->refcount)) { -+ release(kref); -+ return 1; -+ } -+ return 0; -+} -+ - EXPORT_SYMBOL(kref_init); - EXPORT_SYMBOL(kref_get); - EXPORT_SYMBOL(kref_put); -+EXPORT_SYMBOL(kref_sub); diff --git a/packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110222.patch b/packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110222.patch new file mode 100644 index 0000000000..364b99654c --- /dev/null +++ b/packages/linux/patches/linux-2.6.38-rc5-110-drm_nouveau_upstream-20110222.patch @@ -0,0 +1,4649 @@ +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_bios.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-02-20 23:32:11.000000000 +0100 +@@ -282,7 +282,7 @@ + { + #if 0 + sync(); +- msleep(2); ++ mdelay(2); + #endif + } + +@@ -1904,7 +1904,7 @@ + BIOSLOG(bios, "0x%04X: " + "Condition not met, sleeping for 20ms\n", + offset); +- msleep(20); ++ mdelay(20); + } + } + +@@ -1938,7 +1938,7 @@ + BIOSLOG(bios, "0x%04X: Sleeping for 0x%04X milliseconds\n", + offset, time); + +- msleep(time); ++ mdelay(time); + + return 3; + } +@@ -2962,7 +2962,7 @@ + if (time < 1000) + udelay(time); + else +- msleep((time + 900) / 1000); ++ mdelay((time + 900) / 1000); + + return 3; + } +@@ -3856,7 +3856,7 @@ + + if (script == LVDS_PANEL_OFF) { + /* off-on delay in ms */ +- msleep(ROM16(bios->data[bios->fp.xlated_entry + 7])); ++ mdelay(ROM16(bios->data[bios->fp.xlated_entry + 7])); + } + #ifdef __powerpc__ + /* Powerbook specific quirks */ +@@ -5950,6 +5950,11 @@ + } + } + ++static const u8 hpd_gpio[16] = { ++ 0xff, 0x07, 0x08, 0xff, 0xff, 0x51, 0x52, 0xff, ++ 0xff, 0xff, 0xff, 0xff, 0xff, 0x5e, 0x5f, 0x60, ++}; ++ + static void + parse_dcb_connector_table(struct nvbios *bios) + { +@@ -5986,23 +5991,9 @@ + + cte->type = (cte->entry & 0x000000ff) >> 0; + cte->index2 = (cte->entry & 0x00000f00) >> 8; +- switch (cte->entry & 0x00033000) { +- case 0x00001000: +- cte->gpio_tag = 0x07; +- break; +- case 0x00002000: +- cte->gpio_tag = 0x08; +- break; +- case 0x00010000: +- cte->gpio_tag = 0x51; +- break; +- case 0x00020000: +- cte->gpio_tag = 0x52; +- break; +- default: +- cte->gpio_tag = 0xff; +- break; +- } ++ ++ cte->gpio_tag = ffs((cte->entry & 0x07033000) >> 12); ++ cte->gpio_tag = hpd_gpio[cte->gpio_tag]; + + if (cte->type == 0xff) + continue; +@@ -6228,7 +6219,7 @@ + entry->tvconf.has_component_output = false; + break; + case OUTPUT_LVDS: +- if ((conn & 0x00003f00) != 0x10) ++ if ((conn & 0x00003f00) >> 8 != 0x10) + entry->lvdsconf.use_straps_for_mode = true; + entry->lvdsconf.use_power_scripts = true; + break; +@@ -6702,11 +6693,11 @@ + struct nvbios *bios = &dev_priv->vbios; + struct init_exec iexec = { true, false }; + +- mutex_lock(&bios->lock); ++ spin_lock_bh(&bios->lock); + bios->display.output = dcbent; + parse_init_table(bios, table, &iexec); + bios->display.output = NULL; +- mutex_unlock(&bios->lock); ++ spin_unlock_bh(&bios->lock); + } + + static bool NVInitVBIOS(struct drm_device *dev) +@@ -6715,7 +6706,7 @@ + struct nvbios *bios = &dev_priv->vbios; + + memset(bios, 0, sizeof(struct nvbios)); +- mutex_init(&bios->lock); ++ spin_lock_init(&bios->lock); + bios->dev = dev; + + if (!NVShadowVBIOS(dev, bios->data)) +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_bios.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_bios.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_bios.h 2011-02-20 23:32:11.000000000 +0100 +@@ -251,7 +251,7 @@ + uint8_t digital_min_front_porch; + bool fp_no_ddc; + +- struct mutex lock; ++ spinlock_t lock; + + uint8_t data[NV_PROM_SIZE]; + unsigned int length; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_bo.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_bo.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_bo.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_bo.c 2011-02-20 23:32:11.000000000 +0100 +@@ -54,8 +54,8 @@ + } + + static void +-nouveau_bo_fixup_align(struct nouveau_bo *nvbo, int *align, int *size, +- int *page_shift) ++nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, ++ int *align, int *size, int *page_shift) + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + +@@ -80,7 +80,7 @@ + } + } else { + if (likely(dev_priv->chan_vm)) { +- if (*size > 256 * 1024) ++ if (!(flags & TTM_PL_FLAG_TT) && *size > 256 * 1024) + *page_shift = dev_priv->chan_vm->lpg_shift; + else + *page_shift = dev_priv->chan_vm->spg_shift; +@@ -98,8 +98,7 @@ + int + nouveau_bo_new(struct drm_device *dev, struct nouveau_channel *chan, + int size, int align, uint32_t flags, uint32_t tile_mode, +- uint32_t tile_flags, bool no_vm, bool mappable, +- struct nouveau_bo **pnvbo) ++ uint32_t tile_flags, struct nouveau_bo **pnvbo) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_bo *nvbo; +@@ -110,16 +109,14 @@ + return -ENOMEM; + INIT_LIST_HEAD(&nvbo->head); + INIT_LIST_HEAD(&nvbo->entry); +- nvbo->mappable = mappable; +- nvbo->no_vm = no_vm; + nvbo->tile_mode = tile_mode; + nvbo->tile_flags = tile_flags; + nvbo->bo.bdev = &dev_priv->ttm.bdev; + +- nouveau_bo_fixup_align(nvbo, &align, &size, &page_shift); ++ nouveau_bo_fixup_align(nvbo, flags, &align, &size, &page_shift); + align >>= PAGE_SHIFT; + +- if (!nvbo->no_vm && dev_priv->chan_vm) { ++ if (dev_priv->chan_vm) { + ret = nouveau_vm_get(dev_priv->chan_vm, size, page_shift, + NV_MEM_ACCESS_RW, &nvbo->vma); + if (ret) { +@@ -128,6 +125,7 @@ + } + } + ++ nvbo->bo.mem.num_pages = size >> PAGE_SHIFT; + nouveau_bo_placement_set(nvbo, flags, 0); + + nvbo->channel = chan; +@@ -140,11 +138,8 @@ + } + nvbo->channel = NULL; + +- if (nvbo->vma.node) { +- if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) +- nvbo->bo.offset = nvbo->vma.offset; +- } +- ++ if (nvbo->vma.node) ++ nvbo->bo.offset = nvbo->vma.offset; + *pnvbo = nvbo; + return 0; + } +@@ -166,17 +161,17 @@ + set_placement_range(struct nouveau_bo *nvbo, uint32_t type) + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); ++ int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; + + if (dev_priv->card_type == NV_10 && +- nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM)) { ++ nvbo->tile_mode && (type & TTM_PL_FLAG_VRAM) && ++ nvbo->bo.mem.num_pages < vram_pages / 2) { + /* + * Make sure that the color and depth buffers are handled + * by independent memory controller units. Up to a 9x + * speed up when alpha-blending and depth-test are enabled + * at the same time. + */ +- int vram_pages = dev_priv->vram_size >> PAGE_SHIFT; +- + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_ZETA) { + nvbo->placement.fpfn = vram_pages / 2; + nvbo->placement.lpfn = ~0; +@@ -314,11 +309,8 @@ + if (ret) + return ret; + +- if (nvbo->vma.node) { +- if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) +- nvbo->bo.offset = nvbo->vma.offset; +- } +- ++ if (nvbo->vma.node) ++ nvbo->bo.offset = nvbo->vma.offset; + return 0; + } + +@@ -381,7 +373,8 @@ + case NOUVEAU_GART_AGP: + return ttm_agp_backend_init(bdev, dev->agp->bridge); + #endif +- case NOUVEAU_GART_SGDMA: ++ case NOUVEAU_GART_PDMA: ++ case NOUVEAU_GART_HW: + return nouveau_sgdma_init_ttm(dev); + default: + NV_ERROR(dev, "Unknown GART type %d\n", +@@ -427,7 +420,10 @@ + man->default_caching = TTM_PL_FLAG_WC; + break; + case TTM_PL_TT: +- man->func = &ttm_bo_manager_func; ++ if (dev_priv->card_type >= NV_50) ++ man->func = &nouveau_gart_manager; ++ else ++ man->func = &ttm_bo_manager_func; + switch (dev_priv->gart_info.type) { + case NOUVEAU_GART_AGP: + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; +@@ -435,7 +431,8 @@ + TTM_PL_FLAG_WC; + man->default_caching = TTM_PL_FLAG_WC; + break; +- case NOUVEAU_GART_SGDMA: ++ case NOUVEAU_GART_PDMA: ++ case NOUVEAU_GART_HW: + man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | + TTM_MEMTYPE_FLAG_CMA; + man->available_caching = TTM_PL_MASK_CACHING; +@@ -497,45 +494,22 @@ + return ret; + } + +-static inline uint32_t +-nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, +- struct nouveau_channel *chan, struct ttm_mem_reg *mem) +-{ +- struct nouveau_bo *nvbo = nouveau_bo(bo); +- +- if (nvbo->no_vm) { +- if (mem->mem_type == TTM_PL_TT) +- return NvDmaGART; +- return NvDmaVRAM; +- } +- +- if (mem->mem_type == TTM_PL_TT) +- return chan->gart_handle; +- return chan->vram_handle; +-} +- + static int + nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, + struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) + { +- struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); ++ struct nouveau_mem *old_node = old_mem->mm_node; ++ struct nouveau_mem *new_node = new_mem->mm_node; + struct nouveau_bo *nvbo = nouveau_bo(bo); +- u64 src_offset = old_mem->start << PAGE_SHIFT; +- u64 dst_offset = new_mem->start << PAGE_SHIFT; + u32 page_count = new_mem->num_pages; ++ u64 src_offset, dst_offset; + int ret; + +- if (!nvbo->no_vm) { +- if (old_mem->mem_type == TTM_PL_VRAM) +- src_offset = nvbo->vma.offset; +- else +- src_offset += dev_priv->gart_info.aper_base; +- +- if (new_mem->mem_type == TTM_PL_VRAM) +- dst_offset = nvbo->vma.offset; +- else +- dst_offset += dev_priv->gart_info.aper_base; +- } ++ src_offset = old_node->tmp_vma.offset; ++ if (new_node->tmp_vma.node) ++ dst_offset = new_node->tmp_vma.offset; ++ else ++ dst_offset = nvbo->vma.offset; + + page_count = new_mem->num_pages; + while (page_count) { +@@ -570,33 +544,18 @@ + nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, + struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) + { +- struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); ++ struct nouveau_mem *old_node = old_mem->mm_node; ++ struct nouveau_mem *new_node = new_mem->mm_node; + struct nouveau_bo *nvbo = nouveau_bo(bo); + u64 length = (new_mem->num_pages << PAGE_SHIFT); + u64 src_offset, dst_offset; + int ret; + +- src_offset = old_mem->start << PAGE_SHIFT; +- dst_offset = new_mem->start << PAGE_SHIFT; +- if (!nvbo->no_vm) { +- if (old_mem->mem_type == TTM_PL_VRAM) +- src_offset = nvbo->vma.offset; +- else +- src_offset += dev_priv->gart_info.aper_base; +- +- if (new_mem->mem_type == TTM_PL_VRAM) +- dst_offset = nvbo->vma.offset; +- else +- dst_offset += dev_priv->gart_info.aper_base; +- } +- +- ret = RING_SPACE(chan, 3); +- if (ret) +- return ret; +- +- BEGIN_RING(chan, NvSubM2MF, 0x0184, 2); +- OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, old_mem)); +- OUT_RING (chan, nouveau_bo_mem_ctxdma(bo, chan, new_mem)); ++ src_offset = old_node->tmp_vma.offset; ++ if (new_node->tmp_vma.node) ++ dst_offset = new_node->tmp_vma.offset; ++ else ++ dst_offset = nvbo->vma.offset; + + while (length) { + u32 amount, stride, height; +@@ -677,6 +636,15 @@ + return 0; + } + ++static inline uint32_t ++nouveau_bo_mem_ctxdma(struct ttm_buffer_object *bo, ++ struct nouveau_channel *chan, struct ttm_mem_reg *mem) ++{ ++ if (mem->mem_type == TTM_PL_TT) ++ return chan->gart_handle; ++ return chan->vram_handle; ++} ++ + static int + nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo, + struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem) +@@ -730,15 +698,43 @@ + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct nouveau_bo *nvbo = nouveau_bo(bo); ++ struct ttm_mem_reg *old_mem = &bo->mem; + struct nouveau_channel *chan; + int ret; + + chan = nvbo->channel; +- if (!chan || nvbo->no_vm) { ++ if (!chan) { + chan = dev_priv->channel; + mutex_lock_nested(&chan->mutex, NOUVEAU_KCHANNEL_MUTEX); + } + ++ /* create temporary vma for old memory, this will get cleaned ++ * up after ttm destroys the ttm_mem_reg ++ */ ++ if (dev_priv->card_type >= NV_50) { ++ struct nouveau_mem *node = old_mem->mm_node; ++ if (!node->tmp_vma.node) { ++ u32 page_shift = nvbo->vma.node->type; ++ if (old_mem->mem_type == TTM_PL_TT) ++ page_shift = nvbo->vma.vm->spg_shift; ++ ++ ret = nouveau_vm_get(chan->vm, ++ old_mem->num_pages << PAGE_SHIFT, ++ page_shift, NV_MEM_ACCESS_RO, ++ &node->tmp_vma); ++ if (ret) ++ goto out; ++ } ++ ++ if (old_mem->mem_type == TTM_PL_VRAM) ++ nouveau_vm_map(&node->tmp_vma, node); ++ else { ++ nouveau_vm_map_sg(&node->tmp_vma, 0, ++ old_mem->num_pages << PAGE_SHIFT, ++ node, node->pages); ++ } ++ } ++ + if (dev_priv->card_type < NV_50) + ret = nv04_bo_move_m2mf(chan, bo, &bo->mem, new_mem); + else +@@ -752,6 +748,7 @@ + no_wait_gpu, new_mem); + } + ++out: + if (chan == dev_priv->channel) + mutex_unlock(&chan->mutex); + return ret; +@@ -762,6 +759,7 @@ + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) + { ++ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + u32 placement_memtype = TTM_PL_FLAG_TT | TTM_PL_MASK_CACHING; + struct ttm_placement placement; + struct ttm_mem_reg tmp_mem; +@@ -781,11 +779,27 @@ + if (ret) + goto out; + ++ if (dev_priv->card_type >= NV_50) { ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ struct nouveau_mem *node = tmp_mem.mm_node; ++ struct nouveau_vma *vma = &nvbo->vma; ++ if (vma->node->type != vma->vm->spg_shift) ++ vma = &node->tmp_vma; ++ nouveau_vm_map_sg(vma, 0, tmp_mem.num_pages << PAGE_SHIFT, ++ node, node->pages); ++ } ++ + ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, &tmp_mem); ++ ++ if (dev_priv->card_type >= NV_50) { ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ nouveau_vm_unmap(&nvbo->vma); ++ } ++ + if (ret) + goto out; + +- ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); ++ ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, new_mem); + out: + ttm_bo_mem_put(bo, &tmp_mem); + return ret; +@@ -811,11 +825,11 @@ + if (ret) + return ret; + +- ret = ttm_bo_move_ttm(bo, evict, no_wait_reserve, no_wait_gpu, &tmp_mem); ++ ret = ttm_bo_move_ttm(bo, true, no_wait_reserve, no_wait_gpu, &tmp_mem); + if (ret) + goto out; + +- ret = nouveau_bo_move_m2mf(bo, evict, intr, no_wait_reserve, no_wait_gpu, new_mem); ++ ret = nouveau_bo_move_m2mf(bo, true, intr, no_wait_reserve, no_wait_gpu, new_mem); + if (ret) + goto out; + +@@ -824,6 +838,36 @@ + return ret; + } + ++static void ++nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem) ++{ ++ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); ++ struct nouveau_mem *node = new_mem->mm_node; ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ struct nouveau_vma *vma = &nvbo->vma; ++ struct nouveau_vm *vm = vma->vm; ++ ++ if (dev_priv->card_type < NV_50) ++ return; ++ ++ switch (new_mem->mem_type) { ++ case TTM_PL_VRAM: ++ nouveau_vm_map(vma, node); ++ break; ++ case TTM_PL_TT: ++ if (vma->node->type != vm->spg_shift) { ++ nouveau_vm_unmap(vma); ++ vma = &node->tmp_vma; ++ } ++ nouveau_vm_map_sg(vma, 0, new_mem->num_pages << PAGE_SHIFT, ++ node, node->pages); ++ break; ++ default: ++ nouveau_vm_unmap(&nvbo->vma); ++ break; ++ } ++} ++ + static int + nouveau_bo_vm_bind(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem, + struct nouveau_tile_reg **new_tile) +@@ -831,19 +875,13 @@ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct drm_device *dev = dev_priv->dev; + struct nouveau_bo *nvbo = nouveau_bo(bo); +- uint64_t offset; ++ u64 offset = new_mem->start << PAGE_SHIFT; + +- if (nvbo->no_vm || new_mem->mem_type != TTM_PL_VRAM) { +- /* Nothing to do. */ +- *new_tile = NULL; ++ *new_tile = NULL; ++ if (new_mem->mem_type != TTM_PL_VRAM) + return 0; +- } + +- offset = new_mem->start << PAGE_SHIFT; +- +- if (dev_priv->chan_vm) { +- nouveau_vm_map(&nvbo->vma, new_mem->mm_node); +- } else if (dev_priv->card_type >= NV_10) { ++ if (dev_priv->card_type >= NV_10) { + *new_tile = nv10_mem_set_tiling(dev, offset, new_mem->size, + nvbo->tile_mode, + nvbo->tile_flags); +@@ -860,11 +898,8 @@ + struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); + struct drm_device *dev = dev_priv->dev; + +- if (dev_priv->card_type >= NV_10 && +- dev_priv->card_type < NV_50) { +- nv10_mem_put_tile_region(dev, *old_tile, bo->sync_obj); +- *old_tile = new_tile; +- } ++ nv10_mem_put_tile_region(dev, *old_tile, bo->sync_obj); ++ *old_tile = new_tile; + } + + static int +@@ -878,9 +913,11 @@ + struct nouveau_tile_reg *new_tile = NULL; + int ret = 0; + +- ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile); +- if (ret) +- return ret; ++ if (dev_priv->card_type < NV_50) { ++ ret = nouveau_bo_vm_bind(bo, new_mem, &new_tile); ++ if (ret) ++ return ret; ++ } + + /* Fake bo copy. */ + if (old_mem->mem_type == TTM_PL_SYSTEM && !bo->ttm) { +@@ -911,10 +948,12 @@ + ret = ttm_bo_move_memcpy(bo, evict, no_wait_reserve, no_wait_gpu, new_mem); + + out: +- if (ret) +- nouveau_bo_vm_cleanup(bo, NULL, &new_tile); +- else +- nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile); ++ if (dev_priv->card_type < NV_50) { ++ if (ret) ++ nouveau_bo_vm_cleanup(bo, NULL, &new_tile); ++ else ++ nouveau_bo_vm_cleanup(bo, new_tile, &nvbo->tile); ++ } + + return ret; + } +@@ -955,7 +994,7 @@ + break; + case TTM_PL_VRAM: + { +- struct nouveau_vram *vram = mem->mm_node; ++ struct nouveau_mem *node = mem->mm_node; + u8 page_shift; + + if (!dev_priv->bar1_vm) { +@@ -966,23 +1005,23 @@ + } + + if (dev_priv->card_type == NV_C0) +- page_shift = vram->page_shift; ++ page_shift = node->page_shift; + else + page_shift = 12; + + ret = nouveau_vm_get(dev_priv->bar1_vm, mem->bus.size, + page_shift, NV_MEM_ACCESS_RW, +- &vram->bar_vma); ++ &node->bar_vma); + if (ret) + return ret; + +- nouveau_vm_map(&vram->bar_vma, vram); ++ nouveau_vm_map(&node->bar_vma, node); + if (ret) { +- nouveau_vm_put(&vram->bar_vma); ++ nouveau_vm_put(&node->bar_vma); + return ret; + } + +- mem->bus.offset = vram->bar_vma.offset; ++ mem->bus.offset = node->bar_vma.offset; + if (dev_priv->card_type == NV_50) /*XXX*/ + mem->bus.offset -= 0x0020000000ULL; + mem->bus.base = pci_resource_start(dev->pdev, 1); +@@ -999,16 +1038,16 @@ + nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(bdev); +- struct nouveau_vram *vram = mem->mm_node; ++ struct nouveau_mem *node = mem->mm_node; + + if (!dev_priv->bar1_vm || mem->mem_type != TTM_PL_VRAM) + return; + +- if (!vram->bar_vma.node) ++ if (!node->bar_vma.node) + return; + +- nouveau_vm_unmap(&vram->bar_vma); +- nouveau_vm_put(&vram->bar_vma); ++ nouveau_vm_unmap(&node->bar_vma); ++ nouveau_vm_put(&node->bar_vma); + } + + static int +@@ -1058,6 +1097,7 @@ + .invalidate_caches = nouveau_bo_invalidate_caches, + .init_mem_type = nouveau_bo_init_mem_type, + .evict_flags = nouveau_bo_evict_flags, ++ .move_notify = nouveau_bo_move_ntfy, + .move = nouveau_bo_move, + .verify_access = nouveau_bo_verify_access, + .sync_obj_signaled = __nouveau_fence_signalled, +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_channel.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_channel.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-02-20 23:32:11.000000000 +0100 +@@ -35,7 +35,7 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_bo *pb = chan->pushbuf_bo; + struct nouveau_gpuobj *pushbuf = NULL; +- int ret; ++ int ret = 0; + + if (dev_priv->card_type >= NV_50) { + if (dev_priv->card_type < NV_C0) { +@@ -90,8 +90,7 @@ + else + location = TTM_PL_FLAG_TT; + +- ret = nouveau_bo_new(dev, NULL, 65536, 0, location, 0, 0x0000, false, +- true, &pushbuf); ++ ret = nouveau_bo_new(dev, NULL, 65536, 0, location, 0, 0x0000, &pushbuf); + if (ret) { + NV_ERROR(dev, "error allocating DMA push buffer: %d\n", ret); + return NULL; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_connector.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_connector.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-02-20 23:32:11.000000000 +0100 +@@ -507,6 +507,7 @@ + int high_w = 0, high_h = 0, high_v = 0; + + list_for_each_entry(mode, &nv_connector->base.probed_modes, head) { ++ mode->vrefresh = drm_mode_vrefresh(mode); + if (helper->mode_valid(connector, mode) != MODE_OK || + (mode->flags & DRM_MODE_FLAG_INTERLACE)) + continue; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_display.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_display.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_display.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_display.c 2011-02-20 23:32:11.000000000 +0100 +@@ -32,6 +32,7 @@ + #include "nouveau_hw.h" + #include "nouveau_crtc.h" + #include "nouveau_dma.h" ++#include "nv50_display.h" + + static void + nouveau_user_framebuffer_destroy(struct drm_framebuffer *drm_fb) +@@ -61,18 +62,59 @@ + }; + + int +-nouveau_framebuffer_init(struct drm_device *dev, struct nouveau_framebuffer *nouveau_fb, +- struct drm_mode_fb_cmd *mode_cmd, struct nouveau_bo *nvbo) ++nouveau_framebuffer_init(struct drm_device *dev, ++ struct nouveau_framebuffer *nv_fb, ++ struct drm_mode_fb_cmd *mode_cmd, ++ struct nouveau_bo *nvbo) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct drm_framebuffer *fb = &nv_fb->base; + int ret; + +- ret = drm_framebuffer_init(dev, &nouveau_fb->base, &nouveau_framebuffer_funcs); ++ ret = drm_framebuffer_init(dev, fb, &nouveau_framebuffer_funcs); + if (ret) { + return ret; + } + +- drm_helper_mode_fill_fb_struct(&nouveau_fb->base, mode_cmd); +- nouveau_fb->nvbo = nvbo; ++ drm_helper_mode_fill_fb_struct(fb, mode_cmd); ++ nv_fb->nvbo = nvbo; ++ ++ if (dev_priv->card_type >= NV_50) { ++ u32 tile_flags = nouveau_bo_tile_layout(nvbo); ++ if (tile_flags == 0x7a00 || ++ tile_flags == 0xfe00) ++ nv_fb->r_dma = NvEvoFB32; ++ else ++ if (tile_flags == 0x7000) ++ nv_fb->r_dma = NvEvoFB16; ++ else ++ nv_fb->r_dma = NvEvoVRAM_LP; ++ ++ switch (fb->depth) { ++ case 8: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_8; break; ++ case 15: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_15; break; ++ case 16: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_16; break; ++ case 24: ++ case 32: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_24; break; ++ case 30: nv_fb->r_format = NV50_EVO_CRTC_FB_DEPTH_30; break; ++ default: ++ NV_ERROR(dev, "unknown depth %d\n", fb->depth); ++ return -EINVAL; ++ } ++ ++ if (dev_priv->chipset == 0x50) ++ nv_fb->r_format |= (tile_flags << 8); ++ ++ if (!tile_flags) ++ nv_fb->r_pitch = 0x00100000 | fb->pitch; ++ else { ++ u32 mode = nvbo->tile_mode; ++ if (dev_priv->card_type >= NV_C0) ++ mode >>= 4; ++ nv_fb->r_pitch = ((fb->pitch / 4) << 4) | mode; ++ } ++ } ++ + return 0; + } + +@@ -182,6 +224,7 @@ + struct nouveau_page_flip_state *s, + struct nouveau_fence **pfence) + { ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_device *dev = chan->dev; + unsigned long flags; + int ret; +@@ -201,9 +244,12 @@ + if (ret) + goto fail; + +- BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); +- OUT_RING(chan, 0); +- FIRE_RING(chan); ++ if (dev_priv->card_type < NV_C0) ++ BEGIN_RING(chan, NvSubSw, NV_SW_PAGE_FLIP, 1); ++ else ++ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0500, 1); ++ OUT_RING (chan, 0); ++ FIRE_RING (chan); + + ret = nouveau_fence_new(chan, pfence, true); + if (ret) +@@ -244,7 +290,7 @@ + + /* Initialize a page flip struct */ + *s = (struct nouveau_page_flip_state) +- { { }, s->event, nouveau_crtc(crtc)->index, ++ { { }, event, nouveau_crtc(crtc)->index, + fb->bits_per_pixel, fb->pitch, crtc->x, crtc->y, + new_bo->bo.offset }; + +@@ -255,6 +301,14 @@ + mutex_lock(&chan->mutex); + + /* Emit a page flip */ ++ if (dev_priv->card_type >= NV_50) { ++ ret = nv50_display_flip_next(crtc, fb, chan); ++ if (ret) { ++ nouveau_channel_put(&chan); ++ goto fail_unreserve; ++ } ++ } ++ + ret = nouveau_page_flip_emit(chan, old_bo, new_bo, s, &fence); + nouveau_channel_put(&chan); + if (ret) +@@ -305,7 +359,8 @@ + } + + list_del(&s->head); +- *ps = *s; ++ if (ps) ++ *ps = *s; + kfree(s); + + spin_unlock_irqrestore(&dev->event_lock, flags); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_dma.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_dma.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_dma.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_dma.c 2011-02-20 23:32:11.000000000 +0100 +@@ -96,13 +96,15 @@ + OUT_RING(chan, 0); + + /* Initialise NV_MEMORY_TO_MEMORY_FORMAT */ +- ret = RING_SPACE(chan, 4); ++ ret = RING_SPACE(chan, 6); + if (ret) + return ret; + BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_NAME, 1); +- OUT_RING(chan, NvM2MF); +- BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 1); +- OUT_RING(chan, NvNotify0); ++ OUT_RING (chan, NvM2MF); ++ BEGIN_RING(chan, NvSubM2MF, NV_MEMORY_TO_MEMORY_FORMAT_DMA_NOTIFY, 3); ++ OUT_RING (chan, NvNotify0); ++ OUT_RING (chan, chan->vram_handle); ++ OUT_RING (chan, chan->gart_handle); + + /* Sit back and pray the channel works.. */ + FIRE_RING(chan); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_dma.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_dma.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_dma.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_dma.h 2011-02-20 23:32:11.000000000 +0100 +@@ -61,8 +61,6 @@ + NvM2MF = 0x80000001, + NvDmaFB = 0x80000002, + NvDmaTT = 0x80000003, +- NvDmaVRAM = 0x80000004, +- NvDmaGART = 0x80000005, + NvNotify0 = 0x80000006, + Nv2D = 0x80000007, + NvCtxSurf2D = 0x80000008, +@@ -73,12 +71,15 @@ + NvImageBlit = 0x8000000d, + NvSw = 0x8000000e, + NvSema = 0x8000000f, ++ NvEvoSema0 = 0x80000010, ++ NvEvoSema1 = 0x80000011, + + /* G80+ display objects */ + NvEvoVRAM = 0x01000000, + NvEvoFB16 = 0x01000001, + NvEvoFB32 = 0x01000002, +- NvEvoVRAM_LP = 0x01000003 ++ NvEvoVRAM_LP = 0x01000003, ++ NvEvoSync = 0xcafe0000 + }; + + #define NV_MEMORY_TO_MEMORY_FORMAT 0x00000039 +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_dp.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_dp.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_dp.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_dp.c 2011-02-20 23:32:11.000000000 +0100 +@@ -175,7 +175,6 @@ + { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; +- struct bit_displayport_encoder_table_entry *dpse; + struct bit_displayport_encoder_table *dpe; + int ret, i, dpe_headerlen, vs = 0, pre = 0; + uint8_t request[2]; +@@ -183,7 +182,6 @@ + dpe = nouveau_bios_dp_table(dev, nv_encoder->dcb, &dpe_headerlen); + if (!dpe) + return false; +- dpse = (void *)((char *)dpe + dpe_headerlen); + + ret = auxch_rd(encoder, DP_ADJUST_REQUEST_LANE0_1, request, 2); + if (ret) +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_drv.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_drv.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-02-20 23:32:11.000000000 +0100 +@@ -57,7 +57,7 @@ + #include "nouveau_util.h" + + struct nouveau_grctx; +-struct nouveau_vram; ++struct nouveau_mem; + #include "nouveau_vm.h" + + #define MAX_NUM_DCB_ENTRIES 16 +@@ -65,13 +65,16 @@ + #define NOUVEAU_MAX_CHANNEL_NR 128 + #define NOUVEAU_MAX_TILE_NR 15 + +-struct nouveau_vram { ++struct nouveau_mem { + struct drm_device *dev; + + struct nouveau_vma bar_vma; ++ struct nouveau_vma tmp_vma; + u8 page_shift; + ++ struct drm_mm_node *tag; + struct list_head regions; ++ dma_addr_t *pages; + u32 memtype; + u64 offset; + u64 size; +@@ -90,6 +93,7 @@ + struct nouveau_bo { + struct ttm_buffer_object bo; + struct ttm_placement placement; ++ u32 valid_domains; + u32 placements[3]; + u32 busy_placements[3]; + struct ttm_bo_kmap_obj kmap; +@@ -104,8 +108,6 @@ + struct nouveau_channel *channel; + + struct nouveau_vma vma; +- bool mappable; +- bool no_vm; + + uint32_t tile_mode; + uint32_t tile_flags; +@@ -387,6 +389,7 @@ + }; + + struct nouveau_display_engine { ++ void *priv; + int (*early_init)(struct drm_device *); + void (*late_takedown)(struct drm_device *); + int (*create)(struct drm_device *); +@@ -509,8 +512,8 @@ + struct nouveau_vram_engine { + int (*init)(struct drm_device *); + int (*get)(struct drm_device *, u64, u32 align, u32 size_nc, +- u32 type, struct nouveau_vram **); +- void (*put)(struct drm_device *, struct nouveau_vram **); ++ u32 type, struct nouveau_mem **); ++ void (*put)(struct drm_device *, struct nouveau_mem **); + + bool (*flags_valid)(struct drm_device *, u32 tile_flags); + }; +@@ -652,8 +655,6 @@ + /* interrupt handling */ + void (*irq_handler[32])(struct drm_device *); + bool msi_enabled; +- struct workqueue_struct *wq; +- struct work_struct irq_work; + + struct list_head vbl_waiting; + +@@ -691,15 +692,22 @@ + struct { + enum { + NOUVEAU_GART_NONE = 0, +- NOUVEAU_GART_AGP, +- NOUVEAU_GART_SGDMA ++ NOUVEAU_GART_AGP, /* AGP */ ++ NOUVEAU_GART_PDMA, /* paged dma object */ ++ NOUVEAU_GART_HW /* on-chip gart/vm */ + } type; + uint64_t aper_base; + uint64_t aper_size; + uint64_t aper_free; + ++ struct ttm_backend_func *func; ++ ++ struct { ++ struct page *page; ++ dma_addr_t addr; ++ } dummy; ++ + struct nouveau_gpuobj *sg_ctxdma; +- struct nouveau_vma vma; + } gart_info; + + /* nv10-nv40 tiling regions */ +@@ -740,14 +748,6 @@ + + struct backlight_device *backlight; + +- struct nouveau_channel *evo; +- u32 evo_alloc; +- struct { +- struct dcb_entry *dcb; +- u16 script; +- u32 pclk; +- } evo_irq; +- + struct { + struct dentry *channel_root; + } debugfs; +@@ -847,6 +847,7 @@ + struct nouveau_tile_reg *tile, + struct nouveau_fence *fence); + extern const struct ttm_mem_type_manager_func nouveau_vram_manager; ++extern const struct ttm_mem_type_manager_func nouveau_gart_manager; + + /* nouveau_notifier.c */ + extern int nouveau_notifier_init_channel(struct nouveau_channel *); +@@ -1294,7 +1295,7 @@ + extern int nouveau_bo_new(struct drm_device *, struct nouveau_channel *, + int size, int align, uint32_t flags, + uint32_t tile_mode, uint32_t tile_flags, +- bool no_vm, bool mappable, struct nouveau_bo **); ++ struct nouveau_bo **); + extern int nouveau_bo_pin(struct nouveau_bo *, uint32_t flags); + extern int nouveau_bo_unpin(struct nouveau_bo *); + extern int nouveau_bo_map(struct nouveau_bo *); +@@ -1355,9 +1356,9 @@ + + /* nouveau_gem.c */ + extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, +- int size, int align, uint32_t flags, ++ int size, int align, uint32_t domain, + uint32_t tile_mode, uint32_t tile_flags, +- bool no_vm, bool mappable, struct nouveau_bo **); ++ struct nouveau_bo **); + extern int nouveau_gem_object_new(struct drm_gem_object *); + extern void nouveau_gem_object_del(struct drm_gem_object *); + extern int nouveau_gem_ioctl_new(struct drm_device *, void *, +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_fbcon.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_fbcon.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2011-02-20 23:32:11.000000000 +0100 +@@ -296,8 +296,8 @@ + size = mode_cmd.pitch * mode_cmd.height; + size = roundup(size, PAGE_SIZE); + +- ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, TTM_PL_FLAG_VRAM, +- 0, 0x0000, false, true, &nvbo); ++ ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, ++ NOUVEAU_GEM_DOMAIN_VRAM, 0, 0x0000, &nvbo); + if (ret) { + NV_ERROR(dev, "failed to allocate framebuffer\n"); + goto out; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_fb.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_fb.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_fb.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_fb.h 2011-02-20 23:32:11.000000000 +0100 +@@ -30,6 +30,9 @@ + struct nouveau_framebuffer { + struct drm_framebuffer base; + struct nouveau_bo *nvbo; ++ u32 r_dma; ++ u32 r_format; ++ u32 r_pitch; + }; + + static inline struct nouveau_framebuffer * +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_fence.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_fence.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_fence.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_fence.c 2011-02-20 23:32:11.000000000 +0100 +@@ -32,8 +32,7 @@ + #include "nouveau_dma.h" + + #define USE_REFCNT(dev) (nouveau_private(dev)->chipset >= 0x10) +-#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17 && \ +- nouveau_private(dev)->card_type < NV_C0) ++#define USE_SEMA(dev) (nouveau_private(dev)->chipset >= 0x17) + + struct nouveau_fence { + struct nouveau_channel *channel; +@@ -259,11 +258,12 @@ + } + + static struct nouveau_semaphore * +-alloc_semaphore(struct drm_device *dev) ++semaphore_alloc(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_semaphore *sema; +- int ret; ++ int size = (dev_priv->chipset < 0x84) ? 4 : 16; ++ int ret, i; + + if (!USE_SEMA(dev)) + return NULL; +@@ -277,9 +277,9 @@ + goto fail; + + spin_lock(&dev_priv->fence.lock); +- sema->mem = drm_mm_search_free(&dev_priv->fence.heap, 4, 0, 0); ++ sema->mem = drm_mm_search_free(&dev_priv->fence.heap, size, 0, 0); + if (sema->mem) +- sema->mem = drm_mm_get_block_atomic(sema->mem, 4, 0); ++ sema->mem = drm_mm_get_block_atomic(sema->mem, size, 0); + spin_unlock(&dev_priv->fence.lock); + + if (!sema->mem) +@@ -287,7 +287,8 @@ + + kref_init(&sema->ref); + sema->dev = dev; +- nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 0); ++ for (i = sema->mem->start; i < sema->mem->start + size; i += 4) ++ nouveau_bo_wr32(dev_priv->fence.bo, i / 4, 0); + + return sema; + fail: +@@ -296,7 +297,7 @@ + } + + static void +-free_semaphore(struct kref *ref) ++semaphore_free(struct kref *ref) + { + struct nouveau_semaphore *sema = + container_of(ref, struct nouveau_semaphore, ref); +@@ -318,61 +319,107 @@ + if (unlikely(!signalled)) + nouveau_bo_wr32(dev_priv->fence.bo, sema->mem->start / 4, 1); + +- kref_put(&sema->ref, free_semaphore); ++ kref_put(&sema->ref, semaphore_free); + } + + static int +-emit_semaphore(struct nouveau_channel *chan, int method, +- struct nouveau_semaphore *sema) ++semaphore_acquire(struct nouveau_channel *chan, struct nouveau_semaphore *sema) + { +- struct drm_nouveau_private *dev_priv = sema->dev->dev_private; +- struct nouveau_fence *fence; +- bool smart = (dev_priv->card_type >= NV_50); ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct nouveau_fence *fence = NULL; + int ret; + +- ret = RING_SPACE(chan, smart ? 8 : 4); ++ if (dev_priv->chipset < 0x84) { ++ ret = RING_SPACE(chan, 3); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 2); ++ OUT_RING (chan, sema->mem->start); ++ OUT_RING (chan, 1); ++ } else ++ if (dev_priv->chipset < 0xc0) { ++ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; ++ u64 offset = vma->offset + sema->mem->start; ++ ++ ret = RING_SPACE(chan, 5); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubSw, 0x0010, 4); ++ OUT_RING (chan, upper_32_bits(offset)); ++ OUT_RING (chan, lower_32_bits(offset)); ++ OUT_RING (chan, 1); ++ OUT_RING (chan, 1); /* ACQUIRE_EQ */ ++ } else { ++ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; ++ u64 offset = vma->offset + sema->mem->start; ++ ++ ret = RING_SPACE(chan, 5); ++ if (ret) ++ return ret; ++ ++ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); ++ OUT_RING (chan, upper_32_bits(offset)); ++ OUT_RING (chan, lower_32_bits(offset)); ++ OUT_RING (chan, 1); ++ OUT_RING (chan, 0x1001); /* ACQUIRE_EQ */ ++ } ++ ++ /* Delay semaphore destruction until its work is done */ ++ ret = nouveau_fence_new(chan, &fence, true); + if (ret) + return ret; + +- if (smart) { +- BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); +- OUT_RING(chan, NvSema); +- } +- BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1); +- OUT_RING(chan, sema->mem->start); ++ kref_get(&sema->ref); ++ nouveau_fence_work(fence, semaphore_work, sema); ++ nouveau_fence_unref(&fence); ++ return 0; ++} + +- if (smart && method == NV_SW_SEMAPHORE_ACQUIRE) { +- /* +- * NV50 tries to be too smart and context-switch +- * between semaphores instead of doing a "first come, +- * first served" strategy like previous cards +- * do. +- * +- * That's bad because the ACQUIRE latency can get as +- * large as the PFIFO context time slice in the +- * typical DRI2 case where you have several +- * outstanding semaphores at the same moment. +- * +- * If we're going to ACQUIRE, force the card to +- * context switch before, just in case the matching +- * RELEASE is already scheduled to be executed in +- * another channel. +- */ +- BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1); +- OUT_RING(chan, 0); +- } +- +- BEGIN_RING(chan, NvSubSw, method, 1); +- OUT_RING(chan, 1); +- +- if (smart && method == NV_SW_SEMAPHORE_RELEASE) { +- /* +- * Force the card to context switch, there may be +- * another channel waiting for the semaphore we just +- * released. +- */ +- BEGIN_RING(chan, NvSubSw, NV_SW_YIELD, 1); +- OUT_RING(chan, 0); ++static int ++semaphore_release(struct nouveau_channel *chan, struct nouveau_semaphore *sema) ++{ ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct nouveau_fence *fence = NULL; ++ int ret; ++ ++ if (dev_priv->chipset < 0x84) { ++ ret = RING_SPACE(chan, 4); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_OFFSET, 1); ++ OUT_RING (chan, sema->mem->start); ++ BEGIN_RING(chan, NvSubSw, NV_SW_SEMAPHORE_RELEASE, 1); ++ OUT_RING (chan, 1); ++ } else ++ if (dev_priv->chipset < 0xc0) { ++ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; ++ u64 offset = vma->offset + sema->mem->start; ++ ++ ret = RING_SPACE(chan, 5); ++ if (ret) ++ return ret; ++ ++ BEGIN_RING(chan, NvSubSw, 0x0010, 4); ++ OUT_RING (chan, upper_32_bits(offset)); ++ OUT_RING (chan, lower_32_bits(offset)); ++ OUT_RING (chan, 1); ++ OUT_RING (chan, 2); /* RELEASE */ ++ } else { ++ struct nouveau_vma *vma = &dev_priv->fence.bo->vma; ++ u64 offset = vma->offset + sema->mem->start; ++ ++ ret = RING_SPACE(chan, 5); ++ if (ret) ++ return ret; ++ ++ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); ++ OUT_RING (chan, upper_32_bits(offset)); ++ OUT_RING (chan, lower_32_bits(offset)); ++ OUT_RING (chan, 1); ++ OUT_RING (chan, 0x1002); /* RELEASE */ + } + + /* Delay semaphore destruction until its work is done */ +@@ -383,7 +430,6 @@ + kref_get(&sema->ref); + nouveau_fence_work(fence, semaphore_work, sema); + nouveau_fence_unref(&fence); +- + return 0; + } + +@@ -400,7 +446,7 @@ + nouveau_fence_signalled(fence))) + goto out; + +- sema = alloc_semaphore(dev); ++ sema = semaphore_alloc(dev); + if (!sema) { + /* Early card or broken userspace, fall back to + * software sync. */ +@@ -418,17 +464,17 @@ + } + + /* Make wchan wait until it gets signalled */ +- ret = emit_semaphore(wchan, NV_SW_SEMAPHORE_ACQUIRE, sema); ++ ret = semaphore_acquire(wchan, sema); + if (ret) + goto out_unlock; + + /* Signal the semaphore from chan */ +- ret = emit_semaphore(chan, NV_SW_SEMAPHORE_RELEASE, sema); ++ ret = semaphore_release(chan, sema); + + out_unlock: + mutex_unlock(&chan->mutex); + out_unref: +- kref_put(&sema->ref, free_semaphore); ++ kref_put(&sema->ref, semaphore_free); + out: + if (chan) + nouveau_channel_put_unlocked(&chan); +@@ -449,22 +495,23 @@ + struct nouveau_gpuobj *obj = NULL; + int ret; + ++ if (dev_priv->card_type >= NV_C0) ++ goto out_initialised; ++ + /* Create an NV_SW object for various sync purposes */ + ret = nouveau_gpuobj_gr_new(chan, NvSw, NV_SW); + if (ret) + return ret; + + /* we leave subchannel empty for nvc0 */ +- if (dev_priv->card_type < NV_C0) { +- ret = RING_SPACE(chan, 2); +- if (ret) +- return ret; +- BEGIN_RING(chan, NvSubSw, 0, 1); +- OUT_RING(chan, NvSw); +- } ++ ret = RING_SPACE(chan, 2); ++ if (ret) ++ return ret; ++ BEGIN_RING(chan, NvSubSw, 0, 1); ++ OUT_RING(chan, NvSw); + + /* Create a DMA object for the shared cross-channel sync area. */ +- if (USE_SEMA(dev)) { ++ if (USE_SEMA(dev) && dev_priv->chipset < 0x84) { + struct ttm_mem_reg *mem = &dev_priv->fence.bo->bo.mem; + + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, +@@ -484,14 +531,20 @@ + return ret; + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); + OUT_RING(chan, NvSema); ++ } else { ++ ret = RING_SPACE(chan, 2); ++ if (ret) ++ return ret; ++ BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 1); ++ OUT_RING (chan, chan->vram_handle); /* whole VM */ + } + + FIRE_RING(chan); + ++out_initialised: + INIT_LIST_HEAD(&chan->fence.pending); + spin_lock_init(&chan->fence.lock); + atomic_set(&chan->fence.last_sequence_irq, 0); +- + return 0; + } + +@@ -519,12 +572,13 @@ + nouveau_fence_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int size = (dev_priv->chipset < 0x84) ? 4096 : 16384; + int ret; + + /* Create a shared VRAM heap for cross-channel sync. */ + if (USE_SEMA(dev)) { +- ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, +- 0, 0, false, true, &dev_priv->fence.bo); ++ ret = nouveau_bo_new(dev, NULL, size, 0, TTM_PL_FLAG_VRAM, ++ 0, 0, &dev_priv->fence.bo); + if (ret) + return ret; + +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_gem.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_gem.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_gem.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_gem.c 2011-02-20 23:32:11.000000000 +0100 +@@ -61,19 +61,36 @@ + + int + nouveau_gem_new(struct drm_device *dev, struct nouveau_channel *chan, +- int size, int align, uint32_t flags, uint32_t tile_mode, +- uint32_t tile_flags, bool no_vm, bool mappable, +- struct nouveau_bo **pnvbo) ++ int size, int align, uint32_t domain, uint32_t tile_mode, ++ uint32_t tile_flags, struct nouveau_bo **pnvbo) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_bo *nvbo; ++ u32 flags = 0; + int ret; + ++ if (domain & NOUVEAU_GEM_DOMAIN_VRAM) ++ flags |= TTM_PL_FLAG_VRAM; ++ if (domain & NOUVEAU_GEM_DOMAIN_GART) ++ flags |= TTM_PL_FLAG_TT; ++ if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU) ++ flags |= TTM_PL_FLAG_SYSTEM; ++ + ret = nouveau_bo_new(dev, chan, size, align, flags, tile_mode, +- tile_flags, no_vm, mappable, pnvbo); ++ tile_flags, pnvbo); + if (ret) + return ret; + nvbo = *pnvbo; + ++ /* we restrict allowed domains on nv50+ to only the types ++ * that were requested at creation time. not possibly on ++ * earlier chips without busting the ABI. ++ */ ++ nvbo->valid_domains = NOUVEAU_GEM_DOMAIN_VRAM | ++ NOUVEAU_GEM_DOMAIN_GART; ++ if (dev_priv->card_type >= NV_50) ++ nvbo->valid_domains &= domain; ++ + nvbo->gem = drm_gem_object_alloc(dev, nvbo->bo.mem.size); + if (!nvbo->gem) { + nouveau_bo_ref(NULL, pnvbo); +@@ -97,7 +114,7 @@ + + rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; + rep->offset = nvbo->bo.offset; +- rep->map_handle = nvbo->mappable ? nvbo->bo.addr_space_offset : 0; ++ rep->map_handle = nvbo->bo.addr_space_offset; + rep->tile_mode = nvbo->tile_mode; + rep->tile_flags = nvbo->tile_flags; + return 0; +@@ -111,19 +128,11 @@ + struct drm_nouveau_gem_new *req = data; + struct nouveau_bo *nvbo = NULL; + struct nouveau_channel *chan = NULL; +- uint32_t flags = 0; + int ret = 0; + + if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) + dev_priv->ttm.bdev.dev_mapping = dev_priv->dev->dev_mapping; + +- if (req->info.domain & NOUVEAU_GEM_DOMAIN_VRAM) +- flags |= TTM_PL_FLAG_VRAM; +- if (req->info.domain & NOUVEAU_GEM_DOMAIN_GART) +- flags |= TTM_PL_FLAG_TT; +- if (!flags || req->info.domain & NOUVEAU_GEM_DOMAIN_CPU) +- flags |= TTM_PL_FLAG_SYSTEM; +- + if (!dev_priv->engine.vram.flags_valid(dev, req->info.tile_flags)) { + NV_ERROR(dev, "bad page flags: 0x%08x\n", req->info.tile_flags); + return -EINVAL; +@@ -135,10 +144,9 @@ + return PTR_ERR(chan); + } + +- ret = nouveau_gem_new(dev, chan, req->info.size, req->align, flags, +- req->info.tile_mode, req->info.tile_flags, false, +- (req->info.domain & NOUVEAU_GEM_DOMAIN_MAPPABLE), +- &nvbo); ++ ret = nouveau_gem_new(dev, chan, req->info.size, req->align, ++ req->info.domain, req->info.tile_mode, ++ req->info.tile_flags, &nvbo); + if (chan) + nouveau_channel_put(&chan); + if (ret) +@@ -161,7 +169,7 @@ + { + struct nouveau_bo *nvbo = gem->driver_private; + struct ttm_buffer_object *bo = &nvbo->bo; +- uint32_t domains = valid_domains & ++ uint32_t domains = valid_domains & nvbo->valid_domains & + (write_domains ? write_domains : read_domains); + uint32_t pref_flags = 0, valid_flags = 0; + +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_mem.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_mem.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-02-20 23:32:11.000000000 +0100 +@@ -152,7 +152,6 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + +- nouveau_bo_unpin(dev_priv->vga_ram); + nouveau_bo_ref(NULL, &dev_priv->vga_ram); + + ttm_bo_device_release(&dev_priv->ttm.bdev); +@@ -393,11 +392,17 @@ + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + int ret, dma_bits; + +- if (dev_priv->card_type >= NV_50 && +- pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) +- dma_bits = 40; +- else +- dma_bits = 32; ++ dma_bits = 32; ++ if (dev_priv->card_type >= NV_50) { ++ if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(40))) ++ dma_bits = 40; ++ } else ++ if (drm_device_is_pcie(dev) && ++ dev_priv->chipset != 0x40 && ++ dev_priv->chipset != 0x45) { ++ if (pci_dma_supported(dev->pdev, DMA_BIT_MASK(39))) ++ dma_bits = 39; ++ } + + ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(dma_bits)); + if (ret) +@@ -455,13 +460,17 @@ + return ret; + } + +- ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM, +- 0, 0, true, true, &dev_priv->vga_ram); +- if (ret == 0) +- ret = nouveau_bo_pin(dev_priv->vga_ram, TTM_PL_FLAG_VRAM); +- if (ret) { +- NV_WARN(dev, "failed to reserve VGA memory\n"); +- nouveau_bo_ref(NULL, &dev_priv->vga_ram); ++ if (dev_priv->card_type < NV_50) { ++ ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM, ++ 0, 0, &dev_priv->vga_ram); ++ if (ret == 0) ++ ret = nouveau_bo_pin(dev_priv->vga_ram, ++ TTM_PL_FLAG_VRAM); ++ ++ if (ret) { ++ NV_WARN(dev, "failed to reserve VGA memory\n"); ++ nouveau_bo_ref(NULL, &dev_priv->vga_ram); ++ } + } + + dev_priv->fb_mtrr = drm_mtrr_add(pci_resource_start(dev->pdev, 1), +@@ -666,13 +675,14 @@ + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct nouveau_mm *mm; +- u32 b_size; ++ u64 size, block, rsvd; + int ret; + +- p_size = (p_size << PAGE_SHIFT) >> 12; +- b_size = dev_priv->vram_rblock_size >> 12; ++ rsvd = (256 * 1024); /* vga memory */ ++ size = (p_size << PAGE_SHIFT) - rsvd; ++ block = dev_priv->vram_rblock_size; + +- ret = nouveau_mm_init(&mm, 0, p_size, b_size); ++ ret = nouveau_mm_init(&mm, rsvd >> 12, size >> 12, block >> 12); + if (ret) + return ret; + +@@ -700,9 +710,15 @@ + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; ++ struct nouveau_mem *node = mem->mm_node; + struct drm_device *dev = dev_priv->dev; + +- vram->put(dev, (struct nouveau_vram **)&mem->mm_node); ++ if (node->tmp_vma.node) { ++ nouveau_vm_unmap(&node->tmp_vma); ++ nouveau_vm_put(&node->tmp_vma); ++ } ++ ++ vram->put(dev, (struct nouveau_mem **)&mem->mm_node); + } + + static int +@@ -715,7 +731,7 @@ + struct nouveau_vram_engine *vram = &dev_priv->engine.vram; + struct drm_device *dev = dev_priv->dev; + struct nouveau_bo *nvbo = nouveau_bo(bo); +- struct nouveau_vram *node; ++ struct nouveau_mem *node; + u32 size_nc = 0; + int ret; + +@@ -724,7 +740,7 @@ + + ret = vram->get(dev, mem->num_pages << PAGE_SHIFT, + mem->page_alignment << PAGE_SHIFT, size_nc, +- (nvbo->tile_flags >> 8) & 0xff, &node); ++ (nvbo->tile_flags >> 8) & 0x3ff, &node); + if (ret) + return ret; + +@@ -769,3 +785,84 @@ + nouveau_vram_manager_del, + nouveau_vram_manager_debug + }; ++ ++static int ++nouveau_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) ++{ ++ return 0; ++} ++ ++static int ++nouveau_gart_manager_fini(struct ttm_mem_type_manager *man) ++{ ++ return 0; ++} ++ ++static void ++nouveau_gart_manager_del(struct ttm_mem_type_manager *man, ++ struct ttm_mem_reg *mem) ++{ ++ struct nouveau_mem *node = mem->mm_node; ++ ++ if (node->tmp_vma.node) { ++ nouveau_vm_unmap(&node->tmp_vma); ++ nouveau_vm_put(&node->tmp_vma); ++ } ++ mem->mm_node = NULL; ++} ++ ++static int ++nouveau_gart_manager_new(struct ttm_mem_type_manager *man, ++ struct ttm_buffer_object *bo, ++ struct ttm_placement *placement, ++ struct ttm_mem_reg *mem) ++{ ++ struct drm_nouveau_private *dev_priv = nouveau_bdev(bo->bdev); ++ struct nouveau_bo *nvbo = nouveau_bo(bo); ++ struct nouveau_vma *vma = &nvbo->vma; ++ struct nouveau_vm *vm = vma->vm; ++ struct nouveau_mem *node; ++ int ret; ++ ++ if (unlikely((mem->num_pages << PAGE_SHIFT) >= ++ dev_priv->gart_info.aper_size)) ++ return -ENOMEM; ++ ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (!node) ++ return -ENOMEM; ++ ++ /* This node must be for evicting large-paged VRAM ++ * to system memory. Due to a nv50 limitation of ++ * not being able to mix large/small pages within ++ * the same PDE, we need to create a temporary ++ * small-paged VMA for the eviction. ++ */ ++ if (vma->node->type != vm->spg_shift) { ++ ret = nouveau_vm_get(vm, (u64)vma->node->length << 12, ++ vm->spg_shift, NV_MEM_ACCESS_RW, ++ &node->tmp_vma); ++ if (ret) { ++ kfree(node); ++ return ret; ++ } ++ } ++ ++ node->page_shift = nvbo->vma.node->type; ++ mem->mm_node = node; ++ mem->start = 0; ++ return 0; ++} ++ ++void ++nouveau_gart_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) ++{ ++} ++ ++const struct ttm_mem_type_manager_func nouveau_gart_manager = { ++ nouveau_gart_manager_init, ++ nouveau_gart_manager_fini, ++ nouveau_gart_manager_new, ++ nouveau_gart_manager_del, ++ nouveau_gart_manager_debug ++}; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_mm.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_mm.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_mm.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_mm.h 2011-02-20 23:32:11.000000000 +0100 +@@ -53,13 +53,13 @@ + + int nv50_vram_init(struct drm_device *); + int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, +- u32 memtype, struct nouveau_vram **); +-void nv50_vram_del(struct drm_device *, struct nouveau_vram **); ++ u32 memtype, struct nouveau_mem **); ++void nv50_vram_del(struct drm_device *, struct nouveau_mem **); + bool nv50_vram_flags_valid(struct drm_device *, u32 tile_flags); + + int nvc0_vram_init(struct drm_device *); + int nvc0_vram_new(struct drm_device *, u64 size, u32 align, u32 ncmin, +- u32 memtype, struct nouveau_vram **); ++ u32 memtype, struct nouveau_mem **); + bool nvc0_vram_flags_valid(struct drm_device *, u32 tile_flags); + + #endif +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_notifier.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_notifier.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_notifier.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_notifier.c 2011-02-20 23:32:11.000000000 +0100 +@@ -39,12 +39,11 @@ + int ret; + + if (nouveau_vram_notify) +- flags = TTM_PL_FLAG_VRAM; ++ flags = NOUVEAU_GEM_DOMAIN_VRAM; + else +- flags = TTM_PL_FLAG_TT; ++ flags = NOUVEAU_GEM_DOMAIN_GART; + +- ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, +- 0, 0x0000, false, true, &ntfy); ++ ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy); + if (ret) + return ret; + +@@ -99,6 +98,7 @@ + int size, uint32_t *b_offset) + { + struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *nobj = NULL; + struct drm_mm_node *mem; + uint32_t offset; +@@ -112,11 +112,16 @@ + return -ENOMEM; + } + +- if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) +- target = NV_MEM_TARGET_VRAM; +- else +- target = NV_MEM_TARGET_GART; +- offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; ++ if (dev_priv->card_type < NV_50) { ++ if (chan->notifier_bo->bo.mem.mem_type == TTM_PL_VRAM) ++ target = NV_MEM_TARGET_VRAM; ++ else ++ target = NV_MEM_TARGET_GART; ++ offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; ++ } else { ++ target = NV_MEM_TARGET_VM; ++ offset = chan->notifier_bo->vma.offset; ++ } + offset += mem->start; + + ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_IN_MEMORY, offset, +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_object.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_object.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_object.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_object.c 2011-02-20 23:32:11.000000000 +0100 +@@ -36,6 +36,7 @@ + #include "nouveau_drm.h" + #include "nouveau_ramht.h" + #include "nouveau_vm.h" ++#include "nv50_display.h" + + struct nouveau_gpuobj_method { + struct list_head head; +@@ -490,16 +491,22 @@ + } + + if (target == NV_MEM_TARGET_GART) { +- if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) { +- target = NV_MEM_TARGET_PCI_NOSNOOP; +- base += dev_priv->gart_info.aper_base; +- } else +- if (base != 0) { +- base = nouveau_sgdma_get_physical(dev, base); ++ struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; ++ ++ if (dev_priv->gart_info.type == NOUVEAU_GART_PDMA) { ++ if (base == 0) { ++ nouveau_gpuobj_ref(gart, pobj); ++ return 0; ++ } ++ ++ base = nouveau_sgdma_get_physical(dev, base); + target = NV_MEM_TARGET_PCI; + } else { +- nouveau_gpuobj_ref(dev_priv->gart_info.sg_ctxdma, pobj); +- return 0; ++ base += dev_priv->gart_info.aper_base; ++ if (dev_priv->gart_info.type == NOUVEAU_GART_AGP) ++ target = NV_MEM_TARGET_PCI_NOSNOOP; ++ else ++ target = NV_MEM_TARGET_PCI; + } + } + +@@ -776,7 +783,7 @@ + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *vram = NULL, *tt = NULL; +- int ret; ++ int ret, i; + + NV_DEBUG(dev, "ch%d vram=0x%08x tt=0x%08x\n", chan->id, vram_h, tt_h); + +@@ -841,6 +848,25 @@ + nouveau_gpuobj_ref(NULL, &ramht); + if (ret) + return ret; ++ ++ /* dma objects for display sync channel semaphore blocks */ ++ for (i = 0; i < 2; i++) { ++ struct nouveau_gpuobj *sem = NULL; ++ struct nv50_display_crtc *dispc = ++ &nv50_display(dev)->crtc[i]; ++ u64 offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT; ++ ++ ret = nouveau_gpuobj_dma_new(chan, 0x3d, offset, 0xfff, ++ NV_MEM_ACCESS_RW, ++ NV_MEM_TARGET_VRAM, &sem); ++ if (ret) ++ return ret; ++ ++ ret = nouveau_ramht_insert(chan, NvEvoSema0 + i, sem); ++ nouveau_gpuobj_ref(NULL, &sem); ++ if (ret) ++ return ret; ++ } + } + + /* VRAM ctxdma */ +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_pm.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_pm.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-02-20 23:32:11.000000000 +0100 +@@ -543,7 +543,7 @@ + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm_level *perflvl; + +- if (pm->cur == &pm->boot) ++ if (!pm->cur || pm->cur == &pm->boot) + return; + + perflvl = pm->cur; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_ramht.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_ramht.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_ramht.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_ramht.c 2011-02-20 23:32:11.000000000 +0100 +@@ -114,7 +114,9 @@ + (gpuobj->engine << NV40_RAMHT_CONTEXT_ENGINE_SHIFT); + } else { + if (gpuobj->engine == NVOBJ_ENGINE_DISPLAY) { +- ctx = (gpuobj->cinst << 10) | chan->id; ++ ctx = (gpuobj->cinst << 10) | ++ (chan->id << 28) | ++ chan->id; /* HASH_TAG */ + } else { + ctx = (gpuobj->cinst >> 4) | + ((gpuobj->engine << +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_sgdma.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_sgdma.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_sgdma.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_sgdma.c 2011-02-20 23:32:11.000000000 +0100 +@@ -74,8 +74,24 @@ + } + } + ++static void ++nouveau_sgdma_destroy(struct ttm_backend *be) ++{ ++ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; ++ ++ if (be) { ++ NV_DEBUG(nvbe->dev, "\n"); ++ ++ if (nvbe) { ++ if (nvbe->pages) ++ be->func->clear(be); ++ kfree(nvbe); ++ } ++ } ++} ++ + static int +-nouveau_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) ++nv04_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_device *dev = nvbe->dev; +@@ -102,7 +118,7 @@ + } + + static int +-nouveau_sgdma_unbind(struct ttm_backend *be) ++nv04_sgdma_unbind(struct ttm_backend *be) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_device *dev = nvbe->dev; +@@ -125,59 +141,245 @@ + return 0; + } + ++static struct ttm_backend_func nv04_sgdma_backend = { ++ .populate = nouveau_sgdma_populate, ++ .clear = nouveau_sgdma_clear, ++ .bind = nv04_sgdma_bind, ++ .unbind = nv04_sgdma_unbind, ++ .destroy = nouveau_sgdma_destroy ++}; ++ + static void +-nouveau_sgdma_destroy(struct ttm_backend *be) ++nv41_sgdma_flush(struct nouveau_sgdma_be *nvbe) ++{ ++ struct drm_device *dev = nvbe->dev; ++ ++ nv_wr32(dev, 0x100810, 0x00000022); ++ if (!nv_wait(dev, 0x100810, 0x00000100, 0x00000100)) ++ NV_ERROR(dev, "vm flush timeout: 0x%08x\n", ++ nv_rd32(dev, 0x100810)); ++ nv_wr32(dev, 0x100810, 0x00000000); ++} ++ ++static int ++nv41_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; ++ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; ++ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; ++ dma_addr_t *list = nvbe->pages; ++ u32 pte = mem->start << 2; ++ u32 cnt = nvbe->nr_pages; + +- if (be) { +- NV_DEBUG(nvbe->dev, "\n"); ++ nvbe->offset = mem->start << PAGE_SHIFT; + +- if (nvbe) { +- if (nvbe->pages) +- be->func->clear(be); +- kfree(nvbe); ++ while (cnt--) { ++ nv_wo32(pgt, pte, (*list++ >> 7) | 1); ++ pte += 4; ++ } ++ ++ nv41_sgdma_flush(nvbe); ++ nvbe->bound = true; ++ return 0; ++} ++ ++static int ++nv41_sgdma_unbind(struct ttm_backend *be) ++{ ++ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; ++ struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; ++ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; ++ u32 pte = (nvbe->offset >> 12) << 2; ++ u32 cnt = nvbe->nr_pages; ++ ++ while (cnt--) { ++ nv_wo32(pgt, pte, 0x00000000); ++ pte += 4; ++ } ++ ++ nv41_sgdma_flush(nvbe); ++ nvbe->bound = false; ++ return 0; ++} ++ ++static struct ttm_backend_func nv41_sgdma_backend = { ++ .populate = nouveau_sgdma_populate, ++ .clear = nouveau_sgdma_clear, ++ .bind = nv41_sgdma_bind, ++ .unbind = nv41_sgdma_unbind, ++ .destroy = nouveau_sgdma_destroy ++}; ++ ++static void ++nv44_sgdma_flush(struct nouveau_sgdma_be *nvbe) ++{ ++ struct drm_device *dev = nvbe->dev; ++ ++ nv_wr32(dev, 0x100814, (nvbe->nr_pages - 1) << 12); ++ nv_wr32(dev, 0x100808, nvbe->offset | 0x20); ++ if (!nv_wait(dev, 0x100808, 0x00000001, 0x00000001)) ++ NV_ERROR(dev, "gart flush timeout: 0x%08x\n", ++ nv_rd32(dev, 0x100808)); ++ nv_wr32(dev, 0x100808, 0x00000000); ++} ++ ++static void ++nv44_sgdma_fill(struct nouveau_gpuobj *pgt, dma_addr_t *list, u32 base, u32 cnt) ++{ ++ struct drm_nouveau_private *dev_priv = pgt->dev->dev_private; ++ dma_addr_t dummy = dev_priv->gart_info.dummy.addr; ++ u32 pte, tmp[4]; ++ ++ pte = base >> 2; ++ base &= ~0x0000000f; ++ ++ tmp[0] = nv_ro32(pgt, base + 0x0); ++ tmp[1] = nv_ro32(pgt, base + 0x4); ++ tmp[2] = nv_ro32(pgt, base + 0x8); ++ tmp[3] = nv_ro32(pgt, base + 0xc); ++ while (cnt--) { ++ u32 addr = list ? (*list++ >> 12) : (dummy >> 12); ++ switch (pte++ & 0x3) { ++ case 0: ++ tmp[0] &= ~0x07ffffff; ++ tmp[0] |= addr; ++ break; ++ case 1: ++ tmp[0] &= ~0xf8000000; ++ tmp[0] |= addr << 27; ++ tmp[1] &= ~0x003fffff; ++ tmp[1] |= addr >> 5; ++ break; ++ case 2: ++ tmp[1] &= ~0xffc00000; ++ tmp[1] |= addr << 22; ++ tmp[2] &= ~0x0001ffff; ++ tmp[2] |= addr >> 10; ++ break; ++ case 3: ++ tmp[2] &= ~0xfffe0000; ++ tmp[2] |= addr << 17; ++ tmp[3] &= ~0x00000fff; ++ tmp[3] |= addr >> 15; ++ break; + } + } ++ ++ tmp[3] |= 0x40000000; ++ ++ nv_wo32(pgt, base + 0x0, tmp[0]); ++ nv_wo32(pgt, base + 0x4, tmp[1]); ++ nv_wo32(pgt, base + 0x8, tmp[2]); ++ nv_wo32(pgt, base + 0xc, tmp[3]); + } + + static int +-nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) ++nv44_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; ++ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; ++ dma_addr_t *list = nvbe->pages; ++ u32 pte = mem->start << 2, tmp[4]; ++ u32 cnt = nvbe->nr_pages; ++ int i; + + nvbe->offset = mem->start << PAGE_SHIFT; + +- nouveau_vm_map_sg(&dev_priv->gart_info.vma, nvbe->offset, +- nvbe->nr_pages << PAGE_SHIFT, nvbe->pages); ++ if (pte & 0x0000000c) { ++ u32 max = 4 - ((pte >> 2) & 0x3); ++ u32 part = (cnt > max) ? max : cnt; ++ nv44_sgdma_fill(pgt, list, pte, part); ++ pte += (part << 2); ++ list += part; ++ cnt -= part; ++ } ++ ++ while (cnt >= 4) { ++ for (i = 0; i < 4; i++) ++ tmp[i] = *list++ >> 12; ++ nv_wo32(pgt, pte + 0x0, tmp[0] >> 0 | tmp[1] << 27); ++ nv_wo32(pgt, pte + 0x4, tmp[1] >> 5 | tmp[2] << 22); ++ nv_wo32(pgt, pte + 0x8, tmp[2] >> 10 | tmp[3] << 17); ++ nv_wo32(pgt, pte + 0xc, tmp[3] >> 15 | 0x40000000); ++ pte += 0x10; ++ cnt -= 4; ++ } ++ ++ if (cnt) ++ nv44_sgdma_fill(pgt, list, pte, cnt); ++ ++ nv44_sgdma_flush(nvbe); + nvbe->bound = true; + return 0; + } + + static int +-nv50_sgdma_unbind(struct ttm_backend *be) ++nv44_sgdma_unbind(struct ttm_backend *be) + { + struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; + struct drm_nouveau_private *dev_priv = nvbe->dev->dev_private; ++ struct nouveau_gpuobj *pgt = dev_priv->gart_info.sg_ctxdma; ++ u32 pte = (nvbe->offset >> 12) << 2; ++ u32 cnt = nvbe->nr_pages; ++ ++ if (pte & 0x0000000c) { ++ u32 max = 4 - ((pte >> 2) & 0x3); ++ u32 part = (cnt > max) ? max : cnt; ++ nv44_sgdma_fill(pgt, NULL, pte, part); ++ pte += (part << 2); ++ cnt -= part; ++ } + +- if (!nvbe->bound) +- return 0; ++ while (cnt >= 4) { ++ nv_wo32(pgt, pte + 0x0, 0x00000000); ++ nv_wo32(pgt, pte + 0x4, 0x00000000); ++ nv_wo32(pgt, pte + 0x8, 0x00000000); ++ nv_wo32(pgt, pte + 0xc, 0x00000000); ++ pte += 0x10; ++ cnt -= 4; ++ } + +- nouveau_vm_unmap_at(&dev_priv->gart_info.vma, nvbe->offset, +- nvbe->nr_pages << PAGE_SHIFT); ++ if (cnt) ++ nv44_sgdma_fill(pgt, NULL, pte, cnt); ++ ++ nv44_sgdma_flush(nvbe); + nvbe->bound = false; + return 0; + } + +-static struct ttm_backend_func nouveau_sgdma_backend = { ++static struct ttm_backend_func nv44_sgdma_backend = { + .populate = nouveau_sgdma_populate, + .clear = nouveau_sgdma_clear, +- .bind = nouveau_sgdma_bind, +- .unbind = nouveau_sgdma_unbind, ++ .bind = nv44_sgdma_bind, ++ .unbind = nv44_sgdma_unbind, + .destroy = nouveau_sgdma_destroy + }; + ++static int ++nv50_sgdma_bind(struct ttm_backend *be, struct ttm_mem_reg *mem) ++{ ++ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; ++ struct nouveau_mem *node = mem->mm_node; ++ /* noop: bound in move_notify() */ ++ node->pages = nvbe->pages; ++ nvbe->pages = (dma_addr_t *)node; ++ nvbe->bound = true; ++ return 0; ++} ++ ++static int ++nv50_sgdma_unbind(struct ttm_backend *be) ++{ ++ struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)be; ++ struct nouveau_mem *node = (struct nouveau_mem *)nvbe->pages; ++ /* noop: unbound in move_notify() */ ++ nvbe->pages = node->pages; ++ node->pages = NULL; ++ nvbe->bound = false; ++ return 0; ++} ++ + static struct ttm_backend_func nv50_sgdma_backend = { + .populate = nouveau_sgdma_populate, + .clear = nouveau_sgdma_clear, +@@ -198,10 +400,7 @@ + + nvbe->dev = dev; + +- if (dev_priv->card_type < NV_50) +- nvbe->backend.func = &nouveau_sgdma_backend; +- else +- nvbe->backend.func = &nv50_sgdma_backend; ++ nvbe->backend.func = dev_priv->gart_info.func; + return &nvbe->backend; + } + +@@ -210,21 +409,65 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpuobj *gpuobj = NULL; +- uint32_t aper_size, obj_size; +- int i, ret; ++ u32 aper_size, align; ++ int ret; + +- if (dev_priv->card_type < NV_50) { +- if(dev_priv->ramin_rsvd_vram < 2 * 1024 * 1024) +- aper_size = 64 * 1024 * 1024; +- else +- aper_size = 512 * 1024 * 1024; +- +- obj_size = (aper_size >> NV_CTXDMA_PAGE_SHIFT) * 4; +- obj_size += 8; /* ctxdma header */ +- +- ret = nouveau_gpuobj_new(dev, NULL, obj_size, 16, +- NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &gpuobj); ++ if (dev_priv->card_type >= NV_50 || ++ dev_priv->ramin_rsvd_vram >= 2 * 1024 * 1024) ++ aper_size = 512 * 1024 * 1024; ++ else ++ aper_size = 64 * 1024 * 1024; ++ ++ /* Dear NVIDIA, NV44+ would like proper present bits in PTEs for ++ * christmas. The cards before it have them, the cards after ++ * it have them, why is NV44 so unloved? ++ */ ++ dev_priv->gart_info.dummy.page = alloc_page(GFP_DMA32 | GFP_KERNEL); ++ if (!dev_priv->gart_info.dummy.page) ++ return -ENOMEM; ++ ++ dev_priv->gart_info.dummy.addr = ++ pci_map_page(dev->pdev, dev_priv->gart_info.dummy.page, ++ 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ++ if (pci_dma_mapping_error(dev->pdev, dev_priv->gart_info.dummy.addr)) { ++ NV_ERROR(dev, "error mapping dummy page\n"); ++ __free_page(dev_priv->gart_info.dummy.page); ++ dev_priv->gart_info.dummy.page = NULL; ++ return -ENOMEM; ++ } ++ ++ if (dev_priv->card_type >= NV_50) { ++ dev_priv->gart_info.aper_base = 0; ++ dev_priv->gart_info.aper_size = aper_size; ++ dev_priv->gart_info.type = NOUVEAU_GART_HW; ++ dev_priv->gart_info.func = &nv50_sgdma_backend; ++ } else ++ if (drm_device_is_pcie(dev) && ++ dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { ++ if (nv44_graph_class(dev)) { ++ dev_priv->gart_info.func = &nv44_sgdma_backend; ++ align = 512 * 1024; ++ } else { ++ dev_priv->gart_info.func = &nv41_sgdma_backend; ++ align = 16; ++ } ++ ++ ret = nouveau_gpuobj_new(dev, NULL, aper_size / 1024, align, ++ NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &gpuobj); ++ if (ret) { ++ NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); ++ return ret; ++ } ++ ++ dev_priv->gart_info.sg_ctxdma = gpuobj; ++ dev_priv->gart_info.aper_base = 0; ++ dev_priv->gart_info.aper_size = aper_size; ++ dev_priv->gart_info.type = NOUVEAU_GART_HW; ++ } else { ++ ret = nouveau_gpuobj_new(dev, NULL, (aper_size / 1024) + 8, 16, ++ NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &gpuobj); + if (ret) { + NV_ERROR(dev, "Error creating sgdma object: %d\n", ret); + return ret; +@@ -236,25 +479,14 @@ + (0 << 14) /* RW */ | + (2 << 16) /* PCI */); + nv_wo32(gpuobj, 4, aper_size - 1); +- for (i = 2; i < 2 + (aper_size >> 12); i++) +- nv_wo32(gpuobj, i * 4, 0x00000000); + + dev_priv->gart_info.sg_ctxdma = gpuobj; + dev_priv->gart_info.aper_base = 0; + dev_priv->gart_info.aper_size = aper_size; +- } else +- if (dev_priv->chan_vm) { +- ret = nouveau_vm_get(dev_priv->chan_vm, 512 * 1024 * 1024, +- 12, NV_MEM_ACCESS_RW, +- &dev_priv->gart_info.vma); +- if (ret) +- return ret; +- +- dev_priv->gart_info.aper_base = dev_priv->gart_info.vma.offset; +- dev_priv->gart_info.aper_size = 512 * 1024 * 1024; ++ dev_priv->gart_info.type = NOUVEAU_GART_PDMA; ++ dev_priv->gart_info.func = &nv04_sgdma_backend; + } + +- dev_priv->gart_info.type = NOUVEAU_GART_SGDMA; + return 0; + } + +@@ -264,7 +496,13 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + + nouveau_gpuobj_ref(NULL, &dev_priv->gart_info.sg_ctxdma); +- nouveau_vm_put(&dev_priv->gart_info.vma); ++ ++ if (dev_priv->gart_info.dummy.page) { ++ pci_unmap_page(dev->pdev, dev_priv->gart_info.dummy.addr, ++ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ++ __free_page(dev_priv->gart_info.dummy.page); ++ dev_priv->gart_info.dummy.page = NULL; ++ } + } + + uint32_t +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_state.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_state.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_state.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_state.c 2011-02-20 23:32:11.000000000 +0100 +@@ -544,7 +544,6 @@ + nouveau_card_init_channel(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *gpuobj = NULL; + int ret; + + ret = nouveau_channel_alloc(dev, &dev_priv->channel, +@@ -552,41 +551,8 @@ + if (ret) + return ret; + +- /* no dma objects on fermi... */ +- if (dev_priv->card_type >= NV_C0) +- goto out_done; +- +- ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, +- 0, dev_priv->vram_size, +- NV_MEM_ACCESS_RW, NV_MEM_TARGET_VRAM, +- &gpuobj); +- if (ret) +- goto out_err; +- +- ret = nouveau_ramht_insert(dev_priv->channel, NvDmaVRAM, gpuobj); +- nouveau_gpuobj_ref(NULL, &gpuobj); +- if (ret) +- goto out_err; +- +- ret = nouveau_gpuobj_dma_new(dev_priv->channel, NV_CLASS_DMA_IN_MEMORY, +- 0, dev_priv->gart_info.aper_size, +- NV_MEM_ACCESS_RW, NV_MEM_TARGET_GART, +- &gpuobj); +- if (ret) +- goto out_err; +- +- ret = nouveau_ramht_insert(dev_priv->channel, NvDmaGART, gpuobj); +- nouveau_gpuobj_ref(NULL, &gpuobj); +- if (ret) +- goto out_err; +- +-out_done: + mutex_unlock(&dev_priv->channel->mutex); + return 0; +- +-out_err: +- nouveau_channel_put(&dev_priv->channel); +- return ret; + } + + static void nouveau_switcheroo_set_state(struct pci_dev *pdev, +@@ -929,12 +895,6 @@ + NV_DEBUG(dev, "vendor: 0x%X device: 0x%X class: 0x%X\n", + dev->pci_vendor, dev->pci_device, dev->pdev->class); + +- dev_priv->wq = create_workqueue("nouveau"); +- if (!dev_priv->wq) { +- ret = -EINVAL; +- goto err_priv; +- } +- + /* resource 0 is mmio regs */ + /* resource 1 is linear FB */ + /* resource 2 is RAMIN (mmio regs + 0x1000000) */ +@@ -947,7 +907,7 @@ + NV_ERROR(dev, "Unable to initialize the mmio mapping. " + "Please report your setup to " DRIVER_EMAIL "\n"); + ret = -EINVAL; +- goto err_wq; ++ goto err_priv; + } + NV_DEBUG(dev, "regs mapped ok at 0x%llx\n", + (unsigned long long)mmio_start_offs); +@@ -1054,8 +1014,6 @@ + iounmap(dev_priv->ramin); + err_mmio: + iounmap(dev_priv->mmio); +-err_wq: +- destroy_workqueue(dev_priv->wq); + err_priv: + kfree(dev_priv); + dev->dev_private = NULL; +@@ -1126,7 +1084,7 @@ + getparam->value = 1; + break; + case NOUVEAU_GETPARAM_HAS_PAGEFLIP: +- getparam->value = (dev_priv->card_type < NV_50); ++ getparam->value = 1; + break; + case NOUVEAU_GETPARAM_GRAPH_UNITS: + /* NV40 and NV50 versions are quite different, but register +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_temp.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_temp.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_temp.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_temp.c 2011-02-20 23:32:11.000000000 +0100 +@@ -239,11 +239,9 @@ + probe_monitoring_device(struct nouveau_i2c_chan *i2c, + struct i2c_board_info *info) + { +- char modalias[16] = "i2c:"; + struct i2c_client *client; + +- strlcat(modalias, info->type, sizeof(modalias)); +- request_module(modalias); ++ request_module("%s%s", I2C_MODULE_PREFIX, info->type); + + client = i2c_new_device(&i2c->adapter, info); + if (!client) +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_vm.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_vm.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_vm.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_vm.c 2011-02-20 23:32:11.000000000 +0100 +@@ -28,7 +28,7 @@ + #include "nouveau_vm.h" + + void +-nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_vram *vram) ++nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node) + { + struct nouveau_vm *vm = vma->vm; + struct nouveau_mm_node *r; +@@ -40,7 +40,8 @@ + u32 max = 1 << (vm->pgt_bits - bits); + u32 end, len; + +- list_for_each_entry(r, &vram->regions, rl_entry) { ++ delta = 0; ++ list_for_each_entry(r, &node->regions, rl_entry) { + u64 phys = (u64)r->offset << 12; + u32 num = r->length >> bits; + +@@ -52,7 +53,7 @@ + end = max; + len = end - pte; + +- vm->map(vma, pgt, vram, pte, len, phys); ++ vm->map(vma, pgt, node, pte, len, phys, delta); + + num -= len; + pte += len; +@@ -60,6 +61,8 @@ + pde++; + pte = 0; + } ++ ++ delta += (u64)len << vma->node->type; + } + } + +@@ -67,14 +70,14 @@ + } + + void +-nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_vram *vram) ++nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node) + { +- nouveau_vm_map_at(vma, 0, vram); ++ nouveau_vm_map_at(vma, 0, node); + } + + void + nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length, +- dma_addr_t *list) ++ struct nouveau_mem *mem, dma_addr_t *list) + { + struct nouveau_vm *vm = vma->vm; + int big = vma->node->type != vm->spg_shift; +@@ -94,7 +97,7 @@ + end = max; + len = end - pte; + +- vm->map_sg(vma, pgt, pte, list, len); ++ vm->map_sg(vma, pgt, mem, pte, len, list); + + num -= len; + pte += len; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_vm.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_vm.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-02-20 23:32:11.000000000 +0100 +@@ -67,9 +67,10 @@ + void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); + void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *, +- struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); ++ struct nouveau_mem *, u32 pte, u32 cnt, ++ u64 phys, u64 delta); + void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *, +- u32 pte, dma_addr_t *, u32 cnt); ++ struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *); + void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt); + void (*flush)(struct nouveau_vm *); + }; +@@ -82,20 +83,20 @@ + int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift, + u32 access, struct nouveau_vma *); + void nouveau_vm_put(struct nouveau_vma *); +-void nouveau_vm_map(struct nouveau_vma *, struct nouveau_vram *); +-void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_vram *); ++void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *); ++void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *); + void nouveau_vm_unmap(struct nouveau_vma *); + void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length); + void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length, +- dma_addr_t *); ++ struct nouveau_mem *, dma_addr_t *); + + /* nv50_vm.c */ + void nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); + void nv50_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, +- struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); ++ struct nouveau_mem *, u32 pte, u32 cnt, u64 phys, u64 delta); + void nv50_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, +- u32 pte, dma_addr_t *, u32 cnt); ++ struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *); + void nv50_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); + void nv50_vm_flush(struct nouveau_vm *); + void nv50_vm_flush_engine(struct drm_device *, int engine); +@@ -104,9 +105,9 @@ + void nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]); + void nvc0_vm_map(struct nouveau_vma *, struct nouveau_gpuobj *, +- struct nouveau_vram *, u32 pte, u32 cnt, u64 phys); ++ struct nouveau_mem *, u32 pte, u32 cnt, u64 phys, u64 delta); + void nvc0_vm_map_sg(struct nouveau_vma *, struct nouveau_gpuobj *, +- u32 pte, dma_addr_t *, u32 cnt); ++ struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *); + void nvc0_vm_unmap(struct nouveau_gpuobj *, u32 pte, u32 cnt); + void nvc0_vm_flush(struct nouveau_vm *); + +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv04_crtc.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv04_crtc.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-02-20 23:32:11.000000000 +0100 +@@ -1031,7 +1031,7 @@ + drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); + + ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, +- 0, 0x0000, false, true, &nv_crtc->cursor.nvbo); ++ 0, 0x0000, &nv_crtc->cursor.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv04_dfp.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv04_dfp.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv04_dfp.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv04_dfp.c 2011-02-20 23:32:11.000000000 +0100 +@@ -342,8 +342,8 @@ + if (nv_encoder->dcb->type == OUTPUT_LVDS) { + bool duallink, dummy; + +- nouveau_bios_parse_lvds_table(dev, nv_connector->native_mode-> +- clock, &duallink, &dummy); ++ nouveau_bios_parse_lvds_table(dev, output_mode->clock, ++ &duallink, &dummy); + if (duallink) + regp->fp_control |= (8 << 28); + } else +@@ -518,8 +518,6 @@ + return; + + if (nv_encoder->dcb->lvdsconf.use_power_scripts) { +- struct nouveau_connector *nv_connector = nouveau_encoder_connector_get(nv_encoder); +- + /* when removing an output, crtc may not be set, but PANEL_OFF + * must still be run + */ +@@ -527,12 +525,8 @@ + nv04_dfp_get_bound_head(dev, nv_encoder->dcb); + + if (mode == DRM_MODE_DPMS_ON) { +- if (!nv_connector->native_mode) { +- NV_ERROR(dev, "Not turning on LVDS without native mode\n"); +- return; +- } + call_lvds_script(dev, nv_encoder->dcb, head, +- LVDS_PANEL_ON, nv_connector->native_mode->clock); ++ LVDS_PANEL_ON, nv_encoder->mode.clock); + } else + /* pxclk of 0 is fine for PANEL_OFF, and for a + * disconnected LVDS encoder there is no native_mode +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv04_fifo.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv04_fifo.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv04_fifo.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv04_fifo.c 2011-02-20 23:32:11.000000000 +0100 +@@ -379,6 +379,15 @@ + return handled; + } + ++static const char *nv_dma_state_err(u32 state) ++{ ++ static const char * const desc[] = { ++ "NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE", ++ "INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK" ++ }; ++ return desc[(state >> 29) & 0x7]; ++} ++ + void + nv04_fifo_isr(struct drm_device *dev) + { +@@ -460,9 +469,10 @@ + if (nouveau_ratelimit()) + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%02x%08x " + "Put 0x%02x%08x IbGet 0x%08x IbPut 0x%08x " +- "State 0x%08x Push 0x%08x\n", ++ "State 0x%08x (err: %s) Push 0x%08x\n", + chid, ho_get, dma_get, ho_put, + dma_put, ib_get, ib_put, state, ++ nv_dma_state_err(state), + push); + + /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ +@@ -476,8 +486,9 @@ + } + } else { + NV_INFO(dev, "PFIFO_DMA_PUSHER - Ch %d Get 0x%08x " +- "Put 0x%08x State 0x%08x Push 0x%08x\n", +- chid, dma_get, dma_put, state, push); ++ "Put 0x%08x State 0x%08x (err: %s) Push 0x%08x\n", ++ chid, dma_get, dma_put, state, ++ nv_dma_state_err(state), push); + + if (dma_get != dma_put) + nv_wr32(dev, 0x003244, dma_put); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv40_fb.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv40_fb.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv40_fb.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv40_fb.c 2011-02-20 23:32:11.000000000 +0100 +@@ -24,6 +24,53 @@ + } + } + ++static void ++nv40_fb_init_gart(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; ++ ++ if (dev_priv->gart_info.type != NOUVEAU_GART_HW) { ++ nv_wr32(dev, 0x100800, 0x00000001); ++ return; ++ } ++ ++ nv_wr32(dev, 0x100800, gart->pinst | 0x00000002); ++ nv_mask(dev, 0x10008c, 0x00000100, 0x00000100); ++ nv_wr32(dev, 0x100820, 0x00000000); ++} ++ ++static void ++nv44_fb_init_gart(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *gart = dev_priv->gart_info.sg_ctxdma; ++ u32 vinst; ++ ++ if (dev_priv->gart_info.type != NOUVEAU_GART_HW) { ++ nv_wr32(dev, 0x100850, 0x80000000); ++ nv_wr32(dev, 0x100800, 0x00000001); ++ return; ++ } ++ ++ /* calculate vram address of this PRAMIN block, object ++ * must be allocated on 512KiB alignment, and not exceed ++ * a total size of 512KiB for this to work correctly ++ */ ++ vinst = nv_rd32(dev, 0x10020c); ++ vinst -= ((gart->pinst >> 19) + 1) << 19; ++ ++ nv_wr32(dev, 0x100850, 0x80000000); ++ nv_wr32(dev, 0x100818, dev_priv->gart_info.dummy.addr); ++ ++ nv_wr32(dev, 0x100804, dev_priv->gart_info.aper_size); ++ nv_wr32(dev, 0x100850, 0x00008000); ++ nv_mask(dev, 0x10008c, 0x00000200, 0x00000200); ++ nv_wr32(dev, 0x100820, 0x00000000); ++ nv_wr32(dev, 0x10082c, 0x00000001); ++ nv_wr32(dev, 0x100800, vinst | 0x00000010); ++} ++ + int + nv40_fb_init(struct drm_device *dev) + { +@@ -32,12 +79,12 @@ + uint32_t tmp; + int i; + +- /* This is strictly a NV4x register (don't know about NV5x). */ +- /* The blob sets these to all kinds of values, and they mess up our setup. */ +- /* I got value 0x52802 instead. For some cards the blob even sets it back to 0x1. */ +- /* Note: the blob doesn't read this value, so i'm pretty sure this is safe for all cards. */ +- /* Any idea what this is? */ +- nv_wr32(dev, NV40_PFB_UNK_800, 0x1); ++ if (dev_priv->chipset != 0x40 && dev_priv->chipset != 0x45) { ++ if (nv44_graph_class(dev)) ++ nv44_fb_init_gart(dev); ++ else ++ nv40_fb_init_gart(dev); ++ } + + switch (dev_priv->chipset) { + case 0x40: +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv40_graph.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv40_graph.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv40_graph.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv40_graph.c 2011-02-20 23:32:11.000000000 +0100 +@@ -211,18 +211,32 @@ + struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; + + switch (dev_priv->chipset) { ++ case 0x40: ++ case 0x41: /* guess */ ++ case 0x42: ++ case 0x43: ++ case 0x45: /* guess */ ++ case 0x4e: ++ nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); ++ nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); ++ nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); ++ nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); ++ nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); ++ nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); ++ break; + case 0x44: + case 0x4a: +- case 0x4e: + nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); + break; +- + case 0x46: + case 0x47: + case 0x49: + case 0x4b: ++ case 0x4c: ++ case 0x67: ++ default: + nv_wr32(dev, NV47_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(dev, NV47_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(dev, NV47_PGRAPH_TILE(i), tile->addr); +@@ -230,15 +244,6 @@ + nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); + break; +- +- default: +- nv_wr32(dev, NV20_PGRAPH_TSIZE(i), tile->pitch); +- nv_wr32(dev, NV20_PGRAPH_TLIMIT(i), tile->limit); +- nv_wr32(dev, NV20_PGRAPH_TILE(i), tile->addr); +- nv_wr32(dev, NV40_PGRAPH_TSIZE1(i), tile->pitch); +- nv_wr32(dev, NV40_PGRAPH_TLIMIT1(i), tile->limit); +- nv_wr32(dev, NV40_PGRAPH_TILE1(i), tile->addr); +- break; + } + } + +@@ -396,17 +401,20 @@ + break; + default: + switch (dev_priv->chipset) { +- case 0x46: +- case 0x47: +- case 0x49: +- case 0x4b: +- nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); +- nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); +- break; +- default: ++ case 0x41: ++ case 0x42: ++ case 0x43: ++ case 0x45: ++ case 0x4e: ++ case 0x44: ++ case 0x4a: + nv_wr32(dev, 0x4009F0, nv_rd32(dev, NV04_PFB_CFG0)); + nv_wr32(dev, 0x4009F4, nv_rd32(dev, NV04_PFB_CFG1)); + break; ++ default: ++ nv_wr32(dev, 0x400DF0, nv_rd32(dev, NV04_PFB_CFG0)); ++ nv_wr32(dev, 0x400DF4, nv_rd32(dev, NV04_PFB_CFG1)); ++ break; + } + nv_wr32(dev, 0x4069F0, nv_rd32(dev, NV04_PFB_CFG0)); + nv_wr32(dev, 0x4069F4, nv_rd32(dev, NV04_PFB_CFG1)); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_crtc.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_crtc.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-02-20 23:32:11.000000000 +0100 +@@ -65,7 +65,7 @@ + { + struct drm_device *dev = nv_crtc->base.dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + int index = nv_crtc->index, ret; + + NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); +@@ -135,8 +135,7 @@ + nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update) + { + struct drm_device *dev = nv_crtc->base.dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + int ret; + + NV_DEBUG_KMS(dev, "\n"); +@@ -186,8 +185,7 @@ + struct nouveau_connector *nv_connector = + nouveau_crtc_connector_get(nv_crtc); + struct drm_device *dev = nv_crtc->base.dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + struct drm_display_mode *native_mode = NULL; + struct drm_display_mode *mode = &nv_crtc->base.mode; + uint32_t outX, outY, horiz, vert; +@@ -445,6 +443,42 @@ + { + } + ++static int ++nv50_crtc_wait_complete(struct drm_crtc *crtc) ++{ ++ struct drm_device *dev = crtc->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; ++ struct nv50_display *disp = nv50_display(dev); ++ struct nouveau_channel *evo = disp->master; ++ u64 start; ++ int ret; ++ ++ ret = RING_SPACE(evo, 6); ++ if (ret) ++ return ret; ++ BEGIN_RING(evo, 0, 0x0084, 1); ++ OUT_RING (evo, 0x80000000); ++ BEGIN_RING(evo, 0, 0x0080, 1); ++ OUT_RING (evo, 0); ++ BEGIN_RING(evo, 0, 0x0084, 1); ++ OUT_RING (evo, 0x00000000); ++ ++ nv_wo32(disp->ntfy, 0x000, 0x00000000); ++ FIRE_RING (evo); ++ ++ start = ptimer->read(dev); ++ do { ++ nv_wr32(dev, 0x61002c, 0x370); ++ nv_wr32(dev, 0x000140, 1); ++ ++ if (nv_ro32(disp->ntfy, 0x000)) ++ return 0; ++ } while (ptimer->read(dev) - start < 2000000000ULL); ++ ++ return -EBUSY; ++} ++ + static void + nv50_crtc_prepare(struct drm_crtc *crtc) + { +@@ -453,6 +487,7 @@ + + NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + ++ nv50_display_flip_stop(crtc); + drm_vblank_pre_modeset(dev, nv_crtc->index); + nv50_crtc_blank(nv_crtc, true); + } +@@ -461,24 +496,14 @@ + nv50_crtc_commit(struct drm_crtc *crtc) + { + struct drm_device *dev = crtc->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); +- int ret; + + NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + + nv50_crtc_blank(nv_crtc, false); + drm_vblank_post_modeset(dev, nv_crtc->index); +- +- ret = RING_SPACE(evo, 2); +- if (ret) { +- NV_ERROR(dev, "no space while committing crtc\n"); +- return; +- } +- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); +- OUT_RING (evo, 0); +- FIRE_RING (evo); ++ nv50_crtc_wait_complete(crtc); ++ nv50_display_flip_next(crtc, crtc->fb, NULL); + } + + static bool +@@ -491,15 +516,15 @@ + static int + nv50_crtc_do_mode_set_base(struct drm_crtc *crtc, + struct drm_framebuffer *passed_fb, +- int x, int y, bool update, bool atomic) ++ int x, int y, bool atomic) + { + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct drm_device *dev = nv_crtc->base.dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + struct drm_framebuffer *drm_fb = nv_crtc->base.fb; + struct nouveau_framebuffer *fb = nouveau_framebuffer(drm_fb); +- int ret, format; ++ int ret; + + NV_DEBUG_KMS(dev, "index %d\n", nv_crtc->index); + +@@ -525,28 +550,6 @@ + } + } + +- switch (drm_fb->depth) { +- case 8: +- format = NV50_EVO_CRTC_FB_DEPTH_8; +- break; +- case 15: +- format = NV50_EVO_CRTC_FB_DEPTH_15; +- break; +- case 16: +- format = NV50_EVO_CRTC_FB_DEPTH_16; +- break; +- case 24: +- case 32: +- format = NV50_EVO_CRTC_FB_DEPTH_24; +- break; +- case 30: +- format = NV50_EVO_CRTC_FB_DEPTH_30; +- break; +- default: +- NV_ERROR(dev, "unknown depth %d\n", drm_fb->depth); +- return -EINVAL; +- } +- + nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT; + nv_crtc->fb.tile_flags = nouveau_bo_tile_layout(fb->nvbo); + nv_crtc->fb.cpp = drm_fb->bits_per_pixel / 8; +@@ -556,14 +559,7 @@ + return ret; + + BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_DMA), 1); +- if (nv_crtc->fb.tile_flags == 0x7a00 || +- nv_crtc->fb.tile_flags == 0xfe00) +- OUT_RING(evo, NvEvoFB32); +- else +- if (nv_crtc->fb.tile_flags == 0x7000) +- OUT_RING(evo, NvEvoFB16); +- else +- OUT_RING(evo, NvEvoVRAM_LP); ++ OUT_RING (evo, fb->r_dma); + } + + ret = RING_SPACE(evo, 12); +@@ -571,45 +567,26 @@ + return ret; + + BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_OFFSET), 5); +- OUT_RING(evo, nv_crtc->fb.offset >> 8); +- OUT_RING(evo, 0); +- OUT_RING(evo, (drm_fb->height << 16) | drm_fb->width); +- if (!nv_crtc->fb.tile_flags) { +- OUT_RING(evo, drm_fb->pitch | (1 << 20)); +- } else { +- u32 tile_mode = fb->nvbo->tile_mode; +- if (dev_priv->card_type >= NV_C0) +- tile_mode >>= 4; +- OUT_RING(evo, ((drm_fb->pitch / 4) << 4) | tile_mode); +- } +- if (dev_priv->chipset == 0x50) +- OUT_RING(evo, (nv_crtc->fb.tile_flags << 8) | format); +- else +- OUT_RING(evo, format); ++ OUT_RING (evo, nv_crtc->fb.offset >> 8); ++ OUT_RING (evo, 0); ++ OUT_RING (evo, (drm_fb->height << 16) | drm_fb->width); ++ OUT_RING (evo, fb->r_pitch); ++ OUT_RING (evo, fb->r_format); + + BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, CLUT_MODE), 1); +- OUT_RING(evo, fb->base.depth == 8 ? +- NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON); ++ OUT_RING (evo, fb->base.depth == 8 ? ++ NV50_EVO_CRTC_CLUT_MODE_OFF : NV50_EVO_CRTC_CLUT_MODE_ON); + + BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, COLOR_CTRL), 1); +- OUT_RING(evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR); ++ OUT_RING (evo, NV50_EVO_CRTC_COLOR_CTRL_COLOR); + BEGIN_RING(evo, 0, NV50_EVO_CRTC(nv_crtc->index, FB_POS), 1); +- OUT_RING(evo, (y << 16) | x); ++ OUT_RING (evo, (y << 16) | x); + + if (nv_crtc->lut.depth != fb->base.depth) { + nv_crtc->lut.depth = fb->base.depth; + nv50_crtc_lut_load(crtc); + } + +- if (update) { +- ret = RING_SPACE(evo, 2); +- if (ret) +- return ret; +- BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); +- OUT_RING(evo, 0); +- FIRE_RING(evo); +- } +- + return 0; + } + +@@ -619,8 +596,7 @@ + struct drm_framebuffer *old_fb) + { + struct drm_device *dev = crtc->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct nouveau_connector *nv_connector = NULL; + uint32_t hsync_dur, vsync_dur, hsync_start_to_end, vsync_start_to_end; +@@ -700,14 +676,25 @@ + nv_crtc->set_dither(nv_crtc, nv_connector->use_dithering, false); + nv_crtc->set_scale(nv_crtc, nv_connector->scaling_mode, false); + +- return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false, false); ++ return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false); + } + + static int + nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, + struct drm_framebuffer *old_fb) + { +- return nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, true, false); ++ int ret; ++ ++ nv50_display_flip_stop(crtc); ++ ret = nv50_crtc_do_mode_set_base(crtc, old_fb, x, y, false); ++ if (ret) ++ return ret; ++ ++ ret = nv50_crtc_wait_complete(crtc); ++ if (ret) ++ return ret; ++ ++ return nv50_display_flip_next(crtc, crtc->fb, NULL); + } + + static int +@@ -715,7 +702,14 @@ + struct drm_framebuffer *fb, + int x, int y, enum mode_set_atomic state) + { +- return nv50_crtc_do_mode_set_base(crtc, fb, x, y, true, true); ++ int ret; ++ ++ nv50_display_flip_stop(crtc); ++ ret = nv50_crtc_do_mode_set_base(crtc, fb, x, y, true); ++ if (ret) ++ return ret; ++ ++ return nv50_crtc_wait_complete(crtc); + } + + static const struct drm_crtc_helper_funcs nv50_crtc_helper_funcs = { +@@ -758,7 +752,7 @@ + nv_crtc->lut.depth = 0; + + ret = nouveau_bo_new(dev, NULL, 4096, 0x100, TTM_PL_FLAG_VRAM, +- 0, 0x0000, false, true, &nv_crtc->lut.nvbo); ++ 0, 0x0000, &nv_crtc->lut.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) +@@ -784,7 +778,7 @@ + drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); + + ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, +- 0, 0x0000, false, true, &nv_crtc->cursor.nvbo); ++ 0, 0x0000, &nv_crtc->cursor.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); + if (!ret) +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_cursor.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_cursor.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_cursor.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_cursor.c 2011-02-20 23:32:11.000000000 +0100 +@@ -36,9 +36,9 @@ + static void + nv50_cursor_show(struct nouveau_crtc *nv_crtc, bool update) + { +- struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; + struct drm_device *dev = nv_crtc->base.dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + int ret; + + NV_DEBUG_KMS(dev, "\n"); +@@ -71,9 +71,9 @@ + static void + nv50_cursor_hide(struct nouveau_crtc *nv_crtc, bool update) + { +- struct drm_nouveau_private *dev_priv = nv_crtc->base.dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; + struct drm_device *dev = nv_crtc->base.dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + int ret; + + NV_DEBUG_KMS(dev, "\n"); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_dac.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_dac.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_dac.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_dac.c 2011-02-20 23:32:11.000000000 +0100 +@@ -41,8 +41,7 @@ + { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + int ret; + + if (!nv_encoder->crtc) +@@ -216,8 +215,7 @@ + { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); + uint32_t mode_ctl = 0, mode_ctl2 = 0; + int ret; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_display.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_display.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_display.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_display.c 2011-02-20 23:32:11.000000000 +0100 +@@ -24,6 +24,7 @@ + * + */ + ++#define NOUVEAU_DMA_DEBUG (nouveau_reg_debug & NOUVEAU_REG_DEBUG_EVO) + #include "nv50_display.h" + #include "nouveau_crtc.h" + #include "nouveau_encoder.h" +@@ -34,6 +35,7 @@ + #include "drm_crtc_helper.h" + + static void nv50_display_isr(struct drm_device *); ++static void nv50_display_bh(unsigned long); + + static inline int + nv50_sor_nr(struct drm_device *dev) +@@ -172,16 +174,16 @@ + ret = nv50_evo_init(dev); + if (ret) + return ret; +- evo = dev_priv->evo; ++ evo = nv50_display(dev)->master; + + nv_wr32(dev, NV50_PDISPLAY_OBJECTS, (evo->ramin->vinst >> 8) | 9); + +- ret = RING_SPACE(evo, 11); ++ ret = RING_SPACE(evo, 15); + if (ret) + return ret; + BEGIN_RING(evo, 0, NV50_EVO_UNK84, 2); + OUT_RING(evo, NV50_EVO_UNK84_NOTIFY_DISABLED); +- OUT_RING(evo, NV50_EVO_DMA_NOTIFY_HANDLE_NONE); ++ OUT_RING(evo, NvEvoSync); + BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, FB_DMA), 1); + OUT_RING(evo, NV50_EVO_CRTC_FB_DMA_HANDLE_NONE); + BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK0800), 1); +@@ -190,6 +192,11 @@ + OUT_RING(evo, 0); + BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK082C), 1); + OUT_RING(evo, 0); ++ /* required to make display sync channels not hate life */ ++ BEGIN_RING(evo, 0, NV50_EVO_CRTC(0, UNK900), 1); ++ OUT_RING (evo, 0x00000311); ++ BEGIN_RING(evo, 0, NV50_EVO_CRTC(1, UNK900), 1); ++ OUT_RING (evo, 0x00000311); + FIRE_RING(evo); + if (!nv_wait(dev, 0x640004, 0xffffffff, evo->dma.put << 2)) + NV_ERROR(dev, "evo pushbuf stalled\n"); +@@ -201,6 +208,8 @@ + static int nv50_display_disable(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_display *disp = nv50_display(dev); ++ struct nouveau_channel *evo = disp->master; + struct drm_crtc *drm_crtc; + int ret, i; + +@@ -212,12 +221,12 @@ + nv50_crtc_blank(crtc, true); + } + +- ret = RING_SPACE(dev_priv->evo, 2); ++ ret = RING_SPACE(evo, 2); + if (ret == 0) { +- BEGIN_RING(dev_priv->evo, 0, NV50_EVO_UPDATE, 1); +- OUT_RING(dev_priv->evo, 0); ++ BEGIN_RING(evo, 0, NV50_EVO_UPDATE, 1); ++ OUT_RING(evo, 0); + } +- FIRE_RING(dev_priv->evo); ++ FIRE_RING(evo); + + /* Almost like ack'ing a vblank interrupt, maybe in the spirit of + * cleaning up? +@@ -267,10 +276,16 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct dcb_table *dcb = &dev_priv->vbios.dcb; + struct drm_connector *connector, *ct; ++ struct nv50_display *priv; + int ret, i; + + NV_DEBUG_KMS(dev, "\n"); + ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ dev_priv->engine.display.priv = priv; ++ + /* init basic kernel modesetting */ + drm_mode_config_init(dev); + +@@ -330,7 +345,7 @@ + } + } + +- INIT_WORK(&dev_priv->irq_work, nv50_display_irq_handler_bh); ++ tasklet_init(&priv->tasklet, nv50_display_bh, (unsigned long)dev); + nouveau_irq_register(dev, 26, nv50_display_isr); + + ret = nv50_display_init(dev); +@@ -345,12 +360,131 @@ + void + nv50_display_destroy(struct drm_device *dev) + { ++ struct nv50_display *disp = nv50_display(dev); ++ + NV_DEBUG_KMS(dev, "\n"); + + drm_mode_config_cleanup(dev); + + nv50_display_disable(dev); + nouveau_irq_unregister(dev, 26); ++ kfree(disp); ++} ++ ++void ++nv50_display_flip_stop(struct drm_crtc *crtc) ++{ ++ struct nv50_display *disp = nv50_display(crtc->dev); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index]; ++ struct nouveau_channel *evo = dispc->sync; ++ int ret; ++ ++ ret = RING_SPACE(evo, 8); ++ if (ret) { ++ WARN_ON(1); ++ return; ++ } ++ ++ BEGIN_RING(evo, 0, 0x0084, 1); ++ OUT_RING (evo, 0x00000000); ++ BEGIN_RING(evo, 0, 0x0094, 1); ++ OUT_RING (evo, 0x00000000); ++ BEGIN_RING(evo, 0, 0x00c0, 1); ++ OUT_RING (evo, 0x00000000); ++ BEGIN_RING(evo, 0, 0x0080, 1); ++ OUT_RING (evo, 0x00000000); ++ FIRE_RING (evo); ++} ++ ++int ++nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, ++ struct nouveau_channel *chan) ++{ ++ struct drm_nouveau_private *dev_priv = crtc->dev->dev_private; ++ struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); ++ struct nv50_display *disp = nv50_display(crtc->dev); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ struct nv50_display_crtc *dispc = &disp->crtc[nv_crtc->index]; ++ struct nouveau_channel *evo = dispc->sync; ++ int ret; ++ ++ ret = RING_SPACE(evo, 24); ++ if (unlikely(ret)) ++ return ret; ++ ++ /* synchronise with the rendering channel, if necessary */ ++ if (likely(chan)) { ++ u64 offset = dispc->sem.bo->vma.offset + dispc->sem.offset; ++ ++ ret = RING_SPACE(chan, 10); ++ if (ret) { ++ WIND_RING(evo); ++ return ret; ++ } ++ ++ if (dev_priv->chipset < 0xc0) { ++ BEGIN_RING(chan, NvSubSw, 0x0060, 2); ++ OUT_RING (chan, NvEvoSema0 + nv_crtc->index); ++ OUT_RING (chan, dispc->sem.offset); ++ BEGIN_RING(chan, NvSubSw, 0x006c, 1); ++ OUT_RING (chan, 0xf00d0000 | dispc->sem.value); ++ BEGIN_RING(chan, NvSubSw, 0x0064, 2); ++ OUT_RING (chan, dispc->sem.offset ^ 0x10); ++ OUT_RING (chan, 0x74b1e000); ++ BEGIN_RING(chan, NvSubSw, 0x0060, 1); ++ if (dev_priv->chipset < 0x84) ++ OUT_RING (chan, NvSema); ++ else ++ OUT_RING (chan, chan->vram_handle); ++ } else { ++ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); ++ OUT_RING (chan, upper_32_bits(offset)); ++ OUT_RING (chan, lower_32_bits(offset)); ++ OUT_RING (chan, 0xf00d0000 | dispc->sem.value); ++ OUT_RING (chan, 0x1002); ++ BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); ++ OUT_RING (chan, upper_32_bits(offset)); ++ OUT_RING (chan, lower_32_bits(offset ^ 0x10)); ++ OUT_RING (chan, 0x74b1e000); ++ OUT_RING (chan, 0x1001); ++ } ++ FIRE_RING (chan); ++ } else { ++ nouveau_bo_wr32(dispc->sem.bo, dispc->sem.offset / 4, ++ 0xf00d0000 | dispc->sem.value); ++ } ++ ++ /* queue the flip on the crtc's "display sync" channel */ ++ BEGIN_RING(evo, 0, 0x0100, 1); ++ OUT_RING (evo, 0xfffe0000); ++ BEGIN_RING(evo, 0, 0x0084, 5); ++ OUT_RING (evo, chan ? 0x00000100 : 0x00000010); ++ OUT_RING (evo, dispc->sem.offset); ++ OUT_RING (evo, 0xf00d0000 | dispc->sem.value); ++ OUT_RING (evo, 0x74b1e000); ++ OUT_RING (evo, NvEvoSync); ++ BEGIN_RING(evo, 0, 0x00a0, 2); ++ OUT_RING (evo, 0x00000000); ++ OUT_RING (evo, 0x00000000); ++ BEGIN_RING(evo, 0, 0x00c0, 1); ++ OUT_RING (evo, nv_fb->r_dma); ++ BEGIN_RING(evo, 0, 0x0110, 2); ++ OUT_RING (evo, 0x00000000); ++ OUT_RING (evo, 0x00000000); ++ BEGIN_RING(evo, 0, 0x0800, 5); ++ OUT_RING (evo, (nv_fb->nvbo->bo.mem.start << PAGE_SHIFT) >> 8); ++ OUT_RING (evo, 0); ++ OUT_RING (evo, (fb->height << 16) | fb->width); ++ OUT_RING (evo, nv_fb->r_pitch); ++ OUT_RING (evo, nv_fb->r_format); ++ BEGIN_RING(evo, 0, 0x0080, 1); ++ OUT_RING (evo, 0x00000000); ++ FIRE_RING (evo); ++ ++ dispc->sem.offset ^= 0x10; ++ dispc->sem.value++; ++ return 0; + } + + static u16 +@@ -466,11 +600,12 @@ + nv50_display_unk10_handler(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_display *disp = nv50_display(dev); + u32 unk30 = nv_rd32(dev, 0x610030), mc; + int i, crtc, or, type = OUTPUT_ANY; + + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); +- dev_priv->evo_irq.dcb = NULL; ++ disp->irq.dcb = NULL; + + nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) & ~8); + +@@ -541,7 +676,7 @@ + + if (dcb->type == type && (dcb->or & (1 << or))) { + nouveau_bios_run_display_table(dev, dcb, 0, -1); +- dev_priv->evo_irq.dcb = dcb; ++ disp->irq.dcb = dcb; + goto ack; + } + } +@@ -587,15 +722,16 @@ + nv50_display_unk20_handler(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc; ++ struct nv50_display *disp = nv50_display(dev); ++ u32 unk30 = nv_rd32(dev, 0x610030), tmp, pclk, script, mc = 0; + struct dcb_entry *dcb; + int i, crtc, or, type = OUTPUT_ANY; + + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); +- dcb = dev_priv->evo_irq.dcb; ++ dcb = disp->irq.dcb; + if (dcb) { + nouveau_bios_run_display_table(dev, dcb, 0, -2); +- dev_priv->evo_irq.dcb = NULL; ++ disp->irq.dcb = NULL; + } + + /* CRTC clock change requested? */ +@@ -692,9 +828,9 @@ + nv_wr32(dev, NV50_PDISPLAY_DAC_CLK_CTRL2(or), 0); + } + +- dev_priv->evo_irq.dcb = dcb; +- dev_priv->evo_irq.pclk = pclk; +- dev_priv->evo_irq.script = script; ++ disp->irq.dcb = dcb; ++ disp->irq.pclk = pclk; ++ disp->irq.script = script; + + ack: + nv_wr32(dev, NV50_PDISPLAY_INTR_1, NV50_PDISPLAY_INTR_1_CLK_UNK20); +@@ -735,13 +871,13 @@ + static void + nv50_display_unk40_handler(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct dcb_entry *dcb = dev_priv->evo_irq.dcb; +- u16 script = dev_priv->evo_irq.script; +- u32 unk30 = nv_rd32(dev, 0x610030), pclk = dev_priv->evo_irq.pclk; ++ struct nv50_display *disp = nv50_display(dev); ++ struct dcb_entry *dcb = disp->irq.dcb; ++ u16 script = disp->irq.script; ++ u32 unk30 = nv_rd32(dev, 0x610030), pclk = disp->irq.pclk; + + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); +- dev_priv->evo_irq.dcb = NULL; ++ disp->irq.dcb = NULL; + if (!dcb) + goto ack; + +@@ -754,12 +890,10 @@ + nv_wr32(dev, 0x619494, nv_rd32(dev, 0x619494) | 8); + } + +-void +-nv50_display_irq_handler_bh(struct work_struct *work) ++static void ++nv50_display_bh(unsigned long data) + { +- struct drm_nouveau_private *dev_priv = +- container_of(work, struct drm_nouveau_private, irq_work); +- struct drm_device *dev = dev_priv->dev; ++ struct drm_device *dev = (struct drm_device *)data; + + for (;;) { + uint32_t intr0 = nv_rd32(dev, NV50_PDISPLAY_INTR_0); +@@ -807,7 +941,7 @@ + static void + nv50_display_isr(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_display *disp = nv50_display(dev); + uint32_t delayed = 0; + + while (nv_rd32(dev, NV50_PMC_INTR_0) & NV50_PMC_INTR_0_DISPLAY) { +@@ -835,8 +969,7 @@ + NV50_PDISPLAY_INTR_1_CLK_UNK40)); + if (clock) { + nv_wr32(dev, NV03_PMC_INTR_EN_0, 0); +- if (!work_pending(&dev_priv->irq_work)) +- queue_work(dev_priv->wq, &dev_priv->irq_work); ++ tasklet_schedule(&disp->tasklet); + delayed |= clock; + intr1 &= ~clock; + } +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_display.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_display.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_display.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_display.h 2011-02-20 23:32:11.000000000 +0100 +@@ -35,7 +35,36 @@ + #include "nouveau_crtc.h" + #include "nv50_evo.h" + +-void nv50_display_irq_handler_bh(struct work_struct *work); ++struct nv50_display_crtc { ++ struct nouveau_channel *sync; ++ struct { ++ struct nouveau_bo *bo; ++ u32 offset; ++ u16 value; ++ } sem; ++}; ++ ++struct nv50_display { ++ struct nouveau_channel *master; ++ struct nouveau_gpuobj *ntfy; ++ ++ struct nv50_display_crtc crtc[2]; ++ ++ struct tasklet_struct tasklet; ++ struct { ++ struct dcb_entry *dcb; ++ u16 script; ++ u32 pclk; ++ } irq; ++}; ++ ++static inline struct nv50_display * ++nv50_display(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ return dev_priv->engine.display.priv; ++} ++ + int nv50_display_early_init(struct drm_device *dev); + void nv50_display_late_takedown(struct drm_device *dev); + int nv50_display_create(struct drm_device *dev); +@@ -44,4 +73,15 @@ + int nv50_crtc_blank(struct nouveau_crtc *, bool blank); + int nv50_crtc_set_clock(struct drm_device *, int head, int pclk); + ++int nv50_display_flip_next(struct drm_crtc *, struct drm_framebuffer *, ++ struct nouveau_channel *chan); ++void nv50_display_flip_stop(struct drm_crtc *); ++ ++int nv50_evo_init(struct drm_device *dev); ++void nv50_evo_fini(struct drm_device *dev); ++void nv50_evo_dmaobj_init(struct nouveau_gpuobj *, u32 memtype, u64 base, ++ u64 size); ++int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 handle, u32 memtype, ++ u64 base, u64 size, struct nouveau_gpuobj **); ++ + #endif /* __NV50_DISPLAY_H__ */ +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_evo.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_evo.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_evo.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_evo.c 2011-02-20 23:32:11.000000000 +0100 +@@ -27,20 +27,17 @@ + #include "nouveau_drv.h" + #include "nouveau_dma.h" + #include "nouveau_ramht.h" ++#include "nv50_display.h" + + static void + nv50_evo_channel_del(struct nouveau_channel **pevo) + { +- struct drm_nouveau_private *dev_priv; + struct nouveau_channel *evo = *pevo; + + if (!evo) + return; + *pevo = NULL; + +- dev_priv = evo->dev->dev_private; +- dev_priv->evo_alloc &= ~(1 << evo->id); +- + nouveau_gpuobj_channel_takedown(evo); + nouveau_bo_unmap(evo->pushbuf_bo); + nouveau_bo_ref(NULL, &evo->pushbuf_bo); +@@ -51,42 +48,61 @@ + kfree(evo); + } + ++void ++nv50_evo_dmaobj_init(struct nouveau_gpuobj *obj, u32 memtype, u64 base, u64 size) ++{ ++ struct drm_nouveau_private *dev_priv = obj->dev->dev_private; ++ u32 flags5; ++ ++ if (dev_priv->chipset < 0xc0) { ++ /* not supported on 0x50, specified in format mthd */ ++ if (dev_priv->chipset == 0x50) ++ memtype = 0; ++ flags5 = 0x00010000; ++ } else { ++ if (memtype & 0x80000000) ++ flags5 = 0x00000000; /* large pages */ ++ else ++ flags5 = 0x00020000; ++ } ++ ++ nv50_gpuobj_dma_init(obj, 0, 0x3d, base, size, NV_MEM_TARGET_VRAM, ++ NV_MEM_ACCESS_RW, (memtype >> 8) & 0xff, 0); ++ nv_wo32(obj, 0x14, flags5); ++ dev_priv->engine.instmem.flush(obj->dev); ++} ++ + int +-nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 class, u32 name, +- u32 tile_flags, u32 magic_flags, u32 offset, u32 limit, +- u32 flags5) ++nv50_evo_dmaobj_new(struct nouveau_channel *evo, u32 handle, u32 memtype, ++ u64 base, u64 size, struct nouveau_gpuobj **pobj) + { +- struct drm_nouveau_private *dev_priv = evo->dev->dev_private; +- struct drm_device *dev = evo->dev; ++ struct nv50_display *disp = nv50_display(evo->dev); + struct nouveau_gpuobj *obj = NULL; + int ret; + +- ret = nouveau_gpuobj_new(dev, dev_priv->evo, 6*4, 32, 0, &obj); ++ ret = nouveau_gpuobj_new(evo->dev, disp->master, 6*4, 32, 0, &obj); + if (ret) + return ret; + obj->engine = NVOBJ_ENGINE_DISPLAY; + +- nv_wo32(obj, 0, (tile_flags << 22) | (magic_flags << 16) | class); +- nv_wo32(obj, 4, limit); +- nv_wo32(obj, 8, offset); +- nv_wo32(obj, 12, 0x00000000); +- nv_wo32(obj, 16, 0x00000000); +- nv_wo32(obj, 20, flags5); +- dev_priv->engine.instmem.flush(dev); ++ nv50_evo_dmaobj_init(obj, memtype, base, size); + +- ret = nouveau_ramht_insert(evo, name, obj); +- nouveau_gpuobj_ref(NULL, &obj); +- if (ret) { +- return ret; +- } ++ ret = nouveau_ramht_insert(evo, handle, obj); ++ if (ret) ++ goto out; + +- return 0; ++ if (pobj) ++ nouveau_gpuobj_ref(obj, pobj); ++out: ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; + } + + static int +-nv50_evo_channel_new(struct drm_device *dev, struct nouveau_channel **pevo) ++nv50_evo_channel_new(struct drm_device *dev, int chid, ++ struct nouveau_channel **pevo) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_display *disp = nv50_display(dev); + struct nouveau_channel *evo; + int ret; + +@@ -95,25 +111,13 @@ + return -ENOMEM; + *pevo = evo; + +- for (evo->id = 0; evo->id < 5; evo->id++) { +- if (dev_priv->evo_alloc & (1 << evo->id)) +- continue; +- +- dev_priv->evo_alloc |= (1 << evo->id); +- break; +- } +- +- if (evo->id == 5) { +- kfree(evo); +- return -ENODEV; +- } +- ++ evo->id = chid; + evo->dev = dev; + evo->user_get = 4; + evo->user_put = 0; + + ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, +- false, true, &evo->pushbuf_bo); ++ &evo->pushbuf_bo); + if (ret == 0) + ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM); + if (ret) { +@@ -138,8 +142,8 @@ + } + + /* bind primary evo channel's ramht to the channel */ +- if (dev_priv->evo && evo != dev_priv->evo) +- nouveau_ramht_ref(dev_priv->evo->ramht, &evo->ramht, NULL); ++ if (disp->master && evo != disp->master) ++ nouveau_ramht_ref(disp->master->ramht, &evo->ramht, NULL); + + return 0; + } +@@ -212,21 +216,39 @@ + } + } + ++static void ++nv50_evo_destroy(struct drm_device *dev) ++{ ++ struct nv50_display *disp = nv50_display(dev); ++ int i; ++ ++ for (i = 0; i < 2; i++) { ++ if (disp->crtc[i].sem.bo) { ++ nouveau_bo_unmap(disp->crtc[i].sem.bo); ++ nouveau_bo_ref(NULL, &disp->crtc[i].sem.bo); ++ } ++ nv50_evo_channel_del(&disp->crtc[i].sync); ++ } ++ nouveau_gpuobj_ref(NULL, &disp->ntfy); ++ nv50_evo_channel_del(&disp->master); ++} ++ + static int + nv50_evo_create(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_display *disp = nv50_display(dev); + struct nouveau_gpuobj *ramht = NULL; + struct nouveau_channel *evo; +- int ret; ++ int ret, i, j; + + /* create primary evo channel, the one we use for modesetting + * purporses + */ +- ret = nv50_evo_channel_new(dev, &dev_priv->evo); ++ ret = nv50_evo_channel_new(dev, 0, &disp->master); + if (ret) + return ret; +- evo = dev_priv->evo; ++ evo = disp->master; + + /* setup object management on it, any other evo channel will + * use this also as there's no per-channel support on the +@@ -236,109 +258,167 @@ + NVOBJ_FLAG_ZERO_ALLOC, &evo->ramin); + if (ret) { + NV_ERROR(dev, "Error allocating EVO channel memory: %d\n", ret); +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; ++ goto err; + } + + ret = drm_mm_init(&evo->ramin_heap, 0, 32768); + if (ret) { + NV_ERROR(dev, "Error initialising EVO PRAMIN heap: %d\n", ret); +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; ++ goto err; + } + + ret = nouveau_gpuobj_new(dev, evo, 4096, 16, 0, &ramht); + if (ret) { + NV_ERROR(dev, "Unable to allocate EVO RAMHT: %d\n", ret); +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; ++ goto err; + } + + ret = nouveau_ramht_new(dev, ramht, &evo->ramht); + nouveau_gpuobj_ref(NULL, &ramht); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } ++ if (ret) ++ goto err; ++ ++ /* not sure exactly what this is.. ++ * ++ * the first dword of the structure is used by nvidia to wait on ++ * full completion of an EVO "update" command. ++ * ++ * method 0x8c on the master evo channel will fill a lot more of ++ * this structure with some undefined info ++ */ ++ ret = nouveau_gpuobj_new(dev, disp->master, 0x1000, 0, ++ NVOBJ_FLAG_ZERO_ALLOC, &disp->ntfy); ++ if (ret) ++ goto err; ++ ++ ret = nv50_evo_dmaobj_new(disp->master, NvEvoSync, 0x0000, ++ disp->ntfy->vinst, disp->ntfy->size, NULL); ++ if (ret) ++ goto err; + + /* create some default objects for the scanout memtypes we support */ +- if (dev_priv->card_type >= NV_C0) { +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0xfe, 0x19, +- 0, 0xffffffff, 0x00000000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } ++ ret = nv50_evo_dmaobj_new(disp->master, NvEvoVRAM, 0x0000, ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; + +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, +- 0, dev_priv->vram_size, 0x00020000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } ++ ret = nv50_evo_dmaobj_new(disp->master, NvEvoVRAM_LP, 0x80000000, ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; + +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19, +- 0, dev_priv->vram_size, 0x00000000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } +- } else { +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB16, 0x70, 0x19, +- 0, 0xffffffff, 0x00010000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } ++ ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB32, 0x80000000 | ++ (dev_priv->chipset < 0xc0 ? 0x7a00 : 0xfe00), ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; + ++ ret = nv50_evo_dmaobj_new(disp->master, NvEvoFB16, 0x80000000 | ++ (dev_priv->chipset < 0xc0 ? 0x7000 : 0xfe00), ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; + +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoFB32, 0x7a, 0x19, +- 0, 0xffffffff, 0x00010000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } ++ /* create "display sync" channels and other structures we need ++ * to implement page flipping ++ */ ++ for (i = 0; i < 2; i++) { ++ struct nv50_display_crtc *dispc = &disp->crtc[i]; ++ u64 offset; + +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM, 0, 0x19, +- 0, dev_priv->vram_size, 0x00010000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; +- } ++ ret = nv50_evo_channel_new(dev, 1 + i, &dispc->sync); ++ if (ret) ++ goto err; + +- ret = nv50_evo_dmaobj_new(evo, 0x3d, NvEvoVRAM_LP, 0, 0x19, +- 0, dev_priv->vram_size, 0x00010000); +- if (ret) { +- nv50_evo_channel_del(&dev_priv->evo); +- return ret; ++ ret = nouveau_bo_new(dev, NULL, 4096, 0x1000, TTM_PL_FLAG_VRAM, ++ 0, 0x0000, &dispc->sem.bo); ++ if (!ret) { ++ offset = dispc->sem.bo->bo.mem.start << PAGE_SHIFT; ++ ++ ret = nouveau_bo_pin(dispc->sem.bo, TTM_PL_FLAG_VRAM); ++ if (!ret) ++ ret = nouveau_bo_map(dispc->sem.bo); ++ if (ret) ++ nouveau_bo_ref(NULL, &dispc->sem.bo); + } ++ ++ if (ret) ++ goto err; ++ ++ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoSync, 0x0000, ++ offset, 4096, NULL); ++ if (ret) ++ goto err; ++ ++ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoVRAM_LP, 0x80000000, ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; ++ ++ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB32, 0x80000000 | ++ (dev_priv->chipset < 0xc0 ? ++ 0x7a00 : 0xfe00), ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; ++ ++ ret = nv50_evo_dmaobj_new(dispc->sync, NvEvoFB16, 0x80000000 | ++ (dev_priv->chipset < 0xc0 ? ++ 0x7000 : 0xfe00), ++ 0, dev_priv->vram_size, NULL); ++ if (ret) ++ goto err; ++ ++ for (j = 0; j < 4096; j += 4) ++ nouveau_bo_wr32(dispc->sem.bo, j / 4, 0x74b1e000); ++ dispc->sem.offset = 0; + } + + return 0; ++ ++err: ++ nv50_evo_destroy(dev); ++ return ret; + } + + int + nv50_evo_init(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- int ret; ++ struct nv50_display *disp = nv50_display(dev); ++ int ret, i; + +- if (!dev_priv->evo) { ++ if (!disp->master) { + ret = nv50_evo_create(dev); + if (ret) + return ret; + } + +- return nv50_evo_channel_init(dev_priv->evo); ++ ret = nv50_evo_channel_init(disp->master); ++ if (ret) ++ return ret; ++ ++ for (i = 0; i < 2; i++) { ++ ret = nv50_evo_channel_init(disp->crtc[i].sync); ++ if (ret) ++ return ret; ++ } ++ ++ return 0; + } + + void + nv50_evo_fini(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv50_display *disp = nv50_display(dev); ++ int i; + +- if (dev_priv->evo) { +- nv50_evo_channel_fini(dev_priv->evo); +- nv50_evo_channel_del(&dev_priv->evo); ++ for (i = 0; i < 2; i++) { ++ if (disp->crtc[i].sync) ++ nv50_evo_channel_fini(disp->crtc[i].sync); + } ++ ++ if (disp->master) ++ nv50_evo_channel_fini(disp->master); ++ ++ nv50_evo_destroy(dev); + } +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_evo.h linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_evo.h +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_evo.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_evo.h 2011-02-20 23:32:11.000000000 +0100 +@@ -27,12 +27,6 @@ + #ifndef __NV50_EVO_H__ + #define __NV50_EVO_H__ + +-int nv50_evo_init(struct drm_device *dev); +-void nv50_evo_fini(struct drm_device *dev); +-int nv50_evo_dmaobj_new(struct nouveau_channel *, u32 class, u32 name, +- u32 tile_flags, u32 magic_flags, +- u32 offset, u32 limit); +- + #define NV50_EVO_UPDATE 0x00000080 + #define NV50_EVO_UNK84 0x00000084 + #define NV50_EVO_UNK84_NOTIFY 0x40000000 +@@ -119,5 +113,7 @@ + /* Both of these are needed, otherwise nothing happens. */ + #define NV50_EVO_CRTC_SCALE_RES1 0x000008d8 + #define NV50_EVO_CRTC_SCALE_RES2 0x000008dc ++#define NV50_EVO_CRTC_UNK900 0x00000900 ++#define NV50_EVO_CRTC_UNK904 0x00000904 + + #endif +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_fb.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_fb.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_fb.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_fb.c 2011-02-20 23:32:11.000000000 +0100 +@@ -8,31 +8,61 @@ + dma_addr_t r100c08; + }; + ++static void ++nv50_fb_destroy(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; ++ struct nv50_fb_priv *priv = pfb->priv; ++ ++ if (pfb->tag_heap.free_stack.next) ++ drm_mm_takedown(&pfb->tag_heap); ++ ++ if (priv->r100c08_page) { ++ pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE, ++ PCI_DMA_BIDIRECTIONAL); ++ __free_page(priv->r100c08_page); ++ } ++ ++ kfree(priv); ++ pfb->priv = NULL; ++} ++ + static int + nv50_fb_create(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; + struct nv50_fb_priv *priv; ++ u32 tagmem; ++ int ret; + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ pfb->priv = priv; + + priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!priv->r100c08_page) { +- kfree(priv); ++ nv50_fb_destroy(dev); + return -ENOMEM; + } + + priv->r100c08 = pci_map_page(dev->pdev, priv->r100c08_page, 0, + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); + if (pci_dma_mapping_error(dev->pdev, priv->r100c08)) { +- __free_page(priv->r100c08_page); +- kfree(priv); ++ nv50_fb_destroy(dev); + return -EFAULT; + } + +- dev_priv->engine.fb.priv = priv; ++ tagmem = nv_rd32(dev, 0x100320); ++ NV_DEBUG(dev, "%d tags available\n", tagmem); ++ ret = drm_mm_init(&pfb->tag_heap, 0, tagmem); ++ if (ret) { ++ nv50_fb_destroy(dev); ++ return ret; ++ } ++ + return 0; + } + +@@ -81,18 +111,7 @@ + void + nv50_fb_takedown(struct drm_device *dev) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv50_fb_priv *priv; +- +- priv = dev_priv->engine.fb.priv; +- if (!priv) +- return; +- dev_priv->engine.fb.priv = NULL; +- +- pci_unmap_page(dev->pdev, priv->r100c08, PAGE_SIZE, +- PCI_DMA_BIDIRECTIONAL); +- __free_page(priv->r100c08_page); +- kfree(priv); ++ nv50_fb_destroy(dev); + } + + void +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_fifo.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_fifo.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_fifo.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_fifo.c 2011-02-20 23:32:11.000000000 +0100 +@@ -149,6 +149,7 @@ + nv_wr32(dev, 0x3204, 0); + nv_wr32(dev, 0x3210, 0); + nv_wr32(dev, 0x3270, 0); ++ nv_wr32(dev, 0x2044, 0x01003fff); + + /* Enable dummy channels setup by nv50_instmem.c */ + nv50_fifo_channel_enable(dev, 0); +@@ -273,7 +274,7 @@ + nv_wo32(ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->cinst >> 4)); +- nv_wo32(ramfc, 0x44, 0x2101ffff); ++ nv_wo32(ramfc, 0x44, 0x01003fff); + nv_wo32(ramfc, 0x60, 0x7fffffff); + nv_wo32(ramfc, 0x40, 0x00000000); + nv_wo32(ramfc, 0x7c, 0x30000001); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_gpio.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_gpio.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_gpio.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_gpio.c 2011-02-20 23:32:11.000000000 +0100 +@@ -137,6 +137,7 @@ + struct nv50_gpio_priv *priv = pgpio->priv; + struct nv50_gpio_handler *gpioh, *tmp; + struct dcb_gpio_entry *gpio; ++ LIST_HEAD(tofree); + unsigned long flags; + + gpio = nouveau_bios_gpio_entry(dev, tag); +@@ -149,10 +150,14 @@ + gpioh->handler != handler || + gpioh->data != data) + continue; +- list_del(&gpioh->head); +- kfree(gpioh); ++ list_move(&gpioh->head, &tofree); + } + spin_unlock_irqrestore(&priv->lock, flags); ++ ++ list_for_each_entry_safe(gpioh, tmp, &tofree, head) { ++ flush_work_sync(&gpioh->work); ++ kfree(gpioh); ++ } + } + + bool +@@ -205,7 +210,6 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; +- struct nv50_gpio_priv *priv; + int ret; + + if (!pgpio->priv) { +@@ -213,7 +217,6 @@ + if (ret) + return ret; + } +- priv = pgpio->priv; + + /* disable, and ack any pending gpio interrupts */ + nv_wr32(dev, 0xe050, 0x00000000); +@@ -293,7 +296,7 @@ + continue; + gpioh->inhibit = true; + +- queue_work(dev_priv->wq, &gpioh->work); ++ schedule_work(&gpioh->work); + } + spin_unlock(&priv->lock); + } +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_graph.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_graph.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_graph.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_graph.c 2011-02-20 23:32:11.000000000 +0100 +@@ -409,12 +409,7 @@ + nv50_graph_nvsw_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) + { +- struct nouveau_page_flip_state s; +- +- if (!nouveau_finish_page_flip(chan, &s)) { +- /* XXX - Do something here */ +- } +- ++ nouveau_finish_page_flip(chan, NULL); + return 0; + } + +@@ -912,10 +907,10 @@ + printk("\n"); + NV_INFO(dev, "PGRAPH - TRAP_CCACHE %08x %08x %08x %08x" + " %08x %08x %08x\n", +- nv_rd32(dev, 0x405800), nv_rd32(dev, 0x405804), +- nv_rd32(dev, 0x405808), nv_rd32(dev, 0x40580c), +- nv_rd32(dev, 0x405810), nv_rd32(dev, 0x405814), +- nv_rd32(dev, 0x40581c)); ++ nv_rd32(dev, 0x405000), nv_rd32(dev, 0x405004), ++ nv_rd32(dev, 0x405008), nv_rd32(dev, 0x40500c), ++ nv_rd32(dev, 0x405010), nv_rd32(dev, 0x405014), ++ nv_rd32(dev, 0x40501c)); + + } + +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_instmem.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_instmem.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_instmem.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_instmem.c 2011-02-20 23:32:11.000000000 +0100 +@@ -300,7 +300,7 @@ + } + + struct nv50_gpuobj_node { +- struct nouveau_vram *vram; ++ struct nouveau_mem *vram; + struct nouveau_vma chan_vma; + u32 align; + }; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_sor.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_sor.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_sor.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_sor.c 2011-02-20 23:32:11.000000000 +0100 +@@ -41,8 +41,7 @@ + { + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(dev)->master; + int ret; + + if (!nv_encoder->crtc) +@@ -184,8 +183,7 @@ + nv50_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) + { +- struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; +- struct nouveau_channel *evo = dev_priv->evo; ++ struct nouveau_channel *evo = nv50_display(encoder->dev)->master; + struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); + struct drm_device *dev = encoder->dev; + struct nouveau_crtc *crtc = nouveau_crtc(encoder->crtc); +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_vm.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_vm.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_vm.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_vm.c 2011-02-20 23:32:11.000000000 +0100 +@@ -31,7 +31,6 @@ + nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde, + struct nouveau_gpuobj *pgt[2]) + { +- struct drm_nouveau_private *dev_priv = pgd->dev->dev_private; + u64 phys = 0xdeadcafe00000000ULL; + u32 coverage = 0; + +@@ -58,10 +57,9 @@ + } + + static inline u64 +-nv50_vm_addr(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, +- u64 phys, u32 memtype, u32 target) ++nv50_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target) + { +- struct drm_nouveau_private *dev_priv = pgt->dev->dev_private; ++ struct drm_nouveau_private *dev_priv = vma->vm->dev->dev_private; + + phys |= 1; /* present */ + phys |= (u64)memtype << 40; +@@ -85,12 +83,13 @@ + + void + nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, +- struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) ++ struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) + { ++ u32 comp = (mem->memtype & 0x180) >> 7; + u32 block; + int i; + +- phys = nv50_vm_addr(vma, pgt, phys, mem->memtype, 0); ++ phys = nv50_vm_addr(vma, phys, mem->memtype, 0); + pte <<= 3; + cnt <<= 3; + +@@ -107,6 +106,11 @@ + + phys += block << (vma->node->type - 3); + cnt -= block; ++ if (comp) { ++ u32 tag = mem->tag->start + ((delta >> 16) * comp); ++ offset_h |= (tag << 17); ++ delta += block << (vma->node->type - 3); ++ } + + while (block) { + nv_wo32(pgt, pte + 0, offset_l); +@@ -119,11 +123,11 @@ + + void + nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, +- u32 pte, dma_addr_t *list, u32 cnt) ++ struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) + { + pte <<= 3; + while (cnt--) { +- u64 phys = nv50_vm_addr(vma, pgt, (u64)*list++, 0, 2); ++ u64 phys = nv50_vm_addr(vma, (u64)*list++, mem->memtype, 2); + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + pte += 8; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_vram.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_vram.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nv50_vram.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nv50_vram.c 2011-02-20 23:32:11.000000000 +0100 +@@ -48,42 +48,49 @@ + } + + void +-nv50_vram_del(struct drm_device *dev, struct nouveau_vram **pvram) ++nv50_vram_del(struct drm_device *dev, struct nouveau_mem **pmem) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *this; +- struct nouveau_vram *vram; ++ struct nouveau_mem *mem; + +- vram = *pvram; +- *pvram = NULL; +- if (unlikely(vram == NULL)) ++ mem = *pmem; ++ *pmem = NULL; ++ if (unlikely(mem == NULL)) + return; + + mutex_lock(&mm->mutex); +- while (!list_empty(&vram->regions)) { +- this = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); ++ while (!list_empty(&mem->regions)) { ++ this = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); + + list_del(&this->rl_entry); + nouveau_mm_put(mm, this); + } ++ ++ if (mem->tag) { ++ drm_mm_put_block(mem->tag); ++ mem->tag = NULL; ++ } + mutex_unlock(&mm->mutex); + +- kfree(vram); ++ kfree(mem); + } + + int + nv50_vram_new(struct drm_device *dev, u64 size, u32 align, u32 size_nc, +- u32 type, struct nouveau_vram **pvram) ++ u32 memtype, struct nouveau_mem **pmem) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *r; +- struct nouveau_vram *vram; ++ struct nouveau_mem *mem; ++ int comp = (memtype & 0x300) >> 8; ++ int type = (memtype & 0x07f); + int ret; + + if (!types[type]) +@@ -92,32 +99,46 @@ + align >>= 12; + size_nc >>= 12; + +- vram = kzalloc(sizeof(*vram), GFP_KERNEL); +- if (!vram) ++ mem = kzalloc(sizeof(*mem), GFP_KERNEL); ++ if (!mem) + return -ENOMEM; + +- INIT_LIST_HEAD(&vram->regions); +- vram->dev = dev_priv->dev; +- vram->memtype = type; +- vram->size = size; +- + mutex_lock(&mm->mutex); ++ if (comp) { ++ if (align == 16) { ++ struct nouveau_fb_engine *pfb = &dev_priv->engine.fb; ++ int n = (size >> 4) * comp; ++ ++ mem->tag = drm_mm_search_free(&pfb->tag_heap, n, 0, 0); ++ if (mem->tag) ++ mem->tag = drm_mm_get_block(mem->tag, n, 0); ++ } ++ ++ if (unlikely(!mem->tag)) ++ comp = 0; ++ } ++ ++ INIT_LIST_HEAD(&mem->regions); ++ mem->dev = dev_priv->dev; ++ mem->memtype = (comp << 7) | type; ++ mem->size = size; ++ + do { + ret = nouveau_mm_get(mm, types[type], size, size_nc, align, &r); + if (ret) { + mutex_unlock(&mm->mutex); +- nv50_vram_del(dev, &vram); ++ nv50_vram_del(dev, &mem); + return ret; + } + +- list_add_tail(&r->rl_entry, &vram->regions); ++ list_add_tail(&r->rl_entry, &mem->regions); + size -= r->length; + } while (size); + mutex_unlock(&mm->mutex); + +- r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); +- vram->offset = (u64)r->offset << 12; +- *pvram = vram; ++ r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); ++ mem->offset = (u64)r->offset << 12; ++ *pmem = mem; + return 0; + } + +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_fifo.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_fifo.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-02-20 23:32:11.000000000 +0100 +@@ -116,7 +116,7 @@ + + /* allocate vram for control regs, map into polling area */ + ret = nouveau_bo_new(dev, NULL, 0x1000, 0, TTM_PL_FLAG_VRAM, +- 0, 0, true, true, &fifoch->user); ++ 0, 0, &fifoch->user); + if (ret) + goto error; + +@@ -418,6 +418,12 @@ + { + u32 stat = nv_rd32(dev, 0x002100); + ++ if (stat & 0x00000100) { ++ NV_INFO(dev, "PFIFO: unknown status 0x00000100\n"); ++ nv_wr32(dev, 0x002100, 0x00000100); ++ stat &= ~0x00000100; ++ } ++ + if (stat & 0x10000000) { + u32 units = nv_rd32(dev, 0x00259c); + u32 u = units; +@@ -446,10 +452,15 @@ + stat &= ~0x20000000; + } + ++ if (stat & 0x40000000) { ++ NV_INFO(dev, "PFIFO: unknown status 0x40000000\n"); ++ nv_mask(dev, 0x002a00, 0x00000000, 0x00000000); ++ stat &= ~0x40000000; ++ } ++ + if (stat) { + NV_INFO(dev, "PFIFO: unhandled status 0x%08x\n", stat); + nv_wr32(dev, 0x002100, stat); ++ nv_wr32(dev, 0x002140, 0); + } +- +- nv_wr32(dev, 0x2140, 0); + } +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_graph.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_graph.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-02-20 23:32:11.000000000 +0100 +@@ -299,6 +299,14 @@ + } + + static int ++nvc0_graph_mthd_page_flip(struct nouveau_channel *chan, ++ u32 class, u32 mthd, u32 data) ++{ ++ nouveau_finish_page_flip(chan, NULL); ++ return 0; ++} ++ ++static int + nvc0_graph_create(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -395,6 +403,7 @@ + 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; +@@ -640,7 +649,6 @@ + { + 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; + + dev_priv->engine.graph.accel_blocked = true; +@@ -665,7 +673,6 @@ + if (ret) + return ret; + } +- priv = pgraph->priv; + + nvc0_graph_init_obj418880(dev); + nvc0_graph_init_regs(dev); +@@ -730,9 +737,12 @@ + u32 class = nv_rd32(dev, 0x404200 + (subc * 4)); + + if (stat & 0x00000010) { +- NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] subc %d " +- "class 0x%04x mthd 0x%04x data 0x%08x\n", +- chid, inst, subc, class, mthd, data); ++ if (nouveau_gpuobj_mthd_call2(dev, chid, class, mthd, data)) { ++ NV_INFO(dev, "PGRAPH: ILLEGAL_MTHD ch %d [0x%010llx] " ++ "subc %d class 0x%04x mthd 0x%04x " ++ "data 0x%08x\n", ++ chid, inst, subc, class, mthd, data); ++ } + nv_wr32(dev, 0x400100, 0x00000010); + stat &= ~0x00000010; + } +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_vm.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_vm.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_vm.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_vm.c 2011-02-20 23:32:11.000000000 +0100 +@@ -59,7 +59,7 @@ + + void + nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, +- struct nouveau_vram *mem, u32 pte, u32 cnt, u64 phys) ++ struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) + { + u32 next = 1 << (vma->node->type - 8); + +@@ -75,11 +75,11 @@ + + void + nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt, +- u32 pte, dma_addr_t *list, u32 cnt) ++ struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) + { + pte <<= 3; + while (cnt--) { +- u64 phys = nvc0_vm_addr(vma, *list++, 0, 5); ++ u64 phys = nvc0_vm_addr(vma, *list++, mem->memtype, 5); + nv_wo32(pgt, pte + 0, lower_32_bits(phys)); + nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + pte += 8; +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_vram.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_vram.c +--- linux-2.6.38-rc5/drivers/gpu/drm/nouveau/nvc0_vram.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/nouveau/nvc0_vram.c 2011-02-20 23:32:11.000000000 +0100 +@@ -26,64 +26,78 @@ + #include "nouveau_drv.h" + #include "nouveau_mm.h" + ++/* 0 = unsupported ++ * 1 = non-compressed ++ * 3 = compressed ++ */ ++static const u8 types[256] = { ++ 1, 1, 3, 3, 3, 3, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, ++ 0, 1, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, ++ 3, 3, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, 1, 1, 1, 1, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 3, 3, 3, 3, 1, 1, 1, 1, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, ++ 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, ++ 3, 3, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 0, 3, 0, 3, ++ 3, 0, 3, 3, 3, 3, 3, 0, 0, 3, 0, 3, 0, 3, 3, 0, ++ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 1, 1, 0 ++}; ++ + bool + nvc0_vram_flags_valid(struct drm_device *dev, u32 tile_flags) + { +- switch (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) { +- case 0x0000: +- case 0xfe00: +- case 0xdb00: +- case 0x1100: +- return true; +- default: +- break; +- } +- +- return false; ++ u8 memtype = (tile_flags & NOUVEAU_GEM_TILE_LAYOUT_MASK) >> 8; ++ return likely((types[memtype] == 1)); + } + + int + nvc0_vram_new(struct drm_device *dev, u64 size, u32 align, u32 ncmin, +- u32 type, struct nouveau_vram **pvram) ++ u32 type, struct nouveau_mem **pmem) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct ttm_bo_device *bdev = &dev_priv->ttm.bdev; + struct ttm_mem_type_manager *man = &bdev->man[TTM_PL_VRAM]; + struct nouveau_mm *mm = man->priv; + struct nouveau_mm_node *r; +- struct nouveau_vram *vram; ++ struct nouveau_mem *mem; + int ret; + + size >>= 12; + align >>= 12; + ncmin >>= 12; + +- vram = kzalloc(sizeof(*vram), GFP_KERNEL); +- if (!vram) ++ mem = kzalloc(sizeof(*mem), GFP_KERNEL); ++ if (!mem) + return -ENOMEM; + +- INIT_LIST_HEAD(&vram->regions); +- vram->dev = dev_priv->dev; +- vram->memtype = type; +- vram->size = size; ++ INIT_LIST_HEAD(&mem->regions); ++ mem->dev = dev_priv->dev; ++ mem->memtype = (type & 0xff); ++ mem->size = size; + + mutex_lock(&mm->mutex); + do { + ret = nouveau_mm_get(mm, 1, size, ncmin, align, &r); + if (ret) { + mutex_unlock(&mm->mutex); +- nv50_vram_del(dev, &vram); ++ nv50_vram_del(dev, &mem); + return ret; + } + +- list_add_tail(&r->rl_entry, &vram->regions); ++ list_add_tail(&r->rl_entry, &mem->regions); + size -= r->length; + } while (size); + mutex_unlock(&mm->mutex); + +- r = list_first_entry(&vram->regions, struct nouveau_mm_node, rl_entry); +- vram->offset = (u64)r->offset << 12; +- *pvram = vram; ++ r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry); ++ mem->offset = (u64)r->offset << 12; ++ *pmem = mem; + return 0; + } + +diff -Naur linux-2.6.38-rc5/drivers/gpu/drm/ttm/ttm_bo.c linux-2.6.38-rc5.nouveau/drivers/gpu/drm/ttm/ttm_bo.c +--- linux-2.6.38-rc5/drivers/gpu/drm/ttm/ttm_bo.c 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/drivers/gpu/drm/ttm/ttm_bo.c 2011-02-20 23:32:11.000000000 +0100 +@@ -406,11 +406,12 @@ + } + + if (bo->mem.mem_type == TTM_PL_SYSTEM) { ++ if (bdev->driver->move_notify) ++ bdev->driver->move_notify(bo, mem); + bo->mem = *mem; + mem->mm_node = NULL; + goto moved; + } +- + } + + if (bdev->driver->move_notify) +diff -Naur linux-2.6.38-rc5/include/drm/nouveau_drm.h linux-2.6.38-rc5.nouveau/include/drm/nouveau_drm.h +--- linux-2.6.38-rc5/include/drm/nouveau_drm.h 2011-02-16 04:23:45.000000000 +0100 ++++ linux-2.6.38-rc5.nouveau/include/drm/nouveau_drm.h 2011-02-20 23:32:11.000000000 +0100 +@@ -94,6 +94,7 @@ + #define NOUVEAU_GEM_DOMAIN_GART (1 << 2) + #define NOUVEAU_GEM_DOMAIN_MAPPABLE (1 << 3) + ++#define NOUVEAU_GEM_TILE_COMP 0x00030000 /* nv50-only */ + #define NOUVEAU_GEM_TILE_LAYOUT_MASK 0x0000ff00 + #define NOUVEAU_GEM_TILE_16BPP 0x00000001 + #define NOUVEAU_GEM_TILE_32BPP 0x00000002