diff --git a/config/graphic b/config/graphic index 26485bad04..13931f004f 100644 --- a/config/graphic +++ b/config/graphic @@ -31,7 +31,7 @@ get_graphicdrivers() { # DRI_DRIVERS="$DRI_DRIVERS,nouveau" GALLIUM_DRIVERS="$GALLIUM_DRIVERS,nouveau" XORG_DRIVERS="$XORG_DRIVERS nouveau" - LLVM_SUPPORT="yes" +# LLVM_SUPPORT="yes" fi if [ "$drv" = "nvidia" ]; then diff --git a/packages/graphics/Mesa/build b/packages/graphics/Mesa/build index a87cc73e16..51888af2ad 100755 --- a/packages/graphics/Mesa/build +++ b/packages/graphics/Mesa/build @@ -30,19 +30,6 @@ get_graphicdrivers # Mesa fails to build with LTO optimization strip_lto -# dont build with loop and graphite optimization - CFLAGS=`echo $CFLAGS | sed -e "s|-ftree-loop-distribution||"` - CFLAGS=`echo $CFLAGS | sed -e "s|-floop-interchange||"` - CFLAGS=`echo $CFLAGS | sed -e "s|-floop-strip-mine||"` - CFLAGS=`echo $CFLAGS | sed -e "s|-floop-block||"` - CFLAGS=`echo $CFLAGS | sed -e "s|-fgraphite-identity||"` - - CXXFLAGS=`echo $CXXFLAGS | sed -e "s|-ftree-loop-distribution||"` - CXXFLAGS=`echo $CXXFLAGS | sed -e "s|-floop-interchange||"` - CXXFLAGS=`echo $CXXFLAGS | sed -e "s|-floop-strip-mine||"` - CXXFLAGS=`echo $CXXFLAGS | sed -e "s|-floop-block||"` - CXXFLAGS=`echo $CXXFLAGS | sed -e "s|-fgraphite-identity||"` - if [ "$LLVM_SUPPORT" = "yes" ]; then export LLVM_CONFIG="$SYSROOT_PREFIX/usr/bin/llvm-config" MESA_GALLIUM_LLVM="--enable-gallium-llvm" @@ -65,10 +52,10 @@ DRI_DRIVER_SEARCH_DIR="$XORG_PATH_DRI" \ --disable-static \ --enable-shared \ --disable-debug \ - --disable-texture-float \ + --enable-texture-float \ --disable-selinux \ --enable-opengl \ - --disable-glx-tls \ + --enable-glx-tls \ --enable-driglx-direct \ --disable-gles1 \ --disable-gles2 \ @@ -84,9 +71,9 @@ DRI_DRIVER_SEARCH_DIR="$XORG_PATH_DRI" \ --disable-gbm \ --disable-gallium-egl \ --disable-gallium-gbm \ - --enable-shared-glapi \ + --disable-shared-glapi \ --enable-xcb \ - --enable-shared-dricore \ + --disable-shared-dricore \ --disable-egl \ $MESA_GALLIUM_LLVM \ --with-gallium-drivers="$GALLIUM_DRIVERS" \ diff --git a/packages/graphics/Mesa/install b/packages/graphics/Mesa/install index 1dd173c116..6fd67ce905 100755 --- a/packages/graphics/Mesa/install +++ b/packages/graphics/Mesa/install @@ -27,11 +27,11 @@ mkdir -p $INSTALL/usr/lib ln -sf libGL.so.1 $INSTALL/usr/lib/libGL.so ln -sf /var/lib/libGL.so $INSTALL/usr/lib/libGL.so.1 cp -P $PKG_BUILD/lib/libGLU.so* $INSTALL/usr/lib - cp -P $PKG_BUILD/lib/libglapi.so* $INSTALL/usr/lib +# cp -P $PKG_BUILD/lib/libglapi.so* $INSTALL/usr/lib mkdir -p $INSTALL/usr/lib/dri - cp -P $PKG_BUILD/lib/libdricore.so $INSTALL/usr/lib - cp -P $PKG_BUILD/lib/libglsl.so $INSTALL/usr/lib +# cp -P $PKG_BUILD/lib/libdricore.so $INSTALL/usr/lib +# cp -P $PKG_BUILD/lib/libglsl.so $INSTALL/usr/lib cp -P $PKG_BUILD/lib/*_dri.so $INSTALL/usr/lib/dri || true cp -P $PKG_BUILD/lib/gallium/*_dri.so $INSTALL/usr/lib/dri || true diff --git a/packages/graphics/Mesa/meta b/packages/graphics/Mesa/meta index 330b369cb5..43b73709d0 100644 --- a/packages/graphics/Mesa/meta +++ b/packages/graphics/Mesa/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="Mesa" -PKG_VERSION="7.11-rc2" +PKG_VERSION="7.11-rc3" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="OSS" diff --git a/packages/graphics/Mesa/patches/Mesa-7.11-rc2-llvm_so.patch b/packages/graphics/Mesa/patches/Mesa-7.11-rc3-llvm_so.patch similarity index 100% rename from packages/graphics/Mesa/patches/Mesa-7.11-rc2-llvm_so.patch rename to packages/graphics/Mesa/patches/Mesa-7.11-rc3-llvm_so.patch diff --git a/packages/linux/patches/linux-3.0-053-ati_remote-0.1.patch b/packages/linux/patches/linux-3.0-053-ati_remote-0.1.patch new file mode 100644 index 0000000000..4d3d03db11 --- /dev/null +++ b/packages/linux/patches/linux-3.0-053-ati_remote-0.1.patch @@ -0,0 +1,24 @@ +diff -Naur linux-3.0-old/drivers/input/misc/ati_remote2.c linux-3.0-new/drivers/input/misc/ati_remote2.c +--- linux-3.0-old/drivers/input/misc/ati_remote2.c 2011-07-22 08:42:47.000000000 -0700 ++++ linux-3.0-new/drivers/input/misc/ati_remote2.c 2011-07-22 08:44:20.000000000 -0700 +@@ -619,7 +619,7 @@ + idev->phys = ar2->phys; + + usb_to_input_id(ar2->udev, &idev->id); +- idev->dev.parent = &ar2->udev->dev; ++ idev->dev.parent = &ar2->intf[0]->dev; + + retval = input_register_device(idev); + if (retval) +diff -Naur linux-3.0-old/drivers/input/misc/ati_remote.c linux-3.0-new/drivers/input/misc/ati_remote.c +--- linux-3.0-old/drivers/input/misc/ati_remote.c 2011-07-22 08:42:47.000000000 -0700 ++++ linux-3.0-new/drivers/input/misc/ati_remote.c 2011-07-22 08:44:20.000000000 -0700 +@@ -682,7 +682,7 @@ + idev->phys = ati_remote->phys; + + usb_to_input_id(ati_remote->udev, &idev->id); +- idev->dev.parent = &ati_remote->udev->dev; ++ idev->dev.parent = &ati_remote->interface->dev; + } + + static int ati_remote_initialize(struct ati_remote *ati_remote) diff --git a/packages/linux/patches/linux-3.0-055-add_wiimote_hid_driver-0.1.patch b/packages/linux/patches/linux-3.0-055-add_wiimote_hid_driver-0.1.patch new file mode 100644 index 0000000000..5dfb4b853a --- /dev/null +++ b/packages/linux/patches/linux-3.0-055-add_wiimote_hid_driver-0.1.patch @@ -0,0 +1,2563 @@ +From: Linus Torvalds +Date: Fri, 22 Jul 2011 22:02:58 +0000 (-0700) +Subject: Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=22a3b9771117d566def0150ea787fcc95f16e724;hp=acb41c0f928fdb84a1c3753ac92c534a2a0f08d2 + +Merge branch 'for-linus' of git://git./linux/kernel/git/jikos/hid + +* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (31 commits) + HID: fix support for Microsoft comfort mouse 4500 + HID: hid-multitouch: add one new multitouch device's VID/PID + HID: prodikeys: remove a redundant forward declaration of struct pcmidi_snd + HID: prodikeys: make needlessly global symbols static + HID: emsff: properly handle emsff_init failure + HID: ACRUX - add missing hid_hw_stop() in ax_probe() error path + HID: fix horizontal wheel for ms comfort mouse 4500 + HID: uclogic: Add support for UC-Logic WP1062 + HID: wiimote: Add sysfs support to wiimote driver + HID: wiimote: Cache wiimote led state + HID: wiimote: Add wiimote led request + HID: wiimote: Add wiimote input button parser + HID: wiimote: Add wiimote event handler + HID: wiimote: Add output queue for wiimote driver + HID: wiimote: Add wiimote send function + HID: wiimote: Synchronize wiimote input and hid event handling + HID: wiimote: Register input device in wiimote hid driver + HID: wiimote: Add wiimote device structure + HID: wiimote: Register wiimote hid driver stub + HID: wiimote: Add Nintendo Wii Remote driver stub + ... +--- + +diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus +index c1b53b8..65e6e5d 100644 +--- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus ++++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-koneplus +@@ -92,6 +92,14 @@ Description: The mouse has a tracking- and a distance-control-unit. These + This file is writeonly. + Users: http://roccat.sourceforge.net + ++What: /sys/bus/usb/devices/-:./::./koneplus/roccatkoneplus/talk ++Date: May 2011 ++Contact: Stefan Achatz ++Description: Used to active some easy* functions of the mouse from outside. ++ The data has to be 16 bytes long. ++ This file is writeonly. ++Users: http://roccat.sourceforge.net ++ + What: /sys/bus/usb/devices/-:./::./koneplus/roccatkoneplus/tcu + Date: October 2010 + Contact: Stefan Achatz +diff --git a/Documentation/ABI/testing/sysfs-driver-hid-wiimote b/Documentation/ABI/testing/sysfs-driver-hid-wiimote +new file mode 100644 +index 0000000..5d5a16e +--- /dev/null ++++ b/Documentation/ABI/testing/sysfs-driver-hid-wiimote +@@ -0,0 +1,10 @@ ++What: /sys/bus/hid/drivers/wiimote//led1 ++What: /sys/bus/hid/drivers/wiimote//led2 ++What: /sys/bus/hid/drivers/wiimote//led3 ++What: /sys/bus/hid/drivers/wiimote//led4 ++Date: July 2011 ++KernelVersion: 3.1 ++Contact: David Herrmann ++Description: Make it possible to set/get current led state. Reading from it ++ returns 0 if led is off and 1 if it is on. Writing 0 to it ++ disables the led, writing 1 enables it. +diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig +index 36ca465..306b15f 100644 +--- a/drivers/hid/Kconfig ++++ b/drivers/hid/Kconfig +@@ -172,6 +172,20 @@ config HID_EZKEY + ---help--- + Support for Ezkey BTC 8193 keyboard. + ++config HID_HOLTEK ++ tristate "Holtek On Line Grip based game controller support" ++ depends on USB_HID ++ ---help--- ++ Say Y here if you have a Holtek On Line Grip based game controller. ++ ++config HOLTEK_FF ++ bool "Holtek On Line Grip force feedback support" ++ depends on HID_HOLTEK ++ select INPUT_FF_MEMLESS ++ ---help--- ++ Say Y here if you have a Holtek On Line Grip based game controller ++ and want to have force feedback support for it. ++ + config HID_KEYTOUCH + tristate "Keytouch HID devices" + depends on USB_HID +@@ -322,6 +336,7 @@ config HID_MULTITOUCH + - Stantum multitouch panels + - Touch International Panels + - Unitec Panels ++ - XAT optical touch panels + + If unsure, say N. + +@@ -435,6 +450,7 @@ config HID_QUANTA + config HID_ROCCAT + tristate "Roccat special event support" + depends on USB_HID ++ select HID_ROCCAT_COMMON + ---help--- + Support for Roccat special events. + Say Y here if you have a Roccat mouse or keyboard and want OSD or +@@ -442,44 +458,40 @@ config HID_ROCCAT + + config HID_ROCCAT_COMMON + tristate ++ depends on HID_ROCCAT + + config HID_ROCCAT_ARVO + tristate "Roccat Arvo keyboard support" + depends on USB_HID +- select HID_ROCCAT +- select HID_ROCCAT_COMMON ++ depends on HID_ROCCAT + ---help--- + Support for Roccat Arvo keyboard. + + config HID_ROCCAT_KONE + tristate "Roccat Kone Mouse support" + depends on USB_HID +- select HID_ROCCAT +- select HID_ROCCAT_COMMON ++ depends on HID_ROCCAT + ---help--- + Support for Roccat Kone mouse. + + config HID_ROCCAT_KONEPLUS + tristate "Roccat Kone[+] mouse support" + depends on USB_HID +- select HID_ROCCAT +- select HID_ROCCAT_COMMON ++ depends on HID_ROCCAT + ---help--- + Support for Roccat Kone[+] mouse. + + config HID_ROCCAT_KOVAPLUS + tristate "Roccat Kova[+] mouse support" + depends on USB_HID +- select HID_ROCCAT +- select HID_ROCCAT_COMMON ++ depends on HID_ROCCAT + ---help--- + Support for Roccat Kova[+] mouse. + + config HID_ROCCAT_PYRA + tristate "Roccat Pyra mouse support" + depends on USB_HID +- select HID_ROCCAT +- select HID_ROCCAT_COMMON ++ depends on HID_ROCCAT + ---help--- + Support for Roccat Pyra mouse. + +@@ -495,6 +507,12 @@ config HID_SONY + ---help--- + Support for Sony PS3 controller. + ++config HID_SPEEDLINK ++ tristate "Speedlink VAD Cezanne mouse support" ++ depends on USB_HID ++ ---help--- ++ Support for Speedlink Vicious and Divine Cezanne mouse. ++ + config HID_SUNPLUS + tristate "Sunplus wireless desktop" + depends on USB_HID +@@ -568,6 +586,12 @@ config HID_WACOM_POWER_SUPPLY + Say Y here if you want to enable power supply status monitoring for + Wacom Bluetooth devices. + ++config HID_WIIMOTE ++ tristate "Nintendo Wii Remote support" ++ depends on BT_HIDP ++ ---help--- ++ Support for the Nintendo Wii Remote bluetooth device. ++ + config HID_ZEROPLUS + tristate "Zeroplus based game controller support" + depends on USB_HID +diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile +index f8cc4ea..0a0a38e 100644 +--- a/drivers/hid/Makefile ++++ b/drivers/hid/Makefile +@@ -37,6 +37,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o + obj-$(CONFIG_HID_ELECOM) += hid-elecom.o + obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o + obj-$(CONFIG_HID_GYRATION) += hid-gyration.o ++obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o + obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o + obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o + obj-$(CONFIG_HID_KYE) += hid-kye.o +@@ -63,6 +64,7 @@ obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o + obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o + obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o + obj-$(CONFIG_HID_SONY) += hid-sony.o ++obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o + obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o + obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o + obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o +@@ -73,6 +75,7 @@ obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o + obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o + obj-$(CONFIG_HID_WACOM) += hid-wacom.o + obj-$(CONFIG_HID_WALTOP) += hid-waltop.o ++obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o + + obj-$(CONFIG_USB_HID) += usbhid/ + obj-$(CONFIG_USB_MOUSE) += usbhid/ +diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c +index b455428..1215141 100644 +--- a/drivers/hid/hid-axff.c ++++ b/drivers/hid/hid-axff.c +@@ -154,6 +154,7 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) + error = hid_hw_open(hdev); + if (error) { + dev_err(&hdev->dev, "hw open failed\n"); ++ hid_hw_stop(hdev); + return error; + } + +diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c +index 6f3289a..1a5cf0c 100644 +--- a/drivers/hid/hid-core.c ++++ b/drivers/hid/hid-core.c +@@ -1388,6 +1388,7 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, +@@ -1426,10 +1427,12 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LUMIO, USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, + { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, +@@ -1491,6 +1494,7 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0709) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, +@@ -1499,11 +1503,14 @@ static const struct hid_device_id hid_have_special_driver[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_XAT, USB_DEVICE_ID_XAT_CSR) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, + + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, ++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, + { } + }; + +@@ -1771,7 +1778,6 @@ static const struct hid_device_id hid_ignore_list[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) }, + { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) }, + { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) }, +- { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_JESS_YUREX) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) }, + { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) }, +@@ -1912,6 +1918,11 @@ static bool hid_ignore(struct hid_device *hdev) + hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST) + return true; + break; ++ case USB_VENDOR_ID_JESS: ++ if (hdev->product == USB_DEVICE_ID_JESS_YUREX && ++ hdev->type == HID_TYPE_USBNONE) ++ return true; ++ break; + } + + if (hdev->type == HID_TYPE_USBMOUSE && +diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c +index 81877c6..a5dc13f 100644 +--- a/drivers/hid/hid-emsff.c ++++ b/drivers/hid/hid-emsff.c +@@ -126,7 +126,12 @@ static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id) + goto err; + } + +- emsff_init(hdev); ++ ret = emsff_init(hdev); ++ if (ret) { ++ dev_err(&hdev->dev, "force feedback init failed\n"); ++ hid_hw_stop(hdev); ++ goto err; ++ } + + return 0; + err: +diff --git a/drivers/hid/hid-holtekff.c b/drivers/hid/hid-holtekff.c +new file mode 100644 +index 0000000..91e3a03 +--- /dev/null ++++ b/drivers/hid/hid-holtekff.c +@@ -0,0 +1,240 @@ ++/* ++ * Force feedback support for Holtek On Line Grip based gamepads ++ * ++ * These include at least a Brazilian "Clone Joypad Super Power Fire" ++ * which uses vendor ID 0x1241 and identifies as "HOLTEK On Line Grip". ++ * ++ * Copyright (c) 2011 Anssi Hannula ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++ ++#ifdef CONFIG_HOLTEK_FF ++#include "usbhid/usbhid.h" ++ ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("Anssi Hannula "); ++MODULE_DESCRIPTION("Force feedback support for Holtek On Line Grip based devices"); ++ ++/* ++ * These commands and parameters are currently known: ++ * ++ * byte 0: command id: ++ * 01 set effect parameters ++ * 02 play specified effect ++ * 03 stop specified effect ++ * 04 stop all effects ++ * 06 stop all effects ++ * (the difference between 04 and 06 isn't known; win driver ++ * sends 06,04 on application init, and 06 otherwise) ++ * ++ * Commands 01 and 02 need to be sent as pairs, i.e. you need to send 01 ++ * before each 02. ++ * ++ * The rest of the bytes are parameters. Command 01 takes all of them, and ++ * commands 02,03 take only the effect id. ++ * ++ * byte 1: ++ * bits 0-3: effect id: ++ * 1: very strong rumble ++ * 2: periodic rumble, short intervals ++ * 3: very strong rumble ++ * 4: periodic rumble, long intervals ++ * 5: weak periodic rumble, long intervals ++ * 6: weak periodic rumble, short intervals ++ * 7: periodic rumble, short intervals ++ * 8: strong periodic rumble, short intervals ++ * 9: very strong rumble ++ * a: causes an error ++ * b: very strong periodic rumble, very short intervals ++ * c-f: nothing ++ * bit 6: right (weak) motor enabled ++ * bit 7: left (strong) motor enabled ++ * ++ * bytes 2-3: time in milliseconds, big-endian ++ * bytes 5-6: unknown (win driver seems to use at least 10e0 with effect 1 ++ * and 0014 with effect 6) ++ * byte 7: ++ * bits 0-3: effect magnitude ++ */ ++ ++#define HOLTEKFF_MSG_LENGTH 7 ++ ++static const u8 start_effect_1[] = { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static const u8 stop_all4[] = { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++static const u8 stop_all6[] = { 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; ++ ++struct holtekff_device { ++ struct hid_field *field; ++}; ++ ++static void holtekff_send(struct holtekff_device *holtekff, ++ struct hid_device *hid, ++ const u8 data[HOLTEKFF_MSG_LENGTH]) ++{ ++ int i; ++ ++ for (i = 0; i < HOLTEKFF_MSG_LENGTH; i++) { ++ holtekff->field->value[i] = data[i]; ++ } ++ ++ dbg_hid("sending %02x %02x %02x %02x %02x %02x %02x\n", data[0], ++ data[1], data[2], data[3], data[4], data[5], data[6]); ++ ++ usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT); ++} ++ ++static int holtekff_play(struct input_dev *dev, void *data, ++ struct ff_effect *effect) ++{ ++ struct hid_device *hid = input_get_drvdata(dev); ++ struct holtekff_device *holtekff = data; ++ int left, right; ++ /* effect type 1, length 65535 msec */ ++ u8 buf[HOLTEKFF_MSG_LENGTH] = ++ { 0x01, 0x01, 0xff, 0xff, 0x10, 0xe0, 0x00 }; ++ ++ left = effect->u.rumble.strong_magnitude; ++ right = effect->u.rumble.weak_magnitude; ++ dbg_hid("called with 0x%04x 0x%04x\n", left, right); ++ ++ if (!left && !right) { ++ holtekff_send(holtekff, hid, stop_all6); ++ return 0; ++ } ++ ++ if (left) ++ buf[1] |= 0x80; ++ if (right) ++ buf[1] |= 0x40; ++ ++ /* The device takes a single magnitude, so we just sum them up. */ ++ buf[6] = min(0xf, (left >> 12) + (right >> 12)); ++ ++ holtekff_send(holtekff, hid, buf); ++ holtekff_send(holtekff, hid, start_effect_1); ++ ++ return 0; ++} ++ ++static int holtekff_init(struct hid_device *hid) ++{ ++ struct holtekff_device *holtekff; ++ struct hid_report *report; ++ struct hid_input *hidinput = list_entry(hid->inputs.next, ++ struct hid_input, list); ++ struct list_head *report_list = ++ &hid->report_enum[HID_OUTPUT_REPORT].report_list; ++ struct input_dev *dev = hidinput->input; ++ int error; ++ ++ if (list_empty(report_list)) { ++ hid_err(hid, "no output report found\n"); ++ return -ENODEV; ++ } ++ ++ report = list_entry(report_list->next, struct hid_report, list); ++ ++ if (report->maxfield < 1 || report->field[0]->report_count != 7) { ++ hid_err(hid, "unexpected output report layout\n"); ++ return -ENODEV; ++ } ++ ++ holtekff = kzalloc(sizeof(*holtekff), GFP_KERNEL); ++ if (!holtekff) ++ return -ENOMEM; ++ ++ set_bit(FF_RUMBLE, dev->ffbit); ++ ++ holtekff->field = report->field[0]; ++ ++ /* initialize the same way as win driver does */ ++ holtekff_send(holtekff, hid, stop_all4); ++ holtekff_send(holtekff, hid, stop_all6); ++ ++ error = input_ff_create_memless(dev, holtekff, holtekff_play); ++ if (error) { ++ kfree(holtekff); ++ return error; ++ } ++ ++ hid_info(hid, "Force feedback for Holtek On Line Grip based devices by Anssi Hannula \n"); ++ ++ return 0; ++} ++#else ++static inline int holtekff_init(struct hid_device *hid) ++{ ++ return 0; ++} ++#endif ++ ++static int holtek_probe(struct hid_device *hdev, const struct hid_device_id *id) ++{ ++ int ret; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "parse failed\n"); ++ goto err; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); ++ if (ret) { ++ hid_err(hdev, "hw start failed\n"); ++ goto err; ++ } ++ ++ holtekff_init(hdev); ++ ++ return 0; ++err: ++ return ret; ++} ++ ++static const struct hid_device_id holtek_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, holtek_devices); ++ ++static struct hid_driver holtek_driver = { ++ .name = "holtek", ++ .id_table = holtek_devices, ++ .probe = holtek_probe, ++}; ++ ++static int __init holtek_init(void) ++{ ++ return hid_register_driver(&holtek_driver); ++} ++ ++static void __exit holtek_exit(void) ++{ ++ hid_unregister_driver(&holtek_driver); ++} ++ ++module_init(holtek_init); ++module_exit(holtek_exit); ++ +diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h +index a756ee6..db63ccf 100644 +--- a/drivers/hid/hid-ids.h ++++ b/drivers/hid/hid-ids.h +@@ -350,6 +350,9 @@ + #define USB_VENDOR_ID_ILITEK 0x222a + #define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 + ++#define USB_VENDOR_ID_HOLTEK 0x1241 ++#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 ++ + #define USB_VENDOR_ID_IMATION 0x0718 + #define USB_DEVICE_ID_DISC_STAKKA 0xd000 + +@@ -472,6 +475,8 @@ + #define USB_DEVICE_ID_MS_LK6K 0x00f9 + #define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701 + #define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 ++#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730 ++#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c + + #define USB_VENDOR_ID_MOJO 0x8282 + #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 +@@ -495,6 +500,9 @@ + #define USB_VENDOR_ID_NEXTWINDOW 0x1926 + #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 + ++#define USB_VENDOR_ID_NINTENDO 0x057e ++#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 ++ + #define USB_VENDOR_ID_NTRIG 0x1b96 + #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 + #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 +@@ -630,6 +638,7 @@ + #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 + #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 + #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 ++#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 + + #define USB_VENDOR_ID_UNITEC 0x227d + #define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 +@@ -663,6 +672,12 @@ + #define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677 + #define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 + ++#define USB_VENDOR_ID_X_TENSIONS 0x1ae7 ++#define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001 ++ ++#define USB_VENDOR_ID_XAT 0x2505 ++#define USB_DEVICE_ID_XAT_CSR 0x0220 ++ + #define USB_VENDOR_ID_YEALINK 0x6993 + #define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 + +diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c +index 21f205f..a7f916e 100644 +--- a/drivers/hid/hid-lg.c ++++ b/drivers/hid/hid-lg.c +@@ -41,6 +41,66 @@ + #define LG_FF3 0x1000 + #define LG_FF4 0x2000 + ++/* Size of the original descriptor of the Driving Force Pro wheel */ ++#define DFP_RDESC_ORIG_SIZE 97 ++ ++/* Fixed report descriptor for Logitech Driving Force Pro wheel controller ++ * ++ * The original descriptor hides the separate throttle and brake axes in ++ * a custom vendor usage page, providing only a combined value as ++ * GenericDesktop.Y. ++ * This descriptor removes the combined Y axis and instead reports ++ * separate throttle (Y) and brake (RZ). ++ */ ++static __u8 dfp_rdesc_fixed[] = { ++0x05, 0x01, /* Usage Page (Desktop), */ ++0x09, 0x04, /* Usage (Joystik), */ ++0xA1, 0x01, /* Collection (Application), */ ++0xA1, 0x02, /* Collection (Logical), */ ++0x95, 0x01, /* Report Count (1), */ ++0x75, 0x0E, /* Report Size (14), */ ++0x14, /* Logical Minimum (0), */ ++0x26, 0xFF, 0x3F, /* Logical Maximum (16383), */ ++0x34, /* Physical Minimum (0), */ ++0x46, 0xFF, 0x3F, /* Physical Maximum (16383), */ ++0x09, 0x30, /* Usage (X), */ ++0x81, 0x02, /* Input (Variable), */ ++0x95, 0x0E, /* Report Count (14), */ ++0x75, 0x01, /* Report Size (1), */ ++0x25, 0x01, /* Logical Maximum (1), */ ++0x45, 0x01, /* Physical Maximum (1), */ ++0x05, 0x09, /* Usage Page (Button), */ ++0x19, 0x01, /* Usage Minimum (01h), */ ++0x29, 0x0E, /* Usage Maximum (0Eh), */ ++0x81, 0x02, /* Input (Variable), */ ++0x05, 0x01, /* Usage Page (Desktop), */ ++0x95, 0x01, /* Report Count (1), */ ++0x75, 0x04, /* Report Size (4), */ ++0x25, 0x07, /* Logical Maximum (7), */ ++0x46, 0x3B, 0x01, /* Physical Maximum (315), */ ++0x65, 0x14, /* Unit (Degrees), */ ++0x09, 0x39, /* Usage (Hat Switch), */ ++0x81, 0x42, /* Input (Variable, Nullstate), */ ++0x65, 0x00, /* Unit, */ ++0x26, 0xFF, 0x00, /* Logical Maximum (255), */ ++0x46, 0xFF, 0x00, /* Physical Maximum (255), */ ++0x75, 0x08, /* Report Size (8), */ ++0x81, 0x01, /* Input (Constant), */ ++0x09, 0x31, /* Usage (Y), */ ++0x81, 0x02, /* Input (Variable), */ ++0x09, 0x35, /* Usage (Rz), */ ++0x81, 0x02, /* Input (Variable), */ ++0x81, 0x01, /* Input (Constant), */ ++0xC0, /* End Collection, */ ++0xA1, 0x02, /* Collection (Logical), */ ++0x09, 0x02, /* Usage (02h), */ ++0x95, 0x07, /* Report Count (7), */ ++0x91, 0x02, /* Output (Variable), */ ++0xC0, /* End Collection, */ ++0xC0 /* End Collection */ ++}; ++ ++ + /* + * Certain Logitech keyboards send in report #3 keys which are far + * above the logical maximum described in descriptor. This extends +@@ -74,6 +134,18 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc, + rdesc[47] = 0x95; + rdesc[48] = 0x0B; + } ++ ++ switch (hdev->product) { ++ case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: ++ if (*rsize == DFP_RDESC_ORIG_SIZE) { ++ hid_info(hdev, ++ "fixing up Logitech Driving Force Pro report descriptor\n"); ++ rdesc = dfp_rdesc_fixed; ++ *rsize = sizeof(dfp_rdesc_fixed); ++ } ++ break; ++ } ++ + return rdesc; + } + +@@ -380,7 +452,7 @@ static const struct hid_device_id lg_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL), + .driver_data = LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL), +- .driver_data = LG_FF }, ++ .driver_data = LG_NOGET | LG_FF }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL), + .driver_data = LG_FF4 }, + { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ), +diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c +index 0f6fc54..e5c699b 100644 +--- a/drivers/hid/hid-microsoft.c ++++ b/drivers/hid/hid-microsoft.c +@@ -23,11 +23,12 @@ + + #include "hid-ids.h" + +-#define MS_HIDINPUT 0x01 +-#define MS_ERGONOMY 0x02 +-#define MS_PRESENTER 0x04 +-#define MS_RDESC 0x08 +-#define MS_NOGET 0x10 ++#define MS_HIDINPUT 0x01 ++#define MS_ERGONOMY 0x02 ++#define MS_PRESENTER 0x04 ++#define MS_RDESC 0x08 ++#define MS_NOGET 0x10 ++#define MS_DUPLICATE_USAGES 0x20 + + /* + * Microsoft Wireless Desktop Receiver (Model 1028) has +@@ -109,6 +110,18 @@ static int ms_input_mapping(struct hid_device *hdev, struct hid_input *hi, + return 0; + } + ++static int ms_input_mapped(struct hid_device *hdev, struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); ++ ++ if (quirks & MS_DUPLICATE_USAGES) ++ clear_bit(usage->code, *bit); ++ ++ return 0; ++} ++ + static int ms_event(struct hid_device *hdev, struct hid_field *field, + struct hid_usage *usage, __s32 value) + { +@@ -179,8 +192,12 @@ static const struct hid_device_id ms_devices[] = { + .driver_data = MS_ERGONOMY | MS_RDESC }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB), + .driver_data = MS_PRESENTER }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K), ++ .driver_data = MS_ERGONOMY }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0), + .driver_data = MS_NOGET }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), ++ .driver_data = MS_DUPLICATE_USAGES }, + + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), + .driver_data = MS_PRESENTER }, +@@ -193,6 +210,7 @@ static struct hid_driver ms_driver = { + .id_table = ms_devices, + .report_fixup = ms_report_fixup, + .input_mapping = ms_input_mapping, ++ .input_mapped = ms_input_mapped, + .event = ms_event, + .probe = ms_probe, + }; +diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c +index 62cac4d..58d0e7a 100644 +--- a/drivers/hid/hid-multitouch.c ++++ b/drivers/hid/hid-multitouch.c +@@ -727,6 +727,10 @@ static const struct hid_device_id mt_devices[] = { + { .driver_data = MT_CLS_DEFAULT, + HID_USB_DEVICE(USB_VENDOR_ID_UNITEC, + USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19) }, ++ /* XAT */ ++ { .driver_data = MT_CLS_DEFAULT, ++ HID_USB_DEVICE(USB_VENDOR_ID_XAT, ++ USB_DEVICE_ID_XAT_CSR) }, + + { } + }; +diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c +index ab19f29..158b389 100644 +--- a/drivers/hid/hid-prodikeys.c ++++ b/drivers/hid/hid-prodikeys.c +@@ -44,8 +44,6 @@ struct pk_device { + struct pcmidi_snd *pm; /* pcmidi device context */ + }; + +-struct pcmidi_snd; +- + struct pcmidi_sustain { + unsigned long in_use; + struct pcmidi_snd *pm; +@@ -242,7 +240,7 @@ drop_note: + return; + } + +-void pcmidi_sustained_note_release(unsigned long data) ++static void pcmidi_sustained_note_release(unsigned long data) + { + struct pcmidi_sustain *pms = (struct pcmidi_sustain *)data; + +@@ -250,7 +248,7 @@ void pcmidi_sustained_note_release(unsigned long data) + pms->in_use = 0; + } + +-void init_sustain_timers(struct pcmidi_snd *pm) ++static void init_sustain_timers(struct pcmidi_snd *pm) + { + struct pcmidi_sustain *pms; + unsigned i; +@@ -264,7 +262,7 @@ void init_sustain_timers(struct pcmidi_snd *pm) + } + } + +-void stop_sustain_timers(struct pcmidi_snd *pm) ++static void stop_sustain_timers(struct pcmidi_snd *pm) + { + struct pcmidi_sustain *pms; + unsigned i; +@@ -499,7 +497,7 @@ static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data) + return 1; + } + +-int pcmidi_handle_report( ++static int pcmidi_handle_report( + struct pcmidi_snd *pm, unsigned report_id, u8 *data, int size) + { + int ret = 0; +@@ -518,7 +516,8 @@ int pcmidi_handle_report( + return ret; + } + +-void pcmidi_setup_extra_keys(struct pcmidi_snd *pm, struct input_dev *input) ++static void pcmidi_setup_extra_keys( ++ struct pcmidi_snd *pm, struct input_dev *input) + { + /* reassigned functionality for N/A keys + MY PICTURES => KEY_WORDPROCESSOR +@@ -602,7 +601,7 @@ static struct snd_rawmidi_ops pcmidi_in_ops = { + .trigger = pcmidi_in_trigger + }; + +-int pcmidi_snd_initialise(struct pcmidi_snd *pm) ++static int pcmidi_snd_initialise(struct pcmidi_snd *pm) + { + static int dev; + struct snd_card *card; +@@ -720,7 +719,7 @@ fail: + return err; + } + +-int pcmidi_snd_terminate(struct pcmidi_snd *pm) ++static int pcmidi_snd_terminate(struct pcmidi_snd *pm) + { + if (pm->card) { + stop_sustain_timers(pm); +diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c +index 2307471..093bfad 100644 +--- a/drivers/hid/hid-roccat-arvo.c ++++ b/drivers/hid/hid-roccat-arvo.c +@@ -39,7 +39,7 @@ static ssize_t arvo_sysfs_show_mode_key(struct device *dev, + int retval; + + mutex_lock(&arvo->arvo_lock); +- retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_MODE_KEY, ++ retval = roccat_common_receive(usb_dev, ARVO_COMMAND_MODE_KEY, + &temp_buf, sizeof(struct arvo_mode_key)); + mutex_unlock(&arvo->arvo_lock); + if (retval) +@@ -67,7 +67,7 @@ static ssize_t arvo_sysfs_set_mode_key(struct device *dev, + temp_buf.state = state; + + mutex_lock(&arvo->arvo_lock); +- retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_MODE_KEY, ++ retval = roccat_common_send(usb_dev, ARVO_COMMAND_MODE_KEY, + &temp_buf, sizeof(struct arvo_mode_key)); + mutex_unlock(&arvo->arvo_lock); + if (retval) +@@ -87,7 +87,7 @@ static ssize_t arvo_sysfs_show_key_mask(struct device *dev, + int retval; + + mutex_lock(&arvo->arvo_lock); +- retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_KEY_MASK, ++ retval = roccat_common_receive(usb_dev, ARVO_COMMAND_KEY_MASK, + &temp_buf, sizeof(struct arvo_key_mask)); + mutex_unlock(&arvo->arvo_lock); + if (retval) +@@ -115,7 +115,7 @@ static ssize_t arvo_sysfs_set_key_mask(struct device *dev, + temp_buf.key_mask = key_mask; + + mutex_lock(&arvo->arvo_lock); +- retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_KEY_MASK, ++ retval = roccat_common_send(usb_dev, ARVO_COMMAND_KEY_MASK, + &temp_buf, sizeof(struct arvo_key_mask)); + mutex_unlock(&arvo->arvo_lock); + if (retval) +@@ -130,7 +130,7 @@ static int arvo_get_actual_profile(struct usb_device *usb_dev) + struct arvo_actual_profile temp_buf; + int retval; + +- retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE, ++ retval = roccat_common_receive(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, + &temp_buf, sizeof(struct arvo_actual_profile)); + + if (retval) +@@ -163,11 +163,14 @@ static ssize_t arvo_sysfs_set_actual_profile(struct device *dev, + if (retval) + return retval; + ++ if (profile < 1 || profile > 5) ++ return -EINVAL; ++ + temp_buf.command = ARVO_COMMAND_ACTUAL_PROFILE; + temp_buf.actual_profile = profile; + + mutex_lock(&arvo->arvo_lock); +- retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE, ++ retval = roccat_common_send(usb_dev, ARVO_COMMAND_ACTUAL_PROFILE, + &temp_buf, sizeof(struct arvo_actual_profile)); + if (!retval) { + arvo->actual_profile = profile; +@@ -225,7 +228,7 @@ static ssize_t arvo_sysfs_write_button(struct file *fp, + loff_t off, size_t count) + { + return arvo_sysfs_write(fp, kobj, buf, off, count, +- sizeof(struct arvo_button), ARVO_USB_COMMAND_BUTTON); ++ sizeof(struct arvo_button), ARVO_COMMAND_BUTTON); + } + + static ssize_t arvo_sysfs_read_info(struct file *fp, +@@ -233,7 +236,7 @@ static ssize_t arvo_sysfs_read_info(struct file *fp, + loff_t off, size_t count) + { + return arvo_sysfs_read(fp, kobj, buf, off, count, +- sizeof(struct arvo_info), ARVO_USB_COMMAND_INFO); ++ sizeof(struct arvo_info), ARVO_COMMAND_INFO); + } + + +@@ -399,7 +402,7 @@ static int arvo_raw_event(struct hid_device *hdev, + if (size != 3) + return 0; + +- if (arvo->roccat_claimed) ++ if (arvo && arvo->roccat_claimed) + arvo_report_to_chrdev(arvo, data); + + return 0; +diff --git a/drivers/hid/hid-roccat-arvo.h b/drivers/hid/hid-roccat-arvo.h +index d284a78..ce8415e 100644 +--- a/drivers/hid/hid-roccat-arvo.h ++++ b/drivers/hid/hid-roccat-arvo.h +@@ -46,19 +46,6 @@ enum arvo_commands { + ARVO_COMMAND_ACTUAL_PROFILE = 0x7, + }; + +-enum arvo_usb_commands { +- ARVO_USB_COMMAND_MODE_KEY = 0x303, +- /* +- * read/write +- * Read uses both index bytes as profile/key indexes +- * Write has index 0, profile/key is determined by payload +- */ +- ARVO_USB_COMMAND_BUTTON = 0x304, +- ARVO_USB_COMMAND_INFO = 0x305, +- ARVO_USB_COMMAND_KEY_MASK = 0x306, +- ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307, +-}; +- + struct arvo_special_report { + uint8_t unknown1; /* always 0x01 */ + uint8_t event; +diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c +index 13b1eb0..edf898d 100644 +--- a/drivers/hid/hid-roccat-common.c ++++ b/drivers/hid/hid-roccat-common.c +@@ -11,10 +11,16 @@ + * any later version. + */ + ++#include + #include + #include "hid-roccat-common.h" + +-int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, ++static inline uint16_t roccat_common_feature_report(uint8_t report_id) ++{ ++ return 0x300 | report_id; ++} ++ ++int roccat_common_receive(struct usb_device *usb_dev, uint report_id, + void *data, uint size) + { + char *buf; +@@ -25,9 +31,10 @@ int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, + return -ENOMEM; + + len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), +- USB_REQ_CLEAR_FEATURE, ++ HID_REQ_GET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, +- usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); ++ roccat_common_feature_report(report_id), ++ 0, buf, size, USB_CTRL_SET_TIMEOUT); + + memcpy(data, buf, size); + kfree(buf); +@@ -35,7 +42,7 @@ int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, + } + EXPORT_SYMBOL_GPL(roccat_common_receive); + +-int roccat_common_send(struct usb_device *usb_dev, uint usb_command, ++int roccat_common_send(struct usb_device *usb_dev, uint report_id, + void const *data, uint size) + { + char *buf; +@@ -48,9 +55,10 @@ int roccat_common_send(struct usb_device *usb_dev, uint usb_command, + memcpy(buf, data, size); + + len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), +- USB_REQ_SET_CONFIGURATION, ++ HID_REQ_SET_REPORT, + USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, +- usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); ++ roccat_common_feature_report(report_id), ++ 0, buf, size, USB_CTRL_SET_TIMEOUT); + + kfree(buf); + return ((len < 0) ? len : ((len != size) ? -EIO : 0)); +diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h +index fe45fae..9a5bc61 100644 +--- a/drivers/hid/hid-roccat-common.h ++++ b/drivers/hid/hid-roccat-common.h +@@ -15,9 +15,9 @@ + #include + #include + +-int roccat_common_receive(struct usb_device *usb_dev, uint usb_command, ++int roccat_common_receive(struct usb_device *usb_dev, uint report_id, + void *data, uint size); +-int roccat_common_send(struct usb_device *usb_dev, uint usb_command, ++int roccat_common_send(struct usb_device *usb_dev, uint report_id, + void const *data, uint size); + + #endif +diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c +index a57838d..2b8f3a3 100644 +--- a/drivers/hid/hid-roccat-kone.c ++++ b/drivers/hid/hid-roccat-kone.c +@@ -37,6 +37,47 @@ + + static uint profile_numbers[5] = {0, 1, 2, 3, 4}; + ++static int kone_receive(struct usb_device *usb_dev, uint usb_command, ++ void *data, uint size) ++{ ++ char *buf; ++ int len; ++ ++ buf = kmalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0), ++ HID_REQ_GET_REPORT, ++ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, ++ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); ++ ++ memcpy(data, buf, size); ++ kfree(buf); ++ return ((len < 0) ? len : ((len != size) ? -EIO : 0)); ++} ++ ++static int kone_send(struct usb_device *usb_dev, uint usb_command, ++ void const *data, uint size) ++{ ++ char *buf; ++ int len; ++ ++ buf = kmalloc(size, GFP_KERNEL); ++ if (buf == NULL) ++ return -ENOMEM; ++ ++ memcpy(buf, data, size); ++ ++ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0), ++ HID_REQ_SET_REPORT, ++ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, ++ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT); ++ ++ kfree(buf); ++ return ((len < 0) ? len : ((len != size) ? -EIO : 0)); ++} ++ + /* kone_class is used for creating sysfs attributes via roccat char device */ + static struct class *kone_class; + +@@ -68,7 +109,7 @@ static int kone_check_write(struct usb_device *usb_dev) + */ + msleep(80); + +- retval = roccat_common_receive(usb_dev, ++ retval = kone_receive(usb_dev, + kone_command_confirm_write, &data, 1); + if (retval) + return retval; +@@ -96,7 +137,7 @@ static int kone_check_write(struct usb_device *usb_dev) + static int kone_get_settings(struct usb_device *usb_dev, + struct kone_settings *buf) + { +- return roccat_common_receive(usb_dev, kone_command_settings, buf, ++ return kone_receive(usb_dev, kone_command_settings, buf, + sizeof(struct kone_settings)); + } + +@@ -109,7 +150,7 @@ static int kone_set_settings(struct usb_device *usb_dev, + struct kone_settings const *settings) + { + int retval; +- retval = roccat_common_send(usb_dev, kone_command_settings, ++ retval = kone_send(usb_dev, kone_command_settings, + settings, sizeof(struct kone_settings)); + if (retval) + return retval; +@@ -182,7 +223,7 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result) + int retval; + uint8_t data; + +- retval = roccat_common_receive(usb_dev, kone_command_weight, &data, 1); ++ retval = kone_receive(usb_dev, kone_command_weight, &data, 1); + + if (retval) + return retval; +@@ -201,7 +242,7 @@ static int kone_get_firmware_version(struct usb_device *usb_dev, int *result) + int retval; + uint16_t data; + +- retval = roccat_common_receive(usb_dev, kone_command_firmware_version, ++ retval = kone_receive(usb_dev, kone_command_firmware_version, + &data, 2); + if (retval) + return retval; +@@ -384,7 +425,7 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number) + { + unsigned char value; + value = number; +- return roccat_common_send(usb_dev, kone_command_calibrate, &value, 1); ++ return kone_send(usb_dev, kone_command_calibrate, &value, 1); + } + + /* +@@ -791,6 +832,9 @@ static int kone_raw_event(struct hid_device *hdev, struct hid_report *report, + if (size != sizeof(struct kone_mouse_event)) + return 0; + ++ if (kone == NULL) ++ return 0; ++ + /* + * Firmware 1.38 introduced new behaviour for tilt and special buttons. + * Pressed button is reported in each movement event. +diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h +index 4109a02..64abb5b 100644 +--- a/drivers/hid/hid-roccat-kone.h ++++ b/drivers/hid/hid-roccat-kone.h +@@ -166,7 +166,7 @@ enum kone_mouse_events { + /* osd events are thought to be display on screen */ + kone_mouse_event_osd_dpi = 0xa0, + kone_mouse_event_osd_profile = 0xb0, +- /* TODO clarify meaning and occurrence of kone_mouse_event_calibration */ ++ /* TODO clarify meaning and occurence of kone_mouse_event_calibration */ + kone_mouse_event_calibration = 0xc0, + kone_mouse_event_call_overlong_macro = 0xe0, + /* switch events notify if user changed values with mousebutton click */ +diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c +index 5b640a7..59e4777 100644 +--- a/drivers/hid/hid-roccat-koneplus.c ++++ b/drivers/hid/hid-roccat-koneplus.c +@@ -50,7 +50,7 @@ static int koneplus_send_control(struct usb_device *usb_dev, uint value, + control.value = value; + control.request = request; + +- return roccat_common_send(usb_dev, KONEPLUS_USB_COMMAND_CONTROL, ++ return roccat_common_send(usb_dev, KONEPLUS_COMMAND_CONTROL, + &control, sizeof(struct koneplus_control)); + } + +@@ -60,7 +60,7 @@ static int koneplus_receive_control_status(struct usb_device *usb_dev) + struct koneplus_control control; + + do { +- retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL, ++ retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_CONTROL, + &control, sizeof(struct koneplus_control)); + + /* check if we get a completely wrong answer */ +@@ -120,7 +120,7 @@ static int koneplus_select_profile(struct usb_device *usb_dev, uint number, + static int koneplus_get_info(struct usb_device *usb_dev, + struct koneplus_info *buf) + { +- return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO, ++ return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_INFO, + buf, sizeof(struct koneplus_info)); + } + +@@ -134,14 +134,14 @@ static int koneplus_get_profile_settings(struct usb_device *usb_dev, + if (retval) + return retval; + +- return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS, ++ return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, + buf, sizeof(struct koneplus_profile_settings)); + } + + static int koneplus_set_profile_settings(struct usb_device *usb_dev, + struct koneplus_profile_settings const *settings) + { +- return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS, ++ return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_SETTINGS, + settings, sizeof(struct koneplus_profile_settings)); + } + +@@ -155,14 +155,14 @@ static int koneplus_get_profile_buttons(struct usb_device *usb_dev, + if (retval) + return retval; + +- return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS, ++ return roccat_common_receive(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, + buf, sizeof(struct koneplus_profile_buttons)); + } + + static int koneplus_set_profile_buttons(struct usb_device *usb_dev, + struct koneplus_profile_buttons const *buttons) + { +- return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS, ++ return koneplus_send(usb_dev, KONEPLUS_COMMAND_PROFILE_BUTTONS, + buttons, sizeof(struct koneplus_profile_buttons)); + } + +@@ -172,7 +172,7 @@ static int koneplus_get_actual_profile(struct usb_device *usb_dev) + struct koneplus_actual_profile buf; + int retval; + +- retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE, ++ retval = roccat_common_receive(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct koneplus_actual_profile)); + + return retval ? retval : buf.actual_profile; +@@ -187,7 +187,7 @@ static int koneplus_set_actual_profile(struct usb_device *usb_dev, + buf.size = sizeof(struct koneplus_actual_profile); + buf.actual_profile = new_profile; + +- return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_ACTUAL_PROFILE, ++ return koneplus_send(usb_dev, KONEPLUS_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct koneplus_actual_profile)); + } + +@@ -240,12 +240,20 @@ static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj, + return real_size; + } + ++static ssize_t koneplus_sysfs_write_talk(struct file *fp, ++ struct kobject *kobj, struct bin_attribute *attr, char *buf, ++ loff_t off, size_t count) ++{ ++ return koneplus_sysfs_write(fp, kobj, buf, off, count, ++ sizeof(struct koneplus_talk), KONEPLUS_COMMAND_TALK); ++} ++ + static ssize_t koneplus_sysfs_write_macro(struct file *fp, + struct kobject *kobj, struct bin_attribute *attr, char *buf, + loff_t off, size_t count) + { + return koneplus_sysfs_write(fp, kobj, buf, off, count, +- sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO); ++ sizeof(struct koneplus_macro), KONEPLUS_COMMAND_MACRO); + } + + static ssize_t koneplus_sysfs_read_sensor(struct file *fp, +@@ -253,7 +261,7 @@ static ssize_t koneplus_sysfs_read_sensor(struct file *fp, + loff_t off, size_t count) + { + return koneplus_sysfs_read(fp, kobj, buf, off, count, +- sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR); ++ sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR); + } + + static ssize_t koneplus_sysfs_write_sensor(struct file *fp, +@@ -261,7 +269,7 @@ static ssize_t koneplus_sysfs_write_sensor(struct file *fp, + loff_t off, size_t count) + { + return koneplus_sysfs_write(fp, kobj, buf, off, count, +- sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR); ++ sizeof(struct koneplus_sensor), KONEPLUS_COMMAND_SENSOR); + } + + static ssize_t koneplus_sysfs_write_tcu(struct file *fp, +@@ -269,7 +277,7 @@ static ssize_t koneplus_sysfs_write_tcu(struct file *fp, + loff_t off, size_t count) + { + return koneplus_sysfs_write(fp, kobj, buf, off, count, +- sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU); ++ sizeof(struct koneplus_tcu), KONEPLUS_COMMAND_TCU); + } + + static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp, +@@ -277,7 +285,7 @@ static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp, + loff_t off, size_t count) + { + return koneplus_sysfs_read(fp, kobj, buf, off, count, +- sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU); ++ sizeof(struct koneplus_tcu_image), KONEPLUS_COMMAND_TCU); + } + + static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp, +@@ -423,6 +431,9 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, + if (retval) + return retval; + ++ if (profile > 4) ++ return -EINVAL; ++ + mutex_lock(&koneplus->koneplus_lock); + + retval = koneplus_set_actual_profile(usb_dev, profile); +@@ -431,7 +442,7 @@ static ssize_t koneplus_sysfs_set_actual_profile(struct device *dev, + return retval; + } + +- koneplus->actual_profile = profile; ++ koneplus_profile_activated(koneplus, profile); + + roccat_report.type = KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE; + roccat_report.data1 = profile + 1; +@@ -557,6 +568,11 @@ static struct bin_attribute koneplus_bin_attributes[] = { + .size = sizeof(struct koneplus_macro), + .write = koneplus_sysfs_write_macro + }, ++ { ++ .attr = { .name = "talk", .mode = 0220 }, ++ .size = sizeof(struct koneplus_talk), ++ .write = koneplus_sysfs_write_talk ++ }, + __ATTR_NULL + }; + +@@ -738,6 +754,9 @@ static int koneplus_raw_event(struct hid_device *hdev, + != USB_INTERFACE_PROTOCOL_MOUSE) + return 0; + ++ if (koneplus == NULL) ++ return 0; ++ + koneplus_keep_values_up_to_date(koneplus, data); + + if (koneplus->roccat_claimed) +diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h +index c57a376..c03332a 100644 +--- a/drivers/hid/hid-roccat-koneplus.h ++++ b/drivers/hid/hid-roccat-koneplus.h +@@ -14,6 +14,12 @@ + + #include + ++struct koneplus_talk { ++ uint8_t command; /* KONEPLUS_COMMAND_TALK */ ++ uint8_t size; /* always 0x10 */ ++ uint8_t data[14]; ++} __packed; ++ + /* + * case 1: writes request 80 and reads value 1 + * +@@ -137,26 +143,14 @@ enum koneplus_commands { + KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7, + KONEPLUS_COMMAND_MACRO = 0x8, + KONEPLUS_COMMAND_INFO = 0x9, ++ KONEPLUS_COMMAND_TCU = 0xc, + KONEPLUS_COMMAND_E = 0xe, + KONEPLUS_COMMAND_SENSOR = 0xf, ++ KONEPLUS_COMMAND_TALK = 0x10, + KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b, + KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c, + }; + +-enum koneplus_usb_commands { +- KONEPLUS_USB_COMMAND_CONTROL = 0x304, +- KONEPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305, +- KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306, +- KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307, +- KONEPLUS_USB_COMMAND_MACRO = 0x308, +- KONEPLUS_USB_COMMAND_INFO = 0x309, +- KONEPLUS_USB_COMMAND_TCU = 0x30c, +- KONEPLUS_USB_COMMAND_E = 0x30e, +- KONEPLUS_USB_COMMAND_SENSOR = 0x30f, +- KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b, +- KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c, +-}; +- + enum koneplus_mouse_report_numbers { + KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1, + KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2, +@@ -193,6 +187,7 @@ enum koneplus_mouse_report_button_types { + * data2 = action + */ + KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0, ++ KONEPLUS_MOUSE_REPORT_TALK = 0xff, + }; + + enum koneplus_mouse_report_button_action { +diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c +index 984be2f..1f8336e 100644 +--- a/drivers/hid/hid-roccat-kovaplus.c ++++ b/drivers/hid/hid-roccat-kovaplus.c +@@ -58,7 +58,7 @@ static int kovaplus_send_control(struct usb_device *usb_dev, uint value, + control.value = value; + control.request = request; + +- retval = roccat_common_send(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL, ++ retval = roccat_common_send(usb_dev, KOVAPLUS_COMMAND_CONTROL, + &control, sizeof(struct kovaplus_control)); + + return retval; +@@ -70,7 +70,7 @@ static int kovaplus_receive_control_status(struct usb_device *usb_dev) + struct kovaplus_control control; + + do { +- retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL, ++ retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_CONTROL, + &control, sizeof(struct kovaplus_control)); + + /* check if we get a completely wrong answer */ +@@ -90,7 +90,7 @@ static int kovaplus_receive_control_status(struct usb_device *usb_dev) + if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD) + return -EINVAL; + +- hid_err(usb_dev, "kovaplus_receive_control_status: " ++ hid_err(usb_dev, "roccat_common_receive_control_status: " + "unknown response value 0x%x\n", control.value); + return -EINVAL; + } while (1); +@@ -119,7 +119,7 @@ static int kovaplus_select_profile(struct usb_device *usb_dev, uint number, + static int kovaplus_get_info(struct usb_device *usb_dev, + struct kovaplus_info *buf) + { +- return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_INFO, ++ return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_INFO, + buf, sizeof(struct kovaplus_info)); + } + +@@ -133,14 +133,14 @@ static int kovaplus_get_profile_settings(struct usb_device *usb_dev, + if (retval) + return retval; + +- return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS, ++ return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, + buf, sizeof(struct kovaplus_profile_settings)); + } + + static int kovaplus_set_profile_settings(struct usb_device *usb_dev, + struct kovaplus_profile_settings const *settings) + { +- return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS, ++ return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_SETTINGS, + settings, sizeof(struct kovaplus_profile_settings)); + } + +@@ -154,14 +154,14 @@ static int kovaplus_get_profile_buttons(struct usb_device *usb_dev, + if (retval) + return retval; + +- return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS, ++ return roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, + buf, sizeof(struct kovaplus_profile_buttons)); + } + + static int kovaplus_set_profile_buttons(struct usb_device *usb_dev, + struct kovaplus_profile_buttons const *buttons) + { +- return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS, ++ return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_PROFILE_BUTTONS, + buttons, sizeof(struct kovaplus_profile_buttons)); + } + +@@ -171,7 +171,7 @@ static int kovaplus_get_actual_profile(struct usb_device *usb_dev) + struct kovaplus_actual_profile buf; + int retval; + +- retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE, ++ retval = roccat_common_receive(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct kovaplus_actual_profile)); + + return retval ? retval : buf.actual_profile; +@@ -186,7 +186,7 @@ static int kovaplus_set_actual_profile(struct usb_device *usb_dev, + buf.size = sizeof(struct kovaplus_actual_profile); + buf.actual_profile = new_profile; + +- return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE, ++ return kovaplus_send(usb_dev, KOVAPLUS_COMMAND_ACTUAL_PROFILE, + &buf, sizeof(struct kovaplus_actual_profile)); + } + +@@ -337,7 +337,7 @@ static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev, + + mutex_lock(&kovaplus->kovaplus_lock); + retval = kovaplus_set_actual_profile(usb_dev, profile); +- kovaplus->actual_profile = profile; ++ kovaplus_profile_activated(kovaplus, profile); + mutex_unlock(&kovaplus->kovaplus_lock); + if (retval) + return retval; +@@ -662,6 +662,9 @@ static int kovaplus_raw_event(struct hid_device *hdev, + != USB_INTERFACE_PROTOCOL_MOUSE) + return 0; + ++ if (kovaplus == NULL) ++ return 0; ++ + kovaplus_keep_values_up_to_date(kovaplus, data); + + if (kovaplus->roccat_claimed) +diff --git a/drivers/hid/hid-roccat-kovaplus.h b/drivers/hid/hid-roccat-kovaplus.h +index ce40607..fb2aed4 100644 +--- a/drivers/hid/hid-roccat-kovaplus.h ++++ b/drivers/hid/hid-roccat-kovaplus.h +@@ -83,15 +83,6 @@ enum kovaplus_commands { + KOVAPLUS_COMMAND_A = 0xa, + }; + +-enum kovaplus_usb_commands { +- KOVAPLUS_USB_COMMAND_CONTROL = 0x304, +- KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305, +- KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306, +- KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307, +- KOVAPLUS_USB_COMMAND_INFO = 0x309, +- KOVAPLUS_USB_COMMAND_A = 0x30a, +-}; +- + enum kovaplus_mouse_report_numbers { + KOVAPLUS_MOUSE_REPORT_NUMBER_MOUSE = 1, + KOVAPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2, +diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c +index 38280c0..8140776b 100644 +--- a/drivers/hid/hid-roccat-pyra.c ++++ b/drivers/hid/hid-roccat-pyra.c +@@ -53,7 +53,7 @@ static int pyra_send_control(struct usb_device *usb_dev, int value, + control.value = value; + control.request = request; + +- return roccat_common_send(usb_dev, PYRA_USB_COMMAND_CONTROL, ++ return roccat_common_send(usb_dev, PYRA_COMMAND_CONTROL, + &control, sizeof(struct pyra_control)); + } + +@@ -64,7 +64,7 @@ static int pyra_receive_control_status(struct usb_device *usb_dev) + + do { + msleep(10); +- retval = roccat_common_receive(usb_dev, PYRA_USB_COMMAND_CONTROL, ++ retval = roccat_common_receive(usb_dev, PYRA_COMMAND_CONTROL, + &control, sizeof(struct pyra_control)); + + /* requested too early, try again */ +@@ -89,7 +89,7 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev, + PYRA_CONTROL_REQUEST_PROFILE_SETTINGS); + if (retval) + return retval; +- return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, ++ return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, + buf, sizeof(struct pyra_profile_settings)); + } + +@@ -101,20 +101,20 @@ static int pyra_get_profile_buttons(struct usb_device *usb_dev, + PYRA_CONTROL_REQUEST_PROFILE_BUTTONS); + if (retval) + return retval; +- return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, ++ return roccat_common_receive(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, + buf, sizeof(struct pyra_profile_buttons)); + } + + static int pyra_get_settings(struct usb_device *usb_dev, + struct pyra_settings *buf) + { +- return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_SETTINGS, ++ return roccat_common_receive(usb_dev, PYRA_COMMAND_SETTINGS, + buf, sizeof(struct pyra_settings)); + } + + static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf) + { +- return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_INFO, ++ return roccat_common_receive(usb_dev, PYRA_COMMAND_INFO, + buf, sizeof(struct pyra_info)); + } + +@@ -131,26 +131,22 @@ static int pyra_send(struct usb_device *usb_dev, uint command, + static int pyra_set_profile_settings(struct usb_device *usb_dev, + struct pyra_profile_settings const *settings) + { +- return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, settings, ++ return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_SETTINGS, settings, + sizeof(struct pyra_profile_settings)); + } + + static int pyra_set_profile_buttons(struct usb_device *usb_dev, + struct pyra_profile_buttons const *buttons) + { +- return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, buttons, ++ return pyra_send(usb_dev, PYRA_COMMAND_PROFILE_BUTTONS, buttons, + sizeof(struct pyra_profile_buttons)); + } + + static int pyra_set_settings(struct usb_device *usb_dev, + struct pyra_settings const *settings) + { +- int retval; +- retval = roccat_common_send(usb_dev, PYRA_USB_COMMAND_SETTINGS, settings, ++ return pyra_send(usb_dev, PYRA_COMMAND_SETTINGS, settings, + sizeof(struct pyra_settings)); +- if (retval) +- return retval; +- return pyra_receive_control_status(usb_dev); + } + + static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp, +@@ -641,6 +637,9 @@ static int pyra_raw_event(struct hid_device *hdev, struct hid_report *report, + != USB_INTERFACE_PROTOCOL_MOUSE) + return 0; + ++ if (pyra == NULL) ++ return 0; ++ + pyra_keep_values_up_to_date(pyra, data); + + if (pyra->roccat_claimed) +diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h +index 14cbbe1..0442d7f 100644 +--- a/drivers/hid/hid-roccat-pyra.h ++++ b/drivers/hid/hid-roccat-pyra.h +@@ -83,15 +83,6 @@ enum pyra_commands { + PYRA_COMMAND_B = 0xb + }; + +-enum pyra_usb_commands { +- PYRA_USB_COMMAND_CONTROL = 0x304, +- PYRA_USB_COMMAND_SETTINGS = 0x305, +- PYRA_USB_COMMAND_PROFILE_SETTINGS = 0x306, +- PYRA_USB_COMMAND_PROFILE_BUTTONS = 0x307, +- PYRA_USB_COMMAND_INFO = 0x309, +- PYRA_USB_COMMAND_B = 0x30b /* writes 3 bytes */ +-}; +- + enum pyra_mouse_report_numbers { + PYRA_MOUSE_REPORT_NUMBER_HID = 1, + PYRA_MOUSE_REPORT_NUMBER_AUDIO = 2, +diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c +index 936c911..5cd25bd 100644 +--- a/drivers/hid/hid-sony.c ++++ b/drivers/hid/hid-sony.c +@@ -28,6 +28,12 @@ + #define SIXAXIS_CONTROLLER_USB (1 << 1) + #define SIXAXIS_CONTROLLER_BT (1 << 2) + ++static const u8 sixaxis_rdesc_fixup[] = { ++ 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C, ++ 0x81, 0x01, 0x75, 0x10, 0x95, 0x04, 0x26, 0xFF, ++ 0x03, 0x46, 0xFF, 0x03, 0x09, 0x01, 0x81, 0x02 ++}; ++ + struct sony_sc { + unsigned long quirks; + }; +@@ -43,9 +49,37 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, + hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n"); + rdesc[55] = 0x06; + } ++ ++ /* The HID descriptor exposed over BT has a trailing zero byte */ ++ if ((((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize == 148) || ++ ((sc->quirks & SIXAXIS_CONTROLLER_BT) && *rsize == 149)) && ++ rdesc[83] == 0x75) { ++ hid_info(hdev, "Fixing up Sony Sixaxis report descriptor\n"); ++ memcpy((void *)&rdesc[83], (void *)&sixaxis_rdesc_fixup, ++ sizeof(sixaxis_rdesc_fixup)); ++ } + return rdesc; + } + ++static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, ++ __u8 *rd, int size) ++{ ++ struct sony_sc *sc = hid_get_drvdata(hdev); ++ ++ /* Sixaxis HID report has acclerometers/gyro with MSByte first, this ++ * has to be BYTE_SWAPPED before passing up to joystick interface ++ */ ++ if ((sc->quirks & (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT)) && ++ rd[0] == 0x01 && size == 49) { ++ swap(rd[41], rd[42]); ++ swap(rd[43], rd[44]); ++ swap(rd[45], rd[46]); ++ swap(rd[47], rd[48]); ++ } ++ ++ return 0; ++} ++ + /* + * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP + * like it should according to usbhid/hid-core.c::usbhid_output_raw_report() +@@ -194,6 +228,7 @@ static struct hid_driver sony_driver = { + .probe = sony_probe, + .remove = sony_remove, + .report_fixup = sony_report_fixup, ++ .raw_event = sony_raw_event + }; + + static int __init sony_init(void) +diff --git a/drivers/hid/hid-speedlink.c b/drivers/hid/hid-speedlink.c +new file mode 100644 +index 0000000..6020137 +--- /dev/null ++++ b/drivers/hid/hid-speedlink.c +@@ -0,0 +1,89 @@ ++/* ++ * HID driver for Speedlink Vicious and Divine Cezanne (USB mouse). ++ * Fixes "jumpy" cursor and removes nonexistent keyboard LEDS from ++ * the HID descriptor. ++ * ++ * Copyright (c) 2011 Stefan Kriwanek ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++ ++#include "hid-ids.h" ++#include "usbhid/usbhid.h" ++ ++static const struct hid_device_id speedlink_devices[] = { ++ { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE)}, ++ { } ++}; ++ ++static int speedlink_input_mapping(struct hid_device *hdev, ++ struct hid_input *hi, ++ struct hid_field *field, struct hid_usage *usage, ++ unsigned long **bit, int *max) ++{ ++ /* ++ * The Cezanne mouse has a second "keyboard" USB endpoint for it is ++ * able to map keyboard events to the button presses. ++ * It sends a standard keyboard report descriptor, though, whose ++ * LEDs we ignore. ++ */ ++ switch (usage->hid & HID_USAGE_PAGE) { ++ case HID_UP_LED: ++ return -1; ++ } ++ return 0; ++} ++ ++static int speedlink_event(struct hid_device *hdev, struct hid_field *field, ++ struct hid_usage *usage, __s32 value) ++{ ++ /* No other conditions due to usage_table. */ ++ /* Fix "jumpy" cursor (invalid events sent by device). */ ++ if (value == 256) ++ return 1; ++ /* Drop useless distance 0 events (on button clicks etc.) as well */ ++ if (value == 0) ++ return 1; ++ ++ return 0; ++} ++ ++MODULE_DEVICE_TABLE(hid, speedlink_devices); ++ ++static const struct hid_usage_id speedlink_grabbed_usages[] = { ++ { HID_GD_X, EV_REL, 0 }, ++ { HID_GD_Y, EV_REL, 1 }, ++ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1} ++}; ++ ++static struct hid_driver speedlink_driver = { ++ .name = "speedlink", ++ .id_table = speedlink_devices, ++ .usage_table = speedlink_grabbed_usages, ++ .input_mapping = speedlink_input_mapping, ++ .event = speedlink_event, ++}; ++ ++static int __init speedlink_init(void) ++{ ++ return hid_register_driver(&speedlink_driver); ++} ++ ++static void __exit speedlink_exit(void) ++{ ++ hid_unregister_driver(&speedlink_driver); ++} ++ ++module_init(speedlink_init); ++module_exit(speedlink_exit); ++MODULE_LICENSE("GPL"); +diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c +index 05fdc85a..e15732f 100644 +--- a/drivers/hid/hid-uclogic.c ++++ b/drivers/hid/hid-uclogic.c +@@ -343,6 +343,193 @@ static __u8 wp8060u_rdesc_fixed[] = { + }; + + /* ++ * Original WP1062 report descriptor. ++ * ++ * Only report ID 9 is actually used. ++ * ++ * Usage Page (Digitizer), ; Digitizer (0Dh) ++ * Usage (Pen), ; Pen (02h, application collection) ++ * Collection (Application), ++ * Report ID (7), ++ * Usage (Stylus), ; Stylus (20h, logical collection) ++ * Collection (Physical), ++ * Usage (Tip Switch), ; Tip switch (42h, momentary control) ++ * Usage (Barrel Switch), ; Barrel switch (44h, momentary control) ++ * Usage (Eraser), ; Eraser (45h, momentary control) ++ * Logical Minimum (0), ++ * Logical Maximum (1), ++ * Report Size (1), ++ * Report Count (3), ++ * Input (Variable), ++ * Report Count (3), ++ * Input (Constant, Variable), ++ * Usage (In Range), ; In range (32h, momentary control) ++ * Report Count (1), ++ * Input (Variable), ++ * Report Count (1), ++ * Input (Constant, Variable), ++ * Usage Page (Desktop), ; Generic desktop controls (01h) ++ * Usage (X), ; X (30h, dynamic value) ++ * Report Size (16), ++ * Report Count (1), ++ * Push, ++ * Unit Exponent (13), ++ * Unit (Inch), ++ * Physical Minimum (0), ++ * Physical Maximum (10000), ++ * Logical Maximum (20000), ++ * Input (Variable), ++ * Usage (Y), ; Y (31h, dynamic value) ++ * Physical Maximum (6583), ++ * Logical Maximum (13166), ++ * Input (Variable), ++ * Pop, ++ * Usage Page (Digitizer), ; Digitizer (0Dh) ++ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) ++ * Logical Maximum (1023), ++ * Input (Variable), ++ * Report Size (16), ++ * End Collection, ++ * End Collection, ++ * Usage Page (Desktop), ; Generic desktop controls (01h) ++ * Usage (Mouse), ; Mouse (02h, application collection) ++ * Collection (Application), ++ * Report ID (8), ++ * Usage (Pointer), ; Pointer (01h, physical collection) ++ * Collection (Physical), ++ * Usage Page (Button), ; Button (09h) ++ * Usage Minimum (01h), ++ * Usage Maximum (03h), ++ * Logical Minimum (0), ++ * Logical Maximum (1), ++ * Report Count (3), ++ * Report Size (1), ++ * Input (Variable), ++ * Report Count (5), ++ * Input (Constant), ++ * Usage Page (Desktop), ; Generic desktop controls (01h) ++ * Usage (X), ; X (30h, dynamic value) ++ * Usage (Y), ; Y (31h, dynamic value) ++ * Usage (Wheel), ; Wheel (38h, dynamic value) ++ * Usage (00h), ++ * Logical Minimum (-127), ++ * Logical Maximum (127), ++ * Report Size (8), ++ * Report Count (4), ++ * Input (Variable, Relative), ++ * End Collection, ++ * End Collection, ++ * Usage Page (Desktop), ; Generic desktop controls (01h) ++ * Usage (Mouse), ; Mouse (02h, application collection) ++ * Collection (Application), ++ * Report ID (9), ++ * Usage (Pointer), ; Pointer (01h, physical collection) ++ * Collection (Physical), ++ * Usage Page (Button), ; Button (09h) ++ * Usage Minimum (01h), ++ * Usage Maximum (03h), ++ * Logical Minimum (0), ++ * Logical Maximum (1), ++ * Report Count (3), ++ * Report Size (1), ++ * Input (Variable), ++ * Report Count (4), ++ * Input (Constant), ++ * Usage Page (Digitizer), ; Digitizer (0Dh) ++ * Usage (In Range), ; In range (32h, momentary control) ++ * Report Count (1), ++ * Input (Variable), ++ * Usage Page (Desktop), ; Generic desktop controls (01h) ++ * Usage (X), ; X (30h, dynamic value) ++ * Report Size (16), ++ * Report Count (1), ++ * Push, ++ * Unit Exponent (13), ++ * Unit (Inch), ++ * Physical Minimum (0), ++ * Physical Maximum (10000), ++ * Logical Maximum (20000), ++ * Input (Variable), ++ * Usage (Y), ; Y (31h, dynamic value) ++ * Physical Maximum (6583), ++ * Logical Maximum (13166), ++ * Input (Variable), ++ * Pop, ++ * Usage Page (Digitizer), ; Digitizer (0Dh) ++ * Usage (Tip Pressure), ; Tip pressure (30h, dynamic value) ++ * Logical Maximum (1023), ++ * Report Count (1), ++ * Report Size (16), ++ * Input (Variable), ++ * End Collection, ++ * End Collection, ++ * Usage Page (Desktop), ; Generic desktop controls (01h) ++ * Usage (00h), ++ * Collection (Application), ++ * Report ID (4), ++ * Logical Minimum (0), ++ * Logical Maximum (255), ++ * Usage (00h), ++ * Report Size (8), ++ * Report Count (3), ++ * Feature (Variable), ++ * End Collection ++ */ ++ ++/* Size of the original descriptor of WP1062 tablet */ ++#define WP1062_RDESC_ORIG_SIZE 254 ++ ++/* ++ * Fixed WP1062 report descriptor. ++ * ++ * Removed unused reports, corrected second barrel button usage code, physical ++ * units. ++ */ ++static __u8 wp1062_rdesc_fixed[] = { ++ 0x05, 0x0D, /* Usage Page (Digitizer), */ ++ 0x09, 0x02, /* Usage (Pen), */ ++ 0xA1, 0x01, /* Collection (Application), */ ++ 0x85, 0x09, /* Report ID (9), */ ++ 0x09, 0x20, /* Usage (Stylus), */ ++ 0xA0, /* Collection (Physical), */ ++ 0x75, 0x01, /* Report Size (1), */ ++ 0x09, 0x42, /* Usage (Tip Switch), */ ++ 0x09, 0x44, /* Usage (Barrel Switch), */ ++ 0x09, 0x46, /* Usage (Tablet Pick), */ ++ 0x14, /* Logical Minimum (0), */ ++ 0x25, 0x01, /* Logical Maximum (1), */ ++ 0x95, 0x03, /* Report Count (3), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x95, 0x04, /* Report Count (4), */ ++ 0x81, 0x01, /* Input (Constant), */ ++ 0x09, 0x32, /* Usage (In Range), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x75, 0x10, /* Report Size (16), */ ++ 0x95, 0x01, /* Report Count (1), */ ++ 0x14, /* Logical Minimum (0), */ ++ 0xA4, /* Push, */ ++ 0x05, 0x01, /* Usage Page (Desktop), */ ++ 0x55, 0xFD, /* Unit Exponent (-3), */ ++ 0x65, 0x13, /* Unit (Inch), */ ++ 0x34, /* Physical Minimum (0), */ ++ 0x09, 0x30, /* Usage (X), */ ++ 0x46, 0x10, 0x27, /* Physical Maximum (10000), */ ++ 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0x09, 0x31, /* Usage (Y), */ ++ 0x46, 0xB7, 0x19, /* Physical Maximum (6583), */ ++ 0x26, 0x6E, 0x33, /* Logical Maximum (13166), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xB4, /* Pop, */ ++ 0x09, 0x30, /* Usage (Tip Pressure), */ ++ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ ++ 0x81, 0x02, /* Input (Variable), */ ++ 0xC0, /* End Collection, */ ++ 0xC0 /* End Collection */ ++}; ++ ++/* + * Original PF1209 report descriptor. + * + * The descriptor is similar to WPXXXXU descriptors, with an addition of a +@@ -584,6 +771,12 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc, + *rsize = sizeof(wp8060u_rdesc_fixed); + } + break; ++ case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062: ++ if (*rsize == WP1062_RDESC_ORIG_SIZE) { ++ rdesc = wp1062_rdesc_fixed; ++ *rsize = sizeof(wp1062_rdesc_fixed); ++ } ++ break; + } + + return rdesc; +@@ -598,6 +791,8 @@ static const struct hid_device_id uclogic_devices[] = { + USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, + { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, + USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, ++ { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, ++ USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, + { } + }; + MODULE_DEVICE_TABLE(hid, uclogic_devices); +diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c +new file mode 100644 +index 0000000..a594383 +--- /dev/null ++++ b/drivers/hid/hid-wiimote.c +@@ -0,0 +1,489 @@ ++/* ++ * HID driver for Nintendo Wiimote devices ++ * Copyright (c) 2011 David Herrmann ++ */ ++ ++/* ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the Free ++ * Software Foundation; either version 2 of the License, or (at your option) ++ * any later version. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include "hid-ids.h" ++ ++#define WIIMOTE_VERSION "0.1" ++#define WIIMOTE_NAME "Nintendo Wii Remote" ++#define WIIMOTE_BUFSIZE 32 ++ ++struct wiimote_buf { ++ __u8 data[HID_MAX_BUFFER_SIZE]; ++ size_t size; ++}; ++ ++struct wiimote_state { ++ spinlock_t lock; ++ __u8 flags; ++}; ++ ++struct wiimote_data { ++ atomic_t ready; ++ struct hid_device *hdev; ++ struct input_dev *input; ++ ++ spinlock_t qlock; ++ __u8 head; ++ __u8 tail; ++ struct wiimote_buf outq[WIIMOTE_BUFSIZE]; ++ struct work_struct worker; ++ ++ struct wiimote_state state; ++}; ++ ++#define WIIPROTO_FLAG_LED1 0x01 ++#define WIIPROTO_FLAG_LED2 0x02 ++#define WIIPROTO_FLAG_LED3 0x04 ++#define WIIPROTO_FLAG_LED4 0x08 ++#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ ++ WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) ++ ++enum wiiproto_reqs { ++ WIIPROTO_REQ_LED = 0x11, ++ WIIPROTO_REQ_DRM_K = 0x30, ++}; ++ ++enum wiiproto_keys { ++ WIIPROTO_KEY_LEFT, ++ WIIPROTO_KEY_RIGHT, ++ WIIPROTO_KEY_UP, ++ WIIPROTO_KEY_DOWN, ++ WIIPROTO_KEY_PLUS, ++ WIIPROTO_KEY_MINUS, ++ WIIPROTO_KEY_ONE, ++ WIIPROTO_KEY_TWO, ++ WIIPROTO_KEY_A, ++ WIIPROTO_KEY_B, ++ WIIPROTO_KEY_HOME, ++ WIIPROTO_KEY_COUNT ++}; ++ ++static __u16 wiiproto_keymap[] = { ++ KEY_LEFT, /* WIIPROTO_KEY_LEFT */ ++ KEY_RIGHT, /* WIIPROTO_KEY_RIGHT */ ++ KEY_UP, /* WIIPROTO_KEY_UP */ ++ KEY_DOWN, /* WIIPROTO_KEY_DOWN */ ++ KEY_NEXT, /* WIIPROTO_KEY_PLUS */ ++ KEY_PREVIOUS, /* WIIPROTO_KEY_MINUS */ ++ BTN_1, /* WIIPROTO_KEY_ONE */ ++ BTN_2, /* WIIPROTO_KEY_TWO */ ++ BTN_A, /* WIIPROTO_KEY_A */ ++ BTN_B, /* WIIPROTO_KEY_B */ ++ BTN_MODE, /* WIIPROTO_KEY_HOME */ ++}; ++ ++#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \ ++ dev)) ++ ++static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, ++ size_t count) ++{ ++ __u8 *buf; ++ ssize_t ret; ++ ++ if (!hdev->hid_output_raw_report) ++ return -ENODEV; ++ ++ buf = kmemdup(buffer, count, GFP_KERNEL); ++ if (!buf) ++ return -ENOMEM; ++ ++ ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT); ++ ++ kfree(buf); ++ return ret; ++} ++ ++static void wiimote_worker(struct work_struct *work) ++{ ++ struct wiimote_data *wdata = container_of(work, struct wiimote_data, ++ worker); ++ unsigned long flags; ++ ++ spin_lock_irqsave(&wdata->qlock, flags); ++ ++ while (wdata->head != wdata->tail) { ++ spin_unlock_irqrestore(&wdata->qlock, flags); ++ wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data, ++ wdata->outq[wdata->tail].size); ++ spin_lock_irqsave(&wdata->qlock, flags); ++ ++ wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE; ++ } ++ ++ spin_unlock_irqrestore(&wdata->qlock, flags); ++} ++ ++static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer, ++ size_t count) ++{ ++ unsigned long flags; ++ __u8 newhead; ++ ++ if (count > HID_MAX_BUFFER_SIZE) { ++ hid_warn(wdata->hdev, "Sending too large output report\n"); ++ return; ++ } ++ ++ /* ++ * Copy new request into our output queue and check whether the ++ * queue is full. If it is full, discard this request. ++ * If it is empty we need to start a new worker that will ++ * send out the buffer to the hid device. ++ * If the queue is not empty, then there must be a worker ++ * that is currently sending out our buffer and this worker ++ * will reschedule itself until the queue is empty. ++ */ ++ ++ spin_lock_irqsave(&wdata->qlock, flags); ++ ++ memcpy(wdata->outq[wdata->head].data, buffer, count); ++ wdata->outq[wdata->head].size = count; ++ newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE; ++ ++ if (wdata->head == wdata->tail) { ++ wdata->head = newhead; ++ schedule_work(&wdata->worker); ++ } else if (newhead != wdata->tail) { ++ wdata->head = newhead; ++ } else { ++ hid_warn(wdata->hdev, "Output queue is full"); ++ } ++ ++ spin_unlock_irqrestore(&wdata->qlock, flags); ++} ++ ++static void wiiproto_req_leds(struct wiimote_data *wdata, int leds) ++{ ++ __u8 cmd[2]; ++ ++ leds &= WIIPROTO_FLAGS_LEDS; ++ if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds) ++ return; ++ wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds; ++ ++ cmd[0] = WIIPROTO_REQ_LED; ++ cmd[1] = 0; ++ ++ if (leds & WIIPROTO_FLAG_LED1) ++ cmd[1] |= 0x10; ++ if (leds & WIIPROTO_FLAG_LED2) ++ cmd[1] |= 0x20; ++ if (leds & WIIPROTO_FLAG_LED3) ++ cmd[1] |= 0x40; ++ if (leds & WIIPROTO_FLAG_LED4) ++ cmd[1] |= 0x80; ++ ++ wiimote_queue(wdata, cmd, sizeof(cmd)); ++} ++ ++#define wiifs_led_show_set(num) \ ++static ssize_t wiifs_led_show_##num(struct device *dev, \ ++ struct device_attribute *attr, char *buf) \ ++{ \ ++ struct wiimote_data *wdata = dev_to_wii(dev); \ ++ unsigned long flags; \ ++ int state; \ ++ \ ++ if (!atomic_read(&wdata->ready)) \ ++ return -EBUSY; \ ++ \ ++ spin_lock_irqsave(&wdata->state.lock, flags); \ ++ state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \ ++ spin_unlock_irqrestore(&wdata->state.lock, flags); \ ++ \ ++ return sprintf(buf, "%d\n", state); \ ++} \ ++static ssize_t wiifs_led_set_##num(struct device *dev, \ ++ struct device_attribute *attr, const char *buf, size_t count) \ ++{ \ ++ struct wiimote_data *wdata = dev_to_wii(dev); \ ++ int tmp = simple_strtoul(buf, NULL, 10); \ ++ unsigned long flags; \ ++ __u8 state; \ ++ \ ++ if (!atomic_read(&wdata->ready)) \ ++ return -EBUSY; \ ++ \ ++ spin_lock_irqsave(&wdata->state.lock, flags); \ ++ \ ++ state = wdata->state.flags; \ ++ \ ++ if (tmp) \ ++ wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\ ++ else \ ++ wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\ ++ \ ++ spin_unlock_irqrestore(&wdata->state.lock, flags); \ ++ \ ++ return count; \ ++} \ ++static DEVICE_ATTR(led##num, S_IRUGO | S_IWUSR, wiifs_led_show_##num, \ ++ wiifs_led_set_##num) ++ ++wiifs_led_show_set(1); ++wiifs_led_show_set(2); ++wiifs_led_show_set(3); ++wiifs_led_show_set(4); ++ ++static int wiimote_input_event(struct input_dev *dev, unsigned int type, ++ unsigned int code, int value) ++{ ++ struct wiimote_data *wdata = input_get_drvdata(dev); ++ ++ if (!atomic_read(&wdata->ready)) ++ return -EBUSY; ++ /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */ ++ smp_rmb(); ++ ++ return 0; ++} ++ ++static void handler_keys(struct wiimote_data *wdata, const __u8 *payload) ++{ ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT], ++ !!(payload[0] & 0x01)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT], ++ !!(payload[0] & 0x02)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN], ++ !!(payload[0] & 0x04)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP], ++ !!(payload[0] & 0x08)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS], ++ !!(payload[0] & 0x10)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO], ++ !!(payload[1] & 0x01)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE], ++ !!(payload[1] & 0x02)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B], ++ !!(payload[1] & 0x04)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A], ++ !!(payload[1] & 0x08)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS], ++ !!(payload[1] & 0x10)); ++ input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME], ++ !!(payload[1] & 0x80)); ++ input_sync(wdata->input); ++} ++ ++struct wiiproto_handler { ++ __u8 id; ++ size_t size; ++ void (*func)(struct wiimote_data *wdata, const __u8 *payload); ++}; ++ ++static struct wiiproto_handler handlers[] = { ++ { .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys }, ++ { .id = 0 } ++}; ++ ++static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report, ++ u8 *raw_data, int size) ++{ ++ struct wiimote_data *wdata = hid_get_drvdata(hdev); ++ struct wiiproto_handler *h; ++ int i; ++ unsigned long flags; ++ ++ if (!atomic_read(&wdata->ready)) ++ return -EBUSY; ++ /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */ ++ smp_rmb(); ++ ++ if (size < 1) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&wdata->state.lock, flags); ++ ++ for (i = 0; handlers[i].id; ++i) { ++ h = &handlers[i]; ++ if (h->id == raw_data[0] && h->size < size) ++ h->func(wdata, &raw_data[1]); ++ } ++ ++ spin_unlock_irqrestore(&wdata->state.lock, flags); ++ ++ return 0; ++} ++ ++static struct wiimote_data *wiimote_create(struct hid_device *hdev) ++{ ++ struct wiimote_data *wdata; ++ int i; ++ ++ wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); ++ if (!wdata) ++ return NULL; ++ ++ wdata->input = input_allocate_device(); ++ if (!wdata->input) { ++ kfree(wdata); ++ return NULL; ++ } ++ ++ wdata->hdev = hdev; ++ hid_set_drvdata(hdev, wdata); ++ ++ input_set_drvdata(wdata->input, wdata); ++ wdata->input->event = wiimote_input_event; ++ wdata->input->dev.parent = &wdata->hdev->dev; ++ wdata->input->id.bustype = wdata->hdev->bus; ++ wdata->input->id.vendor = wdata->hdev->vendor; ++ wdata->input->id.product = wdata->hdev->product; ++ wdata->input->id.version = wdata->hdev->version; ++ wdata->input->name = WIIMOTE_NAME; ++ ++ set_bit(EV_KEY, wdata->input->evbit); ++ for (i = 0; i < WIIPROTO_KEY_COUNT; ++i) ++ set_bit(wiiproto_keymap[i], wdata->input->keybit); ++ ++ spin_lock_init(&wdata->qlock); ++ INIT_WORK(&wdata->worker, wiimote_worker); ++ ++ spin_lock_init(&wdata->state.lock); ++ ++ return wdata; ++} ++ ++static void wiimote_destroy(struct wiimote_data *wdata) ++{ ++ kfree(wdata); ++} ++ ++static int wiimote_hid_probe(struct hid_device *hdev, ++ const struct hid_device_id *id) ++{ ++ struct wiimote_data *wdata; ++ int ret; ++ ++ wdata = wiimote_create(hdev); ++ if (!wdata) { ++ hid_err(hdev, "Can't alloc device\n"); ++ return -ENOMEM; ++ } ++ ++ ret = device_create_file(&hdev->dev, &dev_attr_led1); ++ if (ret) ++ goto err; ++ ret = device_create_file(&hdev->dev, &dev_attr_led2); ++ if (ret) ++ goto err; ++ ret = device_create_file(&hdev->dev, &dev_attr_led3); ++ if (ret) ++ goto err; ++ ret = device_create_file(&hdev->dev, &dev_attr_led4); ++ if (ret) ++ goto err; ++ ++ ret = hid_parse(hdev); ++ if (ret) { ++ hid_err(hdev, "HID parse failed\n"); ++ goto err; ++ } ++ ++ ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); ++ if (ret) { ++ hid_err(hdev, "HW start failed\n"); ++ goto err; ++ } ++ ++ ret = input_register_device(wdata->input); ++ if (ret) { ++ hid_err(hdev, "Cannot register input device\n"); ++ goto err_stop; ++ } ++ ++ /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */ ++ smp_wmb(); ++ atomic_set(&wdata->ready, 1); ++ hid_info(hdev, "New device registered\n"); ++ ++ /* by default set led1 after device initialization */ ++ spin_lock_irq(&wdata->state.lock); ++ wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1); ++ spin_unlock_irq(&wdata->state.lock); ++ ++ return 0; ++ ++err_stop: ++ hid_hw_stop(hdev); ++err: ++ input_free_device(wdata->input); ++ device_remove_file(&hdev->dev, &dev_attr_led1); ++ device_remove_file(&hdev->dev, &dev_attr_led2); ++ device_remove_file(&hdev->dev, &dev_attr_led3); ++ device_remove_file(&hdev->dev, &dev_attr_led4); ++ wiimote_destroy(wdata); ++ return ret; ++} ++ ++static void wiimote_hid_remove(struct hid_device *hdev) ++{ ++ struct wiimote_data *wdata = hid_get_drvdata(hdev); ++ ++ hid_info(hdev, "Device removed\n"); ++ ++ device_remove_file(&hdev->dev, &dev_attr_led1); ++ device_remove_file(&hdev->dev, &dev_attr_led2); ++ device_remove_file(&hdev->dev, &dev_attr_led3); ++ device_remove_file(&hdev->dev, &dev_attr_led4); ++ ++ hid_hw_stop(hdev); ++ input_unregister_device(wdata->input); ++ ++ cancel_work_sync(&wdata->worker); ++ wiimote_destroy(wdata); ++} ++ ++static const struct hid_device_id wiimote_hid_devices[] = { ++ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, ++ USB_DEVICE_ID_NINTENDO_WIIMOTE) }, ++ { } ++}; ++MODULE_DEVICE_TABLE(hid, wiimote_hid_devices); ++ ++static struct hid_driver wiimote_hid_driver = { ++ .name = "wiimote", ++ .id_table = wiimote_hid_devices, ++ .probe = wiimote_hid_probe, ++ .remove = wiimote_hid_remove, ++ .raw_event = wiimote_hid_event, ++}; ++ ++static int __init wiimote_init(void) ++{ ++ int ret; ++ ++ ret = hid_register_driver(&wiimote_hid_driver); ++ if (ret) ++ pr_err("Can't register wiimote hid driver\n"); ++ ++ return ret; ++} ++ ++static void __exit wiimote_exit(void) ++{ ++ hid_unregister_driver(&wiimote_hid_driver); ++} ++ ++module_init(wiimote_init); ++module_exit(wiimote_exit); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("David Herrmann "); ++MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver"); ++MODULE_VERSION(WIIMOTE_VERSION); +diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c +index 38c261a..ad978f5 100644 +--- a/drivers/hid/usbhid/hid-core.c ++++ b/drivers/hid/usbhid/hid-core.c +@@ -1191,6 +1191,8 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * + if (intf->cur_altsetting->desc.bInterfaceProtocol == + USB_INTERFACE_PROTOCOL_MOUSE) + hid->type = HID_TYPE_USBMOUSE; ++ else if (intf->cur_altsetting->desc.bInterfaceProtocol == 0) ++ hid->type = HID_TYPE_USBNONE; + + if (dev->manufacturer) + strlcpy(hid->name, dev->manufacturer, sizeof(hid->name)); +diff --git a/include/linux/hid.h b/include/linux/hid.h +index 42f7e2f..9cf8e7a 100644 +--- a/include/linux/hid.h ++++ b/include/linux/hid.h +@@ -453,7 +453,8 @@ struct hid_input { + + enum hid_type { + HID_TYPE_OTHER = 0, +- HID_TYPE_USBMOUSE ++ HID_TYPE_USBMOUSE, ++ HID_TYPE_USBNONE + }; + + struct hid_driver; diff --git a/packages/linux/patches/linux-3.0-110-nouveau_drm_update-20110726.patch b/packages/linux/patches/linux-3.0-110-nouveau_drm_update-20110726.patch new file mode 100644 index 0000000000..47476db8b2 --- /dev/null +++ b/packages/linux/patches/linux-3.0-110-nouveau_drm_update-20110726.patch @@ -0,0 +1,12781 @@ +diff -Naur linux-3.0/drivers/gpu/drm/drm_gem.c linux-3.0.patch/drivers/gpu/drm/drm_gem.c +--- linux-3.0/drivers/gpu/drm/drm_gem.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/drm_gem.c 2011-07-26 07:03:44.396050644 +0200 +@@ -211,6 +211,8 @@ + idr_remove(&filp->object_idr, handle); + spin_unlock(&filp->table_lock); + ++ if (dev->driver->gem_close_object) ++ dev->driver->gem_close_object(obj, filp); + drm_gem_object_handle_unreference_unlocked(obj); + + return 0; +@@ -227,7 +229,8 @@ + struct drm_gem_object *obj, + u32 *handlep) + { +- int ret; ++ struct drm_device *dev = obj->dev; ++ int ret; + + /* + * Get the user-visible handle using idr. +@@ -248,6 +251,15 @@ + return ret; + + drm_gem_object_handle_reference(obj); ++ ++ if (dev->driver->gem_open_object) { ++ ret = dev->driver->gem_open_object(obj, file_priv); ++ if (ret) { ++ drm_gem_handle_delete(file_priv, *handlep); ++ return ret; ++ } ++ } ++ + return 0; + } + EXPORT_SYMBOL(drm_gem_handle_create); +@@ -402,7 +414,12 @@ + static int + drm_gem_object_release_handle(int id, void *ptr, void *data) + { ++ struct drm_file *file_priv = data; + struct drm_gem_object *obj = ptr; ++ struct drm_device *dev = obj->dev; ++ ++ if (dev->driver->gem_close_object) ++ dev->driver->gem_close_object(obj, file_priv); + + drm_gem_object_handle_unreference_unlocked(obj); + +@@ -418,7 +435,7 @@ + drm_gem_release(struct drm_device *dev, struct drm_file *file_private) + { + idr_for_each(&file_private->object_idr, +- &drm_gem_object_release_handle, NULL); ++ &drm_gem_object_release_handle, file_private); + + idr_remove_all(&file_private->object_idr); + idr_destroy(&file_private->object_idr); +diff -Naur linux-3.0/drivers/gpu/drm/drm_irq.c linux-3.0.patch/drivers/gpu/drm/drm_irq.c +--- linux-3.0/drivers/gpu/drm/drm_irq.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/drm_irq.c 2011-07-26 07:03:44.396050644 +0200 +@@ -397,13 +397,16 @@ + /* + * Wake up any waiters so they don't hang. + */ +- spin_lock_irqsave(&dev->vbl_lock, irqflags); +- for (i = 0; i < dev->num_crtcs; i++) { +- DRM_WAKEUP(&dev->vbl_queue[i]); +- dev->vblank_enabled[i] = 0; +- dev->last_vblank[i] = dev->driver->get_vblank_counter(dev, i); ++ if (dev->num_crtcs) { ++ spin_lock_irqsave(&dev->vbl_lock, irqflags); ++ for (i = 0; i < dev->num_crtcs; i++) { ++ DRM_WAKEUP(&dev->vbl_queue[i]); ++ dev->vblank_enabled[i] = 0; ++ dev->last_vblank[i] = ++ dev->driver->get_vblank_counter(dev, i); ++ } ++ spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + } +- spin_unlock_irqrestore(&dev->vbl_lock, irqflags); + + if (!irq_enabled) + return -EINVAL; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/Makefile linux-3.0.patch/drivers/gpu/drm/nouveau/Makefile +--- linux-3.0/drivers/gpu/drm/nouveau/Makefile 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/Makefile 2011-07-26 07:03:44.402050716 +0200 +@@ -21,16 +21,17 @@ + nv40_grctx.o nv50_grctx.o nvc0_grctx.o \ + nv84_crypt.o \ + nva3_copy.o nvc0_copy.o \ +- nv40_mpeg.o nv50_mpeg.o \ ++ nv31_mpeg.o nv50_mpeg.o \ + nv04_instmem.o nv50_instmem.o nvc0_instmem.o \ +- nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ +- nv50_cursor.o nv50_display.o \ + 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 \ ++ nv50_evo.o nv50_crtc.o nv50_dac.o nv50_sor.o \ ++ nv50_cursor.o nv50_display.o \ ++ nvd0_display.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 nvc0_pm.o \ + nv50_vram.o nvc0_vram.o \ + nv50_vm.o nvc0_vm.o + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_bios.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_bios.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_bios.c 2011-07-26 07:03:44.405050752 +0200 +@@ -135,13 +135,14 @@ + int i; + + if (dev_priv->card_type >= NV_50) { +- uint32_t vbios_vram = (nv_rd32(dev, 0x619f04) & ~0xff) << 8; +- +- if (!vbios_vram) +- vbios_vram = (nv_rd32(dev, 0x1700) << 16) + 0xf0000; ++ u64 addr = (u64)(nv_rd32(dev, 0x619f04) & 0xffffff00) << 8; ++ if (!addr) { ++ addr = (u64)nv_rd32(dev, 0x1700) << 16; ++ addr += 0xf0000; ++ } + + old_bar0_pramin = nv_rd32(dev, 0x1700); +- nv_wr32(dev, 0x1700, vbios_vram >> 16); ++ nv_wr32(dev, 0x1700, addr >> 16); + } + + /* bail if no rom signature */ +@@ -295,6 +296,11 @@ + if (dev_priv->card_type < NV_50) + return reg; + ++ if (reg & 0x80000000) { ++ BUG_ON(bios->display.crtc < 0); ++ reg += bios->display.crtc * 0x800; ++ } ++ + if (reg & 0x40000000) { + BUG_ON(!dcbent); + +@@ -303,7 +309,7 @@ + reg += 0x00000080; + } + +- reg &= ~0x60000000; ++ reg &= ~0xe0000000; + return reg; + } + +@@ -3220,6 +3226,49 @@ + return 1; + } + ++static void ++init_gpio_unknv50(struct nvbios *bios, struct dcb_gpio_entry *gpio) ++{ ++ const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; ++ u32 r, s, v; ++ ++ /* Not a clue, needs de-magicing */ ++ r = nv50_gpio_ctl[gpio->line >> 4]; ++ s = (gpio->line & 0x0f); ++ v = bios_rd32(bios, r) & ~(0x00010001 << s); ++ switch ((gpio->entry & 0x06000000) >> 25) { ++ case 1: ++ v |= (0x00000001 << s); ++ break; ++ case 2: ++ v |= (0x00010000 << s); ++ break; ++ default: ++ break; ++ } ++ ++ bios_wr32(bios, r, v); ++} ++ ++static void ++init_gpio_unknvd0(struct nvbios *bios, struct dcb_gpio_entry *gpio) ++{ ++ u32 v, i; ++ ++ v = bios_rd32(bios, 0x00d610 + (gpio->line * 4)); ++ v &= 0xffffff00; ++ v |= (gpio->entry & 0x00ff0000) >> 16; ++ bios_wr32(bios, 0x00d610 + (gpio->line * 4), v); ++ ++ i = (gpio->entry & 0x1f000000) >> 24; ++ if (i) { ++ v = bios_rd32(bios, 0x00d640 + ((i - 1) * 4)); ++ v &= 0xffffff00; ++ v |= gpio->line; ++ bios_wr32(bios, 0x00d640 + ((i - 1) * 4), v); ++ } ++} ++ + static int + init_gpio(struct nvbios *bios, uint16_t offset, struct init_exec *iexec) + { +@@ -3234,7 +3283,6 @@ + + struct drm_nouveau_private *dev_priv = bios->dev->dev_private; + struct nouveau_gpio_engine *pgpio = &dev_priv->engine.gpio; +- const uint32_t nv50_gpio_ctl[2] = { 0xe100, 0xe28c }; + int i; + + if (dev_priv->card_type < NV_50) { +@@ -3247,33 +3295,20 @@ + + for (i = 0; i < bios->dcb.gpio.entries; i++) { + struct dcb_gpio_entry *gpio = &bios->dcb.gpio.entry[i]; +- uint32_t r, s, v; + + BIOSLOG(bios, "0x%04X: Entry: 0x%08X\n", offset, gpio->entry); + + BIOSLOG(bios, "0x%04X: set gpio 0x%02x, state %d\n", + offset, gpio->tag, gpio->state_default); +- if (bios->execute) +- pgpio->set(bios->dev, gpio->tag, gpio->state_default); + +- /* The NVIDIA binary driver doesn't appear to actually do +- * any of this, my VBIOS does however. +- */ +- /* Not a clue, needs de-magicing */ +- r = nv50_gpio_ctl[gpio->line >> 4]; +- s = (gpio->line & 0x0f); +- v = bios_rd32(bios, r) & ~(0x00010001 << s); +- switch ((gpio->entry & 0x06000000) >> 25) { +- case 1: +- v |= (0x00000001 << s); +- break; +- case 2: +- v |= (0x00010000 << s); +- break; +- default: +- break; +- } +- bios_wr32(bios, r, v); ++ if (!bios->execute) ++ continue; ++ ++ pgpio->set(bios->dev, gpio->tag, gpio->state_default); ++ if (dev_priv->card_type < NV_D0) ++ init_gpio_unknv50(bios, gpio); ++ else ++ init_gpio_unknvd0(bios, gpio); + } + + return 1; +@@ -4466,8 +4501,8 @@ + } + + int +-nouveau_bios_run_display_table(struct drm_device *dev, struct dcb_entry *dcbent, +- uint32_t sub, int pxclk) ++nouveau_bios_run_display_table(struct drm_device *dev, u16 type, int pclk, ++ struct dcb_entry *dcbent, int crtc) + { + /* + * The display script table is located by the BIT 'U' table. +@@ -4557,22 +4592,22 @@ + return 1; + } + +- if (pxclk < -2 || pxclk > 0) { ++ if (pclk < -2 || pclk > 0) { + /* Try to find matching script table entry */ + for (i = 0; i < otable[5]; i++) { +- if (ROM16(otable[table[4] + i*6]) == sub) ++ if (ROM16(otable[table[4] + i*6]) == type) + break; + } + + if (i == otable[5]) { + NV_ERROR(dev, "Table 0x%04x not found for %d/%d, " + "using first\n", +- sub, dcbent->type, dcbent->or); ++ type, dcbent->type, dcbent->or); + i = 0; + } + } + +- if (pxclk == 0) { ++ if (pclk == 0) { + script = ROM16(otable[6]); + if (!script) { + NV_DEBUG_KMS(dev, "output script 0 not found\n"); +@@ -4580,9 +4615,9 @@ + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 0\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk == -1) { ++ if (pclk == -1) { + script = ROM16(otable[8]); + if (!script) { + NV_DEBUG_KMS(dev, "output script 1 not found\n"); +@@ -4590,9 +4625,9 @@ + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 1\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk == -2) { ++ if (pclk == -2) { + if (table[4] >= 12) + script = ROM16(otable[10]); + else +@@ -4603,31 +4638,31 @@ + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing output script 2\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk > 0) { ++ if (pclk > 0) { + script = ROM16(otable[table[4] + i*6 + 2]); + if (script) +- script = clkcmptable(bios, script, pxclk); ++ script = clkcmptable(bios, script, pclk); + if (!script) { + NV_DEBUG_KMS(dev, "clock script 0 not found\n"); + return 1; + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 0\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } else +- if (pxclk < 0) { ++ if (pclk < 0) { + script = ROM16(otable[table[4] + i*6 + 4]); + if (script) +- script = clkcmptable(bios, script, -pxclk); ++ script = clkcmptable(bios, script, -pclk); + if (!script) { + NV_DEBUG_KMS(dev, "clock script 1 not found\n"); + return 1; + } + + NV_DEBUG_KMS(dev, "0x%04X: parsing clock script 1\n", script); +- nouveau_bios_run_init_table(dev, script, dcbent); ++ nouveau_bios_run_init_table(dev, script, dcbent, crtc); + } + + return 0; +@@ -5186,7 +5221,7 @@ + load_table_ptr = ROM16(bios->data[bitentry->offset]); + + if (load_table_ptr == 0x0) { +- NV_ERROR(dev, "Pointer to BIT loadval table invalid\n"); ++ NV_DEBUG(dev, "Pointer to BIT loadval table invalid\n"); + return -EINVAL; + } + +@@ -5883,9 +5918,15 @@ + } + + e->line = (e->entry & 0x0000001f) >> 0; +- e->state_default = (e->entry & 0x01000000) >> 24; +- e->state[0] = (e->entry & 0x18000000) >> 27; +- e->state[1] = (e->entry & 0x60000000) >> 29; ++ if (gpio[0] == 0x40) { ++ e->state_default = (e->entry & 0x01000000) >> 24; ++ e->state[0] = (e->entry & 0x18000000) >> 27; ++ e->state[1] = (e->entry & 0x60000000) >> 29; ++ } else { ++ e->state_default = (e->entry & 0x00000080) >> 7; ++ e->state[0] = (entry[4] >> 4) & 3; ++ e->state[1] = (entry[4] >> 6) & 3; ++ } + } + } + +@@ -5965,6 +6006,12 @@ + if (cte->type == DCB_CONNECTOR_HDMI_1) + cte->type = DCB_CONNECTOR_DVI_I; + } ++ ++ /* Gigabyte GV-NX86T512H */ ++ if (nv_match_device(dev, 0x0402, 0x1458, 0x3455)) { ++ if (cte->type == DCB_CONNECTOR_HDMI_1) ++ cte->type = DCB_CONNECTOR_DVI_I; ++ } + } + + static const u8 hpd_gpio[16] = { +@@ -6377,6 +6424,37 @@ + } + } + ++ /* Some other twisted XFX board (rhbz#694914) ++ * ++ * The DVI/VGA encoder combo that's supposed to represent the ++ * DVI-I connector actually point at two different ones, and ++ * the HDMI connector ends up paired with the VGA instead. ++ * ++ * Connector table is missing anything for VGA at all, pointing it ++ * an invalid conntab entry 2 so we figure it out ourself. ++ */ ++ if (nv_match_device(dev, 0x0615, 0x1682, 0x2605)) { ++ if (idx == 0) { ++ *conn = 0x02002300; /* VGA, connector 2 */ ++ *conf = 0x00000028; ++ } else ++ if (idx == 1) { ++ *conn = 0x01010312; /* DVI, connector 0 */ ++ *conf = 0x00020030; ++ } else ++ if (idx == 2) { ++ *conn = 0x04020310; /* VGA, connector 0 */ ++ *conf = 0x00000028; ++ } else ++ if (idx == 3) { ++ *conn = 0x02021322; /* HDMI, connector 1 */ ++ *conf = 0x00020010; ++ } else { ++ *conn = 0x0000000e; /* EOL */ ++ *conf = 0x00000000; ++ } ++ } ++ + return true; + } + +@@ -6731,7 +6809,7 @@ + + void + nouveau_bios_run_init_table(struct drm_device *dev, uint16_t table, +- struct dcb_entry *dcbent) ++ struct dcb_entry *dcbent, int crtc) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvbios *bios = &dev_priv->vbios; +@@ -6739,6 +6817,7 @@ + + spin_lock_bh(&bios->lock); + bios->display.output = dcbent; ++ bios->display.crtc = crtc; + parse_init_table(bios, table, &iexec); + bios->display.output = NULL; + spin_unlock_bh(&bios->lock); +@@ -6825,9 +6904,8 @@ + + if (dev_priv->card_type >= NV_50) { + for (i = 0; i < bios->dcb.entries; i++) { +- nouveau_bios_run_display_table(dev, +- &bios->dcb.entry[i], +- 0, 0); ++ nouveau_bios_run_display_table(dev, 0, 0, ++ &bios->dcb.entry[i], -1); + } + } + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_bios.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_bios.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_bios.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_bios.h 2011-07-26 07:03:44.408050788 +0200 +@@ -289,6 +289,7 @@ + + struct { + struct dcb_entry *output; ++ int crtc; + uint16_t script_table_ptr; + uint16_t dp_table_ptr; + } display; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_bo.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_bo.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_bo.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_bo.c 2011-07-26 07:03:44.409050800 +0200 +@@ -49,16 +49,12 @@ + DRM_ERROR("bo %p still attached to GEM object\n", bo); + + nv10_mem_put_tile_region(dev, nvbo->tile, NULL); +- if (nvbo->vma.node) { +- nouveau_vm_unmap(&nvbo->vma); +- nouveau_vm_put(&nvbo->vma); +- } + kfree(nvbo); + } + + static void + nouveau_bo_fixup_align(struct nouveau_bo *nvbo, u32 flags, +- int *align, int *size, int *page_shift) ++ int *align, int *size) + { + struct drm_nouveau_private *dev_priv = nouveau_bdev(nvbo->bo.bdev); + +@@ -82,67 +78,51 @@ + } + } + } else { +- if (likely(dev_priv->chan_vm)) { +- 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; +- } else { +- *page_shift = 12; +- } +- +- *size = roundup(*size, (1 << *page_shift)); +- *align = max((1 << *page_shift), *align); ++ *size = roundup(*size, (1 << nvbo->page_shift)); ++ *align = max((1 << nvbo->page_shift), *align); + } + + *size = roundup(*size, PAGE_SIZE); + } + + 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, struct nouveau_bo **pnvbo) ++nouveau_bo_new(struct drm_device *dev, int size, int align, ++ uint32_t flags, 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; +- int ret = 0, page_shift = 0; ++ int ret; + + nvbo = kzalloc(sizeof(struct nouveau_bo), GFP_KERNEL); + if (!nvbo) + return -ENOMEM; + INIT_LIST_HEAD(&nvbo->head); + INIT_LIST_HEAD(&nvbo->entry); ++ INIT_LIST_HEAD(&nvbo->vma_list); + nvbo->tile_mode = tile_mode; + nvbo->tile_flags = tile_flags; + nvbo->bo.bdev = &dev_priv->ttm.bdev; + +- nouveau_bo_fixup_align(nvbo, flags, &align, &size, &page_shift); +- align >>= PAGE_SHIFT; +- +- if (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; +- } ++ nvbo->page_shift = 12; ++ if (dev_priv->bar1_vm) { ++ if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024) ++ nvbo->page_shift = dev_priv->bar1_vm->lpg_shift; + } + ++ nouveau_bo_fixup_align(nvbo, flags, &align, &size); + nvbo->bo.mem.num_pages = size >> PAGE_SHIFT; + nouveau_bo_placement_set(nvbo, flags, 0); + +- nvbo->channel = chan; + ret = ttm_bo_init(&dev_priv->ttm.bdev, &nvbo->bo, size, +- ttm_bo_type_device, &nvbo->placement, align, 0, +- false, NULL, size, nouveau_bo_del_ttm); ++ ttm_bo_type_device, &nvbo->placement, ++ align >> PAGE_SHIFT, 0, false, NULL, size, ++ nouveau_bo_del_ttm); + if (ret) { + /* ttm will call nouveau_bo_del_ttm if it fails.. */ + return ret; + } +- nvbo->channel = NULL; + +- if (nvbo->vma.node) +- nvbo->bo.offset = nvbo->vma.offset; + *pnvbo = nvbo; + return 0; + } +@@ -312,8 +292,6 @@ + if (ret) + return ret; + +- if (nvbo->vma.node) +- nvbo->bo.offset = nvbo->vma.offset; + return 0; + } + +@@ -440,7 +418,6 @@ + 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", +@@ -501,19 +478,12 @@ + 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 nouveau_mem *old_node = old_mem->mm_node; +- struct nouveau_mem *new_node = new_mem->mm_node; +- struct nouveau_bo *nvbo = nouveau_bo(bo); ++ struct nouveau_mem *node = old_mem->mm_node; ++ u64 src_offset = node->vma[0].offset; ++ u64 dst_offset = node->vma[1].offset; + u32 page_count = new_mem->num_pages; +- u64 src_offset, dst_offset; + int ret; + +- 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) { + int line_count = (page_count > 2047) ? 2047 : page_count; +@@ -547,19 +517,13 @@ + 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 nouveau_mem *old_node = old_mem->mm_node; +- struct nouveau_mem *new_node = new_mem->mm_node; ++ struct nouveau_mem *node = old_mem->mm_node; + struct nouveau_bo *nvbo = nouveau_bo(bo); + u64 length = (new_mem->num_pages << PAGE_SHIFT); +- u64 src_offset, dst_offset; ++ u64 src_offset = node->vma[0].offset; ++ u64 dst_offset = node->vma[1].offset; + int ret; + +- 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; + +@@ -695,6 +659,27 @@ + } + + static int ++nouveau_vma_getmap(struct nouveau_channel *chan, struct nouveau_bo *nvbo, ++ struct ttm_mem_reg *mem, struct nouveau_vma *vma) ++{ ++ struct nouveau_mem *node = mem->mm_node; ++ int ret; ++ ++ ret = nouveau_vm_get(chan->vm, mem->num_pages << PAGE_SHIFT, ++ node->page_shift, NV_MEM_ACCESS_RO, vma); ++ if (ret) ++ return ret; ++ ++ if (mem->mem_type == TTM_PL_VRAM) ++ nouveau_vm_map(vma, node); ++ else ++ nouveau_vm_map_sg(vma, 0, mem->num_pages << PAGE_SHIFT, ++ node, node->pages); ++ ++ return 0; ++} ++ ++static int + nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, + bool no_wait_reserve, bool no_wait_gpu, + struct ttm_mem_reg *new_mem) +@@ -711,31 +696,20 @@ + 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 ++ /* create temporary vmas for the transfer and attach them to the ++ * old nouveau_mem node, these will get cleaned up after ttm has ++ * destroyed 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); +- } ++ ret = nouveau_vma_getmap(chan, nvbo, old_mem, &node->vma[0]); ++ if (ret) ++ goto out; ++ ++ ret = nouveau_vma_getmap(chan, nvbo, new_mem, &node->vma[1]); ++ if (ret) ++ goto out; + } + + if (dev_priv->card_type < NV_50) +@@ -762,7 +736,6 @@ + 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; +@@ -782,23 +755,7 @@ + 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; + +@@ -844,30 +801,22 @@ + 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; ++ struct nouveau_vma *vma; + +- 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) { ++ list_for_each_entry(vma, &nvbo->vma_list, head) { ++ if (new_mem->mem_type == TTM_PL_VRAM) { ++ nouveau_vm_map(vma, new_mem->mm_node); ++ } else ++ if (new_mem->mem_type == TTM_PL_TT && ++ nvbo->page_shift == vma->vm->spg_shift) { ++ nouveau_vm_map_sg(vma, 0, new_mem-> ++ num_pages << PAGE_SHIFT, ++ node, node->pages); ++ } else { + 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; + } + } + +@@ -1007,7 +956,7 @@ + break; + } + +- if (dev_priv->card_type == NV_C0) ++ if (dev_priv->card_type >= NV_C0) + page_shift = node->page_shift; + else + page_shift = 12; +@@ -1113,3 +1062,54 @@ + .io_mem_free = &nouveau_ttm_io_mem_free, + }; + ++struct nouveau_vma * ++nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nouveau_vm *vm) ++{ ++ struct nouveau_vma *vma; ++ list_for_each_entry(vma, &nvbo->vma_list, head) { ++ if (vma->vm == vm) ++ return vma; ++ } ++ ++ return NULL; ++} ++ ++int ++nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm, ++ struct nouveau_vma *vma) ++{ ++ const u32 size = nvbo->bo.mem.num_pages << PAGE_SHIFT; ++ struct nouveau_mem *node = nvbo->bo.mem.mm_node; ++ int ret; ++ ++ ret = nouveau_vm_get(vm, size, nvbo->page_shift, ++ NV_MEM_ACCESS_RW, vma); ++ if (ret) ++ return ret; ++ ++ if (nvbo->bo.mem.mem_type == TTM_PL_VRAM) ++ nouveau_vm_map(vma, nvbo->bo.mem.mm_node); ++ else ++ if (nvbo->bo.mem.mem_type == TTM_PL_TT) ++ nouveau_vm_map_sg(vma, 0, size, node, node->pages); ++ ++ list_add_tail(&vma->head, &nvbo->vma_list); ++ vma->refcount = 1; ++ return 0; ++} ++ ++void ++nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nouveau_vma *vma) ++{ ++ if (vma->node) { ++ if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM) { ++ spin_lock(&nvbo->bo.bdev->fence_lock); ++ ttm_bo_wait(&nvbo->bo, false, false, false); ++ spin_unlock(&nvbo->bo.bdev->fence_lock); ++ nouveau_vm_unmap(vma); ++ } ++ ++ nouveau_vm_put(vma); ++ list_del(&vma->head); ++ } ++} +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_channel.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_channel.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_channel.c 2011-07-26 07:03:44.410050812 +0200 +@@ -27,40 +27,63 @@ + #include "nouveau_drv.h" + #include "nouveau_drm.h" + #include "nouveau_dma.h" ++#include "nouveau_ramht.h" + + static int +-nouveau_channel_pushbuf_ctxdma_init(struct nouveau_channel *chan) ++nouveau_channel_pushbuf_init(struct nouveau_channel *chan) + { ++ u32 mem = nouveau_vram_pushbuf ? TTM_PL_FLAG_VRAM : TTM_PL_FLAG_TT; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_bo *pb = chan->pushbuf_bo; +- struct nouveau_gpuobj *pushbuf = NULL; +- int ret = 0; ++ int ret; ++ ++ /* allocate buffer object */ ++ ret = nouveau_bo_new(dev, 65536, 0, mem, 0, 0, &chan->pushbuf_bo); ++ if (ret) ++ goto out; ++ ++ ret = nouveau_bo_pin(chan->pushbuf_bo, mem); ++ if (ret) ++ goto out; ++ ++ ret = nouveau_bo_map(chan->pushbuf_bo); ++ if (ret) ++ goto out; + ++ /* create DMA object covering the entire memtype where the push ++ * buffer resides, userspace can submit its own push buffers from ++ * anywhere within the same memtype. ++ */ ++ chan->pushbuf_base = chan->pushbuf_bo->bo.offset; + if (dev_priv->card_type >= NV_50) { ++ ret = nouveau_bo_vma_add(chan->pushbuf_bo, chan->vm, ++ &chan->pushbuf_vma); ++ if (ret) ++ goto out; ++ + 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); + } +- chan->pushbuf_base = pb->bo.offset; ++ chan->pushbuf_base = chan->pushbuf_vma.offset; + } else +- if (pb->bo.mem.mem_type == TTM_PL_TT) { ++ if (chan->pushbuf_bo->bo.mem.mem_type == TTM_PL_TT) { + 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; ++ NV_MEM_TARGET_GART, ++ &chan->pushbuf); + } 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_MEM_ACCESS_RO, +- NV_MEM_TARGET_VRAM, &pushbuf); +- chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; ++ NV_MEM_TARGET_VRAM, ++ &chan->pushbuf); + } else { + /* NV04 cmdbuf hack, from original ddx.. not sure of it's + * exact reason for existing :) PCI access to cmdbuf in +@@ -70,47 +93,22 @@ + pci_resource_start(dev->pdev, 1), + dev_priv->fb_available_size, + NV_MEM_ACCESS_RO, +- NV_MEM_TARGET_PCI, &pushbuf); +- chan->pushbuf_base = pb->bo.mem.start << PAGE_SHIFT; ++ NV_MEM_TARGET_PCI, ++ &chan->pushbuf); + } + +- nouveau_gpuobj_ref(pushbuf, &chan->pushbuf); +- nouveau_gpuobj_ref(NULL, &pushbuf); +- return ret; +-} +- +-static struct nouveau_bo * +-nouveau_channel_user_pushbuf_alloc(struct drm_device *dev) +-{ +- struct nouveau_bo *pushbuf = NULL; +- int location, ret; +- +- if (nouveau_vram_pushbuf) +- location = TTM_PL_FLAG_VRAM; +- else +- location = TTM_PL_FLAG_TT; +- +- 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; +- } +- +- ret = nouveau_bo_pin(pushbuf, location); +- if (ret) { +- NV_ERROR(dev, "error pinning DMA push buffer: %d\n", ret); +- nouveau_bo_ref(NULL, &pushbuf); +- return NULL; +- } +- +- ret = nouveau_bo_map(pushbuf); ++out: + if (ret) { +- nouveau_bo_unpin(pushbuf); +- nouveau_bo_ref(NULL, &pushbuf); +- return NULL; ++ NV_ERROR(dev, "error initialising pushbuf: %d\n", ret); ++ nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma); ++ nouveau_gpuobj_ref(NULL, &chan->pushbuf); ++ if (chan->pushbuf_bo) { ++ nouveau_bo_unmap(chan->pushbuf_bo); ++ nouveau_bo_ref(NULL, &chan->pushbuf_bo); ++ } + } + +- return pushbuf; ++ return 0; + } + + /* allocates and initializes a fifo for user space consumption */ +@@ -121,6 +119,7 @@ + { + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_fifo_engine *pfifo = &dev_priv->engine.fifo; ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); + struct nouveau_channel *chan; + unsigned long flags; + int ret; +@@ -160,19 +159,14 @@ + INIT_LIST_HEAD(&chan->nvsw.flip); + INIT_LIST_HEAD(&chan->fence.pending); + +- /* 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); ++ /* setup channel's memory and vm */ ++ ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); ++ if (ret) { ++ NV_ERROR(dev, "gpuobj %d\n", ret); + nouveau_channel_put(&chan); + return ret; + } + +- nouveau_dma_pre_init(chan); +- chan->user_put = 0x40; +- chan->user_get = 0x44; +- + /* Allocate space for per-channel fixed notifier memory */ + ret = nouveau_notifier_init_channel(chan); + if (ret) { +@@ -181,21 +175,17 @@ + return ret; + } + +- /* Setup channel's default objects */ +- ret = nouveau_gpuobj_channel_init(chan, vram_handle, gart_handle); ++ /* Allocate DMA push buffer */ ++ ret = nouveau_channel_pushbuf_init(chan); + if (ret) { +- NV_ERROR(dev, "gpuobj %d\n", ret); ++ NV_ERROR(dev, "pushbuf %d\n", ret); + nouveau_channel_put(&chan); + return ret; + } + +- /* Create a dma object for the push buffer */ +- ret = nouveau_channel_pushbuf_ctxdma_init(chan); +- if (ret) { +- NV_ERROR(dev, "pbctxdma %d\n", ret); +- nouveau_channel_put(&chan); +- return ret; +- } ++ nouveau_dma_pre_init(chan); ++ chan->user_put = 0x40; ++ chan->user_get = 0x44; + + /* disable the fifo caches */ + pfifo->reassign(dev, false); +@@ -220,6 +210,11 @@ + nouveau_debugfs_channel_init(chan); + + NV_DEBUG(dev, "channel %d initialised\n", chan->id); ++ if (fpriv) { ++ spin_lock(&fpriv->lock); ++ list_add(&chan->list, &fpriv->channels); ++ spin_unlock(&fpriv->lock); ++ } + *chan_ret = chan; + return 0; + } +@@ -236,29 +231,23 @@ + } + + struct nouveau_channel * +-nouveau_channel_get(struct drm_device *dev, struct drm_file *file_priv, int id) ++nouveau_channel_get(struct drm_file *file_priv, int id) + { +- struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); + 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); ++ spin_lock(&fpriv->lock); ++ list_for_each_entry(chan, &fpriv->channels, list) { ++ if (chan->id == id) { ++ chan = nouveau_channel_get_unlocked(chan); ++ spin_unlock(&fpriv->lock); ++ mutex_lock(&chan->mutex); ++ return chan; ++ } + } ++ spin_unlock(&fpriv->lock); + +- mutex_lock(&chan->mutex); +- return chan; ++ return ERR_PTR(-EINVAL); + } + + void +@@ -312,12 +301,14 @@ + /* destroy any resources the channel owned */ + nouveau_gpuobj_ref(NULL, &chan->pushbuf); + if (chan->pushbuf_bo) { ++ nouveau_bo_vma_del(chan->pushbuf_bo, &chan->pushbuf_vma); + nouveau_bo_unmap(chan->pushbuf_bo); + nouveau_bo_unpin(chan->pushbuf_bo); + nouveau_bo_ref(NULL, &chan->pushbuf_bo); + } +- nouveau_gpuobj_channel_takedown(chan); ++ nouveau_ramht_ref(NULL, &chan->ramht, chan); + nouveau_notifier_takedown_channel(chan); ++ nouveau_gpuobj_channel_takedown(chan); + + nouveau_channel_ref(NULL, pchan); + } +@@ -383,10 +374,11 @@ + + NV_DEBUG(dev, "clearing FIFO enables from file_priv\n"); + for (i = 0; i < engine->fifo.channels; i++) { +- chan = nouveau_channel_get(dev, file_priv, i); ++ chan = nouveau_channel_get(file_priv, i); + if (IS_ERR(chan)) + continue; + ++ list_del(&chan->list); + atomic_dec(&chan->users); + nouveau_channel_put(&chan); + } +@@ -459,10 +451,11 @@ + struct drm_nouveau_channel_free *req = data; + struct nouveau_channel *chan; + +- chan = nouveau_channel_get(dev, file_priv, req->channel); ++ chan = nouveau_channel_get(file_priv, req->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); + ++ list_del(&chan->list); + atomic_dec(&chan->users); + nouveau_channel_put(&chan); + return 0; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_connector.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_connector.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_connector.c 2011-07-26 07:03:44.411050824 +0200 +@@ -40,7 +40,7 @@ + static void nouveau_connector_hotplug(void *, int); + + static struct nouveau_encoder * +-find_encoder_by_type(struct drm_connector *connector, int type) ++find_encoder(struct drm_connector *connector, int type) + { + struct drm_device *dev = connector->dev; + struct nouveau_encoder *nv_encoder; +@@ -170,8 +170,8 @@ + struct device_node *cn, *dn = pci_device_to_OF_node(dev->pdev); + + if (!dn || +- !((nv_encoder = find_encoder_by_type(connector, OUTPUT_TMDS)) || +- (nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG)))) ++ !((nv_encoder = find_encoder(connector, OUTPUT_TMDS)) || ++ (nv_encoder = find_encoder(connector, OUTPUT_ANALOG)))) + return NULL; + + for_each_child_of_node(dn, cn) { +@@ -233,6 +233,7 @@ + struct drm_device *dev = connector->dev; + struct nouveau_connector *nv_connector = nouveau_connector(connector); + struct nouveau_encoder *nv_encoder = NULL; ++ struct nouveau_encoder *nv_partner; + struct nouveau_i2c_chan *i2c; + int type; + +@@ -266,19 +267,22 @@ + * same i2c channel so the value returned from ddc_detect + * isn't necessarily correct. + */ +- if (nv_connector->dcb->type == DCB_CONNECTOR_DVI_I) { ++ nv_partner = NULL; ++ if (nv_encoder->dcb->type == OUTPUT_TMDS) ++ nv_partner = find_encoder(connector, OUTPUT_ANALOG); ++ if (nv_encoder->dcb->type == OUTPUT_ANALOG) ++ nv_partner = find_encoder(connector, OUTPUT_TMDS); ++ ++ if (nv_partner && ((nv_encoder->dcb->type == OUTPUT_ANALOG && ++ nv_partner->dcb->type == OUTPUT_TMDS) || ++ (nv_encoder->dcb->type == OUTPUT_TMDS && ++ nv_partner->dcb->type == OUTPUT_ANALOG))) { + if (nv_connector->edid->input & DRM_EDID_INPUT_DIGITAL) + type = OUTPUT_TMDS; + else + type = OUTPUT_ANALOG; + +- nv_encoder = find_encoder_by_type(connector, type); +- if (!nv_encoder) { +- NV_ERROR(dev, "Detected %d encoder on %s, " +- "but no object!\n", type, +- drm_get_connector_name(connector)); +- return connector_status_disconnected; +- } ++ nv_encoder = find_encoder(connector, type); + } + + nouveau_connector_set_encoder(connector, nv_encoder); +@@ -292,9 +296,9 @@ + } + + detect_analog: +- nv_encoder = find_encoder_by_type(connector, OUTPUT_ANALOG); ++ nv_encoder = find_encoder(connector, OUTPUT_ANALOG); + if (!nv_encoder && !nouveau_tv_disable) +- nv_encoder = find_encoder_by_type(connector, OUTPUT_TV); ++ nv_encoder = find_encoder(connector, OUTPUT_TV); + if (nv_encoder && force) { + struct drm_encoder *encoder = to_drm_encoder(nv_encoder); + struct drm_encoder_helper_funcs *helper = +@@ -327,7 +331,7 @@ + nv_connector->edid = NULL; + } + +- nv_encoder = find_encoder_by_type(connector, OUTPUT_LVDS); ++ nv_encoder = find_encoder(connector, OUTPUT_LVDS); + if (!nv_encoder) + return connector_status_disconnected; + +@@ -405,7 +409,7 @@ + } else + type = OUTPUT_ANY; + +- nv_encoder = find_encoder_by_type(connector, type); ++ nv_encoder = find_encoder(connector, type); + if (!nv_encoder) { + NV_ERROR(connector->dev, "can't find encoder to force %s on!\n", + drm_get_connector_name(connector)); +@@ -867,7 +871,6 @@ + dev->mode_config.scaling_mode_property, + nv_connector->scaling_mode); + } +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; + /* fall-through */ + case DCB_CONNECTOR_TV_0: + case DCB_CONNECTOR_TV_1: +@@ -884,19 +887,16 @@ + dev->mode_config.dithering_mode_property, + nv_connector->use_dithering ? + DRM_MODE_DITHERING_ON : DRM_MODE_DITHERING_OFF); +- +- if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS) { +- if (dev_priv->card_type >= NV_50) +- connector->polled = DRM_CONNECTOR_POLL_HPD; +- else +- connector->polled = DRM_CONNECTOR_POLL_CONNECT; +- } + break; + } + +- if (pgpio->irq_register) { ++ if (nv_connector->dcb->gpio_tag != 0xff && pgpio->irq_register) { + pgpio->irq_register(dev, nv_connector->dcb->gpio_tag, + nouveau_connector_hotplug, connector); ++ ++ connector->polled = DRM_CONNECTOR_POLL_HPD; ++ } else { ++ connector->polled = DRM_CONNECTOR_POLL_CONNECT; + } + + drm_sysfs_connector_add(connector); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_crtc.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_crtc.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_crtc.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_crtc.h 2011-07-26 07:03:44.411050824 +0200 +@@ -82,14 +82,13 @@ + } + + int nv50_crtc_create(struct drm_device *dev, int index); +-int nv50_cursor_init(struct nouveau_crtc *); +-void nv50_cursor_fini(struct nouveau_crtc *); + int nv50_crtc_cursor_set(struct drm_crtc *drm_crtc, struct drm_file *file_priv, + uint32_t buffer_handle, uint32_t width, + uint32_t height); + int nv50_crtc_cursor_move(struct drm_crtc *drm_crtc, int x, int y); + + int nv04_cursor_init(struct nouveau_crtc *); ++int nv50_cursor_init(struct nouveau_crtc *); + + struct nouveau_connector * + nouveau_crtc_connector_get(struct nouveau_crtc *crtc); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_display.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_display.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_display.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_display.c 2011-07-26 07:03:44.412050836 +0200 +@@ -105,9 +105,12 @@ + if (dev_priv->chipset == 0x50) + nv_fb->r_format |= (tile_flags << 8); + +- if (!tile_flags) +- nv_fb->r_pitch = 0x00100000 | fb->pitch; +- else { ++ if (!tile_flags) { ++ if (dev_priv->card_type < NV_D0) ++ nv_fb->r_pitch = 0x00100000 | fb->pitch; ++ else ++ nv_fb->r_pitch = 0x01000000 | fb->pitch; ++ } else { + u32 mode = nvbo->tile_mode; + if (dev_priv->card_type >= NV_C0) + mode >>= 4; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_dma.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_dma.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_dma.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_dma.c 2011-07-26 07:03:44.412050836 +0200 +@@ -167,8 +167,13 @@ + int delta, int length) + { + struct nouveau_bo *pb = chan->pushbuf_bo; +- uint64_t offset = bo->bo.offset + delta; ++ struct nouveau_vma *vma; + int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base; ++ u64 offset; ++ ++ vma = nouveau_bo_vma_find(bo, chan->vm); ++ BUG_ON(!vma); ++ offset = vma->offset + delta; + + BUG_ON(chan->dma.ib_free < 1); + nouveau_bo_wr32(pb, ip++, lower_32_bits(offset)); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_dp.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_dp.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_dp.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_dp.c 2011-07-26 07:03:44.413050848 +0200 +@@ -300,7 +300,7 @@ + if (dpe->script0) { + NV_DEBUG_KMS(dev, "SOR-%d: running DP script 0\n", nv_encoder->or); + nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script0), +- nv_encoder->dcb); ++ nv_encoder->dcb, -1); + } + + train: +@@ -433,7 +433,7 @@ + if (dpe->script1) { + NV_DEBUG_KMS(dev, "SOR-%d: running DP script 1\n", nv_encoder->or); + nouveau_bios_run_init_table(dev, le16_to_cpu(dpe->script1), +- nv_encoder->dcb); ++ nv_encoder->dcb, -1); + } + + /* re-enable hotplug detect */ +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_drv.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_drv.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_drv.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_drv.c 2011-07-26 07:03:44.413050848 +0200 +@@ -41,7 +41,7 @@ + module_param_named(agpmode, nouveau_agpmode, int, 0400); + + MODULE_PARM_DESC(modeset, "Enable kernel modesetting"); +-static int nouveau_modeset = -1; /* kms */ ++int nouveau_modeset = -1; + module_param_named(modeset, nouveau_modeset, int, 0400); + + MODULE_PARM_DESC(vbios, "Override default VBIOS location"); +@@ -73,7 +73,7 @@ + module_param_named(ignorelid, nouveau_ignorelid, int, 0400); + + MODULE_PARM_DESC(noaccel, "Disable all acceleration"); +-int nouveau_noaccel = 0; ++int nouveau_noaccel = -1; + module_param_named(noaccel, nouveau_noaccel, int, 0400); + + MODULE_PARM_DESC(nofbaccel, "Disable fbcon acceleration"); +@@ -119,6 +119,10 @@ + int nouveau_msi; + module_param_named(msi, nouveau_msi, int, 0400); + ++MODULE_PARM_DESC(ctxfw, "Use external HUB/GPC ucode (fermi)\n"); ++int nouveau_ctxfw; ++module_param_named(ctxfw, nouveau_ctxfw, int, 0400); ++ + int nouveau_fbpercrtc; + #if 0 + module_param_named(fbpercrtc, nouveau_fbpercrtc, int, 0400); +@@ -210,10 +214,13 @@ + pfifo->unload_context(dev); + + for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) { +- if (dev_priv->eng[e]) { +- ret = dev_priv->eng[e]->fini(dev, e); +- if (ret) +- goto out_abort; ++ if (!dev_priv->eng[e]) ++ continue; ++ ++ ret = dev_priv->eng[e]->fini(dev, e, true); ++ if (ret) { ++ NV_ERROR(dev, "... engine %d failed: %d\n", i, ret); ++ goto out_abort; + } + } + +@@ -354,7 +361,7 @@ + + 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; ++ u32 offset = nv_crtc->cursor.nvbo->bo.offset; + + nv_crtc->cursor.set_offset(nv_crtc, offset); + nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x, +@@ -389,7 +396,9 @@ + .firstopen = nouveau_firstopen, + .lastclose = nouveau_lastclose, + .unload = nouveau_unload, ++ .open = nouveau_open, + .preclose = nouveau_preclose, ++ .postclose = nouveau_postclose, + #if defined(CONFIG_DRM_NOUVEAU_DEBUG) + .debugfs_init = nouveau_debugfs_init, + .debugfs_cleanup = nouveau_debugfs_takedown, +@@ -420,6 +429,8 @@ + + .gem_init_object = nouveau_gem_object_new, + .gem_free_object = nouveau_gem_object_del, ++ .gem_open_object = nouveau_gem_object_open, ++ .gem_close_object = nouveau_gem_object_close, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_drv.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_drv.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_drv.h 2011-07-26 07:03:44.415050872 +0200 +@@ -46,9 +46,17 @@ + #include "ttm/ttm_module.h" + + struct nouveau_fpriv { +- struct ttm_object_file *tfile; ++ spinlock_t lock; ++ struct list_head channels; ++ struct nouveau_vm *vm; + }; + ++static inline struct nouveau_fpriv * ++nouveau_fpriv(struct drm_file *file_priv) ++{ ++ return file_priv ? file_priv->driver_priv : NULL; ++} ++ + #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT) + + #include "nouveau_drm.h" +@@ -69,7 +77,7 @@ + struct drm_device *dev; + + struct nouveau_vma bar_vma; +- struct nouveau_vma tmp_vma; ++ struct nouveau_vma vma[2]; + u8 page_shift; + + struct drm_mm_node *tag; +@@ -107,7 +115,8 @@ + + struct nouveau_channel *channel; + +- struct nouveau_vma vma; ++ struct list_head vma_list; ++ unsigned page_shift; + + uint32_t tile_mode; + uint32_t tile_flags; +@@ -176,9 +185,10 @@ + uint32_t flags; + + u32 size; +- u32 pinst; +- u32 cinst; +- u64 vinst; ++ u32 pinst; /* PRAMIN BAR offset */ ++ u32 cinst; /* Channel offset */ ++ u64 vinst; /* VRAM address */ ++ u64 linst; /* VM address */ + + uint32_t engine; + uint32_t class; +@@ -201,6 +211,7 @@ + + struct nouveau_channel { + struct drm_device *dev; ++ struct list_head list; + int id; + + /* references to the channel data structure */ +@@ -228,15 +239,18 @@ + uint32_t sequence; + uint32_t sequence_ack; + atomic_t last_sequence_irq; ++ struct nouveau_vma vma; + } fence; + + /* DMA push buffer */ + struct nouveau_gpuobj *pushbuf; + struct nouveau_bo *pushbuf_bo; ++ struct nouveau_vma pushbuf_vma; + uint32_t pushbuf_base; + + /* Notifier memory */ + struct nouveau_bo *notifier_bo; ++ struct nouveau_vma notifier_vma; + struct drm_mm notifier_heap; + + /* PFIFO context */ +@@ -278,6 +292,7 @@ + + uint32_t sw_subchannel[8]; + ++ struct nouveau_vma dispc_vma[2]; + struct { + struct nouveau_gpuobj *vblsem; + uint32_t vblsem_head; +@@ -297,7 +312,7 @@ + struct nouveau_exec_engine { + void (*destroy)(struct drm_device *, int engine); + int (*init)(struct drm_device *, int engine); +- int (*fini)(struct drm_device *, int engine); ++ int (*fini)(struct drm_device *, int engine, bool suspend); + int (*context_new)(struct nouveau_channel *, int engine); + void (*context_del)(struct nouveau_channel *, int engine); + int (*object_new)(struct nouveau_channel *, int engine, +@@ -314,7 +329,8 @@ + int (*suspend)(struct drm_device *dev); + void (*resume)(struct drm_device *dev); + +- int (*get)(struct nouveau_gpuobj *, u32 size, u32 align); ++ int (*get)(struct nouveau_gpuobj *, struct nouveau_channel *, ++ u32 size, u32 align); + void (*put)(struct nouveau_gpuobj *); + int (*map)(struct nouveau_gpuobj *); + void (*unmap)(struct nouveau_gpuobj *); +@@ -398,12 +414,13 @@ + }; + + struct nouveau_pm_voltage_level { +- u8 voltage; +- u8 vid; ++ u32 voltage; /* microvolts */ ++ u8 vid; + }; + + struct nouveau_pm_voltage { + bool supported; ++ u8 version; + u8 vid_mask; + + struct nouveau_pm_voltage_level *level; +@@ -412,17 +429,48 @@ + + struct nouveau_pm_memtiming { + int id; +- u32 reg_100220; +- u32 reg_100224; +- u32 reg_100228; +- u32 reg_10022c; +- u32 reg_100230; +- u32 reg_100234; +- u32 reg_100238; +- u32 reg_10023c; +- u32 reg_100240; ++ u32 reg_0; /* 0x10f290 on Fermi, 0x100220 for older */ ++ u32 reg_1; ++ u32 reg_2; ++ u32 reg_3; ++ u32 reg_4; ++ u32 reg_5; ++ u32 reg_6; ++ u32 reg_7; ++ u32 reg_8; ++ /* To be written to 0x1002c0 */ ++ u8 CL; ++ u8 WR; ++}; ++ ++struct nouveau_pm_tbl_header{ ++ u8 version; ++ u8 header_len; ++ u8 entry_cnt; ++ u8 entry_len; ++}; ++ ++struct nouveau_pm_tbl_entry{ ++ u8 tWR; ++ u8 tUNK_1; ++ u8 tCL; ++ u8 tRP; /* Byte 3 */ ++ u8 empty_4; ++ u8 tRAS; /* Byte 5 */ ++ u8 empty_6; ++ u8 tRFC; /* Byte 7 */ ++ u8 empty_8; ++ u8 tRC; /* Byte 9 */ ++ u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; ++ u8 empty_15,empty_16,empty_17; ++ u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; + }; + ++/* nouveau_mem.c */ ++void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, ++ struct nouveau_pm_memtiming *timing); ++ + #define NOUVEAU_PM_MAX_LEVEL 8 + struct nouveau_pm_level { + struct device_attribute dev_attr; +@@ -432,11 +480,19 @@ + u32 core; + u32 memory; + u32 shader; +- u32 unk05; +- u32 unk0a; +- +- u8 voltage; +- u8 fanspeed; ++ u32 rop; ++ u32 copy; ++ u32 daemon; ++ u32 vdec; ++ u32 unk05; /* nv50:nva3, roughly.. */ ++ u32 unka0; /* nva3:nvc0 */ ++ u32 hub01; /* nvc0- */ ++ u32 hub06; /* nvc0- */ ++ u32 hub07; /* nvc0- */ ++ ++ u32 volt_min; /* microvolts */ ++ u32 volt_max; ++ u8 fanspeed; + + u16 memscript; + struct nouveau_pm_memtiming *timing; +@@ -445,9 +501,9 @@ + struct nouveau_pm_temp_sensor_constants { + u16 offset_constant; + s16 offset_mult; +- u16 offset_div; +- u16 slope_mult; +- u16 slope_div; ++ s16 offset_div; ++ s16 slope_mult; ++ s16 slope_div; + }; + + struct nouveau_pm_threshold_temp { +@@ -480,6 +536,11 @@ + void *(*clock_pre)(struct drm_device *, struct nouveau_pm_level *, + u32 id, int khz); + void (*clock_set)(struct drm_device *, void *); ++ ++ int (*clocks_get)(struct drm_device *, struct nouveau_pm_level *); ++ void *(*clocks_pre)(struct drm_device *, struct nouveau_pm_level *); ++ void (*clocks_set)(struct drm_device *, void *); ++ + int (*voltage_get)(struct drm_device *); + int (*voltage_set)(struct drm_device *, int voltage); + int (*fanspeed_get)(struct drm_device *); +@@ -488,7 +549,10 @@ + }; + + struct nouveau_vram_engine { ++ struct nouveau_mm mm; ++ + int (*init)(struct drm_device *); ++ void (*takedown)(struct drm_device *dev); + int (*get)(struct drm_device *, u64, u32 align, u32 size_nc, + u32 type, struct nouveau_mem **); + void (*put)(struct drm_device *, struct nouveau_mem **); +@@ -604,17 +668,19 @@ + NV_40 = 0x40, + NV_50 = 0x50, + NV_C0 = 0xc0, ++ NV_D0 = 0xd0 + }; + + struct drm_nouveau_private { + struct drm_device *dev; ++ bool noaccel; + + /* the card type, takes NV_* as values */ + enum nouveau_card_type card_type; + /* exact chipset, derived from NV_PMC_BOOT_0 */ + int chipset; +- int stepping; + int flags; ++ u32 crystal; + + void __iomem *mmio; + +@@ -700,9 +766,7 @@ + /* VRAM/fb configuration */ + uint64_t vram_size; + uint64_t vram_sys_base; +- u32 vram_rblock_size; + +- uint64_t fb_phys; + uint64_t fb_available_size; + uint64_t fb_mappable_pages; + uint64_t fb_aper_free; +@@ -765,6 +829,7 @@ + } + + /* nouveau_drv.c */ ++extern int nouveau_modeset; + extern int nouveau_agpmode; + extern int nouveau_duallink; + extern int nouveau_uscript_lvds; +@@ -784,12 +849,15 @@ + extern char *nouveau_perflvl; + extern int nouveau_perflvl_wr; + extern int nouveau_msi; ++extern int nouveau_ctxfw; + + extern int nouveau_pci_suspend(struct pci_dev *pdev, pm_message_t pm_state); + extern int nouveau_pci_resume(struct pci_dev *pdev); + + /* nouveau_state.c */ ++extern int nouveau_open(struct drm_device *, struct drm_file *); + extern void nouveau_preclose(struct drm_device *dev, struct drm_file *); ++extern void nouveau_postclose(struct drm_device *, struct drm_file *); + extern int nouveau_load(struct drm_device *, unsigned long flags); + extern int nouveau_firstopen(struct drm_device *); + extern void nouveau_lastclose(struct drm_device *); +@@ -802,6 +870,8 @@ + 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_cb(struct drm_device *, u64 timeout, ++ bool (*cond)(void *), void *); + extern bool nouveau_wait_for_idle(struct drm_device *); + extern int nouveau_card_init(struct drm_device *); + +@@ -847,7 +917,7 @@ + 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); ++nouveau_channel_get(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, +@@ -1000,7 +1070,7 @@ + extern void nouveau_bios_takedown(struct drm_device *dev); + extern int nouveau_run_vbios_init(struct drm_device *); + extern void nouveau_bios_run_init_table(struct drm_device *, uint16_t table, +- struct dcb_entry *); ++ struct dcb_entry *, int crtc); + extern struct dcb_gpio_entry *nouveau_bios_gpio_entry(struct drm_device *, + enum dcb_gpio_tag); + extern struct dcb_connector_table_entry * +@@ -1008,9 +1078,8 @@ + extern u32 get_pll_register(struct drm_device *, enum pll_types); + extern int get_pll_limits(struct drm_device *, uint32_t limit_match, + struct pll_lims *); +-extern int nouveau_bios_run_display_table(struct drm_device *, +- struct dcb_entry *, +- uint32_t script, int pxclk); ++extern int nouveau_bios_run_display_table(struct drm_device *, u16 id, int clk, ++ struct dcb_entry *, int crtc); + extern void *nouveau_bios_dp_table(struct drm_device *, struct dcb_entry *, + int *length); + extern bool nouveau_bios_fp_mode(struct drm_device *, struct drm_display_mode *); +@@ -1120,7 +1189,6 @@ + + /* nv04_graph.c */ + extern int nv04_graph_create(struct drm_device *); +-extern void nv04_graph_fifo_access(struct drm_device *, bool); + extern int nv04_graph_object_new(struct nouveau_channel *, int, u32, u16); + extern int nv04_graph_mthd_page_flip(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data); +@@ -1158,8 +1226,8 @@ + /* nvc0_copy.c */ + extern int nvc0_copy_create(struct drm_device *dev, int engine); + +-/* nv40_mpeg.c */ +-extern int nv40_mpeg_create(struct drm_device *dev); ++/* nv31_mpeg.c */ ++extern int nv31_mpeg_create(struct drm_device *dev); + + /* nv50_mpeg.c */ + extern int nv50_mpeg_create(struct drm_device *dev); +@@ -1169,7 +1237,8 @@ + 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_get(struct nouveau_gpuobj *, u32 size, u32 align); ++extern int nv04_instmem_get(struct nouveau_gpuobj *, struct nouveau_channel *, ++ 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 *); +@@ -1180,7 +1249,8 @@ + 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_get(struct nouveau_gpuobj *, u32 size, u32 align); ++extern int nv50_instmem_get(struct nouveau_gpuobj *, struct nouveau_channel *, ++ 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 *); +@@ -1242,15 +1312,19 @@ + extern int nv04_display_init(struct drm_device *); + extern void nv04_display_destroy(struct drm_device *); + ++/* nvd0_display.c */ ++extern int nvd0_display_create(struct drm_device *); ++extern int nvd0_display_init(struct drm_device *); ++extern void nvd0_display_destroy(struct drm_device *); ++ + /* nv04_crtc.c */ + extern int nv04_crtc_create(struct drm_device *, int index); + + /* nouveau_bo.c */ + extern struct ttm_bo_driver nouveau_bo_driver; +-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, +- struct nouveau_bo **); ++extern int nouveau_bo_new(struct drm_device *, int size, int align, ++ uint32_t flags, uint32_t tile_mode, ++ uint32_t tile_flags, 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 *); +@@ -1265,6 +1339,12 @@ + extern int nouveau_bo_validate(struct nouveau_bo *, bool interruptible, + bool no_wait_reserve, bool no_wait_gpu); + ++extern struct nouveau_vma * ++nouveau_bo_vma_find(struct nouveau_bo *, struct nouveau_vm *); ++extern int nouveau_bo_vma_add(struct nouveau_bo *, struct nouveau_vm *, ++ struct nouveau_vma *); ++extern void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *); ++ + /* nouveau_fence.c */ + struct nouveau_fence; + extern int nouveau_fence_init(struct drm_device *); +@@ -1310,12 +1390,14 @@ + } + + /* nouveau_gem.c */ +-extern int nouveau_gem_new(struct drm_device *, struct nouveau_channel *, +- int size, int align, uint32_t domain, +- uint32_t tile_mode, uint32_t tile_flags, +- struct nouveau_bo **); ++extern int nouveau_gem_new(struct drm_device *, int size, int align, ++ uint32_t domain, uint32_t tile_mode, ++ uint32_t tile_flags, 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_object_open(struct drm_gem_object *, struct drm_file *); ++extern void nouveau_gem_object_close(struct drm_gem_object *, ++ struct drm_file *); + extern int nouveau_gem_ioctl_new(struct drm_device *, void *, + struct drm_file *); + extern int nouveau_gem_ioctl_pushbuf(struct drm_device *, void *, +@@ -1344,6 +1426,8 @@ + 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); ++int nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag); ++int nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state); + 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, +@@ -1418,6 +1502,8 @@ + nouveau_wait_eq(dev, 2000000000ULL, (reg), (mask), (val)) + #define nv_wait_ne(dev, reg, mask, val) \ + nouveau_wait_ne(dev, 2000000000ULL, (reg), (mask), (val)) ++#define nv_wait_cb(dev, func, data) \ ++ nouveau_wait_cb(dev, 2000000000ULL, (func), (data)) + + /* PRAMIN access */ + static inline u32 nv_ri32(struct drm_device *dev, unsigned offset) +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_fbcon.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_fbcon.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_fbcon.c 2011-07-26 07:03:44.416050884 +0200 +@@ -279,6 +279,7 @@ + struct fb_info *info; + struct drm_framebuffer *fb; + struct nouveau_framebuffer *nouveau_fb; ++ struct nouveau_channel *chan; + struct nouveau_bo *nvbo; + struct drm_mode_fb_cmd mode_cmd; + struct pci_dev *pdev = dev->pdev; +@@ -296,8 +297,8 @@ + size = mode_cmd.pitch * mode_cmd.height; + size = roundup(size, PAGE_SIZE); + +- ret = nouveau_gem_new(dev, dev_priv->channel, size, 0, +- NOUVEAU_GEM_DOMAIN_VRAM, 0, 0x0000, &nvbo); ++ ret = nouveau_gem_new(dev, size, 0, NOUVEAU_GEM_DOMAIN_VRAM, ++ 0, 0x0000, &nvbo); + if (ret) { + NV_ERROR(dev, "failed to allocate framebuffer\n"); + goto out; +@@ -318,6 +319,15 @@ + goto out; + } + ++ chan = nouveau_nofbaccel ? NULL : dev_priv->channel; ++ if (chan && dev_priv->card_type >= NV_50) { ++ ret = nouveau_bo_vma_add(nvbo, chan->vm, &nfbdev->nouveau_fb.vma); ++ if (ret) { ++ NV_ERROR(dev, "failed to map fb into chan: %d\n", ret); ++ chan = NULL; ++ } ++ } ++ + mutex_lock(&dev->struct_mutex); + + info = framebuffer_alloc(0, device); +@@ -448,6 +458,7 @@ + + if (nouveau_fb->nvbo) { + nouveau_bo_unmap(nouveau_fb->nvbo); ++ nouveau_bo_vma_del(nouveau_fb->nvbo, &nouveau_fb->vma); + drm_gem_object_unreference_unlocked(nouveau_fb->nvbo->gem); + nouveau_fb->nvbo = NULL; + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_fb.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_fb.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_fb.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_fb.h 2011-07-26 07:03:44.416050884 +0200 +@@ -30,6 +30,7 @@ + struct nouveau_framebuffer { + struct drm_framebuffer base; + struct nouveau_bo *nvbo; ++ struct nouveau_vma vma; + u32 r_dma; + u32 r_format; + u32 r_pitch; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_fence.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_fence.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_fence.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_fence.c 2011-07-26 07:03:44.417050896 +0200 +@@ -336,6 +336,7 @@ + { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nouveau_fence *fence = NULL; ++ u64 offset = chan->fence.vma.offset + sema->mem->start; + int ret; + + if (dev_priv->chipset < 0x84) { +@@ -345,13 +346,10 @@ + + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 3); + OUT_RING (chan, NvSema); +- OUT_RING (chan, sema->mem->start); ++ OUT_RING (chan, offset); + 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, 7); + if (ret) + return ret; +@@ -364,9 +362,6 @@ + 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; +@@ -394,6 +389,7 @@ + { + struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct nouveau_fence *fence = NULL; ++ u64 offset = chan->fence.vma.offset + sema->mem->start; + int ret; + + if (dev_priv->chipset < 0x84) { +@@ -403,14 +399,11 @@ + + BEGIN_RING(chan, NvSubSw, NV_SW_DMA_SEMAPHORE, 2); + OUT_RING (chan, NvSema); +- OUT_RING (chan, sema->mem->start); ++ OUT_RING (chan, offset); + 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, 7); + if (ret) + return ret; +@@ -423,9 +416,6 @@ + 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; +@@ -529,7 +519,7 @@ + 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, ++ ret = nouveau_gpuobj_dma_new(chan, NV_CLASS_DMA_FROM_MEMORY, + mem->start << PAGE_SHIFT, + mem->size, NV_MEM_ACCESS_RW, + NV_MEM_TARGET_VRAM, &obj); +@@ -540,6 +530,12 @@ + nouveau_gpuobj_ref(NULL, &obj); + if (ret) + return ret; ++ } else { ++ /* map fence bo into channel's vm */ ++ ret = nouveau_bo_vma_add(dev_priv->fence.bo, chan->vm, ++ &chan->fence.vma); ++ if (ret) ++ return ret; + } + + INIT_LIST_HEAD(&chan->fence.pending); +@@ -551,10 +547,10 @@ + void + nouveau_fence_channel_fini(struct nouveau_channel *chan) + { ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + 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); +@@ -564,8 +560,9 @@ + + kref_put(&fence->refcount, nouveau_fence_del); + } +- + spin_unlock(&chan->fence.lock); ++ ++ nouveau_bo_vma_del(dev_priv->fence.bo, &chan->fence.vma); + } + + int +@@ -577,7 +574,7 @@ + + /* Create a shared VRAM heap for cross-channel sync. */ + if (USE_SEMA(dev)) { +- ret = nouveau_bo_new(dev, NULL, size, 0, TTM_PL_FLAG_VRAM, ++ ret = nouveau_bo_new(dev, size, 0, TTM_PL_FLAG_VRAM, + 0, 0, &dev_priv->fence.bo); + if (ret) + return ret; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_gem.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_gem.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_gem.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_gem.c 2011-07-26 07:03:44.418050908 +0200 +@@ -60,9 +60,71 @@ + } + + int +-nouveau_gem_new(struct drm_device *dev, struct nouveau_channel *chan, +- int size, int align, uint32_t domain, uint32_t tile_mode, +- uint32_t tile_flags, struct nouveau_bo **pnvbo) ++nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv) ++{ ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); ++ struct nouveau_bo *nvbo = nouveau_gem_object(gem); ++ struct nouveau_vma *vma; ++ int ret; ++ ++ if (!fpriv->vm) ++ return 0; ++ ++ ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0); ++ if (ret) ++ return ret; ++ ++ vma = nouveau_bo_vma_find(nvbo, fpriv->vm); ++ if (!vma) { ++ vma = kzalloc(sizeof(*vma), GFP_KERNEL); ++ if (!vma) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = nouveau_bo_vma_add(nvbo, fpriv->vm, vma); ++ if (ret) { ++ kfree(vma); ++ goto out; ++ } ++ } else { ++ vma->refcount++; ++ } ++ ++out: ++ ttm_bo_unreserve(&nvbo->bo); ++ return ret; ++} ++ ++void ++nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv) ++{ ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); ++ struct nouveau_bo *nvbo = nouveau_gem_object(gem); ++ struct nouveau_vma *vma; ++ int ret; ++ ++ if (!fpriv->vm) ++ return; ++ ++ ret = ttm_bo_reserve(&nvbo->bo, false, false, false, 0); ++ if (ret) ++ return; ++ ++ vma = nouveau_bo_vma_find(nvbo, fpriv->vm); ++ if (vma) { ++ if (--vma->refcount == 0) { ++ nouveau_bo_vma_del(nvbo, vma); ++ kfree(vma); ++ } ++ } ++ ttm_bo_unreserve(&nvbo->bo); ++} ++ ++int ++nouveau_gem_new(struct drm_device *dev, 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; +@@ -76,7 +138,7 @@ + if (!flags || domain & NOUVEAU_GEM_DOMAIN_CPU) + flags |= TTM_PL_FLAG_SYSTEM; + +- ret = nouveau_bo_new(dev, chan, size, align, flags, tile_mode, ++ ret = nouveau_bo_new(dev, size, align, flags, tile_mode, + tile_flags, pnvbo); + if (ret) + return ret; +@@ -103,17 +165,28 @@ + } + + static int +-nouveau_gem_info(struct drm_gem_object *gem, struct drm_nouveau_gem_info *rep) ++nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem, ++ struct drm_nouveau_gem_info *rep) + { ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); + struct nouveau_bo *nvbo = nouveau_gem_object(gem); ++ struct nouveau_vma *vma; + + if (nvbo->bo.mem.mem_type == TTM_PL_TT) + rep->domain = NOUVEAU_GEM_DOMAIN_GART; + else + rep->domain = NOUVEAU_GEM_DOMAIN_VRAM; + +- rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; + rep->offset = nvbo->bo.offset; ++ if (fpriv->vm) { ++ vma = nouveau_bo_vma_find(nvbo, fpriv->vm); ++ if (!vma) ++ return -EINVAL; ++ ++ rep->offset = vma->offset; ++ } ++ ++ rep->size = nvbo->bo.mem.num_pages << PAGE_SHIFT; + rep->map_handle = nvbo->bo.addr_space_offset; + rep->tile_mode = nvbo->tile_mode; + rep->tile_flags = nvbo->tile_flags; +@@ -127,7 +200,6 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct drm_nouveau_gem_new *req = data; + struct nouveau_bo *nvbo = NULL; +- struct nouveau_channel *chan = NULL; + int ret = 0; + + if (unlikely(dev_priv->ttm.bdev.dev_mapping == NULL)) +@@ -138,28 +210,21 @@ + 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, ++ ret = nouveau_gem_new(dev, 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) + return ret; + +- ret = nouveau_gem_info(nvbo->gem, &req->info); +- if (ret) +- goto out; +- + ret = drm_gem_handle_create(file_priv, nvbo->gem, &req->info.handle); ++ if (ret == 0) { ++ ret = nouveau_gem_info(file_priv, nvbo->gem, &req->info); ++ if (ret) ++ drm_gem_handle_delete(file_priv, req->info.handle); ++ } ++ + /* drop reference from allocate - handle holds it now */ + drm_gem_object_unreference_unlocked(nvbo->gem); +-out: + return ret; + } + +@@ -318,6 +383,7 @@ + validate_list(struct nouveau_channel *chan, struct list_head *list, + struct drm_nouveau_gem_pushbuf_bo *pbbo, uint64_t user_pbbo_ptr) + { ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; + struct drm_nouveau_gem_pushbuf_bo __user *upbbo = + (void __force __user *)(uintptr_t)user_pbbo_ptr; + struct drm_device *dev = chan->dev; +@@ -356,24 +422,26 @@ + return ret; + } + +- if (nvbo->bo.offset == b->presumed.offset && +- ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && +- b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || +- (nvbo->bo.mem.mem_type == TTM_PL_TT && +- b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART))) +- continue; ++ if (dev_priv->card_type < NV_50) { ++ if (nvbo->bo.offset == b->presumed.offset && ++ ((nvbo->bo.mem.mem_type == TTM_PL_VRAM && ++ b->presumed.domain & NOUVEAU_GEM_DOMAIN_VRAM) || ++ (nvbo->bo.mem.mem_type == TTM_PL_TT && ++ b->presumed.domain & NOUVEAU_GEM_DOMAIN_GART))) ++ continue; + +- if (nvbo->bo.mem.mem_type == TTM_PL_TT) +- b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; +- else +- b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM; +- b->presumed.offset = nvbo->bo.offset; +- b->presumed.valid = 0; +- relocs++; +- +- if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed, +- &b->presumed, sizeof(b->presumed))) +- return -EFAULT; ++ if (nvbo->bo.mem.mem_type == TTM_PL_TT) ++ b->presumed.domain = NOUVEAU_GEM_DOMAIN_GART; ++ else ++ b->presumed.domain = NOUVEAU_GEM_DOMAIN_VRAM; ++ b->presumed.offset = nvbo->bo.offset; ++ b->presumed.valid = 0; ++ relocs++; ++ ++ if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed, ++ &b->presumed, sizeof(b->presumed))) ++ return -EFAULT; ++ } + } + + return relocs; +@@ -548,7 +616,7 @@ + struct nouveau_fence *fence = NULL; + int i, j, ret = 0, do_reloc = 0; + +- chan = nouveau_channel_get(dev, file_priv, req->channel); ++ chan = nouveau_channel_get(file_priv, req->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); + +@@ -782,7 +850,7 @@ + if (!gem) + return -ENOENT; + +- ret = nouveau_gem_info(gem, req); ++ ret = nouveau_gem_info(file_priv, gem, req); + drm_gem_object_unreference_unlocked(gem); + return ret; + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_i2c.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_i2c.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_i2c.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_i2c.c 2011-07-26 07:03:44.444051220 +0200 +@@ -107,6 +107,13 @@ + return !!((nv_rd32(dev, i2c->rd) >> 16) & 8); + } + ++static const uint32_t nv50_i2c_port[] = { ++ 0x00e138, 0x00e150, 0x00e168, 0x00e180, ++ 0x00e254, 0x00e274, 0x00e764, 0x00e780, ++ 0x00e79c, 0x00e7b8 ++}; ++#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) ++ + static int + nv50_i2c_getscl(void *data) + { +@@ -130,28 +137,32 @@ + nv50_i2c_setscl(void *data, int state) + { + struct nouveau_i2c_chan *i2c = data; +- struct drm_device *dev = i2c->dev; + +- nv_wr32(dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); ++ nv_wr32(i2c->dev, i2c->wr, 4 | (i2c->data ? 2 : 0) | (state ? 1 : 0)); + } + + static void + nv50_i2c_setsda(void *data, int state) + { + struct nouveau_i2c_chan *i2c = data; +- struct drm_device *dev = i2c->dev; + +- nv_wr32(dev, i2c->wr, +- (nv_rd32(dev, i2c->rd) & 1) | 4 | (state ? 2 : 0)); ++ nv_mask(i2c->dev, i2c->wr, 0x00000006, 4 | (state ? 2 : 0)); + i2c->data = state; + } + +-static const uint32_t nv50_i2c_port[] = { +- 0x00e138, 0x00e150, 0x00e168, 0x00e180, +- 0x00e254, 0x00e274, 0x00e764, 0x00e780, +- 0x00e79c, 0x00e7b8 +-}; +-#define NV50_I2C_PORTS ARRAY_SIZE(nv50_i2c_port) ++static int ++nvd0_i2c_getscl(void *data) ++{ ++ struct nouveau_i2c_chan *i2c = data; ++ return !!(nv_rd32(i2c->dev, i2c->rd) & 0x10); ++} ++ ++static int ++nvd0_i2c_getsda(void *data) ++{ ++ struct nouveau_i2c_chan *i2c = data; ++ return !!(nv_rd32(i2c->dev, i2c->rd) & 0x20); ++} + + int + nouveau_i2c_init(struct drm_device *dev, struct dcb_i2c_entry *entry, int index) +@@ -163,7 +174,8 @@ + if (entry->chan) + return -EEXIST; + +- if (dev_priv->card_type >= NV_50 && entry->read >= NV50_I2C_PORTS) { ++ if (dev_priv->card_type >= NV_50 && ++ dev_priv->card_type <= NV_C0 && entry->read >= NV50_I2C_PORTS) { + NV_ERROR(dev, "unknown i2c port %d\n", entry->read); + return -EINVAL; + } +@@ -192,10 +204,17 @@ + case 5: + i2c->bit.setsda = nv50_i2c_setsda; + i2c->bit.setscl = nv50_i2c_setscl; +- i2c->bit.getsda = nv50_i2c_getsda; +- i2c->bit.getscl = nv50_i2c_getscl; +- i2c->rd = nv50_i2c_port[entry->read]; +- i2c->wr = i2c->rd; ++ if (dev_priv->card_type < NV_D0) { ++ i2c->bit.getsda = nv50_i2c_getsda; ++ i2c->bit.getscl = nv50_i2c_getscl; ++ i2c->rd = nv50_i2c_port[entry->read]; ++ i2c->wr = i2c->rd; ++ } else { ++ i2c->bit.getsda = nvd0_i2c_getsda; ++ i2c->bit.getscl = nvd0_i2c_getscl; ++ i2c->rd = 0x00d014 + (entry->read * 0x20); ++ i2c->wr = i2c->rd; ++ } + break; + case 6: + i2c->rd = entry->read; +@@ -267,7 +286,10 @@ + val = 0xe001; + } + +- nv_wr32(dev, reg, (nv_rd32(dev, reg) & ~0xf003) | val); ++ /* nfi, but neither auxch or i2c work if it's 1 */ ++ nv_mask(dev, reg + 0x0c, 0x00000001, 0x00000000); ++ /* nfi, but switches auxch vs normal i2c */ ++ nv_mask(dev, reg + 0x00, 0x0000f003, val); + } + + if (!i2c->chan && nouveau_i2c_init(dev, i2c, index)) +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_irq.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_irq.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_irq.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_irq.c 2011-07-26 07:03:44.445051232 +0200 +@@ -79,7 +79,7 @@ + int i; + + stat = nv_rd32(dev, NV03_PMC_INTR_0); +- if (!stat) ++ if (stat == 0 || stat == ~0) + return IRQ_NONE; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_mem.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_mem.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_mem.c 2011-07-26 07:03:44.446051244 +0200 +@@ -408,8 +408,6 @@ + if (ret) + return ret; + +- dev_priv->fb_phys = pci_resource_start(dev->pdev, 1); +- + ret = nouveau_ttm_global_init(dev_priv); + if (ret) + return ret; +@@ -423,38 +421,6 @@ + return ret; + } + +- /* reserve space at end of VRAM for PRAMIN */ +- if (dev_priv->card_type >= NV_50) { +- dev_priv->ramin_rsvd_vram = 1 * 1024 * 1024; +- } else +- if (dev_priv->card_type >= NV_40) { +- u32 vs = hweight8((nv_rd32(dev, 0x001540) & 0x0000ff00) >> 8); +- u32 rsvd; +- +- /* estimate grctx size, the magics come from nv40_grctx.c */ +- if (dev_priv->chipset == 0x40) rsvd = 0x6aa0 * vs; +- else if (dev_priv->chipset < 0x43) rsvd = 0x4f00 * vs; +- else if (nv44_graph_class(dev)) rsvd = 0x4980 * vs; +- else rsvd = 0x4a40 * vs; +- rsvd += 16 * 1024; +- rsvd *= dev_priv->engine.fifo.channels; +- +- /* pciegart table */ +- if (drm_pci_device_is_pcie(dev)) +- rsvd += 512 * 1024; +- +- /* object storage */ +- rsvd += 512 * 1024; +- +- dev_priv->ramin_rsvd_vram = round_up(rsvd, 4096); +- } 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", +@@ -479,7 +445,7 @@ + } + + if (dev_priv->card_type < NV_50) { +- ret = nouveau_bo_new(dev, NULL, 256*1024, 0, TTM_PL_FLAG_VRAM, ++ ret = nouveau_bo_new(dev, 256*1024, 0, TTM_PL_FLAG_VRAM, + 0, 0, &dev_priv->vga_ram); + if (ret == 0) + ret = nouveau_bo_pin(dev_priv->vga_ram, +@@ -536,35 +502,146 @@ + return 0; + } + ++/* XXX: For now a dummy. More samples required, possibly even a card ++ * Called from nouveau_perf.c */ ++void nv30_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, ++ struct nouveau_pm_memtiming *timing) { ++ ++ NV_DEBUG(dev,"Timing entry format unknown, please contact nouveau developers"); ++} ++ ++void nv40_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number, ++ struct nouveau_pm_memtiming *timing) { ++ ++ timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); ++ ++ /* XXX: I don't trust the -1's and +1's... they must come ++ * from somewhere! */ ++ timing->reg_1 = (e->tWR + 2 + magic_number) << 24 | ++ 1 << 16 | ++ (e->tUNK_1 + 2 + magic_number) << 8 | ++ (e->tCL + 2 - magic_number); ++ timing->reg_2 = (magic_number << 24 | e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); ++ timing->reg_2 |= 0x20200000; ++ ++ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x\n", timing->id, ++ timing->reg_0, timing->reg_1,timing->reg_2); ++} ++ ++void nv50_mem_timing_entry(struct drm_device *dev, struct bit_entry *P, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, uint8_t magic_number,struct nouveau_pm_memtiming *timing) { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ uint8_t unk18 = 1, ++ unk19 = 1, ++ unk20 = 0, ++ unk21 = 0; ++ ++ switch (min(hdr->entry_len, (u8) 22)) { ++ case 22: ++ unk21 = e->tUNK_21; ++ case 21: ++ unk20 = e->tUNK_20; ++ case 20: ++ unk19 = e->tUNK_19; ++ case 19: ++ unk18 = e->tUNK_18; ++ break; ++ } ++ ++ timing->reg_0 = (e->tRC << 24 | e->tRFC << 16 | e->tRAS << 8 | e->tRP); ++ ++ /* XXX: I don't trust the -1's and +1's... they must come ++ * from somewhere! */ ++ timing->reg_1 = (e->tWR + unk19 + 1 + magic_number) << 24 | ++ max(unk18, (u8) 1) << 16 | ++ (e->tUNK_1 + unk19 + 1 + magic_number) << 8; ++ if (dev_priv->chipset == 0xa8) { ++ timing->reg_1 |= (e->tCL - 1); ++ } else { ++ timing->reg_1 |= (e->tCL + 2 - magic_number); ++ } ++ timing->reg_2 = (e->tUNK_12 << 16 | e->tUNK_11 << 8 | e->tUNK_10); ++ ++ timing->reg_5 = (e->tRAS << 24 | e->tRC); ++ timing->reg_5 += max(e->tUNK_10, e->tUNK_11) << 16; ++ ++ if (P->version == 1) { ++ timing->reg_2 |= magic_number << 24; ++ timing->reg_3 = (0x14 + e->tCL) << 24 | ++ 0x16 << 16 | ++ (e->tCL - 1) << 8 | ++ (e->tCL - 1); ++ timing->reg_4 = (nv_rd32(dev,0x10022c) & 0xffff0000) | e->tUNK_13 << 8 | e->tUNK_13; ++ timing->reg_5 |= (e->tCL + 2) << 8; ++ timing->reg_7 = 0x4000202 | (e->tCL - 1) << 16; ++ } else { ++ timing->reg_2 |= (unk19 - 1) << 24; ++ /* XXX: reg_10022c for recentish cards pretty much unknown*/ ++ timing->reg_3 = e->tCL - 1; ++ timing->reg_4 = (unk20 << 24 | unk21 << 16 | ++ e->tUNK_13 << 8 | e->tUNK_13); ++ /* XXX: +6? */ ++ timing->reg_5 |= (unk19 + 6) << 8; ++ ++ /* XXX: reg_10023c currently unknown ++ * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ ++ timing->reg_7 = 0x202; ++ } ++ ++ NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", timing->id, ++ timing->reg_0, timing->reg_1, ++ timing->reg_2, timing->reg_3); ++ NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", ++ timing->reg_4, timing->reg_5, ++ timing->reg_6, timing->reg_7); ++ NV_DEBUG(dev, " 240: %08x\n", timing->reg_8); ++} ++ ++void nvc0_mem_timing_entry(struct drm_device *dev, struct nouveau_pm_tbl_header *hdr, ++ struct nouveau_pm_tbl_entry *e, struct nouveau_pm_memtiming *timing) { ++ timing->reg_0 = (e->tRC << 24 | (e->tRFC & 0x7f) << 17 | e->tRAS << 8 | e->tRP); ++ timing->reg_1 = (nv_rd32(dev,0x10f294) & 0xff000000) | (e->tUNK_11&0x0f) << 20 | (e->tUNK_19 << 7) | (e->tCL & 0x0f); ++ timing->reg_2 = (nv_rd32(dev,0x10f298) & 0xff0000ff) | e->tWR << 16 | e->tUNK_1 << 8; ++ timing->reg_3 = e->tUNK_20 << 9 | e->tUNK_13; ++ timing->reg_4 = (nv_rd32(dev,0x10f2a0) & 0xfff000ff) | e->tUNK_12 << 15; ++ NV_DEBUG(dev, "Entry %d: 290: %08x %08x %08x %08x\n", timing->id, ++ timing->reg_0, timing->reg_1, ++ timing->reg_2, timing->reg_3); ++ NV_DEBUG(dev, " 2a0: %08x %08x %08x %08x\n", ++ timing->reg_4, timing->reg_5, ++ timing->reg_6, timing->reg_7); ++} ++ ++/** ++ * Processes the Memory Timing BIOS table, stores generated ++ * register values ++ * @pre init scripts were run, memtiming regs are initialized ++ */ + void + nouveau_mem_timing_init(struct drm_device *dev) + { +- /* cards < NVC0 only */ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm_memtimings *memtimings = &pm->memtimings; + struct nvbios *bios = &dev_priv->vbios; + struct bit_entry P; +- u8 tUNK_0, tUNK_1, tUNK_2; +- u8 tRP; /* Byte 3 */ +- u8 tRAS; /* Byte 5 */ +- u8 tRFC; /* Byte 7 */ +- u8 tRC; /* Byte 9 */ +- u8 tUNK_10, tUNK_11, tUNK_12, tUNK_13, tUNK_14; +- u8 tUNK_18, tUNK_19, tUNK_20, tUNK_21; +- u8 magic_number = 0; /* Yeah... sorry*/ +- u8 *mem = NULL, *entry; +- int i, recordlen, entries; ++ struct nouveau_pm_tbl_header *hdr = NULL; ++ uint8_t magic_number; ++ u8 *entry; ++ int i; + + if (bios->type == NVBIOS_BIT) { + if (bit_table(dev, 'P', &P)) + return; + + if (P.version == 1) +- mem = ROMPTR(bios, P.data[4]); ++ hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[4]); + else + if (P.version == 2) +- mem = ROMPTR(bios, P.data[8]); ++ hdr = (struct nouveau_pm_tbl_header *) ROMPTR(bios, P.data[8]); + else { + NV_WARN(dev, "unknown mem for BIT P %d\n", P.version); + } +@@ -573,150 +650,56 @@ + return; + } + +- if (!mem) { ++ if (!hdr) { + NV_DEBUG(dev, "memory timing table pointer invalid\n"); + return; + } + +- if (mem[0] != 0x10) { +- NV_WARN(dev, "memory timing table 0x%02x unknown\n", mem[0]); ++ if (hdr->version != 0x10) { ++ NV_WARN(dev, "memory timing table 0x%02x unknown\n", hdr->version); + return; + } + + /* validate record length */ +- entries = mem[2]; +- recordlen = mem[3]; +- if (recordlen < 15) { +- NV_ERROR(dev, "mem timing table length unknown: %d\n", mem[3]); ++ if (hdr->entry_len < 15) { ++ NV_ERROR(dev, "mem timing table length unknown: %d\n", hdr->entry_len); + return; + } + + /* parse vbios entries into common format */ + memtimings->timing = +- kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); ++ kcalloc(hdr->entry_cnt, sizeof(*memtimings->timing), GFP_KERNEL); + if (!memtimings->timing) + return; + + /* Get "some number" from the timing reg for NV_40 and NV_50 +- * Used in calculations later */ +- if (dev_priv->card_type >= NV_40 && dev_priv->chipset < 0x98) { ++ * Used in calculations later... source unknown */ ++ magic_number = 0; ++ if (P.version == 1) { + magic_number = (nv_rd32(dev, 0x100228) & 0x0f000000) >> 24; + } + +- entry = mem + mem[1]; +- for (i = 0; i < entries; i++, entry += recordlen) { ++ entry = (u8*) hdr + hdr->header_len; ++ for (i = 0; i < hdr->entry_cnt; i++, entry += hdr->entry_len) { + struct nouveau_pm_memtiming *timing = &pm->memtimings.timing[i]; + if (entry[0] == 0) + continue; + +- tUNK_18 = 1; +- tUNK_19 = 1; +- tUNK_20 = 0; +- tUNK_21 = 0; +- switch (min(recordlen, 22)) { +- case 22: +- tUNK_21 = entry[21]; +- case 21: +- tUNK_20 = entry[20]; +- case 20: +- tUNK_19 = entry[19]; +- case 19: +- tUNK_18 = entry[18]; +- default: +- tUNK_0 = entry[0]; +- tUNK_1 = entry[1]; +- tUNK_2 = entry[2]; +- tRP = entry[3]; +- tRAS = entry[5]; +- tRFC = entry[7]; +- tRC = entry[9]; +- tUNK_10 = entry[10]; +- tUNK_11 = entry[11]; +- tUNK_12 = entry[12]; +- tUNK_13 = entry[13]; +- tUNK_14 = entry[14]; +- break; +- } +- +- timing->reg_100220 = (tRC << 24 | tRFC << 16 | tRAS << 8 | tRP); +- +- /* XXX: I don't trust the -1's and +1's... they must come +- * from somewhere! */ +- timing->reg_100224 = (tUNK_0 + tUNK_19 + 1 + magic_number) << 24 | +- max(tUNK_18, (u8) 1) << 16 | +- (tUNK_1 + tUNK_19 + 1 + magic_number) << 8; +- if (dev_priv->chipset == 0xa8) { +- timing->reg_100224 |= (tUNK_2 - 1); +- } else { +- timing->reg_100224 |= (tUNK_2 + 2 - magic_number); +- } +- +- timing->reg_100228 = (tUNK_12 << 16 | tUNK_11 << 8 | tUNK_10); +- if (dev_priv->chipset >= 0xa3 && dev_priv->chipset < 0xaa) +- timing->reg_100228 |= (tUNK_19 - 1) << 24; +- else +- timing->reg_100228 |= magic_number << 24; +- +- if (dev_priv->card_type == NV_40) { +- /* NV40: don't know what the rest of the regs are.. +- * And don't need to know either */ +- timing->reg_100228 |= 0x20200000; +- } else if (dev_priv->card_type >= NV_50) { +- if (dev_priv->chipset < 0x98 || +- (dev_priv->chipset == 0x98 && +- dev_priv->stepping <= 0xa1)) { +- timing->reg_10022c = (0x14 + tUNK_2) << 24 | +- 0x16 << 16 | +- (tUNK_2 - 1) << 8 | +- (tUNK_2 - 1); +- } else { +- /* XXX: reg_10022c for recentish cards */ +- timing->reg_10022c = tUNK_2 - 1; +- } +- +- timing->reg_100230 = (tUNK_20 << 24 | tUNK_21 << 16 | +- tUNK_13 << 8 | tUNK_13); +- +- timing->reg_100234 = (tRAS << 24 | tRC); +- timing->reg_100234 += max(tUNK_10, tUNK_11) << 16; +- +- if (dev_priv->chipset < 0x98 || +- (dev_priv->chipset == 0x98 && +- dev_priv->stepping <= 0xa1)) { +- timing->reg_100234 |= (tUNK_2 + 2) << 8; +- } else { +- /* XXX: +6? */ +- timing->reg_100234 |= (tUNK_19 + 6) << 8; +- } +- +- /* XXX; reg_100238 +- * reg_100238: 0x00?????? */ +- timing->reg_10023c = 0x202; +- if (dev_priv->chipset < 0x98 || +- (dev_priv->chipset == 0x98 && +- dev_priv->stepping <= 0xa1)) { +- timing->reg_10023c |= 0x4000000 | (tUNK_2 - 1) << 16; +- } else { +- /* XXX: reg_10023c +- * currently unknown +- * 10023c seen as 06xxxxxx, 0bxxxxxx or 0fxxxxxx */ +- } +- +- /* XXX: reg_100240? */ +- } + timing->id = i; ++ timing->WR = entry[0]; ++ timing->CL = entry[2]; + +- NV_DEBUG(dev, "Entry %d: 220: %08x %08x %08x %08x\n", i, +- timing->reg_100220, timing->reg_100224, +- timing->reg_100228, timing->reg_10022c); +- NV_DEBUG(dev, " 230: %08x %08x %08x %08x\n", +- timing->reg_100230, timing->reg_100234, +- timing->reg_100238, timing->reg_10023c); +- NV_DEBUG(dev, " 240: %08x\n", timing->reg_100240); ++ if(dev_priv->card_type <= NV_40) { ++ nv40_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); ++ } else if(dev_priv->card_type == NV_50){ ++ nv50_mem_timing_entry(dev,&P,hdr,(struct nouveau_pm_tbl_entry*) entry,magic_number,&pm->memtimings.timing[i]); ++ } else if(dev_priv->card_type == NV_C0) { ++ nvc0_mem_timing_entry(dev,hdr,(struct nouveau_pm_tbl_entry*) entry,&pm->memtimings.timing[i]); ++ } + } + +- memtimings->nr_timing = entries; +- memtimings->supported = (dev_priv->chipset <= 0x98); ++ memtimings->nr_timing = hdr->entry_cnt; ++ memtimings->supported = P.version == 1; + } + + void +@@ -725,41 +708,38 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_memtimings *mem = &dev_priv->engine.pm.memtimings; + +- kfree(mem->timing); ++ if(mem->timing) { ++ kfree(mem->timing); ++ mem->timing = NULL; ++ } + } + + static int +-nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long p_size) ++nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) + { +- struct drm_nouveau_private *dev_priv = nouveau_bdev(man->bdev); +- struct nouveau_mm *mm; +- u64 size, block, rsvd; +- int ret; +- +- rsvd = (256 * 1024); /* vga memory */ +- size = (p_size << PAGE_SHIFT) - rsvd; +- block = dev_priv->vram_rblock_size; +- +- ret = nouveau_mm_init(&mm, rsvd >> 12, size >> 12, block >> 12); +- if (ret) +- return ret; +- +- man->priv = mm; ++ /* nothing to do */ + return 0; + } + + static int + nouveau_vram_manager_fini(struct ttm_mem_type_manager *man) + { +- struct nouveau_mm *mm = man->priv; +- int ret; ++ /* nothing to do */ ++ return 0; ++} + +- ret = nouveau_mm_fini(&mm); +- if (ret) +- return ret; ++static inline void ++nouveau_mem_node_cleanup(struct nouveau_mem *node) ++{ ++ if (node->vma[0].node) { ++ nouveau_vm_unmap(&node->vma[0]); ++ nouveau_vm_put(&node->vma[0]); ++ } + +- man->priv = NULL; +- return 0; ++ if (node->vma[1].node) { ++ nouveau_vm_unmap(&node->vma[1]); ++ nouveau_vm_put(&node->vma[1]); ++ } + } + + static void +@@ -768,14 +748,9 @@ + { + 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; + +- if (node->tmp_vma.node) { +- nouveau_vm_unmap(&node->tmp_vma); +- nouveau_vm_put(&node->tmp_vma); +- } +- ++ nouveau_mem_node_cleanup(mem->mm_node); + vram->put(dev, (struct nouveau_mem **)&mem->mm_node); + } + +@@ -794,7 +769,7 @@ + int ret; + + if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) +- size_nc = 1 << nvbo->vma.node->type; ++ size_nc = 1 << nvbo->page_shift; + + ret = vram->get(dev, mem->num_pages << PAGE_SHIFT, + mem->page_alignment << PAGE_SHIFT, size_nc, +@@ -804,9 +779,7 @@ + return (ret == -ENOSPC) ? 0 : ret; + } + +- node->page_shift = 12; +- if (nvbo->vma.node) +- node->page_shift = nvbo->vma.node->type; ++ node->page_shift = nvbo->page_shift; + + mem->mm_node = node; + mem->start = node->offset >> PAGE_SHIFT; +@@ -862,15 +835,9 @@ + 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); +- } +- ++ nouveau_mem_node_cleanup(mem->mm_node); ++ kfree(mem->mm_node); + mem->mm_node = NULL; +- kfree(node); + } + + static int +@@ -880,11 +847,7 @@ + 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)) +@@ -893,24 +856,8 @@ + node = kzalloc(sizeof(*node), GFP_KERNEL); + if (!node) + return -ENOMEM; ++ node->page_shift = 12; + +- /* 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; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_mm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_mm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_mm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_mm.c 2011-07-26 07:03:44.447051256 +0200 +@@ -27,7 +27,7 @@ + #include "nouveau_mm.h" + + static inline void +-region_put(struct nouveau_mm *rmm, struct nouveau_mm_node *a) ++region_put(struct nouveau_mm *mm, struct nouveau_mm_node *a) + { + list_del(&a->nl_entry); + list_del(&a->fl_entry); +@@ -35,7 +35,7 @@ + } + + static struct nouveau_mm_node * +-region_split(struct nouveau_mm *rmm, struct nouveau_mm_node *a, u32 size) ++region_split(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size) + { + struct nouveau_mm_node *b; + +@@ -57,33 +57,33 @@ + return b; + } + +-#define node(root, dir) ((root)->nl_entry.dir == &rmm->nodes) ? NULL : \ ++#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ + list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry) + + void +-nouveau_mm_put(struct nouveau_mm *rmm, struct nouveau_mm_node *this) ++nouveau_mm_put(struct nouveau_mm *mm, struct nouveau_mm_node *this) + { + struct nouveau_mm_node *prev = node(this, prev); + struct nouveau_mm_node *next = node(this, next); + +- list_add(&this->fl_entry, &rmm->free); ++ list_add(&this->fl_entry, &mm->free); + this->type = 0; + + if (prev && prev->type == 0) { + prev->length += this->length; +- region_put(rmm, this); ++ region_put(mm, this); + this = prev; + } + + if (next && next->type == 0) { + next->offset = this->offset; + next->length += this->length; +- region_put(rmm, this); ++ region_put(mm, this); + } + } + + int +-nouveau_mm_get(struct nouveau_mm *rmm, int type, u32 size, u32 size_nc, ++nouveau_mm_get(struct nouveau_mm *mm, int type, u32 size, u32 size_nc, + u32 align, struct nouveau_mm_node **pnode) + { + struct nouveau_mm_node *prev, *this, *next; +@@ -92,17 +92,17 @@ + u32 splitoff; + u32 s, e; + +- list_for_each_entry(this, &rmm->free, fl_entry) { ++ list_for_each_entry(this, &mm->free, fl_entry) { + e = this->offset + this->length; + s = this->offset; + + prev = node(this, prev); + if (prev && prev->type != type) +- s = roundup(s, rmm->block_size); ++ s = roundup(s, mm->block_size); + + next = node(this, next); + if (next && next->type != type) +- e = rounddown(e, rmm->block_size); ++ e = rounddown(e, mm->block_size); + + s = (s + align_mask) & ~align_mask; + e &= ~align_mask; +@@ -110,10 +110,10 @@ + continue; + + splitoff = s - this->offset; +- if (splitoff && !region_split(rmm, this, splitoff)) ++ if (splitoff && !region_split(mm, this, splitoff)) + return -ENOMEM; + +- this = region_split(rmm, this, min(size, e - s)); ++ this = region_split(mm, this, min(size, e - s)); + if (!this) + return -ENOMEM; + +@@ -127,45 +127,49 @@ + } + + int +-nouveau_mm_init(struct nouveau_mm **prmm, u32 offset, u32 length, u32 block) ++nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block) + { +- struct nouveau_mm *rmm; +- struct nouveau_mm_node *heap; ++ struct nouveau_mm_node *node; + +- heap = kzalloc(sizeof(*heap), GFP_KERNEL); +- if (!heap) +- return -ENOMEM; +- heap->offset = roundup(offset, block); +- heap->length = rounddown(offset + length, block) - heap->offset; ++ if (block) { ++ mutex_init(&mm->mutex); ++ INIT_LIST_HEAD(&mm->nodes); ++ INIT_LIST_HEAD(&mm->free); ++ mm->block_size = block; ++ mm->heap_nodes = 0; ++ } + +- rmm = kzalloc(sizeof(*rmm), GFP_KERNEL); +- if (!rmm) { +- kfree(heap); ++ node = kzalloc(sizeof(*node), GFP_KERNEL); ++ if (!node) + 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); ++ node->offset = roundup(offset, mm->block_size); ++ node->length = rounddown(offset + length, mm->block_size) - node->offset; + +- *prmm = rmm; ++ list_add_tail(&node->nl_entry, &mm->nodes); ++ list_add_tail(&node->fl_entry, &mm->free); ++ mm->heap_nodes++; + return 0; + } + + int +-nouveau_mm_fini(struct nouveau_mm **prmm) ++nouveau_mm_fini(struct nouveau_mm *mm) + { +- 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; ++ struct nouveau_mm_node *node, *heap = ++ list_first_entry(&mm->nodes, struct nouveau_mm_node, nl_entry); ++ int nodes = 0; ++ ++ list_for_each_entry(node, &mm->nodes, nl_entry) { ++ if (nodes++ == mm->heap_nodes) { ++ printk(KERN_ERR "nouveau_mm in use at destroy time!\n"); ++ list_for_each_entry(node, &mm->nodes, nl_entry) { ++ printk(KERN_ERR "0x%02x: 0x%08x 0x%08x\n", ++ node->type, node->offset, node->length); ++ } ++ WARN_ON(1); ++ return -EBUSY; ++ } ++ } + + kfree(heap); +- kfree(rmm); +- *prmm = NULL; + return 0; + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_mm.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_mm.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_mm.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_mm.h 2011-07-26 07:03:44.447051256 +0200 +@@ -42,16 +42,18 @@ + struct mutex mutex; + + u32 block_size; ++ int heap_nodes; + }; + +-int nouveau_mm_init(struct nouveau_mm **, u32 offset, u32 length, u32 block); +-int nouveau_mm_fini(struct nouveau_mm **); ++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 *); ++void nv50_vram_fini(struct drm_device *); + int nv50_vram_new(struct drm_device *, u64 size, u32 align, u32 size_nc, + u32 memtype, struct nouveau_mem **); + void nv50_vram_del(struct drm_device *, struct nouveau_mem **); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_notifier.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_notifier.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_notifier.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_notifier.c 2011-07-26 07:03:44.448051268 +0200 +@@ -34,6 +34,7 @@ + nouveau_notifier_init_channel(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_bo *ntfy = NULL; + uint32_t flags, ttmpl; + int ret; +@@ -46,7 +47,7 @@ + ttmpl = TTM_PL_FLAG_TT; + } + +- ret = nouveau_gem_new(dev, NULL, PAGE_SIZE, 0, flags, 0, 0, &ntfy); ++ ret = nouveau_gem_new(dev, PAGE_SIZE, 0, flags, 0, 0, &ntfy); + if (ret) + return ret; + +@@ -58,14 +59,22 @@ + if (ret) + goto out_err; + ++ if (dev_priv->card_type >= NV_50) { ++ ret = nouveau_bo_vma_add(ntfy, chan->vm, &chan->notifier_vma); ++ if (ret) ++ goto out_err; ++ } ++ + ret = drm_mm_init(&chan->notifier_heap, 0, ntfy->bo.mem.size); + if (ret) + goto out_err; + + chan->notifier_bo = ntfy; + out_err: +- if (ret) ++ if (ret) { ++ nouveau_bo_vma_del(ntfy, &chan->notifier_vma); + drm_gem_object_unreference_unlocked(ntfy->gem); ++ } + + return ret; + } +@@ -78,6 +87,7 @@ + if (!chan->notifier_bo) + return; + ++ nouveau_bo_vma_del(chan->notifier_bo, &chan->notifier_vma); + nouveau_bo_unmap(chan->notifier_bo); + mutex_lock(&dev->struct_mutex); + nouveau_bo_unpin(chan->notifier_bo); +@@ -122,10 +132,10 @@ + target = NV_MEM_TARGET_VRAM; + else + target = NV_MEM_TARGET_GART; +- offset = chan->notifier_bo->bo.mem.start << PAGE_SHIFT; ++ offset = chan->notifier_bo->bo.offset; + } else { + target = NV_MEM_TARGET_VM; +- offset = chan->notifier_bo->vma.offset; ++ offset = chan->notifier_vma.offset; + } + offset += mem->start; + +@@ -183,7 +193,7 @@ + if (unlikely(dev_priv->card_type >= NV_C0)) + return -EINVAL; + +- chan = nouveau_channel_get(dev, file_priv, na->channel); ++ chan = nouveau_channel_get(file_priv, na->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_object.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_object.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_object.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_object.c 2011-07-26 07:03:44.449051280 +0200 +@@ -125,7 +125,7 @@ + int ret = -EINVAL; + + spin_lock_irqsave(&dev_priv->channels.lock, flags); +- if (chid > 0 && chid < dev_priv->engine.fifo.channels) ++ 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); +@@ -191,7 +191,7 @@ + list_add_tail(&gpuobj->list, &dev_priv->gpuobj_list); + spin_unlock(&dev_priv->ramin_lock); + +- if (chan) { ++ if (!(flags & NVOBJ_FLAG_VM) && chan) { + ramin = drm_mm_search_free(&chan->ramin_heap, size, align, 0); + if (ramin) + ramin = drm_mm_get_block(ramin, size, align); +@@ -208,7 +208,7 @@ + gpuobj->vinst = ramin->start + chan->ramin->vinst; + gpuobj->node = ramin; + } else { +- ret = instmem->get(gpuobj, size, align); ++ ret = instmem->get(gpuobj, chan, size, align); + if (ret) { + nouveau_gpuobj_ref(NULL, &gpuobj); + return ret; +@@ -690,36 +690,69 @@ + return 0; + } + +-int +-nouveau_gpuobj_channel_init(struct nouveau_channel *chan, +- uint32_t vram_h, uint32_t tt_h) ++static int ++nvc0_gpuobj_channel_init(struct nouveau_channel *chan, struct nouveau_vm *vm) + { ++ 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 *vram = NULL, *tt = NULL; ++ struct nouveau_gpuobj *pgd = NULL; ++ struct nouveau_vm_pgd *vpgd; + int ret, i; + +- 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; + +- ret = nouveau_gpuobj_new(dev, NULL, 4096, 0x1000, 0, +- &chan->ramin); ++ /* create page directory for this vm if none currently exists, ++ * will be destroyed automagically when last reference to the ++ * vm is removed ++ */ ++ if (list_empty(&vm->pgd_list)) { ++ ret = nouveau_gpuobj_new(dev, NULL, 65536, 0x1000, 0, &pgd); + if (ret) + return ret; ++ } ++ nouveau_vm_ref(vm, &chan->vm, pgd); ++ nouveau_gpuobj_ref(NULL, &pgd); + +- nouveau_vm_ref(vm, &chan->vm, NULL); ++ /* point channel at vm's page directory */ ++ 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); + +- 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); ++ /* map display semaphore buffers into channel's vm */ ++ if (dev_priv->card_type >= NV_D0) + return 0; ++ ++ for (i = 0; i < 2; i++) { ++ struct nv50_display_crtc *dispc = &nv50_display(dev)->crtc[i]; ++ ++ ret = nouveau_bo_vma_add(dispc->sem.bo, chan->vm, ++ &chan->dispc_vma[i]); ++ if (ret) ++ return ret; + } + ++ return 0; ++} ++ ++int ++nouveau_gpuobj_channel_init(struct nouveau_channel *chan, ++ uint32_t vram_h, uint32_t tt_h) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(chan->file_priv); ++ struct nouveau_vm *vm = fpriv ? fpriv->vm : dev_priv->chan_vm; ++ struct nouveau_gpuobj *vram = NULL, *tt = NULL; ++ int ret, i; ++ ++ 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) ++ return nvc0_gpuobj_channel_init(chan, vm); ++ + /* Allocate a chunk of memory for per-channel object storage */ + ret = nouveau_gpuobj_channel_init_pramin(chan); + if (ret) { +@@ -731,7 +764,7 @@ + * - Allocate per-channel page-directory + * - Link with shared channel VM + */ +- if (dev_priv->chan_vm) { ++ if (vm) { + u32 pgd_offs = (dev_priv->chipset == 0x50) ? 0x1400 : 0x0200; + u64 vm_vinst = chan->ramin->vinst + pgd_offs; + u32 vm_pinst = chan->ramin->pinst; +@@ -744,7 +777,7 @@ + if (ret) + return ret; + +- nouveau_vm_ref(dev_priv->chan_vm, &chan->vm, chan->vm_pd); ++ nouveau_vm_ref(vm, &chan->vm, chan->vm_pd); + } + + /* RAMHT */ +@@ -764,11 +797,11 @@ + return ret; + + /* dma objects for display sync channel semaphore blocks */ +- for (i = 0; i < 2; i++) { ++ for (i = 0; i < dev->mode_config.num_crtc; 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; ++ u64 offset = dispc->sem.bo->bo.offset; + + ret = nouveau_gpuobj_dma_new(chan, 0x3d, offset, 0xfff, + NV_MEM_ACCESS_RW, +@@ -841,10 +874,19 @@ + nouveau_gpuobj_channel_takedown(struct nouveau_channel *chan) + { + struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int i; + + NV_DEBUG(dev, "ch%d\n", chan->id); + +- nouveau_ramht_ref(NULL, &chan->ramht, chan); ++ if (dev_priv->card_type >= NV_50 && dev_priv->card_type <= NV_C0) { ++ struct nv50_display *disp = nv50_display(dev); ++ ++ for (i = 0; i < dev->mode_config.num_crtc; i++) { ++ struct nv50_display_crtc *dispc = &disp->crtc[i]; ++ nouveau_bo_vma_del(dispc->sem.bo, &chan->dispc_vma[i]); ++ } ++ } + + nouveau_vm_ref(NULL, &chan->vm, chan->vm_pd); + nouveau_gpuobj_ref(NULL, &chan->vm_pd); +@@ -909,7 +951,7 @@ + if (init->handle == ~0) + return -EINVAL; + +- chan = nouveau_channel_get(dev, file_priv, init->channel); ++ chan = nouveau_channel_get(file_priv, init->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); + +@@ -936,7 +978,7 @@ + struct nouveau_channel *chan; + int ret; + +- chan = nouveau_channel_get(dev, file_priv, objfree->channel); ++ chan = nouveau_channel_get(file_priv, objfree->channel); + if (IS_ERR(chan)) + return PTR_ERR(chan); + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_perf.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_perf.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_perf.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_perf.c 2011-07-26 07:03:44.449051280 +0200 +@@ -127,13 +127,57 @@ + + entry += ramcfg * recordlen; + if (entry[1] >= pm->memtimings.nr_timing) { +- NV_WARN(dev, "timingset %d does not exist\n", entry[1]); ++ if (entry[1] != 0xff) ++ NV_WARN(dev, "timingset %d does not exist\n", entry[1]); + return NULL; + } + + return &pm->memtimings.timing[entry[1]]; + } + ++static void ++nouveau_perf_voltage(struct drm_device *dev, struct bit_entry *P, ++ struct nouveau_pm_level *perflvl) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvbios *bios = &dev_priv->vbios; ++ u8 *vmap; ++ int id; ++ ++ id = perflvl->volt_min; ++ perflvl->volt_min = 0; ++ ++ /* boards using voltage table version <0x40 store the voltage ++ * level directly in the perflvl entry as a multiple of 10mV ++ */ ++ if (dev_priv->engine.pm.voltage.version < 0x40) { ++ perflvl->volt_min = id * 10000; ++ perflvl->volt_max = perflvl->volt_min; ++ return; ++ } ++ ++ /* on newer ones, the perflvl stores an index into yet another ++ * vbios table containing a min/max voltage value for the perflvl ++ */ ++ if (P->version != 2 || P->length < 34) { ++ NV_DEBUG(dev, "where's our volt map table ptr? %d %d\n", ++ P->version, P->length); ++ return; ++ } ++ ++ vmap = ROMPTR(bios, P->data[32]); ++ if (!vmap) { ++ NV_DEBUG(dev, "volt map table pointer invalid\n"); ++ return; ++ } ++ ++ if (id < vmap[3]) { ++ vmap += vmap[1] + (vmap[2] * id); ++ perflvl->volt_min = ROM32(vmap[0]); ++ perflvl->volt_max = ROM32(vmap[4]); ++ } ++} ++ + void + nouveau_perf_init(struct drm_device *dev) + { +@@ -141,6 +185,8 @@ + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nvbios *bios = &dev_priv->vbios; + struct bit_entry P; ++ struct nouveau_pm_memtimings *memtimings = &pm->memtimings; ++ struct nouveau_pm_tbl_header mt_hdr; + u8 version, headerlen, recordlen, entries; + u8 *perf, *entry; + int vid, i; +@@ -188,6 +234,22 @@ + } + + entry = perf + headerlen; ++ ++ /* For version 0x15, initialize memtiming table */ ++ if(version == 0x15) { ++ memtimings->timing = ++ kcalloc(entries, sizeof(*memtimings->timing), GFP_KERNEL); ++ if(!memtimings) { ++ NV_WARN(dev,"Could not allocate memtiming table\n"); ++ return; ++ } ++ ++ mt_hdr.entry_cnt = entries; ++ mt_hdr.entry_len = 14; ++ mt_hdr.version = version; ++ mt_hdr.header_len = 4; ++ } ++ + for (i = 0; i < entries; i++) { + struct nouveau_pm_level *perflvl = &pm->perflvl[pm->nr_perflvl]; + +@@ -203,7 +265,8 @@ + case 0x13: + case 0x15: + perflvl->fanspeed = entry[55]; +- perflvl->voltage = (recordlen > 56) ? entry[56] : 0; ++ if (recordlen > 56) ++ perflvl->volt_min = entry[56]; + perflvl->core = ROM32(entry[1]) * 10; + perflvl->memory = ROM32(entry[5]) * 20; + break; +@@ -211,7 +274,7 @@ + case 0x23: + case 0x24: + perflvl->fanspeed = entry[4]; +- perflvl->voltage = entry[5]; ++ perflvl->volt_min = entry[5]; + perflvl->core = ROM16(entry[6]) * 1000; + + if (dev_priv->chipset == 0x49 || +@@ -223,7 +286,7 @@ + break; + case 0x25: + perflvl->fanspeed = entry[4]; +- perflvl->voltage = entry[5]; ++ perflvl->volt_min = entry[5]; + perflvl->core = ROM16(entry[6]) * 1000; + perflvl->shader = ROM16(entry[10]) * 1000; + perflvl->memory = ROM16(entry[12]) * 1000; +@@ -232,7 +295,7 @@ + perflvl->memscript = ROM16(entry[2]); + case 0x35: + perflvl->fanspeed = entry[6]; +- perflvl->voltage = entry[7]; ++ perflvl->volt_min = entry[7]; + perflvl->core = ROM16(entry[8]) * 1000; + perflvl->shader = ROM16(entry[10]) * 1000; + perflvl->memory = ROM16(entry[12]) * 1000; +@@ -240,30 +303,34 @@ + perflvl->unk05 = ROM16(entry[16]) * 1000; + break; + case 0x40: +-#define subent(n) entry[perf[2] + ((n) * perf[3])] ++#define subent(n) (ROM16(entry[perf[2] + ((n) * perf[3])]) & 0xfff) * 1000 + perflvl->fanspeed = 0; /*XXX*/ +- perflvl->voltage = entry[2]; ++ perflvl->volt_min = entry[2]; + if (dev_priv->card_type == NV_50) { +- perflvl->core = ROM16(subent(0)) & 0xfff; +- perflvl->shader = ROM16(subent(1)) & 0xfff; +- perflvl->memory = ROM16(subent(2)) & 0xfff; ++ perflvl->core = subent(0); ++ perflvl->shader = subent(1); ++ perflvl->memory = subent(2); ++ perflvl->vdec = subent(3); ++ perflvl->unka0 = subent(4); + } else { +- perflvl->shader = ROM16(subent(3)) & 0xfff; ++ perflvl->hub06 = subent(0); ++ perflvl->hub01 = subent(1); ++ perflvl->copy = subent(2); ++ perflvl->shader = subent(3); ++ perflvl->rop = subent(4); ++ perflvl->memory = subent(5); ++ perflvl->vdec = subent(6); ++ perflvl->daemon = subent(10); ++ perflvl->hub07 = subent(11); + perflvl->core = perflvl->shader / 2; +- perflvl->unk0a = ROM16(subent(4)) & 0xfff; +- perflvl->memory = ROM16(subent(5)) & 0xfff; + } +- +- perflvl->core *= 1000; +- perflvl->shader *= 1000; +- perflvl->memory *= 1000; +- perflvl->unk0a *= 1000; + break; + } + + /* make sure vid is valid */ +- if (pm->voltage.supported && perflvl->voltage) { +- vid = nouveau_volt_vid_lookup(dev, perflvl->voltage); ++ nouveau_perf_voltage(dev, &P, perflvl); ++ if (pm->voltage.supported && perflvl->volt_min) { ++ vid = nouveau_volt_vid_lookup(dev, perflvl->volt_min); + if (vid < 0) { + NV_DEBUG(dev, "drop perflvl %d, bad vid\n", i); + entry += recordlen; +@@ -272,7 +339,11 @@ + } + + /* get the corresponding memory timings */ +- if (version > 0x15) { ++ if (version == 0x15) { ++ memtimings->timing[i].id = i; ++ nv30_mem_timing_entry(dev,&mt_hdr,(struct nouveau_pm_tbl_entry*) &entry[41],0,&memtimings->timing[i]); ++ perflvl->timing = &memtimings->timing[i]; ++ } else if (version > 0x15) { + /* last 3 args are for < 0x40, ignored for >= 0x40 */ + perflvl->timing = + nouveau_perf_timing(dev, &P, +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_pm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_pm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_pm.c 2011-07-26 07:03:44.450051292 +0200 +@@ -64,18 +64,26 @@ + if (perflvl == pm->cur) + return 0; + +- if (pm->voltage.supported && pm->voltage_set && perflvl->voltage) { +- ret = pm->voltage_set(dev, perflvl->voltage); ++ if (pm->voltage.supported && pm->voltage_set && perflvl->volt_min) { ++ ret = pm->voltage_set(dev, perflvl->volt_min); + if (ret) { + NV_ERROR(dev, "voltage_set %d failed: %d\n", +- perflvl->voltage, ret); ++ perflvl->volt_min, ret); + } + } + +- nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); +- nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); +- nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); +- nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); ++ if (pm->clocks_pre) { ++ void *state = pm->clocks_pre(dev, perflvl); ++ if (IS_ERR(state)) ++ return PTR_ERR(state); ++ pm->clocks_set(dev, state); ++ } else ++ if (pm->clock_set) { ++ nouveau_pm_clock_set(dev, perflvl, PLL_CORE, perflvl->core); ++ nouveau_pm_clock_set(dev, perflvl, PLL_SHADER, perflvl->shader); ++ nouveau_pm_clock_set(dev, perflvl, PLL_MEMORY, perflvl->memory); ++ nouveau_pm_clock_set(dev, perflvl, PLL_UNK05, perflvl->unk05); ++ } + + pm->cur = perflvl; + return 0; +@@ -92,9 +100,6 @@ + if (nouveau_perflvl_wr != 7777) + return -EPERM; + +- if (!pm->clock_set) +- return -EINVAL; +- + if (!strncmp(profile, "boot", 4)) + perflvl = &pm->boot; + else { +@@ -123,31 +128,37 @@ + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + int ret; + +- if (!pm->clock_get) +- return -EINVAL; +- + memset(perflvl, 0, sizeof(*perflvl)); + +- ret = pm->clock_get(dev, PLL_CORE); +- if (ret > 0) +- perflvl->core = ret; +- +- ret = pm->clock_get(dev, PLL_MEMORY); +- if (ret > 0) +- perflvl->memory = ret; +- +- ret = pm->clock_get(dev, PLL_SHADER); +- if (ret > 0) +- perflvl->shader = ret; +- +- ret = pm->clock_get(dev, PLL_UNK05); +- if (ret > 0) +- perflvl->unk05 = ret; ++ if (pm->clocks_get) { ++ ret = pm->clocks_get(dev, perflvl); ++ if (ret) ++ return ret; ++ } else ++ if (pm->clock_get) { ++ ret = pm->clock_get(dev, PLL_CORE); ++ if (ret > 0) ++ perflvl->core = ret; ++ ++ ret = pm->clock_get(dev, PLL_MEMORY); ++ if (ret > 0) ++ perflvl->memory = ret; ++ ++ ret = pm->clock_get(dev, PLL_SHADER); ++ if (ret > 0) ++ perflvl->shader = ret; ++ ++ ret = pm->clock_get(dev, PLL_UNK05); ++ if (ret > 0) ++ perflvl->unk05 = ret; ++ } + + if (pm->voltage.supported && pm->voltage_get) { + ret = pm->voltage_get(dev); +- if (ret > 0) +- perflvl->voltage = ret; ++ if (ret > 0) { ++ perflvl->volt_min = ret; ++ perflvl->volt_max = ret; ++ } + } + + return 0; +@@ -156,7 +167,7 @@ + static void + nouveau_pm_perflvl_info(struct nouveau_pm_level *perflvl, char *ptr, int len) + { +- char c[16], s[16], v[16], f[16], t[16]; ++ char c[16], s[16], v[32], f[16], t[16], m[16]; + + c[0] = '\0'; + if (perflvl->core) +@@ -166,9 +177,19 @@ + if (perflvl->shader) + snprintf(s, sizeof(s), " shader %dMHz", perflvl->shader / 1000); + ++ m[0] = '\0'; ++ if (perflvl->memory) ++ snprintf(m, sizeof(m), " memory %dMHz", perflvl->memory / 1000); ++ + v[0] = '\0'; +- if (perflvl->voltage) +- snprintf(v, sizeof(v), " voltage %dmV", perflvl->voltage * 10); ++ if (perflvl->volt_min && perflvl->volt_min != perflvl->volt_max) { ++ snprintf(v, sizeof(v), " voltage %dmV-%dmV", ++ perflvl->volt_min / 1000, perflvl->volt_max / 1000); ++ } else ++ if (perflvl->volt_min) { ++ snprintf(v, sizeof(v), " voltage %dmV", ++ perflvl->volt_min / 1000); ++ } + + f[0] = '\0'; + if (perflvl->fanspeed) +@@ -178,8 +199,7 @@ + if (perflvl->timing) + snprintf(t, sizeof(t), " timing %d", perflvl->timing->id); + +- snprintf(ptr, len, "memory %dMHz%s%s%s%s%s\n", perflvl->memory / 1000, +- c, s, v, f, t); ++ snprintf(ptr, len, "%s%s%s%s%s%s\n", c, s, m, t, v, f); + } + + static ssize_t +@@ -190,7 +210,7 @@ + char *ptr = buf; + int len = PAGE_SIZE; + +- snprintf(ptr, len, "%d: ", perflvl->id); ++ snprintf(ptr, len, "%d:", perflvl->id); + ptr += strlen(buf); + len -= strlen(buf); + +@@ -211,9 +231,9 @@ + if (!pm->cur) + snprintf(ptr, len, "setting: boot\n"); + else if (pm->cur == &pm->boot) +- snprintf(ptr, len, "setting: boot\nc: "); ++ snprintf(ptr, len, "setting: boot\nc:"); + else +- snprintf(ptr, len, "setting: static %d\nc: ", pm->cur->id); ++ snprintf(ptr, len, "setting: static %d\nc:", pm->cur->id); + ptr += strlen(buf); + len -= strlen(buf); + +@@ -292,7 +312,7 @@ + } + } + +-#ifdef CONFIG_HWMON ++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) + static ssize_t + nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) + { +@@ -409,7 +429,7 @@ + static int + nouveau_hwmon_init(struct drm_device *dev) + { +-#ifdef CONFIG_HWMON ++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct device *hwmon_dev; +@@ -442,7 +462,7 @@ + static void + nouveau_hwmon_fini(struct drm_device *dev) + { +-#ifdef CONFIG_HWMON ++#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE)) + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + +@@ -488,7 +508,7 @@ + NV_INFO(dev, "%d available performance level(s)\n", pm->nr_perflvl); + for (i = 0; i < pm->nr_perflvl; i++) { + nouveau_pm_perflvl_info(&pm->perflvl[i], info, sizeof(info)); +- NV_INFO(dev, "%d: %s", pm->perflvl[i].id, info); ++ NV_INFO(dev, "%d:%s", pm->perflvl[i].id, info); + } + + /* determine current ("boot") performance level */ +@@ -498,7 +518,7 @@ + pm->cur = &pm->boot; + + nouveau_pm_perflvl_info(&pm->boot, info, sizeof(info)); +- NV_INFO(dev, "c: %s", info); ++ NV_INFO(dev, "c:%s", info); + } + + /* switch performance levels now if requested */ +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_pm.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_pm.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_pm.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_pm.h 2011-07-26 07:03:44.451051304 +0200 +@@ -59,10 +59,12 @@ + void nv50_pm_clock_set(struct drm_device *, void *); + + /* nva3_pm.c */ +-int nva3_pm_clock_get(struct drm_device *, u32 id); +-void *nva3_pm_clock_pre(struct drm_device *, struct nouveau_pm_level *, +- u32 id, int khz); +-void nva3_pm_clock_set(struct drm_device *, void *); ++int nva3_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); ++void *nva3_pm_clocks_pre(struct drm_device *, struct nouveau_pm_level *); ++void nva3_pm_clocks_set(struct drm_device *, void *); ++ ++/* nvc0_pm.c */ ++int nvc0_pm_clocks_get(struct drm_device *, struct nouveau_pm_level *); + + /* nouveau_temp.c */ + void nouveau_temp_init(struct drm_device *dev); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_state.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_state.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_state.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_state.c 2011-07-26 07:03:44.453051328 +0200 +@@ -91,6 +91,7 @@ + engine->pm.clock_pre = nv04_pm_clock_pre; + engine->pm.clock_set = nv04_pm_clock_set; + engine->vram.init = nouveau_mem_detect; ++ engine->vram.takedown = nouveau_stub_takedown; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; + case 0x10: +@@ -139,6 +140,7 @@ + engine->pm.clock_pre = nv04_pm_clock_pre; + engine->pm.clock_set = nv04_pm_clock_set; + engine->vram.init = nouveau_mem_detect; ++ engine->vram.takedown = nouveau_stub_takedown; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; + case 0x20: +@@ -187,6 +189,7 @@ + engine->pm.clock_pre = nv04_pm_clock_pre; + engine->pm.clock_set = nv04_pm_clock_set; + engine->vram.init = nouveau_mem_detect; ++ engine->vram.takedown = nouveau_stub_takedown; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; + case 0x30: +@@ -237,6 +240,7 @@ + engine->pm.voltage_get = nouveau_voltage_gpio_get; + engine->pm.voltage_set = nouveau_voltage_gpio_set; + engine->vram.init = nouveau_mem_detect; ++ engine->vram.takedown = nouveau_stub_takedown; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; + case 0x40: +@@ -289,12 +293,13 @@ + engine->pm.voltage_set = nouveau_voltage_gpio_set; + engine->pm.temp_get = nv40_temp_get; + engine->vram.init = nouveau_mem_detect; ++ engine->vram.takedown = nouveau_stub_takedown; + engine->vram.flags_valid = nouveau_mem_flags_valid; + break; + case 0x50: + case 0x80: /* gotta love NVIDIA's consistency.. */ + case 0x90: +- case 0xA0: ++ case 0xa0: + engine->instmem.init = nv50_instmem_init; + engine->instmem.takedown = nv50_instmem_takedown; + engine->instmem.suspend = nv50_instmem_suspend; +@@ -354,9 +359,9 @@ + 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; ++ engine->pm.clocks_get = nva3_pm_clocks_get; ++ engine->pm.clocks_pre = nva3_pm_clocks_pre; ++ engine->pm.clocks_set = nva3_pm_clocks_set; + break; + } + engine->pm.voltage_get = nouveau_voltage_gpio_get; +@@ -366,11 +371,12 @@ + else + engine->pm.temp_get = nv40_temp_get; + engine->vram.init = nv50_vram_init; ++ engine->vram.takedown = nv50_vram_fini; + engine->vram.get = nv50_vram_new; + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nv50_vram_flags_valid; + break; +- case 0xC0: ++ case 0xc0: + engine->instmem.init = nvc0_instmem_init; + engine->instmem.takedown = nvc0_instmem_takedown; + engine->instmem.suspend = nvc0_instmem_suspend; +@@ -411,15 +417,78 @@ + engine->gpio.irq_unregister = nv50_gpio_irq_unregister; + engine->gpio.irq_enable = nv50_gpio_irq_enable; + engine->vram.init = nvc0_vram_init; ++ engine->vram.takedown = nv50_vram_fini; + engine->vram.get = nvc0_vram_new; + engine->vram.put = nv50_vram_del; + engine->vram.flags_valid = nvc0_vram_flags_valid; ++ engine->pm.temp_get = nv84_temp_get; ++ engine->pm.clocks_get = nvc0_pm_clocks_get; ++ engine->pm.voltage_get = nouveau_voltage_gpio_get; ++ engine->pm.voltage_set = nouveau_voltage_gpio_set; ++ break; ++ case 0xd0: ++ 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.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; ++ engine->timer.read = nv04_timer_read; ++ engine->timer.takedown = nv04_timer_takedown; ++ engine->fb.init = nvc0_fb_init; ++ engine->fb.takedown = nvc0_fb_takedown; ++ engine->fifo.channels = 128; ++ engine->fifo.init = nvc0_fifo_init; ++ engine->fifo.takedown = nvc0_fifo_takedown; ++ engine->fifo.disable = nvc0_fifo_disable; ++ engine->fifo.enable = nvc0_fifo_enable; ++ engine->fifo.reassign = nvc0_fifo_reassign; ++ engine->fifo.channel_id = nvc0_fifo_channel_id; ++ engine->fifo.create_context = nvc0_fifo_create_context; ++ engine->fifo.destroy_context = nvc0_fifo_destroy_context; ++ engine->fifo.load_context = nvc0_fifo_load_context; ++ engine->fifo.unload_context = nvc0_fifo_unload_context; ++ engine->display.early_init = nouveau_stub_init; ++ engine->display.late_takedown = nouveau_stub_takedown; ++ engine->display.create = nvd0_display_create; ++ engine->display.init = nvd0_display_init; ++ engine->display.destroy = nvd0_display_destroy; ++ engine->gpio.init = nv50_gpio_init; ++ engine->gpio.takedown = nouveau_stub_takedown; ++ engine->gpio.get = nvd0_gpio_get; ++ engine->gpio.set = nvd0_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->vram.init = nvc0_vram_init; ++ engine->vram.takedown = nv50_vram_fini; ++ engine->vram.get = nvc0_vram_new; ++ engine->vram.put = nv50_vram_del; ++ engine->vram.flags_valid = nvc0_vram_flags_valid; ++ engine->pm.clocks_get = nvc0_pm_clocks_get; ++ engine->pm.voltage_get = nouveau_voltage_gpio_get; ++ engine->pm.voltage_set = nouveau_voltage_gpio_set; + break; + default: + NV_ERROR(dev, "NV%02x unsupported\n", dev_priv->chipset); + return 1; + } + ++ /* headless mode */ ++ if (nouveau_modeset == 2) { ++ engine->display.early_init = nouveau_stub_init; ++ engine->display.late_takedown = nouveau_stub_takedown; ++ engine->display.create = nouveau_stub_init; ++ engine->display.init = nouveau_stub_init; ++ engine->display.destroy = nouveau_stub_takedown; ++ } ++ + return 0; + } + +@@ -441,21 +510,6 @@ + return VGA_RSRC_NORMAL_IO | VGA_RSRC_NORMAL_MEM; + } + +-static int +-nouveau_card_init_channel(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- int ret; +- +- ret = nouveau_channel_alloc(dev, &dev_priv->channel, +- (struct drm_file *)-2, NvDmaFB, NvDmaTT); +- if (ret) +- return ret; +- +- mutex_unlock(&dev_priv->channel->mutex); +- return 0; +-} +- + static void nouveau_switcheroo_set_state(struct pci_dev *pdev, + enum vga_switcheroo_state state) + { +@@ -527,7 +581,7 @@ + + nouveau_pm_init(dev); + +- ret = nouveau_mem_vram_init(dev); ++ ret = engine->vram.init(dev); + if (ret) + goto out_bios; + +@@ -539,10 +593,14 @@ + if (ret) + goto out_gpuobj; + +- ret = nouveau_mem_gart_init(dev); ++ ret = nouveau_mem_vram_init(dev); + if (ret) + goto out_instmem; + ++ ret = nouveau_mem_gart_init(dev); ++ if (ret) ++ goto out_ttmvram; ++ + /* PMC */ + ret = engine->mc.init(dev); + if (ret) +@@ -563,7 +621,7 @@ + if (ret) + goto out_timer; + +- if (!nouveau_noaccel) { ++ if (!dev_priv->noaccel) { + switch (dev_priv->card_type) { + case NV_04: + nv04_graph_create(dev); +@@ -618,8 +676,11 @@ + break; + } + +- if (dev_priv->card_type == NV_40) +- nv40_mpeg_create(dev); ++ if (dev_priv->card_type == NV_40 || ++ dev_priv->chipset == 0x31 || ++ dev_priv->chipset == 0x34 || ++ dev_priv->chipset == 0x36) ++ nv31_mpeg_create(dev); + else + if (dev_priv->card_type == NV_50 && + (dev_priv->chipset < 0x98 || dev_priv->chipset == 0xa0)) +@@ -639,50 +700,75 @@ + goto out_engine; + } + +- ret = engine->display.create(dev); ++ ret = nouveau_irq_init(dev); + if (ret) + goto out_fifo; + +- ret = drm_vblank_init(dev, nv_two_heads(dev) ? 2 : 1); +- if (ret) +- goto out_vblank; ++ /* initialise general modesetting */ ++ drm_mode_config_init(dev); ++ drm_mode_create_scaling_mode_property(dev); ++ drm_mode_create_dithering_property(dev); ++ dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; ++ dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1); ++ dev->mode_config.min_width = 0; ++ dev->mode_config.min_height = 0; ++ if (dev_priv->card_type < NV_10) { ++ dev->mode_config.max_width = 2048; ++ dev->mode_config.max_height = 2048; ++ } else ++ if (dev_priv->card_type < NV_50) { ++ dev->mode_config.max_width = 4096; ++ dev->mode_config.max_height = 4096; ++ } else { ++ dev->mode_config.max_width = 8192; ++ dev->mode_config.max_height = 8192; ++ } + +- ret = nouveau_irq_init(dev); ++ ret = engine->display.create(dev); + if (ret) +- goto out_vblank; +- +- /* what about PVIDEO/PCRTC/PRAMDAC etc? */ ++ goto out_irq; + + if (dev_priv->eng[NVOBJ_ENGINE_GR]) { + ret = nouveau_fence_init(dev); + if (ret) +- goto out_irq; ++ goto out_disp; + +- ret = nouveau_card_init_channel(dev); ++ ret = nouveau_channel_alloc(dev, &dev_priv->channel, NULL, ++ NvDmaFB, NvDmaTT); + if (ret) + goto out_fence; ++ ++ mutex_unlock(&dev_priv->channel->mutex); ++ } ++ ++ if (dev->mode_config.num_crtc) { ++ ret = drm_vblank_init(dev, dev->mode_config.num_crtc); ++ if (ret) ++ goto out_chan; ++ ++ nouveau_fbcon_init(dev); ++ drm_kms_helper_poll_init(dev); + } + +- nouveau_fbcon_init(dev); +- drm_kms_helper_poll_init(dev); + return 0; + ++out_chan: ++ nouveau_channel_put_unlocked(&dev_priv->channel); + out_fence: + nouveau_fence_fini(dev); ++out_disp: ++ engine->display.destroy(dev); + out_irq: + nouveau_irq_fini(dev); +-out_vblank: +- drm_vblank_cleanup(dev); +- engine->display.destroy(dev); + out_fifo: +- if (!nouveau_noaccel) ++ if (!dev_priv->noaccel) + engine->fifo.takedown(dev); + out_engine: +- if (!nouveau_noaccel) { ++ if (!dev_priv->noaccel) { + for (e = e - 1; e >= 0; e--) { + if (!dev_priv->eng[e]) + continue; +- dev_priv->eng[e]->fini(dev, e); ++ dev_priv->eng[e]->fini(dev, e, false); + dev_priv->eng[e]->destroy(dev,e ); + } + } +@@ -696,12 +782,14 @@ + engine->mc.takedown(dev); + out_gart: + nouveau_mem_gart_fini(dev); ++out_ttmvram: ++ nouveau_mem_vram_fini(dev); + out_instmem: + engine->instmem.takedown(dev); + out_gpuobj: + nouveau_gpuobj_takedown(dev); + out_vram: +- nouveau_mem_vram_fini(dev); ++ engine->vram.takedown(dev); + out_bios: + nouveau_pm_fini(dev); + nouveau_bios_takedown(dev); +@@ -718,16 +806,25 @@ + struct nouveau_engine *engine = &dev_priv->engine; + int e; + ++ if (dev->mode_config.num_crtc) { ++ drm_kms_helper_poll_fini(dev); ++ nouveau_fbcon_fini(dev); ++ drm_vblank_cleanup(dev); ++ } ++ + if (dev_priv->channel) { +- nouveau_fence_fini(dev); + nouveau_channel_put_unlocked(&dev_priv->channel); ++ nouveau_fence_fini(dev); + } + +- if (!nouveau_noaccel) { ++ engine->display.destroy(dev); ++ drm_mode_config_cleanup(dev); ++ ++ if (!dev_priv->noaccel) { + engine->fifo.takedown(dev); + for (e = NVOBJ_ENGINE_NR - 1; e >= 0; e--) { + if (dev_priv->eng[e]) { +- dev_priv->eng[e]->fini(dev, e); ++ dev_priv->eng[e]->fini(dev, e, false); + dev_priv->eng[e]->destroy(dev,e ); + } + } +@@ -748,13 +845,13 @@ + ttm_bo_clean_mm(&dev_priv->ttm.bdev, TTM_PL_TT); + mutex_unlock(&dev->struct_mutex); + nouveau_mem_gart_fini(dev); ++ nouveau_mem_vram_fini(dev); + + engine->instmem.takedown(dev); + nouveau_gpuobj_takedown(dev); +- nouveau_mem_vram_fini(dev); ++ engine->vram.takedown(dev); + + nouveau_irq_fini(dev); +- drm_vblank_cleanup(dev); + + nouveau_pm_fini(dev); + nouveau_bios_takedown(dev); +@@ -762,6 +859,41 @@ + vga_client_register(dev->pdev, NULL, NULL, NULL); + } + ++int ++nouveau_open(struct drm_device *dev, struct drm_file *file_priv) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_fpriv *fpriv; ++ int ret; ++ ++ fpriv = kzalloc(sizeof(*fpriv), GFP_KERNEL); ++ if (unlikely(!fpriv)) ++ return -ENOMEM; ++ ++ spin_lock_init(&fpriv->lock); ++ INIT_LIST_HEAD(&fpriv->channels); ++ ++ if (dev_priv->card_type == NV_50) { ++ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0020000000ULL, ++ &fpriv->vm); ++ if (ret) { ++ kfree(fpriv); ++ return ret; ++ } ++ } else ++ if (dev_priv->card_type >= NV_C0) { ++ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, ++ &fpriv->vm); ++ if (ret) { ++ kfree(fpriv); ++ return ret; ++ } ++ } ++ ++ file_priv->driver_priv = fpriv; ++ return 0; ++} ++ + /* here a client dies, release the stuff that was allocated for its + * file_priv */ + void nouveau_preclose(struct drm_device *dev, struct drm_file *file_priv) +@@ -769,6 +901,14 @@ + nouveau_channel_cleanup(dev, file_priv); + } + ++void ++nouveau_postclose(struct drm_device *dev, struct drm_file *file_priv) ++{ ++ struct nouveau_fpriv *fpriv = nouveau_fpriv(file_priv); ++ nouveau_vm_ref(NULL, &fpriv->vm, NULL); ++ kfree(fpriv); ++} ++ + /* first module load, setup the mmio/fb mapping */ + /* KMS: we need mmio at load time, not when the first drm client opens. */ + int nouveau_firstopen(struct drm_device *dev) +@@ -844,7 +984,7 @@ + int nouveau_load(struct drm_device *dev, unsigned long flags) + { + struct drm_nouveau_private *dev_priv; +- uint32_t reg0; ++ uint32_t reg0, strap; + resource_size_t mmio_start_offs; + int ret; + +@@ -888,13 +1028,11 @@ + + /* Time to determine the card architecture */ + reg0 = nv_rd32(dev, NV03_PMC_BOOT_0); +- dev_priv->stepping = 0; /* XXX: add stepping for pre-NV10? */ + + /* We're dealing with >=NV10 */ + if ((reg0 & 0x0f000000) > 0) { + /* Bit 27-20 contain the architecture in hex */ + dev_priv->chipset = (reg0 & 0xff00000) >> 20; +- dev_priv->stepping = (reg0 & 0xff); + /* NV04 or NV05 */ + } else if ((reg0 & 0xff00fff0) == 0x20004000) { + if (reg0 & 0x00f00000) +@@ -924,6 +1062,9 @@ + case 0xc0: + dev_priv->card_type = NV_C0; + break; ++ case 0xd0: ++ dev_priv->card_type = NV_D0; ++ break; + default: + NV_INFO(dev, "Unsupported chipset 0x%08x\n", reg0); + ret = -EINVAL; +@@ -933,6 +1074,42 @@ + NV_INFO(dev, "Detected an NV%2x generation card (0x%08x)\n", + dev_priv->card_type, reg0); + ++ /* determine frequency of timing crystal */ ++ strap = nv_rd32(dev, 0x101000); ++ if ( dev_priv->chipset < 0x17 || ++ (dev_priv->chipset >= 0x20 && dev_priv->chipset <= 0x25)) ++ strap &= 0x00000040; ++ else ++ strap &= 0x00400040; ++ ++ switch (strap) { ++ case 0x00000000: dev_priv->crystal = 13500; break; ++ case 0x00000040: dev_priv->crystal = 14318; break; ++ case 0x00400000: dev_priv->crystal = 27000; break; ++ case 0x00400040: dev_priv->crystal = 25000; break; ++ } ++ ++ NV_DEBUG(dev, "crystal freq: %dKHz\n", dev_priv->crystal); ++ ++ /* Determine whether we'll attempt acceleration or not, some ++ * cards are disabled by default here due to them being known ++ * non-functional, or never been tested due to lack of hw. ++ */ ++ dev_priv->noaccel = !!nouveau_noaccel; ++ if (nouveau_noaccel == -1) { ++ switch (dev_priv->chipset) { ++ case 0xc1: /* known broken */ ++ case 0xc8: /* never tested */ ++ NV_INFO(dev, "acceleration disabled by default, pass " ++ "noaccel=0 to force enable\n"); ++ dev_priv->noaccel = true; ++ break; ++ default: ++ dev_priv->noaccel = false; ++ break; ++ } ++ } ++ + ret = nouveau_remove_conflicting_drivers(dev); + if (ret) + goto err_mmio; +@@ -997,11 +1174,7 @@ + int nouveau_unload(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_engine *engine = &dev_priv->engine; + +- drm_kms_helper_poll_fini(dev); +- nouveau_fbcon_fini(dev); +- engine->display.destroy(dev); + nouveau_card_takedown(dev); + + iounmap(dev_priv->mmio); +@@ -1052,7 +1225,7 @@ + getparam->value = 1; + break; + case NOUVEAU_GETPARAM_HAS_PAGEFLIP: +- getparam->value = 1; ++ getparam->value = dev_priv->card_type < NV_D0; + break; + case NOUVEAU_GETPARAM_GRAPH_UNITS: + /* NV40 and NV50 versions are quite different, but register +@@ -1120,6 +1293,23 @@ + return false; + } + ++/* Wait until cond(data) == true, up until timeout has hit */ ++bool ++nouveau_wait_cb(struct drm_device *dev, u64 timeout, ++ bool (*cond)(void *), void *data) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; ++ u64 start = ptimer->read(dev); ++ ++ do { ++ if (cond(data) == true) ++ 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) + { +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_temp.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_temp.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_temp.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_temp.c 2011-07-26 07:03:44.454051340 +0200 +@@ -43,7 +43,7 @@ + + /* Set the default sensor's contants */ + sensor->offset_constant = 0; +- sensor->offset_mult = 1; ++ sensor->offset_mult = 0; + sensor->offset_div = 1; + sensor->slope_mult = 1; + sensor->slope_div = 1; +@@ -99,6 +99,13 @@ + sensor->slope_mult = 431; + sensor->slope_div = 10000; + break; ++ ++ case 0x67: ++ sensor->offset_mult = -26149; ++ sensor->offset_div = 100; ++ sensor->slope_mult = 484; ++ sensor->slope_div = 10000; ++ break; + } + } + +@@ -109,7 +116,7 @@ + + /* Read the entries from the table */ + for (i = 0; i < entries; i++) { +- u16 value = ROM16(temp[1]); ++ s16 value = ROM16(temp[1]); + + switch (temp[0]) { + case 0x01: +@@ -160,8 +167,8 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nouveau_pm_engine *pm = &dev_priv->engine.pm; + struct nouveau_pm_temp_sensor_constants *sensor = &pm->sensor_constants; +- u32 offset = sensor->offset_mult / sensor->offset_div; +- u32 sensor_calibration; ++ s32 offset = sensor->offset_mult / sensor->offset_div; ++ s32 sensor_calibration; + + /* set up the sensors */ + sensor_calibration = 120 - offset - sensor->offset_constant; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_vm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_vm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_vm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_vm.c 2011-07-26 07:03:44.454051340 +0200 +@@ -172,9 +172,9 @@ + vm->map_pgt(vpgd->obj, pde, vpgt->obj); + } + +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + nouveau_gpuobj_ref(NULL, &pgt); +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + } + } + +@@ -191,18 +191,18 @@ + pgt_size = (1 << (vm->pgt_bits + 12)) >> type; + pgt_size *= 8; + +- mutex_unlock(&vm->mm->mutex); ++ 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); ++ 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); ++ mutex_unlock(&vm->mm.mutex); + nouveau_gpuobj_ref(NULL, &pgt); +- mutex_lock(&vm->mm->mutex); ++ mutex_lock(&vm->mm.mutex); + return 0; + } + +@@ -223,10 +223,10 @@ + u32 fpde, lpde, pde; + int ret; + +- mutex_lock(&vm->mm->mutex); +- ret = nouveau_mm_get(vm->mm, page_shift, msize, 0, align, &vma->node); ++ 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); ++ mutex_unlock(&vm->mm.mutex); + return ret; + } + +@@ -245,13 +245,13 @@ + 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); ++ nouveau_mm_put(&vm->mm, vma->node); ++ mutex_unlock(&vm->mm.mutex); + vma->node = NULL; + return ret; + } + } +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + + vma->vm = vm; + vma->offset = (u64)vma->node->offset << 12; +@@ -270,11 +270,11 @@ + fpde = (vma->node->offset >> vm->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> vm->pgt_bits; + +- mutex_lock(&vm->mm->mutex); ++ 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); ++ nouveau_mm_put(&vm->mm, vma->node); + vma->node = NULL; +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); + } + + int +@@ -306,7 +306,7 @@ + block = length; + + } else +- if (dev_priv->card_type == NV_C0) { ++ 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; +@@ -360,32 +360,35 @@ + + nouveau_gpuobj_ref(pgd, &vpgd->obj); + +- mutex_lock(&vm->mm->mutex); ++ 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); ++ mutex_unlock(&vm->mm.mutex); + return 0; + } + + static void +-nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd) ++nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd) + { + struct nouveau_vm_pgd *vpgd, *tmp; ++ struct nouveau_gpuobj *pgd = NULL; + +- if (!pgd) ++ if (!mpgd) + return; + +- mutex_lock(&vm->mm->mutex); ++ 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); ++ if (vpgd->obj == mpgd) { ++ pgd = vpgd->obj; ++ list_del(&vpgd->head); ++ kfree(vpgd); ++ break; ++ } + } +- mutex_unlock(&vm->mm->mutex); ++ mutex_unlock(&vm->mm.mutex); ++ ++ nouveau_gpuobj_ref(NULL, &pgd); + } + + static void +@@ -396,8 +399,8 @@ + 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); + ++ nouveau_mm_fini(&vm->mm); + kfree(vm->pgt); + kfree(vm); + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_vm.h linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_vm.h +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_vm.h 2011-07-26 07:03:44.455051352 +0200 +@@ -41,6 +41,8 @@ + }; + + struct nouveau_vma { ++ struct list_head head; ++ int refcount; + struct nouveau_vm *vm; + struct nouveau_mm_node *node; + u64 offset; +@@ -49,7 +51,7 @@ + + struct nouveau_vm { + struct drm_device *dev; +- struct nouveau_mm *mm; ++ struct nouveau_mm mm; + int refcount; + + struct list_head pgd_list; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nouveau_volt.c linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_volt.c +--- linux-3.0/drivers/gpu/drm/nouveau/nouveau_volt.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nouveau_volt.c 2011-07-26 07:03:44.456051364 +0200 +@@ -27,7 +27,7 @@ + #include "nouveau_drv.h" + #include "nouveau_pm.h" + +-static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a }; ++static const enum dcb_gpio_tag vidtag[] = { 0x04, 0x05, 0x06, 0x1a, 0x73 }; + static int nr_vidtag = sizeof(vidtag) / sizeof(vidtag[0]); + + int +@@ -170,6 +170,13 @@ + */ + vidshift = 2; + break; ++ case 0x40: ++ headerlen = volt[1]; ++ recordlen = volt[2]; ++ entries = volt[3]; /* not a clue what the entries are for.. */ ++ vidmask = volt[11]; /* guess.. */ ++ vidshift = 0; ++ break; + default: + NV_WARN(dev, "voltage table 0x%02x unknown\n", volt[0]); + return; +@@ -197,16 +204,37 @@ + } + + /* parse vbios entries into common format */ +- voltage->level = kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); +- if (!voltage->level) +- return; ++ voltage->version = volt[0]; ++ if (voltage->version < 0x40) { ++ voltage->nr_level = entries; ++ voltage->level = ++ kcalloc(entries, sizeof(*voltage->level), GFP_KERNEL); ++ if (!voltage->level) ++ return; + +- entry = volt + headerlen; +- for (i = 0; i < entries; i++, entry += recordlen) { +- voltage->level[i].voltage = entry[0]; +- voltage->level[i].vid = entry[1] >> vidshift; ++ entry = volt + headerlen; ++ for (i = 0; i < entries; i++, entry += recordlen) { ++ voltage->level[i].voltage = entry[0] * 10000; ++ voltage->level[i].vid = entry[1] >> vidshift; ++ } ++ } else { ++ u32 volt_uv = ROM32(volt[4]); ++ s16 step_uv = ROM16(volt[8]); ++ u8 vid; ++ ++ voltage->nr_level = voltage->vid_mask + 1; ++ voltage->level = kcalloc(voltage->nr_level, ++ sizeof(*voltage->level), GFP_KERNEL); ++ if (!voltage->level) ++ return; ++ ++ for (vid = 0; vid <= voltage->vid_mask; vid++) { ++ voltage->level[vid].voltage = volt_uv; ++ voltage->level[vid].vid = vid; ++ volt_uv += step_uv; ++ } + } +- voltage->nr_level = entries; ++ + voltage->supported = true; + } + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv04_crtc.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_crtc.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_crtc.c 2011-07-26 07:03:44.457051376 +0200 +@@ -1035,7 +1035,7 @@ + drm_crtc_helper_add(&nv_crtc->base, &nv04_crtc_helper_funcs); + drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); + +- ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, ++ ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, + 0, 0x0000, &nv_crtc->cursor.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv04_display.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_display.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv04_display.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_display.c 2011-07-26 07:03:44.457051376 +0200 +@@ -126,27 +126,6 @@ + + nouveau_hw_save_vga_fonts(dev, 1); + +- drm_mode_config_init(dev); +- drm_mode_create_scaling_mode_property(dev); +- drm_mode_create_dithering_property(dev); +- +- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; +- +- dev->mode_config.min_width = 0; +- dev->mode_config.min_height = 0; +- switch (dev_priv->card_type) { +- case NV_04: +- dev->mode_config.max_width = 2048; +- dev->mode_config.max_height = 2048; +- break; +- default: +- dev->mode_config.max_width = 4096; +- dev->mode_config.max_height = 4096; +- break; +- } +- +- dev->mode_config.fb_base = dev_priv->fb_phys; +- + nv04_crtc_create(dev, 0); + if (nv_two_heads(dev)) + nv04_crtc_create(dev, 1); +@@ -235,8 +214,6 @@ + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + crtc->funcs->restore(crtc); + +- drm_mode_config_cleanup(dev); +- + nouveau_hw_save_vga_fonts(dev, 0); + } + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv04_graph.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_graph.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv04_graph.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_graph.c 2011-07-26 07:03:44.458051388 +0200 +@@ -450,13 +450,13 @@ + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv04_graph_fifo_access(dev, false); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + + /* Unload the context if it's the currently active one */ + if (nv04_graph_channel(dev) == chan) + nv04_graph_unload_context(dev); + +- nv04_graph_fifo_access(dev, true); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ +@@ -538,24 +538,18 @@ + } + + static int +-nv04_graph_fini(struct drm_device *dev, int engine) ++nv04_graph_fini(struct drm_device *dev, int engine, bool suspend) + { ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) { ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); ++ return -EBUSY; ++ } + nv04_graph_unload_context(dev); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + return 0; + } + +-void +-nv04_graph_fifo_access(struct drm_device *dev, bool enabled) +-{ +- if (enabled) +- nv_wr32(dev, NV04_PGRAPH_FIFO, +- nv_rd32(dev, NV04_PGRAPH_FIFO) | 1); +- else +- nv_wr32(dev, NV04_PGRAPH_FIFO, +- nv_rd32(dev, NV04_PGRAPH_FIFO) & ~1); +-} +- + static int + nv04_graph_mthd_set_ref(struct nouveau_channel *chan, + u32 class, u32 mthd, u32 data) +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv04_instmem.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_instmem.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv04_instmem.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_instmem.c 2011-07-26 07:03:44.459051400 +0200 +@@ -28,6 +28,31 @@ + /* RAMIN always available */ + dev_priv->ramin_available = true; + ++ /* Reserve space at end of VRAM for PRAMIN */ ++ if (dev_priv->card_type >= NV_40) { ++ u32 vs = hweight8((nv_rd32(dev, 0x001540) & 0x0000ff00) >> 8); ++ u32 rsvd; ++ ++ /* estimate grctx size, the magics come from nv40_grctx.c */ ++ if (dev_priv->chipset == 0x40) rsvd = 0x6aa0 * vs; ++ else if (dev_priv->chipset < 0x43) rsvd = 0x4f00 * vs; ++ else if (nv44_graph_class(dev)) rsvd = 0x4980 * vs; ++ else rsvd = 0x4a40 * vs; ++ rsvd += 16 * 1024; ++ rsvd *= dev_priv->engine.fifo.channels; ++ ++ /* pciegart table */ ++ if (drm_pci_device_is_pcie(dev)) ++ rsvd += 512 * 1024; ++ ++ /* object storage */ ++ rsvd += 512 * 1024; ++ ++ dev_priv->ramin_rsvd_vram = round_up(rsvd, 4096); ++ } else { ++ dev_priv->ramin_rsvd_vram = 512 * 1024; ++ } ++ + /* Setup shared RAMHT */ + ret = nouveau_gpuobj_new_fake(dev, 0x10000, ~0, 4096, + NVOBJ_FLAG_ZERO_ALLOC, &ramht); +@@ -112,7 +137,8 @@ + } + + int +-nv04_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) ++nv04_instmem_get(struct nouveau_gpuobj *gpuobj, struct nouveau_channel *chan, ++ u32 size, u32 align) + { + struct drm_nouveau_private *dev_priv = gpuobj->dev->dev_private; + struct drm_mm_node *ramin = NULL; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv04_pm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_pm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv04_pm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_pm.c 2011-07-26 07:03:44.459051400 +0200 +@@ -68,6 +68,7 @@ + nv04_pm_clock_set(struct drm_device *dev, void *pre_state) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_timer_engine *ptimer = &dev_priv->engine.timer; + struct nv04_pm_state *state = pre_state; + u32 reg = state->pll.reg; + +@@ -85,6 +86,9 @@ + nv_mask(dev, 0x1002c0, 0, 1 << 8); + } + ++ if (reg == NV_PRAMDAC_NVPLL_COEFF) ++ ptimer->init(dev); ++ + kfree(state); + } + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv04_timer.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_timer.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv04_timer.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv04_timer.c 2011-07-26 07:03:44.460051412 +0200 +@@ -6,43 +6,75 @@ + int + nv04_timer_init(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 m, n, d; ++ + nv_wr32(dev, NV04_PTIMER_INTR_EN_0, 0x00000000); + nv_wr32(dev, NV04_PTIMER_INTR_0, 0xFFFFFFFF); + +- /* Just use the pre-existing values when possible for now; these regs +- * are not written in nv (driver writer missed a /4 on the address), and +- * writing 8 and 3 to the correct regs breaks the timings on the LVDS +- * hardware sequencing microcode. +- * A correct solution (involving calculations with the GPU PLL) can +- * be done when kernel modesetting lands +- */ +- if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || +- !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { +- nv_wr32(dev, NV04_PTIMER_NUMERATOR, 0x00000008); +- nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 0x00000003); ++ /* aim for 31.25MHz, which gives us nanosecond timestamps */ ++ d = 1000000 / 32; ++ ++ /* determine base clock for timer source */ ++ if (dev_priv->chipset < 0x40) { ++ n = dev_priv->engine.pm.clock_get(dev, PLL_CORE); ++ } else ++ if (dev_priv->chipset == 0x40) { ++ /*XXX: figure this out */ ++ n = 0; ++ } else { ++ n = dev_priv->crystal; ++ m = 1; ++ while (n < (d * 2)) { ++ n += (n / m); ++ m++; ++ } ++ ++ nv_wr32(dev, 0x009220, m - 1); ++ } ++ ++ if (!n) { ++ NV_WARN(dev, "PTIMER: unknown input clock freq\n"); ++ if (!nv_rd32(dev, NV04_PTIMER_NUMERATOR) || ++ !nv_rd32(dev, NV04_PTIMER_DENOMINATOR)) { ++ nv_wr32(dev, NV04_PTIMER_NUMERATOR, 1); ++ nv_wr32(dev, NV04_PTIMER_DENOMINATOR, 1); ++ } ++ return 0; ++ } ++ ++ /* reduce ratio to acceptable values */ ++ while (((n % 5) == 0) && ((d % 5) == 0)) { ++ n /= 5; ++ d /= 5; + } + ++ while (((n % 2) == 0) && ((d % 2) == 0)) { ++ n /= 2; ++ d /= 2; ++ } ++ ++ while (n > 0xffff || d > 0xffff) { ++ n >>= 1; ++ d >>= 1; ++ } ++ ++ nv_wr32(dev, NV04_PTIMER_NUMERATOR, n); ++ nv_wr32(dev, NV04_PTIMER_DENOMINATOR, d); + return 0; + } + +-uint64_t ++u64 + nv04_timer_read(struct drm_device *dev) + { +- uint32_t low; +- /* From kmmio dumps on nv28 this looks like how the blob does this. +- * It reads the high dword twice, before and after. +- * The only explanation seems to be that the 64-bit timer counter +- * advances between high and low dword reads and may corrupt the +- * result. Not confirmed. +- */ +- uint32_t high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); +- uint32_t high1; ++ u32 hi, lo; ++ + do { +- high1 = high2; +- low = nv_rd32(dev, NV04_PTIMER_TIME_0); +- high2 = nv_rd32(dev, NV04_PTIMER_TIME_1); +- } while (high1 != high2); +- return (((uint64_t)high2) << 32) | (uint64_t)low; ++ hi = nv_rd32(dev, NV04_PTIMER_TIME_1); ++ lo = nv_rd32(dev, NV04_PTIMER_TIME_0); ++ } while (hi != nv_rd32(dev, NV04_PTIMER_TIME_1)); ++ ++ return ((u64)hi << 32 | lo); + } + + void +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv10_graph.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv10_graph.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv10_graph.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv10_graph.c 2011-07-26 07:03:44.461051424 +0200 +@@ -708,8 +708,8 @@ + 0x2c000000 | chan->id << 20 | subchan << 16 | 0x18c); + nv_wr32(dev, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nv_mask(dev, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); +- nv04_graph_fifo_access(dev, true); +- nv04_graph_fifo_access(dev, false); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + + /* Restore the FIFO state */ + for (i = 0; i < ARRAY_SIZE(fifo); i++) +@@ -879,13 +879,13 @@ + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv04_graph_fifo_access(dev, false); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + + /* Unload the context if it's the currently active one */ + if (nv10_graph_channel(dev) == chan) + nv10_graph_unload_context(dev); + +- nv04_graph_fifo_access(dev, true); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ +@@ -957,8 +957,13 @@ + } + + static int +-nv10_graph_fini(struct drm_device *dev, int engine) ++nv10_graph_fini(struct drm_device *dev, int engine, bool suspend) + { ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) { ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); ++ return -EBUSY; ++ } + nv10_graph_unload_context(dev); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + return 0; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv20_graph.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv20_graph.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv20_graph.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv20_graph.c 2011-07-26 07:03:44.461051424 +0200 +@@ -454,13 +454,13 @@ + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv04_graph_fifo_access(dev, false); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + + /* Unload the context if it's the currently active one */ + if (nv10_graph_channel(dev) == chan) + nv20_graph_unload_context(dev); + +- nv04_graph_fifo_access(dev, true); ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ +@@ -654,8 +654,13 @@ + } + + int +-nv20_graph_fini(struct drm_device *dev, int engine) ++nv20_graph_fini(struct drm_device *dev, int engine, bool suspend) + { ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, NV04_PGRAPH_STATUS, ~0, 0) && suspend) { ++ nv_mask(dev, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); ++ return -EBUSY; ++ } + nv20_graph_unload_context(dev); + nv_wr32(dev, NV03_PGRAPH_INTR_EN, 0x00000000); + return 0; +@@ -753,6 +758,7 @@ + break; + default: + NV_ERROR(dev, "PGRAPH: unknown chipset\n"); ++ kfree(pgraph); + return 0; + } + } else { +@@ -774,6 +780,7 @@ + break; + default: + NV_ERROR(dev, "PGRAPH: unknown chipset\n"); ++ kfree(pgraph); + return 0; + } + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv31_mpeg.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv31_mpeg.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv31_mpeg.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv31_mpeg.c 2011-07-26 07:03:44.462051436 +0200 +@@ -0,0 +1,344 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_ramht.h" ++ ++struct nv31_mpeg_engine { ++ struct nouveau_exec_engine base; ++ atomic_t refcount; ++}; ++ ++ ++static int ++nv31_mpeg_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); ++ ++ if (!atomic_add_unless(&pmpeg->refcount, 1, 1)) ++ return -EBUSY; ++ ++ chan->engctx[engine] = (void *)0xdeadcafe; ++ return 0; ++} ++ ++static void ++nv31_mpeg_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct nv31_mpeg_engine *pmpeg = nv_engine(chan->dev, engine); ++ atomic_dec(&pmpeg->refcount); ++ chan->engctx[engine] = NULL; ++} ++ ++static int ++nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_device *dev = chan->dev; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ctx = NULL; ++ unsigned long flags; ++ int ret; ++ ++ NV_DEBUG(dev, "ch%d\n", chan->id); ++ ++ ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &ctx); ++ if (ret) ++ return ret; ++ ++ nv_wo32(ctx, 0x78, 0x02001ec1); ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000000); ++ if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) ++ nv_wr32(dev, 0x00330c, ctx->pinst >> 4); ++ nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); ++ nv_mask(dev, 0x002500, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ chan->engctx[engine] = ctx; ++ return 0; ++} ++ ++static void ++nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = chan->dev->dev_private; ++ struct nouveau_gpuobj *ctx = chan->engctx[engine]; ++ struct drm_device *dev = chan->dev; ++ unsigned long flags; ++ u32 inst = 0x80000000 | (ctx->pinst >> 4); ++ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ if (nv_rd32(dev, 0x00b318) == inst) ++ nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ ++ nouveau_gpuobj_ref(NULL, &ctx); ++ chan->engctx[engine] = NULL; ++} ++ ++static int ++nv31_mpeg_object_new(struct nouveau_channel *chan, int engine, ++ u32 handle, u16 class) ++{ ++ struct drm_device *dev = chan->dev; ++ struct nouveau_gpuobj *obj = NULL; ++ int ret; ++ ++ ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | ++ NVOBJ_FLAG_ZERO_FREE, &obj); ++ if (ret) ++ return ret; ++ obj->engine = 2; ++ obj->class = class; ++ ++ nv_wo32(obj, 0x00, class); ++ ++ ret = nouveau_ramht_insert(chan, handle, obj); ++ nouveau_gpuobj_ref(NULL, &obj); ++ return ret; ++} ++ ++static int ++nv31_mpeg_init(struct drm_device *dev, int engine) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ int i; ++ ++ /* VPE init */ ++ nv_mask(dev, 0x000200, 0x00000002, 0x00000000); ++ nv_mask(dev, 0x000200, 0x00000002, 0x00000002); ++ nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ ++ nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ ++ ++ for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) ++ pmpeg->base.set_tile_region(dev, i); ++ ++ /* PMPEG init */ ++ nv_wr32(dev, 0x00b32c, 0x00000000); ++ nv_wr32(dev, 0x00b314, 0x00000100); ++ nv_wr32(dev, 0x00b220, nv44_graph_class(dev) ? 0x00000044 : 0x00000031); ++ nv_wr32(dev, 0x00b300, 0x02001ec1); ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); ++ ++ nv_wr32(dev, 0x00b100, 0xffffffff); ++ nv_wr32(dev, 0x00b140, 0xffffffff); ++ ++ if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { ++ NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); ++ return -EBUSY; ++ } ++ ++ return 0; ++} ++ ++static int ++nv31_mpeg_fini(struct drm_device *dev, int engine, bool suspend) ++{ ++ /*XXX: context save? */ ++ nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); ++ nv_wr32(dev, 0x00b140, 0x00000000); ++ return 0; ++} ++ ++static int ++nv31_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) ++{ ++ struct drm_device *dev = chan->dev; ++ u32 inst = data << 4; ++ u32 dma0 = nv_ri32(dev, inst + 0); ++ u32 dma1 = nv_ri32(dev, inst + 4); ++ u32 dma2 = nv_ri32(dev, inst + 8); ++ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); ++ u32 size = dma1 + 1; ++ ++ /* only allow linear DMA objects */ ++ if (!(dma0 & 0x00002000)) ++ return -EINVAL; ++ ++ if (mthd == 0x0190) { ++ /* DMA_CMD */ ++ nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); ++ nv_wr32(dev, 0x00b334, base); ++ nv_wr32(dev, 0x00b324, size); ++ } else ++ if (mthd == 0x01a0) { ++ /* DMA_DATA */ ++ nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); ++ nv_wr32(dev, 0x00b360, base); ++ nv_wr32(dev, 0x00b364, size); ++ } else { ++ /* DMA_IMAGE, VRAM only */ ++ if (dma0 & 0x000c0000) ++ return -EINVAL; ++ ++ nv_wr32(dev, 0x00b370, base); ++ nv_wr32(dev, 0x00b374, size); ++ } ++ ++ return 0; ++} ++ ++static int ++nv31_mpeg_isr_chid(struct drm_device *dev, u32 inst) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_gpuobj *ctx; ++ unsigned long flags; ++ int i; ++ ++ /* hardcode drm channel id on nv3x, so swmthd lookup works */ ++ if (dev_priv->card_type < NV_40) ++ return 0; ++ ++ spin_lock_irqsave(&dev_priv->channels.lock, flags); ++ for (i = 0; i < dev_priv->engine.fifo.channels; i++) { ++ if (!dev_priv->channels.ptr[i]) ++ continue; ++ ++ ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; ++ if (ctx && ctx->pinst == inst) ++ break; ++ } ++ spin_unlock_irqrestore(&dev_priv->channels.lock, flags); ++ return i; ++} ++ ++static void ++nv31_vpe_set_tile_region(struct drm_device *dev, int i) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; ++ ++ nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); ++ nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); ++ nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); ++} ++ ++static void ++nv31_mpeg_isr(struct drm_device *dev) ++{ ++ u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; ++ u32 chid = nv31_mpeg_isr_chid(dev, inst); ++ u32 stat = nv_rd32(dev, 0x00b100); ++ u32 type = nv_rd32(dev, 0x00b230); ++ u32 mthd = nv_rd32(dev, 0x00b234); ++ u32 data = nv_rd32(dev, 0x00b238); ++ u32 show = stat; ++ ++ if (stat & 0x01000000) { ++ /* happens on initial binding of the object */ ++ if (type == 0x00000020 && mthd == 0x0000) { ++ nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); ++ show &= ~0x01000000; ++ } ++ ++ if (type == 0x00000010) { ++ if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) ++ show &= ~0x01000000; ++ } ++ } ++ ++ nv_wr32(dev, 0x00b100, stat); ++ nv_wr32(dev, 0x00b230, 0x00000001); ++ ++ if (show && nouveau_ratelimit()) { ++ NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", ++ chid, inst, stat, type, mthd, data); ++ } ++} ++ ++static void ++nv31_vpe_isr(struct drm_device *dev) ++{ ++ if (nv_rd32(dev, 0x00b100)) ++ nv31_mpeg_isr(dev); ++ ++ if (nv_rd32(dev, 0x00b800)) { ++ u32 stat = nv_rd32(dev, 0x00b800); ++ NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); ++ nv_wr32(dev, 0xb800, stat); ++ } ++} ++ ++static void ++nv31_mpeg_destroy(struct drm_device *dev, int engine) ++{ ++ struct nv31_mpeg_engine *pmpeg = nv_engine(dev, engine); ++ ++ nouveau_irq_unregister(dev, 0); ++ ++ NVOBJ_ENGINE_DEL(dev, MPEG); ++ kfree(pmpeg); ++} ++ ++int ++nv31_mpeg_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nv31_mpeg_engine *pmpeg; ++ ++ pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); ++ if (!pmpeg) ++ return -ENOMEM; ++ atomic_set(&pmpeg->refcount, 0); ++ ++ pmpeg->base.destroy = nv31_mpeg_destroy; ++ pmpeg->base.init = nv31_mpeg_init; ++ pmpeg->base.fini = nv31_mpeg_fini; ++ if (dev_priv->card_type < NV_40) { ++ pmpeg->base.context_new = nv31_mpeg_context_new; ++ pmpeg->base.context_del = nv31_mpeg_context_del; ++ } else { ++ pmpeg->base.context_new = nv40_mpeg_context_new; ++ pmpeg->base.context_del = nv40_mpeg_context_del; ++ } ++ pmpeg->base.object_new = nv31_mpeg_object_new; ++ ++ /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between ++ * all VPE engines, for this driver's purposes the PMPEG engine ++ * will be treated as the "master" and handle the global VPE ++ * bits too ++ */ ++ pmpeg->base.set_tile_region = nv31_vpe_set_tile_region; ++ nouveau_irq_register(dev, 0, nv31_vpe_isr); ++ ++ NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); ++ NVOBJ_CLASS(dev, 0x3174, MPEG); ++ NVOBJ_MTHD (dev, 0x3174, 0x0190, nv31_mpeg_mthd_dma); ++ NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv31_mpeg_mthd_dma); ++ NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv31_mpeg_mthd_dma); ++ ++#if 0 ++ NVOBJ_ENGINE_ADD(dev, ME, &pme->base); ++ NVOBJ_CLASS(dev, 0x4075, ME); ++#endif ++ return 0; ++ ++} +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv40_graph.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv40_graph.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv40_graph.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv40_graph.c 2011-07-26 07:03:44.463051448 +0200 +@@ -35,89 +35,6 @@ + u32 grctx_size; + }; + +-static struct nouveau_channel * +-nv40_graph_channel(struct drm_device *dev) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *grctx; +- uint32_t inst; +- int i; +- +- inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR); +- if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED)) +- return NULL; +- inst = (inst & NV40_PGRAPH_CTXCTL_CUR_INSTANCE) << 4; +- +- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { +- if (!dev_priv->channels.ptr[i]) +- continue; +- +- grctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_GR]; +- if (grctx && grctx->pinst == inst) +- return dev_priv->channels.ptr[i]; +- } +- +- return NULL; +-} +- +-static int +-nv40_graph_transfer_context(struct drm_device *dev, uint32_t inst, int save) +-{ +- uint32_t old_cp, tv = 1000, tmp; +- int i; +- +- old_cp = nv_rd32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER); +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, inst); +- +- tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0310); +- tmp |= save ? NV40_PGRAPH_CTXCTL_0310_XFER_SAVE : +- NV40_PGRAPH_CTXCTL_0310_XFER_LOAD; +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_0310, tmp); +- +- tmp = nv_rd32(dev, NV40_PGRAPH_CTXCTL_0304); +- tmp |= NV40_PGRAPH_CTXCTL_0304_XFER_CTX; +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_0304, tmp); +- +- nouveau_wait_for_idle(dev); +- +- for (i = 0; i < tv; i++) { +- if (nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C) == 0) +- break; +- } +- +- nv_wr32(dev, NV20_PGRAPH_CHANNEL_CTX_POINTER, old_cp); +- +- if (i == tv) { +- uint32_t ucstat = nv_rd32(dev, NV40_PGRAPH_CTXCTL_UCODE_STAT); +- NV_ERROR(dev, "Failed: Instance=0x%08x Save=%d\n", inst, save); +- NV_ERROR(dev, "IP: 0x%02x, Opcode: 0x%08x\n", +- ucstat >> NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT, +- ucstat & NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK); +- NV_ERROR(dev, "0x40030C = 0x%08x\n", +- nv_rd32(dev, NV40_PGRAPH_CTXCTL_030C)); +- return -EBUSY; +- } +- +- return 0; +-} +- +-static int +-nv40_graph_unload_context(struct drm_device *dev) +-{ +- uint32_t inst; +- int ret; +- +- inst = nv_rd32(dev, NV40_PGRAPH_CTXCTL_CUR); +- if (!(inst & NV40_PGRAPH_CTXCTL_CUR_LOADED)) +- return 0; +- inst &= NV40_PGRAPH_CTXCTL_CUR_INSTANCE; +- +- ret = nv40_graph_transfer_context(dev, inst, 1); +- +- nv_wr32(dev, NV40_PGRAPH_CTXCTL_CUR, inst); +- return ret; +-} +- + static int + nv40_graph_context_new(struct nouveau_channel *chan, int engine) + { +@@ -163,16 +80,16 @@ + struct nouveau_gpuobj *grctx = chan->engctx[engine]; + struct drm_device *dev = chan->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 inst = 0x01000000 | (grctx->pinst >> 4); + unsigned long flags; + + spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv04_graph_fifo_access(dev, false); +- +- /* Unload the context if it's the currently active one */ +- if (nv40_graph_channel(dev) == chan) +- nv40_graph_unload_context(dev); +- +- nv04_graph_fifo_access(dev, true); ++ nv_mask(dev, 0x400720, 0x00000000, 0x00000001); ++ if (nv_rd32(dev, 0x40032c) == inst) ++ nv_mask(dev, 0x40032c, 0x01000000, 0x00000000); ++ if (nv_rd32(dev, 0x400330) == inst) ++ nv_mask(dev, 0x400330, 0x01000000, 0x00000000); ++ nv_mask(dev, 0x400720, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); + + /* Free the context resources */ +@@ -429,9 +346,20 @@ + } + + static int +-nv40_graph_fini(struct drm_device *dev, int engine) ++nv40_graph_fini(struct drm_device *dev, int engine, bool suspend) + { +- nv40_graph_unload_context(dev); ++ u32 inst = nv_rd32(dev, 0x40032c); ++ if (inst & 0x01000000) { ++ nv_wr32(dev, 0x400720, 0x00000000); ++ nv_wr32(dev, 0x400784, inst); ++ nv_mask(dev, 0x400310, 0x00000020, 0x00000020); ++ nv_mask(dev, 0x400304, 0x00000001, 0x00000001); ++ if (!nv_wait(dev, 0x400300, 0x00000001, 0x00000000)) { ++ u32 insn = nv_rd32(dev, 0x400308); ++ NV_ERROR(dev, "PGRAPH: ctxprog timeout 0x%08x\n", insn); ++ } ++ nv_mask(dev, 0x40032c, 0x01000000, 0x00000000); ++ } + return 0; + } + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv40_mpeg.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv40_mpeg.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv40_mpeg.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv40_mpeg.c 1970-01-01 01:00:00.000000000 +0100 +@@ -1,311 +0,0 @@ +-/* +- * Copyright 2011 Red Hat Inc. +- * +- * Permission is hereby granted, free of charge, to any person obtaining a +- * copy of this software and associated documentation files (the "Software"), +- * to deal in the Software without restriction, including without limitation +- * the rights to use, copy, modify, merge, publish, distribute, sublicense, +- * and/or sell copies of the Software, and to permit persons to whom the +- * Software is furnished to do so, subject to the following conditions: +- * +- * The above copyright notice and this permission notice shall be included in +- * all copies or substantial portions of the Software. +- * +- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +- * OTHER DEALINGS IN THE SOFTWARE. +- * +- * Authors: Ben Skeggs +- */ +- +-#include "drmP.h" +-#include "nouveau_drv.h" +-#include "nouveau_ramht.h" +- +-struct nv40_mpeg_engine { +- struct nouveau_exec_engine base; +-}; +- +-static int +-nv40_mpeg_context_new(struct nouveau_channel *chan, int engine) +-{ +- struct drm_device *dev = chan->dev; +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *ctx = NULL; +- unsigned long flags; +- int ret; +- +- NV_DEBUG(dev, "ch%d\n", chan->id); +- +- ret = nouveau_gpuobj_new(dev, NULL, 264 * 4, 16, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &ctx); +- if (ret) +- return ret; +- +- nv_wo32(ctx, 0x78, 0x02001ec1); +- +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv_mask(dev, 0x002500, 0x00000001, 0x00000000); +- if ((nv_rd32(dev, 0x003204) & 0x1f) == chan->id) +- nv_wr32(dev, 0x00330c, ctx->pinst >> 4); +- nv_wo32(chan->ramfc, 0x54, ctx->pinst >> 4); +- nv_mask(dev, 0x002500, 0x00000001, 0x00000001); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- +- chan->engctx[engine] = ctx; +- return 0; +-} +- +-static void +-nv40_mpeg_context_del(struct nouveau_channel *chan, int engine) +-{ +- struct drm_nouveau_private *dev_priv = chan->dev->dev_private; +- struct nouveau_gpuobj *ctx = chan->engctx[engine]; +- struct drm_device *dev = chan->dev; +- unsigned long flags; +- u32 inst = 0x80000000 | (ctx->pinst >> 4); +- +- spin_lock_irqsave(&dev_priv->context_switch_lock, flags); +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); +- if (nv_rd32(dev, 0x00b318) == inst) +- nv_mask(dev, 0x00b318, 0x80000000, 0x00000000); +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); +- spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); +- +- nouveau_gpuobj_ref(NULL, &ctx); +- chan->engctx[engine] = NULL; +-} +- +-static int +-nv40_mpeg_object_new(struct nouveau_channel *chan, int engine, +- u32 handle, u16 class) +-{ +- struct drm_device *dev = chan->dev; +- struct nouveau_gpuobj *obj = NULL; +- int ret; +- +- ret = nouveau_gpuobj_new(dev, chan, 20, 16, NVOBJ_FLAG_ZERO_ALLOC | +- NVOBJ_FLAG_ZERO_FREE, &obj); +- if (ret) +- return ret; +- obj->engine = 2; +- obj->class = class; +- +- nv_wo32(obj, 0x00, class); +- +- ret = nouveau_ramht_insert(chan, handle, obj); +- nouveau_gpuobj_ref(NULL, &obj); +- return ret; +-} +- +-static int +-nv40_mpeg_init(struct drm_device *dev, int engine) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); +- int i; +- +- /* VPE init */ +- nv_mask(dev, 0x000200, 0x00000002, 0x00000000); +- nv_mask(dev, 0x000200, 0x00000002, 0x00000002); +- nv_wr32(dev, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ +- nv_wr32(dev, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ +- +- for (i = 0; i < dev_priv->engine.fb.num_tiles; i++) +- pmpeg->base.set_tile_region(dev, i); +- +- /* PMPEG init */ +- nv_wr32(dev, 0x00b32c, 0x00000000); +- nv_wr32(dev, 0x00b314, 0x00000100); +- nv_wr32(dev, 0x00b220, 0x00000044); +- nv_wr32(dev, 0x00b300, 0x02001ec1); +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000001); +- +- nv_wr32(dev, 0x00b100, 0xffffffff); +- nv_wr32(dev, 0x00b140, 0xffffffff); +- +- if (!nv_wait(dev, 0x00b200, 0x00000001, 0x00000000)) { +- NV_ERROR(dev, "PMPEG init: 0x%08x\n", nv_rd32(dev, 0x00b200)); +- return -EBUSY; +- } +- +- return 0; +-} +- +-static int +-nv40_mpeg_fini(struct drm_device *dev, int engine) +-{ +- /*XXX: context save? */ +- nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); +- nv_wr32(dev, 0x00b140, 0x00000000); +- return 0; +-} +- +-static int +-nv40_mpeg_mthd_dma(struct nouveau_channel *chan, u32 class, u32 mthd, u32 data) +-{ +- struct drm_device *dev = chan->dev; +- u32 inst = data << 4; +- u32 dma0 = nv_ri32(dev, inst + 0); +- u32 dma1 = nv_ri32(dev, inst + 4); +- u32 dma2 = nv_ri32(dev, inst + 8); +- u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); +- u32 size = dma1 + 1; +- +- /* only allow linear DMA objects */ +- if (!(dma0 & 0x00002000)) +- return -EINVAL; +- +- if (mthd == 0x0190) { +- /* DMA_CMD */ +- nv_mask(dev, 0x00b300, 0x00030000, (dma0 & 0x00030000)); +- nv_wr32(dev, 0x00b334, base); +- nv_wr32(dev, 0x00b324, size); +- } else +- if (mthd == 0x01a0) { +- /* DMA_DATA */ +- nv_mask(dev, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); +- nv_wr32(dev, 0x00b360, base); +- nv_wr32(dev, 0x00b364, size); +- } else { +- /* DMA_IMAGE, VRAM only */ +- if (dma0 & 0x000c0000) +- return -EINVAL; +- +- nv_wr32(dev, 0x00b370, base); +- nv_wr32(dev, 0x00b374, size); +- } +- +- return 0; +-} +- +-static int +-nv40_mpeg_isr_chid(struct drm_device *dev, u32 inst) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_gpuobj *ctx; +- unsigned long flags; +- int i; +- +- spin_lock_irqsave(&dev_priv->channels.lock, flags); +- for (i = 0; i < dev_priv->engine.fifo.channels; i++) { +- if (!dev_priv->channels.ptr[i]) +- continue; +- +- ctx = dev_priv->channels.ptr[i]->engctx[NVOBJ_ENGINE_MPEG]; +- if (ctx && ctx->pinst == inst) +- break; +- } +- spin_unlock_irqrestore(&dev_priv->channels.lock, flags); +- return i; +-} +- +-static void +-nv40_vpe_set_tile_region(struct drm_device *dev, int i) +-{ +- struct drm_nouveau_private *dev_priv = dev->dev_private; +- struct nouveau_tile_reg *tile = &dev_priv->tile.reg[i]; +- +- nv_wr32(dev, 0x00b008 + (i * 0x10), tile->pitch); +- nv_wr32(dev, 0x00b004 + (i * 0x10), tile->limit); +- nv_wr32(dev, 0x00b000 + (i * 0x10), tile->addr); +-} +- +-static void +-nv40_mpeg_isr(struct drm_device *dev) +-{ +- u32 inst = (nv_rd32(dev, 0x00b318) & 0x000fffff) << 4; +- u32 chid = nv40_mpeg_isr_chid(dev, inst); +- u32 stat = nv_rd32(dev, 0x00b100); +- u32 type = nv_rd32(dev, 0x00b230); +- u32 mthd = nv_rd32(dev, 0x00b234); +- u32 data = nv_rd32(dev, 0x00b238); +- u32 show = stat; +- +- if (stat & 0x01000000) { +- /* happens on initial binding of the object */ +- if (type == 0x00000020 && mthd == 0x0000) { +- nv_mask(dev, 0x00b308, 0x00000000, 0x00000000); +- show &= ~0x01000000; +- } +- +- if (type == 0x00000010) { +- if (!nouveau_gpuobj_mthd_call2(dev, chid, 0x3174, mthd, data)) +- show &= ~0x01000000; +- } +- } +- +- nv_wr32(dev, 0x00b100, stat); +- nv_wr32(dev, 0x00b230, 0x00000001); +- +- if (show && nouveau_ratelimit()) { +- NV_INFO(dev, "PMPEG: Ch %d [0x%08x] 0x%08x 0x%08x 0x%08x 0x%08x\n", +- chid, inst, stat, type, mthd, data); +- } +-} +- +-static void +-nv40_vpe_isr(struct drm_device *dev) +-{ +- if (nv_rd32(dev, 0x00b100)) +- nv40_mpeg_isr(dev); +- +- if (nv_rd32(dev, 0x00b800)) { +- u32 stat = nv_rd32(dev, 0x00b800); +- NV_INFO(dev, "PMSRCH: 0x%08x\n", stat); +- nv_wr32(dev, 0xb800, stat); +- } +-} +- +-static void +-nv40_mpeg_destroy(struct drm_device *dev, int engine) +-{ +- struct nv40_mpeg_engine *pmpeg = nv_engine(dev, engine); +- +- nouveau_irq_unregister(dev, 0); +- +- NVOBJ_ENGINE_DEL(dev, MPEG); +- kfree(pmpeg); +-} +- +-int +-nv40_mpeg_create(struct drm_device *dev) +-{ +- struct nv40_mpeg_engine *pmpeg; +- +- pmpeg = kzalloc(sizeof(*pmpeg), GFP_KERNEL); +- if (!pmpeg) +- return -ENOMEM; +- +- pmpeg->base.destroy = nv40_mpeg_destroy; +- pmpeg->base.init = nv40_mpeg_init; +- pmpeg->base.fini = nv40_mpeg_fini; +- pmpeg->base.context_new = nv40_mpeg_context_new; +- pmpeg->base.context_del = nv40_mpeg_context_del; +- pmpeg->base.object_new = nv40_mpeg_object_new; +- +- /* ISR vector, PMC_ENABLE bit, and TILE regs are shared between +- * all VPE engines, for this driver's purposes the PMPEG engine +- * will be treated as the "master" and handle the global VPE +- * bits too +- */ +- pmpeg->base.set_tile_region = nv40_vpe_set_tile_region; +- nouveau_irq_register(dev, 0, nv40_vpe_isr); +- +- NVOBJ_ENGINE_ADD(dev, MPEG, &pmpeg->base); +- NVOBJ_CLASS(dev, 0x3174, MPEG); +- NVOBJ_MTHD (dev, 0x3174, 0x0190, nv40_mpeg_mthd_dma); +- NVOBJ_MTHD (dev, 0x3174, 0x01a0, nv40_mpeg_mthd_dma); +- NVOBJ_MTHD (dev, 0x3174, 0x01b0, nv40_mpeg_mthd_dma); +- +-#if 0 +- NVOBJ_ENGINE_ADD(dev, ME, &pme->base); +- NVOBJ_CLASS(dev, 0x4075, ME); +-#endif +- return 0; +- +-} +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_crtc.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_crtc.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_crtc.c 2011-07-26 07:03:44.488051747 +0200 +@@ -104,7 +104,7 @@ + OUT_RING(evo, nv_crtc->lut.depth == 8 ? + NV50_EVO_CRTC_CLUT_MODE_OFF : + NV50_EVO_CRTC_CLUT_MODE_ON); +- OUT_RING(evo, (nv_crtc->lut.nvbo->bo.mem.start << PAGE_SHIFT) >> 8); ++ OUT_RING(evo, nv_crtc->lut.nvbo->bo.offset >> 8); + if (dev_priv->chipset != 0x50) { + BEGIN_RING(evo, 0, NV84_EVO_CRTC(index, CLUT_DMA), 1); + OUT_RING(evo, NvEvoVRAM); +@@ -329,8 +329,6 @@ + + drm_crtc_cleanup(&nv_crtc->base); + +- nv50_cursor_fini(nv_crtc); +- + nouveau_bo_unmap(nv_crtc->lut.nvbo); + nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); + nouveau_bo_unmap(nv_crtc->cursor.nvbo); +@@ -372,7 +370,7 @@ + + nouveau_bo_unmap(cursor); + +- nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.mem.start << PAGE_SHIFT); ++ nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset); + nv_crtc->cursor.show(nv_crtc, true); + + out: +@@ -546,7 +544,7 @@ + } + } + +- nv_crtc->fb.offset = fb->nvbo->bo.mem.start << PAGE_SHIFT; ++ nv_crtc->fb.offset = fb->nvbo->bo.offset; + 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) { +@@ -747,7 +745,7 @@ + } + nv_crtc->lut.depth = 0; + +- ret = nouveau_bo_new(dev, NULL, 4096, 0x100, TTM_PL_FLAG_VRAM, ++ ret = nouveau_bo_new(dev, 4096, 0x100, TTM_PL_FLAG_VRAM, + 0, 0x0000, &nv_crtc->lut.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); +@@ -773,7 +771,7 @@ + drm_crtc_helper_add(&nv_crtc->base, &nv50_crtc_helper_funcs); + drm_mode_crtc_set_gamma_size(&nv_crtc->base, 256); + +- ret = nouveau_bo_new(dev, NULL, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, ++ ret = nouveau_bo_new(dev, 64*64*4, 0x100, TTM_PL_FLAG_VRAM, + 0, 0x0000, &nv_crtc->cursor.nvbo); + if (!ret) { + ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_cursor.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_cursor.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_cursor.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_cursor.c 2011-07-26 07:03:44.489051759 +0200 +@@ -137,21 +137,3 @@ + nv_crtc->cursor.show = nv50_cursor_show; + return 0; + } +- +-void +-nv50_cursor_fini(struct nouveau_crtc *nv_crtc) +-{ +- struct drm_device *dev = nv_crtc->base.dev; +- int idx = nv_crtc->index; +- +- NV_DEBUG_KMS(dev, "\n"); +- +- nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), 0); +- if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx), +- NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { +- NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); +- NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", +- nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(idx))); +- } +-} +- +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_display.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_display.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_display.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_display.c 2011-07-26 07:03:44.490051771 +0200 +@@ -247,6 +247,16 @@ + } + } + ++ for (i = 0; i < 2; i++) { ++ nv_wr32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), 0); ++ if (!nv_wait(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i), ++ NV50_PDISPLAY_CURSOR_CURSOR_CTRL2_STATUS, 0)) { ++ NV_ERROR(dev, "timeout: CURSOR_CTRL2_STATUS == 0\n"); ++ NV_ERROR(dev, "CURSOR_CTRL2 = 0x%08x\n", ++ nv_rd32(dev, NV50_PDISPLAY_CURSOR_CURSOR_CTRL2(i))); ++ } ++ } ++ + nv50_evo_fini(dev); + + for (i = 0; i < 3; i++) { +@@ -286,23 +296,6 @@ + return -ENOMEM; + dev_priv->engine.display.priv = priv; + +- /* init basic kernel modesetting */ +- drm_mode_config_init(dev); +- +- /* Initialise some optional connector properties. */ +- drm_mode_create_scaling_mode_property(dev); +- drm_mode_create_dithering_property(dev); +- +- dev->mode_config.min_width = 0; +- dev->mode_config.min_height = 0; +- +- dev->mode_config.funcs = (void *)&nouveau_mode_config_funcs; +- +- dev->mode_config.max_width = 8192; +- dev->mode_config.max_height = 8192; +- +- dev->mode_config.fb_base = dev_priv->fb_phys; +- + /* Create CRTC objects */ + for (i = 0; i < 2; i++) + nv50_crtc_create(dev, i); +@@ -364,8 +357,6 @@ + + NV_DEBUG_KMS(dev, "\n"); + +- drm_mode_config_cleanup(dev); +- + nv50_display_disable(dev); + nouveau_irq_unregister(dev, 26); + kfree(disp); +@@ -415,8 +406,6 @@ + + /* 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); +@@ -438,6 +427,8 @@ + else + OUT_RING (chan, chan->vram_handle); + } else { ++ u64 offset = chan->dispc_vma[nv_crtc->index].offset; ++ offset += dispc->sem.offset; + BEGIN_NVC0(chan, 2, NvSubM2MF, 0x0010, 4); + OUT_RING (chan, upper_32_bits(offset)); + OUT_RING (chan, lower_32_bits(offset)); +@@ -484,7 +475,7 @@ + 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, nv_fb->nvbo->bo.offset >> 8); + OUT_RING (evo, 0); + OUT_RING (evo, (fb->height << 16) | fb->width); + OUT_RING (evo, nv_fb->r_pitch); +@@ -698,7 +689,7 @@ + struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; + + if (dcb->type == type && (dcb->or & (1 << or))) { +- nouveau_bios_run_display_table(dev, dcb, 0, -1); ++ nouveau_bios_run_display_table(dev, 0, -1, dcb, -1); + disp->irq.dcb = dcb; + goto ack; + } +@@ -753,7 +744,7 @@ + NV_DEBUG_KMS(dev, "0x610030: 0x%08x\n", unk30); + dcb = disp->irq.dcb; + if (dcb) { +- nouveau_bios_run_display_table(dev, dcb, 0, -2); ++ nouveau_bios_run_display_table(dev, 0, -2, dcb, -1); + disp->irq.dcb = NULL; + } + +@@ -837,7 +828,7 @@ + } + + script = nv50_display_script_select(dev, dcb, mc, pclk); +- nouveau_bios_run_display_table(dev, dcb, script, pclk); ++ nouveau_bios_run_display_table(dev, script, pclk, dcb, -1); + + nv50_display_unk20_dp_hack(dev, dcb); + +@@ -904,7 +895,7 @@ + if (!dcb) + goto ack; + +- nouveau_bios_run_display_table(dev, dcb, script, -pclk); ++ nouveau_bios_run_display_table(dev, script, -pclk, dcb, -1); + nv50_display_unk40_dp_set_tmds(dev, dcb); + + ack: +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_evo.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_evo.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_evo.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_evo.c 2011-07-26 07:03:44.490051771 +0200 +@@ -38,6 +38,7 @@ + return; + *pevo = NULL; + ++ nouveau_ramht_ref(NULL, &evo->ramht, evo); + nouveau_gpuobj_channel_takedown(evo); + nouveau_bo_unmap(evo->pushbuf_bo); + nouveau_bo_ref(NULL, &evo->pushbuf_bo); +@@ -116,7 +117,7 @@ + evo->user_get = 4; + evo->user_put = 0; + +- ret = nouveau_bo_new(dev, NULL, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, ++ ret = nouveau_bo_new(dev, 4096, 0, TTM_PL_FLAG_VRAM, 0, 0, + &evo->pushbuf_bo); + if (ret == 0) + ret = nouveau_bo_pin(evo->pushbuf_bo, TTM_PL_FLAG_VRAM); +@@ -153,7 +154,7 @@ + { + struct drm_device *dev = evo->dev; + int id = evo->id, ret, i; +- u64 pushbuf = evo->pushbuf_bo->bo.mem.start << PAGE_SHIFT; ++ u64 pushbuf = evo->pushbuf_bo->bo.offset; + u32 tmp; + + tmp = nv_rd32(dev, NV50_PDISPLAY_EVO_CTRL(id)); +@@ -331,16 +332,15 @@ + if (ret) + goto err; + +- ret = nouveau_bo_new(dev, NULL, 4096, 0x1000, TTM_PL_FLAG_VRAM, ++ ret = nouveau_bo_new(dev, 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); ++ offset = dispc->sem.bo->bo.offset; + } + + if (ret) +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_fbcon.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_fbcon.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_fbcon.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_fbcon.c 2011-07-26 07:03:44.492051795 +0200 +@@ -159,7 +159,7 @@ + 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; ++ struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; + int ret, format; + + switch (info->var.bits_per_pixel) { +@@ -247,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(nvbo->vma.offset)); +- OUT_RING(chan, lower_32_bits(nvbo->vma.offset)); ++ OUT_RING(chan, upper_32_bits(fb->vma.offset)); ++ OUT_RING(chan, lower_32_bits(fb->vma.offset)); + BEGIN_RING(chan, NvSub2D, 0x0230, 2); + OUT_RING(chan, format); + OUT_RING(chan, 1); +@@ -256,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(nvbo->vma.offset)); +- OUT_RING(chan, lower_32_bits(nvbo->vma.offset)); ++ OUT_RING(chan, upper_32_bits(fb->vma.offset)); ++ OUT_RING(chan, lower_32_bits(fb->vma.offset)); + + return 0; + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_gpio.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_gpio.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_gpio.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_gpio.c 2011-07-26 07:03:44.492051795 +0200 +@@ -98,6 +98,37 @@ + } + + int ++nvd0_gpio_get(struct drm_device *dev, enum dcb_gpio_tag tag) ++{ ++ struct dcb_gpio_entry *gpio; ++ u32 v; ++ ++ gpio = nouveau_bios_gpio_entry(dev, tag); ++ if (!gpio) ++ return -ENOENT; ++ ++ v = nv_rd32(dev, 0x00d610 + (gpio->line * 4)); ++ v &= 0x00004000; ++ return (!!v == (gpio->state[1] & 1)); ++} ++ ++int ++nvd0_gpio_set(struct drm_device *dev, enum dcb_gpio_tag tag, int state) ++{ ++ struct dcb_gpio_entry *gpio; ++ u32 v; ++ ++ gpio = nouveau_bios_gpio_entry(dev, tag); ++ if (!gpio) ++ return -ENOENT; ++ ++ v = gpio->state[state] ^ 2; ++ ++ nv_mask(dev, 0x00d610 + (gpio->line * 4), 0x00003000, v << 12); ++ return 0; ++} ++ ++int + nv50_gpio_irq_register(struct drm_device *dev, enum dcb_gpio_tag tag, + void (*handler)(void *, int), void *data) + { +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_graph.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_graph.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_graph.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_graph.c 2011-07-26 07:03:44.493051807 +0200 +@@ -125,7 +125,6 @@ + nv50_graph_init_reset(struct drm_device *dev) + { + uint32_t pmc_e = NV_PMC_ENABLE_PGRAPH | (1 << 21); +- + NV_DEBUG(dev, "\n"); + + nv_wr32(dev, NV03_PMC_ENABLE, nv_rd32(dev, NV03_PMC_ENABLE) & ~pmc_e); +@@ -255,9 +254,13 @@ + } + + static int +-nv50_graph_fini(struct drm_device *dev, int engine) ++nv50_graph_fini(struct drm_device *dev, int engine, bool suspend) + { +- NV_DEBUG(dev, "\n"); ++ nv_mask(dev, 0x400500, 0x00010001, 0x00000000); ++ if (!nv_wait(dev, 0x400700, ~0, 0) && suspend) { ++ nv_mask(dev, 0x400500, 0x00010001, 0x00010001); ++ return -EBUSY; ++ } + nv50_graph_unload_context(dev); + nv_wr32(dev, 0x40013c, 0x00000000); + return 0; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_grctx.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_grctx.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_grctx.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_grctx.c 2011-07-26 07:03:44.495051831 +0200 +@@ -40,6 +40,9 @@ + #define CP_FLAG_UNK0B ((0 * 32) + 0xb) + #define CP_FLAG_UNK0B_CLEAR 0 + #define CP_FLAG_UNK0B_SET 1 ++#define CP_FLAG_STATE ((0 * 32) + 0x1c) ++#define CP_FLAG_STATE_STOPPED 0 ++#define CP_FLAG_STATE_RUNNING 1 + #define CP_FLAG_UNK1D ((0 * 32) + 0x1d) + #define CP_FLAG_UNK1D_CLEAR 0 + #define CP_FLAG_UNK1D_SET 1 +@@ -194,6 +197,8 @@ + "the devs.\n"); + return -ENOSYS; + } ++ ++ cp_set (ctx, STATE, RUNNING); + /* decide whether we're loading/unloading the context */ + cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save); + cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save); +@@ -260,6 +265,7 @@ + cp_name(ctx, cp_exit); + cp_set (ctx, USER_SAVE, NOT_PENDING); + cp_set (ctx, USER_LOAD, NOT_PENDING); ++ cp_set (ctx, STATE, STOPPED); + cp_out (ctx, CP_END); + ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */ + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_instmem.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_instmem.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_instmem.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_instmem.c 2011-07-26 07:03:44.496051843 +0200 +@@ -305,9 +305,9 @@ + u32 align; + }; + +- + int +-nv50_instmem_get(struct nouveau_gpuobj *gpuobj, u32 size, u32 align) ++nv50_instmem_get(struct nouveau_gpuobj *gpuobj, struct nouveau_channel *chan, ++ u32 size, u32 align) + { + struct drm_device *dev = gpuobj->dev; + struct drm_nouveau_private *dev_priv = dev->dev_private; +@@ -336,7 +336,7 @@ + if (!(gpuobj->flags & NVOBJ_FLAG_VM_USER)) + flags |= NV_MEM_ACCESS_SYS; + +- ret = nouveau_vm_get(dev_priv->chan_vm, size, 12, flags, ++ ret = nouveau_vm_get(chan->vm, size, 12, flags, + &node->chan_vma); + if (ret) { + vram->put(dev, &node->vram); +@@ -345,7 +345,7 @@ + } + + nouveau_vm_map(&node->chan_vma, node->vram); +- gpuobj->vinst = node->chan_vma.offset; ++ gpuobj->linst = node->chan_vma.offset; + } + + gpuobj->size = size; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_mpeg.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_mpeg.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_mpeg.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_mpeg.c 2011-07-26 07:03:44.497051855 +0200 +@@ -160,7 +160,7 @@ + } + + static int +-nv50_mpeg_fini(struct drm_device *dev, int engine) ++nv50_mpeg_fini(struct drm_device *dev, int engine, bool suspend) + { + /*XXX: context save for s/r */ + nv_mask(dev, 0x00b32c, 0x00000001, 0x00000000); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_pm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_pm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_pm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_pm.c 2011-07-26 07:03:44.497051855 +0200 +@@ -115,15 +115,15 @@ + BIT_M.version == 1 && BIT_M.length >= 0x0b) { + script = ROM16(BIT_M.data[0x05]); + if (script) +- nouveau_bios_run_init_table(dev, script, NULL); ++ nouveau_bios_run_init_table(dev, script, NULL, -1); + script = ROM16(BIT_M.data[0x07]); + if (script) +- nouveau_bios_run_init_table(dev, script, NULL); ++ nouveau_bios_run_init_table(dev, script, NULL, -1); + script = ROM16(BIT_M.data[0x09]); + if (script) +- nouveau_bios_run_init_table(dev, script, NULL); ++ nouveau_bios_run_init_table(dev, script, NULL, -1); + +- nouveau_bios_run_init_table(dev, perflvl->memscript, NULL); ++ nouveau_bios_run_init_table(dev, perflvl->memscript, NULL, -1); + } + + if (state->type == PLL_MEMORY) { +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_sor.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_sor.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_sor.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_sor.c 2011-07-26 07:03:44.499051879 +0200 +@@ -318,6 +318,8 @@ + uint32_t tmp; + + tmp = nv_rd32(dev, 0x61c700 + (or * 0x800)); ++ if (!tmp) ++ tmp = nv_rd32(dev, 0x610798 + (or * 8)); + + switch ((tmp & 0x00000f00) >> 8) { + case 8: +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_vm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_vm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_vm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_vm.c 2011-07-26 07:03:44.500051891 +0200 +@@ -156,7 +156,7 @@ + pinstmem->flush(vm->dev); + + /* BAR */ +- if (vm != dev_priv->chan_vm) { ++ if (vm == dev_priv->bar1_vm || vm == dev_priv->bar3_vm) { + nv50_vm_flush_engine(vm->dev, 6); + return; + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv50_vram.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_vram.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv50_vram.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv50_vram.c 2011-07-26 07:03:44.500051891 +0200 +@@ -51,9 +51,7 @@ + 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 *mm = &dev_priv->engine.vram.mm; + struct nouveau_mm_node *this; + struct nouveau_mem *mem; + +@@ -84,9 +82,7 @@ + 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 *mm = &dev_priv->engine.vram.mm; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int comp = (memtype & 0x300) >> 8; +@@ -190,22 +186,35 @@ + nv50_vram_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; ++ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ ++ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ ++ u32 rblock, length; + + 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: ++ /* IGPs, no funky reordering happens here, they don't have VRAM */ ++ if (dev_priv->chipset == 0xaa || ++ dev_priv->chipset == 0xac || ++ dev_priv->chipset == 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; ++ rblock = 4096 >> 12; ++ } else { ++ rblock = nv50_vram_rblock(dev) >> 12; + } + +- return 0; ++ length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; ++ ++ return nouveau_mm_init(&vram->mm, rsvd_head, length, rblock); ++} ++ ++void ++nv50_vram_fini(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; ++ ++ nouveau_mm_fini(&vram->mm); + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nv84_crypt.c linux-3.0.patch/drivers/gpu/drm/nouveau/nv84_crypt.c +--- linux-3.0/drivers/gpu/drm/nouveau/nv84_crypt.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nv84_crypt.c 2011-07-26 07:03:44.501051903 +0200 +@@ -138,7 +138,7 @@ + } + + static int +-nv84_crypt_fini(struct drm_device *dev, int engine) ++nv84_crypt_fini(struct drm_device *dev, int engine, bool suspend) + { + nv_wr32(dev, 0x102140, 0x00000000); + return 0; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nva3_copy.c linux-3.0.patch/drivers/gpu/drm/nouveau/nva3_copy.c +--- linux-3.0/drivers/gpu/drm/nouveau/nva3_copy.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nva3_copy.c 2011-07-26 07:03:44.501051903 +0200 +@@ -140,7 +140,7 @@ + } + + static int +-nva3_copy_fini(struct drm_device *dev, int engine) ++nva3_copy_fini(struct drm_device *dev, int engine, bool suspend) + { + nv_mask(dev, 0x104048, 0x00000003, 0x00000000); + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nva3_pm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nva3_pm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nva3_pm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nva3_pm.c 2011-07-26 07:03:44.502051915 +0200 +@@ -27,178 +27,316 @@ + #include "nouveau_bios.h" + #include "nouveau_pm.h" + +-/* This is actually a lot more complex than it appears here, but hopefully +- * this should be able to deal with what the VBIOS leaves for us.. +- * +- * If not, well, I'll jump off that bridge when I come to it. +- */ ++static u32 read_clk(struct drm_device *, int, bool); ++static u32 read_pll(struct drm_device *, int, u32); + +-struct nva3_pm_state { +- enum pll_types type; +- u32 src0; +- u32 src1; +- u32 ctrl; +- u32 coef; +- u32 old_pnm; +- u32 new_pnm; +- u32 new_div; +-}; ++static u32 ++read_vco(struct drm_device *dev, int clk) ++{ ++ u32 sctl = nv_rd32(dev, 0x4120 + (clk * 4)); ++ if ((sctl & 0x00000030) != 0x00000030) ++ return read_pll(dev, 0x41, 0x00e820); ++ return read_pll(dev, 0x42, 0x00e8a0); ++} + +-static int +-nva3_pm_pll_offset(u32 id) ++static u32 ++read_clk(struct drm_device *dev, int clk, bool ignore_en) + { +- static const u32 pll_map[] = { +- 0x00, PLL_CORE, +- 0x01, PLL_SHADER, +- 0x02, PLL_MEMORY, +- 0x00, 0x00 +- }; +- const u32 *map = pll_map; +- +- while (map[1]) { +- if (id == map[1]) +- return map[0]; +- map += 2; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ u32 sctl, sdiv, sclk; ++ ++ /* refclk for the 0xe8xx plls is a fixed frequency */ ++ if (clk >= 0x40) { ++ if (dev_priv->chipset == 0xaf) { ++ /* no joke.. seriously.. sigh.. */ ++ return nv_rd32(dev, 0x00471c) * 1000; ++ } ++ ++ return dev_priv->crystal; + } + +- return -ENOENT; ++ sctl = nv_rd32(dev, 0x4120 + (clk * 4)); ++ if (!ignore_en && !(sctl & 0x00000100)) ++ return 0; ++ ++ switch (sctl & 0x00003000) { ++ case 0x00000000: ++ return dev_priv->crystal; ++ case 0x00002000: ++ if (sctl & 0x00000040) ++ return 108000; ++ return 100000; ++ case 0x00003000: ++ sclk = read_vco(dev, clk); ++ sdiv = ((sctl & 0x003f0000) >> 16) + 2; ++ return (sclk * 2) / sdiv; ++ default: ++ return 0; ++ } + } + +-int +-nva3_pm_clock_get(struct drm_device *dev, u32 id) ++static u32 ++read_pll(struct drm_device *dev, int clk, u32 pll) ++{ ++ u32 ctrl = nv_rd32(dev, pll + 0); ++ u32 sclk = 0, P = 1, N = 1, M = 1; ++ ++ if (!(ctrl & 0x00000008)) { ++ if (ctrl & 0x00000001) { ++ u32 coef = nv_rd32(dev, pll + 4); ++ M = (coef & 0x000000ff) >> 0; ++ N = (coef & 0x0000ff00) >> 8; ++ P = (coef & 0x003f0000) >> 16; ++ ++ /* no post-divider on these.. */ ++ if ((pll & 0x00ff00) == 0x00e800) ++ P = 1; ++ ++ sclk = read_clk(dev, 0x00 + clk, false); ++ } ++ } else { ++ sclk = read_clk(dev, 0x10 + clk, false); ++ } ++ ++ return sclk * N / (M * P); ++} ++ ++struct creg { ++ u32 clk; ++ u32 pll; ++}; ++ ++static int ++calc_clk(struct drm_device *dev, int clk, u32 pll, u32 khz, struct creg *reg) + { +- u32 src0, src1, ctrl, coef; +- struct pll_lims pll; +- int ret, off; +- int P, N, M; ++ struct pll_lims limits; ++ u32 oclk, sclk, sdiv; ++ int P, N, M, diff; ++ int ret; ++ ++ reg->pll = 0; ++ reg->clk = 0; ++ if (!khz) { ++ NV_DEBUG(dev, "no clock for 0x%04x/0x%02x\n", pll, clk); ++ return 0; ++ } + +- ret = get_pll_limits(dev, id, &pll); ++ switch (khz) { ++ case 27000: ++ reg->clk = 0x00000100; ++ return khz; ++ case 100000: ++ reg->clk = 0x00002100; ++ return khz; ++ case 108000: ++ reg->clk = 0x00002140; ++ return khz; ++ default: ++ sclk = read_vco(dev, clk); ++ sdiv = min((sclk * 2) / (khz - 2999), (u32)65); ++ /* if the clock has a PLL attached, and we can get a within ++ * [-2, 3) MHz of a divider, we'll disable the PLL and use ++ * the divider instead. ++ * ++ * divider can go as low as 2, limited here because NVIDIA ++ * and the VBIOS on my NVA8 seem to prefer using the PLL ++ * for 810MHz - is there a good reason? ++ */ ++ if (sdiv > 4) { ++ oclk = (sclk * 2) / sdiv; ++ diff = khz - oclk; ++ if (!pll || (diff >= -2000 && diff < 3000)) { ++ reg->clk = (((sdiv - 2) << 16) | 0x00003100); ++ return oclk; ++ } ++ } ++ ++ if (!pll) { ++ NV_ERROR(dev, "bad freq %02x: %d %d\n", clk, khz, sclk); ++ return -ERANGE; ++ } ++ ++ break; ++ } ++ ++ ret = get_pll_limits(dev, pll, &limits); + if (ret) + return ret; + +- off = nva3_pm_pll_offset(id); +- if (off < 0) +- return off; +- +- src0 = nv_rd32(dev, 0x4120 + (off * 4)); +- src1 = nv_rd32(dev, 0x4160 + (off * 4)); +- ctrl = nv_rd32(dev, pll.reg + 0); +- coef = nv_rd32(dev, pll.reg + 4); +- NV_DEBUG(dev, "PLL %02x: 0x%08x 0x%08x 0x%08x 0x%08x\n", +- id, src0, src1, ctrl, coef); +- +- if (ctrl & 0x00000008) { +- u32 div = ((src1 & 0x003c0000) >> 18) + 1; +- return (pll.refclk * 2) / div; +- } +- +- P = (coef & 0x003f0000) >> 16; +- N = (coef & 0x0000ff00) >> 8; +- M = (coef & 0x000000ff); +- return pll.refclk * N / M / P; ++ limits.refclk = read_clk(dev, clk - 0x10, true); ++ if (!limits.refclk) ++ return -EINVAL; ++ ++ ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); ++ if (ret >= 0) { ++ reg->clk = nv_rd32(dev, 0x4120 + (clk * 4)); ++ reg->pll = (P << 16) | (N << 8) | M; ++ } ++ return ret; + } + ++static void ++prog_pll(struct drm_device *dev, int clk, u32 pll, struct creg *reg) ++{ ++ const u32 src0 = 0x004120 + (clk * 4); ++ const u32 src1 = 0x004160 + (clk * 4); ++ const u32 ctrl = pll + 0; ++ const u32 coef = pll + 4; ++ u32 cntl; ++ ++ if (!reg->clk && !reg->pll) { ++ NV_DEBUG(dev, "no clock for %02x\n", clk); ++ return; ++ } ++ ++ cntl = nv_rd32(dev, ctrl) & 0xfffffff2; ++ if (reg->pll) { ++ nv_mask(dev, src0, 0x00000101, 0x00000101); ++ nv_wr32(dev, coef, reg->pll); ++ nv_wr32(dev, ctrl, cntl | 0x00000015); ++ nv_mask(dev, src1, 0x00000100, 0x00000000); ++ nv_mask(dev, src1, 0x00000001, 0x00000000); ++ } else { ++ nv_mask(dev, src1, 0x003f3141, 0x00000101 | reg->clk); ++ nv_wr32(dev, ctrl, cntl | 0x0000001d); ++ nv_mask(dev, ctrl, 0x00000001, 0x00000000); ++ nv_mask(dev, src0, 0x00000100, 0x00000000); ++ nv_mask(dev, src0, 0x00000001, 0x00000000); ++ } ++} ++ ++static void ++prog_clk(struct drm_device *dev, int clk, struct creg *reg) ++{ ++ if (!reg->clk) { ++ NV_DEBUG(dev, "no clock for %02x\n", clk); ++ return; ++ } ++ ++ nv_mask(dev, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | reg->clk); ++} ++ ++int ++nva3_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) ++{ ++ perflvl->core = read_pll(dev, 0x00, 0x4200); ++ perflvl->shader = read_pll(dev, 0x01, 0x4220); ++ perflvl->memory = read_pll(dev, 0x02, 0x4000); ++ perflvl->unka0 = read_clk(dev, 0x20, false); ++ perflvl->vdec = read_clk(dev, 0x21, false); ++ perflvl->daemon = read_clk(dev, 0x25, false); ++ perflvl->copy = perflvl->core; ++ return 0; ++} ++ ++struct nva3_pm_state { ++ struct creg nclk; ++ struct creg sclk; ++ struct creg mclk; ++ struct creg vdec; ++ struct creg unka0; ++}; ++ + void * +-nva3_pm_clock_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl, +- u32 id, int khz) ++nva3_pm_clocks_pre(struct drm_device *dev, struct nouveau_pm_level *perflvl) + { +- struct nva3_pm_state *pll; +- struct pll_lims limits; +- int N, M, P, diff; +- int ret, off; ++ struct nva3_pm_state *info; ++ int ret; ++ ++ info = kzalloc(sizeof(*info), GFP_KERNEL); ++ if (!info) ++ return ERR_PTR(-ENOMEM); + +- ret = get_pll_limits(dev, id, &limits); ++ ret = calc_clk(dev, 0x10, 0x4200, perflvl->core, &info->nclk); + if (ret < 0) +- return (ret == -ENOENT) ? NULL : ERR_PTR(ret); ++ goto out; + +- off = nva3_pm_pll_offset(id); +- if (id < 0) +- return ERR_PTR(-EINVAL); ++ ret = calc_clk(dev, 0x11, 0x4220, perflvl->shader, &info->sclk); ++ if (ret < 0) ++ goto out; + ++ ret = calc_clk(dev, 0x12, 0x4000, perflvl->memory, &info->mclk); ++ if (ret < 0) ++ goto out; + +- pll = kzalloc(sizeof(*pll), GFP_KERNEL); +- if (!pll) +- return ERR_PTR(-ENOMEM); +- pll->type = id; +- pll->src0 = 0x004120 + (off * 4); +- pll->src1 = 0x004160 + (off * 4); +- pll->ctrl = limits.reg + 0; +- pll->coef = limits.reg + 4; +- +- /* If target clock is within [-2, 3) MHz of a divisor, we'll +- * use that instead of calculating MNP values +- */ +- pll->new_div = min((limits.refclk * 2) / (khz - 2999), 16); +- if (pll->new_div) { +- diff = khz - ((limits.refclk * 2) / pll->new_div); +- if (diff < -2000 || diff >= 3000) +- pll->new_div = 0; +- } +- +- if (!pll->new_div) { +- ret = nva3_calc_pll(dev, &limits, khz, &N, NULL, &M, &P); +- if (ret < 0) +- return ERR_PTR(ret); ++ ret = calc_clk(dev, 0x20, 0x0000, perflvl->unka0, &info->unka0); ++ if (ret < 0) ++ goto out; + +- pll->new_pnm = (P << 16) | (N << 8) | M; +- pll->new_div = 2 - 1; +- } else { +- pll->new_pnm = 0; +- pll->new_div--; ++ ret = calc_clk(dev, 0x21, 0x0000, perflvl->vdec, &info->vdec); ++ if (ret < 0) ++ goto out; ++ ++out: ++ if (ret < 0) { ++ kfree(info); ++ info = ERR_PTR(ret); + } ++ return info; ++} ++ ++static bool ++nva3_pm_grcp_idle(void *data) ++{ ++ struct drm_device *dev = data; + +- if ((nv_rd32(dev, pll->src1) & 0x00000101) != 0x00000101) +- pll->old_pnm = nv_rd32(dev, pll->coef); +- return pll; ++ if (!(nv_rd32(dev, 0x400304) & 0x00000001)) ++ return true; ++ if (nv_rd32(dev, 0x400308) == 0x0050001c) ++ return true; ++ return false; + } + + void +-nva3_pm_clock_set(struct drm_device *dev, void *pre_state) ++nva3_pm_clocks_set(struct drm_device *dev, void *pre_state) + { +- struct nva3_pm_state *pll = pre_state; +- u32 ctrl = 0; ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nva3_pm_state *info = pre_state; ++ unsigned long flags; ++ ++ /* prevent any new grctx switches from starting */ ++ spin_lock_irqsave(&dev_priv->context_switch_lock, flags); ++ nv_wr32(dev, 0x400324, 0x00000000); ++ nv_wr32(dev, 0x400328, 0x0050001c); /* wait flag 0x1c */ ++ /* wait for any pending grctx switches to complete */ ++ if (!nv_wait_cb(dev, nva3_pm_grcp_idle, dev)) { ++ NV_ERROR(dev, "pm: ctxprog didn't go idle\n"); ++ goto cleanup; ++ } ++ /* freeze PFIFO */ ++ nv_mask(dev, 0x002504, 0x00000001, 0x00000001); ++ if (!nv_wait(dev, 0x002504, 0x00000010, 0x00000010)) { ++ NV_ERROR(dev, "pm: fifo didn't go idle\n"); ++ goto cleanup; ++ } ++ ++ prog_pll(dev, 0x00, 0x004200, &info->nclk); ++ prog_pll(dev, 0x01, 0x004220, &info->sclk); ++ prog_clk(dev, 0x20, &info->unka0); ++ prog_clk(dev, 0x21, &info->vdec); + +- /* For the memory clock, NVIDIA will build a "script" describing +- * the reclocking process and ask PDAEMON to execute it. +- */ +- if (pll->type == PLL_MEMORY) { ++ if (info->mclk.clk || info->mclk.pll) { + nv_wr32(dev, 0x100210, 0); + nv_wr32(dev, 0x1002dc, 1); + nv_wr32(dev, 0x004018, 0x00001000); +- ctrl = 0x18000100; +- } +- +- if (pll->old_pnm || !pll->new_pnm) { +- nv_mask(dev, pll->src1, 0x003c0101, 0x00000101 | +- (pll->new_div << 18)); +- nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); +- nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); +- } +- +- if (pll->new_pnm) { +- nv_mask(dev, pll->src0, 0x00000101, 0x00000101); +- nv_wr32(dev, pll->coef, pll->new_pnm); +- nv_wr32(dev, pll->ctrl, 0x0001001d | ctrl); +- nv_mask(dev, pll->ctrl, 0x00000010, 0x00000000); +- nv_mask(dev, pll->ctrl, 0x00020010, 0x00020010); +- nv_wr32(dev, pll->ctrl, 0x00010015 | ctrl); +- nv_mask(dev, pll->src1, 0x00000100, 0x00000000); +- nv_mask(dev, pll->src1, 0x00000001, 0x00000000); +- if (pll->type == PLL_MEMORY) +- nv_wr32(dev, 0x4018, 0x10005000); +- } else { +- nv_mask(dev, pll->ctrl, 0x00000001, 0x00000000); +- nv_mask(dev, pll->src0, 0x00000100, 0x00000000); +- nv_mask(dev, pll->src0, 0x00000001, 0x00000000); +- if (pll->type == PLL_MEMORY) +- nv_wr32(dev, 0x4018, 0x1000d000); +- } +- +- if (pll->type == PLL_MEMORY) { ++ prog_pll(dev, 0x02, 0x004000, &info->mclk); ++ if (nv_rd32(dev, 0x4000) & 0x00000008) ++ nv_wr32(dev, 0x004018, 0x1000d000); ++ else ++ nv_wr32(dev, 0x004018, 0x10005000); + nv_wr32(dev, 0x1002dc, 0); + nv_wr32(dev, 0x100210, 0x80000000); + } + +- kfree(pll); ++cleanup: ++ /* unfreeze PFIFO */ ++ nv_mask(dev, 0x002504, 0x00000001, 0x00000000); ++ /* restore ctxprog to normal */ ++ nv_wr32(dev, 0x400324, 0x00000000); ++ nv_wr32(dev, 0x400328, 0x0070009c); /* set flag 0x1c */ ++ /* unblock it if necessary */ ++ if (nv_rd32(dev, 0x400308) == 0x0050001c) ++ nv_mask(dev, 0x400824, 0x10000000, 0x10000000); ++ spin_unlock_irqrestore(&dev_priv->context_switch_lock, flags); ++ kfree(info); + } +- +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_copy.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_copy.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_copy.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_copy.c 2011-07-26 07:03:44.503051927 +0200 +@@ -48,14 +48,14 @@ + struct nouveau_gpuobj *ctx = NULL; + int ret; + +- ret = nouveau_gpuobj_new(dev, NULL, 256, 256, ++ ret = nouveau_gpuobj_new(dev, chan, 256, 256, + NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER | + NVOBJ_FLAG_ZERO_ALLOC, &ctx); + if (ret) + return ret; + +- nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->vinst)); +- nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->vinst)); ++ nv_wo32(ramin, pcopy->ctx + 0, lower_32_bits(ctx->linst)); ++ nv_wo32(ramin, pcopy->ctx + 4, upper_32_bits(ctx->linst)); + dev_priv->engine.instmem.flush(dev); + + chan->engctx[engine] = ctx; +@@ -127,7 +127,7 @@ + } + + static int +-nvc0_copy_fini(struct drm_device *dev, int engine) ++nvc0_copy_fini(struct drm_device *dev, int engine, bool suspend) + { + struct nvc0_copy_engine *pcopy = nv_engine(dev, engine); + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_fb.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_fb.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_fb.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_fb.c 2011-07-26 07:03:44.503051927 +0200 +@@ -1,5 +1,5 @@ + /* +- * Copyright 2010 Red Hat Inc. ++ * Copyright 2011 Red Hat Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), +@@ -23,16 +23,80 @@ + */ + + #include "drmP.h" +- ++#include "drm.h" + #include "nouveau_drv.h" ++#include "nouveau_drm.h" ++ ++struct nvc0_fb_priv { ++ struct page *r100c10_page; ++ dma_addr_t r100c10; ++}; ++ ++static void ++nvc0_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 nvc0_fb_priv *priv = pfb->priv; ++ ++ if (priv->r100c10_page) { ++ pci_unmap_page(dev->pdev, priv->r100c10, PAGE_SIZE, ++ PCI_DMA_BIDIRECTIONAL); ++ __free_page(priv->r100c10_page); ++ } ++ ++ kfree(priv); ++ pfb->priv = NULL; ++} ++ ++static int ++nvc0_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 nvc0_fb_priv *priv; ++ ++ priv = kzalloc(sizeof(*priv), GFP_KERNEL); ++ if (!priv) ++ return -ENOMEM; ++ pfb->priv = priv; ++ ++ priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); ++ if (!priv->r100c10_page) { ++ nvc0_fb_destroy(dev); ++ return -ENOMEM; ++ } ++ ++ priv->r100c10 = pci_map_page(dev->pdev, priv->r100c10_page, 0, ++ PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); ++ if (pci_dma_mapping_error(dev->pdev, priv->r100c10)) { ++ nvc0_fb_destroy(dev); ++ return -EFAULT; ++ } ++ ++ return 0; ++} + + int + nvc0_fb_init(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvc0_fb_priv *priv; ++ int ret; ++ ++ if (!dev_priv->engine.fb.priv) { ++ ret = nvc0_fb_create(dev); ++ if (ret) ++ return ret; ++ } ++ priv = dev_priv->engine.fb.priv; ++ ++ nv_wr32(dev, 0x100c10, priv->r100c10 >> 8); + return 0; + } + + void + nvc0_fb_takedown(struct drm_device *dev) + { ++ nvc0_fb_destroy(dev); + } +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_fbcon.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_fbcon.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_fbcon.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_fbcon.c 2011-07-26 07:03:44.504051939 +0200 +@@ -159,7 +159,7 @@ + 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; ++ struct nouveau_framebuffer *fb = &nfbdev->nouveau_fb; + int ret, format; + + ret = nouveau_gpuobj_gr_new(chan, 0x902d, 0x902d); +@@ -203,8 +203,8 @@ + 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)); ++ OUT_RING (chan, upper_32_bits(chan->notifier_vma.offset)); ++ OUT_RING (chan, lower_32_bits(chan->notifier_vma.offset)); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0290, 1); + OUT_RING (chan, 0); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0888, 1); +@@ -249,8 +249,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(nvbo->vma.offset)); +- OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); ++ OUT_RING (chan, upper_32_bits(fb->vma.offset)); ++ OUT_RING (chan, lower_32_bits(fb->vma.offset)); + BEGIN_NVC0(chan, 2, NvSub2D, 0x0230, 10); + OUT_RING (chan, format); + OUT_RING (chan, 1); +@@ -260,8 +260,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(nvbo->vma.offset)); +- OUT_RING (chan, lower_32_bits(nvbo->vma.offset)); ++ OUT_RING (chan, upper_32_bits(fb->vma.offset)); ++ OUT_RING (chan, lower_32_bits(fb->vma.offset)); + FIRE_RING (chan); + + return 0; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_fifo.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_fifo.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_fifo.c 2011-07-26 07:03:44.504051939 +0200 +@@ -210,10 +210,10 @@ + int i; + + for (i = 0; i < 128; i++) { +- if (!(nv_rd32(dev, 0x003004 + (i * 4)) & 1)) ++ if (!(nv_rd32(dev, 0x003004 + (i * 8)) & 1)) + continue; + +- nv_mask(dev, 0x003004 + (i * 4), 0x00000001, 0x00000000); ++ nv_mask(dev, 0x003004 + (i * 8), 0x00000001, 0x00000000); + nv_wr32(dev, 0x002634, i); + if (!nv_wait(dev, 0x002634, 0xffffffff, i)) { + NV_INFO(dev, "PFIFO: kick ch %d failed: 0x%08x\n", +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_graph.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_graph.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_graph.c 2011-07-26 07:03:44.505051951 +0200 +@@ -28,7 +28,34 @@ + + #include "nouveau_drv.h" + #include "nouveau_mm.h" ++ + #include "nvc0_graph.h" ++#include "nvc0_grhub.fuc.h" ++#include "nvc0_grgpc.fuc.h" ++ ++static void ++nvc0_graph_ctxctl_debug_unit(struct drm_device *dev, u32 base) ++{ ++ NV_INFO(dev, "PGRAPH: %06x - done 0x%08x\n", base, ++ nv_rd32(dev, base + 0x400)); ++ NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, ++ nv_rd32(dev, base + 0x800), nv_rd32(dev, base + 0x804), ++ nv_rd32(dev, base + 0x808), nv_rd32(dev, base + 0x80c)); ++ NV_INFO(dev, "PGRAPH: %06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, ++ nv_rd32(dev, base + 0x810), nv_rd32(dev, base + 0x814), ++ nv_rd32(dev, base + 0x818), nv_rd32(dev, base + 0x81c)); ++} ++ ++static void ++nvc0_graph_ctxctl_debug(struct drm_device *dev) ++{ ++ u32 gpcnr = nv_rd32(dev, 0x409604) & 0xffff; ++ u32 gpc; ++ ++ nvc0_graph_ctxctl_debug_unit(dev, 0x409000); ++ for (gpc = 0; gpc < gpcnr; gpc++) ++ nvc0_graph_ctxctl_debug_unit(dev, 0x502000 + (gpc * 0x8000)); ++} + + static int + nvc0_graph_load_context(struct nouveau_channel *chan) +@@ -72,24 +99,44 @@ + if (!ctx) + return -ENOMEM; + +- nvc0_graph_load_context(chan); ++ if (!nouveau_ctxfw) { ++ nv_wr32(dev, 0x409840, 0x80000000); ++ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12); ++ nv_wr32(dev, 0x409504, 0x00000001); ++ if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) { ++ NV_ERROR(dev, "PGRAPH: HUB_SET_CHAN timeout\n"); ++ nvc0_graph_ctxctl_debug(dev); ++ ret = -EBUSY; ++ goto err; ++ } ++ } else { ++ 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); ++ 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; +- } ++ if (ret) ++ goto err; + +- ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst); +- if (ret) { +- kfree(ctx); +- return ret; ++ if (!nouveau_ctxfw) { ++ nv_wr32(dev, 0x409840, 0x80000000); ++ nv_wr32(dev, 0x409500, 0x80000000 | chan->ramin->vinst >> 12); ++ nv_wr32(dev, 0x409504, 0x00000002); ++ if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) { ++ NV_ERROR(dev, "PGRAPH: HUB_CTX_SAVE timeout\n"); ++ nvc0_graph_ctxctl_debug(dev); ++ ret = -EBUSY; ++ goto err; ++ } ++ } else { ++ ret = nvc0_graph_unload_context_to(dev, chan->ramin->vinst); ++ if (ret) ++ goto err; + } + + for (i = 0; i < priv->grctx_size; i += 4) +@@ -97,6 +144,10 @@ + + priv->grctx_vals = ctx; + return 0; ++ ++err: ++ kfree(ctx); ++ return ret; + } + + static int +@@ -108,50 +159,50 @@ + int i = 0, gpc, tp, ret; + u32 magic; + +- ret = nouveau_gpuobj_new(dev, NULL, 0x2000, 256, NVOBJ_FLAG_VM, ++ ret = nouveau_gpuobj_new(dev, chan, 0x2000, 256, NVOBJ_FLAG_VM, + &grch->unk408004); + if (ret) + return ret; + +- ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 256, NVOBJ_FLAG_VM, ++ ret = nouveau_gpuobj_new(dev, chan, 0x8000, 256, NVOBJ_FLAG_VM, + &grch->unk40800c); + if (ret) + return ret; + +- ret = nouveau_gpuobj_new(dev, NULL, 384 * 1024, 4096, ++ ret = nouveau_gpuobj_new(dev, chan, 384 * 1024, 4096, + NVOBJ_FLAG_VM | NVOBJ_FLAG_VM_USER, + &grch->unk418810); + if (ret) + return ret; + +- ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 0, NVOBJ_FLAG_VM, ++ ret = nouveau_gpuobj_new(dev, chan, 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, grch->unk408004->linst >> 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, grch->unk40800c->linst >> 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, 0x80000000 | grch->unk418810->linst >> 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, 0x10000000 | grch->unk418810->linst >> 12); + + nv_wo32(grch->mmio, i++ * 4, 0x00419004); +- nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->vinst >> 8); ++ nv_wo32(grch->mmio, i++ * 4, grch->unk40800c->linst >> 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, grch->unk408004->linst >> 8); + nv_wo32(grch->mmio, i++ * 4, 0x0041880c); + nv_wo32(grch->mmio, i++ * 4, 0x80000018); + +@@ -159,7 +210,7 @@ + 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) { ++ for (tp = 0; tp < priv->tp_nr[gpc]; tp++, magic += 0x0324) { + u32 reg = 0x504520 + (gpc * 0x8000) + (tp * 0x0800); + nv_wo32(grch->mmio, i++ * 4, reg); + nv_wo32(grch->mmio, i++ * 4, magic); +@@ -186,7 +237,7 @@ + return -ENOMEM; + chan->engctx[NVOBJ_ENGINE_GR] = grch; + +- ret = nouveau_gpuobj_new(dev, NULL, priv->grctx_size, 256, ++ ret = nouveau_gpuobj_new(dev, chan, priv->grctx_size, 256, + NVOBJ_FLAG_VM | NVOBJ_FLAG_ZERO_ALLOC, + &grch->grctx); + if (ret) +@@ -197,8 +248,8 @@ + 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)); ++ nv_wo32(chan->ramin, 0x0210, lower_32_bits(grctx->linst) | 4); ++ nv_wo32(chan->ramin, 0x0214, upper_32_bits(grctx->linst)); + pinstmem->flush(dev); + + if (!priv->grctx_vals) { +@@ -210,15 +261,20 @@ + 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); ++ if (!nouveau_ctxfw) { ++ nv_wo32(grctx, 0x00, grch->mmio_nr); ++ nv_wo32(grctx, 0x04, grch->mmio->linst >> 8); ++ } else { ++ 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->linst)); ++ nv_wo32(grctx, 0x18, upper_32_bits(grch->mmio->linst)); ++ 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; + +@@ -248,7 +304,7 @@ + } + + static int +-nvc0_graph_fini(struct drm_device *dev, int engine) ++nvc0_graph_fini(struct drm_device *dev, int engine, bool suspend) + { + return 0; + } +@@ -296,6 +352,7 @@ + nvc0_graph_init_gpc_0(struct drm_device *dev) + { + struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); ++ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tp_total); + u32 data[TP_MAX / 8]; + u8 tpnr[GPC_MAX]; + int i, gpc, tpc; +@@ -307,13 +364,6 @@ + * 465: 3/4/4/0 4 7 + * 470: 3/3/4/4 5 5 + * 480: 3/4/4/4 6 6 +- * +- * magicgpc918 +- * 450: 00200000 00000000001000000000000000000000 +- * 460: 00124925 00000000000100100100100100100101 +- * 465: 000ba2e9 00000000000010111010001011101001 +- * 470: 00092493 00000000000010010010010010010011 +- * 480: 00088889 00000000000010001000100010001001 + */ + + memset(data, 0x00, sizeof(data)); +@@ -336,11 +386,11 @@ + 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_UNIT(gpc, 0x0918), magicgpc918); + } + +- nv_wr32(dev, GPC_BCAST(0x1bd4), priv->magicgpc918); +- nv_wr32(dev, GPC_BCAST(0x08ac), priv->rop_nr); ++ nv_wr32(dev, GPC_BCAST(0x1bd4), magicgpc918); ++ nv_wr32(dev, GPC_BCAST(0x08ac), nv_rd32(dev, 0x100800)); + } + + static void +@@ -419,8 +469,51 @@ + static int + nvc0_graph_init_ctxctl(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_graph_priv *priv = nv_engine(dev, NVOBJ_ENGINE_GR); + u32 r000260; ++ int i; ++ ++ if (!nouveau_ctxfw) { ++ /* load HUB microcode */ ++ r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); ++ nv_wr32(dev, 0x4091c0, 0x01000000); ++ for (i = 0; i < sizeof(nvc0_grhub_data) / 4; i++) ++ nv_wr32(dev, 0x4091c4, nvc0_grhub_data[i]); ++ ++ nv_wr32(dev, 0x409180, 0x01000000); ++ for (i = 0; i < sizeof(nvc0_grhub_code) / 4; i++) { ++ if ((i & 0x3f) == 0) ++ nv_wr32(dev, 0x409188, i >> 6); ++ nv_wr32(dev, 0x409184, nvc0_grhub_code[i]); ++ } ++ ++ /* load GPC microcode */ ++ nv_wr32(dev, 0x41a1c0, 0x01000000); ++ for (i = 0; i < sizeof(nvc0_grgpc_data) / 4; i++) ++ nv_wr32(dev, 0x41a1c4, nvc0_grgpc_data[i]); ++ ++ nv_wr32(dev, 0x41a180, 0x01000000); ++ for (i = 0; i < sizeof(nvc0_grgpc_code) / 4; i++) { ++ if ((i & 0x3f) == 0) ++ nv_wr32(dev, 0x41a188, i >> 6); ++ nv_wr32(dev, 0x41a184, nvc0_grgpc_code[i]); ++ } ++ nv_wr32(dev, 0x000260, r000260); ++ ++ /* start HUB ucode running, it'll init the GPCs */ ++ nv_wr32(dev, 0x409800, dev_priv->chipset); ++ nv_wr32(dev, 0x40910c, 0x00000000); ++ nv_wr32(dev, 0x409100, 0x00000002); ++ if (!nv_wait(dev, 0x409800, 0x80000000, 0x80000000)) { ++ NV_ERROR(dev, "PGRAPH: HUB_INIT timed out\n"); ++ nvc0_graph_ctxctl_debug(dev); ++ return -EBUSY; ++ } ++ ++ priv->grctx_size = nv_rd32(dev, 0x409804); ++ return 0; ++ } + + /* load fuc microcode */ + r000260 = nv_mask(dev, 0x000260, 0x00000001, 0x00000000); +@@ -528,6 +621,22 @@ + } + + static void ++nvc0_graph_ctxctl_isr(struct drm_device *dev) ++{ ++ u32 ustat = nv_rd32(dev, 0x409c18); ++ ++ if (ustat & 0x00000001) ++ NV_INFO(dev, "PGRAPH: CTXCTRL ucode error\n"); ++ if (ustat & 0x00080000) ++ NV_INFO(dev, "PGRAPH: CTXCTRL watchdog timeout\n"); ++ if (ustat & ~0x00080001) ++ NV_INFO(dev, "PGRAPH: CTXCTRL 0x%08x\n", ustat); ++ ++ nvc0_graph_ctxctl_debug(dev); ++ nv_wr32(dev, 0x409c20, ustat); ++} ++ ++static void + nvc0_graph_isr(struct drm_device *dev) + { + u64 inst = (u64)(nv_rd32(dev, 0x409b00) & 0x0fffffff) << 12; +@@ -578,11 +687,7 @@ + } + + if (stat & 0x00080000) { +- u32 ustat = nv_rd32(dev, 0x409c18); +- +- NV_INFO(dev, "PGRAPH: CTXCTRL ustat 0x%08x\n", ustat); +- +- nv_wr32(dev, 0x409c20, ustat); ++ nvc0_graph_ctxctl_isr(dev); + nv_wr32(dev, 0x400100, 0x00080000); + stat &= ~0x00080000; + } +@@ -606,7 +711,7 @@ + u32 st0 = nv_mask(dev, reg + 0x1020, 0, 0); + u32 st1 = nv_mask(dev, reg + 0x1420, 0, 0); + +- NV_INFO(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1); ++ NV_DEBUG(dev, "PRUNK140: %d 0x%08x 0x%08x\n", unit, st0, st1); + units &= ~(1 << unit); + } + } +@@ -651,10 +756,12 @@ + { + struct nvc0_graph_priv *priv = nv_engine(dev, engine); + +- nvc0_graph_destroy_fw(&priv->fuc409c); +- nvc0_graph_destroy_fw(&priv->fuc409d); +- nvc0_graph_destroy_fw(&priv->fuc41ac); +- nvc0_graph_destroy_fw(&priv->fuc41ad); ++ if (nouveau_ctxfw) { ++ nvc0_graph_destroy_fw(&priv->fuc409c); ++ nvc0_graph_destroy_fw(&priv->fuc409d); ++ nvc0_graph_destroy_fw(&priv->fuc41ac); ++ nvc0_graph_destroy_fw(&priv->fuc41ad); ++ } + + nouveau_irq_unregister(dev, 12); + nouveau_irq_unregister(dev, 25); +@@ -675,13 +782,10 @@ + struct drm_nouveau_private *dev_priv = dev->dev_private; + struct nvc0_graph_priv *priv; + int ret, gpc, i; ++ u32 fermi; + +- switch (dev_priv->chipset) { +- case 0xc0: +- case 0xc3: +- case 0xc4: +- break; +- default: ++ fermi = nvc0_graph_class(dev); ++ if (!fermi) { + NV_ERROR(dev, "PGRAPH: unsupported chipset, please report!\n"); + return 0; + } +@@ -701,15 +805,17 @@ + nouveau_irq_register(dev, 12, nvc0_graph_isr); + nouveau_irq_register(dev, 25, nvc0_runk140_isr); + +- if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || +- nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || +- nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || +- nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) { +- ret = 0; +- goto error; ++ if (nouveau_ctxfw) { ++ NV_INFO(dev, "PGRAPH: using external firmware\n"); ++ if (nvc0_graph_create_fw(dev, "fuc409c", &priv->fuc409c) || ++ nvc0_graph_create_fw(dev, "fuc409d", &priv->fuc409d) || ++ nvc0_graph_create_fw(dev, "fuc41ac", &priv->fuc41ac) || ++ nvc0_graph_create_fw(dev, "fuc41ad", &priv->fuc41ad)) { ++ ret = 0; ++ goto error; ++ } + } + +- + ret = nouveau_gpuobj_new(dev, NULL, 0x1000, 256, 0, &priv->unk4188b4); + if (ret) + goto error; +@@ -735,25 +841,31 @@ + case 0xc0: + if (priv->tp_total == 11) { /* 465, 3/4/4/0, 4 */ + priv->magic_not_rop_nr = 0x07; +- /* filled values up to tp_total, the rest 0 */ +- priv->magicgpc918 = 0x000ba2e9; + } else + if (priv->tp_total == 14) { /* 470, 3/3/4/4, 5 */ + priv->magic_not_rop_nr = 0x05; +- priv->magicgpc918 = 0x00092493; + } else + if (priv->tp_total == 15) { /* 480, 3/4/4/4, 6 */ + priv->magic_not_rop_nr = 0x06; +- priv->magicgpc918 = 0x00088889; + } + break; + case 0xc3: /* 450, 4/0/0/0, 2 */ + priv->magic_not_rop_nr = 0x03; +- priv->magicgpc918 = 0x00200000; + break; + case 0xc4: /* 460, 3/4/0/0, 4 */ + priv->magic_not_rop_nr = 0x01; +- priv->magicgpc918 = 0x00124925; ++ break; ++ case 0xc1: /* 2/0/0/0, 1 */ ++ priv->magic_not_rop_nr = 0x01; ++ break; ++ case 0xc8: /* 4/4/3/4, 5 */ ++ priv->magic_not_rop_nr = 0x06; ++ break; ++ case 0xce: /* 4/4/0/0, 4 */ ++ priv->magic_not_rop_nr = 0x03; ++ break; ++ case 0xcf: /* 4/0/0/0, 3 */ ++ priv->magic_not_rop_nr = 0x03; + break; + } + +@@ -763,13 +875,16 @@ + priv->tp_nr[3], priv->rop_nr); + /* use 0xc3's values... */ + priv->magic_not_rop_nr = 0x03; +- priv->magicgpc918 = 0x00200000; + } + + NVOBJ_CLASS(dev, 0x902d, GR); /* 2D */ + NVOBJ_CLASS(dev, 0x9039, GR); /* M2MF */ + NVOBJ_MTHD (dev, 0x9039, 0x0500, nvc0_graph_mthd_page_flip); + NVOBJ_CLASS(dev, 0x9097, GR); /* 3D */ ++ if (fermi >= 0x9197) ++ NVOBJ_CLASS(dev, 0x9197, GR); /* 3D (NVC1-) */ ++ if (fermi >= 0x9297) ++ NVOBJ_CLASS(dev, 0x9297, GR); /* 3D (NVC8-) */ + NVOBJ_CLASS(dev, 0x90c0, GR); /* COMPUTE */ + return 0; + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_graph.fuc linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_graph.fuc +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_graph.fuc 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_graph.fuc 2011-07-26 07:03:44.506051963 +0200 +@@ -0,0 +1,400 @@ ++/* fuc microcode util functions for nvc0 PGRAPH ++ * ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++define(`mmctx_data', `.b32 eval((($2 - 1) << 26) | $1)') ++define(`queue_init', `.skip eval((2 * 4) + ((8 * 4) * 2))') ++ ++ifdef(`include_code', ` ++// Error codes ++define(`E_BAD_COMMAND', 0x01) ++define(`E_CMD_OVERFLOW', 0x02) ++ ++// Util macros to help with debugging ucode hangs etc ++define(`T_WAIT', 0) ++define(`T_MMCTX', 1) ++define(`T_STRWAIT', 2) ++define(`T_STRINIT', 3) ++define(`T_AUTO', 4) ++define(`T_CHAN', 5) ++define(`T_LOAD', 6) ++define(`T_SAVE', 7) ++define(`T_LCHAN', 8) ++define(`T_LCTXH', 9) ++ ++define(`trace_set', ` ++ mov $r8 0x83c ++ shl b32 $r8 6 ++ clear b32 $r9 ++ bset $r9 $1 ++ iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7] ++') ++ ++define(`trace_clr', ` ++ mov $r8 0x85c ++ shl b32 $r8 6 ++ clear b32 $r9 ++ bset $r9 $1 ++ iowr I[$r8 + 0x000] $r9 // CC_SCRATCH[7] ++') ++ ++// queue_put - add request to queue ++// ++// In : $r13 queue pointer ++// $r14 command ++// $r15 data ++// ++queue_put: ++ // make sure we have space.. ++ ld b32 $r8 D[$r13 + 0x0] // GET ++ ld b32 $r9 D[$r13 + 0x4] // PUT ++ xor $r8 8 ++ cmpu b32 $r8 $r9 ++ bra ne queue_put_next ++ mov $r15 E_CMD_OVERFLOW ++ call error ++ ret ++ ++ // store cmd/data on queue ++ queue_put_next: ++ and $r8 $r9 7 ++ shl b32 $r8 3 ++ add b32 $r8 $r13 ++ add b32 $r8 8 ++ st b32 D[$r8 + 0x0] $r14 ++ st b32 D[$r8 + 0x4] $r15 ++ ++ // update PUT ++ add b32 $r9 1 ++ and $r9 0xf ++ st b32 D[$r13 + 0x4] $r9 ++ ret ++ ++// queue_get - fetch request from queue ++// ++// In : $r13 queue pointer ++// ++// Out: $p1 clear on success (data available) ++// $r14 command ++// $r15 data ++// ++queue_get: ++ bset $flags $p1 ++ ld b32 $r8 D[$r13 + 0x0] // GET ++ ld b32 $r9 D[$r13 + 0x4] // PUT ++ cmpu b32 $r8 $r9 ++ bra e queue_get_done ++ // fetch first cmd/data pair ++ and $r9 $r8 7 ++ shl b32 $r9 3 ++ add b32 $r9 $r13 ++ add b32 $r9 8 ++ ld b32 $r14 D[$r9 + 0x0] ++ ld b32 $r15 D[$r9 + 0x4] ++ ++ // update GET ++ add b32 $r8 1 ++ and $r8 0xf ++ st b32 D[$r13 + 0x0] $r8 ++ bclr $flags $p1 ++queue_get_done: ++ ret ++ ++// nv_rd32 - read 32-bit value from nv register ++// ++// In : $r14 register ++// Out: $r15 value ++// ++nv_rd32: ++ mov $r11 0x728 ++ shl b32 $r11 6 ++ mov b32 $r12 $r14 ++ bset $r12 31 // MMIO_CTRL_PENDING ++ iowr I[$r11 + 0x000] $r12 // MMIO_CTRL ++ nv_rd32_wait: ++ iord $r12 I[$r11 + 0x000] ++ xbit $r12 $r12 31 ++ bra ne nv_rd32_wait ++ mov $r10 6 // DONE_MMIO_RD ++ call wait_doneo ++ iord $r15 I[$r11 + 0x100] // MMIO_RDVAL ++ ret ++ ++// nv_wr32 - write 32-bit value to nv register ++// ++// In : $r14 register ++// $r15 value ++// ++nv_wr32: ++ mov $r11 0x728 ++ shl b32 $r11 6 ++ iowr I[$r11 + 0x200] $r15 // MMIO_WRVAL ++ mov b32 $r12 $r14 ++ bset $r12 31 // MMIO_CTRL_PENDING ++ bset $r12 30 // MMIO_CTRL_WRITE ++ iowr I[$r11 + 0x000] $r12 // MMIO_CTRL ++ nv_wr32_wait: ++ iord $r12 I[$r11 + 0x000] ++ xbit $r12 $r12 31 ++ bra ne nv_wr32_wait ++ ret ++ ++// (re)set watchdog timer ++// ++// In : $r15 timeout ++// ++watchdog_reset: ++ mov $r8 0x430 ++ shl b32 $r8 6 ++ bset $r15 31 ++ iowr I[$r8 + 0x000] $r15 ++ ret ++ ++// clear watchdog timer ++watchdog_clear: ++ mov $r8 0x430 ++ shl b32 $r8 6 ++ iowr I[$r8 + 0x000] $r0 ++ ret ++ ++// wait_done{z,o} - wait on FUC_DONE bit to become clear/set ++// ++// In : $r10 bit to wait on ++// ++define(`wait_done', ` ++$1: ++ trace_set(T_WAIT); ++ mov $r8 0x818 ++ shl b32 $r8 6 ++ iowr I[$r8 + 0x000] $r10 // CC_SCRATCH[6] = wait bit ++ wait_done_$1: ++ mov $r8 0x400 ++ shl b32 $r8 6 ++ iord $r8 I[$r8 + 0x000] // DONE ++ xbit $r8 $r8 $r10 ++ bra $2 wait_done_$1 ++ trace_clr(T_WAIT) ++ ret ++') ++wait_done(wait_donez, ne) ++wait_done(wait_doneo, e) ++ ++// mmctx_size - determine size of a mmio list transfer ++// ++// In : $r14 mmio list head ++// $r15 mmio list tail ++// Out: $r15 transfer size (in bytes) ++// ++mmctx_size: ++ clear b32 $r9 ++ nv_mmctx_size_loop: ++ ld b32 $r8 D[$r14] ++ shr b32 $r8 26 ++ add b32 $r8 1 ++ shl b32 $r8 2 ++ add b32 $r9 $r8 ++ add b32 $r14 4 ++ cmpu b32 $r14 $r15 ++ bra ne nv_mmctx_size_loop ++ mov b32 $r15 $r9 ++ ret ++ ++// mmctx_xfer - execute a list of mmio transfers ++// ++// In : $r10 flags ++// bit 0: direction (0 = save, 1 = load) ++// bit 1: set if first transfer ++// bit 2: set if last transfer ++// $r11 base ++// $r12 mmio list head ++// $r13 mmio list tail ++// $r14 multi_stride ++// $r15 multi_mask ++// ++mmctx_xfer: ++ trace_set(T_MMCTX) ++ mov $r8 0x710 ++ shl b32 $r8 6 ++ clear b32 $r9 ++ or $r11 $r11 ++ bra e mmctx_base_disabled ++ iowr I[$r8 + 0x000] $r11 // MMCTX_BASE ++ bset $r9 0 // BASE_EN ++ mmctx_base_disabled: ++ or $r14 $r14 ++ bra e mmctx_multi_disabled ++ iowr I[$r8 + 0x200] $r14 // MMCTX_MULTI_STRIDE ++ iowr I[$r8 + 0x300] $r15 // MMCTX_MULTI_MASK ++ bset $r9 1 // MULTI_EN ++ mmctx_multi_disabled: ++ add b32 $r8 0x100 ++ ++ xbit $r11 $r10 0 ++ shl b32 $r11 16 // DIR ++ bset $r11 12 // QLIMIT = 0x10 ++ xbit $r14 $r10 1 ++ shl b32 $r14 17 ++ or $r11 $r14 // START_TRIGGER ++ iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL ++ ++ // loop over the mmio list, and send requests to the hw ++ mmctx_exec_loop: ++ // wait for space in mmctx queue ++ mmctx_wait_free: ++ iord $r14 I[$r8 + 0x000] // MMCTX_CTRL ++ and $r14 0x1f ++ bra e mmctx_wait_free ++ ++ // queue up an entry ++ ld b32 $r14 D[$r12] ++ or $r14 $r9 ++ iowr I[$r8 + 0x300] $r14 ++ add b32 $r12 4 ++ cmpu b32 $r12 $r13 ++ bra ne mmctx_exec_loop ++ ++ xbit $r11 $r10 2 ++ bra ne mmctx_stop ++ // wait for queue to empty ++ mmctx_fini_wait: ++ iord $r11 I[$r8 + 0x000] // MMCTX_CTRL ++ and $r11 0x1f ++ cmpu b32 $r11 0x10 ++ bra ne mmctx_fini_wait ++ mov $r10 2 // DONE_MMCTX ++ call wait_donez ++ bra mmctx_done ++ mmctx_stop: ++ xbit $r11 $r10 0 ++ shl b32 $r11 16 // DIR ++ bset $r11 12 // QLIMIT = 0x10 ++ bset $r11 18 // STOP_TRIGGER ++ iowr I[$r8 + 0x000] $r11 // MMCTX_CTRL ++ mmctx_stop_wait: ++ // wait for STOP_TRIGGER to clear ++ iord $r11 I[$r8 + 0x000] // MMCTX_CTRL ++ xbit $r11 $r11 18 ++ bra ne mmctx_stop_wait ++ mmctx_done: ++ trace_clr(T_MMCTX) ++ ret ++ ++// Wait for DONE_STRAND ++// ++strand_wait: ++ push $r10 ++ mov $r10 2 ++ call wait_donez ++ pop $r10 ++ ret ++ ++// unknown - call before issuing strand commands ++// ++strand_pre: ++ mov $r8 0x4afc ++ sethi $r8 0x20000 ++ mov $r9 0xc ++ iowr I[$r8] $r9 ++ call strand_wait ++ ret ++ ++// unknown - call after issuing strand commands ++// ++strand_post: ++ mov $r8 0x4afc ++ sethi $r8 0x20000 ++ mov $r9 0xd ++ iowr I[$r8] $r9 ++ call strand_wait ++ ret ++ ++// Selects strand set?! ++// ++// In: $r14 id ++// ++strand_set: ++ mov $r10 0x4ffc ++ sethi $r10 0x20000 ++ sub b32 $r11 $r10 0x500 ++ mov $r12 0xf ++ iowr I[$r10 + 0x000] $r12 // 0x93c = 0xf ++ mov $r12 0xb ++ iowr I[$r11 + 0x000] $r12 // 0x928 = 0xb ++ call strand_wait ++ iowr I[$r10 + 0x000] $r14 // 0x93c = ++ mov $r12 0xa ++ iowr I[$r11 + 0x000] $r12 // 0x928 = 0xa ++ call strand_wait ++ ret ++ ++// Initialise strand context data ++// ++// In : $r15 context base ++// Out: $r15 context size (in bytes) ++// ++// Strandset(?) 3 hardcoded currently ++// ++strand_ctx_init: ++ trace_set(T_STRINIT) ++ call strand_pre ++ mov $r14 3 ++ call strand_set ++ mov $r10 0x46fc ++ sethi $r10 0x20000 ++ add b32 $r11 $r10 0x400 ++ iowr I[$r10 + 0x100] $r0 // STRAND_FIRST_GENE = 0 ++ mov $r12 1 ++ iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_FIRST_GENE ++ call strand_wait ++ sub b32 $r12 $r0 1 ++ iowr I[$r10 + 0x000] $r12 // STRAND_GENE_CNT = 0xffffffff ++ mov $r12 2 ++ iowr I[$r11 + 0x000] $r12 // STRAND_CMD = LATCH_GENE_CNT ++ call strand_wait ++ call strand_post ++ ++ // read the size of each strand, poke the context offset of ++ // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry ++ // about it later then. ++ mov $r8 0x880 ++ shl b32 $r8 6 ++ iord $r9 I[$r8 + 0x000] // STRANDS ++ add b32 $r8 0x2200 ++ shr b32 $r14 $r15 8 ++ ctx_init_strand_loop: ++ iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE ++ iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE ++ iord $r10 I[$r8 + 0x200] // STRAND_SIZE ++ shr b32 $r10 6 ++ add b32 $r10 1 ++ add b32 $r14 $r10 ++ add b32 $r8 4 ++ sub b32 $r9 1 ++ bra ne ctx_init_strand_loop ++ ++ shl b32 $r14 8 ++ sub b32 $r15 $r14 $r15 ++ trace_clr(T_STRINIT) ++ ret ++') +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_graph.h linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_graph.h +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_graph.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_graph.h 2011-07-26 07:03:44.507051975 +0200 +@@ -57,8 +57,7 @@ + struct nouveau_gpuobj *unk4188b4; + struct nouveau_gpuobj *unk4188b8; + +- u8 magic_not_rop_nr; +- u32 magicgpc918; ++ u8 magic_not_rop_nr; + }; + + struct nvc0_graph_chan { +@@ -72,4 +71,26 @@ + + int nvc0_grctx_generate(struct nouveau_channel *); + ++/* nvc0_graph.c uses this also to determine supported chipsets */ ++static inline u32 ++nvc0_graph_class(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ switch (dev_priv->chipset) { ++ case 0xc0: ++ case 0xc3: ++ case 0xc4: ++ case 0xce: /* guess, mmio trace shows only 0x9097 state */ ++ case 0xcf: /* guess, mmio trace shows only 0x9097 state */ ++ return 0x9097; ++ case 0xc1: ++ return 0x9197; ++ case 0xc8: ++ return 0x9297; ++ default: ++ return 0; ++ } ++} ++ + #endif +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_grctx.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grctx.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_grctx.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grctx.c 2011-07-26 07:03:44.509051999 +0200 +@@ -45,6 +45,9 @@ + static void + nvc0_grctx_generate_9097(struct drm_device *dev) + { ++ u32 fermi = nvc0_graph_class(dev); ++ u32 mthd; ++ + nv_mthd(dev, 0x9097, 0x0800, 0x00000000); + nv_mthd(dev, 0x9097, 0x0840, 0x00000000); + nv_mthd(dev, 0x9097, 0x0880, 0x00000000); +@@ -824,134 +827,10 @@ + 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); ++ if (fermi == 0x9097) { ++ for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4) ++ nv_mthd(dev, 0x9097, mthd, 0x00000000); ++ } + nv_mthd(dev, 0x9097, 0x030c, 0x00000001); + nv_mthd(dev, 0x9097, 0x1944, 0x00000000); + nv_mthd(dev, 0x9097, 0x1514, 0x00000000); +@@ -1321,6 +1200,37 @@ + } + + static void ++nvc0_grctx_generate_9197(struct drm_device *dev) ++{ ++ u32 fermi = nvc0_graph_class(dev); ++ u32 mthd; ++ ++ if (fermi == 0x9197) { ++ for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4) ++ nv_mthd(dev, 0x9197, mthd, 0x00000000); ++ } ++ nv_mthd(dev, 0x9197, 0x02e4, 0x0000b001); ++} ++ ++static void ++nvc0_grctx_generate_9297(struct drm_device *dev) ++{ ++ u32 fermi = nvc0_graph_class(dev); ++ u32 mthd; ++ ++ if (fermi == 0x9297) { ++ for (mthd = 0x3400; mthd <= 0x35fc; mthd += 4) ++ nv_mthd(dev, 0x9297, mthd, 0x00000000); ++ } ++ nv_mthd(dev, 0x9297, 0x036c, 0x00000000); ++ nv_mthd(dev, 0x9297, 0x0370, 0x00000000); ++ nv_mthd(dev, 0x9297, 0x07a4, 0x00000000); ++ nv_mthd(dev, 0x9297, 0x07a8, 0x00000000); ++ nv_mthd(dev, 0x9297, 0x0374, 0x00000000); ++ nv_mthd(dev, 0x9297, 0x0378, 0x00000020); ++} ++ ++static void + nvc0_grctx_generate_902d(struct drm_device *dev) + { + nv_mthd(dev, 0x902d, 0x0200, 0x000000cf); +@@ -1559,8 +1469,15 @@ + static void + nvc0_grctx_generate_shaders(struct drm_device *dev) + { +- nv_wr32(dev, 0x405800, 0x078000bf); +- nv_wr32(dev, 0x405830, 0x02180000); ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ ++ if (dev_priv->chipset != 0xc1) { ++ nv_wr32(dev, 0x405800, 0x078000bf); ++ nv_wr32(dev, 0x405830, 0x02180000); ++ } else { ++ nv_wr32(dev, 0x405800, 0x0f8000bf); ++ nv_wr32(dev, 0x405830, 0x02180218); ++ } + nv_wr32(dev, 0x405834, 0x00000000); + nv_wr32(dev, 0x405838, 0x00000000); + nv_wr32(dev, 0x405854, 0x00000000); +@@ -1586,10 +1503,16 @@ + static void + nvc0_grctx_generate_unk64xx(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ + nv_wr32(dev, 0x4064a8, 0x00000000); + nv_wr32(dev, 0x4064ac, 0x00003fff); + nv_wr32(dev, 0x4064b4, 0x00000000); + nv_wr32(dev, 0x4064b8, 0x00000000); ++ if (dev_priv->chipset == 0xc1) { ++ nv_wr32(dev, 0x4064c0, 0x80140078); ++ nv_wr32(dev, 0x4064c4, 0x0086ffff); ++ } + } + + static void +@@ -1622,21 +1545,14 @@ + nvc0_grctx_generate_rop(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int chipset = dev_priv->chipset; + + /* 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, 0x408808, chipset != 0xc1 ? 0x0003e00d : 0x1003e005); ++ nv_wr32(dev, 0x408900, 0x3080b801); ++ nv_wr32(dev, 0x408904, chipset != 0xc1 ? 0x02000001 : 0x62000001); + nv_wr32(dev, 0x408908, 0x00c80929); + nv_wr32(dev, 0x40890c, 0x00000000); + nv_wr32(dev, 0x408980, 0x0000011d); +@@ -1645,6 +1561,8 @@ + static void + nvc0_grctx_generate_gpc(struct drm_device *dev) + { ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int chipset = dev_priv->chipset; + int i; + + /* GPC_BROADCAST */ +@@ -1676,7 +1594,7 @@ + nv_wr32(dev, 0x41880c, 0x00000000); + nv_wr32(dev, 0x418810, 0x00000000); + nv_wr32(dev, 0x418828, 0x00008442); +- nv_wr32(dev, 0x418830, 0x00000001); ++ nv_wr32(dev, 0x418830, chipset != 0xc1 ? 0x00000001 : 0x10000001); + nv_wr32(dev, 0x4188d8, 0x00000008); + nv_wr32(dev, 0x4188e0, 0x01000000); + nv_wr32(dev, 0x4188e8, 0x00000000); +@@ -1684,7 +1602,7 @@ + nv_wr32(dev, 0x4188f0, 0x00000000); + nv_wr32(dev, 0x4188f4, 0x00000000); + nv_wr32(dev, 0x4188f8, 0x00000000); +- nv_wr32(dev, 0x4188fc, 0x00100000); ++ nv_wr32(dev, 0x4188fc, chipset != 0xc1 ? 0x00100000 : 0x00100018); + nv_wr32(dev, 0x41891c, 0x00ff00ff); + nv_wr32(dev, 0x418924, 0x00000000); + nv_wr32(dev, 0x418928, 0x00ffff00); +@@ -1715,6 +1633,8 @@ + nv_wr32(dev, 0x418c24, 0x00000000); + nv_wr32(dev, 0x418c28, 0x00000000); + nv_wr32(dev, 0x418c2c, 0x00000000); ++ if (chipset == 0xc1) ++ nv_wr32(dev, 0x418c6c, 0x00000001); + nv_wr32(dev, 0x418c80, 0x20200004); + nv_wr32(dev, 0x418c8c, 0x00000001); + nv_wr32(dev, 0x419000, 0x00000780); +@@ -1727,10 +1647,13 @@ + nvc0_grctx_generate_tp(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int chipset = dev_priv->chipset; + + /* GPC_BROADCAST.TP_BROADCAST */ ++ nv_wr32(dev, 0x419818, 0x00000000); ++ nv_wr32(dev, 0x41983c, 0x00038bc7); + nv_wr32(dev, 0x419848, 0x00000000); +- nv_wr32(dev, 0x419864, 0x0000012a); ++ nv_wr32(dev, 0x419864, chipset != 0xc1 ? 0x0000012a : 0x00000129); + nv_wr32(dev, 0x419888, 0x00000000); + nv_wr32(dev, 0x419a00, 0x000001f0); + nv_wr32(dev, 0x419a04, 0x00000001); +@@ -1740,8 +1663,8 @@ + 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 */ ++ if (chipset != 0xc0 && chipset != 0xc8) ++ nv_wr32(dev, 0x00419ac4, 0x0007f440); + nv_wr32(dev, 0x419b00, 0x0a418820); + nv_wr32(dev, 0x419b04, 0x062080e6); + nv_wr32(dev, 0x419b08, 0x020398a4); +@@ -1749,17 +1672,22 @@ + nv_wr32(dev, 0x419b10, 0x0a418820); + nv_wr32(dev, 0x419b14, 0x000000e6); + nv_wr32(dev, 0x419bd0, 0x00900103); +- nv_wr32(dev, 0x419be0, 0x00000001); ++ nv_wr32(dev, 0x419be0, chipset != 0xc1 ? 0x00000001 : 0x00400001); + 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); ++ if (chipset == 0xce || chipset == 0xcf) ++ nv_wr32(dev, 0x419cb0, 0x00020048); ++ else ++ nv_wr32(dev, 0x419cb0, 0x00060048); + nv_wr32(dev, 0x419ce8, 0x00000000); + nv_wr32(dev, 0x419cf4, 0x00000183); +- nv_wr32(dev, 0x419d20, 0x02180000); ++ nv_wr32(dev, 0x419d20, chipset != 0xc1 ? 0x02180000 : 0x12180000); + nv_wr32(dev, 0x419d24, 0x00001fff); ++ if (chipset == 0xc1) ++ nv_wr32(dev, 0x419d44, 0x02180218); + nv_wr32(dev, 0x419e04, 0x00000000); + nv_wr32(dev, 0x419e08, 0x00000000); + nv_wr32(dev, 0x419e0c, 0x00000000); +@@ -1785,11 +1713,11 @@ + nv_wr32(dev, 0x419e8c, 0x00000000); + nv_wr32(dev, 0x419e90, 0x00000000); + nv_wr32(dev, 0x419e98, 0x00000000); +- if (dev_priv->chipset != 0xc0) ++ if (chipset != 0xc0 && chipset != 0xc8) + nv_wr32(dev, 0x419ee0, 0x00011110); + nv_wr32(dev, 0x419f50, 0x00000000); + nv_wr32(dev, 0x419f54, 0x00000000); +- if (dev_priv->chipset != 0xc0) ++ if (chipset != 0xc0 && chipset != 0xc8) + nv_wr32(dev, 0x419f58, 0x00000000); + } + +@@ -1801,6 +1729,7 @@ + struct nvc0_graph_chan *grch = chan->engctx[NVOBJ_ENGINE_GR]; + struct drm_device *dev = chan->dev; + int i, gpc, tp, id; ++ u32 fermi = nvc0_graph_class(dev); + u32 r000260, tmp; + + r000260 = nv_rd32(dev, 0x000260); +@@ -1857,10 +1786,7 @@ + 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]; ++ u8 tpnr[GPC_MAX], data[TP_MAX]; + + memcpy(tpnr, priv->tp_nr, sizeof(priv->tp_nr)); + memset(data, 0x1f, sizeof(data)); +@@ -1874,7 +1800,7 @@ + data[tp] = gpc; + } + +- for (i = 0; i < max / 4; i++) ++ for (i = 0; i < 4; i++) + nv_wr32(dev, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + } + +@@ -2633,6 +2559,8 @@ + nv_icmd(dev, 0x0000053f, 0xffff0000); + nv_icmd(dev, 0x00000585, 0x0000003f); + nv_icmd(dev, 0x00000576, 0x00000003); ++ if (dev_priv->chipset == 0xc1) ++ nv_icmd(dev, 0x0000057b, 0x00000059); + nv_icmd(dev, 0x00000586, 0x00000040); + nv_icmd(dev, 0x00000582, 0x00000080); + nv_icmd(dev, 0x00000583, 0x00000080); +@@ -2865,6 +2793,10 @@ + nv_wr32(dev, 0x404154, 0x00000400); + + nvc0_grctx_generate_9097(dev); ++ if (fermi >= 0x9197) ++ nvc0_grctx_generate_9197(dev); ++ if (fermi >= 0x9297) ++ nvc0_grctx_generate_9297(dev); + nvc0_grctx_generate_902d(dev); + nvc0_grctx_generate_9039(dev); + nvc0_grctx_generate_90c0(dev); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc 2011-07-26 07:03:44.511052023 +0200 +@@ -0,0 +1,480 @@ ++/* fuc microcode for nvc0 PGRAPH/GPC ++ * ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++/* To build: ++ * m4 nvc0_grgpc.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grgpc.fuc.h ++ */ ++ ++/* TODO ++ * - bracket certain functions with scratch writes, useful for debugging ++ * - watchdog timer around ctx operations ++ */ ++ ++.section nvc0_grgpc_data ++include(`nvc0_graph.fuc') ++gpc_id: .b32 0 ++gpc_mmio_list_head: .b32 0 ++gpc_mmio_list_tail: .b32 0 ++ ++tpc_count: .b32 0 ++tpc_mask: .b32 0 ++tpc_mmio_list_head: .b32 0 ++tpc_mmio_list_tail: .b32 0 ++ ++cmd_queue: queue_init ++ ++// chipset descriptions ++chipsets: ++.b8 0xc0 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvc0_tpc_mmio_tail ++.b8 0xc1 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc1_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvc1_tpc_mmio_tail ++.b8 0xc3 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvc3_tpc_mmio_tail ++.b8 0xc4 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvc3_tpc_mmio_tail ++.b8 0xc8 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvc0_tpc_mmio_tail ++.b8 0xce 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvc3_tpc_mmio_tail ++.b8 0xcf 0 0 0 ++.b16 nvc0_gpc_mmio_head ++.b16 nvc0_gpc_mmio_tail ++.b16 nvc0_tpc_mmio_head ++.b16 nvcf_tpc_mmio_tail ++.b8 0 0 0 0 ++ ++// GPC mmio lists ++nvc0_gpc_mmio_head: ++mmctx_data(0x000380, 1) ++mmctx_data(0x000400, 6) ++mmctx_data(0x000450, 9) ++mmctx_data(0x000600, 1) ++mmctx_data(0x000684, 1) ++mmctx_data(0x000700, 5) ++mmctx_data(0x000800, 1) ++mmctx_data(0x000808, 3) ++mmctx_data(0x000828, 1) ++mmctx_data(0x000830, 1) ++mmctx_data(0x0008d8, 1) ++mmctx_data(0x0008e0, 1) ++mmctx_data(0x0008e8, 6) ++mmctx_data(0x00091c, 1) ++mmctx_data(0x000924, 3) ++mmctx_data(0x000b00, 1) ++mmctx_data(0x000b08, 6) ++mmctx_data(0x000bb8, 1) ++mmctx_data(0x000c08, 1) ++mmctx_data(0x000c10, 8) ++mmctx_data(0x000c80, 1) ++mmctx_data(0x000c8c, 1) ++mmctx_data(0x001000, 3) ++mmctx_data(0x001014, 1) ++nvc0_gpc_mmio_tail: ++mmctx_data(0x000c6c, 1); ++nvc1_gpc_mmio_tail: ++ ++// TPC mmio lists ++nvc0_tpc_mmio_head: ++mmctx_data(0x000018, 1) ++mmctx_data(0x00003c, 1) ++mmctx_data(0x000048, 1) ++mmctx_data(0x000064, 1) ++mmctx_data(0x000088, 1) ++mmctx_data(0x000200, 6) ++mmctx_data(0x00021c, 2) ++mmctx_data(0x000300, 6) ++mmctx_data(0x0003d0, 1) ++mmctx_data(0x0003e0, 2) ++mmctx_data(0x000400, 3) ++mmctx_data(0x000420, 1) ++mmctx_data(0x0004b0, 1) ++mmctx_data(0x0004e8, 1) ++mmctx_data(0x0004f4, 1) ++mmctx_data(0x000520, 2) ++mmctx_data(0x000604, 4) ++mmctx_data(0x000644, 20) ++mmctx_data(0x000698, 1) ++mmctx_data(0x000750, 2) ++nvc0_tpc_mmio_tail: ++mmctx_data(0x000758, 1) ++mmctx_data(0x0002c4, 1) ++mmctx_data(0x0006e0, 1) ++nvcf_tpc_mmio_tail: ++mmctx_data(0x0004bc, 1) ++nvc3_tpc_mmio_tail: ++mmctx_data(0x000544, 1) ++nvc1_tpc_mmio_tail: ++ ++ ++.section nvc0_grgpc_code ++bra init ++define(`include_code') ++include(`nvc0_graph.fuc') ++ ++// reports an exception to the host ++// ++// In: $r15 error code (see nvc0_graph.fuc) ++// ++error: ++ push $r14 ++ mov $r14 -0x67ec // 0x9814 ++ sethi $r14 0x400000 ++ call nv_wr32 // HUB_CTXCTL_CC_SCRATCH[5] = error code ++ add b32 $r14 0x41c ++ mov $r15 1 ++ call nv_wr32 // HUB_CTXCTL_INTR_UP_SET ++ pop $r14 ++ ret ++ ++// GPC fuc initialisation, executed by triggering ucode start, will ++// fall through to main loop after completion. ++// ++// Input: ++// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh) ++// CC_SCRATCH[1]: context base ++// ++// Output: ++// CC_SCRATCH[0]: ++// 31:31: set to signal completion ++// CC_SCRATCH[1]: ++// 31:0: GPC context size ++// ++init: ++ clear b32 $r0 ++ mov $sp $r0 ++ ++ // enable fifo access ++ mov $r1 0x1200 ++ mov $r2 2 ++ iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE ++ ++ // setup i0 handler, and route all interrupts to it ++ mov $r1 ih ++ mov $iv0 $r1 ++ mov $r1 0x400 ++ iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH ++ ++ // enable fifo interrupt ++ mov $r2 4 ++ iowr I[$r1 + 0x000] $r2 // INTR_EN_SET ++ ++ // enable interrupts ++ bset $flags ie0 ++ ++ // figure out which GPC we are, and how many TPCs we have ++ mov $r1 0x608 ++ shl b32 $r1 6 ++ iord $r2 I[$r1 + 0x000] // UNITS ++ mov $r3 1 ++ and $r2 0x1f ++ shl b32 $r3 $r2 ++ sub b32 $r3 1 ++ st b32 D[$r0 + tpc_count] $r2 ++ st b32 D[$r0 + tpc_mask] $r3 ++ add b32 $r1 0x400 ++ iord $r2 I[$r1 + 0x000] // MYINDEX ++ st b32 D[$r0 + gpc_id] $r2 ++ ++ // find context data for this chipset ++ mov $r2 0x800 ++ shl b32 $r2 6 ++ iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0] ++ mov $r1 chipsets - 12 ++ init_find_chipset: ++ add b32 $r1 12 ++ ld b32 $r3 D[$r1 + 0x00] ++ cmpu b32 $r3 $r2 ++ bra e init_context ++ cmpu b32 $r3 0 ++ bra ne init_find_chipset ++ // unknown chipset ++ ret ++ ++ // initialise context base, and size tracking ++ init_context: ++ mov $r2 0x800 ++ shl b32 $r2 6 ++ iord $r2 I[$r2 + 0x100] // CC_SCRATCH[1], initial base ++ clear b32 $r3 // track GPC context size here ++ ++ // set mmctx base addresses now so we don't have to do it later, ++ // they don't currently ever change ++ mov $r4 0x700 ++ shl b32 $r4 6 ++ shr b32 $r5 $r2 8 ++ iowr I[$r4 + 0x000] $r5 // MMCTX_SAVE_SWBASE ++ iowr I[$r4 + 0x100] $r5 // MMCTX_LOAD_SWBASE ++ ++ // calculate GPC mmio context size, store the chipset-specific ++ // mmio list pointers somewhere we can get at them later without ++ // re-parsing the chipset list ++ clear b32 $r14 ++ clear b32 $r15 ++ ld b16 $r14 D[$r1 + 4] ++ ld b16 $r15 D[$r1 + 6] ++ st b16 D[$r0 + gpc_mmio_list_head] $r14 ++ st b16 D[$r0 + gpc_mmio_list_tail] $r15 ++ call mmctx_size ++ add b32 $r2 $r15 ++ add b32 $r3 $r15 ++ ++ // calculate per-TPC mmio context size, store the list pointers ++ ld b16 $r14 D[$r1 + 8] ++ ld b16 $r15 D[$r1 + 10] ++ st b16 D[$r0 + tpc_mmio_list_head] $r14 ++ st b16 D[$r0 + tpc_mmio_list_tail] $r15 ++ call mmctx_size ++ ld b32 $r14 D[$r0 + tpc_count] ++ mulu $r14 $r15 ++ add b32 $r2 $r14 ++ add b32 $r3 $r14 ++ ++ // round up base/size to 256 byte boundary (for strand SWBASE) ++ add b32 $r4 0x1300 ++ shr b32 $r3 2 ++ iowr I[$r4 + 0x000] $r3 // MMCTX_LOAD_COUNT, wtf for?!? ++ shr b32 $r2 8 ++ shr b32 $r3 6 ++ add b32 $r2 1 ++ add b32 $r3 1 ++ shl b32 $r2 8 ++ shl b32 $r3 8 ++ ++ // calculate size of strand context data ++ mov b32 $r15 $r2 ++ call strand_ctx_init ++ add b32 $r3 $r15 ++ ++ // save context size, and tell HUB we're done ++ mov $r1 0x800 ++ shl b32 $r1 6 ++ iowr I[$r1 + 0x100] $r3 // CC_SCRATCH[1] = context size ++ add b32 $r1 0x800 ++ clear b32 $r2 ++ bset $r2 31 ++ iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000 ++ ++// Main program loop, very simple, sleeps until woken up by the interrupt ++// handler, pulls a command from the queue and executes its handler ++// ++main: ++ bset $flags $p0 ++ sleep $p0 ++ mov $r13 cmd_queue ++ call queue_get ++ bra $p1 main ++ ++ // 0x0000-0x0003 are all context transfers ++ cmpu b32 $r14 0x04 ++ bra nc main_not_ctx_xfer ++ // fetch $flags and mask off $p1/$p2 ++ mov $r1 $flags ++ mov $r2 0x0006 ++ not b32 $r2 ++ and $r1 $r2 ++ // set $p1/$p2 according to transfer type ++ shl b32 $r14 1 ++ or $r1 $r14 ++ mov $flags $r1 ++ // transfer context data ++ call ctx_xfer ++ bra main ++ ++ main_not_ctx_xfer: ++ shl b32 $r15 $r14 16 ++ or $r15 E_BAD_COMMAND ++ call error ++ bra main ++ ++// interrupt handler ++ih: ++ push $r8 ++ mov $r8 $flags ++ push $r8 ++ push $r9 ++ push $r10 ++ push $r11 ++ push $r13 ++ push $r14 ++ push $r15 ++ ++ // incoming fifo command? ++ iord $r10 I[$r0 + 0x200] // INTR ++ and $r11 $r10 0x00000004 ++ bra e ih_no_fifo ++ // queue incoming fifo command for later processing ++ mov $r11 0x1900 ++ mov $r13 cmd_queue ++ iord $r14 I[$r11 + 0x100] // FIFO_CMD ++ iord $r15 I[$r11 + 0x000] // FIFO_DATA ++ call queue_put ++ add b32 $r11 0x400 ++ mov $r14 1 ++ iowr I[$r11 + 0x000] $r14 // FIFO_ACK ++ ++ // ack, and wake up main() ++ ih_no_fifo: ++ iowr I[$r0 + 0x100] $r10 // INTR_ACK ++ ++ pop $r15 ++ pop $r14 ++ pop $r13 ++ pop $r11 ++ pop $r10 ++ pop $r9 ++ pop $r8 ++ mov $flags $r8 ++ pop $r8 ++ bclr $flags $p0 ++ iret ++ ++// Set this GPC's bit in HUB_BAR, used to signal completion of various ++// activities to the HUB fuc ++// ++hub_barrier_done: ++ mov $r15 1 ++ ld b32 $r14 D[$r0 + gpc_id] ++ shl b32 $r15 $r14 ++ mov $r14 -0x6be8 // 0x409418 - HUB_BAR_SET ++ sethi $r14 0x400000 ++ call nv_wr32 ++ ret ++ ++// Disables various things, waits a bit, and re-enables them.. ++// ++// Not sure how exactly this helps, perhaps "ENABLE" is not such a ++// good description for the bits we turn off? Anyways, without this, ++// funny things happen. ++// ++ctx_redswitch: ++ mov $r14 0x614 ++ shl b32 $r14 6 ++ mov $r15 0x020 ++ iowr I[$r14] $r15 // GPC_RED_SWITCH = POWER ++ mov $r15 8 ++ ctx_redswitch_delay: ++ sub b32 $r15 1 ++ bra ne ctx_redswitch_delay ++ mov $r15 0xa20 ++ iowr I[$r14] $r15 // GPC_RED_SWITCH = UNK11, ENABLE, POWER ++ ret ++ ++// Transfer GPC context data between GPU and storage area ++// ++// In: $r15 context base address ++// $p1 clear on save, set on load ++// $p2 set if opposite direction done/will be done, so: ++// on save it means: "a load will follow this save" ++// on load it means: "a save preceeded this load" ++// ++ctx_xfer: ++ // set context base address ++ mov $r1 0xa04 ++ shl b32 $r1 6 ++ iowr I[$r1 + 0x000] $r15// MEM_BASE ++ bra not $p1 ctx_xfer_not_load ++ call ctx_redswitch ++ ctx_xfer_not_load: ++ ++ // strands ++ mov $r1 0x4afc ++ sethi $r1 0x20000 ++ mov $r2 0xc ++ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c ++ call strand_wait ++ mov $r2 0x47fc ++ sethi $r2 0x20000 ++ iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 ++ xbit $r2 $flags $p1 ++ add b32 $r2 3 ++ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) ++ ++ // mmio context ++ xbit $r10 $flags $p1 // direction ++ or $r10 2 // first ++ mov $r11 0x0000 ++ sethi $r11 0x500000 ++ ld b32 $r12 D[$r0 + gpc_id] ++ shl b32 $r12 15 ++ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn ++ ld b32 $r12 D[$r0 + gpc_mmio_list_head] ++ ld b32 $r13 D[$r0 + gpc_mmio_list_tail] ++ mov $r14 0 // not multi ++ call mmctx_xfer ++ ++ // per-TPC mmio context ++ xbit $r10 $flags $p1 // direction ++ or $r10 4 // last ++ mov $r11 0x4000 ++ sethi $r11 0x500000 // base = NV_PGRAPH_GPC0_TPC0 ++ ld b32 $r12 D[$r0 + gpc_id] ++ shl b32 $r12 15 ++ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0 ++ ld b32 $r12 D[$r0 + tpc_mmio_list_head] ++ ld b32 $r13 D[$r0 + tpc_mmio_list_tail] ++ ld b32 $r15 D[$r0 + tpc_mask] ++ mov $r14 0x800 // stride = 0x800 ++ call mmctx_xfer ++ ++ // wait for strands to finish ++ call strand_wait ++ ++ // if load, or a save without a load following, do some ++ // unknown stuff that's done after finishing a block of ++ // strand commands ++ bra $p1 ctx_xfer_post ++ bra not $p2 ctx_xfer_done ++ ctx_xfer_post: ++ mov $r1 0x4afc ++ sethi $r1 0x20000 ++ mov $r2 0xd ++ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0d ++ call strand_wait ++ ++ // mark completion in HUB's barrier ++ ctx_xfer_done: ++ call hub_barrier_done ++ ret ++ ++.align 256 +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grgpc.fuc.h 2011-07-26 07:03:44.511052023 +0200 +@@ -0,0 +1,486 @@ ++uint32_t nvc0_grgpc_data[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x000000c0, ++ 0x011c00bc, ++ 0x01700120, ++ 0x000000c1, ++ 0x012000bc, ++ 0x01840120, ++ 0x000000c3, ++ 0x011c00bc, ++ 0x01800120, ++ 0x000000c4, ++ 0x011c00bc, ++ 0x01800120, ++ 0x000000c8, ++ 0x011c00bc, ++ 0x01700120, ++ 0x000000ce, ++ 0x011c00bc, ++ 0x01800120, ++ 0x000000cf, ++ 0x011c00bc, ++ 0x017c0120, ++ 0x00000000, ++ 0x00000380, ++ 0x14000400, ++ 0x20000450, ++ 0x00000600, ++ 0x00000684, ++ 0x10000700, ++ 0x00000800, ++ 0x08000808, ++ 0x00000828, ++ 0x00000830, ++ 0x000008d8, ++ 0x000008e0, ++ 0x140008e8, ++ 0x0000091c, ++ 0x08000924, ++ 0x00000b00, ++ 0x14000b08, ++ 0x00000bb8, ++ 0x00000c08, ++ 0x1c000c10, ++ 0x00000c80, ++ 0x00000c8c, ++ 0x08001000, ++ 0x00001014, ++ 0x00000c6c, ++ 0x00000018, ++ 0x0000003c, ++ 0x00000048, ++ 0x00000064, ++ 0x00000088, ++ 0x14000200, ++ 0x0400021c, ++ 0x14000300, ++ 0x000003d0, ++ 0x040003e0, ++ 0x08000400, ++ 0x00000420, ++ 0x000004b0, ++ 0x000004e8, ++ 0x000004f4, ++ 0x04000520, ++ 0x0c000604, ++ 0x4c000644, ++ 0x00000698, ++ 0x04000750, ++ 0x00000758, ++ 0x000002c4, ++ 0x000006e0, ++ 0x000004bc, ++ 0x00000544, ++}; ++ ++uint32_t nvc0_grgpc_code[] = { ++ 0x03060ef5, ++ 0x9800d898, ++ 0x86f001d9, ++ 0x0489b808, ++ 0xf00c1bf4, ++ 0x21f502f7, ++ 0x00f802ec, ++ 0xb60798c4, ++ 0x8dbb0384, ++ 0x0880b600, ++ 0x80008e80, ++ 0x90b6018f, ++ 0x0f94f001, ++ 0xf801d980, ++ 0x0131f400, ++ 0x9800d898, ++ 0x89b801d9, ++ 0x210bf404, ++ 0xb60789c4, ++ 0x9dbb0394, ++ 0x0890b600, ++ 0x98009e98, ++ 0x80b6019f, ++ 0x0f84f001, ++ 0xf400d880, ++ 0x00f80132, ++ 0x0728b7f1, ++ 0xb906b4b6, ++ 0xc9f002ec, ++ 0x00bcd01f, ++ 0xc800bccf, ++ 0x1bf41fcc, ++ 0x06a7f0fa, ++ 0x010321f5, ++ 0xf840bfcf, ++ 0x28b7f100, ++ 0x06b4b607, ++ 0xb980bfd0, ++ 0xc9f002ec, ++ 0x1ec9f01f, ++ 0xcf00bcd0, ++ 0xccc800bc, ++ 0xfa1bf41f, ++ 0x87f100f8, ++ 0x84b60430, ++ 0x1ff9f006, ++ 0xf8008fd0, ++ 0x3087f100, ++ 0x0684b604, ++ 0xf80080d0, ++ 0x3c87f100, ++ 0x0684b608, ++ 0x99f094bd, ++ 0x0089d000, ++ 0x081887f1, ++ 0xd00684b6, ++ 0x87f1008a, ++ 0x84b60400, ++ 0x0088cf06, ++ 0xf4888aff, ++ 0x87f1f31b, ++ 0x84b6085c, ++ 0xf094bd06, ++ 0x89d00099, ++ 0xf100f800, ++ 0xb6083c87, ++ 0x94bd0684, ++ 0xd00099f0, ++ 0x87f10089, ++ 0x84b60818, ++ 0x008ad006, ++ 0x040087f1, ++ 0xcf0684b6, ++ 0x8aff0088, ++ 0xf30bf488, ++ 0x085c87f1, ++ 0xbd0684b6, ++ 0x0099f094, ++ 0xf80089d0, ++ 0x9894bd00, ++ 0x85b600e8, ++ 0x0180b61a, ++ 0xbb0284b6, ++ 0xe0b60098, ++ 0x04efb804, ++ 0xb9eb1bf4, ++ 0x00f8029f, ++ 0x083c87f1, ++ 0xbd0684b6, ++ 0x0199f094, ++ 0xf10089d0, ++ 0xb6071087, ++ 0x94bd0684, ++ 0xf405bbfd, ++ 0x8bd0090b, ++ 0x0099f000, ++ 0xf405eefd, ++ 0x8ed00c0b, ++ 0xc08fd080, ++ 0xb70199f0, ++ 0xc8010080, ++ 0xb4b600ab, ++ 0x0cb9f010, ++ 0xb601aec8, ++ 0xbefd11e4, ++ 0x008bd005, ++ 0xf0008ecf, ++ 0x0bf41fe4, ++ 0x00ce98fa, ++ 0xd005e9fd, ++ 0xc0b6c08e, ++ 0x04cdb804, ++ 0xc8e81bf4, ++ 0x1bf402ab, ++ 0x008bcf18, ++ 0xb01fb4f0, ++ 0x1bf410b4, ++ 0x02a7f0f7, ++ 0xf4c921f4, ++ 0xabc81b0e, ++ 0x10b4b600, ++ 0xf00cb9f0, ++ 0x8bd012b9, ++ 0x008bcf00, ++ 0xf412bbc8, ++ 0x87f1fa1b, ++ 0x84b6085c, ++ 0xf094bd06, ++ 0x89d00199, ++ 0xf900f800, ++ 0x02a7f0a0, ++ 0xfcc921f4, ++ 0xf100f8a0, ++ 0xf04afc87, ++ 0x97f00283, ++ 0x0089d00c, ++ 0x020721f5, ++ 0x87f100f8, ++ 0x83f04afc, ++ 0x0d97f002, ++ 0xf50089d0, ++ 0xf8020721, ++ 0xfca7f100, ++ 0x02a3f04f, ++ 0x0500aba2, ++ 0xd00fc7f0, ++ 0xc7f000ac, ++ 0x00bcd00b, ++ 0x020721f5, ++ 0xf000aed0, ++ 0xbcd00ac7, ++ 0x0721f500, ++ 0xf100f802, ++ 0xb6083c87, ++ 0x94bd0684, ++ 0xd00399f0, ++ 0x21f50089, ++ 0xe7f00213, ++ 0x3921f503, ++ 0xfca7f102, ++ 0x02a3f046, ++ 0x0400aba0, ++ 0xf040a0d0, ++ 0xbcd001c7, ++ 0x0721f500, ++ 0x010c9202, ++ 0xf000acd0, ++ 0xbcd002c7, ++ 0x0721f500, ++ 0x2621f502, ++ 0x8087f102, ++ 0x0684b608, ++ 0xb70089cf, ++ 0x95220080, ++ 0x8ed008fe, ++ 0x408ed000, ++ 0xb6808acf, ++ 0xa0b606a5, ++ 0x00eabb01, ++ 0xb60480b6, ++ 0x1bf40192, ++ 0x08e4b6e8, ++ 0xf1f2efbc, ++ 0xb6085c87, ++ 0x94bd0684, ++ 0xd00399f0, ++ 0x00f80089, ++ 0xe7f1e0f9, ++ 0xe3f09814, ++ 0x8d21f440, ++ 0x041ce0b7, ++ 0xf401f7f0, ++ 0xe0fc8d21, ++ 0x04bd00f8, ++ 0xf10004fe, ++ 0xf0120017, ++ 0x12d00227, ++ 0x3e17f100, ++ 0x0010fe04, ++ 0x040017f1, ++ 0xf0c010d0, ++ 0x12d00427, ++ 0x1031f400, ++ 0x060817f1, ++ 0xcf0614b6, ++ 0x37f00012, ++ 0x1f24f001, ++ 0xb60432bb, ++ 0x02800132, ++ 0x04038003, ++ 0x040010b7, ++ 0x800012cf, ++ 0x27f10002, ++ 0x24b60800, ++ 0x0022cf06, ++ 0xb65817f0, ++ 0x13980c10, ++ 0x0432b800, ++ 0xb00b0bf4, ++ 0x1bf40034, ++ 0xf100f8f1, ++ 0xb6080027, ++ 0x22cf0624, ++ 0xf134bd40, ++ 0xb6070047, ++ 0x25950644, ++ 0x0045d008, ++ 0xbd4045d0, ++ 0x58f4bde4, ++ 0x1f58021e, ++ 0x020e4003, ++ 0xf5040f40, ++ 0xbb013d21, ++ 0x3fbb002f, ++ 0x041e5800, ++ 0x40051f58, ++ 0x0f400a0e, ++ 0x3d21f50c, ++ 0x030e9801, ++ 0xbb00effd, ++ 0x3ebb002e, ++ 0x0040b700, ++ 0x0235b613, ++ 0xb60043d0, ++ 0x35b60825, ++ 0x0120b606, ++ 0xb60130b6, ++ 0x34b60824, ++ 0x022fb908, ++ 0x026321f5, ++ 0xf1003fbb, ++ 0xb6080017, ++ 0x13d00614, ++ 0x0010b740, ++ 0xf024bd08, ++ 0x12d01f29, ++ 0x0031f400, ++ 0xf00028f4, ++ 0x21f41cd7, ++ 0xf401f439, ++ 0xf404e4b0, ++ 0x81fe1e18, ++ 0x0627f001, ++ 0x12fd20bd, ++ 0x01e4b604, ++ 0xfe051efd, ++ 0x21f50018, ++ 0x0ef404c3, ++ 0x10ef94d3, ++ 0xf501f5f0, ++ 0xf402ec21, ++ 0x80f9c60e, ++ 0xf90188fe, ++ 0xf990f980, ++ 0xf9b0f9a0, ++ 0xf9e0f9d0, ++ 0x800acff0, ++ 0xf404abc4, ++ 0xb7f11d0b, ++ 0xd7f01900, ++ 0x40becf1c, ++ 0xf400bfcf, ++ 0xb0b70421, ++ 0xe7f00400, ++ 0x00bed001, ++ 0xfc400ad0, ++ 0xfce0fcf0, ++ 0xfcb0fcd0, ++ 0xfc90fca0, ++ 0x0088fe80, ++ 0x32f480fc, ++ 0xf001f800, ++ 0x0e9801f7, ++ 0x04febb00, ++ 0x9418e7f1, ++ 0xf440e3f0, ++ 0x00f88d21, ++ 0x0614e7f1, ++ 0xf006e4b6, ++ 0xefd020f7, ++ 0x08f7f000, ++ 0xf401f2b6, ++ 0xf7f1fd1b, ++ 0xefd00a20, ++ 0xf100f800, ++ 0xb60a0417, ++ 0x1fd00614, ++ 0x0711f400, ++ 0x04a421f5, ++ 0x4afc17f1, ++ 0xf00213f0, ++ 0x12d00c27, ++ 0x0721f500, ++ 0xfc27f102, ++ 0x0223f047, ++ 0xf00020d0, ++ 0x20b6012c, ++ 0x0012d003, ++ 0xf001acf0, ++ 0xb7f002a5, ++ 0x50b3f000, ++ 0xb6000c98, ++ 0xbcbb0fc4, ++ 0x010c9800, ++ 0xf0020d98, ++ 0x21f500e7, ++ 0xacf0015c, ++ 0x04a5f001, ++ 0x4000b7f1, ++ 0x9850b3f0, ++ 0xc4b6000c, ++ 0x00bcbb0f, ++ 0x98050c98, ++ 0x0f98060d, ++ 0x00e7f104, ++ 0x5c21f508, ++ 0x0721f501, ++ 0x0601f402, ++ 0xf11412f4, ++ 0xf04afc17, ++ 0x27f00213, ++ 0x0012d00d, ++ 0x020721f5, ++ 0x048f21f5, ++ 0x000000f8, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_grhub.fuc linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grhub.fuc +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_grhub.fuc 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grhub.fuc 2011-07-26 07:03:44.512052035 +0200 +@@ -0,0 +1,811 @@ ++/* fuc microcode for nvc0 PGRAPH/HUB ++ * ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++/* To build: ++ * m4 nvc0_grhub.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_grhub.fuc.h ++ */ ++ ++.section nvc0_grhub_data ++include(`nvc0_graph.fuc') ++gpc_count: .b32 0 ++rop_count: .b32 0 ++cmd_queue: queue_init ++hub_mmio_list_head: .b32 0 ++hub_mmio_list_tail: .b32 0 ++ ++ctx_current: .b32 0 ++ ++chipsets: ++.b8 0xc0 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail ++.b8 0xc1 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc1_hub_mmio_tail ++.b8 0xc3 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail ++.b8 0xc4 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail ++.b8 0xc8 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail ++.b8 0xce 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail ++.b8 0xcf 0 0 0 ++.b16 nvc0_hub_mmio_head ++.b16 nvc0_hub_mmio_tail ++.b8 0 0 0 0 ++ ++nvc0_hub_mmio_head: ++mmctx_data(0x17e91c, 2) ++mmctx_data(0x400204, 2) ++mmctx_data(0x404004, 11) ++mmctx_data(0x404044, 1) ++mmctx_data(0x404094, 14) ++mmctx_data(0x4040d0, 7) ++mmctx_data(0x4040f8, 1) ++mmctx_data(0x404130, 3) ++mmctx_data(0x404150, 3) ++mmctx_data(0x404164, 2) ++mmctx_data(0x404174, 3) ++mmctx_data(0x404200, 8) ++mmctx_data(0x404404, 14) ++mmctx_data(0x404460, 4) ++mmctx_data(0x404480, 1) ++mmctx_data(0x404498, 1) ++mmctx_data(0x404604, 4) ++mmctx_data(0x404618, 32) ++mmctx_data(0x404698, 21) ++mmctx_data(0x4046f0, 2) ++mmctx_data(0x404700, 22) ++mmctx_data(0x405800, 1) ++mmctx_data(0x405830, 3) ++mmctx_data(0x405854, 1) ++mmctx_data(0x405870, 4) ++mmctx_data(0x405a00, 2) ++mmctx_data(0x405a18, 1) ++mmctx_data(0x406020, 1) ++mmctx_data(0x406028, 4) ++mmctx_data(0x4064a8, 2) ++mmctx_data(0x4064b4, 2) ++mmctx_data(0x407804, 1) ++mmctx_data(0x40780c, 6) ++mmctx_data(0x4078bc, 1) ++mmctx_data(0x408000, 7) ++mmctx_data(0x408064, 1) ++mmctx_data(0x408800, 3) ++mmctx_data(0x408900, 4) ++mmctx_data(0x408980, 1) ++nvc0_hub_mmio_tail: ++mmctx_data(0x4064c0, 2) ++nvc1_hub_mmio_tail: ++ ++.align 256 ++chan_data: ++chan_mmio_count: .b32 0 ++chan_mmio_address: .b32 0 ++ ++.align 256 ++xfer_data: .b32 0 ++ ++.section nvc0_grhub_code ++bra init ++define(`include_code') ++include(`nvc0_graph.fuc') ++ ++// reports an exception to the host ++// ++// In: $r15 error code (see nvc0_graph.fuc) ++// ++error: ++ push $r14 ++ mov $r14 0x814 ++ shl b32 $r14 6 ++ iowr I[$r14 + 0x000] $r15 // CC_SCRATCH[5] = error code ++ mov $r14 0xc1c ++ shl b32 $r14 6 ++ mov $r15 1 ++ iowr I[$r14 + 0x000] $r15 // INTR_UP_SET ++ pop $r14 ++ ret ++ ++// HUB fuc initialisation, executed by triggering ucode start, will ++// fall through to main loop after completion. ++// ++// Input: ++// CC_SCRATCH[0]: chipset (PMC_BOOT_0 read returns 0x0bad0bad... sigh) ++// ++// Output: ++// CC_SCRATCH[0]: ++// 31:31: set to signal completion ++// CC_SCRATCH[1]: ++// 31:0: total PGRAPH context size ++// ++init: ++ clear b32 $r0 ++ mov $sp $r0 ++ mov $xdbase $r0 ++ ++ // enable fifo access ++ mov $r1 0x1200 ++ mov $r2 2 ++ iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE ++ ++ // setup i0 handler, and route all interrupts to it ++ mov $r1 ih ++ mov $iv0 $r1 ++ mov $r1 0x400 ++ iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH ++ ++ // route HUB_CHANNEL_SWITCH to fuc interrupt 8 ++ mov $r3 0x404 ++ shl b32 $r3 6 ++ mov $r2 0x2003 // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8 ++ iowr I[$r3 + 0x000] $r2 ++ ++ // not sure what these are, route them because NVIDIA does, and ++ // the IRQ handler will signal the host if we ever get one.. we ++ // may find out if/why we need to handle these if so.. ++ // ++ mov $r2 0x2004 ++ iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9 ++ mov $r2 0x200b ++ iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10 ++ mov $r2 0x200c ++ iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15 ++ ++ // enable all INTR_UP interrupts ++ mov $r2 0xc24 ++ shl b32 $r2 6 ++ not b32 $r3 $r0 ++ iowr I[$r2] $r3 ++ ++ // enable fifo, ctxsw, 9, 10, 15 interrupts ++ mov $r2 -0x78fc // 0x8704 ++ sethi $r2 0 ++ iowr I[$r1 + 0x000] $r2 // INTR_EN_SET ++ ++ // fifo level triggered, rest edge ++ sub b32 $r1 0x100 ++ mov $r2 4 ++ iowr I[$r1] $r2 ++ ++ // enable interrupts ++ bset $flags ie0 ++ ++ // fetch enabled GPC/ROP counts ++ mov $r14 -0x69fc // 0x409604 ++ sethi $r14 0x400000 ++ call nv_rd32 ++ extr $r1 $r15 16:20 ++ st b32 D[$r0 + rop_count] $r1 ++ and $r15 0x1f ++ st b32 D[$r0 + gpc_count] $r15 ++ ++ // set BAR_REQMASK to GPC mask ++ mov $r1 1 ++ shl b32 $r1 $r15 ++ sub b32 $r1 1 ++ mov $r2 0x40c ++ shl b32 $r2 6 ++ iowr I[$r2 + 0x000] $r1 ++ iowr I[$r2 + 0x100] $r1 ++ ++ // find context data for this chipset ++ mov $r2 0x800 ++ shl b32 $r2 6 ++ iord $r2 I[$r2 + 0x000] // CC_SCRATCH[0] ++ mov $r15 chipsets - 8 ++ init_find_chipset: ++ add b32 $r15 8 ++ ld b32 $r3 D[$r15 + 0x00] ++ cmpu b32 $r3 $r2 ++ bra e init_context ++ cmpu b32 $r3 0 ++ bra ne init_find_chipset ++ // unknown chipset ++ ret ++ ++ // context size calculation, reserve first 256 bytes for use by fuc ++ init_context: ++ mov $r1 256 ++ ++ // calculate size of mmio context data ++ ld b16 $r14 D[$r15 + 4] ++ ld b16 $r15 D[$r15 + 6] ++ sethi $r14 0 ++ st b32 D[$r0 + hub_mmio_list_head] $r14 ++ st b32 D[$r0 + hub_mmio_list_tail] $r15 ++ call mmctx_size ++ ++ // set mmctx base addresses now so we don't have to do it later, ++ // they don't (currently) ever change ++ mov $r3 0x700 ++ shl b32 $r3 6 ++ shr b32 $r4 $r1 8 ++ iowr I[$r3 + 0x000] $r4 // MMCTX_SAVE_SWBASE ++ iowr I[$r3 + 0x100] $r4 // MMCTX_LOAD_SWBASE ++ add b32 $r3 0x1300 ++ add b32 $r1 $r15 ++ shr b32 $r15 2 ++ iowr I[$r3 + 0x000] $r15 // MMCTX_LOAD_COUNT, wtf for?!? ++ ++ // strands, base offset needs to be aligned to 256 bytes ++ shr b32 $r1 8 ++ add b32 $r1 1 ++ shl b32 $r1 8 ++ mov b32 $r15 $r1 ++ call strand_ctx_init ++ add b32 $r1 $r15 ++ ++ // initialise each GPC in sequence by passing in the offset of its ++ // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which ++ // has previously been uploaded by the host) running. ++ // ++ // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31 ++ // when it has completed, and return the size of its context data ++ // in GPCn_CC_SCRATCH[1] ++ // ++ ld b32 $r3 D[$r0 + gpc_count] ++ mov $r4 0x2000 ++ sethi $r4 0x500000 ++ init_gpc: ++ // setup, and start GPC ucode running ++ add b32 $r14 $r4 0x804 ++ mov b32 $r15 $r1 ++ call nv_wr32 // CC_SCRATCH[1] = ctx offset ++ add b32 $r14 $r4 0x800 ++ mov b32 $r15 $r2 ++ call nv_wr32 // CC_SCRATCH[0] = chipset ++ add b32 $r14 $r4 0x10c ++ clear b32 $r15 ++ call nv_wr32 ++ add b32 $r14 $r4 0x104 ++ call nv_wr32 // ENTRY ++ add b32 $r14 $r4 0x100 ++ mov $r15 2 // CTRL_START_TRIGGER ++ call nv_wr32 // CTRL ++ ++ // wait for it to complete, and adjust context size ++ add b32 $r14 $r4 0x800 ++ init_gpc_wait: ++ call nv_rd32 ++ xbit $r15 $r15 31 ++ bra e init_gpc_wait ++ add b32 $r14 $r4 0x804 ++ call nv_rd32 ++ add b32 $r1 $r15 ++ ++ // next! ++ add b32 $r4 0x8000 ++ sub b32 $r3 1 ++ bra ne init_gpc ++ ++ // save context size, and tell host we're ready ++ mov $r2 0x800 ++ shl b32 $r2 6 ++ iowr I[$r2 + 0x100] $r1 // CC_SCRATCH[1] = context size ++ add b32 $r2 0x800 ++ clear b32 $r1 ++ bset $r1 31 ++ iowr I[$r2 + 0x000] $r1 // CC_SCRATCH[0] |= 0x80000000 ++ ++// Main program loop, very simple, sleeps until woken up by the interrupt ++// handler, pulls a command from the queue and executes its handler ++// ++main: ++ // sleep until we have something to do ++ bset $flags $p0 ++ sleep $p0 ++ mov $r13 cmd_queue ++ call queue_get ++ bra $p1 main ++ ++ // context switch, requested by GPU? ++ cmpu b32 $r14 0x4001 ++ bra ne main_not_ctx_switch ++ trace_set(T_AUTO) ++ mov $r1 0xb00 ++ shl b32 $r1 6 ++ iord $r2 I[$r1 + 0x100] // CHAN_NEXT ++ iord $r1 I[$r1 + 0x000] // CHAN_CUR ++ ++ xbit $r3 $r1 31 ++ bra e chsw_no_prev ++ xbit $r3 $r2 31 ++ bra e chsw_prev_no_next ++ push $r2 ++ mov b32 $r2 $r1 ++ trace_set(T_SAVE) ++ bclr $flags $p1 ++ bset $flags $p2 ++ call ctx_xfer ++ trace_clr(T_SAVE); ++ pop $r2 ++ trace_set(T_LOAD); ++ bset $flags $p1 ++ call ctx_xfer ++ trace_clr(T_LOAD); ++ bra chsw_done ++ chsw_prev_no_next: ++ push $r2 ++ mov b32 $r2 $r1 ++ bclr $flags $p1 ++ bclr $flags $p2 ++ call ctx_xfer ++ pop $r2 ++ mov $r1 0xb00 ++ shl b32 $r1 6 ++ iowr I[$r1] $r2 ++ bra chsw_done ++ chsw_no_prev: ++ xbit $r3 $r2 31 ++ bra e chsw_done ++ bset $flags $p1 ++ bclr $flags $p2 ++ call ctx_xfer ++ ++ // ack the context switch request ++ chsw_done: ++ mov $r1 0xb0c ++ shl b32 $r1 6 ++ mov $r2 1 ++ iowr I[$r1 + 0x000] $r2 // 0x409b0c ++ trace_clr(T_AUTO) ++ bra main ++ ++ // request to set current channel? (*not* a context switch) ++ main_not_ctx_switch: ++ cmpu b32 $r14 0x0001 ++ bra ne main_not_ctx_chan ++ mov b32 $r2 $r15 ++ call ctx_chan ++ bra main_done ++ ++ // request to store current channel context? ++ main_not_ctx_chan: ++ cmpu b32 $r14 0x0002 ++ bra ne main_not_ctx_save ++ trace_set(T_SAVE) ++ bclr $flags $p1 ++ bclr $flags $p2 ++ call ctx_xfer ++ trace_clr(T_SAVE) ++ bra main_done ++ ++ main_not_ctx_save: ++ shl b32 $r15 $r14 16 ++ or $r15 E_BAD_COMMAND ++ call error ++ bra main ++ ++ main_done: ++ mov $r1 0x820 ++ shl b32 $r1 6 ++ clear b32 $r2 ++ bset $r2 31 ++ iowr I[$r1 + 0x000] $r2 // CC_SCRATCH[0] |= 0x80000000 ++ bra main ++ ++// interrupt handler ++ih: ++ push $r8 ++ mov $r8 $flags ++ push $r8 ++ push $r9 ++ push $r10 ++ push $r11 ++ push $r13 ++ push $r14 ++ push $r15 ++ ++ // incoming fifo command? ++ iord $r10 I[$r0 + 0x200] // INTR ++ and $r11 $r10 0x00000004 ++ bra e ih_no_fifo ++ // queue incoming fifo command for later processing ++ mov $r11 0x1900 ++ mov $r13 cmd_queue ++ iord $r14 I[$r11 + 0x100] // FIFO_CMD ++ iord $r15 I[$r11 + 0x000] // FIFO_DATA ++ call queue_put ++ add b32 $r11 0x400 ++ mov $r14 1 ++ iowr I[$r11 + 0x000] $r14 // FIFO_ACK ++ ++ // context switch request? ++ ih_no_fifo: ++ and $r11 $r10 0x00000100 ++ bra e ih_no_ctxsw ++ // enqueue a context switch for later processing ++ mov $r13 cmd_queue ++ mov $r14 0x4001 ++ call queue_put ++ ++ // anything we didn't handle, bring it to the host's attention ++ ih_no_ctxsw: ++ mov $r11 0x104 ++ not b32 $r11 ++ and $r11 $r10 $r11 ++ bra e ih_no_other ++ mov $r10 0xc1c ++ shl b32 $r10 6 ++ iowr I[$r10] $r11 // INTR_UP_SET ++ ++ // ack, and wake up main() ++ ih_no_other: ++ iowr I[$r0 + 0x100] $r10 // INTR_ACK ++ ++ pop $r15 ++ pop $r14 ++ pop $r13 ++ pop $r11 ++ pop $r10 ++ pop $r9 ++ pop $r8 ++ mov $flags $r8 ++ pop $r8 ++ bclr $flags $p0 ++ iret ++ ++// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done ++ctx_4160s: ++ mov $r14 0x4160 ++ sethi $r14 0x400000 ++ mov $r15 1 ++ call nv_wr32 ++ ctx_4160s_wait: ++ call nv_rd32 ++ xbit $r15 $r15 4 ++ bra e ctx_4160s_wait ++ ret ++ ++// Without clearing again at end of xfer, some things cause PGRAPH ++// to hang with STATUS=0x00000007 until it's cleared.. fbcon can ++// still function with it set however... ++ctx_4160c: ++ mov $r14 0x4160 ++ sethi $r14 0x400000 ++ clear b32 $r15 ++ call nv_wr32 ++ ret ++ ++// Again, not real sure ++// ++// In: $r15 value to set 0x404170 to ++// ++ctx_4170s: ++ mov $r14 0x4170 ++ sethi $r14 0x400000 ++ or $r15 0x10 ++ call nv_wr32 ++ ret ++ ++// Waits for a ctx_4170s() call to complete ++// ++ctx_4170w: ++ mov $r14 0x4170 ++ sethi $r14 0x400000 ++ call nv_rd32 ++ and $r15 0x10 ++ bra ne ctx_4170w ++ ret ++ ++// Disables various things, waits a bit, and re-enables them.. ++// ++// Not sure how exactly this helps, perhaps "ENABLE" is not such a ++// good description for the bits we turn off? Anyways, without this, ++// funny things happen. ++// ++ctx_redswitch: ++ mov $r14 0x614 ++ shl b32 $r14 6 ++ mov $r15 0x270 ++ iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL ++ mov $r15 8 ++ ctx_redswitch_delay: ++ sub b32 $r15 1 ++ bra ne ctx_redswitch_delay ++ mov $r15 0x770 ++ iowr I[$r14] $r15 // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL ++ ret ++ ++// Not a clue what this is for, except that unless the value is 0x10, the ++// strand context is saved (and presumably restored) incorrectly.. ++// ++// In: $r15 value to set to (0x00/0x10 are used) ++// ++ctx_86c: ++ mov $r14 0x86c ++ shl b32 $r14 6 ++ iowr I[$r14] $r15 // HUB(0x86c) = val ++ mov $r14 -0x75ec ++ sethi $r14 0x400000 ++ call nv_wr32 // ROP(0xa14) = val ++ mov $r14 -0x5794 ++ sethi $r14 0x410000 ++ call nv_wr32 // GPC(0x86c) = val ++ ret ++ ++// ctx_load - load's a channel's ctxctl data, and selects its vm ++// ++// In: $r2 channel address ++// ++ctx_load: ++ trace_set(T_CHAN) ++ ++ // switch to channel, somewhat magic in parts.. ++ mov $r10 12 // DONE_UNK12 ++ call wait_donez ++ mov $r1 0xa24 ++ shl b32 $r1 6 ++ iowr I[$r1 + 0x000] $r0 // 0x409a24 ++ mov $r3 0xb00 ++ shl b32 $r3 6 ++ iowr I[$r3 + 0x100] $r2 // CHAN_NEXT ++ mov $r1 0xa0c ++ shl b32 $r1 6 ++ mov $r4 7 ++ iowr I[$r1 + 0x000] $r2 // MEM_CHAN ++ iowr I[$r1 + 0x100] $r4 // MEM_CMD ++ ctx_chan_wait_0: ++ iord $r4 I[$r1 + 0x100] ++ and $r4 0x1f ++ bra ne ctx_chan_wait_0 ++ iowr I[$r3 + 0x000] $r2 // CHAN_CUR ++ ++ // load channel header, fetch PGRAPH context pointer ++ mov $xtargets $r0 ++ bclr $r2 31 ++ shl b32 $r2 4 ++ add b32 $r2 2 ++ ++ trace_set(T_LCHAN) ++ mov $r1 0xa04 ++ shl b32 $r1 6 ++ iowr I[$r1 + 0x000] $r2 // MEM_BASE ++ mov $r1 0xa20 ++ shl b32 $r1 6 ++ mov $r2 0x0002 ++ sethi $r2 0x80000000 ++ iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vram ++ mov $r1 0x10 // chan + 0x0210 ++ mov $r2 xfer_data ++ sethi $r2 0x00020000 // 16 bytes ++ xdld $r1 $r2 ++ xdwait ++ trace_clr(T_LCHAN) ++ ++ // update current context ++ ld b32 $r1 D[$r0 + xfer_data + 4] ++ shl b32 $r1 24 ++ ld b32 $r2 D[$r0 + xfer_data + 0] ++ shr b32 $r2 8 ++ or $r1 $r2 ++ st b32 D[$r0 + ctx_current] $r1 ++ ++ // set transfer base to start of context, and fetch context header ++ trace_set(T_LCTXH) ++ mov $r2 0xa04 ++ shl b32 $r2 6 ++ iowr I[$r2 + 0x000] $r1 // MEM_BASE ++ mov $r2 1 ++ mov $r1 0xa20 ++ shl b32 $r1 6 ++ iowr I[$r1 + 0x000] $r2 // MEM_TARGET = vm ++ mov $r1 chan_data ++ sethi $r1 0x00060000 // 256 bytes ++ xdld $r0 $r1 ++ xdwait ++ trace_clr(T_LCTXH) ++ ++ trace_clr(T_CHAN) ++ ret ++ ++// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as ++// the active channel for ctxctl, but not actually transfer ++// any context data. intended for use only during initial ++// context construction. ++// ++// In: $r2 channel address ++// ++ctx_chan: ++ call ctx_4160s ++ call ctx_load ++ mov $r10 12 // DONE_UNK12 ++ call wait_donez ++ mov $r1 0xa10 ++ shl b32 $r1 6 ++ mov $r2 5 ++ iowr I[$r1 + 0x000] $r2 // MEM_CMD = 5 (???) ++ ctx_chan_wait: ++ iord $r2 I[$r1 + 0x000] ++ or $r2 $r2 ++ bra ne ctx_chan_wait ++ call ctx_4160c ++ ret ++ ++// Execute per-context state overrides list ++// ++// Only executed on the first load of a channel. Might want to look into ++// removing this and having the host directly modify the channel's context ++// to change this state... The nouveau DRM already builds this list as ++// it's definitely needed for NVIDIA's, so we may as well use it for now ++// ++// Input: $r1 mmio list length ++// ++ctx_mmio_exec: ++ // set transfer base to be the mmio list ++ ld b32 $r3 D[$r0 + chan_mmio_address] ++ mov $r2 0xa04 ++ shl b32 $r2 6 ++ iowr I[$r2 + 0x000] $r3 // MEM_BASE ++ ++ clear b32 $r3 ++ ctx_mmio_loop: ++ // fetch next 256 bytes of mmio list if necessary ++ and $r4 $r3 0xff ++ bra ne ctx_mmio_pull ++ mov $r5 xfer_data ++ sethi $r5 0x00060000 // 256 bytes ++ xdld $r3 $r5 ++ xdwait ++ ++ // execute a single list entry ++ ctx_mmio_pull: ++ ld b32 $r14 D[$r4 + xfer_data + 0x00] ++ ld b32 $r15 D[$r4 + xfer_data + 0x04] ++ call nv_wr32 ++ ++ // next! ++ add b32 $r3 8 ++ sub b32 $r1 1 ++ bra ne ctx_mmio_loop ++ ++ // set transfer base back to the current context ++ ctx_mmio_done: ++ ld b32 $r3 D[$r0 + ctx_current] ++ iowr I[$r2 + 0x000] $r3 // MEM_BASE ++ ++ // disable the mmio list now, we don't need/want to execute it again ++ st b32 D[$r0 + chan_mmio_count] $r0 ++ mov $r1 chan_data ++ sethi $r1 0x00060000 // 256 bytes ++ xdst $r0 $r1 ++ xdwait ++ ret ++ ++// Transfer HUB context data between GPU and storage area ++// ++// In: $r2 channel address ++// $p1 clear on save, set on load ++// $p2 set if opposite direction done/will be done, so: ++// on save it means: "a load will follow this save" ++// on load it means: "a save preceeded this load" ++// ++ctx_xfer: ++ bra not $p1 ctx_xfer_pre ++ bra $p2 ctx_xfer_pre_load ++ ctx_xfer_pre: ++ mov $r15 0x10 ++ call ctx_86c ++ call ctx_4160s ++ bra not $p1 ctx_xfer_exec ++ ++ ctx_xfer_pre_load: ++ mov $r15 2 ++ call ctx_4170s ++ call ctx_4170w ++ call ctx_redswitch ++ clear b32 $r15 ++ call ctx_4170s ++ call ctx_load ++ ++ // fetch context pointer, and initiate xfer on all GPCs ++ ctx_xfer_exec: ++ ld b32 $r1 D[$r0 + ctx_current] ++ mov $r2 0x414 ++ shl b32 $r2 6 ++ iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset ++ mov $r14 -0x5b00 ++ sethi $r14 0x410000 ++ mov b32 $r15 $r1 ++ call nv_wr32 // GPC_BCAST_WRCMD_DATA = ctx pointer ++ add b32 $r14 4 ++ xbit $r15 $flags $p1 ++ xbit $r2 $flags $p2 ++ shl b32 $r2 1 ++ or $r15 $r2 ++ call nv_wr32 // GPC_BCAST_WRCMD_CMD = GPC_XFER(type) ++ ++ // strands ++ mov $r1 0x4afc ++ sethi $r1 0x20000 ++ mov $r2 0xc ++ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x0c ++ call strand_wait ++ mov $r2 0x47fc ++ sethi $r2 0x20000 ++ iowr I[$r2] $r0 // STRAND_FIRST_GENE(0x3f) = 0x00 ++ xbit $r2 $flags $p1 ++ add b32 $r2 3 ++ iowr I[$r1] $r2 // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD) ++ ++ // mmio context ++ xbit $r10 $flags $p1 // direction ++ or $r10 6 // first, last ++ mov $r11 0 // base = 0 ++ ld b32 $r12 D[$r0 + hub_mmio_list_head] ++ ld b32 $r13 D[$r0 + hub_mmio_list_tail] ++ mov $r14 0 // not multi ++ call mmctx_xfer ++ ++ // wait for GPCs to all complete ++ mov $r10 8 // DONE_BAR ++ call wait_doneo ++ ++ // wait for strand xfer to complete ++ call strand_wait ++ ++ // post-op ++ bra $p1 ctx_xfer_post ++ mov $r10 12 // DONE_UNK12 ++ call wait_donez ++ mov $r1 0xa10 ++ shl b32 $r1 6 ++ mov $r2 5 ++ iowr I[$r1] $r2 // MEM_CMD ++ ctx_xfer_post_save_wait: ++ iord $r2 I[$r1] ++ or $r2 $r2 ++ bra ne ctx_xfer_post_save_wait ++ ++ bra $p2 ctx_xfer_done ++ ctx_xfer_post: ++ mov $r15 2 ++ call ctx_4170s ++ clear b32 $r15 ++ call ctx_86c ++ call strand_post ++ call ctx_4170w ++ clear b32 $r15 ++ call ctx_4170s ++ ++ bra not $p1 ctx_xfer_no_post_mmio ++ ld b32 $r1 D[$r0 + chan_mmio_count] ++ or $r1 $r1 ++ bra e ctx_xfer_no_post_mmio ++ call ctx_mmio_exec ++ ++ ctx_xfer_no_post_mmio: ++ call ctx_4160c ++ ++ ctx_xfer_done: ++ ret ++ ++.align 256 +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_grhub.fuc.h 2011-07-26 07:03:44.513052047 +0200 +@@ -0,0 +1,838 @@ ++uint32_t nvc0_grhub_data[] = { ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x000000c0, ++ 0x01340098, ++ 0x000000c1, ++ 0x01380098, ++ 0x000000c3, ++ 0x01340098, ++ 0x000000c4, ++ 0x01340098, ++ 0x000000c8, ++ 0x01340098, ++ 0x000000ce, ++ 0x01340098, ++ 0x000000cf, ++ 0x01340098, ++ 0x00000000, ++ 0x0417e91c, ++ 0x04400204, ++ 0x28404004, ++ 0x00404044, ++ 0x34404094, ++ 0x184040d0, ++ 0x004040f8, ++ 0x08404130, ++ 0x08404150, ++ 0x04404164, ++ 0x08404174, ++ 0x1c404200, ++ 0x34404404, ++ 0x0c404460, ++ 0x00404480, ++ 0x00404498, ++ 0x0c404604, ++ 0x7c404618, ++ 0x50404698, ++ 0x044046f0, ++ 0x54404700, ++ 0x00405800, ++ 0x08405830, ++ 0x00405854, ++ 0x0c405870, ++ 0x04405a00, ++ 0x00405a18, ++ 0x00406020, ++ 0x0c406028, ++ 0x044064a8, ++ 0x044064b4, ++ 0x00407804, ++ 0x1440780c, ++ 0x004078bc, ++ 0x18408000, ++ 0x00408064, ++ 0x08408800, ++ 0x0c408900, ++ 0x00408980, ++ 0x044064c0, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; ++ ++uint32_t nvc0_grhub_code[] = { ++ 0x03090ef5, ++ 0x9800d898, ++ 0x86f001d9, ++ 0x0489b808, ++ 0xf00c1bf4, ++ 0x21f502f7, ++ 0x00f802ec, ++ 0xb60798c4, ++ 0x8dbb0384, ++ 0x0880b600, ++ 0x80008e80, ++ 0x90b6018f, ++ 0x0f94f001, ++ 0xf801d980, ++ 0x0131f400, ++ 0x9800d898, ++ 0x89b801d9, ++ 0x210bf404, ++ 0xb60789c4, ++ 0x9dbb0394, ++ 0x0890b600, ++ 0x98009e98, ++ 0x80b6019f, ++ 0x0f84f001, ++ 0xf400d880, ++ 0x00f80132, ++ 0x0728b7f1, ++ 0xb906b4b6, ++ 0xc9f002ec, ++ 0x00bcd01f, ++ 0xc800bccf, ++ 0x1bf41fcc, ++ 0x06a7f0fa, ++ 0x010321f5, ++ 0xf840bfcf, ++ 0x28b7f100, ++ 0x06b4b607, ++ 0xb980bfd0, ++ 0xc9f002ec, ++ 0x1ec9f01f, ++ 0xcf00bcd0, ++ 0xccc800bc, ++ 0xfa1bf41f, ++ 0x87f100f8, ++ 0x84b60430, ++ 0x1ff9f006, ++ 0xf8008fd0, ++ 0x3087f100, ++ 0x0684b604, ++ 0xf80080d0, ++ 0x3c87f100, ++ 0x0684b608, ++ 0x99f094bd, ++ 0x0089d000, ++ 0x081887f1, ++ 0xd00684b6, ++ 0x87f1008a, ++ 0x84b60400, ++ 0x0088cf06, ++ 0xf4888aff, ++ 0x87f1f31b, ++ 0x84b6085c, ++ 0xf094bd06, ++ 0x89d00099, ++ 0xf100f800, ++ 0xb6083c87, ++ 0x94bd0684, ++ 0xd00099f0, ++ 0x87f10089, ++ 0x84b60818, ++ 0x008ad006, ++ 0x040087f1, ++ 0xcf0684b6, ++ 0x8aff0088, ++ 0xf30bf488, ++ 0x085c87f1, ++ 0xbd0684b6, ++ 0x0099f094, ++ 0xf80089d0, ++ 0x9894bd00, ++ 0x85b600e8, ++ 0x0180b61a, ++ 0xbb0284b6, ++ 0xe0b60098, ++ 0x04efb804, ++ 0xb9eb1bf4, ++ 0x00f8029f, ++ 0x083c87f1, ++ 0xbd0684b6, ++ 0x0199f094, ++ 0xf10089d0, ++ 0xb6071087, ++ 0x94bd0684, ++ 0xf405bbfd, ++ 0x8bd0090b, ++ 0x0099f000, ++ 0xf405eefd, ++ 0x8ed00c0b, ++ 0xc08fd080, ++ 0xb70199f0, ++ 0xc8010080, ++ 0xb4b600ab, ++ 0x0cb9f010, ++ 0xb601aec8, ++ 0xbefd11e4, ++ 0x008bd005, ++ 0xf0008ecf, ++ 0x0bf41fe4, ++ 0x00ce98fa, ++ 0xd005e9fd, ++ 0xc0b6c08e, ++ 0x04cdb804, ++ 0xc8e81bf4, ++ 0x1bf402ab, ++ 0x008bcf18, ++ 0xb01fb4f0, ++ 0x1bf410b4, ++ 0x02a7f0f7, ++ 0xf4c921f4, ++ 0xabc81b0e, ++ 0x10b4b600, ++ 0xf00cb9f0, ++ 0x8bd012b9, ++ 0x008bcf00, ++ 0xf412bbc8, ++ 0x87f1fa1b, ++ 0x84b6085c, ++ 0xf094bd06, ++ 0x89d00199, ++ 0xf900f800, ++ 0x02a7f0a0, ++ 0xfcc921f4, ++ 0xf100f8a0, ++ 0xf04afc87, ++ 0x97f00283, ++ 0x0089d00c, ++ 0x020721f5, ++ 0x87f100f8, ++ 0x83f04afc, ++ 0x0d97f002, ++ 0xf50089d0, ++ 0xf8020721, ++ 0xfca7f100, ++ 0x02a3f04f, ++ 0x0500aba2, ++ 0xd00fc7f0, ++ 0xc7f000ac, ++ 0x00bcd00b, ++ 0x020721f5, ++ 0xf000aed0, ++ 0xbcd00ac7, ++ 0x0721f500, ++ 0xf100f802, ++ 0xb6083c87, ++ 0x94bd0684, ++ 0xd00399f0, ++ 0x21f50089, ++ 0xe7f00213, ++ 0x3921f503, ++ 0xfca7f102, ++ 0x02a3f046, ++ 0x0400aba0, ++ 0xf040a0d0, ++ 0xbcd001c7, ++ 0x0721f500, ++ 0x010c9202, ++ 0xf000acd0, ++ 0xbcd002c7, ++ 0x0721f500, ++ 0x2621f502, ++ 0x8087f102, ++ 0x0684b608, ++ 0xb70089cf, ++ 0x95220080, ++ 0x8ed008fe, ++ 0x408ed000, ++ 0xb6808acf, ++ 0xa0b606a5, ++ 0x00eabb01, ++ 0xb60480b6, ++ 0x1bf40192, ++ 0x08e4b6e8, ++ 0xf1f2efbc, ++ 0xb6085c87, ++ 0x94bd0684, ++ 0xd00399f0, ++ 0x00f80089, ++ 0xe7f1e0f9, ++ 0xe4b60814, ++ 0x00efd006, ++ 0x0c1ce7f1, ++ 0xf006e4b6, ++ 0xefd001f7, ++ 0xf8e0fc00, ++ 0xfe04bd00, ++ 0x07fe0004, ++ 0x0017f100, ++ 0x0227f012, ++ 0xf10012d0, ++ 0xfe05b917, ++ 0x17f10010, ++ 0x10d00400, ++ 0x0437f1c0, ++ 0x0634b604, ++ 0x200327f1, ++ 0xf10032d0, ++ 0xd0200427, ++ 0x27f10132, ++ 0x32d0200b, ++ 0x0c27f102, ++ 0x0732d020, ++ 0x0c2427f1, ++ 0xb90624b6, ++ 0x23d00003, ++ 0x0427f100, ++ 0x0023f087, ++ 0xb70012d0, ++ 0xf0010012, ++ 0x12d00427, ++ 0x1031f400, ++ 0x9604e7f1, ++ 0xf440e3f0, ++ 0xf1c76821, ++ 0x01018090, ++ 0x801ff4f0, ++ 0x17f0000f, ++ 0x041fbb01, ++ 0xf10112b6, ++ 0xb6040c27, ++ 0x21d00624, ++ 0x4021d000, ++ 0x080027f1, ++ 0xcf0624b6, ++ 0xf7f00022, ++ 0x08f0b654, ++ 0xb800f398, ++ 0x0bf40432, ++ 0x0034b00b, ++ 0xf8f11bf4, ++ 0x0017f100, ++ 0x02fe5801, ++ 0xf003ff58, ++ 0x0e8000e3, ++ 0x150f8014, ++ 0x013d21f5, ++ 0x070037f1, ++ 0x950634b6, ++ 0x34d00814, ++ 0x4034d000, ++ 0x130030b7, ++ 0xb6001fbb, ++ 0x3fd002f5, ++ 0x0815b600, ++ 0xb60110b6, ++ 0x1fb90814, ++ 0x6321f502, ++ 0x001fbb02, ++ 0xf1000398, ++ 0xf0200047, ++ 0x4ea05043, ++ 0x1fb90804, ++ 0x8d21f402, ++ 0x08004ea0, ++ 0xf4022fb9, ++ 0x4ea08d21, ++ 0xf4bd010c, ++ 0xa08d21f4, ++ 0xf401044e, ++ 0x4ea08d21, ++ 0xf7f00100, ++ 0x8d21f402, ++ 0x08004ea0, ++ 0xc86821f4, ++ 0x0bf41fff, ++ 0x044ea0fa, ++ 0x6821f408, ++ 0xb7001fbb, ++ 0xb6800040, ++ 0x1bf40132, ++ 0x0027f1b4, ++ 0x0624b608, ++ 0xb74021d0, ++ 0xbd080020, ++ 0x1f19f014, ++ 0xf40021d0, ++ 0x28f40031, ++ 0x08d7f000, ++ 0xf43921f4, ++ 0xe4b1f401, ++ 0x1bf54001, ++ 0x87f100d1, ++ 0x84b6083c, ++ 0xf094bd06, ++ 0x89d00499, ++ 0x0017f100, ++ 0x0614b60b, ++ 0xcf4012cf, ++ 0x13c80011, ++ 0x7e0bf41f, ++ 0xf41f23c8, ++ 0x20f95a0b, ++ 0xf10212b9, ++ 0xb6083c87, ++ 0x94bd0684, ++ 0xd00799f0, ++ 0x32f40089, ++ 0x0231f401, ++ 0x082921f5, ++ 0x085c87f1, ++ 0xbd0684b6, ++ 0x0799f094, ++ 0xfc0089d0, ++ 0x3c87f120, ++ 0x0684b608, ++ 0x99f094bd, ++ 0x0089d006, ++ 0xf50131f4, ++ 0xf1082921, ++ 0xb6085c87, ++ 0x94bd0684, ++ 0xd00699f0, ++ 0x0ef40089, ++ 0xb920f931, ++ 0x32f40212, ++ 0x0232f401, ++ 0x082921f5, ++ 0x17f120fc, ++ 0x14b60b00, ++ 0x0012d006, ++ 0xc8130ef4, ++ 0x0bf41f23, ++ 0x0131f40d, ++ 0xf50232f4, ++ 0xf1082921, ++ 0xb60b0c17, ++ 0x27f00614, ++ 0x0012d001, ++ 0x085c87f1, ++ 0xbd0684b6, ++ 0x0499f094, ++ 0xf50089d0, ++ 0xb0ff200e, ++ 0x1bf401e4, ++ 0x02f2b90d, ++ 0x07b521f5, ++ 0xb0420ef4, ++ 0x1bf402e4, ++ 0x3c87f12e, ++ 0x0684b608, ++ 0x99f094bd, ++ 0x0089d007, ++ 0xf40132f4, ++ 0x21f50232, ++ 0x87f10829, ++ 0x84b6085c, ++ 0xf094bd06, ++ 0x89d00799, ++ 0x110ef400, ++ 0xf010ef94, ++ 0x21f501f5, ++ 0x0ef502ec, ++ 0x17f1fed1, ++ 0x14b60820, ++ 0xf024bd06, ++ 0x12d01f29, ++ 0xbe0ef500, ++ 0xfe80f9fe, ++ 0x80f90188, ++ 0xa0f990f9, ++ 0xd0f9b0f9, ++ 0xf0f9e0f9, ++ 0xc4800acf, ++ 0x0bf404ab, ++ 0x00b7f11d, ++ 0x08d7f019, ++ 0xcf40becf, ++ 0x21f400bf, ++ 0x00b0b704, ++ 0x01e7f004, ++ 0xe400bed0, ++ 0xf40100ab, ++ 0xd7f00d0b, ++ 0x01e7f108, ++ 0x0421f440, ++ 0x0104b7f1, ++ 0xabffb0bd, ++ 0x0d0bf4b4, ++ 0x0c1ca7f1, ++ 0xd006a4b6, ++ 0x0ad000ab, ++ 0xfcf0fc40, ++ 0xfcd0fce0, ++ 0xfca0fcb0, ++ 0xfe80fc90, ++ 0x80fc0088, ++ 0xf80032f4, ++ 0x60e7f101, ++ 0x40e3f041, ++ 0xf401f7f0, ++ 0x21f48d21, ++ 0x04ffc868, ++ 0xf8fa0bf4, ++ 0x60e7f100, ++ 0x40e3f041, ++ 0x21f4f4bd, ++ 0xf100f88d, ++ 0xf04170e7, ++ 0xf5f040e3, ++ 0x8d21f410, ++ 0xe7f100f8, ++ 0xe3f04170, ++ 0x6821f440, ++ 0xf410f4f0, ++ 0x00f8f31b, ++ 0x0614e7f1, ++ 0xf106e4b6, ++ 0xd00270f7, ++ 0xf7f000ef, ++ 0x01f2b608, ++ 0xf1fd1bf4, ++ 0xd00770f7, ++ 0x00f800ef, ++ 0x086ce7f1, ++ 0xd006e4b6, ++ 0xe7f100ef, ++ 0xe3f08a14, ++ 0x8d21f440, ++ 0xa86ce7f1, ++ 0xf441e3f0, ++ 0x00f88d21, ++ 0x083c87f1, ++ 0xbd0684b6, ++ 0x0599f094, ++ 0xf00089d0, ++ 0x21f40ca7, ++ 0x2417f1c9, ++ 0x0614b60a, ++ 0xf10010d0, ++ 0xb60b0037, ++ 0x32d00634, ++ 0x0c17f140, ++ 0x0614b60a, ++ 0xd00747f0, ++ 0x14d00012, ++ 0x4014cf40, ++ 0xf41f44f0, ++ 0x32d0fa1b, ++ 0x000bfe00, ++ 0xb61f2af0, ++ 0x20b60424, ++ 0x3c87f102, ++ 0x0684b608, ++ 0x99f094bd, ++ 0x0089d008, ++ 0x0a0417f1, ++ 0xd00614b6, ++ 0x17f10012, ++ 0x14b60a20, ++ 0x0227f006, ++ 0x800023f1, ++ 0xf00012d0, ++ 0x27f11017, ++ 0x23f00300, ++ 0x0512fa02, ++ 0x87f103f8, ++ 0x84b6085c, ++ 0xf094bd06, ++ 0x89d00899, ++ 0xc1019800, ++ 0x981814b6, ++ 0x25b6c002, ++ 0x0512fd08, ++ 0xf1160180, ++ 0xb6083c87, ++ 0x94bd0684, ++ 0xd00999f0, ++ 0x27f10089, ++ 0x24b60a04, ++ 0x0021d006, ++ 0xf10127f0, ++ 0xb60a2017, ++ 0x12d00614, ++ 0x0017f100, ++ 0x0613f002, ++ 0xf80501fa, ++ 0x5c87f103, ++ 0x0684b608, ++ 0x99f094bd, ++ 0x0089d009, ++ 0x085c87f1, ++ 0xbd0684b6, ++ 0x0599f094, ++ 0xf80089d0, ++ 0x3121f500, ++ 0xb821f506, ++ 0x0ca7f006, ++ 0xf1c921f4, ++ 0xb60a1017, ++ 0x27f00614, ++ 0x0012d005, ++ 0xfd0012cf, ++ 0x1bf40522, ++ 0x4921f5fa, ++ 0x9800f806, ++ 0x27f18103, ++ 0x24b60a04, ++ 0x0023d006, ++ 0x34c434bd, ++ 0x0f1bf4ff, ++ 0x030057f1, ++ 0xfa0653f0, ++ 0x03f80535, ++ 0x98c04e98, ++ 0x21f4c14f, ++ 0x0830b68d, ++ 0xf40112b6, ++ 0x0398df1b, ++ 0x0023d016, ++ 0xf1800080, ++ 0xf0020017, ++ 0x01fa0613, ++ 0xf803f806, ++ 0x0611f400, ++ 0xf01102f4, ++ 0x21f510f7, ++ 0x21f50698, ++ 0x11f40631, ++ 0x02f7f01c, ++ 0x065721f5, ++ 0x066621f5, ++ 0x067821f5, ++ 0x21f5f4bd, ++ 0x21f50657, ++ 0x019806b8, ++ 0x1427f116, ++ 0x0624b604, ++ 0xf10020d0, ++ 0xf0a500e7, ++ 0x1fb941e3, ++ 0x8d21f402, ++ 0xf004e0b6, ++ 0x2cf001fc, ++ 0x0124b602, ++ 0xf405f2fd, ++ 0x17f18d21, ++ 0x13f04afc, ++ 0x0c27f002, ++ 0xf50012d0, ++ 0xf1020721, ++ 0xf047fc27, ++ 0x20d00223, ++ 0x012cf000, ++ 0xd00320b6, ++ 0xacf00012, ++ 0x06a5f001, ++ 0x9800b7f0, ++ 0x0d98140c, ++ 0x00e7f015, ++ 0x015c21f5, ++ 0xf508a7f0, ++ 0xf5010321, ++ 0xf4020721, ++ 0xa7f02201, ++ 0xc921f40c, ++ 0x0a1017f1, ++ 0xf00614b6, ++ 0x12d00527, ++ 0x0012cf00, ++ 0xf40522fd, ++ 0x02f4fa1b, ++ 0x02f7f032, ++ 0x065721f5, ++ 0x21f5f4bd, ++ 0x21f50698, ++ 0x21f50226, ++ 0xf4bd0666, ++ 0x065721f5, ++ 0x981011f4, ++ 0x11fd8001, ++ 0x070bf405, ++ 0x07df21f5, ++ 0x064921f5, ++ 0x000000f8, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++ 0x00000000, ++}; +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_instmem.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_instmem.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_instmem.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_instmem.c 2011-07-26 07:03:44.514052059 +0200 +@@ -32,7 +32,6 @@ + struct nouveau_channel *bar1; + struct nouveau_gpuobj *bar3_pgd; + struct nouveau_channel *bar3; +- struct nouveau_gpuobj *chan_pgd; + }; + + int +@@ -181,17 +180,11 @@ + goto error; + + /* channel vm */ +- ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, &vm); ++ ret = nouveau_vm_new(dev, 0, (1ULL << 40), 0x0008000000ULL, ++ &dev_priv->chan_vm); + if (ret) + goto error; + +- ret = nouveau_gpuobj_new(dev, NULL, 0x8000, 4096, 0, &priv->chan_pgd); +- if (ret) +- goto error; +- +- nouveau_vm_ref(vm, &dev_priv->chan_vm, priv->chan_pgd); +- nouveau_vm_ref(NULL, &vm, NULL); +- + nvc0_instmem_resume(dev); + return 0; + error: +@@ -211,8 +204,7 @@ + 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); ++ nouveau_vm_ref(NULL, &dev_priv->chan_vm, NULL); + + nvc0_channel_del(&priv->bar1); + nouveau_vm_ref(NULL, &dev_priv->bar1_vm, priv->bar1_pgd); +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_pm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_pm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_pm.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_pm.c 2011-07-26 07:03:44.514052059 +0200 +@@ -0,0 +1,151 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include "drmP.h" ++#include "nouveau_drv.h" ++#include "nouveau_bios.h" ++#include "nouveau_pm.h" ++ ++static u32 read_div(struct drm_device *, int, u32, u32); ++static u32 read_pll(struct drm_device *, u32); ++ ++static u32 ++read_vco(struct drm_device *dev, u32 dsrc) ++{ ++ u32 ssrc = nv_rd32(dev, dsrc); ++ if (!(ssrc & 0x00000100)) ++ return read_pll(dev, 0x00e800); ++ return read_pll(dev, 0x00e820); ++} ++ ++static u32 ++read_pll(struct drm_device *dev, u32 pll) ++{ ++ u32 coef = nv_rd32(dev, pll + 4); ++ u32 P = (coef & 0x003f0000) >> 16; ++ u32 N = (coef & 0x0000ff00) >> 8; ++ u32 M = (coef & 0x000000ff) >> 0; ++ u32 sclk, doff; ++ ++ switch (pll & 0xfff000) { ++ case 0x00e000: ++ sclk = 27000; ++ P = 1; ++ break; ++ case 0x137000: ++ doff = (pll - 0x137000) / 0x20; ++ sclk = read_div(dev, doff, 0x137120, 0x137140); ++ break; ++ case 0x132000: ++ switch (pll) { ++ case 0x132000: ++ sclk = read_pll(dev, 0x132020); ++ break; ++ case 0x132020: ++ sclk = read_div(dev, 0, 0x137320, 0x137330); ++ break; ++ default: ++ return 0; ++ } ++ break; ++ default: ++ return 0; ++ } ++ ++ return sclk * N / M / P; ++} ++ ++static u32 ++read_div(struct drm_device *dev, int doff, u32 dsrc, u32 dctl) ++{ ++ u32 ssrc = nv_rd32(dev, dsrc + (doff * 4)); ++ u32 sctl = nv_rd32(dev, dctl + (doff * 4)); ++ ++ switch (ssrc & 0x00000003) { ++ case 0: ++ if ((ssrc & 0x00030000) != 0x00030000) ++ return 27000; ++ return 108000; ++ case 2: ++ return 100000; ++ case 3: ++ if (sctl & 0x80000000) { ++ u32 sclk = read_vco(dev, dsrc); ++ u32 sdiv = (sctl & 0x0000003f) + 2; ++ return (sclk * 2) / sdiv; ++ } ++ ++ return read_vco(dev, dsrc); ++ default: ++ return 0; ++ } ++} ++ ++static u32 ++read_mem(struct drm_device *dev) ++{ ++ u32 ssel = nv_rd32(dev, 0x1373f0); ++ if (ssel & 0x00000001) ++ return read_div(dev, 0, 0x137300, 0x137310); ++ return read_pll(dev, 0x132000); ++} ++ ++static u32 ++read_clk(struct drm_device *dev, int clk) ++{ ++ u32 sctl = nv_rd32(dev, 0x137250 + (clk * 4)); ++ u32 ssel = nv_rd32(dev, 0x137100); ++ u32 sclk, sdiv; ++ ++ if (ssel & (1 << clk)) { ++ if (clk < 7) ++ sclk = read_pll(dev, 0x137000 + (clk * 0x20)); ++ else ++ sclk = read_pll(dev, 0x1370e0); ++ sdiv = ((sctl & 0x00003f00) >> 8) + 2; ++ } else { ++ sclk = read_div(dev, clk, 0x137160, 0x1371d0); ++ sdiv = ((sctl & 0x0000003f) >> 0) + 2; ++ } ++ ++ if (sctl & 0x80000000) ++ return (sclk * 2) / sdiv; ++ return sclk; ++} ++ ++int ++nvc0_pm_clocks_get(struct drm_device *dev, struct nouveau_pm_level *perflvl) ++{ ++ perflvl->shader = read_clk(dev, 0x00); ++ perflvl->core = perflvl->shader / 2; ++ perflvl->memory = read_mem(dev); ++ perflvl->rop = read_clk(dev, 0x01); ++ perflvl->hub07 = read_clk(dev, 0x02); ++ perflvl->hub06 = read_clk(dev, 0x07); ++ perflvl->hub01 = read_clk(dev, 0x08); ++ perflvl->copy = read_clk(dev, 0x09); ++ perflvl->daemon = read_clk(dev, 0x0c); ++ perflvl->vdec = read_clk(dev, 0x0e); ++ return 0; ++} +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_vm.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_vm.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_vm.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_vm.c 2011-07-26 07:03:44.515052071 +0200 +@@ -105,7 +105,11 @@ + struct drm_device *dev = vm->dev; + struct nouveau_vm_pgd *vpgd; + unsigned long flags; +- u32 engine = (dev_priv->chan_vm == vm) ? 1 : 5; ++ u32 engine; ++ ++ engine = 1; ++ if (vm == dev_priv->bar1_vm || vm == dev_priv->bar3_vm) ++ engine |= 4; + + pinstmem->flush(vm->dev); + +diff -Naur linux-3.0/drivers/gpu/drm/nouveau/nvc0_vram.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_vram.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvc0_vram.c 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvc0_vram.c 2011-07-26 07:03:44.515052071 +0200 +@@ -61,9 +61,7 @@ + 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 *mm = &dev_priv->engine.vram.mm; + struct nouveau_mm_node *r; + struct nouveau_mem *mem; + int ret; +@@ -105,9 +103,53 @@ + nvc0_vram_init(struct drm_device *dev) + { + struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_vram_engine *vram = &dev_priv->engine.vram; ++ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ ++ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ ++ u32 parts = nv_rd32(dev, 0x121c74); ++ u32 bsize = nv_rd32(dev, 0x10f20c); ++ u32 offset, length; ++ bool uniform = true; ++ int ret, i; ++ ++ NV_DEBUG(dev, "0x100800: 0x%08x\n", nv_rd32(dev, 0x100800)); ++ NV_DEBUG(dev, "parts 0x%08x bcast_mem_amount 0x%08x\n", parts, bsize); ++ ++ /* read amount of vram attached to each memory controller */ ++ for (i = 0; i < parts; i++) { ++ u32 psize = nv_rd32(dev, 0x11020c + (i * 0x1000)); ++ if (psize != bsize) { ++ if (psize < bsize) ++ bsize = psize; ++ uniform = false; ++ } ++ ++ NV_DEBUG(dev, "%d: mem_amount 0x%08x\n", i, psize); ++ ++ dev_priv->vram_size += (u64)psize << 20; ++ } ++ ++ /* if all controllers have the same amount attached, there's no holes */ ++ if (uniform) { ++ offset = rsvd_head; ++ length = (dev_priv->vram_size >> 12) - rsvd_head - rsvd_tail; ++ return nouveau_mm_init(&vram->mm, offset, length, 1); ++ } ++ ++ /* otherwise, address lowest common amount from 0GiB */ ++ ret = nouveau_mm_init(&vram->mm, rsvd_head, (bsize << 8) * parts, 1); ++ if (ret) ++ return ret; ++ ++ /* and the rest starting from (8GiB + common_size) */ ++ offset = (0x0200000000ULL >> 12) + (bsize << 8); ++ length = (dev_priv->vram_size >> 12) - (bsize << 8) - rsvd_tail; ++ ++ ret = nouveau_mm_init(&vram->mm, offset, length, 0); ++ if (ret) { ++ nouveau_mm_fini(&vram->mm); ++ return ret; ++ } + +- 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-3.0/drivers/gpu/drm/nouveau/nvd0_display.c linux-3.0.patch/drivers/gpu/drm/nouveau/nvd0_display.c +--- linux-3.0/drivers/gpu/drm/nouveau/nvd0_display.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.0.patch/drivers/gpu/drm/nouveau/nvd0_display.c 2011-07-26 07:03:44.517052095 +0200 +@@ -0,0 +1,1456 @@ ++/* ++ * Copyright 2011 Red Hat Inc. ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a ++ * copy of this software and associated documentation files (the "Software"), ++ * to deal in the Software without restriction, including without limitation ++ * the rights to use, copy, modify, merge, publish, distribute, sublicense, ++ * and/or sell copies of the Software, and to permit persons to whom the ++ * Software is furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR ++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ++ * OTHER DEALINGS IN THE SOFTWARE. ++ * ++ * Authors: Ben Skeggs ++ */ ++ ++#include ++ ++#include "drmP.h" ++#include "drm_crtc_helper.h" ++ ++#include "nouveau_drv.h" ++#include "nouveau_connector.h" ++#include "nouveau_encoder.h" ++#include "nouveau_crtc.h" ++#include "nouveau_dma.h" ++#include "nouveau_fb.h" ++#include "nv50_display.h" ++ ++struct nvd0_display { ++ struct nouveau_gpuobj *mem; ++ struct { ++ dma_addr_t handle; ++ u32 *ptr; ++ } evo[1]; ++ ++ struct tasklet_struct tasklet; ++ u32 modeset; ++}; ++ ++static struct nvd0_display * ++nvd0_display(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ return dev_priv->engine.display.priv; ++} ++ ++static inline int ++evo_icmd(struct drm_device *dev, int id, u32 mthd, u32 data) ++{ ++ int ret = 0; ++ nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000001); ++ nv_wr32(dev, 0x610704 + (id * 0x10), data); ++ nv_mask(dev, 0x610704 + (id * 0x10), 0x80000ffc, 0x80000000 | mthd); ++ if (!nv_wait(dev, 0x610704 + (id * 0x10), 0x80000000, 0x00000000)) ++ ret = -EBUSY; ++ nv_mask(dev, 0x610700 + (id * 0x10), 0x00000001, 0x00000000); ++ return ret; ++} ++ ++static u32 * ++evo_wait(struct drm_device *dev, int id, int nr) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 put = nv_rd32(dev, 0x640000 + (id * 0x1000)) / 4; ++ ++ if (put + nr >= (PAGE_SIZE / 4)) { ++ disp->evo[id].ptr[put] = 0x20000000; ++ ++ nv_wr32(dev, 0x640000 + (id * 0x1000), 0x00000000); ++ if (!nv_wait(dev, 0x640004 + (id * 0x1000), ~0, 0x00000000)) { ++ NV_ERROR(dev, "evo %d dma stalled\n", id); ++ return NULL; ++ } ++ ++ put = 0; ++ } ++ ++ return disp->evo[id].ptr + put; ++} ++ ++static void ++evo_kick(u32 *push, struct drm_device *dev, int id) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ nv_wr32(dev, 0x640000 + (id * 0x1000), (push - disp->evo[id].ptr) << 2); ++} ++ ++#define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) ++#define evo_data(p,d) *((p)++) = (d) ++ ++static struct drm_crtc * ++nvd0_display_crtc_get(struct drm_encoder *encoder) ++{ ++ return nouveau_encoder(encoder)->crtc; ++} ++ ++/****************************************************************************** ++ * CRTC ++ *****************************************************************************/ ++static int ++nvd0_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool on, bool update) ++{ ++ struct drm_device *dev = nv_crtc->base.dev; ++ u32 *push, mode; ++ ++ mode = 0x00000000; ++ if (on) { ++ /* 0x11: 6bpc dynamic 2x2 ++ * 0x13: 8bpc dynamic 2x2 ++ * 0x19: 6bpc static 2x2 ++ * 0x1b: 8bpc static 2x2 ++ * 0x21: 6bpc temporal ++ * 0x23: 8bpc temporal ++ */ ++ mode = 0x00000011; ++ } ++ ++ push = evo_wait(dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0490 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, mode); ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ evo_kick(push, dev, 0); ++ } ++ ++ return 0; ++} ++ ++static int ++nvd0_crtc_set_scale(struct nouveau_crtc *nv_crtc, int type, bool update) ++{ ++ struct drm_display_mode *mode = &nv_crtc->base.mode; ++ struct drm_device *dev = nv_crtc->base.dev; ++ struct nouveau_connector *nv_connector; ++ u32 *push, outX, outY; ++ ++ outX = mode->hdisplay; ++ outY = mode->vdisplay; ++ ++ nv_connector = nouveau_crtc_connector_get(nv_crtc); ++ if (nv_connector && nv_connector->native_mode) { ++ struct drm_display_mode *native = nv_connector->native_mode; ++ u32 xratio = (native->hdisplay << 19) / mode->hdisplay; ++ u32 yratio = (native->vdisplay << 19) / mode->vdisplay; ++ ++ switch (type) { ++ case DRM_MODE_SCALE_ASPECT: ++ if (xratio > yratio) { ++ outX = (mode->hdisplay * yratio) >> 19; ++ outY = (mode->vdisplay * yratio) >> 19; ++ } else { ++ outX = (mode->hdisplay * xratio) >> 19; ++ outY = (mode->vdisplay * xratio) >> 19; ++ } ++ break; ++ case DRM_MODE_SCALE_FULLSCREEN: ++ outX = native->hdisplay; ++ outY = native->vdisplay; ++ break; ++ default: ++ break; ++ } ++ } ++ ++ push = evo_wait(dev, 0, 16); ++ if (push) { ++ evo_mthd(push, 0x04c0 + (nv_crtc->index * 0x300), 3); ++ evo_data(push, (outY << 16) | outX); ++ evo_data(push, (outY << 16) | outX); ++ evo_data(push, (outY << 16) | outX); ++ evo_mthd(push, 0x0494 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x04b8 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, (mode->vdisplay << 16) | mode->hdisplay); ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ evo_kick(push, dev, 0); ++ } ++ ++ return 0; ++} ++ ++static int ++nvd0_crtc_set_image(struct nouveau_crtc *nv_crtc, struct drm_framebuffer *fb, ++ int x, int y, bool update) ++{ ++ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(fb); ++ u32 *push; ++ ++ push = evo_wait(fb->dev, 0, 16); ++ if (push) { ++ evo_mthd(push, 0x0460 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, nvfb->nvbo->bo.offset >> 8); ++ evo_mthd(push, 0x0468 + (nv_crtc->index * 0x300), 4); ++ evo_data(push, (fb->height << 16) | fb->width); ++ evo_data(push, nvfb->r_pitch); ++ evo_data(push, nvfb->r_format); ++ evo_data(push, nvfb->r_dma); ++ evo_mthd(push, 0x04b0 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, (y << 16) | x); ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ evo_kick(push, fb->dev, 0); ++ } ++ ++ nv_crtc->fb.tile_flags = nvfb->r_dma; ++ return 0; ++} ++ ++static void ++nvd0_crtc_cursor_show(struct nouveau_crtc *nv_crtc, bool show, bool update) ++{ ++ struct drm_device *dev = nv_crtc->base.dev; ++ u32 *push = evo_wait(dev, 0, 16); ++ if (push) { ++ if (show) { ++ evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); ++ evo_data(push, 0x85000000); ++ evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); ++ evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, NvEvoVRAM); ++ } else { ++ evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x05000000); ++ evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ } ++ ++ if (update) { ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ } ++ ++ evo_kick(push, dev, 0); ++ } ++} ++ ++static void ++nvd0_crtc_dpms(struct drm_crtc *crtc, int mode) ++{ ++} ++ ++static void ++nvd0_crtc_prepare(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ u32 *push; ++ ++ push = evo_wait(crtc->dev, 0, 2); ++ if (push) { ++ evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x03000000); ++ evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, crtc->dev, 0); ++ } ++ ++ nvd0_crtc_cursor_show(nv_crtc, false, false); ++} ++ ++static void ++nvd0_crtc_commit(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ u32 *push; ++ ++ push = evo_wait(crtc->dev, 0, 32); ++ if (push) { ++ evo_mthd(push, 0x0474 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, nv_crtc->fb.tile_flags); ++ evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); ++ evo_data(push, 0x83000000); ++ evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); ++ evo_data(push, 0x00000000); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, NvEvoVRAM); ++ evo_mthd(push, 0x0430 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0xffffff00); ++ evo_kick(push, crtc->dev, 0); ++ } ++ ++ nvd0_crtc_cursor_show(nv_crtc, nv_crtc->cursor.visible, true); ++} ++ ++static bool ++nvd0_crtc_mode_fixup(struct drm_crtc *crtc, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ return true; ++} ++ ++static int ++nvd0_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) ++{ ++ struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb); ++ int ret; ++ ++ ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); ++ if (ret) ++ return ret; ++ ++ if (old_fb) { ++ nvfb = nouveau_framebuffer(old_fb); ++ nouveau_bo_unpin(nvfb->nvbo); ++ } ++ ++ return 0; ++} ++ ++static int ++nvd0_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, ++ struct drm_display_mode *mode, int x, int y, ++ struct drm_framebuffer *old_fb) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ struct nouveau_connector *nv_connector; ++ u32 htotal = mode->htotal; ++ u32 vtotal = mode->vtotal; ++ u32 hsyncw = mode->hsync_end - mode->hsync_start - 1; ++ u32 vsyncw = mode->vsync_end - mode->vsync_start - 1; ++ u32 hfrntp = mode->hsync_start - mode->hdisplay; ++ u32 vfrntp = mode->vsync_start - mode->vdisplay; ++ u32 hbackp = mode->htotal - mode->hsync_end; ++ u32 vbackp = mode->vtotal - mode->vsync_end; ++ u32 hss2be = hsyncw + hbackp; ++ u32 vss2be = vsyncw + vbackp; ++ u32 hss2de = htotal - hfrntp; ++ u32 vss2de = vtotal - vfrntp; ++ u32 syncs, *push; ++ int ret; ++ ++ syncs = 0x00000001; ++ if (mode->flags & DRM_MODE_FLAG_NHSYNC) ++ syncs |= 0x00000008; ++ if (mode->flags & DRM_MODE_FLAG_NVSYNC) ++ syncs |= 0x00000010; ++ ++ ret = nvd0_crtc_swap_fbs(crtc, old_fb); ++ if (ret) ++ return ret; ++ ++ push = evo_wait(crtc->dev, 0, 64); ++ if (push) { ++ evo_mthd(push, 0x0410 + (nv_crtc->index * 0x300), 5); ++ evo_data(push, 0x00000000); ++ evo_data(push, (vtotal << 16) | htotal); ++ evo_data(push, (vsyncw << 16) | hsyncw); ++ evo_data(push, (vss2be << 16) | hss2be); ++ evo_data(push, (vss2de << 16) | hss2de); ++ evo_mthd(push, 0x042c + (nv_crtc->index * 0x300), 1); ++ evo_data(push, 0x00000000); /* ??? */ ++ evo_mthd(push, 0x0450 + (nv_crtc->index * 0x300), 3); ++ evo_data(push, mode->clock * 1000); ++ evo_data(push, 0x00200000); /* ??? */ ++ evo_data(push, mode->clock * 1000); ++ evo_mthd(push, 0x0404 + (nv_crtc->index * 0x300), 1); ++ evo_data(push, syncs); ++ evo_kick(push, crtc->dev, 0); ++ } ++ ++ nv_connector = nouveau_crtc_connector_get(nv_crtc); ++ nvd0_crtc_set_dither(nv_crtc, nv_connector->use_dithering, false); ++ nvd0_crtc_set_scale(nv_crtc, nv_connector->scaling_mode, false); ++ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, false); ++ return 0; ++} ++ ++static int ++nvd0_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, ++ struct drm_framebuffer *old_fb) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ int ret; ++ ++ ret = nvd0_crtc_swap_fbs(crtc, old_fb); ++ if (ret) ++ return ret; ++ ++ nvd0_crtc_set_image(nv_crtc, crtc->fb, x, y, true); ++ return 0; ++} ++ ++static int ++nvd0_crtc_mode_set_base_atomic(struct drm_crtc *crtc, ++ struct drm_framebuffer *fb, int x, int y, ++ enum mode_set_atomic state) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ nvd0_crtc_set_image(nv_crtc, fb, x, y, true); ++ return 0; ++} ++ ++static void ++nvd0_crtc_lut_load(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ void __iomem *lut = nvbo_kmap_obj_iovirtual(nv_crtc->lut.nvbo); ++ int i; ++ ++ for (i = 0; i < 256; i++) { ++ writew(0x6000 + (nv_crtc->lut.r[i] >> 2), lut + (i * 0x20) + 0); ++ writew(0x6000 + (nv_crtc->lut.g[i] >> 2), lut + (i * 0x20) + 2); ++ writew(0x6000 + (nv_crtc->lut.b[i] >> 2), lut + (i * 0x20) + 4); ++ } ++} ++ ++static int ++nvd0_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, ++ uint32_t handle, uint32_t width, uint32_t height) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ struct drm_device *dev = crtc->dev; ++ struct drm_gem_object *gem; ++ struct nouveau_bo *nvbo; ++ bool visible = (handle != 0); ++ int i, ret = 0; ++ ++ if (visible) { ++ if (width != 64 || height != 64) ++ return -EINVAL; ++ ++ gem = drm_gem_object_lookup(dev, file_priv, handle); ++ if (unlikely(!gem)) ++ return -ENOENT; ++ nvbo = nouveau_gem_object(gem); ++ ++ ret = nouveau_bo_map(nvbo); ++ if (ret == 0) { ++ for (i = 0; i < 64 * 64; i++) { ++ u32 v = nouveau_bo_rd32(nvbo, i); ++ nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v); ++ } ++ nouveau_bo_unmap(nvbo); ++ } ++ ++ drm_gem_object_unreference_unlocked(gem); ++ } ++ ++ if (visible != nv_crtc->cursor.visible) { ++ nvd0_crtc_cursor_show(nv_crtc, visible, true); ++ nv_crtc->cursor.visible = visible; ++ } ++ ++ return ret; ++} ++ ++static int ++nvd0_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ const u32 data = (y << 16) | x; ++ ++ nv_wr32(crtc->dev, 0x64d084 + (nv_crtc->index * 0x1000), data); ++ nv_wr32(crtc->dev, 0x64d080 + (nv_crtc->index * 0x1000), 0x00000000); ++ return 0; ++} ++ ++static void ++nvd0_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, ++ uint32_t start, uint32_t size) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ u32 end = max(start + size, (u32)256); ++ u32 i; ++ ++ for (i = start; i < end; i++) { ++ nv_crtc->lut.r[i] = r[i]; ++ nv_crtc->lut.g[i] = g[i]; ++ nv_crtc->lut.b[i] = b[i]; ++ } ++ ++ nvd0_crtc_lut_load(crtc); ++} ++ ++static void ++nvd0_crtc_destroy(struct drm_crtc *crtc) ++{ ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); ++ nouveau_bo_unmap(nv_crtc->cursor.nvbo); ++ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); ++ nouveau_bo_unmap(nv_crtc->lut.nvbo); ++ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); ++ drm_crtc_cleanup(crtc); ++ kfree(crtc); ++} ++ ++static const struct drm_crtc_helper_funcs nvd0_crtc_hfunc = { ++ .dpms = nvd0_crtc_dpms, ++ .prepare = nvd0_crtc_prepare, ++ .commit = nvd0_crtc_commit, ++ .mode_fixup = nvd0_crtc_mode_fixup, ++ .mode_set = nvd0_crtc_mode_set, ++ .mode_set_base = nvd0_crtc_mode_set_base, ++ .mode_set_base_atomic = nvd0_crtc_mode_set_base_atomic, ++ .load_lut = nvd0_crtc_lut_load, ++}; ++ ++static const struct drm_crtc_funcs nvd0_crtc_func = { ++ .cursor_set = nvd0_crtc_cursor_set, ++ .cursor_move = nvd0_crtc_cursor_move, ++ .gamma_set = nvd0_crtc_gamma_set, ++ .set_config = drm_crtc_helper_set_config, ++ .destroy = nvd0_crtc_destroy, ++}; ++ ++static int ++nvd0_crtc_create(struct drm_device *dev, int index) ++{ ++ struct nouveau_crtc *nv_crtc; ++ struct drm_crtc *crtc; ++ int ret, i; ++ ++ nv_crtc = kzalloc(sizeof(*nv_crtc), GFP_KERNEL); ++ if (!nv_crtc) ++ return -ENOMEM; ++ ++ nv_crtc->index = index; ++ nv_crtc->set_dither = nvd0_crtc_set_dither; ++ nv_crtc->set_scale = nvd0_crtc_set_scale; ++ for (i = 0; i < 256; i++) { ++ nv_crtc->lut.r[i] = i << 8; ++ nv_crtc->lut.g[i] = i << 8; ++ nv_crtc->lut.b[i] = i << 8; ++ } ++ ++ crtc = &nv_crtc->base; ++ drm_crtc_init(dev, crtc, &nvd0_crtc_func); ++ drm_crtc_helper_add(crtc, &nvd0_crtc_hfunc); ++ drm_mode_crtc_set_gamma_size(crtc, 256); ++ ++ ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, ++ 0, 0x0000, &nv_crtc->cursor.nvbo); ++ if (!ret) { ++ ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM); ++ if (!ret) ++ ret = nouveau_bo_map(nv_crtc->cursor.nvbo); ++ if (ret) ++ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); ++ } ++ ++ if (ret) ++ goto out; ++ ++ ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, ++ 0, 0x0000, &nv_crtc->lut.nvbo); ++ if (!ret) { ++ ret = nouveau_bo_pin(nv_crtc->lut.nvbo, TTM_PL_FLAG_VRAM); ++ if (!ret) ++ ret = nouveau_bo_map(nv_crtc->lut.nvbo); ++ if (ret) ++ nouveau_bo_ref(NULL, &nv_crtc->lut.nvbo); ++ } ++ ++ if (ret) ++ goto out; ++ ++ nvd0_crtc_lut_load(crtc); ++ ++out: ++ if (ret) ++ nvd0_crtc_destroy(crtc); ++ return ret; ++} ++ ++/****************************************************************************** ++ * DAC ++ *****************************************************************************/ ++static void ++nvd0_dac_dpms(struct drm_encoder *encoder, int mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ int or = nv_encoder->or; ++ u32 dpms_ctrl; ++ ++ dpms_ctrl = 0x80000000; ++ if (mode == DRM_MODE_DPMS_STANDBY || mode == DRM_MODE_DPMS_OFF) ++ dpms_ctrl |= 0x00000001; ++ if (mode == DRM_MODE_DPMS_SUSPEND || mode == DRM_MODE_DPMS_OFF) ++ dpms_ctrl |= 0x00000004; ++ ++ nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); ++ nv_mask(dev, 0x61a004 + (or * 0x0800), 0xc000007f, dpms_ctrl); ++ nv_wait(dev, 0x61a004 + (or * 0x0800), 0x80000000, 0x00000000); ++} ++ ++static bool ++nvd0_dac_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_connector *nv_connector; ++ ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ if (nv_connector && nv_connector->native_mode) { ++ if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { ++ int id = adjusted_mode->base.id; ++ *adjusted_mode = *nv_connector->native_mode; ++ adjusted_mode->base.id = id; ++ } ++ } ++ ++ return true; ++} ++ ++static void ++nvd0_dac_prepare(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_dac_commit(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_dac_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); ++ u32 *push; ++ ++ nvd0_dac_dpms(encoder, DRM_MODE_DPMS_ON); ++ ++ push = evo_wait(encoder->dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 2); ++ evo_data(push, 1 << nv_crtc->index); ++ evo_data(push, 0x00ff); ++ evo_kick(push, encoder->dev, 0); ++ } ++ ++ nv_encoder->crtc = encoder->crtc; ++} ++ ++static void ++nvd0_dac_disconnect(struct drm_encoder *encoder) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ u32 *push; ++ ++ if (nv_encoder->crtc) { ++ nvd0_crtc_prepare(nv_encoder->crtc); ++ ++ push = evo_wait(dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0180 + (nv_encoder->or * 0x20), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, dev, 0); ++ } ++ ++ nv_encoder->crtc = NULL; ++ } ++} ++ ++static enum drm_connector_status ++nvd0_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) ++{ ++ enum drm_connector_status status = connector_status_disconnected; ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ int or = nv_encoder->or; ++ u32 load; ++ ++ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00100000); ++ udelay(9500); ++ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x80000000); ++ ++ load = nv_rd32(dev, 0x61a00c + (or * 0x800)); ++ if ((load & 0x38000000) == 0x38000000) ++ status = connector_status_connected; ++ ++ nv_wr32(dev, 0x61a00c + (or * 0x800), 0x00000000); ++ return status; ++} ++ ++static void ++nvd0_dac_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++ kfree(encoder); ++} ++ ++static const struct drm_encoder_helper_funcs nvd0_dac_hfunc = { ++ .dpms = nvd0_dac_dpms, ++ .mode_fixup = nvd0_dac_mode_fixup, ++ .prepare = nvd0_dac_prepare, ++ .commit = nvd0_dac_commit, ++ .mode_set = nvd0_dac_mode_set, ++ .disable = nvd0_dac_disconnect, ++ .get_crtc = nvd0_display_crtc_get, ++ .detect = nvd0_dac_detect ++}; ++ ++static const struct drm_encoder_funcs nvd0_dac_func = { ++ .destroy = nvd0_dac_destroy, ++}; ++ ++static int ++nvd0_dac_create(struct drm_connector *connector, struct dcb_entry *dcbe) ++{ ++ struct drm_device *dev = connector->dev; ++ struct nouveau_encoder *nv_encoder; ++ struct drm_encoder *encoder; ++ ++ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); ++ if (!nv_encoder) ++ return -ENOMEM; ++ nv_encoder->dcb = dcbe; ++ nv_encoder->or = ffs(dcbe->or) - 1; ++ ++ encoder = to_drm_encoder(nv_encoder); ++ encoder->possible_crtcs = dcbe->heads; ++ encoder->possible_clones = 0; ++ drm_encoder_init(dev, encoder, &nvd0_dac_func, DRM_MODE_ENCODER_DAC); ++ drm_encoder_helper_add(encoder, &nvd0_dac_hfunc); ++ ++ drm_mode_connector_attach_encoder(connector, encoder); ++ return 0; ++} ++ ++/****************************************************************************** ++ * SOR ++ *****************************************************************************/ ++static void ++nvd0_sor_dpms(struct drm_encoder *encoder, int mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ struct drm_encoder *partner; ++ int or = nv_encoder->or; ++ u32 dpms_ctrl; ++ ++ nv_encoder->last_dpms = mode; ++ ++ list_for_each_entry(partner, &dev->mode_config.encoder_list, head) { ++ struct nouveau_encoder *nv_partner = nouveau_encoder(partner); ++ ++ if (partner->encoder_type != DRM_MODE_ENCODER_TMDS) ++ continue; ++ ++ if (nv_partner != nv_encoder && ++ nv_partner->dcb->or == nv_encoder->or) { ++ if (nv_partner->last_dpms == DRM_MODE_DPMS_ON) ++ return; ++ break; ++ } ++ } ++ ++ dpms_ctrl = (mode == DRM_MODE_DPMS_ON); ++ dpms_ctrl |= 0x80000000; ++ ++ nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); ++ nv_mask(dev, 0x61c004 + (or * 0x0800), 0x80000001, dpms_ctrl); ++ nv_wait(dev, 0x61c004 + (or * 0x0800), 0x80000000, 0x00000000); ++ nv_wait(dev, 0x61c030 + (or * 0x0800), 0x10000000, 0x00000000); ++} ++ ++static bool ++nvd0_sor_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode, ++ struct drm_display_mode *adjusted_mode) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_connector *nv_connector; ++ ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ if (nv_connector && nv_connector->native_mode) { ++ if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) { ++ int id = adjusted_mode->base.id; ++ *adjusted_mode = *nv_connector->native_mode; ++ adjusted_mode->base.id = id; ++ } ++ } ++ ++ return true; ++} ++ ++static void ++nvd0_sor_prepare(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_sor_commit(struct drm_encoder *encoder) ++{ ++} ++ ++static void ++nvd0_sor_mode_set(struct drm_encoder *encoder, struct drm_display_mode *umode, ++ struct drm_display_mode *mode) ++{ ++ struct drm_nouveau_private *dev_priv = encoder->dev->dev_private; ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); ++ struct nouveau_connector *nv_connector; ++ struct nvbios *bios = &dev_priv->vbios; ++ u32 mode_ctrl = (1 << nv_crtc->index); ++ u32 *push, or_config; ++ ++ nv_connector = nouveau_encoder_connector_get(nv_encoder); ++ switch (nv_encoder->dcb->type) { ++ case OUTPUT_TMDS: ++ if (nv_encoder->dcb->sorconf.link & 1) { ++ if (mode->clock < 165000) ++ mode_ctrl |= 0x00000100; ++ else ++ mode_ctrl |= 0x00000500; ++ } else { ++ mode_ctrl |= 0x00000200; ++ } ++ ++ or_config = (mode_ctrl & 0x00000f00) >> 8; ++ if (mode->clock >= 165000) ++ or_config |= 0x0100; ++ break; ++ case OUTPUT_LVDS: ++ or_config = (mode_ctrl & 0x00000f00) >> 8; ++ if (bios->fp_no_ddc) { ++ if (bios->fp.dual_link) ++ or_config |= 0x0100; ++ if (bios->fp.if_is_24bit) ++ or_config |= 0x0200; ++ } else { ++ if (nv_connector->dcb->type == DCB_CONNECTOR_LVDS_SPWG) { ++ if (((u8 *)nv_connector->edid)[121] == 2) ++ or_config |= 0x0100; ++ } else ++ if (mode->clock >= bios->fp.duallink_transition_clk) { ++ or_config |= 0x0100; ++ } ++ ++ if (or_config & 0x0100) { ++ if (bios->fp.strapless_is_24bit & 2) ++ or_config |= 0x0200; ++ } else { ++ if (bios->fp.strapless_is_24bit & 1) ++ or_config |= 0x0200; ++ } ++ ++ if (nv_connector->base.display_info.bpc == 8) ++ or_config |= 0x0200; ++ ++ } ++ break; ++ default: ++ BUG_ON(1); ++ break; ++ } ++ ++ nvd0_sor_dpms(encoder, DRM_MODE_DPMS_ON); ++ ++ push = evo_wait(encoder->dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 2); ++ evo_data(push, mode_ctrl); ++ evo_data(push, or_config); ++ evo_kick(push, encoder->dev, 0); ++ } ++ ++ nv_encoder->crtc = encoder->crtc; ++} ++ ++static void ++nvd0_sor_disconnect(struct drm_encoder *encoder) ++{ ++ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); ++ struct drm_device *dev = encoder->dev; ++ u32 *push; ++ ++ if (nv_encoder->crtc) { ++ nvd0_crtc_prepare(nv_encoder->crtc); ++ ++ push = evo_wait(dev, 0, 4); ++ if (push) { ++ evo_mthd(push, 0x0200 + (nv_encoder->or * 0x20), 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0080, 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, dev, 0); ++ } ++ ++ nv_encoder->crtc = NULL; ++ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; ++ } ++} ++ ++static void ++nvd0_sor_destroy(struct drm_encoder *encoder) ++{ ++ drm_encoder_cleanup(encoder); ++ kfree(encoder); ++} ++ ++static const struct drm_encoder_helper_funcs nvd0_sor_hfunc = { ++ .dpms = nvd0_sor_dpms, ++ .mode_fixup = nvd0_sor_mode_fixup, ++ .prepare = nvd0_sor_prepare, ++ .commit = nvd0_sor_commit, ++ .mode_set = nvd0_sor_mode_set, ++ .disable = nvd0_sor_disconnect, ++ .get_crtc = nvd0_display_crtc_get, ++}; ++ ++static const struct drm_encoder_funcs nvd0_sor_func = { ++ .destroy = nvd0_sor_destroy, ++}; ++ ++static int ++nvd0_sor_create(struct drm_connector *connector, struct dcb_entry *dcbe) ++{ ++ struct drm_device *dev = connector->dev; ++ struct nouveau_encoder *nv_encoder; ++ struct drm_encoder *encoder; ++ ++ nv_encoder = kzalloc(sizeof(*nv_encoder), GFP_KERNEL); ++ if (!nv_encoder) ++ return -ENOMEM; ++ nv_encoder->dcb = dcbe; ++ nv_encoder->or = ffs(dcbe->or) - 1; ++ nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; ++ ++ encoder = to_drm_encoder(nv_encoder); ++ encoder->possible_crtcs = dcbe->heads; ++ encoder->possible_clones = 0; ++ drm_encoder_init(dev, encoder, &nvd0_sor_func, DRM_MODE_ENCODER_TMDS); ++ drm_encoder_helper_add(encoder, &nvd0_sor_hfunc); ++ ++ drm_mode_connector_attach_encoder(connector, encoder); ++ return 0; ++} ++ ++/****************************************************************************** ++ * IRQ ++ *****************************************************************************/ ++static struct dcb_entry * ++lookup_dcb(struct drm_device *dev, int id, u32 mc) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ int type, or, i; ++ ++ if (id < 4) { ++ type = OUTPUT_ANALOG; ++ or = id; ++ } else { ++ switch (mc & 0x00000f00) { ++ case 0x00000000: type = OUTPUT_LVDS; break; ++ case 0x00000100: type = OUTPUT_TMDS; break; ++ case 0x00000200: type = OUTPUT_TMDS; break; ++ case 0x00000500: type = OUTPUT_TMDS; break; ++ default: ++ NV_ERROR(dev, "PDISP: unknown SOR mc 0x%08x\n", mc); ++ return NULL; ++ } ++ ++ or = id - 4; ++ } ++ ++ for (i = 0; i < dev_priv->vbios.dcb.entries; i++) { ++ struct dcb_entry *dcb = &dev_priv->vbios.dcb.entry[i]; ++ if (dcb->type == type && (dcb->or & (1 << or))) ++ return dcb; ++ } ++ ++ NV_ERROR(dev, "PDISP: DCB for %d/0x%08x not found\n", id, mc); ++ return NULL; ++} ++ ++static void ++nvd0_display_unk1_handler(struct drm_device *dev, u32 crtc, u32 mask) ++{ ++ struct dcb_entry *dcb; ++ int i; ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); ++ if (!(mcc & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcc); ++ if (!dcb) ++ continue; ++ ++ nouveau_bios_run_display_table(dev, 0x0000, -1, dcb, crtc); ++ } ++ ++ nv_wr32(dev, 0x6101d4, 0x00000000); ++ nv_wr32(dev, 0x6109d4, 0x00000000); ++ nv_wr32(dev, 0x6101d0, 0x80000000); ++} ++ ++static void ++nvd0_display_unk2_handler(struct drm_device *dev, u32 crtc, u32 mask) ++{ ++ struct dcb_entry *dcb; ++ u32 or, tmp, pclk; ++ int i; ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcc = nv_rd32(dev, 0x640180 + (i * 0x20)); ++ if (!(mcc & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcc); ++ if (!dcb) ++ continue; ++ ++ nouveau_bios_run_display_table(dev, 0x0000, -2, dcb, crtc); ++ } ++ ++ pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; ++ if (mask & 0x00010000) { ++ nv50_crtc_set_clock(dev, crtc, pclk); ++ } ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); ++ u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); ++ if (!(mcp & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcp); ++ if (!dcb) ++ continue; ++ or = ffs(dcb->or) - 1; ++ ++ nouveau_bios_run_display_table(dev, cfg, pclk, dcb, crtc); ++ ++ nv_wr32(dev, 0x612200 + (crtc * 0x800), 0x00000000); ++ switch (dcb->type) { ++ case OUTPUT_ANALOG: ++ nv_wr32(dev, 0x612280 + (or * 0x800), 0x00000000); ++ break; ++ case OUTPUT_TMDS: ++ case OUTPUT_LVDS: ++ if (cfg & 0x00000100) ++ tmp = 0x00000101; ++ else ++ tmp = 0x00000000; ++ ++ nv_mask(dev, 0x612300 + (or * 0x800), 0x00000707, tmp); ++ break; ++ default: ++ break; ++ } ++ ++ break; ++ } ++ ++ nv_wr32(dev, 0x6101d4, 0x00000000); ++ nv_wr32(dev, 0x6109d4, 0x00000000); ++ nv_wr32(dev, 0x6101d0, 0x80000000); ++} ++ ++static void ++nvd0_display_unk4_handler(struct drm_device *dev, u32 crtc, u32 mask) ++{ ++ struct dcb_entry *dcb; ++ int pclk, i; ++ ++ pclk = nv_rd32(dev, 0x660450 + (crtc * 0x300)) / 1000; ++ ++ for (i = 0; mask && i < 8; i++) { ++ u32 mcp = nv_rd32(dev, 0x660180 + (i * 0x20)); ++ u32 cfg = nv_rd32(dev, 0x660184 + (i * 0x20)); ++ if (!(mcp & (1 << crtc))) ++ continue; ++ ++ dcb = lookup_dcb(dev, i, mcp); ++ if (!dcb) ++ continue; ++ ++ nouveau_bios_run_display_table(dev, cfg, -pclk, dcb, crtc); ++ } ++ ++ nv_wr32(dev, 0x6101d4, 0x00000000); ++ nv_wr32(dev, 0x6109d4, 0x00000000); ++ nv_wr32(dev, 0x6101d0, 0x80000000); ++} ++ ++static void ++nvd0_display_bh(unsigned long data) ++{ ++ struct drm_device *dev = (struct drm_device *)data; ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 mask, crtc; ++ int i; ++ ++ if (drm_debug & (DRM_UT_DRIVER | DRM_UT_KMS)) { ++ NV_INFO(dev, "PDISP: modeset req %d\n", disp->modeset); ++ NV_INFO(dev, " STAT: 0x%08x 0x%08x 0x%08x\n", ++ nv_rd32(dev, 0x6101d0), ++ nv_rd32(dev, 0x6101d4), nv_rd32(dev, 0x6109d4)); ++ for (i = 0; i < 8; i++) { ++ NV_INFO(dev, " %s%d: 0x%08x 0x%08x\n", ++ i < 4 ? "DAC" : "SOR", i, ++ nv_rd32(dev, 0x640180 + (i * 0x20)), ++ nv_rd32(dev, 0x660180 + (i * 0x20))); ++ } ++ } ++ ++ mask = nv_rd32(dev, 0x6101d4); ++ crtc = 0; ++ if (!mask) { ++ mask = nv_rd32(dev, 0x6109d4); ++ crtc = 1; ++ } ++ ++ if (disp->modeset & 0x00000001) ++ nvd0_display_unk1_handler(dev, crtc, mask); ++ if (disp->modeset & 0x00000002) ++ nvd0_display_unk2_handler(dev, crtc, mask); ++ if (disp->modeset & 0x00000004) ++ nvd0_display_unk4_handler(dev, crtc, mask); ++} ++ ++static void ++nvd0_display_intr(struct drm_device *dev) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 intr = nv_rd32(dev, 0x610088); ++ ++ if (intr & 0x00000002) { ++ u32 stat = nv_rd32(dev, 0x61009c); ++ int chid = ffs(stat) - 1; ++ if (chid >= 0) { ++ u32 mthd = nv_rd32(dev, 0x6101f0 + (chid * 12)); ++ u32 data = nv_rd32(dev, 0x6101f4 + (chid * 12)); ++ u32 unkn = nv_rd32(dev, 0x6101f8 + (chid * 12)); ++ ++ NV_INFO(dev, "EvoCh: chid %d mthd 0x%04x data 0x%08x " ++ "0x%08x 0x%08x\n", ++ chid, (mthd & 0x0000ffc), data, mthd, unkn); ++ nv_wr32(dev, 0x61009c, (1 << chid)); ++ nv_wr32(dev, 0x6101f0 + (chid * 12), 0x90000000); ++ } ++ ++ intr &= ~0x00000002; ++ } ++ ++ if (intr & 0x00100000) { ++ u32 stat = nv_rd32(dev, 0x6100ac); ++ ++ if (stat & 0x00000007) { ++ disp->modeset = stat; ++ tasklet_schedule(&disp->tasklet); ++ ++ nv_wr32(dev, 0x6100ac, (stat & 0x00000007)); ++ stat &= ~0x00000007; ++ } ++ ++ if (stat) { ++ NV_INFO(dev, "PDISP: unknown intr24 0x%08x\n", stat); ++ nv_wr32(dev, 0x6100ac, stat); ++ } ++ ++ intr &= ~0x00100000; ++ } ++ ++ if (intr & 0x01000000) { ++ u32 stat = nv_rd32(dev, 0x6100bc); ++ nv_wr32(dev, 0x6100bc, stat); ++ intr &= ~0x01000000; ++ } ++ ++ if (intr & 0x02000000) { ++ u32 stat = nv_rd32(dev, 0x6108bc); ++ nv_wr32(dev, 0x6108bc, stat); ++ intr &= ~0x02000000; ++ } ++ ++ if (intr) ++ NV_INFO(dev, "PDISP: unknown intr 0x%08x\n", intr); ++} ++ ++/****************************************************************************** ++ * Init ++ *****************************************************************************/ ++static void ++nvd0_display_fini(struct drm_device *dev) ++{ ++ int i; ++ ++ /* fini cursors */ ++ for (i = 14; i >= 13; i--) { ++ if (!(nv_rd32(dev, 0x610490 + (i * 0x10)) & 0x00000001)) ++ continue; ++ ++ nv_mask(dev, 0x610490 + (i * 0x10), 0x00000001, 0x00000000); ++ nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00000000); ++ nv_mask(dev, 0x610090, 1 << i, 0x00000000); ++ nv_mask(dev, 0x6100a0, 1 << i, 0x00000000); ++ } ++ ++ /* fini master */ ++ if (nv_rd32(dev, 0x610490) & 0x00000010) { ++ nv_mask(dev, 0x610490, 0x00000010, 0x00000000); ++ nv_mask(dev, 0x610490, 0x00000003, 0x00000000); ++ nv_wait(dev, 0x610490, 0x80000000, 0x00000000); ++ nv_mask(dev, 0x610090, 0x00000001, 0x00000000); ++ nv_mask(dev, 0x6100a0, 0x00000001, 0x00000000); ++ } ++} ++ ++int ++nvd0_display_init(struct drm_device *dev) ++{ ++ struct nvd0_display *disp = nvd0_display(dev); ++ u32 *push; ++ int i; ++ ++ if (nv_rd32(dev, 0x6100ac) & 0x00000100) { ++ nv_wr32(dev, 0x6100ac, 0x00000100); ++ nv_mask(dev, 0x6194e8, 0x00000001, 0x00000000); ++ if (!nv_wait(dev, 0x6194e8, 0x00000002, 0x00000000)) { ++ NV_ERROR(dev, "PDISP: 0x6194e8 0x%08x\n", ++ nv_rd32(dev, 0x6194e8)); ++ return -EBUSY; ++ } ++ } ++ ++ /* nfi what these are exactly, i do know that SOR_MODE_CTRL won't ++ * work at all unless you do the SOR part below. ++ */ ++ for (i = 0; i < 3; i++) { ++ u32 dac = nv_rd32(dev, 0x61a000 + (i * 0x800)); ++ nv_wr32(dev, 0x6101c0 + (i * 0x800), dac); ++ } ++ ++ for (i = 0; i < 4; i++) { ++ u32 sor = nv_rd32(dev, 0x61c000 + (i * 0x800)); ++ nv_wr32(dev, 0x6301c4 + (i * 0x800), sor); ++ } ++ ++ for (i = 0; i < 2; i++) { ++ u32 crtc0 = nv_rd32(dev, 0x616104 + (i * 0x800)); ++ u32 crtc1 = nv_rd32(dev, 0x616108 + (i * 0x800)); ++ u32 crtc2 = nv_rd32(dev, 0x61610c + (i * 0x800)); ++ nv_wr32(dev, 0x6101b4 + (i * 0x800), crtc0); ++ nv_wr32(dev, 0x6101b8 + (i * 0x800), crtc1); ++ nv_wr32(dev, 0x6101bc + (i * 0x800), crtc2); ++ } ++ ++ /* point at our hash table / objects, enable interrupts */ ++ nv_wr32(dev, 0x610010, (disp->mem->vinst >> 8) | 9); ++ nv_mask(dev, 0x6100b0, 0x00000307, 0x00000307); ++ ++ /* init master */ ++ nv_wr32(dev, 0x610494, (disp->evo[0].handle >> 8) | 3); ++ nv_wr32(dev, 0x610498, 0x00010000); ++ nv_wr32(dev, 0x61049c, 0x00000001); ++ nv_mask(dev, 0x610490, 0x00000010, 0x00000010); ++ nv_wr32(dev, 0x640000, 0x00000000); ++ nv_wr32(dev, 0x610490, 0x01000013); ++ if (!nv_wait(dev, 0x610490, 0x80000000, 0x00000000)) { ++ NV_ERROR(dev, "PDISP: master 0x%08x\n", ++ nv_rd32(dev, 0x610490)); ++ return -EBUSY; ++ } ++ nv_mask(dev, 0x610090, 0x00000001, 0x00000001); ++ nv_mask(dev, 0x6100a0, 0x00000001, 0x00000001); ++ ++ /* init cursors */ ++ for (i = 13; i <= 14; i++) { ++ nv_wr32(dev, 0x610490 + (i * 0x10), 0x00000001); ++ if (!nv_wait(dev, 0x610490 + (i * 0x10), 0x00010000, 0x00010000)) { ++ NV_ERROR(dev, "PDISP: curs%d 0x%08x\n", i, ++ nv_rd32(dev, 0x610490 + (i * 0x10))); ++ return -EBUSY; ++ } ++ ++ nv_mask(dev, 0x610090, 1 << i, 1 << i); ++ nv_mask(dev, 0x6100a0, 1 << i, 1 << i); ++ } ++ ++ push = evo_wait(dev, 0, 32); ++ if (!push) ++ return -EBUSY; ++ evo_mthd(push, 0x0088, 1); ++ evo_data(push, NvEvoSync); ++ evo_mthd(push, 0x0084, 1); ++ evo_data(push, 0x00000000); ++ evo_mthd(push, 0x0084, 1); ++ evo_data(push, 0x80000000); ++ evo_mthd(push, 0x008c, 1); ++ evo_data(push, 0x00000000); ++ evo_kick(push, dev, 0); ++ ++ return 0; ++} ++ ++void ++nvd0_display_destroy(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nvd0_display *disp = nvd0_display(dev); ++ struct pci_dev *pdev = dev->pdev; ++ ++ nvd0_display_fini(dev); ++ ++ pci_free_consistent(pdev, PAGE_SIZE, disp->evo[0].ptr, disp->evo[0].handle); ++ nouveau_gpuobj_ref(NULL, &disp->mem); ++ nouveau_irq_unregister(dev, 26); ++ ++ dev_priv->engine.display.priv = NULL; ++ kfree(disp); ++} ++ ++int ++nvd0_display_create(struct drm_device *dev) ++{ ++ struct drm_nouveau_private *dev_priv = dev->dev_private; ++ struct nouveau_instmem_engine *pinstmem = &dev_priv->engine.instmem; ++ struct dcb_table *dcb = &dev_priv->vbios.dcb; ++ struct drm_connector *connector, *tmp; ++ struct pci_dev *pdev = dev->pdev; ++ struct nvd0_display *disp; ++ struct dcb_entry *dcbe; ++ int ret, i; ++ ++ disp = kzalloc(sizeof(*disp), GFP_KERNEL); ++ if (!disp) ++ return -ENOMEM; ++ dev_priv->engine.display.priv = disp; ++ ++ /* create crtc objects to represent the hw heads */ ++ for (i = 0; i < 2; i++) { ++ ret = nvd0_crtc_create(dev, i); ++ if (ret) ++ goto out; ++ } ++ ++ /* create encoder/connector objects based on VBIOS DCB table */ ++ for (i = 0, dcbe = &dcb->entry[0]; i < dcb->entries; i++, dcbe++) { ++ connector = nouveau_connector_create(dev, dcbe->connector); ++ if (IS_ERR(connector)) ++ continue; ++ ++ if (dcbe->location != DCB_LOC_ON_CHIP) { ++ NV_WARN(dev, "skipping off-chip encoder %d/%d\n", ++ dcbe->type, ffs(dcbe->or) - 1); ++ continue; ++ } ++ ++ switch (dcbe->type) { ++ case OUTPUT_TMDS: ++ case OUTPUT_LVDS: ++ nvd0_sor_create(connector, dcbe); ++ break; ++ case OUTPUT_ANALOG: ++ nvd0_dac_create(connector, dcbe); ++ break; ++ default: ++ NV_WARN(dev, "skipping unsupported encoder %d/%d\n", ++ dcbe->type, ffs(dcbe->or) - 1); ++ continue; ++ } ++ } ++ ++ /* cull any connectors we created that don't have an encoder */ ++ list_for_each_entry_safe(connector, tmp, &dev->mode_config.connector_list, head) { ++ if (connector->encoder_ids[0]) ++ continue; ++ ++ NV_WARN(dev, "%s has no encoders, removing\n", ++ drm_get_connector_name(connector)); ++ connector->funcs->destroy(connector); ++ } ++ ++ /* setup interrupt handling */ ++ tasklet_init(&disp->tasklet, nvd0_display_bh, (unsigned long)dev); ++ nouveau_irq_register(dev, 26, nvd0_display_intr); ++ ++ /* hash table and dma objects for the memory areas we care about */ ++ ret = nouveau_gpuobj_new(dev, NULL, 0x4000, 0x10000, ++ NVOBJ_FLAG_ZERO_ALLOC, &disp->mem); ++ if (ret) ++ goto out; ++ ++ nv_wo32(disp->mem, 0x1000, 0x00000049); ++ nv_wo32(disp->mem, 0x1004, (disp->mem->vinst + 0x2000) >> 8); ++ nv_wo32(disp->mem, 0x1008, (disp->mem->vinst + 0x2fff) >> 8); ++ nv_wo32(disp->mem, 0x100c, 0x00000000); ++ nv_wo32(disp->mem, 0x1010, 0x00000000); ++ nv_wo32(disp->mem, 0x1014, 0x00000000); ++ nv_wo32(disp->mem, 0x0000, NvEvoSync); ++ nv_wo32(disp->mem, 0x0004, (0x1000 << 9) | 0x00000001); ++ ++ nv_wo32(disp->mem, 0x1020, 0x00000049); ++ nv_wo32(disp->mem, 0x1024, 0x00000000); ++ nv_wo32(disp->mem, 0x1028, (dev_priv->vram_size - 1) >> 8); ++ nv_wo32(disp->mem, 0x102c, 0x00000000); ++ nv_wo32(disp->mem, 0x1030, 0x00000000); ++ nv_wo32(disp->mem, 0x1034, 0x00000000); ++ nv_wo32(disp->mem, 0x0008, NvEvoVRAM); ++ nv_wo32(disp->mem, 0x000c, (0x1020 << 9) | 0x00000001); ++ ++ nv_wo32(disp->mem, 0x1040, 0x00000009); ++ nv_wo32(disp->mem, 0x1044, 0x00000000); ++ nv_wo32(disp->mem, 0x1048, (dev_priv->vram_size - 1) >> 8); ++ nv_wo32(disp->mem, 0x104c, 0x00000000); ++ nv_wo32(disp->mem, 0x1050, 0x00000000); ++ nv_wo32(disp->mem, 0x1054, 0x00000000); ++ nv_wo32(disp->mem, 0x0010, NvEvoVRAM_LP); ++ nv_wo32(disp->mem, 0x0014, (0x1040 << 9) | 0x00000001); ++ ++ nv_wo32(disp->mem, 0x1060, 0x0fe00009); ++ nv_wo32(disp->mem, 0x1064, 0x00000000); ++ nv_wo32(disp->mem, 0x1068, (dev_priv->vram_size - 1) >> 8); ++ nv_wo32(disp->mem, 0x106c, 0x00000000); ++ nv_wo32(disp->mem, 0x1070, 0x00000000); ++ nv_wo32(disp->mem, 0x1074, 0x00000000); ++ nv_wo32(disp->mem, 0x0018, NvEvoFB32); ++ nv_wo32(disp->mem, 0x001c, (0x1060 << 9) | 0x00000001); ++ ++ pinstmem->flush(dev); ++ ++ /* push buffers for evo channels */ ++ disp->evo[0].ptr = ++ pci_alloc_consistent(pdev, PAGE_SIZE, &disp->evo[0].handle); ++ if (!disp->evo[0].ptr) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = nvd0_display_init(dev); ++ if (ret) ++ goto out; ++ ++out: ++ if (ret) ++ nvd0_display_destroy(dev); ++ return ret; ++} +diff -Naur linux-3.0/include/drm/drmP.h linux-3.0.patch/include/drm/drmP.h +--- linux-3.0/include/drm/drmP.h 2011-07-22 04:17:23.000000000 +0200 ++++ linux-3.0.patch/include/drm/drmP.h 2011-07-26 07:03:44.518052107 +0200 +@@ -886,6 +886,8 @@ + */ + int (*gem_init_object) (struct drm_gem_object *obj); + void (*gem_free_object) (struct drm_gem_object *obj); ++ int (*gem_open_object) (struct drm_gem_object *, struct drm_file *); ++ void (*gem_close_object) (struct drm_gem_object *, struct drm_file *); + + /* vga arb irq handler */ + void (*vgaarb_irq)(struct drm_device *dev, bool state); diff --git a/packages/mediacenter/xbmc/fonts/DejaVuSans.ttf b/packages/mediacenter/xbmc/fonts/DejaVuSans.ttf new file mode 100644 index 0000000000..84ca1d7503 Binary files /dev/null and b/packages/mediacenter/xbmc/fonts/DejaVuSans.ttf differ diff --git a/packages/mediacenter/xbmc/fonts/Trebuchet MS Bold.ttf b/packages/mediacenter/xbmc/fonts/Trebuchet MS Bold.ttf new file mode 100644 index 0000000000..867f56d776 Binary files /dev/null and b/packages/mediacenter/xbmc/fonts/Trebuchet MS Bold.ttf differ diff --git a/packages/mediacenter/xbmc/fonts/YanoneKaffeesatz-Bold.ttf b/packages/mediacenter/xbmc/fonts/YanoneKaffeesatz-Bold.ttf new file mode 100644 index 0000000000..e9964b0809 Binary files /dev/null and b/packages/mediacenter/xbmc/fonts/YanoneKaffeesatz-Bold.ttf differ diff --git a/packages/mediacenter/xbmc/fonts/cwheib-1.ttf b/packages/mediacenter/xbmc/fonts/cwheib-1.ttf new file mode 100644 index 0000000000..cf1ac59e06 Binary files /dev/null and b/packages/mediacenter/xbmc/fonts/cwheib-1.ttf differ diff --git a/packages/mediacenter/xbmc/init.d/92_setup-xbmc b/packages/mediacenter/xbmc/init.d/92_setup-xbmc index b67bde73bb..99cdca20f2 100644 --- a/packages/mediacenter/xbmc/init.d/92_setup-xbmc +++ b/packages/mediacenter/xbmc/init.d/92_setup-xbmc @@ -108,6 +108,14 @@ EOF EOF +# +# include project specific options +# + + if [ -f /usr/share/xbmc/config/guisettings.xml ]; then + cat /usr/share/xbmc/config/guisettings.xml >> $HOME/.xbmc/userdata/guisettings.xml + fi + # # common setup for amd and nvidia graphic # diff --git a/packages/mediacenter/xbmc/install b/packages/mediacenter/xbmc/install index 1753b43cf8..fcfb59bd33 100755 --- a/packages/mediacenter/xbmc/install +++ b/packages/mediacenter/xbmc/install @@ -74,6 +74,17 @@ mkdir -p $PYTHON_LIBDIR/site-packages/xbmc mkdir -p $INSTALL/etc/pm/sleep.d cp $PKG_DIR/sleep.d/* $INSTALL/etc/pm/sleep.d +# install project specific configs + if [ -f $PROJECT_DIR/$PROJECT/xbmc/*.xml ]; then + mkdir -p $INSTALL/usr/share/xbmc/config + cp -R $PROJECT_DIR/$PROJECT/xbmc/* $INSTALL/usr/share/xbmc/config + fi + +if [ "$XBMC_EXTRA_FONTS" = yes ]; then + mkdir -p $INSTALL/usr/share/xbmc/media/Fonts + cp $PKG_DIR/fonts/*.ttf $INSTALL/usr/share/xbmc/media/Fonts +fi + if [ "$WIIMOTE_SUPPORT" = yes ]; then mkdir -p $INSTALL/usr/bin cp $PKG_BUILD/tools/EventClients/Clients/WiiRemote/WiiUse_WiiRemote $INSTALL/usr/bin/xbmc-wiiremote diff --git a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-332-fix_VAAPI_ticket_10928-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-332-fix_VAAPI_ticket_10928-0.1.patch new file mode 100644 index 0000000000..22c3737778 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-332-fix_VAAPI_ticket_10928-0.1.patch @@ -0,0 +1,72 @@ +From 76b51cce5dd64d6f33348cd36eddce95d571f783 Mon Sep 17 00:00:00 2001 +From: Yuriy Romanenko +Date: Thu, 24 Feb 2011 12:03:53 +0200 +Subject: [PATCH] linux: VAAPI fix from bug #10928 + http://trac.xbmc.org/ticket/10928 + +Signed-off-by: Joakim Plate +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 20 ++++++++++++++------ + 1 files changed, 14 insertions(+), 6 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index 0aac8fe..b03ea5c 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -149,10 +149,10 @@ int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic) + { + VASurfaceID surface = GetSurfaceID(pic); + CSurface* wrapper = NULL; ++ std::list::iterator it = m_surfaces_free.begin(); + if(surface) + { + /* reget call */ +- std::list::iterator it = m_surfaces_free.begin(); + for(; it != m_surfaces_free.end(); it++) + { + if((*it)->m_id == surface) +@@ -171,20 +171,28 @@ int CDecoder::GetBuffer(AVCodecContext *avctx, AVFrame *pic) + } + else + { +- if(m_surfaces_free.empty()) ++ // To avoid stutter, we scan the free surface pool (provided by decoder) for surfaces ++ // that are 100% not in use by renderer. The pointers to these surfaces have a use_count of 1. ++ for (; it != m_surfaces_free.end() && it->use_count() > 1; it++) {} ++ ++ // If we have zero free surface from decoder OR all free surfaces are in use by renderer, we allocate a new surface ++ if (it == m_surfaces_free.end()) + { ++ if (!m_surfaces_free.empty()) CLog::Log(LOGERROR, "VAAPI - renderer still using all freed up surfaces by decoder"); + CLog::Log(LOGERROR, "VAAPI - unable to find free surface, trying to allocate a new one"); + if(!EnsureSurfaces(avctx, m_surfaces_count+1) || m_surfaces_free.empty()) + { + CLog::Log(LOGERROR, "VAAPI - unable to find free surface"); + return -1; + } ++ // Set itarator position to the newly allocated surface (end-1) ++ it = m_surfaces_free.end(); it--; + } + /* getbuffer call */ +- wrapper = m_surfaces_free.front().get(); ++ wrapper = it->get(); + surface = wrapper->m_id; +- m_surfaces_used.push_back(m_surfaces_free.front()); +- m_surfaces_free.pop_front(); ++ m_surfaces_used.push_back(*it); ++ m_surfaces_free.erase(it); + } + + pic->type = FF_BUFFER_TYPE_USER; +@@ -349,7 +357,7 @@ bool CDecoder::EnsureContext(AVCodecContext *avctx) + else + m_refs = 2; + } +- return EnsureSurfaces(avctx, m_refs + 1 + 1); ++ return EnsureSurfaces(avctx, m_refs + 3); + } + + bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) +-- +1.7.5.4 + diff --git a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-333-fix_NULL_conversion_warnings_in_VAAPI-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-333-fix_NULL_conversion_warnings_in_VAAPI-0.1.patch new file mode 100644 index 0000000000..84465aad02 --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-333-fix_NULL_conversion_warnings_in_VAAPI-0.1.patch @@ -0,0 +1,50 @@ +From acef66ba6f0bf1db31906c7c7c4f7c83cfee44c1 Mon Sep 17 00:00:00 2001 +From: Kyle Hill +Date: Sat, 14 May 2011 17:23:45 -0500 +Subject: [PATCH] Fix NULL -> 0 conversion warnings in VAAPI.cpp + +--- + xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp | 10 +++++----- + 1 files changed, 5 insertions(+), 5 deletions(-) + +diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +index b03ea5c..d9d2bd2 100644 +--- a/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp ++++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/VAAPI.cpp +@@ -115,8 +115,8 @@ CDecoder::CDecoder() + { + m_refs = 0; + m_surfaces_count = 0; +- m_config = NULL; +- m_context = NULL; ++ m_config = 0; ++ m_context = 0; + m_hwaccel = (vaapi_context*)calloc(1, sizeof(vaapi_context)); + } + +@@ -212,11 +212,11 @@ void CDecoder::Close() + { + if(m_context) + WARN(vaDestroyContext(m_display->get(), m_context)) +- m_context = NULL; ++ m_context = 0; + + if(m_config) + WARN(vaDestroyConfig(m_display->get(), m_config)) +- m_config = NULL; ++ m_config = 0; + + m_surfaces_free.clear(); + m_surfaces_used.clear(); +@@ -384,7 +384,7 @@ bool CDecoder::EnsureSurfaces(AVCodecContext *avctx, unsigned n_surfaces_count) + + if(m_context) + WARN(vaDestroyContext(m_display->get(), m_context)) +- m_context = NULL; ++ m_context = 0; + + CHECK(vaCreateContext(m_display->get() + , m_config +-- +1.7.5.4 + diff --git a/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-454-disable_backslash-0.1.patch b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-454-disable_backslash-0.1.patch new file mode 100644 index 0000000000..86b5ad0fbf --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-10.1-Dharma-454-disable_backslash-0.1.patch @@ -0,0 +1,12 @@ +diff -Naur xbmc-10.1-Dharma/system/keymaps/keyboard.xml xbmc-10.1-Dharma.patch/system/keymaps/keyboard.xml +--- xbmc-10.1-Dharma/system/keymaps/keyboard.xml 2011-03-08 02:49:23.000000000 +0100 ++++ xbmc-10.1-Dharma.patch/system/keymaps/keyboard.xml 2011-07-23 18:04:59.406603684 +0200 +@@ -75,7 +75,7 @@ + Number7 + Number8 + Number9 +- ToggleFullScreen ++ + XBMC.ActivateWindow(Home) + ActivateWindow(Favourites) + diff --git a/packages/multimedia/rtmpdump/meta b/packages/multimedia/rtmpdump/meta index 0a0849638f..437c96f0c2 100644 --- a/packages/multimedia/rtmpdump/meta +++ b/packages/multimedia/rtmpdump/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="rtmpdump" -PKG_VERSION="c28f1ba" +PKG_VERSION="b627335" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/network/bluez/build b/packages/network/bluez/build index d2a540f563..a6f966af76 100755 --- a/packages/network/bluez/build +++ b/packages/network/bluez/build @@ -47,27 +47,27 @@ cd $PKG_BUILD --enable-optimization \ --enable-fortify \ --disable-pie \ - --disable-network \ + --enable-network \ --disable-sap \ --disable-serial \ - --enable-usb \ --enable-input \ - --disable-audio \ + --enable-audio \ --enable-service \ - --disable-pnat \ - --disable-attrib \ + --enable-health \ + --enable-pnat \ --disable-gstreamer \ --enable-alsa \ + --enable-usb \ --disable-tracer \ + --enable-datafiles \ --enable-pcmcia \ --enable-hid2hci \ --enable-dfutool \ - --enable-hidd \ + --disable-hidd \ --disable-pand \ --disable-dund \ --disable-cups \ - --enable-udevrules \ - --enable-configfiles \ + --enable-wiimote \ --disable-maemo6 \ --disable-dbusoob \ --disable-hal \ diff --git a/packages/network/bluez/install b/packages/network/bluez/install index 58b61d1dcf..54efddd911 100755 --- a/packages/network/bluez/install +++ b/packages/network/bluez/install @@ -27,6 +27,7 @@ PKG_DIR=`find $PACKAGES -type d -name $1` mkdir -p $INSTALL/etc/bluetooth cp $PKG_BUILD/src/main.conf $INSTALL/etc/bluetooth cp $PKG_BUILD/tools/rfcomm.conf $INSTALL/etc/bluetooth + cp $PKG_BUILD/audio/audio.conf $INSTALL/etc/bluetooth cp $PKG_BUILD/input/input.conf $INSTALL/etc/bluetooth mkdir -p $INSTALL/etc/dbus-1/system.d @@ -35,32 +36,13 @@ mkdir -p $INSTALL/etc/dbus-1/system.d mkdir -p $INSTALL/lib/udev cp $PKG_BUILD/scripts/bluetooth_serial $INSTALL/lib/udev chmod +x $INSTALL/lib/udev/bluetooth_serial + cp $PKG_BUILD/tools/hid2hci $INSTALL/lib/udev mkdir -p $INSTALL/lib/udev/rules.d cp $PKG_BUILD/scripts/97-bluetooth.rules $INSTALL/lib/udev/rules.d cp $PKG_BUILD/scripts/97-bluetooth-hid2hci.rules $INSTALL/lib/udev/rules.d cp $PKG_BUILD/scripts/97-bluetooth-serial.rules $INSTALL/lib/udev/rules.d -if [ "$DEVTOOLS" = "yes" ]; then - mkdir -p $INSTALL/usr/bin - cp $PKG_BUILD/tools/.libs/ciptool $INSTALL/usr/bin - cp $PKG_BUILD/tools/.libs/hcitool $INSTALL/usr/bin - cp $PKG_BUILD/tools/.libs/l2ping $INSTALL/usr/bin - cp $PKG_BUILD/tools/.libs/rfcomm $INSTALL/usr/bin - cp $PKG_BUILD/tools/.libs/sdptool $INSTALL/usr/bin - cp $PKG_BUILD/tools/dfutool $INSTALL/usr/bin - cp $PKG_BUILD/compat/.libs/hidd $INSTALL/usr/bin - cp $PKG_BUILD/test/.libs/l2test $INSTALL/usr/bin - cp $PKG_BUILD/test/.libs/rctest $INSTALL/usr/bin - -mkdir -p $INSTALL/usr/sbin - cp $PKG_BUILD/tools/.libs/bccmd $INSTALL/usr/sbin # TODO - cp $PKG_BUILD/tools/.libs/hciattach $INSTALL/usr/sbin - cp $PKG_BUILD/tools/.libs/hciconfig $INSTALL/usr/sbin - cp $PKG_BUILD/tools/hid2hci $INSTALL/usr/sbin - cp $PKG_BUILD/test/.libs/hciemu $INSTALL/usr/sbin -fi - mkdir -p $INSTALL/usr/lib cp $PKG_BUILD/lib/.libs/libbluetooth.so* $INSTALL/usr/lib @@ -68,8 +50,28 @@ mkdir -p $INSTALL/usr/lib/alsa-lib cp $PKG_BUILD/audio/.libs/*.so $INSTALL/usr/lib/alsa-lib mkdir -p $INSTALL/usr/lib/bluetooth/plugins - #cp $PKG_BUILD/plugins/.libs/*.so $INSTALL/usr/lib/bluetooth/plugins mkdir -p $INSTALL/usr/sbin cp $PKG_BUILD/src/.libs/bluetoothd $INSTALL/usr/sbin +mkdir -p $INSTALL/usr/share/alsa + cp $PKG_BUILD/audio/bluetooth.conf $INSTALL/usr/share/alsa + +if [ "$DEVTOOLS" = "yes" ]; then + mkdir -p $INSTALL/usr/bin + cp $PKG_BUILD/tools/.libs/ciptool $INSTALL/usr/bin + cp $PKG_BUILD/tools/dfutool $INSTALL/usr/bin + cp $PKG_BUILD/tools/.libs/hcitool $INSTALL/usr/bin + cp $PKG_BUILD/tools/.libs/l2ping $INSTALL/usr/bin + cp $PKG_BUILD/test/.libs/l2test $INSTALL/usr/bin + cp $PKG_BUILD/test/.libs/rctest $INSTALL/usr/bin + cp $PKG_BUILD/tools/.libs/rfcomm $INSTALL/usr/bin + cp $PKG_BUILD/tools/.libs/sdptool $INSTALL/usr/bin + +mkdir -p $INSTALL/usr/sbin + cp $PKG_BUILD/tools/.libs/bccmd $INSTALL/usr/sbin # TODO + cp $PKG_BUILD/tools/.libs/hciattach $INSTALL/usr/sbin + cp $PKG_BUILD/tools/.libs/hciconfig $INSTALL/usr/sbin + cp $PKG_BUILD/test/.libs/hciemu $INSTALL/usr/sbin +fi + diff --git a/packages/network/bluez/meta b/packages/network/bluez/meta index 646c78b1b5..001a7dea7c 100644 --- a/packages/network/bluez/meta +++ b/packages/network/bluez/meta @@ -19,12 +19,13 @@ ################################################################################ PKG_NAME="bluez" -PKG_VERSION="4.95" +PKG_VERSION="53e6e76" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" PKG_SITE="http://www.bluez.org/" -PKG_URL="http://www.kernel.org/pub/linux/bluetooth/$PKG_NAME-$PKG_VERSION.tar.bz2" +#PKG_URL="http://www.kernel.org/pub/linux/bluetooth/$PKG_NAME-$PKG_VERSION.tar.bz2" +PKG_URL="$OPENELEC_SRC/$PKG_NAME-$PKG_VERSION.tar.xz" PKG_DEPENDS="alsa-lib libusb-compat dbus glib" PKG_BUILD_DEPENDS="toolchain alsa-lib libusb-compat dbus glib" PKG_PRIORITY="optional" diff --git a/packages/network/connman/init.d/21_network b/packages/network/connman/init.d/21_network index c82b6472c6..89da806004 100644 --- a/packages/network/connman/init.d/21_network +++ b/packages/network/connman/init.d/21_network @@ -108,5 +108,8 @@ fi # starting Connection manager progress "starting Connection manager" - /usr/sbin/connmand + while true; do + /usr/sbin/connmand -n > /dev/null 2>&1 + usleep 250000 + done )& diff --git a/packages/sysutils/lm_sensors/meta b/packages/sysutils/lm_sensors/meta index 5fd6ac95cf..0e4a805087 100644 --- a/packages/sysutils/lm_sensors/meta +++ b/packages/sysutils/lm_sensors/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="lm_sensors" -PKG_VERSION="3.3.0" +PKG_VERSION="3.3.1" PKG_REV="1" PKG_ARCH="any" PKG_LICENSE="GPL" diff --git a/packages/x11/driver/xf86-video-fglrx/config/xorg-fglrx.conf b/packages/x11/driver/xf86-video-fglrx/config/xorg-fglrx.conf index e2ea855dc6..60f6205784 100644 --- a/packages/x11/driver/xf86-video-fglrx/config/xorg-fglrx.conf +++ b/packages/x11/driver/xf86-video-fglrx/config/xorg-fglrx.conf @@ -17,3 +17,7 @@ Section "Screen" Depth 24 EndSubSection EndSection + +Section "Extensions" + Option "Composite" "false" +EndSection diff --git a/packages/x11/driver/xf86-video-nouveau/meta b/packages/x11/driver/xf86-video-nouveau/meta index eedab0625f..9ce25297eb 100644 --- a/packages/x11/driver/xf86-video-nouveau/meta +++ b/packages/x11/driver/xf86-video-nouveau/meta @@ -19,7 +19,7 @@ ################################################################################ PKG_NAME="xf86-video-nouveau" -PKG_VERSION="ab89aa0" +PKG_VERSION="de9d1ba" PKG_REV="1" PKG_ARCH="i386 x86_64" PKG_LICENSE="OSS" diff --git a/projects/ATV/linux/linux.i386.conf b/projects/ATV/linux/linux.i386.conf index 9388455d1a..0ba2943b3b 100644 --- a/projects/ATV/linux/linux.i386.conf +++ b/projects/ATV/linux/linux.i386.conf @@ -97,12 +97,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set # CONFIG_IKCONFIG is not set CONFIG_LOG_BUF_SHIFT=16 CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y @@ -229,27 +230,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y # CONFIG_FREEZER is not set @@ -330,8 +331,8 @@ CONFIG_NR_CPUS=2 # CONFIG_SCHED_MC is not set CONFIG_IRQ_TIME_ACCOUNTING=y # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y @@ -626,13 +627,15 @@ CONFIG_XPS=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -644,7 +647,7 @@ CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -# CONFIG_BT_ATH3K is not set +CONFIG_BT_ATH3K=m # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -656,8 +659,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1094,38 +1097,8 @@ CONFIG_INPUT_EVDEV=y # # Input Device Drivers # -CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ADP5588 is not set -# CONFIG_KEYBOARD_ADP5589 is not set -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_QT1070 is not set -# CONFIG_KEYBOARD_QT2160 is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_TCA6416 is not set -# CONFIG_KEYBOARD_LM8323 is not set -# CONFIG_KEYBOARD_MAX7359 is not set -# CONFIG_KEYBOARD_MCS is not set -# CONFIG_KEYBOARD_MPR121 is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_OPENCORES is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -# CONFIG_MOUSE_PS2_ELANTECH is not set -# CONFIG_MOUSE_PS2_SENTELIC is not set -# CONFIG_MOUSE_PS2_TOUCHKIT is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_APPLETOUCH is not set -# CONFIG_MOUSE_BCM5974 is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y # CONFIG_JOYSTICK_ANALOG is not set # CONFIG_JOYSTICK_A3D is not set @@ -1173,15 +1146,7 @@ CONFIG_INPUT_UINPUT=y # # Hardware I/O ports # -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PCIPS2 is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set -# CONFIG_SERIO_ALTERA_PS2 is not set -# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set # @@ -1692,7 +1657,6 @@ CONFIG_DRM_TTM=y # CONFIG_DRM_TDFX is not set # CONFIG_DRM_R128 is not set # CONFIG_DRM_RADEON is not set -# CONFIG_DRM_I810 is not set # CONFIG_DRM_I915 is not set # CONFIG_DRM_MGA is not set # CONFIG_DRM_SIS is not set @@ -1935,6 +1899,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -1959,19 +1924,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2151,7 +2113,6 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_LP3944 is not set # CONFIG_LEDS_LP5521 is not set # CONFIG_LEDS_LP5523 is not set -# CONFIG_LEDS_CLEVO_MAIL is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_INTEL_SS4200 is not set @@ -2533,6 +2494,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/ATV/options b/projects/ATV/options index 07b6bacb1a..fe337796ea 100644 --- a/projects/ATV/options +++ b/projects/ATV/options @@ -112,6 +112,9 @@ # Default Skin (Confluence) SKIN_DEFAULT="Confluence" +# install extra subtitle Fonts for XBMC (yes / no) + XBMC_EXTRA_FONTS="yes" + # Plugins for XBMC to install (SABnzbd) # Space separated list is supported, # e.g. XBMC_PLUGINS="SABnzbd" diff --git a/projects/Fusion/linux/linux.i386.conf b/projects/Fusion/linux/linux.i386.conf index 57a8396d10..2d8d4a0365 100644 --- a/projects/Fusion/linux/linux.i386.conf +++ b/projects/Fusion/linux/linux.i386.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -224,27 +225,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -323,8 +324,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -632,13 +633,15 @@ CONFIG_XPS=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -661,8 +664,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1099,8 +1102,8 @@ CONFIG_USB_NET_DM9601=m # CONFIG_INPUT=y CONFIG_INPUT_FF_MEMLESS=y -CONFIG_INPUT_POLLDEV=m -CONFIG_INPUT_SPARSEKMAP=m +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_SPARSEKMAP=y # # Userland interfaces @@ -1197,7 +1200,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO=y CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y @@ -2111,6 +2114,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2135,19 +2139,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2735,6 +2736,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/Fusion/options b/projects/Fusion/options index 14b4e185d0..082af9c099 100644 --- a/projects/Fusion/options +++ b/projects/Fusion/options @@ -112,6 +112,9 @@ # Default Skin (Confluence) SKIN_DEFAULT="Confluence" +# install extra subtitle Fonts for XBMC (yes / no) + XBMC_EXTRA_FONTS="yes" + # Plugins for XBMC to install (SABnzbd) # Space separated list is supported, # e.g. XBMC_PLUGINS="SABnzbd" diff --git a/projects/Generic/linux/linux.i386.conf b/projects/Generic/linux/linux.i386.conf index 672e5ae1a6..ff5c5e5e2c 100644 --- a/projects/Generic/linux/linux.i386.conf +++ b/projects/Generic/linux/linux.i386.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -224,27 +225,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -325,8 +326,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -640,13 +641,15 @@ CONFIG_XPS=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -671,8 +674,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1233,8 +1236,8 @@ CONFIG_USB_NET_DM9601=m # CONFIG_INPUT=y CONFIG_INPUT_FF_MEMLESS=y -CONFIG_INPUT_POLLDEV=m -CONFIG_INPUT_SPARSEKMAP=m +CONFIG_INPUT_POLLDEV=y +CONFIG_INPUT_SPARSEKMAP=y # # Userland interfaces @@ -1331,7 +1334,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO=y CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y @@ -2055,7 +2058,6 @@ CONFIG_DRM_TTM=y # CONFIG_DRM_R128 is not set CONFIG_DRM_RADEON=y CONFIG_DRM_RADEON_KMS=y -# CONFIG_DRM_I810 is not set CONFIG_DRM_I915=y CONFIG_DRM_I915_KMS=y # CONFIG_DRM_MGA is not set @@ -2309,6 +2311,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2333,19 +2336,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2997,6 +2997,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/Generic/options b/projects/Generic/options index abb08340ee..f756bd0c98 100644 --- a/projects/Generic/options +++ b/projects/Generic/options @@ -112,6 +112,9 @@ # Default Skin (Confluence) SKIN_DEFAULT="Confluence" +# install extra subtitle Fonts for XBMC (yes / no) + XBMC_EXTRA_FONTS="yes" + # Plugins for XBMC to install (SABnzbd) # Space separated list is supported, # e.g. XBMC_PLUGINS="SABnzbd" diff --git a/projects/ION/linux/linux.i386.conf b/projects/ION/linux/linux.i386.conf index 65ed0fa3a8..c20170a9fd 100644 --- a/projects/ION/linux/linux.i386.conf +++ b/projects/ION/linux/linux.i386.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -224,27 +225,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -323,8 +324,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -626,13 +627,15 @@ CONFIG_XPS=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -645,7 +648,7 @@ CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -# CONFIG_BT_ATH3K is not set +CONFIG_BT_ATH3K=m # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -657,8 +660,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1243,7 +1246,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO=y CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y @@ -2162,6 +2165,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2186,19 +2190,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2797,6 +2798,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/ION/linux/linux.x86_64.conf b/projects/ION/linux/linux.x86_64.conf index 64cc3f687d..7b30d0849d 100644 --- a/projects/ION/linux/linux.x86_64.conf +++ b/projects/ION/linux/linux.x86_64.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -222,27 +223,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -295,8 +296,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -577,13 +578,15 @@ CONFIG_HAVE_BPF_JIT=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -596,7 +599,7 @@ CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -# CONFIG_BT_ATH3K is not set +CONFIG_BT_ATH3K=m # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -608,8 +611,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1192,7 +1195,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO=y CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y @@ -2098,6 +2101,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2122,19 +2126,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2740,6 +2741,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/ION/options b/projects/ION/options index 30073f46c3..d27b6558a5 100644 --- a/projects/ION/options +++ b/projects/ION/options @@ -112,6 +112,9 @@ # Default Skin (Confluence) SKIN_DEFAULT="Confluence" +# install extra subtitle Fonts for XBMC (yes / no) + XBMC_EXTRA_FONTS="yes" + # Plugins for XBMC to install (SABnzbd) # Space separated list is supported, # e.g. XBMC_PLUGINS="SABnzbd" diff --git a/projects/Intel/linux/linux.i386.conf b/projects/Intel/linux/linux.i386.conf index 5346e0b712..2a1df55a03 100644 --- a/projects/Intel/linux/linux.i386.conf +++ b/projects/Intel/linux/linux.i386.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -224,27 +225,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -324,8 +325,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -628,13 +629,15 @@ CONFIG_XPS=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -647,7 +650,7 @@ CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -# CONFIG_BT_ATH3K is not set +CONFIG_BT_ATH3K=m # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -659,8 +662,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1278,7 +1281,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO=y CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y @@ -1961,7 +1964,6 @@ CONFIG_DRM_KMS_HELPER=y # CONFIG_DRM_TDFX is not set # CONFIG_DRM_R128 is not set # CONFIG_DRM_RADEON is not set -# CONFIG_DRM_I810 is not set CONFIG_DRM_I915=y CONFIG_DRM_I915_KMS=y # CONFIG_DRM_MGA is not set @@ -2212,6 +2214,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2236,19 +2239,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2854,6 +2854,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/Intel/linux/linux.x86_64.conf b/projects/Intel/linux/linux.x86_64.conf index 6c5f894183..96d27d86bc 100644 --- a/projects/Intel/linux/linux.x86_64.conf +++ b/projects/Intel/linux/linux.x86_64.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -222,27 +223,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -297,8 +298,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -580,13 +581,15 @@ CONFIG_HAVE_BPF_JIT=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -599,7 +602,7 @@ CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -# CONFIG_BT_ATH3K is not set +CONFIG_BT_ATH3K=m # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -611,8 +614,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1132,7 +1135,7 @@ CONFIG_USB_NET_DM9601=m CONFIG_INPUT=y CONFIG_INPUT_FF_MEMLESS=y # CONFIG_INPUT_POLLDEV is not set -CONFIG_INPUT_SPARSEKMAP=m +# CONFIG_INPUT_SPARSEKMAP is not set # # Userland interfaces @@ -1228,7 +1231,7 @@ CONFIG_INPUT_UINPUT=y # CONFIG_SERIO=y CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set +CONFIG_SERIO_SERPORT=y # CONFIG_SERIO_CT82C710 is not set # CONFIG_SERIO_PCIPS2 is not set CONFIG_SERIO_LIBPS2=y @@ -1904,7 +1907,6 @@ CONFIG_DRM_KMS_HELPER=y # CONFIG_DRM_TDFX is not set # CONFIG_DRM_R128 is not set # CONFIG_DRM_RADEON is not set -# CONFIG_DRM_I810 is not set CONFIG_DRM_I915=y CONFIG_DRM_I915_KMS=y # CONFIG_DRM_MGA is not set @@ -2153,6 +2155,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2177,19 +2180,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2793,6 +2793,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/Intel/options b/projects/Intel/options index f2f7ab5cdc..d64994d5f7 100644 --- a/projects/Intel/options +++ b/projects/Intel/options @@ -112,6 +112,9 @@ # Default Skin (Confluence) SKIN_DEFAULT="Confluence" +# install extra subtitle Fonts for XBMC (yes / no) + XBMC_EXTRA_FONTS="yes" + # Plugins for XBMC to install (SABnzbd) # Space separated list is supported, # e.g. XBMC_PLUGINS="SABnzbd" diff --git a/projects/Ultra/linux/linux.x86_64.conf b/projects/Ultra/linux/linux.x86_64.conf index c651f1eb69..75afc557fc 100644 --- a/projects/Ultra/linux/linux.x86_64.conf +++ b/projects/Ultra/linux/linux.x86_64.conf @@ -98,12 +98,13 @@ CONFIG_IRQ_FORCED_THREADING=y # # RCU Subsystem # -CONFIG_TREE_RCU=y -# CONFIG_PREEMPT_RCU is not set +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_PREEMPT_RCU=y # CONFIG_RCU_TRACE is not set CONFIG_RCU_FANOUT=32 # CONFIG_RCU_FANOUT_EXACT is not set # CONFIG_TREE_RCU_TRACE is not set +# CONFIG_RCU_BOOST is not set CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y CONFIG_LOG_BUF_SHIFT=16 @@ -222,27 +223,27 @@ CONFIG_DEFAULT_IOSCHED="cfq" # CONFIG_INLINE_SPIN_LOCK_BH is not set # CONFIG_INLINE_SPIN_LOCK_IRQ is not set # CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set -CONFIG_INLINE_SPIN_UNLOCK=y +# CONFIG_INLINE_SPIN_UNLOCK is not set # CONFIG_INLINE_SPIN_UNLOCK_BH is not set -CONFIG_INLINE_SPIN_UNLOCK_IRQ=y +# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set # CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_READ_TRYLOCK is not set # CONFIG_INLINE_READ_LOCK is not set # CONFIG_INLINE_READ_LOCK_BH is not set # CONFIG_INLINE_READ_LOCK_IRQ is not set # CONFIG_INLINE_READ_LOCK_IRQSAVE is not set -CONFIG_INLINE_READ_UNLOCK=y +# CONFIG_INLINE_READ_UNLOCK is not set # CONFIG_INLINE_READ_UNLOCK_BH is not set -CONFIG_INLINE_READ_UNLOCK_IRQ=y +# CONFIG_INLINE_READ_UNLOCK_IRQ is not set # CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set # CONFIG_INLINE_WRITE_TRYLOCK is not set # CONFIG_INLINE_WRITE_LOCK is not set # CONFIG_INLINE_WRITE_LOCK_BH is not set # CONFIG_INLINE_WRITE_LOCK_IRQ is not set # CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set -CONFIG_INLINE_WRITE_UNLOCK=y +# CONFIG_INLINE_WRITE_UNLOCK is not set # CONFIG_INLINE_WRITE_UNLOCK_BH is not set -CONFIG_INLINE_WRITE_UNLOCK_IRQ=y +# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set # CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set CONFIG_MUTEX_SPIN_ON_OWNER=y CONFIG_FREEZER=y @@ -295,8 +296,8 @@ CONFIG_SCHED_SMT=y CONFIG_SCHED_MC=y # CONFIG_IRQ_TIME_ACCOUNTING is not set # CONFIG_PREEMPT_NONE is not set -CONFIG_PREEMPT_VOLUNTARY=y -# CONFIG_PREEMPT is not set +# CONFIG_PREEMPT_VOLUNTARY is not set +CONFIG_PREEMPT=y CONFIG_X86_LOCAL_APIC=y CONFIG_X86_IO_APIC=y # CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS is not set @@ -573,13 +574,15 @@ CONFIG_HAVE_BPF_JIT=y # CONFIG_HAMRADIO is not set # CONFIG_CAN is not set # CONFIG_IRDA is not set -CONFIG_BT=m +CONFIG_BT=y CONFIG_BT_L2CAP=y CONFIG_BT_SCO=y -CONFIG_BT_RFCOMM=m +CONFIG_BT_RFCOMM=y CONFIG_BT_RFCOMM_TTY=y -# CONFIG_BT_BNEP is not set -CONFIG_BT_HIDP=m +CONFIG_BT_BNEP=y +CONFIG_BT_BNEP_MC_FILTER=y +CONFIG_BT_BNEP_PROTO_FILTER=y +CONFIG_BT_HIDP=y # # Bluetooth device drivers @@ -591,7 +594,7 @@ CONFIG_BT_HCIBTUSB=m # CONFIG_BT_HCIBFUSB is not set # CONFIG_BT_HCIVHCI is not set # CONFIG_BT_MRVL is not set -# CONFIG_BT_ATH3K is not set +CONFIG_BT_ATH3K=m # CONFIG_AF_RXRPC is not set CONFIG_WIRELESS=y CONFIG_WIRELESS_EXT=y @@ -602,8 +605,8 @@ CONFIG_CFG80211=y # CONFIG_NL80211_TESTMODE is not set # CONFIG_CFG80211_DEVELOPER_WARNINGS is not set # CONFIG_CFG80211_REG_DEBUG is not set -# CONFIG_CFG80211_DEFAULT_PS is not set -# CONFIG_CFG80211_INTERNAL_REGDB is not set +CONFIG_CFG80211_DEFAULT_PS=y +CONFIG_CFG80211_INTERNAL_REGDB=y CONFIG_CFG80211_WEXT=y CONFIG_WIRELESS_EXT_SYSFS=y CONFIG_LIB80211=y @@ -1042,38 +1045,8 @@ CONFIG_INPUT_EVDEV=y # # Input Device Drivers # -CONFIG_INPUT_KEYBOARD=y -# CONFIG_KEYBOARD_ADP5588 is not set -# CONFIG_KEYBOARD_ADP5589 is not set -CONFIG_KEYBOARD_ATKBD=y -# CONFIG_KEYBOARD_QT1070 is not set -# CONFIG_KEYBOARD_QT2160 is not set -# CONFIG_KEYBOARD_LKKBD is not set -# CONFIG_KEYBOARD_TCA6416 is not set -# CONFIG_KEYBOARD_LM8323 is not set -# CONFIG_KEYBOARD_MAX7359 is not set -# CONFIG_KEYBOARD_MCS is not set -# CONFIG_KEYBOARD_MPR121 is not set -# CONFIG_KEYBOARD_NEWTON is not set -# CONFIG_KEYBOARD_OPENCORES is not set -# CONFIG_KEYBOARD_STOWAWAY is not set -# CONFIG_KEYBOARD_SUNKBD is not set -# CONFIG_KEYBOARD_XTKBD is not set -CONFIG_INPUT_MOUSE=y -CONFIG_MOUSE_PS2=y -CONFIG_MOUSE_PS2_ALPS=y -CONFIG_MOUSE_PS2_LOGIPS2PP=y -CONFIG_MOUSE_PS2_SYNAPTICS=y -CONFIG_MOUSE_PS2_LIFEBOOK=y -CONFIG_MOUSE_PS2_TRACKPOINT=y -# CONFIG_MOUSE_PS2_ELANTECH is not set -# CONFIG_MOUSE_PS2_SENTELIC is not set -# CONFIG_MOUSE_PS2_TOUCHKIT is not set -# CONFIG_MOUSE_SERIAL is not set -# CONFIG_MOUSE_APPLETOUCH is not set -# CONFIG_MOUSE_BCM5974 is not set -# CONFIG_MOUSE_VSXXXAA is not set -# CONFIG_MOUSE_SYNAPTICS_I2C is not set +# CONFIG_INPUT_KEYBOARD is not set +# CONFIG_INPUT_MOUSE is not set CONFIG_INPUT_JOYSTICK=y # CONFIG_JOYSTICK_ANALOG is not set # CONFIG_JOYSTICK_A3D is not set @@ -1120,15 +1093,7 @@ CONFIG_INPUT_UINPUT=y # # Hardware I/O ports # -CONFIG_SERIO=y -CONFIG_SERIO_I8042=y -# CONFIG_SERIO_SERPORT is not set -# CONFIG_SERIO_CT82C710 is not set -# CONFIG_SERIO_PCIPS2 is not set -CONFIG_SERIO_LIBPS2=y -# CONFIG_SERIO_RAW is not set -# CONFIG_SERIO_ALTERA_PS2 is not set -# CONFIG_SERIO_PS2MULT is not set +# CONFIG_SERIO is not set # CONFIG_GAMEPORT is not set # @@ -1977,6 +1942,7 @@ CONFIG_HID_AUREAL=y # CONFIG_HID_EMS_FF is not set # CONFIG_HID_ELECOM is not set # CONFIG_HID_EZKEY is not set +# CONFIG_HID_HOLTEK is not set # CONFIG_HID_KEYTOUCH is not set # CONFIG_HID_KYE is not set # CONFIG_HID_UCLOGIC is not set @@ -2001,19 +1967,16 @@ CONFIG_HID_MICROSOFT=y # CONFIG_HID_PICOLCD is not set # CONFIG_HID_QUANTA is not set # CONFIG_HID_ROCCAT is not set -# CONFIG_HID_ROCCAT_ARVO is not set -# CONFIG_HID_ROCCAT_KONE is not set -# CONFIG_HID_ROCCAT_KONEPLUS is not set -# CONFIG_HID_ROCCAT_KOVAPLUS is not set -# CONFIG_HID_ROCCAT_PYRA is not set # CONFIG_HID_SAMSUNG is not set CONFIG_HID_SONY=y +# CONFIG_HID_SPEEDLINK is not set CONFIG_HID_SUNPLUS=y # CONFIG_HID_GREENASIA is not set # CONFIG_HID_SMARTJOYPLUS is not set CONFIG_HID_TOPSEED=y # CONFIG_HID_THRUSTMASTER is not set # CONFIG_HID_WACOM is not set +CONFIG_HID_WIIMOTE=y # CONFIG_HID_ZEROPLUS is not set CONFIG_HID_ZYDACRON=y CONFIG_USB_SUPPORT=y @@ -2199,7 +2162,6 @@ CONFIG_LEDS_CLASS=y # CONFIG_LEDS_LP3944 is not set # CONFIG_LEDS_LP5521 is not set # CONFIG_LEDS_LP5523 is not set -# CONFIG_LEDS_CLEVO_MAIL is not set # CONFIG_LEDS_PCA955X is not set # CONFIG_LEDS_BD2802 is not set # CONFIG_LEDS_INTEL_SS4200 is not set @@ -2574,6 +2536,7 @@ CONFIG_FRAME_WARN=1024 CONFIG_ARCH_WANT_FRAME_POINTERS=y # CONFIG_FRAME_POINTER is not set CONFIG_RCU_CPU_STALL_TIMEOUT=60 +CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_SYSCTL_SYSCALL_CHECK=y CONFIG_USER_STACKTRACE_SUPPORT=y CONFIG_HAVE_FUNCTION_TRACER=y diff --git a/projects/Ultra/options b/projects/Ultra/options index 9a155fcbb2..833b71461e 100644 --- a/projects/Ultra/options +++ b/projects/Ultra/options @@ -112,6 +112,9 @@ # Default Skin (Confluence) SKIN_DEFAULT="Confluence" +# install extra subtitle Fonts for XBMC (yes / no) + XBMC_EXTRA_FONTS="yes" + # Plugins for XBMC to install (SABnzbd) # Space separated list is supported, # e.g. XBMC_PLUGINS="SABnzbd" diff --git a/projects/Ultra/xbmc/guisettings.xml b/projects/Ultra/xbmc/guisettings.xml new file mode 100644 index 0000000000..a9642c8082 --- /dev/null +++ b/projects/Ultra/xbmc/guisettings.xml @@ -0,0 +1,15 @@ + + true + custom + 0 + plughw:1,7 + plughw:1,7 + true + true + 0 + false + custom + false + false + false + diff --git a/tools/mkpkg/mkpkg_bluez b/tools/mkpkg/mkpkg_bluez new file mode 100755 index 0000000000..afc67cccf3 --- /dev/null +++ b/tools/mkpkg/mkpkg_bluez @@ -0,0 +1,43 @@ +#!/bin/sh +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# This Program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This Program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +echo "getting sources..." + if [ ! -d bluez.git ]; then + git clone git://git.kernel.org/pub/scm/bluetooth/bluez.git bluez.git + fi + + cd bluez.git + git pull + GIT_REV=`git log -n1 --format=%h` + cd .. + +echo "copying sources..." + rm -rf bluez-$GIT_REV + cp -R bluez.git bluez-$GIT_REV + +echo "cleaning sources..." + rm -rf bluez-$GIT_REV/.git + +echo "packing sources..." + tar cvJf bluez-$GIT_REV.tar.xz bluez-$GIT_REV + +echo "remove temporary sourcedir..." + rm -rf bluez-$GIT_REV diff --git a/tools/mkpkg/mkpkg_xf86-video-nouveau b/tools/mkpkg/mkpkg_xf86-video-nouveau new file mode 100755 index 0000000000..d8f8c213cf --- /dev/null +++ b/tools/mkpkg/mkpkg_xf86-video-nouveau @@ -0,0 +1,43 @@ +#!/bin/sh +################################################################################ +# This file is part of OpenELEC - http://www.openelec.tv +# Copyright (C) 2009-2011 Stephan Raue (stephan@openelec.tv) +# +# This Program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This Program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with OpenELEC.tv; see the file COPYING. If not, write to +# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. +# http://www.gnu.org/copyleft/gpl.html +################################################################################ + +echo "getting sources..." + if [ ! -d xf86-video-nouveau.git ]; then + git clone git://anongit.freedesktop.org/nouveau/xf86-video-nouveau -b master xf86-video-nouveau.git + fi + + cd xf86-video-nouveau.git + git pull + GIT_REV=`git log -n1 --format=%h` + cd .. + +echo "copying sources..." + rm -rf xf86-video-nouveau-$GIT_REV + cp -R xf86-video-nouveau.git xf86-video-nouveau-$GIT_REV + +echo "cleaning sources..." + rm -rf xf86-video-nouveau-$GIT_REV/.git + +echo "packing sources..." + tar cvJf xf86-video-nouveau-$GIT_REV.tar.xz xf86-video-nouveau-$GIT_REV + +echo "remove temporary sourcedir..." + rm -rf xf86-video-nouveau-$GIT_REV